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 internal ObjectSecurity (CommonSecurityDescriptor securityDescriptor)
44 if (securityDescriptor == null)
45 throw new ArgumentNullException ("securityDescriptor");
47 descriptor = securityDescriptor;
48 rw_lock = new ReaderWriterLock ();
51 protected ObjectSecurity (bool isContainer, bool isDS)
52 : this (new CommonSecurityDescriptor
53 (isContainer, isDS, ControlFlags.None, null, null, null,
54 new DiscretionaryAcl (isContainer, isDS, 0)))
58 internal CommonSecurityDescriptor descriptor;
59 AccessControlSections sections_modified;
60 ReaderWriterLock rw_lock;
62 public abstract Type AccessRightType { get; }
64 public abstract Type AccessRuleType { get; }
66 public abstract Type AuditRuleType { get; }
68 public bool AreAccessRulesCanonical {
72 return descriptor.IsDiscretionaryAclCanonical;
79 public bool AreAccessRulesProtected {
83 return 0 != (descriptor.ControlFlags & ControlFlags.DiscretionaryAclProtected);
90 public bool AreAuditRulesCanonical {
94 return descriptor.IsSystemAclCanonical;
101 public bool AreAuditRulesProtected {
105 return 0 != (descriptor.ControlFlags & ControlFlags.SystemAclProtected);
112 internal AccessControlSections AccessControlSectionsModified {
113 get { Reading (); return sections_modified; }
114 set { Writing (); sections_modified = value; }
117 protected bool AccessRulesModified {
118 get { return AreAccessControlSectionsModified (AccessControlSections.Access); }
119 set { SetAccessControlSectionsModified (AccessControlSections.Access, value); }
122 protected bool AuditRulesModified {
123 get { return AreAccessControlSectionsModified (AccessControlSections.Audit); }
124 set { SetAccessControlSectionsModified (AccessControlSections.Audit, value); }
127 protected bool GroupModified {
128 get { return AreAccessControlSectionsModified (AccessControlSections.Group); }
129 set { SetAccessControlSectionsModified (AccessControlSections.Group, value); }
132 protected bool IsContainer {
133 get { return descriptor.IsContainer; }
136 protected bool IsDS {
137 get { return descriptor.IsDS; }
140 protected bool OwnerModified {
141 get { return AreAccessControlSectionsModified (AccessControlSections.Owner); }
142 set { SetAccessControlSectionsModified (AccessControlSections.Owner, value); }
145 public abstract AccessRule AccessRuleFactory (IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type);
147 public abstract AuditRule AuditRuleFactory (IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags);
149 public IdentityReference GetGroup (Type targetType)
153 if (descriptor.Group == null)
156 return descriptor.Group.Translate (targetType);
162 public IdentityReference GetOwner (Type targetType)
166 if (descriptor.Owner == null)
169 return descriptor.Owner.Translate (targetType);
175 public byte[] GetSecurityDescriptorBinaryForm ()
179 byte[] binaryForm = new byte[descriptor.BinaryLength];
180 descriptor.GetBinaryForm (binaryForm, 0);
187 public string GetSecurityDescriptorSddlForm (AccessControlSections includeSections)
191 return descriptor.GetSddlForm (includeSections);
197 public static bool IsSddlConversionSupported ()
199 return GenericSecurityDescriptor.IsSddlConversionSupported ();
202 public virtual bool ModifyAccessRule (AccessControlModification modification, AccessRule rule, out bool modified)
205 throw new ArgumentNullException ("rule");
207 if (!AccessRuleType.IsAssignableFrom (rule.GetType()))
208 throw new ArgumentException ("rule");
210 return ModifyAccess (modification, rule, out modified);
213 public virtual bool ModifyAuditRule (AccessControlModification modification, AuditRule rule, out bool modified)
216 throw new ArgumentNullException ("rule");
218 if (!AuditRuleType.IsAssignableFrom (rule.GetType()))
219 throw new ArgumentException ("rule");
221 return ModifyAudit (modification, rule, out modified);
224 public virtual void PurgeAccessRules (IdentityReference identity)
226 if (null == identity)
227 throw new ArgumentNullException ("identity");
231 descriptor.PurgeAccessControl (SidFromIR (identity));
237 public virtual void PurgeAuditRules (IdentityReference identity)
239 if (null == identity)
240 throw new ArgumentNullException ("identity");
244 descriptor.PurgeAudit (SidFromIR (identity));
250 public void SetAccessRuleProtection (bool isProtected,
251 bool preserveInheritance)
255 descriptor.SetDiscretionaryAclProtection (isProtected, preserveInheritance);
261 public void SetAuditRuleProtection (bool isProtected,
262 bool preserveInheritance)
266 descriptor.SetSystemAclProtection (isProtected, preserveInheritance);
272 public void SetGroup (IdentityReference identity)
276 descriptor.Group = SidFromIR (identity);
277 GroupModified = true;
283 public void SetOwner (IdentityReference identity)
287 descriptor.Owner = SidFromIR (identity);
288 OwnerModified = true;
294 public void SetSecurityDescriptorBinaryForm (byte[] binaryForm)
296 SetSecurityDescriptorBinaryForm (binaryForm, AccessControlSections.All);
299 public void SetSecurityDescriptorBinaryForm (byte[] binaryForm, AccessControlSections includeSections)
301 CopySddlForm (new CommonSecurityDescriptor (IsContainer, IsDS, binaryForm, 0), includeSections);
304 public void SetSecurityDescriptorSddlForm (string sddlForm)
306 SetSecurityDescriptorSddlForm (sddlForm, AccessControlSections.All);
309 public void SetSecurityDescriptorSddlForm (string sddlForm, AccessControlSections includeSections)
311 CopySddlForm (new CommonSecurityDescriptor (IsContainer, IsDS, sddlForm), includeSections);
314 void CopySddlForm (CommonSecurityDescriptor sourceDescriptor, AccessControlSections includeSections)
318 AccessControlSectionsModified |= includeSections;
319 if (0 != (includeSections & AccessControlSections.Audit))
320 descriptor.SystemAcl = sourceDescriptor.SystemAcl;
321 if (0 != (includeSections & AccessControlSections.Access))
322 descriptor.DiscretionaryAcl = sourceDescriptor.DiscretionaryAcl;
323 if (0 != (includeSections & AccessControlSections.Owner))
324 descriptor.Owner = sourceDescriptor.Owner;
325 if (0 != (includeSections & AccessControlSections.Group))
326 descriptor.Group = sourceDescriptor.Group;
332 protected abstract bool ModifyAccess (AccessControlModification modification, AccessRule rule, out bool modified);
334 protected abstract bool ModifyAudit (AccessControlModification modification, AuditRule rule, out bool modified);
336 // For MoMA. NotImplementedException is correct for this base class.
337 Exception GetNotImplementedException ()
339 return new NotImplementedException ();
342 protected virtual void Persist (SafeHandle handle, AccessControlSections includeSections)
344 throw GetNotImplementedException ();
347 protected virtual void Persist (string name, AccessControlSections includeSections)
349 throw GetNotImplementedException ();
353 [HandleProcessCorruptedStateExceptions]
354 protected virtual void Persist (bool enableOwnershipPrivilege, string name, AccessControlSections includeSections)
356 throw new NotImplementedException ();
361 if (!rw_lock.IsReaderLockHeld && !rw_lock.IsWriterLockHeld)
362 throw new InvalidOperationException ("Either a read or a write lock must be held.");
365 protected void ReadLock ()
367 rw_lock.AcquireReaderLock (Timeout.Infinite);
370 protected void ReadUnlock ()
372 rw_lock.ReleaseReaderLock ();
377 if (!rw_lock.IsWriterLockHeld)
378 throw new InvalidOperationException ("Write lock must be held.");
381 protected void WriteLock ()
383 rw_lock.AcquireWriterLock (Timeout.Infinite);
386 protected void WriteUnlock ()
388 rw_lock.ReleaseWriterLock ();
391 internal AuthorizationRuleCollection InternalGetAccessRules (bool includeExplicit,
392 bool includeInherited,
395 List<AuthorizationRule> rules = new List<AuthorizationRule> ();
399 foreach (GenericAce genericAce in descriptor.DiscretionaryAcl) {
400 QualifiedAce ace = genericAce as QualifiedAce;
401 if (null == ace) continue;
402 if (ace.IsInherited && !includeInherited) continue;
403 if (!ace.IsInherited && !includeExplicit) continue;
405 AccessControlType type;
406 if (AceQualifier.AccessAllowed == ace.AceQualifier)
407 type = AccessControlType.Allow;
408 else if (AceQualifier.AccessDenied == ace.AceQualifier)
409 type = AccessControlType.Deny;
413 AccessRule rule = InternalAccessRuleFactory (ace, targetType, type);
420 return new AuthorizationRuleCollection (rules.ToArray ());
423 internal virtual AccessRule InternalAccessRuleFactory (QualifiedAce ace, Type targetType,
424 AccessControlType type)
426 return AccessRuleFactory (ace.SecurityIdentifier.Translate (targetType),
427 ace.AccessMask, ace.IsInherited,
428 ace.InheritanceFlags, ace.PropagationFlags, type);
431 internal AuthorizationRuleCollection InternalGetAuditRules (bool includeExplicit,
432 bool includeInherited,
435 List<AuthorizationRule> rules = new List<AuthorizationRule> ();
439 if (null != descriptor.SystemAcl) {
440 foreach (GenericAce genericAce in descriptor.SystemAcl) {
441 QualifiedAce ace = genericAce as QualifiedAce;
442 if (null == ace) continue;
443 if (ace.IsInherited && !includeInherited) continue;
444 if (!ace.IsInherited && !includeExplicit) continue;
446 if (AceQualifier.SystemAudit != ace.AceQualifier) continue;
448 AuditRule rule = InternalAuditRuleFactory (ace, targetType);
456 return new AuthorizationRuleCollection (rules.ToArray ());
459 internal virtual AuditRule InternalAuditRuleFactory (QualifiedAce ace, Type targetType)
461 return AuditRuleFactory (ace.SecurityIdentifier.Translate (targetType),
462 ace.AccessMask, ace.IsInherited,
463 ace.InheritanceFlags, ace.PropagationFlags, ace.AuditFlags);
466 internal static SecurityIdentifier SidFromIR (IdentityReference identity)
468 if (null == identity)
469 throw new ArgumentNullException ("identity");
471 return (SecurityIdentifier)identity.Translate (typeof (SecurityIdentifier));
474 bool AreAccessControlSectionsModified (AccessControlSections mask)
476 return 0 != (AccessControlSectionsModified & mask);
479 void SetAccessControlSectionsModified(AccessControlSections mask, bool modified)
482 AccessControlSectionsModified |= mask;
484 AccessControlSectionsModified &= ~mask;