Merge pull request #5090 from alexrp/profiler-class-unload-removal
[mono.git] / mcs / class / corlib / System.Security.AccessControl / ObjectSecurity.cs
1 //
2 // System.Security.AccessControl.ObjectSecurity implementation
3 //
4 // Authors:
5 //      Dick Porter  <dick@ximian.com>
6 //      Atsushi Enomoto  <atsushi@ximian.com>
7 //      James Bellinger  <jfb@zer7.com>
8 //
9 // Copyright (C) 2005-2007 Novell, Inc (http://www.novell.com)
10 // Copyright (C) 2012      James Bellinger
11 //
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:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
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.
30 //
31
32 using System.Collections.Generic;
33 using System.Security.Principal;
34 using System.Runtime.InteropServices;
35 using System.Threading;
36 using System.Runtime.ExceptionServices;
37
38 namespace System.Security.AccessControl
39 {
40         public abstract class ObjectSecurity
41         {
42                 protected ObjectSecurity ()
43                 {
44                 }
45
46                 protected ObjectSecurity (CommonSecurityDescriptor securityDescriptor)
47                 {
48                         if (securityDescriptor == null)
49                                 throw new ArgumentNullException ("securityDescriptor");
50                                 
51                         descriptor = securityDescriptor;
52                         rw_lock = new ReaderWriterLock ();
53                 }
54                 
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)))
59                 {
60                 }
61                 
62                 internal CommonSecurityDescriptor descriptor;
63                 AccessControlSections sections_modified;
64                 ReaderWriterLock rw_lock;
65
66                 public abstract Type AccessRightType { get; }
67                 
68                 public abstract Type AccessRuleType { get; }
69                 
70                 public abstract Type AuditRuleType { get; }
71                 
72                 public bool AreAccessRulesCanonical {
73                         get {
74                                 ReadLock ();
75                                 try {
76                                         return descriptor.IsDiscretionaryAclCanonical;
77                                 } finally {
78                                         ReadUnlock ();
79                                 }
80                         }
81                 }
82                 
83                 public bool AreAccessRulesProtected {
84                         get {
85                                 ReadLock ();
86                                 try {
87                                         return 0 != (descriptor.ControlFlags & ControlFlags.DiscretionaryAclProtected);
88                                 } finally {
89                                         ReadUnlock ();
90                                 }
91                         }
92                 }
93                 
94                 public bool AreAuditRulesCanonical {
95                         get {
96                                 ReadLock ();
97                                 try {
98                                         return descriptor.IsSystemAclCanonical;
99                                 } finally {
100                                         ReadUnlock ();
101                                 }
102                         }
103                 }
104                 
105                 public bool AreAuditRulesProtected {
106                         get {
107                                 ReadLock ();
108                                 try {
109                                         return 0 != (descriptor.ControlFlags & ControlFlags.SystemAclProtected);
110                                 } finally {
111                                         ReadUnlock ();
112                                 }
113                         }
114                 }
115                 
116                 internal AccessControlSections AccessControlSectionsModified {
117                         get { Reading (); return sections_modified; }
118                         set { Writing (); sections_modified = value; }
119                 }
120
121                 protected bool AccessRulesModified {
122                         get { return AreAccessControlSectionsModified (AccessControlSections.Access); }
123                         set { SetAccessControlSectionsModified (AccessControlSections.Access, value); }
124                 }
125                 
126                 protected bool AuditRulesModified {
127                         get { return AreAccessControlSectionsModified (AccessControlSections.Audit); }
128                         set { SetAccessControlSectionsModified (AccessControlSections.Audit, value); }
129                 }
130                 
131                 protected bool GroupModified {
132                         get { return AreAccessControlSectionsModified (AccessControlSections.Group); }
133                         set { SetAccessControlSectionsModified (AccessControlSections.Group, value); }
134                 }
135                 
136                 protected bool IsContainer {
137                         get { return descriptor.IsContainer; }
138                 }
139                 
140                 protected bool IsDS {
141                         get { return descriptor.IsDS; }
142                 }
143                 
144                 protected bool OwnerModified {
145                         get { return AreAccessControlSectionsModified (AccessControlSections.Owner); }
146                         set { SetAccessControlSectionsModified (AccessControlSections.Owner, value); }
147                 }
148                 
149                 public abstract AccessRule AccessRuleFactory (IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type);
150                 
151                 public abstract AuditRule AuditRuleFactory (IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags);             
152                                 
153                 public IdentityReference GetGroup (Type targetType)
154                 {
155                         ReadLock ();
156                         try {
157                                 if (descriptor.Group == null)
158                                         return null;
159                                 
160                                 return descriptor.Group.Translate (targetType);
161                         } finally {
162                                 ReadUnlock ();
163                         }
164                 }
165                 
166                 public IdentityReference GetOwner (Type targetType)
167                 {
168                         ReadLock ();
169                         try {
170                                 if (descriptor.Owner == null)
171                                         return null;
172                                 
173                                 return descriptor.Owner.Translate (targetType);
174                         } finally {
175                                 ReadUnlock ();
176                         }
177                 }
178                 
179                 public byte[] GetSecurityDescriptorBinaryForm ()
180                 {
181                         ReadLock ();
182                         try {
183                                 byte[] binaryForm = new byte[descriptor.BinaryLength];
184                                 descriptor.GetBinaryForm (binaryForm, 0);
185                                 return binaryForm;
186                         } finally {
187                                 ReadUnlock ();
188                         }
189                 }
190                 
191                 public string GetSecurityDescriptorSddlForm (AccessControlSections includeSections)
192                 {
193                         ReadLock ();
194                         try {
195                                 return descriptor.GetSddlForm (includeSections);
196                         } finally {
197                                 ReadUnlock ();
198                         }
199                 }
200
201                 public static bool IsSddlConversionSupported ()
202                 {
203                         return GenericSecurityDescriptor.IsSddlConversionSupported ();
204                 }
205                 
206                 public virtual bool ModifyAccessRule (AccessControlModification modification, AccessRule rule, out bool modified)
207                 {
208                         if (rule == null)
209                                 throw new ArgumentNullException ("rule");
210                                 
211                         if (!AccessRuleType.IsAssignableFrom (rule.GetType()))
212                                 throw new ArgumentException ("rule");
213
214                         return ModifyAccess (modification, rule, out modified);
215                 }
216                 
217                 public virtual bool ModifyAuditRule (AccessControlModification modification, AuditRule rule, out bool modified)
218                 {
219                         if (rule == null)
220                                 throw new ArgumentNullException ("rule");
221
222                         if (!AuditRuleType.IsAssignableFrom (rule.GetType()))
223                                 throw new ArgumentException ("rule");
224                                 
225                         return ModifyAudit (modification, rule, out modified);
226                 }
227                 
228                 public virtual void PurgeAccessRules (IdentityReference identity)
229                 {
230                         if (null == identity)
231                                 throw new ArgumentNullException ("identity");
232                                 
233                         WriteLock ();
234                         try {
235                                 descriptor.PurgeAccessControl (SidFromIR (identity));
236                         } finally {
237                                 WriteUnlock ();
238                         }
239                 }
240                 
241                 public virtual void PurgeAuditRules (IdentityReference identity)
242                 {
243                         if (null == identity)
244                                 throw new ArgumentNullException ("identity");
245                                 
246                         WriteLock ();
247                         try {
248                                 descriptor.PurgeAudit (SidFromIR (identity));
249                         } finally {
250                                 WriteUnlock ();
251                         }
252                 }
253                 
254                 public void SetAccessRuleProtection (bool isProtected,
255                                                      bool preserveInheritance)
256                 {
257                         WriteLock ();
258                         try {
259                                 descriptor.SetDiscretionaryAclProtection (isProtected, preserveInheritance);
260                         } finally {
261                                 WriteUnlock();
262                         }
263                 }
264                 
265                 public void SetAuditRuleProtection (bool isProtected,
266                                                     bool preserveInheritance)
267                 {
268                         WriteLock ();
269                         try {
270                                 descriptor.SetSystemAclProtection (isProtected, preserveInheritance);
271                         } finally {
272                                 WriteUnlock ();
273                         }
274                 }
275                 
276                 public void SetGroup (IdentityReference identity)
277                 {
278                         WriteLock ();
279                         try {
280                                 descriptor.Group = SidFromIR (identity);
281                                 GroupModified = true;
282                         } finally {
283                                 WriteUnlock ();
284                         }
285                 }
286                 
287                 public void SetOwner (IdentityReference identity)
288                 {
289                         WriteLock ();
290                         try {
291                                 descriptor.Owner = SidFromIR (identity);
292                                 OwnerModified = true;
293                         } finally {
294                                 WriteUnlock ();
295                         }
296                 }
297                 
298                 public void SetSecurityDescriptorBinaryForm (byte[] binaryForm)
299                 {
300                         SetSecurityDescriptorBinaryForm (binaryForm, AccessControlSections.All);
301                 }
302                 
303                 public void SetSecurityDescriptorBinaryForm (byte[] binaryForm, AccessControlSections includeSections)
304                 {
305                         CopySddlForm (new CommonSecurityDescriptor (IsContainer, IsDS, binaryForm, 0), includeSections);
306                 }
307                 
308                 public void SetSecurityDescriptorSddlForm (string sddlForm)
309                 {
310                         SetSecurityDescriptorSddlForm (sddlForm, AccessControlSections.All);
311                 }
312
313                 public void SetSecurityDescriptorSddlForm (string sddlForm, AccessControlSections includeSections)
314                 {
315                         CopySddlForm (new CommonSecurityDescriptor (IsContainer, IsDS, sddlForm), includeSections);
316                 }
317                 
318                 void CopySddlForm (CommonSecurityDescriptor sourceDescriptor, AccessControlSections includeSections)
319                 {
320                         WriteLock ();
321                         try {
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;
331                         } finally {
332                                 WriteUnlock ();
333                         }
334                 }
335                 
336                 protected abstract bool ModifyAccess (AccessControlModification modification, AccessRule rule, out bool modified);
337                 
338                 protected abstract bool ModifyAudit (AccessControlModification modification, AuditRule rule, out bool modified);
339                 
340                 // For MoMA. NotImplementedException is correct for this base class.
341                 Exception GetNotImplementedException ()
342                 {
343                         return new NotImplementedException ();
344                 }
345                 
346                 protected virtual void Persist (SafeHandle handle, AccessControlSections includeSections)
347                 {
348                         throw GetNotImplementedException ();
349                 }
350                 
351                 protected virtual void Persist (string name, AccessControlSections includeSections)
352                 {
353                         throw GetNotImplementedException ();
354                 }
355                 
356                 [MonoTODO]
357                 [HandleProcessCorruptedStateExceptions]
358                 protected virtual void Persist (bool enableOwnershipPrivilege, string name, AccessControlSections includeSections)
359                 {
360                         throw new NotImplementedException ();
361                 }
362                 
363                 void Reading ()
364                 {
365                         if (!rw_lock.IsReaderLockHeld && !rw_lock.IsWriterLockHeld)
366                                 throw new InvalidOperationException ("Either a read or a write lock must be held.");
367                 }
368                 
369                 protected void ReadLock ()
370                 {
371                         rw_lock.AcquireReaderLock (Timeout.Infinite);
372                 }
373                 
374                 protected void ReadUnlock ()
375                 {
376                         rw_lock.ReleaseReaderLock ();
377                 }
378                 
379                 void Writing ()
380                 {
381                         if (!rw_lock.IsWriterLockHeld)
382                                 throw new InvalidOperationException ("Write lock must be held.");
383                 }
384                 
385                 protected void WriteLock ()
386                 {
387                         rw_lock.AcquireWriterLock (Timeout.Infinite);
388                 }
389                 
390                 protected void WriteUnlock ()
391                 {
392                         rw_lock.ReleaseWriterLock ();
393                 }
394                 
395                 internal AuthorizationRuleCollection InternalGetAccessRules (bool includeExplicit,
396                                                                              bool includeInherited,
397                                                                              Type targetType)
398                 {
399                         List<AuthorizationRule> rules = new List<AuthorizationRule> ();
400                         
401                         ReadLock ();
402                         try {
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;
408                                                         
409                                         AccessControlType type;
410                                         if (AceQualifier.AccessAllowed == ace.AceQualifier)
411                                                 type = AccessControlType.Allow;
412                                         else if (AceQualifier.AccessDenied == ace.AceQualifier)
413                                                 type = AccessControlType.Deny;
414                                         else
415                                                 continue;
416                                                 
417                                         AccessRule rule = InternalAccessRuleFactory (ace, targetType, type);
418                                         rules.Add (rule);
419                                 }
420                         } finally {
421                                 ReadUnlock ();
422                         }
423                         
424                         return new AuthorizationRuleCollection (rules.ToArray ());
425                 }
426                 
427                 internal virtual AccessRule InternalAccessRuleFactory (QualifiedAce ace, Type targetType,
428                                                                        AccessControlType type)
429                 {
430                         return AccessRuleFactory (ace.SecurityIdentifier.Translate (targetType),
431                                                   ace.AccessMask, ace.IsInherited,
432                                                   ace.InheritanceFlags, ace.PropagationFlags, type);
433                 }
434  
435                 internal AuthorizationRuleCollection InternalGetAuditRules (bool includeExplicit,
436                                                                             bool includeInherited,
437                                                                             Type targetType)
438                 {
439                         List<AuthorizationRule> rules = new List<AuthorizationRule> ();
440                         
441                         ReadLock ();
442                         try {
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;
449                                 
450                                                 if (AceQualifier.SystemAudit != ace.AceQualifier) continue;
451                                                 
452                                                 AuditRule rule = InternalAuditRuleFactory (ace, targetType);
453                                                 rules.Add (rule);
454                                         }
455                                 }
456                         } finally {
457                                 ReadUnlock ();
458                         }
459                         
460                         return new AuthorizationRuleCollection (rules.ToArray ());
461                 }
462                 
463                 internal virtual AuditRule InternalAuditRuleFactory (QualifiedAce ace, Type targetType)
464                 {
465                         return AuditRuleFactory (ace.SecurityIdentifier.Translate (targetType),
466                                                  ace.AccessMask, ace.IsInherited,
467                                                  ace.InheritanceFlags, ace.PropagationFlags, ace.AuditFlags);
468                 }
469                                 
470                 internal static SecurityIdentifier SidFromIR (IdentityReference identity)
471                 {
472                         if (null == identity)
473                                 throw new ArgumentNullException ("identity");
474                 
475                         return (SecurityIdentifier)identity.Translate (typeof (SecurityIdentifier));
476                 }
477                 
478                 bool AreAccessControlSectionsModified (AccessControlSections mask)
479                 {
480                         return 0 != (AccessControlSectionsModified & mask);
481                 }
482                 
483                 void SetAccessControlSectionsModified(AccessControlSections mask, bool modified)
484                 {
485                         if (modified)
486                                 AccessControlSectionsModified |= mask;
487                         else
488                                 AccessControlSectionsModified &= ~mask;
489                 }
490         }
491 }
492