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; }
KESYSAPI PPROCESS KEAPI PsCreateProcess( ) /*++ Create process allocating new space for PROCESS --*/ { if (!SUCCESS(SeAccessCheck (SE_1_CREATE_PROCESS, 0))) return NULL; PPROCESS Process = (PPROCESS) ExAllocateHeap( FALSE, sizeof(PROCESS) ); PspCreateProcess( Process ); MmCreateAddressSpace( Process ); PVOID Arguments[1] = { Process }; ExProcessCallbackList ( &PsCreateProcessCallbackList, 3, Arguments ); return Process; }
BOOLEAN NTAPI ObpCheckTraverseAccess(IN PVOID Object, IN ACCESS_MASK TraverseAccess, IN PACCESS_STATE AccessState OPTIONAL, IN BOOLEAN LockHeld, IN KPROCESSOR_MODE AccessMode, OUT PNTSTATUS AccessStatus) { POBJECT_HEADER ObjectHeader; POBJECT_TYPE ObjectType; PSECURITY_DESCRIPTOR SecurityDescriptor; BOOLEAN SdAllocated; BOOLEAN Result; ACCESS_MASK GrantedAccess = 0; PPRIVILEGE_SET Privileges = NULL; NTSTATUS Status; PAGED_CODE(); /* Get the header and type */ ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); ObjectType = ObjectHeader->Type; /* Get the security descriptor */ Status = ObGetObjectSecurity(Object, &SecurityDescriptor, &SdAllocated); if (!NT_SUCCESS(Status)) { /* We failed */ *AccessStatus = Status; return FALSE; } /* Lock the security context */ SeLockSubjectContext(&AccessState->SubjectSecurityContext); /* Now do the entire access check */ Result = SeAccessCheck(SecurityDescriptor, &AccessState->SubjectSecurityContext, TRUE, TraverseAccess, 0, &Privileges, &ObjectType->TypeInfo.GenericMapping, AccessMode, &GrantedAccess, AccessStatus); if (Privileges) { /* We got privileges, append them to the access state and free them */ Status = SeAppendPrivileges(AccessState, Privileges); SeFreePrivileges(Privileges); } /* We're done, unlock the context and release security */ SeUnlockSubjectContext(&AccessState->SubjectSecurityContext); ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated); return Result; }
KESYSAPI PTHREAD KEAPI PsCreateThread( IN PPROCESS OwningProcess, IN PVOID StartRoutine, IN PVOID StartContext ) /*++ Create new thread allocating new space for THREAD --*/ { if (!SUCCESS(SeAccessCheck (SE_1_CREATE_THREAD, 0))) return NULL; PTHREAD NewThread = (PTHREAD) ExAllocateHeap( FALSE, sizeof(THREAD) ); KeZeroMemory( NewThread, sizeof(THREAD) ); STATUS Status = SeInheritAccessTokenProcess ( OwningProcess, OwningProcess->AccessToken->Privileges1, OwningProcess->AccessToken->Privileges2, &NewThread->AccessToken ); if (!SUCCESS(Status)) { ExFreeHeap (NewThread); return NULL; } PspCreateThread( NewThread, OwningProcess, StartRoutine, StartContext ); PVOID Arguments[3] = { NewThread, StartRoutine, StartContext }; ExProcessCallbackList ( &PsCreateThreadCallbackList, 3, Arguments ); return NewThread; }
NTSTATUS FatExplicitDeviceAccessGranted ( IN PIRP_CONTEXT IrpContext, IN PDEVICE_OBJECT DeviceObject, IN PACCESS_STATE AccessState, IN KPROCESSOR_MODE ProcessorMode ) /*++ Routine Description: This function asks whether the SID described in the input access state has been granted any explicit access to the given device object. It does this by acquiring a token stripped of its ability to acquire access via the Everyone SID and re-doing the access check. Arguments: DeviceObject - the device whose ACL will be checked AccessState - the access state describing the security context to be checked ProcessorMode - the mode this check should occur against Return Value: NTSTATUS - Indicating whether explicit access was granted. --*/ { NTSTATUS Status; PACCESS_TOKEN OriginalAccessToken; PACCESS_TOKEN RestrictedAccessToken; PACCESS_TOKEN *EffectiveToken; ACCESS_MASK GrantedAccess; PAGED_CODE(); UNREFERENCED_PARAMETER( IrpContext ); // // If the access state indicates that specific access other // than traverse was acquired, either Everyone does have such // access or explicit access was granted. In both cases, we're // happy to let this proceed. // if (AccessState->PreviouslyGrantedAccess & (SPECIFIC_RIGHTS_ALL ^ FILE_TRAVERSE)) { return STATUS_SUCCESS; } // // If the manage volume privilege is held, this also permits access. // if (FatCheckManageVolumeAccess( IrpContext, AccessState, ProcessorMode )) { return STATUS_SUCCESS; } // // Capture the subject context as a prelude to everything below. // SeLockSubjectContext( &AccessState->SubjectSecurityContext ); // // Convert the token in the subject context into one which does not // acquire access through the Everyone SID. // // The logic for deciding which token is effective comes from // SeQuerySubjectContextToken; since there is no natural way // of getting a pointer to it, do it by hand. // if (ARGUMENT_PRESENT( AccessState->SubjectSecurityContext.ClientToken )) { EffectiveToken = &AccessState->SubjectSecurityContext.ClientToken; } else { EffectiveToken = &AccessState->SubjectSecurityContext.PrimaryToken; } OriginalAccessToken = *EffectiveToken; Status = FatCreateRestrictEveryoneToken( OriginalAccessToken, &RestrictedAccessToken ); if (!NT_SUCCESS(Status)) { SeReleaseSubjectContext( &AccessState->SubjectSecurityContext ); return Status; } // // Now see if the resulting context has access to the device through // its explicitly granted access. We swap in our restricted token // for this check as the effective client token. // *EffectiveToken = RestrictedAccessToken; #ifdef _MSC_VER #pragma prefast( suppress: 28175, "we're a file system, this is ok to touch" ) #endif SeAccessCheck( DeviceObject->SecurityDescriptor, &AccessState->SubjectSecurityContext, FALSE, AccessState->OriginalDesiredAccess, 0, NULL, IoGetFileObjectGenericMapping(), ProcessorMode, &GrantedAccess, &Status ); *EffectiveToken = OriginalAccessToken; // // Cleanup and return. // SeUnlockSubjectContext( &AccessState->SubjectSecurityContext ); ObDereferenceObject( RestrictedAccessToken ); return Status; }
IO_STATUS_BLOCK MsCreateClientEnd ( IN PFCB Fcb, IN PFILE_OBJECT FileObject, IN ACCESS_MASK DesiredAccess, IN USHORT ShareAccess, IN PACCESS_STATE AccessState, IN KPROCESSOR_MODE RequestorMode, IN PETHREAD UserThread ) /*++ Routine Description: This routine performs the operation for opening the client end of a mailslot. This routine does not complete the IRP, it performs the function and then returns a status. Arguments: Fcb - Supplies the FCB for the mailslot being accessed. FileObject - Supplies the file object associated with the client end. DesiredAccess - Supplies the caller's desired access. ShareAccess - Supplies the caller's share access. Return Value: IO_STATUS_BLOCK - Returns the appropriate status for the operation --*/ { IO_STATUS_BLOCK iosb; PCCB ccb; BOOLEAN accessGranted; ACCESS_MASK grantedAccess; UNICODE_STRING name; PPRIVILEGE_SET Privileges = NULL; BOOLEAN shareAccessUpdated = FALSE; PAGED_CODE(); DebugTrace(+1, Dbg, "MsCreateClientEnd\n", 0 ); try { // // First do an access check for the user against the Fcb // SeLockSubjectContext( &AccessState->SubjectSecurityContext ); accessGranted = SeAccessCheck( Fcb->SecurityDescriptor, &AccessState->SubjectSecurityContext, TRUE, // Tokens are locked DesiredAccess, 0, &Privileges, IoGetFileObjectGenericMapping(), RequestorMode, &grantedAccess, &iosb.Status ); if (Privileges != NULL) { (VOID) SeAppendPrivileges( AccessState, Privileges ); SeFreePrivileges( Privileges ); } if (accessGranted) { AccessState->PreviouslyGrantedAccess |= grantedAccess; AccessState->RemainingDesiredAccess &= ~grantedAccess; } RtlInitUnicodeString( &name, L"Mailslot" ); SeOpenObjectAuditAlarm( &name, NULL, &FileObject->FileName, Fcb->SecurityDescriptor, AccessState, FALSE, accessGranted, RequestorMode, &AccessState->GenerateOnClose ); SeUnlockSubjectContext( &AccessState->SubjectSecurityContext ); if (!accessGranted) { DebugTrace(0, Dbg, "Access Denied\n", 0 ); try_return( iosb.Status ); } // // Now make sure our share access is okay. // if (!NT_SUCCESS(iosb.Status = IoCheckShareAccess( DesiredAccess, ShareAccess, FileObject, &Fcb->ShareAccess, TRUE ))) { DebugTrace(0, Dbg, "Sharing violation\n", 0); try_return( NOTHING ); } shareAccessUpdated = TRUE; // // Create a CCB for this client. // ccb = MsCreateCcb( Fcb ); // // Set the file object back pointers and our pointer to the // server file object. // MsSetFileObject( FileObject, ccb, NULL ); ccb->FileObject = FileObject; // // And set our return status // iosb.Status = STATUS_SUCCESS; iosb.Information = FILE_OPENED; try_exit: NOTHING; } finally { DebugTrace(-1, Dbg, "MsCreateClientEnd -> %08lx\n", iosb.Status); if (!NT_SUCCESS(iosb.Status) || AbnormalTermination()) { if (shareAccessUpdated) { IoRemoveShareAccess( FileObject, &Fcb->ShareAccess ); } } } return iosb; }
/*++ * @name ObCheckObjectAccess * * The ObCheckObjectAccess routine <FILLMEIN> * * @param Object * <FILLMEIN> * * @param AccessState * <FILLMEIN> * * @param LockHeld * <FILLMEIN> * * @param AccessMode * <FILLMEIN> * * @param ReturnedStatus * <FILLMEIN> * * @return TRUE if access was granted, FALSE otherwise. * * @remarks None. * *--*/ BOOLEAN NTAPI ObCheckObjectAccess(IN PVOID Object, IN OUT PACCESS_STATE AccessState, IN BOOLEAN LockHeld, IN KPROCESSOR_MODE AccessMode, OUT PNTSTATUS ReturnedStatus) { POBJECT_HEADER ObjectHeader; POBJECT_TYPE ObjectType; PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; BOOLEAN SdAllocated; NTSTATUS Status; BOOLEAN Result; ACCESS_MASK GrantedAccess; PPRIVILEGE_SET Privileges = NULL; PAGED_CODE(); /* Get the object header and type */ ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); ObjectType = ObjectHeader->Type; /* Get security information */ Status = ObGetObjectSecurity(Object, &SecurityDescriptor, &SdAllocated); if (!NT_SUCCESS(Status)) { /* Return failure */ *ReturnedStatus = Status; return FALSE; } else if (!SecurityDescriptor) { /* Otherwise, if we don't actually have an SD, return success */ *ReturnedStatus = Status; return TRUE; } /* Lock the security context */ SeLockSubjectContext(&AccessState->SubjectSecurityContext); /* Now do the entire access check */ Result = SeAccessCheck(SecurityDescriptor, &AccessState->SubjectSecurityContext, TRUE, AccessState->RemainingDesiredAccess, AccessState->PreviouslyGrantedAccess, &Privileges, &ObjectType->TypeInfo.GenericMapping, AccessMode, &GrantedAccess, ReturnedStatus); if (Privileges) { /* We got privileges, append them to the access state and free them */ Status = SeAppendPrivileges(AccessState, Privileges); SeFreePrivileges(Privileges); } /* Check if access was granted */ if (Result) { /* Update the access state */ AccessState->RemainingDesiredAccess &= ~(GrantedAccess | MAXIMUM_ALLOWED); AccessState->PreviouslyGrantedAccess |= GrantedAccess; } /* Do audit alarm */ SeOpenObjectAuditAlarm(&ObjectType->Name, Object, NULL, SecurityDescriptor, AccessState, FALSE, Result, AccessMode, &AccessState->GenerateOnClose); /* We're done, unlock the context and release security */ SeUnlockSubjectContext(&AccessState->SubjectSecurityContext); ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated); return Result; }
BOOLEAN NTAPI ObpCheckObjectReference(IN PVOID Object, IN OUT PACCESS_STATE AccessState, IN BOOLEAN LockHeld, IN KPROCESSOR_MODE AccessMode, OUT PNTSTATUS AccessStatus) { POBJECT_HEADER ObjectHeader; POBJECT_TYPE ObjectType; PSECURITY_DESCRIPTOR SecurityDescriptor; BOOLEAN SdAllocated; BOOLEAN Result; ACCESS_MASK GrantedAccess = 0; PPRIVILEGE_SET Privileges = NULL; NTSTATUS Status; PAGED_CODE(); /* Get the header and type */ ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object); ObjectType = ObjectHeader->Type; /* Get the security descriptor */ Status = ObGetObjectSecurity(Object, &SecurityDescriptor, &SdAllocated); if (!NT_SUCCESS(Status)) { /* We failed */ *AccessStatus = Status; return FALSE; } /* Lock the security context */ SeLockSubjectContext(&AccessState->SubjectSecurityContext); /* Now do the entire access check */ Result = SeAccessCheck(SecurityDescriptor, &AccessState->SubjectSecurityContext, TRUE, AccessState->RemainingDesiredAccess, AccessState->PreviouslyGrantedAccess, &Privileges, &ObjectType->TypeInfo.GenericMapping, AccessMode, &GrantedAccess, AccessStatus); if (Result) { /* Update the access state */ AccessState->RemainingDesiredAccess &= ~GrantedAccess; AccessState->PreviouslyGrantedAccess |= GrantedAccess; } /* Check if we have an SD */ if (SecurityDescriptor) { /* Do audit alarm */ #if 0 SeObjectReferenceAuditAlarm(&AccessState->OperationID, Object, SecurityDescriptor, &AccessState->SubjectSecurityContext, AccessState->RemainingDesiredAccess | AccessState->PreviouslyGrantedAccess, ((PAUX_ACCESS_DATA)(AccessState->AuxData))-> PrivilegeSet, Result, AccessMode); #endif } /* We're done, unlock the context and release security */ SeUnlockSubjectContext(&AccessState->SubjectSecurityContext); ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated); return Result; }
NTSTATUS NTAPI PspSetPrimaryToken(IN PEPROCESS Process, IN HANDLE TokenHandle OPTIONAL, IN PACCESS_TOKEN Token OPTIONAL) { KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); BOOLEAN IsChild; PACCESS_TOKEN NewToken = Token; NTSTATUS Status, AccessStatus; BOOLEAN Result, SdAllocated; PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; SECURITY_SUBJECT_CONTEXT SubjectContext; PSTRACE(PS_SECURITY_DEBUG, "Process: %p Token: %p\n", Process, Token); /* Make sure we got a handle */ if (TokenHandle) { /* Reference it */ Status = ObReferenceObjectByHandle(TokenHandle, TOKEN_ASSIGN_PRIMARY, SeTokenObjectType, PreviousMode, (PVOID*)&NewToken, NULL); if (!NT_SUCCESS(Status)) return Status; } /* Check if this is a child */ Status = SeIsTokenChild(NewToken, &IsChild); if (!NT_SUCCESS(Status)) { /* Failed, dereference */ if (TokenHandle) ObDereferenceObject(NewToken); return Status; } /* Check if this was an independent token */ if (!IsChild) { /* Make sure we have the privilege to assign a new one */ if (!SeSinglePrivilegeCheck(SeAssignPrimaryTokenPrivilege, PreviousMode)) { /* Failed, dereference */ if (TokenHandle) ObDereferenceObject(NewToken); return STATUS_PRIVILEGE_NOT_HELD; } } /* Assign the token */ Status = PspAssignPrimaryToken(Process, NULL, NewToken); if (NT_SUCCESS(Status)) { /* * We need to completely reverify if the process still has access to * itself under this new token. */ Status = ObGetObjectSecurity(Process, &SecurityDescriptor, &SdAllocated); if (NT_SUCCESS(Status)) { /* Setup the security context */ SubjectContext.ProcessAuditId = Process; SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process); SubjectContext.ClientToken = NULL; /* Do the access check */ Result = SeAccessCheck(SecurityDescriptor, &SubjectContext, FALSE, MAXIMUM_ALLOWED, 0, NULL, &PsProcessType->TypeInfo.GenericMapping, PreviousMode, &Process->GrantedAccess, &AccessStatus); /* Dereference the token and let go the SD */ ObFastDereferenceObject(&Process->Token, SubjectContext.PrimaryToken); ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated); /* Remove access if it failed */ if (!Result) Process->GrantedAccess = 0; /* Setup granted access */ Process->GrantedAccess |= (PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE | PROCESS_CREATE_THREAD | PROCESS_DUP_HANDLE | PROCESS_CREATE_PROCESS | PROCESS_SET_INFORMATION | STANDARD_RIGHTS_ALL | PROCESS_SET_QUOTA); } } /* Dereference the token */ if (TokenHandle) ObDereferenceObject(NewToken); return Status; }