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.

424 lines
10 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // formbuf.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // Defines the class FormattedBuffer.
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 08/04/1998 Original version.
  16. // 12/17/1998 Add append overload for IASATTRIBUTE&.
  17. // 01/22/1999 UTF-8 support.
  18. // 01/25/1999 Date and time are separate fields.
  19. // 03/23/1999 Add support for text qualifiers.
  20. // 04/19/1999 Strip null-terminators from OctetStrings.
  21. // 05/17/1999 Handle ANSI strings correctly.
  22. // 06/01/1999 Make sure Class 'string' is printable.
  23. //
  24. ///////////////////////////////////////////////////////////////////////////////
  25. #include <ias.h>
  26. #include <iasattr.h>
  27. #include <iasutil.h>
  28. #include <iasutf8.h>
  29. #include <sdoias.h>
  30. #include <classattr.h>
  31. #include <formbuf.h>
  32. //////////
  33. // Helper function that returns the number of printable characters if an
  34. // OctetString consists solely of printable UTF-8 characters.
  35. //////////
  36. DWORD
  37. WINAPI
  38. IsOctetStringPrintable(
  39. PBYTE buf,
  40. DWORD buflen
  41. ) throw ()
  42. {
  43. // Is the last character just a null terminator?
  44. if (buflen && !buf[buflen - 1]) { --buflen; }
  45. PBYTE p = buf;
  46. PBYTE end = buf + buflen;
  47. // Scan for control characters and delimiters.
  48. while (p < end)
  49. {
  50. if (!(*p & 0x60)) { return 0; }
  51. ++p;
  52. }
  53. // Ensure it's a valid UTF-8 string.
  54. return (IASUtf8ToUnicodeLength((PCSTR)buf, buflen) >= 0) ? buflen : 0;
  55. }
  56. void FormattedBuffer::append(DWORD value)
  57. {
  58. CHAR buffer[11], *p = buffer + 11;
  59. do
  60. {
  61. *--p = '0' + (CHAR)(value % 10);
  62. } while (value /= 10);
  63. append((const BYTE*)p, (DWORD)(buffer + 11 - p));
  64. }
  65. void FormattedBuffer::append(DWORDLONG value)
  66. {
  67. CHAR buffer[21], *p = buffer + 21;
  68. do
  69. {
  70. *--p = '0' + (CHAR)(value % 10);
  71. } while (value /= 10);
  72. append((const BYTE*)p, (DWORD)(buffer + 21 - p));
  73. }
  74. void FormattedBuffer::append(const IASVALUE& value)
  75. {
  76. switch (value.itType)
  77. {
  78. case IASTYPE_BOOLEAN:
  79. case IASTYPE_INTEGER:
  80. case IASTYPE_ENUM:
  81. {
  82. append(value.Integer);
  83. break;
  84. }
  85. case IASTYPE_OCTET_STRING:
  86. case IASTYPE_PROV_SPECIFIC:
  87. {
  88. append(value.OctetString);
  89. break;
  90. }
  91. case IASTYPE_INET_ADDR:
  92. {
  93. CHAR buffer[16];
  94. append(ias_inet_htoa(value.InetAddr, buffer));
  95. break;
  96. }
  97. case IASTYPE_STRING:
  98. {
  99. // Make sure we have a Unicode string available.
  100. if (!value.String.pszWide)
  101. {
  102. // If there's no ANSI string either, then there's nothing to log.
  103. if (!value.String.pszAnsi) { break; }
  104. // Convert the value into an attribute ...
  105. PIASATTRIBUTE p = (PIASATTRIBUTE)
  106. ((ULONG_PTR)&value - FIELD_OFFSET(IASATTRIBUTE, Value));
  107. // ... and allocate a Unicode string.
  108. if (IASAttributeUnicodeAlloc(p) != NO_ERROR)
  109. {
  110. throw std::bad_alloc();
  111. }
  112. }
  113. // Compute the length of the source Unicode string.
  114. DWORD srclen = wcslen(value.String.pszWide);
  115. // Compute the length of the converted UTF-8 string.
  116. LONG dstlen = IASUnicodeToUtf8Length(value.String.pszWide, srclen);
  117. // Allocate space for the converted string.
  118. PSTR dst = (PSTR)_alloca(dstlen);
  119. // Convert the string.
  120. IASUnicodeToUtf8(value.String.pszWide, srclen, dst);
  121. // Write the buffer.
  122. appendText(dst, dstlen);
  123. break;
  124. }
  125. case IASTYPE_UTC_TIME:
  126. {
  127. SYSTEMTIME st;
  128. FileTimeToSystemTime(&value.UTCTime, &st);
  129. appendDate(st);
  130. append(' ');
  131. appendTime(st);
  132. break;
  133. }
  134. }
  135. }
  136. //////////
  137. // Appends a single attribute value.
  138. //////////
  139. void FormattedBuffer::append(const IASATTRIBUTE& attr)
  140. {
  141. // Class attributes are special-cased.
  142. if (attr.dwId == RADIUS_ATTRIBUTE_CLASS)
  143. {
  144. appendClassAttribute(attr.Value.OctetString);
  145. }
  146. else
  147. {
  148. append(attr.Value);
  149. }
  150. }
  151. //////////
  152. // Appends an array of attributes. The array is terminated either by a null
  153. // attribute pointer or an attribute with a different ID.
  154. //////////
  155. void FormattedBuffer::append(const ATTRIBUTEPOSITION* pos)
  156. {
  157. DWORD id = pos->pAttribute->dwId;
  158. // Will this attribute be written as text?
  159. BOOL isText = FALSE;
  160. switch (pos->pAttribute->Value.itType)
  161. {
  162. case IASTYPE_INET_ADDR:
  163. case IASTYPE_STRING:
  164. case IASTYPE_OCTET_STRING:
  165. case IASTYPE_PROV_SPECIFIC:
  166. isText = TRUE;
  167. }
  168. // If so, then we surround it with the text qualifier.
  169. if (isText) { appendQualifier(); }
  170. // Write the first value.
  171. append(*(pos->pAttribute));
  172. ++pos;
  173. // Then add any additional values delimited by a pipe.
  174. while (pos->pAttribute && pos->pAttribute->dwId == id)
  175. {
  176. append('|');
  177. append(*(pos->pAttribute));
  178. ++pos;
  179. }
  180. // Write the closing text qualifier if necessary.
  181. if (isText) { appendQualifier(); }
  182. }
  183. //////////
  184. // Appends an octet string attribute value.
  185. //////////
  186. void FormattedBuffer::append(const IAS_OCTET_STRING& value)
  187. {
  188. DWORD len = IsOctetStringPrintable(value.lpValue, value.dwLength);
  189. if (len)
  190. {
  191. appendText((PCSTR)value.lpValue, len);
  192. }
  193. else
  194. {
  195. appendFormattedOctets(value.lpValue, value.dwLength);
  196. }
  197. }
  198. //////////
  199. // Appends a class attribute
  200. //////////
  201. void FormattedBuffer::appendClassAttribute(const IAS_OCTET_STRING& value)
  202. {
  203. // Extract a class attribute from the blob.
  204. IASClass* cl = (IASClass*)value.lpValue;
  205. if (!cl->isMicrosoft(value.dwLength))
  206. {
  207. // If it's not one of ours try to write is as a string
  208. append(value);
  209. }
  210. else
  211. {
  212. // Vendor ID.
  213. append(cl->getVendorID());
  214. // Version.
  215. append(' ');
  216. append((DWORD)cl->getVersion());
  217. // Server IP address.
  218. CHAR buffer[16];
  219. append(' ');
  220. append(ias_inet_htoa(cl->getServerAddress(), buffer));
  221. // Server reboot time.
  222. FILETIME ft = cl->getLastReboot();
  223. SYSTEMTIME st;
  224. FileTimeToSystemTime(&ft, &st);
  225. append(' ');
  226. appendDate(st);
  227. append(' ');
  228. appendTime(st);
  229. // Session serial number.
  230. DWORDLONG serialNumber = cl->getSerialNumber();
  231. append(' ');
  232. append(serialNumber);
  233. // Class string.
  234. if (value.dwLength > sizeof(IASClass))
  235. {
  236. append(' ');
  237. // Convert the remainder to an OctetString ...
  238. IASVALUE tmp;
  239. tmp.itType = IASTYPE_OCTET_STRING;
  240. tmp.OctetString.lpValue = const_cast<PBYTE>(cl->getString());
  241. tmp.OctetString.dwLength = value.dwLength - sizeof(IASClass);
  242. // ... and append.
  243. append(tmp);
  244. }
  245. }
  246. }
  247. // Convert a hex number to an ascii digit. Does not check for overflow.
  248. #define HEX_TO_ASCII(h) ((h) < 10 ? '0' + (CHAR)(h) : ('A' - 10) + (CHAR)(h))
  249. //////////
  250. // Appends an octet string as stringized hex.
  251. //////////
  252. void FormattedBuffer::appendFormattedOctets(
  253. const BYTE* buf,
  254. DWORD buflen
  255. )
  256. {
  257. PCHAR dst = (PCHAR)reserve(buflen * 2 + 2);
  258. //////////
  259. // Add a leading 0x.
  260. //////////
  261. *dst = '0';
  262. ++dst;
  263. *dst = 'x';
  264. ++dst;
  265. //////////
  266. // Add each octet.
  267. //////////
  268. while (buflen)
  269. {
  270. CHAR digit;
  271. // High-order digit.
  272. digit = (CHAR)(*buf >> 4);
  273. *dst = HEX_TO_ASCII(digit);
  274. ++dst;
  275. // Low-order digit.
  276. digit = (CHAR)(*buf & 0xf);
  277. *dst = HEX_TO_ASCII(digit);
  278. ++dst;
  279. // Advance to the next octet.
  280. ++buf;
  281. --buflen;
  282. }
  283. }
  284. // insert a 4 character integer.
  285. #define INSERT_4u(p, v) \
  286. { *p = '0' + (v) / 1000; ++p; *p = '0' + (v) / 100 % 10; ++p; \
  287. *p = '0' + (v) / 10 % 10; ++p; *p = '0' + (v) % 10; ++p; }
  288. // insert a 2 character integer.
  289. #define INSERT_2u(p, v) \
  290. { *p = '0' + (v) / 10; ++p; *p = '0' + (v) % 10; ++p; }
  291. // insert a single character.
  292. #define INSERT_1c(p, v) \
  293. { *p = v; ++p; }
  294. void FormattedBuffer::appendDate(const SYSTEMTIME& value)
  295. {
  296. PCHAR p = (PCHAR)reserve(10);
  297. INSERT_2u(p, value.wMonth);
  298. INSERT_1c(p, '/');
  299. INSERT_2u(p, value.wDay);
  300. INSERT_1c(p, '/');
  301. INSERT_4u(p, value.wYear);
  302. }
  303. void FormattedBuffer::appendText(PCSTR sz, DWORD szlen)
  304. {
  305. if (textQualifier)
  306. {
  307. /////////
  308. // We have a text qualifier, so we don't have to worry about embedded
  309. // delimiters, but we do have to worry about embedded qualifiers. We
  310. // replace each embedded qualifier with a double qualifier.
  311. /////////
  312. PCSTR p;
  313. while ((p = (PCSTR)memchr(sz, textQualifier, szlen)) != NULL)
  314. {
  315. // Skip past the qualifier.
  316. ++p;
  317. // How many bytes do we have ?
  318. DWORD nbyte = p - sz;
  319. // Write the bytes.
  320. append((const BYTE*)sz, nbyte);
  321. // Add an extra qualifer.
  322. append(textQualifier);
  323. // Update our state to point to the remainder of the text.
  324. sz = p;
  325. szlen -= nbyte;
  326. }
  327. // Write the piece after the last embedded qualifer.
  328. append((PBYTE)sz, szlen);
  329. }
  330. else
  331. {
  332. ////////
  333. // No text qualifer, so we can't handle embedded delimiter.
  334. ////////
  335. if (!memchr(sz, ',', szlen))
  336. {
  337. // No delimiters, so write 'as is'.
  338. append((PBYTE)sz, szlen);
  339. }
  340. else
  341. {
  342. // It contains a delimiter so write as formatted octets.
  343. appendFormattedOctets((PBYTE)sz, szlen);
  344. }
  345. }
  346. }
  347. void FormattedBuffer::appendTime(const SYSTEMTIME& value)
  348. {
  349. PCHAR p = (PCHAR)reserve(8);
  350. INSERT_2u(p, value.wHour);
  351. INSERT_1c(p, ':');
  352. INSERT_2u(p, value.wMinute);
  353. INSERT_1c(p, ':');
  354. INSERT_2u(p, value.wSecond);
  355. }