System.Drawing: added email to icon and test file headers
[mono.git] / mcs / class / corlib / System.Security.AccessControl / GenericAce.cs
1 //
2 // System.Security.AccessControl.GenericAce implementation
3 //
4 // Authors:
5 //      Dick Porter  <dick@ximian.com>
6 //      Atsushi Enomoto  <atsushi@ximian.com>
7 //      Kenneth Bell
8 //
9 // Copyright (C) 2006-2007 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.Globalization;
32 using System.Security.Principal;
33 using System.Text;
34
35 namespace System.Security.AccessControl {
36         public abstract class GenericAce
37         {
38                 private AceFlags ace_flags;
39                 private AceType ace_type;
40                 
41                 internal GenericAce (AceType type, AceFlags flags)
42                 {
43                         if (type > AceType.MaxDefinedAceType) {
44                                 throw new ArgumentOutOfRangeException ("type");
45                         }
46                         
47                         this.ace_type = type;
48                         this.ace_flags = flags;
49                 }
50                 
51                 internal GenericAce(byte[] binaryForm, int offset)
52                 {
53                         if (binaryForm == null)
54                                 throw new ArgumentNullException("binaryForm");
55                         
56                         if (offset < 0 || offset > binaryForm.Length - 2)
57                                 throw new ArgumentOutOfRangeException("offset", offset, "Offset out of range");
58                         
59                         ace_type = (AceType)binaryForm[offset];
60                         ace_flags = (AceFlags)binaryForm[offset + 1];
61                 }
62                 
63                 public AceFlags AceFlags {
64                         get { return ace_flags; }
65                         set { ace_flags = value; }
66                 }
67                 
68                 public AceType AceType {
69                         get { return ace_type; }
70                 }
71                 
72                 public AuditFlags AuditFlags {
73                         get {
74                                 AuditFlags ret = AuditFlags.None;
75                                 if ((ace_flags & AceFlags.SuccessfulAccess) != 0)
76                                         ret |= AuditFlags.Success;
77                                 if ((ace_flags & AceFlags.FailedAccess) != 0)
78                                         ret |= AuditFlags.Failure;
79                                 return ret;
80                         }
81                 }
82                 
83                 public abstract int BinaryLength { get; }
84
85                 public InheritanceFlags InheritanceFlags {
86                         get {
87                                 InheritanceFlags ret = InheritanceFlags.None;
88                                 if ((ace_flags & AceFlags.ObjectInherit) != 0)
89                                         ret |= InheritanceFlags.ObjectInherit;
90                                 if ((ace_flags & AceFlags.ContainerInherit) != 0)
91                                         ret |= InheritanceFlags.ContainerInherit;
92                                 return ret;
93                         }
94                 }
95
96                 public bool IsInherited {
97                         get { return (ace_flags & AceFlags.Inherited) != AceFlags.None; }
98                 }
99
100                 public PropagationFlags PropagationFlags {
101                         get {
102                                 PropagationFlags ret = PropagationFlags.None;
103                                 if ((ace_flags & AceFlags.InheritOnly) != 0)
104                                         ret |= PropagationFlags.InheritOnly;
105                                 if ((ace_flags & AceFlags.NoPropagateInherit) != 0)
106                                         ret |= PropagationFlags.NoPropagateInherit;
107                                 return ret;
108                         }
109                 }
110                 
111                 public GenericAce Copy ()
112                 {
113                         byte[] buffer = new byte[BinaryLength];
114                         GetBinaryForm(buffer, 0);
115                         return GenericAce.CreateFromBinaryForm(buffer, 0);
116                 }
117                 
118                 public static GenericAce CreateFromBinaryForm (byte[] binaryForm, int offset)
119                 {
120                         if (binaryForm == null)
121                                 throw new ArgumentNullException("binaryForm");
122                         
123                         if (offset < 0 || offset > binaryForm.Length - 1)
124                                 throw new ArgumentOutOfRangeException("offset", offset, "Offset out of range");
125                         
126                         AceType type = (AceType)binaryForm[offset];
127                         if (IsObjectType(type))
128                                 return new ObjectAce(binaryForm, offset);
129                         else
130                                 return new CommonAce(binaryForm, offset);
131                 }
132
133                 public override sealed bool Equals (object o)
134                 {
135                         return this == (o as GenericAce);
136                 }
137
138                 public abstract void GetBinaryForm (byte[] binaryForm, int offset);
139
140                 public override sealed int GetHashCode ()
141                 {
142                         byte[] buffer = new byte[BinaryLength];
143                         GetBinaryForm(buffer, 0);
144                         
145                         int code = 0;
146                         for(int i = 0; i < buffer.Length; ++i)
147                         {
148                                 code = (code << 3) | ((code >> 29) & 0x7);
149                                 code ^= ((int)buffer[i]) & 0xff;
150                         }
151                         
152                         return code;
153                 }
154
155                 public static bool operator== (GenericAce left, GenericAce right)
156                 {
157                         if(((object)left) == null)
158                                 return((object)right) == null;
159                         
160                         if(((object)right) == null)
161                                 return false;
162                         
163                         int leftLen = left.BinaryLength;
164                         int rightLen = right.BinaryLength;
165                         if( leftLen != rightLen)
166                                 return false;
167                         
168                         byte[] leftBuffer = new byte[leftLen];
169                         byte[] rightBuffer = new byte[rightLen];
170                         left.GetBinaryForm(leftBuffer, 0);
171                         right.GetBinaryForm(rightBuffer, 0);
172                         
173                         for(int i = 0; i < leftLen; ++i) {
174                                 if(leftBuffer[i] != rightBuffer[i])
175                                         return false;
176                         }
177                         
178                         return true;
179                 }
180
181                 public static bool operator!= (GenericAce left, GenericAce right)
182                 {
183                         if(((object)left) == null)
184                                 return((object)right) != null;
185                         
186                         if(((object)right) == null)
187                                 return true;
188                         
189                         int leftLen = left.BinaryLength;
190                         int rightLen = right.BinaryLength;
191                         if( leftLen != rightLen)
192                                 return true;
193                         
194                         byte[] leftBuffer = new byte[leftLen];
195                         byte[] rightBuffer = new byte[rightLen];
196                         left.GetBinaryForm(leftBuffer, 0);
197                         right.GetBinaryForm(rightBuffer, 0);
198                         
199                         for(int i = 0; i < leftLen; ++i) {
200                                 if(leftBuffer[i] != rightBuffer[i])
201                                         return true;
202                         }
203                         
204                         return false;
205                 }
206                 
207                 internal abstract string GetSddlForm();
208                 
209                 static internal GenericAce CreateFromSddlForm (string sddlForm, ref int pos)
210                 {
211                         if (sddlForm[pos] != '(')
212                                 throw new ArgumentException ("Invalid SDDL string.", "sddlForm");
213                         
214                         int endPos = sddlForm.IndexOf (')', pos);
215                         if (endPos < 0)
216                                 throw new ArgumentException ("Invalid SDDL string.", "sddlForm");
217                         
218                         int count = endPos - (pos + 1);
219                         string elementsStr = sddlForm.Substring (pos + 1,
220                                                                  count);
221                         elementsStr = elementsStr.ToUpperInvariant ();
222                         string[] elements = elementsStr.Split (';');
223                         if (elements.Length != 6)
224                                 throw new ArgumentException ("Invalid SDDL string.", "sddlForm");
225                         
226
227                         ObjectAceFlags objFlags = ObjectAceFlags.None;
228                                 
229                         AceType type = ParseSddlAceType (elements[0]);
230
231                         AceFlags flags = ParseSddlAceFlags (elements[1]);
232
233                         int accessMask = ParseSddlAccessRights (elements[2]);
234
235                         Guid objectType = Guid.Empty;
236                         if (!string.IsNullOrEmpty (elements[3])) {
237                                 objectType = new Guid(elements[3]);
238                                 objFlags |= ObjectAceFlags.ObjectAceTypePresent;
239                         }
240                         
241                         Guid inhObjectType = Guid.Empty;
242                         if (!string.IsNullOrEmpty (elements[4])) {
243                                 inhObjectType = new Guid(elements[4]);
244                                 objFlags |= ObjectAceFlags.InheritedObjectAceTypePresent;
245                         }
246                         
247                         SecurityIdentifier sid
248                                 = new SecurityIdentifier (elements[5]);
249                         
250                         if (type == AceType.AccessAllowedCallback
251                             || type == AceType.AccessDeniedCallback)
252                                 throw new NotImplementedException ("Conditional ACEs not supported");
253                         
254                         pos = endPos + 1;
255                         
256                         if (IsObjectType(type))
257                                 return new ObjectAce(type, flags, accessMask, sid, objFlags, objectType, inhObjectType, null);
258                         else {
259                                 if (objFlags != ObjectAceFlags.None)
260                                         throw new ArgumentException( "Invalid SDDL string.", "sddlForm");
261                                 return new CommonAce (type, flags, accessMask, sid, null);
262                         }
263                 }
264                 
265                 private static bool IsObjectType(AceType type)
266                 {
267                         return type == AceType.AccessAllowedCallbackObject
268                                 || type == AceType.AccessAllowedObject
269                                 || type == AceType.AccessDeniedCallbackObject
270                                 || type == AceType.AccessDeniedObject
271                                 || type == AceType.SystemAlarmCallbackObject
272                                 || type == AceType.SystemAlarmObject
273                                 || type == AceType.SystemAuditCallbackObject
274                                 || type == AceType.SystemAuditObject;
275                 }
276
277                 protected static string GetSddlAceType (AceType type)
278                 {
279                         switch (type) {
280                         case AceType.AccessAllowed:
281                                 return "A";
282                         case AceType.AccessDenied:
283                                 return "D";
284                         case AceType.AccessAllowedObject:
285                                 return "OA";
286                         case AceType.AccessDeniedObject:
287                                 return "OD";
288                         case AceType.SystemAudit:
289                                 return "AU";
290                         case AceType.SystemAlarm:
291                                 return "AL";
292                         case AceType.SystemAuditObject:
293                                 return "OU";
294                         case AceType.SystemAlarmObject:
295                                 return "OL";
296                         case AceType.AccessAllowedCallback:
297                                 return "XA";
298                         case AceType.AccessDeniedCallback:
299                                 return "XD";
300                         default:
301                                 throw new ArgumentException ("Unable to convert to SDDL ACE type: " + type, "type");
302                         }
303                 }
304
305                 private static AceType ParseSddlAceType (string type)
306                 {
307                         switch (type) {
308                         case "A":
309                                 return AceType.AccessAllowed;
310                         case "D":
311                                 return AceType.AccessDenied;
312                         case "OA":
313                                 return AceType.AccessAllowedObject;
314                         case "OD":
315                                 return AceType.AccessDeniedObject;
316                         case "AU":
317                                 return AceType.SystemAudit;
318                         case "AL":
319                                 return AceType.SystemAlarm;
320                         case "OU":
321                                 return AceType.SystemAuditObject;
322                         case "OL":
323                                 return AceType.SystemAlarmObject;
324                         case "XA":
325                                 return AceType.AccessAllowedCallback;
326                         case "XD":
327                                 return AceType.AccessDeniedCallback;
328                         default:
329                                 throw new ArgumentException ("Unable to convert SDDL to ACE type: " + type, "type");
330                         }
331                 }
332
333                 protected static string GetSddlAceFlags (AceFlags flags)
334                 {
335                         StringBuilder result = new StringBuilder ();
336                         if ((flags & AceFlags.ObjectInherit) != 0)
337                                 result.Append ("OI");
338                         if ((flags & AceFlags.ContainerInherit) != 0)
339                                 result.Append ("CI");
340                         if ((flags & AceFlags.NoPropagateInherit) != 0)
341                                 result.Append ("NP");
342                         if ((flags & AceFlags.InheritOnly) != 0)
343                                 result.Append ("IO");
344                         if ((flags & AceFlags.Inherited) != 0)
345                                 result.Append ("ID");
346                         if ((flags & AceFlags.SuccessfulAccess) != 0)
347                                 result.Append ("SA");
348                         if ((flags & AceFlags.FailedAccess) != 0)
349                                 result.Append ("FA");
350                         return result.ToString ();
351                 }
352
353                 private static AceFlags ParseSddlAceFlags (string flags)
354                 {
355                         AceFlags ret = AceFlags.None;
356                         
357                         int pos = 0;
358                         while (pos < flags.Length - 1) {
359                                 string flag = flags.Substring (pos, 2);
360                                 switch (flag) {
361                                 case "CI":
362                                         ret |= AceFlags.ContainerInherit;
363                                         break;
364                                 case "OI":
365                                         ret |= AceFlags.ObjectInherit;
366                                         break;
367                                 case "NP":
368                                         ret |= AceFlags.NoPropagateInherit;
369                                         break;
370                                 case "IO":
371                                         ret |= AceFlags.InheritOnly;
372                                         break;
373                                 case "ID":
374                                         ret |= AceFlags.Inherited;
375                                         break;
376                                 case "SA":
377                                         ret |= AceFlags.SuccessfulAccess;
378                                         break;
379                                 case "FA":
380                                         ret |= AceFlags.FailedAccess;
381                                         break;
382                                 default:
383                                         throw new ArgumentException ("Invalid SDDL string.", "flags");
384                                 }
385                                 
386                                 pos += 2;
387                         }
388                         
389                         if (pos != flags.Length)
390                                 throw new ArgumentException ("Invalid SDDL string.", "flags");
391                         
392                         return ret;
393                 }
394
395                 private static int ParseSddlAccessRights (string accessMask)
396                 {
397                         if (accessMask.StartsWith ("0X")) {
398                                 return int.Parse (accessMask.Substring (2),
399                                                   NumberStyles.HexNumber,
400                                                   CultureInfo.InvariantCulture);
401                         } else if (Char.IsDigit (accessMask, 0)) {
402                                 return int.Parse (accessMask,
403                                                   NumberStyles.Integer,
404                                                   CultureInfo.InvariantCulture);
405                         } else {
406                                 return ParseSddlAliasRights (accessMask);
407                         }
408                 }
409                 
410                 private static int ParseSddlAliasRights(string accessMask)
411                 {
412                         int ret = 0;
413                         
414                         int pos = 0;
415                         while (pos < accessMask.Length - 1) {
416                                 string flag = accessMask.Substring (pos, 2);
417                                 SddlAccessRight right = SddlAccessRight.LookupByName(flag);
418                                 if (right == null)
419                                         throw new ArgumentException ("Invalid SDDL string.", "accessMask");
420                                 
421                                 ret |= right.Value;
422                                 pos += 2;
423                         }
424                         
425                         if (pos != accessMask.Length)
426                                 throw new ArgumentException ("Invalid SDDL string.", "accessMask");
427                         
428                         return ret;
429                 }
430                 
431                 internal static ushort ReadUShort (byte[] buffer, int offset)
432                 {
433                         return (ushort)((((int)buffer[offset + 0]) << 0)
434                                         | (((int)buffer[offset + 1]) << 8));
435                 }
436                 
437                 internal static int ReadInt (byte[] buffer, int offset)
438                 {
439                         return (((int)buffer[offset + 0]) << 0)
440                                 | (((int)buffer[offset + 1]) << 8)
441                                 | (((int)buffer[offset + 2]) << 16)
442                                 | (((int)buffer[offset + 3]) << 24);
443                 }
444                 
445                 internal static void WriteInt (int val, byte[] buffer, int offset)
446                 {
447                         buffer[offset] = (byte)val;
448                         buffer[offset + 1] = (byte)(val >> 8);
449                         buffer[offset + 2] = (byte)(val >> 16);
450                         buffer[offset + 3] = (byte)(val >> 24);
451                 }
452
453                 internal static void WriteUShort (ushort val, byte[] buffer,
454                                                   int offset)
455                 {
456                         buffer[offset] = (byte)val;
457                         buffer[offset + 1] = (byte)(val >> 8);
458                 }
459         }
460 }
461