windows-nt/Source/XPSP1/NT/net/ias/protocol/radius/tunnelpassword.cpp
2020-09-26 16:20:57 +08:00

331 lines
9.3 KiB
C++

//#--------------------------------------------------------------
//
// File: tunnelpassword.cpp
//
// Synopsis: Implementation of CTunnelPassword class methods
//
//
// History: 04/16/98 MKarki Created
//
// Copyright (C) 1997-98 Microsoft Corporation
// All rights reserved.
//
//----------------------------------------------------------------
#include "radcommon.h"
#include "tunnelpassword.h"
#include "align.h"
#include "iastlutl.h"
using namespace IASTL;
const DWORD MAX_TUNNELPASSWORD_LENGTH =
(MAX_ATTRIBUTE_LENGTH/AUTHENTICATOR_SIZE)*AUTHENTICATOR_SIZE;
//////////
// Extracts the Vendor-Type field from a Microsoft VSA. Returns zero if the
// attribute is not a valid Microsoft VSA.
//////////
BYTE
WINAPI
ExtractMicrosoftVendorType(
const IASATTRIBUTE& attr
) throw ()
{
if (attr.Value.itType == IASTYPE_OCTET_STRING &&
attr.Value.OctetString.dwLength > 6 &&
!memcmp(attr.Value.OctetString.lpValue, "\x00\x00\x01\x37", 4))
{
return *(attr.Value.OctetString.lpValue + 4);
}
return (BYTE)0;
}
//////////
// Encrypts the MPPE key attributes in a request.
//////////
HRESULT EncryptMPPEKeys(
const CPacketRadius& packet,
IAttributesRaw* request
) throw ()
{
try
{
IASAttributeVectorWithBuffer<16> attrs;
attrs.load(request, RADIUS_ATTRIBUTE_VENDOR_SPECIFIC);
for (IASAttributeVector::iterator i = attrs.begin();
i != attrs.end();
++i)
{
switch (ExtractMicrosoftVendorType(*(i->pAttribute)))
{
case 12: // MS_ATTRIBUTE_CHAP_MPPE_KEYS
{
packet.cryptBuffer(
TRUE,
FALSE,
i->pAttribute->Value.OctetString.lpValue + 6,
i->pAttribute->Value.OctetString.dwLength - 6
);
break;
}
case 16: // MS_ATTRIBUTE_MPPE_SEND_KEY
case 17: // MS_ATTRIBUTE_MPPE_RECV_KEY
{
packet.cryptBuffer(
TRUE,
TRUE,
i->pAttribute->Value.OctetString.lpValue + 6,
i->pAttribute->Value.OctetString.dwLength - 6
);
break;
}
}
}
}
catch (const _com_error& ce)
{
return ce.Error();
}
return S_OK;
}
//++--------------------------------------------------------------
//
// Function: Process
//
// Synopsis: This is the CTunnelPassword class public method
// responsible for encrypting the Tunnel Passwords
// present in an out-bound RADIUS packet
//
// Arguments:
// PACKETTYPE - Radius packet type
// IAttributesRaw*
// CPacketRadius*
//
// Returns: HRESULT - status
//
// History: MKarki Created 04/16/98
//
//----------------------------------------------------------------
HRESULT
CTunnelPassword::Process (
PACKETTYPE ePacketType,
IAttributesRaw *pIAttributesRaw,
CPacketRadius *pCPacketRadius
)
{
HRESULT hr = S_OK;
DWORD dwCount = 0;
DWORD dwAttributeCount = 0;
DWORD dwTunnelAttributeCount = 0;
static DWORD dwTunnelPasswordType = TUNNEL_PASSWORD_ATTRIB;
PATTRIBUTE pAttribute = NULL;
PATTRIBUTEPOSITION pAttribPos = NULL;
_ASSERT (pIAttributesRaw && pCPacketRadius);
__try
{
//
// the tunnel-password attribute only goes
// into an access-accept packet
//
if (ACCESS_ACCEPT != ePacketType) { __leave; }
// Encrypt the MPPE keys.
hr = EncryptMPPEKeys(*pCPacketRadius, pIAttributesRaw);
if (FAILED(hr)) { __leave; }
//
// get the count of the total attributes in the collection
//
hr = pIAttributesRaw->GetAttributeCount (&dwAttributeCount);
if (FAILED (hr))
{
IASTracePrintf (
"Unable to obtain attribute count in request "
"while processing tunnel-password"
);
__leave;
}
else if (0 == dwAttributeCount)
{
__leave;
}
//
// allocate memory for the ATTRIBUTEPOSITION array
//
pAttribPos = reinterpret_cast <PATTRIBUTEPOSITION> (
::CoTaskMemAlloc (
sizeof (ATTRIBUTEPOSITION)*dwAttributeCount));
if (NULL == pAttribPos)
{
IASTracePrintf (
"Unable to allocate memory for attribute position array "
"while processing tunnel-password"
);
hr = E_OUTOFMEMORY;
__leave;
}
//
// get the Tunnel-Password attributes from
// the collection
//
dwTunnelAttributeCount = dwAttributeCount;
hr = pIAttributesRaw->GetAttributes (
&dwTunnelAttributeCount,
pAttribPos,
1,
&dwTunnelPasswordType
);
if (FAILED (hr))
{
IASTracePrintf (
"Unable to get attributes from request "
"while processing tunnel-password"
);
__leave;
}
else if (0 == dwTunnelAttributeCount)
{
__leave;
}
//
// remove the Tunnel-Password attributes from the collection
//
hr = pIAttributesRaw->RemoveAttributes (
dwTunnelAttributeCount,
pAttribPos
);
if (FAILED (hr))
{
IASTracePrintf (
"Unable to remove attributes from request "
"while processing tunnel-password"
);
__leave;
}
//
// now process the Tunnel-Password attributes
for (DWORD i = 0; i < dwTunnelAttributeCount; ++i)
{
hr = EncryptTunnelPassword (
pCPacketRadius,
pIAttributesRaw,
pAttribPos[i].pAttribute
);
if (FAILED (hr)) { __leave; }
}
}
__finally
{
//
// release all the Tunnel Attributes now
//
for (dwCount = 0; dwCount < dwTunnelAttributeCount; dwCount++)
{
::IASAttributeRelease (pAttribPos[dwCount].pAttribute);
}
//
// free the dynamically allocated memory
//
if (pAttribPos) { ::CoTaskMemFree (pAttribPos); }
}
return (hr);
} // end of CRecvFromPipe::TunnelPasswordSupport method
//++--------------------------------------------------------------
//
// Function: EncryptPassword
//
// Synopsis: This is the CTunnelPassword class private method
// responsible for encrypting the Tunnel Password
// present in an out-bound RADIUS packet. The Encrypted
// password is put in an IAS attribute which is added
// to the attribute collection of the outbound request.
//
// Arguments:
// CPacketRadius*
// IAttributesRaw*
// PIASATTRIBUTE
//
// Returns: HRESULT - status
//
// History: MKarki Created 04/16/98
//
//----------------------------------------------------------------
HRESULT
CTunnelPassword::EncryptTunnelPassword (
CPacketRadius *pCPacketRadius,
IAttributesRaw *pIAttributesRaw,
PIASATTRIBUTE plaintext
)
{
// Extract the password.
const IAS_OCTET_STRING& pwd = plaintext->Value.OctetString;
// We must have at least 4 bytes.
if (pwd.dwLength < 4) { return E_INVALIDARG; }
// How many bytes do we need including padding.
ULONG nbyte = ROUND_UP_COUNT(pwd.dwLength - 3, 16) + 3;
if (nbyte > 253) { return E_INVALIDARG; }
// Create a new IASATTRIBUTE for the encrypted value.
PIASATTRIBUTE encrypted;
if (IASAttributeAlloc(1, &encrypted)) { return E_OUTOFMEMORY; }
encrypted->dwId = RADIUS_ATTRIBUTE_TUNNEL_PASSWORD;
encrypted->dwFlags = plaintext->dwFlags;
encrypted->Value.itType = IASTYPE_OCTET_STRING;
encrypted->Value.OctetString.dwLength = nbyte;
encrypted->Value.OctetString.lpValue = (PBYTE)CoTaskMemAlloc(nbyte);
HRESULT hr;
PBYTE val = encrypted->Value.OctetString.lpValue;
if (val)
{
// Copy in the value.
memcpy(val, pwd.lpValue, pwd.dwLength);
// Zero out the padding.
memset(val + pwd.dwLength, 0, nbyte - pwd.dwLength);
// Encrypt the password.
pCPacketRadius->cryptBuffer(
TRUE,
TRUE,
val + 1,
nbyte - 1
);
// Add the encrypted attribute to the request.
ATTRIBUTEPOSITION pos;
pos.pAttribute = encrypted;
hr = pIAttributesRaw->AddAttributes(1, &pos);
}
else
{
hr = E_OUTOFMEMORY;
}
// Release the encrypted password.
IASAttributeRelease(encrypted);
return hr;
}