X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=common%2Ftr_config.c;h=dc6f77b0edf2cd84ffb910bd9450904bbbbdd95c;hb=3d175240ef0a8e0b465994e881ef98548a39091a;hp=fbd5027bc86ee334013152911bc7638125cf2b98;hpb=bfdfcb31f9a420bf9507260ce1e5a079540b3d2e;p=trust_router.git diff --git a/common/tr_config.c b/common/tr_config.c index fbd5027..dc6f77b 100644 --- a/common/tr_config.c +++ b/common/tr_config.c @@ -38,448 +38,492 @@ #include #include +#include +#include #include +#include #include -#include #include #include +#include +#include +#include -void tr_print_config (FILE *stream, TR_CFG *cfg) { - fprintf(stream, "tr_print_config: Not yet implemented."); - return; -} +#if JANSSON_VERSION_HEX < 0x020500 +#include "jansson_iterators.h" +#endif -void tr_cfg_free (TR_CFG *cfg) { - talloc_free(cfg); - return; +void tr_print_config (TR_CFG *cfg) { + tr_notice("tr_print_config: Logging running trust router configuration."); + tr_print_comms(cfg->ctable); } -TR_CFG_RC tr_apply_new_config (TR_INSTANCE *tr) { - if (!tr) - return TR_CFG_BAD_PARAMS; - - if (tr->active_cfg) - tr_cfg_free(tr->active_cfg); +void tr_print_comms (TR_COMM_TABLE *ctab) +{ + TR_COMM *comm = NULL; - tr->active_cfg = tr->new_cfg; + for (comm = ctab->comms; NULL != comm; comm = comm->next) { + tr_notice("tr_print_config: Community %s:", comm->id->buf); - tr_log_threshold(tr->active_cfg->internal->log_threshold); - tr_console_threshold(tr->active_cfg->internal->console_threshold); + tr_notice("tr_print_config: - Member IdPs:"); + tr_print_comm_idps(ctab, comm); - return TR_CFG_SUCCESS; + tr_notice("tr_print_config: - Member RPs:"); + tr_print_comm_rps(ctab, comm); + } } -static TR_CFG_RC tr_cfg_parse_internal (TR_CFG *trc, json_t *jcfg) { - json_t *jint = NULL; - json_t *jmtd = NULL; - json_t *jtp = NULL; - json_t *jhname = NULL; - json_t *jlog = NULL; - json_t *jconthres = NULL; - json_t *jlogthres = NULL; +void tr_print_comm_idps(TR_COMM_TABLE *ctab, TR_COMM *comm) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TR_COMM_ITER *iter=NULL; + TR_IDP_REALM *idp = NULL; + char *s=NULL; - if ((!trc) || (!jcfg)) - return TR_CFG_BAD_PARAMS; + iter=tr_comm_iter_new(tmp_ctx); + if (iter==NULL) { + tr_notice("tr_print_config: unable to allocate IdP iterator."); + talloc_free(tmp_ctx); + return; + } + + for (idp=tr_idp_realm_iter_first(iter, ctab, tr_comm_get_id(comm)); + NULL!=idp; + idp=tr_idp_realm_iter_next(iter)) { + s=tr_idp_realm_to_str(tmp_ctx, idp); + if (s!=NULL) + tr_notice("tr_print_config: - @%s", s); + else + tr_notice("tr_print_config: unable to allocate IdP output string."); + } + talloc_free(tmp_ctx); +} - if (NULL == trc->internal) { - if (NULL == (trc->internal = talloc(trc, TR_CFG_INTERNAL))) - return TR_CFG_NOMEM; +void tr_print_comm_rps(TR_COMM_TABLE *ctab, TR_COMM *comm) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TR_COMM_ITER *iter=NULL; + TR_RP_REALM *rp = NULL; + char *s=NULL; - memset(trc->internal, 0, sizeof(TR_CFG_INTERNAL)); + iter=tr_comm_iter_new(tmp_ctx); + if (iter==NULL) { + tr_notice("tr_print_config: unable to allocate RP iterator."); + talloc_free(tmp_ctx); + return; } + + for (rp=tr_rp_realm_iter_first(iter, ctab, tr_comm_get_id(comm)); + NULL!=rp; + rp=tr_rp_realm_iter_next(iter)) { + s=tr_rp_realm_to_str(tmp_ctx, rp); + if (s!=NULL) + tr_notice("tr_print_config: - @%s", s); + else + tr_notice("tr_print_config: unable to allocate RP output string."); + } + talloc_free(tmp_ctx); +} - if (NULL != (jint = json_object_get(jcfg, "tr_internal"))) { - if (NULL != (jmtd = json_object_get(jint, "max_tree_depth"))) { - if (json_is_number(jmtd)) { - trc->internal->max_tree_depth = json_integer_value(jmtd); - } else { - tr_debug("tr_cfg_parse_internal: Parsing error, max_tree_depth is not a number."); - return TR_CFG_NOPARSE; - } - } else { - /* If not configured, use the default */ - trc->internal->max_tree_depth = TR_DEFAULT_MAX_TREE_DEPTH; - } - if (NULL != (jtp = json_object_get(jint, "tids_port"))) { - if (json_is_number(jtp)) { - trc->internal->tids_port = json_integer_value(jtp); - } else { - tr_debug("tr_cfg_parse_internal: Parsing error, port is not a number."); - return TR_CFG_NOPARSE; - } - } else { - /* If not configured, use the default */ - trc->internal->tids_port = TR_DEFAULT_TIDS_PORT; - } - if (NULL != (jhname = json_object_get(jint, "hostname"))) { - if (json_is_string(jhname)) { - trc->internal->hostname = json_string_value(jhname); - } else { - tr_debug("tr_cfg_parse_internal: Parsing error, hostname is not a string."); - return TR_CFG_NOPARSE; - } +TR_CFG *tr_cfg_new(TALLOC_CTX *mem_ctx) +{ + TR_CFG *cfg=talloc(mem_ctx, TR_CFG); + if (cfg!=NULL) { + cfg->internal=NULL; + cfg->rp_clients=NULL; + cfg->peers=NULL; + cfg->default_servers=NULL; + cfg->ctable=tr_comm_table_new(cfg); + if (cfg->ctable==NULL) { + talloc_free(cfg); + cfg=NULL; } + } + return cfg; +} - if (NULL != (jlog = json_object_get(jint, "logging"))) { - if (NULL != (jlogthres = json_object_get(jlog, "log_threshold"))) { - if (json_is_string(jlogthres)) { - trc->internal->log_threshold = str2sev(json_string_value(jlogthres)); - } else { - tr_debug("tr_cfg_parse_internal: Parsing error, log_threshold is not a string."); - return TR_CFG_NOPARSE; - } - } else { - /* If not configured, use the default */ - trc->internal->log_threshold = TR_DEFAULT_LOG_THRESHOLD; - } +void tr_cfg_free (TR_CFG *cfg) +{ + talloc_free(cfg); +} - if (NULL != (jconthres = json_object_get(jlog, "console_threshold"))) { - if (json_is_string(jconthres)) { - trc->internal->console_threshold = str2sev(json_string_value(jconthres)); - } else { - tr_debug("tr_cfg_parse_internal: Parsing error, console_threshold is not a string."); - return TR_CFG_NOPARSE; - } - } else { - /* If not configured, use the default */ - trc->internal->console_threshold = TR_DEFAULT_CONSOLE_THRESHOLD; - } - } else { - /* If not configured, use the default */ - trc->internal->console_threshold = TR_DEFAULT_CONSOLE_THRESHOLD; - trc->internal->log_threshold = TR_DEFAULT_LOG_THRESHOLD; - } +TR_CFG_MGR *tr_cfg_mgr_new(TALLOC_CTX *mem_ctx) +{ + return talloc_zero(mem_ctx, TR_CFG_MGR); +} + +void tr_cfg_mgr_free (TR_CFG_MGR *cfg_mgr) { + talloc_free(cfg_mgr); +} + +TR_CFG_RC tr_apply_new_config (TR_CFG_MGR *cfg_mgr) +{ + /* cfg_mgr->active is allowed to be null, but new cannot be */ + if ((cfg_mgr==NULL) || (cfg_mgr->new==NULL)) + return TR_CFG_BAD_PARAMS; + + if (cfg_mgr->active != NULL) + tr_cfg_free(cfg_mgr->active); + + cfg_mgr->active = cfg_mgr->new; + cfg_mgr->new=NULL; /* only keep a single handle on the new configuration */ + + tr_log_threshold(cfg_mgr->active->internal->log_threshold); + tr_console_threshold(cfg_mgr->active->internal->console_threshold); - tr_debug("tr_cfg_parse_internal: Internal config parsed."); - return TR_CFG_SUCCESS; - } return TR_CFG_SUCCESS; } -static TR_CONSTRAINT *tr_cfg_parse_one_constraint (TR_CFG *trc, char *ctype, json_t *jc, TR_CFG_RC *rc) +static TR_CONSTRAINT *tr_cfg_parse_one_constraint(TALLOC_CTX *mem_ctx, char *ctype, json_t *jc, TR_CFG_RC *rc) { - TR_CONSTRAINT *cons; - int i; + TR_CONSTRAINT *cons=NULL; + int i=0; - if ((!trc) || (!ctype) || (!jc) || (!rc) || + if ((!ctype) || (!jc) || (!rc) || (!json_is_array(jc)) || (0 >= json_array_size(jc)) || (TR_MAX_CONST_MATCHES < json_array_size(jc)) || (!json_is_string(json_array_get(jc, 0)))) { - tr_debug("tr_cfg_parse_one_constraint: config error."); - *rc = TR_CFG_NOPARSE; + tr_err("tr_cfg_parse_one_constraint: config error."); + *rc=TR_CFG_NOPARSE; return NULL; } - if (NULL == (cons = talloc(trc, TR_CONSTRAINT))) { + if (NULL==(cons=tr_constraint_new(mem_ctx))) { tr_debug("tr_cfg_parse_one_constraint: Out of memory (cons)."); - *rc = TR_CFG_NOMEM; + *rc=TR_CFG_NOMEM; return NULL; } - memset(cons, 0, sizeof(TR_CONSTRAINT)); - - if (NULL == (cons->type = tr_new_name(ctype))) { - tr_debug("tr_cfg_parse_one_constraint: Out of memory (type)."); - *rc = TR_CFG_NOMEM; + if (NULL==(cons->type=tr_new_name(ctype))) { + tr_err("tr_cfg_parse_one_constraint: Out of memory (type)."); + *rc=TR_CFG_NOMEM; + tr_constraint_free(cons); return NULL; } - for (i = 0; i < json_array_size(jc); i++) { - cons->matches[i] = tr_new_name((char *)(json_string_value(json_array_get(jc, i)))); + for (i=0; i < json_array_size(jc); i++) { + cons->matches[i]=tr_new_name(json_string_value(json_array_get(jc, i))); + if (cons->matches[i]==NULL) { + tr_err("tr_cfg_parse_one_constraint: Out of memory (match %d).", i+1); + *rc=TR_CFG_NOMEM; + tr_constraint_free(cons); + return NULL; + } } return cons; } -static TR_FILTER *tr_cfg_parse_one_filter (TR_CFG *trc, json_t *jfilt, TR_CFG_RC *rc) +static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR_FILTER_TYPE ftype, TR_CFG_RC *rc) { + TALLOC_CTX *tmp_ctx = talloc_new(NULL); TR_FILTER *filt = NULL; - json_t *jftype = NULL; - json_t *jfls = NULL; json_t *jfaction = NULL; + json_t *jfline = NULL; json_t *jfspecs = NULL; - json_t *jffield = NULL; - json_t *jfmatch = NULL; + json_t *this_jfspec = NULL; + json_t *jfield = NULL; + json_t *jmatch = NULL; json_t *jrc = NULL; json_t *jdc = NULL; - int i = 0, j = 0; + json_t *this_jmatch = NULL; + TR_NAME *name = NULL; + size_t i = 0, j = 0, k = 0; - if ((NULL == (jftype = json_object_get(jfilt, "type"))) || - (!json_is_string(jftype))) { - tr_debug("tr_cfg_parse_one_filter: Error parsing filter type."); - *rc = TR_CFG_NOPARSE; - return NULL; - } + *rc = TR_CFG_ERROR; - if ((NULL == (jfls = json_object_get(jfilt, "filter_lines"))) || - (!json_is_array(jfls))) { - tr_debug("tr_cfg_parse_one_filter: Error parsing filter type."); - *rc = TR_CFG_NOPARSE; - return NULL; - } - - if (TR_MAX_FILTER_LINES < json_array_size(jfls)) { - tr_debug("tr_cfg_parse_one_filter: Filter has too many filter_lines, maximimum of %d.", TR_MAX_FILTER_LINES); - *rc = TR_CFG_NOPARSE; - return NULL; + if ((jfilt == NULL) || (rc == NULL)) { + tr_err("tr_cfg_parse_one_filter: null argument"); + *rc = TR_CFG_BAD_PARAMS; + goto cleanup; } - if (NULL == (filt = talloc(trc, TR_FILTER))) { - tr_debug("tr_cfg_parse_one_filter: Out of memory."); + if (NULL == (filt = tr_filter_new(tmp_ctx))) { + tr_err("tr_cfg_parse_one_filter: Out of memory."); *rc = TR_CFG_NOMEM; - return NULL; + goto cleanup; } + tr_filter_set_type(filt, ftype); - memset(filt, 0, sizeof(TR_FILTER)); - - if (!strcmp(json_string_value(jftype), "rp_permitted")) { - filt->type = TR_FILTER_TYPE_RP_PERMITTED; - } - else { - tr_debug("tr_cfg_parse_one_filter: Error parsing filter type, unknown type '%s'.", json_string_value(jftype)); + /* make sure we have space to represent the filter */ + if (json_array_size(jfilt) > TR_MAX_FILTER_LINES) { + tr_err("tr_cfg_parse_one_filter: Filter has too many lines, maximum of %d.", TR_MAX_FILTER_LINES); *rc = TR_CFG_NOPARSE; - tr_filter_free(filt); - return NULL; + goto cleanup; } - /* For each filter line... */ - for (i = 0; i < json_array_size(jfls); i++) { - - if ((NULL == (jfaction = json_object_get(json_array_get(jfls, i), "action"))) || - (!json_is_string(jfaction))) { + /* For each entry in the filter... */ + json_array_foreach(jfilt, i, jfline) { + if ((NULL == (jfaction = json_object_get(jfline, "action"))) || + (!json_is_string(jfaction))) { tr_debug("tr_cfg_parse_one_filter: Error parsing filter action."); *rc = TR_CFG_NOPARSE; - tr_filter_free(filt); - return NULL; + goto cleanup; } - - if ((NULL == (jfspecs = json_object_get(json_array_get(jfls, i), "filter_specs"))) || - (!json_is_array(jfspecs)) || - (0 == json_array_size(jfspecs))) { + + if ((NULL == (jfspecs = json_object_get(jfline, "specs"))) || + (!json_is_array(jfspecs)) || + (0 == json_array_size(jfspecs))) { tr_debug("tr_cfg_parse_one_filter: Error parsing filter specs."); *rc = TR_CFG_NOPARSE; - tr_filter_free(filt); - return NULL; + goto cleanup; } - + if (TR_MAX_FILTER_SPECS < json_array_size(jfspecs)) { - tr_debug("tr_cfg_parse_one_filter: Filter has too many filter_specs, maximimum of %d.", TR_MAX_FILTER_SPECS); + tr_debug("tr_cfg_parse_one_filter: Filter has too many specs, maximimum of %d.", TR_MAX_FILTER_SPECS); *rc = TR_CFG_NOPARSE; - tr_filter_free(filt); - return NULL; + goto cleanup; } - if (NULL == (filt->lines[i] = talloc(trc, TR_FLINE))) { - tr_debug("tr_cfg_parse_one_filter: Out of memory (fline)."); + if (NULL == (filt->lines[i] = tr_fline_new(filt))) { + tr_debug("tr_cfg_parse_one_filter: Out of memory allocating filter line %d.", i + 1); *rc = TR_CFG_NOMEM; - tr_filter_free(filt); - return NULL; + goto cleanup; } - memset(filt->lines[i], 0, sizeof(TR_FLINE)); - if (!strcmp(json_string_value(jfaction), "accept")) { - filt->lines[i]->action = TR_FILTER_ACTION_ACCEPT; - } - else if (!strcmp(json_string_value(jfaction), "reject")) { + filt->lines[i]->action = TR_FILTER_ACTION_ACCEPT; + } else if (!strcmp(json_string_value(jfaction), "reject")) { filt->lines[i]->action = TR_FILTER_ACTION_REJECT; - } - else { - tr_debug("tr_cfg_parse_one_filter: Error parsing filter action, unknown action' %s'.", json_string_value(jfaction)); + } else { + tr_debug("tr_cfg_parse_one_filter: Error parsing filter action, unknown action' %s'.", + json_string_value(jfaction)); *rc = TR_CFG_NOPARSE; - tr_filter_free(filt); - return NULL; + goto cleanup; } - if ((NULL != (jrc = json_object_get(json_array_get(jfls, i), "realm_constraints"))) && - (json_is_array(jrc)) && - (0 != json_array_size(jrc)) && - (TR_MAX_CONST_MATCHES >= json_array_size(jrc))) { - - if (NULL == (filt->lines[i]->realm_cons = tr_cfg_parse_one_constraint(trc, "realm", jrc, rc))) { - tr_debug("tr_cfg_parse_one_filter: Error parsing realm constraint"); - tr_filter_free(filt); - return NULL; + if (NULL != (jrc = json_object_get(jfline, "realm_constraints"))) { + if (!json_is_array(jrc)) { + tr_err("tr_cfg_parse_one_filter: cannot parse realm_constraints, not an array."); + *rc = TR_CFG_NOPARSE; + goto cleanup; + } else if (json_array_size(jrc) > TR_MAX_CONST_MATCHES) { + tr_err("tr_cfg_parse_one_filter: realm_constraints has too many entries, maximum of %d.", + TR_MAX_CONST_MATCHES); + *rc = TR_CFG_NOPARSE; + goto cleanup; + } else if (json_array_size(jrc) > 0) { + /* ok we actually have entries to process */ + if (NULL == (filt->lines[i]->realm_cons = tr_cfg_parse_one_constraint(filt->lines[i], "realm", jrc, rc))) { + tr_debug("tr_cfg_parse_one_filter: Error parsing realm constraint"); + *rc = TR_CFG_NOPARSE; + goto cleanup; + } } } - if ((NULL != (jdc = json_object_get(json_array_get(jfls, i), "domain_constraints"))) && - (json_is_array(jdc)) && - (0 != json_array_size(jdc)) && - (TR_MAX_CONST_MATCHES >= json_array_size(jdc))) { - - if (NULL == (filt->lines[i]->domain_cons = tr_cfg_parse_one_constraint(trc, "domain", jdc, rc))) { - tr_debug("tr_cfg_parse_one_filter: Error parsing domain constraint"); - tr_filter_free(filt); - return NULL; + if (NULL != (jdc = json_object_get(jfline, "domain_constraints"))) { + if (!json_is_array(jdc)) { + tr_err("tr_cfg_parse_one_filter: cannot parse domain_constraints, not an array."); + *rc = TR_CFG_NOPARSE; + goto cleanup; + } else if (json_array_size(jdc) > TR_MAX_CONST_MATCHES) { + tr_err("tr_cfg_parse_one_filter: domain_constraints has too many entries, maximum of %d.", + TR_MAX_CONST_MATCHES); + *rc = TR_CFG_NOPARSE; + goto cleanup; + } else if (json_array_size(jdc) > 0) { + if (NULL == (filt->lines[i]->domain_cons = tr_cfg_parse_one_constraint(filt->lines[i], "domain", jdc, rc))) { + tr_debug("tr_cfg_parse_one_filter: Error parsing domain constraint"); + *rc = TR_CFG_NOPARSE; + goto cleanup; + } } } /*For each filter spec within the filter line... */ - for (j = 0; j lines[i]->specs[j] = talloc(trc, TR_FSPEC))) { - tr_debug("tr_cfg_parse_one_filter: Out of memory."); - *rc = TR_CFG_NOMEM; - tr_filter_free(filt); - return NULL; + /* check that we have a match attribute */ + if (NULL == (jmatch = json_object_get(this_jfspec, "match"))) { + tr_debug("tr_cfg_parse_one_filter: Error parsing filter: missing match for filer spec %d, filter line %d.", i, + j); + *rc = TR_CFG_NOPARSE; + goto cleanup; } - memset(filt->lines[i]->specs[j], 0, sizeof(TR_FSPEC)); - - if ((NULL == (filt->lines[i]->specs[j]->field = tr_new_name((char *)json_string_value(jffield)))) || - (NULL == (filt->lines[i]->specs[j]->match = tr_new_name((char *)json_string_value(jfmatch))))) { - tr_debug("tr_cfg_parse_one_filter: Out of memory."); - *rc = TR_CFG_NOMEM; - tr_filter_free(filt); - return NULL; + /* check that match is a string or an array */ + if ((!json_is_string(jmatch)) && (!json_is_array(jmatch))) { + tr_debug( + "tr_cfg_parse_one_filter: Error parsing filter: match not a string or array for filter spec %d, filter line %d.", + i, j); + *rc = TR_CFG_NOPARSE; + goto cleanup; } - } - } - return filt; -} + /* allocate the filter spec */ + if (NULL == (filt->lines[i]->specs[j] = tr_fspec_new(filt->lines[i]))) { + tr_debug("tr_cfg_parse_one_filter: Out of memory."); + *rc = TR_CFG_NOMEM; + goto cleanup; + } -static TR_RP_CLIENT *tr_cfg_parse_one_rp_client (TR_CFG *trc, json_t *jrp, TR_CFG_RC *rc) -{ - TR_RP_CLIENT *rp = NULL; - json_t *jgns = NULL; - json_t *jfilt = NULL; - json_t *jftype = NULL; - int i = 0; + /* fill in the field */ + if (NULL == (filt->lines[i]->specs[j]->field = tr_new_name(json_string_value(jfield)))) { + tr_debug("tr_cfg_parse_one_filter: Out of memory."); + *rc = TR_CFG_NOMEM; + goto cleanup; + } - if ((!trc) || (!jrp) || (!rc)) { - tr_debug("tr_cfg_parse_one_rp_realm: Bad parameters."); - if (rc) - *rc = TR_CFG_BAD_PARAMS; - return NULL; + /* fill in the matches */ + if (json_is_string(jmatch)) { + if (NULL == (name = tr_new_name(json_string_value(jmatch)))) { + tr_debug("tr_cfg_parse_one_filter: Out of memory."); + *rc = TR_CFG_NOMEM; + goto cleanup; + } + tr_fspec_add_match(filt->lines[i]->specs[j], name); + } else { + /* jmatch is an array (we checked earlier) */ + json_array_foreach(jmatch, k, this_jmatch) { + if (NULL == (name = tr_new_name(json_string_value(this_jmatch)))) { + tr_debug("tr_cfg_parse_one_filter: Out of memory."); + *rc = TR_CFG_NOMEM; + goto cleanup; + } + tr_fspec_add_match(filt->lines[i]->specs[j], name); + } + } + if (!tr_filter_validate_spec_field(ftype, filt->lines[i]->specs[j])){ + tr_debug("tr_cfg_parse_one_filter: Invalid filter field \"%.*s\" for %s filter, spec %d, filter %d.", + filt->lines[i]->specs[j]->field->len, + filt->lines[i]->specs[j]->field->buf, + tr_filter_type_to_string(filt->type), + i, j); + *rc = TR_CFG_ERROR; + goto cleanup; + } + } } - if ((NULL == (jgns = json_object_get(jrp, "gss_names"))) || - (!json_is_array(jgns))) { - tr_debug("tr_cfg_parse_one_rp_client: Error parsing RP client configuration, no GSS names."); - *rc = TR_CFG_NOPARSE; - return NULL; + /* check that the filter is valid */ + if (!tr_filter_validate(filt)) { + *rc = TR_CFG_ERROR; + } else { + *rc = TR_CFG_SUCCESS; + talloc_steal(mem_ctx, filt); } - /* TBD -- Support more than one filter per RP client? */ - if (NULL == (jfilt = json_object_get(jrp, "filter"))) { - tr_debug("tr_cfg_parse_one_rp_client: Error parsing RP client configuration, no filter."); - *rc = TR_CFG_NOPARSE; - return NULL; - } + cleanup: + talloc_free(tmp_ctx); + if (*rc!=TR_CFG_SUCCESS) + filt=NULL; + return filt; +} - /* We only support rp_permitted filters for RP clients */ - if ((NULL == (jftype = json_object_get(jfilt, "type"))) || - (!json_is_string(jftype)) || - (strcmp(json_string_value(jftype), "rp_permitted"))) { - tr_debug("tr_cfg_parse_one_rp_client: Error parsing RP client filter type."); - *rc = TR_CFG_NOPARSE; - return NULL; - } +static TR_FILTER_SET *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_CFG_RC *rc) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + json_t *jfilt; + const char *filt_label=NULL; + TR_FILTER *filt=NULL; + TR_FILTER_SET *filt_set=NULL; + TR_FILTER_TYPE filt_type=TR_FILTER_TYPE_UNKNOWN; - if (TR_MAX_GSS_NAMES < json_array_size(jgns)) { - tr_debug("tr_cfg_parse_one_rp_client: RP Client has too many GSS Names."); - *rc = TR_CFG_NOPARSE; - return NULL; + *rc=TR_CFG_ERROR; + + /* no filters */ + if (jfilts==NULL) { + *rc=TR_CFG_SUCCESS; + goto cleanup; } - if (NULL == (rp = talloc(trc, TR_RP_CLIENT))) { - tr_debug("tr_cfg_parse_one_rp_realm: Out of memory."); + filt_set=tr_filter_set_new(tmp_ctx); + if (filt_set==NULL) { + tr_debug("tr_cfg_parse_filters: Unable to allocate filter set."); *rc = TR_CFG_NOMEM; - return NULL; + goto cleanup; } - - memset(rp, 0, sizeof(TR_RP_CLIENT)); - /* TBD -- support more than one filter entry per RP Client? */ - if (NULL == (rp->filter = tr_cfg_parse_one_filter(trc, jfilt, rc))) { - tr_debug("tr_cfg_parse_one_rp_client: Error parsing filter."); - *rc = TR_CFG_NOPARSE; - return NULL; - } - - for (i = 0; i < json_array_size(jgns); i++) { - if (NULL == (rp->gss_names[i] = tr_new_name ((char *)json_string_value(json_array_get(jgns, i))))) { - tr_debug("tr_cfg_parse_one_rp_client: No memory for GSS Name."); - *rc = TR_CFG_NOMEM; - return NULL; + json_object_foreach(jfilts, filt_label, jfilt) { + /* check that we got a filter */ + if (jfilt == NULL) { + tr_debug("tr_cfg_parse_filters: Definition for %s filter is missing.", filt_label); + *rc = TR_CFG_NOPARSE; + goto cleanup; } - } - - return rp; -} - -static TR_CFG_RC tr_cfg_parse_rp_clients (TR_CFG *trc, json_t *jcfg) { - json_t *jrps = NULL; - TR_RP_CLIENT *rp = NULL; - TR_CFG_RC rc = TR_CFG_SUCCESS; - int i = 0; - - if ((!trc) || (!jcfg)) - return TR_CFG_BAD_PARAMS; - - if (NULL != (jrps = json_object_get(jcfg, "rp_clients"))) { - if (!json_is_array(jrps)) { - return TR_CFG_NOPARSE; + /* check that we recognize the filter type */ + filt_type=tr_filter_type_from_string(filt_label); + if (filt_type==TR_FILTER_TYPE_UNKNOWN) { + tr_debug("tr_cfg_parse_filters: Unrecognized filter (%s) defined.", filt_label); + *rc = TR_CFG_NOPARSE; + goto cleanup; } - for (i = 0; i < json_array_size(jrps); i++) { - if (NULL == (rp = tr_cfg_parse_one_rp_client(trc, - json_array_get(jrps, i), - &rc))) { - return rc; - } - tr_debug("tr_cfg_parse_rp_clients: RP client configured -- first gss: %s", rp->gss_names[0]->buf); - rp->next = trc->rp_clients; - trc->rp_clients = rp; + /* finally, parse the filter */ + tr_debug("tr_cfg_parse_filters: Found %s filter.", filt_label); + filt = tr_cfg_parse_one_filter(tmp_ctx, jfilt, filt_type, rc); + tr_filter_set_add(filt_set, filt); + if (*rc != TR_CFG_SUCCESS) { + tr_debug("tr_cfg_parse_filters: Error parsing %s filter.", filt_label); + *rc = TR_CFG_NOPARSE; + goto cleanup; } } - return rc; + + *rc=TR_CFG_SUCCESS; + + cleanup: + if (*rc==TR_CFG_SUCCESS) + talloc_steal(mem_ctx, filt_set); + else if (filt_set!=NULL) { + talloc_free(filt_set); + filt_set=NULL; + } + + talloc_free(tmp_ctx); + return filt_set; } -static TR_AAA_SERVER *tr_cfg_parse_one_aaa_server (TR_CFG *trc, json_t *jaddr, TR_CFG_RC *rc) { +static TR_AAA_SERVER *tr_cfg_parse_one_aaa_server(TALLOC_CTX *mem_ctx, json_t *jaddr, TR_CFG_RC *rc) +{ TR_AAA_SERVER *aaa = NULL; + TR_NAME *name=NULL; - if ((!trc) || (!jaddr) || (!json_is_string(jaddr))) { + if ((!jaddr) || (!json_is_string(jaddr))) { tr_debug("tr_cfg_parse_one_aaa_server: Bad parameters."); *rc = TR_CFG_BAD_PARAMS; return NULL; } - if (NULL == (aaa = talloc(trc, TR_AAA_SERVER))) { - tr_debug("tr_cfg_parse_one_aaa_server: Out of memory."); + name=tr_new_name(json_string_value(jaddr)); + if (name==NULL) { + tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating hostname."); *rc = TR_CFG_NOMEM; return NULL; } - memset(aaa, 0, sizeof(TR_AAA_SERVER)); - - aaa->hostname = tr_new_name((char *)(json_string_value(jaddr))); + aaa=tr_aaa_server_new(mem_ctx, name); + if (aaa==NULL) { + tr_free_name(name); + tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating AAA server."); + *rc = TR_CFG_NOMEM; + return NULL; + } return aaa; } -static TR_AAA_SERVER *tr_cfg_parse_aaa_servers (TR_CFG *trc, json_t *jaaas, TR_CFG_RC *rc) +static TR_AAA_SERVER *tr_cfg_parse_aaa_servers(TALLOC_CTX *mem_ctx, json_t *jaaas, TR_CFG_RC *rc) { + TALLOC_CTX *tmp_ctx=NULL; TR_AAA_SERVER *aaa = NULL; TR_AAA_SERVER *temp_aaa = NULL; int i = 0; for (i = 0; i < json_array_size(jaaas); i++) { - if (NULL == (temp_aaa = tr_cfg_parse_one_aaa_server(trc, json_array_get(jaaas, i), rc))) { + /* rc gets set in here */ + if (NULL == (temp_aaa = tr_cfg_parse_one_aaa_server(tmp_ctx, json_array_get(jaaas, i), rc))) { + talloc_free(tmp_ctx); return NULL; } /* TBD -- IPv6 addresses */ @@ -487,107 +531,930 @@ static TR_AAA_SERVER *tr_cfg_parse_aaa_servers (TR_CFG *trc, json_t *jaaas, TR_C temp_aaa->next = aaa; aaa = temp_aaa; } + tr_debug("tr_cfg_parse_aaa_servers: Finished (rc=%d)", *rc); + + for (temp_aaa=aaa; temp_aaa!=NULL; temp_aaa=temp_aaa->next) + talloc_steal(mem_ctx, temp_aaa); + talloc_free(tmp_ctx); return aaa; } -static TR_APC *tr_cfg_parse_apcs (TR_CFG *trc, json_t *japcs, TR_CFG_RC *rc) +static TR_APC *tr_cfg_parse_one_apc(TALLOC_CTX *mem_ctx, json_t *japc, TR_CFG_RC *rc) { - TR_APC *apc; - - *rc = TR_CFG_SUCCESS; /* presume success */ + TR_APC *apc=NULL; + TR_NAME *name=NULL; + + *rc = TR_CFG_SUCCESS; /* presume success */ - if ((!trc) || (!japcs) || (!rc)) { - tr_debug("tr_cfg_parse_apcs: Bad parameters."); + if ((!japc) || (!rc) || (!json_is_string(japc))) { + tr_debug("tr_cfg_parse_one_apc: Bad parameters."); if (rc) *rc = TR_CFG_BAD_PARAMS; return NULL; } - if (NULL == (apc = talloc(trc, TR_APC))) { - tr_debug("tr_cfg_parse_apcs: Out of memory."); + apc=tr_apc_new(mem_ctx); + if (apc==NULL) { + tr_debug("tr_cfg_parse_one_apc: Out of memory."); *rc = TR_CFG_NOMEM; return NULL; } - memset(apc, 0, sizeof(TR_APC)); - - /* TBD, deal with more than one APC. In the meantime, though... */ - /* Only parse the first APC, because we only know how to deal with one, anyway. */ - if (0 == json_array_size(japcs)) - return NULL; - - if (NULL == (apc->id = tr_new_name((char *)json_string_value(json_array_get(japcs, 0))))) { - tr_debug("tr_cfg_parse_apcs: No memory for APC name."); + name=tr_new_name(json_string_value(japc)); + if (name==NULL) { + tr_debug("tr_cfg_parse_one_apc: No memory for APC name."); + tr_apc_free(apc); *rc = TR_CFG_NOMEM; return NULL; } + tr_apc_set_id(apc, name); /* apc is now responsible for freeing the name */ return apc; } -static TR_IDP_REALM *tr_cfg_parse_one_idp_realm (TR_CFG *trc, json_t *jidp, TR_CFG_RC *rc) { - TR_IDP_REALM *idp = NULL; - json_t *jrid = NULL; - json_t *jscfg = NULL; - json_t *jsrvrs = NULL; - json_t *japcs = NULL; +static TR_APC *tr_cfg_parse_apcs(TALLOC_CTX *mem_ctx, json_t *japcs, TR_CFG_RC *rc) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TR_APC *apcs=NULL; + TR_APC *new_apc=NULL; + int ii=0; + TR_CFG_RC call_rc=TR_CFG_ERROR; + + *rc = TR_CFG_SUCCESS; /* presume success */ - if ((!trc) || (!jidp) || (!rc)) { - tr_debug("tr_cfg_parse_one_idp_realm: Bad parameters."); - if (rc) + if ((!japcs) || (!rc) || (!json_is_array(japcs))) { + tr_debug("tr_cfg_parse_one_apc: Bad parameters."); + if (rc) *rc = TR_CFG_BAD_PARAMS; return NULL; } - if (NULL == (idp = talloc(trc, TR_IDP_REALM))) { - tr_debug("tr_cfg_parse_one_idp_realm: Out of memory."); - *rc = TR_CFG_NOMEM; - return NULL; + for (ii=0; iishared_config=tr_cfg_parse_shared_config(json_object_get(jidp, "shared_config"), &rc); + if (rc!=TR_CFG_SUCCESS) { + tr_err("tr_cfg_parse_idp: missing or malformed shared_config specification"); + rc=TR_CFG_NOPARSE; + goto cleanup; + } + + apcs=tr_cfg_parse_apcs(tmp_ctx, json_object_get(jidp, "apcs"), &rc); + if ((rc!=TR_CFG_SUCCESS) || (apcs==NULL)) { + tr_err("tr_cfg_parse_idp: unable to parse APC"); + rc=TR_CFG_NOPARSE; + goto cleanup; + } + + aaa=tr_cfg_parse_aaa_servers(idp, json_object_get(jidp, "aaa_servers"), &rc); + if (rc!=TR_CFG_SUCCESS) { + tr_err("tr_cfg_parse_idp: unable to parse AAA servers"); + rc=TR_CFG_NOPARSE; + goto cleanup; + } + + tr_debug("tr_cfg_parse_idp: APC=\"%.*s\"", + apcs->id->len, + apcs->id->buf); + + /* done, fill in the idp structures */ + idp->apcs=apcs; + talloc_steal(idp, apcs); + idp->aaa_servers=aaa; + rc=TR_CFG_SUCCESS; + +cleanup: + if (rc!=TR_CFG_SUCCESS) { + if (apcs!=NULL) + tr_apc_free(apcs); + if (aaa!=NULL) + tr_aaa_server_free(aaa); + } + + talloc_free(tmp_ctx); + return rc; +} + +/* parses idp realm */ +static TR_IDP_REALM *tr_cfg_parse_one_idp_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TR_IDP_REALM *realm=NULL; + TR_CFG_RC call_rc=TR_CFG_ERROR; + + *rc=TR_CFG_ERROR; /* default to error if not set */ + + if ((!jrealm) || (!rc)) { + tr_err("tr_cfg_parse_one_idp_realm: Bad parameters."); + if (rc) + *rc=TR_CFG_BAD_PARAMS; + goto cleanup; + } + + if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) { + tr_err("tr_cfg_parse_one_idp_realm: could not allocate idp realm."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } + + realm->origin=tr_cfg_realm_origin(jrealm); + if (realm->origin!=TR_REALM_LOCAL) { + tr_debug("tr_cfg_parse_one_idp_realm: realm is remote, should not have full IdP info."); + *rc=TR_CFG_NOPARSE; + goto cleanup; + } + + /* must have a name */ + realm->realm_id=tr_cfg_parse_name(realm, + json_object_get(jrealm, "realm"), + &call_rc); + if ((call_rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) { + tr_err("tr_cfg_parse_one_idp_realm: could not parse realm name"); + *rc=TR_CFG_NOPARSE; + goto cleanup; + } + tr_debug("tr_cfg_parse_one_idp_realm: realm_id=\"%.*s\"", + realm->realm_id->len, + realm->realm_id->buf); + + call_rc=tr_cfg_parse_idp(realm, json_object_get(jrealm, "identity_provider")); + if (call_rc!=TR_CFG_SUCCESS) { + tr_err("tr_cfg_parse_one_idp_realm: could not parse identity_provider."); + *rc=TR_CFG_NOPARSE; + goto cleanup; + } + + *rc=TR_CFG_SUCCESS; + +cleanup: + if (*rc==TR_CFG_SUCCESS) + talloc_steal(mem_ctx, realm); + else { + talloc_free(realm); + realm=NULL; } + + talloc_free(tmp_ctx); + return realm; +} - if (0 == strcmp(json_string_value(jscfg), "no")) { - idp->shared_config = 0; + /* Determine whether the realm is an IDP realm */ +static int tr_cfg_is_idp_realm(json_t *jrealm) +{ + /* If a realm spec contains an identity_provider, it's an IDP realm. */ + if (NULL != json_object_get(jrealm, "identity_provider")) + return 1; + else + return 0; +} + +static TR_IDP_REALM *tr_cfg_parse_one_remote_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TR_IDP_REALM *realm=talloc(mem_ctx, TR_IDP_REALM); + + *rc=TR_CFG_ERROR; /* default to error if not set */ + + if ((!jrealm) || (!rc)) { + tr_err("tr_cfg_parse_one_remote_realm: Bad parameters."); + if (rc) + *rc=TR_CFG_BAD_PARAMS; + goto cleanup; + } + + if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) { + tr_err("tr_cfg_parse_one_remote_realm: could not allocate idp realm."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } + + /* must have a name */ + realm->realm_id=tr_cfg_parse_name(realm, + json_object_get(jrealm, "realm"), + rc); + if ((*rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) { + tr_err("tr_cfg_parse_one_remote_realm: could not parse realm name"); + *rc=TR_CFG_NOPARSE; + goto cleanup; + } + tr_debug("tr_cfg_parse_one_remote_realm: realm_id=\"%.*s\"", + realm->realm_id->len, + realm->realm_id->buf); + + realm->origin=tr_cfg_realm_origin(jrealm); + *rc=TR_CFG_SUCCESS; + +cleanup: + if (*rc==TR_CFG_SUCCESS) + talloc_steal(mem_ctx, realm); + else { + talloc_free(realm); + realm=NULL; + } + + talloc_free(tmp_ctx); + return realm; +} + +static int tr_cfg_is_remote_realm(json_t *jrealm) +{ + return (tr_cfg_realm_origin(jrealm)!=TR_REALM_LOCAL); +} + +/* Parse any idp realms in the j_realms object. Ignores other realm types. */ +static TR_IDP_REALM *tr_cfg_parse_idp_realms(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TR_IDP_REALM *realms=NULL; + TR_IDP_REALM *new_realm=NULL; + json_t *this_jrealm=NULL; + int ii=0; + + *rc=TR_CFG_ERROR; + if ((jrealms==NULL) || (!json_is_array(jrealms))) { + tr_err("tr_cfg_parse_idp_realms: realms not an array"); + *rc=TR_CFG_BAD_PARAMS; + goto cleanup; + } + + for (ii=0; iilines[0]=tr_fline_new(filt); + if (filt->lines[0]==NULL) { + tr_debug("tr_cfg_default_filters: could not allocate filter line."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } + + filt->lines[0]->action=TR_FILTER_ACTION_ACCEPT; + filt->lines[0]->specs[0]=tr_fspec_new(filt->lines[0]); + filt->lines[0]->specs[0]->field=n_rp_realm_1; + n_rp_realm_1=NULL; /* we don't own this name any more */ + + name=tr_dup_name(realm); + if (name==NULL) { + tr_debug("tr_cfg_default_filters: could not allocate realm name."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } + tr_fspec_add_match(filt->lines[0]->specs[0], name); + name=NULL; /* we no longer own the name */ + + /* now do the wildcard name */ + filt->lines[0]->specs[1]=tr_fspec_new(filt->lines[0]); + filt->lines[0]->specs[1]->field=n_rp_realm_2; + n_rp_realm_2=NULL; /* we don't own this name any more */ + + if (NULL==(name=tr_name_cat(n_prefix, realm))) { + tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } + + tr_fspec_add_match(filt->lines[0]->specs[1], name); + name=NULL; /* we no longer own the name */ + + /* domain constraint */ + if (NULL==(cons=tr_constraint_new(filt->lines[0]))) { + tr_debug("tr_cfg_default_filters: could not allocate domain constraint."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } + + cons->type=n_domain; + n_domain=NULL; /* belongs to the constraint now */ + name=tr_dup_name(realm); + if (name==NULL) { + tr_debug("tr_cfg_default_filters: could not allocate realm name for domain constraint."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } + cons->matches[0]=name; + name=tr_name_cat(n_prefix, realm); + if (name==NULL) { + tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name for domain constraint."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } + cons->matches[1]=name; + name=NULL; + filt->lines[0]->domain_cons=cons; + + + /* realm constraint */ + if (NULL==(cons=tr_constraint_new(filt->lines[0]))) { + tr_debug("tr_cfg_default_filters: could not allocate realm constraint."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } + + cons->type=n_realm; + n_realm=NULL; /* belongs to the constraint now */ + name=tr_dup_name(realm); + if (name==NULL) { + tr_debug("tr_cfg_default_filters: could not allocate realm name for realm constraint."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } + cons->matches[0]=name; + name=tr_name_cat(n_prefix, realm); + if (name==NULL) { + tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name for realm constraint."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } + cons->matches[1]=name; + name=NULL; + filt->lines[0]->realm_cons=cons; + + /* put the filter in a set */ + filt_set=tr_filter_set_new(tmp_ctx); + if ((filt_set==NULL)||(0!=tr_filter_set_add(filt_set, filt))) { + tr_debug("tr_cfg_default_filters: could not allocate filter set."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } + talloc_steal(mem_ctx, filt_set); + +cleanup: + talloc_free(tmp_ctx); + + if (*rc!=TR_CFG_SUCCESS) + filt=NULL; + + if (n_prefix!=NULL) + tr_free_name(n_prefix); + if (n_rp_realm_1!=NULL) + tr_free_name(n_rp_realm_1); + if (n_rp_realm_2!=NULL) + tr_free_name(n_rp_realm_2); + if (n_realm!=NULL) + tr_free_name(n_realm); + if (n_domain!=NULL) + tr_free_name(n_domain); + if (name!=NULL) + tr_free_name(name); + + return filt_set; +} + +/* parses rp client */ +static TR_RP_CLIENT *tr_cfg_parse_one_rp_client(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TR_RP_CLIENT *client=NULL; + TR_CFG_RC call_rc=TR_CFG_ERROR; + TR_FILTER_SET *new_filts=NULL; + TR_NAME *realm=NULL; + json_t *jfilt=NULL; + json_t *jrealm_id=NULL; + + *rc=TR_CFG_ERROR; /* default to error if not set */ + + if ((!jrealm) || (!rc)) { + tr_err("tr_cfg_parse_one_rp_client: Bad parameters."); + if (rc) + *rc=TR_CFG_BAD_PARAMS; + goto cleanup; + } + + if ((NULL==(jrealm_id=json_object_get(jrealm, "realm"))) || (!json_is_string(jrealm_id))) { + tr_debug("tr_cfg_parse_one_rp_client: no realm ID found."); + *rc=TR_CFG_BAD_PARAMS; + goto cleanup; + } + + tr_debug("tr_cfg_parse_one_rp_client: realm_id=\"%s\"", json_string_value(jrealm_id)); + realm=tr_new_name(json_string_value(jrealm_id)); + if (realm==NULL) { + tr_err("tr_cfg_parse_one_rp_client: could not allocate realm ID."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } + + if (NULL==(client=tr_rp_client_new(tmp_ctx))) { + tr_err("tr_cfg_parse_one_rp_client: could not allocate rp client."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } + + client->gss_names=tr_cfg_parse_gss_names(client, json_object_get(jrealm, "gss_names"), &call_rc); + + if (call_rc!=TR_CFG_SUCCESS) { + tr_err("tr_cfg_parse_one_rp_client: could not parse gss_names."); + *rc=TR_CFG_NOPARSE; + goto cleanup; + } + + /* parse filters */ + jfilt=json_object_get(jrealm, "filters"); + if (jfilt!=NULL) { + new_filts=tr_cfg_parse_filters(tmp_ctx, jfilt, &call_rc); + if (call_rc!=TR_CFG_SUCCESS) { + tr_err("tr_cfg_parse_one_rp_client: could not parse filters."); + *rc=TR_CFG_NOPARSE; + goto cleanup; + } } else { - idp->shared_config = 1; + tr_debug("tr_cfg_parse_one_rp_client: no filters specified, using default filters."); + new_filts= tr_cfg_default_filters(tmp_ctx, realm, &call_rc); + if (call_rc!=TR_CFG_SUCCESS) { + tr_err("tr_cfg_parse_one_rp_client: could not set default filters."); + *rc=TR_CFG_NOPARSE; + goto cleanup; + } } - if (NULL == (idp->realm_id = tr_new_name((char *)json_string_value(jrid)))) { - tr_debug("tr_cfg_parse_one_idp_realm: No memory for realm id."); - *rc = TR_CFG_NOMEM; - return NULL; + tr_rp_client_set_filters(client, new_filts); + *rc=TR_CFG_SUCCESS; + + cleanup: + if (realm!=NULL) + tr_free_name(realm); + + if (*rc==TR_CFG_SUCCESS) + talloc_steal(mem_ctx, client); + else { + talloc_free(client); + client=NULL; + } + + talloc_free(tmp_ctx); + return client; +} + + /* Determine whether the realm is an RP realm */ +static int tr_cfg_is_rp_realm(json_t *jrealm) +{ + /* Check that we have a gss name. */ + if (NULL != json_object_get(jrealm, "gss_names")) + return 1; + else + return 0; +} + +/* Parse any rp clients in the j_realms object. Ignores other realms. */ +static TR_RP_CLIENT *tr_cfg_parse_rp_clients(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TR_RP_CLIENT *clients=NULL; + TR_RP_CLIENT *new_client=NULL; + json_t *this_jrealm=NULL; + int ii=0; + + *rc=TR_CFG_ERROR; + if ((jrealms==NULL) || (!json_is_array(jrealms))) { + tr_err("tr_cfg_parse_rp_clients: realms not an array"); + *rc=TR_CFG_BAD_PARAMS; + goto cleanup; + } + + for (ii=0; iiaaa_servers = tr_cfg_parse_aaa_servers(trc, jsrvrs, rc))) { - tr_debug("tr_cfg_parse_one_idp_realm: Can't parse AAA servers for realm %s.", idp->realm_id->buf); - tr_free_name(idp->realm_id); + if ((j_org==NULL) || (rc==NULL) || (!json_is_string(j_org))) { + tr_debug("tr_cfg_parse_org_name: Bad parameters."); + if (rc!=NULL) + *rc = TR_CFG_BAD_PARAMS; /* fill in return value if we can */ return NULL; } - if ((NULL != (japcs = json_object_get(jidp, "apcs"))) && - (json_is_array(japcs))) { - if (NULL == (idp->apcs = tr_cfg_parse_apcs(trc, japcs, rc))) { - tr_debug("tr_cfg_parse_one_idp_realm: Can't parse APCs for realm %s .", idp->realm_id->buf); - tr_free_name(idp->realm_id); - /* TBD -- free aaa_servers */; - return NULL; + name=tr_new_name(json_string_value(j_org)); + if (name==NULL) + *rc=TR_CFG_NOMEM; + else + *rc=TR_CFG_SUCCESS; + return name; +} + +static TR_CFG_RC tr_cfg_parse_one_local_org(TR_CFG *trc, json_t *jlorg) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TR_CFG_RC retval=TR_CFG_ERROR; /* our return code */ + TR_CFG_RC rc=TR_CFG_ERROR; /* return code from functions we call */ + TR_NAME *org_name=NULL; + json_t *j_org=NULL; + json_t *j_realms=NULL; + TR_IDP_REALM *new_idp_realms=NULL; + TR_RP_CLIENT *new_rp_clients=NULL; + + tr_debug("tr_cfg_parse_one_local_org: parsing local organization"); + + /* get organization_name (optional) */ + if (NULL==(j_org=json_object_get(jlorg, "organization_name"))) { + tr_debug("tr_cfg_parse_one_local_org: organization_name unspecified"); + } else { + org_name=tr_cfg_parse_org_name(tmp_ctx, j_org, &rc); + if (rc==TR_CFG_SUCCESS) { + tr_debug("tr_cfg_parse_one_local_org: organization_name=\"%.*s\"", + org_name->len, + org_name->buf); + /* we don't actually do anything with this, but we could */ + tr_free_name(org_name); + org_name=NULL; } - } - return idp; + } + + /* Now get realms. Allow this to be missing; even though that is a pointless organization entry, + * it's harmless. Report a warning because that might be unintentional. */ + if (NULL==(j_realms=json_object_get(jlorg, "realms"))) { + tr_warning("tr_cfg_parse_one_local_org: warning - no realms in this local organization"); + } else { + /* Allocate in the tmp_ctx so these will be cleaned up if we do not complete successfully. */ + new_idp_realms=tr_cfg_parse_idp_realms(tmp_ctx, j_realms, &rc); + if (rc!=TR_CFG_SUCCESS) + goto cleanup; + + new_rp_clients=tr_cfg_parse_rp_clients(tmp_ctx, j_realms, &rc); + if (rc!=TR_CFG_SUCCESS) + goto cleanup; + } + retval=TR_CFG_SUCCESS; + +cleanup: + /* if we succeeded, link things to the configuration and move out of tmp context */ + if (retval==TR_CFG_SUCCESS) { + if (new_idp_realms!=NULL) { + tr_idp_realm_add(trc->ctable->idp_realms, new_idp_realms); /* fixes talloc contexts except for head*/ + talloc_steal(trc, trc->ctable->idp_realms); /* make sure the head is in the right context */ + } + + if (new_rp_clients!=NULL) { + tr_rp_client_add(trc->rp_clients, new_rp_clients); /* fixes talloc contexts */ + talloc_steal(trc, trc->rp_clients); /* make sure head is in the right context */ + } + } + + talloc_free(tmp_ctx); + return rc; +} + +/* Parse local organizations if present. Returns success if there are none. On failure, the configuration is unreliable. */ +static TR_CFG_RC tr_cfg_parse_local_orgs(TR_CFG *trc, json_t *jcfg) +{ + json_t *jlocorgs=NULL; + size_t ii=0; + + jlocorgs=json_object_get(jcfg, "local_organizations"); + if (jlocorgs==NULL) + return TR_CFG_SUCCESS; + + if (!json_is_array(jlocorgs)) { + tr_err("tr_cfg_parse_local_orgs: local_organizations is not an array."); + return TR_CFG_NOPARSE; + } + + for (ii=0; iipeers, new_peer); + rc=TR_CFG_SUCCESS; + + cleanup: + talloc_free(tmp_ctx); + return rc; +} + +/* Parse peer organizations, if present. Returns success if there are none. */ +static TR_CFG_RC tr_cfg_parse_peer_orgs(TR_CFG *trc, json_t *jcfg) +{ + json_t *jpeerorgs=NULL; + int ii=0; + + jpeerorgs=json_object_get(jcfg, "peer_organizations"); + if (jpeerorgs==NULL) + return TR_CFG_SUCCESS; + + if (!json_is_array(jpeerorgs)) { + tr_err("tr_cfg_parse_peer_orgs: peer_organizations is not an array."); + return TR_CFG_NOPARSE; + } + + for (ii=0; iihostname->buf); @@ -615,105 +1482,111 @@ static TR_CFG_RC tr_cfg_parse_default_servers (TR_CFG *trc, json_t *jcfg) } } + tr_debug("tr_cfg_parse_default_servers: Finished (rc=%d)", rc); return rc; } -static TR_CFG_RC tr_cfg_parse_idp_realms (TR_CFG *trc, json_t *jcfg) -{ - json_t *jidps = NULL; - TR_CFG_RC rc = TR_CFG_SUCCESS; - TR_IDP_REALM *idp = NULL; - int i = 0; - - if ((!trc) || (!jcfg)) - return TR_CFG_BAD_PARAMS; - - /* If there are any IDP Realms, parse them */ - if ((NULL != (jidps = json_object_get(jcfg, "idp_realms"))) && - (json_is_array(jidps))) { - for (i = 0; i < json_array_size(jidps); i++) { - if (NULL == (idp = tr_cfg_parse_one_idp_realm(trc, - json_array_get(jidps, i), - &rc))) { - return rc; - } - tr_debug("tr_cfg_parse_idp_realms: IDP realm configured: %s.", idp->realm_id->buf); - idp->next = trc->idp_realms; - trc->idp_realms = idp; - } - } - - return rc; -} - -static TR_IDP_REALM *tr_cfg_parse_comm_idps (TR_CFG *trc, json_t *jidps, TR_CFG_RC *rc) +static void tr_cfg_parse_comm_idps(TR_CFG *trc, json_t *jidps, TR_COMM *comm, TR_CFG_RC *rc) { - TR_IDP_REALM *idp = NULL; - TR_IDP_REALM *temp_idp = NULL; - int i = 0; + TR_IDP_REALM *found_idp=NULL; + json_t *jidp_name=NULL; + TR_NAME *idp_name=NULL; + size_t ii = 0; if ((!trc) || (!jidps) || (!json_is_array(jidps))) { if (rc) *rc = TR_CFG_BAD_PARAMS; - return NULL; + return; } - for (i = 0; i < json_array_size(jidps); i++) { - if (NULL == (temp_idp = (tr_cfg_find_idp(trc, - tr_new_name((char *)json_string_value(json_array_get(jidps, i))), - rc)))) { - tr_debug("tr_cfg_parse_comm_idps: Unknown IDP %s.", - (char *)json_string_value(json_array_get(jidps, i))); - return NULL; + json_array_foreach(jidps, ii, jidp_name) { + idp_name=tr_new_name(json_string_value(jidp_name)); + if (idp_name==NULL) { + *rc = TR_CFG_NOMEM; + return; } + found_idp=tr_cfg_find_idp(trc, idp_name, rc); + tr_free_name(idp_name); - temp_idp->comm_next = idp; - idp = temp_idp; + if ((found_idp==NULL) || (*rc!=TR_CFG_SUCCESS)) { + tr_debug("tr_cfg_parse_comm_idps: Unknown IDP %s.", json_string_value(jidp_name)); + *rc=TR_CFG_ERROR; + return; + } + tr_comm_add_idp_realm(trc->ctable, comm, found_idp, 0, NULL, NULL); /* no provenance, never expires */ } - return idp; + *rc=TR_CFG_SUCCESS; + return; } -static TR_RP_REALM *tr_cfg_parse_comm_rps (TR_CFG *trc, json_t *jrps, TR_CFG_RC *rc) +static void tr_cfg_parse_comm_rps(TR_CFG *trc, json_t *jrps, TR_COMM *comm, TR_CFG_RC *rc) { - TR_RP_REALM *rp = NULL; - TR_RP_REALM *temp_rp = NULL; - int i = 0; + TR_RP_REALM *found_rp=NULL; + TR_RP_REALM *new_rp=NULL; + TR_NAME *rp_name=NULL; + const char *s=NULL; + int ii=0; if ((!trc) || (!jrps) || (!json_is_array(jrps))) { if (rc) *rc = TR_CFG_BAD_PARAMS; - return NULL; + return; } - for (i = (json_array_size(jrps)-1); i >= 0; i--) { - if (NULL == (temp_rp = talloc(trc, TR_RP_REALM))) { - tr_debug("tr_cfg_parse_comm_rps: Can't allocate memory for RP Realm."); - if (rc) - *rc = TR_CFG_NOMEM; - return NULL; + for (ii=0; iilen, tr_comm_get_id(comm)->buf); + continue; } - memset (temp_rp, 0, sizeof(TR_RP_REALM)); - if (NULL == (temp_rp->realm_name = tr_new_name((char *)json_string_value(json_array_get(jrps, i))))) { - tr_debug("tr_cfg_parse_comm_rps: No memory for RP Realm Name."); - if (rc) - *rc = TR_CFG_NOMEM; - return NULL; + /* convert string to TR_NAME */ + rp_name=tr_new_name(s); + if (rp_name==NULL) { + tr_err("tr_cfg_parse_comm_rps: unable to allocate RP name for %s in community %.*s.", + s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf); } - temp_rp->next = rp; - rp = temp_rp; - } + /* see if we already have this RP in this community */ + found_rp=tr_comm_find_rp(trc->ctable, comm, rp_name); + if (found_rp!=NULL) { + tr_notice("tr_cfg_parse_comm_rps: RP %s repeated in community %.*s.", + s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf); + tr_free_name(rp_name); + continue; + } - return rp; + /* Add the RP to the community, first see if we have the RP in any community */ + found_rp=tr_rp_realm_lookup(trc->ctable->rp_realms, rp_name); + if (found_rp!=NULL) { + tr_debug("tr_cfg_parse_comm_rps: RP realm %s already exists.", s); + new_rp=found_rp; /* use it rather than creating a new realm record */ + } else { + new_rp=tr_rp_realm_new(NULL); + if (new_rp==NULL) { + tr_err("tr_cfg_parse_comm_rps: unable to allocate RP record for %s in community %.*s.", + s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf); + } + tr_debug("tr_cfg_parse_comm_rps: setting name to %s", rp_name->buf); + tr_rp_realm_set_id(new_rp, rp_name); + rp_name=NULL; /* rp_name no longer belongs to us */ + tr_rp_realm_add(trc->ctable->rp_realms, new_rp); + talloc_steal(trc->ctable, trc->ctable->rp_realms); /* make sure head is in the right context */ + } + tr_comm_add_rp_realm(trc->ctable, comm, new_rp, 0, NULL, NULL); + } } -static TR_COMM *tr_cfg_parse_one_comm (TR_CFG *trc, json_t *jcomm, TR_CFG_RC *rc) { +static TR_COMM *tr_cfg_parse_one_comm (TALLOC_CTX *mem_ctx, TR_CFG *trc, json_t *jcomm, TR_CFG_RC *rc) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); TR_COMM *comm = NULL; json_t *jid = NULL; json_t *jtype = NULL; @@ -725,13 +1598,14 @@ static TR_COMM *tr_cfg_parse_one_comm (TR_CFG *trc, json_t *jcomm, TR_CFG_RC *rc tr_debug("tr_cfg_parse_one_comm: Bad parameters."); if (rc) *rc = TR_CFG_BAD_PARAMS; - return NULL; + goto cleanup; } - if (NULL == (comm = talloc_zero(trc, TR_COMM))) { + comm=tr_comm_new(tmp_ctx); + if (comm==NULL) { tr_crit("tr_cfg_parse_one_comm: Out of memory."); *rc = TR_CFG_NOMEM; - return NULL; + goto cleanup; } @@ -747,13 +1621,16 @@ static TR_COMM *tr_cfg_parse_one_comm (TR_CFG *trc, json_t *jcomm, TR_CFG_RC *rc (!json_is_array(jrps))) { tr_debug("tr_cfg_parse_one_comm: Error parsing Communities configuration."); *rc = TR_CFG_NOPARSE; - return NULL; + comm=NULL; + goto cleanup; } - if (NULL == (comm->id = tr_new_name((char *)json_string_value(jid)))) { + tr_comm_set_id(comm, tr_new_name(json_string_value(jid))); + if (NULL == tr_comm_get_id(comm)) { tr_debug("tr_cfg_parse_one_comm: No memory for community id."); *rc = TR_CFG_NOMEM; - return NULL; + comm=NULL; + goto cleanup; } if (0 == strcmp(json_string_value(jtype), "apc")) { @@ -761,47 +1638,66 @@ static TR_COMM *tr_cfg_parse_one_comm (TR_CFG *trc, json_t *jcomm, TR_CFG_RC *rc } else if (0 == strcmp(json_string_value(jtype), "coi")) { comm->type = TR_COMM_COI; if (NULL == (comm->apcs = tr_cfg_parse_apcs(trc, japcs, rc))) { - tr_debug("tr_cfg_parse_one_comm: Can't parse APCs for COI %s.", comm->id->buf); - tr_free_name(comm->id); - return NULL; + tr_debug("tr_cfg_parse_one_comm: Can't parse APCs for COI %s.", + tr_comm_get_id(comm)->buf); + comm=NULL; + goto cleanup; } } else { - tr_debug("tr_cfg_parse_one_comm: Invalid community type, comm = %s, type = %s", comm->id->buf, json_string_value(jtype)); - tr_free_name(comm->id); + tr_debug("tr_cfg_parse_one_comm: Invalid community type, comm = %s, type = %s", + tr_comm_get_id(comm)->buf, json_string_value(jtype)); *rc = TR_CFG_NOPARSE; - return NULL; + comm=NULL; + goto cleanup; } - comm->idp_realms = tr_cfg_parse_comm_idps(trc, jidps, rc); + tr_cfg_parse_comm_idps(trc, jidps, comm, rc); if (TR_CFG_SUCCESS != *rc) { - tr_debug("tr_cfg_parse_one_comm: Can't parse IDP realms for comm %s.", comm->id->buf); - tr_free_name(comm->id); - return NULL; + tr_debug("tr_cfg_parse_one_comm: Can't parse IDP realms for comm %s.", + tr_comm_get_id(comm)->buf); + comm=NULL; + goto cleanup; } - comm->rp_realms = tr_cfg_parse_comm_rps(trc, jrps, rc); + tr_cfg_parse_comm_rps(trc, jrps, comm, rc); if (TR_CFG_SUCCESS != *rc) { - tr_debug("tr_cfg_parse_comm: Can't parse RP realms for comm %s .", comm->id->buf); - tr_free_name(comm->id); - return NULL; + tr_debug("tr_cfg_parse_one_comm: Can't parse RP realms for comm %s .", + tr_comm_get_id(comm)->buf); + comm=NULL; + goto cleanup; } if (TR_COMM_APC == comm->type) { json_t *jexpire = json_object_get(jcomm, "expiration_interval"); comm->expiration_interval = 43200; /*30 days*/ if (jexpire) { - if (!json_is_integer(jexpire)) { - fprintf(stderr, "tr_parse_comm: expirae_interval is not an integer\n"); - return NULL; - } - comm->expiration_interval = json_integer_value(jexpire); - if (comm->expiration_interval <= 10) - comm->expiration_interval = 11; /* Freeradius waits 10 minutes between successful TR queries*/ - if (comm->expiration_interval > 129600) /* 90 days*/ - comm->expiration_interval = 129600; + if (!json_is_integer(jexpire)) { + tr_err("tr_parse_one_comm: expiration_interval is not an integer for comm %.*s", + tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf); + comm=NULL; + goto cleanup; + } + comm->expiration_interval = json_integer_value(jexpire); + if (comm->expiration_interval <= 10) { + comm->expiration_interval = 11; /* Freeradius waits 10 minutes between successful TR queries*/ + tr_notice( + "tr_parse_one_comm: expiration interval for %.*s less than minimum of 11 minutes; using 11 minutes instead.", + tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf); + } + if (comm->expiration_interval > 129600) { + /* > 90 days*/ + comm->expiration_interval = 129600; + tr_notice( + "tr_parse_one_comm: expiration interval for %.*s exceeds maximum of 90 days; using 90 days instead.", + tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf); + } } } - + +cleanup: + if (comm!=NULL) + talloc_steal(mem_ctx, comm); + talloc_free(tmp_ctx); return comm; } @@ -823,20 +1719,24 @@ static TR_CFG_RC tr_cfg_parse_comms (TR_CFG *trc, json_t *jcfg) } for (i = 0; i < json_array_size(jcomms); i++) { - if (NULL == (comm = tr_cfg_parse_one_comm(trc, - json_array_get(jcomms, i), - &rc))) { - return rc; + if (NULL == (comm = tr_cfg_parse_one_comm(NULL, /* TODO: use a talloc context */ + trc, + json_array_get(jcomms, i), + &rc))) { + return rc; } - tr_debug("tr_cfg_parse_comms: Community configured: %s.", comm->id->buf); - comm->next = trc->comms; - trc->comms = comm; + tr_debug("tr_cfg_parse_comms: Community configured: %s.", + tr_comm_get_id(comm)->buf); + + tr_comm_table_add_comm(trc->ctable, comm); } } + tr_debug("tr_cfg_parse_comms: Finished (rc=%d)", rc); return rc; } -TR_CFG_RC tr_cfg_validate (TR_CFG *trc) { +TR_CFG_RC tr_cfg_validate(TR_CFG *trc) +{ TR_CFG_RC rc = TR_CFG_SUCCESS; if (!trc) @@ -853,12 +1753,12 @@ TR_CFG_RC tr_cfg_validate (TR_CFG *trc) { rc = TR_CFG_ERROR; } - if (NULL == trc->comms) { + if (0==tr_comm_table_size(trc->ctable)) { tr_debug("tr_cfg_validate: Error: No Communities configured"); rc = TR_CFG_ERROR; } - if ((NULL == trc->default_servers) && (NULL == trc->idp_realms)) { + if ((NULL == trc->default_servers) && (NULL == trc->ctable->idp_realms)) { tr_debug("tr_cfg_validate: Error: No default servers or IDPs configured."); rc = TR_CFG_ERROR; } @@ -866,64 +1766,202 @@ TR_CFG_RC tr_cfg_validate (TR_CFG *trc) { return rc; } -/* Join two paths and return a pointer to the result. This should be freed - * via talloc_free. Returns NULL on failure. */ -static char *join_paths(const char *p1, const char *p2) { - return talloc_asprintf(NULL, "%s/%s", p1, p2); /* returns NULL on a failure */ +static void tr_cfg_log_json_error(const char *label, json_error_t *rc) +{ + tr_debug("%s: JSON parse error on line %d: %s", + label, + rc->line, + rc->text); } -/* Reads configuration files in config_dir ("" or "./" will use the current directory) */ -TR_CFG_RC tr_parse_config (TR_INSTANCE *tr, const char *config_dir, int n, struct dirent **cfg_files) { - json_t *jcfg; +/** + * Parse a config file and return its JSON structure. Also emits a serial number to the log + * if one is present. + * + * @param file_with_path The file (with path!) to parse + * @return Pointer to the result of parsing, or null on error + */ +static json_t *tr_cfg_parse_one_config_file(const char *file_with_path) +{ + json_t *jcfg=NULL; + json_t *jser=NULL; json_error_t rc; - char *file_with_path; - if ((!tr) || (!cfg_files) || (n<=0)) - return TR_CFG_BAD_PARAMS; + if (NULL==(jcfg=json_load_file(file_with_path, + JSON_DISABLE_EOF_CHECK|JSON_REJECT_DUPLICATES, &rc))) { + tr_debug("tr_cfg_parse_one_config_file: Error parsing config file %s.", + file_with_path); + tr_cfg_log_json_error("tr_cfg_parse_one_config_file", &rc); + return NULL; + } - /* If there is a partial/abandoned config lying around, free it */ - if (tr->new_cfg) - tr_cfg_free(tr->new_cfg); - - if (NULL == (tr->new_cfg = talloc(NULL, TR_CFG))) - return TR_CFG_NOMEM; + // Look for serial number and log it if it exists (borrowed reference, so no need to free it later) + if (NULL!=(jser=json_object_get(jcfg, "serial_number"))) { + if (json_is_number(jser)) { + tr_notice("tr_parse_one_config_file: Attempting to load revision %" JSON_INTEGER_FORMAT " of '%s'.", + json_integer_value(jser), + file_with_path); + } + } - memset(tr->new_cfg, 0, sizeof(TR_CFG)); + return jcfg; +} - /* Parse configuration information from each config file */ - while (n--) { - file_with_path=join_paths(config_dir, cfg_files[n]->d_name); /* must free result with talloc_free */ - if(file_with_path == NULL) { - tr_crit("tr_parse_config: error joining path."); - return TR_CFG_NOMEM; - } - tr_debug("tr_parse_config: Parsing %s.", cfg_files[n]->d_name); /* print the filename without the path */ - if (NULL == (jcfg = json_load_file(file_with_path, - JSON_DISABLE_EOF_CHECK, &rc))) { - tr_debug("tr_parse_config: Error parsing config file %s.", - cfg_files[n]->d_name); - talloc_free(file_with_path); - return TR_CFG_NOPARSE; - } - talloc_free(file_with_path); /* done with filename */ - - if ((TR_CFG_SUCCESS != tr_cfg_parse_internal(tr->new_cfg, jcfg)) || - (TR_CFG_SUCCESS != tr_cfg_parse_rp_clients(tr->new_cfg, jcfg)) || - (TR_CFG_SUCCESS != tr_cfg_parse_idp_realms(tr->new_cfg, jcfg)) || - (TR_CFG_SUCCESS != tr_cfg_parse_default_servers(tr->new_cfg, jcfg)) || - (TR_CFG_SUCCESS != tr_cfg_parse_comms(tr->new_cfg, jcfg))) { - tr_cfg_free(tr->new_cfg); - return TR_CFG_ERROR; +/** + * Helper to free an array returned by tr_cfg_parse_config_files + * @param n_jcfgs + * @param jcfgs + */ +static void tr_cfg_parse_free_jcfgs(unsigned int n_jcfgs, json_t **jcfgs) +{ + int ii=0; + for (ii=0; iinew_cfg)) { - tr_debug("tr_parse_config: Error: INVALID CONFIGURATION, EXITING"); +/* define a type for config parse functions */ +typedef TR_CFG_RC (TR_CFG_PARSE_FN)(TR_CFG *, json_t *); +/** + * Helper function to parse a collection of JSON structures using a generic parse function. + * + * @param cfg Config structure to receive results + * @param parse_fn Function to apply + * @param n_jcfg Number of JSON structures in the array + * @param jcfgs Pointer to an array of decoded JSON structures + * @param key Key to extract from each jcfg before parsing, or NULL to use the object itself + * @return TR_CFG_SUCCESS on success, _FAIL or an error code on failure + */ +static TR_CFG_RC tr_cfg_parse_helper(TR_CFG *cfg, + TR_CFG_PARSE_FN parse_fn, + unsigned int n_jcfg, + json_t **jcfgs, + const char *key) +{ + size_t ii=0; + json_t *this_jcfg=NULL; + TR_CFG_RC ret=TR_CFG_ERROR; + + if ((cfg==NULL) || (jcfgs==NULL) || (parse_fn==NULL)) return TR_CFG_ERROR; + + for (ii=0; iinew != NULL) + tr_cfg_free(cfg_mgr->new); + cfg_mgr->new=tr_cfg_new(tmp_ctx); /* belongs to the temporary context for now */ + if (cfg_mgr->new == NULL) { + cfg_rc=TR_CFG_NOMEM; + goto cleanup; + } + + /* first parse the json */ + jcfgs=tr_cfg_parse_config_files(tmp_ctx, n_files, files_with_paths); + if (jcfgs==NULL) { + cfg_rc=TR_CFG_NOPARSE; + goto cleanup; + } + + cfg_mgr->new->peers=trp_ptable_new(cfg_mgr); /* not sure why this isn't in cfg_mgr->new's context */ + + /* now run through the parsers on the JSON */ + if ((TR_CFG_SUCCESS != (cfg_rc= tr_cfg_parse_helper(cfg_mgr->new, tr_cfg_parse_internal, n_files, jcfgs, "tr_internal"))) || + (TR_CFG_SUCCESS != (cfg_rc= tr_cfg_parse_helper(cfg_mgr->new, tr_cfg_parse_local_orgs, n_files, jcfgs, NULL))) || + (TR_CFG_SUCCESS != (cfg_rc= tr_cfg_parse_helper(cfg_mgr->new, tr_cfg_parse_peer_orgs, n_files, jcfgs, NULL))) || + (TR_CFG_SUCCESS != (cfg_rc= tr_cfg_parse_helper(cfg_mgr->new, tr_cfg_parse_default_servers, n_files, jcfgs, + NULL))) || + (TR_CFG_SUCCESS != (cfg_rc= tr_cfg_parse_helper(cfg_mgr->new, tr_cfg_parse_comms, n_files, jcfgs, NULL)))) + goto cleanup; /* cfg_rc was set above */ + + /* make sure we got a complete, consistent configuration */ + if (TR_CFG_SUCCESS != tr_cfg_validate(cfg_mgr->new)) { + tr_err("tr_parse_config: Error: INVALID CONFIGURATION"); + cfg_rc=TR_CFG_ERROR; + goto cleanup; + } + + /* success! */ + talloc_steal(cfg_mgr, cfg_mgr->new); /* hand this over to the cfg_mgr context */ + cfg_rc=TR_CFG_SUCCESS; + +cleanup: + if (jcfgs!=NULL) + tr_cfg_parse_free_jcfgs(n_files, jcfgs); + talloc_free(tmp_ctx); + return cfg_rc; } TR_IDP_REALM *tr_cfg_find_idp (TR_CFG *tr_cfg, TR_NAME *idp_id, TR_CFG_RC *rc) @@ -937,7 +1975,7 @@ TR_IDP_REALM *tr_cfg_find_idp (TR_CFG *tr_cfg, TR_NAME *idp_id, TR_CFG_RC *rc) return NULL; } - for (cfg_idp = tr_cfg->idp_realms; NULL != cfg_idp; cfg_idp = cfg_idp->next) { + for (cfg_idp = tr_cfg->ctable->idp_realms; NULL != cfg_idp; cfg_idp = cfg_idp->next) { if (!tr_name_cmp (idp_id, cfg_idp->realm_id)) { tr_debug("tr_cfg_find_idp: Found %s.", idp_id->buf); return cfg_idp; @@ -950,7 +1988,6 @@ TR_IDP_REALM *tr_cfg_find_idp (TR_CFG *tr_cfg, TR_NAME *idp_id, TR_CFG_RC *rc) TR_RP_CLIENT *tr_cfg_find_rp (TR_CFG *tr_cfg, TR_NAME *rp_gss, TR_CFG_RC *rc) { TR_RP_CLIENT *cfg_rp; - int i; if ((!tr_cfg) || (!rp_gss)) { if (rc) @@ -959,11 +1996,9 @@ TR_RP_CLIENT *tr_cfg_find_rp (TR_CFG *tr_cfg, TR_NAME *rp_gss, TR_CFG_RC *rc) } for (cfg_rp = tr_cfg->rp_clients; NULL != cfg_rp; cfg_rp = cfg_rp->next) { - for (i = 0; i < TR_MAX_GSS_NAMES; i++) { - if (!tr_name_cmp (rp_gss, cfg_rp->gss_names[i])) { - tr_debug("tr_cfg_find_rp: Found %s.", rp_gss->buf); - return cfg_rp; - } + if (tr_gss_names_matches(cfg_rp->gss_names, rp_gss)) { + tr_debug("tr_cfg_find_rp: Found %s.", rp_gss->buf); + return cfg_rp; } } /* if we didn't find one, return NULL */ @@ -1003,22 +2038,15 @@ static int is_cfg_file(const struct dirent *dent) { * allocated array of pointers to struct dirent entries, as returned * by scandir(). These can be freed with tr_free_config_file_list(). */ -int tr_find_config_files (const char *config_dir, struct dirent ***cfg_files) { - int n = 0, i = 0; +int tr_find_config_files(const char *config_dir, struct dirent ***cfg_files) { + int n = 0; - n = scandir(config_dir, cfg_files, &is_cfg_file, 0); + n = scandir(config_dir, cfg_files, is_cfg_file, alphasort); if (n < 0) { perror("scandir"); tr_debug("tr_find_config: scandir error trying to scan %s.", config_dir); - } else if (n == 0) { - tr_debug("tr_find_config: No config files found."); - } else { - i = n; - while(i--) { - tr_debug("tr_find_config: Config file found (%s).", (*cfg_files)[i]->d_name); - } - } + } return n; }