From cb9e63ae8d870e1b2ece83eb0d4b66f9c443cbfd Mon Sep 17 00:00:00 2001 From: venaas Date: Mon, 14 May 2007 16:00:37 +0000 Subject: supports new server and realm config methods as well as argument for config file path git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@85 e88ac4ed-0b26-0410-9574-a7f39faa03bf --- README | 13 +-- radsecproxy.c | 267 +++++++++++++++++++++++++++++++++++++++++++--------------- radsecproxy.h | 7 +- 3 files changed, 211 insertions(+), 76 deletions(-) diff --git a/README b/README index 62a7714..43be4c6 100644 --- 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 . -Stig Venaas, 2007.05.09 +Stig Venaas, 2007.05.14 diff --git a/radsecproxy.c b/radsecproxy.c index 3772464..570a11f 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -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)); diff --git a/radsecproxy.h b/radsecproxy.h index a3fe108..797fa53 100644 --- a/radsecproxy.h +++ b/radsecproxy.h @@ -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 ? \ -- cgit v1.1