patch to radius.c
neff at panix.com
neff at panix.com
Wed Mar 13 00:27:42 UTC 2002
I have attached a patch for radius.c (the program to authenticate against
a radius server). This patch allows for multiple radius servers and uses
the configuration file routines in conffile.h. If this patch doesn't
quite work, I would be happy to make modifications. -- Felicia
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
neff at panix.com Felicia Neff
Panix Staff
-- Attached file included as plaintext by Ecartis --
-- File: radius.patch
--- radius.c.sav Tue Mar 12 18:52:03 2002
+++ radius.c Tue Mar 12 18:56:00 2002
@@ -2,6 +2,7 @@
**
** Authenticate a user against a remote radius server.
*/
+
#include "config.h"
#include "clibrary.h"
#include <netinet/in.h>
@@ -25,6 +26,7 @@
#include "libinn.h"
#include "nntp.h"
#include "paths.h"
+#include "conffile.h"
/* Needed on AIX 4.1 to get fd_set and friends. */
#ifdef HAVE_SYS_SELECT_H
@@ -54,89 +56,171 @@
char *prefix, *suffix; /* futz with the username, if necessary */
int ignore_source;
+
+ struct _rad_config_t *next; /* point to any additional servers */
} rad_config_t;
-int read_config(FILE *f, rad_config_t *radconfig)
+typedef struct _sending_t {
+ auth_req req;
+ int reqlen;
+ struct sockaddr_in sinr;
+ struct _sending_t *next;
+} sending_t;
+
+#define RADlbrace 1
+#define RADrbrace 2
+#define RADserver 10
+#define RADhost 11
+#define RADsecret 12
+#define RADport 13
+#define RADlochost 14
+#define RADlocport 15
+#define RADprefix 16
+#define RADsuffix 17
+#define RADsource 18
+
+static CONFTOKEN radtoks[] = {
+ { RADlbrace, "{" },
+ { RADrbrace, "}" },
+ { RADserver, "server" },
+ { RADhost, "radhost:" },
+ { RADsecret, "secret:" },
+ { RADport, "radport:" },
+ { RADlochost, "lochost:" },
+ { RADlocport, "locport:" },
+ { RADprefix, "prefix:" },
+ { RADsuffix, "suffix:" },
+ { RADsource, "ignore-source:" },
+ { 0, 0 }
+};
+
+rad_config_t *get_radconf(void)
{
- char buf[SMBUF];
- char *keyword, *iter;
- int lineno;
-
- buf[sizeof(buf)-1] = '\0';
- lineno = 0;
- while (fgets(buf, sizeof(buf)-1, f) != (char*) 0) {
- lineno++;
- buf[strlen(buf)-1] = '\0'; /* strip '\n' */
-
- if (iter = strchr(buf, '#'))
- *iter = '\0'; /* strip comments */
-
- iter = buf+strlen(buf)-1; /* strip trailing whitespace */
- while (iter >= buf && isspace(*iter))
- iter--;
- iter[1] = '\0';
-
- if (buf[0] == '\0')
- continue; /* empty line */
-
- /* get the keyword part of the keyword: value */
- keyword = buf;
- while (isspace(*keyword))
- keyword++;
- iter = strchr(keyword, ':');
- if (!iter) {
- fprintf(stderr, "malformed keyword in rad_config, line %d\n", lineno);
- exit(1);
- }
- *iter++ = '\0';
+ rad_config_t *new;
- /* now the value part */
- while (*iter && isspace(*iter))
- iter++;
- if (!*iter) {
- fprintf(stderr, "expecting value after keyword %s in rad_config, line %d\n",
- keyword, lineno);
- exit(1);
- }
+ new = malloc(sizeof(rad_config_t));
+ if (new == NULL){
+ fprintf(stderr, "radius: unable to malloc\n");
+ exit (1);
+ }
+ new->next = NULL;
+
+ return new;
+}
- /* what are we setting? */
- if (!strcmp(keyword, "secret")) {
+int read_config(char *authfile, rad_config_t *radconf)
+{
+ int inbrace;
+ rad_config_t *radconfig=NULL;
+ CONFFILE *file;
+ CONFTOKEN *token;
+ char *server;
+ int type;
+ char *iter;
+
+ if ((file = CONFfopen(authfile)) == NULL){
+ fprintf(stderr, "radius: couldn't open config file %s: %s\n", authfile,
+ strerror(errno));
+ exit (1);
+ }
+
+ inbrace = 0;
+ while ((token = CONFgettoken(radtoks, file)) != NULL) {
+ if (!inbrace) {
+ if (token->type != RADserver) {
+ fprintf(stderr, "Expected 'server' keyword, line %d\n", file->lineno);
+ exit (1);
+ }
+ if ((token = CONFgettoken(0, file)) == NULL) {
+ fprintf(stderr, "Expected server name, line %d\n", file->lineno);
+ exit (1);
+ }
+ server = COPY(token->name);
+ if ((token = CONFgettoken(radtoks, file)) == NULL
+ || token->type != RADlbrace) {
+ fprintf(stderr, "Expected '{', line %d\n", file->lineno);
+ exit (1);
+ }
+ inbrace = 1;
+
+ if (radconfig == NULL)
+ radconfig = radconf;
+ else {
+ radconfig->next = get_radconf();
+ radconfig = radconfig->next;
+ }
+ }
+ else {
+ type = token->type;
+ if (type == RADrbrace)
+ inbrace = 0;
+ else {
+ if ((token = CONFgettoken(0, file)) == NULL) {
+ fprintf(stderr, "Keyword with no value, line %d\n", file->lineno);
+ exit (1);
+ }
+ iter = token->name;
+
+ /* what are we setting? */
+ switch(type) {
+ case RADsecret:
if (radconfig->secret) continue;
radconfig->secret = COPY(iter);
- } else if (!strcmp(keyword, "radhost")) {
+ break;
+ case RADhost:
if (radconfig->radhost) continue;
radconfig->radhost = COPY(iter);
- } else if (!strcmp(keyword, "radport")) {
+ break;
+ case RADport:
if (radconfig->radport) continue;
radconfig->radport = atoi(iter);
- } else if (!strcmp(keyword, "lochost")) {
+ break;
+ case RADlochost:
if (radconfig->lochost) continue;
radconfig->lochost = COPY(iter);
- } else if (!strcmp(keyword, "locport")) {
+ break;
+ case RADlocport:
if (radconfig->locport) continue;
radconfig->locport = atoi(iter);
- } else if (!strcmp(keyword, "prefix")) {
+ break;
+ case RADprefix:
if (radconfig->prefix) continue;
radconfig->prefix = COPY(iter);
- } else if (!strcmp(keyword, "suffix")) {
+ break;
+ case RADsuffix:
if (radconfig->suffix) continue;
radconfig->suffix = COPY(iter);
- } else if (!strcmp(keyword, "ignore-source")) {
+ break;
+ case RADsource:
if (!strcasecmp(iter, "true"))
radconfig->ignore_source = 1;
else if (!strcasecmp(iter, "false"))
radconfig->ignore_source = 0;
else {
- fprintf(stderr, "Expected \"true\" or \"false\" after %s in rad_config, line %d\n",
- keyword, lineno);
+ fprintf(stderr, "Expected \"true\" or \"false\" after "
+ "ignore-source in rad_config, line %d\n", file->lineno);
exit(1);
}
- } else {
- fprintf(stderr, "unknown keyword %s in rad_config, line %d\n",
- keyword, lineno);
+ break;
+ default:
+ fprintf(stderr, "unknown keyword in rad_config, line %d\n",
+ file->lineno);
exit(1);
+ }
}
+ }
}
+
+ CONFfclose(file);
+
+ if (!radconf->radhost) {
+ fprintf(stderr, "No radius host to authenticate against.\n");
+ exit(1);
+ } else if (!radconf->secret) {
+ fprintf(stderr, "No shared secret with radius host.\n");
+ exit(1);
+ }
+
return(0);
}
@@ -152,7 +236,31 @@
#define PW_AUTHENTICATION_ACK 2
#define PW_AUTHENTICATION_REJECT 3
-int rad_auth(rad_config_t *config, char *uname, char *pass)
+void req_copyto (auth_req to, sending_t *from)
+{
+ to.code = from->req.code;
+ to.id = from->req.id;
+ to.length = from->req.length;
+ strcpy(to.vector, from->req.vector);
+ strcpy(to.data, from->req.data);
+ to.datalen = from->req.datalen;
+
+ return;
+}
+
+void req_copyfrom (sending_t *to, auth_req from)
+{
+ to->req.code = from.code;
+ to->req.id = from.id;
+ to->req.length = from.length;
+ strcpy(to->req.vector, from.vector);
+ strcpy(to->req.data, from.data);
+ to->req.datalen = from.datalen;
+
+ return;
+}
+
+int rad_auth(rad_config_t *radconfig, char *uname, char *pass)
{
auth_req req;
int i, j, jlen, passstart;
@@ -160,12 +268,11 @@
HASH digest;
struct timeval seed;
MD5_CTX ctx;
- struct sockaddr_in sinl, sinr;
+ struct sockaddr_in sinl;
int sock;
struct hostent *hent;
- int done;
+ int done = 0;
int ret;
- int reqlen;
int passlen;
time_t now, end;
struct timeval tmout;
@@ -174,16 +281,38 @@
uint32_t nvalue;
ARGTYPE slen;
int authtries= 3; /* number of times to try reaching the radius server */
+ rad_config_t *config;
+ sending_t *reqtop, *sreq = NULL, *new;
+
+ /* set up the linked list */
+ config = radconfig;
- /* first, build the sockaddrs */
- memset(&sinl, '\0', sizeof(sinl));
- memset(&sinr, '\0', sizeof(sinr));
- sinl.sin_family = AF_INET;
- sinr.sin_family = AF_INET;
- if (config->lochost == NULL) {
- if (gethostname(secbuf, sizeof(secbuf)) != 0) {
- fprintf(stderr, "radius: cant get localhostname\n");
- return(-1);
+ while (config != NULL){
+ new = malloc(sizeof(sending_t));
+ if (new == NULL){
+ fprintf(stderr, "radius: can't malloc sending_t struct\n");
+ return (-2);
+ }
+ new->next = NULL;
+
+ if (sreq == NULL){
+ reqtop = new;
+ sreq = new;
+ } else {
+ sreq->next = new;
+ sreq = sreq->next;
+ }
+ req_copyto(req, sreq);
+
+ /* first, build the sockaddrs */
+ memset(&sinl, '\0', sizeof(sinl));
+ memset(&sreq->sinr, '\0', sizeof(sreq->sinr));
+ sinl.sin_family = AF_INET;
+ sreq->sinr.sin_family = AF_INET;
+ if (config->lochost == NULL) {
+ if (gethostname(secbuf, sizeof(secbuf)) != 0) {
+ fprintf(stderr, "radius: cant get localhostname\n");
+ return (-2);
}
config->lochost = COPY(secbuf);
}
@@ -192,25 +321,26 @@
if ((hent = gethostbyname(config->lochost)) == NULL) {
fprintf(stderr, "radius: cant gethostbyname lochost %s\n",
config->lochost);
- return(-1);
+ return (-2);
}
memcpy(&sinl.sin_addr.s_addr, hent->h_addr,
sizeof(struct in_addr));
}
}
- if (inet_aton(config->radhost, &sinr.sin_addr) != 1) {
+ if (inet_aton(config->radhost, &sreq->sinr.sin_addr) != 1) {
if ((hent = gethostbyname(config->radhost)) == NULL) {
fprintf(stderr, "radius: cant gethostbyname radhost %s\n",
config->radhost);
- return(-1);
+ return (-2);
}
- memcpy(&sinr.sin_addr.s_addr, hent->h_addr_list[0],
+ memcpy(&sreq->sinr.sin_addr.s_addr, hent->h_addr_list[0],
sizeof(struct in_addr));
}
+
if (config->radport)
- sinr.sin_port = htons(config->radport);
+ sreq->sinr.sin_port = htons(config->radport);
else
- sinr.sin_port = htons(PW_AUTH_UDP_PORT);
+ sreq->sinr.sin_port = htons(PW_AUTH_UDP_PORT);
/* seed the random number generator for the auth vector */
gettimeofday(&seed, 0);
@@ -259,7 +389,7 @@
req.datalen += req.data[req.datalen+1];
/* Add NAS_PORT and NAS_IP_ADDRESS into request */
- if ((nvalue = config->locport) == 0)
+ if ((nvalue = config->locport) == 0)
nvalue = RADIUS_LOCAL_PORT;
req.data[req.datalen++] = RAD_NAS_PORT;
req.data[req.datalen++] = sizeof(nvalue) + 2;
@@ -302,9 +432,16 @@
MD5Final(&ctx);
memcpy(digest.hash, ctx.digest, MD5_DIGESTSIZE);
}
+ }
+ sreq->reqlen = req.length;
+ req.length = htons(req.length);
+
+ req_copyfrom(sreq, req);
+
+ /* Go to the next record in the list */
+ config = config->next;
}
- reqlen = req.length;
- req.length = htons(req.length);
+
/* YAYY! The auth_req is ready to go! Build the reply socket and send out
* the message. */
@@ -322,13 +459,20 @@
}
while (!done && authtries--) {
+ for (config = radconfig, sreq = reqtop; sreq != NULL && !done;
+ config = config->next, sreq = sreq->next){
+
+ req_copyto(req, sreq);
+
/* send out the packet and wait for reply. */
- if (sendto(sock, (char *)&req, reqlen, 0, (struct sockaddr*) &sinr,
- sizeof(sinr)) < 0) {
- fprintf(stderr, "radius: cant send auth_req: %s\n", strerror(errno));
- close(sock);
- return(-1);
+ if (sendto(sock, (char *)&req, sreq->reqlen, 0,
+ (struct sockaddr*) &sreq->sinr,
+ sizeof (struct sockaddr_in)) < 0) {
+ fprintf(stderr, "radius: cant send auth_req: %s\n", strerror(errno));
+ close(sock);
+ return(-1);
}
+
/* wait 5 seconds maximum for a radius reply. */
now = time(0);
end = now+5;
@@ -352,43 +496,51 @@
continue;
}
slen = sizeof(sinl);
- if ((jlen = recvfrom(sock, (char *)&req, sizeof(req)-sizeof(int), 0,
- (struct sockaddr*) &sinl, &slen)) < 0) {
+ if ((jlen = recvfrom(sock, (char *)&req,
+ sizeof(req)-sizeof(int), 0,
+ (struct sockaddr*) &sinl, &slen)) < 0) {
fprintf(stderr, "radius: couldnt recvfrom: %s\n", strerror(errno));
break;
}
+
if (!config->ignore_source) {
- if (sinl.sin_addr.s_addr != sinr.sin_addr.s_addr ||
- (sinl.sin_port != sinr.sin_port)) {
- fprintf(stderr, "radius: received unexpected UDP packet from %s:%d.\n",
- inet_ntoa(sinl.sin_addr), ntohs(sinl.sin_port));
+ if ((sinl.sin_addr.s_addr != sreq->sinr.sin_addr.s_addr) ||
+ (sinl.sin_port != sreq->sinr.sin_port)) {
+ fprintf(stderr, "radius: received unexpected UDP packet "
+ "from %s:%d.\n", inet_ntoa(sinl.sin_addr),
+ ntohs(sinl.sin_port));
continue;
}
}
- reqlen = ntohs(req.length);
- if (jlen < 4+AUTH_VECTOR_LEN || jlen != reqlen) {
+
+ sreq->reqlen = ntohs(req.length);
+ if (jlen < 4+AUTH_VECTOR_LEN || jlen != sreq->reqlen) {
fprintf(stderr, "radius: received badly-sized packet.\n");
continue;
}
/* verify the checksum */
- memcpy(((char*)&req)+reqlen, config->secret, strlen(config->secret));
+ memcpy(((char*)&req)+sreq->reqlen, config->secret, strlen(config->secret));
memcpy(secbuf, req.vector, sizeof(req.vector));
memcpy(req.vector, secbuf+sizeof(req.vector), sizeof(req.vector));
MD5Init(&ctx);
- MD5Update(&ctx, (char*)&req, strlen(config->secret)+reqlen);
- MD5COUNT(&ctx, strlen(config->secret)+reqlen);
+ MD5Update(&ctx, (char*)&req, strlen(config->secret)+sreq->reqlen);
+ MD5COUNT(&ctx, strlen(config->secret)+sreq->reqlen);
MD5Final(&ctx);
if (memcmp(ctx.digest, secbuf, sizeof(HASH)) != 0) {
fprintf(stderr, "radius: checksum didn't match.\n");
continue;
}
+
/* FINALLY! Got back a known-good packet. See if we're in. */
ret = (req.code == PW_AUTHENTICATION_ACK) ? 0 : -1;
done = 1;
+
+ req_copyfrom(sreq, req);
+ }
}
if (!done) {
- fprintf(stderr, "radius: couldn't talk to remote radius server %s:%d\n",
- inet_ntoa(sinr.sin_addr), ntohs(sinr.sin_port));
+ fprintf(stderr, "radius: couldn't talk to remote radius server %s:%d\n",
+ inet_ntoa(sreq->sinr.sin_addr), ntohs(sreq->sinr.sin_port));
}
close(sock);
return(ret);
@@ -409,7 +561,6 @@
int havefile, haveother;
char uname[SMBUF], pass[SMBUF];
char buff[SMBUF];
- FILE *f;
rad_config_t radconfig;
int retval;
char *radius_config;
@@ -418,7 +569,7 @@
haveother = havefile = 0;
if (ReadInnConf() < 0) exit(1);
- while ((opt = getopt(argc, argv, "f:h:p:P:q:s:l:S")) != -1) {
+ while ((opt = getopt(argc, argv, "f:h")) != -1) {
switch (opt) {
case 'f':
if (haveother) {
@@ -427,100 +578,27 @@
fprintf(stderr, "-f flag after another, non -f flag.\n");
exit(1);
}
- if (!havefile) {
- /* override the standard config completely if the user
- * specifies an alternate config file */
- bzero(&radconfig, sizeof(rad_config_t));
- havefile = 1;
- }
- f = fopen(optarg, "r");
- if (!f) {
- fprintf(stderr, "couldn't open config file %s: %s\n", optarg, strerror(errno));
- exit(1);
- }
- read_config(f, &radconfig);
- fclose(f);
- break;
+ if (!havefile) {
+ /* override the standard config completely if the user
+ * specifies an alternate config file */
+ bzero(&radconfig, sizeof(rad_config_t));
+ havefile = 1;
+ }
+ read_config(optarg, &radconfig);
+ break;
+ case 'h':
+ printf("Usage: radius [-f config]\n");
+ return 0;
+ break;
+ }
+ }
+ if (argc != optind)
+ exit(2);
+ if (!havefile) {
+ radius_config = cpcatpath(innconf->pathetc, _PATH_RADIUS_CONFIG);
+ read_config(radius_config, &radconfig);
- case 'h':
- if (haveother & RAD_HAVE_HOST) {
- fprintf(stderr, "two -h options.\n");
- exit(1);
- }
- haveother |= RAD_HAVE_HOST;
- if (radconfig.radhost)
- DISPOSE(radconfig.radhost);
- radconfig.radhost = optarg;
- break;
- case 'p':
- if (haveother & RAD_HAVE_PORT) {
- fprintf(stderr, "two -p options.\n");
- exit(1);
- }
- haveother |= RAD_HAVE_PORT;
- radconfig.radport = atoi(optarg);
- break;
- case 'P':
- if (haveother & RAD_HAVE_LOCPORT) {
- fprintf(stderr, "two -P options.\n");
- exit(1);
- }
- haveother |= RAD_HAVE_LOCPORT;
- radconfig.locport = atoi(optarg);
- break;
- case 'q':
- if (haveother & RAD_HAVE_PREFIX) {
- fprintf(stderr, "two -q options.\n");
- exit(1);
- }
- haveother |= RAD_HAVE_PREFIX;
- if (radconfig.prefix)
- DISPOSE(radconfig.prefix);
- radconfig.prefix = optarg;
- break;
- case 's':
- if (haveother & RAD_HAVE_SUFFIX) {
- fprintf(stderr, "two -s options.\n");
- exit(1);
- }
- haveother |= RAD_HAVE_SUFFIX;
- if (radconfig.suffix)
- DISPOSE(radconfig.suffix);
- radconfig.suffix = optarg;
- break;
- case 'l':
- if (haveother & RAD_HAVE_LOCHOST) {
- fprintf(stderr, "two -l options.\n");
- exit(1);
- }
- haveother |= RAD_HAVE_LOCHOST;
- if (radconfig.lochost)
- DISPOSE(radconfig.lochost);
- radconfig.lochost = optarg;
- break;
- case 'S':
- radconfig.ignore_source = 1;
- break;
- }
- }
- if (argc != optind)
- exit(2);
- if (!havefile) {
- radius_config = cpcatpath(innconf->pathetc, _PATH_RADIUS_CONFIG);
- if (!(f = fopen(radius_config, "r"))) {
- fprintf(stderr, "couldn't open config file %s: %s\n", radius_config,
- strerror(errno));
- } else {
- read_config(f, &radconfig);
- fclose(f);
- }
- }
- if (!radconfig.radhost) {
- fprintf(stderr, "No radius host to authenticate against.\n");
- exit(1);
- } else if (!radconfig.secret) {
- fprintf(stderr, "No shared secret with radius host.\n");
- exit(1);
+ DISPOSE(radius_config);
}
uname[0] = '\0';
@@ -544,6 +622,7 @@
exit(3);
/* got username and password, check that they're valid */
+
retval = rad_auth(&radconfig, uname, pass);
if (retval == -1) {
fprintf(stderr, "radius: user %s password doesn't match.\n", uname);
More information about the inn-workers
mailing list