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>
43 #include <tr_config.h>
46 #include <tr_filter.h>
47 #include <trust_router/tr_constraint.h>
50 #include <trust_router/trp.h>
52 void tr_print_config (TR_CFG *cfg) {
53 tr_notice("tr_print_config: Logging running trust router configuration.");
54 tr_print_comms(cfg->comms);
57 void tr_print_comms (TR_COMM_TABLE *ctab)
61 for (comm = ctab->comms; NULL != comm; comm = comm->next) {
62 tr_notice("tr_print_config: Community %s:", comm->id->buf);
64 tr_notice("tr_print_config: - Member IdPs:");
65 tr_print_comm_idps(ctab, comm);
67 tr_notice("tr_print_config: - Member RPs:");
68 tr_print_comm_rps(ctab, comm);
72 void tr_print_comm_idps(TR_COMM_TABLE *ctab, TR_COMM *comm)
74 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
75 TR_COMM_ITER *iter=NULL;
76 TR_IDP_REALM *idp = NULL;
79 iter=tr_comm_iter_new(tmp_ctx);
81 tr_notice("tr_print_config: unable to allocate IdP iterator.");
86 for (idp=tr_idp_realm_iter_first(iter, ctab, tr_comm_get_id(comm));
88 idp=tr_idp_realm_iter_next(iter)) {
89 s=tr_idp_realm_to_str(tmp_ctx, idp);
91 tr_notice("tr_print_config: - @%s", s);
93 tr_notice("tr_print_config: unable to allocate IdP output string.");
98 void tr_print_comm_rps(TR_COMM_TABLE *ctab, TR_COMM *comm)
100 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
101 TR_COMM_ITER *iter=NULL;
102 TR_RP_REALM *rp = NULL;
105 iter=tr_comm_iter_new(tmp_ctx);
107 tr_notice("tr_print_config: unable to allocate RP iterator.");
108 talloc_free(tmp_ctx);
112 for (rp=tr_rp_realm_iter_first(iter, ctab, tr_comm_get_id(comm));
114 rp=tr_rp_realm_iter_next(iter)) {
115 s=tr_rp_realm_to_str(tmp_ctx, rp);
117 tr_notice("tr_print_config: - @%s", s);
119 tr_notice("tr_print_config: unable to allocate RP output string.");
121 talloc_free(tmp_ctx);
124 TR_CFG *tr_cfg_new(TALLOC_CTX *mem_ctx)
126 TR_CFG *cfg=talloc(mem_ctx, TR_CFG);
129 cfg->idp_realms=NULL;
131 cfg->rp_clients=NULL;
133 cfg->default_servers=NULL;
134 cfg->comms=tr_comm_table_new(cfg);
135 if (cfg->comms==NULL) {
143 void tr_cfg_free (TR_CFG *cfg)
148 TR_CFG_MGR *tr_cfg_mgr_new(TALLOC_CTX *mem_ctx)
150 return talloc_zero(mem_ctx, TR_CFG_MGR);
153 void tr_cfg_mgr_free (TR_CFG_MGR *cfg_mgr) {
154 talloc_free(cfg_mgr);
157 TR_CFG_RC tr_apply_new_config (TR_CFG_MGR *cfg_mgr)
159 /* cfg_mgr->active is allowed to be null, but new cannot be */
160 if ((cfg_mgr==NULL) || (cfg_mgr->new==NULL))
161 return TR_CFG_BAD_PARAMS;
163 if (cfg_mgr->active != NULL)
164 tr_cfg_free(cfg_mgr->active);
166 cfg_mgr->active = cfg_mgr->new;
167 cfg_mgr->new=NULL; /* only keep a single handle on the new configuration */
169 tr_log_threshold(cfg_mgr->active->internal->log_threshold);
170 tr_console_threshold(cfg_mgr->active->internal->console_threshold);
172 return TR_CFG_SUCCESS;
175 static TR_CFG_RC tr_cfg_parse_internal(TR_CFG *trc, json_t *jcfg)
179 json_t *jtidsp = NULL;
180 json_t *jtrpsp = NULL;
181 json_t *jhname = NULL;
183 json_t *jconthres = NULL;
184 json_t *jlogthres = NULL;
185 json_t *jcfgpoll = NULL;
186 json_t *jcfgsettle = NULL;
187 json_t *jroutesweep = NULL;
188 json_t *jrouteupdate = NULL;
189 json_t *jrouteconnect = NULL;
191 if ((!trc) || (!jcfg))
192 return TR_CFG_BAD_PARAMS;
194 if (NULL == trc->internal) {
195 if (NULL == (trc->internal = talloc_zero(trc, TR_CFG_INTERNAL)))
199 if (NULL != (jint = json_object_get(jcfg, "tr_internal"))) {
200 if (NULL != (jmtd = json_object_get(jint, "max_tree_depth"))) {
201 if (json_is_number(jmtd)) {
202 trc->internal->max_tree_depth = json_integer_value(jmtd);
204 tr_debug("tr_cfg_parse_internal: Parsing error, max_tree_depth is not a number.");
205 return TR_CFG_NOPARSE;
208 /* If not configured, use the default */
209 trc->internal->max_tree_depth = TR_DEFAULT_MAX_TREE_DEPTH;
211 if (NULL != (jtidsp = json_object_get(jint, "tids_port"))) {
212 if (json_is_number(jtidsp)) {
213 trc->internal->tids_port = json_integer_value(jtidsp);
215 tr_debug("tr_cfg_parse_internal: Parsing error, tids_port is not a number.");
216 return TR_CFG_NOPARSE;
219 /* If not configured, use the default */
220 trc->internal->tids_port = TR_DEFAULT_TIDS_PORT;
222 if (NULL != (jtrpsp = json_object_get(jint, "trps_port"))) {
223 if (json_is_number(jtrpsp)) {
224 trc->internal->trps_port = json_integer_value(jtrpsp);
226 tr_debug("tr_cfg_parse_internal: Parsing error, trps_port is not a number.");
227 return TR_CFG_NOPARSE;
230 /* If not configured, use the default */
231 trc->internal->trps_port = TR_DEFAULT_TRPS_PORT;
233 if (NULL != (jhname = json_object_get(jint, "hostname"))) {
234 if (json_is_string(jhname)) {
235 trc->internal->hostname = json_string_value(jhname);
237 tr_debug("tr_cfg_parse_internal: Parsing error, hostname is not a string.");
238 return TR_CFG_NOPARSE;
241 if (NULL != (jcfgpoll = json_object_get(jint, "cfg_poll_interval"))) {
242 if (json_is_number(jcfgpoll)) {
243 trc->internal->cfg_poll_interval = json_integer_value(jcfgpoll);
245 tr_debug("tr_cfg_parse_internal: Parsing error, cfg_poll_interval is not a number.");
246 return TR_CFG_NOPARSE;
249 trc->internal->cfg_poll_interval = TR_CFGWATCH_DEFAULT_POLL;
252 if (NULL != (jcfgsettle = json_object_get(jint, "cfg_settling_time"))) {
253 if (json_is_number(jcfgsettle)) {
254 trc->internal->cfg_settling_time = json_integer_value(jcfgsettle);
256 tr_debug("tr_cfg_parse_internal: Parsing error, cfg_settling_time is not a number.");
257 return TR_CFG_NOPARSE;
260 trc->internal->cfg_settling_time = TR_CFGWATCH_DEFAULT_SETTLE;
263 if (NULL != (jrouteconnect = json_object_get(jint, "trp_connect_interval"))) {
264 if (json_is_number(jrouteconnect)) {
265 trc->internal->trp_connect_interval = json_integer_value(jrouteconnect);
267 tr_debug("tr_cfg_parse_internal: Parsing error, trp_connect_interval is not a number.");
268 return TR_CFG_NOPARSE;
271 /* if not configured, use the default */
272 trc->internal->trp_connect_interval=TR_DEFAULT_TRP_CONNECT_INTERVAL;
275 if (NULL != (jroutesweep = json_object_get(jint, "trp_sweep_interval"))) {
276 if (json_is_number(jroutesweep)) {
277 trc->internal->trp_sweep_interval = json_integer_value(jroutesweep);
279 tr_debug("tr_cfg_parse_internal: Parsing error, trp_sweep_interval is not a number.");
280 return TR_CFG_NOPARSE;
283 /* if not configured, use the default */
284 trc->internal->trp_sweep_interval=TR_DEFAULT_TRP_SWEEP_INTERVAL;
287 if (NULL != (jrouteupdate = json_object_get(jint, "trp_update_interval"))) {
288 if (json_is_number(jrouteupdate)) {
289 trc->internal->trp_update_interval = json_integer_value(jrouteupdate);
291 tr_debug("tr_cfg_parse_internal: Parsing error, trp_update_interval is not a number.");
292 return TR_CFG_NOPARSE;
295 /* if not configured, use the default */
296 trc->internal->trp_update_interval=TR_DEFAULT_TRP_UPDATE_INTERVAL;
299 if (NULL != (jlog = json_object_get(jint, "logging"))) {
300 if (NULL != (jlogthres = json_object_get(jlog, "log_threshold"))) {
301 if (json_is_string(jlogthres)) {
302 trc->internal->log_threshold = str2sev(json_string_value(jlogthres));
304 tr_debug("tr_cfg_parse_internal: Parsing error, log_threshold is not a string.");
305 return TR_CFG_NOPARSE;
308 /* If not configured, use the default */
309 trc->internal->log_threshold = TR_DEFAULT_LOG_THRESHOLD;
312 if (NULL != (jconthres = json_object_get(jlog, "console_threshold"))) {
313 if (json_is_string(jconthres)) {
314 trc->internal->console_threshold = str2sev(json_string_value(jconthres));
316 tr_debug("tr_cfg_parse_internal: Parsing error, console_threshold is not a string.");
317 return TR_CFG_NOPARSE;
320 /* If not configured, use the default */
321 trc->internal->console_threshold = TR_DEFAULT_CONSOLE_THRESHOLD;
324 /* If not configured, use the default */
325 trc->internal->console_threshold = TR_DEFAULT_CONSOLE_THRESHOLD;
326 trc->internal->log_threshold = TR_DEFAULT_LOG_THRESHOLD;
329 tr_debug("tr_cfg_parse_internal: Internal config parsed.");
330 return TR_CFG_SUCCESS;
332 return TR_CFG_SUCCESS;
335 static TR_CONSTRAINT *tr_cfg_parse_one_constraint(TALLOC_CTX *mem_ctx, char *ctype, json_t *jc, TR_CFG_RC *rc)
337 TR_CONSTRAINT *cons=NULL;
340 if ((!ctype) || (!jc) || (!rc) ||
341 (!json_is_array(jc)) ||
342 (0 >= json_array_size(jc)) ||
343 (TR_MAX_CONST_MATCHES < json_array_size(jc)) ||
344 (!json_is_string(json_array_get(jc, 0)))) {
345 tr_err("tr_cfg_parse_one_constraint: config error.");
350 if (NULL==(cons=tr_constraint_new(mem_ctx))) {
351 tr_debug("tr_cfg_parse_one_constraint: Out of memory (cons).");
356 if (NULL==(cons->type=tr_new_name(ctype))) {
357 tr_err("tr_cfg_parse_one_constraint: Out of memory (type).");
359 tr_constraint_free(cons);
363 for (i=0; i < json_array_size(jc); i++) {
364 cons->matches[i]=tr_new_name(json_string_value(json_array_get(jc, i)));
365 if (cons->matches[i]==NULL) {
366 tr_err("tr_cfg_parse_one_constraint: Out of memory (match %d).", i+1);
368 tr_constraint_free(cons);
376 static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR_FILTER_TYPE ftype, TR_CFG_RC *rc)
378 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
379 TR_FILTER *filt=NULL;
380 json_t *jfaction=NULL;
381 json_t *jfspecs=NULL;
382 json_t *jffield=NULL;
383 json_t *jfmatch=NULL;
391 if ((jfilt==NULL) || (rc==NULL)) {
392 tr_err("tr_cfg_parse_one_filter: null argument");
393 *rc=TR_CFG_BAD_PARAMS;
397 if (NULL==(filt=tr_filter_new(tmp_ctx))) {
398 tr_err("tr_cfg_parse_one_filter: Out of memory.");
402 tr_filter_set_type(filt, ftype);
404 /* make sure we have space to represent the filter */
405 if (json_array_size(jfilt) > TR_MAX_FILTER_LINES) {
406 tr_err("tr_cfg_parse_one_filter: Filter has too many lines, maximum of %d.", TR_MAX_FILTER_LINES);
411 /* For each entry in the filter... */
412 for (i=0; i < json_array_size(jfilt); i++) {
413 if ((NULL==(jfaction=json_object_get(json_array_get(jfilt, i), "action"))) ||
414 (!json_is_string(jfaction))) {
415 tr_debug("tr_cfg_parse_one_filter: Error parsing filter action.");
420 if ((NULL==(jfspecs=json_object_get(json_array_get(jfilt, i), "specs"))) ||
421 (!json_is_array(jfspecs)) ||
422 (0==json_array_size(jfspecs))) {
423 tr_debug("tr_cfg_parse_one_filter: Error parsing filter specs.");
428 if (TR_MAX_FILTER_SPECS < json_array_size(jfspecs)) {
429 tr_debug("tr_cfg_parse_one_filter: Filter has too many specs, maximimum of %d.", TR_MAX_FILTER_SPECS);
434 if (NULL==(filt->lines[i]=tr_fline_new(filt))) {
435 tr_debug("tr_cfg_parse_one_filter: Out of memory allocating filter line %d.", i+1);
440 if (!strcmp(json_string_value(jfaction), "accept")) {
441 filt->lines[i]->action=TR_FILTER_ACTION_ACCEPT;
443 else if (!strcmp(json_string_value(jfaction), "reject")) {
444 filt->lines[i]->action=TR_FILTER_ACTION_REJECT;
447 tr_debug("tr_cfg_parse_one_filter: Error parsing filter action, unknown action' %s'.", json_string_value(jfaction));
452 if (NULL!=(jrc=json_object_get(json_array_get(jfilt, i), "realm_constraints"))) {
453 if (!json_is_array(jrc)) {
454 tr_err("tr_cfg_parse_one_filter: cannot parse realm_constraints, not an array.");
457 } else if (json_array_size(jrc)>TR_MAX_CONST_MATCHES) {
458 tr_err("tr_cfg_parse_one_filter: realm_constraints has too many entries, maximum of %d.",
459 TR_MAX_CONST_MATCHES);
462 } else if (json_array_size(jrc)>0) {
463 /* ok we actually have entries to process */
464 if (NULL==(filt->lines[i]->realm_cons=tr_cfg_parse_one_constraint(filt->lines[i], "realm", jrc, rc))) {
465 tr_debug("tr_cfg_parse_one_filter: Error parsing realm constraint");
472 if (NULL!=(jdc=json_object_get(json_array_get(jfilt, i), "domain_constraints"))) {
473 if (!json_is_array(jdc)) {
474 tr_err("tr_cfg_parse_one_filter: cannot parse domain_constraints, not an array.");
477 } else if (json_array_size(jdc)>TR_MAX_CONST_MATCHES) {
478 tr_err("tr_cfg_parse_one_filter: domain_constraints has too many entries, maximum of %d.",
479 TR_MAX_CONST_MATCHES);
482 } else if (json_array_size(jdc)>0) {
483 if (NULL==(filt->lines[i]->domain_cons=tr_cfg_parse_one_constraint(filt->lines[i], "domain", jdc, rc))) {
484 tr_debug("tr_cfg_parse_one_filter: Error parsing domain constraint");
491 /*For each filter spec within the filter line... */
492 for (j=0; j <json_array_size(jfspecs); j++) {
493 if ((NULL==(jffield=json_object_get(json_array_get(jfspecs, j), "field"))) ||
494 (!json_is_string(jffield))) {
495 tr_debug("tr_cfg_parse_one_filter: Error parsing filter: missing field for filer spec %d, filter line %d.", i, j);
500 /* check that we have a match attribute */
501 if (NULL==(jfmatch=json_object_get(json_array_get(jfspecs, j), "match"))) {
502 tr_debug("tr_cfg_parse_one_filter: Error parsing filter: missing match for filer spec %d, filter line %d.", i, j);
507 /* check that match is a string */
508 if (!json_is_string(jfmatch)) {
509 tr_debug("tr_cfg_parse_one_filter: Error parsing filter: match not a string for filter spec %d, filter line %d.", i, j);
514 /* allocate the filter spec */
515 if (NULL==(filt->lines[i]->specs[j]=tr_fspec_new(filt->lines[i]))) {
516 tr_debug("tr_cfg_parse_one_filter: Out of memory.");
521 /* fill in the field */
522 if (NULL==(filt->lines[i]->specs[j]->field=tr_new_name(json_string_value(jffield)))) {
523 tr_debug("tr_cfg_parse_one_filter: Out of memory.");
528 /* fill in the matches */
529 if (NULL==(name=tr_new_name(json_string_value(jfmatch)))) {
530 tr_debug("tr_cfg_parse_one_filter: Out of memory.");
534 tr_fspec_set_match(filt->lines[i]->specs[j], name);
538 talloc_steal(mem_ctx, filt);
541 talloc_free(tmp_ctx);
542 if (*rc!=TR_CFG_SUCCESS)
547 static TR_FILTER *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_CFG_RC *rc)
549 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
551 TR_FILTER *filt=NULL;
561 jfilt=json_object_get(jfilts, "tid_inbound");
563 filt=tr_cfg_parse_one_filter(tmp_ctx, jfilt, TR_FILTER_TYPE_TID_INCOMING, rc);
564 if (*rc!=TR_CFG_SUCCESS) {
565 tr_debug("tr_cfg_parse_filters: Error parsing tid_inbound filter.");
570 tr_debug("tr_cfg_parse_filters: Unknown filter types in filter block.");
578 if (*rc==TR_CFG_SUCCESS)
579 talloc_steal(mem_ctx, filt);
580 else if (filt!=NULL) {
585 talloc_free(tmp_ctx);
589 static TR_AAA_SERVER *tr_cfg_parse_one_aaa_server(TALLOC_CTX *mem_ctx, json_t *jaddr, TR_CFG_RC *rc)
591 TR_AAA_SERVER *aaa = NULL;
594 if ((!jaddr) || (!json_is_string(jaddr))) {
595 tr_debug("tr_cfg_parse_one_aaa_server: Bad parameters.");
596 *rc = TR_CFG_BAD_PARAMS;
600 name=tr_new_name(json_string_value(jaddr));
602 tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating hostname.");
607 aaa=tr_aaa_server_new(mem_ctx, name);
610 tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating AAA server.");
618 static TR_AAA_SERVER *tr_cfg_parse_aaa_servers(TALLOC_CTX *mem_ctx, json_t *jaaas, TR_CFG_RC *rc)
620 TALLOC_CTX *tmp_ctx=NULL;
621 TR_AAA_SERVER *aaa = NULL;
622 TR_AAA_SERVER *temp_aaa = NULL;
625 for (i = 0; i < json_array_size(jaaas); i++) {
626 /* rc gets set in here */
627 if (NULL == (temp_aaa = tr_cfg_parse_one_aaa_server(tmp_ctx, json_array_get(jaaas, i), rc))) {
628 talloc_free(tmp_ctx);
631 /* TBD -- IPv6 addresses */
632 // tr_debug("tr_cfg_parse_aaa_servers: Configuring AAA Server: ip_addr = %s.", inet_ntoa(temp_aaa->aaa_server_addr));
633 temp_aaa->next = aaa;
636 tr_debug("tr_cfg_parse_aaa_servers: Finished (rc=%d)", *rc);
638 for (temp_aaa=aaa; temp_aaa!=NULL; temp_aaa=temp_aaa->next)
639 talloc_steal(mem_ctx, temp_aaa);
640 talloc_free(tmp_ctx);
644 static TR_APC *tr_cfg_parse_one_apc(TALLOC_CTX *mem_ctx, json_t *japc, TR_CFG_RC *rc)
649 *rc = TR_CFG_SUCCESS; /* presume success */
651 if ((!japc) || (!rc) || (!json_is_string(japc))) {
652 tr_debug("tr_cfg_parse_one_apc: Bad parameters.");
654 *rc = TR_CFG_BAD_PARAMS;
658 apc=tr_apc_new(mem_ctx);
660 tr_debug("tr_cfg_parse_one_apc: Out of memory.");
665 name=tr_new_name(json_string_value(japc));
667 tr_debug("tr_cfg_parse_one_apc: No memory for APC name.");
672 tr_apc_set_id(apc, name); /* apc is now responsible for freeing the name */
677 static TR_APC *tr_cfg_parse_apcs(TALLOC_CTX *mem_ctx, json_t *japcs, TR_CFG_RC *rc)
679 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
681 TR_APC *new_apc=NULL;
683 TR_CFG_RC call_rc=TR_CFG_ERROR;
685 *rc = TR_CFG_SUCCESS; /* presume success */
687 if ((!japcs) || (!rc) || (!json_is_array(japcs))) {
688 tr_debug("tr_cfg_parse_one_apc: Bad parameters.");
690 *rc = TR_CFG_BAD_PARAMS;
694 for (ii=0; ii<json_array_size(japcs); ii++) {
695 new_apc=tr_cfg_parse_one_apc(tmp_ctx, json_array_get(japcs, ii), &call_rc);
696 if ((call_rc!=TR_CFG_SUCCESS) || (new_apc==NULL)) {
697 tr_debug("tr_cfg_parse_apcs: Error parsing APC %d.", ii+1);
701 tr_apc_add(apcs, new_apc);
704 talloc_steal(mem_ctx, apcs);
708 talloc_free(tmp_ctx);
712 static TR_NAME *tr_cfg_parse_name(TALLOC_CTX *mem_ctx, json_t *jname, TR_CFG_RC *rc)
717 if ((jname==NULL) || (!json_is_string(jname))) {
718 tr_err("tr_cfg_parse_name: name missing or not a string");
719 *rc=TR_CFG_BAD_PARAMS;
722 name=tr_new_name(json_string_value(jname));
724 tr_err("tr_cfg_parse_name: could not allocate name");
733 static int tr_cfg_parse_shared_config(json_t *jsc, TR_CFG_RC *rc)
735 const char *shared=NULL;
739 (!json_is_string(jsc)) ||
740 (NULL==(shared=json_string_value(jsc)))) {
741 *rc=TR_CFG_BAD_PARAMS;
745 if (0==strcmp(shared, "no"))
747 else if (0==strcmp(shared, "yes"))
750 /* any other value is an error */
751 tr_debug("tr_cfg_parse_shared_config: invalid shared_config value \"%s\" (should be \"yes\" or \"no\")",
757 static TR_REALM_ORIGIN tr_cfg_realm_origin(json_t *jrealm)
759 json_t *jremote=json_object_get(jrealm, "remote");
763 return TR_REALM_LOCAL;
764 if (!json_is_string(jremote)) {
765 tr_warning("tr_cfg_realm_origin: \"remote\" is not a string, assuming this is a local realm.");
766 return TR_REALM_LOCAL;
768 s=json_string_value(jremote);
769 if (strcasecmp(s, "yes")==0)
770 return TR_REALM_REMOTE_INCOMPLETE;
771 else if (strcasecmp(s, "no")!=0)
772 tr_warning("tr_cfg_realm_origin: \"remote\" is neither 'yes' nor 'no', assuming this is a local realm.");
774 return TR_REALM_LOCAL;
777 /* Parse the identity provider object from a realm and fill in the given TR_IDP_REALM. */
778 static TR_CFG_RC tr_cfg_parse_idp(TR_IDP_REALM *idp, json_t *jidp)
780 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
782 TR_AAA_SERVER *aaa=NULL;
783 TR_CFG_RC rc=TR_CFG_ERROR;
788 idp->shared_config=tr_cfg_parse_shared_config(json_object_get(jidp, "shared_config"), &rc);
789 if (rc!=TR_CFG_SUCCESS) {
790 tr_err("tr_cfg_parse_idp: missing or malformed shared_config specification");
795 apcs=tr_cfg_parse_apcs(tmp_ctx, json_object_get(jidp, "apcs"), &rc);
796 if ((rc!=TR_CFG_SUCCESS) || (apcs==NULL)) {
797 tr_err("tr_cfg_parse_idp: unable to parse APC");
802 aaa=tr_cfg_parse_aaa_servers(idp, json_object_get(jidp, "aaa_servers"), &rc);
803 if (rc!=TR_CFG_SUCCESS) {
804 tr_err("tr_cfg_parse_idp: unable to parse AAA servers");
809 tr_debug("tr_cfg_parse_idp: APC=\"%.*s\"",
813 /* done, fill in the idp structures */
815 talloc_steal(idp, apcs);
816 idp->aaa_servers=aaa;
820 if (rc!=TR_CFG_SUCCESS) {
824 tr_aaa_server_free(aaa);
827 talloc_free(tmp_ctx);
831 /* parses idp realm */
832 static TR_IDP_REALM *tr_cfg_parse_one_idp_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
834 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
835 TR_IDP_REALM *realm=NULL;
836 TR_CFG_RC call_rc=TR_CFG_ERROR;
838 *rc=TR_CFG_ERROR; /* default to error if not set */
840 if ((!jrealm) || (!rc)) {
841 tr_err("tr_cfg_parse_one_idp_realm: Bad parameters.");
843 *rc=TR_CFG_BAD_PARAMS;
847 if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) {
848 tr_err("tr_cfg_parse_one_idp_realm: could not allocate idp realm.");
853 realm->origin=tr_cfg_realm_origin(jrealm);
854 if (realm->origin!=TR_REALM_LOCAL) {
855 tr_debug("tr_cfg_parse_one_idp_realm: realm is remote, should not have full IdP info.");
860 /* must have a name */
861 realm->realm_id=tr_cfg_parse_name(realm,
862 json_object_get(jrealm, "realm"),
864 if ((call_rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) {
865 tr_err("tr_cfg_parse_one_idp_realm: could not parse realm name");
869 tr_debug("tr_cfg_parse_one_idp_realm: realm_id=\"%.*s\"",
870 realm->realm_id->len,
871 realm->realm_id->buf);
873 call_rc=tr_cfg_parse_idp(realm, json_object_get(jrealm, "identity_provider"));
874 if (call_rc!=TR_CFG_SUCCESS) {
875 tr_err("tr_cfg_parse_one_idp_realm: could not parse identity_provider.");
883 if (*rc==TR_CFG_SUCCESS)
884 talloc_steal(mem_ctx, realm);
890 talloc_free(tmp_ctx);
894 /* Determine whether the realm is an IDP realm */
895 static int tr_cfg_is_idp_realm(json_t *jrealm)
897 /* If a realm spec contains an identity_provider, it's an IDP realm. */
898 if (NULL != json_object_get(jrealm, "identity_provider"))
904 static TR_IDP_REALM *tr_cfg_parse_one_remote_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
906 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
907 TR_IDP_REALM *realm=talloc(mem_ctx, TR_IDP_REALM);
909 *rc=TR_CFG_ERROR; /* default to error if not set */
911 if ((!jrealm) || (!rc)) {
912 tr_err("tr_cfg_parse_one_remote_realm: Bad parameters.");
914 *rc=TR_CFG_BAD_PARAMS;
918 if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) {
919 tr_err("tr_cfg_parse_one_remote_realm: could not allocate idp realm.");
924 /* must have a name */
925 realm->realm_id=tr_cfg_parse_name(realm,
926 json_object_get(jrealm, "realm"),
928 if ((*rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) {
929 tr_err("tr_cfg_parse_one_remote_realm: could not parse realm name");
933 tr_debug("tr_cfg_parse_one_remote_realm: realm_id=\"%.*s\"",
934 realm->realm_id->len,
935 realm->realm_id->buf);
937 realm->origin=tr_cfg_realm_origin(jrealm);
941 if (*rc==TR_CFG_SUCCESS)
942 talloc_steal(mem_ctx, realm);
948 talloc_free(tmp_ctx);
952 static int tr_cfg_is_remote_realm(json_t *jrealm)
954 return (tr_cfg_realm_origin(jrealm)!=TR_REALM_LOCAL);
957 /* Parse any idp realms in the j_realms object. Ignores other realm types. */
958 static TR_IDP_REALM *tr_cfg_parse_idp_realms(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc)
960 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
961 TR_IDP_REALM *realms=NULL;
962 TR_IDP_REALM *new_realm=NULL;
963 json_t *this_jrealm=NULL;
967 if ((jrealms==NULL) || (!json_is_array(jrealms))) {
968 tr_err("tr_cfg_parse_idp_realms: realms not an array");
969 *rc=TR_CFG_BAD_PARAMS;
973 for (ii=0; ii<json_array_size(jrealms); ii++) {
974 this_jrealm=json_array_get(jrealms, ii);
975 if (tr_cfg_is_idp_realm(this_jrealm)) {
976 new_realm=tr_cfg_parse_one_idp_realm(tmp_ctx, this_jrealm, rc);
977 if ((*rc)!=TR_CFG_SUCCESS) {
978 tr_err("tr_cfg_parse_idp_realms: error decoding realm entry %d", ii+1);
982 tr_idp_realm_add(realms, new_realm);
983 } else if (tr_cfg_is_remote_realm(this_jrealm)) {
984 new_realm=tr_cfg_parse_one_remote_realm(tmp_ctx, this_jrealm, rc);
985 if ((*rc)!=TR_CFG_SUCCESS) {
986 tr_err("tr_cfg_parse_idp_realms: error decoding remote realm entry %d", ii+1);
990 tr_idp_realm_add(realms, new_realm);
995 talloc_steal(mem_ctx, realms);
998 talloc_free(tmp_ctx);
1002 static TR_GSS_NAMES *tr_cfg_parse_gss_names(TALLOC_CTX *mem_ctx, json_t *jgss_names, TR_CFG_RC *rc)
1004 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1005 TR_GSS_NAMES *gn=NULL;
1010 if ((rc==NULL) || (jgss_names==NULL)) {
1011 tr_err("tr_cfg_parse_gss_names: Bad parameters.");
1012 *rc=TR_CFG_BAD_PARAMS;
1016 if (!json_is_array(jgss_names)) {
1017 tr_err("tr_cfg_parse_gss_names: gss_names not an array.");
1022 gn=tr_gss_names_new(tmp_ctx);
1023 for (ii=0; ii<json_array_size(jgss_names); ii++) {
1024 jname=json_array_get(jgss_names, ii);
1025 if (!json_is_string(jname)) {
1026 tr_err("tr_cfg_parse_gss_names: Encountered non-string gss name.");
1031 name=tr_new_name(json_string_value(jname));
1033 tr_err("tr_cfg_parse_gss_names: Out of memory allocating gss name.");
1038 if (tr_gss_names_add(gn, name)!=0) {
1040 tr_err("tr_cfg_parse_gss_names: Unable to add gss name to RP client.");
1046 talloc_steal(mem_ctx, gn);
1050 talloc_free(tmp_ctx);
1051 if ((*rc!=TR_CFG_SUCCESS) && (gn!=NULL))
1056 /* default filter accepts realm and *.realm */
1057 static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_CFG_RC *rc)
1059 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1060 TR_FILTER *filt=NULL;
1061 TR_CONSTRAINT *cons=NULL;
1063 TR_NAME *n_prefix=tr_new_name("*.");
1064 TR_NAME *n_rp_realm_1=tr_new_name("rp_realm");
1065 TR_NAME *n_rp_realm_2=tr_new_name("rp_realm");
1066 TR_NAME *n_domain=tr_new_name("domain");
1067 TR_NAME *n_realm=tr_new_name("realm");
1070 if ((realm==NULL) || (rc==NULL)) {
1071 tr_debug("tr_cfg_default_filter: invalid arguments.");
1073 *rc=TR_CFG_BAD_PARAMS;
1077 if ((n_prefix==NULL) ||
1078 (n_rp_realm_1==NULL) ||
1079 (n_rp_realm_2==NULL) ||
1082 tr_debug("tr_cfg_default_filter: unable to allocate names.");
1087 filt=tr_filter_new(tmp_ctx);
1089 tr_debug("tr_cfg_default_filter: could not allocate filter.");
1093 tr_filter_set_type(filt, TR_FILTER_TYPE_TID_INCOMING);
1094 filt->lines[0]=tr_fline_new(filt);
1095 if (filt->lines[0]==NULL) {
1096 tr_debug("tr_cfg_default_filter: could not allocate filter line.");
1101 filt->lines[0]->action=TR_FILTER_ACTION_ACCEPT;
1102 filt->lines[0]->specs[0]=tr_fspec_new(filt->lines[0]);
1103 filt->lines[0]->specs[0]->field=n_rp_realm_1;
1104 n_rp_realm_1=NULL; /* we don't own this name any more */
1106 name=tr_dup_name(realm);
1108 tr_debug("tr_cfg_default_filter: could not allocate realm name.");
1112 tr_fspec_set_match(filt->lines[0]->specs[0], name);
1113 name=NULL; /* we no longer own the name */
1115 /* now do the wildcard name */
1116 filt->lines[0]->specs[1]=tr_fspec_new(filt->lines[0]);
1117 filt->lines[0]->specs[1]->field=n_rp_realm_2;
1118 n_rp_realm_2=NULL; /* we don't own this name any more */
1120 if (NULL==(name=tr_name_cat(n_prefix, realm))) {
1121 tr_debug("tr_cfg_default_filter: could not allocate wildcard realm name.");
1126 tr_fspec_set_match(filt->lines[0]->specs[1], name);
1127 name=NULL; /* we no longer own the name */
1129 /* domain constraint */
1130 if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
1131 tr_debug("tr_cfg_default_filter: could not allocate domain constraint.");
1136 cons->type=n_domain;
1137 n_domain=NULL; /* belongs to the constraint now */
1138 name=tr_dup_name(realm);
1140 tr_debug("tr_cfg_default_filter: could not allocate realm name for domain constraint.");
1144 cons->matches[0]=name;
1145 name=tr_name_cat(n_prefix, realm);
1147 tr_debug("tr_cfg_default_filter: could not allocate wildcard realm name for domain constraint.");
1151 cons->matches[1]=name;
1153 filt->lines[0]->domain_cons=cons;
1156 /* realm constraint */
1157 if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
1158 tr_debug("tr_cfg_default_filter: could not allocate realm constraint.");
1164 n_realm=NULL; /* belongs to the constraint now */
1165 name=tr_dup_name(realm);
1167 tr_debug("tr_cfg_default_filter: could not allocate realm name for realm constraint.");
1171 cons->matches[0]=name;
1172 name=tr_name_cat(n_prefix, realm);
1174 tr_debug("tr_cfg_default_filter: could not allocate wildcard realm name for realm constraint.");
1178 cons->matches[1]=name;
1180 filt->lines[0]->realm_cons=cons;
1182 talloc_steal(mem_ctx, filt);
1184 talloc_free(tmp_ctx);
1186 if (*rc!=TR_CFG_SUCCESS)
1190 tr_free_name(n_prefix);
1191 if (n_rp_realm_1!=NULL)
1192 tr_free_name(n_rp_realm_1);
1193 if (n_rp_realm_2!=NULL)
1194 tr_free_name(n_rp_realm_2);
1196 tr_free_name(n_realm);
1198 tr_free_name(n_domain);
1205 /* parses rp client */
1206 static TR_RP_CLIENT *tr_cfg_parse_one_rp_client(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
1208 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1209 TR_RP_CLIENT *client=NULL;
1210 TR_CFG_RC call_rc=TR_CFG_ERROR;
1211 TR_FILTER *new_filt=NULL;
1212 TR_NAME *realm=NULL;
1214 json_t *jrealm_id=NULL;
1216 *rc=TR_CFG_ERROR; /* default to error if not set */
1218 if ((!jrealm) || (!rc)) {
1219 tr_err("tr_cfg_parse_one_rp_client: Bad parameters.");
1221 *rc=TR_CFG_BAD_PARAMS;
1225 if ((NULL==(jrealm_id=json_object_get(jrealm, "realm"))) || (!json_is_string(jrealm_id))) {
1226 tr_debug("tr_cfg_parse_one_rp_client: no realm ID found.");
1227 *rc=TR_CFG_BAD_PARAMS;
1231 tr_debug("tr_cfg_parse_one_rp_client: realm_id=\"%s\"", json_string_value(jrealm_id));
1232 realm=tr_new_name(json_string_value(jrealm_id));
1234 tr_err("tr_cfg_parse_one_rp_client: could not allocate realm ID.");
1239 if (NULL==(client=tr_rp_client_new(tmp_ctx))) {
1240 tr_err("tr_cfg_parse_one_rp_client: could not allocate rp client.");
1245 client->gss_names=tr_cfg_parse_gss_names(client, json_object_get(jrealm, "gss_names"), &call_rc);
1247 if (call_rc!=TR_CFG_SUCCESS) {
1248 tr_err("tr_cfg_parse_one_rp_client: could not parse gss_names.");
1254 jfilt=json_object_get(jrealm, "filters");
1256 new_filt=tr_cfg_parse_filters(tmp_ctx, jfilt, &call_rc);
1257 if (call_rc!=TR_CFG_SUCCESS) {
1258 tr_err("tr_cfg_parse_one_rp_client: could not parse filters.");
1263 tr_debug("tr_cfg_parse_one_rp_client: no filters specified, using default filters.");
1264 new_filt=tr_cfg_default_filter(tmp_ctx, realm, &call_rc);
1265 if (call_rc!=TR_CFG_SUCCESS) {
1266 tr_err("tr_cfg_parse_one_rp_client: could not set default filters.");
1272 tr_rp_client_set_filter(client, new_filt);
1277 tr_free_name(realm);
1279 if (*rc==TR_CFG_SUCCESS)
1280 talloc_steal(mem_ctx, client);
1282 talloc_free(client);
1286 talloc_free(tmp_ctx);
1290 /* Determine whether the realm is an RP realm */
1291 static int tr_cfg_is_rp_realm(json_t *jrealm)
1293 /* Check that we have a gss name. */
1294 if (NULL != json_object_get(jrealm, "gss_names"))
1300 /* Parse any rp clients in the j_realms object. Ignores other realms. */
1301 static TR_RP_CLIENT *tr_cfg_parse_rp_clients(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc)
1303 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1304 TR_RP_CLIENT *clients=NULL;
1305 TR_RP_CLIENT *new_client=NULL;
1306 json_t *this_jrealm=NULL;
1310 if ((jrealms==NULL) || (!json_is_array(jrealms))) {
1311 tr_err("tr_cfg_parse_rp_clients: realms not an array");
1312 *rc=TR_CFG_BAD_PARAMS;
1316 for (ii=0; ii<json_array_size(jrealms); ii++) {
1317 this_jrealm=json_array_get(jrealms, ii);
1318 if (tr_cfg_is_rp_realm(this_jrealm)) {
1319 new_client=tr_cfg_parse_one_rp_client(tmp_ctx, this_jrealm, rc);
1320 if ((*rc)!=TR_CFG_SUCCESS) {
1321 tr_err("tr_cfg_parse_rp_clients: error decoding realm entry %d", ii+1);
1325 tr_rp_client_add(clients, new_client);
1330 talloc_steal(mem_ctx, clients);
1333 talloc_free(tmp_ctx);
1337 /* takes a talloc context, but currently does not use it */
1338 static TR_NAME *tr_cfg_parse_org_name(TALLOC_CTX *mem_ctx, json_t *j_org, TR_CFG_RC *rc)
1342 if ((j_org==NULL) || (rc==NULL) || (!json_is_string(j_org))) {
1343 tr_debug("tr_cfg_parse_org_name: Bad parameters.");
1345 *rc = TR_CFG_BAD_PARAMS; /* fill in return value if we can */
1349 name=tr_new_name(json_string_value(j_org));
1358 /* TODO: are we using this? JLR */
1359 /* Update the community information with data from a new batch of IDP realms.
1360 * May partially add realms if there is a failure, no guarantees.
1361 * Call like comms=tr_comm_idp_update(comms, new_realms, &rc) */
1362 static TR_COMM *tr_cfg_comm_idp_update(TALLOC_CTX *mem_ctx,
1363 TR_COMM_TABLE *ctab,
1364 TR_IDP_REALM *new_realms,
1367 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1368 TR_COMM *comm=NULL; /* community looked up in comms table */
1369 TR_COMM *new_comms=NULL; /* new communities as we create them */
1370 TR_IDP_REALM *realm=NULL;
1371 TR_APC *apc=NULL; /* apc of one realm */
1374 *rc=TR_CFG_BAD_PARAMS;
1378 /* start with an empty list communities, then fill that in */
1379 for (realm=new_realms; realm!=NULL; realm=realm->next) {
1380 for (apc=realm->apcs; apc!=NULL; apc=apc->next) {
1381 comm=tr_comm_lookup(comms, apc->id);
1383 comm=tr_comm_new(tmp_ctx);
1385 tr_debug("tr_cfg_comm_idp_update: unable to allocate new community.");
1389 /* fill in the community with info */
1390 comm->type=TR_COMM_APC; /* realms added this way are in APCs */
1391 comm->expiration_interval=TR_DEFAULT_APC_EXPIRATION_INTERVAL;
1392 tr_comm_set_id(comm, tr_dup_name(apc->id));
1393 tr_comm_add_idp_realm(comm, realm);
1394 tr_comm_add(new_comms, comm);
1396 /* add this realm to the comm */
1397 tr_comm_add_idp_realm(comm, realm);
1402 /* we successfully built a list, add it to the other list */
1403 tr_comm_add(comms, new_comms);
1404 talloc_steal(mem_ctx, comms);
1406 talloc_free(tmp_ctx);
1411 static TR_CFG_RC tr_cfg_parse_one_local_org(TR_CFG *trc, json_t *jlorg)
1413 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1414 TR_CFG_RC retval=TR_CFG_ERROR; /* our return code */
1415 TR_CFG_RC rc=TR_CFG_ERROR; /* return code from functions we call */
1416 TR_NAME *org_name=NULL;
1418 json_t *j_realms=NULL;
1419 TR_IDP_REALM *new_idp_realms=NULL;
1420 TR_RP_CLIENT *new_rp_clients=NULL;
1422 tr_debug("tr_cfg_parse_one_local_org: parsing local organization");
1424 /* get organization_name (optional) */
1425 if (NULL==(j_org=json_object_get(jlorg, "organization_name"))) {
1426 tr_debug("tr_cfg_parse_one_local_org: organization_name unspecified");
1428 org_name=tr_cfg_parse_org_name(tmp_ctx, j_org, &rc);
1429 if (rc==TR_CFG_SUCCESS) {
1430 tr_debug("tr_cfg_parse_one_local_org: organization_name=\"%.*s\"",
1433 /* we don't actually do anything with this, but we could */
1434 tr_free_name(org_name);
1439 /* Now get realms. Allow this to be missing; even though that is a pointless organization entry,
1440 * it's harmless. Report a warning because that might be unintentional. */
1441 if (NULL==(j_realms=json_object_get(jlorg, "realms"))) {
1442 tr_warning("tr_cfg_parse_one_local_org: warning - no realms in this local organization");
1444 /* Allocate in the tmp_ctx so these will be cleaned up if we do not complete successfully. */
1445 new_idp_realms=tr_cfg_parse_idp_realms(tmp_ctx, j_realms, &rc);
1446 if (rc!=TR_CFG_SUCCESS)
1449 new_rp_clients=tr_cfg_parse_rp_clients(tmp_ctx, j_realms, &rc);
1450 if (rc!=TR_CFG_SUCCESS)
1453 retval=TR_CFG_SUCCESS;
1456 /* if we succeeded, link things to the configuration and move out of tmp context */
1457 if (retval==TR_CFG_SUCCESS) {
1458 if (new_idp_realms!=NULL) {
1459 tr_idp_realm_add(trc->idp_realms, new_idp_realms); /* fixes talloc contexts except for head*/
1460 talloc_steal(trc, trc->idp_realms); /* make sure the head is in the right context */
1463 if (new_rp_clients!=NULL) {
1464 tr_rp_client_add(trc->rp_clients, new_rp_clients); /* fixes talloc contexts */
1465 talloc_steal(trc, trc->rp_clients); /* make sure head is in the right context */
1469 talloc_free(tmp_ctx);
1473 /* Parse local organizations if present. Returns success if there are none. On failure, the configuration is unreliable. */
1474 static TR_CFG_RC tr_cfg_parse_local_orgs(TR_CFG *trc, json_t *jcfg)
1476 json_t *jlocorgs=NULL;
1479 jlocorgs=json_object_get(jcfg, "local_organizations");
1481 return TR_CFG_SUCCESS;
1483 if (!json_is_array(jlocorgs)) {
1484 tr_err("tr_cfg_parse_local_orgs: local_organizations is not an array.");
1485 return TR_CFG_NOPARSE;
1488 for (ii=0; ii<json_array_size(jlocorgs); ii++) {
1489 if (tr_cfg_parse_one_local_org(trc, json_array_get(jlocorgs, ii))!=TR_CFG_SUCCESS) {
1490 tr_err("tr_cfg_parse_local_orgs: error parsing local_organization %d.", ii+1);
1491 return TR_CFG_NOPARSE;
1495 return TR_CFG_SUCCESS;
1498 static TR_CFG_RC tr_cfg_parse_one_peer_org(TR_CFG *trc, json_t *jporg)
1500 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1504 TRP_PEER *new_peer=NULL;
1505 TR_GSS_NAMES *names=NULL;
1506 TR_CFG_RC rc=TR_CFG_ERROR;
1508 jhost=json_object_get(jporg, "hostname");
1509 jport=json_object_get(jporg, "port");
1510 jgss=json_object_get(jporg, "gss_names");
1512 if ((jhost==NULL) || (!json_is_string(jhost))) {
1513 tr_err("tr_cfg_parse_one_peer_org: hostname not specified or not a string.");
1518 if ((jport!=NULL) && (!json_is_number(jport))) {
1519 /* note that not specifying the port is allowed, but if set it must be a number */
1520 tr_err("tr_cfg_parse_one_peer_org: port is not a number.");
1525 if ((jgss==NULL) || (!json_is_array(jgss))) {
1526 tr_err("tr_cfg_parse_one_peer_org: gss_names not specified or not an array.");
1531 new_peer=trp_peer_new(tmp_ctx);
1532 if (new_peer==NULL) {
1533 tr_err("tr_cfg_parse_one_peer_org: could not allocate new peer.");
1538 trp_peer_set_server(new_peer, json_string_value(jhost));
1540 trp_peer_set_port(new_peer, TRP_PORT);
1542 trp_peer_set_port(new_peer, json_integer_value(jport));
1544 names=tr_cfg_parse_gss_names(tmp_ctx, jgss, &rc);
1545 if (rc!=TR_CFG_SUCCESS) {
1546 tr_err("tr_cfg_parse_one_peer_org: unable to parse gss names.");
1550 trp_peer_set_gss_names(new_peer, names);
1553 trp_ptable_add(trc->peers, new_peer);
1557 talloc_free(tmp_ctx);
1561 /* Parse peer organizations, if present. Returns success if there are none. */
1562 static TR_CFG_RC tr_cfg_parse_peer_orgs(TR_CFG *trc, json_t *jcfg)
1564 json_t *jpeerorgs=NULL;
1567 jpeerorgs=json_object_get(jcfg, "peer_organizations");
1568 if (jpeerorgs==NULL)
1569 return TR_CFG_SUCCESS;
1571 if (!json_is_array(jpeerorgs)) {
1572 tr_err("tr_cfg_parse_peer_orgs: peer_organizations is not an array.");
1573 return TR_CFG_NOPARSE;
1576 for (ii=0; ii<json_array_size(jpeerorgs); ii++) {
1577 if (tr_cfg_parse_one_peer_org(trc, json_array_get(jpeerorgs, ii))!=TR_CFG_SUCCESS) {
1578 tr_err("tr_cfg_parse_peer_orgs: error parsing peer_organization %d.", ii+1);
1579 return TR_CFG_NOPARSE;
1583 return TR_CFG_SUCCESS;
1586 static TR_CFG_RC tr_cfg_parse_default_servers (TR_CFG *trc, json_t *jcfg)
1588 json_t *jdss = NULL;
1589 TR_CFG_RC rc = TR_CFG_SUCCESS;
1590 TR_AAA_SERVER *ds = NULL;
1593 if ((!trc) || (!jcfg))
1594 return TR_CFG_BAD_PARAMS;
1596 /* If there are default servers, store them */
1597 if ((NULL != (jdss = json_object_get(jcfg, "default_servers"))) &&
1598 (json_is_array(jdss)) &&
1599 (0 < json_array_size(jdss))) {
1601 for (i = 0; i < json_array_size(jdss); i++) {
1602 if (NULL == (ds = tr_cfg_parse_one_aaa_server(trc,
1603 json_array_get(jdss, i),
1607 tr_debug("tr_cfg_parse_default_servers: Default server configured: %s", ds->hostname->buf);
1608 ds->next = trc->default_servers;
1609 trc->default_servers = ds;
1613 tr_debug("tr_cfg_parse_default_servers: Finished (rc=%d)", rc);
1617 static void tr_cfg_parse_comm_idps(TR_CFG *trc, json_t *jidps, TR_COMM *comm, TR_CFG_RC *rc)
1619 TR_IDP_REALM *found_idp=NULL;
1624 (!json_is_array(jidps))) {
1626 *rc = TR_CFG_BAD_PARAMS;
1630 for (i=0; i < json_array_size(jidps); i++) {
1631 found_idp=tr_cfg_find_idp(trc,
1632 tr_new_name((char *)json_string_value(json_array_get(jidps, i))),
1634 if ((found_idp==NULL) || (*rc!=TR_CFG_SUCCESS)) {
1635 tr_debug("tr_cfg_parse_comm_idps: Unknown IDP %s.",
1636 (char *)json_string_value(json_array_get(jidps, i)));
1640 tr_comm_add_idp_realm(trc->comms, comm, found_idp, NULL, NULL); /* no provenance, never expires */
1647 static void tr_cfg_parse_comm_rps(TR_CFG *trc, json_t *jrps, TR_COMM *comm, TR_CFG_RC *rc)
1649 TR_RP_REALM *found_rp=NULL;
1650 TR_RP_REALM *new_rp=NULL;
1651 TR_NAME *rp_name=NULL;
1657 (!json_is_array(jrps))) {
1659 *rc = TR_CFG_BAD_PARAMS;
1663 for (ii=0; ii<json_array_size(jrps); ii++) {
1664 /* get the RP name as a string */
1665 s=json_string_value(json_array_get(jrps, ii));
1667 tr_notice("tr_cfg_parse_comm_rps: null RP found in community %.*s, ignoring.",
1668 tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
1672 /* convert string to TR_NAME */
1673 rp_name=tr_new_name(s);
1674 if (rp_name==NULL) {
1675 tr_err("tr_cfg_parse_comm_rps: unable to allocate RP name for %s in community %.*s.",
1676 s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
1679 /* see if we already have this RP in this community */
1680 found_rp=tr_comm_find_rp(trc->comms, comm, rp_name);
1681 if (found_rp!=NULL) {
1682 tr_notice("tr_cfg_parse_comm_rps: RP %s repeated in community %.*s.",
1683 s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
1684 tr_free_name(rp_name);
1688 /* Add the RP to the community, first see if we have the RP in any community */
1689 found_rp=tr_rp_realm_lookup(trc->rp_realms, rp_name);
1690 if (found_rp!=NULL) {
1691 tr_debug("tr_cfg_parse_comm_rps: RP realm %s already exists.", s);
1692 new_rp=found_rp; /* use it rather than creating a new realm record */
1694 new_rp=tr_rp_realm_new(NULL);
1696 tr_err("tr_cfg_parse_comm_rps: unable to allocate RP record for %s in community %.*s.",
1697 s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
1699 tr_debug("tr_cfg_parse_comm_rps: setting name to %s", rp_name->buf);
1700 tr_rp_realm_set_id(new_rp, rp_name);
1701 rp_name=NULL; /* rp_name no longer belongs to us */
1702 tr_rp_realm_add(trc->rp_realms, new_rp);
1704 tr_comm_add_rp_realm(trc->comms, comm, new_rp, NULL, NULL);
1708 static TR_COMM *tr_cfg_parse_one_comm (TALLOC_CTX *mem_ctx, TR_CFG *trc, json_t *jcomm, TR_CFG_RC *rc)
1710 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1711 TR_COMM *comm = NULL;
1713 json_t *jtype = NULL;
1714 json_t *japcs = NULL;
1715 json_t *jidps = NULL;
1716 json_t *jrps = NULL;
1718 if ((!trc) || (!jcomm) || (!rc)) {
1719 tr_debug("tr_cfg_parse_one_comm: Bad parameters.");
1721 *rc = TR_CFG_BAD_PARAMS;
1725 comm=tr_comm_new(tmp_ctx);
1727 tr_crit("tr_cfg_parse_one_comm: Out of memory.");
1733 if ((NULL == (jid = json_object_get(jcomm, "community_id"))) ||
1734 (!json_is_string(jid)) ||
1735 (NULL == (jtype = json_object_get(jcomm, "type"))) ||
1736 (!json_is_string(jtype)) ||
1737 (NULL == (japcs = json_object_get(jcomm, "apcs"))) ||
1738 (!json_is_array(japcs)) ||
1739 (NULL == (jidps = json_object_get(jcomm, "idp_realms"))) ||
1740 (!json_is_array(jidps)) ||
1741 (NULL == (jrps = json_object_get(jcomm, "rp_realms"))) ||
1742 (!json_is_array(jrps))) {
1743 tr_debug("tr_cfg_parse_one_comm: Error parsing Communities configuration.");
1744 *rc = TR_CFG_NOPARSE;
1749 tr_comm_set_id(comm, tr_new_name(json_string_value(jid)));
1750 if (NULL == tr_comm_get_id(comm)) {
1751 tr_debug("tr_cfg_parse_one_comm: No memory for community id.");
1757 if (0 == strcmp(json_string_value(jtype), "apc")) {
1758 comm->type = TR_COMM_APC;
1759 } else if (0 == strcmp(json_string_value(jtype), "coi")) {
1760 comm->type = TR_COMM_COI;
1761 if (NULL == (comm->apcs = tr_cfg_parse_apcs(trc, japcs, rc))) {
1762 tr_debug("tr_cfg_parse_one_comm: Can't parse APCs for COI %s.",
1763 tr_comm_get_id(comm)->buf);
1768 tr_debug("tr_cfg_parse_one_comm: Invalid community type, comm = %s, type = %s",
1769 tr_comm_get_id(comm)->buf, json_string_value(jtype));
1770 *rc = TR_CFG_NOPARSE;
1775 tr_cfg_parse_comm_idps(trc, jidps, comm, rc);
1776 if (TR_CFG_SUCCESS != *rc) {
1777 tr_debug("tr_cfg_parse_one_comm: Can't parse IDP realms for comm %s.",
1778 tr_comm_get_id(comm)->buf);
1783 tr_cfg_parse_comm_rps(trc, jrps, comm, rc);
1784 if (TR_CFG_SUCCESS != *rc) {
1785 tr_debug("tr_cfg_parse_one_comm: Can't parse RP realms for comm %s .",
1786 tr_comm_get_id(comm)->buf);
1791 if (TR_COMM_APC == comm->type) {
1792 json_t *jexpire = json_object_get(jcomm, "expiration_interval");
1793 comm->expiration_interval = 43200; /*30 days*/
1795 if (!json_is_integer(jexpire)) {
1796 fprintf(stderr, "tr_parse_one_comm: expiration_interval is not an integer\n");
1800 comm->expiration_interval = json_integer_value(jexpire);
1801 if (comm->expiration_interval <= 10)
1802 comm->expiration_interval = 11; /* Freeradius waits 10 minutes between successful TR queries*/
1803 if (comm->expiration_interval > 129600) /* 90 days*/
1804 comm->expiration_interval = 129600;
1810 talloc_steal(mem_ctx, comm);
1811 talloc_free(tmp_ctx);
1815 static TR_CFG_RC tr_cfg_parse_comms (TR_CFG *trc, json_t *jcfg)
1817 json_t *jcomms = NULL;
1818 TR_CFG_RC rc = TR_CFG_SUCCESS;
1819 TR_COMM *comm = NULL;
1822 if ((!trc) || (!jcfg)) {
1823 tr_debug("tr_cfg_parse_comms: Bad Parameters.");
1824 return TR_CFG_BAD_PARAMS;
1827 if (NULL != (jcomms = json_object_get(jcfg, "communities"))) {
1828 if (!json_is_array(jcomms)) {
1829 return TR_CFG_NOPARSE;
1832 for (i = 0; i < json_array_size(jcomms); i++) {
1833 if (NULL == (comm = tr_cfg_parse_one_comm(NULL, /* TODO: use a talloc context */
1835 json_array_get(jcomms, i),
1839 tr_debug("tr_cfg_parse_comms: Community configured: %s.",
1840 tr_comm_get_id(comm)->buf);
1842 tr_comm_table_add_comm(trc->comms, comm);
1845 tr_debug("tr_cfg_parse_comms: Finished (rc=%d)", rc);
1849 TR_CFG_RC tr_cfg_validate(TR_CFG *trc)
1851 TR_CFG_RC rc = TR_CFG_SUCCESS;
1854 return TR_CFG_BAD_PARAMS;
1856 if ((NULL == trc->internal)||
1857 (NULL == trc->internal->hostname)) {
1858 tr_debug("tr_cfg_validate: Error: No internal configuration, or no hostname.");
1862 if (NULL == trc->rp_clients) {
1863 tr_debug("tr_cfg_validate: Error: No RP Clients configured");
1867 if (0==tr_comm_table_size(trc->comms)) {
1868 tr_debug("tr_cfg_validate: Error: No Communities configured");
1872 if ((NULL == trc->default_servers) && (NULL == trc->idp_realms)) {
1873 tr_debug("tr_cfg_validate: Error: No default servers or IDPs configured.");
1880 /* Join two paths and return a pointer to the result. This should be freed
1881 * via talloc_free. Returns NULL on failure. */
1882 static char *join_paths(TALLOC_CTX *mem_ctx, const char *p1, const char *p2)
1884 return talloc_asprintf(mem_ctx, "%s/%s", p1, p2); /* returns NULL on a failure */
1887 static void tr_cfg_log_json_error(const char *label, json_error_t *rc)
1889 tr_debug("%s: JSON parse error on line %d: %s",
1895 TR_CFG_RC tr_cfg_parse_one_config_file(TR_CFG *cfg, const char *file_with_path)
1901 if (NULL==(jcfg=json_load_file(file_with_path,
1902 JSON_DISABLE_EOF_CHECK, &rc))) {
1903 tr_debug("tr_cfg_parse_one_config_file: Error parsing config file %s.",
1905 tr_cfg_log_json_error("tr_cfg_parse_one_config_file", &rc);
1906 return TR_CFG_NOPARSE;
1909 // Look for serial number and log it if it exists
1910 if (NULL!=(jser=json_object_get(jcfg, "serial_number"))) {
1911 if (json_is_number(jser)) {
1912 tr_notice("tr_parse_one_config_file: Attempting to load revision %" JSON_INTEGER_FORMAT " of '%s'.",
1913 json_integer_value(jser),
1918 if ((TR_CFG_SUCCESS != tr_cfg_parse_internal(cfg, jcfg)) ||
1919 (TR_CFG_SUCCESS != tr_cfg_parse_local_orgs(cfg, jcfg)) ||
1920 (TR_CFG_SUCCESS != tr_cfg_parse_peer_orgs(cfg, jcfg)) ||
1921 (TR_CFG_SUCCESS != tr_cfg_parse_default_servers(cfg, jcfg)) ||
1922 (TR_CFG_SUCCESS != tr_cfg_parse_comms(cfg, jcfg)))
1923 return TR_CFG_ERROR;
1925 return TR_CFG_SUCCESS;
1928 /* Reads configuration files in config_dir ("" or "./" will use the current directory). */
1929 TR_CFG_RC tr_parse_config(TR_CFG_MGR *cfg_mgr, const char *config_dir, int n, struct dirent **cfg_files)
1931 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1932 char *file_with_path;
1934 TR_CFG_RC cfg_rc=TR_CFG_ERROR;
1936 if ((!cfg_mgr) || (!cfg_files) || (n<=0)) {
1937 cfg_rc=TR_CFG_BAD_PARAMS;
1941 if (cfg_mgr->new != NULL)
1942 tr_cfg_free(cfg_mgr->new);
1943 cfg_mgr->new=tr_cfg_new(tmp_ctx); /* belongs to the temporary context for now */
1944 if (cfg_mgr->new == NULL) {
1945 cfg_rc=TR_CFG_NOMEM;
1949 cfg_mgr->new->peers=trp_ptable_new(cfg_mgr);
1951 /* Parse configuration information from each config file */
1952 for (ii=0; ii<n; ii++) {
1953 file_with_path=join_paths(tmp_ctx, config_dir, cfg_files[ii]->d_name); /* must free result with talloc_free */
1954 if(file_with_path == NULL) {
1955 tr_crit("tr_parse_config: error joining path.");
1956 cfg_rc=TR_CFG_NOMEM;
1959 tr_debug("tr_parse_config: Parsing %s.", cfg_files[ii]->d_name); /* print the filename without the path */
1960 cfg_rc=tr_cfg_parse_one_config_file(cfg_mgr->new, file_with_path);
1961 if (cfg_rc!=TR_CFG_SUCCESS) {
1962 tr_crit("tr_parse_config: Error parsing %s", file_with_path);
1965 talloc_free(file_with_path); /* done with filename */
1968 /* make sure we got a complete, consistent configuration */
1969 if (TR_CFG_SUCCESS != tr_cfg_validate(cfg_mgr->new)) {
1970 tr_err("tr_parse_config: Error: INVALID CONFIGURATION");
1971 cfg_rc=TR_CFG_ERROR;
1976 talloc_steal(cfg_mgr, cfg_mgr->new); /* hand this over to the cfg_mgr context */
1977 cfg_rc=TR_CFG_SUCCESS;
1980 talloc_free(tmp_ctx);
1984 TR_IDP_REALM *tr_cfg_find_idp (TR_CFG *tr_cfg, TR_NAME *idp_id, TR_CFG_RC *rc)
1987 TR_IDP_REALM *cfg_idp;
1989 if ((!tr_cfg) || (!idp_id)) {
1991 *rc = TR_CFG_BAD_PARAMS;
1995 for (cfg_idp = tr_cfg->idp_realms; NULL != cfg_idp; cfg_idp = cfg_idp->next) {
1996 if (!tr_name_cmp (idp_id, cfg_idp->realm_id)) {
1997 tr_debug("tr_cfg_find_idp: Found %s.", idp_id->buf);
2001 /* if we didn't find one, return NULL */
2005 TR_RP_CLIENT *tr_cfg_find_rp (TR_CFG *tr_cfg, TR_NAME *rp_gss, TR_CFG_RC *rc)
2007 TR_RP_CLIENT *cfg_rp;
2009 if ((!tr_cfg) || (!rp_gss)) {
2011 *rc = TR_CFG_BAD_PARAMS;
2015 for (cfg_rp = tr_cfg->rp_clients; NULL != cfg_rp; cfg_rp = cfg_rp->next) {
2016 if (tr_gss_names_matches(cfg_rp->gss_names, rp_gss)) {
2017 tr_debug("tr_cfg_find_rp: Found %s.", rp_gss->buf);
2021 /* if we didn't find one, return NULL */
2025 static int is_cfg_file(const struct dirent *dent) {
2028 /* Only accept filenames ending in ".cfg" and starting with a character
2029 * other than an ASCII '.' */
2031 /* filename must be at least 4 characters long to be acceptable */
2032 n=strlen(dent->d_name);
2037 /* filename must not start with '.' */
2038 if ('.' == dent->d_name[0]) {
2042 /* If the above passed and the last four characters of the filename are .cfg, accept.
2043 * (n.b., assumes an earlier test checked that the name is >= 4 chars long.) */
2044 if (0 == strcmp(&(dent->d_name[n-4]), ".cfg")) {
2048 /* otherwise, return false. */
2052 /* Find configuration files in a particular directory. Returns the
2053 * number of entries found, 0 if none are found, or <0 for some
2054 * errors. If n>=0, the cfg_files parameter will contain a newly
2055 * allocated array of pointers to struct dirent entries, as returned
2056 * by scandir(). These can be freed with tr_free_config_file_list().
2058 int tr_find_config_files (const char *config_dir, struct dirent ***cfg_files) {
2061 n = scandir(config_dir, cfg_files, is_cfg_file, alphasort);
2065 tr_debug("tr_find_config: scandir error trying to scan %s.", config_dir);
2071 /* Free memory allocated for configuration file list returned from tr_find_config_files().
2072 * This can be called regardless of the return value of tr_find_config_values(). */
2073 void tr_free_config_file_list(int n, struct dirent ***cfg_files) {
2076 /* if n < 0, then scandir did not allocate anything because it failed */
2077 if((n>=0) && (*cfg_files != NULL)) {
2078 for(ii=0; ii<n; ii++) {
2079 free((*cfg_files)[ii]);
2081 free(*cfg_files); /* safe even if n==0 */
2082 *cfg_files=NULL; /* this will help prevent accidentally freeing twice */