[sgen] Untag the vtable during concurrent mark
[mono.git] / mcs / class / corlib / System.Security.AccessControl / NativeObjectSecurity.cs
1 //
2 // System.Security.AccessControl.NativeObjectSecurity implementation
3 //
4 // Authors:
5 //      Dick Porter  <dick@ximian.com>
6 //      James Bellinger  <jfb@zer7.com>
7 //
8 // Copyright (C) 2005, 2006 Novell, Inc (http://www.novell.com)
9 // Copyright (C) 2012       James Bellinger
10 //
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:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
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.
29 //
30
31 using System;
32 using System.IO;
33 using System.Runtime.InteropServices;
34 using System.Security.Principal;
35
36 namespace System.Security.AccessControl
37 {
38         public abstract class NativeObjectSecurity : CommonObjectSecurity
39         {
40                 ExceptionFromErrorCode exception_from_error_code;
41 #if !MOBILE
42                 ResourceType resource_type;
43 #endif
44                 
45                 protected internal delegate Exception ExceptionFromErrorCode (int errorCode,
46                                                                               string name, SafeHandle handle,
47                                                                               object context);
48                 
49                 internal NativeObjectSecurity (CommonSecurityDescriptor securityDescriptor, ResourceType resourceType)
50                         : base (securityDescriptor)
51                 {
52 #if !MOBILE                     
53                         resource_type = resourceType;
54 #endif
55                 }
56
57                 protected NativeObjectSecurity (bool isContainer,
58                                                 ResourceType resourceType)
59                         : this (isContainer, resourceType, null, null)
60                 {
61                 }
62
63                 protected NativeObjectSecurity (bool isContainer,
64                                                 ResourceType resourceType,
65                                                 ExceptionFromErrorCode exceptionFromErrorCode,
66                                                 object exceptionContext)
67                         : base (isContainer)
68                 {
69                         exception_from_error_code = exceptionFromErrorCode;
70 #if !MOBILE                     
71                         resource_type = resourceType;
72 #endif
73                 }
74                 
75                 protected NativeObjectSecurity (bool isContainer,
76                                                 ResourceType resourceType,
77                                                 SafeHandle handle,
78                                                 AccessControlSections includeSections)
79                         : this (isContainer, resourceType, handle, includeSections, null, null)
80                 {
81                 }
82                 
83                 protected NativeObjectSecurity (bool isContainer,
84                                                 ResourceType resourceType,
85                                                 string name,
86                                                 AccessControlSections includeSections)
87                         : this (isContainer, resourceType, name, includeSections, null, null)
88                 {
89                 }
90                 
91                 protected NativeObjectSecurity (bool isContainer,
92                                                 ResourceType resourceType,
93                                                 SafeHandle handle,
94                                                 AccessControlSections includeSections,
95                                                 ExceptionFromErrorCode exceptionFromErrorCode,
96                                                 object exceptionContext)
97                         : this (isContainer, resourceType, exceptionFromErrorCode, exceptionContext)
98                 {
99                         RaiseExceptionOnFailure (InternalGet (handle, includeSections),
100                                                  null, handle, exceptionContext);
101                          ClearAccessControlSectionsModified ();
102                 }
103                 
104                 protected NativeObjectSecurity (bool isContainer,
105                                                 ResourceType resourceType,
106                                                 string name,
107                                                 AccessControlSections includeSections,
108                                                 ExceptionFromErrorCode exceptionFromErrorCode,
109                                                 object exceptionContext)
110                         : this (isContainer, resourceType, exceptionFromErrorCode, exceptionContext)
111                 {
112                         RaiseExceptionOnFailure (InternalGet (name, includeSections),
113                                                  name, null, exceptionContext);
114                         ClearAccessControlSectionsModified ();
115                 }
116
117                 void ClearAccessControlSectionsModified ()
118                 {
119                         WriteLock ();
120                         try {
121                                 AccessControlSectionsModified = AccessControlSections.None;
122                         } finally {
123                                 WriteUnlock ();
124                         }
125                 }
126                 
127                 protected override sealed void Persist (SafeHandle handle,
128                                                         AccessControlSections includeSections)
129                 {
130                         Persist (handle, includeSections, null);
131                 }
132                 
133                 protected override sealed void Persist (string name,
134                                                         AccessControlSections includeSections)
135                 {
136                         Persist (name, includeSections, null);
137                 }
138
139                 internal void Persist (SafeHandle handle)
140                 {
141                         PersistModifications (handle);
142                 }
143                 
144                 internal void PersistModifications (SafeHandle handle)
145                 {
146                         WriteLock();
147                         try {
148                                 Persist (handle, AccessControlSectionsModified, null);
149                         } finally {
150                                 WriteUnlock ();
151                         }
152                 }
153                 
154                 protected void Persist (SafeHandle handle,
155                                         AccessControlSections includeSections,
156                                         object exceptionContext)
157                 {
158                         WriteLock ();
159                         try {
160                                 RaiseExceptionOnFailure (InternalSet (handle, includeSections), null, handle, exceptionContext);
161                                 AccessControlSectionsModified &= ~includeSections;
162                         } finally {
163                                 WriteUnlock ();
164                         }
165                 }
166
167                 internal void PersistModifications (string name)
168                 {
169                         WriteLock();
170                         try {
171                                 Persist (name, AccessControlSectionsModified, null);
172                         } finally {
173                                 WriteUnlock ();
174                         }
175                 }
176                 
177                 protected void Persist (string name,
178                                         AccessControlSections includeSections,
179                                         object exceptionContext)
180                 {
181                         if (null == name)
182                                 throw new ArgumentNullException ("name");
183
184                         WriteLock ();
185                         try {
186                                 RaiseExceptionOnFailure (InternalSet (name, includeSections), name, null, exceptionContext);
187                                 AccessControlSectionsModified &= ~includeSections;
188                         } finally {
189                                 WriteUnlock ();
190                         }
191                 }
192                 
193                 internal static Exception DefaultExceptionFromErrorCode (int errorCode,
194                                                                          string name, SafeHandle handle,
195                                                                          object context)
196                 {
197                         switch (errorCode) {
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());
203                         }
204                 }
205                 
206                 void RaiseExceptionOnFailure (int errorCode, string name, SafeHandle handle, object context)
207                 {
208                         if (errorCode == 0) return;
209                         throw (exception_from_error_code ?? DefaultExceptionFromErrorCode)(errorCode, name, handle, context);
210                 }
211                 
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)
216                 {
217 #if MOBILE
218                         throw new PlatformNotSupportedException ();
219 #else
220                         if (Environment.OSVersion.Platform != PlatformID.Win32NT)
221                                 throw new PlatformNotSupportedException ();
222
223                         return Win32GetHelper (delegate (SecurityInfos securityInfos,
224                                                          out IntPtr owner, out IntPtr group,
225                                                          out IntPtr dacl, out IntPtr sacl, out IntPtr descriptor)
226                                 {
227                                         return GetSecurityInfo (handle, ResourceType, securityInfos,
228                                                                 out owner, out group,
229                                                                 out dacl, out sacl, out descriptor);
230                                 }, includeSections);
231 #endif
232                 }
233                 
234                 internal virtual int InternalGet (string name,
235                                                   AccessControlSections includeSections)
236                 {
237 #if MOBILE
238                         throw new PlatformNotSupportedException ();
239 #else
240                         if (Environment.OSVersion.Platform != PlatformID.Win32NT)
241                                 throw new PlatformNotSupportedException ();
242
243                         return Win32GetHelper (delegate (SecurityInfos securityInfos,
244                                                          out IntPtr owner, out IntPtr group,
245                                                          out IntPtr dacl, out IntPtr sacl, out IntPtr descriptor)
246                                 {
247                                         return GetNamedSecurityInfo (Win32FixName (name), ResourceType, securityInfos,
248                                                                      out owner, out group,
249                                                                      out dacl, out sacl, out descriptor);
250                                 }, includeSections);
251 #endif
252                 }
253                 
254 #if MOBILE
255                 internal virtual int InternalSet (SafeHandle handle, AccessControlSections includeSections)
256                 {
257                         throw new PlatformNotSupportedException ();
258                 }
259
260                 internal virtual int InternalSet (string name, AccessControlSections includeSections)
261                 {
262                         throw new PlatformNotSupportedException ();
263                 }
264 #else
265                 internal virtual int InternalSet (SafeHandle handle,
266                                                   AccessControlSections includeSections)
267                 {
268                         if (Environment.OSVersion.Platform != PlatformID.Win32NT)
269                                 throw new PlatformNotSupportedException ();
270
271                         return Win32SetHelper ((securityInfos, owner, group, dacl, sacl) =>
272                                 SetSecurityInfo (handle, ResourceType, securityInfos, owner, group, dacl, sacl),
273                                 includeSections);
274                 }
275                 
276                 internal virtual int InternalSet (string name,
277                                                   AccessControlSections includeSections)
278                 {       
279                         if (Environment.OSVersion.Platform != PlatformID.Win32NT)
280                                 throw new PlatformNotSupportedException ();
281                 
282                         return Win32SetHelper ((securityInfos, owner, group, dacl, sacl) =>
283                                 SetNamedSecurityInfo (Win32FixName (name), ResourceType, securityInfos, owner, group, dacl, sacl),
284                                 includeSections);
285                 }
286                 
287                 internal ResourceType ResourceType {
288                         get { return resource_type; }
289                 }
290                 
291                 #region Win32 Details           
292                 int Win32GetHelper (GetSecurityInfoNativeCall nativeCall,
293                                     AccessControlSections includeSections)
294                 {
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);
299                         
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;
305                         
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;
310                         
311                         try {
312                                 int binaryLength = 0;
313                                 if (IsValidSecurityDescriptor (descriptor))
314                                         binaryLength = GetSecurityDescriptorLength (descriptor);
315                                         
316                                 byte[] binaryForm = new byte[binaryLength];
317                                 Marshal.Copy (descriptor, binaryForm, 0, binaryLength);
318                                 SetSecurityDescriptorBinaryForm (binaryForm, includeSections);
319                         } finally {
320                                 LocalFree (descriptor);
321                         }
322                         return 0;
323                 }
324                 
325                 int Win32SetHelper (SetSecurityInfoNativeCall nativeCall,
326                                     AccessControlSections includeSections)
327                 {
328                         // SE_REGISTRY_KEY will fail UnauthorizedAccessException without this check.
329                         if (AccessControlSections.None == includeSections) return 0;
330                         
331                         SecurityInfos securityInfos = 0;
332                         byte[] owner = null, group = null, dacl = null, sacl = null;
333                         
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);
340                                 }
341                         }
342                         
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);
349                                 }
350                         }
351                         
352                         if (0 != (includeSections & AccessControlSections.Access)) {
353                                 securityInfos |= SecurityInfos.DiscretionaryAcl;
354                                 if (AreAccessRulesProtected)
355                                         securityInfos |= unchecked((SecurityInfos)0x80000000);
356                                 else
357                                         securityInfos |= (SecurityInfos)0x20000000;
358                                 dacl = new byte[descriptor.DiscretionaryAcl.BinaryLength];
359                                 descriptor.DiscretionaryAcl.GetBinaryForm (dacl, 0);
360                         }
361                         
362                         if (0 != (includeSections & AccessControlSections.Audit)) {
363                                 if (null != descriptor.SystemAcl) {
364                                         securityInfos |= SecurityInfos.SystemAcl;
365                                         if (AreAuditRulesProtected)
366                                                 securityInfos |= (SecurityInfos)0x40000000;
367                                         else
368                                                 securityInfos |= (SecurityInfos)0x10000000;
369                                         sacl = new byte[descriptor.SystemAcl.BinaryLength];
370                                         descriptor.SystemAcl.GetBinaryForm (sacl, 0);
371                                 }
372                         }
373                         
374                         return nativeCall (securityInfos, owner, group, dacl, sacl);
375                 }
376                 
377                 string Win32FixName (string name)
378                 {
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);
383                         }
384                         
385                         return name;
386                 }
387                 #endregion
388                 
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);
393
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);
398
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);
403                                                         
404                 [DllImport ("kernel32.dll", EntryPoint="LocalFree")]
405                 static extern IntPtr LocalFree (IntPtr handle);
406
407                 delegate int SetSecurityInfoNativeCall (SecurityInfos securityInfos,
408                                                         byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
409
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);
413                                                 
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);
417
418                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="GetSecurityDescriptorLength")]
419                 static extern int GetSecurityDescriptorLength (IntPtr descriptor);
420                 
421                 [DllImport ("advapi32.dll", CharSet=CharSet.Unicode, EntryPoint="IsValidSecurityDescriptor")]
422                 [return: MarshalAs (UnmanagedType.Bool)]
423                 static extern bool IsValidSecurityDescriptor (IntPtr descriptor);
424                 
425                 /*
426                 struct SecurityDescriptor
427                 {
428                         public byte Revision, Size;
429                         public ushort ControlFlags;
430                         public IntPtr Owner, Group, Sacl, Dacl;
431                 }
432                 */
433                 #endregion
434 #endif
435         }
436 }
437