2 // System.Security.AccessControl.NativeObjectSecurity implementation
5 // Dick Porter <dick@ximian.com>
6 // James Bellinger <jfb@zer7.com>
8 // Copyright (C) 2005, 2006 Novell, Inc (http://www.novell.com)
9 // Copyright (C) 2012 James Bellinger
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.
33 using System.Runtime.InteropServices;
34 using System.Security.Principal;
36 namespace System.Security.AccessControl
38 public abstract class NativeObjectSecurity : CommonObjectSecurity
40 ExceptionFromErrorCode exception_from_error_code;
41 ResourceType resource_type;
43 protected internal delegate Exception ExceptionFromErrorCode (int errorCode,
44 string name, SafeHandle handle,
47 internal NativeObjectSecurity (CommonSecurityDescriptor securityDescriptor, ResourceType resourceType)
48 : base (securityDescriptor)
50 resource_type = resourceType;
53 protected NativeObjectSecurity (bool isContainer,
54 ResourceType resourceType)
55 : this (isContainer, resourceType, null, null)
59 protected NativeObjectSecurity (bool isContainer,
60 ResourceType resourceType,
61 ExceptionFromErrorCode exceptionFromErrorCode,
62 object exceptionContext)
65 exception_from_error_code = exceptionFromErrorCode;
66 resource_type = resourceType;
69 protected NativeObjectSecurity (bool isContainer,
70 ResourceType resourceType,
72 AccessControlSections includeSections)
73 : this (isContainer, resourceType, handle, includeSections, null, null)
77 protected NativeObjectSecurity (bool isContainer,
78 ResourceType resourceType,
80 AccessControlSections includeSections)
81 : this (isContainer, resourceType, name, includeSections, null, null)
85 protected NativeObjectSecurity (bool isContainer,
86 ResourceType resourceType,
88 AccessControlSections includeSections,
89 ExceptionFromErrorCode exceptionFromErrorCode,
90 object exceptionContext)
91 : this (isContainer, resourceType, exceptionFromErrorCode, exceptionContext)
93 RaiseExceptionOnFailure (InternalGet (handle, includeSections),
94 null, handle, exceptionContext);
95 ClearAccessControlSectionsModified ();
98 protected NativeObjectSecurity (bool isContainer,
99 ResourceType resourceType,
101 AccessControlSections includeSections,
102 ExceptionFromErrorCode exceptionFromErrorCode,
103 object exceptionContext)
104 : this (isContainer, resourceType, exceptionFromErrorCode, exceptionContext)
106 RaiseExceptionOnFailure (InternalGet (name, includeSections),
107 name, null, exceptionContext);
108 ClearAccessControlSectionsModified ();
111 void ClearAccessControlSectionsModified ()
115 AccessControlSectionsModified = AccessControlSections.None;
121 protected override sealed void Persist (SafeHandle handle,
122 AccessControlSections includeSections)
124 Persist (handle, includeSections, null);
127 protected override sealed void Persist (string name,
128 AccessControlSections includeSections)
130 Persist (name, includeSections, null);
133 internal void PersistModifications (SafeHandle handle)
137 Persist (handle, AccessControlSectionsModified, null);
143 protected void Persist (SafeHandle handle,
144 AccessControlSections includeSections,
145 object exceptionContext)
149 RaiseExceptionOnFailure (InternalSet (handle, includeSections), null, handle, exceptionContext);
150 AccessControlSectionsModified &= ~includeSections;
156 internal void PersistModifications (string name)
160 Persist (name, AccessControlSectionsModified, null);
166 protected void Persist (string name,
167 AccessControlSections includeSections,
168 object exceptionContext)
171 throw new ArgumentNullException ("name");
175 RaiseExceptionOnFailure (InternalSet (name, includeSections), name, null, exceptionContext);
176 AccessControlSectionsModified &= ~includeSections;
182 internal static Exception DefaultExceptionFromErrorCode (int errorCode,
183 string name, SafeHandle handle,
187 case 2: return new FileNotFoundException ();
188 case 3: return new DirectoryNotFoundException ();
189 case 5: return new UnauthorizedAccessException ();
190 case 1314: return new PrivilegeNotHeldException (); // happens with audit rules
191 default: return new InvalidOperationException ("OS error code " + errorCode.ToString());
195 void RaiseExceptionOnFailure (int errorCode, string name, SafeHandle handle, object context)
197 if (errorCode == 0) return;
198 throw (exception_from_error_code ?? DefaultExceptionFromErrorCode)(errorCode, name, handle, context);
201 // InternalGet/InternalSet are virtual so that non-Windows platforms which do not share an
202 // API between files, mutexes, etc. can override in the subclass and do their own thing.
203 internal virtual int InternalGet (SafeHandle handle,
204 AccessControlSections includeSections)
206 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
207 throw new PlatformNotSupportedException ();
209 return Win32GetHelper (delegate (SecurityInfos securityInfos,
210 out IntPtr owner, out IntPtr group,
211 out IntPtr dacl, out IntPtr sacl, out IntPtr descriptor)
213 return GetSecurityInfo (handle, ResourceType, securityInfos,
214 out owner, out group,
215 out dacl, out sacl, out descriptor);
219 internal virtual int InternalGet (string name,
220 AccessControlSections includeSections)
222 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
223 throw new PlatformNotSupportedException ();
225 return Win32GetHelper (delegate (SecurityInfos securityInfos,
226 out IntPtr owner, out IntPtr group,
227 out IntPtr dacl, out IntPtr sacl, out IntPtr descriptor)
229 return GetNamedSecurityInfo (Win32FixName (name), ResourceType, securityInfos,
230 out owner, out group,
231 out dacl, out sacl, out descriptor);
235 internal virtual int InternalSet (SafeHandle handle,
236 AccessControlSections includeSections)
238 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
239 throw new PlatformNotSupportedException ();
241 return Win32SetHelper ((securityInfos, owner, group, dacl, sacl) =>
242 SetSecurityInfo (handle, ResourceType, securityInfos, owner, group, dacl, sacl),
246 internal virtual int InternalSet (string name,
247 AccessControlSections includeSections)
249 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
250 throw new PlatformNotSupportedException ();
252 return Win32SetHelper ((securityInfos, owner, group, dacl, sacl) =>
253 SetNamedSecurityInfo (Win32FixName (name), ResourceType, securityInfos, owner, group, dacl, sacl),
257 internal ResourceType ResourceType {
258 get { return resource_type; }
261 #region Win32 Details
262 int Win32GetHelper (GetSecurityInfoNativeCall nativeCall,
263 AccessControlSections includeSections)
265 bool getOwner = 0 != (includeSections & AccessControlSections.Owner);
266 bool getGroup = 0 != (includeSections & AccessControlSections.Group);
267 bool getDacl = 0 != (includeSections & AccessControlSections.Access);
268 bool getSacl = 0 != (includeSections & AccessControlSections.Audit);
270 SecurityInfos securityInfos = 0;
271 if (getOwner) securityInfos |= SecurityInfos.Owner;
272 if (getGroup) securityInfos |= SecurityInfos.Group;
273 if (getDacl ) securityInfos |= SecurityInfos.DiscretionaryAcl;
274 if (getSacl ) securityInfos |= SecurityInfos.SystemAcl;
276 IntPtr owner, group, dacl, sacl, descriptor;
277 int result = nativeCall (securityInfos,
278 out owner, out group, out dacl, out sacl, out descriptor);
279 if (0 != result) return result;
282 int binaryLength = 0;
283 if (IsValidSecurityDescriptor (descriptor))
284 binaryLength = GetSecurityDescriptorLength (descriptor);
286 byte[] binaryForm = new byte[binaryLength];
287 Marshal.Copy (descriptor, binaryForm, 0, binaryLength);
288 SetSecurityDescriptorBinaryForm (binaryForm, includeSections);
290 LocalFree (descriptor);
295 int Win32SetHelper (SetSecurityInfoNativeCall nativeCall,
296 AccessControlSections includeSections)
298 // SE_REGISTRY_KEY will fail UnauthorizedAccessException without this check.
299 if (AccessControlSections.None == includeSections) return 0;
301 SecurityInfos securityInfos = 0;
302 byte[] owner = null, group = null, dacl = null, sacl = null;
304 if (0 != (includeSections & AccessControlSections.Owner)) {
305 securityInfos |= SecurityInfos.Owner;
306 SecurityIdentifier ownerSid = (SecurityIdentifier)GetOwner (typeof (SecurityIdentifier));
307 if (null != ownerSid) {
308 owner = new byte[ownerSid.BinaryLength];
309 ownerSid.GetBinaryForm (owner, 0);
313 if (0 != (includeSections & AccessControlSections.Group)) {
314 securityInfos |= SecurityInfos.Group;
315 SecurityIdentifier groupSid = (SecurityIdentifier)GetGroup (typeof (SecurityIdentifier));
316 if (null != groupSid) {
317 group = new byte[groupSid.BinaryLength];
318 groupSid.GetBinaryForm (group, 0);
322 if (0 != (includeSections & AccessControlSections.Access)) {
323 securityInfos |= SecurityInfos.DiscretionaryAcl;
324 if (AreAccessRulesProtected)
325 securityInfos |= unchecked((SecurityInfos)0x80000000);
327 securityInfos |= (SecurityInfos)0x20000000;
328 dacl = new byte[descriptor.DiscretionaryAcl.BinaryLength];
329 descriptor.DiscretionaryAcl.GetBinaryForm (dacl, 0);
332 if (0 != (includeSections & AccessControlSections.Audit)) {
333 if (null != descriptor.SystemAcl) {
334 securityInfos |= SecurityInfos.SystemAcl;
335 if (AreAuditRulesProtected)
336 securityInfos |= (SecurityInfos)0x40000000;
338 securityInfos |= (SecurityInfos)0x10000000;
339 sacl = new byte[descriptor.SystemAcl.BinaryLength];
340 descriptor.SystemAcl.GetBinaryForm (sacl, 0);
344 return nativeCall (securityInfos, owner, group, dacl, sacl);
347 string Win32FixName (string name)
349 if (ResourceType == ResourceType.RegistryKey) {
350 // For (Get|Set)NamedSecurityInfo, registry paths lack the HKEY_ prefix.
351 if (!name.StartsWith ("HKEY_")) throw new InvalidOperationException ();
352 name = name.Substring ("HKEY_".Length);
359 #region Win32 P/Invokes
360 delegate int GetSecurityInfoNativeCall (SecurityInfos securityInfos,
361 out IntPtr owner, out IntPtr group, out IntPtr dacl, out IntPtr sacl,
362 out IntPtr descriptor);
364 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="GetSecurityInfo")]
365 static extern int GetSecurityInfo (SafeHandle handle, ResourceType resourceType, SecurityInfos securityInfos,
366 out IntPtr owner, out IntPtr group, out IntPtr dacl, out IntPtr sacl,
367 out IntPtr descriptor);
369 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="GetNamedSecurityInfo")]
370 static extern int GetNamedSecurityInfo (string name, ResourceType resourceType, SecurityInfos securityInfos,
371 out IntPtr owner, out IntPtr group, out IntPtr dacl, out IntPtr sacl,
372 out IntPtr descriptor);
374 [DllImport ("kernel32.dll", EntryPoint="LocalFree")]
375 static extern IntPtr LocalFree (IntPtr handle);
377 delegate int SetSecurityInfoNativeCall (SecurityInfos securityInfos,
378 byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
380 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="SetSecurityInfo")]
381 static extern int SetSecurityInfo (SafeHandle handle, ResourceType resourceType, SecurityInfos securityInfos,
382 byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
384 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="SetNamedSecurityInfo")]
385 static extern int SetNamedSecurityInfo (string name, ResourceType resourceType, SecurityInfos securityInfos,
386 byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
388 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="GetSecurityDescriptorLength")]
389 static extern int GetSecurityDescriptorLength (IntPtr descriptor);
391 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="IsValidSecurityDescriptor")]
392 [return: MarshalAs (UnmanagedType.Bool)]
393 static extern bool IsValidSecurityDescriptor (IntPtr descriptor);
395 struct SecurityDescriptor
397 public byte Revision, Size;
398 public ushort ControlFlags;
399 public IntPtr Owner, Group, Sacl, Dacl;