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

241 lines
5.8 KiB
C++

///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1998, Microsoft Corp. All rights reserved.
//
// FILE
//
// radutil.cpp
//
// SYNOPSIS
//
// This file defines methods for converting attributes to and from
// RADIUS wire format.
//
// MODIFICATION HISTORY
//
// 03/08/1998 Original version.
// 08/11/1998 Packing functions moved to iasutil.
// Set pszWide to NULL when initializing IASTYPE_STRING.
//
///////////////////////////////////////////////////////////////////////////////
#include <radcommon.h>
#include <iasutil.h>
#include <iastlutl.h>
#include <radutil.h>
//////////
// The offset between the UNIX and NT epochs.
//////////
const DWORDLONG UNIX_EPOCH = 116444736000000000ui64;
///////////////////////////////////////////////////////////////////////////////
//
// METHOD
//
// RadiusUtil::decode
//
// DESCRIPTION
//
// Decodes an octet string into a newly-allocated IAS Attribute of the
// specified type.
//
///////////////////////////////////////////////////////////////////////////////
PIASATTRIBUTE RadiusUtil::decode(
IASTYPE dstType,
PBYTE src,
ULONG srclen
)
{
// Allocate an attribute to hold the decoded value.
IASTL::IASAttribute dst(true);
// Switch based on the destination type.
switch (dstType)
{
case IASTYPE_BOOLEAN:
{
if (srclen != 4) { _com_issue_error(E_INVALIDARG); }
dst->Value.Boolean = IASExtractDWORD(src) ? TRUE : FALSE;
break;
}
case IASTYPE_INTEGER:
case IASTYPE_ENUM:
case IASTYPE_INET_ADDR:
{
if (srclen != 4) { _com_issue_error(E_INVALIDARG); }
dst->Value.Integer = IASExtractDWORD(src);
break;
}
case IASTYPE_UTC_TIME:
{
if (srclen != 4) { _com_issue_error(E_INVALIDARG); }
DWORDLONG val;
// Extract the UNIX time.
val = IASExtractDWORD(src);
// Convert from seconds to 100 nsec intervals.
val *= 10000000;
// Shift to the NT epoch.
val += 116444736000000000ui64;
// Split into the high and low DWORDs.
dst->Value.UTCTime.dwLowDateTime = (DWORD)val;
dst->Value.UTCTime.dwHighDateTime = (DWORD)(val >> 32);
break;
}
case IASTYPE_STRING:
{
dst.setString(srclen, src);
break;
}
case IASTYPE_OCTET_STRING:
case IASTYPE_PROV_SPECIFIC:
{
dst.setOctetString(srclen, src);
break;
}
}
// All went well, so set type attribute type ...
dst->Value.itType = dstType;
// ... and return.
return dst.detach();
}
///////////////////////////////////////////////////////////////////////////////
//
// METHOD
//
// RadiusUtil::getEncodedSize
//
// DESCRIPTION
//
// Returns the size in bytes of the IASATTRIBUTE when converted to RADIUS
// wire format. This does NOT include the attribute header.
//
///////////////////////////////////////////////////////////////////////////////
ULONG RadiusUtil::getEncodedSize(
const IASATTRIBUTE& src
) throw ()
{
switch (src.Value.itType)
{
case IASTYPE_BOOLEAN:
case IASTYPE_INTEGER:
case IASTYPE_ENUM:
case IASTYPE_INET_ADDR:
case IASTYPE_UTC_TIME:
{
return 4;
}
case IASTYPE_STRING:
{
// Convert the string to ANSI so we can count octets.
IASAttributeAnsiAlloc(const_cast<PIASATTRIBUTE>(&src));
// Allow for NULL strings and don't count the terminator.
return src.Value.String.pszAnsi ? strlen(src.Value.String.pszAnsi)
: 0;
}
case IASTYPE_OCTET_STRING:
case IASTYPE_PROV_SPECIFIC:
{
return src.Value.OctetString.dwLength;
}
}
// All other types have no wire representation.
return 0;
}
///////////////////////////////////////////////////////////////////////////////
//
// METHOD
//
// RadiusUtil::encode
//
// DESCRIPTION
//
// Encodes the IASATTRIBUTE into RADIUS wire format and copies the value
// to the buffer pointed to by 'dst'. The caller should ensure that the
// destination buffer is large enough by first calling getEncodedSize.
// This method only encodes the attribute value, not the header.
//
///////////////////////////////////////////////////////////////////////////////
void RadiusUtil::encode(
PBYTE dst,
const IASATTRIBUTE& src
) throw ()
{
// Switch based on the source's type.
switch (src.Value.itType)
{
case IASTYPE_BOOLEAN:
{
IASInsertDWORD(dst, (src.Value.Boolean ? 1 : 0));
break;
}
case IASTYPE_INTEGER:
case IASTYPE_ENUM:
case IASTYPE_INET_ADDR:
{
IASInsertDWORD(dst, src.Value.Integer);
break;
}
case IASTYPE_UTC_TIME:
{
DWORDLONG val;
// Move in the high DWORD.
val = src.Value.UTCTime.dwHighDateTime;
val <<= 32;
// Move in the low DWORD.
val |= src.Value.UTCTime.dwLowDateTime;
// Convert to the UNIX epoch.
val -= UNIX_EPOCH;
// Convert to seconds.
val /= 10000000;
IASInsertDWORD(dst, (DWORD)val);
break;
}
case IASTYPE_STRING:
{
const BYTE* p = (const BYTE*)src.Value.String.pszAnsi;
// Don't use strcpy since we don't want the null terminator.
if (p) while (*p) *dst++ = *p++;
break;
}
case IASTYPE_OCTET_STRING:
case IASTYPE_PROV_SPECIFIC:
{
memcpy(dst,
src.Value.OctetString.lpValue,
src.Value.OctetString.dwLength);
}
}
}