::const_iterator RadiusAttrIter;
/** RADIUS Packet as defined in RFC 2865 Section 3.
Data Format
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Code | Identifier | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| Authenticator |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Attributes ...
+-+-+-+-+-+-+-+-+-+-+-+-+-
*/
class RadiusMessage
{
public:
/** Create a RADIUS Message with type, no Attriubte yet
Useful for composing a request
*/
RadiusMessage( const RadiusPacketType code );
/** Create a RADIUS Message with type and an Authenticator
No Attriubte yet
Useful for composing a response
*/
RadiusMessage( const RadiusPacketType code,
const u_int8_t requestIdentifer,
const u_int8_t *requestAuth );
/** Create a RADIUS Message from data
Use when a message is received
Request Authenticator is verified automatically. However,
RadiusMessage::verifyResponseAuthenticator(auth,secret)
should be called later for Responses.
If an exception is thrown, the message should be handled
(discarded or rejected) according to the RFCs.
*/
RadiusMessage( const RadiusData data, const char* secret )
throw( VRadiusException& );
///
RadiusMessage( const RadiusMessage& rhs )
{
copyRhsToThis( rhs );
}
///
RadiusMessage& operator=( const RadiusMessage& rhs )
{
if( this != &rhs )
{
copyRhsToThis( rhs );
}
return *this;
}
///
void copyRhsToThis( const RadiusMessage& rhs )
{
memcpy( &myRequestAuthenticator,
rhs.myRequestAuthenticator,
RadiusAuthenticatorLength );
myAttributes = rhs.myAttributes;
myData = rhs.myData;
}
///
RadiusPacketType type()
{
return myData.msgHdr.code;
}
/// Encode all Attributes in this list
RadiusData encodeAttributes() const;
/// TODO: throw exception instead
bool add( const RadiusAttribute& attr );
/// Get the number of attributes
u_int32_t attributeCount() const
{
return myAttributes.size();
}
/**
Get the first instance of Attribute t from the list
Use getAll( RadiusAttributeType ) to retrieve multiple
attributes with the same type
*/
const RadiusAttribute& get( const RadiusAttributeType attrType ) const
throw( VRadiusException& );
/**
Get the list of all attributes of type attrType
*/
list< RadiusAttribute > getAll( const RadiusAttributeType attrType ) const;
/**
For RADIUS requests only
Must be called before Authenticator is calculated
*/
void setIdentifier( const u_int8_t& id )
{
myData.msgHdr.identifier = id;
}
///
u_int8_t getIdentifier() const
{
return myData.msgHdr.identifier;
}
/** Calculate and set the Authenticator
Must be called right before the packet is sent
*/
void calcAuthenticator( const char* secret );
/** Get the Authenticator
*/
const u_int8_t* getAuthenticator() const
{
return myRequestAuthenticator;
}
/** Verify a response with the original request's Authenticator
*/
bool verifyResponseAuthenticator( const u_int8_t *reqAuth,
const char* secret );
/** Get raw message data for sending
*/
const RawMessage& data() const
{
return myData;
}
/// Get a human readable representation of all attributes
string verbose() const;
/// Raw message in hex for debugging
string hexDump() const;
/// Get a human readable representation of the message header
string headerDump() const;
/// Get a human readable representation of the message
string attributesVerbose() const;
private:
/// Disable default constructor
RadiusMessage()
{
}
/** Decode Attributes
If an Attribute is received in an Access-Request but an
exception is thrown, an Access-Reject SHOULD be transmitted.
If an Attribute is received in an Access-Accept, Access-Reject
or Access-Challenge packet and an exception is thrown, the
packet must either be treated as an Access-Reject or else
silently discarded.
*/
void decodeAttributes( const char* secret )
throw( VRadiusException& );
///
bool verifyAccountingRequestAuthenticator( const char* secret );
/** Encode User-Password in Access-Request
oldPassword length must be a multiple of 16 octets
*/
void encodeUserPassword( u_int8_t* newPassword,
const char* secret,
const RadiusData& oldPassword );
/** Decode User-Password in Access-Request
oldPassword length must be a multiple of 16 octets
*/
void decodeUserPassword( u_int8_t* newPassword,
const char* secret,
const RadiusData& oldPassword );
/// Hide User-Password in Access-Request
void hideUserPassword( const char* secret );
/// Calculate and set myRequestAuthenticator for Access-Request packets
void calcAccessRequestAuthenticator();
/** Calculate and set the Authenticator for response (Access-Accept,
Access-Reject, Access-Challenge or Accounting Response) packets
*/
void calcResponseAuthenticator( const char* secret );
/// Calculate and set the Authenticator for Accounting request packets
void calcAccountingRequestAuthenticator( const char* secret );
void calcMD5( u_int8_t *digest,
const u_int8_t *buf,
const u_int32_t bufLen );
/// Request Authenticator
u_int8_t myRequestAuthenticator[ RadiusAuthenticatorLength ];
// TODO: may need a flag to keep myAttrList and myData in sync
/// Attribute list
list< RadiusAttribute > myAttributes;
/// RADIUS packet (in network byte order)
RawMessage myData;
};
// Local Variables:
// mode:c++
// c-file-style:"bsd"
// c-basic-offset:4
// c-file-offsets:((inclass . ++))
// indent-tabs-mode:nil
// End:
#endif