Merge pull request #76 from painless-security/jennifer/trpc_deadlock
authormrw42 <margaret@painless-security.com>
Fri, 4 May 2018 20:58:06 +0000 (16:58 -0400)
committerGitHub <noreply@github.com>
Fri, 4 May 2018 20:58:06 +0000 (16:58 -0400)
Eliminate deadlock in TRPC messaging queueing

49 files changed:
CMakeLists.txt
Makefile.am
common/tests/cfg_test.c
common/tr_comm.c
common/tr_comm_encoders.c
common/tr_config_comms.c
common/tr_config_filters.c
common/tr_config_rp_clients.c
common/tr_constraint.c
common/tr_filter.c
common/tr_filter_encoders.c
common/tr_gss_names.c
common/tr_idp_encoders.c
common/tr_list.c [new file with mode: 0644]
common/tr_msg.c
common/tr_name.c
common/tr_rand_id.c [new file with mode: 0644]
common/tr_rp_client_encoders.c
common/tr_socket.c
common/tr_util.c
include/tid_internal.h
include/tr_comm.h
include/tr_constraint_internal.h [new file with mode: 0644]
include/tr_filter.h
include/tr_gss_names.h
include/tr_list.h [new file with mode: 0644]
include/tr_name_internal.h
include/tr_rand_id.h [new file with mode: 0644]
include/tr_socket.h
include/tr_util.h
include/trp_route.h
include/trust_router/tid.h
include/trust_router/tr_constraint.h
include/trust_router/tr_name.h
mon/mon_req_decode.c
mon/mon_resp_encode.c
mon/mons.c
tid/tid_req.c
tid/tid_resp.c
tid/tidc.c
tid/tids.c
tr/tr_main.c
tr/tr_tid.c
tr/tr_trp.c
trp/trp_conn.c
trp/trp_ptable_encoders.c
trp/trp_route.c
trp/trp_route_encoders.c
trp/trps.c

index 4ae8dba..1221d67 100644 (file)
@@ -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})
index 1c933d6..f75f5da 100644 (file)
@@ -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
index 97cd03c..29a949d 100644 (file)
@@ -41,6 +41,7 @@
 #include <tr_idp.h>
 #include <tr_config.h>
 #include <tr_debug.h>
+#include <tr_gss_names.h>
 
 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; ii<TR_MAX_GSS_NAMES; ii++)
-    assert(cfg->rp_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;
 }
 
index e915b70..725fcac 100644 (file)
 #include <tr_rp.h>
 #include <tr_idp.h>
 #include <tr_name_internal.h>
+#include <trp_internal.h>
 #include <tr_comm.h>
 #include <tr_debug.h>
-
+#include <tr_util.h>
 
 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)
index c33c604..9f53008 100644 (file)
 
 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 */
index 60b5f93..99e2070 100644 (file)
@@ -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);
index 4035e68..7d4c615 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <jansson.h>
-#include <dirent.h>
 #include <talloc.h>
 
+#include <tr_constraint_internal.h>
 #include <tr_cfgwatch.h>
-#include <tr_comm.h>
-#include <tr_config.h>
-#include <tr_gss_names.h>
 #include <tr_debug.h>
-#include <tr_filter.h>
-#include <trust_router/tr_constraint.h>
-#include <tr_idp.h>
-#include <tr.h>
-#include <trust_router/trp.h>
 
 #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;
index 960edce..b263c02 100644 (file)
@@ -44,7 +44,7 @@
 #include <tr_gss_names.h>
 #include <tr_debug.h>
 #include <tr_filter.h>
-#include <trust_router/tr_constraint.h>
+#include <tr_constraint_internal.h>
 #include <tr_idp.h>
 #include <tr.h>
 #include <trust_router/trp.h>
@@ -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);
index da5f42e..f9fcf61 100644 (file)
 #include <assert.h>
 #include <talloc.h>
 
-#include <trust_router/tr_constraint.h>
 #include <tr_filter.h>
 #include <tid_internal.h>
 #include <tr_debug.h>
+#include <tr_constraint_internal.h>
 
-
+/**
+ * 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;
index 52dffb4..2b94526 100644 (file)
@@ -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;
-       ii<TR_MAX_FILTER_LINES;
-       ii++) {
-    /* skip empty lines (these shouldn't really happen) */
-    if (filt->lines[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; jj<TR_MAX_FILTER_SPECS; jj++) {
-      /* skip empty specs (these shouldn't really happen either) */
-      if (filt->lines[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; ii<TR_MAX_FILTER_SPEC_MATCHES; ii++) {
-    if (fspec->match[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; ii<TR_MAX_FILTER_SPEC_MATCHES; ii++)
-      fspec->match[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; ii<TR_MAX_FILTER_SPEC_MATCHES; ii++) {
-    if (fspec->match[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; ii<TR_MAX_FILTER_SPEC_MATCHES; ii++) {
-    if (fspec->match[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; ii<TR_MAX_FILTER_LINES; ii++) {
-    if (filt->lines[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; jj<TR_MAX_FILTER_SPECS; jj++) {
-      if (filt->lines[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; kk<TR_MAX_FILTER_SPEC_MATCHES; kk++) {
-        if (filt->lines[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;
 }
 
index cc22b02..932be9e 100644 (file)
@@ -36,6 +36,7 @@
 #include <jansson.h>
 
 #include <tr_filter.h>
+#include <tr_constraint_internal.h>
 
 /* 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; ii<max_items; ii++) {
-    if (items[ii] != NULL)
-      ARRAY_APPEND_OR_FAIL(jarray, item_encoder(items[ii]));
+  switch(type) {
+    case ARRAY_TYPE_FSPEC:
+      this_match = tr_fspec_iter_first(&fspec_iter, (TR_FSPEC *)obj);
+      break;
+
+    case ARRAY_TYPE_CONSTRAINT:
+      this_match = tr_constraint_iter_first(&cons_iter, (TR_CONSTRAINT *)obj);
+      break;
+  }
+  while(this_match) {
+    ARRAY_APPEND_OR_FAIL(jarray, tr_name_to_json_string(this_match));
+    switch(type) {
+      case ARRAY_TYPE_FSPEC:
+        this_match = tr_fspec_iter_next(&fspec_iter);
+        break;
+
+      case ARRAY_TYPE_CONSTRAINT:
+        this_match = tr_constraint_iter_next(&cons_iter);
+        break;
+    }
   }
   /* success */
   retval = jarray;
@@ -93,9 +124,7 @@ static json_t *tr_fspec_to_json(TR_FSPEC *fspec)
   OBJECT_SET_OR_FAIL(fspec_json, "field",
                      tr_name_to_json_string(fspec->field));
   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));
     }
   }
 
index df15202..416ba8c 100644 (file)
  */
 
 #include <talloc.h>
+#include <glib.h>
 
 #include <tr_gss_names.h>
 #include <tr_debug.h>
 
+/**
+ * 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; ii<TR_MAX_GSS_NAMES; ii++) {
-    if (gss_names->names[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; ii<TR_MAX_GSS_NAMES; ii++)
-      gn->names[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; ii<TR_MAX_GSS_NAMES; ii++) {
-    if (gn->names[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; ii<TR_MAX_GSS_NAMES; ii++) {
-    if ((gn->names[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->ii<TR_MAX_GSS_NAMES)
-    return iter->gn->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);
index fec129a..2167ea9 100644 (file)
@@ -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 (file)
index 0000000..e3269f4
--- /dev/null
@@ -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 <talloc.h>
+#include <tr_list.h>
+
+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;
+}
index ab80345..50e8bc9 100644 (file)
@@ -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;
 }
 
index 84f0c1f..e1f81b4 100644 (file)
@@ -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->len<one->len)
     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->len<two->len)
       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 (file)
index 0000000..a2a0a10
--- /dev/null
@@ -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 <stdio.h>
+#include <string.h>
+#include <openssl/rand.h>
+#include <talloc.h>
+
+#include <tr_rand_id.h>
+
+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;
+}
index d0a5cd0..6a7bda9 100644 (file)
@@ -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 */
index 7f1c917..1bb3cc2 100644 (file)
@@ -40,6 +40,7 @@
 
 #include <tr_debug.h>
 #include <tr_socket.h>
+#include <errno.h>
 
 /**
  * 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;
+}
index ef85776..2e59606 100644 (file)
@@ -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<ts2, >= 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 ts1<ts2, 1 if ts1>ts2.
+ */
+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
index 6b6fb78..8613eb8 100644 (file)
@@ -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;
index 6228c1f..461d75b 100644 (file)
@@ -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 (file)
index 0000000..2182781
--- /dev/null
@@ -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 <talloc.h>
+
+#include <tr_list.h>
+#include <tr_name_internal.h>
+#include <trust_router/tr_constraint.h>
+
+
+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
index ece3650..d241a50 100644 (file)
 
 #include <talloc.h>
 #include <jansson.h>
+#include <glib.h>
 
+#include <tr_list.h>
 #include <tr_name_internal.h>
 #include <trust_router/tr_constraint.h>
 #include <trust_router/tid.h>
 #include <trust_router/trp.h>
 
-#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);
index f8f97a2..c6192be 100644 (file)
 #define __TR_GSS_H__
 
 #include <talloc.h>
-#include <tr_name_internal.h>
+#include <tr_list.h>
 
-#define TR_MAX_GSS_NAMES 5
+#include <tr_name_internal.h>
 
 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 (file)
index 0000000..8bfca38
--- /dev/null
@@ -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 <talloc.h>
+#include <glib.h>
+
+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
index 02c78f8..a67a64d 100644 (file)
  */
 
 #ifndef TR_NAME_INTERNAL_H
+#define TR_NAME_INTERNAL_H
 
 #include<trust_router/tr_name.h>
 #include <jansson.h>
 
 /** 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 (file)
index 0000000..8632c89
--- /dev/null
@@ -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
index 064c6fc..e90a912 100644 (file)
@@ -37,7 +37,9 @@
 
 #include <stdlib.h>
 #include <poll.h> // for nfds_t
+#include <sys/socket.h>
 
 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
index bed0482..9bf7d8e 100644 (file)
 /* 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 */
index d159861..aff0ba0 100644 (file)
@@ -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);
index 35ec577..38833f1 100644 (file)
@@ -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 *);
index 2594b36..88619e4 100644 (file)
 #ifndef TR_CONSTRAINT_H
 #define TR_CONSTRAINT_H
 
-#include <talloc.h>
-
 #include <trust_router/tr_name.h>
 #include <trust_router/tid.h>
 
-
-#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
index 052d291..797a3be 100644 (file)
@@ -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
index 0c7e7f4..21bb64b 100644 (file)
@@ -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;
 }
index 23c3dd8..7e41c65 100644 (file)
@@ -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;
index f2e69c5..cb70d3b 100644 (file)
@@ -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;
   }
 
index 88dd991..002b720 100644 (file)
@@ -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;
 }
 
index dbbc906..3ff3d02 100644 (file)
@@ -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)
 {
index 94cd98d..90335f0 100644 (file)
@@ -41,6 +41,7 @@
 #include <tid_internal.h>
 #include <tr_msg.h>
 #include <tr_debug.h>
+#include <tr_rand_id.h>
 
 
 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.");
index 6a5b172..74e790e 100644 (file)
@@ -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;
   }
 
index 5f8215d..ba738c7 100644 (file)
@@ -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) {
index 038cc3c..62722e8 100644 (file)
@@ -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))) {
index 79a9a27..9f9c558 100644 (file)
@@ -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");
   }
index dfa666c..1cf326d 100644 (file)
@@ -40,6 +40,7 @@
 
 #include <tr_debug.h>
 #include <trp_internal.h>
+#include <tr_socket.h>
 
 /* 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);
index 2ff8c9c..ea97a10 100644 (file)
@@ -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;
index 1334032..6178d97 100644 (file)
@@ -45,6 +45,7 @@
 #include <tr_debug.h>
 #include <trust_router/trp.h>
 #include <trust_router/tid.h>
+#include <tr_util.h>
 
 
 /* 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;
index 8e1809b..c954a81 100644 (file)
@@ -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);
index b737aba..32a7de1 100644 (file)
@@ -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; kk<n_entry; kk++) {
     if (trp_route_get_metric(entry[kk]) < min_metric) {
-      if ((exclude_peer==NULL) || (0!=tr_name_cmp(trp_route_get_peer(entry[kk]),
-                                                  exclude_peer))) {
-        kk_min=kk;
-        min_metric=trp_route_get_metric(entry[kk]);
-      } 
+      if (exclude_peer_label != NULL) {
+        if (!trp_route_is_local(entry[kk])) {
+          /* route is not local, check the peer label */
+          route_peer = trp_ptable_find_gss_name(trps->ptable,
+                                                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; ii<n_comm; ii++) {
     realm=trp_rtable_get_comm_realms(trps->rtable, comm[ii], &n_realm);
     for (jj=0; jj<n_realm; jj++) {
-      best=trps_select_realm_update(trps, comm[ii], realm[jj], peer_gssname);
+      best=trps_select_realm_update(trps, comm[ii], realm[jj], peer_label);
       /* If we found a route, add it to the list. If triggered!=0, then only
        * add triggered routes. */
       if ((best!=NULL) && ((!triggered) || trp_route_is_triggered(best))) {
@@ -1460,7 +1582,11 @@ cleanup:
 }
 
 /* construct an update with all the inforecs for comm/realm/role to be sent to peer */
-static TRP_UPD *trps_comm_update(TALLOC_CTX *mem_ctx, TRPS_INSTANCE *trps, TR_NAME *peer_gssname, TR_COMM *comm, TR_REALM *realm)
+static TRP_UPD *trps_comm_update(TALLOC_CTX *mem_ctx,
+                                 TRPS_INSTANCE *trps,
+                                 TR_NAME *peer_label,
+                                 TR_COMM *comm,
+                                 TR_REALM *realm)
 {
   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
   TRP_UPD *upd=trp_upd_new(tmp_ctx);
@@ -1526,7 +1652,7 @@ cleanup:
 static TRP_RC trps_select_comm_updates_for_peer(TALLOC_CTX *mem_ctx,
                                                 GPtrArray *updates,
                                                 TRPS_INSTANCE *trps,
-                                                TR_NAME *peer_gssname,
+                                                TR_NAME *peer_label,
                                                 int triggered)
 {
   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
@@ -1566,7 +1692,7 @@ static TRP_RC trps_select_comm_updates_for_peer(TALLOC_CTX *mem_ctx,
       tr_debug("trps_select_comm_updates_for_peer: adding realm %.*s",
                tr_realm_get_id(realm)->len,
                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);
     }