Source code of Windows XP (NT5)
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.

330 lines
9.3 KiB

  1. //#--------------------------------------------------------------
  2. //
  3. // File: tunnelpassword.cpp
  4. //
  5. // Synopsis: Implementation of CTunnelPassword class methods
  6. //
  7. //
  8. // History: 04/16/98 MKarki Created
  9. //
  10. // Copyright (C) 1997-98 Microsoft Corporation
  11. // All rights reserved.
  12. //
  13. //----------------------------------------------------------------
  14. #include "radcommon.h"
  15. #include "tunnelpassword.h"
  16. #include "align.h"
  17. #include "iastlutl.h"
  18. using namespace IASTL;
  19. const DWORD MAX_TUNNELPASSWORD_LENGTH =
  20. (MAX_ATTRIBUTE_LENGTH/AUTHENTICATOR_SIZE)*AUTHENTICATOR_SIZE;
  21. //////////
  22. // Extracts the Vendor-Type field from a Microsoft VSA. Returns zero if the
  23. // attribute is not a valid Microsoft VSA.
  24. //////////
  25. BYTE
  26. WINAPI
  27. ExtractMicrosoftVendorType(
  28. const IASATTRIBUTE& attr
  29. ) throw ()
  30. {
  31. if (attr.Value.itType == IASTYPE_OCTET_STRING &&
  32. attr.Value.OctetString.dwLength > 6 &&
  33. !memcmp(attr.Value.OctetString.lpValue, "\x00\x00\x01\x37", 4))
  34. {
  35. return *(attr.Value.OctetString.lpValue + 4);
  36. }
  37. return (BYTE)0;
  38. }
  39. //////////
  40. // Encrypts the MPPE key attributes in a request.
  41. //////////
  42. HRESULT EncryptMPPEKeys(
  43. const CPacketRadius& packet,
  44. IAttributesRaw* request
  45. ) throw ()
  46. {
  47. try
  48. {
  49. IASAttributeVectorWithBuffer<16> attrs;
  50. attrs.load(request, RADIUS_ATTRIBUTE_VENDOR_SPECIFIC);
  51. for (IASAttributeVector::iterator i = attrs.begin();
  52. i != attrs.end();
  53. ++i)
  54. {
  55. switch (ExtractMicrosoftVendorType(*(i->pAttribute)))
  56. {
  57. case 12: // MS_ATTRIBUTE_CHAP_MPPE_KEYS
  58. {
  59. packet.cryptBuffer(
  60. TRUE,
  61. FALSE,
  62. i->pAttribute->Value.OctetString.lpValue + 6,
  63. i->pAttribute->Value.OctetString.dwLength - 6
  64. );
  65. break;
  66. }
  67. case 16: // MS_ATTRIBUTE_MPPE_SEND_KEY
  68. case 17: // MS_ATTRIBUTE_MPPE_RECV_KEY
  69. {
  70. packet.cryptBuffer(
  71. TRUE,
  72. TRUE,
  73. i->pAttribute->Value.OctetString.lpValue + 6,
  74. i->pAttribute->Value.OctetString.dwLength - 6
  75. );
  76. break;
  77. }
  78. }
  79. }
  80. }
  81. catch (const _com_error& ce)
  82. {
  83. return ce.Error();
  84. }
  85. return S_OK;
  86. }
  87. //++--------------------------------------------------------------
  88. //
  89. // Function: Process
  90. //
  91. // Synopsis: This is the CTunnelPassword class public method
  92. // responsible for encrypting the Tunnel Passwords
  93. // present in an out-bound RADIUS packet
  94. //
  95. // Arguments:
  96. // PACKETTYPE - Radius packet type
  97. // IAttributesRaw*
  98. // CPacketRadius*
  99. //
  100. // Returns: HRESULT - status
  101. //
  102. // History: MKarki Created 04/16/98
  103. //
  104. //----------------------------------------------------------------
  105. HRESULT
  106. CTunnelPassword::Process (
  107. PACKETTYPE ePacketType,
  108. IAttributesRaw *pIAttributesRaw,
  109. CPacketRadius *pCPacketRadius
  110. )
  111. {
  112. HRESULT hr = S_OK;
  113. DWORD dwCount = 0;
  114. DWORD dwAttributeCount = 0;
  115. DWORD dwTunnelAttributeCount = 0;
  116. static DWORD dwTunnelPasswordType = TUNNEL_PASSWORD_ATTRIB;
  117. PATTRIBUTE pAttribute = NULL;
  118. PATTRIBUTEPOSITION pAttribPos = NULL;
  119. _ASSERT (pIAttributesRaw && pCPacketRadius);
  120. __try
  121. {
  122. //
  123. // the tunnel-password attribute only goes
  124. // into an access-accept packet
  125. //
  126. if (ACCESS_ACCEPT != ePacketType) { __leave; }
  127. // Encrypt the MPPE keys.
  128. hr = EncryptMPPEKeys(*pCPacketRadius, pIAttributesRaw);
  129. if (FAILED(hr)) { __leave; }
  130. //
  131. // get the count of the total attributes in the collection
  132. //
  133. hr = pIAttributesRaw->GetAttributeCount (&dwAttributeCount);
  134. if (FAILED (hr))
  135. {
  136. IASTracePrintf (
  137. "Unable to obtain attribute count in request "
  138. "while processing tunnel-password"
  139. );
  140. __leave;
  141. }
  142. else if (0 == dwAttributeCount)
  143. {
  144. __leave;
  145. }
  146. //
  147. // allocate memory for the ATTRIBUTEPOSITION array
  148. //
  149. pAttribPos = reinterpret_cast <PATTRIBUTEPOSITION> (
  150. ::CoTaskMemAlloc (
  151. sizeof (ATTRIBUTEPOSITION)*dwAttributeCount));
  152. if (NULL == pAttribPos)
  153. {
  154. IASTracePrintf (
  155. "Unable to allocate memory for attribute position array "
  156. "while processing tunnel-password"
  157. );
  158. hr = E_OUTOFMEMORY;
  159. __leave;
  160. }
  161. //
  162. // get the Tunnel-Password attributes from
  163. // the collection
  164. //
  165. dwTunnelAttributeCount = dwAttributeCount;
  166. hr = pIAttributesRaw->GetAttributes (
  167. &dwTunnelAttributeCount,
  168. pAttribPos,
  169. 1,
  170. &dwTunnelPasswordType
  171. );
  172. if (FAILED (hr))
  173. {
  174. IASTracePrintf (
  175. "Unable to get attributes from request "
  176. "while processing tunnel-password"
  177. );
  178. __leave;
  179. }
  180. else if (0 == dwTunnelAttributeCount)
  181. {
  182. __leave;
  183. }
  184. //
  185. // remove the Tunnel-Password attributes from the collection
  186. //
  187. hr = pIAttributesRaw->RemoveAttributes (
  188. dwTunnelAttributeCount,
  189. pAttribPos
  190. );
  191. if (FAILED (hr))
  192. {
  193. IASTracePrintf (
  194. "Unable to remove attributes from request "
  195. "while processing tunnel-password"
  196. );
  197. __leave;
  198. }
  199. //
  200. // now process the Tunnel-Password attributes
  201. for (DWORD i = 0; i < dwTunnelAttributeCount; ++i)
  202. {
  203. hr = EncryptTunnelPassword (
  204. pCPacketRadius,
  205. pIAttributesRaw,
  206. pAttribPos[i].pAttribute
  207. );
  208. if (FAILED (hr)) { __leave; }
  209. }
  210. }
  211. __finally
  212. {
  213. //
  214. // release all the Tunnel Attributes now
  215. //
  216. for (dwCount = 0; dwCount < dwTunnelAttributeCount; dwCount++)
  217. {
  218. ::IASAttributeRelease (pAttribPos[dwCount].pAttribute);
  219. }
  220. //
  221. // free the dynamically allocated memory
  222. //
  223. if (pAttribPos) { ::CoTaskMemFree (pAttribPos); }
  224. }
  225. return (hr);
  226. } // end of CRecvFromPipe::TunnelPasswordSupport method
  227. //++--------------------------------------------------------------
  228. //
  229. // Function: EncryptPassword
  230. //
  231. // Synopsis: This is the CTunnelPassword class private method
  232. // responsible for encrypting the Tunnel Password
  233. // present in an out-bound RADIUS packet. The Encrypted
  234. // password is put in an IAS attribute which is added
  235. // to the attribute collection of the outbound request.
  236. //
  237. // Arguments:
  238. // CPacketRadius*
  239. // IAttributesRaw*
  240. // PIASATTRIBUTE
  241. //
  242. // Returns: HRESULT - status
  243. //
  244. // History: MKarki Created 04/16/98
  245. //
  246. //----------------------------------------------------------------
  247. HRESULT
  248. CTunnelPassword::EncryptTunnelPassword (
  249. CPacketRadius *pCPacketRadius,
  250. IAttributesRaw *pIAttributesRaw,
  251. PIASATTRIBUTE plaintext
  252. )
  253. {
  254. // Extract the password.
  255. const IAS_OCTET_STRING& pwd = plaintext->Value.OctetString;
  256. // We must have at least 4 bytes.
  257. if (pwd.dwLength < 4) { return E_INVALIDARG; }
  258. // How many bytes do we need including padding.
  259. ULONG nbyte = ROUND_UP_COUNT(pwd.dwLength - 3, 16) + 3;
  260. if (nbyte > 253) { return E_INVALIDARG; }
  261. // Create a new IASATTRIBUTE for the encrypted value.
  262. PIASATTRIBUTE encrypted;
  263. if (IASAttributeAlloc(1, &encrypted)) { return E_OUTOFMEMORY; }
  264. encrypted->dwId = RADIUS_ATTRIBUTE_TUNNEL_PASSWORD;
  265. encrypted->dwFlags = plaintext->dwFlags;
  266. encrypted->Value.itType = IASTYPE_OCTET_STRING;
  267. encrypted->Value.OctetString.dwLength = nbyte;
  268. encrypted->Value.OctetString.lpValue = (PBYTE)CoTaskMemAlloc(nbyte);
  269. HRESULT hr;
  270. PBYTE val = encrypted->Value.OctetString.lpValue;
  271. if (val)
  272. {
  273. // Copy in the value.
  274. memcpy(val, pwd.lpValue, pwd.dwLength);
  275. // Zero out the padding.
  276. memset(val + pwd.dwLength, 0, nbyte - pwd.dwLength);
  277. // Encrypt the password.
  278. pCPacketRadius->cryptBuffer(
  279. TRUE,
  280. TRUE,
  281. val + 1,
  282. nbyte - 1
  283. );
  284. // Add the encrypted attribute to the request.
  285. ATTRIBUTEPOSITION pos;
  286. pos.pAttribute = encrypted;
  287. hr = pIAttributesRaw->AddAttributes(1, &pos);
  288. }
  289. else
  290. {
  291. hr = E_OUTOFMEMORY;
  292. }
  293. // Release the encrypted password.
  294. IASAttributeRelease(encrypted);
  295. return hr;
  296. }