/*
- * The RFC says 4096 octets max, and most packets are less than 256.
- */
-#define MAX_PACKET_LEN 4096
-
-/*
* The maximum number of attributes which we allow in an incoming
* request. If there are more attributes than this, the request
* is rejected.
}
-void rad_print_hex(RADIUS_PACKET *packet)
+void rad_print_hex(RADIUS_PACKET const *packet)
{
int i;
* Convert AF. If unknown, discard packet.
*/
if (!fr_sockaddr2ipaddr(&src, sizeof_src, src_ipaddr, src_port)) {
- FR_DEBUG_STRERROR_PRINTF("Unkown address family");
+ FR_DEBUG_STRERROR_PRINTF("Unknown address family");
rad_recv_discard(sockfd);
return 1;
* encrypting passwords to RADIUS.
*/
static void make_secret(uint8_t *digest, uint8_t const *vector,
- char const *secret, uint8_t const *value)
+ char const *secret, uint8_t const *value, size_t length)
{
FR_MD5_CTX context;
- int i;
+ size_t i;
fr_md5_init(&context);
fr_md5_update(&context, vector, AUTH_VECTOR_LEN);
fr_md5_update(&context, (uint8_t const *) secret, strlen(secret));
fr_md5_final(digest, &context);
- for ( i = 0; i < AUTH_VECTOR_LEN; i++ ) {
+ for ( i = 0; i < length; i++ ) {
digest[i] ^= value[i];
}
}
case PW_TYPE_STRING:
case PW_TYPE_OCTETS:
data = vp->data.ptr;
- if (!data) {
- fr_strerror_printf("ERROR: Cannot encode NULL data");
- return -1;
- }
+ if (!data) return 0;
break;
case PW_TYPE_IFID:
* always fits.
*/
case FLAG_ENCRYPT_ASCEND_SECRET:
- if (len != 16) return 0;
- make_secret(ptr, packet->vector, secret, data);
+ if (len > AUTH_VECTOR_LEN) len = AUTH_VECTOR_LEN;
+ make_secret(ptr, packet->vector, secret, data, len);
len = AUTH_VECTOR_LEN;
break;
ptr[0] = attribute & 0xff;
ptr[1] = 2;
- if (room > ((unsigned) 255 - ptr[1])) room = 255 - ptr[1];
+ if (room > 255) room = 255;
- len = vp2data_any(packet, original, secret, 0, pvp, ptr + ptr[1], room);
+ len = vp2data_any(packet, original, secret, 0, pvp, ptr + ptr[1], room - ptr[1]);
if (len <= 0) return len;
ptr[1] += len;
}
- if (room > ((unsigned) 255 - (dv->type + dv->length))) {
- room = 255 - (dv->type + dv->length);
- }
+ if (room > 255) room = 255;
len = vp2data_any(packet, original, secret, 0, pvp,
- ptr + dv->type + dv->length, room);
+ ptr + dv->type + dv->length, room - (dv->type + dv->length));
if (len <= 0) return len;
if (dv->length) ptr[dv->type + dv->length - 1] += len;
lvalue = htonl(vp->da->vendor);
memcpy(ptr + 2, &lvalue, 4);
- if (room > ((unsigned) 255 - ptr[1])) room = 255 - ptr[1];
+ if (room > 255) room = 255;
len = vp2attr_vsa(packet, original, secret, pvp,
vp->da->attr, vp->da->vendor,
- ptr + ptr[1], room);
+ ptr + ptr[1], room - ptr[1]);
if (len < 0) return len;
#ifndef NDEBUG
/*
* Message-Authenticator is hard-coded.
*/
- if (!vp->da->vendor && (vp->da->attr == PW_MESSAGE_AUTHENTICATOR)) {
+ if (vp->da->attr == PW_MESSAGE_AUTHENTICATOR) {
if (room < 18) return -1;
ptr[0] = PW_MESSAGE_AUTHENTICATOR;
* RFC format attributes take the fast path.
*/
if (!vp->da->vendor) {
- if (vp->da->attr > 255) return 0;
+ if (vp->da->attr > 255) {
+ *pvp = vp->next;
+ return 0;
+ }
return rad_vp2rfc(packet, original, secret, pvp,
start, room);
*/
reply = packet->vps;
while (reply) {
- size_t last_len;
+ size_t last_len, room;
char const *last_name = NULL;
VERIFY_VP(reply);
}
/*
+ * We allow zero-length strings in "unlang", but
+ * skip them (except for CUI, thanks WiMAX!) on
+ * all other attributes.
+ */
+ if (reply->vp_length == 0) {
+ if ((reply->da->vendor != 0) ||
+ ((reply->da->attr != PW_CHARGEABLE_USER_IDENTITY) &&
+ (reply->da->attr != PW_MESSAGE_AUTHENTICATOR))) {
+ reply = reply->next;
+ continue;
+ }
+ }
+
+ /*
* Set the Message-Authenticator to the correct
* length and initial value.
*/
}
last_name = reply->da->name;
- len = rad_vp2attr(packet, original, secret, &reply, ptr,
- ((uint8_t *) data) + sizeof(data) - ptr);
+ room = ((uint8_t *) data) + sizeof(data) - ptr;
+
+ if (room <= 2) break;
+
+ len = rad_vp2attr(packet, original, secret, &reply, ptr, room);
if (len < 0) return -1;
/*
}
/*
+ * Set up the authentication vector with zero, or with
+ * the original vector, prior to signing.
+ */
+ switch (packet->code) {
+ case PW_CODE_ACCOUNTING_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_COA_REQUEST:
+ memset(packet->vector, 0, AUTH_VECTOR_LEN);
+ break;
+
+ case PW_CODE_ACCESS_ACCEPT:
+ case PW_CODE_ACCESS_REJECT:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
+ if (!original) {
+ fr_strerror_printf("ERROR: Cannot sign response packet without a request packet");
+ return -1;
+ }
+ memcpy(packet->vector, original->vector, AUTH_VECTOR_LEN);
+ break;
+
+ case PW_CODE_ACCESS_REQUEST:
+ case PW_CODE_STATUS_SERVER:
+ default:
+ break; /* packet->vector is already random bytes */
+ }
+
+#ifndef NDEBUG
+ if ((fr_debug_lvl > 3) && fr_log_fp) rad_print_hex(packet);
+#endif
+
+ /*
* If there's a Message-Authenticator, update it
- * now, BEFORE updating the authentication vector.
+ * now.
*/
if (packet->offset > 0) {
uint8_t calc_auth_vector[AUTH_VECTOR_LEN];
case PW_CODE_DISCONNECT_NAK:
case PW_CODE_COA_REQUEST:
case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
memset(hdr->vector, 0, AUTH_VECTOR_LEN);
break;
case PW_CODE_ACCESS_ACCEPT:
case PW_CODE_ACCESS_REJECT:
case PW_CODE_ACCESS_CHALLENGE:
- if (!original) {
- fr_strerror_printf("ERROR: Cannot sign response packet without a request packet");
- return -1;
- }
- memcpy(hdr->vector, original->vector,
- AUTH_VECTOR_LEN);
+ memcpy(hdr->vector, original->vector, AUTH_VECTOR_LEN);
break;
- default: /* others have vector already set to zero */
+ default:
break;
-
}
/*
(uint8_t const *) secret, strlen(secret));
memcpy(packet->data + packet->offset + 2,
calc_auth_vector, AUTH_VECTOR_LEN);
-
- /*
- * Copy the original request vector back
- * to the raw packet.
- */
- memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN);
}
/*
+ * Copy the request authenticator over to the packet.
+ */
+ memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN);
+
+ /*
* Switch over the packet code, deciding how to
* sign the packet.
*/
switch (packet->code) {
/*
- * Request packets are not signed, bur
+ * Request packets are not signed, but
* have a random authentication vector.
*/
case PW_CODE_ACCESS_REQUEST:
bool seen_ma = false;
uint32_t num_attributes;
decode_fail_t failure = DECODE_FAIL_NONE;
+ bool eap = false;
+ bool non_eap = false;
/*
* Check for packets smaller than the packet header.
*/
case PW_EAP_MESSAGE:
require_ma = true;
+ eap = true;
+ break;
+
+ case PW_USER_PASSWORD:
+ case PW_CHAP_PASSWORD:
+ case PW_ARAP_PASSWORD:
+ non_eap = true;
break;
case PW_MESSAGE_AUTHENTICATOR:
goto finish;
}
+ if (eap && non_eap) {
+ FR_DEBUG_STRERROR_PRINTF("Bad packet from host %s: Packet contains EAP-Message and non-EAP authentication attribute",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)));
+ failure = DECODE_FAIL_TOO_MANY_AUTH;
+ goto finish;
+ }
+
/*
* Fill RADIUS header fields
*/
goto raw;
} else {
uint8_t my_digest[AUTH_VECTOR_LEN];
+ size_t secret_len;
+
+ secret_len = datalen;
+ if (secret_len > AUTH_VECTOR_LEN) secret_len = AUTH_VECTOR_LEN;
+
make_secret(my_digest,
original->vector,
- secret, data);
+ secret, data, secret_len);
memcpy(buffer, my_digest,
AUTH_VECTOR_LEN );
buffer[AUTH_VECTOR_LEN] = '\0';
* This is per RFC-2868 which adds a two char SALT to the initial intermediate
* value MD5 hash.
*/
-int rad_tunnel_pwencode(char *passwd, size_t *pwlen, char const *secret,
- uint8_t const *vector)
+ssize_t rad_tunnel_pwencode(char *passwd, size_t *pwlen, char const *secret, uint8_t const *vector)
{
uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 3];
unsigned char digest[AUTH_VECTOR_LEN];
* initial intermediate value, to differentiate it from the
* above.
*/
-int rad_tunnel_pwdecode(uint8_t *passwd, size_t *pwlen, char const *secret,
- uint8_t const *vector)
+ssize_t rad_tunnel_pwdecode(uint8_t *passwd, size_t *pwlen, char const *secret, uint8_t const *vector)
{
FR_MD5_CTX context, old;
uint8_t digest[AUTH_VECTOR_LEN];