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.
295 lines
8.2 KiB
295 lines
8.2 KiB
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) Microsoft Corp. All rights reserved.
|
|
//
|
|
// FILE
|
|
//
|
|
// userr.cpp
|
|
//
|
|
// SYNOPSIS
|
|
//
|
|
// Defines the class UserRestrictions.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <ias.h>
|
|
#include <userr.h>
|
|
#include <TimeOfDay.h>
|
|
|
|
IASREQUESTSTATUS UserRestrictions::onSyncRequest(IRequest* pRequest) throw ()
|
|
{
|
|
try
|
|
{
|
|
IASRequest request(pRequest);
|
|
|
|
IASREASON result;
|
|
|
|
if (!checkAllowDialin(request))
|
|
{
|
|
result = IAS_DIALIN_DISABLED;
|
|
}
|
|
else if (!checkTimeOfDay(request))
|
|
{
|
|
result = IAS_INVALID_DIALIN_HOURS;
|
|
}
|
|
else if (!checkAuthenticationType(request))
|
|
{
|
|
result = IAS_INVALID_AUTH_TYPE;
|
|
}
|
|
else if (!checkCallingStationId(request))
|
|
{
|
|
result = IAS_INVALID_CALLING_STATION;
|
|
}
|
|
else if (!checkCalledStationId(request))
|
|
{
|
|
result = IAS_INVALID_CALLED_STATION;
|
|
}
|
|
else if (!checkAllowedPortType(request))
|
|
{
|
|
result = IAS_INVALID_PORT_TYPE;
|
|
}
|
|
else if (!checkPasswordMustChange(request))
|
|
{
|
|
result = IAS_CPW_NOT_ALLOWED;
|
|
}
|
|
else
|
|
{
|
|
result = IAS_SUCCESS;
|
|
}
|
|
|
|
if (result != IAS_SUCCESS)
|
|
{
|
|
request.SetResponse(IAS_RESPONSE_ACCESS_REJECT, result);
|
|
}
|
|
}
|
|
catch (const _com_error&)
|
|
{
|
|
pRequest->SetResponse(IAS_RESPONSE_DISCARD_PACKET, IAS_INTERNAL_ERROR);
|
|
}
|
|
|
|
return IAS_REQUEST_STATUS_HANDLED;
|
|
}
|
|
|
|
BOOL UserRestrictions::checkAllowDialin(
|
|
IAttributesRaw* request
|
|
)
|
|
{
|
|
PIASATTRIBUTE attr = IASPeekAttribute(
|
|
request,
|
|
IAS_ATTRIBUTE_ALLOW_DIALIN,
|
|
IASTYPE_BOOLEAN
|
|
);
|
|
|
|
return !attr || attr->Value.Boolean;
|
|
}
|
|
|
|
BOOL UserRestrictions::checkTimeOfDay(
|
|
IAttributesRaw* request
|
|
)
|
|
{
|
|
AttributeVector attrs;
|
|
attrs.load(request, IAS_ATTRIBUTE_NP_TIME_OF_DAY);
|
|
if (attrs.empty()) { return TRUE; }
|
|
|
|
BYTE hourMap[IAS_HOUR_MAP_LENGTH];
|
|
memset(hourMap, 0, sizeof(hourMap));
|
|
|
|
for (AttributeVector::iterator i = attrs.begin(); i != attrs.end(); ++i)
|
|
{
|
|
IASAttributeUnicodeAlloc(i->pAttribute);
|
|
if (!i->pAttribute->Value.String.pszWide) { issue_error(E_OUTOFMEMORY); }
|
|
|
|
// Convert the text to an hour map.
|
|
DWORD dw = IASHourMapFromText(
|
|
i->pAttribute->Value.String.pszWide,
|
|
TRUE,
|
|
hourMap
|
|
);
|
|
if (dw != NO_ERROR)
|
|
{
|
|
issue_error(HRESULT_FROM_WIN32(dw));
|
|
}
|
|
}
|
|
|
|
SYSTEMTIME now;
|
|
GetLocalTime(&now);
|
|
DWORD timeOut = ComputeTimeout(now, hourMap);
|
|
|
|
if (timeOut == 0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (timeOut != 0xFFFFFFFF)
|
|
{
|
|
// Add the Session-Timeout attribute to the request.
|
|
// it'll be carried over to the response later on.
|
|
IASAttribute sessionTimeout(true);
|
|
sessionTimeout->dwId = MS_ATTRIBUTE_SESSION_TIMEOUT;
|
|
sessionTimeout->Value.itType = IASTYPE_INTEGER;
|
|
sessionTimeout->Value.Integer = timeOut;
|
|
sessionTimeout.setFlag(IAS_INCLUDE_IN_ACCEPT);
|
|
sessionTimeout.store(request);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL UserRestrictions::checkAuthenticationType(
|
|
IAttributesRaw* request
|
|
)
|
|
{
|
|
// special case for the external Auth provider
|
|
PIASATTRIBUTE provider = IASPeekAttribute(
|
|
request,
|
|
IAS_ATTRIBUTE_PROVIDER_TYPE,
|
|
IASTYPE_ENUM
|
|
);
|
|
_ASSERT(provider != 0);
|
|
if (provider->Value.Enumerator == IAS_PROVIDER_EXTERNAL_AUTH)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
AttributeVector attrs;
|
|
attrs.load(request, IAS_ATTRIBUTE_NP_AUTHENTICATION_TYPE);
|
|
if (attrs.empty()) {return TRUE;}
|
|
|
|
PIASATTRIBUTE attr = IASPeekAttribute(
|
|
request,
|
|
IAS_ATTRIBUTE_AUTHENTICATION_TYPE,
|
|
IASTYPE_ENUM
|
|
);
|
|
DWORD authType = attr ? attr->Value.Enumerator : IAS_AUTH_NONE;
|
|
|
|
// We bypass the check for BaseCamp extensions.
|
|
if (authType == IAS_AUTH_CUSTOM) { return TRUE; }
|
|
|
|
for (AttributeVector::iterator i = attrs.begin(); i != attrs.end(); ++i)
|
|
{
|
|
if (i->pAttribute->Value.Integer == authType) { return TRUE; }
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL UserRestrictions::checkCallingStationId(
|
|
IAttributesRaw* request
|
|
)
|
|
{
|
|
return checkStringMatch(
|
|
request,
|
|
IAS_ATTRIBUTE_NP_CALLING_STATION_ID,
|
|
RADIUS_ATTRIBUTE_CALLING_STATION_ID
|
|
);
|
|
}
|
|
|
|
BOOL UserRestrictions::checkCalledStationId(
|
|
IAttributesRaw* request
|
|
)
|
|
{
|
|
return checkStringMatch(
|
|
request,
|
|
IAS_ATTRIBUTE_NP_CALLED_STATION_ID,
|
|
RADIUS_ATTRIBUTE_CALLED_STATION_ID
|
|
);
|
|
}
|
|
|
|
BOOL UserRestrictions::checkAllowedPortType(
|
|
IAttributesRaw* request
|
|
)
|
|
{
|
|
AttributeVector attrs;
|
|
attrs.load(request, IAS_ATTRIBUTE_NP_ALLOWED_PORT_TYPES);
|
|
if (attrs.empty()) { return TRUE; }
|
|
|
|
PIASATTRIBUTE attr = IASPeekAttribute(
|
|
request,
|
|
RADIUS_ATTRIBUTE_NAS_PORT_TYPE,
|
|
IASTYPE_ENUM
|
|
);
|
|
if (!attr) { return FALSE; }
|
|
|
|
for (AttributeVector::iterator i = attrs.begin(); i != attrs.end(); ++i)
|
|
{
|
|
if (i->pAttribute->Value.Enumerator == attr->Value.Enumerator)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// If the password must change, we check to see if the subsequent change
|
|
// password request would be authorized. This prevents prompting the user for a
|
|
// new password when he's not allowed to change it anyway.
|
|
BOOL UserRestrictions::checkPasswordMustChange(
|
|
IASRequest& request
|
|
)
|
|
{
|
|
if (request.get_Reason() != IAS_PASSWORD_MUST_CHANGE)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
PIASATTRIBUTE attr = IASPeekAttribute(
|
|
request,
|
|
IAS_ATTRIBUTE_AUTHENTICATION_TYPE,
|
|
IASTYPE_ENUM
|
|
);
|
|
|
|
DWORD cpwType;
|
|
switch (attr ? attr->Value.Enumerator : IAS_AUTH_NONE)
|
|
{
|
|
case IAS_AUTH_MSCHAP:
|
|
cpwType = IAS_AUTH_MSCHAP_CPW;
|
|
break;
|
|
|
|
case IAS_AUTH_MSCHAP2:
|
|
cpwType = IAS_AUTH_MSCHAP2_CPW;
|
|
break;
|
|
|
|
default:
|
|
return TRUE;
|
|
}
|
|
|
|
AttributeVector attrs;
|
|
attrs.load(request, IAS_ATTRIBUTE_NP_AUTHENTICATION_TYPE);
|
|
for (AttributeVector::iterator i = attrs.begin(); i != attrs.end(); ++i)
|
|
{
|
|
if (i->pAttribute->Value.Integer == cpwType) { return TRUE; }
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL UserRestrictions::checkStringMatch(
|
|
IAttributesRaw* request,
|
|
DWORD allowedId,
|
|
DWORD usedId
|
|
)
|
|
{
|
|
AttributeVector attrs;
|
|
attrs.load(request, allowedId);
|
|
if (attrs.empty()) { return TRUE; }
|
|
|
|
PIASATTRIBUTE attr = IASPeekAttribute(
|
|
request,
|
|
usedId,
|
|
IASTYPE_OCTET_STRING
|
|
);
|
|
if (!attr) { return FALSE; }
|
|
|
|
PCWSTR used = IAS_OCT2WIDE(attr->Value.OctetString);
|
|
|
|
for (AttributeVector::iterator i = attrs.begin(); i != attrs.end(); ++i)
|
|
{
|
|
IASAttributeUnicodeAlloc(i->pAttribute);
|
|
if (!i->pAttribute->Value.String.pszWide) { issue_error(E_OUTOFMEMORY); }
|
|
|
|
if (!_wcsicmp(i->pAttribute->Value.String.pszWide, used)) { return TRUE; }
|
|
}
|
|
|
|
return FALSE;
|
|
}
|