2 // System.Security.AccessControl.ObjectSecurity implementation
5 // Dick Porter <dick@ximian.com>
6 // Atsushi Enomoto <atsushi@ximian.com>
7 // James Bellinger <jfb@zer7.com>
9 // Copyright (C) 2005-2007 Novell, Inc (http://www.novell.com)
10 // Copyright (C) 2012 James Bellinger
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections.Generic;
33 using System.Security.Principal;
34 using System.Runtime.InteropServices;
35 using System.Threading;
37 namespace System.Security.AccessControl
39 public abstract class ObjectSecurity
41 internal ObjectSecurity (CommonSecurityDescriptor securityDescriptor)
43 if (securityDescriptor == null)
44 throw new ArgumentNullException ("securityDescriptor");
46 descriptor = securityDescriptor;
47 rw_lock = new ReaderWriterLock ();
50 protected ObjectSecurity (bool isContainer, bool isDS)
51 : this (new CommonSecurityDescriptor
52 (isContainer, isDS, ControlFlags.None, null, null, null,
53 new DiscretionaryAcl (isContainer, isDS, 0)))
57 internal CommonSecurityDescriptor descriptor;
58 AccessControlSections sections_modified;
59 ReaderWriterLock rw_lock;
61 public abstract Type AccessRightType { get; }
63 public abstract Type AccessRuleType { get; }
65 public abstract Type AuditRuleType { get; }
67 public bool AreAccessRulesCanonical {
71 return descriptor.IsDiscretionaryAclCanonical;
78 public bool AreAccessRulesProtected {
82 return 0 != (descriptor.ControlFlags & ControlFlags.DiscretionaryAclProtected);
89 public bool AreAuditRulesCanonical {
93 return descriptor.IsSystemAclCanonical;
100 public bool AreAuditRulesProtected {
104 return 0 != (descriptor.ControlFlags & ControlFlags.SystemAclProtected);
111 internal AccessControlSections AccessControlSectionsModified {
112 get { Reading (); return sections_modified; }
113 set { Writing (); sections_modified = value; }
116 protected bool AccessRulesModified {
117 get { return AreAccessControlSectionsModified (AccessControlSections.Access); }
118 set { SetAccessControlSectionsModified (AccessControlSections.Access, value); }
121 protected bool AuditRulesModified {
122 get { return AreAccessControlSectionsModified (AccessControlSections.Audit); }
123 set { SetAccessControlSectionsModified (AccessControlSections.Audit, value); }
126 protected bool GroupModified {
127 get { return AreAccessControlSectionsModified (AccessControlSections.Group); }
128 set { SetAccessControlSectionsModified (AccessControlSections.Group, value); }
131 protected bool IsContainer {
132 get { return descriptor.IsContainer; }
135 protected bool IsDS {
136 get { return descriptor.IsDS; }
139 protected bool OwnerModified {
140 get { return AreAccessControlSectionsModified (AccessControlSections.Owner); }
141 set { SetAccessControlSectionsModified (AccessControlSections.Owner, value); }
144 public abstract AccessRule AccessRuleFactory (IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type);
146 public abstract AuditRule AuditRuleFactory (IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags);
148 public IdentityReference GetGroup (Type targetType)
152 if (descriptor.Group == null)
155 return descriptor.Group.Translate (targetType);
161 public IdentityReference GetOwner (Type targetType)
165 if (descriptor.Owner == null)
168 return descriptor.Owner.Translate (targetType);
174 public byte[] GetSecurityDescriptorBinaryForm ()
178 byte[] binaryForm = new byte[descriptor.BinaryLength];
179 descriptor.GetBinaryForm (binaryForm, 0);
186 public string GetSecurityDescriptorSddlForm (AccessControlSections includeSections)
190 return descriptor.GetSddlForm (includeSections);
196 public static bool IsSddlConversionSupported ()
198 return GenericSecurityDescriptor.IsSddlConversionSupported ();
201 public virtual bool ModifyAccessRule (AccessControlModification modification, AccessRule rule, out bool modified)
204 throw new ArgumentNullException ("rule");
206 if (!AccessRuleType.IsAssignableFrom (rule.GetType()))
207 throw new ArgumentException ("rule");
209 return ModifyAccess (modification, rule, out modified);
212 public virtual bool ModifyAuditRule (AccessControlModification modification, AuditRule rule, out bool modified)
215 throw new ArgumentNullException ("rule");
217 if (!AuditRuleType.IsAssignableFrom (rule.GetType()))
218 throw new ArgumentException ("rule");
220 return ModifyAudit (modification, rule, out modified);
223 public virtual void PurgeAccessRules (IdentityReference identity)
225 if (null == identity)
226 throw new ArgumentNullException ("identity");
230 descriptor.PurgeAccessControl (SidFromIR (identity));
236 public virtual void PurgeAuditRules (IdentityReference identity)
238 if (null == identity)
239 throw new ArgumentNullException ("identity");
243 descriptor.PurgeAudit (SidFromIR (identity));
249 public void SetAccessRuleProtection (bool isProtected,
250 bool preserveInheritance)
254 descriptor.SetDiscretionaryAclProtection (isProtected, preserveInheritance);
260 public void SetAuditRuleProtection (bool isProtected,
261 bool preserveInheritance)
265 descriptor.SetSystemAclProtection (isProtected, preserveInheritance);
271 public void SetGroup (IdentityReference identity)
275 descriptor.Group = SidFromIR (identity);
276 GroupModified = true;
282 public void SetOwner (IdentityReference identity)
286 descriptor.Owner = SidFromIR (identity);
287 OwnerModified = true;
293 public void SetSecurityDescriptorBinaryForm (byte[] binaryForm)
295 SetSecurityDescriptorBinaryForm (binaryForm, AccessControlSections.All);
298 public void SetSecurityDescriptorBinaryForm (byte[] binaryForm, AccessControlSections includeSections)
300 CopySddlForm (new CommonSecurityDescriptor (IsContainer, IsDS, binaryForm, 0), includeSections);
303 public void SetSecurityDescriptorSddlForm (string sddlForm)
305 SetSecurityDescriptorSddlForm (sddlForm, AccessControlSections.All);
308 public void SetSecurityDescriptorSddlForm (string sddlForm, AccessControlSections includeSections)
310 CopySddlForm (new CommonSecurityDescriptor (IsContainer, IsDS, sddlForm), includeSections);
313 void CopySddlForm (CommonSecurityDescriptor sourceDescriptor, AccessControlSections includeSections)
317 AccessControlSectionsModified |= includeSections;
318 if (0 != (includeSections & AccessControlSections.Audit))
319 descriptor.SystemAcl = sourceDescriptor.SystemAcl;
320 if (0 != (includeSections & AccessControlSections.Access))
321 descriptor.DiscretionaryAcl = sourceDescriptor.DiscretionaryAcl;
322 if (0 != (includeSections & AccessControlSections.Owner))
323 descriptor.Owner = sourceDescriptor.Owner;
324 if (0 != (includeSections & AccessControlSections.Group))
325 descriptor.Group = sourceDescriptor.Group;
331 protected abstract bool ModifyAccess (AccessControlModification modification, AccessRule rule, out bool modified);
333 protected abstract bool ModifyAudit (AccessControlModification modification, AuditRule rule, out bool modified);
335 // For MoMA. NotImplementedException is correct for this base class.
336 Exception GetNotImplementedException ()
338 return new NotImplementedException ();
341 protected virtual void Persist (SafeHandle handle, AccessControlSections includeSections)
343 throw GetNotImplementedException ();
346 protected virtual void Persist (string name, AccessControlSections includeSections)
348 throw GetNotImplementedException ();
352 protected virtual void Persist (bool enableOwnershipPrivilege, string name, AccessControlSections includeSections)
354 throw new NotImplementedException ();
359 if (!rw_lock.IsReaderLockHeld && !rw_lock.IsWriterLockHeld)
360 throw new InvalidOperationException ("Either a read or a write lock must be held.");
363 protected void ReadLock ()
365 rw_lock.AcquireReaderLock (Timeout.Infinite);
368 protected void ReadUnlock ()
370 rw_lock.ReleaseReaderLock ();
375 if (!rw_lock.IsWriterLockHeld)
376 throw new InvalidOperationException ("Write lock must be held.");
379 protected void WriteLock ()
381 rw_lock.AcquireWriterLock (Timeout.Infinite);
384 protected void WriteUnlock ()
386 rw_lock.ReleaseWriterLock ();
389 internal AuthorizationRuleCollection InternalGetAccessRules (bool includeExplicit,
390 bool includeInherited,
393 List<AuthorizationRule> rules = new List<AuthorizationRule> ();
397 foreach (GenericAce genericAce in descriptor.DiscretionaryAcl) {
398 QualifiedAce ace = genericAce as QualifiedAce;
399 if (null == ace) continue;
400 if (ace.IsInherited && !includeInherited) continue;
401 if (!ace.IsInherited && !includeExplicit) continue;
403 AccessControlType type;
404 if (AceQualifier.AccessAllowed == ace.AceQualifier)
405 type = AccessControlType.Allow;
406 else if (AceQualifier.AccessDenied == ace.AceQualifier)
407 type = AccessControlType.Deny;
411 AccessRule rule = InternalAccessRuleFactory (ace, targetType, type);
418 return new AuthorizationRuleCollection (rules.ToArray ());
421 internal virtual AccessRule InternalAccessRuleFactory (QualifiedAce ace, Type targetType,
422 AccessControlType type)
424 return AccessRuleFactory (ace.SecurityIdentifier.Translate (targetType),
425 ace.AccessMask, ace.IsInherited,
426 ace.InheritanceFlags, ace.PropagationFlags, type);
429 internal AuthorizationRuleCollection InternalGetAuditRules (bool includeExplicit,
430 bool includeInherited,
433 List<AuthorizationRule> rules = new List<AuthorizationRule> ();
437 if (null != descriptor.SystemAcl) {
438 foreach (GenericAce genericAce in descriptor.SystemAcl) {
439 QualifiedAce ace = genericAce as QualifiedAce;
440 if (null == ace) continue;
441 if (ace.IsInherited && !includeInherited) continue;
442 if (!ace.IsInherited && !includeExplicit) continue;
444 if (AceQualifier.SystemAudit != ace.AceQualifier) continue;
446 AuditRule rule = InternalAuditRuleFactory (ace, targetType);
454 return new AuthorizationRuleCollection (rules.ToArray ());
457 internal virtual AuditRule InternalAuditRuleFactory (QualifiedAce ace, Type targetType)
459 return AuditRuleFactory (ace.SecurityIdentifier.Translate (targetType),
460 ace.AccessMask, ace.IsInherited,
461 ace.InheritanceFlags, ace.PropagationFlags, ace.AuditFlags);
464 internal static SecurityIdentifier SidFromIR (IdentityReference identity)
466 if (null == identity)
467 throw new ArgumentNullException ("identity");
469 return (SecurityIdentifier)identity.Translate (typeof (SecurityIdentifier));
472 bool AreAccessControlSectionsModified (AccessControlSections mask)
474 return 0 != (AccessControlSectionsModified & mask);
477 void SetAccessControlSectionsModified(AccessControlSections mask, bool modified)
480 AccessControlSectionsModified |= mask;
482 AccessControlSectionsModified &= ~mask;