diff options
-rw-r--r-- | lib/conf.c | 104 | ||||
-rw-r--r-- | lib/err.c | 45 | ||||
-rw-r--r-- | lib/examples/Makefile | 4 | ||||
-rw-r--r-- | lib/examples/client-blocking.c | 29 | ||||
-rw-r--r-- | lib/examples/client.conf | 10 | ||||
-rw-r--r-- | lib/include/radsec/radsec-impl.h | 8 | ||||
-rw-r--r-- | lib/include/radsec/radsec.h | 3 | ||||
-rw-r--r-- | lib/radsec.c | 70 |
8 files changed, 211 insertions, 62 deletions
diff --git a/lib/conf.c b/lib/conf.c new file mode 100644 index 0000000..9acf4d4 --- /dev/null +++ b/lib/conf.c @@ -0,0 +1,104 @@ +#include <confuse.h> +#include <string.h> +#include <radsec/radsec.h> +#include <radsec/radsec-impl.h> + +#if 0 + realm NAME { + type = STRING + server { + hostname = STRING + service = STRING + secret = STRING + timeout = INT /* optional */ + tries = INT /* optional */ + } + } +#endif + +int +rs_context_read_config(struct rs_handle *ctx, const char *config_file) +{ +#warning "Missing some error handling in rs_context_config_read()" + cfg_opt_t server_opts[] = + { + CFG_STR ("hostname", NULL, CFGF_NONE), + CFG_STR ("service", "radius", CFGF_NONE), + CFG_STR ("secret", NULL, CFGF_NONE), + CFG_INT ("timeout", 3, CFGF_NONE), + CFG_INT ("tries", 1, CFGF_NONE), + CFG_END () + }; + cfg_opt_t realm_opts[] = + { + CFG_STR ("type", "UDP", CFGF_NONE), + CFG_SEC ("server", server_opts, CFGF_MULTI), + CFG_END () + }; + cfg_opt_t opts[] = + { + CFG_SEC ("realm", realm_opts, CFGF_TITLE | CFGF_MULTI), + CFG_END () + }; + cfg_t *cfg, *cfg_realm, *cfg_server; + int i, j; + + cfg = cfg_init (opts, CFGF_NONE); + if (cfg_parse (cfg, config_file) == CFG_PARSE_ERROR) + return rs_err_ctx_push (ctx, RSE_CONFIG, "%s: invalid configuration file", + config_file); + for (i = 0; i < cfg_size (cfg, "realm"); i++) + { + struct rs_realm *r = rs_malloc (ctx, sizeof(*r)); + const char *typestr; + enum rs_conn_type type; + + if (!r) + return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, NULL); + memset (r, 0, sizeof(*r)); + if (ctx->realms) + ctx->realms->next = r; + else + ctx->realms = r; + cfg_realm = cfg_getnsec (cfg, "realm", i); + r->name = strdup (cfg_title (cfg_realm)); + typestr = cfg_getstr (cfg_realm, "type"); + if (!strcmp (typestr, "UDP")) + type = RS_CONN_TYPE_UDP; + else if (!strcmp (typestr, "TCP")) + type = RS_CONN_TYPE_TCP; + else if (!strcmp (typestr, "TLS")) + type = RS_CONN_TYPE_TLS; + else if (!strcmp (typestr, "DTLS")) + type = RS_CONN_TYPE_DTLS; + else + return rs_err_ctx_push_fl (ctx, RSE_CONFIG, __FILE__, __LINE__, + "%s: invalid connection type", typestr); + for (j = 0; j < cfg_size (cfg_realm, "server"); j++) + { + struct rs_peer *p = _rs_peer_create (ctx, &r->peers); + if (!p) + return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, + NULL); + + cfg_server = cfg_getnsec (cfg_realm, "server", j); + _rs_resolv (&p->addr, type, cfg_getstr (cfg_server, "hostname"), + cfg_getstr (cfg_server, "service")); + p->secret = strdup (cfg_getstr (cfg_server, "secret")); + p->timeout = cfg_getint (cfg_server, "timeout"); + p->tries = cfg_getint (cfg_server, "tries"); + } + } + return RSE_OK; +} + +struct rs_realm +*rs_conf_find_realm(struct rs_handle *ctx, const char *name) +{ + struct rs_realm *r; + + for (r = ctx->realms; r; r = r->next) + if (!strcmp (r->name, name)) + return r; + return NULL; +} @@ -18,22 +18,23 @@ const char *_errtxt[] = { "no peer configured" /* 8 RSE_NOPEER */ "libevent error" /* 9 RSE_EVENT */ "connection error" /* 10 RSE_CONNERR */ - "ERR 11" /* RSE_ */ + "invalid configuration file" /* 11 RSE_CONFIG */ "ERR 12" /* RSE_ */ "ERR 13" /* RSE_ */ - "ERR " /* RSE_ */ - "ERR " /* RSE_ */ - "ERR " /* RSE_ */ - "ERR " /* RSE_ */ - "ERR " /* RSE_ */ - "ERR " /* RSE_ */ - "ERR " /* RSE_ */ + "ERR 14" /* RSE_ */ + "ERR 15" /* RSE_ */ + "ERR 16" /* RSE_ */ + "ERR 17" /* RSE_ */ + "ERR 18" /* RSE_ */ + "ERR 19" /* RSE_ */ + "ERR 20" /* RSE_ */ "some error" /* 21 RSE_SOME_ERROR */ }; #define ERRTXT_SIZE (sizeof(_errtxt) / sizeof(*_errtxt)) static struct rs_error * -_err_new (unsigned int code, const char *file, int line, const char *fmt, va_list args) +_err_vcreate (unsigned int code, const char *file, int line, const char *fmt, + va_list args) { struct rs_error *err; @@ -64,10 +65,23 @@ _err_new (unsigned int code, const char *file, int line, const char *fmt, va_lis return err; } +struct rs_error * +_rs_err_create (unsigned int code, const char *file, int line, const char *fmt, + ...) +{ + struct rs_error *err; + + va_list args; + va_start (args, fmt); + err = _err_vcreate (code, file, line, fmt, args); + va_end (args); + return err; +} + static int _ctx_err_vpush_fl (struct rs_handle *ctx, int code, const char *file, int line, const char *fmt, va_list args) { - struct rs_error *err = _err_new (code, file, line, fmt, args); + struct rs_error *err = _err_vcreate (code, file, line, fmt, args); if (err) ctx->err = err; @@ -94,13 +108,20 @@ rs_err_ctx_push_fl (struct rs_handle *ctx, int code, const char *file, int line, return code; } +int +_rs_err_conn_push_err (struct rs_connection *conn, struct rs_error *err) +{ + conn->err = err; /* FIXME: use a stack */ + return err->code; +} + static int _conn_err_vpush_fl (struct rs_connection *conn, int code, const char *file, int line, const char *fmt, va_list args) { - struct rs_error *err = _err_new (code, file, line, fmt, args); + struct rs_error *err = _err_vcreate (code, file, line, fmt, args); if (err) - conn->err = err; + _rs_err_conn_push_err (conn, err); return code; } diff --git a/lib/examples/Makefile b/lib/examples/Makefile index 4802c4b..cf3441b 100644 --- a/lib/examples/Makefile +++ b/lib/examples/Makefile @@ -1,6 +1,6 @@ SPECIAL = #SPECIAL += -DUSE_REQUEST_OBJECT -#SPECIAL += -DUSE_CONFIG_FILE +SPECIAL += -DUSE_CONFIG_FILE CFLAGS = -Wall -g -I ../include $(SPECIAL) @@ -9,7 +9,7 @@ HFILES = ../include/radsec/radsec.h ../include/radsec/radsec-impl.h all: client-blocking client-blocking: client-blocking.c ../libradsec.a $(HFILES) - $(CC) $(CFLAGS) -o $@ $< -L /usr/lib/freeradius -lfreeradius-radius -L .. -lradsec -L /usr/local/lib -levent_core + $(CC) $(CFLAGS) -o $@ $< -lconfuse -L /usr/lib/freeradius -lfreeradius-radius -L .. -lradsec -L /usr/local/lib -levent_core clean: -rm *.o *.gch client-blocking diff --git a/lib/examples/client-blocking.c b/lib/examples/client-blocking.c index 0e6ad39..8cd9968 100644 --- a/lib/examples/client-blocking.c +++ b/lib/examples/client-blocking.c @@ -20,7 +20,6 @@ blocking_client (const char *av1, const char *av2) { struct rs_handle *h; struct rs_connection *conn; - struct rs_peer *server; struct rs_packet *req, *resp; RADIUS_PACKET *fr_pkt; VALUE_PAIR *fr_vp; @@ -29,19 +28,23 @@ blocking_client (const char *av1, const char *av2) return NULL; #if !defined (USE_CONFIG_FILE) - if (rs_conn_create (h, &conn, NULL)) - return rs_err_conn_pop (conn); - rs_conn_set_type (conn, RS_CONN_TYPE_UDP); - if (rs_server_create (conn, &server)) - return rs_err_conn_pop (conn); - if (rs_server_set_address (server, av1, atoi (av2))) - return rs_err_conn_pop (conn); - rs_server_set_timeout (server, 1); - rs_server_set_tries (server, 3); - if (rs_server_set_secret (server, SECRET)) - return rs_err_conn_pop (conn); + { + struct rs_peer *server; + + if (rs_conn_create (h, &conn, NULL)) + return rs_err_conn_pop (conn); + rs_conn_set_type (conn, RS_CONN_TYPE_UDP); + if (rs_server_create (conn, &server)) + return rs_err_conn_pop (conn); + if (rs_server_set_address (server, av1, av2)) + return rs_err_conn_pop (conn); + rs_server_set_timeout (server, 1); + rs_server_set_tries (server, 3); + if (rs_server_set_secret (server, SECRET)) + return rs_err_conn_pop (conn); + } #else - if (rs_context_config_read (h, av1)) + if (rs_context_read_config (h, av1)) return rs_err_ctx_pop (h); if (rs_conn_create (h, &conn, av2)) return rs_err_conn_pop (conn); diff --git a/lib/examples/client.conf b/lib/examples/client.conf new file mode 100644 index 0000000..5f9536f --- /dev/null +++ b/lib/examples/client.conf @@ -0,0 +1,10 @@ +realm blocking { + type = "UDP" + server { + hostname = "localhost" + service = "1820" + secret = "sikrit" + timeout = 1 /* optional */ + tries = 10 /* optional */ + } +} diff --git a/lib/include/radsec/radsec-impl.h b/lib/include/radsec/radsec-impl.h index 503b2e5..9421fd6 100644 --- a/lib/include/radsec/radsec-impl.h +++ b/lib/include/radsec/radsec-impl.h @@ -46,6 +46,7 @@ struct rs_realm { char *name; enum rs_conn_type type; struct rs_peer *peers; + struct rs_realm *next; }; struct rs_handle { @@ -79,6 +80,13 @@ struct rs_attr { VALUE_PAIR *vp; }; +/* Nonpublic functions. */ +struct rs_error *_rs_resolv (struct evutil_addrinfo **addr, rs_conn_type_t type, const char *hostname, const char *service); +struct rs_peer *_rs_peer_create (struct rs_handle *ctx, struct rs_peer **rootp); +struct rs_error *_rs_err_create (unsigned int code, const char *file, int line, const char *fmt, ...); +int _rs_err_conn_push_err (struct rs_connection *conn, struct rs_error *err); + + /* Convenience macros. */ #define rs_calloc(h, nmemb, size) \ (h->alloc_scheme.calloc ? h->alloc_scheme.calloc : calloc)(nmemb, size) diff --git a/lib/include/radsec/radsec.h b/lib/include/radsec/radsec.h index c108d8a..982c430 100644 --- a/lib/include/radsec/radsec.h +++ b/lib/include/radsec/radsec.h @@ -16,6 +16,7 @@ enum rs_err_code { RSE_NOPEER = 8, RSE_EVENT = 9, RSE_CONNERR = 10, + RSE_CONFIG = 11, RSE_SOME_ERROR = 21, }; @@ -89,7 +90,7 @@ int rs_conn_receive_packet(struct rs_connection *conn, struct rs_packet **pkt_ou /* Server and client. */ int rs_server_create(struct rs_connection *conn, struct rs_peer **server); -int rs_server_set_address(struct rs_peer *server, const char *hostname, int port); +int rs_server_set_address(struct rs_peer *server, const char *hostname, const char *service); int rs_server_set_secret(struct rs_peer *server, const char *secret); void rs_server_set_timeout(struct rs_peer *server, int timeout); void rs_server_set_tries(struct rs_peer *server, int tries); diff --git a/lib/radsec.c b/lib/radsec.c index adf5576..96182a6 100644 --- a/lib/radsec.c +++ b/lib/radsec.c @@ -73,12 +73,6 @@ int rs_context_set_alloc_scheme(struct rs_handle *ctx, struct rs_alloc_scheme *s "%s: NYI", __func__); } -int rs_context_config_read(struct rs_handle *ctx, const char *config_file) -{ - return rs_err_ctx_push_fl (ctx, RSE_NOSYS, __FILE__, __LINE__, - "%s: NYI", __func__); -} - int rs_conn_create(struct rs_handle *ctx, struct rs_connection **conn, const char *config) @@ -95,8 +89,12 @@ rs_conn_create(struct rs_handle *ctx, struct rs_connection **conn, struct rs_realm *r = rs_conf_find_realm (ctx, config); if (r) { + struct rs_peer *p; + c->type = r->type; - c->peers = r->peers; /* FIXME: Copy? */ + c->peers = r->peers; /* FIXME: Copy instead? */ + for (p = c->peers; p; p = p->next) + p->conn = c; } } } @@ -111,22 +109,21 @@ rs_conn_set_type(struct rs_connection *conn, rs_conn_type_t type) conn->type = type; } -struct addrinfo * -_resolv (struct rs_connection *conn, const char *hostname, int port) + +struct rs_error * +_rs_resolv (struct evutil_addrinfo **addr, rs_conn_type_t type, + const char *hostname, const char *service) { int err; - char portstr[6]; struct evutil_addrinfo hints, *res = NULL; - snprintf (portstr, sizeof(portstr), "%d", port); memset (&hints, 0, sizeof(struct evutil_addrinfo)); hints.ai_family = AF_UNSPEC; /* v4 or v6. */ hints.ai_flags = AI_ADDRCONFIG; - switch (conn->type) + switch (type) { case RS_CONN_TYPE_NONE: - rs_err_conn_push_fl (conn, RSE_INVALID_CONN, __FILE__, __LINE__, NULL); - return NULL; + return _rs_err_create (RSE_INVALID_CONN, __FILE__, __LINE__, NULL, NULL); case RS_CONN_TYPE_TCP: /* Fall through. */ case RS_CONN_TYPE_TLS: @@ -140,33 +137,30 @@ _resolv (struct rs_connection *conn, const char *hostname, int port) hints.ai_protocol = IPPROTO_UDP; break; } - err = evutil_getaddrinfo (hostname, portstr, &hints, &res); + err = evutil_getaddrinfo (hostname, service, &hints, &res); if (err) - rs_err_conn_push_fl (conn, RSE_BADADDR, __FILE__, __LINE__, - "%s:%d: bad host name or port (%s)", - hostname, port, evutil_gai_strerror(err)); - return res; /* Simply use first result. */ + return _rs_err_create (RSE_BADADDR, __FILE__, __LINE__, + "%s:%s: bad host name or service name (%s)", + hostname, service, evutil_gai_strerror(err)); + *addr = res; /* Simply use first result. */ + return NULL; } -static struct rs_peer * -_peer_new (struct rs_connection *conn) +struct rs_peer * +_rs_peer_create (struct rs_handle *ctx, struct rs_peer **rootp) { struct rs_peer *p; - p = (struct rs_peer *) malloc (sizeof(*p)); + p = (struct rs_peer *) rs_malloc (ctx, sizeof(*p)); if (p) { memset (p, 0, sizeof(struct rs_peer)); - p->conn = conn; p->fd = -1; - p->next = conn->peers; - if (conn->peers) - conn->peers->next = p; + if (*rootp) + (*rootp)->next = p; else - conn->peers = p; + *rootp = p; } - else - rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL); return p; } @@ -175,22 +169,30 @@ rs_server_create (struct rs_connection *conn, struct rs_peer **server) { struct rs_peer *srv; - srv = _peer_new (conn); + srv = _rs_peer_create (conn->ctx, &conn->peers); if (srv) { + srv->conn = conn; srv->timeout = 1; srv->tries = 3; } + else + return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL); if (*server) *server = srv; - return srv ? RSE_OK : -1; + return RSE_OK; } int -rs_server_set_address (struct rs_peer *server, const char *hostname, int port) +rs_server_set_address (struct rs_peer *server, const char *hostname, + const char *service) { - server->addr = _resolv (server->conn, hostname, port); - return server->addr ? RSE_OK : -1; + struct rs_error *err; + + err = _rs_resolv (&server->addr, server->conn->type, hostname, service); + if (err) + return _rs_err_conn_push_err (server->conn, err); + return RSE_OK; } void |