|
|
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) Microsoft Corporation
//
// SYNOPSIS
//
// Defines the class Action.
//
///////////////////////////////////////////////////////////////////////////////
#include "ias.h"
#include "action.h"
#include "attrcvt.h"
#include "eapprofile.h"
#include "sdoias.h"
#include "TunnelTagger.h"
_COM_SMARTPTR_TYPEDEF(ISdo, __uuidof(ISdo)); _COM_SMARTPTR_TYPEDEF(ISdoCollection, __uuidof(ISdoCollection));
Action::Action( PCWSTR name, DWORD nameAttr, _variant_t& action, const TunnelTagger& tagger ) : 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; } // As does the EAP per-policy config.
else if (V_I4(&id) == IAS_ATTRIBUTE_EAP_CONFIG) { EapProfile eap; CheckError(eap.Load(value)); while (!eap.IsEmpty()) { IASAttribute config(true);
EapProfile::ConfigData data; eap.Pop(data);
config->dwId = IAS_ATTRIBUTE_EAP_CONFIG; config->Value.itType = IASTYPE_OCTET_STRING; config->Value.OctetString.dwLength = data.length; config->Value.OctetString.lpValue = data.value;
attributes.push_back(config); } 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); } } } }
tagger.Tag(attributes); }
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.
//////////
BYTE digit2Num(WCHAR digit) throw () { if ((digit >= L'0') && (digit <= L'9')) { return digit - L'0'; } else if ((digit >= L'A') && (digit <= L'F')) { return digit - (L'A' - 10); } else { return 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(); }
|