/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1999, Microsoft Corp. All rights reserved. // // FILE // // action.cpp // // SYNOPSIS // // Defines the class Action. // // MODIFICATION HISTORY // // 02/01/2000 Original version. // /////////////////////////////////////////////////////////////////////////////// #include #include #include #include _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(); }