supports new server and realm config methods as well as argument for config file...
authorvenaas <venaas>
Mon, 14 May 2007 16:00:37 +0000 (16:00 +0000)
committervenaas <venaas@e88ac4ed-0b26-0410-9574-a7f39faa03bf>
Mon, 14 May 2007 16:00:37 +0000 (16:00 +0000)
git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@85 e88ac4ed-0b26-0410-9574-a7f39faa03bf

README
radsecproxy.c
radsecproxy.h

diff --git a/README b/README
index 62a7714..43be4c6 100644 (file)
--- a/README
+++ b/README
@@ -11,12 +11,13 @@ The config files must be in either "/etc/radsecproxy" or the
 proxy's current work directory. You may alter the path near
 the top of radsecproxy.h if necessary.
 
-There are two options that may be specified on the command line.
-They are "-d loglevel" to set a loglevel of 1, 2, 3 or 4 where 4
-is the most detailed logging. Also "-f" to run the proxy in
-the foreground with logging to stderr. Without "-f" the default
-is to detach as a daemon and log to syslog.
+There are three options that may be specified on the command line.
+"-c configfile" to specify a non-default config file path;
+"-d loglevel" to set a loglevel of 1, 2, 3 or 4 where 4 is the most
+detailed; and "-f" to run the proxy in the foreground with logging
+to stderr. Without "-f" the default is to detach as a daemon and
+log to syslog.
 
 For more information, feedback etc. contact <venaas@uninett.no>.
 
-Stig Venaas, 2007.05.09
+Stig Venaas, 2007.05.14
index 3772464..570a11f 100644 (file)
@@ -54,6 +54,7 @@
 static struct options options;
 static struct client *clients = NULL;
 static struct server *servers = NULL;
+static struct realm *realms = NULL;
 
 static int client_udp_count = 0;
 static int client_tls_count = 0;
@@ -61,6 +62,7 @@ static int client_count = 0;
 static int server_udp_count = 0;
 static int server_tls_count = 0;
 static int server_count = 0;
+static int realm_count = 0;
 
 static struct peer *tcp_server_listen;
 static struct peer *udp_server_listen;
@@ -991,8 +993,9 @@ int msmppdecrypt(uint8_t *text, uint8_t len, uint8_t *shared, uint8_t sharedlen,
 
 struct server *id2server(char *id, uint8_t len) {
     int i;
-    char **realm, *idrealm;
-
+    char *idrealm;
+    struct server *deflt = NULL;
+    
     idrealm = strchr(id, '@');
     if (idrealm) {
        idrealm++;
@@ -1001,6 +1004,8 @@ struct server *id2server(char *id, uint8_t len) {
        idrealm = "-";
        len = 1;
     }
+#if 0
+    char **realm;
     for (i = 0; i < server_count; i++) {
        for (realm = servers[i].realms; *realm; realm++) {
            if ((strlen(*realm) == 1 && **realm == '*') ||
@@ -1011,6 +1016,17 @@ struct server *id2server(char *id, uint8_t len) {
        }
     }
     return NULL;
+#else
+    for (i = 0; i < realm_count; i++) {
+       if (!deflt && realms[i].name[0] == '*' && realms[i].name[1] == '\0')
+           deflt = realms[i].server;
+       else if (!strncasecmp(idrealm, realms[i].name, len)) {
+           debug(DBG_DBG, "found matching realm: %s, host %s", realms[i].name, servers[i].peer.host);
+           return servers + i;
+       }
+    }
+    return deflt;
+#endif
 }
 
 int rqinqueue(struct server *to, struct client *from, uint8_t id) {
@@ -1288,10 +1304,10 @@ void *clientrd(void *arg) {
            tmp[attrvallen] = '\0';
            switch (*buf) {
            case RAD_Access_Accept:
-               debug(DBG_INFO, "Access Accept for %s", tmp);
+               debug(DBG_INFO, "Access Accept for %s from %s", tmp, server->peer.host);
                break;
            case RAD_Access_Reject:
-               debug(DBG_INFO, "Access Reject for %s", tmp);
+               debug(DBG_INFO, "Access Reject for %s from %s", tmp, server->peer.host);
                break;
            }
        }
@@ -1631,6 +1647,27 @@ int tlslistener() {
     return 0;
 }
 
+void addrealm(char *value, char *server) {
+    int i;
+    struct realm *realm;
+    
+    for (i = 0; i < server_count; i++)
+       if (!strcasecmp(server, servers[i].peer.host))
+           break;
+    if (i == server_count)
+       debugx(1, DBG_ERR, "addrealm failed, no server %s", server);
+
+    realm_count++;
+    realms = realloc(realms, realm_count * sizeof(struct realm));
+    if (!realms)
+       debugx(1, DBG_ERR, "malloc failed");
+    realm = realms + realm_count - 1;
+    memset(realm, 0, sizeof(struct realm));
+    realm->name = stringcopy(value, 0);
+    realm->server = servers + i;
+    debug(DBG_DBG, "addrealm: added realm %s for server %s", value, server);
+}
+
 char *parsehostport(char *s, struct peer *peer) {
     char *p, *field;
     int ipv6 = 0;
@@ -1669,10 +1706,14 @@ char *parsehostport(char *s, struct peer *peer) {
     return p;
 }
 
+/* TODO remove this */
 /* * is default, else longest match ... ";" used for separator */
 char *parserealmlist(char *s, struct server *server) {
+#if 0    
     char *p;
     int i, n, l;
+    char *realmdata;
+    char **realms;
 
     for (p = s, n = 1; *p && *p != ' ' && *p != '\t' && *p != '\n'; p++)
        if (*p == ';')
@@ -1681,18 +1722,37 @@ char *parserealmlist(char *s, struct server *server) {
     if (!l)
        debugx(1, DBG_ERR, "realm list must be specified");
 
-    server->realmdata = stringcopy(s, l);
-    server->realms = malloc((1+n) * sizeof(char *));
-    if (!server->realms)
+    realmdata = stringcopy(s, l);
+    realms = malloc((1+n) * sizeof(char *));
+    if (!realms)
        debugx(1, DBG_ERR, "malloc failed");
-    server->realms[0] = server->realmdata;
+    realms[0] = realmdata;
     for (n = 1, i = 0; i < l; i++)
-       if (server->realmdata[i] == ';') {
-           server->realmdata[i] = '\0';
-           server->realms[n++] = server->realmdata + i + 1;
+       if (realmdata[i] == ';') {
+           realmdata[i] = '\0';
+           realms[n++] = realmdata + i + 1;
        }       
-    server->realms[n] = NULL;
+    for (i = 0; i < n; i++)
+       addrealm(realms[i], server->peer.host);
+    free(realms);
+    free(realmdata);
     return p;
+#else
+    char *start;
+    char *realm;
+
+    for (start = s;; s++)
+       if (!*s || *s == ';' || *s == ' ' || *s == '\t' || *s == '\n') {
+           if (s - start > 0) {
+               realm = stringcopy(start, s - start);
+               addrealm(realm, server->peer.host);
+               free(realm);
+           }
+           if (*s != ';')
+               return s;
+           start = s + 1;
+       }
+#endif    
 }
 
 FILE *openconfigfile(const char *filename) {
@@ -1723,7 +1783,7 @@ FILE *openconfigfile(const char *filename) {
 void getconfig(const char *serverfile, const char *clientfile) {
     FILE *f;
     char line[1024];
-    char *p, *field, **r;
+    char *p, *field;
     struct client *client;
     struct server *server;
     struct peer *peer;
@@ -1760,6 +1820,16 @@ void getconfig(const char *serverfile, const char *clientfile) {
        if (!servers)
            debugx(1, DBG_ERR, "malloc failed");
     } else {
+       if (client_udp_count) {
+           udp_server_replyq.replies = malloc(client_udp_count * MAX_REQUESTS * sizeof(struct reply));
+           if (!udp_server_replyq.replies)
+               debugx(1, DBG_ERR, "malloc failed");
+           udp_server_replyq.size = client_udp_count * MAX_REQUESTS;
+           udp_server_replyq.count = 0;
+           pthread_mutex_init(&udp_server_replyq.count_mutex, NULL);
+           pthread_cond_init(&udp_server_replyq.count_cond, NULL);
+       }    
+
        count = client_count = client_udp_count + client_tls_count;
        clients = calloc(count, sizeof(struct client));
        if (!clients)
@@ -1831,11 +1901,6 @@ void getconfig(const char *serverfile, const char *clientfile) {
            }
        }
        debug(DBG_DBG, "got type %c, host %s, port %s, secret %s", peer->type, peer->host, peer->port, peer->secret);
-       if (serverfile) {
-           debug(DBG_DBG, "    with realms:");
-           for (r = server->realms; *r; r++)
-               debug(DBG_DBG, "\t%s", *r);
-       }
        i++;
     }
     fclose(f);
@@ -1968,53 +2033,73 @@ void getgeneralconfig(FILE *f, char *block, ...) {
     }
 }
 
-void conf_cb(FILE *f, char *opt, char *val) {
-    char *type = NULL, *secret = NULL /*, *port = NULL*/;
+void confclsrv_cb(FILE *f, char *opt, char *val) {
+    char *type = NULL, *secret = NULL, *port = NULL;
     char *block;
-    struct client *client;
+    struct client *client = NULL;
+    struct server *server = NULL;
     struct peer *peer;
     
     block = malloc(strlen(opt) + strlen(val) + 2);
     if (!block)
        debugx(1, DBG_ERR, "malloc failed");
     sprintf(block, "%s %s", opt, val);
-    debug(DBG_DBG, "conf_cb called for %s", block);
+    debug(DBG_DBG, "confclsrv_cb called for %s", block);
+    
+    if (!strcasecmp(opt, "client")) {
+       getgeneralconfig(f, block,
+                        "type", CONF_STR, &type,
+                        "secret", CONF_STR, &secret,
+                        NULL
+                        );
+       client_count++;
+       clients = realloc(clients, client_count * sizeof(struct client));
+       if (!clients)
+           debugx(1, DBG_ERR, "malloc failed");
+       client = clients + client_count - 1;
+       memset(client, 0, sizeof(struct client));
+       peer = &client->peer;
+    } else {
+       getgeneralconfig(f, block,
+                        "type", CONF_STR, &type,
+                        "secret", CONF_STR, &secret,
+                        "port", CONF_STR, &port,
+                        NULL
+                        );
+       server_count++;
+       servers = realloc(servers, server_count * sizeof(struct server));
+       if (!servers)
+           debugx(1, DBG_ERR, "malloc failed");
+       server = servers + server_count - 1;
+       memset(server, 0, sizeof(struct server));
+       peer = &server->peer;
+       peer->port = port;
+    }
     
-    getgeneralconfig(f, block,
-                    "type", CONF_STR, &type,
-                    "secret", CONF_STR, &secret,
-                    /*              "port", CONF_STR, &port,*/
-                    NULL
-                    );
-
-    client_count++;
-    clients = realloc(clients, client_count * sizeof(struct client));
-    if (!clients)
-       debugx(1, DBG_ERR, "malloc failed");
-    client = clients + client_count - 1;
-    memset(client, 0, sizeof(struct client));
-    peer = &client->peer;
     peer->host = stringcopy(val, 0);
-    /*    peer->port = port;*/
     
     if (type && !strcasecmp(type, "udp")) {
        peer->type = 'U';
-       /*
-       if (!port)
-       peer->port = stringcopy(DEFAULT_UDP_PORT, 0);
-       */
-       client_udp_count++;
+       if (client)
+           client_udp_count++;
+       else {
+           server_udp_count++;
+           if (!port)
+               peer->port = stringcopy(DEFAULT_UDP_PORT, 0);
+       }
     } else if (type && !strcasecmp(type, "tls")) {
        peer->type = 'T';
-       /*
-       if (!port)
-           peer->port = stringcopy(DEFAULT_TLS_PORT, 0);
-       */
-       client_tls_count++;
+       if (client)
+           client_tls_count++;
+       else {
+           server_tls_count++;
+           if (!port)
+               peer->port = stringcopy(DEFAULT_TLS_PORT, 0);
+       }
     } else
        debugx(1, DBG_ERR, "error in block %s, type must be set to UDP or TLS", block);
     free(type);
-    /*    free(port);*/
+    
     if (!resolvepeer(peer, 0))
        debugx(1, DBG_ERR, "failed to resolve host %s port %s, exiting", peer->host, peer->port);
     
@@ -2025,25 +2110,58 @@ void conf_cb(FILE *f, char *opt, char *val) {
     } else {
        peer->secret = secret;
     }
-    
-    if (peer->type == 'U')
-       client->replyq = &udp_server_replyq;
-    else {
-       client->replyq = malloc(sizeof(struct replyq));
-       if (!client->replyq)
-           debugx(1, DBG_ERR, "malloc failed");
-       client->replyq->replies = calloc(MAX_REQUESTS, sizeof(struct reply));
-       if (!client->replyq->replies)
+
+    if (client) {
+       if (peer->type == 'U')
+           client->replyq = &udp_server_replyq;
+       else {
+           client->replyq = malloc(sizeof(struct replyq));
+           if (!client->replyq)
+               debugx(1, DBG_ERR, "malloc failed");
+           client->replyq->replies = calloc(MAX_REQUESTS, sizeof(struct reply));
+           if (!client->replyq->replies)
+               debugx(1, DBG_ERR, "malloc failed");
+           client->replyq->size = MAX_REQUESTS;
+           client->replyq->count = 0;
+           pthread_mutex_init(&client->replyq->count_mutex, NULL);
+           pthread_cond_init(&client->replyq->count_cond, NULL);
+       }
+    } else {
+       pthread_mutex_init(&server->lock, NULL);
+       server->sock = -1;
+       server->requests = calloc(MAX_REQUESTS, sizeof(struct request));
+       if (!server->requests)
            debugx(1, DBG_ERR, "malloc failed");
-       client->replyq->size = MAX_REQUESTS;
-       client->replyq->count = 0;
-       pthread_mutex_init(&client->replyq->count_mutex, NULL);
-       pthread_cond_init(&client->replyq->count_cond, NULL);
+       server->newrq = 0;
+       pthread_mutex_init(&server->newrq_mutex, NULL);
+       pthread_cond_init(&server->newrq_cond, NULL);
     }
     
     free(block);
 }
 
+void confrealm_cb(FILE *f, char *opt, char *val) {
+    char *server = NULL;
+    char *block;
+    
+    block = malloc(strlen(opt) + strlen(val) + 2);
+    if (!block)
+       debugx(1, DBG_ERR, "malloc failed");
+    sprintf(block, "%s %s", opt, val);
+    debug(DBG_DBG, "confrealm_cb called for %s", block);
+    
+    getgeneralconfig(f, block,
+                    "server", CONF_STR, &server,
+                    NULL
+                    );
+    if (!server)
+       debugx(1, DBG_ERR, "error in block %s, server must be specified", block);
+
+    addrealm(val, server);
+    free(server);
+    free(block);
+}
+
 void getmainconfig(const char *configfile) {
     FILE *f;
     char *statusserver = NULL, *loglevel = NULL;
@@ -2062,7 +2180,9 @@ void getmainconfig(const char *configfile) {
                     "StatusServer", CONF_STR, &statusserver,
                     "LogLevel", CONF_STR, &loglevel,
                     "LogDestination", CONF_STR, &options.logdestination,
-                    "Client", CONF_CBK, conf_cb,
+                    "Client", CONF_CBK, confclsrv_cb,
+                    "Server", CONF_CBK, confclsrv_cb,
+                    "Realm", CONF_CBK, confrealm_cb,
                     NULL
                     );
     fclose(f);
@@ -2092,11 +2212,14 @@ void getmainconfig(const char *configfile) {
     }    
 }
 
-void getargs(int argc, char **argv, uint8_t *foreground, uint8_t *loglevel) {
+void getargs(int argc, char **argv, uint8_t *foreground, uint8_t *loglevel, char **configfile) {
     int c;
 
-    while ((c = getopt(argc, argv, "d:f")) != -1) {
+    while ((c = getopt(argc, argv, "c:d:f")) != -1) {
        switch (c) {
+       case 'c':
+           *configfile = optarg;
+           break;
        case 'd':
            if (strlen(optarg) != 1 || *optarg < '1' || *optarg > '4')
                debugx(1, DBG_ERR, "Debug level must be 1, 2, 3 or 4, not %s", optarg);
@@ -2113,7 +2236,7 @@ void getargs(int argc, char **argv, uint8_t *foreground, uint8_t *loglevel) {
        return;
 
  usage:
-    debug(DBG_ERR, "Usage:\n%s [ -f ] [ -d debuglevel ]", argv[0]);
+    debug(DBG_ERR, "Usage:\n%s [ -c configfile ] [ -d debuglevel ] [ -f ]", argv[0]);
     exit(1);
 }
 
@@ -2121,13 +2244,14 @@ int main(int argc, char **argv) {
     pthread_t udpserverth;
     int i;
     uint8_t foreground = 0, loglevel = 0;
+    char *configfile = NULL;
     
     debug_init("radsecproxy");
     debug_set_level(DEBUG_LEVEL);
-    getargs(argc, argv, &foreground, &loglevel);
+    getargs(argc, argv, &foreground, &loglevel, &configfile);
     if (loglevel)
        debug_set_level(loglevel);
-    getmainconfig(CONFIG_MAIN);
+    getmainconfig(configfile ? configfile : CONFIG_MAIN);
     if (loglevel)
        options.loglevel = loglevel;
     else if (options.loglevel)
@@ -2139,10 +2263,17 @@ int main(int argc, char **argv) {
            options.logdestination = "x-syslog://";
        debug_set_destination(options.logdestination);
     }
-    getconfig(CONFIG_SERVERS, NULL);
+
+    /* TODO remove getconfig completely when all use new config method */
+    if (!server_count)
+       getconfig(CONFIG_SERVERS, NULL);
     if (!client_count)
        getconfig(NULL, CONFIG_CLIENTS);
 
+    /* TODO exit if not at least one client and one server configured */
+    if (!realm_count)
+       debugx(1, DBG_ERR, "No realms configured, nothing to do, exiting");
+
     if (!foreground && (daemon(0, 0) < 0))
        debugx(1, DBG_ERR, "daemon() failed: %s", strerror(errno));
        
index a3fe108..797fa53 100644 (file)
@@ -101,8 +101,6 @@ struct client {
 
 struct server {
     struct peer peer;
-    char *realmdata;
-    char **realms;
     int sock;
     pthread_mutex_t lock;
     pthread_t clientth;
@@ -115,6 +113,11 @@ struct server {
     pthread_cond_t newrq_cond;
 };
 
+struct realm {
+    char *name;
+    struct server *server;
+};
+
 #define RADLEN(x) ntohs(((uint16_t *)(x))[1])
 
 #define SOCKADDR_SIZE(addr) ((addr).ss_family == AF_INET ? \