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 using System.Runtime.ExceptionServices;
40 namespace System.Security.AccessControl
42 public abstract class ObjectSecurity
44 internal ObjectSecurity (CommonSecurityDescriptor securityDescriptor)
46 if (securityDescriptor == null)
47 throw new ArgumentNullException ("securityDescriptor");
49 descriptor = securityDescriptor;
50 rw_lock = new ReaderWriterLock ();
53 protected ObjectSecurity (bool isContainer, bool isDS)
54 : this (new CommonSecurityDescriptor
55 (isContainer, isDS, ControlFlags.None, null, null, null,
56 new DiscretionaryAcl (isContainer, isDS, 0)))
60 internal CommonSecurityDescriptor descriptor;
61 AccessControlSections sections_modified;
62 ReaderWriterLock rw_lock;
64 public abstract Type AccessRightType { get; }
66 public abstract Type AccessRuleType { get; }
68 public abstract Type AuditRuleType { get; }
70 public bool AreAccessRulesCanonical {
74 return descriptor.IsDiscretionaryAclCanonical;
81 public bool AreAccessRulesProtected {
85 return 0 != (descriptor.ControlFlags & ControlFlags.DiscretionaryAclProtected);
92 public bool AreAuditRulesCanonical {
96 return descriptor.IsSystemAclCanonical;
103 public bool AreAuditRulesProtected {
107 return 0 != (descriptor.ControlFlags & ControlFlags.SystemAclProtected);
114 internal AccessControlSections AccessControlSectionsModified {
115 get { Reading (); return sections_modified; }
116 set { Writing (); sections_modified = value; }
119 protected bool AccessRulesModified {
120 get { return AreAccessControlSectionsModified (AccessControlSections.Access); }
121 set { SetAccessControlSectionsModified (AccessControlSections.Access, value); }
124 protected bool AuditRulesModified {
125 get { return AreAccessControlSectionsModified (AccessControlSections.Audit); }
126 set { SetAccessControlSectionsModified (AccessControlSections.Audit, value); }
129 protected bool GroupModified {
130 get { return AreAccessControlSectionsModified (AccessControlSections.Group); }
131 set { SetAccessControlSectionsModified (AccessControlSections.Group, value); }
134 protected bool IsContainer {
135 get { return descriptor.IsContainer; }
138 protected bool IsDS {
139 get { return descriptor.IsDS; }
142 protected bool OwnerModified {
143 get { return AreAccessControlSectionsModified (AccessControlSections.Owner); }
144 set { SetAccessControlSectionsModified (AccessControlSections.Owner, value); }
147 public abstract AccessRule AccessRuleFactory (IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type);
149 public abstract AuditRule AuditRuleFactory (IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags);
151 public IdentityReference GetGroup (Type targetType)
155 if (descriptor.Group == null)
158 return descriptor.Group.Translate (targetType);
164 public IdentityReference GetOwner (Type targetType)
168 if (descriptor.Owner == null)
171 return descriptor.Owner.Translate (targetType);
177 public byte[] GetSecurityDescriptorBinaryForm ()
181 byte[] binaryForm = new byte[descriptor.BinaryLength];
182 descriptor.GetBinaryForm (binaryForm, 0);
189 public string GetSecurityDescriptorSddlForm (AccessControlSections includeSections)
193 return descriptor.GetSddlForm (includeSections);
199 public static bool IsSddlConversionSupported ()
201 return GenericSecurityDescriptor.IsSddlConversionSupported ();
204 public virtual bool ModifyAccessRule (AccessControlModification modification, AccessRule rule, out bool modified)
207 throw new ArgumentNullException ("rule");
209 if (!AccessRuleType.IsAssignableFrom (rule.GetType()))
210 throw new ArgumentException ("rule");
212 return ModifyAccess (modification, rule, out modified);
215 public virtual bool ModifyAuditRule (AccessControlModification modification, AuditRule rule, out bool modified)
218 throw new ArgumentNullException ("rule");
220 if (!AuditRuleType.IsAssignableFrom (rule.GetType()))
221 throw new ArgumentException ("rule");
223 return ModifyAudit (modification, rule, out modified);
226 public virtual void PurgeAccessRules (IdentityReference identity)
228 if (null == identity)
229 throw new ArgumentNullException ("identity");
233 descriptor.PurgeAccessControl (SidFromIR (identity));
239 public virtual void PurgeAuditRules (IdentityReference identity)
241 if (null == identity)
242 throw new ArgumentNullException ("identity");
246 descriptor.PurgeAudit (SidFromIR (identity));
252 public void SetAccessRuleProtection (bool isProtected,
253 bool preserveInheritance)
257 descriptor.SetDiscretionaryAclProtection (isProtected, preserveInheritance);
263 public void SetAuditRuleProtection (bool isProtected,
264 bool preserveInheritance)
268 descriptor.SetSystemAclProtection (isProtected, preserveInheritance);
274 public void SetGroup (IdentityReference identity)
278 descriptor.Group = SidFromIR (identity);
279 GroupModified = true;
285 public void SetOwner (IdentityReference identity)
289 descriptor.Owner = SidFromIR (identity);
290 OwnerModified = true;
296 public void SetSecurityDescriptorBinaryForm (byte[] binaryForm)
298 SetSecurityDescriptorBinaryForm (binaryForm, AccessControlSections.All);
301 public void SetSecurityDescriptorBinaryForm (byte[] binaryForm, AccessControlSections includeSections)
303 CopySddlForm (new CommonSecurityDescriptor (IsContainer, IsDS, binaryForm, 0), includeSections);
306 public void SetSecurityDescriptorSddlForm (string sddlForm)
308 SetSecurityDescriptorSddlForm (sddlForm, AccessControlSections.All);
311 public void SetSecurityDescriptorSddlForm (string sddlForm, AccessControlSections includeSections)
313 CopySddlForm (new CommonSecurityDescriptor (IsContainer, IsDS, sddlForm), includeSections);
316 void CopySddlForm (CommonSecurityDescriptor sourceDescriptor, AccessControlSections includeSections)
320 AccessControlSectionsModified |= includeSections;
321 if (0 != (includeSections & AccessControlSections.Audit))
322 descriptor.SystemAcl = sourceDescriptor.SystemAcl;
323 if (0 != (includeSections & AccessControlSections.Access))
324 descriptor.DiscretionaryAcl = sourceDescriptor.DiscretionaryAcl;
325 if (0 != (includeSections & AccessControlSections.Owner))
326 descriptor.Owner = sourceDescriptor.Owner;
327 if (0 != (includeSections & AccessControlSections.Group))
328 descriptor.Group = sourceDescriptor.Group;
334 protected abstract bool ModifyAccess (AccessControlModification modification, AccessRule rule, out bool modified);
336 protected abstract bool ModifyAudit (AccessControlModification modification, AuditRule rule, out bool modified);
338 // For MoMA. NotImplementedException is correct for this base class.
339 Exception GetNotImplementedException ()
341 return new NotImplementedException ();
344 protected virtual void Persist (SafeHandle handle, AccessControlSections includeSections)
346 throw GetNotImplementedException ();
349 protected virtual void Persist (string name, AccessControlSections includeSections)
351 throw GetNotImplementedException ();
356 [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;