summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/event.c29
-rw-r--r--src/lib/packet.c18
-rw-r--r--src/lib/print.c1
-rw-r--r--src/lib/radius.c154
4 files changed, 135 insertions, 67 deletions
diff --git a/src/lib/event.c b/src/lib/event.c
index 9eb9d1a..0d926ad 100644
--- a/src/lib/event.c
+++ b/src/lib/event.c
@@ -47,7 +47,9 @@ typedef struct fr_event_fd_t {
void *ctx;
} fr_event_fd_t;
-#define FR_EV_MAX_FDS (512)
+#define FR_EV_MAX_EVENTS (512)
+
+int fr_ev_max_fds = FR_EV_MAX_EVENTS;
#undef USEC
#define USEC (1000000)
@@ -71,10 +73,10 @@ struct fr_event_list_t {
fd_set write_fds;
#else
int kq;
- struct kevent events[FR_EV_MAX_FDS]; /* so it doesn't go on the stack every time */
+ struct kevent events[FR_EV_MAX_EVENTS]; /* so it doesn't go on the stack every time */
#endif
- fr_event_fd_t readers[FR_EV_MAX_FDS];
+ fr_event_fd_t readers[1];
};
/*
@@ -128,11 +130,12 @@ fr_event_list_t *fr_event_list_create(TALLOC_CTX *ctx, fr_event_status_t status)
int i;
fr_event_list_t *el;
- el = talloc_zero(ctx, fr_event_list_t);
+ el = (fr_event_list_t *) talloc_zero_array(ctx, uint8_t, sizeof(fr_event_list_t) + fr_ev_max_fds * sizeof(el->readers[0]));
if (!fr_assert(el)) {
return NULL;
}
talloc_set_destructor(el, _event_list_free);
+ talloc_set_type(el, fr_event_list_t);
el->times = fr_heap_create(fr_event_list_time_cmp, offsetof(fr_event_t, heap));
if (!el->times) {
@@ -140,7 +143,7 @@ fr_event_list_t *fr_event_list_create(TALLOC_CTX *ctx, fr_event_status_t status)
return NULL;
}
- for (i = 0; i < FR_EV_MAX_FDS; i++) {
+ for (i = 0; i < fr_ev_max_fds; i++) {
el->readers[i].fd = -1;
}
@@ -363,7 +366,7 @@ int fr_event_fd_insert(fr_event_list_t *el, int type, int fd,
return 0;
}
- if (el->num_readers >= FR_EV_MAX_FDS) {
+ if (el->num_readers >= fr_ev_max_fds) {
fr_strerror_printf("Too many readers");
return 0;
}
@@ -385,11 +388,11 @@ int fr_event_fd_insert(fr_event_list_t *el, int type, int fd,
* usually less than 256, we do "FD & 0xff", which is a
* good guess, and makes the lookups mostly O(1).
*/
- for (i = 0; i < FR_EV_MAX_FDS; i++) {
+ for (i = 0; i < fr_ev_max_fds; i++) {
int j;
struct kevent evset;
- j = (i + fd) & (FR_EV_MAX_FDS - 1);
+ j = (i + fd) & (fr_ev_max_fds - 1);
if (el->readers[j].fd >= 0) continue;
@@ -469,11 +472,11 @@ int fr_event_fd_write_handler(fr_event_list_t *el, int type, int fd,
if (type != 0) return 0;
#ifdef HAVE_KQUEUE
- for (i = 0; i < FR_EV_MAX_FDS; i++) {
+ for (i = 0; i < fr_ev_max_fds; i++) {
int j;
struct kevent evset;
- j = (i + fd) & (FR_EV_MAX_FDS - 1);
+ j = (i + fd) & (fr_ev_max_fds - 1);
if (el->readers[j].fd != fd) continue;
@@ -528,11 +531,11 @@ int fr_event_fd_delete(fr_event_list_t *el, int type, int fd)
if (type != 0) return 0;
#ifdef HAVE_KQUEUE
- for (i = 0; i < FR_EV_MAX_FDS; i++) {
+ for (i = 0; i < fr_ev_max_fds; i++) {
int j;
struct kevent evset;
- j = (i + fd) & (FR_EV_MAX_FDS - 1);
+ j = (i + fd) & (fr_ev_max_fds - 1);
if (el->readers[j].fd != fd) continue;
@@ -676,7 +679,7 @@ int fr_event_loop(fr_event_list_t *el)
ts_wake = NULL;
}
- rcode = kevent(el->kq, NULL, 0, el->events, FR_EV_MAX_FDS, ts_wake);
+ rcode = kevent(el->kq, NULL, 0, el->events, FR_EV_MAX_EVENTS, ts_wake);
#endif /* HAVE_KQUEUE */
if (fr_heap_num_elements(el->times) > 0) {
diff --git a/src/lib/packet.c b/src/lib/packet.c
index 971980b..0f870f5 100644
--- a/src/lib/packet.c
+++ b/src/lib/packet.c
@@ -723,6 +723,8 @@ bool fr_packet_list_id_alloc(fr_packet_list_t *pl, int proto,
*/
id = fd = -1;
+ if (request->id >= 0 && request->id < 256)
+ id = request->id;
start_i = fr_rand() & SOCKOFFSET_MASK;
#define ID_i ((i + start_i) & SOCKOFFSET_MASK)
@@ -832,6 +834,18 @@ bool fr_packet_list_id_alloc(fr_packet_list_t *pl, int proto,
*/
/*
+ * An explicit ID was requested
+ */
+
+ if (id != -1) {
+ if ((ps->id[(id >> 3) & 0x1f] & (1 << (id & 0x07))) != 0) continue;
+
+ ps->id[(id >> 3) & 0x1f] |= (1 << (id & 0x07));
+ fd = i;
+ break;
+ }
+
+ /*
* Look for a free Id, starting from a random number.
*/
start_j = fr_rand() & 0x1f;
@@ -1076,7 +1090,7 @@ void fr_packet_header_print(FILE *fp, RADIUS_PACKET *packet, bool received)
* This really belongs in a utility library
*/
if (is_radius_code(packet->code)) {
- fprintf(fp, "%s %s Id %i from %s%s%s:%x to %s%s%s:%u length %zu\n",
+ fprintf(fp, "%s %s Id %i from %s%s%s:%u to %s%s%s:%u length %zu\n",
received ? "Received" : "Sent",
fr_packet_codes[packet->code],
packet->id,
@@ -1094,7 +1108,7 @@ void fr_packet_header_print(FILE *fp, RADIUS_PACKET *packet, bool received)
packet->dst_port,
packet->data_len);
} else {
- fprintf(fp, "%s code %u Id %i from %s%s%s:%u to %s%s%s:%i length %zu\n",
+ fprintf(fp, "%s code %u Id %i from %s%s%s:%u to %s%s%s:%u length %zu\n",
received ? "Received" : "Sent",
packet->code,
packet->id,
diff --git a/src/lib/print.c b/src/lib/print.c
index 57455b6..83aa267 100644
--- a/src/lib/print.c
+++ b/src/lib/print.c
@@ -529,6 +529,7 @@ size_t vp_prints_value_json(char *out, size_t outlen, VALUE_PAIR const *vp, bool
switch (vp->da->type) {
case PW_TYPE_STRING:
+ case PW_TYPE_OCTETS:
for (q = vp->vp_strvalue; q < vp->vp_strvalue + vp->vp_length; q++) {
/* Indicate truncation */
if (freespace < 3) return outlen + 1;
diff --git a/src/lib/radius.c b/src/lib/radius.c
index b2de15b..a19c9a4 100644
--- a/src/lib/radius.c
+++ b/src/lib/radius.c
@@ -145,8 +145,9 @@ char const *fr_packet_codes[FR_MAX_PACKET_CODE] = {
"47",
"48",
"49",
- "IP-Address-Allocate",
- "IP-Address-Release", //!< 50
+ "IP-Address-Allocate", //!< 50
+ "IP-Address-Release",
+ "Protocol-Error",
};
@@ -536,7 +537,7 @@ static void make_secret(uint8_t *digest, uint8_t const *vector,
fr_md5_destroy(&context);
}
-#define MAX_PASS_LEN (128)
+#define MAX_PASS_LEN (256)
static void make_passwd(uint8_t *output, ssize_t *outlen,
uint8_t const *input, size_t inlen,
char const *secret, uint8_t const *vector)
@@ -1819,6 +1820,14 @@ int rad_vp2attr(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
return rad_vp2vsa(packet, original, secret, pvp, start, room);
}
+static const bool code2ma[FR_MAX_PACKET_CODE] = {
+ [ PW_CODE_ACCESS_REQUEST ] = true,
+ [ PW_CODE_ACCESS_ACCEPT ] = true,
+ [ PW_CODE_ACCESS_REJECT ] = true,
+ [ PW_CODE_ACCESS_CHALLENGE ] = true,
+ [ PW_CODE_STATUS_SERVER ] = true,
+ [ PW_CODE_PROTOCOL_ERROR ] = true,
+};
/** Encode a packet
*
@@ -1831,6 +1840,7 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
uint16_t total_length;
int len;
VALUE_PAIR const *reply;
+ bool seen_ma = false;
/*
* A 4K packet, aligned on 64-bits.
@@ -1883,6 +1893,12 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
id = htonl(id);
memcpy(hdr->vector, &id, sizeof(id));
memset(hdr->vector + sizeof(id), 0, sizeof(hdr->vector) - sizeof(id));
+
+ /*
+ * We don't encode Message-Authenticator
+ */
+ seen_ma = true;
+ packet->offset = -1;
} else
#endif
{
@@ -1909,6 +1925,27 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
*/
/*
+ * Always add Message-Authenticator for replies to
+ * Access-Request packets, and for all Access-Accept,
+ * Access-Reject, Access-Challenge.
+ *
+ * It must be the FIRST attribute in the packet.
+ */
+ if (!packet->tls &&
+ ((code2ma[packet->code]) || (original && code2ma[original->code]))) {
+ seen_ma = true;
+
+ packet->offset = RADIUS_HDR_LEN;
+
+ ptr[0] = PW_MESSAGE_AUTHENTICATOR;
+ ptr[1] = 18;
+ memset(ptr + 2, 0, 16);
+
+ ptr += 18;
+ total_length += 18;
+ }
+
+ /*
* Loop over the reply attributes for the packet.
*/
reply = packet->vps;
@@ -1943,18 +1980,9 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
#ifdef WITH_RADIUSV11
/*
- * Do not encode Message-Authenticator for RADIUS/1.1
- */
- if ((reply->da->vendor == 0) && (reply->da->attr == PW_MESSAGE_AUTHENTICATOR)) {
- reply = reply->next;
- continue;
- }
-
-
- /*
* Do not encode Original-Packet-Code for RADIUS/1.1
*/
- if (reply->da->vendor == ((unsigned int) PW_EXTENDED_ATTRIBUTE_1 << 24) && (reply->da->attr == 4)) {
+ if (packet->radiusv11 && reply->da->vendor == ((unsigned int) PW_EXTENDED_ATTRIBUTE_1 << 24) && (reply->da->attr == 4)) {
reply = reply->next;
continue;
}
@@ -1984,15 +2012,13 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
* length and initial value.
*/
if (!reply->da->vendor && (reply->da->attr == PW_MESSAGE_AUTHENTICATOR)) {
-#ifdef WITH_RADIUSV11
/*
- * RADIUSV11 does not encode or verify Message-Authenticator.
+ * We have already encoded the Message-Authenticator, don't do it again.
*/
- if (packet->radiusv11) {
+ if (seen_ma) {
reply = reply->next;
continue;
}
-#endif
if (room < 18) break;
@@ -2152,11 +2178,7 @@ int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
case PW_CODE_ACCOUNTING_REQUEST:
case PW_CODE_DISCONNECT_REQUEST:
- case PW_CODE_DISCONNECT_ACK:
- 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;
@@ -2164,6 +2186,10 @@ int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
case PW_CODE_ACCESS_ACCEPT:
case PW_CODE_ACCESS_REJECT:
case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
memcpy(hdr->vector, original->vector, AUTH_VECTOR_LEN);
break;
@@ -2510,6 +2536,8 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
char host_ipaddr[128];
#ifndef WITH_RADIUSV11_ONLY
bool require_ma = false;
+ bool limit_proxy_state = false;
+ bool seen_proxy_state = false;
bool seen_ma = false;
bool eap = false;
bool non_eap = false;
@@ -2559,15 +2587,23 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
}
/*
- * Message-Authenticator is required in Status-Server
- * packets, otherwise they can be trivially forged.
+ * If the caller requires Message-Authenticator, then set
+ * the flag.
+ *
+ * We also require Message-Authenticator if the packet
+ * code is Status-Server.
+ *
+ * If we're receiving packets from a proxy socket, then
+ * require Message-Authenticator for Access-* replies,
+ * and for Protocol-Error.
*/
- if (hdr->code == PW_CODE_STATUS_SERVER) require_ma = true;
+ require_ma = ((flags & 0x01) != 0) || (hdr->code == PW_CODE_STATUS_SERVER) || (((flags & 0x08) != 0) && code2ma[hdr->code]);
/*
- * It's also required if the caller asks for it.
+ * We only limit Proxy-State if we're not requiring
+ * Message-Authenticator.
*/
- if (flags) require_ma = true;
+ limit_proxy_state = ((flags & 0x04) != 0) && !require_ma;
/*
* Repeat the length checks. This time, instead of
@@ -2723,6 +2759,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
case PW_EAP_MESSAGE:
require_ma = true;
eap = true;
+ packet->eap_message = true;
break;
case PW_USER_PASSWORD:
@@ -2731,6 +2768,11 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
non_eap = true;
break;
+ case PW_PROXY_STATE:
+ seen_proxy_state = true;
+ packet->proxy_state = true;
+ break;
+
case PW_MESSAGE_AUTHENTICATOR:
#ifdef WITH_RADIUSV11
/*
@@ -2749,6 +2791,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
goto finish;
}
seen_ma = true;
+ packet->message_authenticator = true;
break;
}
#endif
@@ -2813,7 +2856,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
!packet->radiusv11 &&
#endif
!seen_ma) {
- FR_DEBUG_STRERROR_PRINTF("Insecure packet from host %s: Packet does not contain required Message-Authenticator attribute",
+ FR_DEBUG_STRERROR_PRINTF("Insecure packet from host %s: Packet does not contain required Message-Authenticator attribute. You may need to set \"require_message_authenticator = no\" in the configuration.",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)));
@@ -2822,6 +2865,18 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
}
#ifndef WITH_RADIUSV11_ONLY
+ /*
+ * The client is a NAS which shouldn't send Proxy-State, but it did!
+ */
+ if (limit_proxy_state && seen_proxy_state && !seen_ma) {
+ FR_DEBUG_STRERROR_PRINTF("Insecure packet from host %s: Packet does not contain required Message-Authenticator attribute, but still has one or more Proxy-State attributes",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)));
+ failure = DECODE_FAIL_MA_MISSING;
+ 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,
@@ -3938,7 +3993,7 @@ ssize_t data2vp(TALLOC_CTX *ctx,
VALUE_PAIR *vp;
uint8_t const *data = start;
char *p;
- uint8_t buffer[256];
+ uint8_t buffer[MAX_PASS_LEN];
/*
* FIXME: Attrlen can be larger than 253 for extended attrs!
@@ -4054,7 +4109,7 @@ ssize_t data2vp(TALLOC_CTX *ctx,
attrlen, secret,
packet->vector);
}
- buffer[253] = '\0';
+ buffer[attrlen] = '\0';
/*
* MS-CHAP-MPPE-Keys are 24 octets, and
@@ -4654,22 +4709,24 @@ int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original,
ssize_t my_len;
#ifdef WITH_RADIUSV11
- /*
- * Don't decode Message-Authenticator
- */
- if (ptr[0] == PW_MESSAGE_AUTHENTICATOR) {
- packet_length -= ptr[1];
- ptr += ptr[1];
- continue;
- }
+ if (packet->radiusv11) {
+ /*
+ * Don't decode Message-Authenticator
+ */
+ if (ptr[0] == PW_MESSAGE_AUTHENTICATOR) {
+ packet_length -= ptr[1];
+ ptr += ptr[1];
+ continue;
+ }
- /*
- * Don't decode Original-Packet-Code
- */
- if ((ptr[0] == PW_EXTENDED_ATTRIBUTE_1) && (ptr[1] >= 3) && (ptr[2] == 4)) {
- packet_length -= ptr[1];
- ptr += ptr[1];
- continue;
+ /*
+ * Don't decode Original-Packet-Code
+ */
+ if ((ptr[0] == PW_EXTENDED_ATTRIBUTE_1) && (ptr[1] >= 3) && (ptr[2] == 4)) {
+ packet_length -= ptr[1];
+ ptr += ptr[1];
+ continue;
+ }
}
#endif
@@ -4761,7 +4818,7 @@ int rad_pwencode(char *passwd, size_t *pwlen, char const *secret,
*/
len = *pwlen;
- if (len > 128) len = 128;
+ if (len > MAX_STRING_LEN) len = MAX_STRING_LEN;
if (len == 0) {
memset(passwd, 0, AUTH_PASS_LEN);
@@ -4821,13 +4878,6 @@ int rad_pwdecode(char *passwd, size_t pwlen, char const *secret,
size_t n, secretlen;
/*
- * The RFC's say that the maximum is 128.
- * The buffer we're putting it into above is 254, so
- * we don't need to do any length checking.
- */
- if (pwlen > 128) pwlen = 128;
-
- /*
* Catch idiots.
*/
if (pwlen == 0) goto done;