Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

354 lines
8.1 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // pipeline.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // Defines the class Pipeline.
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 01/28/2000 Original version.
  16. //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #include <polcypch.h>
  19. #include <iasattr.h>
  20. #include <pipeline.h>
  21. #include <request.h>
  22. #include <sdoias.h>
  23. #include <stage.h>
  24. #include <new>
  25. STDMETHODIMP Pipeline::InitNew()
  26. { return S_OK; }
  27. STDMETHODIMP Pipeline::Initialize()
  28. {
  29. // Set up the Provider-Type for NAS-State requests.
  30. if (IASAttributeAlloc(1, &proxy.pAttribute) != NO_ERROR)
  31. {
  32. return E_OUTOFMEMORY;
  33. }
  34. proxy.pAttribute->dwId = IAS_ATTRIBUTE_PROVIDER_TYPE;
  35. proxy.pAttribute->Value.itType = IASTYPE_ENUM;
  36. proxy.pAttribute->Value.Enumerator = IAS_PROVIDER_RADIUS_PROXY;
  37. // Allocate the TLS use for storing thread state.
  38. tlsIndex = TlsAlloc();
  39. if (tlsIndex == (DWORD)-1)
  40. {
  41. HRESULT hr = GetLastError();
  42. return HRESULT_FROM_WIN32(hr);
  43. }
  44. // Read the configuration from the registry.
  45. HKEY key;
  46. LONG error = RegOpenKeyExW(
  47. HKEY_LOCAL_MACHINE,
  48. L"SYSTEM\\CurrentControlSet\\Services\\RemoteAccess"
  49. L"\\Policy\\Pipeline",
  50. 0,
  51. KEY_READ,
  52. &key
  53. );
  54. if (!error)
  55. {
  56. error = readConfiguration(key);
  57. RegCloseKey(key);
  58. }
  59. if (error) { return HRESULT_FROM_WIN32(error); }
  60. // Initialize the stages.
  61. for (Stage* s = begin; s != end; ++s)
  62. {
  63. HRESULT hr = initializeStage(s);
  64. if (FAILED(hr)) { return hr; }
  65. }
  66. return S_OK;
  67. }
  68. STDMETHODIMP Pipeline::Suspend()
  69. { return S_OK; }
  70. STDMETHODIMP Pipeline::Resume()
  71. { return S_OK; }
  72. STDMETHODIMP Pipeline::Shutdown()
  73. {
  74. delete[] begin;
  75. begin = end = NULL;
  76. SafeArrayDestroy(handlers);
  77. handlers = NULL;
  78. TlsFree(tlsIndex);
  79. tlsIndex = (DWORD)-1;
  80. IASAttributeRelease(proxy.pAttribute);
  81. proxy.pAttribute = NULL;
  82. return S_OK;
  83. }
  84. STDMETHODIMP Pipeline::GetProperty(LONG Id, VARIANT* pValue)
  85. {
  86. return DISP_E_MEMBERNOTFOUND;
  87. }
  88. STDMETHODIMP Pipeline::PutProperty(LONG Id, VARIANT* pValue)
  89. {
  90. if (Id) { return S_OK; }
  91. if (V_VT(pValue) != (VT_ARRAY | VT_VARIANT)) { return DISP_E_TYPEMISMATCH; }
  92. SafeArrayDestroy(handlers);
  93. handlers = NULL;
  94. return SafeArrayCopy(V_ARRAY(pValue), &handlers);
  95. }
  96. STDMETHODIMP Pipeline::OnRequest(IRequest* pRequest) throw ()
  97. {
  98. // Extract the Request object.
  99. Request* request = Request::narrow(pRequest);
  100. if (!request) { return E_NOINTERFACE; }
  101. // Classify the request.
  102. classify(*request);
  103. // Set this as the new source.
  104. request->pushSource(this);
  105. // Set the next stage to execute, i.e., stage zero.
  106. request->pushState(0);
  107. // Execute the request.
  108. execute(*request);
  109. return S_OK;
  110. }
  111. STDMETHODIMP Pipeline::OnRequestComplete(
  112. IRequest* pRequest,
  113. IASREQUESTSTATUS eStatus
  114. )
  115. {
  116. // Extract the Request object.
  117. Request* request = Request::narrow(pRequest);
  118. if (!request) { return E_NOINTERFACE; }
  119. // If TLS is set, then we're on the original thread ...
  120. if (TlsGetValue(tlsIndex))
  121. {
  122. // ... so clear the value to let the thread know we finished.
  123. TlsSetValue(tlsIndex, NULL);
  124. }
  125. else
  126. {
  127. // Otherwise, we're completing asynchronously so continue execution on
  128. // the caller's thread.
  129. execute(*request);
  130. }
  131. return S_OK;
  132. }
  133. Pipeline::Pipeline() throw ()
  134. : tlsIndex((DWORD)-1),
  135. begin(NULL),
  136. end(NULL),
  137. handlers(NULL)
  138. {
  139. memset(&proxy, 0, sizeof(proxy));
  140. }
  141. Pipeline::~Pipeline() throw ()
  142. {
  143. Shutdown();
  144. }
  145. void Pipeline::classify(
  146. Request& request
  147. ) throw ()
  148. {
  149. IASREQUEST routingType = request.getRequest();
  150. switch (routingType)
  151. {
  152. case IAS_REQUEST_ACCESS_REQUEST:
  153. {
  154. PIASATTRIBUTE state = request.findFirst(
  155. RADIUS_ATTRIBUTE_STATE
  156. );
  157. if (state && state->Value.OctetString.dwLength)
  158. {
  159. routingType = IAS_REQUEST_CHALLENGE_RESPONSE;
  160. }
  161. break;
  162. }
  163. case IAS_REQUEST_ACCOUNTING:
  164. {
  165. PIASATTRIBUTE status = request.findFirst(
  166. RADIUS_ATTRIBUTE_ACCT_STATUS_TYPE
  167. );
  168. if (status)
  169. {
  170. switch (status->Value.Integer)
  171. {
  172. case 7: // Accounting-On
  173. case 8: // Accounting-Off
  174. {
  175. // NAS state messages always go to RADIUS proxy.
  176. request.AddAttributes(1, &proxy);
  177. routingType = IAS_REQUEST_NAS_STATE;
  178. }
  179. }
  180. }
  181. break;
  182. }
  183. }
  184. request.setRoutingType(routingType);
  185. }
  186. BOOL Pipeline::executeNext(
  187. Request& request
  188. ) throw ()
  189. {
  190. // Compute the next stage to try.
  191. Stage* nextStage = begin + request.popState();
  192. // Find the next stage that wants to handle the request.
  193. while (nextStage != end && !nextStage->shouldHandle(request))
  194. {
  195. ++nextStage;
  196. }
  197. // Have we reached the end of the pipeline ?
  198. if (nextStage == end)
  199. {
  200. // Reset the source property.
  201. request.popSource();
  202. // We're done.
  203. request.ReturnToSource(IAS_REQUEST_STATUS_HANDLED);
  204. return FALSE;
  205. }
  206. // Save the next stage to try.
  207. request.pushState(nextStage - begin + 1);
  208. // Set TLS, so we'll know we're executing a request.
  209. TlsSetValue(tlsIndex, (PVOID)-1);
  210. // Forward to the handler.
  211. nextStage->onRequest(&request);
  212. // If TLS is not set, then the request completed synchronously.
  213. BOOL keepExecuting = !TlsGetValue(tlsIndex);
  214. // Clear TLS.
  215. TlsSetValue(tlsIndex, NULL);
  216. return keepExecuting;
  217. }
  218. LONG Pipeline::readConfiguration(HKEY key) throw ()
  219. {
  220. // How many stages do we have ?
  221. LONG error;
  222. DWORD subKeys;
  223. error = RegQueryInfoKeyW(
  224. key,
  225. NULL,
  226. NULL,
  227. NULL,
  228. &subKeys,
  229. NULL,
  230. NULL,
  231. NULL,
  232. NULL,
  233. NULL,
  234. NULL,
  235. NULL
  236. );
  237. if (error) { return error; }
  238. // Is the pipeline empty ?
  239. if (!subKeys) { return NO_ERROR; }
  240. // Allocate memory to hold the stages.
  241. begin = new (std::nothrow) Stage[subKeys];
  242. if (!begin) { return ERROR_NOT_ENOUGH_MEMORY; }
  243. end = begin;
  244. // Read the configuration for each stage.
  245. for (DWORD i = 0; i < subKeys; ++i)
  246. {
  247. WCHAR name[32];
  248. DWORD nameLen = 32;
  249. error = RegEnumKeyExW(
  250. key,
  251. i,
  252. name,
  253. &nameLen,
  254. NULL,
  255. NULL,
  256. NULL,
  257. NULL
  258. );
  259. if (error)
  260. {
  261. if (error == ERROR_NO_MORE_ITEMS) { error = NO_ERROR; }
  262. break;
  263. }
  264. error = (end++)->readConfiguration(key, name);
  265. if (error) { break; }
  266. }
  267. // Sort the stages according to priority.
  268. qsort(
  269. begin,
  270. end - begin,
  271. sizeof(Stage),
  272. (CompFn)Stage::sortByPriority
  273. );
  274. return error;
  275. }
  276. HRESULT Pipeline::initializeStage(Stage* stage) throw ()
  277. {
  278. VARIANT *beginHandlers, *endHandlers;
  279. if (handlers)
  280. {
  281. ULONG nelem = handlers->rgsabound[1].cElements;
  282. beginHandlers = (VARIANT*)handlers->pvData;
  283. endHandlers = beginHandlers + nelem * 2;
  284. }
  285. else
  286. {
  287. beginHandlers = endHandlers = NULL;
  288. }
  289. // Did we get this handler from the SDOs ?
  290. for (VARIANT* v = beginHandlers; v != endHandlers; v+= 2)
  291. {
  292. if (!_wcsicmp(stage->getProgID(), V_BSTR(v)))
  293. {
  294. // Yes, so just use the one they gave us.
  295. return stage->setHandler(V_UNKNOWN(++v));
  296. }
  297. }
  298. // No, so create a new one.
  299. return stage->createHandler();
  300. }