Merge pull request #3183 from marek-safar/bug41874
[mono.git] / mcs / class / corlib / System.Security.AccessControl / RawAcl.cs
index 1986b1a8a78f379693165507683fa4df81038daa..b037e0c783d1b4d2be8b0ea03d1e88747b05bfe4 100644 (file)
@@ -4,6 +4,7 @@
 // Authors:
 //     Dick Porter  <dick@ximian.com>
 //     Atsushi Enomoto  <atsushi@ximian.com>
+//     Kenneth Bell
 //
 // Copyright (C) 2006-2007 Novell, Inc (http://www.novell.com)
 //
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-#if NET_2_0
 using System.Collections.Generic;
+using System.Text;
 
 namespace System.Security.AccessControl {
        public sealed class RawAcl : GenericAcl
        {
+               private byte revision;
+               private List<GenericAce> list;
+
                public RawAcl (byte revision, int capacity)
                {
                        this.revision = revision;
@@ -40,18 +44,46 @@ namespace System.Security.AccessControl {
                }
                
                public RawAcl (byte [] binaryForm, int offset)
-                       : this (0, 10)
                {
+                       if (binaryForm == null)
+                               throw new ArgumentNullException("binaryForm");
+                       
+                       if (offset < 0 || offset > binaryForm.Length - 8)
+                               throw new ArgumentOutOfRangeException("offset", offset, "Offset out of range");
+                       
+                       revision = binaryForm[offset];
+                       if (revision != AclRevision && revision != AclRevisionDS)
+                               throw new ArgumentException("Invalid ACL - unknown revision", "binaryForm");
+                       
+                       int binaryLength = ReadUShort(binaryForm, offset + 2);
+                       if (offset > binaryForm.Length - binaryLength)
+                               throw new ArgumentException("Invalid ACL - truncated", "binaryForm");
+                       
+                       int pos = offset + 8;
+                       int numAces = ReadUShort(binaryForm, offset + 4);
+                       list = new List<GenericAce>(numAces);
+                       for (int i = 0; i < numAces; ++i) {
+                               GenericAce newAce = GenericAce.CreateFromBinaryForm(binaryForm, pos);
+                               list.Add(newAce);
+                               pos += newAce.BinaryLength;
+                       }
                }
-
-               byte revision;
-               List<GenericAce> list;
-
-               [MonoTODO]
+               
+               internal RawAcl(byte revision, List<GenericAce> aces)
+               {
+                       this.revision = revision;
+                       this.list = aces;
+               }
+               
                public override int BinaryLength
                {
                        get {
-                               throw new NotImplementedException ();
+                               int len = 8;
+                               foreach(var ace in list)
+                               {
+                                       len += ace.BinaryLength;
+                               }
+                               return len;
                        }
                }
 
@@ -69,11 +101,30 @@ namespace System.Security.AccessControl {
                        get { return revision; }
                }
 
-               [MonoTODO]
                public override void GetBinaryForm (byte[] binaryForm,
-                                                   int offset)
+                                                   int offset)
                {
-                       throw new NotImplementedException ();
+                       if(binaryForm == null)
+                               throw new ArgumentNullException("binaryForm");
+                       
+                       if(offset < 0
+                          || offset > binaryForm.Length - BinaryLength)
+                               throw new ArgumentException("Offset out of range", "offset");
+                       
+                       binaryForm[offset] = Revision;
+                       binaryForm[offset + 1] = 0;
+                       WriteUShort((ushort)BinaryLength, binaryForm,
+                                   offset + 2);
+                       WriteUShort((ushort)list.Count, binaryForm,
+                                   offset + 4);
+                       WriteUShort(0, binaryForm, offset + 6);
+                       
+                       int pos = offset + 8;
+                       foreach(var ace in list)
+                       {
+                               ace.GetBinaryForm(binaryForm, pos);
+                               pos += ace.BinaryLength;
+                       }
                }
 
                public void InsertAce (int index, GenericAce ace)
@@ -87,7 +138,107 @@ namespace System.Security.AccessControl {
                {
                        list.RemoveAt (index);
                }
+               
+               internal override string GetSddlForm(ControlFlags sdFlags,
+                                                    bool isDacl)
+               {
+                       StringBuilder result = new StringBuilder();
+                       
+                       if(isDacl) {
+                               if((sdFlags & ControlFlags.DiscretionaryAclProtected) != 0)
+                                       result.Append("P");
+                               if((sdFlags & ControlFlags.DiscretionaryAclAutoInheritRequired) != 0)
+                                       result.Append("AR");
+                               if((sdFlags & ControlFlags.DiscretionaryAclAutoInherited) != 0)
+                                       result.Append("AI");
+                       } else {
+                               if((sdFlags & ControlFlags.SystemAclProtected) != 0)
+                                       result.Append("P");
+                               if((sdFlags & ControlFlags.SystemAclAutoInheritRequired) != 0)
+                                       result.Append("AR");
+                               if((sdFlags & ControlFlags.SystemAclAutoInherited) != 0)
+                                       result.Append("AI");
+                       }
+                       
+                       foreach(var ace in list)
+                       {
+                               result.Append(ace.GetSddlForm());
+                       }
+                       
+                       return result.ToString();
+               }
+
+               internal static RawAcl ParseSddlForm(string sddlForm,
+                                                    bool isDacl,
+                                                    ref ControlFlags sdFlags,
+                                                    ref int pos)
+               {
+                       ParseFlags(sddlForm, isDacl, ref sdFlags, ref pos);
+                       
+                       byte revision = GenericAcl.AclRevision;
+                       List<GenericAce> aces = new List<GenericAce>();
+                       while(pos < sddlForm.Length && sddlForm[pos] == '(') {
+                               GenericAce ace = GenericAce.CreateFromSddlForm(
+                                                       sddlForm, ref pos);
+                               if ((ace as ObjectAce) != null)
+                                       revision = GenericAcl.AclRevisionDS;
+                               aces.Add(ace);
+                       }
+                       
+                       
+                       return new RawAcl(revision, aces);
+               }
+               
+               private static void ParseFlags(string sddlForm,
+                                              bool isDacl,
+                                              ref ControlFlags sdFlags,
+                                              ref int pos)
+               {
+                       char ch = Char.ToUpperInvariant(sddlForm[pos]);
+                       while(ch == 'P' || ch == 'A') {
+                               if(ch == 'P') {
+                                       if (isDacl)
+                                               sdFlags |= ControlFlags.DiscretionaryAclProtected;
+                                       else
+                                               sdFlags |= ControlFlags.SystemAclProtected;
+                                       pos++;
+                               } else if(sddlForm.Length > pos + 1) {
+                                       ch = Char.ToUpperInvariant(sddlForm[pos + 1]);
+                                       if(ch == 'R') {
+                                               if (isDacl)
+                                                       sdFlags |= ControlFlags.DiscretionaryAclAutoInheritRequired;
+                                               else
+                                                       sdFlags |= ControlFlags.SystemAclAutoInheritRequired;
+                                               pos += 2;
+                                       } else if (ch == 'I') {
+                                               if (isDacl)
+                                                       sdFlags |= ControlFlags.DiscretionaryAclAutoInherited;
+                                               else
+                                                       sdFlags |= ControlFlags.SystemAclAutoInherited;
+                                               pos += 2;
+                                       } else {
+                                               throw new ArgumentException("Invalid SDDL string.", "sddlForm");
+                                       }
+                               } else {
+                                       throw new ArgumentException("Invalid SDDL string.", "sddlForm");
+                               }
+                               
+                               ch = Char.ToUpperInvariant(sddlForm[pos]);
+                       }
+                       
+               }
+               
+               private void WriteUShort (ushort val, byte[] buffer, int offset)
+               {
+                       buffer[offset] = (byte)val;
+                       buffer[offset + 1] = (byte)(val >> 8);
+               }
+               
+               private ushort ReadUShort (byte[] buffer, int offset)
+               {
+                       return (ushort)((((int)buffer[offset + 0]) << 0)
+                                       | (((int)buffer[offset + 1]) << 8));
+               }
        }
 }
 
-#endif