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.
 
 
 
 
 
 

346 lines
8.2 KiB

///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) Microsoft Corp. All rights reserved.
//
// SYNOPSIS
//
// Defines the class Accountant.
//
///////////////////////////////////////////////////////////////////////////////
#include "ias.h"
#include "account.h"
#include <algorithm>
#include "sdoias.h"
#define STACK_ALLOC(type, num) (type*)_alloca(sizeof(type) * (num))
Accountant::Accountant() throw ()
: logAuth(false),
logAcct(false),
logInterim(false),
logAuthInterim(false)
{
}
Accountant::~Accountant() throw ()
{
}
STDMETHODIMP Accountant::Initialize()
{
return schema.initialize();
}
STDMETHODIMP Accountant::Shutdown()
{
schema.shutdown();
return S_OK;
}
HRESULT Accountant::PutProperty(LONG id, VARIANT* value) throw ()
{
if (value == 0)
{
return E_INVALIDARG;
}
HRESULT hr = S_OK;
switch (id)
{
case PROPERTY_ACCOUNTING_LOG_ACCOUNTING:
{
if (V_VT(value) == VT_BOOL)
{
logAcct = (V_BOOL(value) != 0);
}
else
{
hr = DISP_E_TYPEMISMATCH;
}
break;
}
case PROPERTY_ACCOUNTING_LOG_ACCOUNTING_INTERIM:
{
if (V_VT(value) == VT_BOOL)
{
logInterim = (V_BOOL(value) != 0);
}
else
{
hr = DISP_E_TYPEMISMATCH;
}
break;
}
case PROPERTY_ACCOUNTING_LOG_AUTHENTICATION:
{
if (V_VT(value) == VT_BOOL)
{
logAuth = (V_BOOL(value) != 0);
}
else
{
hr = DISP_E_TYPEMISMATCH;
}
break;
}
case PROPERTY_ACCOUNTING_LOG_AUTHENTICATION_INTERIM:
{
if (V_VT(value) == VT_BOOL)
{
logAuthInterim = (V_BOOL(value) != 0);
}
else
{
hr = DISP_E_TYPEMISMATCH;
}
break;
}
default:
{
// We just ignore properties that we don't understand.
break;
}
}
return hr;
}
void Accountant::RecordEvent(void* context, IASTL::IASRequest& request)
{
// Array of PacketTypes to be inserted. PKT_UNKNOWN indicates no record.
PacketType types[3] =
{
PKT_UNKNOWN,
PKT_UNKNOWN,
PKT_UNKNOWN
};
// Determine packet types based on request type and the configuration.
switch (request.get_Request())
{
case IAS_REQUEST_ACCOUNTING:
{
if (IsInterimRecord(request) ? logInterim : logAcct)
{
types[0] = PKT_ACCOUNTING_REQUEST;
}
break;
}
case IAS_REQUEST_ACCESS_REQUEST:
{
switch (request.get_Response())
{
case IAS_RESPONSE_ACCESS_ACCEPT:
{
if (logAuth)
{
types[0] = PKT_ACCESS_REQUEST;
types[1] = PKT_ACCESS_ACCEPT;
}
break;
}
case IAS_RESPONSE_ACCESS_REJECT:
{
if (logAuth)
{
types[0] = PKT_ACCESS_REQUEST;
types[1] = PKT_ACCESS_REJECT;
}
break;
}
case IAS_RESPONSE_ACCESS_CHALLENGE:
{
if (logAuthInterim)
{
types[0] = PKT_ACCESS_REQUEST;
types[1] = PKT_ACCESS_CHALLENGE;
}
break;
}
default:
{
break;
}
}
break;
}
default:
{
break;
}
}
// Get the local SYSTEMTIME.
SYSTEMTIME localTime;
GetLocalTime(&localTime);
// Insert the appropriate records.
for (const PacketType* type = types; *type != PKT_UNKNOWN; ++type)
{
InsertRecord(context, request, localTime, *type);
}
// Flush the accounting stream.
Flush(context, request, localTime);
}
void Accountant::InsertRecord(
void* context,
IASTL::IASRequest& request,
const SYSTEMTIME& localTime,
PacketType packetType
)
{
//////////
// Retrieve all the attributes from the request. Save room for three extra
// attributes: Packet-Type, Reason-Code, and a null-terminator.
//////////
PATTRIBUTEPOSITION firstPos, curPos, lastPos;
DWORD nattr = request.GetAttributeCount();
firstPos = STACK_ALLOC(ATTRIBUTEPOSITION, nattr + 3);
nattr = request.GetAttributes(nattr, firstPos, 0, NULL);
lastPos = firstPos + nattr;
//////////
// Compute the attribute filter and reason code.
//////////
DWORD always, never, reason = 0;
switch (packetType)
{
case PKT_ACCESS_REQUEST:
always = IAS_RECVD_FROM_CLIENT | IAS_RECVD_FROM_PROTOCOL;
never = IAS_INCLUDE_IN_RESPONSE;
break;
case PKT_ACCESS_ACCEPT:
always = IAS_INCLUDE_IN_ACCEPT;
never = IAS_RECVD_FROM_CLIENT |
IAS_INCLUDE_IN_REJECT | IAS_INCLUDE_IN_CHALLENGE;
break;
case PKT_ACCESS_REJECT:
always = IAS_INCLUDE_IN_REJECT;
never = IAS_RECVD_FROM_CLIENT |
IAS_INCLUDE_IN_ACCEPT | IAS_INCLUDE_IN_CHALLENGE;
reason = request.get_Reason();
break;
case PKT_ACCESS_CHALLENGE:
always = IAS_INCLUDE_IN_CHALLENGE;
never = IAS_RECVD_FROM_CLIENT |
IAS_INCLUDE_IN_ACCEPT | IAS_INCLUDE_IN_REJECT;
break;
case PKT_ACCOUNTING_REQUEST:
always = IAS_INCLUDE_IN_ACCEPT | IAS_RECVD_FROM_CLIENT |
IAS_RECVD_FROM_PROTOCOL;
never = IAS_INCLUDE_IN_RESPONSE;
reason = request.get_Reason();
break;
}
//////////
// Filter the attributes based on flags.
//////////
for (curPos = firstPos; curPos != lastPos; )
{
// We can release here since the request still holds a reference.
IASAttributeRelease(curPos->pAttribute);
if (!(curPos->pAttribute->dwFlags & always) &&
(curPos->pAttribute->dwFlags & never ) &&
(curPos->pAttribute->dwId != RADIUS_ATTRIBUTE_CLASS))
{
--lastPos;
std::swap(lastPos->pAttribute, curPos->pAttribute);
}
else
{
++curPos;
}
}
//////////
// Add the Packet-Type pseudo-attribute.
//////////
IASATTRIBUTE packetTypeAttr;
packetTypeAttr.dwId = IAS_ATTRIBUTE_PACKET_TYPE;
packetTypeAttr.dwFlags = (DWORD)-1;
packetTypeAttr.Value.itType = IASTYPE_ENUM;
packetTypeAttr.Value.Enumerator = packetType;
lastPos->pAttribute = &packetTypeAttr;
++lastPos;
//////////
// Add the Reason-Code pseudo-attribute.
//////////
IASATTRIBUTE reasonCodeAttr;
reasonCodeAttr.dwId = IAS_ATTRIBUTE_REASON_CODE;
reasonCodeAttr.dwFlags = (DWORD)-1;
reasonCodeAttr.Value.itType = IASTYPE_INTEGER;
reasonCodeAttr.Value.Integer = reason;
lastPos->pAttribute = &reasonCodeAttr;
++lastPos;
//////////
// Invoke the derived class.
//////////
InsertRecord(context, request, localTime, firstPos, lastPos);
}
IASREQUESTSTATUS Accountant::onSyncRequest(IRequest* pRequest) throw ()
{
try
{
Process(IASTL::IASRequest(pRequest));
}
catch (...)
{
pRequest->SetResponse(IAS_RESPONSE_DISCARD_PACKET, IAS_NO_RECORD);
return IAS_REQUEST_STATUS_ABORT;
}
return IAS_REQUEST_STATUS_CONTINUE;
}
bool Accountant::IsInterimRecord(IAttributesRaw* attrs) throw ()
{
const DWORD accountingInterim = 3;
IASATTRIBUTE* attr = IASPeekAttribute(
attrs,
RADIUS_ATTRIBUTE_ACCT_STATUS_TYPE,
IASTYPE_ENUM
);
return (attr != 0) && (attr->Value.Enumerator == accountingInterim);
}