diff options
author | Linus Nordberg <linus@nordberg.se> | 2013-02-11 16:41:47 +0100 |
---|---|---|
committer | Linus Nordberg <linus@nordberg.se> | 2013-02-11 16:41:47 +0100 |
commit | d640207c74e0aaf5b4a3faf61c38e17796bf76a2 (patch) | |
tree | d79a0eabf66503525f4bf1a3495e00ed50f7d207 /lib/conf.c | |
parent | 8d113bba795b1b8cf4ab55b362108f2c819e039d (diff) |
Add support for configuring client connections too.
We're moving x509 and psk config from rs_realm to rs_peer while
allowing these to be configured on the realm level and overriden at
peer level.
Also, add support for printing the read configuration, for debugging.
Diffstat (limited to 'lib/conf.c')
-rw-r--r-- | lib/conf.c | 255 |
1 files changed, 164 insertions, 91 deletions
@@ -1,4 +1,4 @@ -/* Copyright 2010, 2011 NORDUnet A/S. All rights reserved. +/* Copyright 2010, 2011, 2013 NORDUnet A/S. All rights reserved. See LICENSE for licensing information. */ #if defined HAVE_CONFIG_H @@ -15,49 +15,190 @@ #include "util.h" #include "debug.h" -#if 0 - # common config options - - # common realm config options +#if 0 /* Configuration file syntax. */ + # realm specific configuration realm STRING { type = "UDP"|"TCP"|"TLS"|"DTLS" timeout = INT retries = INT + } + + # realm configuration inherited by clients and servers + realm STRING { cacertfile = STRING #cacertpath = STRING certfile = STRING certkeyfile = STRING - pskstr = STRING # Transport pre-shared key, UTF-8 form. + pskstr = STRING # Transport pre-shared key, UTF-8 form. pskhexstr = STRING # Transport pre-shared key, ASCII hex form. pskid = STRING pskex = "PSK"|"DHE_PSK"|"RSA_PSK" } - # client specific realm config options + # client configuration realm STRING { server { hostname = STRING - service = STRING + service = STRING # name or port number + secret = STRING # RADIUS secret + } + } + + # server configuration + realm STRING { + client { + hostname = STRING + service = STRING # name or port number secret = STRING # RADIUS secret } } #endif +struct confcommon { + struct rs_credentials *transport_cred; + char *cacertfile; + char *cacertpath; + char *certfile; + char *certkeyfile; + char *pskstr; + char *pskhexstr; +}; + +#define CONFGET_STR(dst,cfg,key,def) do { \ + (dst) = cfg_getstr ((cfg), (key)); \ + if ((dst) == NULL) (dst) = (def); \ + } while (0) +#define CONFGET_INT(dst,cfg,key,def) do { \ + (dst) = cfg_getint ((cfg), (key)); \ + if ((dst) == -1) (dst) = (def); \ + } while (0) + +static int +confload_peers (struct rs_context *ctx, + /*const*/ cfg_t *cfg_realm, + enum rs_peer_type type, + struct rs_realm *r) +{ + const char *peer_type_str[] = {"<no type>", "client", "server"}; + cfg_t *cfg_peer = NULL; + int j; + char *def_cacertfile = cfg_getstr (cfg_realm, "cacertfile"); + /*char *def_cacertpath = cfg_getstr (cfg_realm, "cacertpath");*/ + char *def_certfile = cfg_getstr (cfg_realm, "certfile"); + char *def_certkeyfile = cfg_getstr (cfg_realm, "certkeyfile"); + char *def_pskstr = cfg_getstr (cfg_realm, "pskstr"); + char *def_pskhexstr = cfg_getstr (cfg_realm, "pskhexstr"); + + for (j = 0; j < cfg_size (cfg_realm, peer_type_str[type]); j++) + { + char *pskstr = NULL; + char *pskhexstr = NULL; + struct rs_peer *p = peer_create (ctx, &r->peers); + if (p == NULL) + return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, + NULL); + p->type = type; + p->realm = r; + + cfg_peer = cfg_getnsec (cfg_realm, peer_type_str[type], j); + p->hostname = cfg_getstr (cfg_peer, "hostname"); + p->service = cfg_getstr (cfg_peer, "service"); + p->secret = cfg_getstr (cfg_peer, "secret"); + + CONFGET_STR (p->cacertfile, cfg_peer, "cacertfile", def_cacertfile); + CONFGET_STR (p->certfile, cfg_peer, "certfile", def_certfile); + CONFGET_STR (p->certkeyfile, cfg_peer, "certkeyfile", def_certkeyfile); + CONFGET_STR (pskstr, cfg_peer, "pskstr", def_pskstr); + CONFGET_STR (pskhexstr, cfg_peer, "pskhexstr", def_pskhexstr); + + if (pskstr || pskhexstr) + { +#if defined RS_ENABLE_TLS_PSK + char *def_pskex = cfg_getstr (cfg_realm, "pskex"); + char *tmp_pskex = NULL; + rs_cred_type_t type = RS_CRED_NONE; + struct rs_credentials *cred = NULL; + + CONFGET_STR (tmp_pskex, cfg_peer, "pskex", def_pskex); + if (!strcmp (tmp_pskex, "PSK")) + type = RS_CRED_TLS_PSK; + else + { + /* TODO: push a warning on the error stack:*/ + /*rs_err_ctx_push (ctx, RSE_WARN, "%s: unsupported PSK key exchange" + " algorithm -- PSK not used", kex);*/ + } + + if (type != RS_CRED_NONE) + { + char *def_pskid = cfg_getstr (cfg_realm, "pskid"); + cred = rs_calloc (ctx, 1, sizeof (*cred)); + if (cred == NULL) + return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, + NULL); + cred->type = type; + CONFGET_STR (cred->identity, cfg_peer, "pskid", def_pskid); + if (pskhexstr) + { + cred->secret_encoding = RS_KEY_ENCODING_ASCII_HEX; + cred->secret = pskhexstr; + if (pskstr) + ; /* TODO: warn that we're ignoring pskstr */ + } + else + { + cred->secret_encoding = RS_KEY_ENCODING_UTF8; + cred->secret = pskstr; + } + + p->transport_cred = cred; + } +#else /* !RS_ENABLE_TLS_PSK */ + /* TODO: push a warning on the error stack: */ + /* rs_err_ctx_push (ctx, RSE_WARN, "libradsec wasn't configured with " + "support for TLS preshared keys, ignoring pskstr " + "and pskhexstr");*/ +#endif /* RS_ENABLE_TLS_PSK */ + } + + + /* For a TLS or DTLS client or server, validate that we have either of CA + cert file/path or PSK. */ + if ((r->type == RS_CONN_TYPE_TLS || r->type == RS_CONN_TYPE_DTLS) + && (p->cacertfile == NULL && p->cacertpath == NULL) + && p->transport_cred == NULL) + return rs_err_ctx_push (ctx, RSE_CONFIG, + "%s: missing both CA file/path and PSK", + r->name); + } + + return RSE_OK; +} + /* FIXME: Leaking memory in error cases. */ int rs_context_read_config(struct rs_context *ctx, const char *config_file) { - cfg_t *cfg, *cfg_realm, *cfg_server; + cfg_t *cfg, *cfg_realm; int err = 0; - int i, j; + int i; const char *s; struct rs_config *config = NULL; - cfg_opt_t server_opts[] = + cfg_opt_t peer_opts[] = { CFG_STR ("hostname", NULL, CFGF_NONE), CFG_STR ("service", "2083", CFGF_NONE), CFG_STR ("secret", "radsec", CFGF_NONE), + CFG_STR ("cacertfile", NULL, CFGF_NONE), + /*CFG_STR ("cacertpath", NULL, CFGF_NONE),*/ + CFG_STR ("certfile", NULL, CFGF_NONE), + CFG_STR ("certkeyfile", NULL, CFGF_NONE), + CFG_STR ("pskstr", NULL, CFGF_NONE), + CFG_STR ("pskhexstr", NULL, CFGF_NONE), + CFG_STR ("pskid", NULL, CFGF_NONE), + CFG_STR ("pskex", "PSK", CFGF_NONE), + CFG_END () }; cfg_opt_t realm_opts[] = @@ -73,7 +214,8 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) CFG_STR ("pskhexstr", NULL, CFGF_NONE), CFG_STR ("pskid", NULL, CFGF_NONE), CFG_STR ("pskex", "PSK", CFGF_NONE), - CFG_SEC ("server", server_opts, CFGF_MULTI), + CFG_SEC ("server", peer_opts, CFGF_MULTI), + CFG_SEC ("client", peer_opts, CFGF_MULTI), CFG_END () }; cfg_opt_t opts[] = @@ -111,8 +253,9 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) { struct rs_realm *r = NULL; const char *typestr; - char *pskstr = NULL, *pskhexstr = NULL; + struct confcommon cc; + memset (&cc, 0, sizeof(cc)); r = rs_calloc (ctx, 1, sizeof(*r)); if (r == NULL) return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, NULL); @@ -148,87 +291,17 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) return rs_err_ctx_push (ctx, RSE_CONFIG, "%s: invalid connection type: %s", r->name, typestr); + r->timeout = cfg_getint (cfg_realm, "timeout"); r->retries = cfg_getint (cfg_realm, "retries"); - r->cacertfile = cfg_getstr (cfg_realm, "cacertfile"); - /*r->cacertpath = cfg_getstr (cfg_realm, "cacertpath");*/ - r->certfile = cfg_getstr (cfg_realm, "certfile"); - r->certkeyfile = cfg_getstr (cfg_realm, "certkeyfile"); - - pskstr = cfg_getstr (cfg_realm, "pskstr"); - pskhexstr = cfg_getstr (cfg_realm, "pskhexstr"); - if (pskstr || pskhexstr) - { -#if defined RS_ENABLE_TLS_PSK - char *kex = cfg_getstr (cfg_realm, "pskex"); - rs_cred_type_t type = RS_CRED_NONE; - struct rs_credentials *cred = NULL; - assert (kex != NULL); - - if (!strcmp (kex, "PSK")) - type = RS_CRED_TLS_PSK; - else - { - /* TODO: push a warning on the error stack:*/ - /*rs_err_ctx_push (ctx, RSE_WARN, "%s: unsupported PSK key exchange" - " algorithm -- PSK not used", kex);*/ - } - - if (type != RS_CRED_NONE) - { - cred = rs_calloc (ctx, 1, sizeof (*cred)); - if (cred == NULL) - return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, - NULL); - cred->type = type; - cred->identity = cfg_getstr (cfg_realm, "pskid"); - if (pskhexstr) - { - cred->secret_encoding = RS_KEY_ENCODING_ASCII_HEX; - cred->secret = pskhexstr; - if (pskstr) - ; /* TODO: warn that we're ignoring pskstr */ - } - else - { - cred->secret_encoding = RS_KEY_ENCODING_UTF8; - cred->secret = pskstr; - } - - r->transport_cred = cred; - } -#else /* !RS_ENABLE_TLS_PSK */ - /* TODO: push a warning on the error stack: */ - /* rs_err_ctx_push (ctx, RSE_WARN, "libradsec wasn't configured with " - "support for TLS preshared keys, ignoring pskstr " - "and pskhexstr");*/ -#endif /* RS_ENABLE_TLS_PSK */ - } - - /* For TLS and DTLS realms, validate that we either have (i) CA - cert file or path or (ii) PSK. */ - if ((r->type == RS_CONN_TYPE_TLS || r->type == RS_CONN_TYPE_DTLS) - && (r->cacertfile == NULL && r->cacertpath == NULL) - && r->transport_cred == NULL) - return rs_err_ctx_push (ctx, RSE_CONFIG, - "%s: missing both CA file/path and PSK", - r->name); - - /* Add peers, one per server stanza. */ - for (j = 0; j < cfg_size (cfg_realm, "server"); j++) - { - struct rs_peer *p = peer_create (ctx, &r->peers); - if (p == NULL) - return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, - NULL); - p->realm = r; - - cfg_server = cfg_getnsec (cfg_realm, "server", j); - p->hostname = cfg_getstr (cfg_server, "hostname"); - p->service = cfg_getstr (cfg_server, "service"); - p->secret = cfg_getstr (cfg_server, "secret"); - } + /* Add client and server peers. */ + err = confload_peers (ctx, cfg_realm, RS_PEER_TYPE_CLIENT, r); + if (err) + return err; + err = confload_peers (ctx, cfg_realm, RS_PEER_TYPE_SERVER, r); + if (err) + return err; } /* Save config object in context, for freeing in rs_context_destroy(). */ |