Code for testing the filters now works
authorJennifer Richards <jennifer@painless-security.com>
Mon, 12 Jun 2017 17:17:44 +0000 (13:17 -0400)
committerJennifer Richards <jennifer@painless-security.com>
Mon, 12 Jun 2017 17:17:44 +0000 (13:17 -0400)
15 files changed:
common/tests/filt_test.c
common/tests/test-filters/filt-inforec-1-msg.json [new file with mode: 0644]
common/tests/test-filters/filt-inforec-1.json [new file with mode: 0644]
common/tests/test-filters/filt-tidreq-1-msg.json [new file with mode: 0644]
common/tests/test-filters/filt-tidreq-1.json [new file with mode: 0644]
common/tests/test-filters/filter-tests.json [new file with mode: 0644]
common/tr_config.c
common/tr_filter.c
common/tr_rp.c
include/tr_filter.h
include/tr_msg.h
include/tr_rp.h
include/trp_ptable.h
tr/tr_tid.c
trp/trp_ptable.c

index c7eb028..7dc5094 100644 (file)
@@ -35,6 +35,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
+#include <string.h>
+#include <jansson.h>
 
 #include <trp_internal.h>
 #include <tid_internal.h>
  * @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)
+int load_filter(const char *fname, TR_FILTER_SET **filts_out)
 {
   TR_CFG *cfg=tr_cfg_new(NULL);
   TR_CFG_RC rc=TR_CFG_ERROR;
 
   assert(fname);
-  assert(filt_out);
+  assert(filts_out);
 
   rc=tr_cfg_parse_one_config_file(cfg, fname);
   if (rc!=TR_CFG_SUCCESS)
@@ -65,10 +67,10 @@ int load_filter(const char *fname, TR_FILTER **filt_out)
   /* 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);
+  assert(cfg->rp_clients->filters);
+  *filts_out=cfg->rp_clients->filters;
+  cfg->rp_clients->filters=NULL; /* can't use the _set_filter() because that will free the filter */
+  talloc_steal(NULL, *filts_out);
 
 cleanup:
   tr_cfg_free(cfg);
@@ -82,31 +84,174 @@ cleanup:
  */
 int test_load_filter(void)
 {
-  TR_FILTER *filt=NULL;
+  TR_FILTER_SET *filts=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));
+  assert(TR_CFG_SUCCESS==load_filter(FILTER_PATH "valid-filt.json", &filts));
+  if (filts) tr_filter_set_free(filts);
+  filts=NULL;
+  assert(TR_CFG_NOPARSE==load_filter(FILTER_PATH "invalid-filt-repeated-key.json", &filts));
+  if (filts) tr_filter_set_free(filts);
+  filts=NULL;
+  assert(TR_CFG_ERROR==load_filter(FILTER_PATH "invalid-filt-unknown-field.json", &filts));
+  if (filts) tr_filter_set_free(filts);
+  filts=NULL;
   return 1;
 }
 
-int test_trp_inforec_filter(TRP_INFOREC_TYPE type)
+/**
+ * Read the first inforec from the TR_MSG encoded in JSON file named fname.
+ *
+ * @param fname Filename with path for TR_MSG JSON
+ * @return Pointer to the decoded inforec, or NULL on failure
+ */
+TRP_INFOREC *load_inforec(const char *fname)
 {
-  TRP_INFOREC *inforec=trp_inforec_new(NULL, type);
-  TR_FILTER *filt=tr_filter_new(NULL);
+  TR_MSG *msg=NULL;
+  TRP_UPD *upd=NULL;
+  TRP_INFOREC *inforec=NULL;
+  json_t *decoded=json_load_file(fname, JSON_REJECT_DUPLICATES|JSON_DISABLE_EOF_CHECK, NULL);
+  char *encoded=json_dumps(decoded, 0); /* silly way to read the file without mucking around */
+
+  assert(decoded);
+  json_decref(decoded);
 
-  assert(inforec);
-  assert(filt);
+  assert(encoded);
+  assert(msg=tr_msg_decode(encoded, strlen(encoded)));
+  assert(upd=tr_msg_get_trp_upd(msg));
+  assert(inforec=trp_upd_get_inforec(upd));
+  /* now remove the inforec from the update context */
+  talloc_steal(NULL, inforec);
+  tr_msg_free_decoded(msg);
+  tr_msg_free_encoded(encoded);
+  return inforec;
+}
+
+/* make this bigger than your message file */
+#define MAX_FILE_SIZE 20000
+TID_REQ *load_tid_req(const char *fname)
+{
+  TID_REQ *out=NULL;
+  TR_MSG *msg=NULL;
+  FILE *f=NULL;
+  char *msgbuf=NULL;
+  size_t msglen=0;
 
+  msgbuf=malloc(MAX_FILE_SIZE);
+  assert(msgbuf);
+  f=fopen(fname, "r");
+  assert(f);
+  msglen=fread(msgbuf, 1, MAX_FILE_SIZE, f);
+  assert(msglen);
+  assert(feof(f));
+  msg=tr_msg_decode(msgbuf, msglen);
+  free(msgbuf);
+  msgbuf=NULL;
 
-  return 1;
+  assert(msg);
+  assert(tr_msg_get_msg_type(msg)==TID_REQUEST);
+
+  /* take the tid req out of the msg */
+  out=tr_msg_get_req(msg);
+  tr_msg_set_req(msg, NULL);
+  assert(out);
+
+  tr_msg_free_decoded(msg);
+  return out;
 }
 
+/**
+ * Read a set of filters from a config JSON in filt_fname and test against the tid_req or inforec in target_fname.
+ * If expect==1, succeed if the target is accepted by the filter, otherwise succeed if it is rejected.
+ * Takes filters from the first rp_realm defined in the filter file and the first inforec or tid req from
+ * the target file.
+ *
+ * @param filt_fname Name of JSON file containing filters
+ * @param ftype Which type of filter to test
+ * @param target_fname  Name of JSON file containing inforec
+ * @param expected_match 1 if we expect a match, 0 otherwise
+ * @param expected_action Expected action if the filter matches
+ * @return 1 if expected result is obtained, 0 or does not return otherwise
+ */
+int test_one_filter(const char *filt_fname,
+                    TR_FILTER_TYPE ftype,
+                    const char *target_fname,
+                    int expected_match,
+                    TR_FILTER_ACTION expected_action)
+{
+  void *target=NULL;
+  TR_FILTER_SET *filts=NULL;
+  TR_FILTER_ACTION action=TR_FILTER_ACTION_UNKNOWN;
+
+  /* load filter for first test */
+  assert(TR_CFG_SUCCESS==load_filter(filt_fname, &filts));
 
-int test_trp_filter(void)
+  /* load the target req or inforec */
+  switch(ftype) {
+    case TR_FILTER_TYPE_TID_INBOUND:
+      target=load_tid_req(target_fname);
+      break;
+
+    case TR_FILTER_TYPE_TRP_INBOUND:
+    case TR_FILTER_TYPE_TRP_OUTBOUND:
+      target=load_inforec(target_fname);
+      break;
+
+    default:
+      printf("Unknown filter type.\n");
+  }
+  assert(target);
+
+  assert(expected_match==tr_filter_apply(target, tr_filter_set_get(filts, ftype), NULL, &action));
+  if (expected_match==TR_FILTER_MATCH)
+    assert(action==expected_action);
+
+  tr_filter_set_free(filts);
+  switch(ftype) {
+    case TR_FILTER_TYPE_TID_INBOUND:
+      tid_req_free((TID_REQ *)target);
+      break;
+
+    case TR_FILTER_TYPE_TRP_INBOUND:
+    case TR_FILTER_TYPE_TRP_OUTBOUND:
+      trp_inforec_free((TRP_INFOREC *)target);
+      break;
+
+    default:
+      printf("Unknown filter type.\n");
+  }
+  return 1;
+}
+
+int test_filter(void)
 {
-  assert(test_trp_inforec_filter(TRP_INFOREC_TYPE_ROUTE));
-  assert(test_trp_inforec_filter(TRP_INFOREC_TYPE_COMMUNITY));
+  json_t *test_list=json_load_file(FILTER_PATH "filter-tests.json", JSON_DISABLE_EOF_CHECK, NULL);
+  json_t *this;
+  size_t ii;
+  const char *filt_file, *target_file;
+  TR_FILTER_TYPE ftype;
+  int expect_match;
+  TR_FILTER_ACTION action;
+
+  json_array_foreach(test_list, ii, this) {
+    printf("Running filter test case: %s\n", json_string_value(json_object_get(this, "test label")));
+    fflush(stdout);
+
+    filt_file=json_string_value(json_object_get(this, "filter file"));
+    ftype=tr_filter_type_from_string(json_string_value(json_object_get(this, "filter type")));
+    target_file=json_string_value(json_object_get(this, "target file"));
+    if (0==strcmp("yes", json_string_value(json_object_get(this, "expect match"))))
+      expect_match=TR_FILTER_MATCH;
+    else
+      expect_match=TR_FILTER_NO_MATCH;
+
+    if (0==strcmp("accept", json_string_value(json_object_get(this, "action"))))
+      action=TR_FILTER_ACTION_ACCEPT;
+    else
+      action=TR_FILTER_ACTION_REJECT;
+
+    assert(test_one_filter(filt_file, ftype, target_file, expect_match, action));
+  }
+
   return 1;
 }
 
@@ -115,6 +260,7 @@ int test_trp_filter(void)
 int main(void)
 {
   assert(test_load_filter());
+  assert(test_filter());
   printf("Success\n");
   return 0;
 }
\ No newline at end of file
diff --git a/common/tests/test-filters/filt-inforec-1-msg.json b/common/tests/test-filters/filt-inforec-1-msg.json
new file mode 100644 (file)
index 0000000..94e97fb
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "msg_type": "trp_update",
+  "msg_body": {
+    "community": "my community",
+    "realm": "my realm",
+    "records": [
+      {
+        "record_type": "route",
+        "trust_router": "tr",
+        "metric": 27,
+        "interval": 11
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/common/tests/test-filters/filt-inforec-1.json b/common/tests/test-filters/filt-inforec-1.json
new file mode 100644 (file)
index 0000000..df5d1a1
--- /dev/null
@@ -0,0 +1,53 @@
+{
+  "local_organizations": [
+    { "organization_name": "inforec filter test 1",
+      "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": ["route"]}
+                ]
+              },
+              { "action": "accept",
+                "specs": [
+                  { "field": "info_type",
+                    "match": ["community"]}
+                ]
+              }
+            ],
+            "trp_outbound": [
+              { "action": "accept",
+                "specs": [
+                  { "field": "info_type",
+                    "match": ["invalid value"]}
+                ]
+              },
+              { "action": "accept",
+                "specs": [
+                  { "field": "info_type",
+                    "match": ["community"]}
+                ]
+              }
+            ]
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/common/tests/test-filters/filt-tidreq-1-msg.json b/common/tests/test-filters/filt-tidreq-1-msg.json
new file mode 100644 (file)
index 0000000..8497e83
--- /dev/null
@@ -0,0 +1,17 @@
+{
+  "msg_type": "tid_request",
+  "msg_body": {
+    "rp_realm": "my realm",
+    "target_realm": "your realm",
+    "community": "our community",
+    "orig_coi": "our aliased community",
+    "dh_info": {
+      "dh_p": "DEADBEEF",
+      "dh_g": "FEA57",
+      "dh_pub_key": "12345678"
+    },
+    "constraints": [{"constraint": ["value"]}],
+    "path": ["hop", "skip", "jump"],
+    "expiration_interval": 13
+  }
+}
\ No newline at end of file
diff --git a/common/tests/test-filters/filt-tidreq-1.json b/common/tests/test-filters/filt-tidreq-1.json
new file mode 100644 (file)
index 0000000..7325252
--- /dev/null
@@ -0,0 +1,53 @@
+{
+  "local_organizations": [
+    { "organization_name": "tidreq filter test 1",
+      "realms": [
+        { "realm": "realm",
+          "gss_names": ["gss"],
+          "filters": {
+            "tid_inbound": [
+              { "action": "accept",
+                "specs": [
+                  { "field": "rp_realm",
+                    "match": [
+                      "my realm",
+                      "*.my realm"
+                    ]
+                  }
+                ]
+              }
+            ],
+            "trp_inbound": [
+              { "action": "accept",
+                "specs": [
+                  { "field": "info_type",
+                    "match": ["route"]}
+                ]
+              },
+              { "action": "accept",
+                "specs": [
+                  { "field": "info_type",
+                    "match": ["community"]}
+                ]
+              }
+            ],
+            "trp_outbound": [
+              { "action": "accept",
+                "specs": [
+                  { "field": "info_type",
+                    "match": ["invalid value"]}
+                ]
+              },
+              { "action": "accept",
+                "specs": [
+                  { "field": "info_type",
+                    "match": ["community"]}
+                ]
+              }
+            ]
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/common/tests/test-filters/filter-tests.json b/common/tests/test-filters/filter-tests.json
new file mode 100644 (file)
index 0000000..cca4a7d
--- /dev/null
@@ -0,0 +1,23 @@
+[
+  { "test label": "first TRP test",
+    "filter file": "test-filters/filt-inforec-1.json",
+    "filter type": "trp_inbound",
+    "target file": "test-filters/filt-inforec-1-msg.json",
+    "expect match": "yes",
+    "action": "accept"
+  },
+  { "test label": "second TRP test",
+    "filter file": "test-filters/filt-inforec-1.json",
+    "filter type": "trp_outbound",
+    "target file": "test-filters/filt-inforec-1-msg.json",
+    "expect match": "no",
+    "action": ""
+  },
+  { "test label": "first TID test",
+    "filter file": "test-filters/filt-tidreq-1.json",
+    "filter type": "tid_inbound",
+    "target file": "test-filters/filt-tidreq-1-msg.json",
+    "expect match": "yes",
+    "action": "accept"
+  }
+]
index 917a465..e98061f 100644 (file)
@@ -410,41 +410,12 @@ static TR_CONSTRAINT *tr_cfg_parse_one_constraint(TALLOC_CTX *mem_ctx, char *cty
   return cons;
 }
 
-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)
-{
-  size_t ii=0;
-
-  for (ii=0; ii<num_filter_types; ii++) {
-    if (ftype==filter_type[ii])
-      return filter_label[ii];
-  }
-  return "unknown";
-}
-
-static TR_FILTER_TYPE filter_type_from_string(const char *s)
-{
-  size_t ii=0;
-
-  for(ii=0; ii<num_filter_types; ii++) {
-    if (0==strcmp(s, filter_label[ii]))
-      return filter_type[ii];
-  }
-  return TR_FILTER_TYPE_UNKNOWN;
-}
-
 static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR_FILTER_TYPE ftype, TR_CFG_RC *rc)
 {
   TALLOC_CTX *tmp_ctx = talloc_new(NULL);
   TR_FILTER *filt = NULL;
   json_t *jfaction = NULL;
+  json_t *jfline = NULL;
   json_t *jfspecs = NULL;
   json_t *this_jfspec = NULL;
   json_t *jfield = NULL;
@@ -478,15 +449,15 @@ static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR
   }
 
   /* 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"))) ||
+  json_array_foreach(jfilt, i, jfline) {
+    if ((NULL == (jfaction = json_object_get(jfline, "action"))) ||
         (!json_is_string(jfaction))) {
       tr_debug("tr_cfg_parse_one_filter: Error parsing filter action.");
       *rc = TR_CFG_NOPARSE;
       goto cleanup;
     }
 
-    if ((NULL == (jfspecs = json_object_get(json_array_get(jfilt, i), "specs"))) ||
+    if ((NULL == (jfspecs = json_object_get(jfline, "specs"))) ||
         (!json_is_array(jfspecs)) ||
         (0 == json_array_size(jfspecs))) {
       tr_debug("tr_cfg_parse_one_filter: Error parsing filter specs.");
@@ -517,7 +488,7 @@ static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR
       goto cleanup;
     }
 
-    if (NULL != (jrc = json_object_get(json_array_get(jfilt, i), "realm_constraints"))) {
+    if (NULL != (jrc = json_object_get(jfline, "realm_constraints"))) {
       if (!json_is_array(jrc)) {
         tr_err("tr_cfg_parse_one_filter: cannot parse realm_constraints, not an array.");
         *rc = TR_CFG_NOPARSE;
@@ -537,7 +508,7 @@ static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR
       }
     }
 
-    if (NULL != (jdc = json_object_get(json_array_get(jfilt, i), "domain_constraints"))) {
+    if (NULL != (jdc = json_object_get(jfline, "domain_constraints"))) {
       if (!json_is_array(jdc)) {
         tr_err("tr_cfg_parse_one_filter: cannot parse domain_constraints, not an array.");
         *rc = TR_CFG_NOPARSE;
@@ -620,7 +591,7 @@ static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR
         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),
+                 tr_filter_type_to_string(filt->type),
                  i, j);
         *rc = TR_CFG_ERROR;
         goto cleanup;
@@ -643,12 +614,13 @@ static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR
   return filt;
 }
 
-static TR_FILTER *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_CFG_RC *rc)
+static TR_FILTER_SET *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_CFG_RC *rc)
 {
   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
   json_t *jfilt;
   const char *filt_label=NULL;
   TR_FILTER *filt=NULL;
+  TR_FILTER_SET *filt_set=NULL;
   TR_FILTER_TYPE filt_type=TR_FILTER_TYPE_UNKNOWN;
 
   *rc=TR_CFG_ERROR;
@@ -659,6 +631,13 @@ static TR_FILTER *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_C
     goto cleanup;
   }
 
+  filt_set=tr_filter_set_new(tmp_ctx);
+  if (filt_set==NULL) {
+    tr_debug("tr_cfg_parse_filters: Unable to allocate filter set.");
+    *rc = TR_CFG_NOMEM;
+    goto cleanup;
+  }
+
   json_object_foreach(jfilts, filt_label, jfilt) {
     /* check that we got a filter */
     if (jfilt == NULL) {
@@ -668,7 +647,7 @@ static TR_FILTER *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_C
     }
 
     /* check that we recognize the filter type */
-    filt_type=filter_type_from_string(filt_label);
+    filt_type=tr_filter_type_from_string(filt_label);
     if (filt_type==TR_FILTER_TYPE_UNKNOWN) {
       tr_debug("tr_cfg_parse_filters: Unrecognized filter (%s) defined.", filt_label);
       *rc = TR_CFG_NOPARSE;
@@ -678,6 +657,7 @@ static TR_FILTER *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_C
     /* 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;
@@ -689,14 +669,14 @@ static TR_FILTER *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_C
 
  cleanup:
   if (*rc==TR_CFG_SUCCESS)
-    talloc_steal(mem_ctx, filt);
-  else if (filt!=NULL) {
-    talloc_free(filt);
-    filt=NULL;
+    talloc_steal(mem_ctx, filt_set);
+  else if (filt_set!=NULL) {
+    talloc_free(filt_set);
+    filt_set=NULL;
   }
 
   talloc_free(tmp_ctx);
-  return filt;
+  return filt_set;
 }
 
 static TR_AAA_SERVER *tr_cfg_parse_one_aaa_server(TALLOC_CTX *mem_ctx, json_t *jaddr, TR_CFG_RC *rc)
@@ -1167,10 +1147,11 @@ static TR_GSS_NAMES *tr_cfg_parse_gss_names(TALLOC_CTX *mem_ctx, json_t *jgss_na
 }
 
 /* default filter accepts realm and *.realm */
-static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_CFG_RC *rc)
+static TR_FILTER_SET *tr_cfg_default_filters(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_CFG_RC *rc)
 {
   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
   TR_FILTER *filt=NULL;
+  TR_FILTER_SET *filt_set=NULL;
   TR_CONSTRAINT *cons=NULL;
   TR_NAME *name=NULL;
   TR_NAME *n_prefix=tr_new_name("*.");
@@ -1181,7 +1162,7 @@ static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_
   
 
   if ((realm==NULL) || (rc==NULL)) {
-    tr_debug("tr_cfg_default_filter: invalid arguments.");
+    tr_debug("tr_cfg_default_filters: invalid arguments.");
     if (rc!=NULL)
       *rc=TR_CFG_BAD_PARAMS;
     goto cleanup;
@@ -1192,21 +1173,21 @@ static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_
       (n_rp_realm_2==NULL) ||
       (n_domain==NULL) ||
       (n_realm==NULL)) {
-    tr_debug("tr_cfg_default_filter: unable to allocate names.");
+    tr_debug("tr_cfg_default_filters: unable to allocate names.");
     *rc=TR_CFG_NOMEM;
     goto cleanup;
   }
 
   filt=tr_filter_new(tmp_ctx);
   if (filt==NULL) {
-    tr_debug("tr_cfg_default_filter: could not allocate filter.");
+    tr_debug("tr_cfg_default_filters: could not allocate filter.");
     *rc=TR_CFG_NOMEM;
     goto cleanup;
   }
   tr_filter_set_type(filt, TR_FILTER_TYPE_TID_INBOUND);
   filt->lines[0]=tr_fline_new(filt);
   if (filt->lines[0]==NULL) {
-    tr_debug("tr_cfg_default_filter: could not allocate filter line.");
+    tr_debug("tr_cfg_default_filters: could not allocate filter line.");
     *rc=TR_CFG_NOMEM;
     goto cleanup;
   }
@@ -1218,7 +1199,7 @@ static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_
 
   name=tr_dup_name(realm);
   if (name==NULL) {
-    tr_debug("tr_cfg_default_filter: could not allocate realm name.");
+    tr_debug("tr_cfg_default_filters: could not allocate realm name.");
     *rc=TR_CFG_NOMEM;
     goto cleanup;
   }
@@ -1231,7 +1212,7 @@ static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_
   n_rp_realm_2=NULL; /* we don't own this name any more */
 
   if (NULL==(name=tr_name_cat(n_prefix, realm))) {
-    tr_debug("tr_cfg_default_filter: could not allocate wildcard realm name.");
+    tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name.");
     *rc=TR_CFG_NOMEM;
     goto cleanup;
   }
@@ -1241,7 +1222,7 @@ static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_
 
   /* domain constraint */
   if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
-    tr_debug("tr_cfg_default_filter: could not allocate domain constraint.");
+    tr_debug("tr_cfg_default_filters: could not allocate domain constraint.");
     *rc=TR_CFG_NOMEM;
     goto cleanup;
   }
@@ -1250,14 +1231,14 @@ static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_
   n_domain=NULL; /* belongs to the constraint now */
   name=tr_dup_name(realm);
   if (name==NULL) {
-    tr_debug("tr_cfg_default_filter: could not allocate realm name for domain constraint.");
+    tr_debug("tr_cfg_default_filters: could not allocate realm name for domain constraint.");
     *rc=TR_CFG_NOMEM;
     goto cleanup;
   }
   cons->matches[0]=name;
   name=tr_name_cat(n_prefix, realm);
   if (name==NULL) {
-    tr_debug("tr_cfg_default_filter: could not allocate wildcard realm name for domain constraint.");
+    tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name for domain constraint.");
     *rc=TR_CFG_NOMEM;
     goto cleanup;
   }
@@ -1268,7 +1249,7 @@ static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_
 
   /* realm constraint */
   if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
-    tr_debug("tr_cfg_default_filter: could not allocate realm constraint.");
+    tr_debug("tr_cfg_default_filters: could not allocate realm constraint.");
     *rc=TR_CFG_NOMEM;
     goto cleanup;
   }
@@ -1277,14 +1258,14 @@ static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_
   n_realm=NULL; /* belongs to the constraint now */
   name=tr_dup_name(realm);
   if (name==NULL) {
-    tr_debug("tr_cfg_default_filter: could not allocate realm name for realm constraint.");
+    tr_debug("tr_cfg_default_filters: could not allocate realm name for realm constraint.");
     *rc=TR_CFG_NOMEM;
     goto cleanup;
   }
   cons->matches[0]=name;
   name=tr_name_cat(n_prefix, realm);
   if (name==NULL) {
-    tr_debug("tr_cfg_default_filter: could not allocate wildcard realm name for realm constraint.");
+    tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name for realm constraint.");
     *rc=TR_CFG_NOMEM;
     goto cleanup;
   }
@@ -1292,7 +1273,15 @@ static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_
   name=NULL;
   filt->lines[0]->realm_cons=cons;
 
-  talloc_steal(mem_ctx, filt);
+  /* put the filter in a set */
+  filt_set=tr_filter_set_new(tmp_ctx);
+  if ((filt_set==NULL)||(0!=tr_filter_set_add(filt_set, filt))) {
+    tr_debug("tr_cfg_default_filters: could not allocate filter set.");
+    *rc=TR_CFG_NOMEM;
+    goto cleanup;
+  }
+  talloc_steal(mem_ctx, filt_set);
+
 cleanup:
   talloc_free(tmp_ctx);
 
@@ -1312,7 +1301,7 @@ cleanup:
   if (name!=NULL)
     tr_free_name(name);
 
-  return filt;
+  return filt_set;
 }
 
 /* parses rp client */
@@ -1321,7 +1310,7 @@ static TR_RP_CLIENT *tr_cfg_parse_one_rp_client(TALLOC_CTX *mem_ctx, json_t *jre
   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
   TR_RP_CLIENT *client=NULL;
   TR_CFG_RC call_rc=TR_CFG_ERROR;
-  TR_FILTER *new_filt=NULL;
+  TR_FILTER_SET *new_filts=NULL;
   TR_NAME *realm=NULL;
   json_t *jfilt=NULL;
   json_t *jrealm_id=NULL;
@@ -1366,7 +1355,7 @@ static TR_RP_CLIENT *tr_cfg_parse_one_rp_client(TALLOC_CTX *mem_ctx, json_t *jre
   /* parse filters */
   jfilt=json_object_get(jrealm, "filters");
   if (jfilt!=NULL) {
-    new_filt=tr_cfg_parse_filters(tmp_ctx, jfilt, &call_rc);
+    new_filts=tr_cfg_parse_filters(tmp_ctx, jfilt, &call_rc);
     if (call_rc!=TR_CFG_SUCCESS) {
       tr_err("tr_cfg_parse_one_rp_client: could not parse filters.");
       *rc=TR_CFG_NOPARSE;
@@ -1374,7 +1363,7 @@ static TR_RP_CLIENT *tr_cfg_parse_one_rp_client(TALLOC_CTX *mem_ctx, json_t *jre
     }
   } else {
     tr_debug("tr_cfg_parse_one_rp_client: no filters specified, using default filters.");
-    new_filt=tr_cfg_default_filter(tmp_ctx, realm, &call_rc);
+    new_filts= tr_cfg_default_filters(tmp_ctx, realm, &call_rc);
     if (call_rc!=TR_CFG_SUCCESS) {
       tr_err("tr_cfg_parse_one_rp_client: could not set default filters.");
       *rc=TR_CFG_NOPARSE;
@@ -1382,7 +1371,7 @@ static TR_RP_CLIENT *tr_cfg_parse_one_rp_client(TALLOC_CTX *mem_ctx, json_t *jre
     }
   }
 
-  tr_rp_client_set_filter(client, new_filt);
+  tr_rp_client_set_filters(client, new_filts);
   *rc=TR_CFG_SUCCESS;
 
   cleanup:
@@ -1617,7 +1606,7 @@ static TR_CFG_RC tr_cfg_parse_one_peer_org(TR_CFG *trc, json_t *jporg)
   json_t *jfilt=NULL;
   TRP_PEER *new_peer=NULL;
   TR_GSS_NAMES *names=NULL;
-  TR_FILTER *filt=NULL;
+  TR_FILTER_SET *filt_set=NULL;
   TR_CFG_RC rc=TR_CFG_ERROR;
 
   jhost=json_object_get(jporg, "hostname");
@@ -1672,13 +1661,13 @@ 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);
+    filt_set=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);
+    trp_peer_set_filters(new_peer, filt_set);
   }
 
   /* success! */
index c13be74..d30ce7a 100644 (file)
@@ -159,7 +159,7 @@ int tr_filter_apply(void *target,
   /* 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;
-       (ii<TR_MAX_FILTER_LINES) && (retval==TR_FILTER_NO_MATCH);
+       ii<TR_MAX_FILTER_LINES;
        ii++) {
     /* skip empty lines (these shouldn't really happen) */
     if (filt->lines[ii]==NULL)
@@ -178,6 +178,9 @@ int tr_filter_apply(void *target,
         break; /* give up on this filter line */
       }
     }
+
+    if (retval==TR_FILTER_MATCH)
+      break;
   }
 
   if (retval==TR_FILTER_MATCH) {
@@ -418,4 +421,117 @@ int tr_filter_validate_spec_field(TR_FILTER_TYPE ftype, TR_FSPEC *fspec)
     return 0; /* unknown field */
 
   return 1;
-}
\ No newline at end of file
+}
+
+/**
+ * Allocate a new filter set.
+ *
+ * @param mem_ctx Talloc context for the new set
+ * @return Pointer to new set, or null on error
+ */
+TR_FILTER_SET *tr_filter_set_new(TALLOC_CTX *mem_ctx)
+{
+  TR_FILTER_SET *set=talloc(mem_ctx, TR_FILTER_SET);
+  if (set!=NULL) {
+    set->next=NULL;
+    set->this=NULL;
+  }
+  return set;
+}
+
+/**
+ * Free a filter set
+ *
+ * @param fs Filter set to free
+ */
+void tr_filter_set_free(TR_FILTER_SET *fs)
+{
+  talloc_free(fs);
+}
+
+/**
+ * Find the tail of the filter set linked list.
+ *
+ * @param set Set to find tail of
+ * @return Last element in the list
+ */
+static TR_FILTER_SET *tr_filter_set_tail(TR_FILTER_SET *set)
+{
+  while (set->next)
+    set=set->next;
+  return set;
+}
+
+/**
+ * Add new filter to filter set.
+ *
+ * @param set Filter set
+ * @param new New filter to add
+ * @return 0 on success, nonzero on error
+ */
+int tr_filter_set_add(TR_FILTER_SET *set, TR_FILTER *new)
+{
+  TR_FILTER_SET *tail=NULL;
+
+  if (set->this==NULL)
+    tail=set;
+  else {
+    tail=tr_filter_set_tail(set);
+    tail->next=tr_filter_set_new(set);
+    if (tail->next==NULL)
+      return 1;
+    tail=tail->next;
+  }
+  tail->this=new;
+  talloc_steal(tail, new);
+  return 0;
+}
+
+/**
+ * Find a filter of a given type in the filter set. If there are multiple, returns the first one.
+ *
+ * @param set Filter set to search
+ * @param type Type of filter to find
+ * @return Borrowed pointer to the filter, or null if no filter of that type is found
+ */
+TR_FILTER *tr_filter_set_get(TR_FILTER_SET *set, TR_FILTER_TYPE type)
+{
+  TR_FILTER_SET *cur=set;
+  while(cur!=NULL) {
+    if ((cur->this != NULL) && (cur->this->type == type))
+      return cur->this;
+    cur=cur->next;
+  }
+  return NULL;
+}
+
+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]);
+
+const char *tr_filter_type_to_string(TR_FILTER_TYPE ftype)
+{
+  size_t ii=0;
+
+  for (ii=0; ii<num_filter_types; ii++) {
+    if (ftype==filter_type[ii])
+      return filter_label[ii];
+  }
+  return "unknown";
+}
+
+TR_FILTER_TYPE tr_filter_type_from_string(const char *s)
+{
+  size_t ii=0;
+
+  for(ii=0; ii<num_filter_types; ii++) {
+    if (0==strcmp(s, filter_label[ii]))
+      return filter_type[ii];
+  }
+  return TR_FILTER_TYPE_UNKNOWN;
+}
+
index 94a6360..35c2714 100644 (file)
@@ -54,7 +54,7 @@ TR_RP_CLIENT *tr_rp_client_new(TALLOC_CTX *mem_ctx)
     client->next=NULL;
     client->comm_next=NULL;
     client->gss_names=NULL;
-    client->filter=NULL;
+    client->filters=NULL;
     talloc_set_destructor((void *)client, tr_rp_client_destructor);
   }
   return client;
@@ -96,12 +96,12 @@ int tr_rp_client_add_gss_name(TR_RP_CLIENT *rp_client, TR_NAME *gss_name)
   return tr_gss_names_add(rp_client->gss_names, gss_name);
 }
 
-int tr_rp_client_set_filter(TR_RP_CLIENT *client, TR_FILTER *filt)
+int tr_rp_client_set_filters(TR_RP_CLIENT *client, TR_FILTER_SET *filts)
 {
-  if (client->filter!=NULL)
-    tr_filter_free(client->filter);
-  client->filter=filt;
-  talloc_steal(client, filt);
+  if (client->filters!=NULL)
+    tr_filter_set_free(client->filters);
+  client->filters=filts;
+  talloc_steal(client, filts);
   return 0; /* success */
 }
 
index 38082de..a6f8651 100644 (file)
@@ -50,9 +50,9 @@
 
 /* Filter actions */
 typedef enum {
-    TR_FILTER_ACTION_REJECT = 0,
-    TR_FILTER_ACTION_ACCEPT,
-    TR_FILTER_ACTION_UNKNOWN
+  TR_FILTER_ACTION_REJECT = 0,
+  TR_FILTER_ACTION_ACCEPT,
+  TR_FILTER_ACTION_UNKNOWN
 } TR_FILTER_ACTION;
 
 /* Match codes */
@@ -61,29 +61,41 @@ typedef enum {
 
 /* Filter types */
 typedef enum {
-    TR_FILTER_TYPE_TID_INBOUND = 0,
-    TR_FILTER_TYPE_TRP_INBOUND,
-    TR_FILTER_TYPE_TRP_OUTBOUND,
-    TR_FILTER_TYPE_UNKNOWN
+  TR_FILTER_TYPE_TID_INBOUND = 0,
+  TR_FILTER_TYPE_TRP_INBOUND,
+  TR_FILTER_TYPE_TRP_OUTBOUND,
+  TR_FILTER_TYPE_UNKNOWN
 } TR_FILTER_TYPE;
 
 typedef struct tr_fspec {
-    TR_NAME *field;
-    TR_NAME *match[TR_MAX_FILTER_SPEC_MATCHES];
+  TR_NAME *field;
+  TR_NAME *match[TR_MAX_FILTER_SPEC_MATCHES];
 } TR_FSPEC;
 
 typedef struct tr_fline {
-    TR_FILTER_ACTION action;
-    TR_FSPEC *specs[TR_MAX_FILTER_SPECS];
-    TR_CONSTRAINT *realm_cons;
-    TR_CONSTRAINT *domain_cons;
+  TR_FILTER_ACTION action;
+  TR_FSPEC *specs[TR_MAX_FILTER_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_FILTER_TYPE type;
+  TR_FLINE *lines[TR_MAX_FILTER_LINES];
 } TR_FILTER;
 
+
+typedef struct tr_filter_set TR_FILTER_SET;
+struct tr_filter_set {
+  TR_FILTER *this;
+  TR_FILTER_SET *next;
+};
+
+TR_FILTER_SET *tr_filter_set_new(TALLOC_CTX *mem_ctx);
+void tr_filter_set_free(TR_FILTER_SET *fs);
+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);
@@ -116,5 +128,7 @@ 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);
+const char *tr_filter_type_to_string(TR_FILTER_TYPE ftype);
+TR_FILTER_TYPE tr_filter_type_from_string(const char *s);
 
 #endif
index 0a9096f..e10fd1a 100644 (file)
@@ -69,7 +69,7 @@ void tr_msg_set_trp_req(TR_MSG *msg, TRP_REQ *req);
 
 /* Encoders/Decoders */
 char *tr_msg_encode(TR_MSG *msg);
-TR_MSG *tr_msg_decode(char *jmsg, size_t len);
+TR_MSG *tr_msg_decode(const char *jmsg, size_t len);
 void tr_msg_free_encoded(char *jmsg);
 void tr_msg_free_decoded(TR_MSG *msg);
 
index 7e8f8f0..e150f9a 100644 (file)
@@ -44,7 +44,7 @@ typedef struct tr_rp_client {
   struct tr_rp_client *next;
   struct tr_rp_client *comm_next;
   TR_GSS_NAMES *gss_names;
-  TR_FILTER *filter;
+  TR_FILTER_SET *filters;
 } TR_RP_CLIENT;
 
 /* Structure to make a linked list of RP realms by name for community config */
@@ -60,7 +60,7 @@ void tr_rp_client_free(TR_RP_CLIENT *client);
 TR_RP_CLIENT *tr_rp_client_add_func(TR_RP_CLIENT *clients, TR_RP_CLIENT *new);
 #define tr_rp_client_add(clients,new) ((clients)=tr_rp_client_add_func((clients),(new)))
 int tr_rp_client_add_gss_name(TR_RP_CLIENT *client, TR_NAME *name);
-int tr_rp_client_set_filter(TR_RP_CLIENT *client, TR_FILTER *filt);
+int tr_rp_client_set_filters(TR_RP_CLIENT *client, TR_FILTER_SET *filts);
 TR_RP_CLIENT *tr_rp_client_lookup(TR_RP_CLIENT *rp_clients, TR_NAME *gss_name);
 
 TR_RP_REALM *tr_rp_realm_new(TALLOC_CTX *mem_ctx);
index 303bbc3..7171952 100644 (file)
@@ -62,7 +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;
+  TR_FILTER_SET *filters;
 };
 
 typedef struct trp_ptable {
@@ -108,8 +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);
+void trp_peer_set_filters(TRP_PEER *peer, TR_FILTER_SET *filts);
+TR_FILTER *trp_peer_get_filter(TRP_PEER *peer, TR_FILTER_TYPE ftype);
 char *trp_peer_to_str(TALLOC_CTX *memctx, TRP_PEER *peer, const char *sep);
 
 #endif /* _TRP_PTABLE_H_ */
index fb76dd7..7a09dda 100644 (file)
@@ -295,7 +295,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
    * the TIDS handler subprocess. */
 
   if ((!tids->rp_gss) || 
-      (!tids->rp_gss->filter)) {
+      (!tids->rp_gss->filters)) {
     tr_notice("tr_tids_req_handler: No GSS name for incoming request.");
     tids_send_err_response(tids, orig_req, "No GSS name for request");
     retval=-1;
@@ -303,7 +303,8 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
   }
 
   if ((TR_FILTER_NO_MATCH == tr_filter_process_rp_permitted(orig_req->rp_realm,
-                                                            tids->rp_gss->filter,
+                                                            tr_filter_set_get(tids->rp_gss->filters,
+                                                                              TR_FILTER_TYPE_TID_INBOUND),
                                                             orig_req->cons,
                                                            &fwd_req->cons,
                                                            &oaction)) ||
index 4cb0705..b954584 100644 (file)
@@ -66,7 +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;
+    peer->filters=NULL;
     talloc_set_destructor((void *)peer, trp_peer_destructor);
   }
   return peer;
@@ -212,20 +212,20 @@ void trp_peer_set_conn_status_cb(TRP_PEER *peer, void (*cb)(TRP_PEER *, void *),
  * freeing the new filter.
  *
  * @param peer Peer to modify
- * @param filt New filter to attach to the peer
+ * @param filts New filter to attach to the peer
  */
-void trp_peer_set_filter(TRP_PEER *peer, TR_FILTER *filt)
+void trp_peer_set_filters(TRP_PEER *peer, TR_FILTER_SET *filts)
 {
-  if (peer->filter!=NULL)
-    tr_filter_free(peer->filter);
+  if (peer->filters!=NULL)
+    tr_filter_set_free(peer->filters);
 
-  peer->filter=filt;
-  talloc_steal(peer, filt);
+  peer->filters=filts;
+  talloc_steal(peer, filts);
 }
 
-TR_FILTER *trp_peer_get_filter(TRP_PEER *peer)
+TR_FILTER *trp_peer_get_filter(TRP_PEER *peer, TR_FILTER_TYPE ftype)
 {
-  return peer->filter;
+  return tr_filter_set_get(peer->filters, ftype);
 }
 
 struct timespec *trp_peer_get_last_conn_attempt(TRP_PEER *peer)