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.

514 lines
11 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) Microsoft Corporation
  4. //
  5. // SYNOPSIS
  6. //
  7. // Defines the class EapProfile.
  8. //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "ias.h"
  11. #include <algorithm>
  12. #include "EapProfile.h"
  13. #include <align.h>
  14. EapProfile::EapProfile() throw ()
  15. : begin(0),
  16. end(0),
  17. capacity(0)
  18. {
  19. }
  20. EapProfile::~EapProfile() throw ()
  21. {
  22. Clear();
  23. CoTaskMemFree(begin);
  24. }
  25. HRESULT EapProfile::Assign(const EapProfile& rhs) throw ()
  26. {
  27. if (this == &rhs)
  28. {
  29. return S_OK;
  30. }
  31. Clear();
  32. Reserve(rhs.Size());
  33. for (const ConfigData* i = rhs.begin; i != rhs.end; ++i)
  34. {
  35. end->length = i->length;
  36. end->value = static_cast<BYTE*>(CoTaskMemAlloc(i->length));
  37. if (end->value == 0)
  38. {
  39. Clear();
  40. return E_OUTOFMEMORY;
  41. }
  42. memcpy(end->value, i->value, i->length);
  43. ++end;
  44. }
  45. return S_OK;
  46. }
  47. HRESULT EapProfile::Load(VARIANT& src) throw ()
  48. {
  49. HRESULT hr;
  50. Clear();
  51. if (V_VT(&src) == VT_EMPTY)
  52. {
  53. return S_OK;
  54. }
  55. if (V_VT(&src) != (VT_ARRAY | VT_VARIANT))
  56. {
  57. return DISP_E_TYPEMISMATCH;
  58. }
  59. const SAFEARRAY* sa = V_ARRAY(&src);
  60. if (sa == 0)
  61. {
  62. return E_POINTER;
  63. }
  64. // Find the first and last elements of the VARIANT array.
  65. VARIANT* first = static_cast<VARIANT*>(sa->pvData);
  66. VARIANT* last = first + sa->rgsabound[0].cElements;
  67. // Ensure that all the VARIANTs contain a valid config value.
  68. for (const VARIANT* i = first; i != last; ++i)
  69. {
  70. hr = ValidateConfigChunk(*i);
  71. if (FAILED(hr))
  72. {
  73. return hr;
  74. }
  75. }
  76. // Sort the VARIANTs by type and sequence.
  77. std::sort(first, last, LessThan);
  78. // Gather the config for each type.
  79. for (const VARIANT* j = first; j != last; )
  80. {
  81. BYTE type = ExtractString(*j)[0];
  82. // Find the end of the type's config.
  83. const VARIANT* typeEnd = j + 1;
  84. while ((typeEnd != last) && (ExtractString(*typeEnd)[0] == type))
  85. {
  86. ++typeEnd;
  87. }
  88. // Gather the config for this type.
  89. hr = GatherAndAppend(j, typeEnd);
  90. if (FAILED(hr))
  91. {
  92. return hr;
  93. }
  94. // Advance to the next type.
  95. j = typeEnd;
  96. }
  97. return S_OK;
  98. }
  99. HRESULT EapProfile::Store(VARIANT& dst) throw ()
  100. {
  101. HRESULT hr;
  102. // Clear the out parameter.
  103. VariantInit(&dst);
  104. // Computer the number of VARIANTs required.
  105. DWORD nelem = 0;
  106. for (const ConfigData* i = begin; i != end; ++i)
  107. {
  108. nelem += ChunksRequired(*i);
  109. }
  110. // Allocate the SAFEARRAY for the result.
  111. SAFEARRAY* sa = SafeArrayCreateVector(VT_VARIANT, 0, nelem);
  112. if (sa == 0)
  113. {
  114. return E_OUTOFMEMORY;
  115. }
  116. // Scatter the config into the SAFEARRAY.
  117. VARIANT* nextValue = static_cast<VARIANT*>(sa->pvData);
  118. for (const ConfigData* j = begin; j != end; ++j)
  119. {
  120. hr = Scatter(*j, nextValue);
  121. if (FAILED(hr))
  122. {
  123. SafeArrayDestroy(sa);
  124. return hr;
  125. }
  126. }
  127. // Store the result.
  128. V_VT(&dst) = VT_ARRAY | VT_VARIANT;
  129. V_ARRAY(&dst) = sa;
  130. return S_OK;
  131. }
  132. void EapProfile::Clear() throw ()
  133. {
  134. while (end > begin)
  135. {
  136. --end;
  137. CoTaskMemFree(end->value);
  138. }
  139. }
  140. void EapProfile::ClearExcept(BYTE type) throw ()
  141. {
  142. for (ConfigData* i = begin; i != end; )
  143. {
  144. if (i->value[0] != type)
  145. {
  146. // Free the config.
  147. CoTaskMemFree(i->value);
  148. // Decrement the number of elements.
  149. --end;
  150. // After Load completes we don't care if the array is sorted so we can
  151. // just move the last element into the empty slot.
  152. *i = *end;
  153. }
  154. else
  155. {
  156. ++i;
  157. }
  158. }
  159. }
  160. void EapProfile::Erase(BYTE type) throw ()
  161. {
  162. for (ConfigData* i = begin; i != end; ++i)
  163. {
  164. if (i->value[0] == type)
  165. {
  166. // Free the config.
  167. CoTaskMemFree(i->value);
  168. // Decrement the number of elements.
  169. --end;
  170. // After Load completes we don't care if the array is sorted so we can
  171. // just move the last element into the empty slot.
  172. *i = *end;
  173. break;
  174. }
  175. }
  176. }
  177. void EapProfile::Get(BYTE type, ConstConfigData& dst) const throw ()
  178. {
  179. for (const ConfigData* i = begin; i != end; ++i)
  180. {
  181. if (i->value[0] == type)
  182. {
  183. // The EAP DLL doesn't want the type byte.
  184. dst.length = i->length - ALIGN_WORST;
  185. dst.value = i->value + ALIGN_WORST;
  186. return;
  187. }
  188. }
  189. dst.length = 0;
  190. dst.value = 0;
  191. }
  192. HRESULT EapProfile::Set(BYTE type, const ConstConfigData& newConfig) throw ()
  193. {
  194. if (newConfig.length == 0)
  195. {
  196. Erase(type);
  197. return S_OK;
  198. }
  199. if (newConfig.value == 0)
  200. {
  201. return E_POINTER;
  202. }
  203. if (ChunksRequired(newConfig) > maxChunks)
  204. {
  205. return E_INVALIDARG;
  206. }
  207. // Ensure that we have room for the new element before we copy the value.
  208. HRESULT hr = Reserve(Size() + 1);
  209. if (FAILED(hr))
  210. {
  211. return hr;
  212. }
  213. // One extra byte for the type tag. Rounded to ALIGN_WORST
  214. DWORD len = newConfig.length + ALIGN_WORST;
  215. BYTE* val = static_cast<BYTE*>(CoTaskMemAlloc(len));
  216. if (val == 0)
  217. {
  218. return E_OUTOFMEMORY;
  219. }
  220. // Erase any existing config for the type.
  221. Erase(type);
  222. // Start with the lead type byte.
  223. val[0] = type;
  224. // And then the rest of the configuration.
  225. memcpy(val + ALIGN_WORST, newConfig.value, newConfig.length);
  226. // Append the result.
  227. end->length = len;
  228. end->value = val;
  229. ++end;
  230. return S_OK;
  231. }
  232. void EapProfile::Pop(ConfigData& dst) throw ()
  233. {
  234. --end;
  235. dst = *end;
  236. }
  237. void EapProfile::Swap(EapProfile& other) throw ()
  238. {
  239. std::swap(begin, other.begin);
  240. std::swap(end, other.end);
  241. std::swap(capacity, other.capacity);
  242. }
  243. inline EapProfile::SeqNum EapProfile::ExtractSequence(const BYTE* src) throw ()
  244. {
  245. return (static_cast<SeqNum>(src[0]) << 8) | static_cast<SeqNum>(src[1]);
  246. }
  247. inline void EapProfile::InsertSequence(SeqNum seq, BYTE* dst) throw ()
  248. {
  249. dst[0] = static_cast<BYTE>((seq >> 8) & 0xFF);
  250. dst[1] = static_cast<BYTE>(seq & 0xFF);
  251. }
  252. HRESULT EapProfile::GatherAndAppend(
  253. const VARIANT* first,
  254. const VARIANT* last
  255. ) throw ()
  256. {
  257. HRESULT hr = Reserve(Size() + 1);
  258. if (FAILED(hr))
  259. {
  260. return hr;
  261. }
  262. // 1 type byte for the entire config.
  263. DWORD len = ALIGN_WORST;
  264. for (const VARIANT* i = first; i != last; ++i)
  265. {
  266. // Ignore the SDO header.
  267. len += ExtractLength(*i) - sdoHeaderSize;
  268. }
  269. BYTE* val = static_cast<BYTE*>(CoTaskMemAlloc(len));
  270. if (val == 0)
  271. {
  272. return E_OUTOFMEMORY;
  273. }
  274. end->length = len;
  275. end->value = val;
  276. ++end;
  277. // Get the type byte out of the first chunk.
  278. val[0] = ExtractString(*first)[0];
  279. // keep the real value aligned
  280. val += ALIGN_WORST;
  281. // Now concatenate the chunks, ignoring the header.
  282. for (const VARIANT* j = first; j != last; ++j)
  283. {
  284. size_t chunkSize = (ExtractLength(*j) - sdoHeaderSize);
  285. memcpy(val, (ExtractString(*j) + sdoHeaderSize), chunkSize);
  286. val += chunkSize;
  287. }
  288. return S_OK;
  289. }
  290. HRESULT EapProfile::Scatter(
  291. const ConstConfigData& src,
  292. VARIANT*& dst
  293. ) throw ()
  294. {
  295. BYTE type = src.value[0];
  296. const BYTE* val = src.value + ALIGN_WORST;
  297. DWORD len = src.length - ALIGN_WORST;
  298. // Sequence number.
  299. SeqNum sequence = 0;
  300. // Keep scattering until it's all gone.
  301. while (len > 0)
  302. {
  303. // Compute the size of this chunk.
  304. size_t chunkSize = (len > maxChunkSize) ? maxChunkSize : len;
  305. // Create a SAFEARRAY of BYTEs to hold the data.
  306. SAFEARRAY* sa = SafeArrayCreateVector(
  307. VT_UI1,
  308. 0,
  309. (chunkSize + sdoHeaderSize)
  310. );
  311. if (sa == 0)
  312. {
  313. return E_OUTOFMEMORY;
  314. }
  315. // Add the type byte and sequence number.
  316. BYTE* chunk = static_cast<BYTE*>(sa->pvData);
  317. chunk[0] = type;
  318. InsertSequence(sequence, chunk + 1);
  319. memcpy(chunk + sdoHeaderSize, val, chunkSize);
  320. // Store it in the dst VARIANT.
  321. V_VT(dst) = VT_ARRAY | VT_UI1;
  322. V_ARRAY(dst) = sa;
  323. ++dst;
  324. // Update our cursor.
  325. val += chunkSize;
  326. len -= chunkSize;
  327. ++sequence;
  328. }
  329. return S_OK;
  330. }
  331. HRESULT EapProfile::Reserve(size_t newCapacity) throw ()
  332. {
  333. if (newCapacity <= capacity)
  334. {
  335. return S_OK;
  336. }
  337. // Ensure we grow wisely.
  338. const size_t minGrowth = (capacity < 4) ? 4 : ((capacity * 3) / 2);
  339. if (newCapacity < minGrowth)
  340. {
  341. newCapacity = minGrowth;
  342. }
  343. // Allocate the new array.
  344. size_t nbyte = newCapacity * sizeof(ConfigData);
  345. ConfigData* newBegin = static_cast<ConfigData*>(
  346. CoTaskMemAlloc(nbyte)
  347. );
  348. if (newBegin == 0)
  349. {
  350. return E_OUTOFMEMORY;
  351. }
  352. // Save the existing data.
  353. memcpy(newBegin, begin, Size() * sizeof(ConfigData));
  354. // Update the state.
  355. end = newBegin + Size();
  356. capacity = newCapacity;
  357. // Now it's safe to free the old array and swap in the new.
  358. CoTaskMemFree(begin);
  359. begin = newBegin;
  360. return S_OK;
  361. }
  362. inline size_t EapProfile::ChunksRequired(const ConstConfigData& str) throw ()
  363. {
  364. return ((str.length - ALIGN_WORST) + (maxChunkSize - 1)) / maxChunkSize;
  365. }
  366. inline DWORD EapProfile::ExtractLength(const VARIANT& src) throw ()
  367. {
  368. return V_ARRAY(&src)->rgsabound[0].cElements;
  369. }
  370. inline const BYTE* EapProfile::ExtractString(const VARIANT& src) throw ()
  371. {
  372. return static_cast<const BYTE*>(V_ARRAY(&src)->pvData);
  373. }
  374. bool EapProfile::LessThan(const VARIANT& lhs, const VARIANT& rhs) throw ()
  375. {
  376. const BYTE* val1 = ExtractString(lhs);
  377. const BYTE* val2 = ExtractString(rhs);
  378. // Sort first by type, then sequence.
  379. if (val1[0] < val2[0])
  380. {
  381. return true;
  382. }
  383. else if (val1[0] == val2[0])
  384. {
  385. return ExtractSequence(val1 + 1) < ExtractSequence(val2 + 1);
  386. }
  387. else
  388. {
  389. return false;
  390. }
  391. }
  392. HRESULT EapProfile::ValidateConfigChunk(const VARIANT& value) throw ()
  393. {
  394. if (V_VT(&value) != (VT_ARRAY | VT_UI1))
  395. {
  396. return DISP_E_TYPEMISMATCH;
  397. }
  398. const SAFEARRAY* sa = V_ARRAY(&value);
  399. if (sa == 0)
  400. {
  401. return E_POINTER;
  402. }
  403. // The data has to be big enough for the header and 1 data byte.
  404. if (sa->rgsabound[0].cElements <= sdoHeaderSize)
  405. {
  406. return E_INVALIDARG;
  407. }
  408. return S_OK;
  409. }