Leaked source code of windows server 2003
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.

357 lines
8.5 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 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. if (tlsIndex != (DWORD) -1)
  79. {
  80. TlsFree(tlsIndex);
  81. tlsIndex = (DWORD)-1;
  82. }
  83. IASAttributeRelease(proxy.pAttribute);
  84. proxy.pAttribute = NULL;
  85. return S_OK;
  86. }
  87. STDMETHODIMP Pipeline::GetProperty(LONG Id, VARIANT* pValue)
  88. {
  89. return DISP_E_MEMBERNOTFOUND;
  90. }
  91. STDMETHODIMP Pipeline::PutProperty(LONG Id, VARIANT* pValue)
  92. {
  93. if (Id) { return S_OK; }
  94. if (V_VT(pValue) != (VT_ARRAY | VT_VARIANT)) { return DISP_E_TYPEMISMATCH; }
  95. SafeArrayDestroy(handlers);
  96. handlers = NULL;
  97. return SafeArrayCopy(V_ARRAY(pValue), &handlers);
  98. }
  99. STDMETHODIMP Pipeline::OnRequest(IRequest* pRequest) throw ()
  100. {
  101. // Extract the Request object.
  102. Request* request = Request::narrow(pRequest);
  103. if (!request) { return E_NOINTERFACE; }
  104. // Classify the request.
  105. classify(*request);
  106. // Set this as the new source.
  107. request->pushSource(this);
  108. // Set the next stage to execute, i.e., stage zero.
  109. request->pushState(0);
  110. // Execute the request.
  111. execute(*request);
  112. return S_OK;
  113. }
  114. STDMETHODIMP Pipeline::OnRequestComplete(
  115. IRequest* pRequest,
  116. IASREQUESTSTATUS eStatus
  117. )
  118. {
  119. // Extract the Request object.
  120. Request* request = Request::narrow(pRequest);
  121. if (!request) { return E_NOINTERFACE; }
  122. // If TLS is set, then we're on the original thread ...
  123. if (TlsGetValue(tlsIndex))
  124. {
  125. // ... so clear the value to let the thread know we finished.
  126. TlsSetValue(tlsIndex, NULL);
  127. }
  128. else
  129. {
  130. // Otherwise, we're completing asynchronously so continue execution on
  131. // the caller's thread.
  132. execute(*request);
  133. }
  134. return S_OK;
  135. }
  136. Pipeline::Pipeline() throw ()
  137. : tlsIndex((DWORD)-1),
  138. begin(NULL),
  139. end(NULL),
  140. handlers(NULL)
  141. {
  142. memset(&proxy, 0, sizeof(proxy));
  143. }
  144. Pipeline::~Pipeline() throw ()
  145. {
  146. Shutdown();
  147. }
  148. void Pipeline::classify(
  149. Request& request
  150. ) throw ()
  151. {
  152. IASREQUEST routingType = request.getRequest();
  153. switch (routingType)
  154. {
  155. case IAS_REQUEST_ACCESS_REQUEST:
  156. {
  157. PIASATTRIBUTE state = request.findFirst(
  158. RADIUS_ATTRIBUTE_STATE
  159. );
  160. if (state && state->Value.OctetString.dwLength)
  161. {
  162. routingType = IAS_REQUEST_CHALLENGE_RESPONSE;
  163. }
  164. break;
  165. }
  166. case IAS_REQUEST_ACCOUNTING:
  167. {
  168. PIASATTRIBUTE status = request.findFirst(
  169. RADIUS_ATTRIBUTE_ACCT_STATUS_TYPE
  170. );
  171. if (status)
  172. {
  173. switch (status->Value.Integer)
  174. {
  175. case 7: // Accounting-On
  176. case 8: // Accounting-Off
  177. {
  178. // NAS state messages always go to RADIUS proxy.
  179. request.AddAttributes(1, &proxy);
  180. routingType = IAS_REQUEST_NAS_STATE;
  181. }
  182. }
  183. }
  184. break;
  185. }
  186. }
  187. request.setRoutingType(routingType);
  188. }
  189. BOOL Pipeline::executeNext(
  190. Request& request
  191. ) throw ()
  192. {
  193. // Compute the next stage to try.
  194. Stage* nextStage = begin + request.popState();
  195. // Find the next stage that wants to handle the request.
  196. while (nextStage != end && !nextStage->shouldHandle(request))
  197. {
  198. ++nextStage;
  199. }
  200. // Have we reached the end of the pipeline ?
  201. if (nextStage == end)
  202. {
  203. // Reset the source property.
  204. request.popSource();
  205. // We're done.
  206. request.ReturnToSource(IAS_REQUEST_STATUS_HANDLED);
  207. return FALSE;
  208. }
  209. // Save the next stage to try.
  210. request.pushState(nextStage - begin + 1);
  211. // Set TLS, so we'll know we're executing a request.
  212. TlsSetValue(tlsIndex, (PVOID)-1);
  213. // Forward to the handler.
  214. nextStage->onRequest(&request);
  215. // If TLS is not set, then the request completed synchronously.
  216. BOOL keepExecuting = !TlsGetValue(tlsIndex);
  217. // Clear TLS.
  218. TlsSetValue(tlsIndex, NULL);
  219. return keepExecuting;
  220. }
  221. LONG Pipeline::readConfiguration(HKEY key) throw ()
  222. {
  223. // How many stages do we have ?
  224. LONG error;
  225. DWORD subKeys;
  226. error = RegQueryInfoKeyW(
  227. key,
  228. NULL,
  229. NULL,
  230. NULL,
  231. &subKeys,
  232. NULL,
  233. NULL,
  234. NULL,
  235. NULL,
  236. NULL,
  237. NULL,
  238. NULL
  239. );
  240. if (error) { return error; }
  241. // Is the pipeline empty ?
  242. if (!subKeys) { return NO_ERROR; }
  243. // Allocate memory to hold the stages.
  244. begin = new (std::nothrow) Stage[subKeys];
  245. if (!begin) { return ERROR_NOT_ENOUGH_MEMORY; }
  246. end = begin;
  247. // Read the configuration for each stage.
  248. for (DWORD i = 0; i < subKeys; ++i)
  249. {
  250. WCHAR name[32];
  251. DWORD nameLen = 32;
  252. error = RegEnumKeyExW(
  253. key,
  254. i,
  255. name,
  256. &nameLen,
  257. NULL,
  258. NULL,
  259. NULL,
  260. NULL
  261. );
  262. if (error)
  263. {
  264. if (error == ERROR_NO_MORE_ITEMS) { error = NO_ERROR; }
  265. break;
  266. }
  267. error = (end++)->readConfiguration(key, name);
  268. if (error) { break; }
  269. }
  270. // Sort the stages according to priority.
  271. qsort(
  272. begin,
  273. end - begin,
  274. sizeof(Stage),
  275. (CompFn)Stage::sortByPriority
  276. );
  277. return error;
  278. }
  279. HRESULT Pipeline::initializeStage(Stage* stage) throw ()
  280. {
  281. VARIANT *beginHandlers, *endHandlers;
  282. if (handlers)
  283. {
  284. ULONG nelem = handlers->rgsabound[1].cElements;
  285. beginHandlers = (VARIANT*)handlers->pvData;
  286. endHandlers = beginHandlers + nelem * 2;
  287. }
  288. else
  289. {
  290. beginHandlers = endHandlers = NULL;
  291. }
  292. // Did we get this handler from the SDOs ?
  293. for (VARIANT* v = beginHandlers; v != endHandlers; v+= 2)
  294. {
  295. if (!_wcsicmp(stage->getProgID(), V_BSTR(v)))
  296. {
  297. // Yes, so just use the one they gave us.
  298. return stage->setHandler(V_UNKNOWN(++v));
  299. }
  300. }
  301. // No, so create a new one.
  302. return stage->createHandler();
  303. }