2 * Copyright (c) 2012, JANET(UK)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of JANET(UK) nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 * OF THE POSSIBILITY OF SUCH DAMAGE.
41 #include <tr_cfgwatch.h>
42 #include <tr_config.h>
44 #include <tr_filter.h>
45 #include <trust_router/tr_constraint.h>
49 void tr_print_config (TR_CFG *cfg) {
50 tr_notice("tr_print_config: Logging running trust router configuration.");
51 tr_print_comms(cfg->comms);
54 void tr_print_comms (TR_COMM *comm_list) {
57 for (comm = comm_list; NULL != comm; comm = comm->next) {
58 tr_notice("tr_print_config: Community %s:", comm->id->buf);
60 tr_notice("tr_print_config: - Member IdPs:");
61 tr_print_comm_idps(comm->idp_realms);
63 tr_notice("tr_print_config: - Member RPs:");
64 tr_print_comm_rps(comm->rp_realms);
68 void tr_print_comm_idps (TR_IDP_REALM *idp_list) {
69 TR_IDP_REALM *idp = NULL;
71 for (idp = idp_list; NULL != idp; idp = idp->comm_next) {
72 tr_notice("tr_print_config: - @%s", idp->realm_id->buf);
76 void tr_print_comm_rps(TR_RP_REALM *rp_list) {
77 TR_RP_REALM *rp = NULL;
79 for (rp = rp_list; NULL != rp; rp = rp->next) {
80 tr_notice("tr_print_config: - %s", rp->realm_name->buf);
84 TR_CFG *tr_cfg_new(TALLOC_CTX *mem_ctx)
86 return talloc_zero(mem_ctx, TR_CFG);
89 void tr_cfg_free (TR_CFG *cfg) {
93 TR_CFG_MGR *tr_cfg_mgr_new(TALLOC_CTX *mem_ctx)
95 return talloc_zero(mem_ctx, TR_CFG_MGR);
98 void tr_cfg_mgr_free (TR_CFG_MGR *cfg_mgr) {
102 TR_CFG_RC tr_apply_new_config (TR_CFG_MGR *cfg_mgr)
104 /* cfg_mgr->active is allowed to be null, but new cannot be */
105 if ((cfg_mgr==NULL) || (cfg_mgr->new==NULL))
106 return TR_CFG_BAD_PARAMS;
108 if (cfg_mgr->active != NULL)
109 tr_cfg_free(cfg_mgr->active);
111 cfg_mgr->active = cfg_mgr->new;
112 cfg_mgr->new=NULL; /* only keep a single handle on the new configuration */
114 tr_log_threshold(cfg_mgr->active->internal->log_threshold);
115 tr_console_threshold(cfg_mgr->active->internal->console_threshold);
117 return TR_CFG_SUCCESS;
120 static TR_CFG_RC tr_cfg_parse_internal(TR_CFG *trc, json_t *jcfg)
124 json_t *jtidsp = NULL;
125 json_t *jtrpsp = NULL;
126 json_t *jhname = NULL;
128 json_t *jconthres = NULL;
129 json_t *jlogthres = NULL;
130 json_t *jcfgpoll = NULL;
131 json_t *jcfgsettle = NULL;
132 json_t *jroutesweep = NULL;
133 json_t *jrouteupdate = NULL;
134 json_t *jrouteconnect = NULL;
136 if ((!trc) || (!jcfg))
137 return TR_CFG_BAD_PARAMS;
139 if (NULL == trc->internal) {
140 if (NULL == (trc->internal = talloc_zero(trc, TR_CFG_INTERNAL)))
144 if (NULL != (jint = json_object_get(jcfg, "tr_internal"))) {
145 if (NULL != (jmtd = json_object_get(jint, "max_tree_depth"))) {
146 if (json_is_number(jmtd)) {
147 trc->internal->max_tree_depth = json_integer_value(jmtd);
149 tr_debug("tr_cfg_parse_internal: Parsing error, max_tree_depth is not a number.");
150 return TR_CFG_NOPARSE;
153 /* If not configured, use the default */
154 trc->internal->max_tree_depth = TR_DEFAULT_MAX_TREE_DEPTH;
156 if (NULL != (jtidsp = json_object_get(jint, "tids_port"))) {
157 if (json_is_number(jtidsp)) {
158 trc->internal->tids_port = json_integer_value(jtidsp);
160 tr_debug("tr_cfg_parse_internal: Parsing error, tids_port is not a number.");
161 return TR_CFG_NOPARSE;
164 /* If not configured, use the default */
165 trc->internal->tids_port = TR_DEFAULT_TIDS_PORT;
167 if (NULL != (jtrpsp = json_object_get(jint, "trps_port"))) {
168 if (json_is_number(jtrpsp)) {
169 trc->internal->trps_port = json_integer_value(jtrpsp);
171 tr_debug("tr_cfg_parse_internal: Parsing error, trps_port is not a number.");
172 return TR_CFG_NOPARSE;
175 /* If not configured, use the default */
176 trc->internal->trps_port = TR_DEFAULT_TRPS_PORT;
178 if (NULL != (jhname = json_object_get(jint, "hostname"))) {
179 if (json_is_string(jhname)) {
180 trc->internal->hostname = json_string_value(jhname);
182 tr_debug("tr_cfg_parse_internal: Parsing error, hostname is not a string.");
183 return TR_CFG_NOPARSE;
186 if (NULL != (jcfgpoll = json_object_get(jint, "cfg_poll_interval"))) {
187 if (json_is_number(jcfgpoll)) {
188 trc->internal->cfg_poll_interval = json_integer_value(jcfgpoll);
190 tr_debug("tr_cfg_parse_internal: Parsing error, cfg_poll_interval is not a number.");
191 return TR_CFG_NOPARSE;
194 trc->internal->cfg_poll_interval = TR_CFGWATCH_DEFAULT_POLL;
197 if (NULL != (jcfgsettle = json_object_get(jint, "cfg_settling_time"))) {
198 if (json_is_number(jcfgsettle)) {
199 trc->internal->cfg_settling_time = json_integer_value(jcfgsettle);
201 tr_debug("tr_cfg_parse_internal: Parsing error, cfg_settling_time is not a number.");
202 return TR_CFG_NOPARSE;
205 trc->internal->cfg_settling_time = TR_CFGWATCH_DEFAULT_SETTLE;
208 if (NULL != (jrouteconnect = json_object_get(jint, "trp_connect_interval"))) {
209 if (json_is_number(jrouteconnect)) {
210 trc->internal->trp_connect_interval = json_integer_value(jrouteconnect);
212 tr_debug("tr_cfg_parse_internal: Parsing error, trp_connect_interval is not a number.");
213 return TR_CFG_NOPARSE;
216 /* if not configured, use the default */
217 trc->internal->trp_connect_interval=TR_DEFAULT_TRP_CONNECT_INTERVAL;
220 if (NULL != (jroutesweep = json_object_get(jint, "trp_sweep_interval"))) {
221 if (json_is_number(jroutesweep)) {
222 trc->internal->trp_sweep_interval = json_integer_value(jroutesweep);
224 tr_debug("tr_cfg_parse_internal: Parsing error, trp_sweep_interval is not a number.");
225 return TR_CFG_NOPARSE;
228 /* if not configured, use the default */
229 trc->internal->trp_sweep_interval=TR_DEFAULT_TRP_SWEEP_INTERVAL;
232 if (NULL != (jrouteupdate = json_object_get(jint, "trp_update_interval"))) {
233 if (json_is_number(jrouteupdate)) {
234 trc->internal->trp_update_interval = json_integer_value(jrouteupdate);
236 tr_debug("tr_cfg_parse_internal: Parsing error, trp_update_interval is not a number.");
237 return TR_CFG_NOPARSE;
240 /* if not configured, use the default */
241 trc->internal->trp_update_interval=TR_DEFAULT_TRP_UPDATE_INTERVAL;
244 if (NULL != (jlog = json_object_get(jint, "logging"))) {
245 if (NULL != (jlogthres = json_object_get(jlog, "log_threshold"))) {
246 if (json_is_string(jlogthres)) {
247 trc->internal->log_threshold = str2sev(json_string_value(jlogthres));
249 tr_debug("tr_cfg_parse_internal: Parsing error, log_threshold is not a string.");
250 return TR_CFG_NOPARSE;
253 /* If not configured, use the default */
254 trc->internal->log_threshold = TR_DEFAULT_LOG_THRESHOLD;
257 if (NULL != (jconthres = json_object_get(jlog, "console_threshold"))) {
258 if (json_is_string(jconthres)) {
259 trc->internal->console_threshold = str2sev(json_string_value(jconthres));
261 tr_debug("tr_cfg_parse_internal: Parsing error, console_threshold is not a string.");
262 return TR_CFG_NOPARSE;
265 /* If not configured, use the default */
266 trc->internal->console_threshold = TR_DEFAULT_CONSOLE_THRESHOLD;
269 /* If not configured, use the default */
270 trc->internal->console_threshold = TR_DEFAULT_CONSOLE_THRESHOLD;
271 trc->internal->log_threshold = TR_DEFAULT_LOG_THRESHOLD;
274 tr_debug("tr_cfg_parse_internal: Internal config parsed.");
275 return TR_CFG_SUCCESS;
277 return TR_CFG_SUCCESS;
280 static TR_CONSTRAINT *tr_cfg_parse_one_constraint(TALLOC_CTX *mem_ctx, char *ctype, json_t *jc, TR_CFG_RC *rc)
282 TR_CONSTRAINT *cons=NULL;
285 if ((!ctype) || (!jc) || (!rc) ||
286 (!json_is_array(jc)) ||
287 (0 >= json_array_size(jc)) ||
288 (TR_MAX_CONST_MATCHES < json_array_size(jc)) ||
289 (!json_is_string(json_array_get(jc, 0)))) {
290 tr_err("tr_cfg_parse_one_constraint: config error.");
295 if (NULL==(cons=tr_constraint_new(mem_ctx))) {
296 tr_debug("tr_cfg_parse_one_constraint: Out of memory (cons).");
301 if (NULL==(cons->type=tr_new_name(ctype))) {
302 tr_err("tr_cfg_parse_one_constraint: Out of memory (type).");
304 tr_constraint_free(cons);
308 for (i=0; i < json_array_size(jc); i++) {
309 cons->matches[i]=tr_new_name(json_string_value(json_array_get(jc, i)));
310 if (cons->matches[i]==NULL) {
311 tr_err("tr_cfg_parse_one_constraint: Out of memory (match %d).", i+1);
313 tr_constraint_free(cons);
321 static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR_FILTER_TYPE ftype, TR_CFG_RC *rc)
323 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
324 TR_FILTER *filt=NULL;
325 json_t *jfaction=NULL;
326 json_t *jfspecs=NULL;
327 json_t *jffield=NULL;
328 json_t *jfmatch=NULL;
335 if ((jfilt==NULL) || (rc==NULL)) {
336 tr_err("tr_cfg_parse_one_filter: null argument");
341 if (NULL==(filt=tr_filter_new(tmp_ctx))) {
342 tr_err("tr_cfg_parse_one_filter: Out of memory.");
346 tr_filter_set_type(filt, ftype);
348 /* make sure we have space to represent the filter */
349 if (json_array_size(jfilt) > TR_MAX_FILTER_LINES) {
350 tr_err("tr_cfg_parse_one_filter: Filter has too many lines, maximum of %d.", TR_MAX_FILTER_LINES);
355 /* For each entry in the filter... */
356 for (i=0; i < json_array_size(jfilt); i++) {
357 if ((NULL==(jfaction=json_object_get(json_array_get(jfilt, i), "action"))) ||
358 (!json_is_string(jfaction))) {
359 tr_debug("tr_cfg_parse_one_filter: Error parsing filter action.");
364 if ((NULL==(jfspecs=json_object_get(json_array_get(jfilt, i), "filter_specs"))) ||
365 (!json_is_array(jfspecs)) ||
366 (0==json_array_size(jfspecs))) {
367 tr_debug("tr_cfg_parse_one_filter: Error parsing filter specs.");
372 if (TR_MAX_FILTER_SPECS < json_array_size(jfspecs)) {
373 tr_debug("tr_cfg_parse_one_filter: Filter has too many filter_specs, maximimum of %d.", TR_MAX_FILTER_SPECS);
378 if (NULL==(filt->lines[i]=tr_fline_new(filt))) {
379 tr_debug("tr_cfg_parse_one_filter: Out of memory allocating filter line %d.", i+1);
384 if (!strcmp(json_string_value(jfaction), "accept")) {
385 filt->lines[i]->action=TR_FILTER_ACTION_ACCEPT;
387 else if (!strcmp(json_string_value(jfaction), "reject")) {
388 filt->lines[i]->action=TR_FILTER_ACTION_REJECT;
391 tr_debug("tr_cfg_parse_one_filter: Error parsing filter action, unknown action' %s'.", json_string_value(jfaction));
396 if (NULL!=(jrc=json_object_get(json_array_get(jfilt, i), "realm_constraints")) {
397 if (!json_is_array(jrc)) {
398 tr_err("tr_cfg_parse_one_filter: cannot parse realm_constraints, not an array.");
401 } else if (json_array_size(jrc)>TR_MAX_CONST_MATCHES) {
402 tr_err("tr_cfg_parse_one_filter: realm_constraints has too many entries, maximum of %d.",
403 TR_MAX_CONST_MATCHES);
406 } else if (json_array_size(jrc)>0) {
407 /* ok we actually have entries to process */
408 if (NULL==(filt->lines[i]->realm_cons=tr_cfg_parse_one_constraint(filt->lines[i], "realm", jrc, rc))) {
409 tr_debug("tr_cfg_parse_one_filter: Error parsing realm constraint");
417 if (NULL!=(jdc=json_object_get(json_array_get(jfilt, i), "domain_constraints"))) {
418 if (!json_is_array(jdc)) {
419 tr_err("tr_cfg_parse_one_filter: cannot parse domain_constraints, not an array.");
422 } else if (json_array_size(jdc)>TR_MAX_CONST_MATCHES) {
423 tr_err("tr_cfg_parse_one_filter: domain_constraints has too many entries, maximum of %d.",
424 TR_MAX_CONST_MATCHES);
427 } else if (json_array_size(jdc)>0) {
428 if (NULL==(filt->lines[i]->domain_cons=tr_cfg_parse_one_constraint(filt->lines[i], "domain", jdc, rc))) {
429 tr_debug("tr_cfg_parse_one_filter: Error parsing domain constraint");
436 /*For each filter spec within the filter line... */
437 for (j=0; j <json_array_size(jfspecs); j++) {
438 if ((NULL==(jffield=json_object_get(json_array_get(jfspecs, j), "field"))) ||
439 (!json_is_string(jffield)) ||
440 (NULL==(jfmatch=json_object_get(json_array_get(jfspecs, j), "match"))) ||
441 (!json_is_string(jfmatch))) {
442 tr_debug("tr_cfg_parse_one_filter: Error parsing filter field and match for filter spec %d, filter line %d.", i, j);
447 if (NULL==(filt->lines[i]->specs[j]=tr_fspec_new(filt->lines[i]))) {
448 tr_debug("tr_cfg_parse_one_filter: Out of memory.");
453 if ((NULL==(filt->lines[i]->specs[j]->field=tr_new_name(json_string_value(jffield)))) ||
454 (NULL==(filt->lines[i]->specs[j]->match=tr_new_name(json_string_value(jfmatch))))) {
455 tr_debug("tr_cfg_parse_one_filter: Out of memory.");
462 talloc_steal(mem_ctx, filt);
465 talloc_free(tmp_ctx);
469 static TR_AAA_SERVER *tr_cfg_parse_one_aaa_server(TALLOC_CTX *mem_ctx, json_t *jaddr, TR_CFG_RC *rc)
471 TR_AAA_SERVER *aaa = NULL;
474 if ((!jaddr) || (!json_is_string(jaddr))) {
475 tr_debug("tr_cfg_parse_one_aaa_server: Bad parameters.");
476 *rc = TR_CFG_BAD_PARAMS;
480 name=tr_new_name(json_string_value(jaddr));
482 tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating hostname.");
487 aaa=tr_aaa_server_new(mem_ctx, name);
490 tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating AAA server.");
498 static TR_AAA_SERVER *tr_cfg_parse_one_aaa_server(TALLOC_CTX *mem_ctx, json_t *jaddr, TR_CFG_RC *rc)
500 TR_AAA_SERVER *aaa = NULL;
503 if ((!jaddr) || (!json_is_string(jaddr))) {
504 tr_debug("tr_cfg_parse_one_aaa_server: Bad parameters.");
505 *rc = TR_CFG_BAD_PARAMS;
509 name=tr_new_name(json_string_value(jaddr));
511 tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating hostname.");
516 aaa=tr_aaa_server_new(mem_ctx, name);
519 tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating AAA server.");
527 static TR_AAA_SERVER *tr_cfg_parse_aaa_servers(TALLOC_CTX *mem_ctx, json_t *jaaas, TR_CFG_RC *rc)
529 TALLOC_CTX *tmp_ctx=NULL;
530 TR_AAA_SERVER *aaa = NULL;
531 TR_AAA_SERVER *temp_aaa = NULL;
534 for (i = 0; i < json_array_size(jaaas); i++) {
535 if (NULL == (temp_aaa = tr_cfg_parse_one_aaa_server(tmp_ctx, json_array_get(jaaas, i), rc))) {
536 talloc_free(tmp_ctx);
539 /* TBD -- IPv6 addresses */
540 // tr_debug("tr_cfg_parse_aaa_servers: Configuring AAA Server: ip_addr = %s.", inet_ntoa(temp_aaa->aaa_server_addr));
541 temp_aaa->next = aaa;
544 tr_debug("tr_cfg_parse_aaa_servers: Finished (rc=%d)", *rc);
546 for (temp_aaa=aaa; temp_aaa!=NULL; temp_aaa=temp_aaa->next)
547 talloc_steal(mem_ctx, temp_aaa);
548 talloc_free(tmp_ctx);
552 /* not talloc-aware */
553 static TR_APC *tr_cfg_parse_apc(json_t *japc, TR_CFG_RC *rc)
558 *rc = TR_CFG_SUCCESS; /* presume success */
560 if ((!japc) || (!rc) || (!json_is_string(japc))) {
561 tr_debug("tr_cfg_parse_apc: Bad parameters.");
563 *rc = TR_CFG_BAD_PARAMS;
567 apc=tr_apc_new(mem_ctx);
569 tr_debug("tr_cfg_parse_apc: Out of memory.");
574 name=tr_new_name(json_string_value(json));
576 tr_debug("tr_cfg_parse_apc: No memory for APC name.");
581 tr_apc_set_id(apc, name); /* apc is now responsible for freeing the name */
586 static TR_NAME *tr_cfg_parse_name(TALLOC_CTX *mem_ctx, json_t *jname, TR_CFG_RC *rc)
591 if ((jname==NULL) || (!json_is_string(jname))) {
592 tr_err("tr_cfg_parse_name: name missing or not a string");
596 name=tr_new_name(json_string_value(jname));
598 tr_err("tr_cfg_parse_name: could not allocate name");
607 static int tr_cfg_parse_shared_config(json_t *jsc, TR_CFG_RC *rc)
609 const char *shared=NULL;
613 (!json_is_string(jsc)) ||
614 (NULL==(shared=json_string_value(jsc)))) {
619 if (0==strcmp(shared, "no"))
621 else if (0==strcmp(shared, "yes"))
624 /* any other value is an error */
625 tr_debug("tr_cfg_parse_shared_config: invalid shared_config value \"%s\" (should be \"yes\" or \"no\")",
631 /* Parse the identity provider object from a realm and fill in the given TR_IDP_REALM. */
632 static TR_CFG_RC tr_cfg_parse_idp(TR_IDP_REALM *idp, json_t *jidp)
635 TR_AAA_SERVER *aaa=NULL;
636 TR_CFG_RC rc=TR_CFG_ERROR;
641 idp->origin=TR_REALM_LOCAL; /* if we're parsing it from a config file, it's local */
642 idp->shared_config=tr_cfg_parse_shared_config(json_object_get(jidp, "shared_config"), &rc);
643 if (rc!=TR_CFG_SUCCESS) {
644 tr_err("tr_cfg_parse_idp: missing or malformed shared_config specification");
649 apc=tr_cfg_parse_name(json_object_get(jidp, "apc"), &rc);
650 if ((rc!=TR_CFG_SUCCESS) || (apc==NULL)) {
651 tr_err("tr_cfg_parse_idp: unable to parse APC");
656 aaa=tr_cfg_parse_aaa_servers(idp, json_object_get(jidp, "aaa_servers"), &rc);
657 if ((rc!=TR_CFG_SUCCESS) || (aaa==NULL)) {
658 tr_err("tr_cfg_parse_idp: unable to parse AAA servers");
663 /* done, fill in the idp structures */
664 idp->apcs=tr_apc_new(idp);
665 if (idp->apcs==NULL) {
666 tr_err("tr_cfg_parse_idp: unable to allocate APC.");
670 tr_apc_set_id(idp->apcs, apc);
671 idp->aaa_servers=aaa;
675 if (rc!=TR_CFG_SUCCESS) {
679 tr_aaa_server_free(aaa);
685 /* parses idp realm */
686 static TR_IDP_REALM *tr_cfg_parse_one_idp_realm(TALLOC_CTX *mem_ctx, TR_CFG *trc, json_t *jrealm, TR_CFG_RC *rc)
688 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
689 TR_IDP_REALM *realm=NULL;
690 json_t *jremote=NULL;
694 TR_CFG_RC call_rc=TR_CFG_ERROR;
696 *rc=TR_CFG_ERROR; /* default to error if not set */
698 if ((!trc) || (!jrealm) || (!rc)) {
699 tr_err("tr_cfg_parse_one_idp_realm: Bad parameters.");
701 *rc=TR_CFG_BAD_PARAMS;
705 if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) {
706 tr_err("tr_cfg_parse_one_idp_realm: could not allocate idp realm.");
711 /* must have a name */
712 realm->realm_id=tr_cfg_parse_realm_name(realm,
713 json_object_get(jrealm, "realm"),
715 if ((call_rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) {
716 tr_err("tr_cfg_parse_one_idp_realm: could not parse realm name");
721 call_rc=tr_cfg_parse_idp(realm, json_object_get(jrealm, "identity_provider"));
722 if (call_rc!=TR_CFG_SUCCESS) {
723 tr_err("tr_cfg_parse_one_idp_realm: could not parse identity_provider.");
729 if (*rc==TR_CFG_SUCCESS)
730 talloc_steal(mem_ctx, realm);
736 talloc_free(tmp_ctx);
740 /* Determine whether the realm is an IDP realm */
741 static int tr_cfg_is_idp_realm(json_t *jrealm)
743 /* If a realm spec contains an identity_provider, it's an IDP realm. */
744 if (NULL != json_object_get(jrealm, "identity_provider"))
750 /* Parse any idp realms in the j_realms object. Ignores other realm types. */
751 static TR_IDP_REALM *tr_cfg_parse_idp_realms(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc)
753 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
754 TR_IDP_REALM *realms=NULL;
755 TR_IDP_REALM *new_realm=NULL;
756 json_t *this_jrealm=NULL;
758 TR_CFG_RC rc=TR_CFG_ERROR;
761 if ((jrealms==NULL) || (!json_is_array(jrealms))) {
762 tr_err("tr_cfg_parse_idp_realms: realms not an array");
767 for (ii=0; ii<json_array_size(jrealms); ii++) {
768 this_jrealm=json_array_get(jrealms, ii);
769 if (tr_cfg_is_idp_realm(this_jrealm)) {
770 new_realm=tr_cfg_parse_one_idp_realm(tmp_ctx, this_jrealm, &rc);
771 if (rc!=TR_CFG_SUCCESS) {
772 tr_err("tr_cfg_parse_idp_realms: error decoding realm entry %d", ii+1);
776 realms=tr_idp_realm_add(realms, new_realm);
781 talloc_steal(mem_ctx, realms);
784 talloc_free(tmp_ctx);
788 /* takes a talloc context, but currently does not use it */
789 static TR_NAME *tr_cfg_parse_org_name(TALLOC_CTX *mem_ctx, json_t *j_org, TR_CFG_RC *rc)
793 if ((j_org==NULL) || (rc==NULL) || (!json_is_string(j_org))) {
794 tr_debug("tr_cfg_parse_org_name: Bad parameters.");
796 *rc = TR_CFG_BAD_PARAMS; /* fill in return value if we can */
800 name=tr_new_name(json_string_value(j_org));
808 static TR_CFG_RC tr_cfg_parse_one_local_org(TALLOC_CTX *mem_ctx, TR_CFG *trc, json_t *jlorg)
810 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
811 TR_CFG_RC retval=TR_CFG_ERROR; /* our return code */
812 TR_CFG_RC rc=TR_CFG_ERROR; /* return code from functions we call */
813 TR_NAME *org_name=NULL;
815 json_t *j_realms=NULL;
816 TRP_IDP_REALM *new_idp_realms=NULL;
817 TR_RP_REALM *new_rp_realms=NULL;
819 tr_debug("tr_cfg_parse_one_local_org: parsing local organization");
821 /* get organization_name (optional) */
822 if (NULL==(j_org=json_object_get(jlorg, "organization_name"))) {
823 tr_debug("tr_cfg_parse_one_local_org: organization_name unspecified");
825 org_name=tr_cfg_parse_org_name(tmp_ctx, j_org, &rc);
826 if (rc==TR_SUCCESS) {
827 tr_debug("tr_cfg_parse_one_local_org: organization_name=%.*s", org_name->len, org_name->buf);
828 /* we don't actually do anything with this, but we could */
829 tr_free_name(org_name);
834 /* Now get realms. Allow this to be missing; even though that is a pointless organization entry,
835 * it's harmless. Report a warning because that might be unintentional. */
836 if (NULL==(j_realms=json_object_get(jlorg, "realms"))) {
837 tr_warning("tr_cfg_parse_one_local_org: warning - no realms in this local organization");
839 /* Allocate in the tmp_ctx so these will be cleaned up if we do not complete successfully. */
840 new_idp_realms=tr_cfg_parse_idp_realms(tmp_ctx, j_realms, &rc);
841 if (rc!=TR_CFG_SUCCESS)
844 new_rp_realms=tr_cfg_parse_rp_realms(tmp_ctx, j_realms, &rc);
845 if (rc!=TR_CFG_SUCCESS)
848 retval=TR_CFG_SUCCESS;
851 /* if we succeeded, link things to the configuration and move out of tmp context */
852 if (retval==TR_CFG_SUCCESS) {
853 if (new_idp_realms!=NULL)
854 trc->idp_realms=tr_idp_realm_add(trc->idp_realms, new_idp_realms); /* fixes talloc contexts */
855 if (new_rp_realms!=NULL)
856 trc->rp_realms=tr_rp_realm_add(trc->rp_realms, new_rp_realms); /* fixes talloc contexts */
859 talloc_free(tmp_ctx);
863 /* Parse local organizations if present. Returns success if there are none. */
867 TR_CFG_RC tr_cfg_validate(TR_CFG *trc)
869 TR_CFG_RC rc = TR_CFG_SUCCESS;
872 return TR_CFG_BAD_PARAMS;
874 if ((NULL == trc->internal)||
875 (NULL == trc->internal->hostname)) {
876 tr_debug("tr_cfg_validate: Error: No internal configuration, or no hostname.");
880 if (NULL == trc->rp_clients) {
881 tr_debug("tr_cfg_validate: Error: No RP Clients configured");
885 if (NULL == trc->comms) {
886 tr_debug("tr_cfg_validate: Error: No Communities configured");
890 if ((NULL == trc->default_servers) && (NULL == trc->idp_realms)) {
891 tr_debug("tr_cfg_validate: Error: No default servers or IDPs configured.");
898 /* Join two paths and return a pointer to the result. This should be freed
899 * via talloc_free. Returns NULL on failure. */
900 static char *join_paths(TALLOC_CTX *mem_ctx, const char *p1, const char *p2)
902 return talloc_asprintf(mem_ctx, "%s/%s", p1, p2); /* returns NULL on a failure */
905 /* Reads configuration files in config_dir ("" or "./" will use the current directory). */
906 TR_CFG_RC tr_parse_config (TR_CFG_MGR *cfg_mgr, const char *config_dir, int n, struct dirent **cfg_files)
908 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
912 char *file_with_path;
914 TR_CFG_RC cfg_rc=TR_CFG_ERROR;
916 if ((!cfg_mgr) || (!cfg_files) || (n<=0)) {
917 cfg_rc=TR_CFG_BAD_PARAMS;
921 if (cfg_mgr->new != NULL)
922 tr_cfg_free(cfg_mgr->new);
923 cfg_mgr->new=tr_cfg_new(tmp_ctx); /* belongs to the temporary context for now */
924 if (cfg_mgr->new == NULL) {
929 /* Parse configuration information from each config file */
930 for (ii=0; ii<n; ii++) {
931 file_with_path=join_paths(tmp_ctx, config_dir, cfg_files[ii]->d_name); /* must free result with talloc_free */
932 if(file_with_path == NULL) {
933 tr_crit("tr_parse_config: error joining path.");
937 tr_debug("tr_parse_config: Parsing %s.", cfg_files[ii]->d_name); /* print the filename without the path */
938 if (NULL == (jcfg = json_load_file(file_with_path,
939 JSON_DISABLE_EOF_CHECK, &rc))) {
940 tr_debug("tr_parse_config: Error parsing config file %s.",
941 cfg_files[ii]->d_name);
942 cfg_rc=TR_CFG_NOPARSE;
945 talloc_free(file_with_path); /* done with filename */
947 // Look for serial number and log it if it exists
948 if (NULL != (jser = json_object_get(jcfg, "serial_number"))) {
949 if (json_is_number(jser)) {
950 tr_notice("tr_read_config: Attempting to load revision %" JSON_INTEGER_FORMAT " of '%s'.",
951 json_integer_value(jser),
952 cfg_files[n]->d_name);
956 /* TODO: parse using the new functions */
957 if ((TR_CFG_SUCCESS != tr_cfg_parse_internal(cfg_mgr->new, jcfg)) ||
958 (TR_CFG_SUCCESS != tr_cfg_parse_rp_clients(cfg_mgr->new, jcfg)) ||
959 (TR_CFG_SUCCESS != tr_cfg_parse_idp_realms(cfg_mgr->new, jcfg)) ||
960 (TR_CFG_SUCCESS != tr_cfg_parse_default_servers(cfg_mgr->new, jcfg)) ||
961 (TR_CFG_SUCCESS != tr_cfg_parse_comms(cfg_mgr->new, jcfg))) {
967 /* make sure we got a complete, consistent configuration */
968 if (TR_CFG_SUCCESS != tr_cfg_validate(cfg_mgr->new)) {
969 tr_err("tr_parse_config: Error: INVALID CONFIGURATION");
975 talloc_steal(cfg_mgr, cfg_mgr->new); /* hand this over to the cfg_mgr context */
976 cfg_rc=TR_CFG_SUCCESS;
979 talloc_free(tmp_ctx);
983 TR_IDP_REALM *tr_cfg_find_idp (TR_CFG *tr_cfg, TR_NAME *idp_id, TR_CFG_RC *rc)
986 TR_IDP_REALM *cfg_idp;
988 if ((!tr_cfg) || (!idp_id)) {
990 *rc = TR_CFG_BAD_PARAMS;
994 for (cfg_idp = tr_cfg->idp_realms; NULL != cfg_idp; cfg_idp = cfg_idp->next) {
995 if (!tr_name_cmp (idp_id, cfg_idp->realm_id)) {
996 tr_debug("tr_cfg_find_idp: Found %s.", idp_id->buf);
1000 /* if we didn't find one, return NULL */
1004 TR_RP_CLIENT *tr_cfg_find_rp (TR_CFG *tr_cfg, TR_NAME *rp_gss, TR_CFG_RC *rc)
1006 TR_RP_CLIENT *cfg_rp;
1009 if ((!tr_cfg) || (!rp_gss)) {
1011 *rc = TR_CFG_BAD_PARAMS;
1015 for (cfg_rp = tr_cfg->rp_clients; NULL != cfg_rp; cfg_rp = cfg_rp->next) {
1016 for (i = 0; i < TR_MAX_GSS_NAMES; i++) {
1017 if (!tr_name_cmp (rp_gss, cfg_rp->gss_names[i])) {
1018 tr_debug("tr_cfg_find_rp: Found %s.", rp_gss->buf);
1023 /* if we didn't find one, return NULL */
1027 static int is_cfg_file(const struct dirent *dent) {
1030 /* Only accept filenames ending in ".cfg" and starting with a character
1031 * other than an ASCII '.' */
1033 /* filename must be at least 4 characters long to be acceptable */
1034 n=strlen(dent->d_name);
1039 /* filename must not start with '.' */
1040 if ('.' == dent->d_name[0]) {
1044 /* If the above passed and the last four characters of the filename are .cfg, accept.
1045 * (n.b., assumes an earlier test checked that the name is >= 4 chars long.) */
1046 if (0 == strcmp(&(dent->d_name[n-4]), ".cfg")) {
1050 /* otherwise, return false. */
1054 /* Find configuration files in a particular directory. Returns the
1055 * number of entries found, 0 if none are found, or <0 for some
1056 * errors. If n>=0, the cfg_files parameter will contain a newly
1057 * allocated array of pointers to struct dirent entries, as returned
1058 * by scandir(). These can be freed with tr_free_config_file_list().
1060 int tr_find_config_files (const char *config_dir, struct dirent ***cfg_files) {
1063 n = scandir(config_dir, cfg_files, is_cfg_file, alphasort);
1067 tr_debug("tr_find_config: scandir error trying to scan %s.", config_dir);
1073 /* Free memory allocated for configuration file list returned from tr_find_config_files().
1074 * This can be called regardless of the return value of tr_find_config_values(). */
1075 void tr_free_config_file_list(int n, struct dirent ***cfg_files) {
1078 /* if n < 0, then scandir did not allocate anything because it failed */
1079 if((n>=0) && (*cfg_files != NULL)) {
1080 for(ii=0; ii<n; ii++) {
1081 free((*cfg_files)[ii]);
1083 free(*cfg_files); /* safe even if n==0 */
1084 *cfg_files=NULL; /* this will help prevent accidentally freeing twice */