-/*
- * radius.c Functions to send/receive radius packets.
+/**
+ * @file radius.c
+ * @brief Functions to send/receive radius packets.
*
* Version: $Id$
*
} else {
ptr += 2;
total -= 2;
- vendor = 0;
}
print_hex_data(ptr, attrlen, 3);
fflush(stdout);
}
-/*
- * Wrapper for sendto which handles sendfromto, IPv6, and all
+/**
+ * @brief Wrapper for sendto which handles sendfromto, IPv6, and all
* possible combinations.
*/
static int rad_sendto(int sockfd, void *data, size_t data_len, int flags,
*/
rcode = sendto(sockfd, data, data_len, flags,
(struct sockaddr *) &dst, sizeof_dst);
+#ifdef WITH_UDPFROMTO
+done:
+#endif
if (rcode < 0) {
DEBUG("rad_send() failed: %s\n", strerror(errno));
}
}
-/*
- * wrapper for recvfrom, which handles recvfromto, IPv6, and all
+/**
+ * @brief wrapper for recvfrom, which handles recvfromto, IPv6, and all
* possible combinations.
*/
static ssize_t rad_recvfrom(int sockfd, uint8_t **pbuf, int flags,
#define AUTH_PASS_LEN (AUTH_VECTOR_LEN)
-/*************************************************************************
- *
- * Function: make_secret
- *
- * Purpose: Build an encrypted secret value to return in a reply
- * packet. The secret is hidden by xoring with a MD5 digest
+/**
+ * @brief Build an encrypted secret value to return in a reply packet
+ *
+ * The secret is hidden by xoring with a MD5 digest
* created from the shared secret and the authentication
* vector. We put them into MD5 in the reverse order from
* that used when encrypting passwords to RADIUS.
*
- *************************************************************************/
+ */
static void make_secret(uint8_t *digest, const uint8_t *vector,
const char *secret, const uint8_t *value)
{
const char *secret, const VALUE_PAIR **pvp,
unsigned int attribute, uint8_t *ptr, size_t room);
-/*
- * This is really a sub-function of vp2data_any. It encodes
+/**
+ * @brief This is really a sub-function of vp2data_any(). It encodes
* the *data* portion of the TLV, and assumes that the encapsulating
* attribute has already been encoded.
*/
ssize_t len;
size_t my_room;
uint8_t *ptr = start;
- const VALUE_PAIR *old_vp;
const VALUE_PAIR *vp = *pvp;
const VALUE_PAIR *svp = vp;
-#ifndef NDEBUG
+ if (!svp) return 0;
+#ifndef NDEBUG
if (nest > fr_attr_max_tlv) {
fr_strerror_printf("vp2data_tlvs: attribute nesting overflow");
return -1;
while (vp) {
if (room < 2) return ptr - start;
- old_vp = vp;
ptr[0] = (vp->attribute >> fr_attr_shift[nest]) & fr_attr_mask[nest];
ptr[1] = 2;
}
-/*
- * Encodes the data portion of an attribute.
- * Returns -1 on error, or the length of the data portion.
+/**
+ * @brief Encodes the data portion of an attribute.
+ * @return -1 on error, or the length of the data portion.
*/
static ssize_t vp2data_any(const RADIUS_PACKET *packet,
const RADIUS_PACKET *original,
const uint8_t *data;
uint8_t *ptr = start;
uint8_t array[4];
+ uint64_t lvalue64;
const VALUE_PAIR *vp = *pvp;
/*
data = vp->vp_octets;
len = vp->length;
+ /*
+ * Short-circuit it for long attributes. They can't be
+ * encrypted, tagged, etc.
+ */
+ if ((vp->type & PW_FLAG_LONG) != 0) goto do_tlv;
+
switch(vp->type) {
case PW_TYPE_STRING:
case PW_TYPE_OCTETS:
data = array;
break;
+ case PW_TYPE_INTEGER64:
+ len = 8; /* just in case */
+ lvalue64 = htonll(vp->vp_integer64);
+ data = (uint8_t *) &lvalue64;
+ break;
+
case PW_TYPE_IPADDR:
data = (const uint8_t *) &vp->vp_ipaddr;
len = 4; /* just in case */
}
case PW_TYPE_TLV:
+ do_tlv:
data = vp->vp_tlv;
if (!data) {
fr_strerror_printf("ERROR: Cannot encode NULL TLV");
return -1;
}
- len = vp->length;
break;
default: /* unknown type: ignore it */
}
-/*
- * Encode an "extended" attribute.
+/**
+ * @brief Encode an "extended" attribute.
*/
int rad_vp2extended(const RADIUS_PACKET *packet,
const RADIUS_PACKET *original,
}
-/*
- * Encode a WiMAX attribute.
+/**
+ * @brief Encode a WiMAX attribute.
*/
int rad_vp2wimax(const RADIUS_PACKET *packet,
const RADIUS_PACKET *original,
return (ptr + ptr[1]) - start;
}
-/*
- * Encode an RFC format TLV. This could be a standard attribute,
+/**
+ * @brief Encode an RFC format TLV.
+ *
+ * This could be a standard attribute,
* or a TLV data type. If it's a standard attribute, then
* vp->attribute == attribute. Otherwise, attribute may be
* something else.
}
-/*
- * Encode a VSA which is a TLV. If it's in the RFC format, call
+/**
+ * @brief Encode a VSA which is a TLV. If it's in the RFC format, call
* vp2attr_rfc. Otherwise, encode it here.
*/
static ssize_t vp2attr_vsa(const RADIUS_PACKET *packet,
}
-/*
- * Encode a Vendor-Specific attribute.
+/**
+ * @brief Encode a Vendor-Specific attribute.
*/
int rad_vp2vsa(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
const char *secret, const VALUE_PAIR **pvp, uint8_t *ptr,
}
-/*
- * Encode an RFC standard attribute 1..255
+/**
+ * @brief Encode an RFC standard attribute 1..255
*/
int rad_vp2rfc(const RADIUS_PACKET *packet,
const RADIUS_PACKET *original,
return -1;
}
+ /*
+ * Only CUI is allowed to have zero length.
+ * Thank you, WiMAX!
+ */
if ((vp->length == 0) &&
- (vp->attribute != PW_CHARGEABLE_USER_IDENTITY)) {
+ (vp->attribute == PW_CHARGEABLE_USER_IDENTITY)) {
+ ptr[0] = PW_CHARGEABLE_USER_IDENTITY;
+ ptr[1] = 2;
+
*pvp = vp->next;
- return 0;
+ return 2;
}
return vp2attr_rfc(packet, original, secret, pvp, vp->attribute,
}
-/*
- * Parse a data structure into a RADIUS attribute.
+/**
+ * @brief Parse a data structure into a RADIUS attribute.
*/
int rad_vp2attr(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
const char *secret, const VALUE_PAIR **pvp, uint8_t *start,
}
-/*
- * Encode a packet.
+/**
+ * @brief Encode a packet.
*/
int rad_encode(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
const char *secret)
}
-/*
- * Sign a previously encoded packet.
+/**
+ * @brief Sign a previously encoded packet.
*/
int rad_sign(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
const char *secret)
uint8_t calc_auth_vector[AUTH_VECTOR_LEN];
switch (packet->code) {
- case PW_ACCOUNTING_REQUEST:
case PW_ACCOUNTING_RESPONSE:
+ if (original && original->code == PW_STATUS_SERVER) {
+ goto do_ack;
+ }
+
+ case PW_ACCOUNTING_REQUEST:
case PW_DISCONNECT_REQUEST:
case PW_DISCONNECT_ACK:
case PW_DISCONNECT_NAK:
memset(hdr->vector, 0, AUTH_VECTOR_LEN);
break;
+ do_ack:
case PW_AUTHENTICATION_ACK:
case PW_AUTHENTICATION_REJECT:
case PW_ACCESS_CHALLENGE:
return 0;
}
-/*
- * Reply to the request. Also attach
+/**
+ * @brief Reply to the request. Also attach
* reply attribute value pairs and any user message provided.
*/
int rad_send(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
&packet->dst_ipaddr, packet->dst_port);
}
-/*
- * Do a comparison of two authentication digests by comparing
- * the FULL digest. Otehrwise, the server can be subject to
+/**
+ * @brief Do a comparison of two authentication digests by comparing
+ * the FULL digest.
+ *
+ * Otherwise, the server can be subject to
* timing attacks that allow attackers find a valid message
* authenticator.
*
}
-/*
- * Validates the requesting client NAS. Calculates the
+/**
+ * @brief Validates the requesting client NAS. Calculates the
* signature based on the clients private key.
*/
static int calc_acctdigest(RADIUS_PACKET *packet, const char *secret)
}
-/*
- * Validates the requesting client NAS. Calculates the
+/**
+ * @brief Validates the requesting client NAS. Calculates the
* signature based on the clients private key.
*/
static int calc_replydigest(RADIUS_PACKET *packet, RADIUS_PACKET *original,
}
-/*
- * Check if a set of RADIUS formatted TLVs are OK.
+/**
+ * @brief Check if a set of RADIUS formatted TLVs are OK.
*/
int rad_tlv_ok(const uint8_t *data, size_t length,
size_t dv_type, size_t dv_length)
}
-/*
- * See if the data pointed to by PTR is a valid RADIUS packet.
+/**
+ * @brief See if the data pointed to by PTR is a valid RADIUS packet.
*
* packet is not 'const * const' because we may update data_len,
* if there's more data in the UDP packet than in the RADIUS packet.
}
-/*
- * Receive UDP client requests, and fill in
+/**
+ * @brief Receive UDP client requests, and fill in
* the basics of a RADIUS_PACKET structure.
*/
RADIUS_PACKET *rad_recv(int fd, int flags)
}
-/*
- * Verify the signature of a packet.
+/**
+ * @brief Verify the signature of a packet.
*/
int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original,
const char *secret)
default:
break;
- case PW_ACCOUNTING_REQUEST:
case PW_ACCOUNTING_RESPONSE:
+ if (original &&
+ (original->code == PW_STATUS_SERVER)) {
+ goto do_ack;
+ }
+
+ case PW_ACCOUNTING_REQUEST:
case PW_DISCONNECT_REQUEST:
case PW_DISCONNECT_ACK:
case PW_DISCONNECT_NAK:
memset(packet->data + 4, 0, AUTH_VECTOR_LEN);
break;
+ do_ack:
case PW_AUTHENTICATION_ACK:
case PW_AUTHENTICATION_REJECT:
case PW_ACCESS_CHALLENGE:
}
-/*
- * Create a "raw" attribute from the attribute contents.
+/**
+ * @brief Create a "raw" attribute from the attribute contents.
*/
static ssize_t data2vp_raw(UNUSED const RADIUS_PACKET *packet,
UNUSED const RADIUS_PACKET *original,
vp->length = length;
/*
- * If the data is too large, mark it as a "TLV".
+ * If it's short, put it into the array. If it's too
+ * long, flag it as such, and put it somewhere else;
*/
if (length <= sizeof(vp->vp_octets)) {
memcpy(vp->vp_octets, data, length);
} else {
- vp->type = PW_TYPE_TLV;
+ vp->type |= PW_FLAG_LONG;
vp->vp_tlv = malloc(length);
if (!vp->vp_tlv) {
pairfree(&vp);
const uint8_t *start, size_t length,
VALUE_PAIR **pvp);
-/*
- * Create any kind of VP from the attribute contents.
- *
- * Will return -1 on error, or "length".
+/**
+ * @brief Create any kind of VP from the attribute contents.
+ * @return -1 on error, or "length".
*/
static ssize_t data2vp_any(const RADIUS_PACKET *packet,
const RADIUS_PACKET *original,
int data_offset = 0;
DICT_ATTR *da;
VALUE_PAIR *vp = NULL;
+ uint8_t buffer[256];
if (length == 0) {
/*
}
/*
+ * The data is very long.
+ */
+ if (length > sizeof(vp->vp_octets)) {
+ /*
+ * Long encrypted attributes are forbidden.
+ */
+ if (da->flags.encrypt != FLAG_ENCRYPT_NONE) goto raw;
+
+#ifndef NDEBUG
+ /*
+ * Catch programming errors.
+ */
+ if ((da->type != PW_TYPE_STRING) &&
+ (da->type != PW_TYPE_OCTETS)) goto raw;
+
+#endif
+
+ /*
+ * FIXME: Figure out how to deal with long
+ * strings and binary data!
+ */
+ goto raw;
+ }
+
+ /*
* The attribute is known, and well formed. We can now
* create it. The main failure from here on in is being
* out of memory.
/*
* Copy the data to be decrypted
*/
- vp->length = length - data_offset;
- memcpy(&vp->vp_octets[0], data + data_offset, vp->length);
+ vp->length = length - data_offset;
+ memcpy(buffer, data + data_offset, vp->length);
/*
* Decrypt the attribute.
*/
- if (secret) switch (vp->flags.encrypt) {
+ if (secret && packet) switch (vp->flags.encrypt) {
/*
* User-Password
*/
case FLAG_ENCRYPT_USER_PASSWORD:
if (original) {
- rad_pwdecode(vp->vp_strvalue,
+ rad_pwdecode((char *) buffer,
vp->length, secret,
original->vector);
} else {
- rad_pwdecode(vp->vp_strvalue,
+ rad_pwdecode((char *) buffer,
vp->length, secret,
packet->vector);
}
+ buffer[253] = '\0';
if (vp->attribute == PW_USER_PASSWORD) {
- vp->length = strlen(vp->vp_strvalue);
+ vp->length = strlen((char *) buffer);
}
break;
case FLAG_ENCRYPT_TUNNEL_PASSWORD:
if (!original) goto raw;
- if (rad_tunnel_pwdecode(vp->vp_octets, &vp->length,
+ if (rad_tunnel_pwdecode(buffer, &vp->length,
secret, original->vector) < 0) {
goto raw;
}
make_secret(my_digest,
original->vector,
secret, data);
- memcpy(vp->vp_strvalue, my_digest,
+ memcpy(buffer, my_digest,
AUTH_VECTOR_LEN );
- vp->vp_strvalue[AUTH_VECTOR_LEN] = '\0';
- vp->length = strlen(vp->vp_strvalue);
+ buffer[AUTH_VECTOR_LEN] = '\0';
+ vp->length = strlen((char *) buffer);
}
break;
switch (vp->type) {
case PW_TYPE_STRING:
+ memcpy(vp->vp_strvalue, buffer, vp->length);
+ vp->vp_strvalue[vp->length] = '\0';
+ break;
+
case PW_TYPE_OCTETS:
case PW_TYPE_ABINARY:
- /* nothing more to do */
+ memcpy(vp->vp_octets, buffer, vp->length);
break;
case PW_TYPE_BYTE:
if (vp->length != 1) goto raw;
- vp->vp_integer = vp->vp_octets[0];
+ vp->vp_integer = buffer[0];
break;
case PW_TYPE_SHORT:
if (vp->length != 2) goto raw;
- vp->vp_integer = (vp->vp_octets[0] << 8) | vp->vp_octets[1];
+ vp->vp_integer = (buffer[0] << 8) | buffer[1];
break;
case PW_TYPE_INTEGER:
if (vp->length != 4) goto raw;
- memcpy(&vp->vp_integer, vp->vp_octets, 4);
+ memcpy(&vp->vp_integer, buffer, 4);
vp->vp_integer = ntohl(vp->vp_integer);
if (vp->flags.has_tag) vp->vp_integer &= 0x00ffffff;
+ break;
- /*
- * Try to get named VALUEs
- */
- {
- DICT_VALUE *dval;
- dval = dict_valbyattr(vp->attribute, vp->vendor,
- vp->vp_integer);
- if (dval) {
- strlcpy(vp->vp_strvalue,
- dval->name,
- sizeof(vp->vp_strvalue));
- }
- }
+ case PW_TYPE_INTEGER64:
+ if (vp->length != 8) goto raw;
+
+ /* vp_integer64 is a union with vp_octets */
+ memcpy(&vp->vp_integer64, buffer, 8);
+ vp->vp_integer64 = ntohll(vp->vp_integer64);
break;
case PW_TYPE_DATE:
if (vp->length != 4) goto raw;
- memcpy(&vp->vp_date, vp->vp_octets, 4);
+ memcpy(&vp->vp_date, buffer, 4);
vp->vp_date = ntohl(vp->vp_date);
break;
case PW_TYPE_IPADDR:
if (vp->length != 4) goto raw;
- memcpy(&vp->vp_ipaddr, vp->vp_octets, 4);
+ memcpy(&vp->vp_ipaddr, buffer, 4);
break;
/*
*/
case PW_TYPE_IFID:
if (vp->length != 8) goto raw;
- /* vp->vp_ifid == vp->vp_octets */
+ memcpy(&vp->vp_ifid, buffer, 8);
break;
/*
*/
case PW_TYPE_IPV6ADDR:
if (vp->length != 16) goto raw;
- /* vp->vp_ipv6addr == vp->vp_octets */
+ memcpy(&vp->vp_ipv6addr, buffer, 16);
break;
/*
*/
case PW_TYPE_IPV6PREFIX:
if (vp->length < 2 || vp->length > 18) goto raw;
- if (vp->vp_octets[1] > 128) goto raw;
+ if (buffer[1] > 128) goto raw;
/*
* FIXME: double-check that
* (vp->vp_octets[1] >> 3) matches vp->length + 2
*/
+ memcpy(&vp->vp_ipv6prefix, buffer, vp->length);
if (vp->length < 18) {
- memset(vp->vp_octets + vp->length, 0,
+ memset(((uint8_t *)vp->vp_ipv6prefix) + vp->length, 0,
18 - vp->length);
}
break;
* Overload vp_integer for ntohl, which takes
* uint32_t, not int32_t
*/
- memcpy(&vp->vp_integer, vp->vp_octets, 4);
+ memcpy(&vp->vp_integer, buffer, 4);
vp->vp_integer = ntohl(vp->vp_integer);
- memcpy(&vp->vp_signed, &vp->vp_integer, 4);
break;
case PW_TYPE_TLV:
case PW_TYPE_COMBO_IP:
if (vp->length == 4) {
vp->type = PW_TYPE_IPADDR;
- memcpy(&vp->vp_ipaddr, vp->vp_octets, 4);
+ memcpy(&vp->vp_ipaddr, buffer, 4);
break;
} else if (vp->length == 16) {
vp->type = PW_TYPE_IPV6ADDR;
- /* vp->vp_ipv6addr == vp->vp_octets */
+ memcpy(&vp->vp_ipv6addr, buffer, 16);
break;
}
}
-/*
- * Convert a top-level VSA to a VP.
+/**
+ * @brief Convert a top-level VSA to a VP.
*/
static ssize_t attr2vp_vsa(const RADIUS_PACKET *packet,
const RADIUS_PACKET *original,
return dv_type + dv_length + attrlen;
}
-/*
- * Convert one or more TLVs to VALUE_PAIRs. This function can
+/**
+ * @brief Convert one or more TLVs to VALUE_PAIRs. This function can
* be called recursively...
*/
static ssize_t data2vp_tlvs(const RADIUS_PACKET *packet,
}
-/*
- * Group "continued" attributes together, and create VPs from them.
+/**
+ * @brief Group "continued" attributes together, and create VPs from them.
+ *
* The caller ensures that the RADIUS packet is OK, and that the
* continuations have all been checked.
*/
while (left > 0) {
#ifndef NDEBUG
if (data >= (start + length)) {
+ free(attr);
fr_strerror_printf("data2vp_continued: Internal sanity check failed");
return -1;
}
}
-/*
- * Create a "raw" VALUE_PAIR from a RADIUS attribute.
+/**
+ * @brief Create a "raw" VALUE_PAIR from a RADIUS attribute.
*/
ssize_t rad_attr2vp_raw(const RADIUS_PACKET *packet,
const RADIUS_PACKET *original,
}
-/*
- * Get the length of the data portion of all of the contiguous
+/**
+ * @brief Get the length of the data portion of all of the contiguous
* continued attributes.
- *
+ * @return
* 0 for "no continuation"
* -1 on malformed packets (continuation followed by non-wimax, etc.)
*/
}
-/*
- * Get the length of the data portion of all of the contiguous
+/**
+ * @brief Get the length of the data portion of all of the contiguous
* continued attributes.
*
- * 0 for "no continuation"
+ * @return
+ * 0 for "no continuation"
* -1 on malformed packets (continuation followed by non-wimax, etc.)
*/
static ssize_t extended_attrlen(const uint8_t *start, const uint8_t *end)
}
-/*
- * Create WiMAX VALUE_PAIRs from a RADIUS attribute.
+/**
+ * @brief Create WiMAX VALUE_PAIRs from a RADIUS attribute.
*/
ssize_t rad_attr2vp_wimax(const RADIUS_PACKET *packet,
const RADIUS_PACKET *original,
return data[1];
}
-/*
- * Create Vendor-Specifc VALUE_PAIRs from a RADIUS attribute.
+/**
+ * @brief Create Vendor-Specifc VALUE_PAIRs from a RADIUS attribute.
*/
ssize_t rad_attr2vp_vsa(const RADIUS_PACKET *packet,
const RADIUS_PACKET *original,
return data[1];
}
-/*
- * Create an "extended" VALUE_PAIR from a RADIUS attribute.
+/**
+ * @brief Create an "extended" VALUE_PAIR from a RADIUS attribute.
*/
ssize_t rad_attr2vp_extended(const RADIUS_PACKET *packet,
const RADIUS_PACKET *original,
}
-/*
- * Create a "standard" RFC VALUE_PAIR from the given data.
+/**
+ * @brief Create a "standard" RFC VALUE_PAIR from the given data.
*/
ssize_t rad_attr2vp_rfc(const RADIUS_PACKET *packet,
const RADIUS_PACKET *original,
return data[1];
}
-/*
- * Create a "normal" VALUE_PAIR from the given data.
+/**
+ * @brief Create a "normal" VALUE_PAIR from the given data.
*/
ssize_t rad_attr2vp(const RADIUS_PACKET *packet,
const RADIUS_PACKET *original,
}
-/*
- * Calculate/check digest, and decode radius attributes.
- * Returns:
- * -1 on decoding error
- * 0 on success
+/**
+ * @brief Calculate/check digest, and decode radius attributes.
+ * @return -1 on decoding error, 0 on success
*/
int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original,
const char *secret)
}
-/*
- * Encode password.
+/**
+ * @brief Encode password.
*
* We assume that the passwd buffer passed is big enough.
* RFC2138 says the password is max 128 chars, so the size
return 0;
}
-/*
- * Decode password.
+/**
+ * @brief Decode password.
*/
int rad_pwdecode(char *passwd, size_t pwlen, const char *secret,
const uint8_t *vector)
}
-/*
- * Encode Tunnel-Password attributes when sending them out on the wire.
+/**
+ * @brief Encode Tunnel-Password attributes when sending them out on the wire.
*
* int *pwlen is updated to the new length of the encrypted
* password - a multiple of 16 bytes.
return 0;
}
-/*
- * Decode Tunnel-Password encrypted attributes.
+/**
+ * @brief Decode Tunnel-Password encrypted attributes.
*
* Defined in RFC-2868, this uses a two char SALT along with the
* initial intermediate value, to differentiate it from the
return reallen;
}
-/*
- * Encode a CHAP password
+/**
+ * @brief Encode a CHAP password
*
- * FIXME: might not work with Ascend because
+ * @bug FIXME: might not work with Ascend because
* we use vp->length, and Ascend gear likes
* to send an extra '\0' in the string!
*/
}
-/*
- * Seed the random number generator.
+/**
+ * @brief Seed the random number generator.
*
* May be called any number of times.
*/
}
-/*
- * Return a 32-bit random number.
+/**
+ * @brief Return a 32-bit random number.
*/
uint32_t fr_rand(void)
{
}
-/*
- * Allocate a new RADIUS_PACKET
+/**
+ * @brief Allocate a new RADIUS_PACKET
*/
RADIUS_PACKET *rad_alloc(int newvector)
{
}
-/*
- * Free a RADIUS_PACKET
+/**
+ * @brief Free a RADIUS_PACKET
*/
void rad_free(RADIUS_PACKET **radius_packet_ptr)
{