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 Persist (SafeHandle handle)
135 PersistModifications (handle);
138 internal void PersistModifications (SafeHandle handle)
142 Persist (handle, AccessControlSectionsModified, null);
148 protected void Persist (SafeHandle handle,
149 AccessControlSections includeSections,
150 object exceptionContext)
154 RaiseExceptionOnFailure (InternalSet (handle, includeSections), null, handle, exceptionContext);
155 AccessControlSectionsModified &= ~includeSections;
161 internal void PersistModifications (string name)
165 Persist (name, AccessControlSectionsModified, null);
171 protected void Persist (string name,
172 AccessControlSections includeSections,
173 object exceptionContext)
176 throw new ArgumentNullException ("name");
180 RaiseExceptionOnFailure (InternalSet (name, includeSections), name, null, exceptionContext);
181 AccessControlSectionsModified &= ~includeSections;
187 internal static Exception DefaultExceptionFromErrorCode (int errorCode,
188 string name, SafeHandle handle,
192 case 2: return new FileNotFoundException ();
193 case 3: return new DirectoryNotFoundException ();
194 case 5: return new UnauthorizedAccessException ();
195 case 1314: return new PrivilegeNotHeldException (); // happens with audit rules
196 default: return new InvalidOperationException ("OS error code " + errorCode.ToString());
200 void RaiseExceptionOnFailure (int errorCode, string name, SafeHandle handle, object context)
202 if (errorCode == 0) return;
203 throw (exception_from_error_code ?? DefaultExceptionFromErrorCode)(errorCode, name, handle, context);
206 // InternalGet/InternalSet are virtual so that non-Windows platforms which do not share an
207 // API between files, mutexes, etc. can override in the subclass and do their own thing.
208 internal virtual int InternalGet (SafeHandle handle,
209 AccessControlSections includeSections)
212 throw new PlatformNotSupportedException ();
214 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
215 throw new PlatformNotSupportedException ();
217 return Win32GetHelper (delegate (SecurityInfos securityInfos,
218 out IntPtr owner, out IntPtr group,
219 out IntPtr dacl, out IntPtr sacl, out IntPtr descriptor)
221 return GetSecurityInfo (handle, ResourceType, securityInfos,
222 out owner, out group,
223 out dacl, out sacl, out descriptor);
228 internal virtual int InternalGet (string name,
229 AccessControlSections includeSections)
232 throw new PlatformNotSupportedException ();
234 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
235 throw new PlatformNotSupportedException ();
237 return Win32GetHelper (delegate (SecurityInfos securityInfos,
238 out IntPtr owner, out IntPtr group,
239 out IntPtr dacl, out IntPtr sacl, out IntPtr descriptor)
241 return GetNamedSecurityInfo (Win32FixName (name), ResourceType, securityInfos,
242 out owner, out group,
243 out dacl, out sacl, out descriptor);
249 internal virtual int InternalSet (SafeHandle handle, AccessControlSections includeSections)
251 throw new PlatformNotSupportedException ();
254 internal virtual int InternalSet (string name, AccessControlSections includeSections)
256 throw new PlatformNotSupportedException ();
259 internal virtual int InternalSet (SafeHandle handle,
260 AccessControlSections includeSections)
262 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
263 throw new PlatformNotSupportedException ();
265 return Win32SetHelper ((securityInfos, owner, group, dacl, sacl) =>
266 SetSecurityInfo (handle, ResourceType, securityInfos, owner, group, dacl, sacl),
270 internal virtual int InternalSet (string name,
271 AccessControlSections includeSections)
273 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
274 throw new PlatformNotSupportedException ();
276 return Win32SetHelper ((securityInfos, owner, group, dacl, sacl) =>
277 SetNamedSecurityInfo (Win32FixName (name), ResourceType, securityInfos, owner, group, dacl, sacl),
281 internal ResourceType ResourceType {
282 get { return resource_type; }
285 #region Win32 Details
286 int Win32GetHelper (GetSecurityInfoNativeCall nativeCall,
287 AccessControlSections includeSections)
289 bool getOwner = 0 != (includeSections & AccessControlSections.Owner);
290 bool getGroup = 0 != (includeSections & AccessControlSections.Group);
291 bool getDacl = 0 != (includeSections & AccessControlSections.Access);
292 bool getSacl = 0 != (includeSections & AccessControlSections.Audit);
294 SecurityInfos securityInfos = 0;
295 if (getOwner) securityInfos |= SecurityInfos.Owner;
296 if (getGroup) securityInfos |= SecurityInfos.Group;
297 if (getDacl ) securityInfos |= SecurityInfos.DiscretionaryAcl;
298 if (getSacl ) securityInfos |= SecurityInfos.SystemAcl;
300 IntPtr owner, group, dacl, sacl, descriptor;
301 int result = nativeCall (securityInfos,
302 out owner, out group, out dacl, out sacl, out descriptor);
303 if (0 != result) return result;
306 int binaryLength = 0;
307 if (IsValidSecurityDescriptor (descriptor))
308 binaryLength = GetSecurityDescriptorLength (descriptor);
310 byte[] binaryForm = new byte[binaryLength];
311 Marshal.Copy (descriptor, binaryForm, 0, binaryLength);
312 SetSecurityDescriptorBinaryForm (binaryForm, includeSections);
314 LocalFree (descriptor);
319 int Win32SetHelper (SetSecurityInfoNativeCall nativeCall,
320 AccessControlSections includeSections)
322 // SE_REGISTRY_KEY will fail UnauthorizedAccessException without this check.
323 if (AccessControlSections.None == includeSections) return 0;
325 SecurityInfos securityInfos = 0;
326 byte[] owner = null, group = null, dacl = null, sacl = null;
328 if (0 != (includeSections & AccessControlSections.Owner)) {
329 securityInfos |= SecurityInfos.Owner;
330 SecurityIdentifier ownerSid = (SecurityIdentifier)GetOwner (typeof (SecurityIdentifier));
331 if (null != ownerSid) {
332 owner = new byte[ownerSid.BinaryLength];
333 ownerSid.GetBinaryForm (owner, 0);
337 if (0 != (includeSections & AccessControlSections.Group)) {
338 securityInfos |= SecurityInfos.Group;
339 SecurityIdentifier groupSid = (SecurityIdentifier)GetGroup (typeof (SecurityIdentifier));
340 if (null != groupSid) {
341 group = new byte[groupSid.BinaryLength];
342 groupSid.GetBinaryForm (group, 0);
346 if (0 != (includeSections & AccessControlSections.Access)) {
347 securityInfos |= SecurityInfos.DiscretionaryAcl;
348 if (AreAccessRulesProtected)
349 securityInfos |= unchecked((SecurityInfos)0x80000000);
351 securityInfos |= (SecurityInfos)0x20000000;
352 dacl = new byte[descriptor.DiscretionaryAcl.BinaryLength];
353 descriptor.DiscretionaryAcl.GetBinaryForm (dacl, 0);
356 if (0 != (includeSections & AccessControlSections.Audit)) {
357 if (null != descriptor.SystemAcl) {
358 securityInfos |= SecurityInfos.SystemAcl;
359 if (AreAuditRulesProtected)
360 securityInfos |= (SecurityInfos)0x40000000;
362 securityInfos |= (SecurityInfos)0x10000000;
363 sacl = new byte[descriptor.SystemAcl.BinaryLength];
364 descriptor.SystemAcl.GetBinaryForm (sacl, 0);
368 return nativeCall (securityInfos, owner, group, dacl, sacl);
371 string Win32FixName (string name)
373 if (ResourceType == ResourceType.RegistryKey) {
374 // For (Get|Set)NamedSecurityInfo, registry paths lack the HKEY_ prefix.
375 if (!name.StartsWith ("HKEY_")) throw new InvalidOperationException ();
376 name = name.Substring ("HKEY_".Length);
383 #region Win32 P/Invokes
384 delegate int GetSecurityInfoNativeCall (SecurityInfos securityInfos,
385 out IntPtr owner, out IntPtr group, out IntPtr dacl, out IntPtr sacl,
386 out IntPtr descriptor);
388 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="GetSecurityInfo")]
389 static extern int GetSecurityInfo (SafeHandle handle, ResourceType resourceType, SecurityInfos securityInfos,
390 out IntPtr owner, out IntPtr group, out IntPtr dacl, out IntPtr sacl,
391 out IntPtr descriptor);
393 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="GetNamedSecurityInfo")]
394 static extern int GetNamedSecurityInfo (string name, ResourceType resourceType, SecurityInfos securityInfos,
395 out IntPtr owner, out IntPtr group, out IntPtr dacl, out IntPtr sacl,
396 out IntPtr descriptor);
398 [DllImport ("kernel32.dll", EntryPoint="LocalFree")]
399 static extern IntPtr LocalFree (IntPtr handle);
401 delegate int SetSecurityInfoNativeCall (SecurityInfos securityInfos,
402 byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
404 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="SetSecurityInfo")]
405 static extern int SetSecurityInfo (SafeHandle handle, ResourceType resourceType, SecurityInfos securityInfos,
406 byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
408 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="SetNamedSecurityInfo")]
409 static extern int SetNamedSecurityInfo (string name, ResourceType resourceType, SecurityInfos securityInfos,
410 byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
412 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="GetSecurityDescriptorLength")]
413 static extern int GetSecurityDescriptorLength (IntPtr descriptor);
415 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="IsValidSecurityDescriptor")]
416 [return: MarshalAs (UnmanagedType.Bool)]
417 static extern bool IsValidSecurityDescriptor (IntPtr descriptor);
419 struct SecurityDescriptor
421 public byte Revision, Size;
422 public ushort ControlFlags;
423 public IntPtr Owner, Group, Sacl, Dacl;