windows-nt/Source/XPSP1/NT/net/ias/providers/nap/dll/action.cpp
2020-09-26 16:20:57 +08:00

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();
}