Fix infinite loop parsing some SDDL strings
[mono.git] / mcs / class / corlib / System.Security.AccessControl / RawAcl.cs
1 //
2 // System.Security.AccessControl.RawAcl 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.Collections.Generic;
32 using System.Text;
33
34 namespace System.Security.AccessControl {
35         public sealed class RawAcl : GenericAcl
36         {
37                 private byte revision;
38                 private List<GenericAce> list;
39
40                 public RawAcl (byte revision, int capacity)
41                 {
42                         this.revision = revision;
43                         list = new List<GenericAce> (capacity);
44                 }
45                 
46                 public RawAcl (byte [] binaryForm, int offset)
47                 {
48                         if (binaryForm == null)
49                                 throw new ArgumentNullException("binaryForm");
50                         
51                         if (offset < 0 || offset > binaryForm.Length - 8)
52                                 throw new ArgumentOutOfRangeException("offset", offset, "Offset out of range");
53                         
54                         revision = binaryForm[offset];
55                         if (revision != AclRevision && revision != AclRevisionDS)
56                                 throw new ArgumentException("Invalid ACL - unknown revision", "binaryForm");
57                         
58                         int binaryLength = ReadUShort(binaryForm, offset + 2);
59                         if (offset > binaryForm.Length - binaryLength)
60                                 throw new ArgumentException("Invalid ACL - truncated", "binaryForm");
61                         
62                         int pos = offset + 8;
63                         int numAces = ReadUShort(binaryForm, offset + 4);
64                         list = new List<GenericAce>(numAces);
65                         for (int i = 0; i < numAces; ++i) {
66                                 GenericAce newAce = GenericAce.CreateFromBinaryForm(binaryForm, pos);
67                                 list.Add(newAce);
68                                 pos += newAce.BinaryLength;
69                         }
70                 }
71                 
72                 internal RawAcl(byte revision, List<GenericAce> aces)
73                 {
74                         this.revision = revision;
75                         this.list = aces;
76                 }
77                 
78                 public override int BinaryLength
79                 {
80                         get {
81                                 int len = 8;
82                                 foreach(var ace in list)
83                                 {
84                                         len += ace.BinaryLength;
85                                 }
86                                 return len;
87                         }
88                 }
89
90                 public override int Count {
91                         get { return list.Count; }
92                 }
93
94                 public override GenericAce this [int index]
95                 {
96                         get { return list [index]; }
97                         set { list [index] = value; }
98                 }
99                 
100                 public override byte Revision {
101                         get { return revision; }
102                 }
103
104                 public override void GetBinaryForm (byte[] binaryForm,
105                                                     int offset)
106                 {
107                         if(binaryForm == null)
108                                 throw new ArgumentNullException("binaryForm");
109                         
110                         if(offset < 0
111                            || offset > binaryForm.Length - BinaryLength)
112                                 throw new ArgumentException("Offset out of range", "offset");
113                         
114                         binaryForm[offset] = Revision;
115                         binaryForm[offset + 1] = 0;
116                         WriteUShort((ushort)BinaryLength, binaryForm,
117                                     offset + 2);
118                         WriteUShort((ushort)list.Count, binaryForm,
119                                     offset + 4);
120                         WriteUShort(0, binaryForm, offset + 6);
121                         
122                         int pos = offset + 8;
123                         foreach(var ace in list)
124                         {
125                                 ace.GetBinaryForm(binaryForm, pos);
126                                 pos += ace.BinaryLength;
127                         }
128                 }
129
130                 public void InsertAce (int index, GenericAce ace)
131                 {
132                         if (ace == null)
133                                 throw new ArgumentNullException ("ace");
134                         list.Insert (index, ace);
135                 }
136                 
137                 public void RemoveAce (int index)
138                 {
139                         list.RemoveAt (index);
140                 }
141                 
142                 internal override string GetSddlForm(ControlFlags sdFlags,
143                                                      bool isDacl)
144                 {
145                         StringBuilder result = new StringBuilder();
146                         
147                         if(isDacl) {
148                                 if((sdFlags & ControlFlags.DiscretionaryAclProtected) != 0)
149                                         result.Append("P");
150                                 if((sdFlags & ControlFlags.DiscretionaryAclAutoInheritRequired) != 0)
151                                         result.Append("AR");
152                                 if((sdFlags & ControlFlags.DiscretionaryAclAutoInherited) != 0)
153                                         result.Append("AI");
154                         } else {
155                                 if((sdFlags & ControlFlags.SystemAclProtected) != 0)
156                                         result.Append("P");
157                                 if((sdFlags & ControlFlags.SystemAclAutoInheritRequired) != 0)
158                                         result.Append("AR");
159                                 if((sdFlags & ControlFlags.SystemAclAutoInherited) != 0)
160                                         result.Append("AI");
161                         }
162                         
163                         foreach(var ace in list)
164                         {
165                                 result.Append(ace.GetSddlForm());
166                         }
167                         
168                         return result.ToString();
169                 }
170
171                 internal static RawAcl ParseSddlForm(string sddlForm,
172                                                      bool isDacl,
173                                                      ref ControlFlags sdFlags,
174                                                      ref int pos)
175                 {
176                         ParseFlags(sddlForm, isDacl, ref sdFlags, ref pos);
177                         
178                         byte revision = GenericAcl.AclRevision;
179                         List<GenericAce> aces = new List<GenericAce>();
180                         while(pos < sddlForm.Length && sddlForm[pos] == '(') {
181                                 GenericAce ace = GenericAce.CreateFromSddlForm(
182                                                         sddlForm, ref pos);
183                                 if ((ace as ObjectAce) != null)
184                                         revision = GenericAcl.AclRevisionDS;
185                                 aces.Add(ace);
186                         }
187                         
188                         
189                         return new RawAcl(revision, aces);
190                 }
191                 
192                 private static void ParseFlags(string sddlForm,
193                                                bool isDacl,
194                                                ref ControlFlags sdFlags,
195                                                ref int pos)
196                 {
197                         char ch = Char.ToUpperInvariant(sddlForm[pos]);
198                         while(ch == 'P' || ch == 'A') {
199                                 if(ch == 'P') {
200                                         if (isDacl)
201                                                 sdFlags |= ControlFlags.DiscretionaryAclProtected;
202                                         else
203                                                 sdFlags |= ControlFlags.SystemAclProtected;
204                                         pos++;
205                                 } else if(sddlForm.Length > pos + 1) {
206                                         ch = Char.ToUpperInvariant(sddlForm[pos + 1]);
207                                         if(ch == 'R') {
208                                                 if (isDacl)
209                                                         sdFlags |= ControlFlags.DiscretionaryAclAutoInheritRequired;
210                                                 else
211                                                         sdFlags |= ControlFlags.SystemAclAutoInheritRequired;
212                                                 pos += 2;
213                                         } else if (ch == 'I') {
214                                                 if (isDacl)
215                                                         sdFlags |= ControlFlags.DiscretionaryAclAutoInherited;
216                                                 else
217                                                         sdFlags |= ControlFlags.SystemAclAutoInherited;
218                                                 pos += 2;
219                                         } else {
220                                                 throw new ArgumentException("Invalid SDDL string.", "sddlForm");
221                                         }
222                                 } else {
223                                         throw new ArgumentException("Invalid SDDL string.", "sddlForm");
224                                 }
225                                 
226                                 ch = Char.ToUpperInvariant(sddlForm[pos]);
227                         }
228                         
229                 }
230                 
231                 private void WriteUShort (ushort val, byte[] buffer, int offset)
232                 {
233                         buffer[offset] = (byte)val;
234                         buffer[offset + 1] = (byte)(val >> 8);
235                 }
236                 
237                 private ushort ReadUShort (byte[] buffer, int offset)
238                 {
239                         return (ushort)((((int)buffer[offset + 0]) << 0)
240                                         | (((int)buffer[offset + 1]) << 8));
241                 }
242         }
243 }
244