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