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 PersistModifications (SafeHandle handle)
143 Persist (handle, AccessControlSectionsModified, null);
149 protected void Persist (SafeHandle handle,
150 AccessControlSections includeSections,
151 object exceptionContext)
155 RaiseExceptionOnFailure (InternalSet (handle, includeSections), null, handle, exceptionContext);
156 AccessControlSectionsModified &= ~includeSections;
162 internal void PersistModifications (string name)
166 Persist (name, AccessControlSectionsModified, null);
172 protected void Persist (string name,
173 AccessControlSections includeSections,
174 object exceptionContext)
177 throw new ArgumentNullException ("name");
181 RaiseExceptionOnFailure (InternalSet (name, includeSections), name, null, exceptionContext);
182 AccessControlSectionsModified &= ~includeSections;
188 internal static Exception DefaultExceptionFromErrorCode (int errorCode,
189 string name, SafeHandle handle,
193 case 2: return new FileNotFoundException ();
194 case 3: return new DirectoryNotFoundException ();
195 case 5: return new UnauthorizedAccessException ();
196 case 1314: return new PrivilegeNotHeldException (); // happens with audit rules
197 default: return new InvalidOperationException ("OS error code " + errorCode.ToString());
201 void RaiseExceptionOnFailure (int errorCode, string name, SafeHandle handle, object context)
203 if (errorCode == 0) return;
204 throw (exception_from_error_code ?? DefaultExceptionFromErrorCode)(errorCode, name, handle, context);
207 // InternalGet/InternalSet are virtual so that non-Windows platforms which do not share an
208 // API between files, mutexes, etc. can override in the subclass and do their own thing.
209 internal virtual int InternalGet (SafeHandle handle,
210 AccessControlSections includeSections)
213 throw new PlatformNotSupportedException ();
215 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
216 throw new PlatformNotSupportedException ();
218 return Win32GetHelper (delegate (SecurityInfos securityInfos,
219 out IntPtr owner, out IntPtr group,
220 out IntPtr dacl, out IntPtr sacl, out IntPtr descriptor)
222 return GetSecurityInfo (handle, ResourceType, securityInfos,
223 out owner, out group,
224 out dacl, out sacl, out descriptor);
229 internal virtual int InternalGet (string name,
230 AccessControlSections includeSections)
233 throw new PlatformNotSupportedException ();
235 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
236 throw new PlatformNotSupportedException ();
238 return Win32GetHelper (delegate (SecurityInfos securityInfos,
239 out IntPtr owner, out IntPtr group,
240 out IntPtr dacl, out IntPtr sacl, out IntPtr descriptor)
242 return GetNamedSecurityInfo (Win32FixName (name), ResourceType, securityInfos,
243 out owner, out group,
244 out dacl, out sacl, out descriptor);
250 internal virtual int InternalSet (SafeHandle handle, AccessControlSections includeSections)
252 throw new PlatformNotSupportedException ();
255 internal virtual int InternalSet (string name, AccessControlSections includeSections)
257 throw new PlatformNotSupportedException ();
260 internal virtual int InternalSet (SafeHandle handle,
261 AccessControlSections includeSections)
263 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
264 throw new PlatformNotSupportedException ();
266 return Win32SetHelper ((securityInfos, owner, group, dacl, sacl) =>
267 SetSecurityInfo (handle, ResourceType, securityInfos, owner, group, dacl, sacl),
271 internal virtual int InternalSet (string name,
272 AccessControlSections includeSections)
274 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
275 throw new PlatformNotSupportedException ();
277 return Win32SetHelper ((securityInfos, owner, group, dacl, sacl) =>
278 SetNamedSecurityInfo (Win32FixName (name), ResourceType, securityInfos, owner, group, dacl, sacl),
282 internal ResourceType ResourceType {
283 get { return resource_type; }
286 #region Win32 Details
287 int Win32GetHelper (GetSecurityInfoNativeCall nativeCall,
288 AccessControlSections includeSections)
290 bool getOwner = 0 != (includeSections & AccessControlSections.Owner);
291 bool getGroup = 0 != (includeSections & AccessControlSections.Group);
292 bool getDacl = 0 != (includeSections & AccessControlSections.Access);
293 bool getSacl = 0 != (includeSections & AccessControlSections.Audit);
295 SecurityInfos securityInfos = 0;
296 if (getOwner) securityInfos |= SecurityInfos.Owner;
297 if (getGroup) securityInfos |= SecurityInfos.Group;
298 if (getDacl ) securityInfos |= SecurityInfos.DiscretionaryAcl;
299 if (getSacl ) securityInfos |= SecurityInfos.SystemAcl;
301 IntPtr owner, group, dacl, sacl, descriptor;
302 int result = nativeCall (securityInfos,
303 out owner, out group, out dacl, out sacl, out descriptor);
304 if (0 != result) return result;
307 int binaryLength = 0;
308 if (IsValidSecurityDescriptor (descriptor))
309 binaryLength = GetSecurityDescriptorLength (descriptor);
311 byte[] binaryForm = new byte[binaryLength];
312 Marshal.Copy (descriptor, binaryForm, 0, binaryLength);
313 SetSecurityDescriptorBinaryForm (binaryForm, includeSections);
315 LocalFree (descriptor);
320 int Win32SetHelper (SetSecurityInfoNativeCall nativeCall,
321 AccessControlSections includeSections)
323 // SE_REGISTRY_KEY will fail UnauthorizedAccessException without this check.
324 if (AccessControlSections.None == includeSections) return 0;
326 SecurityInfos securityInfos = 0;
327 byte[] owner = null, group = null, dacl = null, sacl = null;
329 if (0 != (includeSections & AccessControlSections.Owner)) {
330 securityInfos |= SecurityInfos.Owner;
331 SecurityIdentifier ownerSid = (SecurityIdentifier)GetOwner (typeof (SecurityIdentifier));
332 if (null != ownerSid) {
333 owner = new byte[ownerSid.BinaryLength];
334 ownerSid.GetBinaryForm (owner, 0);
338 if (0 != (includeSections & AccessControlSections.Group)) {
339 securityInfos |= SecurityInfos.Group;
340 SecurityIdentifier groupSid = (SecurityIdentifier)GetGroup (typeof (SecurityIdentifier));
341 if (null != groupSid) {
342 group = new byte[groupSid.BinaryLength];
343 groupSid.GetBinaryForm (group, 0);
347 if (0 != (includeSections & AccessControlSections.Access)) {
348 securityInfos |= SecurityInfos.DiscretionaryAcl;
349 if (AreAccessRulesProtected)
350 securityInfos |= unchecked((SecurityInfos)0x80000000);
352 securityInfos |= (SecurityInfos)0x20000000;
353 dacl = new byte[descriptor.DiscretionaryAcl.BinaryLength];
354 descriptor.DiscretionaryAcl.GetBinaryForm (dacl, 0);
357 if (0 != (includeSections & AccessControlSections.Audit)) {
358 if (null != descriptor.SystemAcl) {
359 securityInfos |= SecurityInfos.SystemAcl;
360 if (AreAuditRulesProtected)
361 securityInfos |= (SecurityInfos)0x40000000;
363 securityInfos |= (SecurityInfos)0x10000000;
364 sacl = new byte[descriptor.SystemAcl.BinaryLength];
365 descriptor.SystemAcl.GetBinaryForm (sacl, 0);
369 return nativeCall (securityInfos, owner, group, dacl, sacl);
372 string Win32FixName (string name)
374 if (ResourceType == ResourceType.RegistryKey) {
375 // For (Get|Set)NamedSecurityInfo, registry paths lack the HKEY_ prefix.
376 if (!name.StartsWith ("HKEY_")) throw new InvalidOperationException ();
377 name = name.Substring ("HKEY_".Length);
384 #region Win32 P/Invokes
385 delegate int GetSecurityInfoNativeCall (SecurityInfos securityInfos,
386 out IntPtr owner, out IntPtr group, out IntPtr dacl, out IntPtr sacl,
387 out IntPtr descriptor);
389 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="GetSecurityInfo")]
390 static extern int GetSecurityInfo (SafeHandle handle, ResourceType resourceType, 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="GetNamedSecurityInfo")]
395 static extern int GetNamedSecurityInfo (string name, ResourceType resourceType, SecurityInfos securityInfos,
396 out IntPtr owner, out IntPtr group, out IntPtr dacl, out IntPtr sacl,
397 out IntPtr descriptor);
399 [DllImport ("kernel32.dll", EntryPoint="LocalFree")]
400 static extern IntPtr LocalFree (IntPtr handle);
402 delegate int SetSecurityInfoNativeCall (SecurityInfos securityInfos,
403 byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
405 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="SetSecurityInfo")]
406 static extern int SetSecurityInfo (SafeHandle handle, ResourceType resourceType, SecurityInfos securityInfos,
407 byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
409 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="SetNamedSecurityInfo")]
410 static extern int SetNamedSecurityInfo (string name, ResourceType resourceType, SecurityInfos securityInfos,
411 byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
413 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="GetSecurityDescriptorLength")]
414 static extern int GetSecurityDescriptorLength (IntPtr descriptor);
416 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="IsValidSecurityDescriptor")]
417 [return: MarshalAs (UnmanagedType.Bool)]
418 static extern bool IsValidSecurityDescriptor (IntPtr descriptor);
421 struct SecurityDescriptor
423 public byte Revision, Size;
424 public ushort ControlFlags;
425 public IntPtr Owner, Group, Sacl, Dacl;