From: mrw42 Date: Fri, 4 May 2018 20:58:06 +0000 (-0400) Subject: Merge pull request #76 from painless-security/jennifer/trpc_deadlock X-Git-Tag: 3.4.0~1^2~34 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=trust_router.git;a=commitdiff_plain;h=81a61f8c6064bf52ff2a40a3d28e6ee5b2e478d4;hp=e404e4c6cbddaca8fcb9a563ce20fb19d6a722a3 Merge pull request #76 from painless-security/jennifer/trpc_deadlock Eliminate deadlock in TRPC messaging queueing --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ae8dba..1221d67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,7 +96,7 @@ set(SOURCE_FILES trp/trp_upd.c trp/trpc.c trp/trps.c include/tr_name_internal.h mon/mon_req.c mon/mon_req_encode.c mon/mon_req_decode.c - mon/mon_resp.c mon/mon_common.c mon/mon_resp_encode.c mon/mon_resp_decode.c tr/tr_mon.c mon/mons.c include/tr_socket.h common/tr_gss.c include/tr_gss.h common/tr_config_internal.c mon/mons_handlers.c include/mons_handlers.h tr/tr_tid_mons.c tr/tr_tid_mons.c trp/trp_route.c include/trp_route.h trp/trp_rtable_encoders.c trp/trp_route_encoders.c trp/trp_peer.c include/trp_peer.h trp/trp_peer_encoders.c trp/trp_ptable_encoders.c common/tr_idp_encoders.c common/tr_comm_encoders.c common/tr_rp_client.c include/tr_rp_client.h common/tr_rp_client_encoders.c common/tr_filter_encoders.c common/tr_config_encoders.c common/tr_config_filters.c common/tr_config_realms.c common/tr_config_rp_clients.c common/tr_config_orgs.c common/tr_config_comms.c) + mon/mon_resp.c mon/mon_common.c mon/mon_resp_encode.c mon/mon_resp_decode.c tr/tr_mon.c mon/mons.c include/tr_socket.h common/tr_gss.c include/tr_gss.h common/tr_config_internal.c mon/mons_handlers.c include/mons_handlers.h tr/tr_tid_mons.c tr/tr_tid_mons.c trp/trp_route.c include/trp_route.h trp/trp_rtable_encoders.c trp/trp_route_encoders.c trp/trp_peer.c include/trp_peer.h trp/trp_peer_encoders.c trp/trp_ptable_encoders.c common/tr_idp_encoders.c common/tr_comm_encoders.c common/tr_rp_client.c include/tr_rp_client.h common/tr_rp_client_encoders.c common/tr_filter_encoders.c common/tr_config_encoders.c common/tr_config_filters.c common/tr_config_realms.c common/tr_config_rp_clients.c common/tr_config_orgs.c common/tr_config_comms.c common/tr_list.c include/tr_list.h include/tr_constraint_internal.h) # Does not actually build! add_executable(trust_router ${SOURCE_FILES}) diff --git a/Makefile.am b/Makefile.am index 1c933d6..f75f5da 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,12 +27,14 @@ common_srcs = common/tr_name.c \ common/tr_filter_encoders.c \ common/tr_gss_names.c \ common/tr_socket.c \ + common/tr_list.c \ $(mon_srcs) tid_srcs = tid/tid_resp.c \ tid/tid_req.c \ tid/tids.c \ -tid/tidc.c +tid/tidc.c \ +common/tr_rand_id.c trp_srcs = trp/trp_conn.c \ trp/trps.c \ @@ -96,6 +98,7 @@ common/tr_debug.c \ common/tr_name.c \ common/tr_constraint.c \ common/tr_dh.c \ +common/tr_rand_id.c \ tid/tid_req.c \ tid/tid_resp.c @@ -145,6 +148,7 @@ tr_trmon_LDFLAGS = $(AM_LDFLAGS) -pthread trp_msgtst_SOURCES = trp/msgtst.c \ $(common_srcs) \ +common/tr_rand_id.c \ trp/trp_req.c \ trp/trp_upd.c \ tid/tid_resp.c \ @@ -156,6 +160,7 @@ common/tr_name.c \ common/tr_gss_names.c \ common/tr_debug.c \ common/tr_util.c \ +common/tr_list.c \ trp/trp_route.c \ trp/trp_route_encoders.c \ trp/trp_rtable.c \ @@ -277,6 +282,7 @@ noinst_HEADERS = include/gsscon.h include/tr_config.h \ include/tr_cfgwatch.h include/tr_event.h \ include/tr_mq.h include/trp_peer.h include/trp_ptable.h \ include/trp_rtable.h include/tr_util.h \ + include/tr_list.h \ include/tr_name_internal.h include/tr_gss.h pkgdata_DATA=schema.sql diff --git a/common/tests/cfg_test.c b/common/tests/cfg_test.c index 97cd03c..29a949d 100644 --- a/common/tests/cfg_test.c +++ b/common/tests/cfg_test.c @@ -41,6 +41,7 @@ #include #include #include +#include static void tr_talloc_log(const char *msg) { @@ -98,7 +99,6 @@ static int verify_idp_cfg(TR_CFG *cfg) static int verify_rp_cfg(TR_CFG *cfg) { - int ii=0; TR_NAME *name=NULL; assert(cfg!=NULL); @@ -107,11 +107,9 @@ static int verify_rp_cfg(TR_CFG *cfg) assert(cfg->rp_clients->comm_next==NULL); assert(cfg->rp_clients->gss_names!=NULL); - for (ii=1; iirp_clients->gss_names->names[ii]==NULL); - assert(cfg->rp_clients->gss_names->names[0]!=NULL); + assert(tr_gss_names_length(cfg->rp_clients->gss_names) == 1); name=tr_new_name("gss@example.com"); - assert(tr_name_cmp(name, cfg->rp_clients->gss_names->names[0])==0); + assert(tr_name_cmp(name, tr_gss_names_index(cfg->rp_clients->gss_names, 0))==0); return 0; } diff --git a/common/tr_comm.c b/common/tr_comm.c index e915b70..725fcac 100644 --- a/common/tr_comm.c +++ b/common/tr_comm.c @@ -40,9 +40,10 @@ #include #include #include +#include #include #include - +#include static int tr_comm_destructor(void *obj) { @@ -1060,6 +1061,18 @@ struct timespec *tr_comm_memb_get_expiry(TR_COMM_MEMB *memb) return memb->expiry; } +/** + * Get the expiration according to the realtime clock + * + * @param memb + * @param result space to store the result + * @return pointer to the result, or null on error + */ +struct timespec *tr_comm_memb_get_expiry_realtime(TR_COMM_MEMB *memb, struct timespec *result) +{ + return tr_clock_convert(TRP_CLOCK, memb->expiry, CLOCK_REALTIME, result); +} + int tr_comm_memb_is_expired(TR_COMM_MEMB *memb, struct timespec *curtime) { tr_debug("tr_comm_memb_is_expired: (cur->tv_sec>memb->expiry->tv_sec)=(%u > %u)=%s", @@ -1365,11 +1378,24 @@ TR_COMM *tr_comm_table_find_comm(TR_COMM_TABLE *ctab, TR_NAME *comm_id) return tr_comm_lookup(ctab->comms, comm_id); } -void tr_comm_table_add_comm(TR_COMM_TABLE *ctab, TR_COMM *new) +/** + * Add a community to the table. + * + * Does not allow duplicate community ids. + * + * @param ctab + * @param new + * @return 0 on success, -1 on failure + */ +int tr_comm_table_add_comm(TR_COMM_TABLE *ctab, TR_COMM *new) { + if (tr_comm_table_find_comm(ctab, tr_comm_get_id(new)) != NULL) + return -1; + tr_comm_add(ctab->comms, new); if (ctab->comms!=NULL) talloc_steal(ctab, ctab->comms); /* make sure it's in the right context */ + return 0; } void tr_comm_table_remove_comm(TR_COMM_TABLE *ctab, TR_COMM *comm) diff --git a/common/tr_comm_encoders.c b/common/tr_comm_encoders.c index c33c604..9f53008 100644 --- a/common/tr_comm_encoders.c +++ b/common/tr_comm_encoders.c @@ -40,19 +40,20 @@ static json_t *expiry_to_json_string(TR_COMM_MEMB *memb) { - struct timespec ts_zero = {0, 0}; + struct timespec ts = {0}; /* initialization to zero is important */ char *s = NULL; json_t *jstr = NULL; - if (tr_cmp_timespec(tr_comm_memb_get_expiry(memb), &ts_zero) == 0) { - s = strdup(""); - } else { - s = timespec_to_str(tr_comm_memb_get_expiry(memb)); - } + if (tr_cmp_timespec(tr_comm_memb_get_expiry(memb), &ts) > 0) { + if (tr_comm_memb_get_expiry_realtime(memb, &ts) == NULL) + s = strdup("error"); + else + s = timespec_to_str(&ts); - if (s) { - jstr = json_string(s); - free(s); + if (s) { + jstr = json_string(s); + free(s); + } } return jstr; @@ -143,10 +144,10 @@ static json_t *tr_comm_memb_sources_to_json(TR_COMM_MEMB *first_memb) goto cleanup; /* Iterate over all the memberships for this realm/comm pair that come from different origins */ - memb = tr_comm_memb_iter_first(iter, first_memb); - while (memb) { + for (memb = tr_comm_memb_iter_first(iter, first_memb); + memb != NULL; + memb = tr_comm_memb_iter_next(iter)) { ARRAY_APPEND_OR_FAIL(jarray, tr_comm_memb_to_json(memb)); - memb = tr_comm_memb_iter_next(iter); } /* success */ @@ -171,10 +172,12 @@ static json_t *tr_comm_realms_to_json(TR_COMM_TABLE *ctable, TR_NAME *comm_name, TR_COMM_MEMB *memb = NULL; iter = tr_comm_iter_new(NULL); - realm = tr_realm_iter_first(iter, ctable, comm_name); + realm = NULL; /* Do not display the full realm json here, only the name and info relevant to the community listing */ - while(realm) { + for (realm = tr_realm_iter_first(iter, ctable, comm_name); + realm != NULL; + realm = tr_realm_iter_next(iter)) { if (realm->role == role) { realm_json = json_object(); OBJECT_SET_OR_FAIL(realm_json, "realm", @@ -192,7 +195,6 @@ static json_t *tr_comm_realms_to_json(TR_COMM_TABLE *ctable, TR_NAME *comm_name, json_array_append_new(jarray, realm_json); realm_json = NULL; /* so we don't free this twice during cleanup */ } - realm = tr_realm_iter_next(iter); } /* Success - increment the reference count so return value survives */ @@ -275,15 +277,15 @@ json_t *tr_comm_table_to_json(TR_COMM_TABLE *ctable) goto cleanup; /* Iterate over communities in the table */ - comm = tr_comm_table_iter_first(iter, ctable); - while (comm) { + for (comm = tr_comm_table_iter_first(iter, ctable); + comm != NULL; + comm = tr_comm_table_iter_next(iter)) { comm_json = tr_comm_to_json(ctable, comm); if (comm_json == NULL) goto cleanup; json_array_append_new(ctable_json, comm_json); - comm = tr_comm_table_iter_next(iter); } /* succeeded - set the return value and increment the reference count */ diff --git a/common/tr_config_comms.c b/common/tr_config_comms.c index 60b5f93..99e2070 100644 --- a/common/tr_config_comms.c +++ b/common/tr_config_comms.c @@ -323,10 +323,13 @@ TR_CFG_RC tr_cfg_parse_comms (TR_CFG *trc, json_t *jcfg) &rc))) { return rc; } + if (tr_comm_table_add_comm(trc->ctable, comm) != 0) { + tr_debug("tr_cfg_parse_comms: Duplicate community %s.", tr_comm_get_id(comm)->buf); + return TR_CFG_NOPARSE; + } + 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); diff --git a/common/tr_config_filters.c b/common/tr_config_filters.c index 4035e68..7d4c615 100644 --- a/common/tr_config_filters.c +++ b/common/tr_config_filters.c @@ -35,33 +35,29 @@ #include #include #include -#include #include +#include #include -#include -#include -#include #include -#include -#include -#include -#include -#include #if JANSSON_VERSION_HEX < 0x020500 #include "jansson_iterators.h" #endif -static TR_CONSTRAINT *tr_cfg_parse_one_constraint(TALLOC_CTX *mem_ctx, char *ctype, json_t *jc, TR_CFG_RC *rc) +static TR_CONSTRAINT *tr_cfg_parse_one_constraint(TALLOC_CTX *mem_ctx, const char *ctype, json_t *jc, TR_CFG_RC *rc) { TR_CONSTRAINT *cons=NULL; - int i=0; + size_t i=0; - if ((!ctype) || (!jc) || (!rc) || + if (!rc) { + tr_err("tr_cfg_parse_one_constraint: rc is null, cannot process constraint."); + return NULL; + } + + if ((!ctype) || (!jc) || (!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_err("tr_cfg_parse_one_constraint: config error."); *rc=TR_CFG_NOPARSE; @@ -82,9 +78,8 @@ static TR_CONSTRAINT *tr_cfg_parse_one_constraint(TALLOC_CTX *mem_ctx, char *cty } 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); + if (NULL == tr_constraint_add_match(cons, tr_new_name(json_string_value(json_array_get(jc, i))))) { + tr_err("tr_cfg_parse_one_constraint: Out of memory (match %d).", i); *rc=TR_CFG_NOMEM; tr_constraint_free(cons); return NULL; @@ -98,6 +93,8 @@ static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR { TALLOC_CTX *tmp_ctx = talloc_new(NULL); TR_FILTER *filt = NULL; + TR_FLINE *fline = NULL; + TR_FSPEC *fspec = NULL; json_t *jfaction = NULL; json_t *jfline = NULL; json_t *jfspecs = NULL; @@ -125,13 +122,6 @@ static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR } tr_filter_set_type(filt, ftype); - /* 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; - goto cleanup; - } - /* For each entry in the filter... */ json_array_foreach(jfilt, i, jfline) { if ((NULL == (jfaction = json_object_get(jfline, "action"))) || @@ -149,24 +139,21 @@ static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR goto cleanup; } - if (TR_MAX_FILTER_SPECS < json_array_size(jfspecs)) { - tr_debug("tr_cfg_parse_one_filter: Filter has too many specs, maximimum of %d.", TR_MAX_FILTER_SPECS); - *rc = TR_CFG_NOPARSE; - goto cleanup; - } - - 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); + fline = tr_fline_new(tmp_ctx); + if (fline == NULL) { + tr_debug("tr_cfg_parse_one_filter: Out of memory allocating filter line %d.", i); *rc = TR_CFG_NOMEM; goto cleanup; } - if (!strcmp(json_string_value(jfaction), "accept")) { - filt->lines[i]->action = TR_FILTER_ACTION_ACCEPT; + fline->action = TR_FILTER_ACTION_ACCEPT; + tr_debug("tr_cfg_parse_one_filter: Filter action is 'accept'"); + } else if (!strcmp(json_string_value(jfaction), "reject")) { - filt->lines[i]->action = TR_FILTER_ACTION_REJECT; + fline->action = TR_FILTER_ACTION_REJECT; + tr_debug("tr_cfg_parse_one_filter: Filter action is 'reject'"); } else { - tr_debug("tr_cfg_parse_one_filter: Error parsing filter action, unknown action' %s'.", + tr_debug("tr_cfg_parse_one_filter: Error parsing filter action, unknown action '%s'.", json_string_value(jfaction)); *rc = TR_CFG_NOPARSE; goto cleanup; @@ -177,14 +164,9 @@ static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR 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))) { + if (NULL == (fline->realm_cons = tr_cfg_parse_one_constraint(fline, "realm", jrc, rc))) { tr_debug("tr_cfg_parse_one_filter: Error parsing realm constraint"); *rc = TR_CFG_NOPARSE; goto cleanup; @@ -197,13 +179,8 @@ static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR 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))) { + if (NULL == (fline->domain_cons = tr_cfg_parse_one_constraint(fline, "domain", jdc, rc))) { tr_debug("tr_cfg_parse_one_filter: Error parsing domain constraint"); *rc = TR_CFG_NOPARSE; goto cleanup; @@ -212,6 +189,7 @@ static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR } /*For each filter spec within the filter line... */ + tr_debug("tr_cfg_parse_one_filter: Filter line has %d spec(s)", json_array_size(jfspecs)); json_array_foreach(jfspecs, j, this_jfspec) { if ((NULL == (jfield = json_object_get(this_jfspec, "field"))) || (!json_is_string(jfield))) { @@ -239,14 +217,14 @@ static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR } /* allocate the filter spec */ - if (NULL == (filt->lines[i]->specs[j] = tr_fspec_new(filt->lines[i]))) { + if (NULL == (fspec = tr_fspec_new(fline))) { tr_debug("tr_cfg_parse_one_filter: Out of memory."); *rc = TR_CFG_NOMEM; goto cleanup; } /* fill in the field */ - if (NULL == (filt->lines[i]->specs[j]->field = tr_new_name(json_string_value(jfield)))) { + if (NULL == (fspec->field = tr_new_name(json_string_value(jfield)))) { tr_debug("tr_cfg_parse_one_filter: Out of memory."); *rc = TR_CFG_NOMEM; goto cleanup; @@ -259,7 +237,7 @@ static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR *rc = TR_CFG_NOMEM; goto cleanup; } - tr_fspec_add_match(filt->lines[i]->specs[j], name); + tr_fspec_add_match(fspec, name); } else { /* jmatch is an array (we checked earlier) */ json_array_foreach(jmatch, k, this_jmatch) { @@ -268,19 +246,32 @@ static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR *rc = TR_CFG_NOMEM; goto cleanup; } - tr_fspec_add_match(filt->lines[i]->specs[j], name); + tr_fspec_add_match(fspec, name); } } - if (!tr_filter_validate_spec_field(ftype, filt->lines[i]->specs[j])){ + if (!tr_filter_validate_spec_field(ftype, fspec)) { 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, + fspec->field->len, + fspec->field->buf, tr_filter_type_to_string(filt->type), i, j); *rc = TR_CFG_ERROR; goto cleanup; } + + if (tr_fline_add_spec(fline, fspec) == NULL) { + tr_debug("tr_cfg_parse_one_filter: Unable to add spec %d to line %d of %s filter.", + j, i, tr_filter_type_to_string(filt->type)); + } + } + + if (NULL == tr_filter_add_line(filt, fline)) { + tr_debug("tr_cfg_parse_one_filter: Error adding line %d for %s filter", + i, tr_filter_type_to_string(filt->type)); + *rc = TR_CFG_NOMEM; + goto cleanup; } + tr_debug("tr_cfg_parse_one_filter: Added line %d to %s filter", i, tr_filter_type_to_string(filt->type)); } /* check that the filter is valid */ @@ -341,12 +332,16 @@ TR_FILTER_SET *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_CFG_ /* 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; } + if (tr_filter_set_add(filt_set, filt) != 0) { + tr_debug("tr_cfg_parse_filters: Error adding %s filter to filter set.", filt_label); + *rc = TR_CFG_NOPARSE; + goto cleanup; + } } *rc=TR_CFG_SUCCESS; diff --git a/common/tr_config_rp_clients.c b/common/tr_config_rp_clients.c index 960edce..b263c02 100644 --- a/common/tr_config_rp_clients.c +++ b/common/tr_config_rp_clients.c @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include #include @@ -113,6 +113,8 @@ static TR_FILTER_SET *tr_cfg_default_filters(TALLOC_CTX *mem_ctx, TR_NAME *realm { TALLOC_CTX *tmp_ctx=talloc_new(NULL); TR_FILTER *filt=NULL; + TR_FLINE *fline = NULL; + TR_FSPEC *fspec = NULL; TR_FILTER_SET *filt_set=NULL; TR_CONSTRAINT *cons=NULL; TR_NAME *name=NULL; @@ -147,16 +149,18 @@ static TR_FILTER_SET *tr_cfg_default_filters(TALLOC_CTX *mem_ctx, TR_NAME *realm goto cleanup; } tr_filter_set_type(filt, TR_FILTER_TYPE_TID_INBOUND); - filt->lines[0]=tr_fline_new(filt); - if (filt->lines[0]==NULL) { + + fline = tr_fline_new(tmp_ctx); + if (fline==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; + fline->action=TR_FILTER_ACTION_ACCEPT; + + fspec=tr_fspec_new(tmp_ctx); + fspec->field=n_rp_realm_1; n_rp_realm_1=NULL; /* we don't own this name any more */ name=tr_dup_name(realm); @@ -165,12 +169,18 @@ static TR_FILTER_SET *tr_cfg_default_filters(TALLOC_CTX *mem_ctx, TR_NAME *realm *rc=TR_CFG_NOMEM; goto cleanup; } - tr_fspec_add_match(filt->lines[0]->specs[0], name); + tr_fspec_add_match(fspec, name); name=NULL; /* we no longer own the name */ + if (tr_fline_add_spec(fline, fspec) == NULL) { + tr_debug("tr_cfg_default_filters: could not add first spec to filter line"); + *rc = TR_CFG_NOMEM; + goto cleanup; + } + /* 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; + fspec=tr_fspec_new(tmp_ctx); + fspec->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))) { @@ -179,11 +189,17 @@ static TR_FILTER_SET *tr_cfg_default_filters(TALLOC_CTX *mem_ctx, TR_NAME *realm goto cleanup; } - tr_fspec_add_match(filt->lines[0]->specs[1], name); + tr_fspec_add_match(fspec, name); name=NULL; /* we no longer own the name */ + if (tr_fline_add_spec(fline, fspec) == NULL) { + tr_debug("tr_cfg_default_filters: could not add second spec to filter line"); + *rc = TR_CFG_NOMEM; + goto cleanup; + } + /* domain constraint */ - if (NULL==(cons=tr_constraint_new(filt->lines[0]))) { + if (NULL==(cons=tr_constraint_new(fline))) { tr_debug("tr_cfg_default_filters: could not allocate domain constraint."); *rc=TR_CFG_NOMEM; goto cleanup; @@ -197,20 +213,28 @@ static TR_FILTER_SET *tr_cfg_default_filters(TALLOC_CTX *mem_ctx, TR_NAME *realm *rc=TR_CFG_NOMEM; goto cleanup; } - cons->matches[0]=name; + if (NULL == tr_constraint_add_match(cons, name)) { + tr_debug("tr_cfg_default_filters: could not add realm name for domain constraint."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } 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; + if (NULL == tr_constraint_add_match(cons, name)) { + tr_debug("tr_cfg_default_filters: could not add wildcard realm name for domain constraint."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } name=NULL; - filt->lines[0]->domain_cons=cons; + fline->domain_cons=cons; /* realm constraint */ - if (NULL==(cons=tr_constraint_new(filt->lines[0]))) { + if (NULL==(cons=tr_constraint_new(fline))) { tr_debug("tr_cfg_default_filters: could not allocate realm constraint."); *rc=TR_CFG_NOMEM; goto cleanup; @@ -224,16 +248,31 @@ static TR_FILTER_SET *tr_cfg_default_filters(TALLOC_CTX *mem_ctx, TR_NAME *realm *rc=TR_CFG_NOMEM; goto cleanup; } - cons->matches[0]=name; + if (NULL == tr_constraint_add_match(cons, name)) { + tr_debug("tr_cfg_default_filters: could not add realm name for realm constraint."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } 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; + if (NULL == tr_constraint_add_match(cons, name)) { + tr_debug("tr_cfg_default_filters: could not add wildcard realm name for realm constraint."); + *rc=TR_CFG_NOMEM; + goto cleanup; + } name=NULL; - filt->lines[0]->realm_cons=cons; + fline->realm_cons=cons; + + /* put the fline in the filter */ + if (NULL == tr_filter_add_line(filt, fline)) { + tr_debug("tr_cfg_default_filters: could not add line to filter."); + *rc = TR_CFG_NOMEM; + goto cleanup; + } /* put the filter in a set */ filt_set=tr_filter_set_new(tmp_ctx); diff --git a/common/tr_constraint.c b/common/tr_constraint.c index da5f42e..f9fcf61 100644 --- a/common/tr_constraint.c +++ b/common/tr_constraint.c @@ -38,35 +38,46 @@ #include #include -#include #include #include #include +#include - +/** + * Helper for tr_constraint_destructor - calls tr_free_name on its first argument + * + * @param item void pointer to a TR_NAME + * @param cookie ignored + */ +static void constraint_destruct_helper(void *item, void *cookie) +{ + TR_NAME *name = (TR_NAME *) item; + tr_free_name(name); +} static int tr_constraint_destructor(void *obj) { TR_CONSTRAINT *cons = talloc_get_type_abort(obj, TR_CONSTRAINT); - int ii = 0; - if (cons->type != NULL) + if (cons->type) tr_free_name(cons->type); - for (ii = 0; ii < TR_MAX_CONST_MATCHES; ii++) { - if (cons->matches[ii] != NULL) - tr_free_name(cons->matches[ii]); - } + + if (cons->matches) + tr_list_foreach(cons->matches, constraint_destruct_helper, NULL); + return 0; } TR_CONSTRAINT *tr_constraint_new(TALLOC_CTX *mem_ctx) { TR_CONSTRAINT *cons = talloc(mem_ctx, TR_CONSTRAINT); - int ii = 0; if (cons != NULL) { cons->type = NULL; - for (ii = 0; ii < TR_MAX_CONST_MATCHES; ii++) - cons->matches[ii] = NULL; + cons->matches = tr_list_new(cons); + if (cons->matches == NULL) { + talloc_free(cons); + return NULL; + } talloc_set_destructor((void *) cons, tr_constraint_destructor); } return cons; @@ -77,25 +88,63 @@ void tr_constraint_free(TR_CONSTRAINT *cons) talloc_free(cons); } +/** + * Helper for tr_constraint_dup - duplicates a TR_NAME and adds it as a TR_CONSTRAINT match + * + * No return value. If this succeeds, it will have added a new entry to the TR_CONSTRAINT + * match list. Check the length of that - you won't be able to tell whether the allocation + * of the duplicate TR_NAME or the addition to the list failed, but either of those is probably + * due to a memory allocation failure, in which case the system is probably crashing anyway. + * + * @param item void pointer to a TR_NAME to add as a match + * @param cookie void pointer to a TR_CONSTRAINT to add the match to + */ +static void cons_dup_helper(void *item, void *cookie) +{ + TR_CONSTRAINT *new_cons = talloc_get_type_abort(cookie, TR_CONSTRAINT); + TR_NAME *new_name = tr_dup_name((TR_NAME *) item); + if (new_name) { + /* check that new_name is added, free if it fails */ + if (tr_constraint_add_match(new_cons, new_name) == NULL) + tr_free_name(new_name); + } +} +/** + * Duplicate a TR_CONSTRAINT + * + * @param mem_ctx talloc context for the result + * @param cons TR_CONSTRAINT to duplicate + * @return pointer to the new TR_CONSTRAINT, or NULL on error + */ TR_CONSTRAINT *tr_constraint_dup(TALLOC_CTX *mem_ctx, TR_CONSTRAINT *cons) { - TALLOC_CTX *tmp_ctx = NULL; + TALLOC_CTX *tmp_ctx = talloc_new(NULL); TR_CONSTRAINT *new = NULL; - int ii = 0; if (cons == NULL) - return NULL; + goto cleanup; - tmp_ctx = talloc_new(NULL); new = tr_constraint_new(tmp_ctx); + if (new == NULL) + goto cleanup; + + new->type = tr_dup_name(cons->type); + if (new->type == NULL) { + new = NULL; + goto cleanup; + } - if (new != NULL) { - new->type = tr_dup_name(cons->type); - for (ii = 0; ii < TR_MAX_CONST_MATCHES; ii++) - new->matches[ii] = tr_dup_name(cons->matches[ii]); - talloc_steal(mem_ctx, new); + tr_list_foreach(cons->matches, cons_dup_helper, new); /* copies matches to new->matches */ + /* check that we were successful - if we were, then the lists will be the same length */ + if (tr_list_length(new->matches) != tr_list_length(cons->matches)) { + new = NULL; + goto cleanup; /* at least one dup or add failed */ } + /* success */ + talloc_steal(mem_ctx, new); + +cleanup: talloc_free(tmp_ctx); return new; } @@ -165,7 +214,8 @@ void tr_constraint_add_to_set(TR_CONSTRAINT_SET **cset, TR_CONSTRAINT *cons) { json_t *jcons = NULL; json_t *jmatches = NULL; - int i = 0; + TR_NAME *this_match = NULL; + TR_CONSTRAINT_ITER iter = {0}; if ((!cset) || (!cons)) return; @@ -178,8 +228,11 @@ void tr_constraint_add_to_set(TR_CONSTRAINT_SET **cset, TR_CONSTRAINT *cons) jmatches = json_array(); jcons = json_object(); - for (i = 0; ((i < TR_MAX_CONST_MATCHES) && (NULL != cons->matches[i])); i++) { - json_array_append_new(jmatches, json_string(cons->matches[i]->buf)); + for (this_match = tr_constraint_iter_first(&iter, cons); + this_match != NULL; + this_match = tr_constraint_iter_next(&iter)) + { + json_array_append_new(jmatches, tr_name_to_json_string(this_match)); } json_object_set_new(jcons, cons->type->buf, jmatches); @@ -226,7 +279,6 @@ int tr_constraint_set_validate(TR_CONSTRAINT_SET *cset) { return 1; } - /** * Create a new constraint set containing all constraints from #orig * with constraint_type #constraint_type and no others. This constraint set is @@ -244,7 +296,8 @@ TR_CONSTRAINT_SET *tr_constraint_set_filter(TID_REQ *request, tr_debug ("tr_constraint_set_filter: not a valid constraint set\n"); return NULL; } - assert (new_cs = json_array()); + new_cs = json_array(); + assert(new_cs); json_array_foreach(orig_cset, index, set_member) { if (json_object_get(set_member, constraint_type)) json_array_append(new_cs, set_member); @@ -350,12 +403,14 @@ TR_CONSTRAINT_SET *tr_constraint_set_intersect(TID_REQ *request, domain = constraint_intersect_internal(input, "domain"); realm = constraint_intersect_internal(input, "realm"); } - assert(result = json_object()); + result = json_object(); + assert(result); if (domain) json_object_set_new(result, "domain", domain); if (realm) json_object_set_new(result, "realm", realm); - assert(result_array = json_array()); + result_array = json_array(); + assert(result_array); json_array_append_new(result_array, result); tid_req_cleanup_json(request, result_array); return (TR_CONSTRAINT_SET *) result_array; diff --git a/common/tr_filter.c b/common/tr_filter.c index 52dffb4..2b94526 100644 --- a/common/tr_filter.c +++ b/common/tr_filter.c @@ -408,34 +408,34 @@ int tr_filter_apply(TR_FILTER_TARGET *target, TR_CONSTRAINT_SET **constraints, TR_FILTER_ACTION *out_action) { - unsigned int ii=0, jj=0; + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + TR_FILTER_ITER *filt_iter = tr_filter_iter_new(tmp_ctx); + TR_FLINE *this_fline = NULL; + TR_FLINE_ITER *fline_iter = tr_fline_iter_new(tmp_ctx); + TR_FSPEC *this_fspec = NULL; int retval=TR_FILTER_NO_MATCH; /* Default action is reject */ *out_action = TR_FILTER_ACTION_REJECT; /* Validate filter */ - if ((filt==NULL) || (filt->type==TR_FILTER_TYPE_UNKNOWN)) + if ((filt_iter == NULL) || (fline_iter == NULL) || (filt==NULL) || (filt->type==TR_FILTER_TYPE_UNKNOWN)) { + talloc_free(tmp_ctx); return TR_FILTER_NO_MATCH; + } /* Step through filter lines looking for a match. If a line matches, retval * will be set to TR_FILTER_MATCH, so stop then. */ - for (ii=0, retval=TR_FILTER_NO_MATCH; - iilines[ii]==NULL) - continue; - + for (this_fline = tr_filter_iter_first(filt_iter, filt); + this_fline != NULL; + this_fline = tr_filter_iter_next(filt_iter)) { /* Assume we are going to succeed. If any specs fail to match, we'll set * this to TR_FILTER_NO_MATCH. */ retval=TR_FILTER_MATCH; - for (jj=0; jjlines[ii]->specs[jj]==NULL) - continue; - - if (!tr_fspec_matches(filt->lines[ii]->specs[jj], filt->type, target)) { + for (this_fspec = tr_fline_iter_first(fline_iter, this_fline); + this_fspec != NULL; + this_fspec = tr_fline_iter_next(fline_iter)) { + if (!tr_fspec_matches(this_fspec, filt->type, target)) { retval=TR_FILTER_NO_MATCH; /* set this in case this is the last filter line */ break; /* give up on this filter line */ } @@ -443,15 +443,16 @@ int tr_filter_apply(TR_FILTER_TARGET *target, if (retval==TR_FILTER_MATCH) break; + } if (retval==TR_FILTER_MATCH) { /* Matched line ii. Grab its action and constraints. */ - *out_action = filt->lines[ii]->action; + *out_action = this_fline->action; if (constraints!=NULL) { /* if either constraint is missing, these are no-ops */ - tr_constraint_add_to_set(constraints, filt->lines[ii]->realm_cons); - tr_constraint_add_to_set(constraints, filt->lines[ii]->domain_cons); + tr_constraint_add_to_set(constraints, this_fline->realm_cons); + tr_constraint_add_to_set(constraints, this_fline->domain_cons); } } @@ -463,55 +464,65 @@ void tr_fspec_free(TR_FSPEC *fspec) talloc_free(fspec); } +/** + * Helper for tr_fspec_destructor - calls tr_free_name on its first argument + * + * @param item void pointer to a TR_NAME + * @param cookie ignored + */ +static void fspec_destruct_helper(void *item, void *cookie) +{ + TR_NAME *name = (TR_NAME *) item; + tr_free_name(name); +} static int tr_fspec_destructor(void *obj) { TR_FSPEC *fspec = talloc_get_type_abort(obj, TR_FSPEC); - size_t ii; if (fspec->field != NULL) tr_free_name(fspec->field); - for (ii=0; iimatch[ii] != NULL) - tr_free_name(fspec->match[ii]); - } + + if (fspec->match) + tr_list_foreach(fspec->match, fspec_destruct_helper, NULL); + return 0; } TR_FSPEC *tr_fspec_new(TALLOC_CTX *mem_ctx) { TR_FSPEC *fspec = talloc(mem_ctx, TR_FSPEC); - size_t ii=0; if (fspec != NULL) { fspec->field = NULL; - for (ii=0; iimatch[ii] = NULL; - + fspec->match = tr_list_new(fspec); + if (fspec->match == NULL) { + talloc_free(fspec); + return NULL; + } talloc_set_destructor((void *)fspec, tr_fspec_destructor); } return fspec; } -void tr_fspec_add_match(TR_FSPEC *fspec, TR_NAME *match) +/* Helper function and cookie structure for finding a match. The helper is called + * for every item in the match list, even after a match is found. If a match is found, + * match should be pointed to the matching item. If this is not NULL, do not change it + * because a match has already been found. */ +struct fspec_match_cookie { TR_NAME *name; TR_NAME *match;}; +static void fspec_match_helper(void *item, void *data) { - size_t ii; - for (ii=0; iimatch[ii]==NULL) { - fspec->match[ii]=match; - break; - } + TR_NAME *this_name = (TR_NAME *) item; + struct fspec_match_cookie *cookie = (struct fspec_match_cookie *) data; + if (cookie->match == NULL) { + if (tr_name_prefix_wildcard_match(cookie->name, this_name)) + cookie->match = this_name; } - /* TODO: handle case that adding the match failed */ } - /* returns 1 if the spec matches */ int tr_fspec_matches(TR_FSPEC *fspec, TR_FILTER_TYPE ftype, TR_FILTER_TARGET *target) { struct tr_filter_field_entry *field=NULL; - TR_NAME *name=NULL; - int retval=0; - - size_t ii=0; + struct fspec_match_cookie cookie = {0}; if (fspec==NULL) return 0; @@ -525,32 +536,27 @@ int tr_fspec_matches(TR_FSPEC *fspec, TR_FILTER_TYPE ftype, TR_FILTER_TARGET *ta return 0; } - name=field->get(target); - if (name==NULL) + cookie.name = field->get(target); + if (cookie.name==NULL) return 0; /* if there's no value, there's no match */ - for (ii=0; iimatch[ii]!=NULL) { - if (tr_name_prefix_wildcard_match(name, fspec->match[ii])) { - retval=1; - tr_debug("tr_fspec_matches: Field %.*s value \"%.*s\" matches \"%.*s\" for %s filter.", - fspec->field->len, fspec->field->buf, - name->len, name->buf, - fspec->match[ii]->len, fspec->match[ii]->buf, - tr_filter_type_to_string(ftype)); - break; - } - } - } - - if (!retval) { + cookie.match = NULL; + tr_list_foreach(fspec->match, + fspec_match_helper, + &cookie); + if (cookie.match) { + tr_debug("tr_fspec_matches: Field %.*s value \"%.*s\" matches \"%.*s\" for %s filter.", + fspec->field->len, fspec->field->buf, + cookie.name->len, cookie.name->buf, + cookie.match->len, cookie.match->buf, + tr_filter_type_to_string(ftype)); + } else { tr_debug("tr_fspec_matches: Field %.*s value \"%.*s\" does not match for %s filter.", fspec->field->len, fspec->field->buf, - name->len, name->buf, + cookie.name->len, cookie.name->buf, tr_filter_type_to_string(ftype)); } - tr_free_name(name); - return retval; + return (cookie.match != NULL); } void tr_fline_free(TR_FLINE *fline) @@ -561,14 +567,16 @@ void tr_fline_free(TR_FLINE *fline) TR_FLINE *tr_fline_new(TALLOC_CTX *mem_ctx) { TR_FLINE *fl = talloc(mem_ctx, TR_FLINE); - int ii = 0; if (fl != NULL) { fl->action = TR_FILTER_ACTION_UNKNOWN; fl->realm_cons = NULL; fl->domain_cons = NULL; - for (ii = 0; ii < TR_MAX_FILTER_SPECS; ii++) - fl->specs[ii] = NULL; + fl->specs = tr_list_new(fl); + if (fl->specs == NULL) { + talloc_free(fl); + return NULL; + } } return fl; } @@ -576,12 +584,14 @@ TR_FLINE *tr_fline_new(TALLOC_CTX *mem_ctx) TR_FILTER *tr_filter_new(TALLOC_CTX *mem_ctx) { TR_FILTER *f = talloc(mem_ctx, TR_FILTER); - int ii = 0; if (f != NULL) { f->type = TR_FILTER_TYPE_UNKNOWN; - for (ii = 0; ii < TR_MAX_FILTER_LINES; ii++) - f->lines[ii] = NULL; + f->lines = tr_list_new(f); + if (f->lines == NULL) { + talloc_free(f); + return NULL; + } } return f; } @@ -609,10 +619,16 @@ TR_FILTER_TYPE tr_filter_get_type(TR_FILTER *filt) */ int tr_filter_validate(TR_FILTER *filt) { - size_t ii=0, jj=0, kk=0; - - if (!filt) + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + TR_FILTER_ITER *filt_iter = tr_filter_iter_new(tmp_ctx); + TR_FLINE *this_fline = NULL; + TR_FLINE_ITER *fline_iter = tr_fline_iter_new(tmp_ctx); + TR_FSPEC *this_fspec = NULL; + + if ((!filt) || (!filt_iter) || (!fline_iter)) { + talloc_free(tmp_ctx); return 0; + } /* check that we recognize the type */ switch(filt->type) { @@ -622,41 +638,43 @@ int tr_filter_validate(TR_FILTER *filt) break; default: + talloc_free(tmp_ctx); return 0; /* if we get here, either TR_FILTER_TYPE_UNKNOWN or an invalid value was found */ } - for (ii=0; iilines[ii]==NULL) - continue; /* an empty filter line is valid */ - + + for (this_fline = tr_filter_iter_first(filt_iter, filt); + this_fline != NULL; + this_fline = tr_filter_iter_next(filt_iter)) { /* check that we recognize the action */ - switch(filt->lines[ii]->action) { + switch(this_fline->action) { case TR_FILTER_ACTION_ACCEPT: case TR_FILTER_ACTION_REJECT: break; default: /* if we get here, either TR_FILTER_ACTION_UNKNOWN or an invalid value was found */ + talloc_free(tmp_ctx); return 0; } - for (jj=0; jjlines[ii]->specs[jj]==NULL) - continue; /* an empty filter spec is valid */ - - if (!tr_filter_validate_spec_field(filt->type, filt->lines[ii]->specs[jj])) + for (this_fspec = tr_fline_iter_first(fline_iter, this_fline); + this_fspec != NULL; + this_fspec = tr_fline_iter_next(fline_iter)) { + if (!tr_filter_validate_spec_field(filt->type, this_fspec)) { + talloc_free(tmp_ctx); return 0; - - /* check that at least one match is non-null */ - for (kk=0; kklines[ii]->specs[jj]->match[kk]!=NULL) - break; } - if (kk==TR_MAX_FILTER_SPEC_MATCHES) + + /* check that at least one match is defined*/ + if (tr_list_length(this_fspec->match) == 0) { + talloc_free(tmp_ctx); return 0; + } } } /* We ran the gauntlet. Success! */ + talloc_free(tmp_ctx); return 1; } diff --git a/common/tr_filter_encoders.c b/common/tr_filter_encoders.c index cc22b02..932be9e 100644 --- a/common/tr_filter_encoders.c +++ b/common/tr_filter_encoders.c @@ -36,6 +36,7 @@ #include #include +#include /* helper for below */ #define OBJECT_SET_OR_FAIL(jobj, key, val) \ @@ -57,18 +58,48 @@ do { \ typedef json_t *(ITEM_ENCODER_FUNC)(void *); -static json_t *items_to_json_array(void *items[], ITEM_ENCODER_FUNC *item_encoder, size_t max_items) +enum array_type { + ARRAY_TYPE_FSPEC, + ARRAY_TYPE_CONSTRAINT +}; +/** + * Make an array of matches from a TR_FSPEC or TR_CONSTRAINT + * + * @param obj + * @param type + * @return + */ +static json_t *tr_names_to_json_array(void *obj, enum array_type type) { - size_t ii; json_t *jarray = json_array(); json_t *retval = NULL; + TR_FSPEC_ITER fspec_iter = {0}; + TR_CONSTRAINT_ITER cons_iter = {0}; + TR_NAME *this_match = NULL; if (jarray == NULL) goto cleanup; - for (ii=0; iifield)); OBJECT_SET_OR_FAIL(fspec_json, "matches", - items_to_json_array((void **)fspec->match, - (ITEM_ENCODER_FUNC *) tr_name_to_json_string, - TR_MAX_FILTER_SPEC_MATCHES)); + tr_names_to_json_array(fspec, ARRAY_TYPE_FSPEC)); /* succeeded - set the return value and increment the reference count */ retval = fspec_json; @@ -107,6 +136,34 @@ cleanup: return retval; } +static json_t *tr_fspecs_to_json_array(TR_FLINE *fline) +{ + json_t *jarray = json_array(); + json_t *retval = NULL; + TR_FLINE_ITER *iter = tr_fline_iter_new(NULL); + TR_FSPEC *this_fspec = NULL; + + if ((jarray == NULL) || (iter == NULL)) + goto cleanup; + + for (this_fspec = tr_fline_iter_first(iter, fline); + this_fspec != NULL; + this_fspec = tr_fline_iter_next(iter)) { + ARRAY_APPEND_OR_FAIL(jarray, tr_fspec_to_json(this_fspec)); + } + /* success */ + retval = jarray; + json_incref(retval); + +cleanup: + if (jarray) + json_decref(jarray); + if (iter) + tr_fline_iter_free(iter); + + return retval; +} + static json_t *tr_fline_to_json(TR_FLINE *fline) { json_t *fline_json = NULL; @@ -119,20 +176,14 @@ static json_t *tr_fline_to_json(TR_FLINE *fline) OBJECT_SET_OR_FAIL(fline_json, "action", json_string( (fline->action == TR_FILTER_ACTION_ACCEPT) ? "accept" : "reject")); OBJECT_SET_OR_FAIL(fline_json, "specs", - items_to_json_array((void **)fline->specs, - (ITEM_ENCODER_FUNC *) tr_fspec_to_json, - TR_MAX_FILTER_SPECS)); + tr_fspecs_to_json_array(fline)); if (fline->realm_cons) { OBJECT_SET_OR_FAIL(fline_json, "realm_constraints", - items_to_json_array((void **) fline->realm_cons->matches, - (ITEM_ENCODER_FUNC *) tr_name_to_json_string, - TR_MAX_CONST_MATCHES)); + tr_names_to_json_array(fline->realm_cons, ARRAY_TYPE_CONSTRAINT)); } if (fline->domain_cons) { OBJECT_SET_OR_FAIL(fline_json, "domain_constraints", - items_to_json_array((void **) fline->domain_cons->matches, - (ITEM_ENCODER_FUNC *) tr_name_to_json_string, - TR_MAX_CONST_MATCHES)); + tr_names_to_json_array(fline->domain_cons, ARRAY_TYPE_CONSTRAINT)); } /* succeeded - set the return value and increment the reference count */ @@ -145,6 +196,33 @@ cleanup: return retval; } +static json_t *tr_flines_to_json_array(TR_FILTER *filt) +{ + json_t *jarray = json_array(); + json_t *retval = NULL; + TR_FILTER_ITER *iter = tr_filter_iter_new(NULL); + TR_FLINE *this_fline = NULL; + + if ((jarray == NULL) || (iter == NULL)) + goto cleanup; + + for(this_fline = tr_filter_iter_first(iter, filt); + this_fline != NULL; + this_fline = tr_filter_iter_next(iter)) { + ARRAY_APPEND_OR_FAIL(jarray, tr_fline_to_json(this_fline)); + } + /* success */ + retval = jarray; + json_incref(retval); + +cleanup: + if (jarray) + json_decref(jarray); + if (iter) + tr_filter_iter_free(iter); + + return retval; +} json_t *tr_filter_set_to_json(TR_FILTER_SET *filter_set) { json_t *fset_json = NULL; @@ -166,9 +244,7 @@ json_t *tr_filter_set_to_json(TR_FILTER_SET *filter_set) filt = tr_filter_set_get(filter_set, *filt_type); if (filt) { OBJECT_SET_OR_FAIL(fset_json, tr_filter_type_to_string(*filt_type), - items_to_json_array((void **)filt->lines, - (ITEM_ENCODER_FUNC *) tr_fline_to_json, - TR_MAX_FILTER_LINES)); + tr_flines_to_json_array(filt)); } } diff --git a/common/tr_gss_names.c b/common/tr_gss_names.c index df15202..416ba8c 100644 --- a/common/tr_gss_names.c +++ b/common/tr_gss_names.c @@ -33,29 +33,38 @@ */ #include +#include #include #include +/** + * Helper for tr_gss_names_destructor - calls tr_free_name on its first argument + * + * @param item void pointer to a TR_NAME + * @param cookie ignored + */ +static void gss_names_destruct_helper(void *item, void *cookie) +{ + TR_NAME *name = (TR_NAME *) item; + tr_free_name(name); +} static int tr_gss_names_destructor(void *obj) { TR_GSS_NAMES *gss_names=talloc_get_type_abort(obj, TR_GSS_NAMES); - int ii=0; - - for (ii=0; iinames[ii]!=NULL) - tr_free_name(gss_names->names[ii]); - } + if (gss_names->names) + tr_list_foreach(gss_names->names, gss_names_destruct_helper, NULL); return 0; } TR_GSS_NAMES *tr_gss_names_new(TALLOC_CTX *mem_ctx) { - TR_GSS_NAMES *gn=talloc(mem_ctx, TR_GSS_NAMES); - int ii=0; - - if (gn!=NULL) { - for (ii=0; iinames[ii]=NULL; + TR_GSS_NAMES *gn = talloc(mem_ctx, TR_GSS_NAMES); + if (gn != NULL) { + gn->names = tr_list_new(gn); + if (gn->names == NULL) { + talloc_free(gn); + return NULL; + } talloc_set_destructor((void *)gn, tr_gss_names_destructor); } return gn; @@ -69,17 +78,7 @@ void tr_gss_names_free(TR_GSS_NAMES *gn) /* returns 0 on success */ int tr_gss_names_add(TR_GSS_NAMES *gn, TR_NAME *new) { - int ii=0; - - for (ii=0; iinames[ii]==NULL) - break; - } - if (ii!=TR_MAX_GSS_NAMES) { - gn->names[ii]=new; - return 0; - } else - return -1; + return (NULL == tr_list_add(gn->names, new, 0)); /* nonzero if the add failed */ } /** @@ -100,68 +99,36 @@ TR_GSS_NAMES *tr_gss_names_dup(TALLOC_CTX *mem_ctx, TR_GSS_NAMES *orig) talloc_free(tmp_ctx); return NULL; } - this = tr_gss_names_iter_first(iter, orig); - while (this) { + for (this = tr_gss_names_iter_first(iter, orig); + this != NULL; + this = tr_gss_names_iter_next(iter)) { if (tr_gss_names_add(new, tr_dup_name(this)) != 0) { talloc_free(tmp_ctx); return NULL; } - this = tr_gss_names_iter_next(iter); } /* success */ talloc_steal(mem_ctx, new); return new; } + int tr_gss_names_matches(TR_GSS_NAMES *gn, TR_NAME *name) { - int ii=0; + TR_GSS_NAMES_ITER iter={0}; + TR_NAME *this = NULL; - if (!gn) + if ((!gn) || (!name)) return 0; - for (ii=0; iinames[ii]!=NULL) && - (0==tr_name_cmp(gn->names[ii], name))) + for (this = tr_gss_names_iter_first(&iter, gn); + this != NULL; + this = tr_gss_names_iter_next(&iter)) { + if (tr_name_cmp(name, this) == 0) return 1; } return 0; } -/* iterators */ -TR_GSS_NAMES_ITER *tr_gss_names_iter_new(TALLOC_CTX *mem_ctx) -{ - TR_GSS_NAMES_ITER *iter=talloc(mem_ctx, TR_GSS_NAMES_ITER); - if (iter!=NULL) { - iter->gn=NULL; - iter->ii=0; - } - return iter; -} - -TR_NAME *tr_gss_names_iter_first(TR_GSS_NAMES_ITER *iter, TR_GSS_NAMES *gn) -{ - iter->gn=gn; - iter->ii=-1; - return tr_gss_names_iter_next(iter); -} - -TR_NAME *tr_gss_names_iter_next(TR_GSS_NAMES_ITER *iter) -{ - for (iter->ii++; - (iter->ii < TR_MAX_GSS_NAMES) && (iter->gn->names[iter->ii]==NULL); - iter->ii++) { } - - if (iter->iign->names[iter->ii]; - - return NULL; -} - -void tr_gss_names_iter_free(TR_GSS_NAMES_ITER *iter) -{ - talloc_free(iter); -} - json_t *tr_gss_names_to_json_array(TR_GSS_NAMES *gss_names) { TR_GSS_NAMES_ITER *iter = tr_gss_names_iter_new(NULL); diff --git a/common/tr_idp_encoders.c b/common/tr_idp_encoders.c index fec129a..2167ea9 100644 --- a/common/tr_idp_encoders.c +++ b/common/tr_idp_encoders.c @@ -148,10 +148,10 @@ static json_t *tr_apcs_to_json(TR_APC *apcs) if ((jarray == NULL) || (iter == NULL)) goto cleanup; - apc = tr_apc_iter_first(iter, apcs); - while (apc) { + for (apc = tr_apc_iter_first(iter, apcs); + apc != NULL; + apc = tr_apc_iter_next(iter)) { ARRAY_APPEND_OR_FAIL(jarray, tr_name_to_json_string(tr_apc_get_id(apc))); - apc = tr_apc_iter_next(iter); } /* success */ @@ -192,10 +192,10 @@ static json_t *tr_aaa_servers_to_json(TR_AAA_SERVER *aaas) if ((jarray == NULL) || (iter == NULL)) goto cleanup; - aaa = tr_aaa_server_iter_first(iter, aaas); - while (aaa) { + for (aaa = tr_aaa_server_iter_first(iter, aaas); + aaa != NULL; + aaa = tr_aaa_server_iter_next(iter)) { ARRAY_APPEND_OR_FAIL(jarray, tr_aaa_server_to_json(aaa)); - aaa = tr_aaa_server_iter_next(iter); } /* success */ diff --git a/common/tr_list.c b/common/tr_list.c new file mode 100644 index 0000000..e3269f4 --- /dev/null +++ b/common/tr_list.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2018 JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +#include + +static int tr_list_destructor(void *object) +{ + TR_LIST *list = talloc_get_type_abort(object, TR_LIST); + if (*list) + g_ptr_array_unref(*list); + return 0; +} + +/* Note that the TR_LIST type is a pointer-to-pointer to + * a GPtrArray. This is done so that we can hook a talloc destructor + * to the list to ensure that the GLib reference count is handled correctly + * when used with talloc. */ +TR_LIST *tr_list_new(TALLOC_CTX *mem_ctx) +{ + TR_LIST *list = talloc(mem_ctx, TR_LIST); + if (list) { + *list = g_ptr_array_new(); + if (*list == NULL) { + talloc_free(list); + return NULL; + } + talloc_set_destructor((void *)list, tr_list_destructor); + } + return list; +} + +void tr_list_free(TR_LIST *list) +{ + talloc_free(list); +} + +/** + * Add an item to the list + * + * If steal != 0, performs a talloc_steal() to put the new item in the + * list's context. If steal == 0, does not do this - in that case, you'll + * need to be sure that the memory is cleaned up through some other means. + * (This allows the list to represent non-talloc'ed items.) + * + * @param list list to add an item to + * @param item pointer to the item to add + * @param steal if non-zero, the item will be added to the list's context with talloc_steal() + * @return pointer to the added item or null if there was an error + */ +void *tr_list_add(TR_LIST *list, void *item, int steal) +{ + guint old_len = (*list)->len; + g_ptr_array_add((*list), item); + + if ((*list)->len == old_len) + return NULL; /* failed to add */ + + if (steal) + talloc_steal(list, item); + + return item; +} + +/** + * Call func(item, cookie) on each item in the list. + * + * @param list list to iterate over + * @param func function, takes two void pointer arguments, first is the item, second the cookie + * @param cookie + */ +void tr_list_foreach(TR_LIST *list, TR_LIST_FOREACH_FUNC *func, void *cookie) +{ + g_ptr_array_foreach((*list), func, cookie); +} + +TR_LIST_ITER *tr_list_iter_new(TALLOC_CTX *mem_ctx) +{ + TR_LIST_ITER *iter = talloc(mem_ctx, TR_LIST_ITER); + if (iter) + iter->list = NULL; + return iter; +} + +void tr_list_iter_free(TR_LIST_ITER *iter) +{ + talloc_free(iter); +} + +void *tr_list_iter_first(TR_LIST_ITER *iter, TR_LIST *list) +{ + if (!iter || !list || (!(*list))) + return NULL; + + iter->list = list; + iter->index = 0; + return tr_list_iter_next(iter); +} + +void *tr_list_iter_next(TR_LIST_ITER *iter) +{ + if (!iter) + return NULL; + + if (iter->index < (*(iter->list))->len) + return g_ptr_array_index(*(iter->list), iter->index++); + return NULL; +} diff --git a/common/tr_msg.c b/common/tr_msg.c index ab80345..50e8bc9 100644 --- a/common/tr_msg.c +++ b/common/tr_msg.c @@ -329,12 +329,17 @@ static json_t * tr_msg_encode_tidreq(TID_REQ *req) jstr = tr_name_to_json_string(req->comm); json_object_set_new(jreq, "community", jstr); - + if (req->orig_coi) { jstr = tr_name_to_json_string(req->orig_coi); json_object_set_new(jreq, "orig_coi", jstr); } + if (tid_req_get_request_id(req)) { + jstr = tr_name_to_json_string(tid_req_get_request_id(req)); + json_object_set_new(jreq, "request_id", jstr); + } + json_object_set_new(jreq, "dh_info", tr_msg_encode_dh(req->tidc_dh)); if (req->cons) @@ -356,6 +361,7 @@ static TID_REQ *tr_msg_decode_tidreq(TALLOC_CTX *mem_ctx, json_t *jreq) json_t *jrealm = NULL; json_t *jcomm = NULL; json_t *jorig_coi = NULL; + json_t *jrequest_id = NULL; json_t *jdh = NULL; json_t *jpath = NULL; json_t *jexpire_interval = NULL; @@ -378,9 +384,9 @@ static TID_REQ *tr_msg_decode_tidreq(TALLOC_CTX *mem_ctx, json_t *jreq) jpath = json_object_get(jreq, "path"); jexpire_interval = json_object_get(jreq, "expiration_interval"); - treq->rp_realm = tr_new_name((char *)json_string_value(jrp_realm)); - treq->realm = tr_new_name((char *)json_string_value(jrealm)); - treq->comm = tr_new_name((char *)json_string_value(jcomm)); + treq->rp_realm = tr_new_name(json_string_value(jrp_realm)); + treq->realm = tr_new_name(json_string_value(jrealm)); + treq->comm = tr_new_name(json_string_value(jcomm)); /* Get DH Info from the request */ if (NULL == (jdh = json_object_get(jreq, "dh_info"))) { @@ -392,7 +398,12 @@ static TID_REQ *tr_msg_decode_tidreq(TALLOC_CTX *mem_ctx, json_t *jreq) /* store optional "orig_coi" field */ if (NULL != (jorig_coi = json_object_get(jreq, "orig_coi"))) { - treq->orig_coi = tr_new_name((char *)json_string_value(jorig_coi)); + treq->orig_coi = tr_new_name(json_string_value(jorig_coi)); + } + + /* store optional "request_id" field */ + if (NULL != (jrequest_id = json_object_get(jreq, "request_id"))) { + tid_req_set_request_id(treq, tr_new_name(json_string_value(jrequest_id))); } treq->cons = (TR_CONSTRAINT_SET *) json_object_get(jreq, "constraints"); @@ -573,6 +584,11 @@ static json_t * tr_msg_encode_tidresp(TID_RESP *resp) json_object_set_new(jresp, "orig_coi", jstr); } + if (tid_resp_get_request_id(resp)) { + jstr = tr_name_to_json_string(tid_resp_get_request_id(resp)); + json_object_set_new(jresp, "request_id", jstr); + } + if (NULL == resp->servers) { tr_debug("tr_msg_encode_tidresp(): No servers to encode."); } @@ -595,6 +611,7 @@ static TID_RESP *tr_msg_decode_tidresp(TALLOC_CTX *mem_ctx, json_t *jresp) json_t *jrealm = NULL; json_t *jcomm = NULL; json_t *jorig_coi = NULL; + json_t *jrequest_id = NULL; json_t *jservers = NULL; json_t *jerr_msg = NULL; @@ -648,10 +665,16 @@ static TID_RESP *tr_msg_decode_tidresp(TALLOC_CTX *mem_ctx, json_t *jresp) /* store optional "orig_coi" field */ if ((NULL != (jorig_coi = json_object_get(jresp, "orig_coi"))) && - (!json_is_object(jorig_coi))) { + json_is_string(jorig_coi)) { tresp->orig_coi = tr_new_name(json_string_value(jorig_coi)); } - + + /* store optional "request_id" field */ + if ((NULL != (jrequest_id = json_object_get(jresp, "request_id"))) && + json_is_string(jrequest_id)) { + tid_resp_set_request_id(tresp, tr_new_name(json_string_value(jrequest_id))); + } + return tresp; } diff --git a/common/tr_name.c b/common/tr_name.c index 84f0c1f..e1f81b4 100644 --- a/common/tr_name.c +++ b/common/tr_name.c @@ -52,9 +52,11 @@ TR_NAME *tr_new_name (const char *name) { TR_NAME *new; - if (new = malloc(sizeof(TR_NAME))) { - new->len = strlen(name); - if (new->buf = malloc((new->len)+1)) { + new = malloc(sizeof(TR_NAME)); + if (new) { + new->len = (int) strlen(name); + new->buf = malloc(1 + (size_t) new->len); + if (new->buf) { strcpy(new->buf, name); } else { free(new); @@ -64,7 +66,7 @@ TR_NAME *tr_new_name (const char *name) return new; } -TR_NAME *tr_dup_name (TR_NAME *from) +TR_NAME *tr_dup_name (const TR_NAME *from) { TR_NAME *to; @@ -74,15 +76,15 @@ TR_NAME *tr_dup_name (TR_NAME *from) if (NULL != (to = malloc(sizeof(TR_NAME)))) { to->len = from->len; - if (NULL != (to->buf = malloc(to->len+1))) { - strncpy(to->buf, from->buf, from->len); + if (NULL != (to->buf = malloc(1 + (size_t) to->len))) { + strncpy(to->buf, from->buf, (size_t) from->len); to->buf[to->len] = 0; /* NULL terminate for debugging printf()s */ } } return to; } -int tr_name_cmp(TR_NAME *one, TR_NAME *two) +int tr_name_cmp(const TR_NAME *one, const TR_NAME *two) { int len=one->len; int cmp=0; @@ -90,7 +92,7 @@ int tr_name_cmp(TR_NAME *one, TR_NAME *two) if (two->lenlen) len=two->len; /* len now min(one->len,two->len) */ - cmp=strncmp(one->buf, two->buf, len); + cmp=strncmp(one->buf, two->buf, (size_t) len); if (cmp==0) { if (one->lenlen) return -1; @@ -109,7 +111,7 @@ int tr_name_cmp(TR_NAME *one, TR_NAME *two) * @param two_str Ordinary C null-terminated string * @return 0 on match, <0 if one precedes two, >0 if two precedes one */ -int tr_name_cmp_str(TR_NAME *one, const char *two_str) +int tr_name_cmp_str(const TR_NAME *one, const char *two_str) { TR_NAME *two=tr_new_name(two_str); int cmp=tr_name_cmp(one, two); @@ -126,7 +128,7 @@ int tr_name_cmp_str(TR_NAME *one, const char *two_str) * @return 1 if the the string (str) matches the wildcard string (wc_str), 0 if not. * */ -int tr_name_prefix_wildcard_match(TR_NAME *str, TR_NAME *wc_str) +int tr_name_prefix_wildcard_match(const TR_NAME *str, const TR_NAME *wc_str) { const char *wc_post=NULL; size_t wc_len = 0; @@ -134,7 +136,8 @@ int tr_name_prefix_wildcard_match(TR_NAME *str, TR_NAME *wc_str) if ((!str) || (!wc_str)) return 0; - if (0 == (wc_len = wc_str->len)) + wc_len = (size_t) wc_str->len; + if (wc_len == 0) return 0; if ('*' == wc_str->buf[0]) { @@ -145,7 +148,7 @@ int tr_name_prefix_wildcard_match(TR_NAME *str, TR_NAME *wc_str) /* No wildcard, but the strings are the same length so may match. * Compare the full strings. */ wc_post=wc_str->buf; - wc_len=wc_str->len; + wc_len = (size_t) wc_str->len; } else { /* No wildcard and strings are different length, so no match */ return 0; @@ -165,24 +168,25 @@ void tr_name_strlcat(char *dest, const TR_NAME *src, size_t len) size_t used_len; if (src->len >= len) used_len = len-1; - else used_len = src->len; + else + used_len = (size_t) src->len; if (used_len > 0) strncat(dest, src->buf, used_len); else dest[0] = '\0'; } -char * tr_name_strdup(TR_NAME *src) +char * tr_name_strdup(const TR_NAME *src) { - char *s = calloc(src->len+1, 1); + char *s = calloc(1 + (size_t) src->len, 1); if (s) { - memcpy(s, src->buf, src->len); + memcpy(s, src->buf, (size_t) src->len); s[src->len] = '\0'; } return s; } -json_t *tr_name_to_json_string(TR_NAME *src) +json_t *tr_name_to_json_string(const TR_NAME *src) { char *s=tr_name_strdup(src); json_t *js=json_string(s); @@ -191,16 +195,16 @@ json_t *tr_name_to_json_string(TR_NAME *src) return js; } -TR_NAME *tr_name_cat(TR_NAME *n1, TR_NAME *n2) +TR_NAME *tr_name_cat(const TR_NAME *n1, const TR_NAME *n2) { - char *s=malloc(n1->len+n2->len+1); + char *s=malloc((size_t) n1->len + (size_t) n2->len + 1); TR_NAME *name=NULL; if (s==NULL) return NULL; *s=0; - strncat(s, n1->buf, n1->len); - strncat(s, n2->buf, n2->len); + strncat(s, n1->buf, (size_t) n1->len); + strncat(s, n2->buf, (size_t) n2->len); name=tr_new_name(s); free(s); return name; diff --git a/common/tr_rand_id.c b/common/tr_rand_id.c new file mode 100644 index 0000000..a2a0a10 --- /dev/null +++ b/common/tr_rand_id.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include + +#include + +static char *bytes_to_hex(TALLOC_CTX *mem_ctx, const unsigned char *bytes, size_t len) +{ + char *hex = talloc_size(mem_ctx, 1 + len * 2 * sizeof(char)); + char *p = NULL; + + if (hex) { + p = hex; + while(len--) { + p += sprintf(p, "%02x", *(bytes++)); + } + } + + return hex; +} + +/** + * Generate n random bytes of data + * + * @param dst destination buffer, at least n bytes long + * @param n number of bytes to generate + * @return -1 on error + */ +static int random_bytes(unsigned char *dst, size_t n) +{ + return RAND_pseudo_bytes(dst, n); +} + +#define ID_LENGTH 15 +/** + * Generate a random ID + * + * @param mem_ctx talloc context for the result + * @return random string of hex characters or null if it is unable to generate them + */ +char *tr_random_id(TALLOC_CTX *mem_ctx) +{ + unsigned char bytes[ID_LENGTH]; + char *hex = NULL; + + if (random_bytes(bytes, ID_LENGTH) >= 0) + hex = bytes_to_hex(mem_ctx, bytes, ID_LENGTH); + + return hex; +} diff --git a/common/tr_rp_client_encoders.c b/common/tr_rp_client_encoders.c index d0a5cd0..6a7bda9 100644 --- a/common/tr_rp_client_encoders.c +++ b/common/tr_rp_client_encoders.c @@ -87,10 +87,10 @@ json_t *tr_rp_clients_to_json(TR_RP_CLIENT *rp_clients) if ((jarray == NULL) || (iter == NULL)) goto cleanup; - rp_client = tr_rp_client_iter_first(iter, rp_clients); - while (rp_client) { + for (rp_client = tr_rp_client_iter_first(iter, rp_clients); + rp_client != NULL; + rp_client = tr_rp_client_iter_next(iter)) { ARRAY_APPEND_OR_FAIL(jarray, tr_rp_client_to_json(rp_client)); - rp_client = tr_rp_client_iter_next(iter); } /* succeeded - set the return value and increment the reference count */ diff --git a/common/tr_socket.c b/common/tr_socket.c index 7f1c917..1bb3cc2 100644 --- a/common/tr_socket.c +++ b/common/tr_socket.c @@ -40,6 +40,7 @@ #include #include +#include /** * Open sockets on all interface addresses @@ -137,3 +138,63 @@ nfds_t tr_sock_listen_all(unsigned int port, int *fd_out, nfds_t max_fd) return n_opened; } +/** + * Extract a string-formatted socket address from a struct sockaddr + * + * @param s + * @param dst pointer to allocated space of at least INET6_ADDRSLEN bytes + * @param dst_len size of space allocated at dst + * @return pointer to dst or null on error + */ +static const char *tr_sock_ip_address(struct sockaddr *s, char *dst, size_t dst_len) +{ + switch (s->sa_family) { + case AF_INET: + inet_ntop(AF_INET, + &(((struct sockaddr_in *)s)->sin_addr), + dst, + (socklen_t) dst_len); + break; + + case AF_INET6: + inet_ntop(AF_INET6, + &(((struct sockaddr_in6 *)s)->sin6_addr), + dst, + (socklen_t) dst_len); + break; + + default: + snprintf(dst, dst_len, "addr family %u", s->sa_family); + break; + } + + return dst; +} + +/** + * Accept a socket connection + * + * @param sock + * @return -1 on error, connection fd on success + */ +int tr_sock_accept(int sock) +{ + int conn = -1; + struct sockaddr_storage peeraddr; + socklen_t addr_len = sizeof(peeraddr); + char peeraddr_string[INET6_ADDRSTRLEN]; + char err[80]; + + if (0 > (conn = accept(sock, (struct sockaddr *)&(peeraddr), &addr_len))) { + if (strerror_r(errno, err, sizeof(err))) + snprintf(err, sizeof(err), "errno = %d", errno); + tr_err("tr_sock_accept: Unable to accept connection: %s", err); + } else { + tr_notice("tr_sock_accept: Incoming connection on fd %d from %s", + conn, + tr_sock_ip_address((struct sockaddr *)&peeraddr, + peeraddr_string, + sizeof(peeraddr_string))); + } + return conn; +} diff --git a/common/tr_util.c b/common/tr_util.c index ef85776..2e59606 100644 --- a/common/tr_util.c +++ b/common/tr_util.c @@ -51,9 +51,16 @@ void tr_bin_to_hex(const unsigned char * bin, size_t bin_len, } } -/* Returns 0 if ts1==ts2, <0 if ts1= if ts1>ts2. - * Assumes that tv_nsec <= 1e9. */ -int tr_cmp_timespec(struct timespec *ts1, struct timespec *ts2) +/** + * Compare two timespecs + * + * Assumes tv_nsec <= 1e9 + * + * @param ts1 + * @param ts2 + * @return 0 if ts1==ts2, -1 if ts1ts2. + */ +int tr_cmp_timespec(const struct timespec *ts1, const struct timespec *ts2) { if (ts1->tv_sec > ts2->tv_sec) return 1; @@ -73,26 +80,133 @@ int tr_cmp_timespec(struct timespec *ts1, struct timespec *ts2) } /** + * Compute ts1 + ts2 + * + * @param ts1 + * @param ts2 + * @param sum ts1 + ts2 + * @return 0 on success, nonzero on error + */ +int tr_add_timespec(const struct timespec *ts1, const struct timespec *ts2, struct timespec *sum) +{ + const time_t ONE_BILLION = 1000000000; + + if (!ts1 || !ts2 || !sum) + return -1; + + /* would be nice to do range checking, but I don't know a portable way to get the + * max value of a time_t. Figure that nsec <= 1e9 and seconds are unlikely to go off + * too close to infinity, so overflow is unlikely */ + sum->tv_nsec = ts1->tv_nsec + ts2->tv_nsec; + sum->tv_sec = ts1->tv_sec + ts2->tv_sec; + + /* make sure that we have no more than a second worth of nsec */ + while (sum->tv_nsec >= ONE_BILLION) { + sum->tv_nsec -= ONE_BILLION; + sum->tv_sec += 1; + } + + return 0; +} + +/** + * Compute ts1 - ts2 + * + * Allows negative results, which will be represented as a negative tv_sec. + * The returned tv_nsec is always positive and less than 1e9. + * + * (The value represented is tv_sec + tv_nsec/1e9 seconds - this is a little + * counterintuitive when tv_sec is negative. E.g., -1.5 seconds is represented + * as {-2, 500000000). Negative time_t values are not guaranteed to be supported + * anyway, so it's probably best to stay away from them.) + * + * @param ts1 + * @param ts2 + * @param diff ts1 - ts2 + * @return 0 on success, nonzero on error + */ +int tr_sub_timespec(const struct timespec *ts1, const struct timespec *ts2, struct timespec *diff) +{ + const time_t ONE_BILLION = 1000000000; + struct timespec ts1_copy = {0}; + struct timespec ts2_copy = {0}; + + if (!ts1 || !ts2 || !diff) + return -1; + + ts1_copy = *ts1; + ts2_copy = *ts2; + + while (ts2_copy.tv_nsec > ts1_copy.tv_nsec) { + /* Reduce ts2 by one second worth of nsec, balanced by removing a second + * from ts1. Repeat until ts2->tv_nsec <= ts1->tv_nsec. */ + ts2_copy.tv_nsec -= ONE_BILLION; + ts1_copy.tv_sec -= 1; + } + + diff->tv_nsec = ts1_copy.tv_nsec - ts2_copy.tv_nsec; /* >= 0 */ + diff->tv_sec = ts1_copy.tv_sec - ts2_copy.tv_sec; /* sign indeterminate */ + + /* make sure we have no more than 1 sec worth of nsec */ + while (diff->tv_nsec > ONE_BILLION) { + diff->tv_nsec -= ONE_BILLION; + diff->tv_sec += 1; + } + + return 0; +} + +/** * Convert a struct timespec to a string representation * @param ts * @return */ -char *timespec_to_str(struct timespec *ts) +char *timespec_to_str(const struct timespec *ts) { struct tm tm; char *s=NULL; - if (localtime_r(&(ts->tv_sec), &tm)==NULL) + if (gmtime_r(&(ts->tv_sec), &tm)==NULL) return NULL; s=malloc(40); /* long enough to contain strftime result */ if (s==NULL) return NULL; - if (strftime(s, 40, "%F %T", &tm)==0) { + if (strftime(s, 40, "%F %T UTC", &tm)==0) { free(s); return NULL; } return s; } +/** + * Convert a time from one clock to another + * + * Because this involves reading each clock, it is not exact. + * + * @param from clock to convert from + * @param when time to convert, measured on the 'from' clock + * @param to clock to convert to + * @param dst destination, measured on the 'to' clock + * @return dst or null on error + */ +struct timespec *tr_clock_convert(clockid_t from, const struct timespec *when, + clockid_t to, struct timespec *dst) +{ + struct timespec now_from = {0}; + struct timespec diff = {0}; /* difference between when and now_from */ + struct timespec now_to = {0}; + + if ((clock_gettime(from, &now_from) != 0) + || (clock_gettime(to, &now_to) != 0)) { + return NULL; + } + if (tr_sub_timespec(when, &now_from, &diff) != 0) { + return NULL; + } + if (tr_add_timespec(&now_to, &diff, dst) != 0) { + return NULL; + } + return dst; +} \ No newline at end of file diff --git a/include/tid_internal.h b/include/tid_internal.h index 6b6fb78..8613eb8 100644 --- a/include/tid_internal.h +++ b/include/tid_internal.h @@ -52,6 +52,7 @@ struct tid_srvr_blk { struct tid_resp { TID_RC result; + TR_NAME *request_id; TR_NAME *err_msg; TR_NAME *rp_realm; TR_NAME *realm; @@ -67,6 +68,7 @@ struct tid_req { int resp_sent; int conn; int free_conn; /* free conn and gss ctx*/ + TR_NAME *request_id; gss_ctx_id_t gssctx; int resp_rcvd; TR_NAME *rp_realm; diff --git a/include/tr_comm.h b/include/tr_comm.h index 6228c1f..461d75b 100644 --- a/include/tr_comm.h +++ b/include/tr_comm.h @@ -113,7 +113,7 @@ void tr_comm_table_free(TR_COMM_TABLE *ctab); TR_COMM_TABLE *tr_comm_table_new(TALLOC_CTX *mem_ctx); void tr_comm_table_free(TR_COMM_TABLE *ctab); void tr_comm_table_sweep(TR_COMM_TABLE *ctab); -void tr_comm_table_add_comm(TR_COMM_TABLE *ctab, TR_COMM *new); +int tr_comm_table_add_comm(TR_COMM_TABLE *ctab, TR_COMM *new); void tr_comm_table_remove_comm(TR_COMM_TABLE *ctab, TR_COMM *comm); TR_RP_REALM *tr_comm_table_find_rp_realm(TR_COMM_TABLE *ctab, TR_NAME *realm_id); void tr_comm_table_add_rp_realm(TR_COMM_TABLE *ctab, TR_RP_REALM *new); @@ -155,6 +155,7 @@ void tr_comm_memb_set_interval(TR_COMM_MEMB *memb, unsigned int interval); unsigned int tr_comm_memb_get_interval(TR_COMM_MEMB *memb); void tr_comm_memb_set_expiry(TR_COMM_MEMB *memb, struct timespec *time); struct timespec *tr_comm_memb_get_expiry(TR_COMM_MEMB *memb); +struct timespec *tr_comm_memb_get_expiry_realtime(TR_COMM_MEMB *memb, struct timespec *result); int tr_comm_memb_is_expired(TR_COMM_MEMB *memb, struct timespec *curtime); void tr_comm_memb_set_triggered(TR_COMM_MEMB *memb, int trig); int tr_comm_memb_is_triggered(TR_COMM_MEMB *memb); diff --git a/include/tr_constraint_internal.h b/include/tr_constraint_internal.h new file mode 100644 index 0000000..2182781 --- /dev/null +++ b/include/tr_constraint_internal.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#ifndef TRUST_ROUTER_TR_CONSTRAINT_INTERNAL_H +#define TRUST_ROUTER_TR_CONSTRAINT_INTERNAL_H + +#include + +#include +#include +#include + + +struct tr_constraint { + TR_NAME *type; + TR_LIST *matches; +}; + +TR_CONSTRAINT *tr_constraint_new(TALLOC_CTX *mem_ctx); +void tr_constraint_free(TR_CONSTRAINT *cons); +TR_CONSTRAINT *tr_constraint_dup(TALLOC_CTX *mem_ctx, TR_CONSTRAINT *cons); + +/* Iterator for TR_CONS matches */ +typedef TR_LIST_ITER TR_CONSTRAINT_ITER; +#define tr_constraint_iter_new(CTX) (tr_list_iter_new(CTX)) +#define tr_constraint_iter_free(ITER) (tr_list_iter_free(ITER)) +#define tr_constraint_iter_first(ITER, CONS) ((TR_NAME *) tr_list_iter_first((ITER), (CONS)->matches)) +#define tr_constraint_iter_next(ITER) ((TR_NAME *) tr_list_iter_next(ITER)) +#define tr_constraint_add_match(CONS, MATCH) ((TR_NAME *) tr_list_add((CONS)->matches, (MATCH), 0)) + +#endif //TRUST_ROUTER_TR_CONSTRAINT_INTERNAL_H diff --git a/include/tr_filter.h b/include/tr_filter.h index ece3650..d241a50 100644 --- a/include/tr_filter.h +++ b/include/tr_filter.h @@ -37,17 +37,14 @@ #include #include +#include +#include #include #include #include #include -#define TR_MAX_FILTERS 5 -#define TR_MAX_FILTER_LINES 8 -#define TR_MAX_FILTER_SPECS 8 -#define TR_MAX_FILTER_SPEC_MATCHES 64 - /* Filter actions */ typedef enum tr_filter_action { TR_FILTER_ACTION_REJECT = 0, @@ -69,22 +66,21 @@ typedef enum { typedef struct tr_fspec { TR_NAME *field; - TR_NAME *match[TR_MAX_FILTER_SPEC_MATCHES]; + TR_LIST *match; } TR_FSPEC; typedef struct tr_fline { TR_FILTER_ACTION action; - TR_FSPEC *specs[TR_MAX_FILTER_SPECS]; + TR_LIST *specs; TR_CONSTRAINT *realm_cons; TR_CONSTRAINT *domain_cons; } TR_FLINE; typedef struct tr_filter { TR_FILTER_TYPE type; - TR_FLINE *lines[TR_MAX_FILTER_LINES]; + TR_LIST *lines; } TR_FILTER; - typedef struct tr_filter_set TR_FILTER_SET; struct tr_filter_set { TR_FILTER *this; @@ -109,25 +105,45 @@ int tr_filter_set_add(TR_FILTER_SET *set, TR_FILTER *new); TR_FILTER *tr_filter_set_get(TR_FILTER_SET *set, TR_FILTER_TYPE type); TR_FILTER *tr_filter_new(TALLOC_CTX *mem_ctx); - void tr_filter_free(TR_FILTER *filt); void tr_filter_set_type(TR_FILTER *filt, TR_FILTER_TYPE type); - TR_FILTER_TYPE tr_filter_get_type(TR_FILTER *filt); +TR_FLINE *tr_filter_add_line(TR_FILTER *filt, TR_FLINE *line); TR_FLINE *tr_fline_new(TALLOC_CTX *mem_ctx); - void tr_fline_free(TR_FLINE *fline); +TR_FSPEC *tr_fline_add_spec(TR_FLINE *fline, TR_FSPEC *spec); TR_FSPEC *tr_fspec_new(TALLOC_CTX *mem_ctx); - void tr_fspec_free(TR_FSPEC *fspec); - -void tr_fspec_add_match(TR_FSPEC *fspec, TR_NAME *match); +TR_NAME *tr_fspec_add_match(TR_FSPEC *fspec, TR_NAME *match); int tr_fspec_matches(TR_FSPEC *fspec, TR_FILTER_TYPE ftype, TR_FILTER_TARGET *target); +/* Iterator for TR_FILTER lines */ +typedef TR_LIST_ITER TR_FILTER_ITER; +#define tr_filter_iter_new(CTX) (tr_list_iter_new(CTX)) +#define tr_filter_iter_free(ITER) (tr_list_iter_free(ITER)) +#define tr_filter_iter_first(ITER, FILT) ((TR_FLINE *) tr_list_iter_first((ITER), (FILT)->lines)) +#define tr_filter_iter_next(ITER) ((TR_FLINE *) tr_list_iter_next(ITER)) +#define tr_filter_add_line(FILT, LINE) ((TR_FLINE *) tr_list_add((FILT)->lines, (LINE), 1)) + +/* Iterator for TR_FSPEC matches */ +typedef TR_LIST_ITER TR_FSPEC_ITER; +#define tr_fspec_iter_new(CTX) (tr_list_iter_new(CTX)) +#define tr_fspec_iter_free(ITER) (tr_list_iter_free(ITER)) +#define tr_fspec_iter_first(ITER, SPEC) (tr_list_iter_first((ITER), (SPEC)->match)) +#define tr_fspec_iter_next(ITER) (tr_list_iter_next(ITER)) +#define tr_fspec_add_match(SPEC, MATCH) ((TR_NAME *) tr_list_add((SPEC)->match, (MATCH), 0)) + +/* Iterator for TR_FLINE specs */ +typedef TR_LIST_ITER TR_FLINE_ITER; +#define tr_fline_iter_new(CTX) (tr_list_iter_new(CTX)) +#define tr_fline_iter_free(ITER) (tr_list_iter_free(ITER)) +#define tr_fline_iter_first(ITER, LINE) (tr_list_iter_first((ITER), (LINE)->specs)) +#define tr_fline_iter_next(ITER) (tr_list_iter_next(ITER)) +#define tr_fline_add_spec(LINE, SPEC) ((TR_NAME *) tr_list_add((LINE)->specs, (SPEC), 1)) /*In tr_constraint.c and exported, but not really a public symbol; needed by tr_filter.c and by tr_constraint.c*/ int TR_EXPORT tr_prefix_wildcard_match(const char *str, const char *wc_str); diff --git a/include/tr_gss_names.h b/include/tr_gss_names.h index f8f97a2..c6192be 100644 --- a/include/tr_gss_names.h +++ b/include/tr_gss_names.h @@ -36,29 +36,29 @@ #define __TR_GSS_H__ #include -#include +#include -#define TR_MAX_GSS_NAMES 5 +#include typedef struct tr_gss_names { - TR_NAME *names[TR_MAX_GSS_NAMES]; + TR_LIST *names; } TR_GSS_NAMES; -typedef struct tr_gss_names_iter { - TR_GSS_NAMES *gn; - int ii; /* which entry did we last output? */ -} TR_GSS_NAMES_ITER; +typedef TR_LIST_ITER TR_GSS_NAMES_ITER; + +/* Iterator for TR_FILTER lines */ +#define tr_gss_names_iter_new(CTX) (tr_list_iter_new(CTX)) +#define tr_gss_names_iter_free(ITER) (tr_list_iter_free(ITER)) +#define tr_gss_names_iter_first(ITER, GSSN) ((TR_NAME *) tr_list_iter_first((ITER), (GSSN)->names)) +#define tr_gss_names_iter_next(ITER) ((TR_NAME *) tr_list_iter_next(ITER)) TR_GSS_NAMES *tr_gss_names_new(TALLOC_CTX *mem_ctx); void tr_gss_names_free(TR_GSS_NAMES *gn); int tr_gss_names_add(TR_GSS_NAMES *gn, TR_NAME *new); TR_GSS_NAMES *tr_gss_names_dup(TALLOC_CTX *mem_ctx, TR_GSS_NAMES *orig); int tr_gss_names_matches(TR_GSS_NAMES *gn, TR_NAME *name); - -TR_GSS_NAMES_ITER *tr_gss_names_iter_new(TALLOC_CTX *mem_ctx); -TR_NAME *tr_gss_names_iter_first(TR_GSS_NAMES_ITER *iter, TR_GSS_NAMES *gn); -TR_NAME *tr_gss_names_iter_next(TR_GSS_NAMES_ITER *iter); -void tr_gss_names_iter_free(TR_GSS_NAMES_ITER *iter); +#define tr_gss_names_length(GSSN) (tr_list_length((GSSN)->names)) +#define tr_gss_names_index(GSSN, INDEX) (tr_list_index((GSSN)->names, (INDEX))) json_t *tr_gss_names_to_json_array(TR_GSS_NAMES *gss_names); diff --git a/include/tr_list.h b/include/tr_list.h new file mode 100644 index 0000000..8bfca38 --- /dev/null +++ b/include/tr_list.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018 JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef TRUST_ROUTER_TR_LIST_H +#define TRUST_ROUTER_TR_LIST_H + +#include +#include + +typedef GPtrArray *TR_LIST; + +typedef void (TR_LIST_FOREACH_FUNC)(void *item, void *cookie); + +typedef struct tr_list_iter{ + TR_LIST *list; + guint index; +} TR_LIST_ITER; + +#define tr_list_index(LIST, INDEX) (g_ptr_array_index(*(LIST),(INDEX))) +#define tr_list_length(LIST) ((size_t)((*(LIST))->len)) + +TR_LIST *tr_list_new(TALLOC_CTX *mem_ctx); +void tr_list_free(TR_LIST *list); +void *tr_list_add(TR_LIST *list, void *item, int steal); + +TR_LIST_ITER *tr_list_iter_new(TALLOC_CTX *mem_ctx); +void tr_list_iter_free(TR_LIST_ITER *iter); +void *tr_list_iter_first(TR_LIST_ITER *iter, TR_LIST *list); +void *tr_list_iter_next(TR_LIST_ITER *iter); +void tr_list_foreach(TR_LIST *list, TR_LIST_FOREACH_FUNC *func, void *cookie); + +#endif //TRUST_ROUTER_TR_LIST_H diff --git a/include/tr_name_internal.h b/include/tr_name_internal.h index 02c78f8..a67a64d 100644 --- a/include/tr_name_internal.h +++ b/include/tr_name_internal.h @@ -40,15 +40,14 @@ */ #ifndef TR_NAME_INTERNAL_H +#define TR_NAME_INTERNAL_H #include #include /** Prototypes */ -json_t *tr_name_to_json_string(TR_NAME *src); -int tr_name_cmp_str(TR_NAME *one, const char *two_str); -int tr_name_prefix_wildcard_match(TR_NAME *str, TR_NAME *wc_str); - -#define TR_NAME_INTERNAL_H +json_t *tr_name_to_json_string(const TR_NAME *src); +int tr_name_cmp_str(const TR_NAME *one, const char *two_str); +int tr_name_prefix_wildcard_match(const TR_NAME *str, const TR_NAME *wc_str); #endif //TRUST_ROUTER_TR_NAME_INTERNAL_H diff --git a/include/tr_rand_id.h b/include/tr_rand_id.h new file mode 100644 index 0000000..8632c89 --- /dev/null +++ b/include/tr_rand_id.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef TRUST_ROUTER_TR_RAND_ID_H +#define TRUST_ROUTER_TR_RAND_ID_H + +char *tr_random_id(TALLOC_CTX *mem_ctx); + +#endif //TRUST_ROUTER_TR_RAND_ID_H diff --git a/include/tr_socket.h b/include/tr_socket.h index 064c6fc..e90a912 100644 --- a/include/tr_socket.h +++ b/include/tr_socket.h @@ -37,7 +37,9 @@ #include #include // for nfds_t +#include nfds_t tr_sock_listen_all(unsigned int port, int *fd_out, nfds_t max_fd); +int tr_sock_accept(int sock); #endif //TRUST_ROUTER_TR_SOCKET_H diff --git a/include/tr_util.h b/include/tr_util.h index bed0482..9bf7d8e 100644 --- a/include/tr_util.h +++ b/include/tr_util.h @@ -40,7 +40,11 @@ /* NB, tr_bin_to_hex() is also prototyped in trust_router/tr_dh.h */ TR_EXPORT void tr_bin_to_hex(const unsigned char * bin, size_t binlen, char * hex_out, size_t hex_len); -TR_EXPORT int tr_cmp_timespec(struct timespec *ts1, struct timespec *ts2); -char *timespec_to_str(struct timespec *ts); +TR_EXPORT int tr_cmp_timespec(const struct timespec *ts1, const struct timespec *ts2); +int tr_add_timespec(const struct timespec *ts1, const struct timespec *ts2, struct timespec *sum); +int tr_sub_timespec(const struct timespec *ts1_copy, const struct timespec *ts2_copy, struct timespec *diff); +char *timespec_to_str(const struct timespec *ts); +struct timespec *tr_clock_convert(clockid_t from, const struct timespec *when, + clockid_t to, struct timespec *dst); #endif /* TR_UTIL_H */ diff --git a/include/trp_route.h b/include/trp_route.h index d159861..aff0ba0 100644 --- a/include/trp_route.h +++ b/include/trp_route.h @@ -78,6 +78,7 @@ void trp_route_set_interval(TRP_ROUTE *entry, int interval); int trp_route_get_interval(TRP_ROUTE *entry); void trp_route_set_expiry(TRP_ROUTE *entry, struct timespec *exp); struct timespec *trp_route_get_expiry(TRP_ROUTE *entry); +struct timespec *trp_route_get_expiry_realtime(TRP_ROUTE *comm, struct timespec *result); void trp_route_set_local(TRP_ROUTE *entry, int local); int trp_route_is_local(TRP_ROUTE *entry); void trp_route_set_triggered(TRP_ROUTE *entry, int trig); diff --git a/include/trust_router/tid.h b/include/trust_router/tid.h index 35ec577..38833f1 100644 --- a/include/trust_router/tid.h +++ b/include/trust_router/tid.h @@ -96,6 +96,8 @@ TR_EXPORT TR_NAME *tid_req_get_comm(TID_REQ *req); void tid_req_set_comm(TID_REQ *req, TR_NAME *comm); TR_EXPORT TR_NAME *tid_req_get_orig_coi(TID_REQ *req); void tid_req_set_orig_coi(TID_REQ *req, TR_NAME *orig_coi); +TR_EXPORT TR_NAME *tid_req_get_request_id(TID_REQ *req); +void tid_req_set_request_id(TID_REQ *req, TR_NAME *request_id); TR_EXPORT TIDC_RESP_FUNC *tid_req_get_resp_func(TID_REQ *req); void tid_req_set_resp_func(TID_REQ *req, TIDC_RESP_FUNC *resp_func); TR_EXPORT void *tid_req_get_cookie(TID_REQ *req); @@ -120,6 +122,8 @@ TR_EXPORT TR_NAME *tid_resp_get_comm(TID_RESP *resp); void tid_resp_set_comm(TID_RESP *resp, TR_NAME *comm); TR_EXPORT TR_NAME *tid_resp_get_orig_coi(TID_RESP *resp); void tid_resp_set_orig_coi(TID_RESP *resp, TR_NAME *orig_coi); +TR_EXPORT TR_NAME *tid_resp_get_request_id(TID_RESP *resp); +void tid_resp_set_request_id(TID_RESP *resp, TR_NAME *request_id); TR_EXPORT TID_SRVR_BLK *tid_resp_get_server(TID_RESP *resp, size_t index); TR_EXPORT size_t tid_resp_get_num_servers(const TID_RESP *resp); TR_EXPORT const TID_PATH *tid_resp_get_error_path(const TID_RESP *); diff --git a/include/trust_router/tr_constraint.h b/include/trust_router/tr_constraint.h index 2594b36..88619e4 100644 --- a/include/trust_router/tr_constraint.h +++ b/include/trust_router/tr_constraint.h @@ -35,23 +35,10 @@ #ifndef TR_CONSTRAINT_H #define TR_CONSTRAINT_H -#include - #include #include - -#define TR_MAX_CONST_MATCHES 24 - - -typedef struct tr_constraint { - TR_NAME *type; - TR_NAME *matches[TR_MAX_CONST_MATCHES]; -} TR_CONSTRAINT; - -TR_CONSTRAINT *tr_constraint_new(TALLOC_CTX *mem_ctx); -void tr_constraint_free(TR_CONSTRAINT *cons); -TR_CONSTRAINT *tr_constraint_dup(TALLOC_CTX *mem_ctx, TR_CONSTRAINT *cons); +typedef struct tr_constraint TR_CONSTRAINT; void TR_EXPORT tr_constraint_add_to_set (TR_CONSTRAINT_SET **cs, TR_CONSTRAINT *c); int TR_EXPORT tr_constraint_set_validate( TR_CONSTRAINT_SET *); @@ -65,6 +52,4 @@ int TR_EXPORT tr_constraint_set_get_match_strings(TID_REQ *, const char * constraint_type, tr_const_string **output, size_t *output_len); - - #endif diff --git a/include/trust_router/tr_name.h b/include/trust_router/tr_name.h index 052d291..797a3be 100644 --- a/include/trust_router/tr_name.h +++ b/include/trust_router/tr_name.h @@ -45,11 +45,11 @@ typedef struct tr__name { } TR_NAME; TR_EXPORT TR_NAME *tr_new_name (const char *name); -TR_EXPORT TR_NAME *tr_dup_name (TR_NAME *from); +TR_EXPORT TR_NAME *tr_dup_name (const TR_NAME *from); TR_EXPORT void tr_free_name (TR_NAME *name); -TR_EXPORT int tr_name_cmp (TR_NAME *one, TR_NAME *two); +TR_EXPORT int tr_name_cmp (const TR_NAME *one, const TR_NAME *two); TR_EXPORT void tr_name_strlcat(char *dest, const TR_NAME *src, size_t len); -TR_EXPORT char *tr_name_strdup(TR_NAME *); -TR_EXPORT TR_NAME *tr_name_cat(TR_NAME *n1, TR_NAME *n2); +TR_EXPORT char *tr_name_strdup(const TR_NAME *); +TR_EXPORT TR_NAME *tr_name_cat(const TR_NAME *n1, const TR_NAME *n2); #endif diff --git a/mon/mon_req_decode.c b/mon/mon_req_decode.c index 0c7e7f4..21bb64b 100644 --- a/mon/mon_req_decode.c +++ b/mon/mon_req_decode.c @@ -126,7 +126,7 @@ MON_REQ *mon_req_parse(TALLOC_CTX *mem_ctx, const char *input) * * (options are optional) * - * Caller must free the return value with MON_REQ_free(). + * Caller must free the return value with mon_req_free(). * * @param mem_ctx talloc context for the returned struct * @param req_json reference to JSON request object @@ -171,8 +171,6 @@ MON_REQ *mon_req_decode(TALLOC_CTX *mem_ctx, json_t *req_json) cleanup: talloc_free(tmp_ctx); - if (req_json) - json_decref(req_json); return req; } diff --git a/mon/mon_resp_encode.c b/mon/mon_resp_encode.c index 23c3dd8..7e41c65 100644 --- a/mon/mon_resp_encode.c +++ b/mon/mon_resp_encode.c @@ -79,6 +79,7 @@ json_t *mon_resp_encode(MON_RESP *resp) /* If we have a payload, add it */ if (resp->payload) { object_set_or_free_and_return(resp_json, jval, "payload", resp->payload); + json_incref(resp->payload); /* we just created a second reference to the payload */ } return resp_json; diff --git a/mon/mons.c b/mon/mons.c index f2e69c5..cb70d3b 100644 --- a/mon/mons.c +++ b/mon/mons.c @@ -225,8 +225,8 @@ int mons_accept(MONS_INSTANCE *mons, int listen) int conn=-1; int pid=-1; - if (0 > (conn = accept(listen, NULL, NULL))) { - perror("Error from monitoring interface accept()"); + if (0 > (conn = tr_sock_accept(listen))) { + tr_err("mons_accept: Error accepting connection"); return 1; } diff --git a/tid/tid_req.c b/tid/tid_req.c index 88dd991..002b720 100644 --- a/tid/tid_req.c +++ b/tid/tid_req.c @@ -63,6 +63,8 @@ static int destroy_tid_req(TID_REQ *req) tr_free_name(req->comm); if (req->orig_coi!=NULL) tr_free_name(req->orig_coi); + if (req->request_id!=NULL) + tr_free_name(req->request_id); return 0; } @@ -76,6 +78,7 @@ TID_REQ *tid_req_new() assert(req->json_references); req->conn = -1; req->free_conn = 1; + req->request_id = NULL; return req; } @@ -169,6 +172,16 @@ void tid_req_set_orig_coi(TID_REQ *req, TR_NAME *orig_coi) req->orig_coi = orig_coi; } +void tid_req_set_request_id(TID_REQ *req, TR_NAME *request_id) +{ + req->request_id = request_id; +} + +TR_NAME *tid_req_get_request_id(TID_REQ *req) +{ + return(req->request_id); +} + TIDC_RESP_FUNC *tid_req_get_resp_func(TID_REQ *req) { return(req->resp_func); @@ -215,7 +228,13 @@ TID_REQ *tid_dup_req (TID_REQ *orig_req) tr_crit("tid_dup_req: Can't duplicate request (orig_coi)."); } } - + + if (orig_req->request_id) { + if (NULL == (new_req->request_id = tr_dup_name(orig_req->request_id))) { + tr_crit("tid_dup_req: Can't duplicate request (request_id)."); + } + } + return new_req; } diff --git a/tid/tid_resp.c b/tid/tid_resp.c index dbbc906..3ff3d02 100644 --- a/tid/tid_resp.c +++ b/tid/tid_resp.c @@ -53,6 +53,8 @@ static int tid_resp_destructor(void *obj) tr_free_name(resp->comm); if (resp->orig_coi!=NULL) tr_free_name(resp->orig_coi); + if (resp->request_id!=NULL) + tr_free_name(resp->request_id); return 0; } @@ -68,6 +70,7 @@ TID_RESP *tid_resp_new(TALLOC_CTX *mem_ctx) resp->cons=NULL; resp->orig_coi=NULL; resp->servers=NULL; + resp->request_id=NULL; resp->error_path=NULL; talloc_set_destructor((void *)resp, tid_resp_destructor); } @@ -192,6 +195,16 @@ void tid_resp_set_orig_coi(TID_RESP *resp, TR_NAME *orig_coi) resp->orig_coi = orig_coi; } +TR_EXPORT TR_NAME *tid_resp_get_request_id(TID_RESP *resp) +{ + return(resp->request_id); +} + +void tid_resp_set_request_id(TID_RESP *resp, TR_NAME *request_id) +{ + resp->request_id = request_id; +} + TR_EXPORT TID_SRVR_BLK *tid_resp_get_server(TID_RESP *resp, size_t index) { diff --git a/tid/tidc.c b/tid/tidc.c index 94cd98d..90335f0 100644 --- a/tid/tidc.c +++ b/tid/tidc.c @@ -41,6 +41,7 @@ #include #include #include +#include int tmp_len = 32; @@ -96,6 +97,7 @@ int tidc_send_request (TIDC_INSTANCE *tidc, void *cookie) { TID_REQ *tid_req = NULL; + char *request_id = NULL; int rc; int orig_conn = 0; gss_ctx_id_t *orig_gss_ctx = NULL; @@ -129,6 +131,17 @@ int tidc_send_request (TIDC_INSTANCE *tidc, tid_req->tidc_dh = tr_dh_dup(tidc->gssc->client_dh); + /* generate an ID */ + request_id = tr_random_id(NULL); + if (request_id) { + if (tid_req->request_id = tr_new_name(request_id)) + tr_debug("tidc_send_request: Created TID request ID: %s", request_id); + else + tr_debug("tidc_send_request: Unable to set request ID, proceeding without one"); + talloc_free(request_id); + } else + tr_debug("tidc_send_request: Failed to generate a TID request ID, proceeding without one"); + rc = tidc_fwd_request(tidc, tid_req, resp_handler, cookie); goto cleanup; error: @@ -150,6 +163,7 @@ int tidc_fwd_request(TIDC_INSTANCE *tidc, TALLOC_CTX *tmp_ctx = talloc_new(NULL); TR_MSG *msg = NULL; TR_MSG *resp_msg = NULL; + TID_RESP *tid_resp = NULL; int rc = 0; /* Create and populate a TID msg structure */ @@ -168,11 +182,27 @@ int tidc_fwd_request(TIDC_INSTANCE *tidc, goto error; /* TBD -- Check if this is actually a valid response */ - if (TID_RESPONSE != tr_msg_get_msg_type(resp_msg)) { + tid_resp = tr_msg_get_resp(resp_msg); + if (tid_resp == NULL) { tr_err( "tidc_fwd_request: Error, no response in the response!\n"); goto error; } + /* Check whether the request IDs matched and warn if not. Do nothing if we don't get + * an ID on the return - it is not mandatory to preserve that field. */ + if (tid_req->request_id) { + if ((tid_resp->request_id) + && (tr_name_cmp(tid_resp->request_id, tid_req->request_id) != 0)) { + /* Requests present but do not match */ + tr_warning("tidc_fwd_request: Sent request ID %.*s, received response for %.*s", + tid_req->request_id->len, tid_req->request_id->buf, + tid_resp->request_id->len, tid_resp->request_id->buf); + } + } else if (tid_resp->request_id) { + tr_warning("tidc_fwd_request: Sent request without ID, received response for %.*s", + tid_resp->request_id->len, tid_resp->request_id->buf); + } + if (resp_handler) { /* Call the caller's response function. It must copy any data it needs before returning. */ tr_debug("tidc_fwd_request: calling response callback function."); diff --git a/tid/tids.c b/tid/tids.c index 6a5b172..74e790e 100644 --- a/tid/tids.c +++ b/tid/tids.c @@ -80,6 +80,12 @@ static TID_RESP *tids_create_response(TALLOC_CTX *mem_ctx, TID_REQ *req) goto cleanup; } } + if (req->request_id) { + if (NULL == (resp->request_id = tr_dup_name(req->request_id))) { + tr_crit("tids_create_response: Error allocating fields in response."); + goto cleanup; + } + } success=1; @@ -399,8 +405,8 @@ int tids_accept(TIDS_INSTANCE *tids, int listen) int pipe_fd[2]; struct tid_process tp = {0}; - if (0 > (conn = accept(listen, NULL, NULL))) { - perror("Error from TIDS Server accept()"); + if (0 > (conn = tr_sock_accept(listen))) { + tr_err("tids_accept: Error accepting connection"); return 1; } diff --git a/tr/tr_main.c b/tr/tr_main.c index 5f8215d..ba738c7 100644 --- a/tr/tr_main.c +++ b/tr/tr_main.c @@ -81,13 +81,15 @@ static const char arg_doc[]=""; /* string describing arguments, if any */ * { long-name, short-name, variable name, options, help description } */ static const struct argp_option cmdline_options[] = { { "config-dir", 'c', "DIR", 0, "Specify configuration file location (default is current directory)"}, - { "version", 'v', NULL, 0, "Print version information and exit"}, + { "config-validate", 'C', NULL, 0, "Validate configuration files and exit"}, + { "version", 1, NULL, 0, "Print version information and exit"}, { NULL } }; /* structure for communicating with option parser */ struct cmdline_args { int version_requested; + int validate_config_and_exit; char *config_dir; }; @@ -106,10 +108,14 @@ static error_t parse_option(int key, char *arg, struct argp_state *state) arguments->config_dir=arg; break; - case 'v': + case 1: arguments->version_requested=1; break; + case 'C': + arguments->validate_config_and_exit=1; + break; + default: return ARGP_ERR_UNKNOWN; } @@ -207,6 +213,7 @@ int main(int argc, char *argv[]) /***** parse command-line arguments *****/ /* set defaults */ opts.version_requested=0; + opts.validate_config_and_exit=0; opts.config_dir="."; /* parse the command line*/ @@ -271,6 +278,11 @@ int main(int argc, char *argv[]) return 1; } + /***** Exit here if we are just validating our configuration *****/ + if (opts.validate_config_and_exit) { + printf("Valid configuration found in %s.\n", opts.config_dir); + return 0; + } /***** Set up the event loop *****/ ev_base=tr_event_loop_init(); /* Set up the event loop */ if (ev_base==NULL) { diff --git a/tr/tr_tid.c b/tr/tr_tid.c index 038cc3c..62722e8 100644 --- a/tr/tr_tid.c +++ b/tr/tr_tid.c @@ -346,6 +346,12 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids, tr_debug("tr_tids_req_handler: Request received (conn = %d)! Realm = %s, Comm = %s", orig_req->conn, orig_req->realm->buf, orig_req->comm->buf); + if (orig_req->request_id) + tr_debug("tr_tids_req_handler: TID request ID: %.*s", orig_req->request_id->len, orig_req->request_id->buf); + else + tr_debug("tr_tids_req_handler: TID request ID: none"); + + tids->req_count++; /* Duplicate the request, so we can modify and forward it */ if (NULL == (fwd_req=tid_dup_req(orig_req))) { diff --git a/tr/tr_trp.c b/tr/tr_trp.c index 79a9a27..9f9c558 100644 --- a/tr/tr_trp.c +++ b/tr/tr_trp.c @@ -114,7 +114,7 @@ static int tr_trps_gss_handler(gss_name_t client_name, gss_buffer_t gss_name, tr_debug("tr_trps_gss_handler()"); - if ((!client_name) || (!gss_name) || (!trps) || (!cfg_mgr)) { + if ((!client_name) || (!trps) || (!cfg_mgr)) { tr_debug("tr_trps_gss_handler: Bad parameters."); return -1; } @@ -884,7 +884,11 @@ void tr_config_changed(TR_CFG *new_cfg, void *cookie) tr_debug("tr_config_changed: freeing tr->mons->authorized_gss_names"); tr_gss_names_free(tr->mons->authorized_gss_names); } - tr->mons->authorized_gss_names = tr_gss_names_dup(tr->mons, new_cfg->internal->monitoring_credentials); + if (new_cfg->internal->monitoring_credentials != NULL) { + tr->mons->authorized_gss_names = tr_gss_names_dup(tr->mons, new_cfg->internal->monitoring_credentials); + } else { + tr->mons->authorized_gss_names = tr_gss_names_new(tr->mons); + } if (tr->mons->authorized_gss_names == NULL) { tr_err("tr_config_changed: Error configuring monitoring credentials"); } diff --git a/trp/trp_conn.c b/trp/trp_conn.c index dfa666c..1cf326d 100644 --- a/trp/trp_conn.c +++ b/trp/trp_conn.c @@ -40,6 +40,7 @@ #include #include +#include /* Threading note: mutex lock is only used for protecting get_status() and set_status(). * If needed, locking for other operations (notably adding/removing connections) must be managed @@ -349,10 +350,10 @@ TRP_CONNECTION *trp_connection_accept(TALLOC_CTX *mem_ctx, int listen, TR_NAME * int conn_fd=-1; TRP_CONNECTION *conn=NULL; - conn_fd = accept(listen, NULL, NULL); + conn_fd = tr_sock_accept(listen); if (0 > conn_fd) { - tr_notice("trp_connection_accept: accept() returned error."); + tr_notice("trp_connection_accept: Error accepting connection."); return NULL; } conn=trp_connection_new(mem_ctx); diff --git a/trp/trp_ptable_encoders.c b/trp/trp_ptable_encoders.c index 2ff8c9c..ea97a10 100644 --- a/trp/trp_ptable_encoders.c +++ b/trp/trp_ptable_encoders.c @@ -60,10 +60,12 @@ json_t *trp_ptable_to_json(TRP_PTABLE *ptbl) { TRP_PTABLE_ITER *iter = trp_ptable_iter_new(NULL); json_t *ptbl_json = json_array(); - TRP_PEER *peer = trp_ptable_iter_first(iter, ptbl); - while(peer) { + TRP_PEER *peer = NULL; + + for (trp_ptable_iter_first(iter, ptbl); + peer != NULL; + peer = trp_ptable_iter_next(iter)) { json_array_append_new(ptbl_json, trp_peer_to_json(peer)); - peer = trp_ptable_iter_next(iter); } trp_ptable_iter_free(iter); return ptbl_json; diff --git a/trp/trp_route.c b/trp/trp_route.c index 1334032..6178d97 100644 --- a/trp/trp_route.c +++ b/trp/trp_route.c @@ -45,6 +45,7 @@ #include #include #include +#include /* Note: be careful mixing talloc with glib. */ @@ -225,6 +226,18 @@ struct timespec *trp_route_get_expiry(TRP_ROUTE *entry) return entry->expiry; } +/** + * Get the expiration according to the realtime clock + * + * @param entry + * @param result space to store the result + * @return pointer to the result, or null on error + */ +struct timespec *trp_route_get_expiry_realtime(TRP_ROUTE *entry, struct timespec *result) +{ + return tr_clock_convert(TRP_CLOCK, entry->expiry, CLOCK_REALTIME, result); +} + void trp_route_set_local(TRP_ROUTE *entry, int local) { entry->local=local; diff --git a/trp/trp_route_encoders.c b/trp/trp_route_encoders.c index 8e1809b..c954a81 100644 --- a/trp/trp_route_encoders.c +++ b/trp/trp_route_encoders.c @@ -84,12 +84,15 @@ char *trp_route_to_str(TALLOC_CTX *mem_ctx, TRP_ROUTE *entry, const char *sep) /* helper */ static json_t *expiry_to_json_string(TRP_ROUTE *route) { - struct timespec ts_zero = {0, 0}; + struct timespec ts = {0}; /* initialization to zero is important */ char *s = NULL; json_t *jstr = NULL; - if (tr_cmp_timespec(trp_route_get_expiry(route), &ts_zero) > 0) { - s = timespec_to_str(trp_route_get_expiry(route)); + if (tr_cmp_timespec(trp_route_get_expiry(route), &ts) > 0) { + if (trp_route_get_expiry_realtime(route, &ts) == NULL) + s = strdup("error"); + else + s = timespec_to_str(&ts); if (s) { jstr = json_string(s); diff --git a/trp/trps.c b/trp/trps.c index b737aba..32a7de1 100644 --- a/trp/trps.c +++ b/trp/trps.c @@ -656,36 +656,51 @@ static TRP_RC trps_accept_update(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_INFOREC static TRP_RC trps_handle_inforec_route(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_INFOREC *rec) { TRP_ROUTE *route=NULL; + TR_COMM *comm = NULL; unsigned int feas=0; /* determine feasibility */ feas=trps_check_feasibility(trps, trp_upd_get_realm(upd), trp_upd_get_comm(upd), rec); tr_debug("trps_handle_update: record feasibility=%d", feas); - /* do we have an existing route? */ - route=trps_get_route(trps, - trp_upd_get_comm(upd), - trp_upd_get_realm(upd), - trp_upd_get_peer(upd)); - if (route!=NULL) { - /* there was a route table entry already */ - tr_debug("trps_handle_updates: route entry already exists."); - if (feas) { - /* Update is feasible. Accept it. */ - trps_accept_update(trps, upd, rec); - } else { - /* Update is infeasible. Ignore it unless the trust router has changed. */ - if (0!=tr_name_cmp(trp_route_get_trust_router(route), - trp_inforec_get_trust_router(rec))) { - /* the trust router associated with the route has changed, treat update as a retraction */ - trps_retract_route(trps, route); + /* verify that the community is an APC */ + comm = tr_comm_table_find_comm(trps->ctable, trp_upd_get_comm(upd)); + if (comm == NULL) { + /* We don't know this community. Reject the route. */ + tr_debug("trps_handle_updates: community %.*s unknown, ignoring route for %.*s", + trp_upd_get_comm(upd)->len, trp_upd_get_comm(upd)->buf, + trp_upd_get_realm(upd)->len, trp_upd_get_realm(upd)->buf); + } else if (tr_comm_get_type(comm) != TR_COMM_APC) { + /* The community in a route request *must* be an APC. This was not - ignore it. */ + tr_debug("trps_handle_updates: community %.*s is not an APC, ignoring route for %.*s", + trp_upd_get_comm(upd)->len, trp_upd_get_comm(upd)->buf, + trp_upd_get_realm(upd)->len, trp_upd_get_realm(upd)->buf); + } else { + /* do we have an existing route? */ + route=trps_get_route(trps, + trp_upd_get_comm(upd), + trp_upd_get_realm(upd), + trp_upd_get_peer(upd)); + if (route!=NULL) { + /* there was a route table entry already */ + tr_debug("trps_handle_updates: route entry already exists."); + if (feas) { + /* Update is feasible. Accept it. */ + trps_accept_update(trps, upd, rec); + } else { + /* Update is infeasible. Ignore it unless the trust router has changed. */ + if (0!=tr_name_cmp(trp_route_get_trust_router(route), + trp_inforec_get_trust_router(rec))) { + /* the trust router associated with the route has changed, treat update as a retraction */ + trps_retract_route(trps, route); + } } + } else { + /* No existing route table entry. Ignore it unless it is feasible and not a retraction. */ + tr_debug("trps_handle_update: no route entry exists yet."); + if (feas && trp_metric_is_finite(trp_inforec_get_metric(rec))) + trps_accept_update(trps, upd, rec); } - } else { - /* No existing route table entry. Ignore it unless it is feasible and not a retraction. */ - tr_debug("trps_handle_update: no route entry exists yet."); - if (feas && trp_metric_is_finite(trp_inforec_get_metric(rec))) - trps_accept_update(trps, upd, rec); } return TRP_SUCCESS; @@ -771,7 +786,7 @@ cleanup: return comm; } -static TR_RP_REALM *trps_create_new_rp_realm(TALLOC_CTX *mem_ctx, TR_NAME *realm_id, TRP_INFOREC *rec) +static TR_RP_REALM *trps_create_new_rp_realm(TALLOC_CTX *mem_ctx, TR_NAME *comm, TR_NAME *realm_id, TRP_INFOREC *rec) { TALLOC_CTX *tmp_ctx=talloc_new(NULL); TR_RP_REALM *rp=tr_rp_realm_new(tmp_ctx); @@ -794,11 +809,15 @@ cleanup: return rp; } -static TR_IDP_REALM *trps_create_new_idp_realm(TALLOC_CTX *mem_ctx, TR_NAME *realm_id, TRP_INFOREC *rec) +static TR_IDP_REALM *trps_create_new_idp_realm(TALLOC_CTX *mem_ctx, + TR_NAME *comm_id, + TR_NAME *realm_id, + TRP_INFOREC *rec) { TALLOC_CTX *tmp_ctx=talloc_new(NULL); TR_IDP_REALM *idp=tr_idp_realm_new(tmp_ctx); - + TR_APC *realm_apcs = NULL; + if (idp==NULL) { tr_debug("trps_create_new_idp_realm: unable to allocate new realm."); goto cleanup; @@ -810,14 +829,52 @@ static TR_IDP_REALM *trps_create_new_idp_realm(TALLOC_CTX *mem_ctx, TR_NAME *rea idp=NULL; goto cleanup; } - if (trp_inforec_get_apcs(rec)!=NULL) { - tr_idp_realm_set_apcs(idp, tr_apc_dup(tmp_ctx, trp_inforec_get_apcs(rec))); - if (tr_idp_realm_get_apcs(idp)==NULL) { - tr_debug("trps_create_new_idp_realm: unable to allocate APC list."); - idp=NULL; + + /* Set the APCs. If the community is a CoI, copy its APCs. If it is an APC, then + * that community itself is the APC for the realm. */ + if (trp_inforec_get_comm_type(rec) == TR_COMM_APC) { + /* the community is an APC for this realm */ + realm_apcs = tr_apc_new(tmp_ctx); + if (realm_apcs == NULL) { + tr_debug("trps_create_new_idp_realm: unable to allocate new APC list."); + idp = NULL; + goto cleanup; + } + + tr_apc_set_id(realm_apcs, tr_dup_name(comm_id)); + if (tr_apc_get_id(realm_apcs) == NULL) { + tr_debug("trps_create_new_idp_realm: unable to allocate new APC name."); + idp = NULL; + goto cleanup; + } + } else { + /* the community is not an APC for this realm */ + realm_apcs = trp_inforec_get_apcs(rec); + if (realm_apcs == NULL) { + tr_debug("trps_create_new_idp_realm: no APCs for realm %.*s/%.*s, cannot add.", + realm_id->len, realm_id->buf, + comm_id->len, comm_id->buf); + idp = NULL; + goto cleanup; + } + + /* we have APCs, make our own copy */ + realm_apcs = tr_apc_dup(tmp_ctx, realm_apcs); + if (realm_apcs == NULL) { + tr_debug("trps_create_new_idp_realm: unable to duplicate APC list."); + idp = NULL; goto cleanup; } } + + /* Whether the community is an APC or CoI, the APCs for the realm are in realm_apcs */ + tr_idp_realm_set_apcs(idp, realm_apcs); /* takes realm_apcs out of tmp_ctx on success */ + if (tr_idp_realm_get_apcs(idp) == NULL) { + tr_debug("trps_create_new_idp_realm: unable to set APC list for new realm."); + idp=NULL; + goto cleanup; + } + idp->origin=TR_REALM_DISCOVERED; talloc_steal(mem_ctx, idp); @@ -867,7 +924,11 @@ static TRP_RC trps_handle_inforec_comm(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_IN tr_debug("trps_handle_inforec_comm: unable to create new community."); goto cleanup; } - tr_comm_table_add_comm(trps->ctable, comm); + if (tr_comm_table_add_comm(trps->ctable, comm) != 0) + { + tr_debug("trps_handle_inforec_comm: unable to add community to community table."); + goto cleanup; + } } /* TODO: see if other comm data match the new inforec and update or complain */ @@ -881,7 +942,7 @@ static TRP_RC trps_handle_inforec_comm(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_IN if (rp_realm==NULL) { tr_debug("trps_handle_inforec_comm: unknown RP realm %.*s in inforec, creating it.", realm_id->len, realm_id->buf); - rp_realm=trps_create_new_rp_realm(tmp_ctx, realm_id, rec); + rp_realm= trps_create_new_rp_realm(tmp_ctx, tr_comm_get_id(comm), realm_id, rec); if (rp_realm==NULL) { tr_debug("trps_handle_inforec_comm: unable to create new RP realm."); /* we may leave an unused community in the table, but it will only last until @@ -902,7 +963,7 @@ static TRP_RC trps_handle_inforec_comm(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_IN if (idp_realm==NULL) { tr_debug("trps_handle_inforec_comm: unknown IDP realm %.*s in inforec, creating it.", realm_id->len, realm_id->buf); - idp_realm=trps_create_new_idp_realm(tmp_ctx, realm_id, rec); + idp_realm= trps_create_new_idp_realm(tmp_ctx, tr_comm_get_id(comm), realm_id, rec); if (idp_realm==NULL) { tr_debug("trps_handle_inforec_comm: unable to create new IDP realm."); /* we may leave an unused community in the table, but it will only last until @@ -1055,12 +1116,13 @@ static TRP_RC trps_validate_request(TRPS_INSTANCE *trps, TRP_REQ *req) /* choose the best route to comm/realm, optionally excluding routes to a particular peer */ static TRP_ROUTE *trps_find_best_route(TRPS_INSTANCE *trps, - TR_NAME *comm, - TR_NAME *realm, - TR_NAME *exclude_peer) + TR_NAME *comm, + TR_NAME *realm, + TR_NAME *exclude_peer_label) { TRP_ROUTE **entry=NULL; TRP_ROUTE *best=NULL; + TRP_PEER *route_peer = NULL; size_t n_entry=0; unsigned int kk=0; unsigned int kk_min=0; @@ -1069,13 +1131,31 @@ static TRP_ROUTE *trps_find_best_route(TRPS_INSTANCE *trps, entry=trp_rtable_get_realm_entries(trps->rtable, comm, realm, &n_entry); for (kk=0; kkptable, + trp_route_get_peer(entry[kk])); + if (route_peer == NULL) { + tr_err("trps_find_best_route: unknown peer GSS name (%.*s) for route %d to %.*s/%.*s", + trp_route_get_peer(entry[kk])->len, trp_route_get_peer(entry[kk])->buf, + kk, + realm->len, realm->buf, + comm->len, comm->buf); + continue; /* unknown peer, skip the route */ + } + if (0 == tr_name_cmp(exclude_peer_label, trp_peer_get_label(route_peer))) { + /* we're excluding this peer - skip the route */ + continue; + } + } + } + /* if we get here, we're not excluding the route */ + kk_min = kk; + min_metric = trp_route_get_metric(entry[kk]); } } + if (trp_metric_is_finite(min_metric)) best=entry[kk_min]; @@ -1182,6 +1262,7 @@ TRP_RC trps_sweep_ctable(TRPS_INSTANCE *trps) { TALLOC_CTX *tmp_ctx=talloc_new(NULL); struct timespec sweep_time={0,0}; + struct timespec tmp = {0}; TR_COMM_MEMB *memb=NULL; TR_COMM_ITER *iter=NULL; TRP_RC rc=TRP_ERROR; @@ -1214,7 +1295,7 @@ TRP_RC trps_sweep_ctable(TRPS_INSTANCE *trps) tr_comm_memb_get_realm_id(memb)->len, tr_comm_memb_get_realm_id(memb)->buf, tr_comm_get_id(tr_comm_memb_get_comm(memb))->len, tr_comm_get_id(tr_comm_memb_get_comm(memb))->buf, tr_comm_memb_get_origin(memb)->len, tr_comm_memb_get_origin(memb)->buf, - timespec_to_str(tr_comm_memb_get_expiry(memb))); + timespec_to_str(tr_comm_memb_get_expiry_realtime(memb, &tmp))); tr_comm_table_remove_memb(trps->ctable, memb); tr_comm_memb_free(memb); } else { @@ -1222,8 +1303,8 @@ TRP_RC trps_sweep_ctable(TRPS_INSTANCE *trps) tr_comm_memb_expire(memb); trps_compute_expiry(trps, tr_comm_memb_get_interval(memb), tr_comm_memb_get_expiry(memb)); tr_debug("trps_sweep_ctable: community membership expired at %s, resetting expiry to %s (%.*s in %.*s, origin %.*s).", - timespec_to_str(&sweep_time), - timespec_to_str(tr_comm_memb_get_expiry(memb)), + timespec_to_str(tr_clock_convert(TRP_CLOCK, &sweep_time, CLOCK_REALTIME, &tmp)), + timespec_to_str(tr_comm_memb_get_expiry_realtime(memb, &tmp)), tr_comm_memb_get_realm_id(memb)->len, tr_comm_memb_get_realm_id(memb)->buf, tr_comm_get_id(tr_comm_memb_get_comm(memb))->len, tr_comm_get_id(tr_comm_memb_get_comm(memb))->buf, tr_comm_memb_get_origin(memb)->len, tr_comm_memb_get_origin(memb)->buf); @@ -1324,26 +1405,67 @@ cleanup: } /* select the correct route to comm/realm to be announced to peer */ -static TRP_ROUTE *trps_select_realm_update(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer_gssname) +static TRP_ROUTE *trps_select_realm_update(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer_label) { - TRP_ROUTE *route; + TRP_ROUTE *route = NULL; + TRP_PEER *route_peer = NULL; + TR_NAME *route_peer_label = NULL; /* Take the currently selected route unless it is through the peer we're sending the update to. - * I.e., enforce the split horizon rule. */ + * I.e., enforce the split horizon rule. Start by looking up the currently selected route. */ route=trp_rtable_get_selected_entry(trps->rtable, comm, realm); if (route==NULL) { /* No selected route, this should only happen if the only route has been retracted, * in which case we do not want to advertise it. */ return NULL; } - tr_debug("trps_select_realm_update: %s vs %s", peer_gssname->buf, - trp_route_get_peer(route)->buf); - if (0==tr_name_cmp(peer_gssname, trp_route_get_peer(route))) { - tr_debug("trps_select_realm_update: matched, finding alternate route"); - /* the selected entry goes through the peer we're reporting to, choose an alternate */ - route=trps_find_best_route(trps, comm, realm, peer_gssname); - if ((route==NULL) || (!trp_metric_is_finite(trp_route_get_metric(route)))) - return NULL; /* don't advertise a nonexistent or retracted route */ + + /* Check whether it's local. */ + if (trp_route_is_local(route)) { + /* It is always ok to announce a local route */ + tr_debug("trps_select_realm_update: selected route for %.*s/%.*s is local", + realm->len, realm->buf, + comm->len, comm->buf); + } else { + /* It's not local. Get the route's peer and check whether it's the same place we + * got the selected route from. Peer should always correspond to an entry in our + * peer table. */ + tr_debug("trps_select_realm_update: selected route for %.*s/%.*s is not local", + realm->len, realm->buf, + comm->len, comm->buf); + route_peer = trp_ptable_find_gss_name(trps->ptable, trp_route_get_peer(route)); + if (route_peer == NULL) { + tr_err("trps_select_realm_update: unknown peer GSS name (%.*s) for selected route for %.*s/%.*s", + trp_route_get_peer(route)->len, trp_route_get_peer(route)->buf, + realm->len, realm->buf, + comm->len, comm->buf); + return NULL; + } + route_peer_label = trp_peer_get_label(route_peer); + if (route_peer_label == NULL) { + tr_err("trps_select_realm_update: error retrieving peer label for selected route for %.*s/%.*s", + realm->len, realm->buf, + comm->len, comm->buf); + return NULL; + } + + /* see if these match */ + tr_debug("trps_select_realm_update: %.*s vs %.*s", + peer_label->len, peer_label->buf, + route_peer_label->len, route_peer_label->buf); + + if (0==tr_name_cmp(peer_label, route_peer_label)) { + /* the selected entry goes through the peer we're reporting to, choose an alternate */ + tr_debug("trps_select_realm_update: matched, finding alternate route"); + route=trps_find_best_route(trps, comm, realm, peer_label); + if ((route==NULL) || (!trp_metric_is_finite(trp_route_get_metric(route)))) { + tr_debug("trps_select_realm_update: no route to %.*s/%.*s suitable to advertise to %.*s", + realm->len, realm->buf, + comm->len, comm->buf, + peer_label->len, peer_label->buf); + return NULL; /* don't advertise a nonexistent or retracted route */ + } + } } return route; } @@ -1352,7 +1474,7 @@ static TRP_ROUTE *trps_select_realm_update(TRPS_INSTANCE *trps, TR_NAME *comm, T static TRP_RC trps_select_route_updates_for_peer(TALLOC_CTX *mem_ctx, GPtrArray *updates, TRPS_INSTANCE *trps, - TR_NAME *peer_gssname, + TR_NAME *peer_label, int triggered) { size_t n_comm=0; @@ -1369,7 +1491,7 @@ static TRP_RC trps_select_route_updates_for_peer(TALLOC_CTX *mem_ctx, for (ii=0; iirtable, comm[ii], &n_realm); for (jj=0; jjlen, tr_realm_get_id(realm)->buf); - upd=trps_comm_update(mem_ctx, trps, peer_gssname, comm, realm); + upd=trps_comm_update(mem_ctx, trps, peer_label, comm, realm); if (upd!=NULL) g_ptr_array_add(updates, upd); }