Merge pull request #50 from painless-security/jennifer/refactoring_tids
authormrw42 <margaret@painless-security.com>
Thu, 3 May 2018 20:02:05 +0000 (16:02 -0400)
committerGitHub <noreply@github.com>
Thu, 3 May 2018 20:02:05 +0000 (16:02 -0400)
TID refactoring (pull request 2)

34 files changed:
CMakeLists.txt
Makefile.am
common/tr_config.c
common/tr_config_internal.c [new file with mode: 0644]
common/tr_gss.c
common/tr_gss_names.c [new file with mode: 0644]
common/tr_msg.c
common/tr_rp.c
common/tr_socket.c [new file with mode: 0644]
include/mon_internal.h
include/tid_internal.h
include/tr_config.h
include/tr_event.h
include/tr_gss.h
include/tr_gss_names.h [new file with mode: 0644]
include/tr_mon.h [new file with mode: 0644]
include/tr_msg.h
include/tr_rp.h
include/tr_socket.h [new file with mode: 0644]
include/tr_trp.h
include/trp_ptable.h
include/trust_router/tid.h
mon/mons.c [new file with mode: 0644]
tid/tid_resp.c
tid/tidc.c
tid/tids.c
tr/tr_main.c
tr/tr_mon.c [new file with mode: 0644]
tr/tr_tid.c
tr/tr_trp.c
trp/msgtst.c
trp/test/ptbl_test.c
trp/trp_ptable.c
trp/trps.c

index 5d30c36..2fe9749 100644 (file)
@@ -29,7 +29,7 @@ set(SOURCE_FILES
     common/tr_debug.c
     common/tr_dh.c
     common/tr_filter.c
-    common/tr_gss.c
+        common/tr_gss_names.c
     common/tr_idp.c
     common/tr_mq.c
     common/tr_msg.c
@@ -57,7 +57,7 @@ set(SOURCE_FILES
     include/tr_debug.h
     include/tr_event.h
     include/tr_filter.h
-    include/tr_gss.h
+        include/tr_gss_names.h
     include/tr_idp.h
     include/tr_mq.h
     include/tr_msg.h
@@ -91,7 +91,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.c mon/mon_common.c mon/mon_resp_encode.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)
 
 # Does not actually build!
 add_executable(trust_router ${SOURCE_FILES})
index 845ce17..49bf774 100644 (file)
@@ -20,7 +20,8 @@ common_srcs = common/tr_name.c \
        common/tr_rp.c \
        common/tr_idp.c \
        common/tr_filter.c \
-       common/tr_gss.c
+       common/tr_gss_names.c \
+       common/tr_socket.c
 
 tid_srcs = tid/tid_resp.c \
 tid/tid_req.c \
@@ -35,10 +36,12 @@ trp/trp_rtable.c \
 trp/trp_req.c \
 trp/trp_upd.c \
 common/tr_config.c \
+common/tr_config_internal.c \
 common/tr_mq.c
 
-mon_srcs =                      \
-    mon/mon_common.c                \
+mon_srcs =                   \
+    mon/mons.c               \
+    mon/mon_common.c         \
     mon/mon_req.c            \
     mon/mon_req_encode.c     \
     mon/mon_req_decode.c     \
@@ -77,14 +80,18 @@ tr/tr_event.c \
 tr/tr_cfgwatch.c \
 tr/tr_tid.c \
 tr/tr_trp.c \
+tr/tr_mon.c \
+common/tr_gss.c \
 $(tid_srcs) \
 $(trp_srcs) \
+$(mon_srcs) \
 $(common_srcs)
 
 tr_trust_router_LDFLAGS = $(AM_LDFLAGS) -levent_pthreads -pthread
 tr_trust_router_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
 tr_trpc_SOURCES =tr/trpc_main.c \
 tr/tr_trp.c \
+common/tr_gss.c \
 $(trp_srcs) \
 $(tid_srcs) \
 $(common_srcs)
@@ -102,12 +109,13 @@ trp_msgtst_LDADD =  $(GLIB_LIBS)
 
 trp_test_rtbl_test_SOURCES = trp/test/rtbl_test.c \
 common/tr_name.c \
-common/tr_gss.c \
+common/tr_gss_names.c \
 common/tr_debug.c \
 trp/trp_rtable.c
 trp_test_rtbl_test_LDADD =  $(GLIB_LIBS)
 
 trp_test_ptbl_test_SOURCES = trp/test/ptbl_test.c \
+common/tr_gss.c \
 $(tid_srcs) \
 $(trp_srcs) \
 $(common_srcs)
@@ -115,6 +123,7 @@ trp_test_ptbl_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
 trp_test_ptbl_test_LDFLAGS = $(AM_LDFLAGS) -pthread
 
 tid_example_tidc_SOURCES = tid/example/tidc_main.c \
+common/tr_gss.c \
 $(tid_srcs) \
 $(trp_srcs) \
 $(common_srcs)
@@ -122,6 +131,7 @@ tid_example_tidc_LDADD = gsscon/libgsscon.la  $(GLIB_LIBS)
 tid_example_tidc_LDFLAGS = $(AM_LDFLAGS) -pthread
 
 tid_example_tids_SOURCES = tid/example/tids_main.c \
+common/tr_gss.c \
 $(tid_srcs) \
 $(trp_srcs) \
 $(common_srcs)
@@ -140,6 +150,7 @@ common_tests_mq_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc -pthread
 
 common_tests_cfg_test_SOURCES = common/tests/cfg_test.c \
 $(common_srcs) \
+common/tr_gss.c \
 $(tid_srcs) \
 $(trp_srcs)
 common_tests_cfg_test_LDADD = gsscon/libgsscon.la  $(GLIB_LIBS)
@@ -151,6 +162,7 @@ common/tests/thread_test.c
 
 common_tests_commtest_SOURCES = common/tests/commtest.c \
 $(common_srcs) \
+common/tr_gss.c \
 $(tid_srcs) \
 $(trp_srcs)
 common_tests_commtest_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
@@ -160,6 +172,7 @@ common_tests_thread_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc -pthread
 
 common_tests_name_test_SOURCES = common/tests/name_test.c \
               $(common_srcs) \
+              common/tr_gss.c \
               $(tid_srcs) \
               $(trp_srcs)
 common_tests_name_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
@@ -168,6 +181,7 @@ common_tests_name_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
 
 common_tests_filt_test_SOURCES = common/tests/filt_test.c \
               $(common_srcs) \
+              common/tr_gss.c \
               $(tid_srcs) \
               $(trp_srcs)
 common_tests_filt_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
@@ -202,13 +216,13 @@ noinst_HEADERS = include/gsscon.h include/tr_config.h \
        include/tr_msg.h include/tr.h \
        include/tr_idp.h include/tr_rp.h \
        include/tr_comm.h include/tr_apc.h \
-       include/tr_tid.h include/tr_trp.h \
-       include/tr_filter.h include/tr_gss.h \
+       include/tr_tid.h include/tr_trp.h include/tr_mon.h \
+       include/tr_filter.h include/tr_gss_names.h \
        include/tid_internal.h include/trp_internal.h \
        include/tr_cfgwatch.h include/tr_event.h \
        include/tr_mq.h include/trp_ptable.h \
        include/trp_rtable.h include/tr_util.h \
-       include/tr_name_internal.h
+       include/tr_name_internal.h include/tr_gss.h
 
 pkgdata_DATA=schema.sql
 nobase_dist_pkgdata_DATA=redhat/init redhat/sysconfig redhat/organizations.cfg redhat/tidc-wrapper redhat/trust_router-wrapper redhat/tr-test-internal.cfg redhat/default-internal.cfg redhat/tids-wrapper redhat/sysconfig.tids
index c1fc6d9..dc6f77b 100644 (file)
@@ -41,7 +41,7 @@
 #include <tr_cfgwatch.h>
 #include <tr_comm.h>
 #include <tr_config.h>
-#include <tr_gss.h>
+#include <tr_gss_names.h>
 #include <tr_debug.h>
 #include <tr_filter.h>
 #include <trust_router/tr_constraint.h>
@@ -174,205 +174,6 @@ TR_CFG_RC tr_apply_new_config (TR_CFG_MGR *cfg_mgr)
   return TR_CFG_SUCCESS;
 }
 
-static TR_CFG_RC tr_cfg_parse_internal(TR_CFG *trc, json_t *jcfg)
-{
-  json_t *jint = NULL;
-  json_t *jmtd = NULL;
-  json_t *jtidsp = NULL;
-  json_t *jtrpsp = NULL;
-  json_t *jhname = NULL;
-  json_t *jlog = NULL;
-  json_t *jconthres = NULL;
-  json_t *jlogthres = NULL;
-  json_t *jcfgpoll = NULL;
-  json_t *jcfgsettle = NULL;
-  json_t *jroutesweep = NULL;
-  json_t *jrouteupdate = NULL;
-  json_t *jtidreq_timeout = NULL;
-  json_t *jtidresp_numer = NULL;
-  json_t *jtidresp_denom = NULL;
-  json_t *jrouteconnect = NULL;
-
-  if ((!trc) || (!jcfg))
-    return TR_CFG_BAD_PARAMS;
-
-  if (NULL == trc->internal) {
-    if (NULL == (trc->internal = talloc_zero(trc, TR_CFG_INTERNAL)))
-      return TR_CFG_NOMEM;
-  }
-
-  if (NULL != (jint = json_object_get(jcfg, "tr_internal"))) {
-    if (NULL != (jmtd = json_object_get(jint, "max_tree_depth"))) {
-      if (json_is_number(jmtd)) {
-        trc->internal->max_tree_depth = json_integer_value(jmtd);
-      } else {
-        tr_debug("tr_cfg_parse_internal: Parsing error, max_tree_depth is not a number.");
-        return TR_CFG_NOPARSE;
-      }
-    } else {
-      /* If not configured, use the default */
-      trc->internal->max_tree_depth = TR_DEFAULT_MAX_TREE_DEPTH;
-    }
-    if (NULL != (jtidsp = json_object_get(jint, "tids_port"))) {
-      if (json_is_number(jtidsp)) {
-        trc->internal->tids_port = json_integer_value(jtidsp);
-      } else {
-        tr_debug("tr_cfg_parse_internal: Parsing error, tids_port is not a number.");
-        return TR_CFG_NOPARSE;
-      }
-    } else {
-      /* If not configured, use the default */
-      trc->internal->tids_port = TR_DEFAULT_TIDS_PORT;
-    }
-    if (NULL != (jtrpsp = json_object_get(jint, "trps_port"))) {
-      if (json_is_number(jtrpsp)) {
-        trc->internal->trps_port = json_integer_value(jtrpsp);
-      } else {
-        tr_debug("tr_cfg_parse_internal: Parsing error, trps_port is not a number.");
-        return TR_CFG_NOPARSE;
-      }
-    } else {
-      /* If not configured, use the default */
-      trc->internal->trps_port = TR_DEFAULT_TRPS_PORT;
-    }
-    if (NULL != (jhname = json_object_get(jint, "hostname"))) {
-      if (json_is_string(jhname)) {
-        trc->internal->hostname = talloc_strdup(trc->internal, json_string_value(jhname));
-      } else {
-        tr_debug("tr_cfg_parse_internal: Parsing error, hostname is not a string.");
-        return TR_CFG_NOPARSE;
-      }
-    }
-    if (NULL != (jcfgpoll = json_object_get(jint, "cfg_poll_interval"))) {
-      if (json_is_number(jcfgpoll)) {
-        trc->internal->cfg_poll_interval = json_integer_value(jcfgpoll);
-      } else {
-        tr_debug("tr_cfg_parse_internal: Parsing error, cfg_poll_interval is not a number.");
-        return TR_CFG_NOPARSE;
-      }
-    } else {
-      trc->internal->cfg_poll_interval = TR_CFGWATCH_DEFAULT_POLL;
-    }
-
-    if (NULL != (jcfgsettle = json_object_get(jint, "cfg_settling_time"))) {
-      if (json_is_number(jcfgsettle)) {
-        trc->internal->cfg_settling_time = json_integer_value(jcfgsettle);
-      } else {
-        tr_debug("tr_cfg_parse_internal: Parsing error, cfg_settling_time is not a number.");
-        return TR_CFG_NOPARSE;
-      }
-    } else {
-      trc->internal->cfg_settling_time = TR_CFGWATCH_DEFAULT_SETTLE;
-    }
-
-    if (NULL != (jrouteconnect = json_object_get(jint, "trp_connect_interval"))) {
-      if (json_is_number(jrouteconnect)) {
-        trc->internal->trp_connect_interval = json_integer_value(jrouteconnect);
-      } else {
-        tr_debug("tr_cfg_parse_internal: Parsing error, trp_connect_interval is not a number.");
-        return TR_CFG_NOPARSE;
-      }
-    } else {
-      /* if not configured, use the default */
-      trc->internal->trp_connect_interval=TR_DEFAULT_TRP_CONNECT_INTERVAL;
-    }
-
-    if (NULL != (jroutesweep = json_object_get(jint, "trp_sweep_interval"))) {
-      if (json_is_number(jroutesweep)) {
-        trc->internal->trp_sweep_interval = json_integer_value(jroutesweep);
-      } else {
-        tr_debug("tr_cfg_parse_internal: Parsing error, trp_sweep_interval is not a number.");
-        return TR_CFG_NOPARSE;
-      }
-    } else {
-      /* if not configured, use the default */
-      trc->internal->trp_sweep_interval=TR_DEFAULT_TRP_SWEEP_INTERVAL;
-    }
-
-    if (NULL != (jrouteupdate = json_object_get(jint, "trp_update_interval"))) {
-      if (json_is_number(jrouteupdate)) {
-        trc->internal->trp_update_interval = json_integer_value(jrouteupdate);
-      } else {
-        tr_debug("tr_cfg_parse_internal: Parsing error, trp_update_interval is not a number.");
-        return TR_CFG_NOPARSE;
-      }
-    } else {
-      /* if not configured, use the default */
-      trc->internal->trp_update_interval=TR_DEFAULT_TRP_UPDATE_INTERVAL;
-    }
-
-    if (NULL != (jtidreq_timeout = json_object_get(jint, "tid_request_timeout"))) {
-      if (json_is_number(jtidreq_timeout)) {
-        trc->internal->tid_req_timeout = json_integer_value(jtidreq_timeout);
-      } else {
-        tr_debug("tr_cfg_parse_internal: Parsing error, tid_request_timeout is not a number.");
-        return TR_CFG_NOPARSE;
-      }
-    } else {
-      /* if not configured, use the default */
-      trc->internal->tid_req_timeout=TR_DEFAULT_TID_REQ_TIMEOUT;
-    }
-
-    if (NULL != (jtidresp_numer = json_object_get(jint, "tid_response_numerator"))) {
-      if (json_is_number(jtidresp_numer)) {
-        trc->internal->tid_resp_numer = json_integer_value(jtidresp_numer);
-      } else {
-        tr_debug("tr_cfg_parse_internal: Parsing error, tid_response_numerator is not a number.");
-        return TR_CFG_NOPARSE;
-      }
-    } else {
-      /* if not configured, use the default */
-      trc->internal->tid_resp_numer=TR_DEFAULT_TID_RESP_NUMER;
-    }
-
-    if (NULL != (jtidresp_denom = json_object_get(jint, "tid_response_denominator"))) {
-      if (json_is_number(jtidresp_denom)) {
-        trc->internal->tid_resp_denom = json_integer_value(jtidresp_denom);
-      } else {
-        tr_debug("tr_cfg_parse_internal: Parsing error, tid_response_denominator is not a number.");
-        return TR_CFG_NOPARSE;
-      }
-    } else {
-      /* if not configured, use the default */
-      trc->internal->tid_resp_denom=TR_DEFAULT_TID_RESP_DENOM;
-    }
-
-    if (NULL != (jlog = json_object_get(jint, "logging"))) {
-      if (NULL != (jlogthres = json_object_get(jlog, "log_threshold"))) {
-        if (json_is_string(jlogthres)) {
-          trc->internal->log_threshold = str2sev(json_string_value(jlogthres));
-        } else {
-          tr_debug("tr_cfg_parse_internal: Parsing error, log_threshold is not a string.");
-          return TR_CFG_NOPARSE;
-        }
-      } else {
-        /* If not configured, use the default */
-        trc->internal->log_threshold = TR_DEFAULT_LOG_THRESHOLD;
-      }
-
-      if (NULL != (jconthres = json_object_get(jlog, "console_threshold"))) {
-        if (json_is_string(jconthres)) {
-            trc->internal->console_threshold = str2sev(json_string_value(jconthres));
-        } else {
-          tr_debug("tr_cfg_parse_internal: Parsing error, console_threshold is not a string.");
-          return TR_CFG_NOPARSE;
-        }
-      } else {
-        /* If not configured, use the default */
-        trc->internal->console_threshold = TR_DEFAULT_CONSOLE_THRESHOLD;
-      }
-    } else {
-        /* If not configured, use the default */
-        trc->internal->console_threshold = TR_DEFAULT_CONSOLE_THRESHOLD;
-        trc->internal->log_threshold = TR_DEFAULT_LOG_THRESHOLD;
-    }
-
-    tr_debug("tr_cfg_parse_internal: Internal config parsed.");
-    return TR_CFG_SUCCESS;
-  }
-  return TR_CFG_SUCCESS;
-}
-
 static TR_CONSTRAINT *tr_cfg_parse_one_constraint(TALLOC_CTX *mem_ctx, char *ctype, json_t *jc, TR_CFG_RC *rc)
 {
   TR_CONSTRAINT *cons=NULL;
@@ -2062,12 +1863,17 @@ typedef TR_CFG_RC (TR_CFG_PARSE_FN)(TR_CFG *, json_t *);
  * Helper function to parse a collection of JSON structures using a generic parse function.
  *
  * @param cfg Config structure to receive results
- * @param jcfgs Pointer to an array of decoded JSON structures
- * @param n_jcfg Number of JSON structures in the array
  * @param parse_fn Function to apply
+ * @param n_jcfg Number of JSON structures in the array
+ * @param jcfgs Pointer to an array of decoded JSON structures
+ * @param key Key to extract from each jcfg before parsing, or NULL to use the object itself
  * @return TR_CFG_SUCCESS on success, _FAIL or an error code on failure
  */
-static TR_CFG_RC tr_cfg_parse_helper(TR_CFG *cfg, unsigned int n_jcfg, json_t **jcfgs, TR_CFG_PARSE_FN parse_fn)
+static TR_CFG_RC tr_cfg_parse_helper(TR_CFG *cfg,
+                                     TR_CFG_PARSE_FN parse_fn,
+                                     unsigned int n_jcfg,
+                                     json_t **jcfgs,
+                                     const char *key)
 {
   size_t ii=0;
   json_t *this_jcfg=NULL;
@@ -2077,7 +1883,15 @@ static TR_CFG_RC tr_cfg_parse_helper(TR_CFG *cfg, unsigned int n_jcfg, json_t **
     return TR_CFG_ERROR;
 
   for (ii=0; ii<n_jcfg; ii++) {
-    this_jcfg=jcfgs[ii];
+    if (key)
+      this_jcfg = json_object_get(jcfgs[ii], key);
+    else
+      this_jcfg = jcfgs[ii];
+
+    /* do not try to parse a missing jcfg */
+    if (this_jcfg == NULL)
+      continue;
+
     ret=parse_fn(cfg, this_jcfg);
     if (ret!=TR_CFG_SUCCESS)
       break;
@@ -2124,11 +1938,12 @@ TR_CFG_RC tr_parse_config(TR_CFG_MGR *cfg_mgr, unsigned int n_files, char **file
   cfg_mgr->new->peers=trp_ptable_new(cfg_mgr); /* not sure why this isn't in cfg_mgr->new's context */
 
   /* now run through the parsers on the JSON */
-  if ((TR_CFG_SUCCESS != (cfg_rc=tr_cfg_parse_helper(cfg_mgr->new, n_files, jcfgs, tr_cfg_parse_internal))) ||
-      (TR_CFG_SUCCESS != (cfg_rc=tr_cfg_parse_helper(cfg_mgr->new, n_files, jcfgs, tr_cfg_parse_local_orgs))) ||
-      (TR_CFG_SUCCESS != (cfg_rc=tr_cfg_parse_helper(cfg_mgr->new, n_files, jcfgs, tr_cfg_parse_peer_orgs))) ||
-      (TR_CFG_SUCCESS != (cfg_rc=tr_cfg_parse_helper(cfg_mgr->new, n_files, jcfgs, tr_cfg_parse_default_servers))) ||
-      (TR_CFG_SUCCESS != (cfg_rc=tr_cfg_parse_helper(cfg_mgr->new, n_files, jcfgs, tr_cfg_parse_comms))))
+  if ((TR_CFG_SUCCESS != (cfg_rc= tr_cfg_parse_helper(cfg_mgr->new, tr_cfg_parse_internal, n_files, jcfgs, "tr_internal"))) ||
+      (TR_CFG_SUCCESS != (cfg_rc= tr_cfg_parse_helper(cfg_mgr->new, tr_cfg_parse_local_orgs, n_files, jcfgs, NULL))) ||
+      (TR_CFG_SUCCESS != (cfg_rc= tr_cfg_parse_helper(cfg_mgr->new, tr_cfg_parse_peer_orgs, n_files, jcfgs, NULL))) ||
+      (TR_CFG_SUCCESS != (cfg_rc= tr_cfg_parse_helper(cfg_mgr->new, tr_cfg_parse_default_servers, n_files, jcfgs,
+                                                      NULL))) ||
+      (TR_CFG_SUCCESS != (cfg_rc= tr_cfg_parse_helper(cfg_mgr->new, tr_cfg_parse_comms, n_files, jcfgs, NULL))))
     goto cleanup; /* cfg_rc was set above */
 
   /* make sure we got a complete, consistent configuration */
diff --git a/common/tr_config_internal.c b/common/tr_config_internal.c
new file mode 100644 (file)
index 0000000..82a57e2
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2012-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 <jansson.h>
+#include <tr_debug.h>
+#include <tr_config.h>
+#include <tr_cfgwatch.h>
+
+/**
+ * Parse an unsigned integer
+ *
+ * If the key does not exist in the src object, returns success but does fill in *dest.
+ *
+ * @param src JSON object to pull a value from
+ * @param key key to pull
+ * @param dest (output) pointer to an allocated unsigned integer
+ * @return TR_CFG_SUCCESS or an error code
+ */
+static TR_CFG_RC tr_cfg_parse_unsigned(json_t *src, const char *key, unsigned int *dest)
+{
+  json_t *jtmp;
+
+  /* Validate parameters */
+  if ((src == NULL) || (key == NULL) || (dest == NULL))
+    return TR_CFG_BAD_PARAMS;
+
+  /* See if we have a value for this key; do nothing if not */
+  jtmp = json_object_get(src, key);
+  if (jtmp) {
+    if (json_is_number(jtmp)) {
+      *dest = (unsigned int) json_integer_value(jtmp);
+    } else {
+      tr_debug("tr_cfg_parse_unsigned: Parsing error, %s is not a number.", key);
+      return TR_CFG_NOPARSE;
+    }
+  }
+
+  return TR_CFG_SUCCESS;
+}
+
+/**
+ * Parse a string
+ *
+ * If the key does not exist in the src object, returns success but does not allocate
+ * a return value in dest. Nulls the destination pointer if there is no return value.
+ *
+ * Return value is allocated in talloc's NULL context and must be freed with talloc_free()
+ * or put into a non-NULL context with talloc_steal()
+ *
+ * @param src JSON object to pull a value from
+ * @param key key to pull
+ * @param dest (output) pointer to a pointer that will hold the newly allocated return value
+ * @return TR_CFG_SUCCESS or an error code
+ */
+static TR_CFG_RC tr_cfg_parse_string(json_t *src, const char *key, const char **dest)
+{
+  json_t *jtmp;
+
+  /* Validate parameters */
+  if ((src == NULL) || (key == NULL) || (dest == NULL))
+    return TR_CFG_BAD_PARAMS;
+
+  /* See if we have a value for this key; do nothing if not */
+  jtmp = json_object_get(src, key);
+  if (!jtmp) {
+    *dest = NULL; /* No return value, null this out */
+  } else {
+    if (json_is_string(jtmp)) {
+      *dest = talloc_strdup(NULL, json_string_value(jtmp));
+    } else {
+      tr_debug("tr_cfg_parse_string: Parsing error, %s is not a string.", key);
+      return TR_CFG_NOPARSE;
+    }
+  }
+
+  return TR_CFG_SUCCESS;
+}
+
+/**
+ * Set default values for settings that have them
+ *
+ * @param cfg configuration structure to fill in, not null
+ */
+static void set_defaults(TR_CFG_INTERNAL *cfg)
+{
+  cfg->max_tree_depth = TR_DEFAULT_MAX_TREE_DEPTH;
+  cfg->tids_port = TR_DEFAULT_TIDS_PORT;
+  cfg->trps_port = TR_DEFAULT_TRPS_PORT;
+  cfg->cfg_poll_interval = TR_CFGWATCH_DEFAULT_POLL;
+  cfg->cfg_settling_time = TR_CFGWATCH_DEFAULT_SETTLE;
+  cfg->trp_connect_interval = TR_DEFAULT_TRP_CONNECT_INTERVAL;
+  cfg->trp_sweep_interval = TR_DEFAULT_TRP_SWEEP_INTERVAL;
+  cfg->trp_update_interval = TR_DEFAULT_TRP_UPDATE_INTERVAL;
+  cfg->tid_req_timeout = TR_DEFAULT_TID_REQ_TIMEOUT;
+  cfg->tid_resp_numer = TR_DEFAULT_TID_RESP_NUMER;
+  cfg->tid_resp_denom = TR_DEFAULT_TID_RESP_DENOM;
+  cfg->log_threshold = TR_DEFAULT_LOG_THRESHOLD;
+  cfg->console_threshold = TR_DEFAULT_CONSOLE_THRESHOLD;
+}
+
+/* Helper that checks return value of a parse fn and returns if it failed */
+#define NOPARSE_UNLESS(x)    \
+do {                         \
+  if ((x) != TR_CFG_SUCCESS) \
+    return TR_CFG_NOPARSE;   \
+} while(0)
+
+/**
+ * Parse internal configuration JSON
+ *
+ * @param trc configuration structure to fill in
+ * @param jint internal configuration JSON object
+ * @return TR_CFG_SUCCESS or an error code
+ */
+TR_CFG_RC tr_cfg_parse_internal(TR_CFG *trc, json_t *jint)
+{
+  json_t *jtmp = NULL;
+  const char *s = NULL;
+
+  if ((!trc) || (!jint))
+    return TR_CFG_BAD_PARAMS;
+
+  /* If we don't yet have an internal config, allocate one and set defaults. If it
+   * already exists, do not disturb existing settings. */
+  if (NULL == trc->internal) {
+    if (NULL == (trc->internal = talloc_zero(trc, TR_CFG_INTERNAL)))
+      return TR_CFG_NOMEM;
+    set_defaults(trc->internal); /* Install defaults for any unspecified settings */
+  }
+
+  NOPARSE_UNLESS(tr_cfg_parse_string(jint, "hostname", &(trc->internal->hostname)));
+  talloc_steal(trc->internal, trc->internal->hostname);
+
+  NOPARSE_UNLESS(tr_cfg_parse_unsigned(jint, "max_tree_depth",           &(trc->internal->max_tree_depth)));
+  NOPARSE_UNLESS(tr_cfg_parse_unsigned(jint, "tids_port",                &(trc->internal->tids_port)));
+  NOPARSE_UNLESS(tr_cfg_parse_unsigned(jint, "trps_port",                &(trc->internal->trps_port)));
+  NOPARSE_UNLESS(tr_cfg_parse_unsigned(jint, "cfg_poll_interval",        &(trc->internal->cfg_poll_interval)));
+  NOPARSE_UNLESS(tr_cfg_parse_unsigned(jint, "cfg_settling_time",        &(trc->internal->cfg_settling_time)));
+  NOPARSE_UNLESS(tr_cfg_parse_unsigned(jint, "trp_connect_interval",     &(trc->internal->trp_connect_interval)));
+  NOPARSE_UNLESS(tr_cfg_parse_unsigned(jint, "trp_sweep_interval",       &(trc->internal->trp_sweep_interval)));
+  NOPARSE_UNLESS(tr_cfg_parse_unsigned(jint, "trp_update_interval",      &(trc->internal->trp_update_interval)));
+  NOPARSE_UNLESS(tr_cfg_parse_unsigned(jint, "tid_request_timeout",      &(trc->internal->tid_req_timeout)));
+  NOPARSE_UNLESS(tr_cfg_parse_unsigned(jint, "tid_response_numerator",   &(trc->internal->tid_resp_numer)));
+  NOPARSE_UNLESS(tr_cfg_parse_unsigned(jint, "tid_response_denominator", &(trc->internal->tid_resp_denom)));
+
+  /* Parse the logging section */
+  if (NULL != (jtmp = json_object_get(jint, "logging"))) {
+    NOPARSE_UNLESS(tr_cfg_parse_string(jtmp, "log_threshold", &s));
+    if (s) {
+      trc->internal->log_threshold = str2sev(s);
+      talloc_free((void *) s);
+    }
+
+    NOPARSE_UNLESS(tr_cfg_parse_string(jtmp, "console_threshold", &s));
+    if (s) {
+      trc->internal->console_threshold = str2sev(s);
+      talloc_free((void *) s);
+    }
+  }
+
+  /* Parse the monitoring section */
+  if (NULL != (jtmp = json_object_get(jint, "monitoring"))) {
+    NOPARSE_UNLESS(tr_cfg_parse_unsigned(jtmp, "port", &(trc->internal->monitoring_port)));
+  }
+
+  tr_debug("tr_cfg_parse_internal: Internal config parsed.");
+  return TR_CFG_SUCCESS;
+}
index 7fa6876..39a13a9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, JANET(UK)
+ * Copyright (c) 2018, JANET(UK)
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  */
 
 #include <talloc.h>
+#include <gssapi.h>
+#include <string.h>
 
+#include <tr_msg.h>
+#include <tr_debug.h>
+#include <gsscon.h>
 #include <tr_gss.h>
 
-static int tr_gss_names_destructor(void *obj)
+/**
+ * tr_gss.c - GSS connection handler
+ *
+ * The chief entry point to this module is tr_gss_handle_connection(). This
+ * function accepts an incoming socket connection, runs the GSS authorization
+ * and authentication process, accepts a request, processes it, then sends
+ * the reply and returns without closing the connection.
+ *
+ * Callers need to provide two callbacks, each with a cookie for passing
+ * custom data to the callback.
+ *
+ *   * TR_GSS_AUTH_FN auth_cb: Authorization callback
+ *     - This callback is used during the GSS auth process to determine whether
+ *       a credential should be authorized to connect.
+ *
+ *   * TR_GSS_HANDLE_REQ_FN req_cb: Request handler callback
+ *     - After auth, this callback is passed the string form of the incoming request.
+ *       It should process the request and return a string form of the outgoing
+ *       response, if any.
+ */
+
+typedef struct tr_gss_cookie {
+  TR_GSS_AUTH_FN *auth_cb;
+  void *auth_cookie;
+} TR_GSS_COOKIE;
+
+static int tr_gss_auth_cb(gss_name_t clientName, gss_buffer_t displayName, void *data)
 {
-  TR_GSS_NAMES *gss_names=talloc_get_type_abort(obj, TR_GSS_NAMES);
-  int ii=0;
+  TR_GSS_COOKIE *cookie = talloc_get_type_abort(data, TR_GSS_COOKIE);
+  TR_NAME name ={(char *) displayName->value, (int) displayName->length};
+  int result=0;
 
-  for (ii=0; ii<TR_MAX_GSS_NAMES; ii++) {
-    if (gss_names->names[ii]!=NULL)
-      tr_free_name(gss_names->names[ii]);
+  if (cookie->auth_cb(clientName, &name, cookie->auth_cookie)) {
+    tr_debug("tr_gss_auth_cb: client '%.*s' denied authorization.", name.len, name.buf);
+    result=EACCES; /* denied */
   }
-  return 0;
+
+  return result;
 }
-TR_GSS_NAMES *tr_gss_names_new(TALLOC_CTX *mem_ctx)
+
+
+/**
+ * Handle GSS authentication and authorization
+ *
+ * @param conn connection file descriptor
+ * @param acceptor_name name of acceptor to present to initiator
+ * @param acceptor_realm realm of acceptor to present to initiator
+ * @param gssctx GSS context
+ * @param auth_cb authorization callback
+ * @param auth_cookie generic data to pass to the authorization callback
+ * @return 0 on successful auth, 1 on disallowed auth, -1 on error
+ */
+static int tr_gss_auth_connection(int conn,
+                                  const char *acceptor_name,
+                                  const char *acceptor_realm,
+                                  gss_ctx_id_t *gssctx,
+                                  TR_GSS_AUTH_FN auth_cb,
+                                  void *auth_cookie)
 {
-  TR_GSS_NAMES *gn=talloc(mem_ctx, TR_GSS_NAMES);
-  int ii=0;
+  int rc = 0;
+  int auth, autherr = 0;
+  gss_buffer_desc nameBuffer = {0, NULL};
+  TR_GSS_COOKIE *cookie = NULL;
 
-  if (gn!=NULL) {
-    for (ii=0; ii<TR_MAX_GSS_NAMES; ii++)
-      gn->names[ii]=NULL;
-    talloc_set_destructor((void *)gn, tr_gss_names_destructor);
+  nameBuffer.value = talloc_asprintf(NULL, "%s@%s", acceptor_name, acceptor_realm);
+  if (nameBuffer.value == NULL) {
+    tr_err("tr_gss_auth_connection: Error allocating acceptor name.");
+    return -1;
   }
-  return gn;
-}
+  nameBuffer.length = strlen(nameBuffer.value);
 
-void tr_gss_names_free(TR_GSS_NAMES *gn)
-{
-  talloc_free(gn);
+  /* Set up for the auth callback. There are two layers of callbacks here: we
+   * use our own, which handles gsscon interfacing and calls the auth_cb parameter
+   * to do the actual auth. Store the auth_cb information in a metacookie. */
+  cookie = talloc(NULL, TR_GSS_COOKIE);
+  cookie->auth_cb=auth_cb;
+  cookie->auth_cookie=auth_cookie;
+
+  /* Now call gsscon with *our* auth callback and cookie */
+  rc = gsscon_passive_authenticate(conn, nameBuffer, gssctx, tr_gss_auth_cb, cookie);
+  talloc_free(cookie);
+  talloc_free(nameBuffer.value);
+  if (rc) {
+    tr_debug("tr_gss_auth_connection: Error from gsscon_passive_authenticate(), rc = %d.", rc);
+    return -1;
+  }
+
+  rc = gsscon_authorize(*gssctx, &auth, &autherr);
+  if (rc) {
+    tr_debug("tr_gss_auth_connection: Error from gsscon_authorize, rc = %d, autherr = %d.",
+             rc, autherr);
+    return -1;
+  }
+
+  if (auth)
+    tr_debug("tr_gss_auth_connection: Connection authenticated, conn = %d.", conn);
+  else
+    tr_debug("tr_gss_auth_connection: Authentication failed, conn %d.", conn);
+
+  return !auth;
 }
 
-/* returns 0 on success */
-int tr_gss_names_add(TR_GSS_NAMES *gn, TR_NAME *new)
+/**
+ * Read a request from the GSS connection
+ *
+ * @param mem_ctx talloc context for the result
+ * @param conn file descriptor for the connection
+ * @param gssctx GSS context
+ * @return talloc'ed string containing the request, or null on error
+ */
+static char *tr_gss_read_req(TALLOC_CTX *mem_ctx, int conn, gss_ctx_id_t gssctx)
 {
-  int ii=0;
+  int err;
+  char *retval = NULL;
+  char *buf = NULL;
+  size_t buflen = 0;
 
-  for (ii=0; ii<TR_MAX_GSS_NAMES; ii++) {
-    if (gn->names[ii]==NULL)
-      break;
+  err = gsscon_read_encrypted_token(conn, gssctx, &buf, &buflen);
+  if (err || (buf == NULL)) {
+    if (buf)
+      free(buf);
+    tr_debug("tr_gss_read_req: Error reading from connection, rc=%d", err);
+    return NULL;
   }
-  if (ii!=TR_MAX_GSS_NAMES) {
-    gn->names[ii]=new;
-    return 0;
-  } else
-    return -1;
+
+  tr_debug("tr_gss_read_req: Read %u bytes.", (unsigned) buflen);
+
+  // get a talloc'ed version, guaranteed to have a null termination
+  retval = talloc_asprintf(mem_ctx, "%.*s", (int) buflen, buf);
+  free(buf);
+
+  return retval;
 }
 
-int tr_gss_names_matches(TR_GSS_NAMES *gn, TR_NAME *name)
+/**
+ * Write a response to the GSS connection
+ *
+ * @param conn file descriptor for the connection
+ * @param gssctx GSS context
+ * @param resp encoded response string to send
+ * @return 0 on success, -1 on error
+ */
+static int tr_gss_write_resp(int conn, gss_ctx_id_t gssctx, const char *resp)
 {
-  int ii=0;
-
-  if (!gn)
-    return 0;
+  int err = 0;
 
-  for (ii=0; ii<TR_MAX_GSS_NAMES; ii++) {
-    if ((gn->names[ii]!=NULL) &&
-        (0==tr_name_cmp(gn->names[ii], name)))
-      return 1;
+  /* Send the response over the connection */
+  err = gsscon_write_encrypted_token (conn, gssctx, resp, strlen(resp) + 1);
+  if (err) {
+    tr_debug("tr_gss_send_response: Error sending response over connection, rc=%d.", err);
+    return -1;
   }
   return 0;
 }
 
-/* iterators */
-TR_GSS_NAMES_ITER *tr_gss_names_iter_new(TALLOC_CTX *mem_ctx)
+/**
+ * Handle a request/response connection
+ *
+ * Authorizes/authenticates the connection, then reads a response, passes that to a
+ * callback to get a response, sends that, then returns.
+ *
+ * @param conn connection file descriptor
+ * @param acceptor_name acceptor name to present
+ * @param acceptor_realm acceptor realm to present
+ * @param auth_cb callback for authorization
+ * @param auth_cookie cookie for the auth_cb
+ * @param req_cb callback to handle the request and produce the response
+ * @param req_cookie cookie for the req_cb
+ */
+void tr_gss_handle_connection(int conn,
+                              const char *acceptor_name,
+                              const char *acceptor_realm,
+                              TR_GSS_AUTH_FN auth_cb,
+                              void *auth_cookie,
+                              TR_GSS_HANDLE_REQ_FN req_cb,
+                              void *req_cookie)
 {
-  TR_GSS_NAMES_ITER *iter=talloc(mem_ctx, TR_GSS_NAMES_ITER);
-  if (iter!=NULL) {
-    iter->gn=NULL;
-    iter->ii=0;
+  TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+  gss_ctx_id_t gssctx = GSS_C_NO_CONTEXT;
+  char *req_str = NULL;
+  char *resp_str = NULL;
+
+  if (tr_gss_auth_connection(conn,
+                             acceptor_name,
+                             acceptor_realm,
+                             &gssctx,
+                             auth_cb,
+                             auth_cookie)) {
+    tr_notice("tr_gss_handle_connection: Error authorizing connection.");
+    goto cleanup;
   }
-  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_debug("tr_gss_handle_connection: Connection authorized");
 
-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;
-}
+  // TODO: should there be a timeout on this?
+  while (1) {  /* continue until an error breaks us out */
+    // try to read a request
+    req_str = tr_gss_read_req(tmp_ctx, conn, gssctx);
 
-void tr_gss_names_iter_free(TR_GSS_NAMES_ITER *iter)
-{
-  talloc_free(iter);
+    if ( req_str == NULL) {
+      // an error occurred, give up
+      tr_notice("tr_gss_handle_connection: Error reading request");
+      goto cleanup;
+    } else if (strlen(req_str) > 0) {
+      // we got a request message, exit the loop and process it
+      break;
+    }
+
+    // no error, but no message, keep waiting for one
+    talloc_free(req_str); // this would be cleaned up anyway, but may as well free it
+  }
+
+  /* Hand off the request for processing and get the response */
+  resp_str = req_cb(tmp_ctx, req_str, req_cookie);
+
+  if (resp_str == NULL) {
+    // no response, clean up
+    goto cleanup;
+  }
+
+  // send the response
+  if (tr_gss_write_resp(conn, gssctx, resp_str)) {
+    tr_notice("tr_gss_handle_connection: Error writing response");
+  }
+
+cleanup:
+  talloc_free(tmp_ctx);
 }
diff --git a/common/tr_gss_names.c b/common/tr_gss_names.c
new file mode 100644 (file)
index 0000000..12941b3
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2016, 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_gss_names.h>
+
+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]);
+  }
+  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;
+    talloc_set_destructor((void *)gn, tr_gss_names_destructor);
+  }
+  return gn;
+}
+
+void tr_gss_names_free(TR_GSS_NAMES *gn)
+{
+  talloc_free(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;
+}
+
+int tr_gss_names_matches(TR_GSS_NAMES *gn, TR_NAME *name)
+{
+  int ii=0;
+
+  if (!gn)
+    return 0;
+
+  for (ii=0; ii<TR_MAX_GSS_NAMES; ii++) {
+    if ((gn->names[ii]!=NULL) &&
+        (0==tr_name_cmp(gn->names[ii], name)))
+      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);
+}
index 59a2efd..e0e406a 100644 (file)
@@ -1144,10 +1144,11 @@ cleanup:
   return req;
 }
 
-char *tr_msg_encode(TR_MSG *msg) 
+char *tr_msg_encode(TALLOC_CTX *mem_ctx, TR_MSG *msg)
 {
   json_t *jmsg=NULL;
   json_t *jmsg_type=NULL;
+  char *encoded_tmp=NULL;
   char *encoded=NULL;
   TID_RESP *tidresp=NULL;
   TID_REQ *tidreq=NULL;
@@ -1192,9 +1193,14 @@ char *tr_msg_encode(TR_MSG *msg)
       return NULL;
     }
 
-  encoded=json_dumps(jmsg, 0);
+  /* We should perhaps use json_set_alloc_funcs to automatically use talloc, but for
+   * now, we'll encode to a malloc'ed buffer, then copy that to a talloc'ed buffer. */
+  encoded_tmp=json_dumps(jmsg, 0);                // malloc'ed version
+  json_decref(jmsg);                              // free the JSON structure
+  encoded = talloc_strdup(mem_ctx, encoded_tmp);  // get the talloc'ed version
+  free(encoded_tmp);                              // free the malloc'ed version
+
   tr_debug("tr_msg_encode: outgoing msg=%s", encoded);
-  json_decref(jmsg);
   return encoded;
 }
 
index 4acdc4b..6d0880a 100644 (file)
@@ -36,7 +36,7 @@
 
 #include <tr.h>
 #include <tr_name_internal.h>
-#include <tr_gss.h>
+#include <tr_gss_names.h>
 #include <tr_config.h>
 #include <tr_rp.h>
 #include <tr_debug.h>
diff --git a/common/tr_socket.c b/common/tr_socket.c
new file mode 100644 (file)
index 0000000..313d931
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2016-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 <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <poll.h> // for nfds_t
+
+#include <tr_debug.h>
+#include <tr_socket.h>
+
+/**
+ * Open sockets on all interface addresses
+ *
+ * Uses getaddrinfo() to find all TCP addresses and opens sockets in
+ * non-blocking modes. Binds to most max_fd sockets and stores file descriptors
+ * in fd_out. Unused entries in fd_out are not modified. Returns the actual
+ * number of sockets opened.
+ *
+ * @param port port to listen on
+ * @param fd_out output array, at least max_fd long
+ * @param max_fd maximum number of file descriptors to write
+ * @return number of file descriptors written into the output array
+ */
+nfds_t tr_sock_listen_all(unsigned int port, int *fd_out, nfds_t max_fd)
+{
+  int rc = 0;
+  int conn = -1;
+  int optval = 1;
+  int gai_retval = 0;
+  struct addrinfo *ai=NULL;
+  struct addrinfo *ai_head=NULL;
+  struct addrinfo hints={
+      .ai_flags=AI_PASSIVE,
+      .ai_family=AF_UNSPEC,
+      .ai_socktype=SOCK_STREAM,
+      .ai_protocol=IPPROTO_TCP
+  };
+  char *port_str=NULL;
+  nfds_t n_opened=0;
+
+  port_str=talloc_asprintf(NULL, "%d", port);
+  if (port_str==NULL) {
+    tr_err("tr_sock_listen_all: unable to allocate port");
+    return 0;
+  }
+
+  gai_retval = getaddrinfo(NULL, port_str, &hints, &ai_head);
+  talloc_free(port_str);
+  if (gai_retval != 0) {
+    tr_err("tr_sock_listen_all: getaddrinfo() failed (%s)", gai_strerror(gai_retval));
+    return 0;
+  }
+  tr_debug("tr_sock_listen_all: got address info");
+
+  /* TODO: listen on all ports - I don't recall what this means (jlr, 4/11/2018) */
+  for (ai=ai_head,n_opened=0; (ai!=NULL)&&(n_opened<max_fd); ai=ai->ai_next) {
+    if (0 > (conn = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))) {
+      tr_debug("tr_sock_listen_all: unable to open socket");
+      continue;
+    }
+
+    optval=1;
+    if (0!=setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)))
+      tr_debug("tids_listen: unable to set SO_REUSEADDR"); /* not fatal? */
+
+    if (ai->ai_family==AF_INET6) {
+      /* don't allow IPv4-mapped IPv6 addresses (per RFC4942, not sure
+       * if still relevant) */
+      if (0!=setsockopt(conn, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval))) {
+        tr_debug("tr_sock_listen_all: unable to set IPV6_V6ONLY, skipping interface");
+        close(conn);
+        continue;
+      }
+    }
+
+    rc=bind(conn, ai->ai_addr, ai->ai_addrlen);
+    if (rc<0) {
+      tr_debug("tr_sock_listen_all: unable to bind to socket");
+      close(conn);
+      continue;
+    }
+
+    if (0>listen(conn, 512)) {
+      tr_debug("tr_sock_listen_all: unable to listen on bound socket");
+      close(conn);
+      continue;
+    }
+
+    /* ok, this one worked. Save it */
+    fd_out[n_opened++]=conn;
+  }
+  freeaddrinfo(ai_head);
+
+  if (n_opened==0) {
+    tr_debug("tr_sock_listen_all: no addresses available for listening.");
+    return 0;
+  }
+
+  tr_debug("tr_sock_listen_all: monitoring interface listening on port %d on %d socket%s",
+           port,
+           n_opened,
+           (n_opened==1)?"":"s");
+
+  return n_opened;
+}
+
index 58cfdee..171ce18 100644 (file)
 #define TRUST_ROUTER_MON_REQ_H
 
 #include <talloc.h>
+#include <stdint.h>
 #include <jansson.h>
 #include <gmodule.h>
+#include <trp_internal.h>
+#include <tr_gss_names.h>
 #include <tr_name_internal.h>
+#include <gssapi.h>
 
 /* Typedefs */
 typedef struct mon_req MON_REQ;
@@ -53,6 +57,10 @@ typedef enum mon_opt_type MON_OPT_TYPE;
 
 typedef enum mon_rc MON_RC;
 
+typedef struct mons_instance MONS_INSTANCE;
+
+typedef int (MONS_REQ_FUNC)(MONS_INSTANCE *, MON_REQ *, MON_RESP *, void *);
+typedef int (MONS_AUTH_FUNC)(gss_name_t client_name, TR_NAME *display_name, void *cookie);
 
 /* Struct and enum definitions */
 enum mon_rc {
@@ -108,6 +116,18 @@ struct mon_resp {
   json_t *payload;
 };
 
+/* Monitoring server instance */
+struct mons_instance {
+  const char *hostname;
+  unsigned int port;
+  TR_GSS_NAMES *authorized_gss_names;
+  TIDS_INSTANCE *tids;
+  TRPS_INSTANCE *trps;
+  MONS_REQ_FUNC *req_handler;
+  MONS_AUTH_FUNC *auth_handler;
+  void *cookie;
+};
+
 /* Prototypes */
 /* tr_mon.c */
 const char *mon_cmd_to_string(MON_CMD cmd);
@@ -139,4 +159,10 @@ void mon_resp_free(MON_RESP *resp);
 /* mon_resp_encode.c */
 json_t *mon_resp_encode(MON_RESP *resp);
 
+/* mons.c */
+MONS_INSTANCE *mons_new(TALLOC_CTX *mem_ctx);
+int mons_get_listener(MONS_INSTANCE *mons, MONS_REQ_FUNC *req_handler, MONS_AUTH_FUNC *auth_handler, const char *hostname,
+                      unsigned int port, void *cookie, int *fd_out, size_t max_fd);
+int mons_accept(MONS_INSTANCE *mons, int listen);
+
 #endif //TRUST_ROUTER_MON_REQ_H
index f02c4d1..c5ecdc8 100644 (file)
@@ -97,7 +97,7 @@ struct tids_instance {
   TIDS_REQ_FUNC *req_handler;
   tids_auth_func *auth_handler;
   void *cookie;
-  uint16_t tids_port;
+  unsigned int tids_port;
   TR_NAME *gss_name;           /* GSS name client used for authentication */
 };
 
@@ -115,6 +115,7 @@ TID_SRVR_BLK *tid_srvr_blk_add_func(TID_SRVR_BLK *head, TID_SRVR_BLK *new);
 #define tid_srvr_blk_add(head, new) ((head)=tid_srvr_blk_add_func((head),(new)))
 void tid_srvr_blk_set_path(TID_SRVR_BLK *block, TID_PATH *path);
 
+TID_RC tid_resp_cpy(TID_RESP *dst, TID_RESP *src);
 void tid_resp_set_cons(TID_RESP *resp, TR_CONSTRAINT_SET *cons);
 void tid_resp_set_error_path(TID_RESP *resp, json_t *ep);
 
index 89fd328..aaf016b 100644 (file)
@@ -73,6 +73,7 @@ typedef struct tr_cfg_internal {
   unsigned int max_tree_depth;
   unsigned int tids_port;
   unsigned int trps_port;
+  unsigned int monitoring_port;
   const char *hostname;
   int log_threshold;
   int console_threshold;
@@ -118,4 +119,7 @@ void tr_print_comm_rps(TR_COMM_TABLE *ctab, TR_COMM *comm);
 TR_IDP_REALM *tr_cfg_find_idp (TR_CFG *cfg, TR_NAME *idp_id, TR_CFG_RC *rc);
 TR_RP_CLIENT *tr_cfg_find_rp (TR_CFG *cfg, TR_NAME *rp_gss, TR_CFG_RC *rc);
 
+/* tr_config_internal.c */
+TR_CFG_RC tr_cfg_parse_internal(TR_CFG *trc, json_t *jint);
+
 #endif
index dc93860..55cc272 100644 (file)
@@ -41,7 +41,7 @@
 
 /* struct for hanging on to a socket listener event */
 struct tr_socket_event {
-  size_t n_sock_fd; /* how many of those are filled in? */
+  int n_sock_fd; /* how many of those are filled in? */
   int sock_fd[TR_MAX_SOCKETS]; /* the fd for the socket */
   struct event *ev[TR_MAX_SOCKETS]; /* its events */
 };
index 676c8e4..30abc6d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, JANET(UK)
+ * Copyright (c) 2018, JANET(UK)
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  *
  */
 
-#ifndef __TR_GSS_H__
-#define __TR_GSS_H__
+#ifndef TRUST_ROUTER_TR_GSS_H
+#define TRUST_ROUTER_TR_GSS_H
 
-#include <talloc.h>
-#include <tr_name_internal.h>
+#include <tr_msg.h>
 
-#define TR_MAX_GSS_NAMES 5
+typedef int (TR_GSS_AUTH_FN)(gss_name_t, TR_NAME *, void *);
+typedef char *(TR_GSS_HANDLE_REQ_FN)(TALLOC_CTX *, const char *, void *);
 
-typedef struct tr_gss_names {
-  TR_NAME *names[TR_MAX_GSS_NAMES];
-} TR_GSS_NAMES;
+void tr_gss_handle_connection(int conn, const char *acceptor_name, const char *acceptor_realm, TR_GSS_AUTH_FN auth_cb,
+                              void *auth_cookie, TR_GSS_HANDLE_REQ_FN req_cb, void *req_cookie);
 
-typedef struct tr_gss_names_iter {
-  TR_GSS_NAMES *gn;
-  int ii; /* which entry did we last output? */
-} TR_GSS_NAMES_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);
-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);
-
-#endif /* __TR_GSS_H__ */
+#endif //TRUST_ROUTER_TR_GSS_H
diff --git a/include/tr_gss_names.h b/include/tr_gss_names.h
new file mode 100644 (file)
index 0000000..676c8e4
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016, 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 __TR_GSS_H__
+#define __TR_GSS_H__
+
+#include <talloc.h>
+#include <tr_name_internal.h>
+
+#define TR_MAX_GSS_NAMES 5
+
+typedef struct tr_gss_names {
+  TR_NAME *names[TR_MAX_GSS_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;
+
+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);
+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);
+
+#endif /* __TR_GSS_H__ */
diff --git a/include/tr_mon.h b/include/tr_mon.h
new file mode 100644 (file)
index 0000000..e956db2
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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 TR_MON_H
+#define TR_MON_H
+
+#include <tr_event.h>
+#include <tr_config.h>
+#include <mon_internal.h>
+
+int tr_mons_event_init(struct event_base *base,
+                       MONS_INSTANCE *mons,
+                       TR_CFG_MGR *cfg_mgr,
+                       struct tr_socket_event *mons_ev);
+
+#endif /* TR_MON_H */
index e10fd1a..59b7cf7 100644 (file)
@@ -68,7 +68,7 @@ void tr_msg_set_trp_req(TR_MSG *msg, TRP_REQ *req);
 
 
 /* Encoders/Decoders */
-char *tr_msg_encode(TR_MSG *msg);
+char *tr_msg_encode(TALLOC_CTX *mem_ctx, TR_MSG *msg);
 TR_MSG *tr_msg_decode(const char *jmsg, size_t len);
 void tr_msg_free_encoded(char *jmsg);
 void tr_msg_free_decoded(TR_MSG *msg);
index fa6b84e..a9e56df 100644 (file)
@@ -37,7 +37,7 @@
 
 #include <talloc.h>
 
-#include <tr_gss.h>
+#include <tr_gss_names.h>
 #include <tr_filter.h>
 
 typedef struct tr_rp_client {
diff --git a/include/tr_socket.h b/include/tr_socket.h
new file mode 100644 (file)
index 0000000..064c6fc
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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_SOCKET_H
+#define TRUST_ROUTER_TR_SOCKET_H
+
+#include <stdlib.h>
+#include <poll.h> // for nfds_t
+
+nfds_t tr_sock_listen_all(unsigned int port, int *fd_out, nfds_t max_fd);
+
+#endif //TRUST_ROUTER_TR_SOCKET_H
index 297295f..80c9a61 100644 (file)
@@ -44,6 +44,7 @@
 #include <tr_config.h>
 #include <tr_cfgwatch.h>
 #include <tr_event.h>
+#include <mon_internal.h>
 
 typedef struct tr_trps_events {
   struct event *trps_ev;
@@ -59,6 +60,7 @@ struct tr_instance {
   TR_CFG_MGR *cfg_mgr;
   TIDS_INSTANCE *tids;
   TRPS_INSTANCE *trps;
+  MONS_INSTANCE *mons;
   TR_CFGWATCH *cfgwatch;
   TR_TRPS_EVENTS *events;
 };
index 186f77a..0bf7c30 100644 (file)
@@ -39,7 +39,7 @@
 #include <talloc.h>
 
 #include <tr_name_internal.h>
-#include <tr_gss.h>
+#include <tr_gss_names.h>
 #include <trust_router/trp.h>
 #include <tr_filter.h>
 
index 8fc4267..91a9816 100644 (file)
@@ -44,6 +44,7 @@
 #include <trust_router/tr_versioning.h>
 
 #include <gssapi.h>
+#include <poll.h>
 
 
 #define TID_PORT       12309
@@ -151,13 +152,14 @@ TR_EXPORT DH *tidc_set_dh(TIDC_INSTANCE *, DH *);
 TR_EXPORT void tidc_destroy(TIDC_INSTANCE *tidc);
 
 /* TID Server functions, in tid/tids.c */
+TIDS_INSTANCE *tids_new(TALLOC_CTX *mem_ctx);
 TR_EXPORT TIDS_INSTANCE *tids_create (void);
 TR_EXPORT int tids_start (TIDS_INSTANCE *tids, TIDS_REQ_FUNC *req_handler,
                           tids_auth_func *auth_handler, const char *hostname,
                           unsigned int port, void *cookie);
-TR_EXPORT int tids_get_listener (TIDS_INSTANCE *tids, TIDS_REQ_FUNC *req_handler,
-                                 tids_auth_func *auth_handler, const char *hostname, 
-                                 unsigned int port, void *cookie, int *fd_out, size_t max_fd);
+TR_EXPORT nfds_t tids_get_listener(TIDS_INSTANCE *tids, TIDS_REQ_FUNC *req_handler,
+                                   tids_auth_func *auth_handler, const char *hostname,
+                                   unsigned int port, void *cookie, int *fd_out, size_t max_fd);
 TR_EXPORT int tids_accept(TIDS_INSTANCE *tids, int listen);
 TR_EXPORT int tids_send_response (TIDS_INSTANCE *tids, TID_REQ *req, TID_RESP *resp);
 TR_EXPORT int tids_send_err_response (TIDS_INSTANCE *tids, TID_REQ *req, const char *err_msg);
diff --git a/mon/mons.c b/mon/mons.c
new file mode 100644 (file)
index 0000000..d79cbcb
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * 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 <fcntl.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include <tr.h>
+#include <tr_debug.h>
+#include <mon_internal.h>
+#include <tr_socket.h>
+#include <sys/wait.h>
+#include <tr_gss.h>
+
+/**
+ * Allocate a new MONS_INSTANCE
+ *
+ * @param mem_ctx talloc context for allocation
+ * @return new MONS_INSTANCE or null on failure
+ */
+MONS_INSTANCE *mons_new(TALLOC_CTX *mem_ctx)
+{
+  MONS_INSTANCE *mons = talloc(mem_ctx, MONS_INSTANCE);
+
+  if (mons) {
+    mons->hostname = NULL;
+    mons->port = 0;
+    mons->tids = NULL;
+    mons->trps = NULL;
+    mons->req_handler = NULL;
+    mons->auth_handler = NULL;
+    mons->cookie = NULL;
+    mons->authorized_gss_names = tr_gss_names_new(mons);
+    if (mons->authorized_gss_names == NULL) {
+      talloc_free(mons);
+      mons = NULL;
+    }
+  }
+  return mons;
+}
+
+/**
+ * Callback to process a request and produce a response
+ *
+ * @param req_str JSON-encoded request
+ * @param data pointer to a MONS_INSTANCE
+ * @return pointer to the response string or null to send no response
+ */
+static char *mons_req_cb(TALLOC_CTX *mem_ctx, const char *req_str, void *data)
+{
+  return "This is a response.";
+}
+
+/**
+ * Create a listener for monitoring requests
+ *
+ * Accept connections with mons_accept()
+ *
+ * @param mons monitoring server instance
+ * @param req_handler
+ * @param auth_handler
+ * @param hostname
+ * @param port
+ * @param cookie
+ * @param fd_out
+ * @param max_fd
+ * @return
+ */
+int mons_get_listener(MONS_INSTANCE *mons, MONS_REQ_FUNC *req_handler, MONS_AUTH_FUNC *auth_handler, const char *hostname,
+                      unsigned int port, void *cookie, int *fd_out, size_t max_fd)
+{
+  size_t n_fd=0;
+  size_t ii=0;
+
+  mons->port = port;
+  n_fd = tr_sock_listen_all(port, fd_out, max_fd);
+  if (n_fd<=0)
+    tr_err("mons_get_listener: Error opening port %d");
+  else {
+    /* opening port succeeded */
+    tr_info("mons_get_listener: Opened port %d.", port);
+
+    /* make this socket non-blocking */
+    for (ii=0; ii<n_fd; ii++) {
+      if (0 != fcntl(fd_out[ii], F_SETFL, O_NONBLOCK)) {
+        tr_err("mons_get_listener: Error setting O_NONBLOCK.");
+        for (ii=0; ii<n_fd; ii++) {
+          close(fd_out[ii]);
+          fd_out[ii]=-1;
+        }
+        n_fd=0;
+        break;
+      }
+    }
+  }
+
+  if (n_fd>0) {
+    /* store the caller's request handler & cookie */
+    mons->req_handler = req_handler;
+    mons->auth_handler = auth_handler;
+    mons->hostname = hostname;
+    mons->cookie = cookie;
+  }
+
+  return (int) n_fd;
+}
+
+/**
+ * Accept and process a connection on a port opened with mons_get_listener()
+ *
+ * @param mons monitoring interface instance
+ * @param listen FD of the connection socket
+ * @return 0 on success
+ */
+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()");
+    return 1;
+  }
+
+  if (0 > (pid = fork())) {
+    perror("Error on fork()");
+    return 1;
+  }
+
+  if (pid == 0) {
+    close(listen);
+    tr_gss_handle_connection(conn,
+                             "trustmonitor", mons->hostname, /* acceptor name */
+                             mons->auth_handler, mons->cookie, /* auth callback and cookie */
+                             mons_req_cb, mons /* req callback and cookie */
+    );
+    close(conn);
+    exit(0); /* exit to kill forked child process */
+  } else {
+    close(conn);
+  }
+
+  /* clean up any processes that have completed */
+  while (waitpid(-1, 0, WNOHANG) > 0);
+
+  return 0;
+}
index e75571b..dbbc906 100644 (file)
@@ -80,6 +80,13 @@ void tid_resp_free(TID_RESP *resp)
     talloc_free(resp);
 }
 
+/**
+ * Allocate a new copy of a TID_RESP
+ *
+ * @param mem_ctx
+ * @param resp
+ * @return
+ */
 TID_RESP *tid_resp_dup(TALLOC_CTX *mem_ctx, TID_RESP *resp)
 {
   TID_RESP *newresp=NULL;
@@ -90,19 +97,38 @@ TID_RESP *tid_resp_dup(TALLOC_CTX *mem_ctx, TID_RESP *resp)
   newresp=tid_resp_new(mem_ctx);
 
   if (NULL!=newresp) {
-    newresp->result=resp->result;
-    newresp->err_msg=tr_dup_name(resp->err_msg);
-    newresp->rp_realm=tr_dup_name(resp->rp_realm);
-    newresp->realm=tr_dup_name(resp->realm);
-    newresp->comm=tr_dup_name(resp->comm);
-    newresp->orig_coi=tr_dup_name(resp->orig_coi);
-    newresp->servers=tid_srvr_blk_dup(newresp, resp->servers);
-    tid_resp_set_cons(newresp, resp->cons);
-    tid_resp_set_error_path(newresp, resp->error_path);
+    tid_resp_cpy(newresp, resp);
   }
   return newresp;
 }
 
+/**
+ * Copy contents of one TID_RESP to an existing TID_RESP
+ *
+ * @param dst
+ * @param src
+ * @return TID_SUCCESS on success, error code on error
+ */
+TID_RC tid_resp_cpy(TID_RESP *dst, TID_RESP *src)
+{
+  tid_resp_set_result(dst, tid_resp_get_result(src));
+  tid_resp_set_err_msg(dst,
+                       tr_dup_name(tid_resp_get_err_msg(src)));
+  tid_resp_set_rp_realm(dst,
+                        tr_dup_name(tid_resp_get_rp_realm(src)));
+  tid_resp_set_realm(dst,
+                     tr_dup_name(tid_resp_get_realm(src)));
+  tid_resp_set_comm(dst,
+                    tr_dup_name(tid_resp_get_comm(src)));
+  tid_resp_set_cons(dst, src->cons);
+  tid_resp_set_orig_coi(dst,
+                        tr_dup_name(tid_resp_get_orig_coi(src)));
+  dst->servers = tid_srvr_blk_dup(dst, src->servers);
+  tid_resp_set_error_path(dst, src->error_path);
+
+  return TID_SUCCESS;
+}
+
 TR_EXPORT int tid_resp_get_result(TID_RESP *resp)
 {
   return(resp->result);
index d724322..648107a 100644 (file)
@@ -157,7 +157,7 @@ int tidc_fwd_request(TIDC_INSTANCE *tidc,
 
 
   /* Encode the request into a json string */
-  if (!(req_buf = tr_msg_encode(msg))) {
+  if (!(req_buf = tr_msg_encode(NULL, msg))) {
     tr_err("tidc_fwd_request: Error encoding TID request.\n");
     goto error;
   }
index c1c9bcb..4abc6ca 100644 (file)
  *
  */
 
-#include <assert.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <string.h>
 #include <stdio.h>
-#include <errno.h>
 #include <sys/socket.h>
 #include <sys/wait.h>
-#include <netinet/in.h>
 #include <jansson.h>
 #include <talloc.h>
 #include <poll.h>
 #include <gsscon.h>
 #include <tr_debug.h>
 #include <tr_msg.h>
+#include <tr_socket.h>
+#include <tr_gss.h>
+#include <tr_event.h>
 
-static TID_RESP *tids_create_response (TIDS_INSTANCE *tids, TID_REQ *req) 
+/**
+ * Create a response with minimal fields filled in
+ *
+ * @param mem_ctx talloc context for the return value
+ * @param req request to respond to
+ * @return new response structure allocated in the mem_ctx context
+ */
+static TID_RESP *tids_create_response(TALLOC_CTX *mem_ctx, TID_REQ *req)
 {
   TID_RESP *resp=NULL;
   int success=0;
 
-  if (NULL == (resp = tid_resp_new(req))) {
+  if (NULL == (resp = tid_resp_new(mem_ctx))) {
     tr_crit("tids_create_response: Error allocating response structure.");
     return NULL;
   }
@@ -84,250 +91,137 @@ cleanup:
   return resp;
 }
 
-static int tids_listen(TIDS_INSTANCE *tids, int port, int *fd_out, size_t max_fd) 
-{
-  int rc = 0;
-  int conn = -1;
-  int optval = 1;
-  struct addrinfo *ai=NULL;
-  struct addrinfo *ai_head=NULL;
-  struct addrinfo hints={.ai_flags=AI_PASSIVE,
-                         .ai_family=AF_UNSPEC,
-                         .ai_socktype=SOCK_STREAM,
-                         .ai_protocol=IPPROTO_TCP};
-  char *port_str=NULL;
-  size_t n_opened=0;
-
-  tr_debug("tids_listen: started!");
-  port_str=talloc_asprintf(NULL, "%d", port);
-  if (port_str==NULL) {
-    tr_debug("tids_listen: unable to allocate port.");
-    return -1;
-  }
-
-  tr_debug("getaddrinfo()=%d", getaddrinfo(NULL, port_str, &hints, &ai_head));
-  talloc_free(port_str);
-  tr_debug("tids_listen: got address info");
-
-  /* TODO: listen on all ports */
-  for (ai=ai_head,n_opened=0; (ai!=NULL)&&(n_opened<max_fd); ai=ai->ai_next) {
-    if (0 > (conn = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))) {
-      tr_debug("tids_listen: unable to open socket.");
-      continue;
-    }
-
-    optval=1;
-    if (0!=setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)))
-      tr_debug("tids_listen: unable to set SO_REUSEADDR."); /* not fatal? */
-
-    if (ai->ai_family==AF_INET6) {
-      /* don't allow IPv4-mapped IPv6 addresses (per RFC4942, not sure
-       * if still relevant) */
-      if (0!=setsockopt(conn, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval))) {
-        tr_debug("tids_listen: unable to set IPV6_V6ONLY. Skipping interface.");
-        close(conn);
-        continue;
-      }
-    }
-
-    rc=bind(conn, ai->ai_addr, ai->ai_addrlen);
-    if (rc<0) {
-      tr_debug("tids_listen: unable to bind to socket.");
-      close(conn);
-      continue;
-    }
-
-    if (0>listen(conn, 512)) {
-      tr_debug("tids_listen: unable to listen on bound socket.");
-      close(conn);
-      continue;
-    }
-
-    /* ok, this one worked. Save it */
-    fd_out[n_opened++]=conn;
-  }
-  freeaddrinfo(ai_head);
-
-  if (n_opened==0) {
-    tr_debug("tids_listen: no addresses available for listening.");
-    return -1;
-  }
-
-  tr_debug("tids_listen: TRP Server listening on port %d on %d socket%s",
-           port,
-           n_opened,
-           (n_opened==1)?"":"s");
-
-  return n_opened;
-}
-
-/* returns EACCES if authorization is denied */
-static int tids_auth_cb(gss_name_t clientName, gss_buffer_t displayName,
-                       void *data)
-{
-  struct tids_instance *inst = (struct tids_instance *) data;
-  TR_NAME name ={(char *) displayName->value,
-                displayName->length};
-  int result=0;
-
-  if (0!=inst->auth_handler(clientName, &name, inst->cookie)) {
-    tr_debug("tids_auth_cb: client '%.*s' denied authorization.", name.len, name.buf);
-    result=EACCES; /* denied */
-  }
-
-  return result;
-}
-
-/* returns 0 on authorization success, 1 on failure, or -1 in case of error */
-static int tids_auth_connection (TIDS_INSTANCE *inst,
-                                int conn,
-                                 gss_ctx_id_t *gssctx)
-{
-  int rc = 0;
-  int auth, autherr = 0;
-  gss_buffer_desc nameBuffer = {0, NULL};
-  char *name = 0;
-  int nameLen = 0;
-
-  nameLen = asprintf(&name, "trustidentity@%s", inst->hostname);
-  nameBuffer.length = nameLen;
-  nameBuffer.value = name;
-
-  if (rc = gsscon_passive_authenticate(conn, nameBuffer, gssctx, tids_auth_cb, inst)) {
-    tr_debug("tids_auth_connection: Error from gsscon_passive_authenticate(), rc = %d.", rc);
-    free(name);
-    return -1;
-  }
-  free(name);
-  nameBuffer.value=NULL; nameBuffer.length=0;
-
-  if (rc = gsscon_authorize(*gssctx, &auth, &autherr)) {
-    tr_debug("tids_auth_connection: Error from gsscon_authorize, rc = %d, autherr = %d.", 
-           rc, autherr);
-    return -1;
-  }
-
-  if (auth)
-    tr_debug("tids_auth_connection: Connection authenticated, conn = %d.", conn);
-  else
-    tr_debug("tids_auth_connection: Authentication failed, conn %d.", conn);
-
-  return !auth;
-}
-
-static int tids_read_request (TIDS_INSTANCE *tids, int conn, gss_ctx_id_t *gssctx, TR_MSG **mreq)
-{
-  int err;
-  char *buf;
-  size_t buflen = 0;
-
-  if (err = gsscon_read_encrypted_token(conn, *gssctx, &buf, &buflen)) {
-    if (buf)
-      free(buf);
-    return -1;
-  }
-
-  tr_debug("tids_read_request():Request Received, %u bytes.", (unsigned) buflen);
-
-  /* Parse request */
-  if (NULL == ((*mreq) = tr_msg_decode(buf, buflen))) {
-    tr_debug("tids_read_request():Error decoding request.");
-    free (buf);
-    return -1;
-  }
-
-  /* If this isn't a TID Request, just drop it. */
-  if (TID_REQUEST != (*mreq)->msg_type) {
-    tr_debug("tids_read_request(): Not a TID Request, dropped.");
-    return -1;
-  }
-
-  free (buf);
-  return buflen;
-}
-
-static int tids_handle_request (TIDS_INSTANCE *tids, TR_MSG *mreq, TID_RESP *resp) 
+static int tids_handle_request(TIDS_INSTANCE *tids, TID_REQ *req, TID_RESP *resp)
 {
   int rc=-1;
 
   /* Check that this is a valid TID Request.  If not, send an error return. */
-  if ((!tr_msg_get_req(mreq)) ||
-      (!tr_msg_get_req(mreq)->rp_realm) ||
-      (!tr_msg_get_req(mreq)->realm) ||
-      (!tr_msg_get_req(mreq)->comm)) {
+  if ((!req) ||
+      (!(req->rp_realm)) ||
+      (!(req->realm)) ||
+      (!(req->comm))) {
     tr_notice("tids_handle_request(): Not a valid TID Request.");
-    resp->result = TID_ERROR;
-    resp->err_msg = tr_new_name("Bad request format");
+    tid_resp_set_result(resp, TID_ERROR);
+    tid_resp_set_err_msg(resp, tr_new_name("Bad request format"));
     return -1;
   }
 
   tr_debug("tids_handle_request: adding self to req path.");
-  tid_req_add_path(tr_msg_get_req(mreq), tids->hostname, tids->tids_port);
+  tid_req_add_path(req, tids->hostname, tids->tids_port);
   
   /* Call the caller's request handler */
   /* TBD -- Handle different error returns/msgs */
-  if (0 > (rc = (*tids->req_handler)(tids, tr_msg_get_req(mreq), resp, tids->cookie))) {
+  if (0 > (rc = (*tids->req_handler)(tids, req, resp, tids->cookie))) {
     /* set-up an error response */
     tr_debug("tids_handle_request: req_handler returned error.");
-    resp->result = TID_ERROR;
-    if (!resp->err_msg)        /* Use msg set by handler, if any */
-      resp->err_msg = tr_new_name("Internal processing error");
-  }
-  else {
+    tid_resp_set_result(resp, TID_ERROR);
+    if (!tid_resp_get_err_msg(resp))   /* Use msg set by handler, if any */
+      tid_resp_set_err_msg(resp, tr_new_name("Internal processing error"));
+  } else {
     /* set-up a success response */
     tr_debug("tids_handle_request: req_handler returned success.");
-    resp->result = TID_SUCCESS;
+    tid_resp_set_result(resp, TID_SUCCESS);
     resp->err_msg = NULL;      /* No error msg on successful return */
   }
     
   return rc;
 }
 
+/**
+ * Produces a JSON-encoded msg containing the TID response
+ *
+ * @param mem_ctx talloc context for the return value
+ * @param resp outgoing response
+ * @return JSON-encoded message containing the TID response
+ */
+static char *tids_encode_response(TALLOC_CTX *mem_ctx, TID_RESP *resp)
+{
+  TR_MSG mresp;
+  char *resp_buf = NULL;
+
+  /* Construct the response message */
+  mresp.msg_type = TID_RESPONSE;
+  tr_msg_set_resp(&mresp, resp);
+
+  /* Encode the message to JSON */
+  resp_buf = tr_msg_encode(mem_ctx, &mresp);
+  if (resp_buf == NULL) {
+    tr_err("tids_encode_response: Error encoding json response.");
+    return NULL;
+  }
+  tr_debug("tids_encode_response: Encoded response: %s", resp_buf);
+
+  /* Success */
+  return resp_buf;
+}
+
+/**
+ * Encode/send an error response
+ *
+ * Part of the public interface
+ *
+ * @param tids
+ * @param req
+ * @param err_msg
+ * @return
+ */
 int tids_send_err_response (TIDS_INSTANCE *tids, TID_REQ *req, const char *err_msg) {
   TID_RESP *resp = NULL;
   int rc = 0;
 
+  if ((!tids) || (!req) || (!err_msg)) {
+    tr_debug("tids_send_err_response: Invalid parameters.");
+    return -1;
+  }
+
   /* If we already sent a response, don't send another no matter what. */
   if (req->resp_sent)
     return 0;
 
-  if (NULL == (resp = tids_create_response(tids, req))) {
+  if (NULL == (resp = tids_create_response(req, req))) {
     tr_crit("tids_send_err_response: Can't create response.");
     return -1;
   }
-  
+
   /* mark this as an error response, and include the error message */
   resp->result = TID_ERROR;
   resp->err_msg = tr_new_name((char *)err_msg);
   resp->error_path = req->path;
 
   rc = tids_send_response(tids, req, resp);
-  
+
   tid_resp_free(resp);
   return rc;
 }
 
+/**
+ * Encode/send a response
+ *
+ * Part of the public interface
+ *
+ * @param tids not actually used, but kept for ABI compatibility
+ * @param req
+ * @param resp
+ * @return
+ */
 int tids_send_response (TIDS_INSTANCE *tids, TID_REQ *req, TID_RESP *resp)
 {
   int err;
-  TR_MSG mresp;
   char *resp_buf;
 
-  if ((!tids) || (!req) || (!resp))
+  if ((!tids) || (!req) || (!resp)) {
     tr_debug("tids_send_response: Invalid parameters.");
+    return -1;
+  }
 
   /* Never send a second response if we already sent one. */
   if (req->resp_sent)
     return 0;
 
-  mresp.msg_type = TID_RESPONSE;
-  tr_msg_set_resp(&mresp, resp);
-
-  if (NULL == (resp_buf = tr_msg_encode(&mresp))) {
-
+  resp_buf = tids_encode_response(NULL, NULL);
+  if (resp_buf == NULL) {
     tr_err("tids_send_response: Error encoding json response.");
     tr_audit_req(req);
-
     return -1;
   }
 
@@ -338,12 +232,11 @@ int tids_send_response (TIDS_INSTANCE *tids, TID_REQ *req, TID_RESP *resp)
   tr_audit_resp(resp);
 
   /* Send the response over the connection */
-  if (err = gsscon_write_encrypted_token (req->conn, req->gssctx, resp_buf, 
-                                         strlen(resp_buf) + 1)) {
+  err = gsscon_write_encrypted_token (req->conn, req->gssctx, resp_buf,
+                                            strlen(resp_buf) + 1);
+  if (err) {
     tr_notice("tids_send_response: Error sending response over connection.");
-
     tr_audit_req(req);
-
     return -1;
   }
 
@@ -355,83 +248,97 @@ int tids_send_response (TIDS_INSTANCE *tids, TID_REQ *req, TID_RESP *resp)
   return 0;
 }
 
-static void tids_handle_connection (TIDS_INSTANCE *tids, int conn)
+/**
+ * Callback to process a request and produce a response
+ *
+ * @param req_str JSON-encoded request
+ * @param data pointer to a TIDS_INSTANCE
+ * @return pointer to the response string or null to send no response
+ */
+static char *tids_req_cb(TALLOC_CTX *mem_ctx, const char *req_str, void *data)
 {
+  TIDS_INSTANCE *tids = talloc_get_type_abort(data, TIDS_INSTANCE);
   TR_MSG *mreq = NULL;
+  TID_REQ *req = NULL;
   TID_RESP *resp = NULL;
+  char *resp_str = NULL;
   int rc = 0;
-  gss_ctx_id_t gssctx = GSS_C_NO_CONTEXT;
 
-  if (tids_auth_connection(tids, conn, &gssctx)) {
-    tr_notice("tids_handle_connection: Error authorizing TID Server connection.");
-    close(conn);
-    return;
+  mreq = tr_msg_decode(req_str, strlen(req_str)); // allocates memory on success!
+  if (mreq == NULL) {
+    tr_debug("tids_req_cb: Error decoding request.");
+    return NULL;
   }
 
-  tr_debug("tids_handle_connection: Connection authorized!");
+  /* If this isn't a TID Request, just drop it. */
+  if (mreq->msg_type != TID_REQUEST) {
+    tr_msg_free_decoded(mreq);
+    tr_debug("tids_req_cb: Not a TID request, dropped.");
+    return NULL;
+  }
 
-  while (1) {  /* continue until an error breaks us out */
+  /* Get a handle on the request itself. Don't free req - it belongs to mreq */
+  req = tr_msg_get_req(mreq);
+
+  /* Allocate a response structure and populate common fields. The resp is in req's talloc context,
+   * which will be cleaned up when mreq is freed. */
+  resp = tids_create_response(req, req);
+  if (resp == NULL) {
+    /* If we were unable to create a response, we cannot reply. Log an
+     * error if we can, then drop the request. */
+    tr_msg_free_decoded(mreq);
+    tr_crit("tids_req_cb: Error creating response structure.");
+    return NULL;
+  }
 
-    if (0 > (rc = tids_read_request(tids, conn, &gssctx, &mreq))) {
-      tr_debug("tids_handle_connection: Error from tids_read_request(), rc = %d.", rc);
-      return;
-    } else if (0 == rc) {
-      continue;
-    }
+  /* Handle the request and fill in resp */
+  rc = tids_handle_request(tids, req, resp);
+  if (rc < 0) {
+    tr_debug("tids_req_cb: Error from tids_handle_request(), rc = %d.", rc);
+    /* Fall through, to send the response, either way */
+  }
 
-    /* Put connection information into the request structure */
-    tr_msg_get_req(mreq)->conn = conn;
-    tr_msg_get_req(mreq)->gssctx = gssctx;
-
-    /* Allocate a response structure and populate common fields */
-    if (NULL == (resp = tids_create_response (tids, tr_msg_get_req(mreq)))) {
-      tr_crit("tids_handle_connection: Error creating response structure.");
-      /* try to send an error */
-      tids_send_err_response(tids, tr_msg_get_req(mreq), "Error creating response.");
-      tr_msg_free_decoded(mreq);
-      return;
-    }
+  /* Convert the completed response into an encoded response */
+  resp_str = tids_encode_response(mem_ctx, resp);
 
-    if (0 > (rc = tids_handle_request(tids, mreq, resp))) {
-      tr_debug("tids_handle_connection: Error from tids_handle_request(), rc = %d.", rc);
-      /* Fall through, to send the response, either way */
-    }
+  /* Finished; free the request and return */
+  tr_msg_free_decoded(mreq); // this frees req and resp, too
+  return resp_str;
+}
 
-    if (0 > (rc = tids_send_response(tids, tr_msg_get_req(mreq), resp))) {
-      tr_debug("tids_handle_connection: Error from tids_send_response(), rc = %d.", rc);
-      /* if we didn't already send a response, try to send a generic error. */
-      if (!tr_msg_get_req(mreq)->resp_sent)
-        tids_send_err_response(tids, tr_msg_get_req(mreq), "Error sending response.");
-      /* Fall through to free the response, either way. */
-    }
-    
-    tr_msg_free_decoded(mreq); /* takes resp with it */
-    return;
-  } 
+TIDS_INSTANCE *tids_new(TALLOC_CTX *mem_ctx)
+{
+  return talloc_zero(mem_ctx, TIDS_INSTANCE);
 }
 
-TIDS_INSTANCE *tids_create (void)
+/**
+ * Create a new TIDS instance
+ *
+ * Deprecated: exists for ABI compatibility, but tids_new() should be used instead
+ *
+ */
+TIDS_INSTANCE *tids_create(void)
 {
   return talloc_zero(NULL, TIDS_INSTANCE);
 }
-
 /* Get a listener for tids requests, returns its socket fd. Accept
  * connections with tids_accept() */
-int tids_get_listener(TIDS_INSTANCE *tids, 
-                      TIDS_REQ_FUNC *req_handler,
-                      tids_auth_func *auth_handler,
-                      const char *hostname,
-                      unsigned int port,
-                      void *cookie,
-                      int *fd_out,
-                      size_t max_fd)
+nfds_t tids_get_listener(TIDS_INSTANCE *tids,
+                         TIDS_REQ_FUNC *req_handler,
+                         tids_auth_func *auth_handler,
+                         const char *hostname,
+                         unsigned int port,
+                         void *cookie,
+                         int *fd_out,
+                         size_t max_fd)
 {
-  size_t n_fd=0;
-  size_t ii=0;
+  nfds_t n_fd = 0;
+  nfds_t ii = 0;
 
   tids->tids_port = port;
-  n_fd=tids_listen(tids, port, fd_out, max_fd);
-  if (n_fd<=0)
+  n_fd = tr_sock_listen_all(port, fd_out, max_fd);
+
+  if (n_fd == 0)
     tr_err("tids_get_listener: Error opening port %d");
   else {
     /* opening port succeeded */
@@ -445,13 +352,13 @@ int tids_get_listener(TIDS_INSTANCE *tids,
           close(fd_out[ii]);
           fd_out[ii]=-1;
         }
-        n_fd=0;
+        n_fd = 0;
         break;
       }
     }
   }
 
-  if (n_fd>0) {
+  if (n_fd > 0) {
     /* store the caller's request handler & cookie */
     tids->req_handler = req_handler;
     tids->auth_handler = auth_handler;
@@ -459,7 +366,7 @@ int tids_get_listener(TIDS_INSTANCE *tids,
     tids->cookie = cookie;
   }
 
-  return n_fd;
+  return (int)n_fd;
 }
 
 /* Accept and process a connection on a port opened with tids_get_listener() */
@@ -480,7 +387,11 @@ int tids_accept(TIDS_INSTANCE *tids, int listen)
 
   if (pid == 0) {
     close(listen);
-    tids_handle_connection(tids, conn);
+    tr_gss_handle_connection(conn,
+                             "trustidentity", tids->hostname, /* acceptor name */
+                             tids->auth_handler, tids->cookie, /* auth callback and cookie */
+                             tids_req_cb, tids /* req callback and cookie */
+    );
     close(conn);
     exit(0); /* exit to kill forked child process */
   } else {
@@ -494,20 +405,19 @@ int tids_accept(TIDS_INSTANCE *tids, int listen)
 }
 
 /* Process tids requests forever. Should not return except on error. */
-#define MAX_SOCKETS 10
-int tids_start (TIDS_INSTANCE *tids, 
+int tids_start (TIDS_INSTANCE *tids,
                 TIDS_REQ_FUNC *req_handler,
                 tids_auth_func *auth_handler,
                 const char *hostname,
                 unsigned int port,
                 void *cookie)
 {
-  int fd[MAX_SOCKETS]={0};
-  size_t n_fd=0;
-  struct pollfd poll_fd[MAX_SOCKETS]={{0}};
+  int fd[TR_MAX_SOCKETS]={0};
+  nfds_t n_fd=0;
+  struct pollfd poll_fd[TR_MAX_SOCKETS]={{0}};
   int ii=0;
 
-  n_fd=tids_get_listener(tids, req_handler, auth_handler, hostname, port, cookie, fd, MAX_SOCKETS);
+  n_fd = tids_get_listener(tids, req_handler, auth_handler, hostname, port, cookie, fd, TR_MAX_SOCKETS);
   if (n_fd <= 0) {
     perror ("Error from tids_listen()");
     return 1;
@@ -551,7 +461,6 @@ int tids_start (TIDS_INSTANCE *tids,
 
   return 1;    /* should never get here, loops "forever" */
 }
-#undef MAX_SOCKETS
 
 void tids_destroy (TIDS_INSTANCE *tids)
 {
index 4f09d12..8c8202d 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <jansson.h>
 #include <argp.h>
 #include <event2/event.h>
 #include <talloc.h>
-#include <sys/time.h>
 #include <signal.h>
-#include <pthread.h>
 
 #include <tid_internal.h>
+#include <mon_internal.h>
+#include <tr_mon.h>
 #include <tr_tid.h>
 #include <tr_trp.h>
 #include <tr_config.h>
@@ -159,6 +158,7 @@ int main(int argc, char *argv[])
   struct cmdline_args opts;
   struct event_base *ev_base;
   struct tr_socket_event tids_ev = {0};
+  struct tr_socket_event mon_ev = {0};
   struct event *cfgwatch_ev;
 
   configure_signals();
@@ -199,11 +199,10 @@ int main(int argc, char *argv[])
   }
 
   /***** initialize the trust path query server instance *****/
-  if (NULL == (tr->tids = tids_create())) {
+  if (NULL == (tr->tids = tids_new(tr))) {
     tr_crit("Error initializing Trust Path Query Server instance.");
     return 1;
   }
-  talloc_steal(tr, tr->tids);
 
   /***** initialize the trust router protocol server instance *****/
   if (NULL == (tr->trps = trps_new(tr))) {
@@ -211,6 +210,15 @@ int main(int argc, char *argv[])
     return 1;
   }
 
+  /***** initialize the monitoring interface instance *****/
+  if (NULL == (tr->mons = mons_new(tr))) {
+    tr_crit("Error initializing monitoring interface instance.");
+    return 1;
+  }
+  /* Monitor our tids/trps instances */
+  tr->mons->tids = tr->tids;
+  tr->mons->trps = tr->trps;
+
   /***** process configuration *****/
   tr->cfgwatch=tr_cfgwatch_create(tr);
   if (tr->cfgwatch == NULL) {
@@ -244,7 +252,12 @@ int main(int argc, char *argv[])
     return 1;
   }
 
-  /*tr_status_event_init();*/ /* install status reporting events */
+  /* install monitoring interface events */
+  tr_debug("Initializing monitoring interface events.");
+  if (0 != tr_mons_event_init(ev_base, tr->mons, tr->cfg_mgr, &mon_ev)) {
+    tr_crit("Error initializing monitoring interface.");
+    return 1;
+  }
 
   /* install TID server events */
   tr_debug("Initializing TID server events.");
diff --git a/tr/tr_mon.c b/tr/tr_mon.c
new file mode 100644 (file)
index 0000000..8138198
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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_config.h>
+#include <tr_debug.h>
+#include <mon_internal.h>
+#include <tr_mon.h>
+
+/*
+ * Cookie for the event handling callback
+ */
+struct tr_mons_event_cookie {
+  MONS_INSTANCE *mons;
+  TR_CFG_MGR *cfg_mgr;
+};
+
+
+/**
+ * Callback to handle a triggered event
+ *
+ * @param listener file descriptor of the socket that triggered the event
+ * @param event libevent2 event
+ * @param arg pointer to our MONS_INSTANCE
+ */
+static void tr_mons_event_cb(int listener, short event, void *arg)
+{
+  MONS_INSTANCE *mons = talloc_get_type_abort(arg, MONS_INSTANCE);
+
+  // check that we were not accidentally triggered
+  if (0==(event & EV_READ))
+    tr_debug("tr_mons_event_cb: unexpected event on monitoring interface socket (event=0x%X)", event);
+  else
+    mons_accept(mons, listener);
+}
+
+
+/**
+ * Callback to handle an incoming monitoring request
+ *
+ * @param mons monitoring interface instance
+ * @param orig_req incoming request
+ * @param resp destination for outgoing response
+ * @param cookie_in cookie from the event handling system
+ * @return 0 on success
+ */
+static int tr_mons_req_handler(MONS_INSTANCE *mons,
+                               MON_REQ *orig_req,
+                               MON_RESP *resp,
+                               void *cookie_in)
+{
+  return -1;
+}
+
+/**
+ * Callback to authorize a GSS client
+ *
+ * @param client_name ?
+ * @param gss_name GSS name of credential attempting to authorize
+ * @param cookie_in event cookie
+ * @return 0 if authorization is successful, -1 if not
+ */
+static int tr_mons_auth_handler(gss_name_t client_name, TR_NAME *gss_name, void *cookie_in)
+{
+  struct tr_mons_event_cookie *cookie=talloc_get_type_abort(cookie_in, struct tr_mons_event_cookie);
+  MONS_INSTANCE *mons = cookie->mons;
+  TR_CFG_MGR *cfg_mgr = cookie->cfg_mgr;
+
+  if ((!client_name) || (!gss_name) || (!mons) || (!cfg_mgr)) {
+    tr_debug("tr_mons_gss_handler: Bad parameters.");
+    return -1;
+  }
+
+  /* Ensure at least one client exists using this GSS name */
+  if (! tr_gss_names_matches(mons->authorized_gss_names, gss_name)) {
+    tr_info("tr_mons_gss_handler: Unauthorized request from %.*s", gss_name->len, gss_name->buf);
+    return -1;
+  }
+
+  /* Credential was valid, authorize it */
+  tr_info("tr_mons_gss_handler: Authorized request from %.*s", gss_name->len, gss_name->buf);
+  return 0;
+}
+
+
+/*
+ *
+ * Get a listener for monitoring requests, returns its socket fd. Accept
+ * connections with tids_accept() */
+
+/**
+ * Configure the monitoring service instance and set up its event handler
+ *
+ * @param base libevent2 event base
+ * @param mons MONS_INSTANCE for this monitoring interface
+ * @param cfg_mgr configuration manager instance
+ * @param mons_ev monitoring interface event instance
+ * @return 0 on success, nonzero on failure.
+ * */
+int tr_mons_event_init(struct event_base *base,
+                       MONS_INSTANCE *mons,
+                       TR_CFG_MGR *cfg_mgr,
+                       struct tr_socket_event *mons_ev)
+{
+  TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+  struct tr_mons_event_cookie *cookie=NULL;
+  int retval=0;
+  int ii=0;
+
+  if (mons_ev == NULL) {
+    tr_debug("tr_mon_event_init: Null mons_ev.");
+    retval=1;
+    goto cleanup;
+  }
+
+  /* Create the cookie for callbacks. We'll put it in the mons context, so it will
+   * be cleaned up when mons is freed by talloc_free. */
+  cookie=talloc(tmp_ctx, struct tr_mons_event_cookie);
+  if (cookie == NULL) {
+    tr_debug("tr_mons_event_init: Unable to allocate cookie.");
+    retval=1;
+    goto cleanup;
+  }
+  cookie->mons=mons;
+  cookie->cfg_mgr=cfg_mgr;
+  talloc_steal(mons, cookie);
+
+  /* get a monitoring interface listener */
+  mons_ev->n_sock_fd = mons_get_listener(mons, tr_mons_req_handler,
+                                         tr_mons_auth_handler,
+                                         cfg_mgr->active->internal->hostname,
+                                         cfg_mgr->active->internal->monitoring_port,
+                                         (void *) cookie, mons_ev->sock_fd,
+                                         TR_MAX_SOCKETS);
+  if (mons_ev->n_sock_fd==0) {
+    tr_crit("Error opening monitoring interface socket.");
+    retval=1;
+    goto cleanup;
+  }
+
+  /* Set up events */
+  for (ii=0; ii<mons_ev->n_sock_fd; ii++) {
+    mons_ev->ev[ii]=event_new(base,
+                              mons_ev->sock_fd[ii],
+                              EV_READ|EV_PERSIST,
+                              tr_mons_event_cb,
+                              (void *)mons);
+    event_add(mons_ev->ev[ii], NULL);
+  }
+
+cleanup:
+  talloc_free(tmp_ctx);
+  return retval;
+}
index 0c69d55..89fe994 100644 (file)
@@ -230,6 +230,18 @@ static TID_RC tr_tids_merge_resps(TID_RESP *r1, TID_RESP *r2)
   return TID_SUCCESS;
 }
 
+/**
+ * Process a TID request
+ *
+ * Return value of -1 means to send a TID_ERROR response. Fill in resp->err_msg or it will
+ * be returned as a generic error.
+ *
+ * @param tids
+ * @param orig_req
+ * @param resp
+ * @param cookie_in
+ * @return
+ */
 static int tr_tids_req_handler(TIDS_INSTANCE *tids,
                                TID_REQ *orig_req, 
                                TID_RESP *resp,
@@ -280,14 +292,14 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
   /* Duplicate the request, so we can modify and forward it */
   if (NULL == (fwd_req=tid_dup_req(orig_req))) {
     tr_debug("tr_tids_req_handler: Unable to duplicate request.");
-    retval=-1;
+    retval=-1; /* response will be a generic internal error */
     goto cleanup;
   }
   talloc_steal(tmp_ctx, fwd_req);
 
   if (NULL == (cfg_comm=tr_comm_table_find_comm(cfg_mgr->active->ctable, orig_req->comm))) {
     tr_notice("tr_tids_req_hander: Request for unknown comm: %s.", orig_req->comm->buf);
-    tids_send_err_response(tids, orig_req, "Unknown community");
+    tid_resp_set_err_msg(resp, tr_new_name("Unknown community"));
     retval=-1;
     goto cleanup;
   }
@@ -300,7 +312,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
 
   if (!tids->gss_name) {
     tr_notice("tr_tids_req_handler: No GSS name for incoming request.");
-    tids_send_err_response(tids, orig_req, "No GSS name for request");
+    tid_resp_set_err_msg(resp, tr_new_name("No GSS name for request"));
     retval=-1;
     goto cleanup;
   }
@@ -312,7 +324,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
   target=tr_filter_target_tid_req(tmp_ctx, orig_req);
   if (target==NULL) {
     tr_crit("tid_req_handler: Unable to allocate filter target, cannot apply filter!");
-    tids_send_err_response(tids, orig_req, "Incoming TID request filter error");
+    tid_resp_set_err_msg(resp, tr_new_name("Incoming TID request filter error"));
     retval=-1;
     goto cleanup;
   }
@@ -342,7 +354,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
    * a default action of reject, so we don't have to check why we exited the loop. */
   if (oaction != TR_FILTER_ACTION_ACCEPT) {
     tr_notice("tr_tids_req_handler: Incoming TID request rejected by filter for GSS name", orig_req->rp_realm->buf);
-    tids_send_err_response(tids, orig_req, "Incoming TID request filter error");
+    tid_resp_set_err_msg(resp, tr_new_name("Incoming TID request filter error"));
     retval = -1;
     goto cleanup;
   }
@@ -350,7 +362,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
   /* Check that the rp_realm is a member of the community in the request */
   if (NULL == tr_comm_find_rp(cfg_mgr->active->ctable, cfg_comm, orig_req->rp_realm)) {
     tr_notice("tr_tids_req_handler: RP Realm (%s) not member of community (%s).", orig_req->rp_realm->buf, orig_req->comm->buf);
-    tids_send_err_response(tids, orig_req, "RP COI membership error");
+    tid_resp_set_err_msg(resp, tr_new_name("RP COI membership error"));
     retval=-1;
     goto cleanup;
   }
@@ -360,7 +372,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
     if (orig_req->orig_coi!=NULL) {
       tr_notice("tr_tids_req_handler: community %s is COI but COI to APC mapping already occurred. Dropping request.",
                orig_req->comm->buf);
-      tids_send_err_response(tids, orig_req, "Second COI to APC mapping would result, permitted only once.");
+      tid_resp_set_err_msg(resp, tr_new_name("Second COI to APC mapping would result, permitted only once."));
       retval=-1;
       goto cleanup;
     }
@@ -369,7 +381,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
     /* TBD -- In theory there can be more than one?  How would that work? */
     if ((!cfg_comm->apcs) || (!cfg_comm->apcs->id)) {
       tr_notice("No valid APC for COI %s.", orig_req->comm->buf);
-      tids_send_err_response(tids, orig_req, "No valid APC for community");
+      tid_resp_set_err_msg(resp, tr_new_name("No valid APC for community"));
       retval=-1;
       goto cleanup;
     }
@@ -378,7 +390,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
     /* Check that the APC is configured */
     if (NULL == (cfg_apc = tr_comm_table_find_comm(cfg_mgr->active->ctable, apc))) {
       tr_notice("tr_tids_req_hander: Request for unknown comm: %s.", apc->buf);
-      tids_send_err_response(tids, orig_req, "Unknown APC");
+      tid_resp_set_err_msg(resp, tr_new_name("Unknown APC"));
       retval=-1;
       goto cleanup;
     }
@@ -389,7 +401,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
     /* Check that rp_realm is a  member of this APC */
     if (NULL == (tr_comm_find_rp(cfg_mgr->active->ctable, cfg_apc, orig_req->rp_realm))) {
       tr_notice("tr_tids_req_hander: RP Realm (%s) not member of community (%s).", orig_req->rp_realm->buf, orig_req->comm->buf);
-      tids_send_err_response(tids, orig_req, "RP APC membership error");
+      tid_resp_set_err_msg(resp, tr_new_name("RP APC membership error"));
       retval=-1;
       goto cleanup;
     }
@@ -404,7 +416,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
     if (NULL == (aaa_servers = tr_default_server_lookup(cfg_mgr->active->default_servers,
                                                         orig_req->comm))) {
       tr_notice("tr_tids_req_handler: No default AAA servers, discarded.");
-      tids_send_err_response(tids, orig_req, "No path to AAA Server(s) for realm");
+      tid_resp_set_err_msg(resp, tr_new_name("No path to AAA Server(s) for realm"));
       retval = -1;
       goto cleanup;
     }
@@ -427,13 +439,13 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
     /* Since we aren't defaulting, check idp coi and apc membership */
     if (NULL == (tr_comm_find_idp(cfg_mgr->active->ctable, cfg_comm, fwd_req->realm))) {
       tr_notice("tr_tids_req_handler: IDP Realm (%s) not member of community (%s).", orig_req->realm->buf, orig_req->comm->buf);
-      tids_send_err_response(tids, orig_req, "IDP community membership error");
+      tid_resp_set_err_msg(resp, tr_new_name("IDP community membership error"));
       retval=-1;
       goto cleanup;
     }
     if ( cfg_apc && (NULL == (tr_comm_find_idp(cfg_mgr->active->ctable, cfg_apc, fwd_req->realm)))) {
       tr_notice("tr_tids_req_handler: IDP Realm (%s) not member of APC (%s).", orig_req->realm->buf, orig_req->comm->buf);
-      tids_send_err_response(tids, orig_req, "IDP APC membership error");
+      tid_resp_set_err_msg(resp, tr_new_name("IDP APC membership error"));
       retval=-1;
       goto cleanup;
     }
@@ -443,7 +455,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
   if (NULL == aaa_servers) {
     tr_notice("tr_tids_req_handler: no route or AAA server for realm (%s) in community (%s).",
               orig_req->realm->buf, orig_req->comm->buf);
-    tids_send_err_response(tids, orig_req, "Missing trust route error");
+    tid_resp_set_err_msg(resp, tr_new_name("Missing trust route error"));
     retval = -1;
     goto cleanup;
   }
@@ -608,13 +620,19 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
   }
 
   if (n_responses==0) {
-    /* No requests succeeded. Forward an error if we got any error responses. */
+    /* No requests succeeded, so this will be an error */
+    retval = -1;
+
+    /* If we got any error responses, send an arbitrarily chosen one. */
     for (ii=0; ii<n_aaa; ii++) {
-      if (aaa_resp[ii]!=NULL)
-        tids_send_response(tids, orig_req, aaa_resp[ii]);
-      else
-        tids_send_err_response(tids, orig_req, "Unable to contact AAA server(s).");
+      if (aaa_resp[ii] != NULL) {
+        tid_resp_cpy(resp, aaa_resp[ii]);
+        goto cleanup;
+      }
     }
+    /* No error responses at all, so generate our own error. */
+    tid_resp_set_err_msg(resp, tr_new_name("Unable to contact AAA server(s)."));
+    goto cleanup;
   }
 
   /* success! */
@@ -676,7 +694,7 @@ int tr_tids_event_init(struct event_base *base,
   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
   struct tr_tids_event_cookie *cookie=NULL;
   int retval=0;
-  size_t ii=0;
+  int ii=0;
 
   if (tids_ev == NULL) {
     tr_debug("tr_tids_event_init: Null tids_ev.");
@@ -698,14 +716,14 @@ int tr_tids_event_init(struct event_base *base,
   talloc_steal(tids, cookie);
 
   /* get a tids listener */
-  tids_ev->n_sock_fd=tids_get_listener(tids,
-                                       tr_tids_req_handler,
-                                       tr_tids_gss_handler,
-                                       cfg_mgr->active->internal->hostname,
-                                       cfg_mgr->active->internal->tids_port,
-                                       (void *)cookie,
-                                       tids_ev->sock_fd,
-                                       TR_MAX_SOCKETS);
+  tids_ev->n_sock_fd = (int)tids_get_listener(tids,
+                                              tr_tids_req_handler,
+                                              tr_tids_gss_handler,
+                                              cfg_mgr->active->internal->hostname,
+                                              cfg_mgr->active->internal->tids_port,
+                                              (void *)cookie,
+                                              tids_ev->sock_fd,
+                                              TR_MAX_SOCKETS);
   if (tids_ev->n_sock_fd==0) {
     tr_crit("Error opening TID server socket.");
     retval=1;
index 298299e..8873720 100644 (file)
@@ -870,6 +870,10 @@ void tr_config_changed(TR_CFG *new_cfg, void *cookie)
   tr->cfgwatch->settling_time.tv_sec=new_cfg->internal->cfg_settling_time;
   tr->cfgwatch->settling_time.tv_usec=0;
 
+  /* These need to be updated */
+  tr->tids->hostname = new_cfg->internal->hostname;
+  tr->mons->hostname = new_cfg->internal->hostname;
+
   trps_set_connect_interval(trps, new_cfg->internal->trp_connect_interval);
   trps_set_update_interval(trps, new_cfg->internal->trp_update_interval);
   trps_set_sweep_interval(trps, new_cfg->internal->trp_sweep_interval);
index da39570..512e92e 100644 (file)
@@ -88,7 +88,7 @@ int main(int argc, const char *argv[])
 
   printf("\nEncoding...\n");
 
-  printf("Result: \n%s\n\n", tr_msg_encode(msg));
+  printf("Result: \n%s\n\n", tr_msg_encode(NULL, msg));
 
   talloc_report_full(main_ctx, stdout);
 
index e4824ea..568a445 100644 (file)
@@ -36,7 +36,7 @@
 #include <talloc.h>
 #include <assert.h>
 
-#include <tr_gss.h>
+#include <tr_gss_names.h>
 #include <trp_internal.h>
 #include <trp_ptable.h>
 
index e47846e..7552cff 100644 (file)
@@ -37,7 +37,7 @@
 
 #include <tr_name_internal.h>
 #include <trp_internal.h>
-#include <tr_gss.h>
+#include <tr_gss_names.h>
 #include <trp_ptable.h>
 #include <tr_debug.h>
 
index ebc365d..11c6ddf 100644 (file)
@@ -39,6 +39,7 @@
 #include <sys/time.h>
 #include <glib.h>
 #include <string.h>
+#include <poll.h> // for nfds_t
 
 #include <gsscon.h>
 #include <tr_comm.h>
 #include <tr_rp.h>
 #include <tr_name_internal.h>
 #include <trp_internal.h>
-#include <tr_gss.h>
+#include <tr_gss_names.h>
 #include <trp_ptable.h>
 #include <trp_rtable.h>
 #include <tr_debug.h>
 #include <tr_util.h>
+#include <tr_socket.h>
 
 static int trps_destructor(void *object)
 {
@@ -276,82 +278,6 @@ TRP_RC trps_send_msg(TRPS_INSTANCE *trps, TRP_PEER *peer, const char *msg)
   return rc;
 }
 
-/* Listens on all interfaces. Returns number of sockets opened. Their
- * descriptors are stored in *fd_out, which should point to space for
- * up to max_fd of them. */
-static size_t trps_listen(TRPS_INSTANCE *trps, int port, int *fd_out, size_t max_fd) 
-{
-  int rc = 0;
-  int conn = -1;
-  int optval=0;
-  struct addrinfo *ai=NULL;
-  struct addrinfo *ai_head=NULL;
-  struct addrinfo hints={.ai_flags=AI_PASSIVE,
-                         .ai_family=AF_UNSPEC,
-                         .ai_socktype=SOCK_STREAM,
-                         .ai_protocol=IPPROTO_TCP};
-  char *port_str=NULL;
-  size_t n_opened=0;
-
-  port_str=talloc_asprintf(NULL, "%d", port);
-  if (port_str==NULL) {
-    tr_debug("trps_listen: unable to allocate port.");
-    return -1;
-  }
-  getaddrinfo(NULL, port_str, &hints, &ai_head);
-  talloc_free(port_str);
-
-  for (ai=ai_head,n_opened=0; (ai!=NULL)&&(n_opened<max_fd); ai=ai->ai_next) {
-    if (0 > (conn = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))) {
-      tr_debug("trps_listen: unable to open socket.");
-      continue;
-    }
-
-    optval=1;
-    if (0!=setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)))
-      tr_debug("trps_listen: unable to set SO_REUSEADDR."); /* not fatal? */
-
-    if (ai->ai_family==AF_INET6) {
-      /* don't allow IPv4-mapped IPv6 addresses (per RFC4942, not sure
-       * if still relevant) */
-      if (0!=setsockopt(conn, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval))) {
-        tr_debug("trps_listen: unable to set IPV6_V6ONLY. Skipping interface.");
-        close(conn);
-        continue;
-      }
-    }
-
-    rc=bind(conn, ai->ai_addr, ai->ai_addrlen);
-    if (rc<0) {
-      tr_debug("trps_listen: unable to bind to socket.");
-      close(conn);
-      continue;
-    }
-
-    if (0>listen(conn, 512)) {
-      tr_debug("trps_listen: unable to listen on bound socket.");
-      close(conn);
-      continue;
-    }
-
-    /* ok, this one worked. Save it */
-    fd_out[n_opened++]=conn;
-  }
-  freeaddrinfo(ai_head);
-
-  if (n_opened==0) {
-    tr_debug("trps_listen: no addresses available for listening.");
-    return -1;
-  }
-  
-  tr_debug("trps_listen: TRP Server listening on port %d on %d socket%s",
-           port,
-           n_opened,
-           (n_opened==1)?"":"s");
-
-  return n_opened;
-}
-
 /* get the currently selected route if available */
 TRP_ROUTE *trps_get_route(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer)
 {
@@ -459,11 +385,12 @@ int trps_get_listener(TRPS_INSTANCE *trps,
                       int *fd_out,
                       size_t max_fd)
 {
-  size_t n_fd=0;
-  size_t ii=0;
+  nfds_t n_fd=0;
+  nfds_t ii=0;
+
+  n_fd = tr_sock_listen_all(port, fd_out, max_fd);
 
-  n_fd=trps_listen(trps, port, fd_out, max_fd);
-  if (n_fd==0)
+  if (n_fd == 0)
     tr_err("trps_get_listener: Error opening port %d.");
   else {
     /* opening port succeeded */
@@ -477,13 +404,13 @@ int trps_get_listener(TRPS_INSTANCE *trps,
           close(fd_out[ii]);
           fd_out[ii]=-1;
         }
-        n_fd=0;
+        n_fd = 0;
         break;
       }
     }
   }
 
-  if (n_fd>0) {
+  if (n_fd > 0) {
     /* store the caller's request handler & cookie */
     trps->msg_handler = msg_handler;
     trps->auth_handler = auth_handler;
@@ -492,7 +419,7 @@ int trps_get_listener(TRPS_INSTANCE *trps,
     trps->cookie = cookie;
   }
 
-  return n_fd;
+  return (int) n_fd;
 }
 
 TRP_RC trps_authorize_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *conn)
@@ -1821,7 +1748,7 @@ static TRP_RC trps_update_one_peer(TRPS_INSTANCE *trps,
         upd = (TRP_UPD *) g_ptr_array_index(updates, ii);
         /* now encode the update message */
         tr_msg_set_trp_upd(&msg, upd);
-        encoded = tr_msg_encode(&msg);
+        encoded = tr_msg_encode(NULL, &msg);
         if (encoded == NULL) {
           tr_err("trps_update_one_peer: error encoding update.");
           rc = TRP_ERROR;
@@ -2006,7 +1933,7 @@ TRP_RC trps_wildcard_route_req(TRPS_INSTANCE *trps, TR_NAME *peer_servicename)
   }
 
   tr_msg_set_trp_req(&msg, req);
-  encoded=tr_msg_encode(&msg);
+  encoded= tr_msg_encode(NULL, &msg);
   if (encoded==NULL) {
     tr_err("trps_wildcard_route_req: error encoding wildcard TRP request.");
     rc=TRP_ERROR;