PageRenderTime 405ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Activation/Utility.cs

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