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