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;
42 ResourceType resource_type;
45 protected internal delegate Exception ExceptionFromErrorCode (int errorCode,
46 string name, SafeHandle handle,
49 internal NativeObjectSecurity (CommonSecurityDescriptor securityDescriptor, ResourceType resourceType)
50 : base (securityDescriptor)
53 resource_type = resourceType;
57 protected NativeObjectSecurity (bool isContainer,
58 ResourceType resourceType)
59 : this (isContainer, resourceType, null, null)
63 protected NativeObjectSecurity (bool isContainer,
64 ResourceType resourceType,
65 ExceptionFromErrorCode exceptionFromErrorCode,
66 object exceptionContext)
69 exception_from_error_code = exceptionFromErrorCode;
71 resource_type = resourceType;
75 protected NativeObjectSecurity (bool isContainer,
76 ResourceType resourceType,
78 AccessControlSections includeSections)
79 : this (isContainer, resourceType, handle, includeSections, null, null)
83 protected NativeObjectSecurity (bool isContainer,
84 ResourceType resourceType,
86 AccessControlSections includeSections)
87 : this (isContainer, resourceType, name, includeSections, null, null)
91 protected NativeObjectSecurity (bool isContainer,
92 ResourceType resourceType,
94 AccessControlSections includeSections,
95 ExceptionFromErrorCode exceptionFromErrorCode,
96 object exceptionContext)
97 : this (isContainer, resourceType, exceptionFromErrorCode, exceptionContext)
99 RaiseExceptionOnFailure (InternalGet (handle, includeSections),
100 null, handle, exceptionContext);
101 ClearAccessControlSectionsModified ();
104 protected NativeObjectSecurity (bool isContainer,
105 ResourceType resourceType,
107 AccessControlSections includeSections,
108 ExceptionFromErrorCode exceptionFromErrorCode,
109 object exceptionContext)
110 : this (isContainer, resourceType, exceptionFromErrorCode, exceptionContext)
112 RaiseExceptionOnFailure (InternalGet (name, includeSections),
113 name, null, exceptionContext);
114 ClearAccessControlSectionsModified ();
117 void ClearAccessControlSectionsModified ()
121 AccessControlSectionsModified = AccessControlSections.None;
127 protected override sealed void Persist (SafeHandle handle,
128 AccessControlSections includeSections)
130 Persist (handle, includeSections, null);
133 protected override sealed void Persist (string name,
134 AccessControlSections includeSections)
136 Persist (name, includeSections, null);
139 internal void Persist (SafeHandle handle)
141 PersistModifications (handle);
144 internal void PersistModifications (SafeHandle handle)
148 Persist (handle, AccessControlSectionsModified, null);
154 protected void Persist (SafeHandle handle,
155 AccessControlSections includeSections,
156 object exceptionContext)
160 RaiseExceptionOnFailure (InternalSet (handle, includeSections), null, handle, exceptionContext);
161 AccessControlSectionsModified &= ~includeSections;
167 internal void PersistModifications (string name)
171 Persist (name, AccessControlSectionsModified, null);
177 protected void Persist (string name,
178 AccessControlSections includeSections,
179 object exceptionContext)
182 throw new ArgumentNullException ("name");
186 RaiseExceptionOnFailure (InternalSet (name, includeSections), name, null, exceptionContext);
187 AccessControlSectionsModified &= ~includeSections;
193 internal static Exception DefaultExceptionFromErrorCode (int errorCode,
194 string name, SafeHandle handle,
198 case 2: return new FileNotFoundException ();
199 case 3: return new DirectoryNotFoundException ();
200 case 5: return new UnauthorizedAccessException ();
201 case 1314: return new PrivilegeNotHeldException (); // happens with audit rules
202 default: return new InvalidOperationException ("OS error code " + errorCode.ToString());
206 void RaiseExceptionOnFailure (int errorCode, string name, SafeHandle handle, object context)
208 if (errorCode == 0) return;
209 throw (exception_from_error_code ?? DefaultExceptionFromErrorCode)(errorCode, name, handle, context);
212 // InternalGet/InternalSet are virtual so that non-Windows platforms which do not share an
213 // API between files, mutexes, etc. can override in the subclass and do their own thing.
214 internal virtual int InternalGet (SafeHandle handle,
215 AccessControlSections includeSections)
218 throw new PlatformNotSupportedException ();
220 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
221 throw new PlatformNotSupportedException ();
223 return Win32GetHelper (delegate (SecurityInfos securityInfos,
224 out IntPtr owner, out IntPtr group,
225 out IntPtr dacl, out IntPtr sacl, out IntPtr descriptor)
227 return GetSecurityInfo (handle, ResourceType, securityInfos,
228 out owner, out group,
229 out dacl, out sacl, out descriptor);
234 internal virtual int InternalGet (string name,
235 AccessControlSections includeSections)
238 throw new PlatformNotSupportedException ();
240 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
241 throw new PlatformNotSupportedException ();
243 return Win32GetHelper (delegate (SecurityInfos securityInfos,
244 out IntPtr owner, out IntPtr group,
245 out IntPtr dacl, out IntPtr sacl, out IntPtr descriptor)
247 return GetNamedSecurityInfo (Win32FixName (name), ResourceType, securityInfos,
248 out owner, out group,
249 out dacl, out sacl, out descriptor);
255 internal virtual int InternalSet (SafeHandle handle, AccessControlSections includeSections)
257 throw new PlatformNotSupportedException ();
260 internal virtual int InternalSet (string name, AccessControlSections includeSections)
262 throw new PlatformNotSupportedException ();
265 internal virtual int InternalSet (SafeHandle handle,
266 AccessControlSections includeSections)
268 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
269 throw new PlatformNotSupportedException ();
271 return Win32SetHelper ((securityInfos, owner, group, dacl, sacl) =>
272 SetSecurityInfo (handle, ResourceType, securityInfos, owner, group, dacl, sacl),
276 internal virtual int InternalSet (string name,
277 AccessControlSections includeSections)
279 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
280 throw new PlatformNotSupportedException ();
282 return Win32SetHelper ((securityInfos, owner, group, dacl, sacl) =>
283 SetNamedSecurityInfo (Win32FixName (name), ResourceType, securityInfos, owner, group, dacl, sacl),
287 internal ResourceType ResourceType {
288 get { return resource_type; }
291 #region Win32 Details
292 int Win32GetHelper (GetSecurityInfoNativeCall nativeCall,
293 AccessControlSections includeSections)
295 bool getOwner = 0 != (includeSections & AccessControlSections.Owner);
296 bool getGroup = 0 != (includeSections & AccessControlSections.Group);
297 bool getDacl = 0 != (includeSections & AccessControlSections.Access);
298 bool getSacl = 0 != (includeSections & AccessControlSections.Audit);
300 SecurityInfos securityInfos = 0;
301 if (getOwner) securityInfos |= SecurityInfos.Owner;
302 if (getGroup) securityInfos |= SecurityInfos.Group;
303 if (getDacl ) securityInfos |= SecurityInfos.DiscretionaryAcl;
304 if (getSacl ) securityInfos |= SecurityInfos.SystemAcl;
306 IntPtr owner, group, dacl, sacl, descriptor;
307 int result = nativeCall (securityInfos,
308 out owner, out group, out dacl, out sacl, out descriptor);
309 if (0 != result) return result;
312 int binaryLength = 0;
313 if (IsValidSecurityDescriptor (descriptor))
314 binaryLength = GetSecurityDescriptorLength (descriptor);
316 byte[] binaryForm = new byte[binaryLength];
317 Marshal.Copy (descriptor, binaryForm, 0, binaryLength);
318 SetSecurityDescriptorBinaryForm (binaryForm, includeSections);
320 LocalFree (descriptor);
325 int Win32SetHelper (SetSecurityInfoNativeCall nativeCall,
326 AccessControlSections includeSections)
328 // SE_REGISTRY_KEY will fail UnauthorizedAccessException without this check.
329 if (AccessControlSections.None == includeSections) return 0;
331 SecurityInfos securityInfos = 0;
332 byte[] owner = null, group = null, dacl = null, sacl = null;
334 if (0 != (includeSections & AccessControlSections.Owner)) {
335 securityInfos |= SecurityInfos.Owner;
336 SecurityIdentifier ownerSid = (SecurityIdentifier)GetOwner (typeof (SecurityIdentifier));
337 if (null != ownerSid) {
338 owner = new byte[ownerSid.BinaryLength];
339 ownerSid.GetBinaryForm (owner, 0);
343 if (0 != (includeSections & AccessControlSections.Group)) {
344 securityInfos |= SecurityInfos.Group;
345 SecurityIdentifier groupSid = (SecurityIdentifier)GetGroup (typeof (SecurityIdentifier));
346 if (null != groupSid) {
347 group = new byte[groupSid.BinaryLength];
348 groupSid.GetBinaryForm (group, 0);
352 if (0 != (includeSections & AccessControlSections.Access)) {
353 securityInfos |= SecurityInfos.DiscretionaryAcl;
354 if (AreAccessRulesProtected)
355 securityInfos |= unchecked((SecurityInfos)0x80000000);
357 securityInfos |= (SecurityInfos)0x20000000;
358 dacl = new byte[descriptor.DiscretionaryAcl.BinaryLength];
359 descriptor.DiscretionaryAcl.GetBinaryForm (dacl, 0);
362 if (0 != (includeSections & AccessControlSections.Audit)) {
363 if (null != descriptor.SystemAcl) {
364 securityInfos |= SecurityInfos.SystemAcl;
365 if (AreAuditRulesProtected)
366 securityInfos |= (SecurityInfos)0x40000000;
368 securityInfos |= (SecurityInfos)0x10000000;
369 sacl = new byte[descriptor.SystemAcl.BinaryLength];
370 descriptor.SystemAcl.GetBinaryForm (sacl, 0);
374 return nativeCall (securityInfos, owner, group, dacl, sacl);
377 string Win32FixName (string name)
379 if (ResourceType == ResourceType.RegistryKey) {
380 // For (Get|Set)NamedSecurityInfo, registry paths lack the HKEY_ prefix.
381 if (!name.StartsWith ("HKEY_")) throw new InvalidOperationException ();
382 name = name.Substring ("HKEY_".Length);
389 #region Win32 P/Invokes
390 delegate int GetSecurityInfoNativeCall (SecurityInfos securityInfos,
391 out IntPtr owner, out IntPtr group, out IntPtr dacl, out IntPtr sacl,
392 out IntPtr descriptor);
394 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="GetSecurityInfo")]
395 static extern int GetSecurityInfo (SafeHandle handle, ResourceType resourceType, SecurityInfos securityInfos,
396 out IntPtr owner, out IntPtr group, out IntPtr dacl, out IntPtr sacl,
397 out IntPtr descriptor);
399 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="GetNamedSecurityInfo")]
400 static extern int GetNamedSecurityInfo (string name, ResourceType resourceType, SecurityInfos securityInfos,
401 out IntPtr owner, out IntPtr group, out IntPtr dacl, out IntPtr sacl,
402 out IntPtr descriptor);
404 [DllImport ("kernel32.dll", EntryPoint="LocalFree")]
405 static extern IntPtr LocalFree (IntPtr handle);
407 delegate int SetSecurityInfoNativeCall (SecurityInfos securityInfos,
408 byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
410 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="SetSecurityInfo")]
411 static extern int SetSecurityInfo (SafeHandle handle, ResourceType resourceType, SecurityInfos securityInfos,
412 byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
414 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="SetNamedSecurityInfo")]
415 static extern int SetNamedSecurityInfo (string name, ResourceType resourceType, SecurityInfos securityInfos,
416 byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
418 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="GetSecurityDescriptorLength")]
419 static extern int GetSecurityDescriptorLength (IntPtr descriptor);
421 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="IsValidSecurityDescriptor")]
422 [return: MarshalAs (UnmanagedType.Bool)]
423 static extern bool IsValidSecurityDescriptor (IntPtr descriptor);
425 struct SecurityDescriptor
427 public byte Revision, Size;
428 public ushort ControlFlags;
429 public IntPtr Owner, Group, Sacl, Dacl;