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; }
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; }
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; }
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; }
/* * @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, FALSE)) { 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; }
/*++ * @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; }