BOOLEAN SrvIsAdmin( CtxtHandle Handle ) /*++ Routine Description: Returns TRUE if the user represented by Handle is an administrator Arguments: Handle - Represents the user we're interested in Return Value: TRUE if the user is an administrator. FALSE otherwise. --*/ { NTSTATUS status; SECURITY_SUBJECT_CONTEXT SubjectContext; ACCESS_MASK GrantedAccess; GENERIC_MAPPING Mapping = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS }; HANDLE NullHandle = NULL; BOOLEAN retval = FALSE; PAGED_CODE(); // // Impersonate the client // status = ImpersonateSecurityContext( &Handle ); if( !NT_SUCCESS( status ) ) return FALSE; SeCaptureSubjectContext( &SubjectContext ); retval = SeAccessCheck( &SrvAdminSecurityDescriptor, &SubjectContext, FALSE, FILE_GENERIC_READ, 0, NULL, &Mapping, UserMode, &GrantedAccess, &status ); SeReleaseSubjectContext( &SubjectContext ); // // Revert back to our original identity // NtSetInformationThread( NtCurrentThread( ), ThreadImpersonationToken, &NullHandle, sizeof(NullHandle) ); return retval; }
BOOLEAN AFSIsInGroup(PSID Sid) { SECURITY_SUBJECT_CONTEXT subjectContext; PTOKEN_GROUPS groups; PACCESS_TOKEN token; BOOLEAN retVal = FALSE; SeCaptureSubjectContext( &subjectContext ); SeLockSubjectContext( &subjectContext ); token = SeQuerySubjectContextToken( &subjectContext ); if (NT_SUCCESS(SeQueryInformationToken(token, TokenGroups, (PVOID*) &groups))) { ULONG i; for (i = 0; !retVal && i < groups->GroupCount; i++) { retVal = RtlEqualSid(Sid, groups->Groups[i].Sid); } ExFreePool( groups ); } SeUnlockSubjectContext( &subjectContext ); SeReleaseSubjectContext( &subjectContext ); return retVal; }
NTSTATUS FspFsvolSetSecurityPrepare( PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request) { PAGED_CODE(); NTSTATUS Result; SECURITY_SUBJECT_CONTEXT SecuritySubjectContext; SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService; SECURITY_CLIENT_CONTEXT SecurityClientContext; HANDLE UserModeAccessToken; PEPROCESS Process; /* duplicate the subject context access token into an impersonation token */ SecurityQualityOfService.Length = sizeof SecurityQualityOfService; SecurityQualityOfService.ImpersonationLevel = SecurityIdentification; SecurityQualityOfService.ContextTrackingMode = SECURITY_STATIC_TRACKING; SecurityQualityOfService.EffectiveOnly = FALSE; SeCaptureSubjectContext(&SecuritySubjectContext); SeLockSubjectContext(&SecuritySubjectContext); Result = SeCreateClientSecurityFromSubjectContext(&SecuritySubjectContext, &SecurityQualityOfService, FALSE, &SecurityClientContext); SeUnlockSubjectContext(&SecuritySubjectContext); SeReleaseSubjectContext(&SecuritySubjectContext); if (!NT_SUCCESS(Result)) return Result; ASSERT(TokenImpersonation == SeTokenType(SecurityClientContext.ClientToken)); /* get a user-mode handle to the impersonation token */ Result = ObOpenObjectByPointer(SecurityClientContext.ClientToken, 0, 0, TOKEN_QUERY, *SeTokenObjectType, UserMode, &UserModeAccessToken); SeDeleteClientSecurity(&SecurityClientContext); if (!NT_SUCCESS(Result)) return Result; /* get a pointer to the current process so that we can close the impersonation token later */ Process = PsGetCurrentProcess(); ObReferenceObject(Process); /* send the user-mode handle to the user-mode file system */ FspIopRequestContext(Request, RequestAccessToken) = UserModeAccessToken; FspIopRequestContext(Request, RequestProcess) = Process; Request->Req.SetSecurity.AccessToken = (UINT_PTR)UserModeAccessToken; return STATUS_SUCCESS; }
BOOLEAN AFSIsUser( IN PSID Sid) { SECURITY_SUBJECT_CONTEXT subjectContext; PTOKEN_USER user; PACCESS_TOKEN token; BOOLEAN retVal = FALSE; SeCaptureSubjectContext( &subjectContext); SeLockSubjectContext( &subjectContext); token = SeQuerySubjectContextToken( &subjectContext); if (NT_SUCCESS (SeQueryInformationToken( token, TokenUser, (PVOID*) &user))) { retVal = RtlEqualSid( user->User.Sid, Sid); ExFreePool( user ); } SeUnlockSubjectContext( &subjectContext); SeReleaseSubjectContext( &subjectContext); return retVal; }
VOID NtfsInitializeNtfsData ( IN PDRIVER_OBJECT DriverObject ) /*++ Routine Description: This routine initializes the global ntfs data record Arguments: DriverObject - Supplies the driver object for NTFS Return Value: None. --*/ { USHORT FileLockMaxDepth; USHORT IoContextMaxDepth; USHORT IrpContextMaxDepth; USHORT KeventMaxDepth; USHORT ScbNonpagedMaxDepth; USHORT ScbSnapshotMaxDepth; USHORT CcbDataMaxDepth; USHORT CcbMaxDepth; USHORT DeallocatedRecordsMaxDepth; USHORT FcbDataMaxDepth; USHORT FcbIndexMaxDepth; USHORT IndexContextMaxDepth; USHORT LcbMaxDepth; USHORT NukemMaxDepth; USHORT ScbDataMaxDepth; PSECURITY_SUBJECT_CONTEXT SubjectContext = NULL; BOOLEAN CapturedSubjectContext = FALSE; PACL SystemDacl = NULL; ULONG SystemDaclLength; PSID AdminSid = NULL; PSID SystemSid = NULL; NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); DebugTrace( +1, Dbg, ("NtfsInitializeNtfsData\n") ); // // Zero the record and set its node type code and size // RtlZeroMemory( &NtfsData, sizeof(NTFS_DATA)); NtfsData.NodeTypeCode = NTFS_NTC_DATA_HEADER; NtfsData.NodeByteSize = sizeof(NTFS_DATA); // // Initialize the queue of mounted Vcbs // InitializeListHead(&NtfsData.VcbQueue); // // This list head keeps track of closes yet to be done. // InitializeListHead( &NtfsData.AsyncCloseList ); InitializeListHead( &NtfsData.DelayedCloseList ); ExInitializeWorkItem( &NtfsData.NtfsCloseItem, (PWORKER_THREAD_ROUTINE)NtfsFspClose, NULL ); // // Set the driver object, device object, and initialize the global // resource protecting the file system // NtfsData.DriverObject = DriverObject; ExInitializeResource( &NtfsData.Resource ); // // Now allocate and initialize the s-list structures used as our pool // of IRP context records. The size of the zone is based on the // system memory size. We also initialize the spin lock used to protect // the zone. // KeInitializeSpinLock( &NtfsData.StrucSupSpinLock ); { switch ( MmQuerySystemSize() ) { case MmSmallSystem: NtfsData.FreeEresourceTotal = 14; // // Nonpaged Lookaside list maximum depths // FileLockMaxDepth = 8; IoContextMaxDepth = 8; IrpContextMaxDepth = 4; KeventMaxDepth = 8; ScbNonpagedMaxDepth = 8; ScbSnapshotMaxDepth = 8; // // Paged Lookaside list maximum depths // CcbDataMaxDepth = 4; CcbMaxDepth = 4; DeallocatedRecordsMaxDepth = 8; FcbDataMaxDepth = 8; FcbIndexMaxDepth = 4; IndexContextMaxDepth = 8; LcbMaxDepth = 4; NukemMaxDepth = 8; ScbDataMaxDepth = 4; SetFlag( NtfsData.Flags, NTFS_FLAGS_SMALL_SYSTEM ); NtfsMaxDelayedCloseCount = MAX_DELAYED_CLOSE_COUNT; break; case MmMediumSystem: NtfsData.FreeEresourceTotal = 30; // // Nonpaged Lookaside list maximum depths // FileLockMaxDepth = 8; IoContextMaxDepth = 8; IrpContextMaxDepth = 8; KeventMaxDepth = 8; ScbNonpagedMaxDepth = 30; ScbSnapshotMaxDepth = 8; // // Paged Lookaside list maximum depths // CcbDataMaxDepth = 12; CcbMaxDepth = 6; DeallocatedRecordsMaxDepth = 8; FcbDataMaxDepth = 30; FcbIndexMaxDepth = 12; IndexContextMaxDepth = 8; LcbMaxDepth = 12; NukemMaxDepth = 8; ScbDataMaxDepth = 12; SetFlag( NtfsData.Flags, NTFS_FLAGS_MEDIUM_SYSTEM ); NtfsMaxDelayedCloseCount = 4 * MAX_DELAYED_CLOSE_COUNT; break; case MmLargeSystem: SetFlag( NtfsData.Flags, NTFS_FLAGS_LARGE_SYSTEM ); NtfsMaxDelayedCloseCount = 16 * MAX_DELAYED_CLOSE_COUNT; if (MmIsThisAnNtAsSystem()) { NtfsData.FreeEresourceTotal = 256; // // Nonpaged Lookaside list maximum depths // FileLockMaxDepth = 8; IoContextMaxDepth = 8; IrpContextMaxDepth = 256; KeventMaxDepth = 8; ScbNonpagedMaxDepth = 128; ScbSnapshotMaxDepth = 8; // // Paged Lookaside list maximum depths // CcbDataMaxDepth = 40; CcbMaxDepth = 20; DeallocatedRecordsMaxDepth = 8; FcbDataMaxDepth = 128; FcbIndexMaxDepth = 40; IndexContextMaxDepth = 8; LcbMaxDepth = 40; NukemMaxDepth = 8; ScbDataMaxDepth = 40; } else { NtfsData.FreeEresourceTotal = 128; // // Nonpaged Lookaside list maximum depths // FileLockMaxDepth = 8; IoContextMaxDepth = 8; IrpContextMaxDepth = 64; KeventMaxDepth = 8; ScbNonpagedMaxDepth = 64; ScbSnapshotMaxDepth = 8; // // Paged Lookaside list maximum depths // CcbDataMaxDepth = 20; CcbMaxDepth = 10; DeallocatedRecordsMaxDepth = 8; FcbDataMaxDepth = 64; FcbIndexMaxDepth = 20; IndexContextMaxDepth = 8; LcbMaxDepth = 20; NukemMaxDepth = 8; ScbDataMaxDepth = 20; } break; } NtfsMinDelayedCloseCount = NtfsMaxDelayedCloseCount * 4 / 5; } // // Initialize our various lookaside lists. To make it a bit more readable we'll // define two quick macros to do the initialization // #if DBG && i386 && defined (NTFSPOOLCHECK) #define NPagedInit(L,S,T,D) { ExInitializeNPagedLookasideList( (L), NtfsDebugAllocatePoolWithTag, NtfsDebugFreePool, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); } #define PagedInit(L,S,T,D) { ExInitializePagedLookasideList( (L), NtfsDebugAllocatePoolWithTag, NtfsDebugFreePool, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); } #else // DBG && i386 #define NPagedInit(L,S,T,D) { ExInitializeNPagedLookasideList( (L), NULL, NULL, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); } #define PagedInit(L,S,T,D) { ExInitializePagedLookasideList( (L), NULL, NULL, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); } #endif // DBG && i386 NPagedInit( &NtfsFileLockLookasideList, sizeof(FILE_LOCK), 'kftN', FileLockMaxDepth ); NPagedInit( &NtfsIoContextLookasideList, sizeof(NTFS_IO_CONTEXT), 'IftN', IoContextMaxDepth ); NPagedInit( &NtfsIrpContextLookasideList, sizeof(IRP_CONTEXT), 'iftN', IrpContextMaxDepth ); NPagedInit( &NtfsKeventLookasideList, sizeof(KEVENT), 'KftN', KeventMaxDepth ); NPagedInit( &NtfsScbNonpagedLookasideList, sizeof(SCB_NONPAGED), 'nftN', ScbNonpagedMaxDepth ); NPagedInit( &NtfsScbSnapshotLookasideList, sizeof(SCB_SNAPSHOT), 'TftN', ScbSnapshotMaxDepth ); PagedInit( &NtfsCcbLookasideList, sizeof(CCB), 'CftN', CcbMaxDepth ); PagedInit( &NtfsCcbDataLookasideList, sizeof(CCB_DATA), 'cftN', CcbDataMaxDepth ); PagedInit( &NtfsDeallocatedRecordsLookasideList, sizeof(DEALLOCATED_RECORDS), 'DftN', DeallocatedRecordsMaxDepth ); PagedInit( &NtfsFcbDataLookasideList, sizeof(FCB_DATA), 'fftN', FcbDataMaxDepth ); PagedInit( &NtfsFcbIndexLookasideList, sizeof(FCB_INDEX), 'FftN', FcbIndexMaxDepth ); PagedInit( &NtfsIndexContextLookasideList, sizeof(INDEX_CONTEXT), 'EftN', IndexContextMaxDepth ); PagedInit( &NtfsLcbLookasideList, sizeof(LCB), 'lftN', LcbMaxDepth ); PagedInit( &NtfsNukemLookasideList, sizeof(NUKEM), 'NftN', NukemMaxDepth ); PagedInit( &NtfsScbDataLookasideList, SIZEOF_SCB_DATA, 'sftN', ScbDataMaxDepth ); // // Initialize the cache manager callback routines, First are the routines // for normal file manipulations, followed by the routines for // volume manipulations. // { PCACHE_MANAGER_CALLBACKS Callbacks = &NtfsData.CacheManagerCallbacks; Callbacks->AcquireForLazyWrite = &NtfsAcquireScbForLazyWrite; Callbacks->ReleaseFromLazyWrite = &NtfsReleaseScbFromLazyWrite; Callbacks->AcquireForReadAhead = &NtfsAcquireScbForReadAhead; Callbacks->ReleaseFromReadAhead = &NtfsReleaseScbFromReadAhead; } { PCACHE_MANAGER_CALLBACKS Callbacks = &NtfsData.CacheManagerVolumeCallbacks; Callbacks->AcquireForLazyWrite = &NtfsAcquireVolumeFileForLazyWrite; Callbacks->ReleaseFromLazyWrite = &NtfsReleaseVolumeFileFromLazyWrite; Callbacks->AcquireForReadAhead = NULL; Callbacks->ReleaseFromReadAhead = NULL; } // // Initialize the queue of read ahead threads // InitializeListHead(&NtfsData.ReadAheadThreads); // // Set up global pointer to our process. // NtfsData.OurProcess = PsGetCurrentProcess(); // // Use a try-finally to cleanup on errors. // try { SECURITY_DESCRIPTOR NewDescriptor; SID_IDENTIFIER_AUTHORITY Authority = SECURITY_NT_AUTHORITY; SubjectContext = NtfsAllocatePool( PagedPool, sizeof( SECURITY_SUBJECT_CONTEXT )); SeCaptureSubjectContext( SubjectContext ); CapturedSubjectContext = TRUE; // // Build the default security descriptor which gives full access to // system and administrator. // AdminSid = (PSID) NtfsAllocatePool( PagedPool, RtlLengthRequiredSid( 2 )); RtlInitializeSid( AdminSid, &Authority, 2 ); *(RtlSubAuthoritySid( AdminSid, 0 )) = SECURITY_BUILTIN_DOMAIN_RID; *(RtlSubAuthoritySid( AdminSid, 1 )) = DOMAIN_ALIAS_RID_ADMINS; SystemSid = (PSID) NtfsAllocatePool( PagedPool, RtlLengthRequiredSid( 1 )); RtlInitializeSid( SystemSid, &Authority, 1 ); *(RtlSubAuthoritySid( SystemSid, 0 )) = SECURITY_LOCAL_SYSTEM_RID; SystemDaclLength = sizeof( ACL ) + (2 * sizeof( ACCESS_ALLOWED_ACE )) + SeLengthSid( AdminSid ) + SeLengthSid( SystemSid ) + 8; // The 8 is just for good measure SystemDacl = NtfsAllocatePool( PagedPool, SystemDaclLength ); Status = RtlCreateAcl( SystemDacl, SystemDaclLength, ACL_REVISION2 ); if (!NT_SUCCESS( Status )) { leave; } Status = RtlAddAccessAllowedAce( SystemDacl, ACL_REVISION2, GENERIC_ALL, SystemSid ); if (!NT_SUCCESS( Status )) { leave; } Status = RtlAddAccessAllowedAce( SystemDacl, ACL_REVISION2, GENERIC_ALL, AdminSid ); if (!NT_SUCCESS( Status )) { leave; } Status = RtlCreateSecurityDescriptor( &NewDescriptor, SECURITY_DESCRIPTOR_REVISION1 ); if (!NT_SUCCESS( Status )) { leave; } Status = RtlSetDaclSecurityDescriptor( &NewDescriptor, TRUE, SystemDacl, FALSE ); if (!NT_SUCCESS( Status )) { leave; } Status = SeAssignSecurity( NULL, &NewDescriptor, &NtfsData.DefaultDescriptor, FALSE, SubjectContext, IoGetFileObjectGenericMapping(), PagedPool ); if (!NT_SUCCESS( Status )) { leave; } NtfsData.DefaultDescriptorLength = RtlLengthSecurityDescriptor( NtfsData.DefaultDescriptor ); ASSERT( SeValidSecurityDescriptor( NtfsData.DefaultDescriptorLength, NtfsData.DefaultDescriptor )); } finally { if (CapturedSubjectContext) { SeReleaseSubjectContext( SubjectContext ); } if (SubjectContext != NULL) { NtfsFreePool( SubjectContext ); } if (SystemDacl != NULL) { NtfsFreePool( SystemDacl ); } if (AdminSid != NULL) { NtfsFreePool( AdminSid ); } if (SystemSid != NULL) { NtfsFreePool( SystemSid ); } } // // Raise if we hit an error building the security descriptor. // if (!NT_SUCCESS( Status )) { ExRaiseStatus( Status ); } // // And return to our caller // DebugTrace( -1, Dbg, ("NtfsInitializeNtfsData -> VOID\n") ); return; }
BOOLEAN SeCheckPrivilegedObject( __in LUID PrivilegeValue, __in HANDLE ObjectHandle, __in ACCESS_MASK DesiredAccess, __in KPROCESSOR_MODE PreviousMode ) /*++ Routine Description: This function will check for the passed privilege value in the current context, and generate audits as appropriate. Arguments: PrivilegeValue - The value of the privilege being checked. Object - Specifies a pointer to the object being accessed. ObjectHandle - Specifies the object handle being used. DesiredAccess - The desired access mask, if any PreviousMode - The previous processor mode Return Value: TRUE - The current subject has the desired privilege. FALSE - The current subject does not have the desired privilege. --*/ { BOOLEAN AccessGranted; PRIVILEGE_SET RequiredPrivileges; SECURITY_SUBJECT_CONTEXT SubjectSecurityContext; PAGED_CODE(); // // Make sure the caller has the privilege to make this // call. // RequiredPrivileges.PrivilegeCount = 1; RequiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY; RequiredPrivileges.Privilege[0].Luid = PrivilegeValue; RequiredPrivileges.Privilege[0].Attributes = 0; SeCaptureSubjectContext( &SubjectSecurityContext ); AccessGranted = SePrivilegeCheck( &RequiredPrivileges, &SubjectSecurityContext, PreviousMode ); if ( PreviousMode != KernelMode ) { SePrivilegeObjectAuditAlarm( ObjectHandle, &SubjectSecurityContext, DesiredAccess, &RequiredPrivileges, AccessGranted, PreviousMode ); } SeReleaseSubjectContext( &SubjectSecurityContext ); return( AccessGranted ); }
BOOLEAN SeSinglePrivilegeCheck( __in LUID PrivilegeValue, __in KPROCESSOR_MODE PreviousMode ) /*++ Routine Description: This function will check for the passed privilege value in the current context. Arguments: PrivilegeValue - The value of the privilege being checked. Return Value: TRUE - The current subject has the desired privilege. FALSE - The current subject does not have the desired privilege. --*/ { BOOLEAN AccessGranted; PRIVILEGE_SET RequiredPrivileges; SECURITY_SUBJECT_CONTEXT SubjectSecurityContext; PAGED_CODE(); // // Make sure the caller has the privilege to make this // call. // RequiredPrivileges.PrivilegeCount = 1; RequiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY; RequiredPrivileges.Privilege[0].Luid = PrivilegeValue; RequiredPrivileges.Privilege[0].Attributes = 0; SeCaptureSubjectContext( &SubjectSecurityContext ); AccessGranted = SePrivilegeCheck( &RequiredPrivileges, &SubjectSecurityContext, PreviousMode ); if ( PreviousMode != KernelMode ) { SePrivilegedServiceAuditAlarm ( NULL, &SubjectSecurityContext, &RequiredPrivileges, AccessGranted ); } SeReleaseSubjectContext( &SubjectSecurityContext ); return( AccessGranted ); }
/* * @implemented */ NTSTATUS NTAPI NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN HANDLE TokenHandle, IN ACCESS_MASK DesiredAccess, IN PGENERIC_MAPPING GenericMapping, OUT PPRIVILEGE_SET PrivilegeSet OPTIONAL, IN OUT PULONG PrivilegeSetLength, 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) { /* Check if kernel wants everything */ if (DesiredAccess & MAXIMUM_ALLOWED) { /* Give it */ *GrantedAccess = GenericMapping->GenericAll; *GrantedAccess |= (DesiredAccess &~ MAXIMUM_ALLOWED); } else { /* 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)); /* Initialize the privilege set */ PrivilegeSet->PrivilegeCount = 0; } _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, SeTokenObjectType, PreviousMode, (PVOID*)&Token, NULL); if (!NT_SUCCESS(Status)) { DPRINT("Failed to reference token (Status %lx)\n", Status); return Status; } /* Check token type */ if (Token->TokenType != TokenImpersonation) { DPRINT("No impersonation token\n"); ObDereferenceObject(Token); 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 */ SeCaptureSubjectContext(&SubjectSecurityContext); /* Lock the token */ SepAcquireTokenLockShared(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, FALSE)) // 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); } /* Release subject context and unlock the token */ SeReleaseSubjectContext(&SubjectSecurityContext); SepReleaseTokenLock(Token); /* Release the captured security descriptor */ SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, PreviousMode, FALSE); /* Dereference the token */ ObDereferenceObject(Token); /* Check succeeded */ return STATUS_SUCCESS; }