chiark / gitweb /
REORG Delete everything that's not innduct or build system or changed for innduct
[inn-innduct.git] / authprogs / radius.c
diff --git a/authprogs/radius.c b/authprogs/radius.c
deleted file mode 100644 (file)
index e6da348..0000000
+++ /dev/null
@@ -1,564 +0,0 @@
-/*  $Id: radius.c 7745 2008-04-06 10:18:54Z iulius $
-**
-**  Authenticate a user against a remote radius server.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/time.h"
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <signal.h>
-
-/* Needed on AIX 4.1 to get fd_set and friends. */
-#if HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-
-#include "inn/innconf.h"
-#include "inn/md5.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "nntp.h"
-#include "paths.h"
-#include "conffile.h"
-
-#include "libauth.h"
-
-#define RADIUS_LOCAL_PORT       NNTP_PORT
-
-#define AUTH_VECTOR_LEN 16
-
-typedef struct _auth_req {
-    unsigned char      code;
-    unsigned char      id;
-    unsigned short     length;
-    unsigned char      vector[AUTH_VECTOR_LEN];
-    unsigned char      data[NNTP_STRLEN*2];
-    int                        datalen;
-} auth_req;
-
-typedef struct _rad_config_t {
-    char *secret;      /* pseudo encryption thingy secret that radius uses */
-
-    char *radhost;     /* parameters for talking to the remote radius sever */
-    int radport;
-    char *lochost;
-    int locport;
-
-    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 rad_config_t *get_radconf(void)
-{
-  rad_config_t *new;
-
-  new = xcalloc(1, sizeof(rad_config_t));
-  new->next = NULL;
-
-  return new;
-}
-
-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)
-      sysdie("cannot open config file %s", authfile);
-
-    inbrace = 0;
-    while ((token = CONFgettoken(radtoks, file)) != NULL) {
-      if (!inbrace) {
-       if (token->type != RADserver)
-          die("expected server keyword on line %d", file->lineno);
-       if ((token = CONFgettoken(0, file)) == NULL)
-          die("expected server name on line %d", file->lineno);
-       server = xstrdup(token->name);
-       if ((token = CONFgettoken(radtoks, file)) == NULL 
-           || token->type != RADlbrace)
-          die("expected { on line %d", file->lineno);
-       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)
-            die("keyword with no value on line %d", file->lineno);
-         iter = token->name;
-
-         /* what are we setting? */
-         switch(type) {
-         case RADsecret:
-           if (radconfig->secret) continue;
-           radconfig->secret = xstrdup(iter);
-           break;
-         case RADhost:
-           if (radconfig->radhost) continue;
-           radconfig->radhost = xstrdup(iter);
-           break;
-         case RADport:
-           if (radconfig->radport) continue;
-           radconfig->radport = atoi(iter);
-           break;
-         case RADlochost:
-           if (radconfig->lochost) continue;
-           radconfig->lochost = xstrdup(iter);
-           break;
-         case RADlocport:
-           if (radconfig->locport) continue;
-           radconfig->locport = atoi(iter);
-           break;
-         case RADprefix:
-           if (radconfig->prefix) continue;
-           radconfig->prefix = xstrdup(iter);
-           break;
-         case RADsuffix:
-           if (radconfig->suffix) continue;
-           radconfig->suffix = xstrdup(iter);
-           break;
-         case RADsource:
-           if (!strcasecmp(iter, "true"))
-               radconfig->ignore_source = 1;
-           else if (!strcasecmp(iter, "false"))
-               radconfig->ignore_source = 0;
-           else
-                die("expected true or false after ignore-source on line %d",
-                    file->lineno);
-           break;
-         default:
-            die("unknown keyword on line %d", file->lineno);
-         }
-       }
-      }
-    }
-
-    CONFfclose(file);
-
-    if (!radconf->radhost)
-        die("no radius host specified");
-    else if (!radconf->secret)
-        die("no shared secret with radius host specified");
-
-    return(0);
-}
-
-#define PW_AUTH_UDP_PORT 1645
-
-#define PW_AUTHENTICATION_REQUEST 1
-#define PW_AUTHENTICATION_ACK     2
-#define PW_AUTHENTICATION_REJECT  3
-
-#define PW_USER_NAME            1
-#define PW_PASSWORD             2
-
-#define PW_SERVICE_TYPE         6
-#define PW_SERVICE_AUTH_ONLY    8
-
-#define RAD_NAS_IP_ADDRESS      4       /* IP address */
-#define RAD_NAS_PORT            5       /* Integer */
-
-static void req_copyto (auth_req to, sending_t *from)
-{
-    to = from->req;
-}
-
-static void req_copyfrom (sending_t *to, auth_req from)
-{
-    to->req = from;
-}
-
-static int rad_auth(rad_config_t *radconfig, char *uname, char *pass)
-{
-    auth_req req;
-    int i, j, jlen, passstart;
-    unsigned char secbuf[128];
-    char hostname[SMBUF];
-    unsigned char digest[MD5_DIGESTSIZE];
-    struct timeval seed;
-    struct sockaddr_in sinl;
-    int sock;
-    struct hostent *hent;
-    int passlen;
-    time_t now, end;
-    struct timeval tmout;
-    int got;
-    fd_set rdfds;
-    uint32_t nvalue;
-    socklen_t slen;
-    int authtries= 3; /* number of times to try reaching the radius server */
-    rad_config_t *config;
-    sending_t *reqtop, *sreq, *new;
-    int done;
-
-    /* set up the linked list */
-    config = radconfig;
-
-    if (config == NULL) {
-      warn("no configuration file");
-      return(-2);
-    } else {
-      /* setting sreq to NULL guarantees reqtop will be properly set later */
-      sreq = NULL;
-      reqtop = NULL;
-    }
-
-    while (config != NULL){
-      new = xmalloc(sizeof(sending_t));
-      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(hostname, sizeof(hostname)) != 0) {
-          syswarn("cannot get local hostname");
-          return(-2);
-        }
-       config->lochost = xstrdup(hostname);
-      }
-      if (config->lochost) {
-       if (inet_aton(config->lochost, &sinl.sin_addr) != 1) {
-          if ((hent = gethostbyname(config->lochost)) == NULL) {
-            warn("cannot gethostbyname lochost %s", config->lochost);
-            return(-2);
-          }
-          memcpy(&sinl.sin_addr.s_addr, hent->h_addr,
-                 sizeof(struct in_addr));
-       }
-      }
-      if (inet_aton(config->radhost, &sreq->sinr.sin_addr) != 1) {
-        if ((hent = gethostbyname(config->radhost)) == NULL) {
-          warn("cannot gethostbyname radhost %s", config->radhost);
-          return(-2);
-        }
-       memcpy(&sreq->sinr.sin_addr.s_addr, hent->h_addr_list[0],
-               sizeof(struct in_addr));
-      }
-
-      if (config->radport)
-        sreq->sinr.sin_port = htons(config->radport);
-      else
-       sreq->sinr.sin_port = htons(PW_AUTH_UDP_PORT);
-
-      /* seed the random number generator for the auth vector */
-      gettimeofday(&seed, 0);
-      srandom((unsigned) seed.tv_sec+seed.tv_usec);
-      /* build the visible part of the auth vector randomly */
-      for (i = 0; i < AUTH_VECTOR_LEN; i++)
-       req.vector[i] = random() % 256;
-      strlcpy((char *) secbuf, config->secret, sizeof(secbuf));
-      memcpy(secbuf+strlen(config->secret), req.vector, AUTH_VECTOR_LEN);
-      md5_hash(secbuf, strlen(config->secret)+AUTH_VECTOR_LEN, digest);
-      /* fill in the auth_req data */
-      req.code = PW_AUTHENTICATION_REQUEST;
-      req.id = 0;
-
-      /* bracket the username in the configured prefix/suffix */
-      req.data[0] = PW_USER_NAME;
-      req.data[1] = 2;
-      req.data[2] = '\0';
-      if (config->prefix) {
-       req.data[1] += strlen(config->prefix);
-       strlcat((char *) &req.data[2], config->prefix, sizeof(req.data) - 2);
-      }
-      req.data[1] += strlen(uname);
-      strlcat((char *)&req.data[2], uname, sizeof(req.data) - 2);
-      if (!strchr(uname, '@') && config->suffix) {
-       req.data[1] += strlen(config->suffix);
-       strlcat((char *)&req.data[2], config->suffix, sizeof(req.data) - 2);
-      }
-      req.datalen = req.data[1];
-
-      /* set the password */
-      passstart = req.datalen;
-      req.data[req.datalen] = PW_PASSWORD;
-      /* Null pad the password */
-      passlen = (strlen(pass) + 15) / 16;
-      passlen *= 16;
-      req.data[req.datalen+1] = passlen+2;
-      strlcpy((char *)&req.data[req.datalen+2], pass,
-              sizeof(req.data) - req.datalen - 2);
-      passlen -= strlen(pass);
-      while (passlen--)
-       req.data[req.datalen+passlen+2+strlen(pass)] = '\0';
-      req.datalen += req.data[req.datalen+1];
-
-      /* Add NAS_PORT and NAS_IP_ADDRESS into request */
-      if ((nvalue = config->locport) == 0)
-        nvalue = RADIUS_LOCAL_PORT;
-      req.data[req.datalen++] = RAD_NAS_PORT;
-      req.data[req.datalen++] = sizeof(nvalue) + 2;
-      nvalue = htonl(nvalue);
-      memcpy(req.data + req.datalen, &nvalue, sizeof(nvalue));
-      req.datalen += sizeof(nvalue);
-      req.data[req.datalen++] = RAD_NAS_IP_ADDRESS;
-      req.data[req.datalen++] = sizeof(struct in_addr) + 2;
-      memcpy(req.data + req.datalen, &sinl.sin_addr.s_addr,
-           sizeof(struct in_addr));
-      req.datalen += sizeof(struct in_addr);
-
-      /* we're only doing authentication */
-      req.data[req.datalen] = PW_SERVICE_TYPE;
-      req.data[req.datalen+1] = 6;
-      req.data[req.datalen+2] = (PW_SERVICE_AUTH_ONLY >> 24) & 0x000000ff;
-      req.data[req.datalen+3] = (PW_SERVICE_AUTH_ONLY >> 16) & 0x000000ff;
-      req.data[req.datalen+4] = (PW_SERVICE_AUTH_ONLY >> 8) & 0x000000ff;
-      req.data[req.datalen+5] = PW_SERVICE_AUTH_ONLY & 0x000000ff;
-      req.datalen += req.data[req.datalen+1];
-
-      /* filled in the data, now we know what the actual length is. */
-      req.length = 4+AUTH_VECTOR_LEN+req.datalen;
-
-      /* "encrypt" the password */
-      for (i = 0; i < req.data[passstart+1]-2; i += sizeof(HASH)) {
-       jlen = sizeof(HASH);
-       if (req.data[passstart+1]-(unsigned)i-2 < sizeof(HASH))
-           jlen = req.data[passstart+1]-i-2;
-       for (j = 0; j < jlen; j++)
-           req.data[passstart+2+i+j] ^= digest[j];
-       if (jlen == sizeof(HASH)) {
-           /* Recalculate the digest from the HASHed previous */
-           strlcpy((char *) secbuf, config->secret, sizeof(secbuf));
-           memcpy(secbuf+strlen(config->secret), &req.data[passstart+2+i],
-                   sizeof(HASH));
-            md5_hash(secbuf, strlen(config->secret)+sizeof(HASH), digest);
-       }
-      }
-      sreq->reqlen = req.length;
-      req.length = htons(req.length);
-
-      req_copyfrom(sreq, req);
-
-      /* Go to the next record in the list */
-      config = config->next;
-    }
-
-    /* YAYY! The auth_req is ready to go! Build the reply socket and send out
-     * the message. */
-
-    /* now, build the sockets */
-    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-      syswarn("cannot build reply socket");
-      return(-1);
-    }
-    if (bind(sock, (struct sockaddr*) &sinl, sizeof(sinl)) < 0) {
-      syswarn("cannot bind reply socket");
-      close(sock);
-      return(-1);
-    }
-
-    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, sreq->reqlen, 0, 
-                  (struct sockaddr*) &sreq->sinr, 
-                  sizeof (struct sockaddr_in)) < 0) {
-          syswarn("cannot send auth_reg");
-         close(sock);
-         return(-1);
-       }
-
-       /* wait 5 seconds maximum for a radius reply. */
-       now = time(0);
-       end = now+5;
-       tmout.tv_sec = 6;
-       tmout.tv_usec = 0;
-       FD_ZERO(&rdfds);
-       /* store the old vector to verify next checksum */
-       memcpy(secbuf+sizeof(req.vector), req.vector, sizeof(req.vector));
-       FD_SET(sock, &rdfds);
-       got = select(sock+1, &rdfds, 0, 0, &tmout);
-       if (got < 0) {
-            syswarn("cannot not select");
-           break;
-       } else if (got == 0) {
-           /* timer ran out */
-           now = time(0);
-           tmout.tv_sec = end - now + 1;
-           tmout.tv_usec = 0;
-           continue;
-       }
-       slen = sizeof(sinl);
-       if ((jlen = recvfrom(sock, (char *)&req, sizeof(req)-sizeof(int), 0, 
-                            (struct sockaddr*) &sinl, &slen)) < 0) {
-            syswarn("cannot recvfrom");
-           break;
-       }
-       if (!config->ignore_source) {
-           if (sinl.sin_addr.s_addr != sreq->sinr.sin_addr.s_addr ||
-             (sinl.sin_port != sreq->sinr.sin_port)) {
-                warn("received unexpected UDP packet from %s:%d",
-                     inet_ntoa(sinl.sin_addr), ntohs(sinl.sin_port));
-               continue;
-           }
-       }
-       sreq->reqlen = ntohs(req.length);
-       if (jlen < 4+AUTH_VECTOR_LEN || jlen != sreq->reqlen) {
-            warn("received badly-sized packet");
-           continue;
-       }
-       /* verify the checksum */
-       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((unsigned char *)&req, strlen(config->secret)+sreq->reqlen,
-           digest);
-       if (memcmp(digest, secbuf, sizeof(HASH)) != 0) {
-            warn("checksum didn't match");
-           continue;
-       }
-       /* 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)
-        warn("cannot talk to remote radius server %s:%d",
-             inet_ntoa(sreq->sinr.sin_addr), ntohs(sreq->sinr.sin_port));
-    return(-2);
-}
-
-#define RAD_HAVE_HOST 1
-#define RAD_HAVE_PORT 2
-#define RAD_HAVE_PREFIX 4
-#define RAD_HAVE_SUFFIX 8
-#define RAD_HAVE_LOCHOST 16
-#define RAD_HAVE_LOCPORT 32
-
-int main(int argc, char *argv[])
-{
-    int opt;
-    int havefile, haveother;
-    struct auth_info *authinfo;
-    rad_config_t radconfig;
-    int retval;
-    char *radius_config;
-
-    message_program_name = "radius";
-
-    if (!innconf_read(NULL))
-        exit(1);
-
-    memset(&radconfig, '\0', sizeof(rad_config_t));
-    haveother = havefile = 0;
-
-    while ((opt = getopt(argc, argv, "f:h")) != -1) {
-       switch (opt) {
-         case 'f':
-           if (haveother)
-                die("-f flag after another flag");
-           if (!havefile) {
-              /* override the standard config completely if the user
-               * specifies an alternate config file */
-              memset(&radconfig, '\0', sizeof(rad_config_t));
-              havefile = 1;
-           }
-           read_config(optarg, &radconfig);
-           break;
-       case 'h':
-         printf("Usage: radius [-f config]\n");
-          exit(0);
-       }
-    }
-    if (argc != optind)
-      exit(2);
-    if (!havefile) {
-      radius_config = concatpath(innconf->pathetc, _PATH_RADIUS_CONFIG);
-      read_config(radius_config, &radconfig);
-  
-      free(radius_config);
-    }
-
-    authinfo = get_auth_info(stdin);
-    if (authinfo == NULL)
-        die("failed getting auth info");
-    if (authinfo->username[0] == '\0')
-        die("empty username");
-
-    /* got username and password, check that they're valid */
-
-    retval = rad_auth(&radconfig, authinfo->username, authinfo->password);
-    if (retval == -1)
-        die("user %s password doesn't match", authinfo->username);
-    else if (retval == -2)
-       /* couldn't talk to the radius server..  output logged above. */
-       exit(1);
-    else if (retval != 0)
-        die("unexpected return code from authentication function: %d",
-            retval);
-
-    /* radius password matches! */
-    printf("User:%s\n", authinfo->username);
-    exit(0);
-}