summaryrefslogtreecommitdiff
path: root/lib/radius/radpkt.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/radius/radpkt.c')
-rw-r--r--lib/radius/radpkt.c920
1 files changed, 0 insertions, 920 deletions
diff --git a/lib/radius/radpkt.c b/lib/radius/radpkt.c
deleted file mode 100644
index d9486ea..0000000
--- a/lib/radius/radpkt.c
+++ /dev/null
@@ -1,920 +0,0 @@
-/*
-Copyright (c) 2011, Network RADIUS SARL
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of the <organization> nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** \file packet.c
- * \brief Encoding and decoding packets
- */
-
-#include "client.h"
-
-#if RS_MAX_PACKET_LEN < 64
-#error RS_MAX_PACKET_LEN is too small. It should be at least 64.
-#endif
-
-#if RS_MAX_PACKET_LEN > 16384
-#error RS_MAX_PACKET_LEN is too large. It should be smaller than 16K.
-#endif
-
-const char *nr_packet_codes[RS_MAX_PACKET_CODE + 1] = {
- NULL,
- "Access-Request",
- "Access-Accept",
- "Access-Reject",
- "Accounting-Request",
- "Accounting-Response",
- NULL, NULL, NULL, NULL, NULL,
- "Access-Challenge",
- "Status-Server", /* 12 */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 19 */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 20..29 */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 30..39 */
- "Disconnect-Request",
- "Disconnect-ACK",
- "Disconnect-NAK",
- "CoA-Request",
- "CoA-ACK",
- "CoA-NAK"
-};
-
-
-static uint64_t allowed_responses[RS_MAX_PACKET_CODE + 1] = {
- 0,
- (1 << PW_ACCESS_ACCEPT) | (1 << PW_ACCESS_REJECT) | (1 << PW_ACCESS_CHALLENGE),
- 0, 0,
- 1 << PW_ACCOUNTING_RESPONSE,
- 0,
- 0, 0, 0, 0, 0,
- 0,
- (1 << PW_ACCESS_ACCEPT) | (1 << PW_ACCESS_REJECT) | (1 << PW_ACCESS_CHALLENGE) | (1 << PW_ACCOUNTING_RESPONSE),
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20..29 */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30..39 */
- (((uint64_t) 1) << PW_DISCONNECT_ACK) | (((uint64_t) 1) << PW_DISCONNECT_NAK),
- 0,
- 0,
- (((uint64_t) 1) << PW_COA_ACK) | (((uint64_t) 1) << PW_COA_NAK),
- 0,
- 0
-};
-
-
-int nr_packet_ok_raw(const uint8_t *data, size_t sizeof_data)
-{
- size_t packet_len;
- const uint8_t *attr, *end;
-
- if (!data || (sizeof_data < 20)) {
- nr_debug_error("Invalid argument");
- return -RSE_INVAL;
- }
-
- packet_len = (data[2] << 8) | data[3];
- if (packet_len < 20) {
- nr_debug_error("Packet length is too small");
- return -RSE_PACKET_TOO_SMALL;
- }
-
- if (packet_len > sizeof_data) {
- nr_debug_error("Packet length overflows received data");
- return -RSE_PACKET_TOO_LARGE;
- }
-
- /*
- * If we receive 100 bytes, and the header says it's 20 bytes,
- * then it's 20 bytes.
- */
- end = data + packet_len;
-
- for (attr = data + 20; attr < end; attr += attr[1]) {
- if ((attr + 2) > end) {
- nr_debug_error("Attribute overflows packet");
- return -RSE_ATTR_OVERFLOW;
- }
-
- if (attr[1] < 2) {
- nr_debug_error("Attribute length is too small");
- return -RSE_ATTR_TOO_SMALL;
- }
-
- if ((attr + attr[1]) > end) {
- nr_debug_error("Attribute length is too large");
- return -RSE_ATTR_TOO_LARGE;
- }
- }
-
- return 0;
-}
-
-int nr_packet_ok(RADIUS_PACKET *packet)
-{
- int rcode;
-
- if (!packet) return -RSE_INVAL;
-
- if ((packet->flags & RS_PACKET_OK) != 0) return 0;
-
- rcode = nr_packet_ok_raw(packet->data, packet->length);
- if (rcode < 0) return rcode;
-
- packet->flags |= RS_PACKET_OK;
- return 0;
-}
-
-
-/*
- * Comparison function that is time-independent. Using "memcmp"
- * would satisfy the "comparison" part. However, it would also
- * leak information about *which* bytes are wrong. Attackers
- * could use that leak to create a "correct" RADIUS packet which
- * will be accepted by the client and/or server.
- */
-static int digest_cmp(const uint8_t *a, const uint8_t *b, size_t length)
-{
- int result = 0;
- size_t i;
-
- for (i = 0; i < length; i++) {
- result |= (a[i] ^ b[i]);
- }
-
- return result;
-}
-
-
-#ifdef PW_MESSAGE_AUTHENTICATOR
-static int msg_auth_ok(const RADIUS_PACKET *original,
- uint8_t *ma,
- uint8_t *data, size_t length)
-{
- uint8_t packet_vector[sizeof(original->vector)];
- uint8_t msg_auth_vector[sizeof(original->vector)];
- uint8_t calc_auth_vector[sizeof(original->vector)];
-
- if (ma[1] != 18) {
- nr_debug_error("Message-Authenticator has invalid length");
- return -RSE_MSG_AUTH_LEN;
- }
-
- memcpy(packet_vector, data + 4, sizeof(packet_vector));
- memcpy(msg_auth_vector, ma + 2, sizeof(msg_auth_vector));
- memset(ma + 2, 0, sizeof(msg_auth_vector));
-
- switch (data[0]) {
- default:
- break;
-
- case PW_ACCOUNTING_REQUEST:
- case PW_ACCOUNTING_RESPONSE:
- case PW_DISCONNECT_REQUEST:
- case PW_DISCONNECT_ACK:
- case PW_DISCONNECT_NAK:
- case PW_COA_REQUEST:
- case PW_COA_ACK:
- case PW_COA_NAK:
- memset(data + 4, 0, sizeof(packet_vector));
- break;
-
- case PW_ACCESS_ACCEPT:
- case PW_ACCESS_REJECT:
- case PW_ACCESS_CHALLENGE:
- if (!original) {
- nr_debug_error("Cannot validate response without request");
- return -RSE_REQUEST_REQUIRED;
- }
- memcpy(data + 4, original->vector, sizeof(original->vector));
- break;
- }
-
- nr_hmac_md5(data, length,
- (const uint8_t *) original->secret, original->sizeof_secret,
- calc_auth_vector);
-
- memcpy(ma + 2, msg_auth_vector, sizeof(msg_auth_vector));
- memcpy(data + 4, packet_vector, sizeof(packet_vector));
-
- if (digest_cmp(calc_auth_vector, msg_auth_vector,
- sizeof(calc_auth_vector)) != 0) {
- nr_debug_error("Invalid Message-Authenticator");
- return -RSE_MSG_AUTH_WRONG;
- }
-
- return 1;
-}
-#endif
-
-/*
- * The caller ensures that the packet codes are as expected.
- */
-static int packet_auth_ok(const RADIUS_PACKET *original,
- uint8_t *data, size_t length)
-{
- uint8_t packet_vector[sizeof(original->vector)];
- uint8_t calc_digest[sizeof(original->vector)];
- RS_MD5_CTX ctx;
-
- if ((data[0] == PW_ACCESS_REQUEST) ||
- (data[0] == PW_STATUS_SERVER)) return 1;
-
- memcpy(packet_vector, data + 4, sizeof(packet_vector));
-
- if (!original) {
- memset(data + 4, 0, sizeof(packet_vector));
- } else {
- memcpy(data + 4, original->vector, sizeof(original->vector));
- }
-
- RS_MD5Init(&ctx);
- RS_MD5Update(&ctx, data, length);
- RS_MD5Update(&ctx, (const unsigned char *)original->secret, original->sizeof_secret);
- RS_MD5Final(calc_digest, &ctx);
-
- memcpy(data + 4, packet_vector, sizeof(packet_vector));
-
- if (digest_cmp(calc_digest, packet_vector,
- sizeof(packet_vector)) != 0) {
- nr_debug_error("Invalid authentication vector");
- return -RSE_AUTH_VECTOR_WRONG;
- }
-
- return 0;
-}
-
-
-int nr_packet_verify(RADIUS_PACKET *packet, const RADIUS_PACKET *original)
-{
- int rcode;
- uint8_t *attr;
-#ifdef PW_MESSAGE_AUTHENTICATOR
- const uint8_t *end;
-#endif
-
- if (!packet || !packet->data || !packet->secret) {
- nr_debug_error("Invalid argument");
- return -RSE_INVAL;
- }
-
- if ((packet->flags & RS_PACKET_VERIFIED) != 0) return 0;
-
- /*
- * Packet isn't well formed. Ignore it.
- */
- rcode = nr_packet_ok(packet);
- if (rcode < 0) return rcode;
-
- /*
- * Get rid of improper packets as early as possible.
- */
- if (original) {
- uint64_t mask;
-
- if (original->code > RS_MAX_PACKET_CODE) {
- nr_debug_error("Invalid original code %u",
- original->code);
- return -RSE_INVALID_REQUEST_CODE;
- }
-
- if (packet->data[1] != original->id) {
- nr_debug_error("Ignoring response with wrong ID %u",
- packet->data[1]);
- return -RSE_INVALID_RESPONSE_CODE;
- }
-
- mask = 1;
- mask <<= packet->data[0];
-
- if ((allowed_responses[original->code] & mask) == 0) {
- nr_debug_error("Ignoring response with wrong code %u",
- packet->data[0]);
- return -RSE_INVALID_RESPONSE_CODE;
- }
-
- if ((memcmp(&packet->src, &original->dst, sizeof(packet->src)) != 0) &&
- (evutil_sockaddr_cmp((struct sockaddr *)&packet->src, (struct sockaddr *)&original->dst, 1) != 0)) {
- nr_debug_error("Ignoring response from wrong IP/port");
- return -RSE_INVALID_RESPONSE_SRC;
- }
-
- } else if (allowed_responses[packet->data[0]] != 0) {
- nr_debug_error("Ignoring response without original");
- return -RSE_INVALID_RESPONSE_CODE;
- }
-
-#ifdef PW_MESSAGE_AUTHENTICATOR
- end = packet->data + packet->length;
-
- /*
- * Note that the packet MUST be well-formed here.
- */
- for (attr = packet->data + 20; attr < end; attr += attr[1]) {
- if (attr[0] == PW_MESSAGE_AUTHENTICATOR) {
- rcode = msg_auth_ok(original, attr,
- packet->data, packet->length);
- if (rcode < 0) return rcode;
- }
- }
-#endif
-
- /*
- * Verify the packet authenticator.
- */
- rcode = packet_auth_ok(original, packet->data, packet->length);
- if (rcode < 0) return rcode;
-
- packet->flags |= RS_PACKET_VERIFIED;
-
- return 0;
-}
-
-
-int nr_packet_decode(RADIUS_PACKET *packet, const RADIUS_PACKET *original)
-{
- int rcode, num_attributes;
- uint8_t *data, *attr;
- const uint8_t *end;
- VALUE_PAIR **tail, *vp;
-
- if (!packet) return -RSE_INVAL;
-
- if ((packet->flags & RS_PACKET_DECODED) != 0) return 0;
-
- rcode = nr_packet_ok(packet);
- if (rcode < 0) return rcode;
-
- data = packet->data;
- end = data + packet->length;
- tail = &packet->vps;
- num_attributes = 0;
-
- /*
- * Loop over the packet, converting attrs to VPs.
- */
- for (attr = data + 20; attr < end; attr += attr[1]) {
- rcode = nr_attr2vp(packet, original,
- attr, end - attr, &vp);
- if (rcode < 0) {
- nr_vp_free(&packet->vps);
- return -rcode;
- }
-
- *tail = vp;
- while (vp) {
- num_attributes++;
- tail = &(vp->next);
- vp = vp->next;
- }
-
- if (num_attributes > RS_MAX_ATTRIBUTES) {
- nr_debug_error("Too many attributes");
- nr_vp_free(&packet->vps);
- return -RSE_TOO_MANY_ATTRS;
- }
- }
-
- packet->code = data[0];
- packet->id = data[1];
- memcpy(packet->vector, data + 4, sizeof(packet->vector));
-
- packet->flags |= RS_PACKET_DECODED;
-
- return 0;
-}
-
-
-int nr_packet_sign(RADIUS_PACKET *packet, const RADIUS_PACKET *original)
-{
-#ifdef PW_MESSAGE_AUTHENTICATOR
- size_t ma = 0;
- const uint8_t *attr, *end;
-#endif
-
- if ((packet->flags & RS_PACKET_SIGNED) != 0) return 0;
-
- if ((packet->flags & RS_PACKET_ENCODED) == 0) {
- int rcode;
-
- rcode = nr_packet_encode(packet, original);
- if (rcode < 0) return rcode;
- }
-
- if ((packet->code == PW_ACCESS_ACCEPT) ||
- (packet->code == PW_ACCESS_CHALLENGE) ||
- (packet->code == PW_ACCESS_REJECT)) {
-#ifdef PW_MESSAGE_AUTHENTICATOR
- if (!original) {
- nr_debug_error("Original packet is required to create the Message-Authenticator");
- return -RSE_REQUEST_REQUIRED;
- }
-#endif
-
- memcpy(packet->data + 4, original->vector,
- sizeof(original->vector));
- } else {
- memcpy(packet->data + 4, packet->vector,
- sizeof(packet->vector));
- }
-
-#ifdef PW_MESSAGE_AUTHENTICATOR
- end = packet->data + packet->length;
-
- for (attr = packet->data + 20; attr < end; attr += attr[1]) {
- if (attr[0] == PW_MESSAGE_AUTHENTICATOR) {
- ma = (attr - packet->data);
- break;
- }
- }
-
- /*
- * Force all Access-Request packets to have a
- * Message-Authenticator.
- */
- if (!ma && ((packet->length + 18) <= packet->sizeof_data) &&
- ((packet->code == PW_ACCESS_REQUEST) ||
- (packet->code == PW_STATUS_SERVER))) {
- ma = packet->length;
-
- packet->data[ma]= PW_MESSAGE_AUTHENTICATOR;
- packet->data[ma + 1] = 18;
- memset(&packet->data[ma + 2], 0, 16);
- packet->length += 18;
- }
-
- /*
- * Reset the length.
- */
- packet->data[2] = (packet->length >> 8) & 0xff;
- packet->data[3] = packet->length & 0xff;
-
- /*
- * Sign the Message-Authenticator && packet.
- */
- if (ma) {
- nr_hmac_md5(packet->data, packet->length,
- (const uint8_t *) packet->secret, packet->sizeof_secret,
- packet->data + ma + 2);
- }
-#endif
-
- /*
- * Calculate the signature.
- */
- if (!((packet->code == PW_ACCESS_REQUEST) ||
- (packet->code == PW_STATUS_SERVER))) {
- RS_MD5_CTX ctx;
-
- RS_MD5Init(&ctx);
- RS_MD5Update(&ctx, packet->data, packet->length);
- RS_MD5Update(&ctx, (const unsigned char *)packet->secret, packet->sizeof_secret);
- RS_MD5Final(packet->vector, &ctx);
- }
-
- memcpy(packet->data + 4, packet->vector, sizeof(packet->vector));
-
- packet->attempts = 0;
- packet->flags |= RS_PACKET_SIGNED;
-
- return 0;
-}
-
-
-static int can_encode_packet(RADIUS_PACKET *packet,
- const RADIUS_PACKET *original)
-{
- if ((packet->code == 0) ||
- (packet->code > RS_MAX_PACKET_CODE) ||
- (original && (original->code > RS_MAX_PACKET_CODE))) {
- nr_debug_error("Cannot send unknown packet code");
- return -RSE_INVALID_REQUEST_CODE;
- }
-
- if (!nr_packet_codes[packet->code]) {
- nr_debug_error("Cannot handle packet code %u",
- packet->code);
- return -RSE_INVALID_REQUEST_CODE;
- }
-
-#ifdef NR_NO_MALLOC
- if (!packet->data) {
- nr_debug_error("No place to put packet");
- return -RSE_NO_PACKET_DATA;
- }
-#endif
-
- if (packet->sizeof_data < 20) {
- nr_debug_error("The buffer is too small to encode the packet");
- return -RSE_PACKET_TOO_SMALL;
- }
-
- /*
- * Enforce request / response correlation.
- */
- if (original) {
- uint64_t mask;
-
- mask = 1;
- mask <<= packet->code;
-
- if ((allowed_responses[original->code] & mask) == 0) {
- nr_debug_error("Cannot encode response %u to packet %u",
- packet->code, original->code);
- return -RSE_INVALID_RESPONSE_CODE;
- }
- packet->id = original->id;
-
- } else if (allowed_responses[packet->code] == 0) {
- nr_debug_error("Cannot encode response %u without original",
- packet->code);
- return -RSE_REQUEST_REQUIRED;
- }
-
- return 0;
-}
-
-static void encode_header(RADIUS_PACKET *packet)
-{
- if ((packet->flags & RS_PACKET_HEADER) != 0) return;
-
- memset(packet->data, 0, 20);
- packet->data[0] = packet->code;
- packet->data[1] = packet->id;
- packet->data[2] = 0;
- packet->data[3] = 20;
- packet->length = 20;
-
- /*
- * Calculate a random authentication vector.
- */
- if ((packet->code == PW_ACCESS_REQUEST) ||
- (packet->code == PW_STATUS_SERVER)) {
- nr_rand_bytes(packet->vector, sizeof(packet->vector));
- } else {
- memset(packet->vector, 0, sizeof(packet->vector));
- }
-
- memcpy(packet->data + 4, packet->vector, sizeof(packet->vector));
-
- packet->flags |= RS_PACKET_HEADER;
-}
-
-int nr_packet_encode(RADIUS_PACKET *packet, const RADIUS_PACKET *original)
-{
-#ifdef PW_MESSAGE_AUTHENTICATOR
- size_t ma = 0;
-#endif
- int rcode;
- ssize_t len;
- const VALUE_PAIR *vp;
- uint8_t *data, *end;
-
- if ((packet->flags & RS_PACKET_ENCODED) != 0) return 0;
-
- rcode = can_encode_packet(packet, original);
- if (rcode < 0) return rcode;
-
- data = packet->data;
- end = data + packet->sizeof_data;
-
- encode_header(packet);
- data += 20;
-
- /*
- * Encode each VALUE_PAIR
- */
- vp = packet->vps;
- while (vp) {
-#ifdef PW_MESSAGE_AUTHENTICATOR
- if (vp->da->attr == PW_MESSAGE_AUTHENTICATOR) {
- ma = (data - packet->data);
- }
-#endif
- len = nr_vp2attr(packet, original, &vp,
- data, end - data);
- if (len < 0) return len;
-
- if (len == 0) break; /* insufficient room to encode it */
-
- data += data[1];
- }
-
-#ifdef PW_MESSAGE_AUTHENTICATOR
- /*
- * Always send a Message-Authenticator.
- *
- * We do *not* recommend removing this code.
- */
- if (((packet->code == PW_ACCESS_REQUEST) ||
- (packet->code == PW_STATUS_SERVER)) &&
- !ma &&
- ((data + 18) <= end)) {
- ma = (data - packet->data);
- data[0] = PW_MESSAGE_AUTHENTICATOR;
- data[1] = 18;
- memset(data + 2, 0, 16);
- data += data[1];
- }
-#endif
-
- packet->length = data - packet->data;
-
- packet->data[2] = (packet->length >> 8) & 0xff;
- packet->data[3] = packet->length & 0xff;
-
- packet->flags |= RS_PACKET_ENCODED;
-
- return packet->length;
-}
-
-
-/*
- * Ensure that the nr_data2attr_t structure is filled in
- * appropriately. This includes filling in a fake DICT_ATTR
- * structure, if necessary.
- */
-static int do_callback(void *ctx, nr_packet_walk_func_t callback,
- int attr, int vendor,
- const uint8_t *data, size_t sizeof_data)
-
-{
- int rcode;
- const DICT_ATTR *da;
- DICT_ATTR myda;
- char buffer[64];
-
- da = nr_dict_attr_byvalue(attr, vendor);
-
- /*
- * The attribute is supposed to have a particular length,
- * but does not. It is therefore malformed.
- */
- if (da && (da->flags.length != 0) &&
- da->flags.length != sizeof_data) {
- da = NULL;
- }
-
- if (!da) {
- rcode = nr_dict_attr_2struct(&myda, attr, vendor,
- buffer, sizeof(buffer));
-
- if (rcode < 0) return rcode;
- da = &myda;
- }
-
- rcode = callback(ctx, da, data, sizeof_data);
- if (rcode < 0) return rcode;
-
- return 0;
-}
-
-
-int nr_packet_walk(RADIUS_PACKET *packet, void *ctx,
- nr_packet_walk_func_t callback)
-{
- int rcode;
- uint8_t *attr;
- const uint8_t *end;
-
- if (!packet || !callback) return -RSE_INVAL;
-
- rcode = nr_packet_ok(packet);
- if (rcode < 0) return rcode;
-
- end = packet->data + packet->length;
-
- for (attr = packet->data + 20; attr < end; attr += attr[1]) {
- int length, value;
- int dv_type, dv_length;
- uint32_t vendorpec;
- const uint8_t *vsa;
- const DICT_VENDOR *dv = NULL;
-
- vendorpec = 0;
- value = attr[0];
-
- if (value != PW_VENDOR_SPECIFIC) {
- raw:
- rcode = do_callback(ctx, callback,
- attr[0], 0,
- attr + 2, attr[1] - 2);
- if (rcode < 0) return rcode;
- continue;
- }
-
- if (attr[1] < 6) goto raw;
- memcpy(&vendorpec, attr + 2, 4);
- vendorpec = ntohl(vendorpec);
-
- if (dv && (dv->vendor != vendorpec)) dv = NULL;
-
- if (!dv) dv = nr_dict_vendor_byvalue(vendorpec);
-
- if (dv) {
- dv_type = dv->type;
- dv_length = dv->length;
- } else {
- dv_type = 1;
- dv_length = 1;
- }
-
- /*
- * Malformed: it's a raw attribute.
- */
- if (nr_tlv_ok(attr + 6, attr[1] - 6, dv_type, dv_length) < 0) {
- goto raw;
- }
-
- for (vsa = attr + 6; vsa < attr + attr[1]; vsa += length) {
- switch (dv_type) {
- case 4:
- value = (vsa[2] << 8) | vsa[3];
- break;
-
- case 2:
- value = (vsa[0] << 8) | vsa[1];
- break;
-
- case 1:
- value = vsa[0];
- break;
-
- default:
- return -RSE_INTERNAL;
- }
-
- switch (dv_length) {
- case 0:
- length = attr[1] - 6 - dv_type;
- break;
-
- case 2:
- case 1:
- length = vsa[dv_type + dv_length - 1];
- break;
-
- default:
- return -RSE_INTERNAL;
- }
-
- rcode = do_callback(ctx, callback,
- value, vendorpec,
- vsa + dv_type + dv_length,
- length - dv_type - dv_length);
- if (rcode < 0) return rcode;
- }
- }
-
- return 0;
-}
-
-int nr_packet_init(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
- const char *secret, int code,
- void *data, size_t sizeof_data)
-{
- int rcode;
-
- if ((code < 0) || (code > RS_MAX_PACKET_CODE)) {
- return -RSE_INVALID_REQUEST_CODE;
- }
-
- if (!data || (sizeof_data < 20)) return -RSE_INVAL;
-
- memset(packet, 0, sizeof(*packet));
- packet->secret = secret;
- packet->sizeof_secret = secret ? strlen(secret) : 0;
- packet->code = code;
- packet->id = 0;
- packet->data = data;
- packet->sizeof_data = sizeof_data;
-
- rcode = can_encode_packet(packet, original);
- if (rcode < 0) return rcode;
-
- encode_header(packet);
-
- return 0;
-}
-
-
-static int pack_eap(RADIUS_PACKET *packet,
- const void *data, size_t data_len)
-{
- uint8_t *attr, *end;
- const uint8_t *eap;
- size_t left;
-
- eap = data;
- left = data_len;
- attr = packet->data + packet->length;
- end = attr + packet->sizeof_data;
-
- while (left > 253) {
- if ((attr + 255) > end) return -RSE_ATTR_OVERFLOW;
-
- attr[0] = PW_EAP_MESSAGE;
- attr[1] = 255;
- memcpy(attr + 2, eap, 253);
- attr += attr[1];
- eap += 253;
- left -= 253;
- }
-
- if ((attr + (2 + left)) > end) return -RSE_ATTR_OVERFLOW;
-
- attr[0] = PW_EAP_MESSAGE;
- attr[1] = 2 + left;
- memcpy(attr + 2, eap, left);
- attr += attr[1];
- packet->length = attr - packet->data;
-
- return 0;
-}
-
-ssize_t nr_packet_attr_append(RADIUS_PACKET *packet,
- const RADIUS_PACKET *original,
- const DICT_ATTR *da,
- const void *data, size_t data_len)
-{
- ssize_t rcode;
- uint8_t *attr, *end;
- VALUE_PAIR my_vp;
- const VALUE_PAIR *vp;
-
- if (!packet || !da || !data) {
- return -RSE_INVAL;
- }
-
- if (data_len == 0) {
- if (da->type != RS_TYPE_STRING) return -RSE_ATTR_TOO_SMALL;
-
- data_len = strlen(data);
- }
-
- /* We're going to mark the whole packet as encoded so we
- better not have any unencoded value-pairs attached. */
- if (packet->vps)
- return -RSE_INVAL;
- packet->flags |= RS_PACKET_ENCODED;
-
- attr = packet->data + packet->length;
- end = attr + packet->sizeof_data;
-
- if ((attr + 2 + data_len) > end) {
- return -RSE_ATTR_OVERFLOW;
- }
-
- if ((da->flags.length != 0) &&
- (data_len != da->flags.length)) {
- return -RSE_ATTR_VALUE_MALFORMED;
- }
-
-#ifdef PW_EAP_MESSAGE
- /*
- * automatically split EAP-Message into multiple
- * attributes.
- */
- if (!da->vendor && (da->attr == PW_EAP_MESSAGE) && (data_len > 253)) {
- return pack_eap(packet, data, data_len);
- }
-#endif
-
- if (data_len > 253) return -RSE_ATTR_TOO_LARGE;
-
- vp = nr_vp_init(&my_vp, da);
- rcode = nr_vp_set_data(&my_vp, data, data_len);
- if (rcode < 0) return rcode;
-
- /*
- * Note that this function packs VSAs each into their own
- * Vendor-Specific attribute. If this isn't what you
- * want, use the version of the library with full support
- * for TLVs, WiMAX, and extended attributes.
- */
- rcode = nr_vp2attr(packet, original, &vp, attr, end - attr);
- if (rcode <= 0) return rcode;
-
- packet->length += rcode;
-
- return rcode;
-}