ComPlusThreadInitializer.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.ComIntegration
  5. {
  6. using System;
  7. using System.Runtime.Diagnostics;
  8. using System.ServiceModel.Channels;
  9. using System.ServiceModel.Dispatcher;
  10. using System.ServiceModel.Description;
  11. using System.Security.Principal;
  12. using System.ServiceModel;
  13. using System.Transactions;
  14. using System.Diagnostics;
  15. using System.ServiceModel.Diagnostics;
  16. using System.EnterpriseServices;
  17. using SR = System.ServiceModel.SR;
  18. using System.Globalization;
  19. class ComPlusThreadInitializer : ICallContextInitializer
  20. {
  21. ServiceInfo info;
  22. ComPlusAuthorization comAuth;
  23. Guid iid;
  24. public ComPlusThreadInitializer(ContractDescription contract,
  25. DispatchOperation operation,
  26. ServiceInfo info)
  27. {
  28. this.info = info;
  29. iid = contract.ContractType.GUID;
  30. if (info.CheckRoles)
  31. {
  32. string[] serviceRoleMembers = null;
  33. string[] contractRoleMembers = null;
  34. string[] operationRoleMembers = null;
  35. // Figure out the role members we want...
  36. //
  37. serviceRoleMembers = info.ComponentRoleMembers;
  38. foreach (ContractInfo contractInfo in this.info.Contracts)
  39. {
  40. if (contractInfo.IID == iid)
  41. {
  42. contractRoleMembers = contractInfo.InterfaceRoleMembers;
  43. foreach (OperationInfo opInfo in contractInfo.Operations)
  44. {
  45. if (opInfo.Name == operation.Name)
  46. {
  47. operationRoleMembers = opInfo.MethodRoleMembers;
  48. break;
  49. }
  50. }
  51. if (operationRoleMembers == null)
  52. {
  53. // Did not find the operation
  54. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ListenerInitFailed(
  55. SR.GetString(SR.ComOperationNotFound,
  56. contract.Name,
  57. operation.Name)));
  58. }
  59. break;
  60. }
  61. }
  62. this.comAuth = new ComPlusAuthorization(serviceRoleMembers,
  63. contractRoleMembers,
  64. operationRoleMembers);
  65. }
  66. }
  67. public object BeforeInvoke(
  68. InstanceContext instanceContext,
  69. IClientChannel channel,
  70. Message message)
  71. {
  72. ComPlusServerSecurity serverSecurity = null;
  73. WindowsImpersonationContext impersonateContext = null;
  74. bool errorTraced = false;
  75. WindowsIdentity identity = null;
  76. Uri from = null;
  77. object instance = null;
  78. int instanceID = 0;
  79. string action = null;
  80. TransactionProxy proxy = null;
  81. Transaction tx = null;
  82. Guid incomingTransactionID = Guid.Empty;
  83. // The outer try block is to comply with FXCOP's WrapVulnerableFinallyClausesInOuterTry rule.
  84. try
  85. {
  86. try
  87. {
  88. identity = MessageUtil.GetMessageIdentity(message);
  89. if (message.Headers.From != null)
  90. from = message.Headers.From.Uri;
  91. instance = instanceContext.GetServiceInstance(message);
  92. instanceID = instance.GetHashCode();
  93. action = message.Headers.Action;
  94. ComPlusMethodCallTrace.Trace(TraceEventType.Verbose, TraceCode.ComIntegrationInvokingMethod,
  95. SR.TraceCodeComIntegrationInvokingMethod, this.info, from, action, identity.Name, iid, instanceID, false);
  96. // Security
  97. //
  98. if (this.info.CheckRoles)
  99. {
  100. if (!this.comAuth.IsAuthorizedForOperation(identity))
  101. {
  102. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.CallAccessDenied());
  103. }
  104. }
  105. if (this.info.HostingMode != HostingMode.WebHostOutOfProcess)
  106. {
  107. // NOTE: This has the side effect of setting up
  108. // the COM server security thing, so be sure
  109. // to clear it with Dispose() eventually.
  110. //
  111. serverSecurity = new ComPlusServerSecurity(identity,
  112. this.info.CheckRoles);
  113. }
  114. // Transactions
  115. //
  116. proxy = instanceContext.Extensions.Find<TransactionProxy>();
  117. if (proxy != null)
  118. {
  119. // This makes the Tx header Understood.
  120. tx = MessageUtil.GetMessageTransaction(message);
  121. if (tx != null)
  122. {
  123. incomingTransactionID = tx.TransactionInformation.DistributedIdentifier;
  124. }
  125. try
  126. {
  127. if (tx != null)
  128. {
  129. proxy.SetTransaction(tx);
  130. }
  131. else
  132. {
  133. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.TransactionMismatch());
  134. }
  135. ComPlusMethodCallTrace.Trace(TraceEventType.Verbose, TraceCode.ComIntegrationInvokingMethodNewTransaction,
  136. SR.TraceCodeComIntegrationInvokingMethodNewTransaction, this.info, from, action, identity.Name, iid, instanceID, incomingTransactionID);
  137. }
  138. catch (FaultException e)
  139. {
  140. Transaction txProxy = proxy.CurrentTransaction;
  141. Guid currentTransactionID = Guid.Empty;
  142. if (txProxy != null)
  143. currentTransactionID = txProxy.TransactionInformation.DistributedIdentifier;
  144. string identityName = String.Empty;
  145. if (null != identity)
  146. identityName = identity.Name;
  147. DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
  148. (ushort)System.Runtime.Diagnostics.EventLogCategory.ComPlus,
  149. (uint)System.Runtime.Diagnostics.EventLogEventId.ComPlusInvokingMethodFailedMismatchedTransactions,
  150. incomingTransactionID.ToString("B").ToUpperInvariant(),
  151. currentTransactionID.ToString("B").ToUpperInvariant(),
  152. from.ToString(),
  153. this.info.AppID.ToString("B").ToUpperInvariant(),
  154. this.info.Clsid.ToString("B").ToUpperInvariant(),
  155. iid.ToString(),
  156. action,
  157. instanceID.ToString(CultureInfo.InvariantCulture),
  158. System.Threading.Thread.CurrentThread.ManagedThreadId.ToString(CultureInfo.InvariantCulture),
  159. SafeNativeMethods.GetCurrentThreadId().ToString(CultureInfo.InvariantCulture),
  160. identityName,
  161. e.ToString());
  162. errorTraced = true;
  163. throw;
  164. }
  165. }
  166. else
  167. {
  168. ComPlusMethodCallTrace.Trace(TraceEventType.Verbose, TraceCode.ComIntegrationInvokingMethodContextTransaction,
  169. SR.TraceCodeComIntegrationInvokingMethodContextTransaction, this.info, from, action, identity.Name, iid, instanceID, true);
  170. }
  171. // Impersonation
  172. //
  173. if (this.info.HostingMode == HostingMode.WebHostOutOfProcess)
  174. {
  175. impersonateContext = identity.Impersonate();
  176. }
  177. CorrelationState correlationState;
  178. correlationState = new CorrelationState(impersonateContext,
  179. serverSecurity,
  180. from,
  181. action,
  182. identity.Name,
  183. instanceID);
  184. impersonateContext = null;
  185. serverSecurity = null;
  186. return correlationState;
  187. }
  188. finally
  189. {
  190. if (impersonateContext != null)
  191. impersonateContext.Undo();
  192. if (serverSecurity != null)
  193. ((IDisposable)serverSecurity).Dispose();
  194. }
  195. }
  196. catch (Exception e)
  197. {
  198. if (errorTraced == false)
  199. {
  200. if (DiagnosticUtility.ShouldTraceError)
  201. {
  202. DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
  203. (ushort)System.Runtime.Diagnostics.EventLogCategory.ComPlus,
  204. (uint)System.Runtime.Diagnostics.EventLogEventId.ComPlusInvokingMethodFailed,
  205. from == null ? string.Empty : from.ToString(),
  206. this.info.AppID.ToString("B").ToUpperInvariant(),
  207. this.info.Clsid.ToString("B").ToUpperInvariant(),
  208. iid.ToString("B").ToUpperInvariant(),
  209. action,
  210. instanceID.ToString(CultureInfo.InvariantCulture),
  211. System.Threading.Thread.CurrentThread.ManagedThreadId.ToString(CultureInfo.InvariantCulture),
  212. SafeNativeMethods.GetCurrentThreadId().ToString(CultureInfo.InvariantCulture),
  213. identity.Name,
  214. e.ToString());
  215. }
  216. }
  217. throw;
  218. }
  219. }
  220. public void AfterInvoke(object correlationState)
  221. {
  222. CorrelationState state = (CorrelationState)correlationState;
  223. if (state != null)
  224. {
  225. ComPlusMethodCallTrace.Trace(TraceEventType.Verbose, TraceCode.ComIntegrationInvokedMethod,
  226. SR.TraceCodeComIntegrationInvokedMethod, this.info, state.From, state.Action, state.CallerIdentity, iid, state.InstanceID, false);
  227. state.Cleanup();
  228. }
  229. }
  230. class CorrelationState
  231. {
  232. WindowsImpersonationContext impersonationContext;
  233. ComPlusServerSecurity serverSecurity;
  234. Uri from;
  235. string action;
  236. string callerIdentity;
  237. int instanceID;
  238. public CorrelationState(WindowsImpersonationContext context,
  239. ComPlusServerSecurity serverSecurity,
  240. Uri from,
  241. string action,
  242. string callerIdentity,
  243. int instanceID)
  244. {
  245. this.impersonationContext = context;
  246. this.serverSecurity = serverSecurity;
  247. this.from = from;
  248. this.action = action;
  249. this.callerIdentity = callerIdentity;
  250. this.instanceID = instanceID;
  251. }
  252. public Uri From
  253. {
  254. get
  255. {
  256. return this.from;
  257. }
  258. }
  259. public string Action
  260. {
  261. get
  262. {
  263. return this.action;
  264. }
  265. }
  266. public string CallerIdentity
  267. {
  268. get
  269. {
  270. return this.callerIdentity;
  271. }
  272. }
  273. public int InstanceID
  274. {
  275. get
  276. {
  277. return this.instanceID;
  278. }
  279. }
  280. public void Cleanup()
  281. {
  282. if (this.impersonationContext != null)
  283. this.impersonationContext.Undo();
  284. if (this.serverSecurity != null)
  285. ((IDisposable)this.serverSecurity).Dispose();
  286. }
  287. }
  288. }
  289. }