WsatConfiguration.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Transactions
  5. {
  6. using System;
  7. using System.Diagnostics.CodeAnalysis;
  8. using System.Runtime;
  9. using System.ServiceModel.Channels;
  10. using System.ServiceModel;
  11. using System.IO;
  12. using System.Net;
  13. using System.Security;
  14. using System.ServiceModel.ComIntegration;
  15. using System.ServiceModel.Security;
  16. using System.Transactions;
  17. using Microsoft.Transactions.Wsat.Messaging;
  18. using Microsoft.Transactions.Wsat.Protocol;
  19. using Microsoft.Transactions.Wsat.Recovery;
  20. class TransactionManagerConfigurationException : TransactionException
  21. {
  22. public TransactionManagerConfigurationException(string error, Exception e)
  23. :
  24. base(error, e)
  25. {
  26. }
  27. public TransactionManagerConfigurationException(string error)
  28. :
  29. base(error)
  30. {
  31. }
  32. }
  33. class WsatConfiguration
  34. {
  35. static readonly string DisabledRegistrationPath;
  36. const string WsatKey = @"Software\Microsoft\WSAT\3.0";
  37. const string OleTxUpgradeEnabledValue = "OleTxUpgradeEnabled";
  38. const bool OleTxUpgradeEnabledDefault = true;
  39. bool oleTxUpgradeEnabled;
  40. EndpointAddress localActivationService10;
  41. EndpointAddress localActivationService11;
  42. EndpointAddress remoteActivationService10;
  43. EndpointAddress remoteActivationService11;
  44. Uri registrationServiceAddress10;
  45. Uri registrationServiceAddress11;
  46. bool protocolService10Enabled = false;
  47. bool protocolService11Enabled = false;
  48. bool inboundEnabled;
  49. bool issuedTokensEnabled;
  50. TimeSpan maxTimeout;
  51. [SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The calls to BindingStrings are safe.")]
  52. static WsatConfiguration()
  53. {
  54. DisabledRegistrationPath = string.Concat(BindingStrings.AddressPrefix, "/", BindingStrings.RegistrationCoordinatorSuffix(ProtocolVersion.Version10), BindingStrings.DisabledSuffix);
  55. }
  56. [SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The calls to ProtocolInformationReader.IsV10Enabled and IsV11Enabled are safe.")]
  57. public WsatConfiguration()
  58. {
  59. // Get whereabouts
  60. WhereaboutsReader whereabouts = GetWhereabouts();
  61. ProtocolInformationReader protocol = whereabouts.ProtocolInformation;
  62. if (protocol != null)
  63. {
  64. this.protocolService10Enabled = protocol.IsV10Enabled;
  65. this.protocolService11Enabled = protocol.IsV11Enabled;
  66. }
  67. Initialize(whereabouts);
  68. // Read local registry flag
  69. this.oleTxUpgradeEnabled = ReadFlag(WsatKey, OleTxUpgradeEnabledValue, OleTxUpgradeEnabledDefault);
  70. }
  71. void Initialize(WhereaboutsReader whereabouts)
  72. {
  73. // MB 47153: don't throw system exception if whereabouts data is broken
  74. try
  75. {
  76. InitializeForUnmarshal(whereabouts);
  77. InitializeForMarshal(whereabouts);
  78. }
  79. catch (UriFormatException e)
  80. {
  81. // UriBuilder.Uri can throw this if the URI is ultimately invalid
  82. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  83. new TransactionManagerConfigurationException(SR.GetString(SR.WsatUriCreationFailed), e));
  84. }
  85. catch (ArgumentOutOfRangeException e)
  86. {
  87. // UriBuilder constructor can throw this if port < 0
  88. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  89. new TransactionManagerConfigurationException(SR.GetString(SR.WsatUriCreationFailed), e));
  90. }
  91. }
  92. public bool OleTxUpgradeEnabled
  93. {
  94. get { return this.oleTxUpgradeEnabled; }
  95. }
  96. public TimeSpan MaxTimeout
  97. {
  98. get { return this.maxTimeout; }
  99. }
  100. public bool IssuedTokensEnabled
  101. {
  102. get { return this.issuedTokensEnabled; }
  103. }
  104. public bool InboundEnabled
  105. {
  106. get { return this.inboundEnabled; }
  107. }
  108. public bool IsProtocolServiceEnabled(ProtocolVersion protocolVersion)
  109. {
  110. switch (protocolVersion)
  111. {
  112. case ProtocolVersion.Version10:
  113. return this.protocolService10Enabled;
  114. case ProtocolVersion.Version11:
  115. return this.protocolService11Enabled;
  116. default:
  117. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  118. new ArgumentException(SR.GetString(SR.InvalidWsatProtocolVersion)));
  119. }
  120. }
  121. public EndpointAddress LocalActivationService(ProtocolVersion protocolVersion)
  122. {
  123. switch (protocolVersion)
  124. {
  125. case ProtocolVersion.Version10:
  126. return this.localActivationService10;
  127. case ProtocolVersion.Version11:
  128. return this.localActivationService11;
  129. default:
  130. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  131. new ArgumentException(SR.GetString(SR.InvalidWsatProtocolVersion)));
  132. }
  133. }
  134. public EndpointAddress RemoteActivationService(ProtocolVersion protocolVersion)
  135. {
  136. switch (protocolVersion)
  137. {
  138. case ProtocolVersion.Version10:
  139. return this.remoteActivationService10;
  140. case ProtocolVersion.Version11:
  141. return this.remoteActivationService11;
  142. default:
  143. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  144. new ArgumentException(SR.GetString(SR.InvalidWsatProtocolVersion)));
  145. }
  146. }
  147. public EndpointAddress CreateRegistrationService(AddressHeader refParam, ProtocolVersion protocolVersion)
  148. {
  149. switch (protocolVersion)
  150. {
  151. case ProtocolVersion.Version10:
  152. return new EndpointAddress(this.registrationServiceAddress10, refParam);
  153. case ProtocolVersion.Version11:
  154. return new EndpointAddress(this.registrationServiceAddress11, refParam);
  155. default:
  156. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  157. new ArgumentException(SR.GetString(SR.InvalidWsatProtocolVersion)));
  158. }
  159. }
  160. public bool IsLocalRegistrationService(EndpointAddress endpoint, ProtocolVersion protocolVersion)
  161. {
  162. if (endpoint.Uri == null)
  163. return false;
  164. switch (protocolVersion)
  165. {
  166. case ProtocolVersion.Version10:
  167. return endpoint.Uri == this.registrationServiceAddress10;
  168. case ProtocolVersion.Version11:
  169. return endpoint.Uri == this.registrationServiceAddress11;
  170. default:
  171. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  172. new ArgumentException(SR.GetString(SR.InvalidWsatProtocolVersion)));
  173. }
  174. }
  175. public bool IsDisabledRegistrationService(EndpointAddress endpoint)
  176. {
  177. return endpoint.Uri.AbsolutePath == DisabledRegistrationPath;
  178. }
  179. //
  180. // Internals
  181. //
  182. WhereaboutsReader GetWhereabouts()
  183. {
  184. try
  185. {
  186. return new WhereaboutsReader(TransactionInterop.GetWhereabouts());
  187. }
  188. catch (SerializationException e)
  189. {
  190. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  191. new TransactionManagerConfigurationException(SR.GetString(SR.WhereaboutsReadFailed), e));
  192. }
  193. // If GetWhereabouts throws TransactionException, let it propagate
  194. }
  195. [SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The calls to the ProtocolInformationReader properties and to BindingStrings.RegistrationCoordinatorSuffix(..) are safe.")]
  196. void InitializeForUnmarshal(WhereaboutsReader whereabouts)
  197. {
  198. ProtocolInformationReader protocol = whereabouts.ProtocolInformation;
  199. if (protocol != null && protocol.NetworkInboundAccess)
  200. {
  201. this.inboundEnabled = true;
  202. bool isTmLocal = string.Compare(Environment.MachineName,
  203. protocol.NodeName,
  204. StringComparison.OrdinalIgnoreCase) == 0;
  205. string spnIdentity;
  206. string activationCoordinatorSuffix10 =
  207. BindingStrings.ActivationCoordinatorSuffix(ProtocolVersion.Version10);
  208. string activationCoordinatorSuffix11 =
  209. BindingStrings.ActivationCoordinatorSuffix(ProtocolVersion.Version11);
  210. if (protocol.IsClustered ||
  211. (protocol.NetworkClientAccess && !isTmLocal))
  212. {
  213. if (protocol.IsClustered)
  214. {
  215. // We cannot reliably perform mutual authentication against a clustered resource
  216. // See MB 43523 for more details on this
  217. spnIdentity = null;
  218. }
  219. else
  220. {
  221. spnIdentity = "host/" + protocol.HostName;
  222. }
  223. if (protocol.IsV10Enabled)
  224. {
  225. this.remoteActivationService10 = CreateActivationEndpointAddress(protocol,
  226. activationCoordinatorSuffix10,
  227. spnIdentity,
  228. true);
  229. }
  230. if (protocol.IsV11Enabled)
  231. {
  232. this.remoteActivationService11 = CreateActivationEndpointAddress(protocol,
  233. activationCoordinatorSuffix11,
  234. spnIdentity,
  235. true);
  236. }
  237. }
  238. if (isTmLocal)
  239. {
  240. spnIdentity = "host/" + protocol.NodeName;
  241. // The net.pipe Activation endpoint uses the host name as a discriminant
  242. // for cluster scenarios with more than one service on a node.
  243. if (protocol.IsV10Enabled)
  244. {
  245. this.localActivationService10 = CreateActivationEndpointAddress(protocol,
  246. activationCoordinatorSuffix10,
  247. spnIdentity,
  248. false);
  249. }
  250. if (protocol.IsV11Enabled)
  251. {
  252. this.localActivationService11 = CreateActivationEndpointAddress(protocol,
  253. activationCoordinatorSuffix11,
  254. spnIdentity,
  255. false);
  256. }
  257. }
  258. }
  259. }
  260. [SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The calls to the ProtocolInformationReader properties (HostName, HttpsPort, BasePath) are safe.")]
  261. EndpointAddress CreateActivationEndpointAddress(ProtocolInformationReader protocol,
  262. string suffix,
  263. string spnIdentity,
  264. bool isRemote)
  265. {
  266. string uriScheme;
  267. string host;
  268. int port;
  269. string path;
  270. if (isRemote)
  271. {
  272. uriScheme = Uri.UriSchemeHttps;
  273. host = protocol.HostName;
  274. port = protocol.HttpsPort;
  275. path = protocol.BasePath + "/" + suffix + BindingStrings.RemoteProxySuffix;
  276. }
  277. else
  278. {
  279. uriScheme = Uri.UriSchemeNetPipe;
  280. host = "localhost";
  281. port = -1;
  282. path = protocol.HostName + "/" + protocol.BasePath + "/" + suffix;
  283. }
  284. UriBuilder builder = new UriBuilder(uriScheme, host, port, path);
  285. if (spnIdentity != null)
  286. {
  287. EndpointIdentity identity = EndpointIdentity.CreateSpnIdentity(spnIdentity);
  288. return new EndpointAddress(builder.Uri, identity);
  289. }
  290. else
  291. {
  292. return new EndpointAddress(builder.Uri);
  293. }
  294. }
  295. [SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The calls to the ProtocolInformationReader properties and to BindingStrings.RegistrationCoordinatorSuffix(..) are safe.")]
  296. void InitializeForMarshal(WhereaboutsReader whereabouts)
  297. {
  298. ProtocolInformationReader protocol = whereabouts.ProtocolInformation;
  299. if (protocol != null && protocol.NetworkOutboundAccess)
  300. {
  301. // We can marshal outgoing transactions using a valid address
  302. if (protocol.IsV10Enabled)
  303. {
  304. UriBuilder builder10 = new UriBuilder(Uri.UriSchemeHttps,
  305. protocol.HostName,
  306. protocol.HttpsPort,
  307. protocol.BasePath + "/" +
  308. BindingStrings.RegistrationCoordinatorSuffix(ProtocolVersion.Version10));
  309. this.registrationServiceAddress10 = builder10.Uri;
  310. }
  311. // when we have a WSAT1.1 coordinator
  312. if (protocol.IsV11Enabled)
  313. {
  314. UriBuilder builder11 = new UriBuilder(Uri.UriSchemeHttps,
  315. protocol.HostName,
  316. protocol.HttpsPort,
  317. protocol.BasePath + "/" +
  318. BindingStrings.RegistrationCoordinatorSuffix(ProtocolVersion.Version11));
  319. this.registrationServiceAddress11 = builder11.Uri;
  320. }
  321. this.issuedTokensEnabled = protocol.IssuedTokensEnabled;
  322. this.maxTimeout = protocol.MaxTimeout;
  323. }
  324. else
  325. {
  326. // Generate an address that will not work
  327. // We do this in order to generate coordination contexts that can be propagated
  328. // between processes on the same node even if WS-AT is disabled
  329. UriBuilder builder = new UriBuilder(Uri.UriSchemeHttps,
  330. whereabouts.HostName,
  331. 443,
  332. DisabledRegistrationPath);
  333. this.registrationServiceAddress10 = builder.Uri;
  334. this.registrationServiceAddress11 = builder.Uri;
  335. this.issuedTokensEnabled = false;
  336. this.maxTimeout = TimeSpan.FromMinutes(5);
  337. }
  338. }
  339. static object ReadValue(string key, string value)
  340. {
  341. try
  342. {
  343. using (RegistryHandle regKey = RegistryHandle.GetNativeHKLMSubkey(key, false))
  344. {
  345. if (regKey == null)
  346. return null;
  347. return regKey.GetValue(value);
  348. }
  349. }
  350. catch (SecurityException e)
  351. {
  352. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  353. new TransactionManagerConfigurationException(SR.GetString(SR.WsatRegistryValueReadError, value), e));
  354. }
  355. catch (IOException e)
  356. {
  357. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  358. new TransactionManagerConfigurationException(SR.GetString(SR.WsatRegistryValueReadError, value), e));
  359. }
  360. }
  361. static int ReadInt(string key, string value, int defaultValue)
  362. {
  363. object regValue = ReadValue(key, value);
  364. if (regValue == null || !(regValue is Int32))
  365. return defaultValue;
  366. return (int)regValue;
  367. }
  368. static bool ReadFlag(string key, string value, bool defaultValue)
  369. {
  370. return (int)ReadInt(key, value, defaultValue ? 1 : 0) != 0;
  371. }
  372. }
  373. }