From f98d872ef431521d9b39b1a362c4697be7f31c04 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Thu, 8 Jun 2017 19:01:54 -0400 Subject: [PATCH] In-progress commit. * Allow array for filter spec match field * Validate filters and filter specs * Add filter to TRP_PEER * Add filter tests in filt_test.c * Add several test filter JSON files --- Makefile.am | 11 +- common/tests/filt_test.c | 76 +++++- .../test-filters/invalid-filt-repeated-key.json | 59 +++++ .../test-filters/invalid-filt-unknown-field.json | 59 +++++ common/tests/test-filters/valid-filt.json | 53 ++++ common/tr_config.c | 277 ++++++++++++++------- common/tr_filter.c | 137 ++++++---- include/tr_filter.h | 12 +- include/trp_ptable.h | 4 + trp/trp_ptable.c | 24 +- 10 files changed, 567 insertions(+), 145 deletions(-) create mode 100644 common/tests/test-filters/invalid-filt-repeated-key.json create mode 100644 common/tests/test-filters/invalid-filt-unknown-field.json create mode 100644 common/tests/test-filters/valid-filt.json diff --git a/Makefile.am b/Makefile.am index b8a5104..2254baf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@ DISTCHECK_CONFIGURE_FLAGS = \ --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) bin_PROGRAMS= tr/trust_router tr/trpc tid/example/tidc tid/example/tids common/tests/tr_dh_test common/tests/mq_test \ common/tests/thread_test trp/msgtst trp/test/rtbl_test trp/test/ptbl_test common/tests/cfg_test \ - common/tests/commtest common/tests/name_test + common/tests/commtest common/tests/name_test common/tests/filt_test AM_CPPFLAGS=-I$(srcdir)/include $(GLIB_CFLAGS) AM_CFLAGS = -Wall -Werror=missing-prototypes -Werror -Wno-parentheses $(GLIB_CFLAGS) SUBDIRS = gsscon @@ -37,6 +37,7 @@ common/tr_mq.c check_PROGRAMS = common/t_constraint TESTS = common/t_constraint +TEST_CFLAGS = -Wno-missing-prototypes lib_LTLIBRARIES = libtr_tid.la @@ -153,7 +154,15 @@ common_tests_name_test_SOURCES = common/tests/name_test.c \ $(trp_srcs) common_tests_name_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS) common_tests_name_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc -pthread +common_tests_name_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +common_tests_filt_test_SOURCES = common/tests/filt_test.c \ + $(common_srcs) \ + $(tid_srcs) \ + $(trp_srcs) +common_tests_filt_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS) +common_tests_filt_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc -pthread +common_tests_filt_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) pkginclude_HEADERS = include/trust_router/tid.h include/trust_router/tr_name.h \ include/tr_debug.h include/trust_router/trp.h \ diff --git a/common/tests/filt_test.c b/common/tests/filt_test.c index cffeebc..c7eb028 100644 --- a/common/tests/filt_test.c +++ b/common/tests/filt_test.c @@ -36,17 +36,85 @@ #include #include +#include +#include #include +#include -int test_field_lookup(void) +#define FILTER_PATH "./test-filters/" + +/** + * Load a JSON file containing filters and return the filters from the first rp_client. + * + * @param fname File to read + * @param filt_out Will point to the loaded filter on success + * @return Return value from tr_cfg_parse_one_config_file() + */ +int load_filter(const char *fname, TR_FILTER **filt_out) { + TR_CFG *cfg=tr_cfg_new(NULL); + TR_CFG_RC rc=TR_CFG_ERROR; - return 0; + assert(fname); + assert(filt_out); + + rc=tr_cfg_parse_one_config_file(cfg, fname); + if (rc!=TR_CFG_SUCCESS) + goto cleanup; + + /* Steal the filter from the first rp_client */ + assert(cfg); + assert(cfg->rp_clients); + assert(cfg->rp_clients->filter); + *filt_out=cfg->rp_clients->filter; + cfg->rp_clients->filter=NULL; /* can't use the _set_filter() because that will free the filter */ + talloc_steal(NULL, *filt_out); + +cleanup: + tr_cfg_free(cfg); + return rc; } -int main(void) +/** + * Test that filters load / fail to load as expected. + * + * @return 1 if all tests pass + */ +int test_load_filter(void) +{ + TR_FILTER *filt=NULL; + + assert(TR_CFG_SUCCESS==load_filter(FILTER_PATH "valid-filt.json", &filt)); + assert(TR_CFG_NOPARSE==load_filter(FILTER_PATH "invalid-filt-repeated-key.json", &filt)); + assert(TR_CFG_ERROR==load_filter(FILTER_PATH "invalid-filt-unknown-field.json", &filt)); + return 1; +} + +int test_trp_inforec_filter(TRP_INFOREC_TYPE type) { + TRP_INFOREC *inforec=trp_inforec_new(NULL, type); + TR_FILTER *filt=tr_filter_new(NULL); + + assert(inforec); + assert(filt); - printf("Success.\n"); + + return 1; +} + + +int test_trp_filter(void) +{ + assert(test_trp_inforec_filter(TRP_INFOREC_TYPE_ROUTE)); + assert(test_trp_inforec_filter(TRP_INFOREC_TYPE_COMMUNITY)); + return 1; +} + + + +int main(void) +{ + assert(test_load_filter()); + printf("Success\n"); return 0; } \ No newline at end of file diff --git a/common/tests/test-filters/invalid-filt-repeated-key.json b/common/tests/test-filters/invalid-filt-repeated-key.json new file mode 100644 index 0000000..5ff336f --- /dev/null +++ b/common/tests/test-filters/invalid-filt-repeated-key.json @@ -0,0 +1,59 @@ +{ + "local_organizations": [ + { "organization_name": "invalid filter - repeated key", + "realms": [ + { "realm": "realm", + "gss_names": ["gss"], + "filters": { + "tid_inbound": [ + { "action": "accept", + "specs": [ + { "field": "rp_realm", + "match": [ + "a.realm", + "*.a.realm" + ] + } + ] + }, + { "action": "accept", + "specs": [ + { "field": "info_type", + "match": ["community"]} + ] + } + ], + "tid_inbound": [ + { "action": "accept", + "specs": [ + { "field": "info_type", + "match": ["realm"]} + ] + }, + { "action": "accept", + "specs": [ + { "field": "info_type", + "match": ["community"]} + ] + } + ], + "trp_outbound": [ + { "action": "accept", + "specs": [ + { "field": "info_type", + "match": ["realm"]} + ] + }, + { "action": "accept", + "specs": [ + { "field": "info_type", + "match": ["community"]} + ] + } + ] + } + } + ] + } + ] +} diff --git a/common/tests/test-filters/invalid-filt-unknown-field.json b/common/tests/test-filters/invalid-filt-unknown-field.json new file mode 100644 index 0000000..92c56dd --- /dev/null +++ b/common/tests/test-filters/invalid-filt-unknown-field.json @@ -0,0 +1,59 @@ +{ + "local_organizations": [ + { "organization_name": "invalid filter - unknown field", + "realms": [ + { "realm": "realm", + "gss_names": ["gss"], + "filters": { + "tid_inbound": [ + { "action": "accept", + "specs": [ + { "field": "rp_realm", + "match": [ + "a.realm", + "*.a.realm" + ] + } + ] + }, + { "action": "accept", + "specs": [ + { "field": "info_type", + "match": ["community"]} + ] + } + ], + "trp_inbound": [ + { "action": "accept", + "specs": [ + { "field": "this is not a real field", + "match": ["realm"]} + ] + }, + { "action": "accept", + "specs": [ + { "field": "info_type", + "match": ["community"]} + ] + } + ], + "trp_outbound": [ + { "action": "accept", + "specs": [ + { "field": "info_type", + "match": ["realm"]} + ] + }, + { "action": "accept", + "specs": [ + { "field": "info_type", + "match": ["community"]} + ] + } + ] + } + } + ] + } + ] +} diff --git a/common/tests/test-filters/valid-filt.json b/common/tests/test-filters/valid-filt.json new file mode 100644 index 0000000..b4fdfb3 --- /dev/null +++ b/common/tests/test-filters/valid-filt.json @@ -0,0 +1,53 @@ +{ + "local_organizations": [ + { "organization_name": "valid filter test", + "realms": [ + { "realm": "realm", + "gss_names": ["gss"], + "filters": { + "tid_inbound": [ + { "action": "accept", + "specs": [ + { "field": "rp_realm", + "match": [ + "a.realm", + "*.a.realm" + ] + } + ] + } + ], + "trp_inbound": [ + { "action": "accept", + "specs": [ + { "field": "info_type", + "match": ["realm"]} + ] + }, + { "action": "accept", + "specs": [ + { "field": "info_type", + "match": ["community"]} + ] + } + ], + "trp_outbound": [ + { "action": "accept", + "specs": [ + { "field": "info_type", + "match": ["realm"]} + ] + }, + { "action": "accept", + "specs": [ + { "field": "info_type", + "match": ["community"]} + ] + } + ] + } + } + ] + } + ] +} diff --git a/common/tr_config.c b/common/tr_config.c index ab3388e..917a465 100644 --- a/common/tr_config.c +++ b/common/tr_config.c @@ -410,30 +410,62 @@ static TR_CONSTRAINT *tr_cfg_parse_one_constraint(TALLOC_CTX *mem_ctx, char *cty return cons; } -static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR_FILTER_TYPE ftype, TR_CFG_RC *rc) +TR_FILTER_TYPE filter_type[]={TR_FILTER_TYPE_TID_INBOUND, + TR_FILTER_TYPE_TRP_INBOUND, + TR_FILTER_TYPE_TRP_OUTBOUND}; +const char *filter_label[]={"tid_inbound", + "trp_inbound", + "trp_outbound"}; +size_t num_filter_types=sizeof(filter_type)/sizeof(filter_type[0]); + +static const char *filter_type_to_string(TR_FILTER_TYPE ftype) { - TALLOC_CTX *tmp_ctx=talloc_new(NULL); - TR_FILTER *filt=NULL; - json_t *jfaction=NULL; - json_t *jfspecs=NULL; - json_t *jffield=NULL; - json_t *jfmatch=NULL; - json_t *jrc=NULL; - json_t *jdc=NULL; - TR_NAME *name=NULL; - int i=0, j=0; + size_t ii=0; - *rc=TR_CFG_ERROR; + for (ii=0; ii 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; + *rc = TR_CFG_NOPARSE; goto cleanup; } /* For each entry in the filter... */ - for (i=0; i < json_array_size(jfilt); i++) { - if ((NULL==(jfaction=json_object_get(json_array_get(jfilt, i), "action"))) || + for (i = 0; i < json_array_size(jfilt); i++) { + if ((NULL == (jfaction = json_object_get(json_array_get(jfilt, i), "action"))) || (!json_is_string(jfaction))) { tr_debug("tr_cfg_parse_one_filter: Error parsing filter action."); - *rc=TR_CFG_NOPARSE; + *rc = TR_CFG_NOPARSE; goto cleanup; } - - if ((NULL==(jfspecs=json_object_get(json_array_get(jfilt, i), "specs"))) || + + if ((NULL == (jfspecs = json_object_get(json_array_get(jfilt, i), "specs"))) || (!json_is_array(jfspecs)) || - (0==json_array_size(jfspecs))) { + (0 == json_array_size(jfspecs))) { tr_debug("tr_cfg_parse_one_filter: Error parsing filter specs."); - *rc=TR_CFG_NOPARSE; + *rc = TR_CFG_NOPARSE; 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; + *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); - *rc=TR_CFG_NOMEM; + if (NULL == (filt->lines[i] = tr_fline_new(filt))) { + tr_debug("tr_cfg_parse_one_filter: Out of memory allocating filter line %d.", i + 1); + *rc = TR_CFG_NOMEM; goto cleanup; } if (!strcmp(json_string_value(jfaction), "accept")) { - filt->lines[i]->action=TR_FILTER_ACTION_ACCEPT; - } - else if (!strcmp(json_string_value(jfaction), "reject")) { - filt->lines[i]->action=TR_FILTER_ACTION_REJECT; - } - else { - tr_debug("tr_cfg_parse_one_filter: Error parsing filter action, unknown action' %s'.", json_string_value(jfaction)); - *rc=TR_CFG_NOPARSE; + filt->lines[i]->action = TR_FILTER_ACTION_ACCEPT; + } else if (!strcmp(json_string_value(jfaction), "reject")) { + filt->lines[i]->action = TR_FILTER_ACTION_REJECT; + } else { + tr_debug("tr_cfg_parse_one_filter: Error parsing filter action, unknown action' %s'.", + json_string_value(jfaction)); + *rc = TR_CFG_NOPARSE; goto cleanup; } - if (NULL!=(jrc=json_object_get(json_array_get(jfilt, i), "realm_constraints"))) { + if (NULL != (jrc = json_object_get(json_array_get(jfilt, i), "realm_constraints"))) { if (!json_is_array(jrc)) { tr_err("tr_cfg_parse_one_filter: cannot parse realm_constraints, not an array."); - *rc=TR_CFG_NOPARSE; + *rc = TR_CFG_NOPARSE; goto cleanup; - } else if (json_array_size(jrc)>TR_MAX_CONST_MATCHES) { + } 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; + *rc = TR_CFG_NOPARSE; goto cleanup; - } else if (json_array_size(jrc)>0) { + } 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 == (filt->lines[i]->realm_cons = tr_cfg_parse_one_constraint(filt->lines[i], "realm", jrc, rc))) { tr_debug("tr_cfg_parse_one_filter: Error parsing realm constraint"); - *rc=TR_CFG_NOPARSE; + *rc = TR_CFG_NOPARSE; goto cleanup; } } } - if (NULL!=(jdc=json_object_get(json_array_get(jfilt, i), "domain_constraints"))) { + if (NULL != (jdc = json_object_get(json_array_get(jfilt, i), "domain_constraints"))) { if (!json_is_array(jdc)) { tr_err("tr_cfg_parse_one_filter: cannot parse domain_constraints, not an array."); - *rc=TR_CFG_NOPARSE; + *rc = TR_CFG_NOPARSE; goto cleanup; - } else if (json_array_size(jdc)>TR_MAX_CONST_MATCHES) { + } 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; + *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))) { + } else if (json_array_size(jdc) > 0) { + if (NULL == (filt->lines[i]->domain_cons = tr_cfg_parse_one_constraint(filt->lines[i], "domain", jdc, rc))) { tr_debug("tr_cfg_parse_one_filter: Error parsing domain constraint"); - *rc=TR_CFG_NOPARSE; + *rc = TR_CFG_NOPARSE; goto cleanup; } } } /*For each filter spec within the filter line... */ - for (j=0; j lines[i]->specs[j]=tr_fspec_new(filt->lines[i]))) { + if (NULL == (filt->lines[i]->specs[j] = tr_fspec_new(filt->lines[i]))) { tr_debug("tr_cfg_parse_one_filter: Out of memory."); - *rc=TR_CFG_NOMEM; + *rc = TR_CFG_NOMEM; goto cleanup; } /* fill in the field */ - if (NULL==(filt->lines[i]->specs[j]->field=tr_new_name(json_string_value(jffield)))) { + if (NULL == (filt->lines[i]->specs[j]->field = tr_new_name(json_string_value(jfield)))) { tr_debug("tr_cfg_parse_one_filter: Out of memory."); - *rc=TR_CFG_NOMEM; + *rc = TR_CFG_NOMEM; goto cleanup; } /* fill in the matches */ - if (NULL==(name=tr_new_name(json_string_value(jfmatch)))) { - tr_debug("tr_cfg_parse_one_filter: Out of memory."); - *rc=TR_CFG_NOMEM; + if (json_is_string(jmatch)) { + if (NULL == (name = tr_new_name(json_string_value(jmatch)))) { + tr_debug("tr_cfg_parse_one_filter: Out of memory."); + *rc = TR_CFG_NOMEM; + goto cleanup; + } + tr_fspec_add_match(filt->lines[i]->specs[j], name); + } else { + /* jmatch is an array (we checked earlier) */ + json_array_foreach(jmatch, k, this_jmatch) { + if (NULL == (name = tr_new_name(json_string_value(this_jmatch)))) { + tr_debug("tr_cfg_parse_one_filter: Out of memory."); + *rc = TR_CFG_NOMEM; + goto cleanup; + } + tr_fspec_add_match(filt->lines[i]->specs[j], name); + } + } + if (!tr_filter_validate_spec_field(ftype, filt->lines[i]->specs[j])){ + tr_debug("tr_cfg_parse_one_filter: Invalid filter field \"%.*s\" for %s filter, spec %d, filter %d.", + filt->lines[i]->specs[j]->field->len, + filt->lines[i]->specs[j]->field->buf, + filter_type_to_string(filt->type), + i, j); + *rc = TR_CFG_ERROR; goto cleanup; } - tr_fspec_set_match(filt->lines[i]->specs[j], name); } } - *rc=TR_CFG_SUCCESS; - talloc_steal(mem_ctx, filt); - + + /* check that the filter is valid */ + if (!tr_filter_validate(filt)) { + *rc = TR_CFG_ERROR; + } else { + *rc = TR_CFG_SUCCESS; + talloc_steal(mem_ctx, filt); + } + cleanup: talloc_free(tmp_ctx); if (*rc!=TR_CFG_SUCCESS) @@ -585,7 +647,9 @@ static TR_FILTER *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_C { TALLOC_CTX *tmp_ctx=talloc_new(NULL); json_t *jfilt; + const char *filt_label=NULL; TR_FILTER *filt=NULL; + TR_FILTER_TYPE filt_type=TR_FILTER_TYPE_UNKNOWN; *rc=TR_CFG_ERROR; @@ -595,20 +659,32 @@ static TR_FILTER *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_C goto cleanup; } - jfilt=json_object_get(jfilts, "tid_inbound"); - if (jfilt!=NULL) { - filt=tr_cfg_parse_one_filter(tmp_ctx, jfilt, TR_FILTER_TYPE_TID_INBOUND, rc); - if (*rc!=TR_CFG_SUCCESS) { - tr_debug("tr_cfg_parse_filters: Error parsing tid_inbound filter."); - *rc=TR_CFG_NOPARSE; + json_object_foreach(jfilts, filt_label, jfilt) { + /* check that we got a filter */ + if (jfilt == NULL) { + tr_debug("tr_cfg_parse_filters: Definition for %s filter is missing.", filt_label); + *rc = TR_CFG_NOPARSE; + goto cleanup; + } + + /* check that we recognize the filter type */ + filt_type=filter_type_from_string(filt_label); + if (filt_type==TR_FILTER_TYPE_UNKNOWN) { + tr_debug("tr_cfg_parse_filters: Unrecognized filter (%s) defined.", filt_label); + *rc = TR_CFG_NOPARSE; + goto cleanup; + } + + /* 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); + if (*rc != TR_CFG_SUCCESS) { + tr_debug("tr_cfg_parse_filters: Error parsing %s filter.", filt_label); + *rc = TR_CFG_NOPARSE; goto cleanup; } - } else { - tr_debug("tr_cfg_parse_filters: Unknown filter types in filter block."); - *rc=TR_CFG_NOPARSE; - goto cleanup; } - + *rc=TR_CFG_SUCCESS; cleanup: @@ -1146,7 +1222,7 @@ static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_ *rc=TR_CFG_NOMEM; goto cleanup; } - tr_fspec_set_match(filt->lines[0]->specs[0], name); + tr_fspec_add_match(filt->lines[0]->specs[0], name); name=NULL; /* we no longer own the name */ /* now do the wildcard name */ @@ -1160,7 +1236,7 @@ static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_ goto cleanup; } - tr_fspec_set_match(filt->lines[0]->specs[1], name); + tr_fspec_add_match(filt->lines[0]->specs[1], name); name=NULL; /* we no longer own the name */ /* domain constraint */ @@ -1511,7 +1587,7 @@ cleanup: static TR_CFG_RC tr_cfg_parse_local_orgs(TR_CFG *trc, json_t *jcfg) { json_t *jlocorgs=NULL; - int ii=0; + size_t ii=0; jlocorgs=json_object_get(jcfg, "local_organizations"); if (jlocorgs==NULL) @@ -1538,13 +1614,16 @@ static TR_CFG_RC tr_cfg_parse_one_peer_org(TR_CFG *trc, json_t *jporg) json_t *jhost=NULL; json_t *jport=NULL; json_t *jgss=NULL; + json_t *jfilt=NULL; TRP_PEER *new_peer=NULL; TR_GSS_NAMES *names=NULL; + TR_FILTER *filt=NULL; TR_CFG_RC rc=TR_CFG_ERROR; jhost=json_object_get(jporg, "hostname"); jport=json_object_get(jporg, "port"); jgss=json_object_get(jporg, "gss_names"); + jfilt=json_object_get(jporg, "filters"); if ((jhost==NULL) || (!json_is_string(jhost))) { tr_err("tr_cfg_parse_one_peer_org: hostname not specified or not a string."); @@ -1558,13 +1637,19 @@ static TR_CFG_RC tr_cfg_parse_one_peer_org(TR_CFG *trc, json_t *jporg) rc=TR_CFG_NOPARSE; goto cleanup; } - + if ((jgss==NULL) || (!json_is_array(jgss))) { tr_err("tr_cfg_parse_one_peer_org: gss_names not specified or not an array."); rc=TR_CFG_NOPARSE; goto cleanup; } + if ((jfilt!=NULL) && (!json_is_array(jfilt))) { + tr_err("tr_cfg_parse_one_peer_org: filters is not an array."); + rc=TR_CFG_NOPARSE; + goto cleanup; + } + new_peer=trp_peer_new(tmp_ctx); if (new_peer==NULL) { tr_err("tr_cfg_parse_one_peer_org: could not allocate new peer."); @@ -1586,6 +1671,16 @@ static TR_CFG_RC tr_cfg_parse_one_peer_org(TR_CFG *trc, json_t *jporg) } trp_peer_set_gss_names(new_peer, names); + if (jfilt) { + filt=tr_cfg_parse_filters(tmp_ctx, jfilt, &rc); + if (rc!=TR_CFG_SUCCESS) { + tr_err("tr_cfg_parse_one_peer_org: unable to parse filters."); + rc=TR_CFG_NOPARSE; + goto cleanup; + } + trp_peer_set_filter(new_peer, filt); + } + /* success! */ trp_ptable_add(trc->peers, new_peer); rc=TR_CFG_SUCCESS; @@ -1937,7 +2032,7 @@ TR_CFG_RC tr_cfg_parse_one_config_file(TR_CFG *cfg, const char *file_with_path) json_error_t rc; if (NULL==(jcfg=json_load_file(file_with_path, - JSON_DISABLE_EOF_CHECK, &rc))) { + JSON_DISABLE_EOF_CHECK|JSON_REJECT_DUPLICATES, &rc))) { tr_debug("tr_cfg_parse_one_config_file: Error parsing config file %s.", file_with_path); tr_cfg_log_json_error("tr_cfg_parse_one_config_file", &rc); diff --git a/common/tr_filter.c b/common/tr_filter.c index 701ec85..c13be74 100644 --- a/common/tr_filter.c +++ b/common/tr_filter.c @@ -43,37 +43,6 @@ #include #include -const TR_FILTER_TYPE tr_filter_types[] = { - TR_FILTER_TYPE_TID_INBOUND, - TR_FILTER_TYPE_TRP_INBOUND, - TR_FILTER_TYPE_TRP_OUTBOUND -}; -const size_t tr_num_filter_types=sizeof(tr_filter_types)/sizeof(tr_filter_types[0]); -static const char *tr_filter_type_strings[] = { - "tid_inbound", - "trp_inbound", - "trp_outbound" -}; - -const char *tr_filter_type_to_string(TR_FILTER_TYPE t) { - int ii; - for (ii=0; iifield != NULL) tr_free_name(fspec->field); - if (fspec->match != NULL) - tr_free_name(fspec->match); + for (ii=0; iimatch[ii] != NULL) + tr_free_name(fspec->match[ii]); + } 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; - fspec->match = NULL; - talloc_set_destructor((void *) fspec, tr_fspec_destructor); + for (ii=0; iimatch[ii] = NULL; + + talloc_set_destructor((void *)fspec, tr_fspec_destructor); } return fspec; } -void tr_fspec_set_match(TR_FSPEC *fspec, TR_NAME *match) +void tr_fspec_add_match(TR_FSPEC *fspec, TR_NAME *match) { - if (fspec->match != NULL) - tr_free_name(fspec->match); - fspec->match = match; + size_t ii; + for (ii=0; iimatch[ii]==NULL) { + fspec->match[ii]=match; + break; + } + } + /* TODO: handle case that adding the match failed */ } /* returns 1 if the spec matches */ @@ -305,8 +285,9 @@ int tr_fspec_matches(TR_FSPEC *fspec, TR_FILTER_TYPE ftype, void *target) { struct tr_filter_field_entry *field=NULL; TR_NAME *name=NULL; + size_t ii=0; - if ((fspec==NULL) || (fspec->match==NULL)) + if (fspec==NULL) return 0; /* Look up how to handle the requested field */ @@ -315,8 +296,13 @@ int tr_fspec_matches(TR_FSPEC *fspec, TR_FILTER_TYPE ftype, void *target) return 0; name=field->get(target); - return ((fspec->match != NULL) && - (0 != tr_name_prefix_wildcard_match(name, fspec->match))); + for (ii=0; iimatch[ii]!=NULL) { + if (tr_name_prefix_wildcard_match(name, fspec->match[ii])) + return 1; + } + } + return 0; } void tr_fline_free(TR_FLINE *fline) @@ -366,3 +352,70 @@ TR_FILTER_TYPE tr_filter_get_type(TR_FILTER *filt) { return filt->type; } + +/** + * Check that a filter is valid, i.e., can be processed. + * + * @param filt Filter to verify + * @return 1 if the filter is valid, 0 otherwise + */ +int tr_filter_validate(TR_FILTER *filt) +{ + size_t ii=0, jj=0, kk=0; + + if (!filt) + return 0; + + /* check that we recognize the type */ + switch(filt->type) { + case TR_FILTER_TYPE_TID_INBOUND: + case TR_FILTER_TYPE_TRP_INBOUND: + case TR_FILTER_TYPE_TRP_OUTBOUND: + break; + + default: + 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 */ + + /* check that we recognize the action */ + switch(filt->lines[ii]->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 */ + 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])) + 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) + return 0; + } + } + + /* We ran the gauntlet. Success! */ + return 1; +} + +int tr_filter_validate_spec_field(TR_FILTER_TYPE ftype, TR_FSPEC *fspec) +{ + if ((fspec==NULL) || (tr_filter_field_entry(ftype, fspec->field)==NULL)) + return 0; /* unknown field */ + + return 1; +} \ No newline at end of file diff --git a/include/tr_filter.h b/include/tr_filter.h index c3d4ed1..38082de 100644 --- a/include/tr_filter.h +++ b/include/tr_filter.h @@ -46,6 +46,7 @@ #define TR_MAX_FILTERS 5 #define TR_MAX_FILTER_LINES 8 #define TR_MAX_FILTER_SPECS 8 +#define TR_MAX_FILTER_SPEC_MATCHES 8 /* Filter actions */ typedef enum { @@ -66,13 +67,9 @@ typedef enum { TR_FILTER_TYPE_UNKNOWN } TR_FILTER_TYPE; -extern const size_t tr_num_filter_types; -const char *tr_filter_type_to_string(TR_FILTER_TYPE t); -TR_FILTER_TYPE tr_filter_type_from_string(const char *s); - typedef struct tr_fspec { TR_NAME *field; - TR_NAME *match; + TR_NAME *match[TR_MAX_FILTER_SPEC_MATCHES]; } TR_FSPEC; typedef struct tr_fline { @@ -103,7 +100,7 @@ TR_FSPEC *tr_fspec_new(TALLOC_CTX *mem_ctx); void tr_fspec_free(TR_FSPEC *fspec); -void tr_fspec_set_match(TR_FSPEC *fspec, TR_NAME *match); +void tr_fspec_add_match(TR_FSPEC *fspec, TR_NAME *match); int tr_fspec_matches(TR_FSPEC *fspec, TR_FILTER_TYPE ftype, void *target); @@ -117,4 +114,7 @@ int tr_filter_process_rp_permitted(TR_NAME *rp_realm, TR_FILTER *rpp_filter, TR_ TR_CONSTRAINT_SET *tr_constraint_set_from_fline(TR_FLINE *fline); +int tr_filter_validate(TR_FILTER *filt); +int tr_filter_validate_spec_field(TR_FILTER_TYPE ftype, TR_FSPEC *fspec); + #endif diff --git a/include/trp_ptable.h b/include/trp_ptable.h index a0d17b3..303bbc3 100644 --- a/include/trp_ptable.h +++ b/include/trp_ptable.h @@ -41,6 +41,7 @@ #include #include #include +#include typedef enum trp_peer_conn_status { PEER_DISCONNECTED=0, @@ -61,6 +62,7 @@ struct trp_peer { TRP_PEER_CONN_STATUS incoming_status; void (*conn_status_cb)(TRP_PEER *, void *); /* callback for connected status change */ void *conn_status_cookie; + TR_FILTER *filter; }; typedef struct trp_ptable { @@ -106,6 +108,8 @@ void trp_peer_set_incoming_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status); int trp_peer_is_connected(TRP_PEER *peer); void trp_peer_set_linkcost(TRP_PEER *peer, unsigned int linkcost); void trp_peer_set_conn_status_cb(TRP_PEER *peer, void (*cb)(TRP_PEER *, void *), void *cookie); +void trp_peer_set_filter(TRP_PEER *peer, TR_FILTER *filt); +TR_FILTER *trp_peer_get_filter(TRP_PEER *peer); char *trp_peer_to_str(TALLOC_CTX *memctx, TRP_PEER *peer, const char *sep); #endif /* _TRP_PTABLE_H_ */ diff --git a/trp/trp_ptable.c b/trp/trp_ptable.c index f5ea1fb..4cb0705 100644 --- a/trp/trp_ptable.c +++ b/trp/trp_ptable.c @@ -66,6 +66,7 @@ TRP_PEER *trp_peer_new(TALLOC_CTX *memctx) peer->incoming_status=PEER_DISCONNECTED; peer->conn_status_cb=NULL; peer->conn_status_cookie=NULL; + peer->filter=NULL; talloc_set_destructor((void *)peer, trp_peer_destructor); } return peer; @@ -147,7 +148,7 @@ void trp_peer_add_gss_name(TRP_PEER *peer, TR_NAME *gss_name) void trp_peer_set_gss_names(TRP_PEER *peer, TR_GSS_NAMES *gss_names) { if (peer->gss_names!=NULL) - talloc_free(peer->gss_names); + tr_gss_names_free(peer->gss_names); peer->gss_names=gss_names; talloc_steal(peer, gss_names); @@ -206,6 +207,27 @@ void trp_peer_set_conn_status_cb(TRP_PEER *peer, void (*cb)(TRP_PEER *, void *), peer->conn_status_cookie=cookie; } +/** + * Set the filter associated with this peer. Any existing filter will be freed. Takes responsibility for + * freeing the new filter. + * + * @param peer Peer to modify + * @param filt New filter to attach to the peer + */ +void trp_peer_set_filter(TRP_PEER *peer, TR_FILTER *filt) +{ + if (peer->filter!=NULL) + tr_filter_free(peer->filter); + + peer->filter=filt; + talloc_steal(peer, filt); +} + +TR_FILTER *trp_peer_get_filter(TRP_PEER *peer) +{ + return peer->filter; +} + struct timespec *trp_peer_get_last_conn_attempt(TRP_PEER *peer) { return &(peer->last_conn_attempt); -- 2.1.4