1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 /*============================================================
6 **
7 **
8 **
9 ** Purpose: Managed ACL wrapper for Win32 mutexes.
10 **
11 **
12 ===========================================================*/
13 
14 using System;
15 using System.Collections;
16 using System.Runtime.InteropServices;
17 using System.Security.Principal;
18 using System.Threading;
19 using Microsoft.Win32;
20 using Microsoft.Win32.SafeHandles;
21 
22 namespace System.Security.AccessControl
23 {
24     // Derive this list of values from winnt.h and MSDN docs:
25     // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/synchronization_object_security_and_access_rights.asp
26 
27     // In order to call ReleaseMutex, you must have an ACL granting you
28     // MUTEX_MODIFY_STATE rights (0x0001).  The other interesting value
29     // in a Mutex's ACL is MUTEX_ALL_ACCESS (0x1F0001).
30     // You need SYNCHRONIZE to be able to open a handle to a mutex.
31     [Flags]
32     public enum MutexRights
33     {
34         Modify = 0x000001,
35         Delete = 0x010000,
36         ReadPermissions = 0x020000,
37         ChangePermissions = 0x040000,
38         TakeOwnership = 0x080000,
39         Synchronize = 0x100000,  // SYNCHRONIZE
40         FullControl = 0x1F0001
41     }
42 
43 
44     public sealed class MutexAccessRule : AccessRule
45     {
46         // Constructor for creating access rules for registry objects
47 
MutexAccessRule(IdentityReference identity, MutexRights eventRights, AccessControlType type)48         public MutexAccessRule(IdentityReference identity, MutexRights eventRights, AccessControlType type)
49             : this(identity, (int)eventRights, false, InheritanceFlags.None, PropagationFlags.None, type)
50         {
51         }
52 
MutexAccessRule(String identity, MutexRights eventRights, AccessControlType type)53         public MutexAccessRule(String identity, MutexRights eventRights, AccessControlType type)
54             : this(new NTAccount(identity), (int)eventRights, false, InheritanceFlags.None, PropagationFlags.None, type)
55         {
56         }
57 
58         //
59         // Internal constructor to be called by public constructors
60         // and the access rule factory methods of {File|Folder}Security
61         //
MutexAccessRule( IdentityReference identity, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type)62         internal MutexAccessRule(
63             IdentityReference identity,
64             int accessMask,
65             bool isInherited,
66             InheritanceFlags inheritanceFlags,
67             PropagationFlags propagationFlags,
68             AccessControlType type)
69             : base(
70                 identity,
71                 accessMask,
72                 isInherited,
73                 inheritanceFlags,
74                 propagationFlags,
75                 type)
76         {
77         }
78 
79         public MutexRights MutexRights
80         {
81             get { return (MutexRights)base.AccessMask; }
82         }
83     }
84 
85 
86     public sealed class MutexAuditRule : AuditRule
87     {
MutexAuditRule(IdentityReference identity, MutexRights eventRights, AuditFlags flags)88         public MutexAuditRule(IdentityReference identity, MutexRights eventRights, AuditFlags flags)
89             : this(identity, (int)eventRights, false, InheritanceFlags.None, PropagationFlags.None, flags)
90         {
91         }
92 
MutexAuditRule(IdentityReference identity, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags)93         internal MutexAuditRule(IdentityReference identity, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags)
94             : base(identity, accessMask, isInherited, inheritanceFlags, propagationFlags, flags)
95         {
96         }
97 
98         public MutexRights MutexRights
99         {
100             get { return (MutexRights)base.AccessMask; }
101         }
102     }
103 
104 
105     public sealed class MutexSecurity : NativeObjectSecurity
106     {
MutexSecurity()107         public MutexSecurity()
108             : base(true, ResourceType.KernelObject)
109         {
110         }
111 
MutexSecurity(String name, AccessControlSections includeSections)112         public MutexSecurity(String name, AccessControlSections includeSections)
113             : base(true, ResourceType.KernelObject, name, includeSections, HandleErrorCode, null)
114         {
115             // Let the underlying ACL API's demand unmanaged code permission.
116         }
117 
MutexSecurity(SafeWaitHandle handle, AccessControlSections includeSections)118         internal MutexSecurity(SafeWaitHandle handle, AccessControlSections includeSections)
119             : base(true, ResourceType.KernelObject, handle, includeSections, HandleErrorCode, null)
120         {
121             // Let the underlying ACL API's demand unmanaged code permission.
122         }
123 
HandleErrorCode(int errorCode, string name, SafeHandle handle, object context)124         private static Exception HandleErrorCode(int errorCode, string name, SafeHandle handle, object context)
125         {
126             System.Exception exception = null;
127 
128             switch (errorCode)
129             {
130                 case Interop.Errors.ERROR_INVALID_NAME:
131                 case Interop.Errors.ERROR_INVALID_HANDLE:
132                 case Interop.Errors.ERROR_FILE_NOT_FOUND:
133                     if ((name != null) && (name.Length != 0))
134                         exception = new WaitHandleCannotBeOpenedException(SR.Format(SR.WaitHandleCannotBeOpenedException_InvalidHandle, name));
135                     else
136                         exception = new WaitHandleCannotBeOpenedException();
137                     break;
138             }
139 
140             return exception;
141         }
142 
AccessRuleFactory(IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type)143         public override AccessRule AccessRuleFactory(IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type)
144         {
145             return new MutexAccessRule(identityReference, accessMask, isInherited, inheritanceFlags, propagationFlags, type);
146         }
147 
AuditRuleFactory(IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags)148         public override AuditRule AuditRuleFactory(IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags)
149         {
150             return new MutexAuditRule(identityReference, accessMask, isInherited, inheritanceFlags, propagationFlags, flags);
151         }
152 
GetAccessControlSectionsFromChanges()153         internal AccessControlSections GetAccessControlSectionsFromChanges()
154         {
155             AccessControlSections persistRules = AccessControlSections.None;
156             if (AccessRulesModified)
157                 persistRules |= AccessControlSections.Access;
158             if (AuditRulesModified)
159                 persistRules |= AccessControlSections.Audit;
160             if (OwnerModified)
161                 persistRules |= AccessControlSections.Owner;
162             if (GroupModified)
163                 persistRules |= AccessControlSections.Group;
164             return persistRules;
165         }
166 
Persist(SafeWaitHandle handle)167         internal void Persist(SafeWaitHandle handle)
168         {
169             // Let the underlying ACL API's demand unmanaged code.
170 
171             WriteLock();
172 
173             try
174             {
175                 AccessControlSections persistSections = GetAccessControlSectionsFromChanges();
176                 if (persistSections == AccessControlSections.None)
177                     return;  // Don't need to persist anything.
178 
179                 base.Persist(handle, persistSections);
180                 OwnerModified = GroupModified = AuditRulesModified = AccessRulesModified = false;
181             }
182             finally
183             {
184                 WriteUnlock();
185             }
186         }
187 
AddAccessRule(MutexAccessRule rule)188         public void AddAccessRule(MutexAccessRule rule)
189         {
190             base.AddAccessRule(rule);
191         }
192 
SetAccessRule(MutexAccessRule rule)193         public void SetAccessRule(MutexAccessRule rule)
194         {
195             base.SetAccessRule(rule);
196         }
197 
ResetAccessRule(MutexAccessRule rule)198         public void ResetAccessRule(MutexAccessRule rule)
199         {
200             base.ResetAccessRule(rule);
201         }
202 
RemoveAccessRule(MutexAccessRule rule)203         public bool RemoveAccessRule(MutexAccessRule rule)
204         {
205             return base.RemoveAccessRule(rule);
206         }
207 
RemoveAccessRuleAll(MutexAccessRule rule)208         public void RemoveAccessRuleAll(MutexAccessRule rule)
209         {
210             base.RemoveAccessRuleAll(rule);
211         }
212 
RemoveAccessRuleSpecific(MutexAccessRule rule)213         public void RemoveAccessRuleSpecific(MutexAccessRule rule)
214         {
215             base.RemoveAccessRuleSpecific(rule);
216         }
217 
AddAuditRule(MutexAuditRule rule)218         public void AddAuditRule(MutexAuditRule rule)
219         {
220             base.AddAuditRule(rule);
221         }
222 
SetAuditRule(MutexAuditRule rule)223         public void SetAuditRule(MutexAuditRule rule)
224         {
225             base.SetAuditRule(rule);
226         }
227 
RemoveAuditRule(MutexAuditRule rule)228         public bool RemoveAuditRule(MutexAuditRule rule)
229         {
230             return base.RemoveAuditRule(rule);
231         }
232 
RemoveAuditRuleAll(MutexAuditRule rule)233         public void RemoveAuditRuleAll(MutexAuditRule rule)
234         {
235             base.RemoveAuditRuleAll(rule);
236         }
237 
RemoveAuditRuleSpecific(MutexAuditRule rule)238         public void RemoveAuditRuleSpecific(MutexAuditRule rule)
239         {
240             base.RemoveAuditRuleSpecific(rule);
241         }
242 
243         public override Type AccessRightType
244         {
245             get { return typeof(MutexRights); }
246         }
247 
248         public override Type AccessRuleType
249         {
250             get { return typeof(MutexAccessRule); }
251         }
252 
253         public override Type AuditRuleType
254         {
255             get { return typeof(MutexAuditRule); }
256         }
257     }
258 }
259