344 lines
8.6 KiB
C++
344 lines
8.6 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 1999, Microsoft Corp. All rights reserved.
|
|
//
|
|
// FILE
|
|
//
|
|
// action.cpp
|
|
//
|
|
// SYNOPSIS
|
|
//
|
|
// Defines the class Action.
|
|
//
|
|
// MODIFICATION HISTORY
|
|
//
|
|
// 02/01/2000 Original version.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <ias.h>
|
|
#include <attrcvt.h>
|
|
#include <sdoias.h>
|
|
#include <action.h>
|
|
|
|
_COM_SMARTPTR_TYPEDEF(ISdo, __uuidof(ISdo));
|
|
_COM_SMARTPTR_TYPEDEF(ISdoCollection, __uuidof(ISdoCollection));
|
|
|
|
Action::Action(
|
|
PCWSTR name,
|
|
DWORD nameAttr,
|
|
_variant_t& action
|
|
)
|
|
: attributes(4),
|
|
realmsTarget(RADIUS_ATTRIBUTE_USER_NAME)
|
|
{
|
|
using _com_util::CheckError;
|
|
|
|
//////////
|
|
// Add the policy name attribute.
|
|
//////////
|
|
|
|
IASAttribute policyName(true);
|
|
policyName->dwId = nameAttr;
|
|
policyName.setString(name);
|
|
policyName.setFlag(IAS_INCLUDE_IN_RESPONSE);
|
|
attributes.push_back(policyName);
|
|
|
|
//////////
|
|
// Get an enumerator for the attributes collection.
|
|
//////////
|
|
|
|
ISdoCollectionPtr profile(action);
|
|
IUnknownPtr unk;
|
|
CheckError(profile->get__NewEnum(&unk));
|
|
IEnumVARIANTPtr iter(unk);
|
|
|
|
//////////
|
|
// Iterate through the attributes.
|
|
//////////
|
|
|
|
_variant_t element;
|
|
unsigned long fetched;
|
|
while (iter->Next(1, &element, &fetched) == S_OK && fetched == 1)
|
|
{
|
|
// Convert to an SDO.
|
|
ISdoPtr attribute(element);
|
|
element.Clear();
|
|
|
|
// Get the necessary properties.
|
|
_variant_t id, value, syntax;
|
|
CheckError(attribute->GetProperty(PROPERTY_ATTRIBUTE_ID, &id));
|
|
CheckError(attribute->GetProperty(PROPERTY_ATTRIBUTE_VALUE, &value));
|
|
CheckError(attribute->GetProperty(PROPERTY_ATTRIBUTE_SYNTAX, &syntax));
|
|
|
|
// Attribute-Manipulation-Rule gets processed 'as is'.
|
|
if (V_I4(&id) == IAS_ATTRIBUTE_MANIPULATION_RULE)
|
|
{
|
|
realms.setRealms(&value);
|
|
continue;
|
|
}
|
|
|
|
// For everything else we process the VARIANTs one at a time.
|
|
VARIANT *begin, *end;
|
|
if (V_VT(&value) == (VT_VARIANT | VT_ARRAY))
|
|
{
|
|
begin = (VARIANT*)V_ARRAY(&value)->pvData;
|
|
end = begin + V_ARRAY(&value)->rgsabound[0].cElements;
|
|
}
|
|
else
|
|
{
|
|
begin = &value;
|
|
end = begin + 1;
|
|
}
|
|
|
|
// Iterate through each value.
|
|
for (VARIANT* v = begin; v != end; ++v)
|
|
{
|
|
// Process based on the attribute ID.
|
|
switch (V_I4(&id))
|
|
{
|
|
case IAS_ATTRIBUTE_MANIPULATION_TARGET:
|
|
{
|
|
realmsTarget = V_I4(v);
|
|
break;
|
|
}
|
|
case IAS_ATTRIBUTE_AUTH_PROVIDER_TYPE:
|
|
{
|
|
IASAttribute type(true);
|
|
type->dwId = IAS_ATTRIBUTE_PROVIDER_TYPE;
|
|
type->Value.itType = IASTYPE_ENUM;
|
|
type->Value.Integer = V_I4(v);
|
|
authProvider.push_back(type);
|
|
break;
|
|
}
|
|
case IAS_ATTRIBUTE_AUTH_PROVIDER_NAME:
|
|
{
|
|
IASAttribute name(true);
|
|
name->dwId = IAS_ATTRIBUTE_PROVIDER_NAME;
|
|
name.setString(V_BSTR(v));
|
|
authProvider.push_back(name);
|
|
break;
|
|
}
|
|
case IAS_ATTRIBUTE_ACCT_PROVIDER_TYPE:
|
|
{
|
|
IASAttribute type(true);
|
|
type->dwId = IAS_ATTRIBUTE_PROVIDER_TYPE;
|
|
type->Value.itType = IASTYPE_ENUM;
|
|
type->Value.Integer = V_I4(v);
|
|
acctProvider.push_back(type);
|
|
break;
|
|
}
|
|
case IAS_ATTRIBUTE_ACCT_PROVIDER_NAME:
|
|
{
|
|
IASAttribute name(true);
|
|
name->dwId = IAS_ATTRIBUTE_PROVIDER_NAME;
|
|
name.setString(V_BSTR(v));
|
|
acctProvider.push_back(name);
|
|
break;
|
|
}
|
|
case RADIUS_ATTRIBUTE_VENDOR_SPECIFIC:
|
|
{
|
|
IASAttribute attr(VSAFromString(V_BSTR(v)), FALSE);
|
|
attr->dwId = RADIUS_ATTRIBUTE_VENDOR_SPECIFIC;
|
|
attr.setFlag(IAS_INCLUDE_IN_ACCEPT);
|
|
attributes.push_back(attr);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
IASTYPEENUM type = (IASTYPEENUM)V_I4(&syntax);
|
|
IASAttribute attr(IASAttributeFromVariant(v, type), false);
|
|
attr->dwId = V_I4(&id);
|
|
attr.setFlag(IAS_INCLUDE_IN_ACCEPT);
|
|
attributes.push_back(attr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Action::doAction(IASRequest& request) const
|
|
{
|
|
// Populate the provider information:
|
|
switch (request.get_Request())
|
|
{
|
|
case IAS_REQUEST_ACCESS_REQUEST:
|
|
authProvider.store(request);
|
|
break;
|
|
|
|
case IAS_REQUEST_ACCOUNTING:
|
|
acctProvider.store(request);
|
|
break;
|
|
}
|
|
|
|
// Perform attribute manipulation.
|
|
if (!realms.empty())
|
|
{
|
|
IASAttribute attr;
|
|
attr.load(request, realmsTarget, IASTYPE_OCTET_STRING);
|
|
|
|
if (attr)
|
|
{
|
|
CComBSTR newVal;
|
|
realms.process(IAS_OCT2WIDE(attr->Value.OctetString), &newVal);
|
|
if (newVal)
|
|
{
|
|
if (realmsTarget == RADIUS_ATTRIBUTE_USER_NAME)
|
|
{
|
|
IASAttribute userName(true);
|
|
userName->dwId = RADIUS_ATTRIBUTE_USER_NAME;
|
|
userName->dwFlags = attr->dwFlags;
|
|
userName.setOctetString(newVal);
|
|
userName.store(request);
|
|
|
|
// Now that the new User-Name is safely stored, we can rename
|
|
// the old User-Name.
|
|
attr->dwId = IAS_ATTRIBUTE_ORIGINAL_USER_NAME;
|
|
}
|
|
else
|
|
{
|
|
// No need to save the old, so modify in place.
|
|
attr.setOctetString(newVal);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Store the profile attributes.
|
|
attributes.store(request);
|
|
}
|
|
|
|
/////////
|
|
// Various formats of VSA strings.
|
|
/////////
|
|
enum Format
|
|
{
|
|
FORMAT_RAW_HEX,
|
|
FORMAT_STRING,
|
|
FORMAT_INTEGER,
|
|
FORMAT_HEX,
|
|
FORMAT_INET_ADDR
|
|
};
|
|
|
|
/////////
|
|
// Layout of the VSA strings.
|
|
/////////
|
|
struct VSAFormat
|
|
{
|
|
WCHAR format[2];
|
|
WCHAR vendorID[8];
|
|
union
|
|
{
|
|
WCHAR rawValue[1];
|
|
struct
|
|
{
|
|
WCHAR vendorType[2];
|
|
WCHAR vendorLength[2];
|
|
WCHAR value[1];
|
|
};
|
|
};
|
|
};
|
|
|
|
//////////
|
|
// Convert a hex digit to the number it represents.
|
|
//////////
|
|
inline BYTE digit2Num(WCHAR digit) throw ()
|
|
{
|
|
return (digit >= L'0' && digit <= L'9') ? digit - L'0'
|
|
: digit - (L'A' - 10);
|
|
}
|
|
|
|
//////////
|
|
// Pack a hex digit into a byte stream.
|
|
//////////
|
|
PBYTE packHex(PCWSTR src, ULONG srclen, PBYTE dst) throw ()
|
|
{
|
|
for (ULONG dstlen = srclen / 2; dstlen; --dstlen)
|
|
{
|
|
*dst = digit2Num(*src++) << 4;
|
|
*dst++ |= digit2Num(*src++);
|
|
}
|
|
|
|
return dst;
|
|
}
|
|
|
|
//////////
|
|
// Convert a string describing a VSA into an IASATTRIBUTE.
|
|
//////////
|
|
PIASATTRIBUTE Action::VSAFromString(PCWSTR string)
|
|
{
|
|
// Number of characters to process.
|
|
SIZE_T len = wcslen(string);
|
|
|
|
// Overlay the layout struct.
|
|
VSAFormat* vsa = (VSAFormat*)string;
|
|
|
|
// Get the string format.
|
|
ULONG format = digit2Num(vsa->format[0]);
|
|
format <<= 8;
|
|
format |= digit2Num(vsa->format[1]);
|
|
|
|
// Temporary buffer used for formatting the VSA.
|
|
BYTE buffer[253], *dst = buffer;
|
|
|
|
// Pack the Vendor-ID.
|
|
dst = packHex(vsa->vendorID, 8, dst);
|
|
|
|
// Pack the Vendor-Type and Vendor-Length for conformant VSAs.
|
|
if (format != FORMAT_RAW_HEX)
|
|
{
|
|
dst = packHex(vsa->vendorType, 2, dst);
|
|
dst = packHex(vsa->vendorLength, 2, dst);
|
|
}
|
|
|
|
// Pack the value.
|
|
switch (format)
|
|
{
|
|
case FORMAT_RAW_HEX:
|
|
{
|
|
dst = packHex(
|
|
vsa->rawValue,
|
|
len - 10,
|
|
dst
|
|
);
|
|
break;
|
|
}
|
|
|
|
case FORMAT_INTEGER:
|
|
case FORMAT_HEX:
|
|
case FORMAT_INET_ADDR:
|
|
{
|
|
dst = packHex(
|
|
vsa->value,
|
|
len - 14,
|
|
dst
|
|
);
|
|
break;
|
|
}
|
|
|
|
case FORMAT_STRING:
|
|
{
|
|
int nchar = WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
vsa->value,
|
|
len - 14,
|
|
(PSTR)dst,
|
|
sizeof(buffer) - 6,
|
|
NULL,
|
|
NULL
|
|
);
|
|
dst += nchar;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Store the temporary buffer in an attribute ...
|
|
IASAttribute attr(true);
|
|
attr.setOctetString(dst - buffer, buffer);
|
|
|
|
// ... and return.
|
|
return attr.detach();
|
|
}
|