2 // System.Security.AccessControl.GenericAce implementation
5 // Dick Porter <dick@ximian.com>
6 // Atsushi Enomoto <atsushi@ximian.com>
9 // Copyright (C) 2006-2007 Novell, Inc (http://www.novell.com)
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
31 using System.Globalization;
32 using System.Security.Principal;
35 namespace System.Security.AccessControl {
36 public abstract class GenericAce
38 private AceFlags ace_flags;
39 private AceType ace_type;
41 internal GenericAce (AceType type, AceFlags flags)
43 if (type > AceType.MaxDefinedAceType) {
44 throw new ArgumentOutOfRangeException ("type");
48 this.ace_flags = flags;
51 internal GenericAce(byte[] binaryForm, int offset)
53 if (binaryForm == null)
54 throw new ArgumentNullException("binaryForm");
56 if (offset < 0 || offset > binaryForm.Length - 2)
57 throw new ArgumentOutOfRangeException("offset", offset, "Offset out of range");
59 ace_type = (AceType)binaryForm[offset];
60 ace_flags = (AceFlags)binaryForm[offset + 1];
63 public AceFlags AceFlags {
64 get { return ace_flags; }
65 set { ace_flags = value; }
68 public AceType AceType {
69 get { return ace_type; }
72 public AuditFlags AuditFlags {
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;
83 public abstract int BinaryLength { get; }
85 public InheritanceFlags InheritanceFlags {
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;
96 public bool IsInherited {
97 get { return (ace_flags & AceFlags.Inherited) != AceFlags.None; }
100 public PropagationFlags PropagationFlags {
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;
111 public GenericAce Copy ()
113 byte[] buffer = new byte[BinaryLength];
114 GetBinaryForm(buffer, 0);
115 return GenericAce.CreateFromBinaryForm(buffer, 0);
118 public static GenericAce CreateFromBinaryForm (byte[] binaryForm, int offset)
120 if (binaryForm == null)
121 throw new ArgumentNullException("binaryForm");
123 if (offset < 0 || offset > binaryForm.Length - 1)
124 throw new ArgumentOutOfRangeException("offset", offset, "Offset out of range");
126 AceType type = (AceType)binaryForm[offset];
127 if (IsObjectType(type))
128 return new ObjectAce(binaryForm, offset);
130 return new CommonAce(binaryForm, offset);
133 public override sealed bool Equals (object o)
135 return this == (o as GenericAce);
138 public abstract void GetBinaryForm (byte[] binaryForm, int offset);
140 public override sealed int GetHashCode ()
142 byte[] buffer = new byte[BinaryLength];
143 GetBinaryForm(buffer, 0);
146 for(int i = 0; i < buffer.Length; ++i)
148 code = (code << 3) | ((code >> 29) & 0x7);
149 code ^= ((int)buffer[i]) & 0xff;
155 public static bool operator== (GenericAce left, GenericAce right)
157 if(((object)left) == null)
158 return((object)right) == null;
160 if(((object)right) == null)
163 int leftLen = left.BinaryLength;
164 int rightLen = right.BinaryLength;
165 if( leftLen != rightLen)
168 byte[] leftBuffer = new byte[leftLen];
169 byte[] rightBuffer = new byte[rightLen];
170 left.GetBinaryForm(leftBuffer, 0);
171 right.GetBinaryForm(rightBuffer, 0);
173 for(int i = 0; i < leftLen; ++i) {
174 if(leftBuffer[i] != rightBuffer[i])
181 public static bool operator!= (GenericAce left, GenericAce right)
183 if(((object)left) == null)
184 return((object)right) != null;
186 if(((object)right) == null)
189 int leftLen = left.BinaryLength;
190 int rightLen = right.BinaryLength;
191 if( leftLen != rightLen)
194 byte[] leftBuffer = new byte[leftLen];
195 byte[] rightBuffer = new byte[rightLen];
196 left.GetBinaryForm(leftBuffer, 0);
197 right.GetBinaryForm(rightBuffer, 0);
199 for(int i = 0; i < leftLen; ++i) {
200 if(leftBuffer[i] != rightBuffer[i])
207 internal abstract string GetSddlForm();
209 static internal GenericAce CreateFromSddlForm (string sddlForm, ref int pos)
211 if (sddlForm[pos] != '(')
212 throw new ArgumentException ("Invalid SDDL string.", "sddlForm");
214 int endPos = sddlForm.IndexOf (')', pos);
216 throw new ArgumentException ("Invalid SDDL string.", "sddlForm");
218 int count = endPos - (pos + 1);
219 string elementsStr = sddlForm.Substring (pos + 1,
221 elementsStr = elementsStr.ToUpperInvariant ();
222 string[] elements = elementsStr.Split (';');
223 if (elements.Length != 6)
224 throw new ArgumentException ("Invalid SDDL string.", "sddlForm");
227 ObjectAceFlags objFlags = ObjectAceFlags.None;
229 AceType type = ParseSddlAceType (elements[0]);
231 AceFlags flags = ParseSddlAceFlags (elements[1]);
233 int accessMask = ParseSddlAccessRights (elements[2]);
235 Guid objectType = Guid.Empty;
236 if (!string.IsNullOrEmpty (elements[3])) {
237 objectType = new Guid(elements[3]);
238 objFlags |= ObjectAceFlags.ObjectAceTypePresent;
241 Guid inhObjectType = Guid.Empty;
242 if (!string.IsNullOrEmpty (elements[4])) {
243 inhObjectType = new Guid(elements[4]);
244 objFlags |= ObjectAceFlags.InheritedObjectAceTypePresent;
247 SecurityIdentifier sid
248 = new SecurityIdentifier (elements[5]);
250 if (type == AceType.AccessAllowedCallback
251 || type == AceType.AccessDeniedCallback)
252 throw new NotImplementedException ("Conditional ACEs not supported");
256 if (IsObjectType(type))
257 return new ObjectAce(type, flags, accessMask, sid, objFlags, objectType, inhObjectType, null);
259 if (objFlags != ObjectAceFlags.None)
260 throw new ArgumentException( "Invalid SDDL string.", "sddlForm");
261 return new CommonAce (type, flags, accessMask, sid, null);
265 private static bool IsObjectType(AceType type)
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;
277 protected static string GetSddlAceType (AceType type)
280 case AceType.AccessAllowed:
282 case AceType.AccessDenied:
284 case AceType.AccessAllowedObject:
286 case AceType.AccessDeniedObject:
288 case AceType.SystemAudit:
290 case AceType.SystemAlarm:
292 case AceType.SystemAuditObject:
294 case AceType.SystemAlarmObject:
296 case AceType.AccessAllowedCallback:
298 case AceType.AccessDeniedCallback:
301 throw new ArgumentException ("Unable to convert to SDDL ACE type: " + type, "type");
305 private static AceType ParseSddlAceType (string type)
309 return AceType.AccessAllowed;
311 return AceType.AccessDenied;
313 return AceType.AccessAllowedObject;
315 return AceType.AccessDeniedObject;
317 return AceType.SystemAudit;
319 return AceType.SystemAlarm;
321 return AceType.SystemAuditObject;
323 return AceType.SystemAlarmObject;
325 return AceType.AccessAllowedCallback;
327 return AceType.AccessDeniedCallback;
329 throw new ArgumentException ("Unable to convert SDDL to ACE type: " + type, "type");
333 protected static string GetSddlAceFlags (AceFlags flags)
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 ();
353 private static AceFlags ParseSddlAceFlags (string flags)
355 AceFlags ret = AceFlags.None;
358 while (pos < flags.Length - 1) {
359 string flag = flags.Substring (pos, 2);
362 ret |= AceFlags.ContainerInherit;
365 ret |= AceFlags.ObjectInherit;
368 ret |= AceFlags.NoPropagateInherit;
371 ret |= AceFlags.InheritOnly;
374 ret |= AceFlags.Inherited;
377 ret |= AceFlags.SuccessfulAccess;
380 ret |= AceFlags.FailedAccess;
383 throw new ArgumentException ("Invalid SDDL string.", "flags");
389 if (pos != flags.Length)
390 throw new ArgumentException ("Invalid SDDL string.", "flags");
395 private static int ParseSddlAccessRights (string accessMask)
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);
406 return ParseSddlAliasRights (accessMask);
410 private static int ParseSddlAliasRights(string accessMask)
415 while (pos < accessMask.Length - 1) {
416 string flag = accessMask.Substring (pos, 2);
417 SddlAccessRight right = SddlAccessRight.LookupByName(flag);
419 throw new ArgumentException ("Invalid SDDL string.", "accessMask");
425 if (pos != accessMask.Length)
426 throw new ArgumentException ("Invalid SDDL string.", "accessMask");
431 internal static ushort ReadUShort (byte[] buffer, int offset)
433 return (ushort)((((int)buffer[offset + 0]) << 0)
434 | (((int)buffer[offset + 1]) << 8));
437 internal static int ReadInt (byte[] buffer, int offset)
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);
445 internal static void WriteInt (int val, byte[] buffer, int offset)
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);
453 internal static void WriteUShort (ushort val, byte[] buffer,
456 buffer[offset] = (byte)val;
457 buffer[offset + 1] = (byte)(val >> 8);