On Thu, 02 Mar 2023 17:28:01 +0100, "Peter J. Philipp" wrote:
> I just looked up RADIUS in RFC 2865 and on page 15 it reads:
>
> --------->
> Length
>
> The Length field is two octets. It indicates the length of the
> packet including the Code, Identifier, Length, Authenticator and
> Attribute fields. Octets outside the range of the Length field
> MUST be treated as padding and ignored on reception. If the
> packet is shorter than the Length field indicates, it MUST be
> silently discarded. The minimum length is 20 and maximum length
> is 4096.
>
> <---------
>
> Notice the silent discard, so perhaps we should try again? I adjusted
> the patch for this, but I can't test.
I think it is simplest to just retry if rad_recv() returns -1 until
we hit the max retries. Here's a diff relative to the earlier one
I just committed that simplifies the retry logic a bit by removing
the use of timedout in raddauth().
- todd
Index: libexec/login_radius/raddauth.c
===================================================================
RCS file: /cvs/src/libexec/login_radius/raddauth.c,v
retrieving revision 1.31
diff -u -p -u -r1.31 raddauth.c
--- libexec/login_radius/raddauth.c 2 Mar 2023 16:13:57 -0000 1.31
+++ libexec/login_radius/raddauth.c 2 Mar 2023 16:50:27 -0000
@@ -114,13 +114,10 @@
char *radius_dir = RADIUS_DIR;
char auth_secret[MAXSECRETLEN+1];
volatile sig_atomic_t timedout;
-int alt_retries;
-int retries;
+in_port_t radius_port;
+in_addr_t auth_server;
int sockfd;
int timeout;
-in_addr_t alt_server;
-in_addr_t auth_server;
-in_port_t radius_port;
typedef struct {
u_char code;
@@ -158,6 +155,8 @@ raddauth(char *username, char *class, ch
struct servent *svp;
struct sockaddr_in sin;
struct sigaction sa;
+ int alt_retries, retries;
+ in_addr_t alt_server;
const char *errstr;
memset(_pwstate, 0, sizeof(_pwstate));
@@ -268,24 +267,20 @@ raddauth(char *username, char *class, ch
sa.sa_flags = 0; /* don't restart system calls */
(void)sigaction(SIGALRM, &sa, NULL);
retry:
- if (timedout) {
- timedout = 0;
- if (--retries <= 0) {
- /*
- * If we ran out of tries but there is an alternate
- * server, switch to it and try again.
- */
- if (alt_retries) {
- auth_server = alt_server;
- retries = alt_retries;
- alt_retries = 0;
- getsecret();
- } else
- warnx("no response from authentication server");
- }
+ if (retries-- <= 0) {
+ /*
+ * If we ran out of tries but there is an alternate
+ * server, switch to it and try again.
+ */
+ if (alt_retries) {
+ auth_server = alt_server;
+ retries = alt_retries;
+ alt_retries = 0;
+ getsecret();
+ } else
+ warnx("no response from authentication server");
}
-
- if (retries > 0) {
+ if (retries >= 0) {
rad_request(req_id, userstyle, passwd, auth_port, vector,
pwstate);
@@ -324,9 +319,11 @@ retry:
passwd = "";
break;
+ case -1:
+ /* Timeout or bad packet, retry. */
+ goto retry;
+
default:
- if (timedout)
- goto retry;
snprintf(_pwstate, sizeof(_pwstate),
"invalid response type %d\n", i);
*emsg = _pwstate;
@@ -460,12 +457,16 @@ rad_recv(char *state, char *challenge, u
(struct sockaddr *)&sin, &salen);
alarm(0);
if (total_length < AUTH_HDR_LEN) {
- if (timedout)
+ if (timedout) {
+ timedout = 0;
return(-1);
+ }
errx(1, "bogus auth packet from server");
}
- if (ntohs(auth.length) > total_length)
- errx(1, "bogus auth packet from server");
+ if (ntohs(auth.length) > total_length) {
+ /* RFC 2865 says to silently discard short packets. */
+ return(-1);
+ }
if (sin.sin_addr.s_addr != auth_server)
errx(1, "bogus authentication server");