patch to radius.c
neff at panix.com
neff at panix.com
Wed Mar 13 22:12:52 UTC 2002
Okay, the patch against CURRENT is attached. -- Felicia
On Wed, 13 Mar 2002 neff at panix.com wrote:
>
> Sorry, I see what you are asking now. Yes, I will create a patch against
> CURRENT and get back to you. -- Felicia
>
> On Wed, 13 Mar 2002 neff at panix.com wrote:
>
> >
> > Actually, this patch is against radius.c from inn-STABLE-20020305. Is
> > that okay? -- Felicia
> >
> > On Tue, 12 Mar 2002, Jeffrey M. Vinocur wrote:
> >
> > >
> > > On Tue, 12 Mar 2002, neff at panix.com wrote:
> > >
> > > > 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
> > >
> > > Hmm. This is against 2.3.2, isn't it?
> > >
> > > I don't suppose you want to get it to work on the CURRENT (2.4 prerelease)
> > > snapshots?
> > >
> > >
> > > --
> > > Jeffrey M. Vinocur
> > > jeff at litech.org
> > >
> > >
> >
> >
>
>
-- Attached file included as plaintext by Ecartis --
-- File: radius.patch
--- radius.c.orig Wed Mar 13 05:00:05 2002
+++ radius.c Wed Mar 13 17:05:58 2002
@@ -22,6 +22,7 @@
#include "macros.h"
#include "nntp.h"
#include "paths.h"
+#include "conffile.h"
#define RADIUS_LOCAL_PORT NNTP_PORT
@@ -46,89 +47,173 @@
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;
+
+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 }
+};
-static int read_config(FILE *f, rad_config_t *radconfig)
+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, '#')) != NULL)
- *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")) {
+static 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);
}
@@ -147,17 +232,40 @@
#define RAD_NAS_IP_ADDRESS 4 /* IP address */
#define RAD_NAS_PORT 5 /* Integer */
-static 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;
+}
+
+static int rad_auth(rad_config_t *radconfig, char *uname, char *pass)
{
auth_req req;
int i, j, jlen, passstart;
char secbuf[128];
HASH digest;
struct timeval seed;
- struct sockaddr_in sinl, sinr;
+ struct sockaddr_in sinl;
int sock;
struct hostent *hent;
- int reqlen;
int passlen;
time_t now, end;
struct timeval tmout;
@@ -166,16 +274,39 @@
uint32_t nvalue;
socklen_t slen;
int authtries= 3; /* number of times to try reaching the radius server */
-
- /* 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);
+ rad_config_t *config;
+ sending_t *reqtop, *sreq = NULL, *new;
+ int done;
+
+ /* set up the linked list */
+ config = radconfig;
+
+ 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);
}
@@ -184,25 +315,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);
@@ -247,7 +379,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;
@@ -286,9 +418,16 @@
sizeof(HASH));
md5_hash(secbuf, strlen(config->secret)+sizeof(HASH), digest.hash);
}
+ }
+ 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. */
@@ -305,14 +444,20 @@
return(-1);
}
- for( ; authtries > 0; authtries--) {
+ for(done = 0; authtries > 0 && !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;
@@ -340,23 +485,23 @@
break;
}
if (!config->ignore_source) {
- if (sinl.sin_addr.s_addr != sinr.sin_addr.s_addr ||
- (sinl.sin_port != sinr.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));
- md5_hash((char *)&req, strlen(config->secret)+reqlen, digest.hash);
+ md5_hash((char *)&req, strlen(config->secret)+sreq->reqlen, digest.hash);
if (memcmp(digest.hash, secbuf, sizeof(HASH)) != 0) {
fprintf(stderr, "radius: checksum didn't match.\n");
continue;
@@ -364,12 +509,15 @@
/* FINALLY! Got back a known-good packet. See if we're in. */
close(sock);
return (req.code == PW_AUTHENTICATION_ACK) ? 0 : -1;
+ done = 1;
+ req_copyfrom(sreq, req);
break;
+ }
}
if (authtries == 0) {
fprintf(stderr,
"radius: couldn't talk to remote radius server %s:%d\n",
- inet_ntoa(sinr.sin_addr), ntohs(sinr.sin_port));
+ inet_ntoa(sreq->sinr.sin_addr), ntohs(sreq->sinr.sin_port));
}
return(-2);
}
@@ -388,7 +536,6 @@
int opt;
int havefile, haveother;
char uname[SMBUF], pass[SMBUF];
- FILE *f;
rad_config_t radconfig;
int retval;
char *radius_config;
@@ -397,7 +544,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) {
@@ -407,100 +554,26 @@
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;
-
- 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);
+ /* override the standard config completely if the user
+ * specifies an alternate config file */
+ bzero(&radconfig, sizeof(rad_config_t));
+ havefile = 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;
+ read_config(optarg, &radconfig);
break;
+ case 'h':
+ printf("Usage: radius [-f config]\n");
+ return 0;
+ break;
}
}
if (argc != optind)
- exit(2);
+ exit(2);
if (!havefile) {
- radius_config = concatpath(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);
- }
- free(radius_config);
- }
- 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);
+ radius_config = concatpath(innconf->pathetc, _PATH_RADIUS_CONFIG);
+ read_config(radius_config, &radconfig);
+
+ free(radius_config);
}
if (get_auth(uname,pass) != 0) {
@@ -509,6 +582,7 @@
}
/* 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