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.

402 lines
9.6 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) Microsoft Corporation
  4. //
  5. // SYNOPSIS
  6. //
  7. // Defines the class CClients.
  8. //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "radcommon.h"
  11. #include "clients.h"
  12. #include "client.h"
  13. CClients::CClients() throw ()
  14. : m_CritSectInitialized(false),
  15. m_pCClientArray(0),
  16. m_hResolverEvent(0),
  17. m_dwMaxClients(0),
  18. m_fAllowSubnetSyntax(false)
  19. {
  20. }
  21. CClients::~CClients() throw ()
  22. {
  23. if (m_hResolverEvent != 0)
  24. {
  25. CloseHandle(m_hResolverEvent);
  26. }
  27. DeleteObjects();
  28. CoTaskMemFree(m_pCClientArray);
  29. if (m_CritSectInitialized)
  30. {
  31. DeleteCriticalSection(&m_CritSect);
  32. }
  33. }
  34. HRESULT CClients::Init() throw ()
  35. {
  36. IAS_PRODUCT_LIMITS limits;
  37. DWORD error = IASGetProductLimits(0, &limits);
  38. if (error != NO_ERROR)
  39. {
  40. return HRESULT_FROM_WIN32(error);
  41. }
  42. m_dwMaxClients = limits.maxClients;
  43. m_fAllowSubnetSyntax = (limits.allowSubnetSyntax != FALSE);
  44. if (!InitializeCriticalSectionAndSpinCount(&m_CritSect, 0))
  45. {
  46. error = GetLastError();
  47. return HRESULT_FROM_WIN32(error);
  48. }
  49. m_CritSectInitialized = true;
  50. // Get the IClassFactory interface to be used to create the Client COM
  51. // objects
  52. HRESULT hr = CoGetClassObject(
  53. __uuidof(CClient),
  54. CLSCTX_INPROC_SERVER,
  55. 0,
  56. __uuidof(IClassFactory),
  57. reinterpret_cast<void**>(&m_pIClassFactory)
  58. );
  59. if (FAILED(hr))
  60. {
  61. return hr;
  62. }
  63. m_hResolverEvent = CreateEventW(
  64. 0, // security attribs
  65. TRUE, // manual reset
  66. TRUE, // initial state
  67. 0 // event name
  68. );
  69. if (m_hResolverEvent == 0)
  70. {
  71. error = GetLastError();
  72. return HRESULT_FROM_WIN32(error);
  73. }
  74. return S_OK;
  75. }
  76. void CClients::Shutdown() throw ()
  77. {
  78. StopResolvingClients();
  79. }
  80. HRESULT CClients::SetClients(VARIANT* pVarClients) throw ()
  81. {
  82. // check the input arguments
  83. if ((pVarClients == 0) ||
  84. (V_VT(pVarClients) != VT_DISPATCH) ||
  85. (V_DISPATCH(pVarClients) == 0))
  86. {
  87. return E_INVALIDARG;
  88. }
  89. HRESULT hr;
  90. // stop any previous client configuration in progress
  91. hr = StopResolvingClients();
  92. if (FAILED(hr))
  93. {
  94. return hr;
  95. }
  96. // get the ISdoCollection interface now
  97. CComPtr<ISdoCollection> pISdoCollection;
  98. hr = V_DISPATCH(pVarClients)->QueryInterface(
  99. __uuidof(ISdoCollection),
  100. reinterpret_cast<void**>(&pISdoCollection)
  101. );
  102. if (FAILED(hr))
  103. {
  104. return hr;
  105. }
  106. // get the number of objects in the collection
  107. LONG lCount;
  108. hr = pISdoCollection->get_Count(&lCount);
  109. if (FAILED (hr))
  110. {
  111. return hr;
  112. }
  113. else if (lCount == 0)
  114. {
  115. DeleteObjects();
  116. return S_OK;
  117. }
  118. else if (lCount > m_dwMaxClients)
  119. {
  120. IASTracePrintf(
  121. "License Violation: %ld RADIUS Clients are configured, but only "
  122. "%lu are allowed for this product type.",
  123. lCount,
  124. m_dwMaxClients
  125. );
  126. IASReportLicenseViolation();
  127. return IAS_E_LICENSE_VIOLATION;
  128. }
  129. // allocate array of CClient* to temporarily store the CClient objects until
  130. // the addresses are resolved
  131. m_pCClientArray = static_cast<CClient**>(
  132. CoTaskMemAlloc(sizeof(CClient*) * lCount)
  133. );
  134. if (m_pCClientArray == 0)
  135. {
  136. return E_OUTOFMEMORY;
  137. }
  138. // get the enumerator for the clients collection
  139. CComPtr<IUnknown> pIUnknown;
  140. hr = pISdoCollection->get__NewEnum(&pIUnknown);
  141. if (FAILED (hr))
  142. {
  143. return hr;
  144. }
  145. // get the enum variant
  146. CComPtr<IEnumVARIANT> pIEnumVariant;
  147. hr = pIUnknown->QueryInterface(
  148. __uuidof(IEnumVARIANT),
  149. reinterpret_cast<void**>(&pIEnumVariant)
  150. );
  151. if (FAILED (hr))
  152. {
  153. return hr;
  154. }
  155. // get clients out of the collection and initialize
  156. CComVariant varPerClient;
  157. DWORD dwClientsLeft;
  158. hr = pIEnumVariant->Next(1, &varPerClient, &dwClientsLeft);
  159. if (FAILED(hr))
  160. {
  161. return hr;
  162. }
  163. DWORD dwCurrentIndex = 0;
  164. while ((dwClientsLeft > 0) && (dwCurrentIndex < lCount))
  165. {
  166. // get an Sdo pointer from the variant we received
  167. CComPtr<ISdo> pISdo;
  168. hr = V_DISPATCH(&varPerClient)->QueryInterface(
  169. __uuidof(ISdo),
  170. reinterpret_cast<void**>(&pISdo)
  171. );
  172. if (FAILED(hr))
  173. {
  174. break;
  175. }
  176. // create a new Client object now
  177. CClient* pIIasClient;
  178. hr = m_pIClassFactory->CreateInstance(
  179. 0,
  180. __uuidof(CClient),
  181. reinterpret_cast<void**>(&pIIasClient)
  182. );
  183. if (FAILED(hr))
  184. {
  185. break;
  186. }
  187. // store this CClient class object in the object array temporarily
  188. m_pCClientArray[dwCurrentIndex] = pIIasClient;
  189. ++dwCurrentIndex;
  190. // initalize the client
  191. hr = pIIasClient->Init(pISdo);
  192. if (FAILED(hr))
  193. {
  194. break;
  195. }
  196. if (!m_fAllowSubnetSyntax &&
  197. IASIsStringSubNetW(pIIasClient->GetClientAddressW()))
  198. {
  199. IASTracePrintf(
  200. "License Violation: RADIUS Client '%S' uses sub-net syntax, "
  201. "which is not allowed for this product type.",
  202. pIIasClient->GetClientNameW()
  203. );
  204. IASReportLicenseViolation();
  205. hr = IAS_E_LICENSE_VIOLATION;
  206. break;
  207. }
  208. // clear the perClient value from this variant
  209. varPerClient.Clear();
  210. // get next client out of the collection
  211. hr = pIEnumVariant->Next(1, &varPerClient, &dwClientsLeft);
  212. if (FAILED(hr))
  213. {
  214. break;
  215. }
  216. }
  217. if (FAILED(hr))
  218. {
  219. FreeClientArray(dwCurrentIndex);
  220. return hr;
  221. }
  222. ConfigureCallback* cback = static_cast<ConfigureCallback*>(
  223. CoTaskMemAlloc(sizeof(ConfigureCallback))
  224. );
  225. if (cback == 0)
  226. {
  227. return E_OUTOFMEMORY;
  228. }
  229. cback->CallbackRoutine = CallbackRoutine;
  230. cback->self = this;
  231. cback->numClients = dwCurrentIndex;
  232. // We reset the event which will be set by the resolver thread when its done
  233. // and start the resolver thread
  234. ResetEvent(m_hResolverEvent);
  235. if (!IASRequestThread(cback))
  236. {
  237. CallbackRoutine(cback);
  238. }
  239. return S_OK;
  240. }
  241. BOOL CClients::FindObject(DWORD dwKey, IIasClient** ppIIasClient) throw ()
  242. {
  243. EnterCriticalSection(&m_CritSect);
  244. IIasClient* client = m_mapClients.Find(dwKey);
  245. if (ppIIasClient != 0)
  246. {
  247. *ppIIasClient = client;
  248. if (client != 0)
  249. {
  250. client->AddRef();
  251. }
  252. }
  253. LeaveCriticalSection(&m_CritSect);
  254. return client != 0;
  255. }
  256. void CClients::DeleteObjects() throw ()
  257. {
  258. m_mapClients.Clear();
  259. }
  260. void CClients::FreeClientArray(DWORD dwCount) throw ()
  261. {
  262. for (DWORD i = 0; i < dwCount; ++i)
  263. {
  264. m_pCClientArray[i]->Release();
  265. }
  266. CoTaskMemFree(m_pCClientArray);
  267. m_pCClientArray = 0;
  268. }
  269. void CClients::Resolve(DWORD dwArraySize) throw ()
  270. {
  271. // Set up iterators for the clients array.
  272. CClient** begin = m_pCClientArray;
  273. CClient** end = begin + dwArraySize;
  274. CClient** i;
  275. // Resolve the client addresses.
  276. for (i = begin; i != end; ++i)
  277. {
  278. (*i)->ResolveAddress();
  279. }
  280. //////////
  281. // Update the client map.
  282. //////////
  283. EnterCriticalSection(&m_CritSect);
  284. DeleteObjects();
  285. try
  286. {
  287. for (i = begin; i != end; ++i)
  288. {
  289. const CClient::Address* beginAddrs = (*i)->GetAddressList();
  290. for (const CClient::Address* paddr = beginAddrs;
  291. paddr->ipAddress != INADDR_NONE;
  292. ++paddr)
  293. {
  294. if ((paddr == beginAddrs) || m_fAllowSubnetSyntax)
  295. {
  296. m_mapClients.Insert(SubNet(paddr->ipAddress, paddr->width), *i);
  297. }
  298. else
  299. {
  300. IASTracePrintf(
  301. "License Restriction: RADIUS Client '%S' resolves to more "
  302. "than one IP address; on this product type only the first "
  303. "address will be used.",
  304. (*i)->GetClientNameW()
  305. );
  306. break;
  307. }
  308. }
  309. }
  310. }
  311. catch (const std::bad_alloc&)
  312. {
  313. }
  314. LeaveCriticalSection(&m_CritSect);
  315. // Clean up the array of client objects.
  316. FreeClientArray(dwArraySize);
  317. // Set the event indicating that the Resolver thread is done
  318. SetEvent(m_hResolverEvent);
  319. }
  320. HRESULT CClients::StopResolvingClients() throw ()
  321. {
  322. DWORD result = WaitForSingleObject(m_hResolverEvent, INFINITE);
  323. if (result == WAIT_FAILED)
  324. {
  325. DWORD error = GetLastError();
  326. return HRESULT_FROM_WIN32(error);
  327. }
  328. return S_OK;
  329. }
  330. void WINAPI CClients::CallbackRoutine(IAS_CALLBACK* context) throw ()
  331. {
  332. ConfigureCallback* cback = static_cast<ConfigureCallback*>(context);
  333. cback->self->Resolve(cback->numClients);
  334. CoTaskMemFree(cback);
  335. }