Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / Activation / Utility.cs
1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4 namespace System.ServiceModel.Activation
5 {
6     using System;
7     using System.Collections.Generic;
8     using System.ComponentModel;
9     using System.Diagnostics;
10     using System.Globalization;
11     using System.Runtime;
12     using System.Runtime.InteropServices;
13     using System.Security;
14     using System.Security.AccessControl;
15     using System.Security.Permissions;
16     using System.Security.Principal;
17     using System.ServiceModel;
18     using System.ServiceModel.Channels;
19     using System.ServiceModel.ComIntegration;
20     using System.Text;
21
22     unsafe static class Utility
23     {
24         const string WindowsServiceAccountFormat = "NT Service\\{0}";
25
26         internal static Uri FormatListenerEndpoint(string serviceName, string listenerEndPoint)
27         {
28             UriBuilder builder = new UriBuilder(Uri.UriSchemeNetPipe, serviceName);
29             builder.Path = string.Format(CultureInfo.InvariantCulture, "/{0}/", listenerEndPoint);
30             return builder.Uri;
31         }
32
33         static SafeCloseHandle OpenCurrentProcessForWrite()
34         {
35             int processId = Process.GetCurrentProcess().Id;
36 #pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
37             SafeCloseHandle process = ListenerUnsafeNativeMethods.OpenProcess(ListenerUnsafeNativeMethods.PROCESS_QUERY_INFORMATION | ListenerUnsafeNativeMethods.WRITE_DAC | ListenerUnsafeNativeMethods.READ_CONTROL, false, processId);
38             if (process.IsInvalid)
39             {
40                 Exception exception = new Win32Exception();
41                 process.SetHandleAsInvalid();
42                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
43             }
44             return process;
45         }
46
47         static SafeCloseHandle OpenProcessForQuery(int pid)
48         {
49 #pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
50             SafeCloseHandle process = ListenerUnsafeNativeMethods.OpenProcess(ListenerUnsafeNativeMethods.PROCESS_QUERY_INFORMATION, false, pid);
51             if (process.IsInvalid)
52             {
53                 Exception exception = new Win32Exception();
54                 process.SetHandleAsInvalid();
55                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
56             }
57             return process;
58         }
59
60         static SafeCloseHandle GetProcessToken(SafeCloseHandle process, int requiredAccess)
61         {
62             SafeCloseHandle processToken;
63             bool success = ListenerUnsafeNativeMethods.OpenProcessToken(process, requiredAccess, out processToken);
64             int error = Marshal.GetLastWin32Error();
65             if (!success)
66             {
67                 System.ServiceModel.Diagnostics.Utility.CloseInvalidOutSafeHandle(processToken);
68                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error));
69             }
70
71             return processToken;
72         }
73
74         static int GetTokenInformationLength(SafeCloseHandle token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS tic)
75         {
76             int lengthNeeded;
77             bool success = ListenerUnsafeNativeMethods.GetTokenInformation(token, tic, null, 0, out lengthNeeded);
78             if (!success)
79             {
80                 int error = Marshal.GetLastWin32Error();
81                 if (error != ListenerUnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER)
82                 {
83                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error));
84                 }
85             }
86
87             return lengthNeeded;
88         }
89
90         static void GetTokenInformation(SafeCloseHandle token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS tic, byte[] tokenInformation)
91         {
92             int lengthNeeded;
93             if (!ListenerUnsafeNativeMethods.GetTokenInformation(token, tic, tokenInformation, tokenInformation.Length, out lengthNeeded))
94             {
95                 int error = Marshal.GetLastWin32Error();
96                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error));
97             }
98         }
99
100         static SafeServiceHandle OpenSCManager()
101         {
102 #pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
103             SafeServiceHandle scManager = ListenerUnsafeNativeMethods.OpenSCManager(null, null, ListenerUnsafeNativeMethods.SC_MANAGER_CONNECT);
104             if (scManager.IsInvalid)
105             {
106                 Exception exception = new Win32Exception();
107                 scManager.SetHandleAsInvalid();
108                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
109             }
110             return scManager;
111         }
112
113         static SafeServiceHandle OpenService(SafeServiceHandle scManager, string serviceName, int purpose)
114         {
115 #pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
116             SafeServiceHandle service = ListenerUnsafeNativeMethods.OpenService(scManager, serviceName, purpose);
117             if (service.IsInvalid)
118             {
119                 Exception exception = new Win32Exception();
120                 service.SetHandleAsInvalid();
121                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
122             }
123             return service;
124         }
125
126         internal static void AddRightGrantedToAccounts(List<SecurityIdentifier> accounts, int right, bool onProcess)
127         {
128             SafeCloseHandle process = OpenCurrentProcessForWrite();
129             try
130             {
131                 if (onProcess)
132                 {
133                     EditKernelObjectSecurity(process, accounts, null, right, true);
134                 }
135                 else
136                 {
137                     SafeCloseHandle token = GetProcessToken(process, ListenerUnsafeNativeMethods.TOKEN_QUERY | ListenerUnsafeNativeMethods.WRITE_DAC | ListenerUnsafeNativeMethods.READ_CONTROL);
138                     try
139                     {
140                         EditKernelObjectSecurity(token, accounts, null, right, true);
141                     }
142                     finally
143                     {
144                         token.Close();
145                     }
146                 }
147             }
148             finally
149             {
150                 process.Close();
151             }
152         }
153
154         internal static void AddRightGrantedToAccount(SecurityIdentifier account, int right)
155         {
156             SafeCloseHandle process = OpenCurrentProcessForWrite();
157             try
158             {
159                 EditKernelObjectSecurity(process, null, account, right, true);
160             }
161             finally
162             {
163                 process.Close();
164             }
165         }
166
167         internal static void RemoveRightGrantedToAccount(SecurityIdentifier account, int right)
168         {
169             SafeCloseHandle process = OpenCurrentProcessForWrite();
170             try
171             {
172                 EditKernelObjectSecurity(process, null, account, right, false);
173             }
174             finally
175             {
176                 process.Close();
177             }
178         }
179
180         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
181         internal static void KeepOnlyPrivilegeInProcess(string privilege)
182         {
183             SafeCloseHandle process = OpenCurrentProcessForWrite();
184             try
185             {
186                 SafeCloseHandle token = GetProcessToken(process, ListenerUnsafeNativeMethods.TOKEN_QUERY | ListenerUnsafeNativeMethods.TOKEN_ADJUST_PRIVILEGES | ListenerUnsafeNativeMethods.READ_CONTROL);
187                 try
188                 {
189                     LUID luid;
190                     bool success = ListenerUnsafeNativeMethods.LookupPrivilegeValue(IntPtr.Zero, privilege, &luid);
191                     if (!success)
192                     {
193                         int error = Marshal.GetLastWin32Error();
194                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error));
195                     }
196
197                     int length = GetTokenInformationLength(token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS.TokenPrivileges);
198                     byte[] tokenInformation = new byte[length];
199                     fixed (byte* pTokenPrivileges = tokenInformation)
200                     {
201                         GetTokenInformation(token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS.TokenPrivileges,
202                             tokenInformation);
203
204                         ListenerUnsafeNativeMethods.TOKEN_PRIVILEGES* pTP = (ListenerUnsafeNativeMethods.TOKEN_PRIVILEGES*)pTokenPrivileges;
205                         LUID_AND_ATTRIBUTES* pLuidAndAttributes = (LUID_AND_ATTRIBUTES*)(&(pTP->Privileges));
206                         int privilegeCount = 0;
207                         for (int i = 0; i < pTP->PrivilegeCount; i++)
208                         {
209                             if (!pLuidAndAttributes[i].Luid.Equals(luid))
210                             {
211                                 pLuidAndAttributes[privilegeCount].Attributes = PrivilegeAttribute.SE_PRIVILEGE_REMOVED;
212                                 pLuidAndAttributes[privilegeCount].Luid = pLuidAndAttributes[i].Luid;
213                                 privilegeCount++;
214                             }
215                         }
216                         pTP->PrivilegeCount = privilegeCount;
217
218                         success = ListenerUnsafeNativeMethods.AdjustTokenPrivileges(token, false, pTP, tokenInformation.Length, IntPtr.Zero, IntPtr.Zero);
219                         int error = Marshal.GetLastWin32Error();
220                         if (!success || error != UnsafeNativeMethods.ERROR_SUCCESS)
221                         {
222                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error));
223                         }
224                     }
225                 }
226                 finally
227                 {
228                     token.Close();
229                 }
230             }
231             finally
232             {
233                 process.Close();
234             }
235         }
236
237         // Do not use this method unless you understand the consequnces of lack of synchronization
238         static void EditKernelObjectSecurity(SafeCloseHandle kernelObject, List<SecurityIdentifier> accounts, SecurityIdentifier account, int right, bool add)
239         {
240             // take the SECURITY_DESCRIPTOR from the kernelObject
241             int lpnLengthNeeded;
242             bool success = ListenerUnsafeNativeMethods.GetKernelObjectSecurity(kernelObject, ListenerUnsafeNativeMethods.DACL_SECURITY_INFORMATION, null, 0, out lpnLengthNeeded);
243             if (!success)
244             {
245                 int errorCode = Marshal.GetLastWin32Error();
246                 if (errorCode != ListenerUnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER)
247                 {
248                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
249                 }
250             }
251             byte[] pSecurityDescriptor = new byte[lpnLengthNeeded];
252 #pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
253             success = ListenerUnsafeNativeMethods.GetKernelObjectSecurity(kernelObject, ListenerUnsafeNativeMethods.DACL_SECURITY_INFORMATION, pSecurityDescriptor, pSecurityDescriptor.Length, out lpnLengthNeeded);
254             if (!success)
255             {
256                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception());
257             }
258             CommonSecurityDescriptor securityDescriptor = new CommonSecurityDescriptor(false, false, pSecurityDescriptor, 0);
259             DiscretionaryAcl dacl = securityDescriptor.DiscretionaryAcl;
260             // add ACEs to the SECURITY_DESCRIPTOR of the kernelObject
261             if (account != null)
262             {
263                 EditDacl(dacl, account, right, add);
264             }
265             else if (accounts != null)
266             {
267                 foreach (SecurityIdentifier accountInList in accounts)
268                 {
269                     EditDacl(dacl, accountInList, right, add);
270                 }
271             }
272             lpnLengthNeeded = securityDescriptor.BinaryLength;
273             pSecurityDescriptor = new byte[lpnLengthNeeded];
274             securityDescriptor.GetBinaryForm(pSecurityDescriptor, 0);
275             // set the SECURITY_DESCRIPTOR on the kernelObject
276 #pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
277             success = ListenerUnsafeNativeMethods.SetKernelObjectSecurity(kernelObject, ListenerUnsafeNativeMethods.DACL_SECURITY_INFORMATION, pSecurityDescriptor);
278             if (!success)
279             {
280                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception());
281             }
282         }
283
284         static void EditDacl(DiscretionaryAcl dacl, SecurityIdentifier account, int right, bool add)
285         {
286             if (add)
287             {
288                 dacl.AddAccess(AccessControlType.Allow, account, right, InheritanceFlags.None, PropagationFlags.None);
289             }
290             else
291             {
292                 dacl.RemoveAccess(AccessControlType.Allow, account, right, InheritanceFlags.None, PropagationFlags.None);
293             }
294         }
295
296         internal static SecurityIdentifier GetWindowsServiceSid(string name)
297         {
298             Fx.Assert(OSEnvironmentHelper.IsVistaOrGreater, "This method can be called only on Vista or greater.");
299             string accountName = string.Format(CultureInfo.InvariantCulture, WindowsServiceAccountFormat, name);
300
301             byte[] sid = null;
302             uint cbSid = 0;
303             uint cchReferencedDomainName = 0;
304             short peUse;
305             int error = UnsafeNativeMethods.ERROR_SUCCESS;
306             if (!ListenerUnsafeNativeMethods.LookupAccountName(null, accountName, sid, ref cbSid,
307                 null, ref cchReferencedDomainName, out peUse))
308             {
309                 error = Marshal.GetLastWin32Error();
310                 if (error != ListenerUnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER)
311                 {
312                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error));
313                 }
314             }
315
316             sid = new byte[cbSid];
317             StringBuilder referencedDomainName = new StringBuilder((int)cchReferencedDomainName);
318             if (!ListenerUnsafeNativeMethods.LookupAccountName(null, accountName, sid, ref cbSid,
319                 referencedDomainName, ref cchReferencedDomainName, out peUse))
320             {
321                 error = Marshal.GetLastWin32Error();
322                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error));
323             }
324
325             return new SecurityIdentifier(sid, 0);
326         }
327
328         internal static int GetPidForService(string serviceName)
329         {
330             return GetStatusForService(serviceName).dwProcessId;
331         }
332
333         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
334         internal static SecurityIdentifier GetLogonSidForPid(int pid)
335         {
336             SafeCloseHandle process = OpenProcessForQuery(pid);
337             try
338             {
339                 SafeCloseHandle token = GetProcessToken(process, ListenerUnsafeNativeMethods.TOKEN_QUERY);
340                 try
341                 {
342                     int length = GetTokenInformationLength(token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS.TokenGroups);
343                     byte[] tokenInformation = new byte[length];
344                     fixed (byte* pTokenInformation = tokenInformation)
345                     {
346                         GetTokenInformation(token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS.TokenGroups, tokenInformation);
347
348                         ListenerUnsafeNativeMethods.TOKEN_GROUPS* ptg = (ListenerUnsafeNativeMethods.TOKEN_GROUPS*)pTokenInformation;
349                         ListenerUnsafeNativeMethods.SID_AND_ATTRIBUTES* sids = (ListenerUnsafeNativeMethods.SID_AND_ATTRIBUTES*)(&(ptg->Groups));
350                         for (int i = 0; i < ptg->GroupCount; i++)
351                         {
352                             if ((sids[i].Attributes & ListenerUnsafeNativeMethods.SidAttribute.SE_GROUP_LOGON_ID) == ListenerUnsafeNativeMethods.SidAttribute.SE_GROUP_LOGON_ID)
353                             {
354                                 return new SecurityIdentifier(sids[i].Sid);
355                             }
356                         }
357                     }
358                     return new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null);
359                 }
360                 finally
361                 {
362                     token.Close();
363                 }
364             }
365             finally
366             {
367                 process.Close();
368             }
369         }
370
371         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
372         internal static SecurityIdentifier GetUserSidForPid(int pid)
373         {
374             SafeCloseHandle process = OpenProcessForQuery(pid);
375             try
376             {
377                 SafeCloseHandle token = GetProcessToken(process, ListenerUnsafeNativeMethods.TOKEN_QUERY);
378                 try
379                 {
380                     int length = GetTokenInformationLength(token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS.TokenUser);
381                     byte[] tokenInformation = new byte[length];
382                     fixed (byte* pTokenInformation = tokenInformation)
383                     {
384                         GetTokenInformation(token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS.TokenUser, tokenInformation);
385
386                         ListenerUnsafeNativeMethods.TOKEN_USER* ptg = (ListenerUnsafeNativeMethods.TOKEN_USER*)pTokenInformation;
387                         ListenerUnsafeNativeMethods.SID_AND_ATTRIBUTES* sids = (ListenerUnsafeNativeMethods.SID_AND_ATTRIBUTES*)(&(ptg->User));
388                         return new SecurityIdentifier(sids->Sid);
389                     }
390                 }
391                 finally
392                 {
393                     token.Close();
394                 }
395             }
396             finally
397             {
398                 process.Close();
399             }
400         }
401
402         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
403         static ListenerUnsafeNativeMethods.SERVICE_STATUS_PROCESS GetStatusForService(string serviceName)
404         {
405             SafeServiceHandle scManager = OpenSCManager();
406             try
407             {
408                 SafeServiceHandle service = OpenService(scManager, serviceName, ListenerUnsafeNativeMethods.SERVICE_QUERY_STATUS);
409                 try
410                 {
411                     int lpnLengthNeeded;
412                     bool success = ListenerUnsafeNativeMethods.QueryServiceStatusEx(service, ListenerUnsafeNativeMethods.SC_STATUS_PROCESS_INFO, null, 0, out lpnLengthNeeded);
413                     if (!success)
414                     {
415                         int errorCode = Marshal.GetLastWin32Error();
416                         if (errorCode != ListenerUnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER)
417                         {
418                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
419                         }
420                     }
421                     byte[] serviceStatusProcess = new byte[lpnLengthNeeded];
422 #pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
423                     success = ListenerUnsafeNativeMethods.QueryServiceStatusEx(service, ListenerUnsafeNativeMethods.SC_STATUS_PROCESS_INFO, serviceStatusProcess, serviceStatusProcess.Length, out lpnLengthNeeded);
424                     if (!success)
425                     {
426                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception());
427                     }
428                     fixed (byte* pServiceStatusProcess = serviceStatusProcess)
429                     {
430                         return (ListenerUnsafeNativeMethods.SERVICE_STATUS_PROCESS)Marshal.PtrToStructure((IntPtr)pServiceStatusProcess, typeof(ListenerUnsafeNativeMethods.SERVICE_STATUS_PROCESS));
431                     }
432                 }
433                 finally
434                 {
435                     service.Close();
436                 }
437             }
438             finally
439             {
440                 scManager.Close();
441             }
442         }
443     }
444 }