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.

372 lines
9.7 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) Microsoft Corporation
  4. //
  5. // SYNOPSIS
  6. //
  7. // Defines the class Action.
  8. //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "ias.h"
  11. #include "action.h"
  12. #include "attrcvt.h"
  13. #include "eapprofile.h"
  14. #include "sdoias.h"
  15. #include "TunnelTagger.h"
  16. _COM_SMARTPTR_TYPEDEF(ISdo, __uuidof(ISdo));
  17. _COM_SMARTPTR_TYPEDEF(ISdoCollection, __uuidof(ISdoCollection));
  18. Action::Action(
  19. PCWSTR name,
  20. DWORD nameAttr,
  21. _variant_t& action,
  22. const TunnelTagger& tagger
  23. )
  24. : attributes(4),
  25. realmsTarget(RADIUS_ATTRIBUTE_USER_NAME)
  26. {
  27. using _com_util::CheckError;
  28. //////////
  29. // Add the policy name attribute.
  30. //////////
  31. IASAttribute policyName(true);
  32. policyName->dwId = nameAttr;
  33. policyName.setString(name);
  34. policyName.setFlag(IAS_INCLUDE_IN_RESPONSE);
  35. attributes.push_back(policyName);
  36. //////////
  37. // Get an enumerator for the attributes collection.
  38. //////////
  39. ISdoCollectionPtr profile(action);
  40. IUnknownPtr unk;
  41. CheckError(profile->get__NewEnum(&unk));
  42. IEnumVARIANTPtr iter(unk);
  43. //////////
  44. // Iterate through the attributes.
  45. //////////
  46. _variant_t element;
  47. unsigned long fetched;
  48. while (iter->Next(1, &element, &fetched) == S_OK && fetched == 1)
  49. {
  50. // Convert to an SDO.
  51. ISdoPtr attribute(element);
  52. element.Clear();
  53. // Get the necessary properties.
  54. _variant_t id, value, syntax;
  55. CheckError(attribute->GetProperty(PROPERTY_ATTRIBUTE_ID, &id));
  56. CheckError(attribute->GetProperty(PROPERTY_ATTRIBUTE_VALUE, &value));
  57. CheckError(attribute->GetProperty(PROPERTY_ATTRIBUTE_SYNTAX, &syntax));
  58. // Attribute-Manipulation-Rule gets processed 'as is'.
  59. if (V_I4(&id) == IAS_ATTRIBUTE_MANIPULATION_RULE)
  60. {
  61. realms.setRealms(&value);
  62. continue;
  63. }
  64. // As does the EAP per-policy config.
  65. else if (V_I4(&id) == IAS_ATTRIBUTE_EAP_CONFIG)
  66. {
  67. EapProfile eap;
  68. CheckError(eap.Load(value));
  69. while (!eap.IsEmpty())
  70. {
  71. IASAttribute config(true);
  72. EapProfile::ConfigData data;
  73. eap.Pop(data);
  74. config->dwId = IAS_ATTRIBUTE_EAP_CONFIG;
  75. config->Value.itType = IASTYPE_OCTET_STRING;
  76. config->Value.OctetString.dwLength = data.length;
  77. config->Value.OctetString.lpValue = data.value;
  78. attributes.push_back(config);
  79. }
  80. continue;
  81. }
  82. // For everything else we process the VARIANTs one at a time.
  83. VARIANT *begin, *end;
  84. if (V_VT(&value) == (VT_VARIANT | VT_ARRAY))
  85. {
  86. begin = (VARIANT*)V_ARRAY(&value)->pvData;
  87. end = begin + V_ARRAY(&value)->rgsabound[0].cElements;
  88. }
  89. else
  90. {
  91. begin = &value;
  92. end = begin + 1;
  93. }
  94. // Iterate through each value.
  95. for (VARIANT* v = begin; v != end; ++v)
  96. {
  97. // Process based on the attribute ID.
  98. switch (V_I4(&id))
  99. {
  100. case IAS_ATTRIBUTE_MANIPULATION_TARGET:
  101. {
  102. realmsTarget = V_I4(v);
  103. break;
  104. }
  105. case IAS_ATTRIBUTE_AUTH_PROVIDER_TYPE:
  106. {
  107. IASAttribute type(true);
  108. type->dwId = IAS_ATTRIBUTE_PROVIDER_TYPE;
  109. type->Value.itType = IASTYPE_ENUM;
  110. type->Value.Integer = V_I4(v);
  111. authProvider.push_back(type);
  112. break;
  113. }
  114. case IAS_ATTRIBUTE_AUTH_PROVIDER_NAME:
  115. {
  116. IASAttribute name(true);
  117. name->dwId = IAS_ATTRIBUTE_PROVIDER_NAME;
  118. name.setString(V_BSTR(v));
  119. authProvider.push_back(name);
  120. break;
  121. }
  122. case IAS_ATTRIBUTE_ACCT_PROVIDER_TYPE:
  123. {
  124. IASAttribute type(true);
  125. type->dwId = IAS_ATTRIBUTE_PROVIDER_TYPE;
  126. type->Value.itType = IASTYPE_ENUM;
  127. type->Value.Integer = V_I4(v);
  128. acctProvider.push_back(type);
  129. break;
  130. }
  131. case IAS_ATTRIBUTE_ACCT_PROVIDER_NAME:
  132. {
  133. IASAttribute name(true);
  134. name->dwId = IAS_ATTRIBUTE_PROVIDER_NAME;
  135. name.setString(V_BSTR(v));
  136. acctProvider.push_back(name);
  137. break;
  138. }
  139. case RADIUS_ATTRIBUTE_VENDOR_SPECIFIC:
  140. {
  141. IASAttribute attr(VSAFromString(V_BSTR(v)), false);
  142. attr->dwId = RADIUS_ATTRIBUTE_VENDOR_SPECIFIC;
  143. attr.setFlag(IAS_INCLUDE_IN_ACCEPT);
  144. attributes.push_back(attr);
  145. break;
  146. }
  147. default:
  148. {
  149. IASTYPEENUM type = (IASTYPEENUM)V_I4(&syntax);
  150. IASAttribute attr(IASAttributeFromVariant(v, type), false);
  151. attr->dwId = V_I4(&id);
  152. attr.setFlag(IAS_INCLUDE_IN_ACCEPT);
  153. attributes.push_back(attr);
  154. }
  155. }
  156. }
  157. }
  158. tagger.Tag(attributes);
  159. }
  160. void Action::doAction(IASRequest& request) const
  161. {
  162. // Populate the provider information:
  163. switch (request.get_Request())
  164. {
  165. case IAS_REQUEST_ACCESS_REQUEST:
  166. authProvider.store(request);
  167. break;
  168. case IAS_REQUEST_ACCOUNTING:
  169. acctProvider.store(request);
  170. break;
  171. }
  172. // Perform attribute manipulation.
  173. if (!realms.empty())
  174. {
  175. IASAttribute attr;
  176. attr.load(request, realmsTarget, IASTYPE_OCTET_STRING);
  177. if (attr)
  178. {
  179. CComBSTR newVal;
  180. realms.process(IAS_OCT2WIDE(attr->Value.OctetString), &newVal);
  181. if (newVal)
  182. {
  183. if (realmsTarget == RADIUS_ATTRIBUTE_USER_NAME)
  184. {
  185. IASAttribute userName(true);
  186. userName->dwId = RADIUS_ATTRIBUTE_USER_NAME;
  187. userName->dwFlags = attr->dwFlags;
  188. userName.setOctetString(newVal);
  189. userName.store(request);
  190. // Now that the new User-Name is safely stored, we can rename
  191. // the old User-Name.
  192. attr->dwId = IAS_ATTRIBUTE_ORIGINAL_USER_NAME;
  193. }
  194. else
  195. {
  196. // No need to save the old, so modify in place.
  197. attr.setOctetString(newVal);
  198. }
  199. }
  200. }
  201. }
  202. // Store the profile attributes.
  203. attributes.store(request);
  204. }
  205. /////////
  206. // Various formats of VSA strings.
  207. /////////
  208. enum Format
  209. {
  210. FORMAT_RAW_HEX,
  211. FORMAT_STRING,
  212. FORMAT_INTEGER,
  213. FORMAT_HEX,
  214. FORMAT_INET_ADDR
  215. };
  216. /////////
  217. // Layout of the VSA strings.
  218. /////////
  219. struct VSAFormat
  220. {
  221. WCHAR format[2];
  222. WCHAR vendorID[8];
  223. union
  224. {
  225. WCHAR rawValue[1];
  226. struct
  227. {
  228. WCHAR vendorType[2];
  229. WCHAR vendorLength[2];
  230. WCHAR value[1];
  231. };
  232. };
  233. };
  234. //////////
  235. // Convert a hex digit to the number it represents.
  236. //////////
  237. BYTE digit2Num(WCHAR digit) throw ()
  238. {
  239. if ((digit >= L'0') && (digit <= L'9'))
  240. {
  241. return digit - L'0';
  242. }
  243. else if ((digit >= L'A') && (digit <= L'F'))
  244. {
  245. return digit - (L'A' - 10);
  246. }
  247. else
  248. {
  249. return digit - (L'a' - 10);
  250. }
  251. }
  252. //////////
  253. // Pack a hex digit into a byte stream.
  254. //////////
  255. PBYTE packHex(PCWSTR src, ULONG srclen, PBYTE dst) throw ()
  256. {
  257. for (ULONG dstlen = srclen / 2; dstlen; --dstlen)
  258. {
  259. *dst = digit2Num(*src++) << 4;
  260. *dst++ |= digit2Num(*src++);
  261. }
  262. return dst;
  263. }
  264. //////////
  265. // Convert a string describing a VSA into an IASATTRIBUTE.
  266. //////////
  267. PIASATTRIBUTE Action::VSAFromString(PCWSTR string)
  268. {
  269. // Number of characters to process.
  270. SIZE_T len = wcslen(string);
  271. // Overlay the layout struct.
  272. VSAFormat* vsa = (VSAFormat*)string;
  273. // Get the string format.
  274. ULONG format = digit2Num(vsa->format[0]);
  275. format <<= 8;
  276. format |= digit2Num(vsa->format[1]);
  277. // Temporary buffer used for formatting the VSA.
  278. BYTE buffer[253], *dst = buffer;
  279. // Pack the Vendor-ID.
  280. dst = packHex(vsa->vendorID, 8, dst);
  281. // Pack the Vendor-Type and Vendor-Length for conformant VSAs.
  282. if (format != FORMAT_RAW_HEX)
  283. {
  284. dst = packHex(vsa->vendorType, 2, dst);
  285. dst = packHex(vsa->vendorLength, 2, dst);
  286. }
  287. // Pack the value.
  288. switch (format)
  289. {
  290. case FORMAT_RAW_HEX:
  291. {
  292. dst = packHex(
  293. vsa->rawValue,
  294. len - 10,
  295. dst
  296. );
  297. break;
  298. }
  299. case FORMAT_INTEGER:
  300. case FORMAT_HEX:
  301. case FORMAT_INET_ADDR:
  302. {
  303. dst = packHex(
  304. vsa->value,
  305. len - 14,
  306. dst
  307. );
  308. break;
  309. }
  310. case FORMAT_STRING:
  311. {
  312. int nchar = WideCharToMultiByte(
  313. CP_ACP,
  314. 0,
  315. vsa->value,
  316. len - 14,
  317. (PSTR)dst,
  318. sizeof(buffer) - 6,
  319. NULL,
  320. NULL
  321. );
  322. dst += nchar;
  323. break;
  324. }
  325. }
  326. // Store the temporary buffer in an attribute ...
  327. IASAttribute attr(true);
  328. attr.setOctetString(dst - buffer, buffer);
  329. // ... and return.
  330. return attr.detach();
  331. }