1 /* Copyright 2010, 2011, 2013 NORDUnet A/S. All rights reserved.
2 See LICENSE for licensing information. */
4 #if defined HAVE_CONFIG_H
12 #include <radsec/radsec.h>
13 #include <radsec/radsec-impl.h>
18 #if 0 /* Configuration file syntax. */
19 # realm specific configuration
21 type = "UDP"|"TCP"|"TLS"|"DTLS"
26 # realm configuration inherited by clients and servers
32 pskstr = STRING # Transport pre-shared key, UTF-8 form.
33 pskhexstr = STRING # Transport pre-shared key, ASCII hex form.
35 pskex = "PSK"|"DHE_PSK"|"RSA_PSK"
38 # client configuration
42 service = STRING # name or port number
43 secret = STRING # RADIUS secret
47 # server configuration
51 service = STRING # name or port number
52 secret = STRING # RADIUS secret
58 struct rs_credentials *transport_cred;
67 #define CONFGET_STR(dst,cfg,key,def) do { \
68 (dst) = cfg_getstr ((cfg), (key)); \
69 if ((dst) == NULL) (dst) = (def); \
71 #define CONFGET_INT(dst,cfg,key,def) do { \
72 (dst) = cfg_getint ((cfg), (key)); \
73 if ((dst) == -1) (dst) = (def); \
77 confload_peers (struct rs_context *ctx,
78 /*const*/ cfg_t *cfg_realm,
79 enum rs_peer_type type,
82 const char *peer_type_str[] = {"<no type>", "client", "server"};
83 cfg_t *cfg_peer = NULL;
85 char *def_cacertfile = cfg_getstr (cfg_realm, "cacertfile");
86 /*char *def_cacertpath = cfg_getstr (cfg_realm, "cacertpath");*/
87 char *def_certfile = cfg_getstr (cfg_realm, "certfile");
88 char *def_certkeyfile = cfg_getstr (cfg_realm, "certkeyfile");
89 char *def_pskstr = cfg_getstr (cfg_realm, "pskstr");
90 char *def_pskhexstr = cfg_getstr (cfg_realm, "pskhexstr");
92 for (j = 0; j < cfg_size (cfg_realm, peer_type_str[type]); j++)
95 char *pskhexstr = NULL;
96 struct rs_peer *p = peer_create (ctx, &r->peers);
98 return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__,
103 cfg_peer = cfg_getnsec (cfg_realm, peer_type_str[type], j);
104 p->hostname = cfg_getstr (cfg_peer, "hostname");
105 p->service = cfg_getstr (cfg_peer, "service");
106 p->secret = cfg_getstr (cfg_peer, "secret");
108 CONFGET_STR (p->cacertfile, cfg_peer, "cacertfile", def_cacertfile);
109 CONFGET_STR (p->certfile, cfg_peer, "certfile", def_certfile);
110 CONFGET_STR (p->certkeyfile, cfg_peer, "certkeyfile", def_certkeyfile);
111 CONFGET_STR (pskstr, cfg_peer, "pskstr", def_pskstr);
112 CONFGET_STR (pskhexstr, cfg_peer, "pskhexstr", def_pskhexstr);
114 if (pskstr || pskhexstr)
116 #if defined RS_ENABLE_TLS_PSK
117 char *def_pskex = cfg_getstr (cfg_realm, "pskex");
118 char *tmp_pskex = NULL;
119 rs_cred_type_t type = RS_CRED_NONE;
120 struct rs_credentials *cred = NULL;
122 CONFGET_STR (tmp_pskex, cfg_peer, "pskex", def_pskex);
123 if (!strcmp (tmp_pskex, "PSK"))
124 type = RS_CRED_TLS_PSK;
127 /* TODO: push a warning on the error stack:*/
128 /*rs_err_ctx_push (ctx, RSE_WARN, "%s: unsupported PSK key exchange"
129 " algorithm -- PSK not used", kex);*/
132 if (type != RS_CRED_NONE)
134 char *def_pskid = cfg_getstr (cfg_realm, "pskid");
135 cred = rs_calloc (ctx, 1, sizeof (*cred));
137 return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__,
140 CONFGET_STR (cred->identity, cfg_peer, "pskid", def_pskid);
143 cred->secret_encoding = RS_KEY_ENCODING_ASCII_HEX;
144 cred->secret = pskhexstr;
146 ; /* TODO: warn that we're ignoring pskstr */
150 cred->secret_encoding = RS_KEY_ENCODING_UTF8;
151 cred->secret = pskstr;
154 p->transport_cred = cred;
156 #else /* !RS_ENABLE_TLS_PSK */
157 /* TODO: push a warning on the error stack: */
158 /* rs_err_ctx_push (ctx, RSE_WARN, "libradsec wasn't configured with "
159 "support for TLS preshared keys, ignoring pskstr "
161 #endif /* RS_ENABLE_TLS_PSK */
165 /* For a TLS or DTLS client or server, validate that we have either of CA
166 cert file/path or PSK. */
167 if ((r->type == RS_CONN_TYPE_TLS || r->type == RS_CONN_TYPE_DTLS)
168 && (p->cacertfile == NULL && p->cacertpath == NULL)
169 && p->transport_cred == NULL)
170 return rs_err_ctx_push (ctx, RSE_CONFIG,
171 "%s: missing both CA file/path and PSK",
178 /* FIXME: Leaking memory in error cases. */
180 rs_context_read_config(struct rs_context *ctx, const char *config_file)
182 cfg_t *cfg, *cfg_realm;
186 struct rs_config *config = NULL;
188 cfg_opt_t peer_opts[] =
190 CFG_STR ("hostname", NULL, CFGF_NONE),
191 CFG_STR ("service", "2083", CFGF_NONE),
192 CFG_STR ("secret", "radsec", CFGF_NONE),
193 CFG_STR ("cacertfile", NULL, CFGF_NONE),
194 /*CFG_STR ("cacertpath", NULL, CFGF_NONE),*/
195 CFG_STR ("certfile", NULL, CFGF_NONE),
196 CFG_STR ("certkeyfile", NULL, CFGF_NONE),
197 CFG_STR ("pskstr", NULL, CFGF_NONE),
198 CFG_STR ("pskhexstr", NULL, CFGF_NONE),
199 CFG_STR ("pskid", NULL, CFGF_NONE),
200 CFG_STR ("pskex", "PSK", CFGF_NONE),
204 cfg_opt_t realm_opts[] =
206 CFG_STR ("type", "UDP", CFGF_NONE),
207 CFG_INT ("timeout", 2, CFGF_NONE), /* FIXME: Remove? */
208 CFG_INT ("retries", 2, CFGF_NONE), /* FIXME: Remove? */
209 CFG_STR ("cacertfile", NULL, CFGF_NONE),
210 /*CFG_STR ("cacertpath", NULL, CFGF_NONE),*/
211 CFG_STR ("certfile", NULL, CFGF_NONE),
212 CFG_STR ("certkeyfile", NULL, CFGF_NONE),
213 CFG_STR ("pskstr", NULL, CFGF_NONE),
214 CFG_STR ("pskhexstr", NULL, CFGF_NONE),
215 CFG_STR ("pskid", NULL, CFGF_NONE),
216 CFG_STR ("pskex", "PSK", CFGF_NONE),
217 CFG_SEC ("server", peer_opts, CFGF_MULTI),
218 CFG_SEC ("client", peer_opts, CFGF_MULTI),
223 CFG_SEC ("realm", realm_opts, CFGF_TITLE | CFGF_MULTI),
227 cfg = cfg_init (opts, CFGF_NONE);
229 return rs_err_ctx_push (ctx, RSE_CONFIG, "unable to initialize libconfuse");
230 err = cfg_parse (cfg, config_file);
236 return rs_err_ctx_push (ctx, RSE_CONFIG,
237 "%s: unable to open configuration file",
239 case CFG_PARSE_ERROR:
240 return rs_err_ctx_push (ctx, RSE_CONFIG, "%s: invalid configuration file",
243 return rs_err_ctx_push (ctx, RSE_CONFIG, "%s: unknown parse error",
247 config = rs_calloc (ctx, 1, sizeof (*config));
249 return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, NULL);
250 ctx->config = config;
252 for (i = 0; i < cfg_size (cfg, "realm"); i++)
254 struct rs_realm *r = NULL;
256 struct confcommon cc;
258 memset (&cc, 0, sizeof(cc));
259 r = rs_calloc (ctx, 1, sizeof(*r));
261 return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, NULL);
262 if (config->realms != NULL)
264 r->next = config->realms->next;
265 config->realms->next = r;
271 cfg_realm = cfg_getnsec (cfg, "realm", i);
272 s = cfg_title (cfg_realm);
274 return rs_err_ctx_push_fl (ctx, RSE_CONFIG, __FILE__, __LINE__,
275 "missing realm name");
276 /* We use a copy of the return value of cfg_title() since it's const. */
277 r->name = rs_strdup (ctx, s);
281 typestr = cfg_getstr (cfg_realm, "type");
282 if (strcmp (typestr, "UDP") == 0)
283 r->type = RS_CONN_TYPE_UDP;
284 else if (strcmp (typestr, "TCP") == 0)
285 r->type = RS_CONN_TYPE_TCP;
286 else if (strcmp (typestr, "TLS") == 0)
287 r->type = RS_CONN_TYPE_TLS;
288 else if (strcmp (typestr, "DTLS") == 0)
289 r->type = RS_CONN_TYPE_DTLS;
291 return rs_err_ctx_push (ctx, RSE_CONFIG,
292 "%s: invalid connection type: %s",
295 r->timeout = cfg_getint (cfg_realm, "timeout");
296 r->retries = cfg_getint (cfg_realm, "retries");
298 /* Add client and server peers. */
299 err = confload_peers (ctx, cfg_realm, RS_PEER_TYPE_CLIENT, r);
302 err = confload_peers (ctx, cfg_realm, RS_PEER_TYPE_SERVER, r);
307 /* Save config object in context, for freeing in rs_context_destroy(). */
308 ctx->config->cfg = cfg;
314 rs_conf_find_realm(struct rs_context *ctx, const char *name)
320 for (r = ctx->config->realms; r; r = r->next)
321 if (strcmp (r->name, name) == 0)