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.

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