1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //-----------------------------------------------------------------------------
4 namespace System.ServiceModel.Activation
7 using System.Collections.Generic;
8 using System.ComponentModel;
9 using System.Diagnostics;
10 using System.Globalization;
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;
22 unsafe static class Utility
24 const string WindowsServiceAccountFormat = "NT Service\\{0}";
26 internal static Uri FormatListenerEndpoint(string serviceName, string listenerEndPoint)
28 UriBuilder builder = new UriBuilder(Uri.UriSchemeNetPipe, serviceName);
29 builder.Path = string.Format(CultureInfo.InvariantCulture, "/{0}/", listenerEndPoint);
33 static SafeCloseHandle OpenCurrentProcessForWrite()
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)
40 Exception exception = new Win32Exception();
41 process.SetHandleAsInvalid();
42 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
47 static SafeCloseHandle OpenProcessForQuery(int pid)
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)
53 Exception exception = new Win32Exception();
54 process.SetHandleAsInvalid();
55 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
60 static SafeCloseHandle GetProcessToken(SafeCloseHandle process, int requiredAccess)
62 SafeCloseHandle processToken;
63 bool success = ListenerUnsafeNativeMethods.OpenProcessToken(process, requiredAccess, out processToken);
64 int error = Marshal.GetLastWin32Error();
67 System.ServiceModel.Diagnostics.Utility.CloseInvalidOutSafeHandle(processToken);
68 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error));
74 static int GetTokenInformationLength(SafeCloseHandle token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS tic)
77 bool success = ListenerUnsafeNativeMethods.GetTokenInformation(token, tic, null, 0, out lengthNeeded);
80 int error = Marshal.GetLastWin32Error();
81 if (error != ListenerUnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER)
83 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error));
90 static void GetTokenInformation(SafeCloseHandle token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS tic, byte[] tokenInformation)
93 if (!ListenerUnsafeNativeMethods.GetTokenInformation(token, tic, tokenInformation, tokenInformation.Length, out lengthNeeded))
95 int error = Marshal.GetLastWin32Error();
96 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error));
100 static SafeServiceHandle OpenSCManager()
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)
106 Exception exception = new Win32Exception();
107 scManager.SetHandleAsInvalid();
108 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
113 static SafeServiceHandle OpenService(SafeServiceHandle scManager, string serviceName, int purpose)
115 #pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
116 SafeServiceHandle service = ListenerUnsafeNativeMethods.OpenService(scManager, serviceName, purpose);
117 if (service.IsInvalid)
119 Exception exception = new Win32Exception();
120 service.SetHandleAsInvalid();
121 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
126 internal static void AddRightGrantedToAccounts(List<SecurityIdentifier> accounts, int right, bool onProcess)
128 SafeCloseHandle process = OpenCurrentProcessForWrite();
133 EditKernelObjectSecurity(process, accounts, null, right, true);
137 SafeCloseHandle token = GetProcessToken(process, ListenerUnsafeNativeMethods.TOKEN_QUERY | ListenerUnsafeNativeMethods.WRITE_DAC | ListenerUnsafeNativeMethods.READ_CONTROL);
140 EditKernelObjectSecurity(token, accounts, null, right, true);
154 internal static void AddRightGrantedToAccount(SecurityIdentifier account, int right)
156 SafeCloseHandle process = OpenCurrentProcessForWrite();
159 EditKernelObjectSecurity(process, null, account, right, true);
167 internal static void RemoveRightGrantedToAccount(SecurityIdentifier account, int right)
169 SafeCloseHandle process = OpenCurrentProcessForWrite();
172 EditKernelObjectSecurity(process, null, account, right, false);
180 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
181 internal static void KeepOnlyPrivilegeInProcess(string privilege)
183 SafeCloseHandle process = OpenCurrentProcessForWrite();
186 SafeCloseHandle token = GetProcessToken(process, ListenerUnsafeNativeMethods.TOKEN_QUERY | ListenerUnsafeNativeMethods.TOKEN_ADJUST_PRIVILEGES | ListenerUnsafeNativeMethods.READ_CONTROL);
190 bool success = ListenerUnsafeNativeMethods.LookupPrivilegeValue(IntPtr.Zero, privilege, &luid);
193 int error = Marshal.GetLastWin32Error();
194 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error));
197 int length = GetTokenInformationLength(token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS.TokenPrivileges);
198 byte[] tokenInformation = new byte[length];
199 fixed (byte* pTokenPrivileges = tokenInformation)
201 GetTokenInformation(token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS.TokenPrivileges,
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++)
209 if (!pLuidAndAttributes[i].Luid.Equals(luid))
211 pLuidAndAttributes[privilegeCount].Attributes = PrivilegeAttribute.SE_PRIVILEGE_REMOVED;
212 pLuidAndAttributes[privilegeCount].Luid = pLuidAndAttributes[i].Luid;
216 pTP->PrivilegeCount = privilegeCount;
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)
222 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error));
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)
240 // take the SECURITY_DESCRIPTOR from the kernelObject
242 bool success = ListenerUnsafeNativeMethods.GetKernelObjectSecurity(kernelObject, ListenerUnsafeNativeMethods.DACL_SECURITY_INFORMATION, null, 0, out lpnLengthNeeded);
245 int errorCode = Marshal.GetLastWin32Error();
246 if (errorCode != ListenerUnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER)
248 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
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);
256 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception());
258 CommonSecurityDescriptor securityDescriptor = new CommonSecurityDescriptor(false, false, pSecurityDescriptor, 0);
259 DiscretionaryAcl dacl = securityDescriptor.DiscretionaryAcl;
260 // add ACEs to the SECURITY_DESCRIPTOR of the kernelObject
263 EditDacl(dacl, account, right, add);
265 else if (accounts != null)
267 foreach (SecurityIdentifier accountInList in accounts)
269 EditDacl(dacl, accountInList, right, add);
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);
280 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception());
284 static void EditDacl(DiscretionaryAcl dacl, SecurityIdentifier account, int right, bool add)
288 dacl.AddAccess(AccessControlType.Allow, account, right, InheritanceFlags.None, PropagationFlags.None);
292 dacl.RemoveAccess(AccessControlType.Allow, account, right, InheritanceFlags.None, PropagationFlags.None);
296 internal static SecurityIdentifier GetWindowsServiceSid(string name)
298 Fx.Assert(OSEnvironmentHelper.IsVistaOrGreater, "This method can be called only on Vista or greater.");
299 string accountName = string.Format(CultureInfo.InvariantCulture, WindowsServiceAccountFormat, name);
303 uint cchReferencedDomainName = 0;
305 int error = UnsafeNativeMethods.ERROR_SUCCESS;
306 if (!ListenerUnsafeNativeMethods.LookupAccountName(null, accountName, sid, ref cbSid,
307 null, ref cchReferencedDomainName, out peUse))
309 error = Marshal.GetLastWin32Error();
310 if (error != ListenerUnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER)
312 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error));
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))
321 error = Marshal.GetLastWin32Error();
322 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error));
325 return new SecurityIdentifier(sid, 0);
328 internal static int GetPidForService(string serviceName)
330 return GetStatusForService(serviceName).dwProcessId;
333 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
334 internal static SecurityIdentifier GetLogonSidForPid(int pid)
336 SafeCloseHandle process = OpenProcessForQuery(pid);
339 SafeCloseHandle token = GetProcessToken(process, ListenerUnsafeNativeMethods.TOKEN_QUERY);
342 int length = GetTokenInformationLength(token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS.TokenGroups);
343 byte[] tokenInformation = new byte[length];
344 fixed (byte* pTokenInformation = tokenInformation)
346 GetTokenInformation(token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS.TokenGroups, tokenInformation);
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++)
352 if ((sids[i].Attributes & ListenerUnsafeNativeMethods.SidAttribute.SE_GROUP_LOGON_ID) == ListenerUnsafeNativeMethods.SidAttribute.SE_GROUP_LOGON_ID)
354 return new SecurityIdentifier(sids[i].Sid);
358 return new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null);
371 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
372 internal static SecurityIdentifier GetUserSidForPid(int pid)
374 SafeCloseHandle process = OpenProcessForQuery(pid);
377 SafeCloseHandle token = GetProcessToken(process, ListenerUnsafeNativeMethods.TOKEN_QUERY);
380 int length = GetTokenInformationLength(token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS.TokenUser);
381 byte[] tokenInformation = new byte[length];
382 fixed (byte* pTokenInformation = tokenInformation)
384 GetTokenInformation(token, ListenerUnsafeNativeMethods.TOKEN_INFORMATION_CLASS.TokenUser, tokenInformation);
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);
402 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
403 static ListenerUnsafeNativeMethods.SERVICE_STATUS_PROCESS GetStatusForService(string serviceName)
405 SafeServiceHandle scManager = OpenSCManager();
408 SafeServiceHandle service = OpenService(scManager, serviceName, ListenerUnsafeNativeMethods.SERVICE_QUERY_STATUS);
412 bool success = ListenerUnsafeNativeMethods.QueryServiceStatusEx(service, ListenerUnsafeNativeMethods.SC_STATUS_PROCESS_INFO, null, 0, out lpnLengthNeeded);
415 int errorCode = Marshal.GetLastWin32Error();
416 if (errorCode != ListenerUnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER)
418 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
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);
426 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception());
428 fixed (byte* pServiceStatusProcess = serviceStatusProcess)
430 return (ListenerUnsafeNativeMethods.SERVICE_STATUS_PROCESS)Marshal.PtrToStructure((IntPtr)pServiceStatusProcess, typeof(ListenerUnsafeNativeMethods.SERVICE_STATUS_PROCESS));