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.

506 lines
13 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // translate.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // Defines the class Translator.
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 02/04/2000 Original version.
  16. // 04/17/2000 Add support for UTCTime.
  17. //
  18. ///////////////////////////////////////////////////////////////////////////////
  19. #include <proxypch.h>
  20. #include <iasutil.h>
  21. #include <attrdnry.h>
  22. #include <radpack.h>
  23. #include <translate.h>
  24. //////////
  25. // The offset between the UNIX and NT epochs.
  26. //////////
  27. const ULONG64 UNIX_EPOCH = 116444736000000000ui64;
  28. ///////////////////////////////////////////////////////////////////////////////
  29. //
  30. // CLASS
  31. //
  32. // ByteSource
  33. //
  34. // DESCRIPTION
  35. //
  36. // Simple class for extracting bytes from an octet string.
  37. //
  38. ///////////////////////////////////////////////////////////////////////////////
  39. class ByteSource
  40. {
  41. public:
  42. ByteSource(const BYTE* buf, ULONG buflen) throw ()
  43. : next(buf), last(buf + buflen) { }
  44. // Returns true if there are any bytes remaining.
  45. bool more() const throw ()
  46. {
  47. return next != last;
  48. }
  49. // Extracts 'nbyte' bytes.
  50. const BYTE* extract(ULONG nbyte)
  51. {
  52. const BYTE* retval = next;
  53. // Update the cursor.
  54. next += nbyte;
  55. // Did we overflow ?
  56. if (next > last) { _com_issue_error(E_INVALIDARG); }
  57. return retval;
  58. }
  59. ULONG remaining() const throw ()
  60. {
  61. return (ULONG)(last - next);
  62. }
  63. protected:
  64. const BYTE* next; // The next byte in the stream.
  65. const BYTE* last; // The end of the stream.
  66. private:
  67. // Not implemented.
  68. ByteSource(const ByteSource&);
  69. ByteSource& operator=(const ByteSource&);
  70. };
  71. HRESULT Translator::FinalConstruct() throw ()
  72. {
  73. return dnary.FinalConstruct();
  74. }
  75. void Translator::toRadius(
  76. IASATTRIBUTE& src,
  77. IASAttributeVector& dst
  78. ) const
  79. {
  80. if (src.dwId > 0 && src.dwId < 256)
  81. {
  82. // This is already a RADIUS attribute, so all we have to do is convert
  83. // the value to an octet string.
  84. if (src.Value.itType == IASTYPE_OCTET_STRING)
  85. {
  86. // It's already an octet string, so just scatter into dst.
  87. scatter(0, src, dst);
  88. }
  89. else
  90. {
  91. // Convert to an octet string ...
  92. IASAttribute attr(true);
  93. encode(0, src, attr);
  94. // ... and scatter into dst.
  95. scatter(0, *attr, dst);
  96. }
  97. }
  98. else
  99. {
  100. // Look up the attribute definition.
  101. const AttributeDefinition* def = dnary.findByID(src.dwId);
  102. // We only process VSAs. At this point, anything else is an internal
  103. // attribute that has no RADIUS representation.
  104. if (def && def->vendorID)
  105. {
  106. // Allocate an attribute for the VSA.
  107. IASAttribute attr(true);
  108. // USR uses a different header than everybody else.
  109. ULONG headerLength = (def->vendorID != 429) ? 6 : 8;
  110. // Encode the data.
  111. ULONG dataLength = encode(headerLength, src, attr);
  112. // Pack the Vendor-Id.
  113. PBYTE buf = attr->Value.OctetString.lpValue;
  114. IASInsertDWORD(buf, def->vendorID);
  115. buf += 4;
  116. // Pack the Vendor-Type and Vendor-Length;
  117. if (def->vendorID != 429)
  118. {
  119. *buf++ = (BYTE)def->vendorType;
  120. *buf++ = (BYTE)(dataLength + 2);
  121. }
  122. else
  123. {
  124. IASInsertDWORD(buf, def->vendorType);
  125. buf += 4;
  126. }
  127. // Mark it as a VSA.
  128. attr->dwId = RADIUS_ATTRIBUTE_VENDOR_SPECIFIC;
  129. // Scatter into multiple attributes if necessary.
  130. scatter(headerLength, *attr, dst);
  131. }
  132. }
  133. }
  134. void Translator::fromRadius(
  135. const RadiusAttribute& src,
  136. DWORD flags,
  137. IASAttributeVector& dst
  138. )
  139. {
  140. if (src.type != RADIUS_ATTRIBUTE_VENDOR_SPECIFIC)
  141. {
  142. // Look this up in the dictionary.
  143. const AttributeDefinition* def = dnary.findByID(src.type);
  144. // If we don't recognize the attribute, treat it as an octet string.
  145. IASTYPE syntax = def ? (IASTYPE)def->syntax : IASTYPE_OCTET_STRING;
  146. // Create the new attribute.
  147. IASAttribute attr(true);
  148. attr->dwId = src.type;
  149. attr->dwFlags = flags;
  150. decode(syntax, src.value, src.length, attr);
  151. // Add to the destination vector.
  152. dst.push_back(attr);
  153. }
  154. else
  155. {
  156. // Create a byte source from the attribute value.
  157. ByteSource bytes(src.value, src.length);
  158. // Extract the vendor ID.
  159. ULONG vendorID = IASExtractDWORD(bytes.extract(4));
  160. // Loop through the value and convert each sub-VSA.
  161. do
  162. {
  163. // Extract the Vendor-Type and the data length.
  164. ULONG type, length;
  165. if (vendorID != 429)
  166. {
  167. type = *bytes.extract(1);
  168. length = *bytes.extract(1) - 2;
  169. }
  170. else
  171. {
  172. type = IASExtractDWORD(bytes.extract(4));
  173. length = bytes.remaining();
  174. }
  175. // Do we have this VSA in our dictionary ?
  176. const AttributeDefinition* def = dnary.findByVendorInfo(
  177. vendorID,
  178. type
  179. );
  180. if (!def)
  181. {
  182. // No, so we'll just leave it 'as is'.
  183. IASAttribute attr(true);
  184. attr->dwId = RADIUS_ATTRIBUTE_VENDOR_SPECIFIC;
  185. attr->dwFlags = flags;
  186. attr.setOctetString(src.length, src.value);
  187. dst.push_back(attr);
  188. break;
  189. }
  190. // Yes, so we can decode this properly.
  191. IASAttribute attr(true);
  192. attr->dwId = def->id;
  193. attr->dwFlags = flags;
  194. decode((IASTYPE)def->syntax, bytes.extract(length), length, attr);
  195. dst.push_back(attr);
  196. } while (bytes.more());
  197. }
  198. }
  199. void Translator::decode(
  200. IASTYPE dstType,
  201. const BYTE* src,
  202. ULONG srclen,
  203. IASAttribute& dst
  204. )
  205. {
  206. // Switch based on the destination type.
  207. switch (dstType)
  208. {
  209. case IASTYPE_BOOLEAN:
  210. {
  211. if (srclen != 4) { _com_issue_error(E_INVALIDARG); }
  212. dst->Value.Boolean = IASExtractDWORD(src) ? TRUE : FALSE;
  213. break;
  214. }
  215. case IASTYPE_INTEGER:
  216. case IASTYPE_ENUM:
  217. case IASTYPE_INET_ADDR:
  218. {
  219. if (srclen != 4) { _com_issue_error(E_INVALIDARG); }
  220. dst->Value.Integer = IASExtractDWORD(src);
  221. break;
  222. }
  223. case IASTYPE_UTC_TIME:
  224. {
  225. if (srclen != 4) { _com_issue_error(E_INVALIDARG); }
  226. // Extract the UNIX time.
  227. ULONG64 val = IASExtractDWORD(src);
  228. // Convert from seconds to 100 nsec intervals.
  229. val *= 10000000;
  230. // Shift to the NT epoch.
  231. val += 116444736000000000ui64;
  232. // Split into the high and low DWORDs.
  233. dst->Value.UTCTime.dwLowDateTime = (DWORD)val;
  234. dst->Value.UTCTime.dwHighDateTime = (DWORD)(val >> 32);
  235. break;
  236. }
  237. case IASTYPE_STRING:
  238. {
  239. dst.setString(srclen, src);
  240. break;
  241. }
  242. default:
  243. {
  244. dst.setOctetString(srclen, src);
  245. break;
  246. }
  247. }
  248. // All went well, so set type attribute type.
  249. dst->Value.itType = dstType;
  250. }
  251. ULONG Translator::getEncodedSize(
  252. const IASATTRIBUTE& src
  253. )
  254. {
  255. // Note: this is the same as RadiusUtil::getEncodedSize
  256. // only one version should be kept
  257. ULONG size;
  258. switch (src.Value.itType)
  259. {
  260. case IASTYPE_BOOLEAN:
  261. case IASTYPE_INTEGER:
  262. case IASTYPE_ENUM:
  263. case IASTYPE_INET_ADDR:
  264. case IASTYPE_UTC_TIME:
  265. {
  266. size = 4;
  267. break;
  268. }
  269. case IASTYPE_STRING:
  270. {
  271. // Convert the string to ANSI so we can count octets.
  272. DWORD dwErr = IASAttributeAnsiAlloc(const_cast<PIASATTRIBUTE>(&src));
  273. if (dwErr != NO_ERROR)
  274. {
  275. _com_issue_error(HRESULT_FROM_WIN32(dwErr));
  276. }
  277. // Allow for NULL strings and don't count the terminator.
  278. if (src.Value.String.pszAnsi)
  279. {
  280. size = strlen(src.Value.String.pszAnsi);
  281. }
  282. else
  283. {
  284. size = 0;
  285. }
  286. break;
  287. }
  288. case IASTYPE_OCTET_STRING:
  289. {
  290. size = src.Value.OctetString.dwLength;
  291. break;
  292. }
  293. default:
  294. // All other types have no wire representation.
  295. size = 0;
  296. }
  297. return size;
  298. }
  299. void Translator::encode(
  300. PBYTE dst,
  301. const IASATTRIBUTE& src
  302. ) throw ()
  303. {
  304. // Switch based on the source's type.
  305. switch (src.Value.itType)
  306. {
  307. case IASTYPE_BOOLEAN:
  308. {
  309. IASInsertDWORD(dst, (src.Value.Boolean ? 1 : 0));
  310. break;
  311. }
  312. case IASTYPE_INTEGER:
  313. case IASTYPE_ENUM:
  314. case IASTYPE_INET_ADDR:
  315. {
  316. IASInsertDWORD(dst, src.Value.Integer);
  317. break;
  318. }
  319. case IASTYPE_STRING:
  320. {
  321. const BYTE* p = (const BYTE*)src.Value.String.pszAnsi;
  322. // Don't use strcpy since we don't want the null terminator.
  323. if (p)
  324. {
  325. while (*p) { *dst++ = *p++; }
  326. }
  327. break;
  328. }
  329. case IASTYPE_UTC_TIME:
  330. {
  331. ULONG64 val;
  332. // Move in the high DWORD.
  333. val = src.Value.UTCTime.dwHighDateTime;
  334. val <<= 32;
  335. // Move in the low DWORD.
  336. val |= src.Value.UTCTime.dwLowDateTime;
  337. // Convert to the UNIX epoch.
  338. val -= UNIX_EPOCH;
  339. // Convert to seconds.
  340. val /= 10000000;
  341. IASInsertDWORD(dst, (DWORD)val);
  342. break;
  343. }
  344. case IASTYPE_OCTET_STRING:
  345. {
  346. memcpy(dst,
  347. src.Value.OctetString.lpValue,
  348. src.Value.OctetString.dwLength);
  349. }
  350. }
  351. }
  352. ULONG Translator::encode(
  353. ULONG headerLength,
  354. const IASATTRIBUTE& src,
  355. IASAttribute& dst
  356. )
  357. {
  358. // Compute the encoded size.
  359. ULONG dataLength = getEncodedSize(src);
  360. ULONG attrLength = dataLength + headerLength;
  361. // Allocate a buffer for the value.
  362. PBYTE buf = (PBYTE)CoTaskMemAlloc(attrLength);
  363. if (!buf) { _com_issue_error(E_OUTOFMEMORY); }
  364. // Encode the data.
  365. encode(buf + headerLength, src);
  366. // Store the buffer in the attribute.
  367. dst->dwId = src.dwId;
  368. dst->dwFlags = src.dwFlags;
  369. dst->Value.itType = IASTYPE_OCTET_STRING;
  370. dst->Value.OctetString.dwLength = attrLength;
  371. dst->Value.OctetString.lpValue = buf;
  372. return dataLength;
  373. }
  374. void Translator::scatter(
  375. ULONG headerLength,
  376. IASATTRIBUTE& src,
  377. IASAttributeVector& dst
  378. )
  379. {
  380. if (src.Value.OctetString.dwLength <= 253)
  381. {
  382. // If the attribute is already small enough, then there's nothing to do.
  383. dst.push_back(&src);
  384. }
  385. else
  386. {
  387. // Maximum length of data that can be store in each attribute.
  388. ULONG maxDataLength = 253 - headerLength;
  389. // Number of bytes remaining to be scattered.
  390. ULONG remaining = src.Value.OctetString.dwLength - headerLength;
  391. // Next byte to be scattered.
  392. PBYTE next = src.Value.OctetString.lpValue + headerLength;
  393. do
  394. {
  395. // Allocate an attribute for the next chunk.
  396. IASAttribute chunk(true);
  397. // Compute the data length and attribute length for this chunk.
  398. ULONG dataLength = min(remaining, maxDataLength);
  399. ULONG attrLength = dataLength + headerLength;
  400. // Allocate a buffer for the value.
  401. PBYTE buf = (PBYTE)CoTaskMemAlloc(attrLength);
  402. if (!buf) { _com_issue_error(E_OUTOFMEMORY); }
  403. // Copy in the header ...
  404. memcpy(buf, src.Value.OctetString.lpValue, headerLength);
  405. // ... and the next chunk of data.
  406. memcpy(buf + headerLength, next, dataLength);
  407. // Store the buffer in the attribute.
  408. chunk->dwId = src.dwId;
  409. chunk->dwFlags = src.dwFlags;
  410. chunk->Value.itType = IASTYPE_OCTET_STRING;
  411. chunk->Value.OctetString.dwLength = attrLength;
  412. chunk->Value.OctetString.lpValue = buf;
  413. // Append to the destination vector.
  414. dst.push_back(chunk);
  415. // Advance to the next chunk.
  416. remaining -= dataLength;
  417. next += dataLength;
  418. } while (remaining);
  419. }
  420. }