Merge pull request #3433 from ntherning/fix-DoubleTest.Parse-assumes-en-US
[mono.git] / mcs / class / corlib / System.Security.AccessControl / CommonAcl.cs
1 //
2 // System.Security.AccessControl.CommonAcl 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) 2006-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
35 namespace System.Security.AccessControl
36 {
37         /* NB: Note the Remarks section in the CommonAcl class docs
38          * concerning ACE management
39          */
40         public abstract class CommonAcl : GenericAcl
41         {
42                 const int default_capacity = 10; // FIXME: not verified
43
44                 internal delegate bool RemoveAcesCallback<T> (T ace);
45
46                 internal CommonAcl (bool isContainer, bool isDS, RawAcl rawAcl)
47                 {
48                         if (rawAcl == null) {
49                                 rawAcl = new RawAcl (isDS ? AclRevisionDS : AclRevision, default_capacity);
50                         } else {
51                                 // The RawAcl ACEs are cloned.
52                                 byte[] binaryForm = new byte [rawAcl.BinaryLength];
53                                 rawAcl.GetBinaryForm (binaryForm, 0);
54                                 rawAcl = new RawAcl (binaryForm, 0);
55                         }
56
57                         Init (isContainer, isDS, rawAcl);
58                 }
59
60                 internal CommonAcl (bool isContainer, bool isDS, byte revision, int capacity)
61                 {
62                         Init (isContainer, isDS, new RawAcl (revision, capacity));
63                 }
64
65                 internal CommonAcl (bool isContainer, bool isDS, int capacity)
66                         : this (isContainer, isDS, isDS ? AclRevisionDS : AclRevision, capacity)
67                 {
68                 }
69
70                 void Init (bool isContainer, bool isDS, RawAcl rawAcl)
71                 {
72                         is_container = isContainer;
73                         is_ds = isDS;
74                         raw_acl = rawAcl;
75                         CanonicalizeAndClearAefa ();
76                 }
77
78                 bool is_aefa, is_canonical, is_container, is_ds;
79                 internal RawAcl raw_acl;
80
81                 public override sealed int BinaryLength {
82                         get { return raw_acl.BinaryLength; }
83                 }
84
85                 public override sealed int Count {
86                         get { return raw_acl.Count; }
87                 }
88
89                 public bool IsCanonical {
90                         get { return is_canonical; }
91                 }
92
93                 public bool IsContainer {
94                         get { return is_container; }
95                 }
96                 
97                 public bool IsDS {
98                         get { return is_ds; }
99                 }
100
101                 // See CommonSecurityDescriptorTest's AefaModifiedFlagIsStoredOnDiscretionaryAcl unit test.
102                 internal bool IsAefa {
103                         get { return is_aefa; }
104                         set { is_aefa = value; }
105                 }
106                 
107                 public override sealed byte Revision {
108                         get { return raw_acl.Revision; }
109                 }
110                 
111                 public override sealed GenericAce this[int index] {
112                         get { return CopyAce (raw_acl [index]); }
113                         set { throw new NotSupportedException (); }
114                 }
115                 
116                 public override sealed void GetBinaryForm (byte[] binaryForm, int offset)
117                 {
118                         raw_acl.GetBinaryForm (binaryForm, offset);
119                 }
120                 
121                 public void Purge (SecurityIdentifier sid)
122                 {
123                         RequireCanonicity ();
124                         RemoveAces<KnownAce> (ace => ace.SecurityIdentifier == sid);
125                 }
126
127                 public void RemoveInheritedAces ()
128                 {
129                         RequireCanonicity ();
130                         RemoveAces<GenericAce> (ace => ace.IsInherited);
131                 }
132
133                 internal void RequireCanonicity ()
134                 {
135                         if (!IsCanonical)
136                                 throw new InvalidOperationException("ACL is not canonical.");
137                 }
138                 
139                 internal void CanonicalizeAndClearAefa ()
140                 {
141                         RemoveAces<GenericAce> (IsAceMeaningless);
142
143                         is_canonical = TestCanonicity ();
144                         
145                         if (IsCanonical) {
146                                 ApplyCanonicalSortToExplicitAces ();
147                                 MergeExplicitAces ();
148                         }
149                         
150                         IsAefa = false;
151                 }
152                 
153                 internal virtual bool IsAceMeaningless (GenericAce ace)
154                 {
155                         AceFlags flags = ace.AceFlags;
156
157                         KnownAce knownAce = ace as KnownAce;
158                         if (knownAce != null) {
159                                 if (0 == knownAce.AccessMask) return true;
160                                 if (0 != (flags & AceFlags.InheritOnly)) {
161                                         if (knownAce is ObjectAce) return true;
162                                         if (!IsContainer) return true;
163                                         if (0 == (flags & (AceFlags.ContainerInherit|AceFlags.ObjectInherit))) return true;
164                                 }
165                         }
166
167                         return false;
168                 }
169
170                 bool TestCanonicity ()
171                 {
172                         foreach (GenericAce ace in this) {
173                                 if (!(ace is QualifiedAce)) return false;
174                         }
175
176                         bool gotInheritedAce = false;
177                         foreach (QualifiedAce ace in this) {
178                                 if (ace.IsInherited) {
179                                         gotInheritedAce = true;
180                                 } else {
181                                         if (gotInheritedAce) return false;
182                                 }
183                         }
184
185                         bool gotExplicitAllow = false;
186                         foreach (QualifiedAce ace in this) {
187                                 if (ace.IsInherited) break;
188                                 if (AceQualifier.AccessAllowed == ace.AceQualifier) {
189                                         gotExplicitAllow = true;
190                                 } else if (AceQualifier.AccessDenied == ace.AceQualifier) {
191                                         if (gotExplicitAllow) return false;
192                                 }
193                         }
194
195                         return true;
196                 }
197
198                 internal int GetCanonicalExplicitDenyAceCount ()
199                 {
200                         int i;
201                         for (i = 0; i < Count; i ++) {
202                                 if (raw_acl [i].IsInherited) break;
203
204                                 QualifiedAce ace = raw_acl [i] as QualifiedAce;
205                                 if (ace == null || ace.AceQualifier != AceQualifier.AccessDenied) break;
206                         }
207                         return i;
208                 }
209                 
210                 internal int GetCanonicalExplicitAceCount ()
211                 {
212                         int i;
213                         for (i = 0; i < Count; i ++)
214                                 if (raw_acl [i].IsInherited) break;
215                         return i;
216                 }
217                 
218                 void MergeExplicitAces ()
219                 {
220                         int explicitCount = GetCanonicalExplicitAceCount ();
221                         
222                         for (int i = 0; i < explicitCount - 1; ) {
223                                 GenericAce mergedAce = MergeExplicitAcePair (raw_acl [i], raw_acl [i + 1]);
224                                 if (null != mergedAce) {
225                                         raw_acl [i] = mergedAce;
226                                         raw_acl.RemoveAce (i + 1);
227                                         explicitCount --;
228                                 } else {
229                                         i ++;
230                                 }
231                         }
232                 }
233
234                 GenericAce MergeExplicitAcePair (GenericAce ace1, GenericAce ace2)
235                 {
236                         QualifiedAce qace1 = ace1 as QualifiedAce;
237                         QualifiedAce qace2 = ace2 as QualifiedAce;
238                         if (!(null != qace1 && null != qace2)) return null;
239                         if (!(qace1.AceQualifier == qace2.AceQualifier)) return null;
240                         if (!(qace1.SecurityIdentifier == qace2.SecurityIdentifier)) return null;
241                         
242                         AceFlags aceFlags1 = qace1.AceFlags, aceFlags2 = qace2.AceFlags, aceFlagsNew;
243                         int accessMask1 = qace1.AccessMask, accessMask2 = qace2.AccessMask, accessMaskNew;
244                         
245                         if (!IsContainer) {
246                                 aceFlags1 &= ~AceFlags.InheritanceFlags;
247                                 aceFlags2 &= ~AceFlags.InheritanceFlags;
248                         }
249                         
250                         if (aceFlags1 != aceFlags2) {
251                                 if (accessMask1 != accessMask2) return null;
252                                 if ((aceFlags1 & ~(AceFlags.ContainerInherit|AceFlags.ObjectInherit)) ==
253                                     (aceFlags2 & ~(AceFlags.ContainerInherit|AceFlags.ObjectInherit))) {
254                                         aceFlagsNew = aceFlags1|aceFlags2; // merge InheritanceFlags
255                                         accessMaskNew = accessMask1;
256                                 } else if ((aceFlags1 & ~(AceFlags.SuccessfulAccess|AceFlags.FailedAccess)) ==
257                                            (aceFlags2 & ~(AceFlags.SuccessfulAccess|AceFlags.FailedAccess))) {
258                                         aceFlagsNew = aceFlags1|aceFlags2; // merge AuditFlags
259                                         accessMaskNew = accessMask1;
260                                 } else {
261                                         return null;
262                                 }
263                         } else {
264                                 aceFlagsNew = aceFlags1;
265                                 accessMaskNew = accessMask1|accessMask2;
266                         }
267                         
268                         CommonAce cace1 = ace1 as CommonAce;
269                         CommonAce cace2 = ace2 as CommonAce;
270                         if (null != cace1 && null != cace2) {
271                                 return new CommonAce (aceFlagsNew, cace1.AceQualifier, accessMaskNew,
272                                         cace1.SecurityIdentifier, cace1.IsCallback, cace1.GetOpaque());
273                         }
274                         
275                         ObjectAce oace1 = ace1 as ObjectAce;
276                         ObjectAce oace2 = ace2 as ObjectAce;
277                         if (null != oace1 && null != oace2) {
278                                 // See DiscretionaryAclTest.GuidEmptyMergesRegardlessOfFlagsAndOpaqueDataIsNotConsidered
279                                 Guid type1, inheritedType1; GetObjectAceTypeGuids(oace1, out type1, out inheritedType1);
280                                 Guid type2, inheritedType2; GetObjectAceTypeGuids(oace2, out type2, out inheritedType2);
281                                 
282                                 if (type1 == type2 && inheritedType1 == inheritedType2) {
283                                         return new ObjectAce (aceFlagsNew, oace1.AceQualifier, accessMaskNew,
284                                                 oace1.SecurityIdentifier,
285                                                 oace1.ObjectAceFlags, oace1.ObjectAceType, oace1.InheritedObjectAceType,
286                                                 oace1.IsCallback, oace1.GetOpaque());
287                                 }
288                         }
289                         
290                         return null;
291                 }
292                 
293                 static void GetObjectAceTypeGuids(ObjectAce ace, out Guid type, out Guid inheritedType)
294                 {
295                         type = Guid.Empty; inheritedType = Guid.Empty;
296                         if (0 != (ace.ObjectAceFlags & ObjectAceFlags.ObjectAceTypePresent))
297                                 type = ace.ObjectAceType;
298                         if (0 != (ace.ObjectAceFlags & ObjectAceFlags.InheritedObjectAceTypePresent))
299                                 inheritedType = ace.InheritedObjectAceType;
300                 }
301
302                 internal abstract void ApplyCanonicalSortToExplicitAces ();
303                 
304                 internal void ApplyCanonicalSortToExplicitAces (int start, int count)
305                 {
306                         int i, j;
307                         for (i = start + 1; i < start + count; i ++)
308                         {
309                                 KnownAce ace = (KnownAce)raw_acl [i];
310                                 SecurityIdentifier sid = ace.SecurityIdentifier;
311                                 for (j = i; j > start && ((KnownAce)raw_acl [j - 1]).SecurityIdentifier.CompareTo (sid) > 0; j --)
312                                         raw_acl [j] = raw_acl [j - 1];
313                                 raw_acl [j] = ace;
314                         }
315                 }
316                 
317                 internal override string GetSddlForm (ControlFlags sdFlags, bool isDacl)
318                 {
319                         return raw_acl.GetSddlForm (sdFlags, isDacl);
320                 }
321
322                 internal void RemoveAces<T> (RemoveAcesCallback<T> callback)
323                         where T : GenericAce
324                 {
325                         for (int i = 0; i < raw_acl.Count; ) {
326                                 if (raw_acl [i] is T && callback ((T)raw_acl [i])) {
327                                         raw_acl.RemoveAce (i);
328                                 } else {
329                                         i ++;
330                                 }
331                         }
332                 }
333                 
334                 // DiscretionaryAcl/SystemAcl shared implementation below...
335                 internal void AddAce (AceQualifier aceQualifier,
336                                       SecurityIdentifier sid, int accessMask,
337                                       InheritanceFlags inheritanceFlags,
338                                       PropagationFlags propagationFlags,
339                                       AuditFlags auditFlags)
340                 {
341                         QualifiedAce ace = AddAceGetQualifiedAce (aceQualifier, sid, accessMask,
342                                                                   inheritanceFlags, propagationFlags, auditFlags);
343                         AddAce (ace);
344                 }
345                 
346                 internal void AddAce (AceQualifier aceQualifier,
347                                       SecurityIdentifier sid, int accessMask,
348                                       InheritanceFlags inheritanceFlags,
349                                       PropagationFlags propagationFlags,
350                                       AuditFlags auditFlags,
351                                       ObjectAceFlags objectFlags,
352                                       Guid objectType,
353                                       Guid inheritedObjectType)
354                 {
355                         QualifiedAce ace = AddAceGetQualifiedAce (aceQualifier, sid, accessMask,
356                                                                   inheritanceFlags, propagationFlags, auditFlags,
357                                                                   objectFlags, objectType, inheritedObjectType);
358                         AddAce (ace);
359                 }
360                 
361                 QualifiedAce AddAceGetQualifiedAce (AceQualifier aceQualifier,
362                                                     SecurityIdentifier sid, int accessMask,
363                                                     InheritanceFlags inheritanceFlags,
364                                                     PropagationFlags propagationFlags,
365                                                     AuditFlags auditFlags,
366                                                     ObjectAceFlags objectFlags,
367                                                     Guid objectType,
368                                                     Guid inheritedObjectType)
369                 {
370                         if (!IsDS)
371                                 throw new InvalidOperationException ("For this overload, IsDS must be true.");
372                                 
373                         if (ObjectAceFlags.None == objectFlags)
374                                 return AddAceGetQualifiedAce (aceQualifier, sid, accessMask,
375                                                               inheritanceFlags, propagationFlags, auditFlags);
376                         
377                         AceFlags flags = GetAceFlags (inheritanceFlags, propagationFlags, auditFlags);
378                         return new ObjectAce (flags, aceQualifier, accessMask, sid,
379                                               objectFlags, objectType, inheritedObjectType, false, null);
380                 }
381                 
382                 QualifiedAce AddAceGetQualifiedAce (AceQualifier aceQualifier,
383                                                     SecurityIdentifier sid, int accessMask,
384                                                     InheritanceFlags inheritanceFlags,
385                                                     PropagationFlags propagationFlags,
386                                                     AuditFlags auditFlags)
387                 {
388                         AceFlags flags = GetAceFlags (inheritanceFlags, propagationFlags, auditFlags);
389                         return new CommonAce (flags, aceQualifier, accessMask, sid, false, null);
390                 }
391                 
392                 void AddAce (QualifiedAce newAce)
393                 {
394                         RequireCanonicity ();
395                                 
396                         int pos = GetAceInsertPosition (newAce.AceQualifier);
397                         raw_acl.InsertAce (pos, CopyAce (newAce));
398                         CanonicalizeAndClearAefa ();
399                 }
400                 
401                 static GenericAce CopyAce (GenericAce ace)
402                 {
403                         byte[] binaryForm = new byte[ace.BinaryLength];
404                         ace.GetBinaryForm (binaryForm, 0);
405                         return GenericAce.CreateFromBinaryForm (binaryForm, 0);
406                 }
407                 
408                 internal abstract int GetAceInsertPosition (AceQualifier aceQualifier);
409                 
410                 AceFlags GetAceFlags (InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags auditFlags)
411                 {
412                         if (InheritanceFlags.None != inheritanceFlags && !IsContainer)
413                                 throw new ArgumentException ("Flags only work with containers.", "inheritanceFlags");
414                         
415                         if (InheritanceFlags.None == inheritanceFlags && PropagationFlags.None != propagationFlags)
416                                 throw new ArgumentException ("Propagation flags need inheritance flags.", "propagationFlags");
417                         
418                         AceFlags flags = AceFlags.None;
419                         if (0 != (InheritanceFlags.ContainerInherit & inheritanceFlags))
420                                 flags |= AceFlags.ContainerInherit;
421                         if (0 != (InheritanceFlags.ObjectInherit & inheritanceFlags))
422                                 flags |= AceFlags.ObjectInherit;
423                         if (0 != (PropagationFlags.InheritOnly & propagationFlags))
424                                 flags |= AceFlags.InheritOnly;
425                         if (0 != (PropagationFlags.NoPropagateInherit & propagationFlags))
426                                 flags |= AceFlags.NoPropagateInherit;
427                         if (0 != (AuditFlags.Success & auditFlags))
428                                 flags |= AceFlags.SuccessfulAccess;
429                         if (0 != (AuditFlags.Failure & auditFlags))
430                                 flags |= AceFlags.FailedAccess;
431                         return flags;
432                 }
433                 
434                 internal void RemoveAceSpecific (AceQualifier aceQualifier,
435                                                  SecurityIdentifier sid,
436                                                  int accessMask,
437                                                  InheritanceFlags inheritanceFlags,
438                                                  PropagationFlags propagationFlags,
439                                                  AuditFlags auditFlags)
440                 {
441                         RequireCanonicity ();
442                         RemoveAces<CommonAce> (ace =>
443                         {
444                                 if (ace.AccessMask != accessMask) return false;
445                                 if (ace.AceQualifier != aceQualifier) return false;
446                                 if (ace.SecurityIdentifier != sid) return false;
447                                 if (ace.InheritanceFlags != inheritanceFlags) return false;
448                                 if (InheritanceFlags.None != inheritanceFlags)
449                                         if (ace.PropagationFlags != propagationFlags) return false;
450                                 if (ace.AuditFlags != auditFlags) return false;
451                                 return true;
452                         });
453                         CanonicalizeAndClearAefa ();
454                 }
455                 
456                 internal void RemoveAceSpecific (AceQualifier aceQualifier,
457                                                  SecurityIdentifier sid,
458                                                  int accessMask,
459                                                  InheritanceFlags inheritanceFlags,
460                                                  PropagationFlags propagationFlags,
461                                                  AuditFlags auditFlags,
462                                                  ObjectAceFlags objectFlags,
463                                                  Guid objectType,
464                                                  Guid inheritedObjectType)
465                 {
466                         if (!IsDS)
467                                 throw new InvalidOperationException ("For this overload, IsDS must be true.");
468                                 
469                         if (ObjectAceFlags.None == objectFlags) {
470                                 RemoveAceSpecific (aceQualifier, sid, accessMask, inheritanceFlags, propagationFlags, auditFlags);
471                                 return;
472                         }
473
474                         RequireCanonicity ();
475                         RemoveAces<ObjectAce> (ace =>
476                         {
477                                 if (ace.AccessMask != accessMask) return false;
478                                 if (ace.AceQualifier != aceQualifier) return false;
479                                 if (ace.SecurityIdentifier != sid) return false;
480                                 if (ace.InheritanceFlags != inheritanceFlags) return false;
481                                 if (InheritanceFlags.None != inheritanceFlags)
482                                         if (ace.PropagationFlags != propagationFlags) return false;
483                                 if (ace.AuditFlags != auditFlags) return false;
484                                 if (ace.ObjectAceFlags != objectFlags) return false;
485                                 if (0 != (objectFlags & ObjectAceFlags.ObjectAceTypePresent))
486                                         if (ace.ObjectAceType != objectType) return false;
487                                 if (0 != (objectFlags & ObjectAceFlags.InheritedObjectAceTypePresent))
488                                         if (ace.InheritedObjectAceType != objectType) return false;
489                                 return true;
490                         });
491                         CanonicalizeAndClearAefa ();
492                 }
493                 
494                 internal void SetAce (AceQualifier aceQualifier,
495                                       SecurityIdentifier sid,
496                                       int accessMask,
497                                       InheritanceFlags inheritanceFlags,
498                                       PropagationFlags propagationFlags,
499                                       AuditFlags auditFlags)
500                 {
501                         QualifiedAce ace = AddAceGetQualifiedAce (aceQualifier, sid, accessMask,
502                                                                   inheritanceFlags, propagationFlags, auditFlags);
503                         SetAce (ace);
504                 }
505                 
506                 internal void SetAce (AceQualifier aceQualifier,
507                                       SecurityIdentifier sid,
508                                       int accessMask,
509                                       InheritanceFlags inheritanceFlags,
510                                       PropagationFlags propagationFlags,
511                                       AuditFlags auditFlags,
512                                       ObjectAceFlags objectFlags,
513                                       Guid objectType,
514                                       Guid inheritedObjectType)
515                 {
516                         QualifiedAce ace = AddAceGetQualifiedAce (aceQualifier, sid, accessMask,
517                                                                   inheritanceFlags, propagationFlags, auditFlags,
518                                                                   objectFlags, objectType, inheritedObjectType);
519                         SetAce (ace);
520                 }
521                 
522                 void SetAce (QualifiedAce newAce)
523                 {
524                         RequireCanonicity ();
525                         
526                         RemoveAces<QualifiedAce> (oldAce =>
527                         {
528                                 return oldAce.AceQualifier == newAce.AceQualifier &&
529                                        oldAce.SecurityIdentifier == newAce.SecurityIdentifier;
530                         });
531                         CanonicalizeAndClearAefa ();
532                                                 
533                         AddAce (newAce);
534                 }
535         }
536 }
537