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;
36 using System.Runtime.ExceptionServices;
38 namespace System.Security.AccessControl
40 public abstract class ObjectSecurity
42 protected ObjectSecurity ()
46 protected ObjectSecurity (CommonSecurityDescriptor securityDescriptor)
48 if (securityDescriptor == null)
49 throw new ArgumentNullException ("securityDescriptor");
51 descriptor = securityDescriptor;
52 rw_lock = new ReaderWriterLock ();
55 protected ObjectSecurity (bool isContainer, bool isDS)
56 : this (new CommonSecurityDescriptor
57 (isContainer, isDS, ControlFlags.None, null, null, null,
58 new DiscretionaryAcl (isContainer, isDS, 0)))
62 internal CommonSecurityDescriptor descriptor;
63 AccessControlSections sections_modified;
64 ReaderWriterLock rw_lock;
66 public abstract Type AccessRightType { get; }
68 public abstract Type AccessRuleType { get; }
70 public abstract Type AuditRuleType { get; }
72 public bool AreAccessRulesCanonical {
76 return descriptor.IsDiscretionaryAclCanonical;
83 public bool AreAccessRulesProtected {
87 return 0 != (descriptor.ControlFlags & ControlFlags.DiscretionaryAclProtected);
94 public bool AreAuditRulesCanonical {
98 return descriptor.IsSystemAclCanonical;
105 public bool AreAuditRulesProtected {
109 return 0 != (descriptor.ControlFlags & ControlFlags.SystemAclProtected);
116 internal AccessControlSections AccessControlSectionsModified {
117 get { Reading (); return sections_modified; }
118 set { Writing (); sections_modified = value; }
121 protected bool AccessRulesModified {
122 get { return AreAccessControlSectionsModified (AccessControlSections.Access); }
123 set { SetAccessControlSectionsModified (AccessControlSections.Access, value); }
126 protected bool AuditRulesModified {
127 get { return AreAccessControlSectionsModified (AccessControlSections.Audit); }
128 set { SetAccessControlSectionsModified (AccessControlSections.Audit, value); }
131 protected bool GroupModified {
132 get { return AreAccessControlSectionsModified (AccessControlSections.Group); }
133 set { SetAccessControlSectionsModified (AccessControlSections.Group, value); }
136 protected bool IsContainer {
137 get { return descriptor.IsContainer; }
140 protected bool IsDS {
141 get { return descriptor.IsDS; }
144 protected bool OwnerModified {
145 get { return AreAccessControlSectionsModified (AccessControlSections.Owner); }
146 set { SetAccessControlSectionsModified (AccessControlSections.Owner, value); }
149 public abstract AccessRule AccessRuleFactory (IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type);
151 public abstract AuditRule AuditRuleFactory (IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags);
153 public IdentityReference GetGroup (Type targetType)
157 if (descriptor.Group == null)
160 return descriptor.Group.Translate (targetType);
166 public IdentityReference GetOwner (Type targetType)
170 if (descriptor.Owner == null)
173 return descriptor.Owner.Translate (targetType);
179 public byte[] GetSecurityDescriptorBinaryForm ()
183 byte[] binaryForm = new byte[descriptor.BinaryLength];
184 descriptor.GetBinaryForm (binaryForm, 0);
191 public string GetSecurityDescriptorSddlForm (AccessControlSections includeSections)
195 return descriptor.GetSddlForm (includeSections);
201 public static bool IsSddlConversionSupported ()
203 return GenericSecurityDescriptor.IsSddlConversionSupported ();
206 public virtual bool ModifyAccessRule (AccessControlModification modification, AccessRule rule, out bool modified)
209 throw new ArgumentNullException ("rule");
211 if (!AccessRuleType.IsAssignableFrom (rule.GetType()))
212 throw new ArgumentException ("rule");
214 return ModifyAccess (modification, rule, out modified);
217 public virtual bool ModifyAuditRule (AccessControlModification modification, AuditRule rule, out bool modified)
220 throw new ArgumentNullException ("rule");
222 if (!AuditRuleType.IsAssignableFrom (rule.GetType()))
223 throw new ArgumentException ("rule");
225 return ModifyAudit (modification, rule, out modified);
228 public virtual void PurgeAccessRules (IdentityReference identity)
230 if (null == identity)
231 throw new ArgumentNullException ("identity");
235 descriptor.PurgeAccessControl (SidFromIR (identity));
241 public virtual void PurgeAuditRules (IdentityReference identity)
243 if (null == identity)
244 throw new ArgumentNullException ("identity");
248 descriptor.PurgeAudit (SidFromIR (identity));
254 public void SetAccessRuleProtection (bool isProtected,
255 bool preserveInheritance)
259 descriptor.SetDiscretionaryAclProtection (isProtected, preserveInheritance);
265 public void SetAuditRuleProtection (bool isProtected,
266 bool preserveInheritance)
270 descriptor.SetSystemAclProtection (isProtected, preserveInheritance);
276 public void SetGroup (IdentityReference identity)
280 descriptor.Group = SidFromIR (identity);
281 GroupModified = true;
287 public void SetOwner (IdentityReference identity)
291 descriptor.Owner = SidFromIR (identity);
292 OwnerModified = true;
298 public void SetSecurityDescriptorBinaryForm (byte[] binaryForm)
300 SetSecurityDescriptorBinaryForm (binaryForm, AccessControlSections.All);
303 public void SetSecurityDescriptorBinaryForm (byte[] binaryForm, AccessControlSections includeSections)
305 CopySddlForm (new CommonSecurityDescriptor (IsContainer, IsDS, binaryForm, 0), includeSections);
308 public void SetSecurityDescriptorSddlForm (string sddlForm)
310 SetSecurityDescriptorSddlForm (sddlForm, AccessControlSections.All);
313 public void SetSecurityDescriptorSddlForm (string sddlForm, AccessControlSections includeSections)
315 CopySddlForm (new CommonSecurityDescriptor (IsContainer, IsDS, sddlForm), includeSections);
318 void CopySddlForm (CommonSecurityDescriptor sourceDescriptor, AccessControlSections includeSections)
322 AccessControlSectionsModified |= includeSections;
323 if (0 != (includeSections & AccessControlSections.Audit))
324 descriptor.SystemAcl = sourceDescriptor.SystemAcl;
325 if (0 != (includeSections & AccessControlSections.Access))
326 descriptor.DiscretionaryAcl = sourceDescriptor.DiscretionaryAcl;
327 if (0 != (includeSections & AccessControlSections.Owner))
328 descriptor.Owner = sourceDescriptor.Owner;
329 if (0 != (includeSections & AccessControlSections.Group))
330 descriptor.Group = sourceDescriptor.Group;
336 protected abstract bool ModifyAccess (AccessControlModification modification, AccessRule rule, out bool modified);
338 protected abstract bool ModifyAudit (AccessControlModification modification, AuditRule rule, out bool modified);
340 // For MoMA. NotImplementedException is correct for this base class.
341 Exception GetNotImplementedException ()
343 return new NotImplementedException ();
346 protected virtual void Persist (SafeHandle handle, AccessControlSections includeSections)
348 throw GetNotImplementedException ();
351 protected virtual void Persist (string name, AccessControlSections includeSections)
353 throw GetNotImplementedException ();
357 [HandleProcessCorruptedStateExceptions]
358 protected virtual void Persist (bool enableOwnershipPrivilege, string name, AccessControlSections includeSections)
360 throw new NotImplementedException ();
365 if (!rw_lock.IsReaderLockHeld && !rw_lock.IsWriterLockHeld)
366 throw new InvalidOperationException ("Either a read or a write lock must be held.");
369 protected void ReadLock ()
371 rw_lock.AcquireReaderLock (Timeout.Infinite);
374 protected void ReadUnlock ()
376 rw_lock.ReleaseReaderLock ();
381 if (!rw_lock.IsWriterLockHeld)
382 throw new InvalidOperationException ("Write lock must be held.");
385 protected void WriteLock ()
387 rw_lock.AcquireWriterLock (Timeout.Infinite);
390 protected void WriteUnlock ()
392 rw_lock.ReleaseWriterLock ();
395 internal AuthorizationRuleCollection InternalGetAccessRules (bool includeExplicit,
396 bool includeInherited,
399 List<AuthorizationRule> rules = new List<AuthorizationRule> ();
403 foreach (GenericAce genericAce in descriptor.DiscretionaryAcl) {
404 QualifiedAce ace = genericAce as QualifiedAce;
405 if (null == ace) continue;
406 if (ace.IsInherited && !includeInherited) continue;
407 if (!ace.IsInherited && !includeExplicit) continue;
409 AccessControlType type;
410 if (AceQualifier.AccessAllowed == ace.AceQualifier)
411 type = AccessControlType.Allow;
412 else if (AceQualifier.AccessDenied == ace.AceQualifier)
413 type = AccessControlType.Deny;
417 AccessRule rule = InternalAccessRuleFactory (ace, targetType, type);
424 return new AuthorizationRuleCollection (rules.ToArray ());
427 internal virtual AccessRule InternalAccessRuleFactory (QualifiedAce ace, Type targetType,
428 AccessControlType type)
430 return AccessRuleFactory (ace.SecurityIdentifier.Translate (targetType),
431 ace.AccessMask, ace.IsInherited,
432 ace.InheritanceFlags, ace.PropagationFlags, type);
435 internal AuthorizationRuleCollection InternalGetAuditRules (bool includeExplicit,
436 bool includeInherited,
439 List<AuthorizationRule> rules = new List<AuthorizationRule> ();
443 if (null != descriptor.SystemAcl) {
444 foreach (GenericAce genericAce in descriptor.SystemAcl) {
445 QualifiedAce ace = genericAce as QualifiedAce;
446 if (null == ace) continue;
447 if (ace.IsInherited && !includeInherited) continue;
448 if (!ace.IsInherited && !includeExplicit) continue;
450 if (AceQualifier.SystemAudit != ace.AceQualifier) continue;
452 AuditRule rule = InternalAuditRuleFactory (ace, targetType);
460 return new AuthorizationRuleCollection (rules.ToArray ());
463 internal virtual AuditRule InternalAuditRuleFactory (QualifiedAce ace, Type targetType)
465 return AuditRuleFactory (ace.SecurityIdentifier.Translate (targetType),
466 ace.AccessMask, ace.IsInherited,
467 ace.InheritanceFlags, ace.PropagationFlags, ace.AuditFlags);
470 internal static SecurityIdentifier SidFromIR (IdentityReference identity)
472 if (null == identity)
473 throw new ArgumentNullException ("identity");
475 return (SecurityIdentifier)identity.Translate (typeof (SecurityIdentifier));
478 bool AreAccessControlSectionsModified (AccessControlSections mask)
480 return 0 != (AccessControlSectionsModified & mask);
483 void SetAccessControlSectionsModified(AccessControlSections mask, bool modified)
486 AccessControlSectionsModified |= mask;
488 AccessControlSectionsModified &= ~mask;