Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1194 lines
29 KiB

///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) Microsoft Corporation
//
// SYNOPSIS
//
// Defines the class RadiusRequest
//
///////////////////////////////////////////////////////////////////////////////
#include "Precompiled.h"
#include "ias.h"
#include "ControlBlock.h"
namespace
{
DWORD AsWindowsError(const _com_error& ce) throw ()
{
HRESULT error = ce.Error();
if (HRESULT_FACILITY(error) == FACILITY_WIN32)
{
return error & 0x0000FFFF;
}
else
{
return error;
}
}
}
Attribute::Attribute(
const ATTRIBUTEPOSITION& iasAttr,
DWORD authIfId
)
: ias(iasAttr)
{
LoadAuthIfFromIas(authIfId);
// Convert the ratProvider enumeration if necessary.
if (authIf.dwAttrType == ratProvider)
{
switch (ias.getAttribute()->Value.Integer)
{
case IAS_PROVIDER_NONE:
{
authIf.dwValue = rapNone;
break;
}
case IAS_PROVIDER_WINDOWS:
{
authIf.dwValue = rapWindowsNT;
break;
}
case IAS_PROVIDER_RADIUS_PROXY:
{
authIf.dwValue = rapProxy;
break;
}
case IAS_PROVIDER_EXTERNAL_AUTH:
{
authIf.dwValue = rapProxy;
break;
}
default:
{
authIf.dwValue = rapUnknown;
break;
}
}
}
}
Attribute::Attribute(
const ATTRIBUTEPOSITION& iasAttr,
const RADIUS_ATTRIBUTE& authIfAttr
) throw ()
: authIf(authIfAttr),
ias(iasAttr)
{
}
Attribute::Attribute(
const RADIUS_ATTRIBUTE& authIfAttr,
DWORD flags,
DWORD iasId
)
{
// First create a new IAS attribute.
IASAttribute newAttr(true);
newAttr->dwFlags = flags;
newAttr->dwId = iasId;
switch (authIfAttr.fDataType)
{
case rdtAddress:
{
newAttr->Value.itType = IASTYPE_INET_ADDR;
newAttr->Value.InetAddr = authIfAttr.dwValue;
break;
}
case rdtInteger:
case rdtTime:
{
newAttr->Value.itType = IASTYPE_INTEGER;
newAttr->Value.InetAddr = authIfAttr.dwValue;
break;
}
case rdtString:
{
if (IsIasString(newAttr->dwId))
{
newAttr.setString(
authIfAttr.cbDataLength,
reinterpret_cast<const BYTE*>(authIfAttr.lpValue)
);
}
else
{
newAttr.setOctetString(
authIfAttr.cbDataLength,
reinterpret_cast<const BYTE*>(authIfAttr.lpValue)
);
}
break;
}
default:
{
issue_error(E_INVALIDARG);
break;
}
}
ias = newAttr;
// Initialize our AuthIf attribute from the IAS attribute. This ensures that
// we're referencing the copied memory instead of the caller supplied
// memory.
LoadAuthIfFromIas(authIfAttr.dwAttrType);
// Convert the ratProvider enumeration if necessary.
if (authIf.dwAttrType == ratProvider)
{
switch (authIf.dwValue)
{
case rapNone:
{
ias.getAttribute()->Value.Integer = IAS_PROVIDER_NONE;
break;
}
case rapWindowsNT:
{
ias.getAttribute()->Value.Integer = IAS_PROVIDER_WINDOWS;
break;
}
case rapProxy:
{
ias.getAttribute()->Value.Integer = IAS_PROVIDER_RADIUS_PROXY;
break;
}
default:
{
issue_error(E_INVALIDARG);
break;
}
}
}
}
void Attribute::LoadAuthIfFromIas(DWORD authIfId)
{
authIf.dwAttrType = authIfId;
IASATTRIBUTE* src = ias.getAttribute();
switch (src->Value.itType)
{
case IASTYPE_BOOLEAN:
case IASTYPE_INTEGER:
case IASTYPE_ENUM:
{
authIf.fDataType = rdtInteger;
authIf.cbDataLength = sizeof(DWORD);
authIf.dwValue = src->Value.Integer;
break;
}
case IASTYPE_INET_ADDR:
{
authIf.fDataType = rdtAddress;
authIf.cbDataLength = sizeof(DWORD);
authIf.dwValue = src->Value.InetAddr;
break;
}
case IASTYPE_STRING:
{
DWORD error = IASAttributeAnsiAlloc(src);
if (error != NO_ERROR)
{
issue_error(HRESULT_FROM_WIN32(error));
}
authIf.fDataType = rdtString;
authIf.cbDataLength = strlen(src->Value.String.pszAnsi) + 1;
authIf.lpValue = src->Value.String.pszAnsi;
break;
}
case IASTYPE_OCTET_STRING:
case IASTYPE_PROV_SPECIFIC:
{
authIf.fDataType = rdtString;
authIf.cbDataLength = src->Value.OctetString.dwLength;
authIf.lpValue = reinterpret_cast<const char*>(
src->Value.OctetString.lpValue
);
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 -= 116444736000000000ui64;
// Convert to seconds.
val /= 10000000;
authIf.fDataType = rdtTime;
authIf.cbDataLength = sizeof(DWORD);
authIf.dwValue = static_cast<DWORD>(val);
break;
}
default:
{
// This is some IAS data type that AuthIf extensions don't know about;
// just give them an empty attribute.
authIf.fDataType = rdtString;
authIf.cbDataLength = 0;
authIf.lpValue = 0;
break;
}
}
}
bool Attribute::IsIasString(DWORD iasId) throw ()
{
bool isString;
switch (iasId)
{
// RADIUS attributes are always stored as octet strings, so we only have
// to worry about internal attributes.
case IAS_ATTRIBUTE_NT4_ACCOUNT_NAME:
case IAS_ATTRIBUTE_FULLY_QUALIFIED_USER_NAME:
case IAS_ATTRIBUTE_NP_NAME:
{
isString = true;
break;
}
default:
{
isString = false;
break;
}
}
return isString;
}
AttributeArray::AttributeArray(IASRequest& request)
: source(request),
name(0),
wasCracked(false)
{
vtbl.cbSize = sizeof(vtbl);
vtbl.Add = Add;
vtbl.AttributeAt = AttributeAt;
vtbl.GetSize = GetSize;
vtbl.InsertAt = InsertAt;
vtbl.RemoveAt = RemoveAt;
vtbl.SetAt = SetAt;
}
void AttributeArray::Assign(
const char* arrayName,
RADIUS_CODE arrayType,
const IASAttributeVector& attrs
)
{
// Reset the array.
array.clear();
name = arrayName;
// Determine our flags based on the array type.
switch (arrayType)
{
case rcAccessAccept:
flags = IAS_INCLUDE_IN_ACCEPT;
break;
case rcAccessReject:
flags = IAS_INCLUDE_IN_REJECT;
break;
case rcAccessChallenge:
flags = IAS_INCLUDE_IN_CHALLENGE;
break;
default:
flags = 0;
break;
}
// Select our attributes and add them to the array.
for (IASAttributeVector::const_iterator i = attrs.begin();
i != attrs.end();
++i)
{
const IASATTRIBUTE& attr = *(i->pAttribute);
if (Classify(attr) == arrayType)
{
switch (attr.dwId)
{
case RADIUS_ATTRIBUTE_USER_NAME:
{
AppendUserName(attrs, *i);
break;
}
case IAS_ATTRIBUTE_CLIENT_PACKET_HEADER:
{
AppendPacketHeader(attrs, *i);
break;
}
case IAS_ATTRIBUTE_NT4_ACCOUNT_NAME:
{
wasCracked = true;
// Fall through.
}
default:
{
DWORD authIfId = ConvertIasToAuthIf(attr.dwId);
if (authIfId != ratMinimum)
{
Append(*i, authIfId);
}
break;
}
}
}
}
// If this is a request array, add the ratUniqueId if necessary.
if ((arrayType == rcAccessRequest) && (Find(ratUniqueId) == 0))
{
static long nextId;
RADIUS_ATTRIBUTE uniqueId;
uniqueId.dwAttrType = ratUniqueId;
uniqueId.fDataType = rdtInteger;
uniqueId.cbDataLength = sizeof(DWORD);
uniqueId.dwValue = static_cast<DWORD>(InterlockedIncrement(&nextId));
array.push_back(Attribute(uniqueId, 0, IAS_ATTRIBUTE_REQUEST_ID));
}
}
RADIUS_CODE AttributeArray::Classify(const IASATTRIBUTE& attr) throw ()
{
if (attr.dwId < 256)
{
if ((attr.dwFlags & IAS_INCLUDE_IN_ACCEPT) != 0)
{
return rcAccessAccept;
}
if ((attr.dwFlags & IAS_INCLUDE_IN_REJECT) != 0)
{
return rcAccessReject;
}
if ((attr.dwFlags & IAS_INCLUDE_IN_CHALLENGE) != 0)
{
return rcAccessChallenge;
}
}
return rcAccessRequest;
}
DWORD AttributeArray::ConvertIasToAuthIf(DWORD iasId) throw ()
{
DWORD authIfId;
if (iasId < 256)
{
authIfId = iasId;
}
else
{
switch (iasId)
{
case IAS_ATTRIBUTE_CLIENT_IP_ADDRESS:
authIfId = ratSrcIPAddress;
break;
case IAS_ATTRIBUTE_CLIENT_UDP_PORT:
authIfId = ratSrcPort;
break;
case IAS_ATTRIBUTE_ORIGINAL_USER_NAME:
authIfId = ratUserName;
break;
case IAS_ATTRIBUTE_NT4_ACCOUNT_NAME:
authIfId = ratStrippedUserName;
break;
case IAS_ATTRIBUTE_FULLY_QUALIFIED_USER_NAME:
authIfId = ratFQUserName;
break;
case IAS_ATTRIBUTE_NP_NAME:
authIfId = ratPolicyName;
break;
case IAS_ATTRIBUTE_PROVIDER_TYPE:
authIfId = ratProvider;
break;
case IAS_ATTRIBUTE_EXTENSION_STATE:
authIfId = ratExtensionState;
break;
default:
authIfId = ratMinimum;
break;
}
}
return authIfId;
}
DWORD AttributeArray::ConvertAuthIfToIas(DWORD authIfId) throw ()
{
DWORD iasId;
if (authIfId < 256)
{
iasId = authIfId;
}
else
{
switch (authIfId)
{
case ratSrcIPAddress:
iasId = IAS_ATTRIBUTE_CLIENT_IP_ADDRESS;
break;
case ratSrcPort:
iasId = IAS_ATTRIBUTE_CLIENT_UDP_PORT;
break;
case ratFQUserName:
iasId = IAS_ATTRIBUTE_FULLY_QUALIFIED_USER_NAME;
break;
case ratPolicyName:
iasId = IAS_ATTRIBUTE_NP_NAME;
break;
case ratExtensionState:
iasId = IAS_ATTRIBUTE_EXTENSION_STATE;
break;
default:
iasId = ATTRIBUTE_UNDEFINED;
break;
}
}
return iasId;
}
bool AttributeArray::IsReadOnly(DWORD authIfId) throw ()
{
bool retval;
if (authIfId < 256)
{
retval = false;
}
else
{
switch (authIfId)
{
case ratCode:
case ratIdentifier:
case ratAuthenticator:
case ratSrcIPAddress:
case ratSrcPort:
case ratUniqueId:
retval = true;
break;
default:
retval = false;
break;
}
}
return retval;
}
inline void AttributeArray::Append(
const ATTRIBUTEPOSITION& attr,
DWORD authIfId
)
{
array.push_back(Attribute(attr, authIfId));
}
void AttributeArray::AppendUserName(
const IASAttributeVector& attrs,
const ATTRIBUTEPOSITION& attr
)
{
// For IAS, RADIUS_ATTRIBUTE_USER_NAME contains the RADIUS User-Name with
// any attribute manipulation rules applied.
// For AuthIf, ratUserName must contain the original RADIUS User-Name sent
// by the client, and ratStrippedUserName must contain the User-Name after
// attribute manipulation *and* name cracking.
if (!attrs.contains(IAS_ATTRIBUTE_ORIGINAL_USER_NAME))
{
// The User-Name hasn't been stripped, so the RADIUS_ATTRIBUTE_USER_NAME
// is the ratUserName.
Append(attr, ratUserName);
}
else if (!attrs.contains(IAS_ATTRIBUTE_NT4_ACCOUNT_NAME))
{
// The User-Name has been stripped, but it hasn't been cracked, so the
// RADIUS_ATTRIBUTE_USER_NAME is the ratStrippedUserName.
Append(attr, ratStrippedUserName);
}
// Otherwise, the User-Name has been stripped and cracked, so
// RADIUS_ATTRIBUTE_USER_NAME is ignored. In this case, ratUserName contains
// IAS_ATTRIBUTE_ORIGINAL_USER_NAME, and ratStrippedUserName contains
// IAS_ATTRIBUTE_NT4_ACCOUNT_NAME.
}
void AttributeArray::AppendPacketHeader(
const IASAttributeVector& attrs,
const ATTRIBUTEPOSITION& attr
)
{
RADIUS_ATTRIBUTE authIfAttr;
// Get the RADIUS identifier from the header.
authIfAttr.dwAttrType = ratIdentifier;
authIfAttr.fDataType = rdtInteger;
authIfAttr.cbDataLength = sizeof(DWORD);
authIfAttr.dwValue = *static_cast<const BYTE*>(
attr.pAttribute->Value.OctetString.lpValue + 1
);
array.push_back(Attribute(attr, authIfAttr));
// If the request doesn't contain a Chap-Challenge, then get the
// authenticator from the header.
if (!attrs.contains(RADIUS_ATTRIBUTE_CHAP_CHALLENGE))
{
authIfAttr.dwAttrType = ratAuthenticator;
authIfAttr.fDataType = rdtString;
authIfAttr.cbDataLength = 16;
authIfAttr.lpValue = reinterpret_cast<const char*>(
attr.pAttribute->Value.OctetString.lpValue + 4
);
array.push_back(Attribute(attr, authIfAttr));
}
}
inline const AttributeArray* AttributeArray::Narrow(
const RADIUS_ATTRIBUTE_ARRAY* p
) throw ()
{
return reinterpret_cast<const AttributeArray*>(p);
}
inline AttributeArray* AttributeArray::Narrow(
RADIUS_ATTRIBUTE_ARRAY* p
) throw ()
{
return reinterpret_cast<AttributeArray*>(p);
}
const Attribute* AttributeArray::Find(DWORD authIfId) const throw ()
{
for (std::vector<Attribute>::const_iterator i = array.begin();
i != array.end();
++i)
{
if (i->AsAuthIf()->dwAttrType == authIfId)
{
return i;
}
}
return 0;
}
void AttributeArray::StripUserNames() throw ()
{
// An extension is stripping the User-Name, so preserve any existing
// RADIUS_ATTRIBUTE_USER_NAME attributes.
for (std::vector<Attribute>::iterator i = array.begin();
i != array.end();
++i)
{
if (i->AsIas()->pAttribute->dwId == RADIUS_ATTRIBUTE_USER_NAME)
{
i->AsIas()->pAttribute->dwId = IAS_ATTRIBUTE_ORIGINAL_USER_NAME;
}
}
}
void AttributeArray::UnstripUserNames() throw ()
{
// An extension is unstripping the User-Name, so revert any existing
// IAS_ATTRIBUTE_ORIGINAL_USER_NAME attributes.
for (std::vector<Attribute>::iterator i = array.begin();
i != array.end();
++i)
{
if (i->AsIas()->pAttribute->dwId == IAS_ATTRIBUTE_ORIGINAL_USER_NAME)
{
i->AsIas()->pAttribute->dwId = RADIUS_ATTRIBUTE_USER_NAME;
}
}
}
inline void AttributeArray::Add(const RADIUS_ATTRIBUTE& attr)
{
InsertAt(array.size(), attr);
}
inline const RADIUS_ATTRIBUTE* AttributeArray::AttributeAt(
DWORD dwIndex
) const throw ()
{
return (dwIndex < array.size()) ? array[dwIndex].AsAuthIf() : 0;
}
inline DWORD AttributeArray::GetSize() const throw ()
{
return array.size();
}
void AttributeArray::InsertAt(
DWORD dwIndex,
const RADIUS_ATTRIBUTE& attr
)
{
if (dwIndex > array.size())
{
issue_error(E_INVALIDARG);
}
// Determine the IAS id for this attribute.
DWORD iasId;
if (attr.dwAttrType == ratStrippedUserName)
{
if (Find(ratStrippedUserName) != 0)
{
// We can't have two stripped usernames.
issue_error(E_ACCESSDENIED);
}
if (wasCracked)
{
iasId = IAS_ATTRIBUTE_NT4_ACCOUNT_NAME;
}
else
{
StripUserNames();
iasId = RADIUS_ATTRIBUTE_USER_NAME;
}
}
else if (attr.dwAttrType == ratUserName)
{
// If there's already a ratUserName attribute, then this attribute should
// use the same ID (either RADIUS_ATTRIBUTE_USER_NAME or
// IAS_ATTRIBUTE_ORIGINAL_USER_NAME). Otherwise, its the first
// ratUserName, so it always goes to RADIUS_ATTRIBUTE_USER_NAME.
const Attribute* existing = Find(ratUserName);
iasId = (existing != 0) ? existing->AsIas()->pAttribute->dwId
: RADIUS_ATTRIBUTE_USER_NAME;
}
else if (IsReadOnly(attr.dwAttrType))
{
issue_error(E_ACCESSDENIED);
}
else
{
iasId = ConvertAuthIfToIas(attr.dwAttrType);
if (iasId == ATTRIBUTE_UNDEFINED)
{
issue_error(E_INVALIDARG);
}
}
Attribute newAttr(attr, flags, iasId);
if (dwIndex == array.size())
{
source.AddAttributes(1, newAttr.AsIas());
array.push_back(newAttr);
}
else
{
source.InsertBefore(newAttr.AsIas(), array[dwIndex].AsIas());
array.insert(array.begin() + dwIndex, newAttr);
}
}
void AttributeArray::RemoveAt(DWORD dwIndex)
{
if (dwIndex >= array.size())
{
issue_error(E_INVALIDARG);
}
Attribute& target = array[dwIndex];
if (target.AsAuthIf()->dwAttrType == ratStrippedUserName)
{
if (target.AsIas()->pAttribute->dwId == RADIUS_ATTRIBUTE_USER_NAME)
{
UnstripUserNames();
}
// Otherwise, extension is removing IAS_ATTRIBUTE_NT4_ACCOUNT_NAME.
}
else if (IsReadOnly(target.AsAuthIf()->dwAttrType))
{
issue_error(E_ACCESSDENIED);
}
source.RemoveAttributes(1, array[dwIndex].AsIas());
array.erase(array.begin() + dwIndex);
}
inline void AttributeArray::SetAt(
DWORD dwIndex,
const RADIUS_ATTRIBUTE& attr
)
{
RemoveAt(dwIndex);
InsertAt(dwIndex, attr);
}
DWORD AttributeArray::Add(
RADIUS_ATTRIBUTE_ARRAY* This,
const RADIUS_ATTRIBUTE *pAttr
) throw ()
{
if ((This == 0) || (pAttr == 0))
{
return ERROR_INVALID_PARAMETER;
}
IASTracePrintf(
"RADIUS_ATTRIBUTE_ARRAY.Add(%s, %lu)",
Narrow(This)->name,
pAttr->dwAttrType
);
try
{
Narrow(This)->Add(*pAttr);
}
catch (const std::bad_alloc&)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
catch (const _com_error& ce)
{
return AsWindowsError(ce);
}
return NO_ERROR;
}
const RADIUS_ATTRIBUTE* AttributeArray::AttributeAt(
const RADIUS_ATTRIBUTE_ARRAY* This,
DWORD dwIndex
) throw ()
{
return (This != 0) ? Narrow(This)->AttributeAt(dwIndex) : 0;
}
DWORD AttributeArray::GetSize(
const RADIUS_ATTRIBUTE_ARRAY* This
) throw ()
{
return (This != 0) ? Narrow(This)->GetSize() : 0;
}
DWORD AttributeArray::InsertAt(
RADIUS_ATTRIBUTE_ARRAY* This,
DWORD dwIndex,
const RADIUS_ATTRIBUTE* pAttr
) throw ()
{
if ((This == 0) || (pAttr == 0))
{
return ERROR_INVALID_PARAMETER;
}
IASTracePrintf(
"RADIUS_ATTRIBUTE_ARRAY.InsertAt(%s, %lu, %lu)",
Narrow(This)->name,
dwIndex,
pAttr->dwAttrType
);
try
{
Narrow(This)->InsertAt(dwIndex, *pAttr);
}
catch (const std::bad_alloc&)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
catch (const _com_error& ce)
{
return AsWindowsError(ce);
}
return NO_ERROR;
}
DWORD AttributeArray::RemoveAt(
RADIUS_ATTRIBUTE_ARRAY* This,
DWORD dwIndex
) throw ()
{
if (This == 0)
{
return ERROR_INVALID_PARAMETER;
}
IASTracePrintf(
"RADIUS_ATTRIBUTE_ARRAY.RemoveAt(%s, %lu)",
Narrow(This)->name,
dwIndex
);
try
{
Narrow(This)->RemoveAt(dwIndex);
}
catch (const std::bad_alloc&)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
catch (const _com_error& ce)
{
return AsWindowsError(ce);
}
return NO_ERROR;
}
DWORD AttributeArray::SetAt(
RADIUS_ATTRIBUTE_ARRAY* This,
DWORD dwIndex,
const RADIUS_ATTRIBUTE *pAttr
) throw ()
{
if ((This == 0) || (pAttr == 0))
{
return ERROR_INVALID_PARAMETER;
}
IASTracePrintf(
"RADIUS_ATTRIBUTE_ARRAY.SetAt(%s, %lu, %lu)",
Narrow(This)->name,
dwIndex,
pAttr->dwAttrType
);
try
{
Narrow(This)->SetAt(dwIndex, *pAttr);
}
catch (const std::bad_alloc&)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
catch (const _com_error& ce)
{
return AsWindowsError(ce);
}
return NO_ERROR;
}
ControlBlock::ControlBlock(
RADIUS_EXTENSION_POINT point,
IASRequest& request
)
: source(request),
requestAttrs(request),
acceptAttrs(request),
rejectAttrs(request),
challengeAttrs(request)
{
ecb.cbSize = sizeof(ecb);
ecb.dwVersion = RADIUS_EXTENSION_VERSION;
ecb.repPoint = point;
// Friendly names for arrays.
const char* requestName;
const char* successName;
// Set the request type.
switch (source.get_Request())
{
case IAS_REQUEST_ACCESS_REQUEST:
ecb.rcRequestType = rcAccessRequest;
requestName = "rcAccessRequest";
successName = "rcAccessAccept";
break;
case IAS_REQUEST_ACCOUNTING:
ecb.rcRequestType = rcAccountingRequest;
requestName = "rcAccountingRequest";
successName = "rcAccountingResponse";
break;
default:
ecb.rcRequestType = rcUnknown;
requestName = "rcUnknown";
successName = "rcAccessAccept";
break;
}
// Set the response type.
switch (source.get_Response())
{
case IAS_RESPONSE_ACCESS_ACCEPT:
ecb.rcResponseType = rcAccessAccept;
break;
case IAS_RESPONSE_ACCESS_REJECT:
ecb.rcResponseType = rcAccessReject;
break;
case IAS_RESPONSE_ACCESS_CHALLENGE:
ecb.rcResponseType = rcAccessChallenge;
break;
case IAS_RESPONSE_ACCOUNTING:
ecb.rcResponseType = rcAccountingResponse;
break;
case IAS_RESPONSE_DISCARD_PACKET:
ecb.rcResponseType = rcDiscard;
break;
default:
ecb.rcResponseType = rcUnknown;
break;
}
// Fill in the vtbl.
ecb.GetRequest = GetRequest;
ecb.GetResponse = GetResponse;
ecb.SetResponseType = SetResponseType;
// Initialize the attribute vectors.
IASAttributeVector attrs;
attrs.load(source);
requestAttrs.Assign(requestName, rcAccessRequest, attrs);
acceptAttrs.Assign(successName, rcAccessAccept,attrs);
rejectAttrs.Assign("rcAccessReject", rcAccessReject, attrs);
challengeAttrs.Assign("rcAccessChallenge", rcAccessChallenge, attrs);
}
inline ControlBlock* ControlBlock::Narrow(
RADIUS_EXTENSION_CONTROL_BLOCK* p
) throw ()
{
return reinterpret_cast<ControlBlock*>(p);
}
void ControlBlock::AddAuthType()
{
// First, remove any existing auth type because now the extension is making
// the authoritative decision.
DWORD attrId = IAS_ATTRIBUTE_AUTHENTICATION_TYPE;
source.RemoveAttributesByType(1, &attrId);
IASAttribute authType(true);
authType->dwId = IAS_ATTRIBUTE_AUTHENTICATION_TYPE;
authType->Value.itType = IASTYPE_ENUM;
authType->Value.Enumerator = IAS_AUTH_CUSTOM;
authType.store(source);
}
inline RADIUS_ATTRIBUTE_ARRAY* ControlBlock::GetRequest() throw ()
{
return requestAttrs.Get();
}
inline RADIUS_ATTRIBUTE_ARRAY* ControlBlock::GetResponse(
RADIUS_CODE rcResponseType
) throw ()
{
switch (MAKELONG(ecb.rcRequestType, rcResponseType))
{
case MAKELONG(rcAccessRequest, rcAccessAccept):
// Fall through.
case MAKELONG(rcAccountingRequest, rcAccessAccept):
// Fall through.
case MAKELONG(rcAccountingRequest, rcAccountingResponse):
// Fall through.
case MAKELONG(rcAccountingRequest, rcUnknown):
return acceptAttrs.Get();
case MAKELONG(rcAccountingRequest, rcAccessReject):
// Fall through.
case MAKELONG(rcAccessRequest, rcAccessReject):
return rejectAttrs.Get();
case MAKELONG(rcAccessRequest, rcAccessChallenge):
return challengeAttrs.Get();
default:
// like (anything, rcUnknown). Should not happen
return 0;
}
}
DWORD ControlBlock::SetResponseType(RADIUS_CODE rcResponseType) throw ()
{
if (rcResponseType == ecb.rcResponseType)
{
return NO_ERROR;
}
switch (MAKELONG(ecb.rcRequestType, rcResponseType))
{
case MAKELONG(rcAccessRequest, rcAccessAccept):
source.SetResponse(
IAS_RESPONSE_ACCESS_ACCEPT,
S_OK
);
AddAuthType();
break;
case MAKELONG(rcAccountingRequest, rcAccountingResponse):
source.SetResponse(
IAS_RESPONSE_ACCOUNTING,
S_OK
);
break;
case MAKELONG(rcAccessRequest, rcAccessReject):
source.SetResponse(
IAS_RESPONSE_ACCESS_REJECT,
IAS_EXTENSION_REJECT
);
AddAuthType();
break;
case MAKELONG(rcAccessRequest, rcAccessChallenge):
source.SetResponse(
IAS_RESPONSE_ACCESS_CHALLENGE,
S_OK
);
break;
case MAKELONG(rcAccessRequest, rcDiscard):
// fall through.
case MAKELONG(rcAccountingRequest, rcDiscard):
source.SetResponse(
IAS_RESPONSE_DISCARD_PACKET,
IAS_EXTENSION_DISCARD
);
break;
default:
return ERROR_INVALID_PARAMETER;
}
ecb.rcResponseType = rcResponseType;
return NO_ERROR;
}
RADIUS_ATTRIBUTE_ARRAY* ControlBlock::GetRequest(
RADIUS_EXTENSION_CONTROL_BLOCK* This
) throw ()
{
return (This != 0) ? Narrow(This)->GetRequest() : 0;
}
RADIUS_ATTRIBUTE_ARRAY* ControlBlock::GetResponse(
RADIUS_EXTENSION_CONTROL_BLOCK* This,
RADIUS_CODE rcResponseType
) throw ()
{
return (This != 0) ? Narrow(This)->GetResponse(rcResponseType) : 0;
}
DWORD ControlBlock::SetResponseType(
RADIUS_EXTENSION_CONTROL_BLOCK* This,
RADIUS_CODE rcResponseType
) throw ()
{
if (This == 0)
{
return ERROR_INVALID_PARAMETER;
}
IASTracePrintf(
"RADIUS_EXTENSION_CONTROL_BLOCK.SetResponseType(%lu)",
rcResponseType
);
return Narrow(This)->SetResponseType(rcResponseType);
}