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)
207 throw new PlatformNotSupportedException ();
209 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
210 throw new PlatformNotSupportedException ();
212 return Win32GetHelper (delegate (SecurityInfos securityInfos,
213 out IntPtr owner, out IntPtr group,
214 out IntPtr dacl, out IntPtr sacl, out IntPtr descriptor)
216 return GetSecurityInfo (handle, ResourceType, securityInfos,
217 out owner, out group,
218 out dacl, out sacl, out descriptor);
223 internal virtual int InternalGet (string name,
224 AccessControlSections includeSections)
227 throw new PlatformNotSupportedException ();
229 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
230 throw new PlatformNotSupportedException ();
232 return Win32GetHelper (delegate (SecurityInfos securityInfos,
233 out IntPtr owner, out IntPtr group,
234 out IntPtr dacl, out IntPtr sacl, out IntPtr descriptor)
236 return GetNamedSecurityInfo (Win32FixName (name), ResourceType, securityInfos,
237 out owner, out group,
238 out dacl, out sacl, out descriptor);
244 internal virtual int InternalSet (SafeHandle handle, AccessControlSections includeSections)
246 throw new PlatformNotSupportedException ();
249 internal virtual int InternalSet (string name, AccessControlSections includeSections)
251 throw new PlatformNotSupportedException ();
254 internal virtual int InternalSet (SafeHandle handle,
255 AccessControlSections includeSections)
257 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
258 throw new PlatformNotSupportedException ();
260 return Win32SetHelper ((securityInfos, owner, group, dacl, sacl) =>
261 SetSecurityInfo (handle, ResourceType, securityInfos, owner, group, dacl, sacl),
265 internal virtual int InternalSet (string name,
266 AccessControlSections includeSections)
268 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
269 throw new PlatformNotSupportedException ();
271 return Win32SetHelper ((securityInfos, owner, group, dacl, sacl) =>
272 SetNamedSecurityInfo (Win32FixName (name), ResourceType, securityInfos, owner, group, dacl, sacl),
276 internal ResourceType ResourceType {
277 get { return resource_type; }
280 #region Win32 Details
281 int Win32GetHelper (GetSecurityInfoNativeCall nativeCall,
282 AccessControlSections includeSections)
284 bool getOwner = 0 != (includeSections & AccessControlSections.Owner);
285 bool getGroup = 0 != (includeSections & AccessControlSections.Group);
286 bool getDacl = 0 != (includeSections & AccessControlSections.Access);
287 bool getSacl = 0 != (includeSections & AccessControlSections.Audit);
289 SecurityInfos securityInfos = 0;
290 if (getOwner) securityInfos |= SecurityInfos.Owner;
291 if (getGroup) securityInfos |= SecurityInfos.Group;
292 if (getDacl ) securityInfos |= SecurityInfos.DiscretionaryAcl;
293 if (getSacl ) securityInfos |= SecurityInfos.SystemAcl;
295 IntPtr owner, group, dacl, sacl, descriptor;
296 int result = nativeCall (securityInfos,
297 out owner, out group, out dacl, out sacl, out descriptor);
298 if (0 != result) return result;
301 int binaryLength = 0;
302 if (IsValidSecurityDescriptor (descriptor))
303 binaryLength = GetSecurityDescriptorLength (descriptor);
305 byte[] binaryForm = new byte[binaryLength];
306 Marshal.Copy (descriptor, binaryForm, 0, binaryLength);
307 SetSecurityDescriptorBinaryForm (binaryForm, includeSections);
309 LocalFree (descriptor);
314 int Win32SetHelper (SetSecurityInfoNativeCall nativeCall,
315 AccessControlSections includeSections)
317 // SE_REGISTRY_KEY will fail UnauthorizedAccessException without this check.
318 if (AccessControlSections.None == includeSections) return 0;
320 SecurityInfos securityInfos = 0;
321 byte[] owner = null, group = null, dacl = null, sacl = null;
323 if (0 != (includeSections & AccessControlSections.Owner)) {
324 securityInfos |= SecurityInfos.Owner;
325 SecurityIdentifier ownerSid = (SecurityIdentifier)GetOwner (typeof (SecurityIdentifier));
326 if (null != ownerSid) {
327 owner = new byte[ownerSid.BinaryLength];
328 ownerSid.GetBinaryForm (owner, 0);
332 if (0 != (includeSections & AccessControlSections.Group)) {
333 securityInfos |= SecurityInfos.Group;
334 SecurityIdentifier groupSid = (SecurityIdentifier)GetGroup (typeof (SecurityIdentifier));
335 if (null != groupSid) {
336 group = new byte[groupSid.BinaryLength];
337 groupSid.GetBinaryForm (group, 0);
341 if (0 != (includeSections & AccessControlSections.Access)) {
342 securityInfos |= SecurityInfos.DiscretionaryAcl;
343 if (AreAccessRulesProtected)
344 securityInfos |= unchecked((SecurityInfos)0x80000000);
346 securityInfos |= (SecurityInfos)0x20000000;
347 dacl = new byte[descriptor.DiscretionaryAcl.BinaryLength];
348 descriptor.DiscretionaryAcl.GetBinaryForm (dacl, 0);
351 if (0 != (includeSections & AccessControlSections.Audit)) {
352 if (null != descriptor.SystemAcl) {
353 securityInfos |= SecurityInfos.SystemAcl;
354 if (AreAuditRulesProtected)
355 securityInfos |= (SecurityInfos)0x40000000;
357 securityInfos |= (SecurityInfos)0x10000000;
358 sacl = new byte[descriptor.SystemAcl.BinaryLength];
359 descriptor.SystemAcl.GetBinaryForm (sacl, 0);
363 return nativeCall (securityInfos, owner, group, dacl, sacl);
366 string Win32FixName (string name)
368 if (ResourceType == ResourceType.RegistryKey) {
369 // For (Get|Set)NamedSecurityInfo, registry paths lack the HKEY_ prefix.
370 if (!name.StartsWith ("HKEY_")) throw new InvalidOperationException ();
371 name = name.Substring ("HKEY_".Length);
378 #region Win32 P/Invokes
379 delegate int GetSecurityInfoNativeCall (SecurityInfos securityInfos,
380 out IntPtr owner, out IntPtr group, out IntPtr dacl, out IntPtr sacl,
381 out IntPtr descriptor);
383 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="GetSecurityInfo")]
384 static extern int GetSecurityInfo (SafeHandle handle, ResourceType resourceType, 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="GetNamedSecurityInfo")]
389 static extern int GetNamedSecurityInfo (string name, ResourceType resourceType, SecurityInfos securityInfos,
390 out IntPtr owner, out IntPtr group, out IntPtr dacl, out IntPtr sacl,
391 out IntPtr descriptor);
393 [DllImport ("kernel32.dll", EntryPoint="LocalFree")]
394 static extern IntPtr LocalFree (IntPtr handle);
396 delegate int SetSecurityInfoNativeCall (SecurityInfos securityInfos,
397 byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
399 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="SetSecurityInfo")]
400 static extern int SetSecurityInfo (SafeHandle handle, ResourceType resourceType, SecurityInfos securityInfos,
401 byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
403 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="SetNamedSecurityInfo")]
404 static extern int SetNamedSecurityInfo (string name, ResourceType resourceType, SecurityInfos securityInfos,
405 byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
407 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="GetSecurityDescriptorLength")]
408 static extern int GetSecurityDescriptorLength (IntPtr descriptor);
410 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="IsValidSecurityDescriptor")]
411 [return: MarshalAs (UnmanagedType.Bool)]
412 static extern bool IsValidSecurityDescriptor (IntPtr descriptor);
414 struct SecurityDescriptor
416 public byte Revision, Size;
417 public ushort ControlFlags;
418 public IntPtr Owner, Group, Sacl, Dacl;