-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAcl.cs
302 lines (231 loc) · 9.04 KB
/
Acl.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Text;
namespace HttpConfig
{
public enum UrlPermission
{
All,
Registration,
Delegation,
Other,
}
public class Acl : ICloneable
{
private ArrayList _acl = new ArrayList();
public Acl() { }
public ArrayList Aces
{
get { return _acl; }
}
public object Clone()
{
Acl newAcl = new Acl();
foreach(Ace entry in _acl)
newAcl._acl.Add(new Ace(entry.User, entry.AccountNameMapped, entry.Permission, entry.OtherPerm));
return newAcl;
}
public string FriendlyString
{
get
{
StringBuilder friendlyString = new StringBuilder();
foreach(Ace entry in _acl)
{
friendlyString.Append("(");
friendlyString.Append(entry.User);
friendlyString.Append(";");
friendlyString.Append(entry.Permission.ToString());
friendlyString.Append(")");
}
return friendlyString.ToString();
}
}
public static Acl FromSddl(string sddl)
{
Acl newAcl = new Acl();
string[] aceStrings = sddl.Split(new char[] { '(', ')' });
// it's split on ( and ), so we have blanks every other item
for(int i = 1; i < aceStrings.Length; i++)
{
if((i % 2) > 0)
newAcl._acl.Add(Ace.FromSddl(aceStrings[i]));
}
return newAcl;
}
public string ToSddl()
{
StringBuilder sddl = new StringBuilder();
sddl.Append("D:");
foreach(Ace ace in _acl)
ace.AddSddl(sddl);
return sddl.ToString();
}
}
public class Ace
{
private string _user;
private UrlPermission _permission;
private string _otherPerm;
private bool _accountNameMapped;
private Ace() { }
public Ace(string user, bool accountNameMapped, UrlPermission permission, string otherPerm)
{
_user = user;
_accountNameMapped = accountNameMapped;
_permission = permission;
_otherPerm = otherPerm;
}
public string User
{
get { return _user; }
set { _user = value; }
}
public bool AccountNameMapped
{
get { return _accountNameMapped; }
set { _accountNameMapped = value; }
}
public UrlPermission Permission
{
get { return _permission; }
set { _permission = value; }
}
public string OtherPerm
{
get { return _otherPerm; }
set { _otherPerm = value; }
}
public void AddSddl(StringBuilder sddl)
{
sddl.Append("(A;;");
switch(_permission)
{
case UrlPermission.All:
sddl.Append("GA");
break;
case UrlPermission.Registration:
sddl.Append("GX");
break;
case UrlPermission.Delegation:
sddl.Append("GW");
break;
case UrlPermission.Other:
sddl.Append(_otherPerm);
break;
}
sddl.Append(";;;");
sddl.Append(_accountNameMapped ? EncodeSid() : _user);
sddl.Append(")");
}
public static Ace FromSddl(string sddl)
{
string[] tokens = sddl.Split(';');
if(tokens.Length != 6)
throw new ArgumentException("Invalid SDDL string. Too many or too few tokens.", "sddl");
string permString = tokens[2];
string stringSid = tokens[5];
Ace ace = new Ace();
switch(permString)
{
case "GA":
ace._permission = UrlPermission.All;
break;
case "GX":
ace._permission = UrlPermission.Registration;
break;
case "GW":
ace._permission = UrlPermission.Delegation;
break;
default:
ace._permission = UrlPermission.Other;
ace._otherPerm = permString;
break;
}
ace._accountNameMapped = DecodeSid(stringSid, out ace._user);
return ace;
}
private static bool DecodeSid(string stringSid, out string accountName)
{
IntPtr pSid = IntPtr.Zero;
IntPtr pAccount = IntPtr.Zero;
IntPtr pDomain = IntPtr.Zero;
try
{
accountName = stringSid;
if(!SecurityApi.ConvertStringSidToSid(stringSid, out pSid))
throw new Exception("ConvertStringSidToSid failed. Error = " + Marshal.GetLastWin32Error().ToString());
int accountLength = 0;
int domainLength = 0;
SecurityApi.SidNameUse use;
if(!SecurityApi.LookupAccountSid(null, pSid, pAccount, ref accountLength, pDomain, ref domainLength, out use))
{
int error = Marshal.GetLastWin32Error();
if(error != (int)SecurityApi.Error.ERROR_INSUFFICIENT_BUFFER)
{
if((error == (int)SecurityApi.Error.ERROR_NONE_MAPPED) || (error == (int)SecurityApi.Error.ERROR_TRUSTED_RELATIONSHIP_FAILURE))
return false;
else
throw new Exception("LookupAccountSid failed. Error = " + Marshal.GetLastWin32Error().ToString());
}
}
pAccount = Marshal.AllocHGlobal(accountLength * 2); // 2-byte unicode...we're using the "W" variety of the funcion
pDomain = Marshal.AllocHGlobal(domainLength * 2); // 2-byte unicode...we're using the "W" variety of the funcion
if(!SecurityApi.LookupAccountSid(null, pSid, pAccount, ref accountLength, pDomain, ref domainLength, out use))
{
int error = Marshal.GetLastWin32Error();
if((error == (int)SecurityApi.Error.ERROR_NONE_MAPPED) || (error == (int)SecurityApi.Error.ERROR_TRUSTED_RELATIONSHIP_FAILURE))
return false;
else
throw new Exception("LookupAccountSid failed. Error = " + error.ToString());
}
accountName = Marshal.PtrToStringUni(pDomain) + "\\" + Marshal.PtrToStringUni(pAccount);
return true;
}
finally
{
if(pSid != IntPtr.Zero)
SecurityApi.LocalFree(pSid);
if(pAccount != IntPtr.Zero)
Marshal.FreeHGlobal(pAccount);
if(pDomain != IntPtr.Zero)
Marshal.FreeHGlobal(pDomain);
}
}
private string EncodeSid()
{
IntPtr pSid = IntPtr.Zero;
IntPtr pStringSid = IntPtr.Zero;
IntPtr pDomain = IntPtr.Zero;
try
{
int sidLength = 0;
int domainLength = 0;
SecurityApi.SidNameUse use;
if(!SecurityApi.LookupAccountName(null, _user, pSid, ref sidLength, pDomain, ref domainLength, out use))
{
int error = Marshal.GetLastWin32Error();
if(error != (int)SecurityApi.Error.ERROR_INSUFFICIENT_BUFFER)
throw new Exception("LookupAccountName failed. Error = " + Marshal.GetLastWin32Error().ToString());
}
pSid = Marshal.AllocHGlobal(sidLength);
pDomain = Marshal.AllocHGlobal(domainLength * 2); // 2-byte unicode...we're using the "W" variety of the funcion
if(!SecurityApi.LookupAccountName(null, _user, pSid, ref sidLength, pDomain, ref domainLength, out use))
throw new Exception("LookupAccountName failed. Error = " + Marshal.GetLastWin32Error().ToString());
if(!SecurityApi.ConvertSidToStringSid(pSid, out pStringSid))
throw new Exception("ConvertSidToStringSid failed. Error = " + Marshal.GetLastWin32Error().ToString());
return Marshal.PtrToStringUni(pStringSid);
}
finally
{
if(pSid != IntPtr.Zero)
SecurityApi.LocalFree(pSid);
if(pStringSid != IntPtr.Zero)
SecurityApi.LocalFree(pStringSid);
if(pDomain != IntPtr.Zero)
Marshal.FreeHGlobal(pDomain);
}
}
}
}