|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Classes: Common Object Security class
**
**
===========================================================*/
using Microsoft.Win32;
using System;
using System.Collections;
using System.Security.Principal;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Diagnostics.Contracts;
namespace System.Security.AccessControl
{
[PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
public abstract class CommonObjectSecurity: ObjectSecurity
{
#region Constructors
protected CommonObjectSecurity( bool isContainer )
: base( isContainer, false )
{
}
internal CommonObjectSecurity( CommonSecurityDescriptor securityDescriptor )
: base( securityDescriptor )
{
}
#endregion
#region Private Methods
private AuthorizationRuleCollection GetRules( bool access, bool includeExplicit, bool includeInherited, System.Type targetType )
{
ReadLock();
try
{
AuthorizationRuleCollection result = new AuthorizationRuleCollection();
if ( !SecurityIdentifier.IsValidTargetTypeStatic( targetType ))
{
throw new ArgumentException(
Environment.GetResourceString("Arg_MustBeIdentityReferenceType"),
"targetType" );
}
CommonAcl acl = null;
if ( access )
{
if (( _securityDescriptor.ControlFlags & ControlFlags.DiscretionaryAclPresent ) != 0)
{
acl = _securityDescriptor.DiscretionaryAcl;
}
}
else // !access == audit
{
if (( _securityDescriptor.ControlFlags & ControlFlags.SystemAclPresent ) != 0)
{
acl = _securityDescriptor.SystemAcl;
}
}
if ( acl == null )
{
//
// The required ACL was not present; return an empty collection.
//
return result;
}
IdentityReferenceCollection irTarget = null;
if ( targetType != typeof( SecurityIdentifier ))
{
IdentityReferenceCollection irSource = new IdentityReferenceCollection( acl.Count );
for ( int i = 0; i < acl.Count; i++ )
{
//
// Calling the indexer on a common ACL results in cloning,
// (which would not be the case if we were to use the internal RawAcl property)
// but also ensures that the resulting order of ACEs is proper
// However, this is a big price to pay - cloning all the ACEs just so that
// the canonical order could be ascertained just once.
// A better way would be to have an internal method that would canonicalize the ACL
// and call it once, then use the RawAcl.
//
CommonAce ace = acl[i] as CommonAce;
if (AceNeedsTranslation(ace, access, includeExplicit, includeInherited))
{
irSource.Add( ace.SecurityIdentifier );
}
}
irTarget = irSource.Translate( targetType );
}
int targetIndex = 0;
for ( int i = 0; i < acl.Count; i++ )
{
//
// Calling the indexer on a common ACL results in cloning,
// (which would not be the case if we were to use the internal RawAcl property)
// but also ensures that the resulting order of ACEs is proper
// However, this is a big price to pay - cloning all the ACEs just so that
// the canonical order could be ascertained just once.
// A better way would be to have an internal method that would canonicalize the ACL
// and call it once, then use the RawAcl.
//
CommonAce ace = acl[i] as CommonAce;
if (AceNeedsTranslation(ace, access, includeExplicit, includeInherited))
{
IdentityReference iref = ( targetType == typeof(SecurityIdentifier )) ? ace.SecurityIdentifier : irTarget[targetIndex++];
if ( access )
{
AccessControlType type;
if (ace.AceQualifier == AceQualifier.AccessAllowed)
{
type = AccessControlType.Allow;
}
else
{
type = AccessControlType.Deny;
}
result.AddRule(
AccessRuleFactory(
iref,
ace.AccessMask,
ace.IsInherited,
ace.InheritanceFlags,
ace.PropagationFlags,
type ));
}
else
{
result.AddRule(
AuditRuleFactory(
iref,
ace.AccessMask,
ace.IsInherited,
ace.InheritanceFlags,
ace.PropagationFlags,
ace.AuditFlags));
}
}
}
return result;
}
finally
{
ReadUnlock();
}
}
private bool AceNeedsTranslation(CommonAce ace, bool isAccessAce, bool includeExplicit, bool includeInherited)
{
if ( ace == null )
{
//
// Only consider common ACEs
//
return false;
}
if ( isAccessAce )
{
if ( ace.AceQualifier != AceQualifier.AccessAllowed &&
ace.AceQualifier != AceQualifier.AccessDenied )
{
return false;
}
}
else
{
if ( ace.AceQualifier != AceQualifier.SystemAudit )
{
return false;
}
}
if (( includeExplicit &&
(( ace.AceFlags & AceFlags.Inherited ) == 0 )) ||
( includeInherited &&
(( ace.AceFlags & AceFlags.Inherited ) != 0 )))
{
return true;
}
return false;
}
//
// Modifies the DACL
//
protected override bool ModifyAccess(AccessControlModification modification, AccessRule rule, out bool modified)
{
if (rule == null)
{
throw new ArgumentNullException("rule");
}
Contract.EndContractBlock();
WriteLock();
try
{
bool result = true;
if ( _securityDescriptor.DiscretionaryAcl == null )
{
if ( modification == AccessControlModification.Remove ||
modification == AccessControlModification.RemoveAll ||
modification == AccessControlModification.RemoveSpecific )
{
modified = false;
return result;
}
_securityDescriptor.DiscretionaryAcl = new DiscretionaryAcl( IsContainer, IsDS, GenericAcl.AclRevision, 1 );
_securityDescriptor.AddControlFlags(ControlFlags.DiscretionaryAclPresent);
}
SecurityIdentifier sid = rule.IdentityReference.Translate( typeof( SecurityIdentifier )) as SecurityIdentifier;
if ( rule.AccessControlType == AccessControlType.Allow )
{
switch ( modification )
{
case AccessControlModification.Add:
_securityDescriptor.DiscretionaryAcl.AddAccess( AccessControlType.Allow, sid, rule.AccessMask, rule.InheritanceFlags, rule.PropagationFlags );
break;
case AccessControlModification.Set:
_securityDescriptor.DiscretionaryAcl.SetAccess( AccessControlType.Allow, sid, rule.AccessMask, rule.InheritanceFlags, rule.PropagationFlags );
break;
case AccessControlModification.Reset:
_securityDescriptor.DiscretionaryAcl.RemoveAccess( AccessControlType.Deny, sid, -1, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, 0 );
_securityDescriptor.DiscretionaryAcl.SetAccess( AccessControlType.Allow, sid, rule.AccessMask, rule.InheritanceFlags, rule.PropagationFlags );
break;
case AccessControlModification.Remove:
result = _securityDescriptor.DiscretionaryAcl.RemoveAccess( AccessControlType.Allow, sid, rule.AccessMask, rule.InheritanceFlags, rule.PropagationFlags );
break;
case AccessControlModification.RemoveAll:
result = _securityDescriptor.DiscretionaryAcl.RemoveAccess( AccessControlType.Allow, sid, -1, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, 0 );
if ( result == false )
{
Contract.Assert( false, "Invalid operation" );
throw new SystemException();
}
break;
case AccessControlModification.RemoveSpecific:
_securityDescriptor.DiscretionaryAcl.RemoveAccessSpecific( AccessControlType.Allow, sid, rule.AccessMask, rule.InheritanceFlags, rule.PropagationFlags );
break;
default :
throw new ArgumentOutOfRangeException(
"modification",
Environment.GetResourceString( "ArgumentOutOfRange_Enum" ));
}
}
else if ( rule.AccessControlType == AccessControlType.Deny )
{
switch ( modification )
{
case AccessControlModification.Add :
_securityDescriptor.DiscretionaryAcl.AddAccess( AccessControlType.Deny, sid, rule.AccessMask, rule.InheritanceFlags, rule.PropagationFlags );
break;
case AccessControlModification.Set :
_securityDescriptor.DiscretionaryAcl.SetAccess( AccessControlType.Deny, sid, rule.AccessMask, rule.InheritanceFlags, rule.PropagationFlags );
break;
case AccessControlModification.Reset :
_securityDescriptor.DiscretionaryAcl.RemoveAccess( AccessControlType.Allow, sid, -1, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, 0 );
_securityDescriptor.DiscretionaryAcl.SetAccess( AccessControlType.Deny, sid, rule.AccessMask, rule.InheritanceFlags, rule.PropagationFlags );
break;
case AccessControlModification.Remove :
result = _securityDescriptor.DiscretionaryAcl.RemoveAccess(AccessControlType.Deny, sid, rule.AccessMask, rule.InheritanceFlags, rule.PropagationFlags );
break;
case AccessControlModification.RemoveAll :
result = _securityDescriptor.DiscretionaryAcl.RemoveAccess(AccessControlType.Deny, sid, -1, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, 0 );
if ( result == false )
{
Contract.Assert( false, "Invalid operation" );
throw new SystemException();
}
break;
case AccessControlModification.RemoveSpecific :
_securityDescriptor.DiscretionaryAcl.RemoveAccessSpecific( AccessControlType.Deny, sid, rule.AccessMask, rule.InheritanceFlags, rule.PropagationFlags );
break;
default :
throw new ArgumentOutOfRangeException(
"modification",
Environment.GetResourceString( "ArgumentOutOfRange_Enum" ));
}
}
else
{
Contract.Assert( false, "rule.AccessControlType unrecognized" );
throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)rule.AccessControlType), "rule.AccessControlType" );
}
modified = result;
AccessRulesModified |= modified;
return result;
}
finally
{
WriteUnlock();
}
}
//
// Modifies the SACL
//
protected override bool ModifyAudit( AccessControlModification modification, AuditRule rule, out bool modified )
{
if (rule == null)
{
throw new ArgumentNullException("rule");
}
Contract.EndContractBlock();
WriteLock();
try
{
bool result = true;
if ( _securityDescriptor.SystemAcl == null )
{
if ( modification == AccessControlModification.Remove ||
modification == AccessControlModification.RemoveAll ||
modification == AccessControlModification.RemoveSpecific )
{
modified = false;
return result;
}
_securityDescriptor.SystemAcl = new SystemAcl( IsContainer, IsDS, GenericAcl.AclRevision, 1 );
_securityDescriptor.AddControlFlags(ControlFlags.SystemAclPresent);
}
SecurityIdentifier sid = rule.IdentityReference.Translate( typeof( SecurityIdentifier )) as SecurityIdentifier;
switch ( modification )
{
case AccessControlModification.Add :
_securityDescriptor.SystemAcl.AddAudit( rule.AuditFlags, sid, rule.AccessMask, rule.InheritanceFlags, rule.PropagationFlags );
break;
case AccessControlModification.Set :
_securityDescriptor.SystemAcl.SetAudit( rule.AuditFlags, sid, rule.AccessMask, rule.InheritanceFlags, rule.PropagationFlags );
break;
case AccessControlModification.Reset :
_securityDescriptor.SystemAcl.SetAudit( rule.AuditFlags, sid, rule.AccessMask, rule.InheritanceFlags, rule.PropagationFlags );
break;
case AccessControlModification.Remove :
result = _securityDescriptor.SystemAcl.RemoveAudit( rule.AuditFlags, sid, rule.AccessMask, rule.InheritanceFlags, rule.PropagationFlags );
break;
case AccessControlModification.RemoveAll :
result = _securityDescriptor.SystemAcl.RemoveAudit( AuditFlags.Failure | AuditFlags.Success, sid, -1, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, 0 );
if ( result == false )
{
throw new InvalidProgramException();
}
break;
case AccessControlModification.RemoveSpecific :
_securityDescriptor.SystemAcl.RemoveAuditSpecific(rule.AuditFlags, sid, rule.AccessMask, rule.InheritanceFlags, rule.PropagationFlags );
break;
default :
throw new ArgumentOutOfRangeException(
"modification",
Environment.GetResourceString( "ArgumentOutOfRange_Enum" ));
}
modified = result;
AuditRulesModified |= modified;
return result;
}
finally
{
WriteUnlock();
}
}
#endregion
#region Protected Methods
#endregion
#region Public Methods
protected void AddAccessRule( AccessRule rule )
{
if ( rule == null )
{
throw new ArgumentNullException("rule");
}
Contract.EndContractBlock();
WriteLock();
try
{
bool modified;
ModifyAccess( AccessControlModification.Add, rule, out modified );
}
finally
{
WriteUnlock();
}
}
protected void SetAccessRule( AccessRule rule )
{
if ( rule == null )
{
throw new ArgumentNullException("rule");
}
Contract.EndContractBlock();
WriteLock();
try
{
bool modified;
ModifyAccess( AccessControlModification.Set, rule, out modified );
}
finally
{
WriteUnlock();
}
}
protected void ResetAccessRule( AccessRule rule )
{
if ( rule == null )
{
throw new ArgumentNullException("rule");
}
Contract.EndContractBlock();
WriteLock();
try
{
bool modified;
ModifyAccess( AccessControlModification.Reset, rule, out modified );
}
finally
{
WriteUnlock();
}
return;
}
protected bool RemoveAccessRule(AccessRule rule)
{
if ( rule == null )
{
throw new ArgumentNullException( "rule" );
}
Contract.EndContractBlock();
WriteLock();
try
{
if ( _securityDescriptor == null )
{
return true;
}
bool modified;
return ModifyAccess( AccessControlModification.Remove, rule, out modified );
}
finally
{
WriteUnlock();
}
}
protected void RemoveAccessRuleAll( AccessRule rule )
{
if ( rule == null )
{
throw new ArgumentNullException("rule");
}
Contract.EndContractBlock();
WriteLock();
try
{
if ( _securityDescriptor == null )
{
return;
}
bool modified;
ModifyAccess( AccessControlModification.RemoveAll, rule, out modified );
}
finally
{
WriteUnlock();
}
return;
}
protected void RemoveAccessRuleSpecific( AccessRule rule )
{
if ( rule == null )
{
throw new ArgumentNullException("rule");
}
Contract.EndContractBlock();
WriteLock();
try
{
if ( _securityDescriptor == null )
{
return;
}
bool modified;
ModifyAccess( AccessControlModification.RemoveSpecific, rule, out modified );
}
finally
{
WriteUnlock();
}
}
protected void AddAuditRule( AuditRule rule )
{
if ( rule == null )
{
throw new ArgumentNullException( "rule" );
}
Contract.EndContractBlock();
WriteLock();
try
{
bool modified;
ModifyAudit( AccessControlModification.Add, rule, out modified );
}
finally
{
WriteUnlock();
}
}
protected void SetAuditRule( AuditRule rule )
{
if ( rule == null )
{
throw new ArgumentNullException( "rule" );
}
Contract.EndContractBlock();
WriteLock();
try
{
bool modified;
ModifyAudit( AccessControlModification.Set, rule, out modified );
}
finally
{
WriteUnlock();
}
}
protected bool RemoveAuditRule( AuditRule rule )
{
if ( rule == null )
{
throw new ArgumentNullException( "rule" );
}
Contract.EndContractBlock();
WriteLock();
try
{
bool modified;
return ModifyAudit( AccessControlModification.Remove, rule, out modified );
}
finally
{
WriteUnlock();
}
}
protected void RemoveAuditRuleAll( AuditRule rule )
{
if ( rule == null )
{
throw new ArgumentNullException( "rule" );
}
Contract.EndContractBlock();
WriteLock();
try
{
bool modified;
ModifyAudit( AccessControlModification.RemoveAll, rule, out modified );
}
finally
{
WriteUnlock();
}
}
protected void RemoveAuditRuleSpecific( AuditRule rule )
{
if ( rule == null )
{
throw new ArgumentNullException( "rule" );
}
Contract.EndContractBlock();
WriteLock();
try
{
bool modified;
ModifyAudit( AccessControlModification.RemoveSpecific, rule, out modified );
}
finally
{
WriteUnlock();
}
}
public AuthorizationRuleCollection GetAccessRules( bool includeExplicit, bool includeInherited, System.Type targetType )
{
return GetRules( true, includeExplicit, includeInherited, targetType );
}
public AuthorizationRuleCollection GetAuditRules( bool includeExplicit, bool includeInherited, System.Type targetType )
{
return GetRules( false, includeExplicit, includeInherited, targetType );
}
#endregion
}
}
|