Merge pull request #439 from mono-soc-2012/garyb/iconfix
[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 #if NET_4_0
37 using System.Runtime.ExceptionServices;
38 #endif
39
40 namespace System.Security.AccessControl
41 {
42         public abstract class ObjectSecurity
43         {
44                 internal ObjectSecurity (CommonSecurityDescriptor securityDescriptor)
45                 {
46                         if (securityDescriptor == null)
47                                 throw new ArgumentNullException ("securityDescriptor");
48                                 
49                         descriptor = securityDescriptor;
50                         rw_lock = new ReaderWriterLock ();
51                 }
52                 
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)))
57                 {
58                 }
59                 
60                 internal CommonSecurityDescriptor descriptor;
61                 AccessControlSections sections_modified;
62                 ReaderWriterLock rw_lock;
63
64                 public abstract Type AccessRightType { get; }
65                 
66                 public abstract Type AccessRuleType { get; }
67                 
68                 public abstract Type AuditRuleType { get; }
69                 
70                 public bool AreAccessRulesCanonical {
71                         get {
72                                 ReadLock ();
73                                 try {
74                                         return descriptor.IsDiscretionaryAclCanonical;
75                                 } finally {
76                                         ReadUnlock ();
77                                 }
78                         }
79                 }
80                 
81                 public bool AreAccessRulesProtected {
82                         get {
83                                 ReadLock ();
84                                 try {
85                                         return 0 != (descriptor.ControlFlags & ControlFlags.DiscretionaryAclProtected);
86                                 } finally {
87                                         ReadUnlock ();
88                                 }
89                         }
90                 }
91                 
92                 public bool AreAuditRulesCanonical {
93                         get {
94                                 ReadLock ();
95                                 try {
96                                         return descriptor.IsSystemAclCanonical;
97                                 } finally {
98                                         ReadUnlock ();
99                                 }
100                         }
101                 }
102                 
103                 public bool AreAuditRulesProtected {
104                         get {
105                                 ReadLock ();
106                                 try {
107                                         return 0 != (descriptor.ControlFlags & ControlFlags.SystemAclProtected);
108                                 } finally {
109                                         ReadUnlock ();
110                                 }
111                         }
112                 }
113                 
114                 internal AccessControlSections AccessControlSectionsModified {
115                         get { Reading (); return sections_modified; }
116                         set { Writing (); sections_modified = value; }
117                 }
118
119                 protected bool AccessRulesModified {
120                         get { return AreAccessControlSectionsModified (AccessControlSections.Access); }
121                         set { SetAccessControlSectionsModified (AccessControlSections.Access, value); }
122                 }
123                 
124                 protected bool AuditRulesModified {
125                         get { return AreAccessControlSectionsModified (AccessControlSections.Audit); }
126                         set { SetAccessControlSectionsModified (AccessControlSections.Audit, value); }
127                 }
128                 
129                 protected bool GroupModified {
130                         get { return AreAccessControlSectionsModified (AccessControlSections.Group); }
131                         set { SetAccessControlSectionsModified (AccessControlSections.Group, value); }
132                 }
133                 
134                 protected bool IsContainer {
135                         get { return descriptor.IsContainer; }
136                 }
137                 
138                 protected bool IsDS {
139                         get { return descriptor.IsDS; }
140                 }
141                 
142                 protected bool OwnerModified {
143                         get { return AreAccessControlSectionsModified (AccessControlSections.Owner); }
144                         set { SetAccessControlSectionsModified (AccessControlSections.Owner, value); }
145                 }
146                 
147                 public abstract AccessRule AccessRuleFactory (IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type);
148                 
149                 public abstract AuditRule AuditRuleFactory (IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags);             
150                                 
151                 public IdentityReference GetGroup (Type targetType)
152                 {
153                         ReadLock ();
154                         try {
155                                 if (descriptor.Group == null)
156                                         return null;
157                                 
158                                 return descriptor.Group.Translate (targetType);
159                         } finally {
160                                 ReadUnlock ();
161                         }
162                 }
163                 
164                 public IdentityReference GetOwner (Type targetType)
165                 {
166                         ReadLock ();
167                         try {
168                                 if (descriptor.Owner == null)
169                                         return null;
170                                 
171                                 return descriptor.Owner.Translate (targetType);
172                         } finally {
173                                 ReadUnlock ();
174                         }
175                 }
176                 
177                 public byte[] GetSecurityDescriptorBinaryForm ()
178                 {
179                         ReadLock ();
180                         try {
181                                 byte[] binaryForm = new byte[descriptor.BinaryLength];
182                                 descriptor.GetBinaryForm (binaryForm, 0);
183                                 return binaryForm;
184                         } finally {
185                                 ReadUnlock ();
186                         }
187                 }
188                 
189                 public string GetSecurityDescriptorSddlForm (AccessControlSections includeSections)
190                 {
191                         ReadLock ();
192                         try {
193                                 return descriptor.GetSddlForm (includeSections);
194                         } finally {
195                                 ReadUnlock ();
196                         }
197                 }
198
199                 public static bool IsSddlConversionSupported ()
200                 {
201                         return GenericSecurityDescriptor.IsSddlConversionSupported ();
202                 }
203                 
204                 public virtual bool ModifyAccessRule (AccessControlModification modification, AccessRule rule, out bool modified)
205                 {
206                         if (rule == null)
207                                 throw new ArgumentNullException ("rule");
208                                 
209                         if (!AccessRuleType.IsAssignableFrom (rule.GetType()))
210                                 throw new ArgumentException ("rule");
211
212                         return ModifyAccess (modification, rule, out modified);
213                 }
214                 
215                 public virtual bool ModifyAuditRule (AccessControlModification modification, AuditRule rule, out bool modified)
216                 {
217                         if (rule == null)
218                                 throw new ArgumentNullException ("rule");
219
220                         if (!AuditRuleType.IsAssignableFrom (rule.GetType()))
221                                 throw new ArgumentException ("rule");
222                                 
223                         return ModifyAudit (modification, rule, out modified);
224                 }
225                 
226                 public virtual void PurgeAccessRules (IdentityReference identity)
227                 {
228                         if (null == identity)
229                                 throw new ArgumentNullException ("identity");
230                                 
231                         WriteLock ();
232                         try {
233                                 descriptor.PurgeAccessControl (SidFromIR (identity));
234                         } finally {
235                                 WriteUnlock ();
236                         }
237                 }
238                 
239                 public virtual void PurgeAuditRules (IdentityReference identity)
240                 {
241                         if (null == identity)
242                                 throw new ArgumentNullException ("identity");
243                                 
244                         WriteLock ();
245                         try {
246                                 descriptor.PurgeAudit (SidFromIR (identity));
247                         } finally {
248                                 WriteUnlock ();
249                         }
250                 }
251                 
252                 public void SetAccessRuleProtection (bool isProtected,
253                                                      bool preserveInheritance)
254                 {
255                         WriteLock ();
256                         try {
257                                 descriptor.SetDiscretionaryAclProtection (isProtected, preserveInheritance);
258                         } finally {
259                                 WriteUnlock();
260                         }
261                 }
262                 
263                 public void SetAuditRuleProtection (bool isProtected,
264                                                     bool preserveInheritance)
265                 {
266                         WriteLock ();
267                         try {
268                                 descriptor.SetSystemAclProtection (isProtected, preserveInheritance);
269                         } finally {
270                                 WriteUnlock ();
271                         }
272                 }
273                 
274                 public void SetGroup (IdentityReference identity)
275                 {
276                         WriteLock ();
277                         try {
278                                 descriptor.Group = SidFromIR (identity);
279                                 GroupModified = true;
280                         } finally {
281                                 WriteUnlock ();
282                         }
283                 }
284                 
285                 public void SetOwner (IdentityReference identity)
286                 {
287                         WriteLock ();
288                         try {
289                                 descriptor.Owner = SidFromIR (identity);
290                                 OwnerModified = true;
291                         } finally {
292                                 WriteUnlock ();
293                         }
294                 }
295                 
296                 public void SetSecurityDescriptorBinaryForm (byte[] binaryForm)
297                 {
298                         SetSecurityDescriptorBinaryForm (binaryForm, AccessControlSections.All);
299                 }
300                 
301                 public void SetSecurityDescriptorBinaryForm (byte[] binaryForm, AccessControlSections includeSections)
302                 {
303                         CopySddlForm (new CommonSecurityDescriptor (IsContainer, IsDS, binaryForm, 0), includeSections);
304                 }
305                 
306                 public void SetSecurityDescriptorSddlForm (string sddlForm)
307                 {
308                         SetSecurityDescriptorSddlForm (sddlForm, AccessControlSections.All);
309                 }
310
311                 public void SetSecurityDescriptorSddlForm (string sddlForm, AccessControlSections includeSections)
312                 {
313                         CopySddlForm (new CommonSecurityDescriptor (IsContainer, IsDS, sddlForm), includeSections);
314                 }
315                 
316                 void CopySddlForm (CommonSecurityDescriptor sourceDescriptor, AccessControlSections includeSections)
317                 {
318                         WriteLock ();
319                         try {
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;
329                         } finally {
330                                 WriteUnlock ();
331                         }
332                 }
333                 
334                 protected abstract bool ModifyAccess (AccessControlModification modification, AccessRule rule, out bool modified);
335                 
336                 protected abstract bool ModifyAudit (AccessControlModification modification, AuditRule rule, out bool modified);
337                 
338                 // For MoMA. NotImplementedException is correct for this base class.
339                 Exception GetNotImplementedException ()
340                 {
341                         return new NotImplementedException ();
342                 }
343                 
344                 protected virtual void Persist (SafeHandle handle, AccessControlSections includeSections)
345                 {
346                         throw GetNotImplementedException ();
347                 }
348                 
349                 protected virtual void Persist (string name, AccessControlSections includeSections)
350                 {
351                         throw GetNotImplementedException ();
352                 }
353                 
354                 [MonoTODO]
355 #if NET_4_0
356                 [HandleProcessCorruptedStateExceptions]
357 #endif
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