--- /dev/null
+# Rudimentary CMakeLists.txt
+#
+# This is not used for real builds, it mostly exists to enable code navigation in
+# CLion. Real builds use autotools + make.
+#
+cmake_minimum_required(VERSION 3.6)
+project(trust_router)
+
+set(CMAKE_CXX_STANDARD 11)
+
+include(FindPkgConfig)
+pkg_check_modules(GLIB glib-2.0 REQUIRED)
+include_directories(${GLIB_INCLUDE_DIRS})
+
+include_directories(include)
+
+# Fill these in so CLion doesn't complain. The real versions are set in the Makefile
+add_definitions(-DPACKAGE_VERSION="built-with-cmake"
+ -DPACKAGE_NAME="Moonshot Trust Router"
+ -DPACKAGE_BUGREPORT="bugs@painless-security.com")
+
+set(SOURCE_FILES
+ common/tests/cfg_test.c
+ common/tests/commtest.c
+ common/tests/dh_test.c
+ common/tests/mq_test.c
+ common/tests/thread_test.c
+ common/jansson_iterators.h
+ common/t_constraint.c
+ common/tr_apc.c
+ common/tr_comm.c
+ common/tr_config.c
+ common/tr_constraint.c
+ common/tr_debug.c
+ common/tr_dh.c
+ common/tr_filter.c
+ common/tr_gss_names.c
+ common/tr_idp.c
+ common/tr_mq.c
+ common/tr_msg.c
+ common/tr_name.c
+ common/tr_rp.c
+ common/tr_util.c
+ gsscon/test/gsscon_client.c
+ gsscon/test/gsscon_server.c
+ gsscon/gsscon_active.c
+ gsscon/gsscon_common.c
+ gsscon/gsscon_passive.c
+ include/trust_router/tid.h
+ include/trust_router/tr_constraint.h
+ include/trust_router/tr_dh.h
+ include/trust_router/tr_name.h
+ include/trust_router/tr_versioning.h
+ include/trust_router/trp.h
+ include/gsscon.h
+ include/tid_internal.h
+ include/tr.h
+ include/tr_apc.h
+ include/tr_cfgwatch.h
+ include/tr_comm.h
+ include/tr_config.h
+ include/tr_debug.h
+ include/tr_event.h
+ include/tr_filter.h
+ include/tr_gss_names.h
+ include/tr_idp.h
+ include/tr_mq.h
+ include/tr_msg.h
+ include/tr_rp.h
+ include/tr_tid.h
+ include/tr_trp.h
+ include/tr_util.h
+ include/trp_internal.h
+ include/trp_ptable.h
+ include/trp_rtable.h
+ tid/example/tidc_main.c
+ tid/example/tids_main.c
+ tid/tid_req.c
+ tid/tid_resp.c
+ tid/tidc.c
+ tid/tids.c
+ tr/tr.c
+ tr/tr_cfgwatch.c
+ tr/tr_event.c
+ tr/tr_main.c
+ tr/tr_tid.c
+ tr/tr_trp.c
+ tr/trpc_main.c
+ trp/test/ptbl_test.c
+ trp/test/rtbl_test.c
+ trp/msgtst.c
+ trp/trp_conn.c
+ trp/trp_ptable.c
+ trp/trp_req.c
+ trp/trp_rtable.c
+ trp/trp_upd.c
+ trp/trpc.c
+ trp/trps.c include/tr_name_internal.h mon/mon_req.c mon/mon_req_encode.c mon/mon_req_decode.c
+ mon/mon_resp.c mon/mon_common.c mon/mon_resp_encode.c mon/mon_resp_decode.c tr/tr_mon.c mon/mons.c include/tr_socket.h common/tr_gss.c include/tr_gss.h common/tr_config_internal.c mon/mons_handlers.c include/mons_handlers.h tr/tr_tid_mons.c tr/tr_tid_mons.c trp/trp_route.c include/trp_route.h trp/trp_rtable_encoders.c trp/trp_route_encoders.c trp/trp_peer.c include/trp_peer.h trp/trp_peer_encoders.c trp/trp_ptable_encoders.c common/tr_idp_encoders.c common/tr_comm_encoders.c common/tr_rp_client.c include/tr_rp_client.h common/tr_rp_client_encoders.c common/tr_filter_encoders.c common/tr_config_encoders.c common/tr_config_filters.c common/tr_config_realms.c common/tr_config_rp_clients.c common/tr_config_orgs.c common/tr_config_comms.c)
+
+# Does not actually build!
+add_executable(trust_router ${SOURCE_FILES})
+
+add_executable(trmon mon/monc.c tr/trmon_main.c common/tr_gss_client.c include/tr_gss_client.h)
+
+# Test build targets - for debugging
+add_executable(test_mon_req_encode mon/mon_common.c mon/mon_req.c mon/tests/test_mon_req_encode.c mon/mon_req_encode.c)
+target_link_libraries(test_mon_req_encode jansson talloc glib-2.0)
+
+add_executable(test_mon_req_decode mon/mon_common.c mon/mon_req.c mon/tests/test_mon_req_decode.c mon/mon_req_decode.c)
+target_link_libraries(test_mon_req_decode jansson talloc glib-2.0)
+
+add_executable(test_mon_resp_encode mon/mon_common.c mon/mon_req.c mon/mon_resp.c mon/mon_resp_encode.c common/tr_name.c mon/tests/test_mon_resp_encode.c)
+target_link_libraries(test_mon_resp_encode jansson talloc glib-2.0)
+ACLOCAL_AMFLAGS = -I m4
DISTCHECK_CONFIGURE_FLAGS = \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
bin_PROGRAMS= tr/trust_router tr/trpc tid/example/tidc tid/example/tids common/tests/tr_dh_test common/tests/mq_test \
common/tests/thread_test trp/msgtst trp/test/rtbl_test trp/test/ptbl_test common/tests/cfg_test \
- common/tests/commtest common/tests/name_test common/tests/filt_test
+ common/tests/commtest common/tests/name_test common/tests/filt_test mon/tests/test_mon_req_encode \
+ mon/tests/test_mon_req_decode mon/tests/test_mon_resp_encode tr/trmon
AM_CPPFLAGS=-I$(srcdir)/include $(GLIB_CFLAGS)
AM_CFLAGS = -Wall -Werror=missing-prototypes -Werror -Wno-parentheses $(GLIB_CFLAGS)
SUBDIRS = gsscon
common/tr_util.c \
common/tr_apc.c \
common/tr_comm.c \
+ common/tr_comm_encoders.c \
common/tr_rp.c \
+ common/tr_rp_client.c \
+ common/tr_rp_client_encoders.c \
common/tr_idp.c \
+ common/tr_idp_encoders.c \
common/tr_filter.c \
- common/tr_gss.c
+ common/tr_filter_encoders.c \
+ common/tr_gss_names.c \
+ common/tr_socket.c \
+ $(mon_srcs)
tid_srcs = tid/tid_resp.c \
tid/tid_req.c \
trp_srcs = trp/trp_conn.c \
trp/trps.c \
trp/trpc.c \
+trp/trp_peer.c \
+trp/trp_peer_encoders.c \
trp/trp_ptable.c \
+trp/trp_ptable_encoders.c \
+trp/trp_route.c \
+trp/trp_route_encoders.c \
trp/trp_rtable.c \
+trp/trp_rtable_encoders.c \
trp/trp_req.c \
trp/trp_upd.c \
-common/tr_config.c \
-common/tr_mq.c
+common/tr_mq.c \
+$(config_srcs)
+
+# configuration parsing sources
+config_srcs = \
+ common/tr_config.c \
+ common/tr_config_comms.c \
+ common/tr_config_encoders.c \
+ common/tr_config_filters.c \
+ common/tr_config_internal.c \
+ common/tr_config_orgs.c \
+ common/tr_config_realms.c \
+ common/tr_config_rp_clients.c
+
+# general monitoring message sources
+mon_srcs = \
+ mon/mon_common.c \
+ mon/mon_req.c \
+ mon/mon_req_encode.c \
+ mon/mon_req_decode.c \
+ mon/mon_resp.c \
+ mon/mon_resp_decode.c \
+ mon/mon_resp_encode.c
+
+# monitoring server sources
+mons_srcs = \
+ mon/mons.c \
+ mon/mons_handlers.c
check_PROGRAMS = common/t_constraint
TESTS = common/t_constraint
tr/tr_event.c \
tr/tr_cfgwatch.c \
tr/tr_tid.c \
+tr/tr_tid_mons.c \
tr/tr_trp.c \
+tr/tr_trp_mons.c \
+tr/tr_mon.c \
+common/tr_gss.c \
+common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs) \
-$(common_srcs)
+$(common_srcs) \
+$(mons_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 \
+common/tr_gss_client.c \
$(trp_srcs) \
$(tid_srcs) \
$(common_srcs)
tr_trpc_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
tr_trpc_LDFLAGS = $(AM_LDFLAGS) -pthread
+tr_trmon_SOURCES = tr/trmon_main.c \
+common/tr_gss.c \
+common/tr_gss_client.c \
+$(tid_srcs) \
+$(trp_srcs) \
+$(common_srcs) \
+mon/monc.c
+
+tr_trmon_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
+tr_trmon_LDFLAGS = $(AM_LDFLAGS) -pthread
+
trp_msgtst_SOURCES = trp/msgtst.c \
$(common_srcs) \
common/tr_rand_id.c \
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
+common/tr_util.c \
+trp/trp_route.c \
+trp/trp_route_encoders.c \
+trp/trp_rtable.c \
+trp/trp_rtable_encoders.c
trp_test_rtbl_test_LDADD = $(GLIB_LIBS)
trp_test_ptbl_test_SOURCES = trp/test/ptbl_test.c \
+common/tr_gss.c \
+common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs) \
$(common_srcs)
trp_test_ptbl_test_LDFLAGS = $(AM_LDFLAGS) -pthread
tid_example_tidc_SOURCES = tid/example/tidc_main.c \
+common/tr_gss.c \
+common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs) \
$(common_srcs)
tid_example_tidc_LDFLAGS = $(AM_LDFLAGS) -pthread
tid_example_tids_SOURCES = tid/example/tids_main.c \
+common/tr_gss.c \
+common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs) \
$(common_srcs)
common_tests_cfg_test_SOURCES = common/tests/cfg_test.c \
$(common_srcs) \
+common/tr_gss.c \
+common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs)
common_tests_cfg_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
common_tests_commtest_SOURCES = common/tests/commtest.c \
$(common_srcs) \
+common/tr_gss.c \
+common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs)
common_tests_commtest_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
common_tests_name_test_SOURCES = common/tests/name_test.c \
$(common_srcs) \
+ common/tr_gss.c \
+ common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs)
common_tests_name_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
common_tests_filt_test_SOURCES = common/tests/filt_test.c \
$(common_srcs) \
+ common/tr_gss.c \
+ common/tr_gss_client.c \
$(tid_srcs) \
$(trp_srcs)
common_tests_filt_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
common_tests_filt_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc -pthread
common_tests_filt_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+mon_tests_test_mon_req_encode_SOURCES = mon/tests/test_mon_req_encode.c \
+ $(mon_srcs) \
+ common/tr_name.c
+mon_tests_test_mon_req_encode_LDADD = $(GLIB_LIBS)
+mon_tests_test_mon_req_encode_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
+mon_tests_test_mon_req_decode_SOURCES = mon/tests/test_mon_req_decode.c \
+ $(mon_srcs) \
+ common/tr_name.c
+mon_tests_test_mon_req_decode_LDADD = $(GLIB_LIBS)
+mon_tests_test_mon_req_decode_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
+mon_tests_test_mon_resp_encode_SOURCES = mon/tests/test_mon_resp_encode.c \
+ $(mon_srcs) \
+ common/tr_name.c
+mon_tests_test_mon_resp_encode_LDADD = $(GLIB_LIBS)
+mon_tests_test_mon_resp_encode_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
pkginclude_HEADERS = include/trust_router/tid.h include/trust_router/tr_name.h \
include/tr_debug.h include/trust_router/trp.h \
include/trust_router/tr_dh.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/tid_internal.h include/trp_internal.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/trp_route.h \
include/tr_cfgwatch.h include/tr_event.h \
- include/tr_mq.h include/trp_ptable.h \
+ include/tr_mq.h include/trp_peer.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
json_decref(decoded);
assert(encoded);
- assert(msg=tr_msg_decode(encoded, strlen(encoded)));
+ assert(msg= tr_msg_decode(NULL, encoded, strlen(encoded)));
assert(upd=tr_msg_get_trp_upd(msg));
assert(inforec=trp_upd_get_inforec(upd));
/* now remove the inforec from the update context */
msglen=fread(msgbuf, 1, MAX_FILE_SIZE, f);
assert(msglen);
assert(feof(f));
- msg=tr_msg_decode(msgbuf, msglen);
+ msg= tr_msg_decode(NULL, msgbuf, msglen);
free(msgbuf);
msgbuf=NULL;
/*
- * Copyright (c) 2012, JANET(UK)
+ * Copyright (c) 2012-2018, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
--- /dev/null
+/*
+ * 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 <jansson.h>
+#include <tr_idp.h>
+#include <tr_comm.h>
+#include <tr_util.h>
+#include <tr_debug.h>
+
+static json_t *expiry_to_json_string(TR_COMM_MEMB *memb)
+{
+ struct timespec ts_zero = {0, 0};
+ char *s = NULL;
+ json_t *jstr = NULL;
+
+ if (tr_cmp_timespec(tr_comm_memb_get_expiry(memb), &ts_zero) == 0) {
+ s = strdup("");
+ } else {
+ s = timespec_to_str(tr_comm_memb_get_expiry(memb));
+ }
+
+ if (s) {
+ jstr = json_string(s);
+ free(s);
+ }
+
+ return jstr;
+}
+
+/**
+ * Get the provenance from the member, handling empty provenance safely
+ */
+static json_t *provenance_to_json(TR_COMM_MEMB *memb)
+{
+ json_t *prov = tr_comm_memb_get_provenance(memb);
+
+ if (prov) {
+ json_incref(prov);
+ return prov;
+ } else {
+ return json_array();
+ }
+}
+
+/* helper for below */
+#define OBJECT_SET_OR_FAIL(jobj, key, val) \
+do { \
+ if (val) \
+ json_object_set_new((jobj),(key),(val)); \
+ else \
+ goto cleanup; \
+} while (0)
+
+#define ARRAY_APPEND_OR_FAIL(jary, val) \
+do { \
+ if (val) \
+ json_array_append_new((jary),(val)); \
+ else \
+ goto cleanup; \
+} while (0)
+
+static json_t *tr_comm_memb_to_json(TR_COMM_MEMB *memb)
+{
+ json_t *memb_json = NULL;
+ json_t *retval = NULL;
+
+ memb_json = json_object();
+ if (memb_json == NULL)
+ goto cleanup;
+
+ if (tr_comm_memb_get_origin(memb) == NULL) {
+ OBJECT_SET_OR_FAIL(memb_json, "origin", json_string("file"));
+ } else {
+ OBJECT_SET_OR_FAIL(memb_json, "origin",
+ tr_name_to_json_string(tr_comm_memb_get_origin(memb)));
+ OBJECT_SET_OR_FAIL(memb_json, "provenance",
+ provenance_to_json(memb));
+ OBJECT_SET_OR_FAIL(memb_json, "expires",
+ expiry_to_json_string(memb));
+ OBJECT_SET_OR_FAIL(memb_json, "announce_interval",
+ json_integer(tr_comm_memb_get_interval(memb)));
+ OBJECT_SET_OR_FAIL(memb_json, "times_expired",
+ json_integer(tr_comm_memb_get_times_expired(memb)));
+ }
+
+ /* succeeded - set the return value and increment the reference count */
+ retval = memb_json;
+ json_incref(retval);
+
+cleanup:
+ if (memb_json)
+ json_decref(memb_json);
+ return retval;
+}
+
+/**
+ * Summarize the different reasons we believe a realm belongs to a community
+ */
+static json_t *tr_comm_memb_sources_to_json(TR_COMM_MEMB *first_memb)
+{
+ json_t *jarray = NULL;
+ json_t *retval = NULL;
+ TR_COMM_ITER *iter = NULL;
+ TR_COMM_MEMB *memb = NULL;
+
+ jarray = json_array();
+ if (jarray == NULL)
+ goto cleanup;
+
+ iter = tr_comm_iter_new(NULL);
+ if (iter == NULL)
+ goto cleanup;
+
+ /* Iterate over all the memberships for this realm/comm pair that come from different origins */
+ memb = tr_comm_memb_iter_first(iter, first_memb);
+ while (memb) {
+ ARRAY_APPEND_OR_FAIL(jarray, tr_comm_memb_to_json(memb));
+ memb = tr_comm_memb_iter_next(iter);
+ }
+
+ /* success */
+ retval = jarray;
+ json_incref(retval);
+
+cleanup:
+ if (jarray)
+ json_decref(jarray);
+ if (iter)
+ talloc_free(iter);
+ return retval;
+}
+
+static json_t *tr_comm_realms_to_json(TR_COMM_TABLE *ctable, TR_NAME *comm_name, TR_REALM_ROLE role)
+{
+ json_t *jarray = json_array();
+ json_t *realm_json = NULL;
+ json_t *retval = NULL;
+ TR_COMM_ITER *iter = NULL;
+ TR_REALM *realm = NULL;
+ TR_COMM_MEMB *memb = NULL;
+
+ iter = tr_comm_iter_new(NULL);
+ realm = tr_realm_iter_first(iter, ctable, comm_name);
+
+ /* Do not display the full realm json here, only the name and info relevant to the community listing */
+ while(realm) {
+ if (realm->role == role) {
+ realm_json = json_object();
+ OBJECT_SET_OR_FAIL(realm_json, "realm",
+ tr_name_to_json_string(tr_realm_get_id(realm)));
+ memb = tr_comm_table_find_memb(ctable,
+ tr_realm_get_id(realm),
+ comm_name);
+ if (memb == NULL) {
+ /* This should not happen - there must be a matching membership if we
+ * believed the realm was in the community in the first place! */
+ goto cleanup;
+ }
+ OBJECT_SET_OR_FAIL(realm_json, "sources",
+ tr_comm_memb_sources_to_json(memb));
+ json_array_append_new(jarray, realm_json);
+ realm_json = NULL; /* so we don't free this twice during cleanup */
+ }
+ realm = tr_realm_iter_next(iter);
+ }
+
+ /* Success - increment the reference count so return value survives */
+ retval = jarray;
+ json_incref(retval);
+
+cleanup:
+ if (jarray)
+ json_decref(jarray);
+
+ if (realm_json)
+ json_decref(realm_json);
+
+ if (iter)
+ tr_comm_iter_free(iter);
+
+ return retval;
+}
+
+static json_t *tr_comm_to_json(TR_COMM_TABLE *ctable, TR_COMM *comm)
+{
+ json_t *comm_json = NULL;
+ json_t *retval = NULL;
+
+ comm_json = json_object();
+ if (comm_json == NULL)
+ goto cleanup;
+
+ OBJECT_SET_OR_FAIL(comm_json, "type",
+ json_string(tr_comm_type_to_str(tr_comm_get_type(comm))));
+ if (tr_comm_get_type(comm) == TR_COMM_APC) {
+ OBJECT_SET_OR_FAIL(comm_json, "expiration_interval",
+ json_integer(comm->expiration_interval));
+ } else {
+ /* just get the first apc */
+ OBJECT_SET_OR_FAIL(comm_json, "apc",
+ tr_name_to_json_string(
+ tr_apc_get_id(
+ tr_comm_get_apcs(comm))));
+ }
+ OBJECT_SET_OR_FAIL(comm_json, "name",
+ tr_name_to_json_string(tr_comm_get_id(comm)));
+ if (tr_comm_get_owner_realm(comm)) {
+ OBJECT_SET_OR_FAIL(comm_json, "owner_realm",
+ tr_name_to_json_string(tr_comm_get_owner_realm(comm)));
+ }
+ if (tr_comm_get_owner_contact(comm)) {
+ OBJECT_SET_OR_FAIL(comm_json, "owner_contact",
+ tr_name_to_json_string(tr_comm_get_owner_contact(comm)));
+ }
+ OBJECT_SET_OR_FAIL(comm_json, "idp_realms",
+ tr_comm_realms_to_json(ctable, tr_comm_get_id(comm), TR_ROLE_IDP));
+ OBJECT_SET_OR_FAIL(comm_json, "rp_realms",
+ tr_comm_realms_to_json(ctable, tr_comm_get_id(comm), TR_ROLE_RP));
+
+ /* succeeded - set the return value and increment the reference count */
+ retval = comm_json;
+ json_incref(retval);
+
+ cleanup:
+ if (comm_json)
+ json_decref(comm_json);
+ return retval;
+}
+
+json_t *tr_comm_table_to_json(TR_COMM_TABLE *ctable)
+{
+ json_t *ctable_json = NULL;
+ json_t *retval = NULL;
+ json_t *comm_json = NULL;
+ TR_COMM_ITER *iter = NULL;
+ TR_COMM *comm = NULL;
+
+ ctable_json = json_array();
+ if (ctable_json == NULL)
+ goto cleanup;
+
+ iter = tr_comm_iter_new(NULL);
+ if (iter == NULL)
+ goto cleanup;
+
+ /* Iterate over communities in the table */
+ comm = tr_comm_table_iter_first(iter, ctable);
+ while (comm) {
+ comm_json = tr_comm_to_json(ctable, comm);
+
+ if (comm_json == NULL)
+ goto cleanup;
+
+ json_array_append_new(ctable_json, comm_json);
+ comm = tr_comm_table_iter_next(iter);
+ }
+
+ /* succeeded - set the return value and increment the reference count */
+ retval = ctable_json;
+ json_incref(retval);
+
+cleanup:
+ if (iter)
+ tr_comm_iter_free(iter);
+
+ if (ctable_json)
+ json_decref(ctable_json);
+
+ return retval;
+
+}
\ No newline at end of file
/*
- * Copyright (c) 2012, JANET(UK)
+ * Copyright (c) 2012-2018, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#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>
talloc_free(tmp_ctx);
}
-TR_CFG *tr_cfg_new(TALLOC_CTX *mem_ctx)
-{
- TR_CFG *cfg=talloc(mem_ctx, TR_CFG);
- if (cfg!=NULL) {
- cfg->internal=NULL;
- cfg->rp_clients=NULL;
- cfg->peers=NULL;
- cfg->default_servers=NULL;
- cfg->ctable=tr_comm_table_new(cfg);
- if (cfg->ctable==NULL) {
- talloc_free(cfg);
- cfg=NULL;
- }
- }
- return cfg;
-}
-
-void tr_cfg_free (TR_CFG *cfg)
-{
- talloc_free(cfg);
-}
-
-TR_CFG_MGR *tr_cfg_mgr_new(TALLOC_CTX *mem_ctx)
-{
- return talloc_zero(mem_ctx, TR_CFG_MGR);
-}
-
-void tr_cfg_mgr_free (TR_CFG_MGR *cfg_mgr) {
- talloc_free(cfg_mgr);
-}
-
-TR_CFG_RC tr_apply_new_config (TR_CFG_MGR *cfg_mgr)
-{
- /* cfg_mgr->active is allowed to be null, but new cannot be */
- if ((cfg_mgr==NULL) || (cfg_mgr->new==NULL))
- return TR_CFG_BAD_PARAMS;
-
- if (cfg_mgr->active != NULL)
- tr_cfg_free(cfg_mgr->active);
-
- cfg_mgr->active = cfg_mgr->new;
- cfg_mgr->new=NULL; /* only keep a single handle on the new configuration */
-
- tr_log_threshold(cfg_mgr->active->internal->log_threshold);
- tr_console_threshold(cfg_mgr->active->internal->console_threshold);
-
- 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;
- int i=0;
-
- if ((!ctype) || (!jc) || (!rc) ||
- (!json_is_array(jc)) ||
- (0 >= json_array_size(jc)) ||
- (TR_MAX_CONST_MATCHES < json_array_size(jc)) ||
- (!json_is_string(json_array_get(jc, 0)))) {
- tr_err("tr_cfg_parse_one_constraint: config error.");
- *rc=TR_CFG_NOPARSE;
- return NULL;
- }
-
- if (NULL==(cons=tr_constraint_new(mem_ctx))) {
- tr_debug("tr_cfg_parse_one_constraint: Out of memory (cons).");
- *rc=TR_CFG_NOMEM;
- return NULL;
- }
-
- if (NULL==(cons->type=tr_new_name(ctype))) {
- tr_err("tr_cfg_parse_one_constraint: Out of memory (type).");
- *rc=TR_CFG_NOMEM;
- tr_constraint_free(cons);
- return NULL;
- }
-
- for (i=0; i < json_array_size(jc); i++) {
- cons->matches[i]=tr_new_name(json_string_value(json_array_get(jc, i)));
- if (cons->matches[i]==NULL) {
- tr_err("tr_cfg_parse_one_constraint: Out of memory (match %d).", i+1);
- *rc=TR_CFG_NOMEM;
- tr_constraint_free(cons);
- return NULL;
- }
- }
-
- return cons;
-}
-
-static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR_FILTER_TYPE ftype, TR_CFG_RC *rc)
-{
- TALLOC_CTX *tmp_ctx = talloc_new(NULL);
- TR_FILTER *filt = NULL;
- json_t *jfaction = NULL;
- json_t *jfline = NULL;
- json_t *jfspecs = NULL;
- json_t *this_jfspec = NULL;
- json_t *jfield = NULL;
- json_t *jmatch = NULL;
- json_t *jrc = NULL;
- json_t *jdc = NULL;
- json_t *this_jmatch = NULL;
- TR_NAME *name = NULL;
- size_t i = 0, j = 0, k = 0;
-
- *rc = TR_CFG_ERROR;
-
- if ((jfilt == NULL) || (rc == NULL)) {
- tr_err("tr_cfg_parse_one_filter: null argument");
- *rc = TR_CFG_BAD_PARAMS;
- goto cleanup;
- }
-
- if (NULL == (filt = tr_filter_new(tmp_ctx))) {
- tr_err("tr_cfg_parse_one_filter: Out of memory.");
- *rc = TR_CFG_NOMEM;
- goto cleanup;
- }
- tr_filter_set_type(filt, ftype);
-
- /* make sure we have space to represent the filter */
- if (json_array_size(jfilt) > TR_MAX_FILTER_LINES) {
- tr_err("tr_cfg_parse_one_filter: Filter has too many lines, maximum of %d.", TR_MAX_FILTER_LINES);
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- /* For each entry in the filter... */
- json_array_foreach(jfilt, i, jfline) {
- if ((NULL == (jfaction = json_object_get(jfline, "action"))) ||
- (!json_is_string(jfaction))) {
- tr_debug("tr_cfg_parse_one_filter: Error parsing filter action.");
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- if ((NULL == (jfspecs = json_object_get(jfline, "specs"))) ||
- (!json_is_array(jfspecs)) ||
- (0 == json_array_size(jfspecs))) {
- tr_debug("tr_cfg_parse_one_filter: Error parsing filter specs.");
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- if (TR_MAX_FILTER_SPECS < json_array_size(jfspecs)) {
- tr_debug("tr_cfg_parse_one_filter: Filter has too many specs, maximimum of %d.", TR_MAX_FILTER_SPECS);
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- if (NULL == (filt->lines[i] = tr_fline_new(filt))) {
- tr_debug("tr_cfg_parse_one_filter: Out of memory allocating filter line %d.", i + 1);
- *rc = TR_CFG_NOMEM;
- goto cleanup;
- }
-
- if (!strcmp(json_string_value(jfaction), "accept")) {
- filt->lines[i]->action = TR_FILTER_ACTION_ACCEPT;
- } else if (!strcmp(json_string_value(jfaction), "reject")) {
- filt->lines[i]->action = TR_FILTER_ACTION_REJECT;
- } else {
- tr_debug("tr_cfg_parse_one_filter: Error parsing filter action, unknown action' %s'.",
- json_string_value(jfaction));
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- if (NULL != (jrc = json_object_get(jfline, "realm_constraints"))) {
- if (!json_is_array(jrc)) {
- tr_err("tr_cfg_parse_one_filter: cannot parse realm_constraints, not an array.");
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- } else if (json_array_size(jrc) > TR_MAX_CONST_MATCHES) {
- tr_err("tr_cfg_parse_one_filter: realm_constraints has too many entries, maximum of %d.",
- TR_MAX_CONST_MATCHES);
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- } else if (json_array_size(jrc) > 0) {
- /* ok we actually have entries to process */
- if (NULL == (filt->lines[i]->realm_cons = tr_cfg_parse_one_constraint(filt->lines[i], "realm", jrc, rc))) {
- tr_debug("tr_cfg_parse_one_filter: Error parsing realm constraint");
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- }
- }
- }
-
- if (NULL != (jdc = json_object_get(jfline, "domain_constraints"))) {
- if (!json_is_array(jdc)) {
- tr_err("tr_cfg_parse_one_filter: cannot parse domain_constraints, not an array.");
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- } else if (json_array_size(jdc) > TR_MAX_CONST_MATCHES) {
- tr_err("tr_cfg_parse_one_filter: domain_constraints has too many entries, maximum of %d.",
- TR_MAX_CONST_MATCHES);
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- } else if (json_array_size(jdc) > 0) {
- if (NULL == (filt->lines[i]->domain_cons = tr_cfg_parse_one_constraint(filt->lines[i], "domain", jdc, rc))) {
- tr_debug("tr_cfg_parse_one_filter: Error parsing domain constraint");
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- }
- }
- }
-
- /*For each filter spec within the filter line... */
- json_array_foreach(jfspecs, j, this_jfspec) {
- if ((NULL == (jfield = json_object_get(this_jfspec, "field"))) ||
- (!json_is_string(jfield))) {
- tr_debug("tr_cfg_parse_one_filter: Error parsing filter: missing field for filer spec %d, filter line %d.", i,
- j);
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- /* check that we have a match attribute */
- if (NULL == (jmatch = json_object_get(this_jfspec, "match"))) {
- tr_debug("tr_cfg_parse_one_filter: Error parsing filter: missing match for filer spec %d, filter line %d.", i,
- j);
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- /* check that match is a string or an array */
- if ((!json_is_string(jmatch)) && (!json_is_array(jmatch))) {
- tr_debug(
- "tr_cfg_parse_one_filter: Error parsing filter: match not a string or array for filter spec %d, filter line %d.",
- i, j);
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- /* allocate the filter spec */
- if (NULL == (filt->lines[i]->specs[j] = tr_fspec_new(filt->lines[i]))) {
- tr_debug("tr_cfg_parse_one_filter: Out of memory.");
- *rc = TR_CFG_NOMEM;
- goto cleanup;
- }
-
- /* fill in the field */
- if (NULL == (filt->lines[i]->specs[j]->field = tr_new_name(json_string_value(jfield)))) {
- tr_debug("tr_cfg_parse_one_filter: Out of memory.");
- *rc = TR_CFG_NOMEM;
- goto cleanup;
- }
-
- /* fill in the matches */
- if (json_is_string(jmatch)) {
- if (NULL == (name = tr_new_name(json_string_value(jmatch)))) {
- tr_debug("tr_cfg_parse_one_filter: Out of memory.");
- *rc = TR_CFG_NOMEM;
- goto cleanup;
- }
- tr_fspec_add_match(filt->lines[i]->specs[j], name);
- } else {
- /* jmatch is an array (we checked earlier) */
- json_array_foreach(jmatch, k, this_jmatch) {
- if (NULL == (name = tr_new_name(json_string_value(this_jmatch)))) {
- tr_debug("tr_cfg_parse_one_filter: Out of memory.");
- *rc = TR_CFG_NOMEM;
- goto cleanup;
- }
- tr_fspec_add_match(filt->lines[i]->specs[j], name);
- }
- }
- if (!tr_filter_validate_spec_field(ftype, filt->lines[i]->specs[j])){
- tr_debug("tr_cfg_parse_one_filter: Invalid filter field \"%.*s\" for %s filter, spec %d, filter %d.",
- filt->lines[i]->specs[j]->field->len,
- filt->lines[i]->specs[j]->field->buf,
- tr_filter_type_to_string(filt->type),
- i, j);
- *rc = TR_CFG_ERROR;
- goto cleanup;
- }
- }
- }
-
- /* check that the filter is valid */
- if (!tr_filter_validate(filt)) {
- *rc = TR_CFG_ERROR;
- } else {
- *rc = TR_CFG_SUCCESS;
- talloc_steal(mem_ctx, filt);
- }
-
- cleanup:
- talloc_free(tmp_ctx);
- if (*rc!=TR_CFG_SUCCESS)
- filt=NULL;
- return filt;
-}
-
-static TR_FILTER_SET *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_CFG_RC *rc)
-{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- json_t *jfilt;
- const char *filt_label=NULL;
- TR_FILTER *filt=NULL;
- TR_FILTER_SET *filt_set=NULL;
- TR_FILTER_TYPE filt_type=TR_FILTER_TYPE_UNKNOWN;
-
- *rc=TR_CFG_ERROR;
-
- /* no filters */
- if (jfilts==NULL) {
- *rc=TR_CFG_SUCCESS;
- goto cleanup;
- }
-
- filt_set=tr_filter_set_new(tmp_ctx);
- if (filt_set==NULL) {
- tr_debug("tr_cfg_parse_filters: Unable to allocate filter set.");
- *rc = TR_CFG_NOMEM;
- goto cleanup;
- }
-
- json_object_foreach(jfilts, filt_label, jfilt) {
- /* check that we got a filter */
- if (jfilt == NULL) {
- tr_debug("tr_cfg_parse_filters: Definition for %s filter is missing.", filt_label);
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- /* check that we recognize the filter type */
- filt_type=tr_filter_type_from_string(filt_label);
- if (filt_type==TR_FILTER_TYPE_UNKNOWN) {
- tr_debug("tr_cfg_parse_filters: Unrecognized filter (%s) defined.", filt_label);
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- /* finally, parse the filter */
- tr_debug("tr_cfg_parse_filters: Found %s filter.", filt_label);
- filt = tr_cfg_parse_one_filter(tmp_ctx, jfilt, filt_type, rc);
- tr_filter_set_add(filt_set, filt);
- if (*rc != TR_CFG_SUCCESS) {
- tr_debug("tr_cfg_parse_filters: Error parsing %s filter.", filt_label);
- *rc = TR_CFG_NOPARSE;
- goto cleanup;
- }
- }
-
- *rc=TR_CFG_SUCCESS;
-
- cleanup:
- if (*rc==TR_CFG_SUCCESS)
- talloc_steal(mem_ctx, filt_set);
- else if (filt_set!=NULL) {
- talloc_free(filt_set);
- filt_set=NULL;
- }
-
- talloc_free(tmp_ctx);
- return filt_set;
-}
-
-static TR_AAA_SERVER *tr_cfg_parse_one_aaa_server(TALLOC_CTX *mem_ctx, json_t *jaddr, TR_CFG_RC *rc)
-{
- TR_AAA_SERVER *aaa = NULL;
- TR_NAME *name=NULL;
-
- if ((!jaddr) || (!json_is_string(jaddr))) {
- tr_debug("tr_cfg_parse_one_aaa_server: Bad parameters.");
- *rc = TR_CFG_BAD_PARAMS;
- return NULL;
- }
-
- name=tr_new_name(json_string_value(jaddr));
- if (name==NULL) {
- tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating hostname.");
- *rc = TR_CFG_NOMEM;
- return NULL;
- }
-
- aaa=tr_aaa_server_new(mem_ctx, name);
- if (aaa==NULL) {
- tr_free_name(name);
- tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating AAA server.");
- *rc = TR_CFG_NOMEM;
- return NULL;
- }
-
- return aaa;
-}
-
-static TR_AAA_SERVER *tr_cfg_parse_aaa_servers(TALLOC_CTX *mem_ctx, json_t *jaaas, TR_CFG_RC *rc)
-{
- TALLOC_CTX *tmp_ctx=NULL;
- TR_AAA_SERVER *aaa = NULL;
- TR_AAA_SERVER *temp_aaa = NULL;
- int i = 0;
-
- for (i = 0; i < json_array_size(jaaas); i++) {
- /* rc gets set in here */
- if (NULL == (temp_aaa = tr_cfg_parse_one_aaa_server(tmp_ctx, json_array_get(jaaas, i), rc))) {
- talloc_free(tmp_ctx);
- return NULL;
- }
- /* TBD -- IPv6 addresses */
- // tr_debug("tr_cfg_parse_aaa_servers: Configuring AAA Server: ip_addr = %s.", inet_ntoa(temp_aaa->aaa_server_addr));
- temp_aaa->next = aaa;
- aaa = temp_aaa;
- }
- tr_debug("tr_cfg_parse_aaa_servers: Finished (rc=%d)", *rc);
-
- for (temp_aaa=aaa; temp_aaa!=NULL; temp_aaa=temp_aaa->next)
- talloc_steal(mem_ctx, temp_aaa);
- talloc_free(tmp_ctx);
- return aaa;
-}
-
-static TR_APC *tr_cfg_parse_one_apc(TALLOC_CTX *mem_ctx, json_t *japc, TR_CFG_RC *rc)
-{
- TR_APC *apc=NULL;
- TR_NAME *name=NULL;
-
- *rc = TR_CFG_SUCCESS; /* presume success */
-
- if ((!japc) || (!rc) || (!json_is_string(japc))) {
- tr_debug("tr_cfg_parse_one_apc: Bad parameters.");
- if (rc)
- *rc = TR_CFG_BAD_PARAMS;
- return NULL;
- }
-
- apc=tr_apc_new(mem_ctx);
- if (apc==NULL) {
- tr_debug("tr_cfg_parse_one_apc: Out of memory.");
- *rc = TR_CFG_NOMEM;
- return NULL;
- }
-
- name=tr_new_name(json_string_value(japc));
- if (name==NULL) {
- tr_debug("tr_cfg_parse_one_apc: No memory for APC name.");
- tr_apc_free(apc);
- *rc = TR_CFG_NOMEM;
- return NULL;
- }
- tr_apc_set_id(apc, name); /* apc is now responsible for freeing the name */
-
- return apc;
-}
-
-static TR_APC *tr_cfg_parse_apcs(TALLOC_CTX *mem_ctx, json_t *japcs, TR_CFG_RC *rc)
-{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- TR_APC *apcs=NULL;
- TR_APC *new_apc=NULL;
- int ii=0;
- TR_CFG_RC call_rc=TR_CFG_ERROR;
-
- *rc = TR_CFG_SUCCESS; /* presume success */
-
- if ((!japcs) || (!rc) || (!json_is_array(japcs))) {
- tr_debug("tr_cfg_parse_one_apc: Bad parameters.");
- if (rc)
- *rc = TR_CFG_BAD_PARAMS;
- return NULL;
- }
-
- for (ii=0; ii<json_array_size(japcs); ii++) {
- new_apc=tr_cfg_parse_one_apc(tmp_ctx, json_array_get(japcs, ii), &call_rc);
- if ((call_rc!=TR_CFG_SUCCESS) || (new_apc==NULL)) {
- tr_debug("tr_cfg_parse_apcs: Error parsing APC %d.", ii+1);
- *rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
- tr_apc_add(apcs, new_apc);
- }
-
- talloc_steal(mem_ctx, apcs);
- *rc=TR_CFG_SUCCESS;
-
- cleanup:
- talloc_free(tmp_ctx);
- return apcs;
-}
-
-static TR_NAME *tr_cfg_parse_name(TALLOC_CTX *mem_ctx, json_t *jname, TR_CFG_RC *rc)
-{
- TR_NAME *name=NULL;
- *rc=TR_CFG_ERROR;
-
- if ((jname==NULL) || (!json_is_string(jname))) {
- tr_err("tr_cfg_parse_name: name missing or not a string");
- *rc=TR_CFG_BAD_PARAMS;
- name=NULL;
- } else {
- name=tr_new_name(json_string_value(jname));
- if (name==NULL) {
- tr_err("tr_cfg_parse_name: could not allocate name");
- *rc=TR_CFG_NOMEM;
- } else {
- *rc=TR_CFG_SUCCESS;
- }
- }
- return name;
-}
-
-static int tr_cfg_parse_shared_config(json_t *jsc, TR_CFG_RC *rc)
-{
- const char *shared=NULL;
- *rc=TR_CFG_SUCCESS;
-
- if ((jsc==NULL) ||
- (!json_is_string(jsc)) ||
- (NULL==(shared=json_string_value(jsc)))) {
- *rc=TR_CFG_BAD_PARAMS;
- return -1;
- }
-
- if (0==strcmp(shared, "no"))
- return 0;
- else if (0==strcmp(shared, "yes"))
- return 1;
-
- /* any other value is an error */
- tr_debug("tr_cfg_parse_shared_config: invalid shared_config value \"%s\" (should be \"yes\" or \"no\")",
- shared);
- *rc=TR_CFG_NOPARSE;
- return -1;
-}
-
-static TR_REALM_ORIGIN tr_cfg_realm_origin(json_t *jrealm)
-{
- json_t *jremote=json_object_get(jrealm, "remote");
- const char *s=NULL;
-
- if (jremote==NULL)
- return TR_REALM_LOCAL;
- if (!json_is_string(jremote)) {
- tr_warning("tr_cfg_realm_origin: \"remote\" is not a string, assuming this is a local realm.");
- return TR_REALM_LOCAL;
- }
- s=json_string_value(jremote);
- if (strcasecmp(s, "yes")==0)
- return TR_REALM_REMOTE_INCOMPLETE;
- else if (strcasecmp(s, "no")!=0)
- tr_warning("tr_cfg_realm_origin: \"remote\" is neither 'yes' nor 'no', assuming this is a local realm.");
-
- return TR_REALM_LOCAL;
-}
-
-/* Parse the identity provider object from a realm and fill in the given TR_IDP_REALM. */
-static TR_CFG_RC tr_cfg_parse_idp(TR_IDP_REALM *idp, json_t *jidp)
-{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- TR_APC *apcs=NULL;
- TR_AAA_SERVER *aaa=NULL;
- TR_CFG_RC rc=TR_CFG_ERROR;
-
- if (jidp==NULL)
- goto cleanup;
-
- idp->shared_config=tr_cfg_parse_shared_config(json_object_get(jidp, "shared_config"), &rc);
- if (rc!=TR_CFG_SUCCESS) {
- tr_err("tr_cfg_parse_idp: missing or malformed shared_config specification");
- rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- apcs=tr_cfg_parse_apcs(tmp_ctx, json_object_get(jidp, "apcs"), &rc);
- if ((rc!=TR_CFG_SUCCESS) || (apcs==NULL)) {
- tr_err("tr_cfg_parse_idp: unable to parse APC");
- rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- aaa=tr_cfg_parse_aaa_servers(idp, json_object_get(jidp, "aaa_servers"), &rc);
- if (rc!=TR_CFG_SUCCESS) {
- tr_err("tr_cfg_parse_idp: unable to parse AAA servers");
- rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- tr_debug("tr_cfg_parse_idp: APC=\"%.*s\"",
- apcs->id->len,
- apcs->id->buf);
-
- /* done, fill in the idp structures */
- idp->apcs=apcs;
- talloc_steal(idp, apcs);
- idp->aaa_servers=aaa;
- rc=TR_CFG_SUCCESS;
-
-cleanup:
- if (rc!=TR_CFG_SUCCESS) {
- if (apcs!=NULL)
- tr_apc_free(apcs);
- if (aaa!=NULL)
- tr_aaa_server_free(aaa);
- }
-
- talloc_free(tmp_ctx);
- return rc;
-}
-
-/* parses idp realm */
-static TR_IDP_REALM *tr_cfg_parse_one_idp_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
-{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- TR_IDP_REALM *realm=NULL;
- TR_CFG_RC call_rc=TR_CFG_ERROR;
-
- *rc=TR_CFG_ERROR; /* default to error if not set */
-
- if ((!jrealm) || (!rc)) {
- tr_err("tr_cfg_parse_one_idp_realm: Bad parameters.");
- if (rc)
- *rc=TR_CFG_BAD_PARAMS;
- goto cleanup;
- }
-
- if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) {
- tr_err("tr_cfg_parse_one_idp_realm: could not allocate idp realm.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
-
- realm->origin=tr_cfg_realm_origin(jrealm);
- if (realm->origin!=TR_REALM_LOCAL) {
- tr_debug("tr_cfg_parse_one_idp_realm: realm is remote, should not have full IdP info.");
- *rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- /* must have a name */
- realm->realm_id=tr_cfg_parse_name(realm,
- json_object_get(jrealm, "realm"),
- &call_rc);
- if ((call_rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) {
- tr_err("tr_cfg_parse_one_idp_realm: could not parse realm name");
- *rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
- tr_debug("tr_cfg_parse_one_idp_realm: realm_id=\"%.*s\"",
- realm->realm_id->len,
- realm->realm_id->buf);
-
- call_rc=tr_cfg_parse_idp(realm, json_object_get(jrealm, "identity_provider"));
- if (call_rc!=TR_CFG_SUCCESS) {
- tr_err("tr_cfg_parse_one_idp_realm: could not parse identity_provider.");
- *rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- *rc=TR_CFG_SUCCESS;
-
-cleanup:
- if (*rc==TR_CFG_SUCCESS)
- talloc_steal(mem_ctx, realm);
- else {
- talloc_free(realm);
- realm=NULL;
- }
-
- talloc_free(tmp_ctx);
- return realm;
-}
-
- /* Determine whether the realm is an IDP realm */
-static int tr_cfg_is_idp_realm(json_t *jrealm)
-{
- /* If a realm spec contains an identity_provider, it's an IDP realm. */
- if (NULL != json_object_get(jrealm, "identity_provider"))
- return 1;
- else
- return 0;
-}
-
-static TR_IDP_REALM *tr_cfg_parse_one_remote_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
-{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- TR_IDP_REALM *realm=talloc(mem_ctx, TR_IDP_REALM);
-
- *rc=TR_CFG_ERROR; /* default to error if not set */
-
- if ((!jrealm) || (!rc)) {
- tr_err("tr_cfg_parse_one_remote_realm: Bad parameters.");
- if (rc)
- *rc=TR_CFG_BAD_PARAMS;
- goto cleanup;
- }
-
- if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) {
- tr_err("tr_cfg_parse_one_remote_realm: could not allocate idp realm.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
-
- /* must have a name */
- realm->realm_id=tr_cfg_parse_name(realm,
- json_object_get(jrealm, "realm"),
- rc);
- if ((*rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) {
- tr_err("tr_cfg_parse_one_remote_realm: could not parse realm name");
- *rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
- tr_debug("tr_cfg_parse_one_remote_realm: realm_id=\"%.*s\"",
- realm->realm_id->len,
- realm->realm_id->buf);
-
- realm->origin=tr_cfg_realm_origin(jrealm);
- *rc=TR_CFG_SUCCESS;
-
-cleanup:
- if (*rc==TR_CFG_SUCCESS)
- talloc_steal(mem_ctx, realm);
- else {
- talloc_free(realm);
- realm=NULL;
- }
-
- talloc_free(tmp_ctx);
- return realm;
-}
-
-static int tr_cfg_is_remote_realm(json_t *jrealm)
-{
- return (tr_cfg_realm_origin(jrealm)!=TR_REALM_LOCAL);
-}
-
-/* Parse any idp realms in the j_realms object. Ignores other realm types. */
-static TR_IDP_REALM *tr_cfg_parse_idp_realms(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc)
-{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- TR_IDP_REALM *realms=NULL;
- TR_IDP_REALM *new_realm=NULL;
- json_t *this_jrealm=NULL;
- int ii=0;
-
- *rc=TR_CFG_ERROR;
- if ((jrealms==NULL) || (!json_is_array(jrealms))) {
- tr_err("tr_cfg_parse_idp_realms: realms not an array");
- *rc=TR_CFG_BAD_PARAMS;
- goto cleanup;
- }
-
- for (ii=0; ii<json_array_size(jrealms); ii++) {
- this_jrealm=json_array_get(jrealms, ii);
- if (tr_cfg_is_idp_realm(this_jrealm)) {
- new_realm=tr_cfg_parse_one_idp_realm(tmp_ctx, this_jrealm, rc);
- if ((*rc)!=TR_CFG_SUCCESS) {
- tr_err("tr_cfg_parse_idp_realms: error decoding realm entry %d", ii+1);
- *rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
- tr_idp_realm_add(realms, new_realm);
- } else if (tr_cfg_is_remote_realm(this_jrealm)) {
- new_realm=tr_cfg_parse_one_remote_realm(tmp_ctx, this_jrealm, rc);
- if ((*rc)!=TR_CFG_SUCCESS) {
- tr_err("tr_cfg_parse_idp_realms: error decoding remote realm entry %d", ii+1);
- *rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
- tr_idp_realm_add(realms, new_realm);
- }
- }
-
- *rc=TR_CFG_SUCCESS;
- talloc_steal(mem_ctx, realms);
-
-cleanup:
- talloc_free(tmp_ctx);
- return realms;
-}
-
-static TR_GSS_NAMES *tr_cfg_parse_gss_names(TALLOC_CTX *mem_ctx, json_t *jgss_names, TR_CFG_RC *rc)
-{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- TR_GSS_NAMES *gn=NULL;
- json_t *jname=NULL;
- int ii=0;
- TR_NAME *name=NULL;
-
- if ((rc==NULL) || (jgss_names==NULL)) {
- tr_err("tr_cfg_parse_gss_names: Bad parameters.");
- *rc=TR_CFG_BAD_PARAMS;
-
- }
-
- if (!json_is_array(jgss_names)) {
- tr_err("tr_cfg_parse_gss_names: gss_names not an array.");
- *rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- gn=tr_gss_names_new(tmp_ctx);
- for (ii=0; ii<json_array_size(jgss_names); ii++) {
- jname=json_array_get(jgss_names, ii);
- if (!json_is_string(jname)) {
- tr_err("tr_cfg_parse_gss_names: Encountered non-string gss name.");
- *rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- name=tr_new_name(json_string_value(jname));
- if (name==NULL) {
- tr_err("tr_cfg_parse_gss_names: Out of memory allocating gss name.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
-
- if (tr_gss_names_add(gn, name)!=0) {
- tr_free_name(name);
- tr_err("tr_cfg_parse_gss_names: Unable to add gss name to RP client.");
- *rc=TR_CFG_ERROR;
- goto cleanup;
- }
- }
-
- talloc_steal(mem_ctx, gn);
- *rc=TR_CFG_SUCCESS;
-
- cleanup:
- talloc_free(tmp_ctx);
- if ((*rc!=TR_CFG_SUCCESS) && (gn!=NULL))
- gn=NULL;
- return gn;
-}
-
-/* default filter accepts realm and *.realm */
-static TR_FILTER_SET *tr_cfg_default_filters(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_CFG_RC *rc)
-{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- TR_FILTER *filt=NULL;
- TR_FILTER_SET *filt_set=NULL;
- TR_CONSTRAINT *cons=NULL;
- TR_NAME *name=NULL;
- TR_NAME *n_prefix=tr_new_name("*.");
- TR_NAME *n_rp_realm_1=tr_new_name("rp_realm");
- TR_NAME *n_rp_realm_2=tr_new_name("rp_realm");
- TR_NAME *n_domain=tr_new_name("domain");
- TR_NAME *n_realm=tr_new_name("realm");
-
-
- if ((realm==NULL) || (rc==NULL)) {
- tr_debug("tr_cfg_default_filters: invalid arguments.");
- if (rc!=NULL)
- *rc=TR_CFG_BAD_PARAMS;
- goto cleanup;
- }
-
- if ((n_prefix==NULL) ||
- (n_rp_realm_1==NULL) ||
- (n_rp_realm_2==NULL) ||
- (n_domain==NULL) ||
- (n_realm==NULL)) {
- tr_debug("tr_cfg_default_filters: unable to allocate names.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
-
- filt=tr_filter_new(tmp_ctx);
- if (filt==NULL) {
- tr_debug("tr_cfg_default_filters: could not allocate filter.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
- tr_filter_set_type(filt, TR_FILTER_TYPE_TID_INBOUND);
- filt->lines[0]=tr_fline_new(filt);
- if (filt->lines[0]==NULL) {
- tr_debug("tr_cfg_default_filters: could not allocate filter line.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
-
- filt->lines[0]->action=TR_FILTER_ACTION_ACCEPT;
- filt->lines[0]->specs[0]=tr_fspec_new(filt->lines[0]);
- filt->lines[0]->specs[0]->field=n_rp_realm_1;
- n_rp_realm_1=NULL; /* we don't own this name any more */
-
- name=tr_dup_name(realm);
- if (name==NULL) {
- tr_debug("tr_cfg_default_filters: could not allocate realm name.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
- tr_fspec_add_match(filt->lines[0]->specs[0], name);
- name=NULL; /* we no longer own the name */
-
- /* now do the wildcard name */
- filt->lines[0]->specs[1]=tr_fspec_new(filt->lines[0]);
- filt->lines[0]->specs[1]->field=n_rp_realm_2;
- n_rp_realm_2=NULL; /* we don't own this name any more */
-
- if (NULL==(name=tr_name_cat(n_prefix, realm))) {
- tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
-
- tr_fspec_add_match(filt->lines[0]->specs[1], name);
- name=NULL; /* we no longer own the name */
-
- /* domain constraint */
- if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
- tr_debug("tr_cfg_default_filters: could not allocate domain constraint.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
-
- cons->type=n_domain;
- n_domain=NULL; /* belongs to the constraint now */
- name=tr_dup_name(realm);
- if (name==NULL) {
- tr_debug("tr_cfg_default_filters: could not allocate realm name for domain constraint.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
- cons->matches[0]=name;
- name=tr_name_cat(n_prefix, realm);
- if (name==NULL) {
- tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name for domain constraint.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
- cons->matches[1]=name;
- name=NULL;
- filt->lines[0]->domain_cons=cons;
-
-
- /* realm constraint */
- if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
- tr_debug("tr_cfg_default_filters: could not allocate realm constraint.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
-
- cons->type=n_realm;
- n_realm=NULL; /* belongs to the constraint now */
- name=tr_dup_name(realm);
- if (name==NULL) {
- tr_debug("tr_cfg_default_filters: could not allocate realm name for realm constraint.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
- cons->matches[0]=name;
- name=tr_name_cat(n_prefix, realm);
- if (name==NULL) {
- tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name for realm constraint.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
- cons->matches[1]=name;
- name=NULL;
- filt->lines[0]->realm_cons=cons;
-
- /* put the filter in a set */
- filt_set=tr_filter_set_new(tmp_ctx);
- if ((filt_set==NULL)||(0!=tr_filter_set_add(filt_set, filt))) {
- tr_debug("tr_cfg_default_filters: could not allocate filter set.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
- talloc_steal(mem_ctx, filt_set);
-
-cleanup:
- talloc_free(tmp_ctx);
-
- if (*rc!=TR_CFG_SUCCESS)
- filt=NULL;
-
- if (n_prefix!=NULL)
- tr_free_name(n_prefix);
- if (n_rp_realm_1!=NULL)
- tr_free_name(n_rp_realm_1);
- if (n_rp_realm_2!=NULL)
- tr_free_name(n_rp_realm_2);
- if (n_realm!=NULL)
- tr_free_name(n_realm);
- if (n_domain!=NULL)
- tr_free_name(n_domain);
- if (name!=NULL)
- tr_free_name(name);
-
- return filt_set;
-}
-
-/* parses rp client */
-static TR_RP_CLIENT *tr_cfg_parse_one_rp_client(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
-{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- TR_RP_CLIENT *client=NULL;
- TR_CFG_RC call_rc=TR_CFG_ERROR;
- TR_FILTER_SET *new_filts=NULL;
- TR_NAME *realm=NULL;
- json_t *jfilt=NULL;
- json_t *jrealm_id=NULL;
-
- *rc=TR_CFG_ERROR; /* default to error if not set */
-
- if ((!jrealm) || (!rc)) {
- tr_err("tr_cfg_parse_one_rp_client: Bad parameters.");
- if (rc)
- *rc=TR_CFG_BAD_PARAMS;
- goto cleanup;
- }
-
- if ((NULL==(jrealm_id=json_object_get(jrealm, "realm"))) || (!json_is_string(jrealm_id))) {
- tr_debug("tr_cfg_parse_one_rp_client: no realm ID found.");
- *rc=TR_CFG_BAD_PARAMS;
- goto cleanup;
- }
-
- tr_debug("tr_cfg_parse_one_rp_client: realm_id=\"%s\"", json_string_value(jrealm_id));
- realm=tr_new_name(json_string_value(jrealm_id));
- if (realm==NULL) {
- tr_err("tr_cfg_parse_one_rp_client: could not allocate realm ID.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
-
- if (NULL==(client=tr_rp_client_new(tmp_ctx))) {
- tr_err("tr_cfg_parse_one_rp_client: could not allocate rp client.");
- *rc=TR_CFG_NOMEM;
- goto cleanup;
- }
-
- client->gss_names=tr_cfg_parse_gss_names(client, json_object_get(jrealm, "gss_names"), &call_rc);
-
- if (call_rc!=TR_CFG_SUCCESS) {
- tr_err("tr_cfg_parse_one_rp_client: could not parse gss_names.");
- *rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- /* parse filters */
- jfilt=json_object_get(jrealm, "filters");
- if (jfilt!=NULL) {
- new_filts=tr_cfg_parse_filters(tmp_ctx, jfilt, &call_rc);
- if (call_rc!=TR_CFG_SUCCESS) {
- tr_err("tr_cfg_parse_one_rp_client: could not parse filters.");
- *rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
- } else {
- tr_debug("tr_cfg_parse_one_rp_client: no filters specified, using default filters.");
- new_filts= tr_cfg_default_filters(tmp_ctx, realm, &call_rc);
- if (call_rc!=TR_CFG_SUCCESS) {
- tr_err("tr_cfg_parse_one_rp_client: could not set default filters.");
- *rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
- }
-
- tr_rp_client_set_filters(client, new_filts);
- *rc=TR_CFG_SUCCESS;
-
- cleanup:
- if (realm!=NULL)
- tr_free_name(realm);
-
- if (*rc==TR_CFG_SUCCESS)
- talloc_steal(mem_ctx, client);
- else {
- talloc_free(client);
- client=NULL;
- }
-
- talloc_free(tmp_ctx);
- return client;
-}
-
- /* Determine whether the realm is an RP realm */
-static int tr_cfg_is_rp_realm(json_t *jrealm)
-{
- /* Check that we have a gss name. */
- if (NULL != json_object_get(jrealm, "gss_names"))
- return 1;
- else
- return 0;
-}
-
-/* Parse any rp clients in the j_realms object. Ignores other realms. */
-static TR_RP_CLIENT *tr_cfg_parse_rp_clients(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc)
-{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- TR_RP_CLIENT *clients=NULL;
- TR_RP_CLIENT *new_client=NULL;
- json_t *this_jrealm=NULL;
- int ii=0;
-
- *rc=TR_CFG_ERROR;
- if ((jrealms==NULL) || (!json_is_array(jrealms))) {
- tr_err("tr_cfg_parse_rp_clients: realms not an array");
- *rc=TR_CFG_BAD_PARAMS;
- goto cleanup;
- }
-
- for (ii=0; ii<json_array_size(jrealms); ii++) {
- this_jrealm=json_array_get(jrealms, ii);
- if (tr_cfg_is_rp_realm(this_jrealm)) {
- new_client=tr_cfg_parse_one_rp_client(tmp_ctx, this_jrealm, rc);
- if ((*rc)!=TR_CFG_SUCCESS) {
- tr_err("tr_cfg_parse_rp_clients: error decoding realm entry %d", ii+1);
- *rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
- tr_rp_client_add(clients, new_client);
- }
- }
-
- *rc=TR_CFG_SUCCESS;
- talloc_steal(mem_ctx, clients);
-
-cleanup:
- talloc_free(tmp_ctx);
- return clients;
-}
-
-/* takes a talloc context, but currently does not use it */
-static TR_NAME *tr_cfg_parse_org_name(TALLOC_CTX *mem_ctx, json_t *j_org, TR_CFG_RC *rc)
+static int tr_cfg_destructor(void *object)
{
- TR_NAME *name=NULL;
-
- if ((j_org==NULL) || (rc==NULL) || (!json_is_string(j_org))) {
- tr_debug("tr_cfg_parse_org_name: Bad parameters.");
- if (rc!=NULL)
- *rc = TR_CFG_BAD_PARAMS; /* fill in return value if we can */
- return NULL;
- }
-
- name=tr_new_name(json_string_value(j_org));
- if (name==NULL)
- *rc=TR_CFG_NOMEM;
- else
- *rc=TR_CFG_SUCCESS;
- return name;
-}
-
-static TR_CFG_RC tr_cfg_parse_one_local_org(TR_CFG *trc, json_t *jlorg)
-{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- TR_CFG_RC retval=TR_CFG_ERROR; /* our return code */
- TR_CFG_RC rc=TR_CFG_ERROR; /* return code from functions we call */
- TR_NAME *org_name=NULL;
- json_t *j_org=NULL;
- json_t *j_realms=NULL;
- TR_IDP_REALM *new_idp_realms=NULL;
- TR_RP_CLIENT *new_rp_clients=NULL;
-
- tr_debug("tr_cfg_parse_one_local_org: parsing local organization");
-
- /* get organization_name (optional) */
- if (NULL==(j_org=json_object_get(jlorg, "organization_name"))) {
- tr_debug("tr_cfg_parse_one_local_org: organization_name unspecified");
- } else {
- org_name=tr_cfg_parse_org_name(tmp_ctx, j_org, &rc);
- if (rc==TR_CFG_SUCCESS) {
- tr_debug("tr_cfg_parse_one_local_org: organization_name=\"%.*s\"",
- org_name->len,
- org_name->buf);
- /* we don't actually do anything with this, but we could */
- tr_free_name(org_name);
- org_name=NULL;
- }
- }
-
- /* Now get realms. Allow this to be missing; even though that is a pointless organization entry,
- * it's harmless. Report a warning because that might be unintentional. */
- if (NULL==(j_realms=json_object_get(jlorg, "realms"))) {
- tr_warning("tr_cfg_parse_one_local_org: warning - no realms in this local organization");
- } else {
- /* Allocate in the tmp_ctx so these will be cleaned up if we do not complete successfully. */
- new_idp_realms=tr_cfg_parse_idp_realms(tmp_ctx, j_realms, &rc);
- if (rc!=TR_CFG_SUCCESS)
- goto cleanup;
-
- new_rp_clients=tr_cfg_parse_rp_clients(tmp_ctx, j_realms, &rc);
- if (rc!=TR_CFG_SUCCESS)
- goto cleanup;
- }
- retval=TR_CFG_SUCCESS;
-
-cleanup:
- /* if we succeeded, link things to the configuration and move out of tmp context */
- if (retval==TR_CFG_SUCCESS) {
- if (new_idp_realms!=NULL) {
- tr_idp_realm_add(trc->ctable->idp_realms, new_idp_realms); /* fixes talloc contexts except for head*/
- talloc_steal(trc, trc->ctable->idp_realms); /* make sure the head is in the right context */
- }
-
- if (new_rp_clients!=NULL) {
- tr_rp_client_add(trc->rp_clients, new_rp_clients); /* fixes talloc contexts */
- talloc_steal(trc, trc->rp_clients); /* make sure head is in the right context */
- }
- }
-
- talloc_free(tmp_ctx);
- return rc;
+ TR_CFG *cfg = talloc_get_type_abort(object, TR_CFG);
+ if (cfg->files)
+ g_array_unref(cfg->files);
+ return 0;
}
-
-/* Parse local organizations if present. Returns success if there are none. On failure, the configuration is unreliable. */
-static TR_CFG_RC tr_cfg_parse_local_orgs(TR_CFG *trc, json_t *jcfg)
+TR_CFG *tr_cfg_new(TALLOC_CTX *mem_ctx)
{
- json_t *jlocorgs=NULL;
- size_t ii=0;
-
- jlocorgs=json_object_get(jcfg, "local_organizations");
- if (jlocorgs==NULL)
- return TR_CFG_SUCCESS;
-
- if (!json_is_array(jlocorgs)) {
- tr_err("tr_cfg_parse_local_orgs: local_organizations is not an array.");
- return TR_CFG_NOPARSE;
- }
-
- for (ii=0; ii<json_array_size(jlocorgs); ii++) {
- if (tr_cfg_parse_one_local_org(trc, json_array_get(jlocorgs, ii))!=TR_CFG_SUCCESS) {
- tr_err("tr_cfg_parse_local_orgs: error parsing local_organization %d.", ii+1);
- return TR_CFG_NOPARSE;
+ TR_CFG *cfg=talloc(mem_ctx, TR_CFG);
+ if (cfg!=NULL) {
+ cfg->internal=NULL;
+ cfg->rp_clients=NULL;
+ cfg->peers=NULL;
+ cfg->default_servers=NULL;
+ cfg->ctable=tr_comm_table_new(cfg);
+ if (cfg->ctable==NULL) {
+ talloc_free(cfg);
+ return NULL;
}
- }
-
- return TR_CFG_SUCCESS;
-}
-
-static TR_CFG_RC tr_cfg_parse_one_peer_org(TR_CFG *trc, json_t *jporg)
-{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- json_t *jhost=NULL;
- json_t *jport=NULL;
- json_t *jgss=NULL;
- json_t *jfilt=NULL;
- TRP_PEER *new_peer=NULL;
- TR_GSS_NAMES *names=NULL;
- TR_FILTER_SET *filt_set=NULL;
- TR_CFG_RC rc=TR_CFG_ERROR;
-
- jhost=json_object_get(jporg, "hostname");
- jport=json_object_get(jporg, "port");
- jgss=json_object_get(jporg, "gss_names");
- jfilt=json_object_get(jporg, "filters");
-
- if ((jhost==NULL) || (!json_is_string(jhost))) {
- tr_err("tr_cfg_parse_one_peer_org: hostname not specified or not a string.");
- rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- if ((jport!=NULL) && (!json_is_number(jport))) {
- /* note that not specifying the port is allowed, but if set it must be a number */
- tr_err("tr_cfg_parse_one_peer_org: port is not a number.");
- rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- if ((jgss==NULL) || (!json_is_array(jgss))) {
- tr_err("tr_cfg_parse_one_peer_org: gss_names not specified or not an array.");
- rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- if ((jfilt!=NULL) && (!json_is_object(jfilt))) {
- tr_err("tr_cfg_parse_one_peer_org: filters is not an object.");
- rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
-
- new_peer=trp_peer_new(tmp_ctx);
- if (new_peer==NULL) {
- tr_err("tr_cfg_parse_one_peer_org: could not allocate new peer.");
- rc=TR_CFG_NOMEM;
- goto cleanup;
- }
-
- trp_peer_set_server(new_peer, json_string_value(jhost)); /* string is strdup'ed in _set_server() */
- if (jport==NULL)
- trp_peer_set_port(new_peer, TRP_PORT);
- else
- trp_peer_set_port(new_peer, json_integer_value(jport));
-
- names=tr_cfg_parse_gss_names(tmp_ctx, jgss, &rc);
- if (rc!=TR_CFG_SUCCESS) {
- tr_err("tr_cfg_parse_one_peer_org: unable to parse gss names.");
- rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
- trp_peer_set_gss_names(new_peer, names);
-
- if (jfilt) {
- filt_set=tr_cfg_parse_filters(tmp_ctx, jfilt, &rc);
- if (rc!=TR_CFG_SUCCESS) {
- tr_err("tr_cfg_parse_one_peer_org: unable to parse filters.");
- rc=TR_CFG_NOPARSE;
- goto cleanup;
+ cfg->files = g_array_new(FALSE, FALSE, sizeof(TR_CFG_FILE));
+ if (cfg->files == NULL) {
+ talloc_free(cfg);
+ return NULL;
}
- trp_peer_set_filters(new_peer, filt_set);
+ talloc_set_destructor((void *)cfg, tr_cfg_destructor);
}
-
- /* success! */
- trp_ptable_add(trc->peers, new_peer);
- rc=TR_CFG_SUCCESS;
-
- cleanup:
- talloc_free(tmp_ctx);
- return rc;
+ return cfg;
}
-/* Parse peer organizations, if present. Returns success if there are none. */
-static TR_CFG_RC tr_cfg_parse_peer_orgs(TR_CFG *trc, json_t *jcfg)
-{
- json_t *jpeerorgs=NULL;
- int ii=0;
-
- jpeerorgs=json_object_get(jcfg, "peer_organizations");
- if (jpeerorgs==NULL)
- return TR_CFG_SUCCESS;
-
- if (!json_is_array(jpeerorgs)) {
- tr_err("tr_cfg_parse_peer_orgs: peer_organizations is not an array.");
- return TR_CFG_NOPARSE;
- }
-
- for (ii=0; ii<json_array_size(jpeerorgs); ii++) {
- if (tr_cfg_parse_one_peer_org(trc, json_array_get(jpeerorgs, ii))!=TR_CFG_SUCCESS) {
- tr_err("tr_cfg_parse_peer_orgs: error parsing peer_organization %d.", ii+1);
- return TR_CFG_NOPARSE;
- }
- }
-
- return TR_CFG_SUCCESS;
-}
-
-static TR_CFG_RC tr_cfg_parse_default_servers (TR_CFG *trc, json_t *jcfg)
+void tr_cfg_free (TR_CFG *cfg)
{
- json_t *jdss = NULL;
- TR_CFG_RC rc = TR_CFG_SUCCESS;
- TR_AAA_SERVER *ds = NULL;
- int i = 0;
-
- if ((!trc) || (!jcfg))
- return TR_CFG_BAD_PARAMS;
-
- /* If there are default servers, store them */
- if ((NULL != (jdss = json_object_get(jcfg, "default_servers"))) &&
- (json_is_array(jdss)) &&
- (0 < json_array_size(jdss))) {
-
- for (i = 0; i < json_array_size(jdss); i++) {
- if (NULL == (ds = tr_cfg_parse_one_aaa_server(trc,
- json_array_get(jdss, i),
- &rc))) {
- return rc;
- }
- tr_debug("tr_cfg_parse_default_servers: Default server configured: %s", ds->hostname->buf);
- ds->next = trc->default_servers;
- trc->default_servers = ds;
- }
- }
-
- tr_debug("tr_cfg_parse_default_servers: Finished (rc=%d)", rc);
- return rc;
+ talloc_free(cfg);
}
-static void tr_cfg_parse_comm_idps(TR_CFG *trc, json_t *jidps, TR_COMM *comm, TR_CFG_RC *rc)
+TR_CFG_MGR *tr_cfg_mgr_new(TALLOC_CTX *mem_ctx)
{
- TR_IDP_REALM *found_idp=NULL;
- json_t *jidp_name=NULL;
- TR_NAME *idp_name=NULL;
- size_t ii = 0;
-
- if ((!trc) ||
- (!jidps) ||
- (!json_is_array(jidps))) {
- if (rc)
- *rc = TR_CFG_BAD_PARAMS;
- return;
- }
-
- json_array_foreach(jidps, ii, jidp_name) {
- idp_name=tr_new_name(json_string_value(jidp_name));
- if (idp_name==NULL) {
- *rc = TR_CFG_NOMEM;
- return;
- }
- found_idp=tr_cfg_find_idp(trc, idp_name, rc);
- tr_free_name(idp_name);
-
- if ((found_idp==NULL) || (*rc!=TR_CFG_SUCCESS)) {
- tr_debug("tr_cfg_parse_comm_idps: Unknown IDP %s.", json_string_value(jidp_name));
- *rc=TR_CFG_ERROR;
- return;
- }
- tr_comm_add_idp_realm(trc->ctable, comm, found_idp, 0, NULL, NULL); /* no provenance, never expires */
- }
-
- *rc=TR_CFG_SUCCESS;
- return;
+ return talloc_zero(mem_ctx, TR_CFG_MGR);
}
-static void tr_cfg_parse_comm_rps(TR_CFG *trc, json_t *jrps, TR_COMM *comm, TR_CFG_RC *rc)
-{
- TR_RP_REALM *found_rp=NULL;
- TR_RP_REALM *new_rp=NULL;
- TR_NAME *rp_name=NULL;
- const char *s=NULL;
- int ii=0;
-
- if ((!trc) ||
- (!jrps) ||
- (!json_is_array(jrps))) {
- if (rc)
- *rc = TR_CFG_BAD_PARAMS;
- return;
- }
-
- for (ii=0; ii<json_array_size(jrps); ii++) {
- /* get the RP name as a string */
- s=json_string_value(json_array_get(jrps, ii));
- if (s==NULL) {
- tr_notice("tr_cfg_parse_comm_rps: null RP found in community %.*s, ignoring.",
- tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
- continue;
- }
-
- /* convert string to TR_NAME */
- rp_name=tr_new_name(s);
- if (rp_name==NULL) {
- tr_err("tr_cfg_parse_comm_rps: unable to allocate RP name for %s in community %.*s.",
- s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
- }
-
- /* see if we already have this RP in this community */
- found_rp=tr_comm_find_rp(trc->ctable, comm, rp_name);
- if (found_rp!=NULL) {
- tr_notice("tr_cfg_parse_comm_rps: RP %s repeated in community %.*s.",
- s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
- tr_free_name(rp_name);
- continue;
- }
-
- /* Add the RP to the community, first see if we have the RP in any community */
- found_rp=tr_rp_realm_lookup(trc->ctable->rp_realms, rp_name);
- if (found_rp!=NULL) {
- tr_debug("tr_cfg_parse_comm_rps: RP realm %s already exists.", s);
- new_rp=found_rp; /* use it rather than creating a new realm record */
- } else {
- new_rp=tr_rp_realm_new(NULL);
- if (new_rp==NULL) {
- tr_err("tr_cfg_parse_comm_rps: unable to allocate RP record for %s in community %.*s.",
- s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
- }
- tr_debug("tr_cfg_parse_comm_rps: setting name to %s", rp_name->buf);
- tr_rp_realm_set_id(new_rp, rp_name);
- rp_name=NULL; /* rp_name no longer belongs to us */
- tr_rp_realm_add(trc->ctable->rp_realms, new_rp);
- talloc_steal(trc->ctable, trc->ctable->rp_realms); /* make sure head is in the right context */
- }
- tr_comm_add_rp_realm(trc->ctable, comm, new_rp, 0, NULL, NULL);
- }
+void tr_cfg_mgr_free (TR_CFG_MGR *cfg_mgr) {
+ talloc_free(cfg_mgr);
}
-static TR_COMM *tr_cfg_parse_one_comm (TALLOC_CTX *mem_ctx, TR_CFG *trc, json_t *jcomm, TR_CFG_RC *rc)
+TR_CFG_RC tr_apply_new_config (TR_CFG_MGR *cfg_mgr)
{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- TR_COMM *comm = NULL;
- json_t *jid = NULL;
- json_t *jtype = NULL;
- json_t *japcs = NULL;
- json_t *jidps = NULL;
- json_t *jrps = NULL;
-
- if ((!trc) || (!jcomm) || (!rc)) {
- tr_debug("tr_cfg_parse_one_comm: Bad parameters.");
- if (rc)
- *rc = TR_CFG_BAD_PARAMS;
- goto cleanup;
- }
-
- comm=tr_comm_new(tmp_ctx);
- if (comm==NULL) {
- tr_crit("tr_cfg_parse_one_comm: Out of memory.");
- *rc = TR_CFG_NOMEM;
- goto cleanup;
- }
-
-
- if ((NULL == (jid = json_object_get(jcomm, "community_id"))) ||
- (!json_is_string(jid)) ||
- (NULL == (jtype = json_object_get(jcomm, "type"))) ||
- (!json_is_string(jtype)) ||
- (NULL == (japcs = json_object_get(jcomm, "apcs"))) ||
- (!json_is_array(japcs)) ||
- (NULL == (jidps = json_object_get(jcomm, "idp_realms"))) ||
- (!json_is_array(jidps)) ||
- (NULL == (jrps = json_object_get(jcomm, "rp_realms"))) ||
- (!json_is_array(jrps))) {
- tr_debug("tr_cfg_parse_one_comm: Error parsing Communities configuration.");
- *rc = TR_CFG_NOPARSE;
- comm=NULL;
- goto cleanup;
- }
-
- tr_comm_set_id(comm, tr_new_name(json_string_value(jid)));
- if (NULL == tr_comm_get_id(comm)) {
- tr_debug("tr_cfg_parse_one_comm: No memory for community id.");
- *rc = TR_CFG_NOMEM;
- comm=NULL;
- goto cleanup;
- }
-
- if (0 == strcmp(json_string_value(jtype), "apc")) {
- comm->type = TR_COMM_APC;
- } else if (0 == strcmp(json_string_value(jtype), "coi")) {
- comm->type = TR_COMM_COI;
- if (NULL == (comm->apcs = tr_cfg_parse_apcs(trc, japcs, rc))) {
- tr_debug("tr_cfg_parse_one_comm: Can't parse APCs for COI %s.",
- tr_comm_get_id(comm)->buf);
- comm=NULL;
- goto cleanup;
- }
- } else {
- tr_debug("tr_cfg_parse_one_comm: Invalid community type, comm = %s, type = %s",
- tr_comm_get_id(comm)->buf, json_string_value(jtype));
- *rc = TR_CFG_NOPARSE;
- comm=NULL;
- goto cleanup;
- }
+ /* cfg_mgr->active is allowed to be null, but new cannot be */
+ if ((cfg_mgr==NULL) || (cfg_mgr->new==NULL))
+ return TR_CFG_BAD_PARAMS;
- tr_cfg_parse_comm_idps(trc, jidps, comm, rc);
- if (TR_CFG_SUCCESS != *rc) {
- tr_debug("tr_cfg_parse_one_comm: Can't parse IDP realms for comm %s.",
- tr_comm_get_id(comm)->buf);
- comm=NULL;
- goto cleanup;
- }
+ if (cfg_mgr->active != NULL)
+ tr_cfg_free(cfg_mgr->active);
- tr_cfg_parse_comm_rps(trc, jrps, comm, rc);
- if (TR_CFG_SUCCESS != *rc) {
- tr_debug("tr_cfg_parse_one_comm: Can't parse RP realms for comm %s .",
- tr_comm_get_id(comm)->buf);
- comm=NULL;
- goto cleanup;
- }
+ cfg_mgr->active = cfg_mgr->new;
+ cfg_mgr->new=NULL; /* only keep a single handle on the new configuration */
- if (TR_COMM_APC == comm->type) {
- json_t *jexpire = json_object_get(jcomm, "expiration_interval");
- comm->expiration_interval = 43200; /*30 days*/
- if (jexpire) {
- if (!json_is_integer(jexpire)) {
- tr_err("tr_parse_one_comm: expiration_interval is not an integer for comm %.*s",
- tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
- comm=NULL;
- goto cleanup;
- }
- comm->expiration_interval = json_integer_value(jexpire);
- if (comm->expiration_interval <= 10) {
- comm->expiration_interval = 11; /* Freeradius waits 10 minutes between successful TR queries*/
- tr_notice(
- "tr_parse_one_comm: expiration interval for %.*s less than minimum of 11 minutes; using 11 minutes instead.",
- tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
- }
- if (comm->expiration_interval > 129600) {
- /* > 90 days*/
- comm->expiration_interval = 129600;
- tr_notice(
- "tr_parse_one_comm: expiration interval for %.*s exceeds maximum of 90 days; using 90 days instead.",
- tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
- }
- }
- }
+ tr_log_threshold(cfg_mgr->active->internal->log_threshold);
+ tr_console_threshold(cfg_mgr->active->internal->console_threshold);
-cleanup:
- if (comm!=NULL)
- talloc_steal(mem_ctx, comm);
- talloc_free(tmp_ctx);
- return comm;
+ return TR_CFG_SUCCESS;
}
-static TR_CFG_RC tr_cfg_parse_comms (TR_CFG *trc, json_t *jcfg)
-{
- json_t *jcomms = NULL;
- TR_CFG_RC rc = TR_CFG_SUCCESS;
- TR_COMM *comm = NULL;
- int i = 0;
-
- if ((!trc) || (!jcfg)) {
- tr_debug("tr_cfg_parse_comms: Bad Parameters.");
- return TR_CFG_BAD_PARAMS;
- }
-
- if (NULL != (jcomms = json_object_get(jcfg, "communities"))) {
- if (!json_is_array(jcomms)) {
- return TR_CFG_NOPARSE;
- }
-
- for (i = 0; i < json_array_size(jcomms); i++) {
- if (NULL == (comm = tr_cfg_parse_one_comm(NULL, /* TODO: use a talloc context */
- trc,
- json_array_get(jcomms, i),
- &rc))) {
- return rc;
- }
- tr_debug("tr_cfg_parse_comms: Community configured: %s.",
- tr_comm_get_id(comm)->buf);
-
- tr_comm_table_add_comm(trc->ctable, comm);
- }
- }
- tr_debug("tr_cfg_parse_comms: Finished (rc=%d)", rc);
- return rc;
-}
TR_CFG_RC tr_cfg_validate(TR_CFG *trc)
{
static json_t *tr_cfg_parse_one_config_file(const char *file_with_path)
{
json_t *jcfg=NULL;
- json_t *jser=NULL;
json_error_t rc;
if (NULL==(jcfg=json_load_file(file_with_path,
return NULL;
}
- // Look for serial number and log it if it exists (borrowed reference, so no need to free it later)
- if (NULL!=(jser=json_object_get(jcfg, "serial_number"))) {
- if (json_is_number(jser)) {
- tr_notice("tr_parse_one_config_file: Attempting to load revision %" JSON_INTEGER_FORMAT " of '%s'.",
- json_integer_value(jser),
- file_with_path);
+ return jcfg;
+}
+
+/* extract serial number */
+static json_int_t get_cfg_serial(json_t *jcfg)
+{
+ json_t *jser=NULL;
+
+ if (NULL != (jser = json_object_get(jcfg, "serial_number"))) {
+ if (json_is_integer(jser)) {
+ return json_integer_value(jser);
}
}
-
- return jcfg;
+ return TR_CFG_INVALID_SERIAL;
}
/**
* @param cfg_files
* @return
*/
-static json_t **tr_cfg_parse_config_files(TALLOC_CTX *mem_ctx, unsigned int n_files, char **files_with_paths)
+static json_t **tr_cfg_parse_config_files(TALLOC_CTX *mem_ctx, unsigned int n_files, GArray *files)
{
TALLOC_CTX *tmp_ctx=talloc_new(NULL);
unsigned int ii=0;
json_t **jcfgs=NULL;
+ TR_CFG_FILE *this_file = NULL;
/* first allocate the jcfgs */
jcfgs=talloc_array(NULL, json_t *, n_files);
goto cleanup;
}
for (ii=0; ii<n_files; ii++) {
- jcfgs[ii]=tr_cfg_parse_one_config_file(files_with_paths[ii]);
+ this_file = &g_array_index(files, TR_CFG_FILE, ii);
+ jcfgs[ii]=tr_cfg_parse_one_config_file(this_file->name);
if (jcfgs[ii]==NULL) {
- tr_err("tr_parse_config: Error parsing JSON in %s", files_with_paths[ii]);
+ tr_err("tr_parse_config: Error parsing JSON in %s", this_file->name);
tr_cfg_parse_free_jcfgs(ii, jcfgs); /* frees the JSON objects and the jcfgs array */
jcfgs=NULL;
goto cleanup;
}
+
+ this_file->serial = get_cfg_serial(jcfgs[ii]);
+ if (this_file->serial != TR_CFG_INVALID_SERIAL) {
+ tr_notice("tr_parse_one_config_file: Attempting to load revision %"
+ JSON_INTEGER_FORMAT
+ " of '%s'.",
+ this_file->serial,
+ this_file->name);
+ } else {
+ tr_notice("tr_parse_one_config_file: Attempting to load '%s'.",
+ this_file->name);
+ }
}
+
cleanup:
if (jcfgs)
talloc_steal(mem_ctx, jcfgs); /* give this to the caller's context if we succeeded */
* 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;
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;
return ret;
}
+static void add_files(TR_CFG *cfg, unsigned int n, char **filenames)
+{
+ TR_CFG_FILE frec = {0};
+
+ while ((n--) > 0) {
+ frec.name = talloc_strdup(cfg, filenames[n]);
+ frec.serial = TR_CFG_INVALID_SERIAL;
+
+ g_array_append_val(cfg->files, frec);
+ }
+}
/**
- * Reads configuration files in config_dir ("" or "./" will use the current directory).
+ * Read a list of configuration files
*
* @param cfg_mgr Configuration manager
* @param n_files Number of entries in cfg_files
goto cleanup;
}
+ /* add the list of files to the config */
+ add_files(cfg_mgr->new, n_files, files_with_paths);
+
/* first parse the json */
- jcfgs=tr_cfg_parse_config_files(tmp_ctx, n_files, files_with_paths);
+ jcfgs=tr_cfg_parse_config_files(tmp_ctx, n_files, cfg_mgr->new->files);
if (jcfgs==NULL) {
cfg_rc=TR_CFG_NOPARSE;
goto cleanup;
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 */
return cfg_rc;
}
-TR_IDP_REALM *tr_cfg_find_idp (TR_CFG *tr_cfg, TR_NAME *idp_id, TR_CFG_RC *rc)
-{
-
- TR_IDP_REALM *cfg_idp;
-
- if ((!tr_cfg) || (!idp_id)) {
- if (rc)
- *rc = TR_CFG_BAD_PARAMS;
- return NULL;
- }
-
- for (cfg_idp = tr_cfg->ctable->idp_realms; NULL != cfg_idp; cfg_idp = cfg_idp->next) {
- if (!tr_name_cmp (idp_id, cfg_idp->realm_id)) {
- tr_debug("tr_cfg_find_idp: Found %s.", idp_id->buf);
- return cfg_idp;
- }
- }
- /* if we didn't find one, return NULL */
- return NULL;
-}
-
-TR_RP_CLIENT *tr_cfg_find_rp (TR_CFG *tr_cfg, TR_NAME *rp_gss, TR_CFG_RC *rc)
-{
- TR_RP_CLIENT *cfg_rp;
-
- if ((!tr_cfg) || (!rp_gss)) {
- if (rc)
- *rc = TR_CFG_BAD_PARAMS;
- return NULL;
- }
-
- for (cfg_rp = tr_cfg->rp_clients; NULL != cfg_rp; cfg_rp = cfg_rp->next) {
- if (tr_gss_names_matches(cfg_rp->gss_names, rp_gss)) {
- tr_debug("tr_cfg_find_rp: Found %s.", rp_gss->buf);
- return cfg_rp;
- }
- }
- /* if we didn't find one, return NULL */
- return NULL;
-}
-
static int is_cfg_file(const struct dirent *dent) {
- int n;
+ size_t n;
/* Only accept filenames ending in ".cfg" and starting with a character
* other than an ASCII '.' */
--- /dev/null
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <jansson.h>
+#include <dirent.h>
+#include <talloc.h>
+
+#include <tr_cfgwatch.h>
+#include <tr_comm.h>
+#include <tr_config.h>
+#include <tr_gss_names.h>
+#include <tr_debug.h>
+#include <tr_filter.h>
+#include <trust_router/tr_constraint.h>
+#include <tr_idp.h>
+#include <tr.h>
+#include <trust_router/trp.h>
+
+#if JANSSON_VERSION_HEX < 0x020500
+#include "jansson_iterators.h"
+#endif
+
+TR_CFG_RC tr_cfg_parse_default_servers (TR_CFG *trc, json_t *jcfg)
+{
+ json_t *jdss = NULL;
+ TR_CFG_RC rc = TR_CFG_SUCCESS;
+ TR_AAA_SERVER *ds = NULL;
+ int i = 0;
+
+ if ((!trc) || (!jcfg))
+ return TR_CFG_BAD_PARAMS;
+
+ /* If there are default servers, store them */
+ if ((NULL != (jdss = json_object_get(jcfg, "default_servers"))) &&
+ (json_is_array(jdss)) &&
+ (0 < json_array_size(jdss))) {
+
+ for (i = 0; i < json_array_size(jdss); i++) {
+ if (NULL == (ds = tr_cfg_parse_one_aaa_server(trc,
+ json_array_get(jdss, i),
+ &rc))) {
+ return rc;
+ }
+ tr_debug("tr_cfg_parse_default_servers: Default server configured: %s", ds->hostname->buf);
+ ds->next = trc->default_servers;
+ trc->default_servers = ds;
+ }
+ }
+
+ tr_debug("tr_cfg_parse_default_servers: Finished (rc=%d)", rc);
+ return rc;
+}
+
+static void tr_cfg_parse_comm_idps(TR_CFG *trc, json_t *jidps, TR_COMM *comm, TR_CFG_RC *rc)
+{
+ TR_IDP_REALM *found_idp=NULL;
+ json_t *jidp_name=NULL;
+ TR_NAME *idp_name=NULL;
+ size_t ii = 0;
+
+ if ((!trc) ||
+ (!jidps) ||
+ (!json_is_array(jidps))) {
+ if (rc)
+ *rc = TR_CFG_BAD_PARAMS;
+ return;
+ }
+
+ json_array_foreach(jidps, ii, jidp_name) {
+ idp_name=tr_new_name(json_string_value(jidp_name));
+ if (idp_name==NULL) {
+ *rc = TR_CFG_NOMEM;
+ return;
+ }
+ found_idp=tr_cfg_find_idp(trc, idp_name, rc);
+ tr_free_name(idp_name);
+
+ if ((found_idp==NULL) || (*rc!=TR_CFG_SUCCESS)) {
+ tr_debug("tr_cfg_parse_comm_idps: Unknown IDP %s.", json_string_value(jidp_name));
+ *rc=TR_CFG_ERROR;
+ return;
+ }
+ tr_comm_add_idp_realm(trc->ctable, comm, found_idp, 0, NULL, NULL); /* no provenance, never expires */
+ }
+
+ *rc=TR_CFG_SUCCESS;
+ return;
+}
+
+static void tr_cfg_parse_comm_rps(TR_CFG *trc, json_t *jrps, TR_COMM *comm, TR_CFG_RC *rc)
+{
+ TR_RP_REALM *found_rp=NULL;
+ TR_RP_REALM *new_rp=NULL;
+ TR_NAME *rp_name=NULL;
+ const char *s=NULL;
+ int ii=0;
+
+ if ((!trc) ||
+ (!jrps) ||
+ (!json_is_array(jrps))) {
+ if (rc)
+ *rc = TR_CFG_BAD_PARAMS;
+ return;
+ }
+
+ for (ii=0; ii<json_array_size(jrps); ii++) {
+ /* get the RP name as a string */
+ s=json_string_value(json_array_get(jrps, ii));
+ if (s==NULL) {
+ tr_notice("tr_cfg_parse_comm_rps: null RP found in community %.*s, ignoring.",
+ tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
+ continue;
+ }
+
+ /* convert string to TR_NAME */
+ rp_name=tr_new_name(s);
+ if (rp_name==NULL) {
+ tr_err("tr_cfg_parse_comm_rps: unable to allocate RP name for %s in community %.*s.",
+ s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
+ }
+
+ /* see if we already have this RP in this community */
+ found_rp=tr_comm_find_rp(trc->ctable, comm, rp_name);
+ if (found_rp!=NULL) {
+ tr_notice("tr_cfg_parse_comm_rps: RP %s repeated in community %.*s.",
+ s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
+ tr_free_name(rp_name);
+ continue;
+ }
+
+ /* Add the RP to the community, first see if we have the RP in any community */
+ found_rp=tr_rp_realm_lookup(trc->ctable->rp_realms, rp_name);
+ if (found_rp!=NULL) {
+ tr_debug("tr_cfg_parse_comm_rps: RP realm %s already exists.", s);
+ new_rp=found_rp; /* use it rather than creating a new realm record */
+ } else {
+ new_rp=tr_rp_realm_new(NULL);
+ if (new_rp==NULL) {
+ tr_err("tr_cfg_parse_comm_rps: unable to allocate RP record for %s in community %.*s.",
+ s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
+ }
+ tr_debug("tr_cfg_parse_comm_rps: setting name to %s", rp_name->buf);
+ tr_rp_realm_set_id(new_rp, rp_name);
+ rp_name=NULL; /* rp_name no longer belongs to us */
+ tr_rp_realm_add(trc->ctable->rp_realms, new_rp);
+ talloc_steal(trc->ctable, trc->ctable->rp_realms); /* make sure head is in the right context */
+ }
+ tr_comm_add_rp_realm(trc->ctable, comm, new_rp, 0, NULL, NULL);
+ }
+}
+
+static TR_COMM *tr_cfg_parse_one_comm (TALLOC_CTX *mem_ctx, TR_CFG *trc, json_t *jcomm, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_COMM *comm = NULL;
+ json_t *jid = NULL;
+ json_t *jtype = NULL;
+ json_t *japcs = NULL;
+ json_t *jidps = NULL;
+ json_t *jrps = NULL;
+
+ if ((!trc) || (!jcomm) || (!rc)) {
+ tr_debug("tr_cfg_parse_one_comm: Bad parameters.");
+ if (rc)
+ *rc = TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ comm=tr_comm_new(tmp_ctx);
+ if (comm==NULL) {
+ tr_crit("tr_cfg_parse_one_comm: Out of memory.");
+ *rc = TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+
+ if ((NULL == (jid = json_object_get(jcomm, "community_id"))) ||
+ (!json_is_string(jid)) ||
+ (NULL == (jtype = json_object_get(jcomm, "type"))) ||
+ (!json_is_string(jtype)) ||
+ (NULL == (japcs = json_object_get(jcomm, "apcs"))) ||
+ (!json_is_array(japcs)) ||
+ (NULL == (jidps = json_object_get(jcomm, "idp_realms"))) ||
+ (!json_is_array(jidps)) ||
+ (NULL == (jrps = json_object_get(jcomm, "rp_realms"))) ||
+ (!json_is_array(jrps))) {
+ tr_debug("tr_cfg_parse_one_comm: Error parsing Communities configuration.");
+ *rc = TR_CFG_NOPARSE;
+ comm=NULL;
+ goto cleanup;
+ }
+
+ tr_comm_set_id(comm, tr_new_name(json_string_value(jid)));
+ if (NULL == tr_comm_get_id(comm)) {
+ tr_debug("tr_cfg_parse_one_comm: No memory for community id.");
+ *rc = TR_CFG_NOMEM;
+ comm=NULL;
+ goto cleanup;
+ }
+
+ if (0 == strcmp(json_string_value(jtype), "apc")) {
+ comm->type = TR_COMM_APC;
+ } else if (0 == strcmp(json_string_value(jtype), "coi")) {
+ comm->type = TR_COMM_COI;
+ if (NULL == (comm->apcs = tr_cfg_parse_apcs(trc, japcs, rc))) {
+ tr_debug("tr_cfg_parse_one_comm: Can't parse APCs for COI %s.",
+ tr_comm_get_id(comm)->buf);
+ comm=NULL;
+ goto cleanup;
+ }
+ } else {
+ tr_debug("tr_cfg_parse_one_comm: Invalid community type, comm = %s, type = %s",
+ tr_comm_get_id(comm)->buf, json_string_value(jtype));
+ *rc = TR_CFG_NOPARSE;
+ comm=NULL;
+ goto cleanup;
+ }
+
+ tr_cfg_parse_comm_idps(trc, jidps, comm, rc);
+ if (TR_CFG_SUCCESS != *rc) {
+ tr_debug("tr_cfg_parse_one_comm: Can't parse IDP realms for comm %s.",
+ tr_comm_get_id(comm)->buf);
+ comm=NULL;
+ goto cleanup;
+ }
+
+ tr_cfg_parse_comm_rps(trc, jrps, comm, rc);
+ if (TR_CFG_SUCCESS != *rc) {
+ tr_debug("tr_cfg_parse_one_comm: Can't parse RP realms for comm %s .",
+ tr_comm_get_id(comm)->buf);
+ comm=NULL;
+ goto cleanup;
+ }
+
+ if (TR_COMM_APC == comm->type) {
+ json_t *jexpire = json_object_get(jcomm, "expiration_interval");
+ comm->expiration_interval = 43200; /*30 days*/
+ if (jexpire) {
+ if (!json_is_integer(jexpire)) {
+ tr_err("tr_parse_one_comm: expiration_interval is not an integer for comm %.*s",
+ tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
+ comm=NULL;
+ goto cleanup;
+ }
+ comm->expiration_interval = json_integer_value(jexpire);
+ if (comm->expiration_interval <= 10) {
+ comm->expiration_interval = 11; /* Freeradius waits 10 minutes between successful TR queries*/
+ tr_notice(
+ "tr_parse_one_comm: expiration interval for %.*s less than minimum of 11 minutes; using 11 minutes instead.",
+ tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
+ }
+ if (comm->expiration_interval > 129600) {
+ /* > 90 days*/
+ comm->expiration_interval = 129600;
+ tr_notice(
+ "tr_parse_one_comm: expiration interval for %.*s exceeds maximum of 90 days; using 90 days instead.",
+ tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
+ }
+ }
+ }
+
+cleanup:
+ if (comm!=NULL)
+ talloc_steal(mem_ctx, comm);
+ talloc_free(tmp_ctx);
+ return comm;
+}
+
+TR_CFG_RC tr_cfg_parse_comms (TR_CFG *trc, json_t *jcfg)
+{
+ json_t *jcomms = NULL;
+ TR_CFG_RC rc = TR_CFG_SUCCESS;
+ TR_COMM *comm = NULL;
+ int i = 0;
+
+ if ((!trc) || (!jcfg)) {
+ tr_debug("tr_cfg_parse_comms: Bad Parameters.");
+ return TR_CFG_BAD_PARAMS;
+ }
+
+ if (NULL != (jcomms = json_object_get(jcfg, "communities"))) {
+ if (!json_is_array(jcomms)) {
+ return TR_CFG_NOPARSE;
+ }
+
+ for (i = 0; i < json_array_size(jcomms); i++) {
+ if (NULL == (comm = tr_cfg_parse_one_comm(NULL, /* TODO: use a talloc context */
+ trc,
+ json_array_get(jcomms, i),
+ &rc))) {
+ return rc;
+ }
+ tr_debug("tr_cfg_parse_comms: Community configured: %s.",
+ tr_comm_get_id(comm)->buf);
+
+ tr_comm_table_add_comm(trc->ctable, comm);
+ }
+ }
+ tr_debug("tr_cfg_parse_comms: Finished (rc=%d)", rc);
+ return rc;
+}
+
+TR_IDP_REALM *tr_cfg_find_idp (TR_CFG *tr_cfg, TR_NAME *idp_id, TR_CFG_RC *rc)
+{
+
+ TR_IDP_REALM *cfg_idp;
+
+ if ((!tr_cfg) || (!idp_id)) {
+ if (rc)
+ *rc = TR_CFG_BAD_PARAMS;
+ return NULL;
+ }
+
+ for (cfg_idp = tr_cfg->ctable->idp_realms; NULL != cfg_idp; cfg_idp = cfg_idp->next) {
+ if (!tr_name_cmp (idp_id, cfg_idp->realm_id)) {
+ tr_debug("tr_cfg_find_idp: Found %s.", idp_id->buf);
+ return cfg_idp;
+ }
+ }
+ /* if we didn't find one, return NULL */
+ return NULL;
+}
+
+TR_RP_CLIENT *tr_cfg_find_rp (TR_CFG *tr_cfg, TR_NAME *rp_gss, TR_CFG_RC *rc)
+{
+ TR_RP_CLIENT *cfg_rp;
+
+ if ((!tr_cfg) || (!rp_gss)) {
+ if (rc)
+ *rc = TR_CFG_BAD_PARAMS;
+ return NULL;
+ }
+
+ for (cfg_rp = tr_cfg->rp_clients; NULL != cfg_rp; cfg_rp = cfg_rp->next) {
+ if (tr_gss_names_matches(cfg_rp->gss_names, rp_gss)) {
+ tr_debug("tr_cfg_find_rp: Found %s.", rp_gss->buf);
+ return cfg_rp;
+ }
+ }
+ /* if we didn't find one, return NULL */
+ return NULL;
+}
--- /dev/null
+/*
+ * Copyright (c) 2012, 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 <jansson.h>
+#include <tr_config.h>
+
+/* helper for below */
+#define OBJECT_SET_OR_FAIL(jobj, key, val) \
+do { \
+ if (val) \
+ json_object_set_new((jobj),(key),(val)); \
+ else \
+ goto cleanup; \
+} while (0)
+
+#define ARRAY_APPEND_OR_FAIL(jary, val) \
+do { \
+ if (val) \
+ json_array_append_new((jary),(val)); \
+ else \
+ goto cleanup; \
+} while (0)
+
+static json_t *tr_cfg_file_to_json(TR_CFG_FILE *cfg_file)
+{
+ json_t *file_json = NULL;
+ json_t *retval = NULL;
+
+ file_json = json_object();
+ if (file_json == NULL)
+ goto cleanup;
+
+ OBJECT_SET_OR_FAIL(file_json, "name", json_string(cfg_file->name));
+ if (cfg_file->serial != TR_CFG_INVALID_SERIAL)
+ OBJECT_SET_OR_FAIL(file_json, "serial", json_integer(cfg_file->serial));
+
+ /* succeeded - set the return value and increment the reference count */
+ retval = file_json;
+ json_incref(retval);
+
+cleanup:
+ if (file_json)
+ json_decref(file_json);
+
+ return retval;
+}
+
+json_t *tr_cfg_files_to_json_array(TR_CFG *cfg)
+{
+ guint ii;
+ json_t *jarray = json_array();
+ json_t *retval = NULL;
+
+ if (jarray == NULL)
+ goto cleanup;
+
+ for (ii=0; ii<cfg->files->len; ii++) {
+ ARRAY_APPEND_OR_FAIL(jarray,
+ tr_cfg_file_to_json(
+ &g_array_index(cfg->files, TR_CFG_FILE, ii)));
+ }
+
+ /* success */
+ retval = jarray;
+ json_incref(retval);
+
+cleanup:
+ if (jarray)
+ json_decref(jarray);
+
+ return retval;
+}
--- /dev/null
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <jansson.h>
+#include <dirent.h>
+#include <talloc.h>
+
+#include <tr_cfgwatch.h>
+#include <tr_comm.h>
+#include <tr_config.h>
+#include <tr_gss_names.h>
+#include <tr_debug.h>
+#include <tr_filter.h>
+#include <trust_router/tr_constraint.h>
+#include <tr_idp.h>
+#include <tr.h>
+#include <trust_router/trp.h>
+
+#if JANSSON_VERSION_HEX < 0x020500
+#include "jansson_iterators.h"
+#endif
+
+static TR_CONSTRAINT *tr_cfg_parse_one_constraint(TALLOC_CTX *mem_ctx, char *ctype, json_t *jc, TR_CFG_RC *rc)
+{
+ TR_CONSTRAINT *cons=NULL;
+ int i=0;
+
+ if ((!ctype) || (!jc) || (!rc) ||
+ (!json_is_array(jc)) ||
+ (0 >= json_array_size(jc)) ||
+ (TR_MAX_CONST_MATCHES < json_array_size(jc)) ||
+ (!json_is_string(json_array_get(jc, 0)))) {
+ tr_err("tr_cfg_parse_one_constraint: config error.");
+ *rc=TR_CFG_NOPARSE;
+ return NULL;
+ }
+
+ if (NULL==(cons=tr_constraint_new(mem_ctx))) {
+ tr_debug("tr_cfg_parse_one_constraint: Out of memory (cons).");
+ *rc=TR_CFG_NOMEM;
+ return NULL;
+ }
+
+ if (NULL==(cons->type=tr_new_name(ctype))) {
+ tr_err("tr_cfg_parse_one_constraint: Out of memory (type).");
+ *rc=TR_CFG_NOMEM;
+ tr_constraint_free(cons);
+ return NULL;
+ }
+
+ for (i=0; i < json_array_size(jc); i++) {
+ cons->matches[i]=tr_new_name(json_string_value(json_array_get(jc, i)));
+ if (cons->matches[i]==NULL) {
+ tr_err("tr_cfg_parse_one_constraint: Out of memory (match %d).", i+1);
+ *rc=TR_CFG_NOMEM;
+ tr_constraint_free(cons);
+ return NULL;
+ }
+ }
+
+ return cons;
+}
+
+static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR_FILTER_TYPE ftype, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ TR_FILTER *filt = NULL;
+ json_t *jfaction = NULL;
+ json_t *jfline = NULL;
+ json_t *jfspecs = NULL;
+ json_t *this_jfspec = NULL;
+ json_t *jfield = NULL;
+ json_t *jmatch = NULL;
+ json_t *jrc = NULL;
+ json_t *jdc = NULL;
+ json_t *this_jmatch = NULL;
+ TR_NAME *name = NULL;
+ size_t i = 0, j = 0, k = 0;
+
+ *rc = TR_CFG_ERROR;
+
+ if ((jfilt == NULL) || (rc == NULL)) {
+ tr_err("tr_cfg_parse_one_filter: null argument");
+ *rc = TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ if (NULL == (filt = tr_filter_new(tmp_ctx))) {
+ tr_err("tr_cfg_parse_one_filter: Out of memory.");
+ *rc = TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ tr_filter_set_type(filt, ftype);
+
+ /* make sure we have space to represent the filter */
+ if (json_array_size(jfilt) > TR_MAX_FILTER_LINES) {
+ tr_err("tr_cfg_parse_one_filter: Filter has too many lines, maximum of %d.", TR_MAX_FILTER_LINES);
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ /* For each entry in the filter... */
+ json_array_foreach(jfilt, i, jfline) {
+ if ((NULL == (jfaction = json_object_get(jfline, "action"))) ||
+ (!json_is_string(jfaction))) {
+ tr_debug("tr_cfg_parse_one_filter: Error parsing filter action.");
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ if ((NULL == (jfspecs = json_object_get(jfline, "specs"))) ||
+ (!json_is_array(jfspecs)) ||
+ (0 == json_array_size(jfspecs))) {
+ tr_debug("tr_cfg_parse_one_filter: Error parsing filter specs.");
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ if (TR_MAX_FILTER_SPECS < json_array_size(jfspecs)) {
+ tr_debug("tr_cfg_parse_one_filter: Filter has too many specs, maximimum of %d.", TR_MAX_FILTER_SPECS);
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ if (NULL == (filt->lines[i] = tr_fline_new(filt))) {
+ tr_debug("tr_cfg_parse_one_filter: Out of memory allocating filter line %d.", i + 1);
+ *rc = TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ if (!strcmp(json_string_value(jfaction), "accept")) {
+ filt->lines[i]->action = TR_FILTER_ACTION_ACCEPT;
+ } else if (!strcmp(json_string_value(jfaction), "reject")) {
+ filt->lines[i]->action = TR_FILTER_ACTION_REJECT;
+ } else {
+ tr_debug("tr_cfg_parse_one_filter: Error parsing filter action, unknown action' %s'.",
+ json_string_value(jfaction));
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ if (NULL != (jrc = json_object_get(jfline, "realm_constraints"))) {
+ if (!json_is_array(jrc)) {
+ tr_err("tr_cfg_parse_one_filter: cannot parse realm_constraints, not an array.");
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ } else if (json_array_size(jrc) > TR_MAX_CONST_MATCHES) {
+ tr_err("tr_cfg_parse_one_filter: realm_constraints has too many entries, maximum of %d.",
+ TR_MAX_CONST_MATCHES);
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ } else if (json_array_size(jrc) > 0) {
+ /* ok we actually have entries to process */
+ if (NULL == (filt->lines[i]->realm_cons = tr_cfg_parse_one_constraint(filt->lines[i], "realm", jrc, rc))) {
+ tr_debug("tr_cfg_parse_one_filter: Error parsing realm constraint");
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ }
+ }
+
+ if (NULL != (jdc = json_object_get(jfline, "domain_constraints"))) {
+ if (!json_is_array(jdc)) {
+ tr_err("tr_cfg_parse_one_filter: cannot parse domain_constraints, not an array.");
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ } else if (json_array_size(jdc) > TR_MAX_CONST_MATCHES) {
+ tr_err("tr_cfg_parse_one_filter: domain_constraints has too many entries, maximum of %d.",
+ TR_MAX_CONST_MATCHES);
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ } else if (json_array_size(jdc) > 0) {
+ if (NULL == (filt->lines[i]->domain_cons = tr_cfg_parse_one_constraint(filt->lines[i], "domain", jdc, rc))) {
+ tr_debug("tr_cfg_parse_one_filter: Error parsing domain constraint");
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ }
+ }
+
+ /*For each filter spec within the filter line... */
+ json_array_foreach(jfspecs, j, this_jfspec) {
+ if ((NULL == (jfield = json_object_get(this_jfspec, "field"))) ||
+ (!json_is_string(jfield))) {
+ tr_debug("tr_cfg_parse_one_filter: Error parsing filter: missing field for filer spec %d, filter line %d.", i,
+ j);
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ /* check that we have a match attribute */
+ if (NULL == (jmatch = json_object_get(this_jfspec, "match"))) {
+ tr_debug("tr_cfg_parse_one_filter: Error parsing filter: missing match for filer spec %d, filter line %d.", i,
+ j);
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ /* check that match is a string or an array */
+ if ((!json_is_string(jmatch)) && (!json_is_array(jmatch))) {
+ tr_debug(
+ "tr_cfg_parse_one_filter: Error parsing filter: match not a string or array for filter spec %d, filter line %d.",
+ i, j);
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ /* allocate the filter spec */
+ if (NULL == (filt->lines[i]->specs[j] = tr_fspec_new(filt->lines[i]))) {
+ tr_debug("tr_cfg_parse_one_filter: Out of memory.");
+ *rc = TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ /* fill in the field */
+ if (NULL == (filt->lines[i]->specs[j]->field = tr_new_name(json_string_value(jfield)))) {
+ tr_debug("tr_cfg_parse_one_filter: Out of memory.");
+ *rc = TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ /* fill in the matches */
+ if (json_is_string(jmatch)) {
+ if (NULL == (name = tr_new_name(json_string_value(jmatch)))) {
+ tr_debug("tr_cfg_parse_one_filter: Out of memory.");
+ *rc = TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ tr_fspec_add_match(filt->lines[i]->specs[j], name);
+ } else {
+ /* jmatch is an array (we checked earlier) */
+ json_array_foreach(jmatch, k, this_jmatch) {
+ if (NULL == (name = tr_new_name(json_string_value(this_jmatch)))) {
+ tr_debug("tr_cfg_parse_one_filter: Out of memory.");
+ *rc = TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ tr_fspec_add_match(filt->lines[i]->specs[j], name);
+ }
+ }
+ if (!tr_filter_validate_spec_field(ftype, filt->lines[i]->specs[j])){
+ tr_debug("tr_cfg_parse_one_filter: Invalid filter field \"%.*s\" for %s filter, spec %d, filter %d.",
+ filt->lines[i]->specs[j]->field->len,
+ filt->lines[i]->specs[j]->field->buf,
+ tr_filter_type_to_string(filt->type),
+ i, j);
+ *rc = TR_CFG_ERROR;
+ goto cleanup;
+ }
+ }
+ }
+
+ /* check that the filter is valid */
+ if (!tr_filter_validate(filt)) {
+ *rc = TR_CFG_ERROR;
+ } else {
+ *rc = TR_CFG_SUCCESS;
+ talloc_steal(mem_ctx, filt);
+ }
+
+cleanup:
+ talloc_free(tmp_ctx);
+ if (*rc!=TR_CFG_SUCCESS)
+ filt=NULL;
+ return filt;
+}
+
+TR_FILTER_SET *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ json_t *jfilt;
+ const char *filt_label=NULL;
+ TR_FILTER *filt=NULL;
+ TR_FILTER_SET *filt_set=NULL;
+ TR_FILTER_TYPE filt_type=TR_FILTER_TYPE_UNKNOWN;
+
+ *rc=TR_CFG_ERROR;
+
+ /* no filters */
+ if (jfilts==NULL) {
+ *rc=TR_CFG_SUCCESS;
+ goto cleanup;
+ }
+
+ filt_set=tr_filter_set_new(tmp_ctx);
+ if (filt_set==NULL) {
+ tr_debug("tr_cfg_parse_filters: Unable to allocate filter set.");
+ *rc = TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ json_object_foreach(jfilts, filt_label, jfilt) {
+ /* check that we got a filter */
+ if (jfilt == NULL) {
+ tr_debug("tr_cfg_parse_filters: Definition for %s filter is missing.", filt_label);
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ /* check that we recognize the filter type */
+ filt_type=tr_filter_type_from_string(filt_label);
+ if (filt_type==TR_FILTER_TYPE_UNKNOWN) {
+ tr_debug("tr_cfg_parse_filters: Unrecognized filter (%s) defined.", filt_label);
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ /* finally, parse the filter */
+ tr_debug("tr_cfg_parse_filters: Found %s filter.", filt_label);
+ filt = tr_cfg_parse_one_filter(tmp_ctx, jfilt, filt_type, rc);
+ tr_filter_set_add(filt_set, filt);
+ if (*rc != TR_CFG_SUCCESS) {
+ tr_debug("tr_cfg_parse_filters: Error parsing %s filter.", filt_label);
+ *rc = TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ }
+
+ *rc=TR_CFG_SUCCESS;
+
+cleanup:
+ if (*rc==TR_CFG_SUCCESS)
+ talloc_steal(mem_ctx, filt_set);
+ else if (filt_set!=NULL) {
+ talloc_free(filt_set);
+ filt_set=NULL;
+ }
+
+ talloc_free(tmp_ctx);
+ return filt_set;
+}
--- /dev/null
+/*
+ * 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 a boolean
+ *
+ * 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 integer
+ * @return TR_CFG_SUCCESS or an error code
+ */
+static TR_CFG_RC tr_cfg_parse_boolean(json_t *src, const char *key, 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_boolean(jtmp)) {
+ *dest = json_boolean_value(jtmp);
+ } else {
+ tr_debug("tr_cfg_parse_unsigned: Parsing error, %s is not a boolean.", key);
+ return TR_CFG_NOPARSE;
+ }
+ }
+
+ return TR_CFG_SUCCESS;
+}
+
+/**
+ * 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->monitoring_port = TR_DEFAULT_MONITORING_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;
+ cfg->monitoring_credentials = NULL;
+}
+
+/* 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)
+
+static TR_CFG_RC tr_cfg_parse_monitoring(TR_CFG *trc, json_t *jmon)
+{
+ int enabled = 1; /* assume we are enabled unless we are told not to be */
+
+ NOPARSE_UNLESS(tr_cfg_parse_boolean(jmon, "enabled", &enabled));
+ if (enabled) {
+ NOPARSE_UNLESS(tr_cfg_parse_unsigned(jmon, "port", &(trc->internal->monitoring_port)));
+ NOPARSE_UNLESS(tr_cfg_parse_gss_names(trc->internal,
+ json_object_get(jmon, "authorized_credentials"),
+ &(trc->internal->monitoring_credentials)));
+ }
+
+ return TR_CFG_SUCCESS;
+}
+
+/**
+ * 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_monitoring(trc, jtmp));
+ }
+
+ tr_debug("tr_cfg_parse_internal: Internal config parsed.");
+ return TR_CFG_SUCCESS;
+}
--- /dev/null
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <jansson.h>
+#include <dirent.h>
+#include <talloc.h>
+
+#include <tr_cfgwatch.h>
+#include <tr_comm.h>
+#include <tr_config.h>
+#include <tr_gss_names.h>
+#include <tr_debug.h>
+#include <tr_filter.h>
+#include <trust_router/tr_constraint.h>
+#include <tr_idp.h>
+#include <tr.h>
+#include <trust_router/trp.h>
+
+#if JANSSON_VERSION_HEX < 0x020500
+#include "jansson_iterators.h"
+#endif
+
+/* takes a talloc context, but currently does not use it */
+static TR_NAME *tr_cfg_parse_org_name(TALLOC_CTX *mem_ctx, json_t *j_org, TR_CFG_RC *rc)
+{
+ TR_NAME *name=NULL;
+
+ if ((j_org==NULL) || (rc==NULL) || (!json_is_string(j_org))) {
+ tr_debug("tr_cfg_parse_org_name: Bad parameters.");
+ if (rc!=NULL)
+ *rc = TR_CFG_BAD_PARAMS; /* fill in return value if we can */
+ return NULL;
+ }
+
+ name=tr_new_name(json_string_value(j_org));
+ if (name==NULL)
+ *rc=TR_CFG_NOMEM;
+ else
+ *rc=TR_CFG_SUCCESS;
+ return name;
+}
+
+static TR_CFG_RC tr_cfg_parse_one_local_org(TR_CFG *trc, json_t *jlorg)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_CFG_RC retval=TR_CFG_ERROR; /* our return code */
+ TR_CFG_RC rc=TR_CFG_ERROR; /* return code from functions we call */
+ TR_NAME *org_name=NULL;
+ json_t *j_org=NULL;
+ json_t *j_realms=NULL;
+ TR_IDP_REALM *new_idp_realms=NULL;
+ TR_RP_CLIENT *new_rp_clients=NULL;
+
+ tr_debug("tr_cfg_parse_one_local_org: parsing local organization");
+
+ /* get organization_name (optional) */
+ if (NULL==(j_org=json_object_get(jlorg, "organization_name"))) {
+ tr_debug("tr_cfg_parse_one_local_org: organization_name unspecified");
+ } else {
+ org_name=tr_cfg_parse_org_name(tmp_ctx, j_org, &rc);
+ if (rc==TR_CFG_SUCCESS) {
+ tr_debug("tr_cfg_parse_one_local_org: organization_name=\"%.*s\"",
+ org_name->len,
+ org_name->buf);
+ /* we don't actually do anything with this, but we could */
+ tr_free_name(org_name);
+ org_name=NULL;
+ }
+ }
+
+ /* Now get realms. Allow this to be missing; even though that is a pointless organization entry,
+ * it's harmless. Report a warning because that might be unintentional. */
+ if (NULL==(j_realms=json_object_get(jlorg, "realms"))) {
+ tr_warning("tr_cfg_parse_one_local_org: warning - no realms in this local organization");
+ } else {
+ /* Allocate in the tmp_ctx so these will be cleaned up if we do not complete successfully. */
+ new_idp_realms=tr_cfg_parse_idp_realms(tmp_ctx, j_realms, &rc);
+ if (rc!=TR_CFG_SUCCESS)
+ goto cleanup;
+
+ new_rp_clients=tr_cfg_parse_rp_clients(tmp_ctx, j_realms, &rc);
+ if (rc!=TR_CFG_SUCCESS)
+ goto cleanup;
+ }
+ retval=TR_CFG_SUCCESS;
+
+cleanup:
+ /* if we succeeded, link things to the configuration and move out of tmp context */
+ if (retval==TR_CFG_SUCCESS) {
+ if (new_idp_realms!=NULL) {
+ tr_idp_realm_add(trc->ctable->idp_realms, new_idp_realms); /* fixes talloc contexts except for head*/
+ talloc_steal(trc, trc->ctable->idp_realms); /* make sure the head is in the right context */
+ }
+
+ if (new_rp_clients!=NULL) {
+ tr_rp_client_add(trc->rp_clients, new_rp_clients); /* fixes talloc contexts */
+ talloc_steal(trc, trc->rp_clients); /* make sure head is in the right context */
+ }
+ }
+
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+/* Parse local organizations if present. Returns success if there are none. On failure, the configuration is unreliable. */
+TR_CFG_RC tr_cfg_parse_local_orgs(TR_CFG *trc, json_t *jcfg)
+{
+ json_t *jlocorgs=NULL;
+ size_t ii=0;
+
+ jlocorgs=json_object_get(jcfg, "local_organizations");
+ if (jlocorgs==NULL)
+ return TR_CFG_SUCCESS;
+
+ if (!json_is_array(jlocorgs)) {
+ tr_err("tr_cfg_parse_local_orgs: local_organizations is not an array.");
+ return TR_CFG_NOPARSE;
+ }
+
+ for (ii=0; ii<json_array_size(jlocorgs); ii++) {
+ if (tr_cfg_parse_one_local_org(trc, json_array_get(jlocorgs, ii))!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_local_orgs: error parsing local_organization %d.", ii+1);
+ return TR_CFG_NOPARSE;
+ }
+ }
+
+ return TR_CFG_SUCCESS;
+}
+
+static TR_CFG_RC tr_cfg_parse_one_peer_org(TR_CFG *trc, json_t *jporg)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ json_t *jhost=NULL;
+ json_t *jport=NULL;
+ json_t *jgss=NULL;
+ json_t *jfilt=NULL;
+ TRP_PEER *new_peer=NULL;
+ TR_GSS_NAMES *names=NULL;
+ TR_FILTER_SET *filt_set=NULL;
+ TR_CFG_RC rc=TR_CFG_ERROR;
+
+ jhost=json_object_get(jporg, "hostname");
+ jport=json_object_get(jporg, "port");
+ jgss=json_object_get(jporg, "gss_names");
+ jfilt=json_object_get(jporg, "filters");
+
+ if ((jhost==NULL) || (!json_is_string(jhost))) {
+ tr_err("tr_cfg_parse_one_peer_org: hostname not specified or not a string.");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ if ((jport!=NULL) && (!json_is_number(jport))) {
+ /* note that not specifying the port is allowed, but if set it must be a number */
+ tr_err("tr_cfg_parse_one_peer_org: port is not a number.");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ if ((jgss==NULL) || (!json_is_array(jgss))) {
+ tr_err("tr_cfg_parse_one_peer_org: gss_names not specified or not an array.");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ if ((jfilt!=NULL) && (!json_is_object(jfilt))) {
+ tr_err("tr_cfg_parse_one_peer_org: filters is not an object.");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ new_peer=trp_peer_new(tmp_ctx);
+ if (new_peer==NULL) {
+ tr_err("tr_cfg_parse_one_peer_org: could not allocate new peer.");
+ rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ trp_peer_set_server(new_peer, json_string_value(jhost)); /* string is strdup'ed in _set_server() */
+ if (jport==NULL)
+ trp_peer_set_port(new_peer, TRP_PORT);
+ else
+ trp_peer_set_port(new_peer, json_integer_value(jport));
+
+ rc = tr_cfg_parse_gss_names(tmp_ctx, jgss, &names);
+ if (rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_one_peer_org: unable to parse gss names.");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ trp_peer_set_gss_names(new_peer, names);
+
+ if (jfilt) {
+ filt_set=tr_cfg_parse_filters(tmp_ctx, jfilt, &rc);
+ if (rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_one_peer_org: unable to parse filters.");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ trp_peer_set_filters(new_peer, filt_set);
+ }
+
+ /* success! */
+ trp_ptable_add(trc->peers, new_peer);
+ rc=TR_CFG_SUCCESS;
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+/* Parse peer organizations, if present. Returns success if there are none. */
+TR_CFG_RC tr_cfg_parse_peer_orgs(TR_CFG *trc, json_t *jcfg)
+{
+ json_t *jpeerorgs=NULL;
+ int ii=0;
+
+ jpeerorgs=json_object_get(jcfg, "peer_organizations");
+ if (jpeerorgs==NULL)
+ return TR_CFG_SUCCESS;
+
+ if (!json_is_array(jpeerorgs)) {
+ tr_err("tr_cfg_parse_peer_orgs: peer_organizations is not an array.");
+ return TR_CFG_NOPARSE;
+ }
+
+ for (ii=0; ii<json_array_size(jpeerorgs); ii++) {
+ if (tr_cfg_parse_one_peer_org(trc, json_array_get(jpeerorgs, ii))!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_peer_orgs: error parsing peer_organization %d.", ii+1);
+ return TR_CFG_NOPARSE;
+ }
+ }
+
+ return TR_CFG_SUCCESS;
+}
+
--- /dev/null
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <jansson.h>
+#include <dirent.h>
+#include <talloc.h>
+
+#include <tr_cfgwatch.h>
+#include <tr_comm.h>
+#include <tr_config.h>
+#include <tr_gss_names.h>
+#include <tr_debug.h>
+#include <tr_filter.h>
+#include <trust_router/tr_constraint.h>
+#include <tr_idp.h>
+#include <tr.h>
+#include <trust_router/trp.h>
+
+#if JANSSON_VERSION_HEX < 0x020500
+#include "jansson_iterators.h"
+#endif
+
+TR_AAA_SERVER *tr_cfg_parse_one_aaa_server(TALLOC_CTX *mem_ctx, json_t *jaddr, TR_CFG_RC *rc)
+{
+ TR_AAA_SERVER *aaa = NULL;
+ TR_NAME *name=NULL;
+
+ if ((!jaddr) || (!json_is_string(jaddr))) {
+ tr_debug("tr_cfg_parse_one_aaa_server: Bad parameters.");
+ *rc = TR_CFG_BAD_PARAMS;
+ return NULL;
+ }
+
+ name=tr_new_name(json_string_value(jaddr));
+ if (name==NULL) {
+ tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating hostname.");
+ *rc = TR_CFG_NOMEM;
+ return NULL;
+ }
+
+ aaa=tr_aaa_server_new(mem_ctx, name);
+ if (aaa==NULL) {
+ tr_free_name(name);
+ tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating AAA server.");
+ *rc = TR_CFG_NOMEM;
+ return NULL;
+ }
+
+ return aaa;
+}
+
+static TR_AAA_SERVER *tr_cfg_parse_aaa_servers(TALLOC_CTX *mem_ctx, json_t *jaaas, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=NULL;
+ TR_AAA_SERVER *aaa = NULL;
+ TR_AAA_SERVER *temp_aaa = NULL;
+ int i = 0;
+
+ for (i = 0; i < json_array_size(jaaas); i++) {
+ /* rc gets set in here */
+ if (NULL == (temp_aaa = tr_cfg_parse_one_aaa_server(tmp_ctx, json_array_get(jaaas, i), rc))) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ /* TBD -- IPv6 addresses */
+ // tr_debug("tr_cfg_parse_aaa_servers: Configuring AAA Server: ip_addr = %s.", inet_ntoa(temp_aaa->aaa_server_addr));
+ temp_aaa->next = aaa;
+ aaa = temp_aaa;
+ }
+ tr_debug("tr_cfg_parse_aaa_servers: Finished (rc=%d)", *rc);
+
+ for (temp_aaa=aaa; temp_aaa!=NULL; temp_aaa=temp_aaa->next)
+ talloc_steal(mem_ctx, temp_aaa);
+ talloc_free(tmp_ctx);
+ return aaa;
+}
+
+static TR_APC *tr_cfg_parse_one_apc(TALLOC_CTX *mem_ctx, json_t *japc, TR_CFG_RC *rc)
+{
+ TR_APC *apc=NULL;
+ TR_NAME *name=NULL;
+
+ *rc = TR_CFG_SUCCESS; /* presume success */
+
+ if ((!japc) || (!rc) || (!json_is_string(japc))) {
+ tr_debug("tr_cfg_parse_one_apc: Bad parameters.");
+ if (rc)
+ *rc = TR_CFG_BAD_PARAMS;
+ return NULL;
+ }
+
+ apc=tr_apc_new(mem_ctx);
+ if (apc==NULL) {
+ tr_debug("tr_cfg_parse_one_apc: Out of memory.");
+ *rc = TR_CFG_NOMEM;
+ return NULL;
+ }
+
+ name=tr_new_name(json_string_value(japc));
+ if (name==NULL) {
+ tr_debug("tr_cfg_parse_one_apc: No memory for APC name.");
+ tr_apc_free(apc);
+ *rc = TR_CFG_NOMEM;
+ return NULL;
+ }
+ tr_apc_set_id(apc, name); /* apc is now responsible for freeing the name */
+
+ return apc;
+}
+
+TR_APC *tr_cfg_parse_apcs(TALLOC_CTX *mem_ctx, json_t *japcs, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_APC *apcs=NULL;
+ TR_APC *new_apc=NULL;
+ int ii=0;
+ TR_CFG_RC call_rc=TR_CFG_ERROR;
+
+ *rc = TR_CFG_SUCCESS; /* presume success */
+
+ if ((!japcs) || (!rc) || (!json_is_array(japcs))) {
+ tr_debug("tr_cfg_parse_one_apc: Bad parameters.");
+ if (rc)
+ *rc = TR_CFG_BAD_PARAMS;
+ return NULL;
+ }
+
+ for (ii=0; ii<json_array_size(japcs); ii++) {
+ new_apc=tr_cfg_parse_one_apc(tmp_ctx, json_array_get(japcs, ii), &call_rc);
+ if ((call_rc!=TR_CFG_SUCCESS) || (new_apc==NULL)) {
+ tr_debug("tr_cfg_parse_apcs: Error parsing APC %d.", ii+1);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ tr_apc_add(apcs, new_apc);
+ }
+
+ talloc_steal(mem_ctx, apcs);
+ *rc=TR_CFG_SUCCESS;
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return apcs;
+}
+
+static TR_NAME *tr_cfg_parse_name(TALLOC_CTX *mem_ctx, json_t *jname, TR_CFG_RC *rc)
+{
+ TR_NAME *name=NULL;
+ *rc=TR_CFG_ERROR;
+
+ if ((jname==NULL) || (!json_is_string(jname))) {
+ tr_err("tr_cfg_parse_name: name missing or not a string");
+ *rc=TR_CFG_BAD_PARAMS;
+ name=NULL;
+ } else {
+ name=tr_new_name(json_string_value(jname));
+ if (name==NULL) {
+ tr_err("tr_cfg_parse_name: could not allocate name");
+ *rc=TR_CFG_NOMEM;
+ } else {
+ *rc=TR_CFG_SUCCESS;
+ }
+ }
+ return name;
+}
+
+static int tr_cfg_parse_shared_config(json_t *jsc, TR_CFG_RC *rc)
+{
+ const char *shared=NULL;
+ *rc=TR_CFG_SUCCESS;
+
+ if ((jsc==NULL) ||
+ (!json_is_string(jsc)) ||
+ (NULL==(shared=json_string_value(jsc)))) {
+ *rc=TR_CFG_BAD_PARAMS;
+ return -1;
+ }
+
+ if (0==strcmp(shared, "no"))
+ return 0;
+ else if (0==strcmp(shared, "yes"))
+ return 1;
+
+ /* any other value is an error */
+ tr_debug("tr_cfg_parse_shared_config: invalid shared_config value \"%s\" (should be \"yes\" or \"no\")",
+ shared);
+ *rc=TR_CFG_NOPARSE;
+ return -1;
+}
+
+static TR_REALM_ORIGIN tr_cfg_realm_origin(json_t *jrealm)
+{
+ json_t *jremote=json_object_get(jrealm, "remote");
+ const char *s=NULL;
+
+ if (jremote==NULL)
+ return TR_REALM_LOCAL;
+ if (!json_is_string(jremote)) {
+ tr_warning("tr_cfg_realm_origin: \"remote\" is not a string, assuming this is a local realm.");
+ return TR_REALM_LOCAL;
+ }
+ s=json_string_value(jremote);
+ if (strcasecmp(s, "yes")==0)
+ return TR_REALM_REMOTE_INCOMPLETE;
+ else if (strcasecmp(s, "no")!=0)
+ tr_warning("tr_cfg_realm_origin: \"remote\" is neither 'yes' nor 'no', assuming this is a local realm.");
+
+ return TR_REALM_LOCAL;
+}
+
+/* Parse the identity provider object from a realm and fill in the given TR_IDP_REALM. */
+static TR_CFG_RC tr_cfg_parse_idp(TR_IDP_REALM *idp, json_t *jidp)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_APC *apcs=NULL;
+ TR_AAA_SERVER *aaa=NULL;
+ TR_CFG_RC rc=TR_CFG_ERROR;
+
+ if (jidp==NULL)
+ goto cleanup;
+
+ idp->shared_config=tr_cfg_parse_shared_config(json_object_get(jidp, "shared_config"), &rc);
+ if (rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_idp: missing or malformed shared_config specification");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ apcs=tr_cfg_parse_apcs(tmp_ctx, json_object_get(jidp, "apcs"), &rc);
+ if ((rc!=TR_CFG_SUCCESS) || (apcs==NULL)) {
+ tr_err("tr_cfg_parse_idp: unable to parse APC");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ aaa=tr_cfg_parse_aaa_servers(idp, json_object_get(jidp, "aaa_servers"), &rc);
+ if (rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_idp: unable to parse AAA servers");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ tr_debug("tr_cfg_parse_idp: APC=\"%.*s\"",
+ apcs->id->len,
+ apcs->id->buf);
+
+ /* done, fill in the idp structures */
+ idp->apcs=apcs;
+ talloc_steal(idp, apcs);
+ idp->aaa_servers=aaa;
+ rc=TR_CFG_SUCCESS;
+
+cleanup:
+ if (rc!=TR_CFG_SUCCESS) {
+ if (apcs!=NULL)
+ tr_apc_free(apcs);
+ if (aaa!=NULL)
+ tr_aaa_server_free(aaa);
+ }
+
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+/* parses idp realm */
+static TR_IDP_REALM *tr_cfg_parse_one_idp_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_IDP_REALM *realm=NULL;
+ TR_CFG_RC call_rc=TR_CFG_ERROR;
+
+ *rc=TR_CFG_ERROR; /* default to error if not set */
+
+ if ((!jrealm) || (!rc)) {
+ tr_err("tr_cfg_parse_one_idp_realm: Bad parameters.");
+ if (rc)
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) {
+ tr_err("tr_cfg_parse_one_idp_realm: could not allocate idp realm.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ realm->origin=tr_cfg_realm_origin(jrealm);
+ if (realm->origin!=TR_REALM_LOCAL) {
+ tr_debug("tr_cfg_parse_one_idp_realm: realm is remote, should not have full IdP info.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ /* must have a name */
+ realm->realm_id=tr_cfg_parse_name(realm,
+ json_object_get(jrealm, "realm"),
+ &call_rc);
+ if ((call_rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) {
+ tr_err("tr_cfg_parse_one_idp_realm: could not parse realm name");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ tr_debug("tr_cfg_parse_one_idp_realm: realm_id=\"%.*s\"",
+ realm->realm_id->len,
+ realm->realm_id->buf);
+
+ call_rc=tr_cfg_parse_idp(realm, json_object_get(jrealm, "identity_provider"));
+ if (call_rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_one_idp_realm: could not parse identity_provider.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ *rc=TR_CFG_SUCCESS;
+
+cleanup:
+ if (*rc==TR_CFG_SUCCESS)
+ talloc_steal(mem_ctx, realm);
+ else {
+ talloc_free(realm);
+ realm=NULL;
+ }
+
+ talloc_free(tmp_ctx);
+ return realm;
+}
+
+/* Determine whether the realm is an IDP realm */
+static int tr_cfg_is_idp_realm(json_t *jrealm)
+{
+ /* If a realm spec contains an identity_provider, it's an IDP realm. */
+ if (NULL != json_object_get(jrealm, "identity_provider"))
+ return 1;
+ else
+ return 0;
+}
+
+static TR_IDP_REALM *tr_cfg_parse_one_remote_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_IDP_REALM *realm=talloc(mem_ctx, TR_IDP_REALM);
+
+ *rc=TR_CFG_ERROR; /* default to error if not set */
+
+ if ((!jrealm) || (!rc)) {
+ tr_err("tr_cfg_parse_one_remote_realm: Bad parameters.");
+ if (rc)
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) {
+ tr_err("tr_cfg_parse_one_remote_realm: could not allocate idp realm.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ /* must have a name */
+ realm->realm_id=tr_cfg_parse_name(realm,
+ json_object_get(jrealm, "realm"),
+ rc);
+ if ((*rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) {
+ tr_err("tr_cfg_parse_one_remote_realm: could not parse realm name");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ tr_debug("tr_cfg_parse_one_remote_realm: realm_id=\"%.*s\"",
+ realm->realm_id->len,
+ realm->realm_id->buf);
+
+ realm->origin=tr_cfg_realm_origin(jrealm);
+ *rc=TR_CFG_SUCCESS;
+
+cleanup:
+ if (*rc==TR_CFG_SUCCESS)
+ talloc_steal(mem_ctx, realm);
+ else {
+ talloc_free(realm);
+ realm=NULL;
+ }
+
+ talloc_free(tmp_ctx);
+ return realm;
+}
+
+static int tr_cfg_is_remote_realm(json_t *jrealm)
+{
+ return (tr_cfg_realm_origin(jrealm)!=TR_REALM_LOCAL);
+}
+
+/* Parse any idp realms in the j_realms object. Ignores other realm types. */
+TR_IDP_REALM *tr_cfg_parse_idp_realms(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_IDP_REALM *realms=NULL;
+ TR_IDP_REALM *new_realm=NULL;
+ json_t *this_jrealm=NULL;
+ int ii=0;
+
+ *rc=TR_CFG_ERROR;
+ if ((jrealms==NULL) || (!json_is_array(jrealms))) {
+ tr_err("tr_cfg_parse_idp_realms: realms not an array");
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ for (ii=0; ii<json_array_size(jrealms); ii++) {
+ this_jrealm=json_array_get(jrealms, ii);
+ if (tr_cfg_is_idp_realm(this_jrealm)) {
+ new_realm=tr_cfg_parse_one_idp_realm(tmp_ctx, this_jrealm, rc);
+ if ((*rc)!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_idp_realms: error decoding realm entry %d", ii+1);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ tr_idp_realm_add(realms, new_realm);
+ } else if (tr_cfg_is_remote_realm(this_jrealm)) {
+ new_realm=tr_cfg_parse_one_remote_realm(tmp_ctx, this_jrealm, rc);
+ if ((*rc)!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_idp_realms: error decoding remote realm entry %d", ii+1);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ tr_idp_realm_add(realms, new_realm);
+ }
+ }
+
+ *rc=TR_CFG_SUCCESS;
+ talloc_steal(mem_ctx, realms);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return realms;
+}
--- /dev/null
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <jansson.h>
+#include <dirent.h>
+#include <talloc.h>
+
+#include <tr_cfgwatch.h>
+#include <tr_comm.h>
+#include <tr_config.h>
+#include <tr_gss_names.h>
+#include <tr_debug.h>
+#include <tr_filter.h>
+#include <trust_router/tr_constraint.h>
+#include <tr_idp.h>
+#include <tr.h>
+#include <trust_router/trp.h>
+
+#if JANSSON_VERSION_HEX < 0x020500
+#include "jansson_iterators.h"
+#endif
+
+
+TR_CFG_RC tr_cfg_parse_gss_names(TALLOC_CTX *mem_ctx, json_t *jgss_names, TR_GSS_NAMES **gssn_out)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_GSS_NAMES *gn=NULL;
+ json_t *jname=NULL;
+ size_t ii=0;
+ TR_NAME *name=NULL;
+ TR_CFG_RC rc = TR_CFG_ERROR;
+
+ if (jgss_names==NULL) {
+ tr_err("tr_cfg_parse_gss_names: Bad parameters.");
+ rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ if (!json_is_array(jgss_names)) {
+ tr_err("tr_cfg_parse_gss_names: gss_names not an array.");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ gn=tr_gss_names_new(tmp_ctx);
+ for (ii=0; ii<json_array_size(jgss_names); ii++) {
+ jname=json_array_get(jgss_names, ii);
+ if (!json_is_string(jname)) {
+ tr_err("tr_cfg_parse_gss_names: Encountered non-string gss name.");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ name=tr_new_name(json_string_value(jname));
+ if (name==NULL) {
+ tr_err("tr_cfg_parse_gss_names: Out of memory allocating gss name.");
+ rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ if (tr_gss_names_add(gn, name)!=0) {
+ tr_free_name(name);
+ tr_err("tr_cfg_parse_gss_names: Unable to add gss name to RP client.");
+ rc=TR_CFG_ERROR;
+ goto cleanup;
+ }
+ }
+
+ *gssn_out = gn;
+ talloc_steal(mem_ctx, *gssn_out);
+ rc=TR_CFG_SUCCESS;
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+/* default filter accepts realm and *.realm */
+static TR_FILTER_SET *tr_cfg_default_filters(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_FILTER *filt=NULL;
+ TR_FILTER_SET *filt_set=NULL;
+ TR_CONSTRAINT *cons=NULL;
+ TR_NAME *name=NULL;
+ TR_NAME *n_prefix=tr_new_name("*.");
+ TR_NAME *n_rp_realm_1=tr_new_name("rp_realm");
+ TR_NAME *n_rp_realm_2=tr_new_name("rp_realm");
+ TR_NAME *n_domain=tr_new_name("domain");
+ TR_NAME *n_realm=tr_new_name("realm");
+
+
+ if ((realm==NULL) || (rc==NULL)) {
+ tr_debug("tr_cfg_default_filters: invalid arguments.");
+ if (rc!=NULL)
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ if ((n_prefix==NULL) ||
+ (n_rp_realm_1==NULL) ||
+ (n_rp_realm_2==NULL) ||
+ (n_domain==NULL) ||
+ (n_realm==NULL)) {
+ tr_debug("tr_cfg_default_filters: unable to allocate names.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ filt=tr_filter_new(tmp_ctx);
+ if (filt==NULL) {
+ tr_debug("tr_cfg_default_filters: could not allocate filter.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ tr_filter_set_type(filt, TR_FILTER_TYPE_TID_INBOUND);
+ filt->lines[0]=tr_fline_new(filt);
+ if (filt->lines[0]==NULL) {
+ tr_debug("tr_cfg_default_filters: could not allocate filter line.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ filt->lines[0]->action=TR_FILTER_ACTION_ACCEPT;
+ filt->lines[0]->specs[0]=tr_fspec_new(filt->lines[0]);
+ filt->lines[0]->specs[0]->field=n_rp_realm_1;
+ n_rp_realm_1=NULL; /* we don't own this name any more */
+
+ name=tr_dup_name(realm);
+ if (name==NULL) {
+ tr_debug("tr_cfg_default_filters: could not allocate realm name.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ tr_fspec_add_match(filt->lines[0]->specs[0], name);
+ name=NULL; /* we no longer own the name */
+
+ /* now do the wildcard name */
+ filt->lines[0]->specs[1]=tr_fspec_new(filt->lines[0]);
+ filt->lines[0]->specs[1]->field=n_rp_realm_2;
+ n_rp_realm_2=NULL; /* we don't own this name any more */
+
+ if (NULL==(name=tr_name_cat(n_prefix, realm))) {
+ tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ tr_fspec_add_match(filt->lines[0]->specs[1], name);
+ name=NULL; /* we no longer own the name */
+
+ /* domain constraint */
+ if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
+ tr_debug("tr_cfg_default_filters: could not allocate domain constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ cons->type=n_domain;
+ n_domain=NULL; /* belongs to the constraint now */
+ name=tr_dup_name(realm);
+ if (name==NULL) {
+ tr_debug("tr_cfg_default_filters: could not allocate realm name for domain constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ cons->matches[0]=name;
+ name=tr_name_cat(n_prefix, realm);
+ if (name==NULL) {
+ tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name for domain constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ cons->matches[1]=name;
+ name=NULL;
+ filt->lines[0]->domain_cons=cons;
+
+
+ /* realm constraint */
+ if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
+ tr_debug("tr_cfg_default_filters: could not allocate realm constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ cons->type=n_realm;
+ n_realm=NULL; /* belongs to the constraint now */
+ name=tr_dup_name(realm);
+ if (name==NULL) {
+ tr_debug("tr_cfg_default_filters: could not allocate realm name for realm constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ cons->matches[0]=name;
+ name=tr_name_cat(n_prefix, realm);
+ if (name==NULL) {
+ tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name for realm constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ cons->matches[1]=name;
+ name=NULL;
+ filt->lines[0]->realm_cons=cons;
+
+ /* put the filter in a set */
+ filt_set=tr_filter_set_new(tmp_ctx);
+ if ((filt_set==NULL)||(0!=tr_filter_set_add(filt_set, filt))) {
+ tr_debug("tr_cfg_default_filters: could not allocate filter set.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ talloc_steal(mem_ctx, filt_set);
+
+cleanup:
+ talloc_free(tmp_ctx);
+
+ if (*rc!=TR_CFG_SUCCESS)
+ filt=NULL;
+
+ if (n_prefix!=NULL)
+ tr_free_name(n_prefix);
+ if (n_rp_realm_1!=NULL)
+ tr_free_name(n_rp_realm_1);
+ if (n_rp_realm_2!=NULL)
+ tr_free_name(n_rp_realm_2);
+ if (n_realm!=NULL)
+ tr_free_name(n_realm);
+ if (n_domain!=NULL)
+ tr_free_name(n_domain);
+ if (name!=NULL)
+ tr_free_name(name);
+
+ return filt_set;
+}
+
+/* parses rp client */
+static TR_RP_CLIENT *tr_cfg_parse_one_rp_client(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_RP_CLIENT *client=NULL;
+ TR_CFG_RC call_rc=TR_CFG_ERROR;
+ TR_FILTER_SET *new_filts=NULL;
+ TR_NAME *realm=NULL;
+ json_t *jfilt=NULL;
+ json_t *jrealm_id=NULL;
+
+ *rc=TR_CFG_ERROR; /* default to error if not set */
+
+ if ((!jrealm) || (!rc)) {
+ tr_err("tr_cfg_parse_one_rp_client: Bad parameters.");
+ if (rc)
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ if ((NULL==(jrealm_id=json_object_get(jrealm, "realm"))) || (!json_is_string(jrealm_id))) {
+ tr_debug("tr_cfg_parse_one_rp_client: no realm ID found.");
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ tr_debug("tr_cfg_parse_one_rp_client: realm_id=\"%s\"", json_string_value(jrealm_id));
+ realm=tr_new_name(json_string_value(jrealm_id));
+ if (realm==NULL) {
+ tr_err("tr_cfg_parse_one_rp_client: could not allocate realm ID.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ if (NULL==(client=tr_rp_client_new(tmp_ctx))) {
+ tr_err("tr_cfg_parse_one_rp_client: could not allocate rp client.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ call_rc = tr_cfg_parse_gss_names(client, json_object_get(jrealm, "gss_names"), &(client->gss_names));
+
+ if (call_rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_one_rp_client: could not parse gss_names.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ /* parse filters */
+ jfilt=json_object_get(jrealm, "filters");
+ if (jfilt!=NULL) {
+ new_filts=tr_cfg_parse_filters(tmp_ctx, jfilt, &call_rc);
+ if (call_rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_one_rp_client: could not parse filters.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ } else {
+ tr_debug("tr_cfg_parse_one_rp_client: no filters specified, using default filters.");
+ new_filts= tr_cfg_default_filters(tmp_ctx, realm, &call_rc);
+ if (call_rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_one_rp_client: could not set default filters.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ }
+
+ tr_rp_client_set_filters(client, new_filts);
+ *rc=TR_CFG_SUCCESS;
+
+cleanup:
+ if (realm!=NULL)
+ tr_free_name(realm);
+
+ if (*rc==TR_CFG_SUCCESS)
+ talloc_steal(mem_ctx, client);
+ else {
+ talloc_free(client);
+ client=NULL;
+ }
+
+ talloc_free(tmp_ctx);
+ return client;
+}
+
+/* Determine whether the realm is an RP realm */
+static int tr_cfg_is_rp_realm(json_t *jrealm)
+{
+ /* Check that we have a gss name. */
+ if (NULL != json_object_get(jrealm, "gss_names"))
+ return 1;
+ else
+ return 0;
+}
+
+/* Parse any rp clients in the j_realms object. Ignores other realms. */
+TR_RP_CLIENT *tr_cfg_parse_rp_clients(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_RP_CLIENT *clients=NULL;
+ TR_RP_CLIENT *new_client=NULL;
+ json_t *this_jrealm=NULL;
+ int ii=0;
+
+ *rc=TR_CFG_ERROR;
+ if ((jrealms==NULL) || (!json_is_array(jrealms))) {
+ tr_err("tr_cfg_parse_rp_clients: realms not an array");
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ for (ii=0; ii<json_array_size(jrealms); ii++) {
+ this_jrealm=json_array_get(jrealms, ii);
+ if (tr_cfg_is_rp_realm(this_jrealm)) {
+ new_client=tr_cfg_parse_one_rp_client(tmp_ctx, this_jrealm, rc);
+ if ((*rc)!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_rp_clients: error decoding realm entry %d", ii+1);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ tr_rp_client_add(clients, new_client);
+ }
+ }
+
+ *rc=TR_CFG_SUCCESS;
+ talloc_steal(mem_ctx, clients);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return clients;
+}
--- /dev/null
+/*
+ * 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 <jansson.h>
+
+#include <tr_filter.h>
+
+/* helper for below */
+#define OBJECT_SET_OR_FAIL(jobj, key, val) \
+do { \
+ if (val) \
+ json_object_set_new((jobj),(key),(val)); \
+ else \
+ goto cleanup; \
+} while (0)
+
+#define ARRAY_APPEND_OR_FAIL(jary, val) \
+do { \
+ if (val) \
+ json_array_append_new((jary),(val)); \
+ else \
+ goto cleanup; \
+} while (0)
+
+
+typedef json_t *(ITEM_ENCODER_FUNC)(void *);
+
+static json_t *items_to_json_array(void *items[], ITEM_ENCODER_FUNC *item_encoder, size_t max_items)
+{
+ size_t ii;
+ json_t *jarray = json_array();
+ json_t *retval = NULL;
+
+ if (jarray == NULL)
+ goto cleanup;
+
+ for (ii=0; ii<max_items; ii++) {
+ if (items[ii] != NULL)
+ ARRAY_APPEND_OR_FAIL(jarray, item_encoder(items[ii]));
+ }
+ /* success */
+ retval = jarray;
+ json_incref(retval);
+
+cleanup:
+ if (jarray)
+ json_decref(jarray);
+
+ return retval;
+}
+
+static json_t *tr_fspec_to_json(TR_FSPEC *fspec)
+{
+ json_t *fspec_json = NULL;
+ json_t *retval = NULL;
+
+ fspec_json = json_object();
+ if (fspec_json == NULL)
+ goto cleanup;
+
+ OBJECT_SET_OR_FAIL(fspec_json, "field",
+ tr_name_to_json_string(fspec->field));
+ OBJECT_SET_OR_FAIL(fspec_json, "matches",
+ items_to_json_array((void **)fspec->match,
+ (ITEM_ENCODER_FUNC *) tr_name_to_json_string,
+ TR_MAX_FILTER_SPEC_MATCHES));
+
+ /* succeeded - set the return value and increment the reference count */
+ retval = fspec_json;
+ json_incref(retval);
+
+cleanup:
+ if (fspec_json)
+ json_decref(fspec_json);
+ return retval;
+}
+
+static json_t *tr_fline_to_json(TR_FLINE *fline)
+{
+ json_t *fline_json = NULL;
+ json_t *retval = NULL;
+
+ fline_json = json_object();
+ if (fline_json == NULL)
+ goto cleanup;
+
+ OBJECT_SET_OR_FAIL(fline_json, "action",
+ json_string( (fline->action == TR_FILTER_ACTION_ACCEPT) ? "accept" : "reject"));
+ OBJECT_SET_OR_FAIL(fline_json, "specs",
+ items_to_json_array((void **)fline->specs,
+ (ITEM_ENCODER_FUNC *) tr_fspec_to_json,
+ TR_MAX_FILTER_SPECS));
+ if (fline->realm_cons) {
+ OBJECT_SET_OR_FAIL(fline_json, "realm_constraints",
+ items_to_json_array((void **) fline->realm_cons->matches,
+ (ITEM_ENCODER_FUNC *) tr_name_to_json_string,
+ TR_MAX_CONST_MATCHES));
+ }
+ if (fline->domain_cons) {
+ OBJECT_SET_OR_FAIL(fline_json, "domain_constraints",
+ items_to_json_array((void **) fline->domain_cons->matches,
+ (ITEM_ENCODER_FUNC *) tr_name_to_json_string,
+ TR_MAX_CONST_MATCHES));
+ }
+
+ /* succeeded - set the return value and increment the reference count */
+ retval = fline_json;
+ json_incref(retval);
+
+cleanup:
+ if (fline_json)
+ json_decref(fline_json);
+ return retval;
+}
+
+json_t *tr_filter_set_to_json(TR_FILTER_SET *filter_set)
+{
+ json_t *fset_json = NULL;
+ json_t *retval = NULL;
+ TR_FILTER *filt = NULL;
+ TR_FILTER_TYPE *filt_type = NULL;
+ TR_FILTER_TYPE types[] = {
+ TR_FILTER_TYPE_TID_INBOUND,
+ TR_FILTER_TYPE_TRP_INBOUND,
+ TR_FILTER_TYPE_TRP_OUTBOUND,
+ TR_FILTER_TYPE_UNKNOWN /* list terminator */
+ };
+
+ fset_json = json_object();
+ if (fset_json == NULL)
+ goto cleanup;
+
+ for (filt_type = types; *filt_type != TR_FILTER_TYPE_UNKNOWN; filt_type++) {
+ filt = tr_filter_set_get(filter_set, *filt_type);
+ if (filt) {
+ OBJECT_SET_OR_FAIL(fset_json, tr_filter_type_to_string(*filt_type),
+ items_to_json_array((void **)filt->lines,
+ (ITEM_ENCODER_FUNC *) tr_fline_to_json,
+ TR_MAX_FILTER_LINES));
+ }
+ }
+
+ /* succeeded - set the return value and increment the reference count */
+ retval = fset_json;
+ json_incref(retval);
+
+cleanup:
+ if (fset_json)
+ json_decref(fset_json);
+ return retval;
+}
+
/*
- * 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]);
+ tr_debug("tr_gss_auth_cb: Calling auth handler for %.*s.", name.len, name.buf);
+ 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_service name of acceptor to present to initiator
+ * @param acceptor_hostname hostname 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_service,
+ const char *acceptor_hostname,
+ 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_service, acceptor_hostname);
+ 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 */
+ tr_debug("tr_gss_auth_connection: Beginning passive authentication as %.*s",
+ nameBuffer.length, nameBuffer.value);
+ 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;
+ }
+
+ tr_debug("tr_gss_auth_connection: Authentication succeeded, now authorizing.");
+ 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_service acceptor name to present
+ * @param acceptor_hostname acceptor hostname 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_service,
+ const char *acceptor_hostname,
+ 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;
+ size_t req_len = 0;
+ TR_MSG *req_msg = NULL;
+ TR_MSG *resp_msg = NULL;
+ char *resp_str = NULL;
+
+ tr_debug("tr_gss_handle_connection: Attempting to accept %s connection on fd %d.",
+ acceptor_service, conn);
+
+ if (tr_gss_auth_connection(conn,
+ acceptor_service,
+ acceptor_hostname,
+ &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?
+ do {
+ /* 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;
+ }
+
+ req_len = strlen(req_str);
+
+ /* If we got no characters, we will loop again. Free the empty response for the next loop. */
+ if (req_len == 0)
+ talloc_free(req_str);
+
+ } while (req_len == 0);
+
+ /* Decode the request */
+ req_msg = tr_msg_decode(tmp_ctx, req_str, req_len);
+ if (req_msg == NULL) {
+ tr_notice("tr_gss_handle_connection: Error decoding response");
+ goto cleanup;
+ }
+
+ /* Hand off the request for processing and get the response */
+ resp_msg = req_cb(tmp_ctx, req_msg, req_cookie);
+
+ if (resp_msg == NULL) {
+ // no response, clean up
+ goto cleanup;
+ }
+
+ /* Encode the response */
+ resp_str = tr_msg_encode(tmp_ctx, resp_msg);
+ if (resp_str == NULL) {
+ /* We apparently can't encode a response, so just return */
+ tr_err("tr_gss_handle_connection: Error encoding response");
+ goto cleanup;
+ }
+
+ // send the response
+ if (tr_gss_write_resp(conn, gssctx, resp_str)) {
+ tr_err("tr_gss_handle_connection: Error writing response");
+ goto cleanup;
+ }
+
+cleanup:
+ talloc_free(tmp_ctx);
}
--- /dev/null
+/*
+ * Copyright (c) 2012, 2014-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 <trust_router/tr_dh.h>
+#include <tr_msg.h>
+#include <gsscon.h>
+#include <tr_debug.h>
+#include <tr_gss_client.h>
+
+static int tr_gssc_destructor(void *obj)
+{
+ TR_GSSC_INSTANCE *tr_gssc=talloc_get_type_abort(obj, TR_GSSC_INSTANCE);
+ if (NULL!=tr_gssc) {
+ if (NULL!=tr_gssc->client_dh)
+ tr_destroy_dh_params(tr_gssc->client_dh);
+ }
+ return 0;
+}
+
+TR_GSSC_INSTANCE *tr_gssc_instance_new(TALLOC_CTX *mem_ctx)
+{
+ TR_GSSC_INSTANCE *gssc=talloc(NULL, TR_GSSC_INSTANCE);
+ if (gssc != NULL) {
+ gssc->service_name = NULL;
+ gssc->client_dh = NULL;
+ gssc->conn = -1;
+ gssc->gss_ctx = talloc(gssc, gss_ctx_id_t);
+ if (gssc->gss_ctx == NULL) {
+ talloc_free(gssc); /* before the destructor is set */
+ return NULL;
+ }
+ talloc_set_destructor((void *)gssc, tr_gssc_destructor);
+ }
+ return gssc;
+}
+
+void tr_gssc_instance_free(TR_GSSC_INSTANCE *tr_gssc)
+{
+ talloc_free(tr_gssc);
+}
+
+/**
+ * Open a connection to the requested server:port
+ *
+ * @param gssc client instance
+ * @param server server name/address
+ * @param port TCP port to connect
+ * @return 0 on success, -1 on failure
+ */
+int tr_gssc_open_connection(TR_GSSC_INSTANCE *gssc, const char *server, unsigned int port)
+{
+ tr_debug("tr_gssc_open_connection: opening connection to %s:%d", server, port);
+ if (0 != gsscon_connect(server, port, gssc->service_name, &(gssc->conn), gssc->gss_ctx))
+ return -1;
+
+ return 0; /* success */
+}
+
+/**
+ * Send a request message and retrieve a response message
+ *
+ * @param mem_ctx
+ * @param gssc
+ * @param req_msg
+ * @return decoded message, or null on error
+ */
+TR_MSG *tr_gssc_exchange_msgs(TALLOC_CTX *mem_ctx, TR_GSSC_INSTANCE *gssc, TR_MSG *req_msg)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ char *req_buf = NULL;
+ char *resp_buf = NULL;
+ size_t resp_buflen = 0;
+ TR_MSG *resp_msg = NULL; /* this is the return value */
+ int err;
+
+ /* Validate inputs */
+ if ((gssc == NULL) || (req_msg == NULL))
+ goto cleanup;
+
+ /* Encode the request into a json string */
+ if (!(req_buf = tr_msg_encode(tmp_ctx, req_msg))) {
+ tr_err("tr_gssc_exchange_msgs: Error encoding request message.\n");
+ goto cleanup;
+ }
+
+ tr_debug( "tr_gssc_exchange_msgs: Sending request message:\n%s\n", req_buf);
+
+ /* Send the request over the connection */
+ err = gsscon_write_encrypted_token(gssc->conn, *(gssc->gss_ctx), req_buf, strlen(req_buf));
+ if (err) {
+ tr_err( "tr_gssc_exchange_msgs: Error sending request.\n");
+ goto cleanup;
+ }
+
+ /* Read the response from the connection */
+ /* TBD -- timeout? */
+ if (gsscon_read_encrypted_token(gssc->conn, *(gssc->gss_ctx), &resp_buf, &resp_buflen))
+ goto cleanup;
+
+ tr_debug( "tr_gssc_exchange_msgs: Response Received (%u bytes).\n%s\n", (unsigned) resp_buflen, resp_buf);
+ resp_msg = tr_msg_decode(mem_ctx, resp_buf, resp_buflen);
+ free(resp_buf);
+
+ if (resp_msg == NULL) {
+ tr_err( "tr_gssc_exchange_msgs: Error decoding response.\n");
+ goto cleanup;
+ }
+
+ /* If we get here, then we decoded the message and resp_msg is not null. Nothing more to do. */
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return resp_msg;
+}
+
+DH * tr_gssc_get_dh(TR_GSSC_INSTANCE *inst)
+{
+ return inst->client_dh;
+}
+
+DH *tr_gssc_set_dh(TR_GSSC_INSTANCE *inst, DH *dh)
+{
+ inst->client_dh = dh;
+ return dh;
+}
--- /dev/null
+/*
+ * 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>
+#include <tr_debug.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;
+}
+
+/**
+ * Create a duplicate GSS names struct
+ *
+ * @param mem_ctx
+ * @param orig
+ * @return
+ */
+TR_GSS_NAMES *tr_gss_names_dup(TALLOC_CTX *mem_ctx, TR_GSS_NAMES *orig)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ TR_GSS_NAMES *new = tr_gss_names_new(tmp_ctx);
+ TR_GSS_NAMES_ITER *iter = tr_gss_names_iter_new(tmp_ctx);
+ TR_NAME *this = NULL;
+
+ if ( !orig || !new || !iter ) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ this = tr_gss_names_iter_first(iter, orig);
+ while (this) {
+ if (tr_gss_names_add(new, tr_dup_name(this)) != 0) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ this = tr_gss_names_iter_next(iter);
+ }
+ /* success */
+ talloc_steal(mem_ctx, new);
+ return new;
+}
+int tr_gss_names_matches(TR_GSS_NAMES *gn, TR_NAME *name)
+{
+ int ii=0;
+
+ 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);
+}
+
+json_t *tr_gss_names_to_json_array(TR_GSS_NAMES *gss_names)
+{
+ TR_GSS_NAMES_ITER *iter = tr_gss_names_iter_new(NULL);
+ json_t *jarray = json_array();
+ TR_NAME *name = tr_gss_names_iter_first(iter, gss_names);
+ while (name) {
+ json_array_append_new(jarray, tr_name_to_json_string(name));
+ name = tr_gss_names_iter_next(iter);
+ }
+ tr_gss_names_iter_free(iter);
+ return jarray;
+}
+
return head;
}
-static int tr_idp_realm_apc_count(TR_IDP_REALM *idp)
+int tr_idp_realm_apc_count(TR_IDP_REALM *idp)
{
int ii=0;
TR_APC *apc=idp->apcs;
return ii;
}
-static int tr_idp_realm_aaa_server_count(TR_IDP_REALM *idp)
+int tr_idp_realm_aaa_server_count(TR_IDP_REALM *idp)
{
int ii=0;
TR_AAA_SERVER *aaa=idp->aaa_servers;
return ii;
}
-static char *tr_aaa_server_to_str(TALLOC_CTX *mem_ctx, TR_AAA_SERVER *aaa)
-{
- return talloc_strndup(mem_ctx, aaa->hostname->buf, aaa->hostname->len);
-}
-
-char *tr_idp_realm_to_str(TALLOC_CTX *mem_ctx, TR_IDP_REALM *idp)
-{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- char **s_aaa=NULL, *aaa_servers=NULL;
- char **s_apc=NULL, *apcs=NULL;
- int ii=0, aaa_servers_strlen=0, apcs_strlen=0;
- int n_aaa_servers=tr_idp_realm_aaa_server_count(idp);
- int n_apcs=tr_idp_realm_apc_count(idp);
- TR_AAA_SERVER *aaa=NULL;
- TR_APC *apc=NULL;
- char *result=NULL;
-
- /* get the AAA servers */
- if (n_aaa_servers<=0)
- aaa_servers=talloc_strdup(tmp_ctx, "");
- else {
- s_aaa=talloc_array(tmp_ctx, char *, n_aaa_servers);
- for (aaa=idp->aaa_servers,ii=0; aaa!=NULL; aaa=aaa->next,ii++) {
- s_aaa[ii]=tr_aaa_server_to_str(s_aaa, aaa);
- aaa_servers_strlen+=strlen(s_aaa[ii]);
- }
-
- /* add space for comma-space separators */
- aaa_servers_strlen+=2*(n_aaa_servers-1);
-
- aaa_servers=talloc_array(tmp_ctx, char, aaa_servers_strlen+1);
- aaa_servers[0]='\0';
- for (ii=0; ii<n_aaa_servers; ii++) {
- strcat(aaa_servers, s_aaa[ii]);
- if (ii<(n_aaa_servers-1))
- strcat(aaa_servers, ", ");
- }
- talloc_free(s_aaa);
- }
-
- /* get the APCs */
- if (n_apcs<=0)
- apcs=talloc_strdup(tmp_ctx, "");
- else {
- s_apc=talloc_array(tmp_ctx, char *, n_apcs);
- for (apc=idp->apcs,ii=0; apc!=NULL; apc=apc->next,ii++) {
- s_apc[ii]=tr_apc_to_str(s_apc, apc);
- apcs_strlen+=strlen(s_apc[ii]);
- }
-
- /* add space for comma-space separators */
- apcs_strlen+=2*(n_apcs-1);
-
- apcs=talloc_array(tmp_ctx, char, apcs_strlen+1);
- apcs[0]='\0';
- for (ii=0; ii<n_apcs; ii++) {
- strcat(apcs, s_apc[ii]);
- if (ii<(n_apcs-1))
- strcat(apcs, ", ");
- }
- talloc_free(s_apc);
- }
-
- result=talloc_asprintf(mem_ctx,
- "IDP realm: \"%.*s\""
- " shared: %s"
- " local: %s"
- " AAA servers: %s"
- " APCs: %s",
- idp->realm_id->len, idp->realm_id->buf,
- (idp->shared_config)?"yes":"no",
- (idp->origin==TR_REALM_LOCAL)?"yes":"no",
- aaa_servers,
- apcs);
- talloc_free(tmp_ctx);
- return result;
-}
-
void tr_idp_realm_incref(TR_IDP_REALM *realm)
{
realm->refcount++;
--- /dev/null
+/*
+ * 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 <time.h>
+#include <jansson.h>
+
+#include <tr_name_internal.h>
+#include <tr_idp.h>
+#include <tr_config.h>
+#include <tr_debug.h>
+
+static char *tr_aaa_server_to_str(TALLOC_CTX *mem_ctx, TR_AAA_SERVER *aaa)
+{
+ return talloc_strndup(mem_ctx, aaa->hostname->buf, aaa->hostname->len);
+}
+
+
+char *tr_idp_realm_to_str(TALLOC_CTX *mem_ctx, TR_IDP_REALM *idp)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ char **s_aaa=NULL, *aaa_servers=NULL;
+ char **s_apc=NULL, *apcs=NULL;
+ int ii=0, aaa_servers_strlen=0, apcs_strlen=0;
+ int n_aaa_servers=tr_idp_realm_aaa_server_count(idp);
+ int n_apcs=tr_idp_realm_apc_count(idp);
+ TR_AAA_SERVER *aaa=NULL;
+ TR_APC *apc=NULL;
+ char *result=NULL;
+
+ /* get the AAA servers */
+ if (n_aaa_servers<=0)
+ aaa_servers=talloc_strdup(tmp_ctx, "");
+ else {
+ s_aaa=talloc_array(tmp_ctx, char *, n_aaa_servers);
+ for (aaa=idp->aaa_servers,ii=0; aaa!=NULL; aaa=aaa->next,ii++) {
+ s_aaa[ii]=tr_aaa_server_to_str(s_aaa, aaa);
+ aaa_servers_strlen+=strlen(s_aaa[ii]);
+ }
+
+ /* add space for comma-space separators */
+ aaa_servers_strlen+=2*(n_aaa_servers-1);
+
+ aaa_servers=talloc_array(tmp_ctx, char, aaa_servers_strlen+1);
+ aaa_servers[0]='\0';
+ for (ii=0; ii<n_aaa_servers; ii++) {
+ strcat(aaa_servers, s_aaa[ii]);
+ if (ii<(n_aaa_servers-1))
+ strcat(aaa_servers, ", ");
+ }
+ talloc_free(s_aaa);
+ }
+
+ /* get the APCs */
+ if (n_apcs<=0)
+ apcs=talloc_strdup(tmp_ctx, "");
+ else {
+ s_apc=talloc_array(tmp_ctx, char *, n_apcs);
+ for (apc=idp->apcs,ii=0; apc!=NULL; apc=apc->next,ii++) {
+ s_apc[ii]=tr_apc_to_str(s_apc, apc);
+ apcs_strlen+=strlen(s_apc[ii]);
+ }
+
+ /* add space for comma-space separators */
+ apcs_strlen+=2*(n_apcs-1);
+
+ apcs=talloc_array(tmp_ctx, char, apcs_strlen+1);
+ apcs[0]='\0';
+ for (ii=0; ii<n_apcs; ii++) {
+ strcat(apcs, s_apc[ii]);
+ if (ii<(n_apcs-1))
+ strcat(apcs, ", ");
+ }
+ talloc_free(s_apc);
+ }
+
+ result=talloc_asprintf(mem_ctx,
+ "IDP realm: \"%.*s\""
+ " shared: %s"
+ " local: %s"
+ " AAA servers: %s"
+ " APCs: %s",
+ idp->realm_id->len, idp->realm_id->buf,
+ (idp->shared_config)?"yes":"no",
+ (idp->origin==TR_REALM_LOCAL)?"yes":"no",
+ aaa_servers,
+ apcs);
+ talloc_free(tmp_ctx);
+ return result;
+}
+
+
+/* helper for below */
+#define OBJECT_SET_OR_FAIL(jobj, key, val) \
+do { \
+ if (val) \
+ json_object_set_new((jobj),(key),(val)); \
+ else \
+ goto cleanup; \
+} while (0)
+
+#define ARRAY_APPEND_OR_FAIL(jary, val) \
+do { \
+ if (val) \
+ json_array_append_new((jary),(val)); \
+ else \
+ goto cleanup; \
+} while (0)
+
+static json_t *tr_apcs_to_json(TR_APC *apcs)
+{
+ json_t *jarray = json_array();
+ json_t *retval = NULL;
+ TR_APC_ITER *iter = tr_apc_iter_new(NULL);
+ TR_APC *apc = NULL;
+
+ if ((jarray == NULL) || (iter == NULL))
+ goto cleanup;
+
+ apc = tr_apc_iter_first(iter, apcs);
+ while (apc) {
+ ARRAY_APPEND_OR_FAIL(jarray, tr_name_to_json_string(tr_apc_get_id(apc)));
+ apc = tr_apc_iter_next(iter);
+ }
+
+ /* success */
+ retval = jarray;
+ json_incref(retval);
+
+cleanup:
+ if (jarray)
+ json_decref(jarray);
+
+ return retval;
+}
+
+static json_t *tr_aaa_server_to_json(TR_AAA_SERVER *aaa)
+{
+ char *hostname = tr_name_strdup(aaa->hostname);
+ char *s = NULL;
+ json_t *jstr = NULL;
+
+ if (hostname == NULL)
+ return NULL;
+
+ s = talloc_asprintf(NULL, "%s:%d", hostname, TID_PORT);
+ if (s) {
+ jstr = json_string(s);
+ talloc_free(s);
+ }
+ return jstr;
+}
+
+static json_t *tr_aaa_servers_to_json(TR_AAA_SERVER *aaas)
+{
+ json_t *jarray = json_array();
+ json_t *retval = NULL;
+ TR_AAA_SERVER_ITER *iter = tr_aaa_server_iter_new(NULL);
+ TR_AAA_SERVER *aaa = NULL;
+
+ if ((jarray == NULL) || (iter == NULL))
+ goto cleanup;
+
+ aaa = tr_aaa_server_iter_first(iter, aaas);
+ while (aaa) {
+ ARRAY_APPEND_OR_FAIL(jarray, tr_aaa_server_to_json(aaa));
+ aaa = tr_aaa_server_iter_next(iter);
+ }
+
+ /* success */
+ retval = jarray;
+ json_incref(retval);
+
+cleanup:
+ if (jarray)
+ json_decref(jarray);
+
+ return retval;
+}
+
+static json_t *tr_idp_realm_to_json(TR_IDP_REALM *idp)
+{
+ json_t *idp_json = json_object();
+ json_t *retval = NULL;
+
+ if (idp_json == NULL)
+ goto cleanup;
+
+
+ /* success */
+ retval = idp_json;
+ json_incref(retval);
+
+ OBJECT_SET_OR_FAIL(idp_json, "realm",
+ tr_name_to_json_string(tr_idp_realm_get_id(idp)));
+ OBJECT_SET_OR_FAIL(idp_json, "discovered",
+ json_boolean(idp->origin == TR_REALM_DISCOVERED));
+ OBJECT_SET_OR_FAIL(idp_json, "apcs",
+ tr_apcs_to_json(tr_idp_realm_get_apcs(idp)));
+ OBJECT_SET_OR_FAIL(idp_json, "aaa_servers",
+ tr_aaa_servers_to_json(idp->aaa_servers));
+ OBJECT_SET_OR_FAIL(idp_json, "shared_config",
+ json_boolean(idp->shared_config));
+cleanup:
+ if (idp_json)
+ json_decref(idp_json);
+
+ return retval;
+}
+
+json_t *tr_idp_realms_to_json(TR_IDP_REALM *idps)
+{
+ {
+ json_t *jarray = json_array();
+ json_t *retval = NULL;
+ TR_IDP_REALM *this = NULL;
+
+ if (jarray == NULL)
+ goto cleanup;
+
+ for (this=idps; this != NULL; this=this->next)
+ ARRAY_APPEND_OR_FAIL(jarray, tr_idp_realm_to_json(this));
+
+ /* success */
+ retval = jarray;
+ json_incref(retval);
+
+ cleanup:
+ if (jarray)
+ json_decref(jarray);
+
+ return retval;
+ }
+
+}
\ No newline at end of file
#include <assert.h>
#include <talloc.h>
-
#include <tr_apc.h>
#include <tr_comm.h>
+#include <trp_internal.h>
+#include <mon_internal.h>
#include <tr_msg.h>
#include <tr_name_internal.h>
-#include <trp_internal.h>
#include <trust_router/tr_constraint.h>
#include <trust_router/tr_dh.h>
#include <tr_debug.h>
msg->msg_type = type;
}
+/* NOTE: If you are manipulating messages with these getters/setters, the msg_rep
+ * objects are *not* put in the talloc context of the msg. If you are allocating
+ * the message directly with talloc, then you can talloc_steal() the rep into the
+ * message's context, but this is not handled automatically. */
+
+/**
+ * Get a TID_REQ message payload
+ *
+ * @param msg
+ * @return the message payload, or null if it is not a TID_REQUEST message
+ */
TID_REQ *tr_msg_get_req(TR_MSG *msg)
{
if (msg->msg_type == TID_REQUEST)
return NULL;
}
+/**
+ * Set message's payload
+ *
+ * Does not manage talloc contexts, works with any means of allocating
+ * the objects.
+ */
void tr_msg_set_req(TR_MSG *msg, TID_REQ *req)
{
msg->msg_rep = req;
msg->msg_type = TID_REQUEST;
}
+/**
+ * Get a TID_RESP message payload
+ *
+ * @param msg
+ * @return the message payload, or null if it is not a TID_RESPONSE message
+ */
TID_RESP *tr_msg_get_resp(TR_MSG *msg)
{
if (msg->msg_type == TID_RESPONSE)
return NULL;
}
+/**
+ * Set message's payload
+ *
+ * Does not manage talloc contexts, works with any means of allocating
+ * the objects.
+ */
void tr_msg_set_resp(TR_MSG *msg, TID_RESP *resp)
{
msg->msg_rep = resp;
msg->msg_type = TID_RESPONSE;
}
+/**
+ * Get a MON_REQ message payload
+ *
+ * @param msg
+ * @return the message payload, or null if it is not a MON_REQUEST message
+ */
+MON_REQ *tr_msg_get_mon_req(TR_MSG *msg)
+{
+ if (msg->msg_type == MON_REQUEST)
+ return (MON_REQ *)msg->msg_rep;
+ return NULL;
+}
+
+/**
+ * Set message's payload
+ *
+ * Does not manage talloc contexts, works with any means of allocating
+ * the objects.
+ */
+void tr_msg_set_mon_req(TR_MSG *msg, MON_REQ *req)
+{
+ msg->msg_rep = req;
+ msg->msg_type = MON_REQUEST;
+}
+
+/**
+ * Get a MON_RESP message payload
+ *
+ * @param msg
+ * @return the message payload, or null if it is not a MON_RESPONSE message
+ */
+MON_RESP *tr_msg_get_mon_resp(TR_MSG *msg)
+{
+ if (msg->msg_type == MON_RESPONSE)
+ return (MON_RESP *)msg->msg_rep;
+ return NULL;
+}
+
+/**
+ * Set message's payload
+ *
+ * Does not manage talloc contexts, works with any means of allocating
+ * the objects.
+ */
+void tr_msg_set_mon_resp(TR_MSG *msg, MON_RESP *resp)
+{
+ msg->msg_rep = resp;
+ msg->msg_type = MON_RESPONSE;
+}
+
+/**
+ * Get a TRP_UPD message payload
+ *
+ * @param msg
+ * @return the message payload, or null if it is not a TRP_UPDATE message
+ */
TRP_UPD *tr_msg_get_trp_upd(TR_MSG *msg)
{
if (msg->msg_type == TRP_UPDATE)
return NULL;
}
+/**
+ * Set message's payload
+ *
+ * Does not manage talloc contexts, works with any means of allocating
+ * the objects.
+ */
void tr_msg_set_trp_upd(TR_MSG *msg, TRP_UPD *update)
{
msg->msg_rep=update;
- talloc_steal(NULL, update); /* should attach to msg, but TR_MSG not usually talloc'ed */
msg->msg_type=TRP_UPDATE;
}
+/**
+ * Get a TRP_REQ message payload
+ *
+ * @param msg
+ * @return the message payload, or null if it is not a TRP_REQUEST message
+ */
TRP_REQ *tr_msg_get_trp_req(TR_MSG *msg)
{
if (msg->msg_type == TRP_REQUEST)
return NULL;
}
+/**
+ * Set message's payload
+ *
+ * Does not manage talloc contexts, works with any means of allocating
+ * the objects.
+ */
void tr_msg_set_trp_req(TR_MSG *msg, TRP_REQ *req)
{
msg->msg_rep=req;
if ((!req) || (!req->rp_realm) || (!req->realm) || !(req->comm))
return NULL;
- assert(jreq = json_object());
+ jreq = json_object();
+ assert(jreq);
jstr = tr_name_to_json_string(req->rp_realm);
json_object_set_new(jreq, "rp_realm", jstr);
return jreq;
}
-static TID_REQ *tr_msg_decode_tidreq(json_t *jreq)
+static TID_REQ *tr_msg_decode_tidreq(TALLOC_CTX *mem_ctx, json_t *jreq)
{
TID_REQ *treq = NULL;
json_t *jrp_realm = NULL;
tr_crit("tr_msg_decode_tidreq(): Error allocating TID_REQ structure.");
return NULL;
}
-
+ talloc_steal(mem_ctx, treq);
+
/* store required fields from request */
if ((NULL == (jrp_realm = json_object_get(jreq, "rp_realm"))) ||
(NULL == (jrealm = json_object_get(jreq, "target_realm"))) ||
return jresp;
}
-static TID_RESP *tr_msg_decode_tidresp(json_t *jresp)
+static TID_RESP *tr_msg_decode_tidresp(TALLOC_CTX *mem_ctx, json_t *jresp)
{
TID_RESP *tresp = NULL;
json_t *jresult = NULL;
json_t *jservers = NULL;
json_t *jerr_msg = NULL;
- if (!(tresp=tid_resp_new(NULL))) {
+ if (!(tresp=tid_resp_new(mem_ctx))) {
tr_crit("tr_msg_decode_tidresp(): Error allocating TID_RESP structure.");
return NULL;
}
-
/* store required fields from response */
if ((NULL == (jresult = json_object_get(jresp, "result"))) ||
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;
TRP_UPD *trpupd=NULL;
TRP_REQ *trpreq=NULL;
+ MON_REQ *monreq=NULL;
+ MON_RESP *monresp=NULL;
/* TBD -- add error handling */
jmsg = json_object();
- switch (msg->msg_type)
- {
+ switch (msg->msg_type) {
case TID_REQUEST:
jmsg_type = json_string("tid_request");
json_object_set_new(jmsg, "msg_type", jmsg_type);
json_object_set_new(jmsg, "msg_body", tr_msg_encode_trp_req(trpreq));
break;
+ case MON_REQUEST:
+ jmsg_type = json_string("mon_request");
+ json_object_set_new(jmsg, "msg_type", jmsg_type);
+ monreq=tr_msg_get_mon_req(msg);
+ json_object_set_new(jmsg, "msg_body", mon_req_encode(monreq));
+ break;
+
+ case MON_RESPONSE:
+ jmsg_type = json_string("mon_response");
+ json_object_set_new(jmsg, "msg_type", jmsg_type);
+ monresp=tr_msg_get_mon_resp(msg);
+ json_object_set_new(jmsg, "msg_body", mon_resp_encode(monresp));
+ break;
+
default:
json_decref(jmsg);
return NULL;
- }
+ }
+
+ /* 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
- encoded=json_dumps(jmsg, 0);
tr_debug("tr_msg_encode: outgoing msg=%s", encoded);
- json_decref(jmsg);
return encoded;
}
-TR_MSG *tr_msg_decode(const char *jbuf, size_t buflen)
+TR_MSG *tr_msg_decode(TALLOC_CTX *mem_ctx, const char *jbuf, size_t buflen)
{
TR_MSG *msg=NULL;
json_t *jmsg = NULL;
return NULL;
}
- if (!(msg = malloc(sizeof(TR_MSG)))) {
+ if (!(msg = talloc_zero(mem_ctx, TR_MSG))) {
tr_debug("tr_msg_decode(): Error allocating TR_MSG structure.");
json_decref(jmsg);
return NULL;
}
- memset(msg, 0, sizeof(TR_MSG));
-
if ((NULL == (jtype = json_object_get(jmsg, "msg_type"))) ||
(NULL == (jbody = json_object_get(jmsg, "msg_body")))) {
tr_debug("tr_msg_decode(): Error parsing message header.");
if (0 == strcmp(mtype, "tid_request")) {
msg->msg_type = TID_REQUEST;
- tr_msg_set_req(msg, tr_msg_decode_tidreq(jbody));
+ tr_msg_set_req(msg, tr_msg_decode_tidreq(msg, jbody));
}
else if (0 == strcmp(mtype, "tid_response")) {
msg->msg_type = TID_RESPONSE;
- tr_msg_set_resp(msg, tr_msg_decode_tidresp(jbody));
+ tr_msg_set_resp(msg, tr_msg_decode_tidresp(msg, jbody));
}
else if (0 == strcmp(mtype, "trp_update")) {
msg->msg_type = TRP_UPDATE;
- tr_msg_set_trp_upd(msg, tr_msg_decode_trp_upd(NULL, jbody)); /* null talloc context for now */
+ tr_msg_set_trp_upd(msg, tr_msg_decode_trp_upd(msg, jbody));
}
else if (0 == strcmp(mtype, "trp_request")) {
msg->msg_type = TRP_UPDATE;
- tr_msg_set_trp_req(msg, tr_msg_decode_trp_req(NULL, jbody)); /* null talloc context for now */
+ tr_msg_set_trp_req(msg, tr_msg_decode_trp_req(msg, jbody));
+ }
+ else if (0 == strcmp(mtype, "mon_request")) {
+ msg->msg_type = MON_REQUEST;
+ tr_msg_set_mon_req(msg, mon_req_decode(msg, jbody));
+ }
+ /* We do not currently handle monitoring responses */
+ else if (0 == strcmp(mtype, "mon_response")) {
+ msg->msg_type = MON_RESPONSE;
+ tr_msg_set_mon_resp(msg, mon_resp_decode(msg, jbody));
}
else {
msg->msg_type = TR_UNKNOWN;
void tr_msg_free_encoded(char *jmsg)
{
if (jmsg)
- free (jmsg);
+ talloc_free(jmsg);
}
void tr_msg_free_decoded(TR_MSG *msg)
{
- if (msg) {
- if (msg->msg_rep!=NULL) {
- switch (msg->msg_type) {
- case TID_REQUEST:
- tid_req_free(tr_msg_get_req(msg));
- break;
- case TID_RESPONSE:
- tid_resp_free(tr_msg_get_resp(msg));
- break;
- case TRP_UPDATE:
- trp_upd_free(tr_msg_get_trp_upd(msg));
- break;
- case TRP_REQUEST:
- trp_req_free(tr_msg_get_trp_req(msg));
- default:
- break;
- }
- }
- free (msg);
- }
+ if (msg)
+ talloc_free(msg);
}
#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>
-static int tr_rp_client_destructor(void *obj)
-{
- return 0;
-}
-
-TR_RP_CLIENT *tr_rp_client_new(TALLOC_CTX *mem_ctx)
-{
- TR_RP_CLIENT *client=talloc(mem_ctx, TR_RP_CLIENT);
-
- if (client!=NULL) {
- client->next=NULL;
- client->comm_next=NULL;
- client->gss_names=NULL;
- client->filters=NULL;
- talloc_set_destructor((void *)client, tr_rp_client_destructor);
- }
- return client;
-}
-
-void tr_rp_client_free(TR_RP_CLIENT *client)
-{
- talloc_free(client);
-}
-
-static TR_RP_CLIENT *tr_rp_client_tail(TR_RP_CLIENT *client)
-{
- if (client==NULL)
- return NULL;
-
- while (client->next!=NULL)
- client=client->next;
- return client;
-}
-
-/* do not call directly, use the tr_rp_client_add() macro */
-TR_RP_CLIENT *tr_rp_client_add_func(TR_RP_CLIENT *clients, TR_RP_CLIENT *new)
-{
- if (clients==NULL)
- clients=new;
- else {
- tr_rp_client_tail(clients)->next=new;
- while (new!=NULL) {
- talloc_steal(clients, new); /* put it in the right context */
- new=new->next;
- }
- }
- return clients;
-}
-
-
-int tr_rp_client_add_gss_name(TR_RP_CLIENT *rp_client, TR_NAME *gss_name)
-{
- return tr_gss_names_add(rp_client->gss_names, gss_name);
-}
-
-int tr_rp_client_set_filters(TR_RP_CLIENT *client, TR_FILTER_SET *filts)
-{
- if (client->filters!=NULL)
- tr_filter_set_free(client->filters);
- client->filters=filts;
- talloc_steal(client, filts);
- return 0; /* success */
-}
-
-TR_RP_CLIENT_ITER *tr_rp_client_iter_new(TALLOC_CTX *memctx)
-{
- return talloc(memctx, TR_RP_CLIENT_ITER);
-}
-
-void tr_rp_client_iter_free(TR_RP_CLIENT_ITER *iter)
-{
- talloc_free(iter);
-}
-
-TR_RP_CLIENT *tr_rp_client_iter_first(TR_RP_CLIENT_ITER *iter, TR_RP_CLIENT *rp_clients)
-{
- if (!iter) {
- tr_err("tr_rp_client_iter_first: Iterator is null, failing.");
- return NULL;
- }
- *iter=rp_clients;
- return *iter;
-}
-
-TR_RP_CLIENT *tr_rp_client_iter_next(TR_RP_CLIENT_ITER *iter)
-{
- if (*iter)
- *iter=(*iter)->next;
- return *iter;
-}
-
-/**
- * Find a client associated with a GSS name. It's possible there are other clients that match as well.
- *
- * @param rp_clients List of RP clients to search
- * @param gss_name GSS name to search for
- * @return Borrowed reference to an RP client linked to the GSS name
- */
-TR_RP_CLIENT *tr_rp_client_lookup(TR_RP_CLIENT *rp_clients, TR_NAME *gss_name)
-{
- TR_RP_CLIENT_ITER *iter=tr_rp_client_iter_new(NULL);
- TR_RP_CLIENT *client=NULL;
-
- if (iter==NULL) {
- tr_err("tr_rp_client_lookup: Unable to allocate iterator");
- return NULL;
- }
- for (client=tr_rp_client_iter_first(iter, rp_clients); client != NULL; client=tr_rp_client_iter_next(iter)) {
- if (tr_gss_names_matches(client->gss_names, gss_name))
- break;
- }
- tr_rp_client_iter_free(iter);
- return client;
-}
-
TR_RP_REALM *tr_rp_realm_lookup(TR_RP_REALM *rp_realms, TR_NAME *rp_name)
{
TR_RP_REALM *rp = NULL;
"RP realm: \"%.*s\"\n",
rp->realm_id->len, rp->realm_id->buf);
}
+
--- /dev/null
+/*
+ * 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 <tr_rp_client.h>
+#include <tr_debug.h>
+
+static int tr_rp_client_destructor(void *obj)
+{
+ return 0;
+}
+
+TR_RP_CLIENT *tr_rp_client_new(TALLOC_CTX *mem_ctx)
+{
+ TR_RP_CLIENT *client=talloc(mem_ctx, TR_RP_CLIENT);
+
+ if (client!=NULL) {
+ client->next=NULL;
+ client->comm_next=NULL;
+ client->gss_names=NULL;
+ client->filters=NULL;
+ talloc_set_destructor((void *)client, tr_rp_client_destructor);
+ }
+ return client;
+}
+
+void tr_rp_client_free(TR_RP_CLIENT *client)
+{
+ talloc_free(client);
+}
+
+static TR_RP_CLIENT *tr_rp_client_tail(TR_RP_CLIENT *client)
+{
+ if (client==NULL)
+ return NULL;
+
+ while (client->next!=NULL)
+ client=client->next;
+ return client;
+}
+
+/* do not call directly, use the tr_rp_client_add() macro */
+TR_RP_CLIENT *tr_rp_client_add_func(TR_RP_CLIENT *clients, TR_RP_CLIENT *new)
+{
+ if (clients==NULL)
+ clients=new;
+ else {
+ tr_rp_client_tail(clients)->next=new;
+ while (new!=NULL) {
+ talloc_steal(clients, new); /* put it in the right context */
+ new=new->next;
+ }
+ }
+ return clients;
+}
+
+
+int tr_rp_client_add_gss_name(TR_RP_CLIENT *rp_client, TR_NAME *gss_name)
+{
+ return tr_gss_names_add(rp_client->gss_names, gss_name);
+}
+
+int tr_rp_client_set_filters(TR_RP_CLIENT *client, TR_FILTER_SET *filts)
+{
+ if (client->filters!=NULL)
+ tr_filter_set_free(client->filters);
+ client->filters=filts;
+ talloc_steal(client, filts);
+ return 0; /* success */
+}
+
+TR_RP_CLIENT_ITER *tr_rp_client_iter_new(TALLOC_CTX *memctx)
+{
+ return talloc(memctx, TR_RP_CLIENT_ITER);
+}
+
+void tr_rp_client_iter_free(TR_RP_CLIENT_ITER *iter)
+{
+ talloc_free(iter);
+}
+
+TR_RP_CLIENT *tr_rp_client_iter_first(TR_RP_CLIENT_ITER *iter, TR_RP_CLIENT *rp_clients)
+{
+ if (!iter) {
+ tr_err("tr_rp_client_iter_first: Iterator is null, failing.");
+ return NULL;
+ }
+ *iter=rp_clients;
+ return *iter;
+}
+
+TR_RP_CLIENT *tr_rp_client_iter_next(TR_RP_CLIENT_ITER *iter)
+{
+ if (*iter)
+ *iter=(*iter)->next;
+ return *iter;
+}
+
+/**
+ * Find a client associated with a GSS name. It's possible there are other clients that match as well.
+ *
+ * @param rp_clients List of RP clients to search
+ * @param gss_name GSS name to search for
+ * @return Borrowed reference to an RP client linked to the GSS name
+ */
+TR_RP_CLIENT *tr_rp_client_lookup(TR_RP_CLIENT *rp_clients, TR_NAME *gss_name)
+{
+ TR_RP_CLIENT_ITER *iter=tr_rp_client_iter_new(NULL);
+ TR_RP_CLIENT *client=NULL;
+
+ if (iter==NULL) {
+ tr_err("tr_rp_client_lookup: Unable to allocate iterator");
+ return NULL;
+ }
+ for (client=tr_rp_client_iter_first(iter, rp_clients); client != NULL; client=tr_rp_client_iter_next(iter)) {
+ if (tr_gss_names_matches(client->gss_names, gss_name))
+ break;
+ }
+ tr_rp_client_iter_free(iter);
+ return client;
+}
+
--- /dev/null
+/*
+ * 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 <jansson.h>
+
+#include <tr_gss_names.h>
+#include <tr_rp_client.h>
+
+/* helper for below */
+#define OBJECT_SET_OR_FAIL(jobj, key, val) \
+do { \
+ if (val) \
+ json_object_set_new((jobj),(key),(val)); \
+ else \
+ goto cleanup; \
+} while (0)
+
+#define ARRAY_APPEND_OR_FAIL(jary, val) \
+do { \
+ if (val) \
+ json_array_append_new((jary),(val)); \
+ else \
+ goto cleanup; \
+} while (0)
+
+static json_t *tr_rp_client_to_json(TR_RP_CLIENT *rp_client)
+{
+ json_t *client_json = NULL;
+ json_t *retval = NULL;
+
+ client_json = json_object();
+ if (client_json == NULL)
+ goto cleanup;
+
+ OBJECT_SET_OR_FAIL(client_json, "gss_names", tr_gss_names_to_json_array(rp_client->gss_names));
+ OBJECT_SET_OR_FAIL(client_json, "filters", tr_filter_set_to_json(rp_client->filters));
+
+ /* succeeded - set the return value and increment the reference count */
+ retval = client_json;
+ json_incref(retval);
+
+cleanup:
+ if (client_json)
+ json_decref(client_json);
+ return retval;
+}
+
+json_t *tr_rp_clients_to_json(TR_RP_CLIENT *rp_clients)
+{
+ json_t *jarray = json_array();
+ json_t *retval = NULL;
+ TR_RP_CLIENT_ITER *iter = tr_rp_client_iter_new(NULL);
+ TR_RP_CLIENT *rp_client = NULL;
+
+ if ((jarray == NULL) || (iter == NULL))
+ goto cleanup;
+
+ rp_client = tr_rp_client_iter_first(iter, rp_clients);
+ while (rp_client) {
+ ARRAY_APPEND_OR_FAIL(jarray, tr_rp_client_to_json(rp_client));
+ rp_client = tr_rp_client_iter_next(iter);
+ }
+
+ /* succeeded - set the return value and increment the reference count */
+ retval = jarray;
+ json_incref(retval);
+
+cleanup:
+ if (jarray)
+ json_decref(jarray);
+
+ if (iter)
+ tr_rp_client_iter_free(iter);
+
+ return retval;
+}
--- /dev/null
+/*
+ * 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: listening on port %d on %d socket%s",
+ port,
+ n_opened,
+ (n_opened==1)?"":"s");
+
+ return n_opened;
+}
+
#include <stdio.h>
#include <string.h>
#include <time.h>
-#include <trust_router/tr_dh.h>
#include <tr_util.h>
+#include <stdlib.h>
void tr_bin_to_hex(const unsigned char * bin, size_t bin_len,
char * hex_out, size_t hex_len)
return 0;
}
+
+/**
+ * Convert a struct timespec to a string representation
+ * @param ts
+ * @return
+ */
+char *timespec_to_str(struct timespec *ts)
+{
+ struct tm tm;
+ char *s=NULL;
+
+ if (localtime_r(&(ts->tv_sec), &tm)==NULL)
+ return NULL;
+
+ s=malloc(40); /* long enough to contain strftime result */
+ if (s==NULL)
+ return NULL;
+
+ if (strftime(s, 40, "%F %T", &tm)==0) {
+ free(s);
+ return NULL;
+ }
+ return s;
+}
+
AC_PREREQ(2.63)
-AC_INIT([trust_router],[3.3.0],
+AC_INIT([trust_router],[3.4.0~1],
[bugs@project-moonshot.org])
AC_CONFIG_MACRO_DIR(m4)
AC_CONFIG_AUX_DIR(build-aux)
--- /dev/null
+/*
+ * 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_MON_H
+#define TRUST_ROUTER_MON_H
+
+#include <gssapi.h>
+#include <trust_router/tr_name.h>
+
+/* Typedefs */
+typedef struct mon_req MON_REQ;
+typedef struct mon_resp MON_RESP;
+
+typedef enum mon_cmd MON_CMD;
+typedef enum mon_resp_code MON_RESP_CODE;
+
+typedef struct mon_opt MON_OPT;
+typedef enum mon_opt_type MON_OPT_TYPE;
+
+typedef enum mon_rc MON_RC;
+
+typedef struct mons_instance MONS_INSTANCE;
+typedef struct monc_instance MONC_INSTANCE;
+
+typedef struct mons_dispatch_table_entry MONS_DISPATCH_TABLE_ENTRY;
+
+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);
+typedef int (MONC_RESP_FUNC)(MONS_INSTANCE *, MON_REQ *, MON_RESP *, void *);
+
+#endif //TRUST_ROUTER_MON_H
--- /dev/null
+/*
+ * 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_MON_REQ_H
+#define TRUST_ROUTER_MON_REQ_H
+
+#include <talloc.h>
+#include <stdint.h>
+#include <jansson.h>
+#include <gmodule.h>
+#include <gssapi.h>
+#include <trust_router/tid.h>
+#include <trp_internal.h>
+#include <tr_gss_names.h>
+#include <tr_gss_client.h>
+#include <tr_name_internal.h>
+#include <trust_router/tr_dh.h>
+#include <mon.h>
+
+/* Typedefs */
+typedef struct mon_req MON_REQ;
+typedef struct mon_resp MON_RESP;
+
+typedef enum mon_cmd MON_CMD;
+typedef enum mon_resp_code MON_RESP_CODE;
+
+typedef struct mon_opt MON_OPT;
+typedef enum mon_opt_type MON_OPT_TYPE;
+
+typedef enum mon_rc MON_RC;
+
+typedef struct mons_instance MONS_INSTANCE;
+typedef struct monc_instance MONC_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);
+typedef int (MONC_RESP_FUNC)(MONS_INSTANCE *, MON_REQ *, MON_RESP *, void *);
+
+/* Struct and enum definitions */
+enum mon_rc {
+ MON_SUCCESS=0,
+ MON_ERROR, /* generic error */
+ MON_BADARG, /* problem with the arguments */
+ MON_NOMEM, /* out of memory */
+ MON_NOPARSE, /* parsing failed */
+};
+
+enum mon_cmd {
+ MON_CMD_UNKNOWN=0,
+ MON_CMD_RECONFIGURE,
+ MON_CMD_SHOW
+};
+
+/* These should be explicitly numbered because they form part of the public API */
+enum mon_resp_code {
+ MON_RESP_SUCCESS=0,
+ MON_RESP_ERROR=1, // generic error
+};
+
+enum mon_opt_type {
+ OPT_TYPE_UNKNOWN=0,
+ OPT_TYPE_ANY,
+
+ // System information
+ OPT_TYPE_SHOW_VERSION,
+ OPT_TYPE_SHOW_CONFIG_FILES,
+
+ // System statistics
+ OPT_TYPE_SHOW_UPTIME,
+ OPT_TYPE_SHOW_TID_REQ_COUNT,
+ OPT_TYPE_SHOW_TID_REQ_ERR_COUNT,
+ OPT_TYPE_SHOW_TID_REQ_PENDING,
+
+ // Dynamic trust router state
+ OPT_TYPE_SHOW_ROUTES,
+ OPT_TYPE_SHOW_PEERS,
+ OPT_TYPE_SHOW_COMMUNITIES,
+ OPT_TYPE_SHOW_REALMS,
+ OPT_TYPE_SHOW_RP_CLIENTS
+};
+
+struct mon_opt {
+ MON_OPT_TYPE type;
+};
+
+struct mon_req {
+ MON_CMD command;
+ GArray *options;
+};
+
+struct mon_resp {
+ MON_RESP_CODE code;
+ TR_NAME *message;
+ 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;
+ GPtrArray *handlers;
+ GArray *pids; /* PIDs of active mons processes */
+};
+
+/* Client instance */
+struct monc_instance {
+ TR_GSSC_INSTANCE *gssc;
+};
+
+/* Prototypes */
+/* tr_mon.c */
+const char *mon_cmd_to_string(MON_CMD cmd);
+MON_CMD mon_cmd_from_string(const char *s);
+const char *mon_opt_type_to_string(MON_OPT_TYPE opt_type);
+MON_OPT_TYPE mon_opt_type_from_string(const char *s);
+
+/* mon_req.c */
+MON_REQ *mon_req_new(TALLOC_CTX *mem_ctx, MON_CMD cmd);
+void mon_req_free(MON_REQ *req);
+MON_RC mon_req_add_option(MON_REQ *req, MON_OPT_TYPE opt_type);
+size_t mon_req_opt_count(MON_REQ *req);
+MON_OPT *mon_req_opt_index(MON_REQ *req, size_t index);
+
+/* mon_req_encode.c */
+json_t *mon_req_encode(MON_REQ *req);
+
+/* mon_req_decode.c */
+MON_REQ *mon_req_decode(TALLOC_CTX *mem_ctx, json_t *req_json);
+MON_REQ *mon_req_parse(TALLOC_CTX *mem_ctx, const char *input);
+
+/* mon_resp.c */
+MON_RESP *mon_resp_new(TALLOC_CTX *mem_ctx, MON_RESP_CODE code, const char *msg, json_t *payload);
+void mon_resp_free(MON_RESP *resp);
+int mon_resp_set_message(MON_RESP *resp, const char *new_msg);
+void mon_resp_set_payload(MON_RESP *resp, json_t *new_payload);
+
+/* mon_resp_encode.c */
+json_t *mon_resp_encode(MON_RESP *resp);
+
+/* mon_resp_decode.c */
+MON_RESP * mon_resp_decode(TALLOC_CTX *mem_ctx, json_t *resp_json);
+
+/* 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);
+
+/* monc.c */
+MONC_INSTANCE *monc_new(TALLOC_CTX *mem_ctx);
+void monc_free(MONC_INSTANCE *monc);
+DH *monc_get_dh(MONC_INSTANCE *inst);
+DH *monc_set_dh(MONC_INSTANCE *inst, DH *dh);
+int monc_open_connection(MONC_INSTANCE *monc, const char *server, unsigned int port);
+MON_RESP *monc_send_request(TALLOC_CTX *mem_ctx, MONC_INSTANCE *monc, MON_REQ *req);
+
+#endif //TRUST_ROUTER_MON_REQ_H
--- /dev/null
+/*
+ * 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_MONS_HANDLERS_H
+#define TRUST_ROUTER_MONS_HANDLERS_H
+
+typedef MON_RC (MONS_HANDLER_FUNC)(void *cookie, json_t **result_ptr);
+
+struct mons_dispatch_table_entry {
+ MON_CMD command;
+ MON_OPT_TYPE opt_type;
+ MONS_HANDLER_FUNC *handler;
+ void *cookie;
+};
+
+/* mons_handlers.c */
+MON_RESP *mons_handle_request(TALLOC_CTX *mem_ctx, MONS_INSTANCE *mons, MON_REQ *req);
+MON_RC mons_register_handler(MONS_INSTANCE *mons, MON_CMD cmd, MON_OPT_TYPE opt_type, MONS_HANDLER_FUNC *f, void *cookie);
+
+#endif //TRUST_ROUTER_MONS_HANDLERS_H
#include <tr_rp.h>
#include <trust_router/tid.h>
#include <jansson.h>
+#include "tr_gss_client.h"
struct tid_srvr_blk {
TID_SRVR_BLK *next;
};
struct tidc_instance {
- // TID_REQ *req_list;
- // TBD -- Do we still need a separate private key */
- // char *priv_key;
- // int priv_len;
- DH *client_dh; /* Client's DH struct with priv and pub keys */
+ TR_GSSC_INSTANCE *gssc;
+};
+
+struct tid_process {
+ pid_t pid;
+ int read_fd;
};
struct tids_instance {
int req_count;
+ int error_count;
char *priv_key;
char *ipaddr;
const char *hostname;
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 */
+ GArray *pids; /* PIDs of active tids processes */
};
/** Decrement a reference to #json when this tid_req is cleaned up. A
#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);
+void tids_sweep_procs(TIDS_INSTANCE *tids);
+
#endif
const char *tr_realm_role_to_str(TR_REALM_ROLE role);
TR_REALM_ROLE tr_realm_role_from_str(const char *s);
+/* tr_comm_encoders.c */
+json_t *tr_comm_table_to_json(TR_COMM_TABLE *ctable);
+
#endif
#include <syslog.h>
#include <sys/time.h>
#include <talloc.h>
+#include <gmodule.h>
#include <tr_comm.h>
#include <tr_rp.h>
+#include <tr_rp_client.h>
#include <tr_idp.h>
#include <trp_ptable.h>
#include <trp_internal.h>
#define TR_DEFAULT_MAX_TREE_DEPTH 12
#define TR_DEFAULT_TRPS_PORT 12308
#define TR_DEFAULT_TIDS_PORT 12309
+#define TR_DEFAULT_MONITORING_PORT 0 /* defaults to being turned off */
#define TR_DEFAULT_LOG_THRESHOLD LOG_INFO
#define TR_DEFAULT_CONSOLE_THRESHOLD LOG_NOTICE
#define TR_DEFAULT_APC_EXPIRATION_INTERVAL 43200
#define TR_DEFAULT_TID_RESP_NUMER 2
#define TR_DEFAULT_TID_RESP_DENOM 3
+#define TR_CFG_INVALID_SERIAL -1
+
typedef enum tr_cfg_rc {
TR_CFG_SUCCESS = 0, /* No error */
TR_CFG_ERROR, /* General processing error */
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;
unsigned int tid_req_timeout;
unsigned int tid_resp_numer; /* numerator of fraction of AAA servers to wait for in unshared mode */
unsigned int tid_resp_denom; /* denominator of fraction of AAA servers to wait for in unshared mode */
+ TR_GSS_NAMES *monitoring_credentials;
} TR_CFG_INTERNAL;
+/* record of files loaded for this configuration */
+typedef struct tr_cfg_file {
+ const char *name;
+ json_int_t serial;
+} TR_CFG_FILE;
+
typedef struct tr_cfg {
TR_CFG_INTERNAL *internal; /* internal trust router config */
TR_RP_CLIENT *rp_clients; /* locally associated RP Clients */
TRP_PTABLE *peers; /* TRP peer table */
TR_COMM_TABLE *ctable; /* communities/realms */
TR_AAA_SERVER *default_servers; /* default server list */
- /* TBD -- Global Filters */
+
+ GArray *files; /* files loaded to make this configuration */
} TR_CFG;
typedef struct tr_cfg_mgr {
void tr_print_comm_idps(TR_COMM_TABLE *ctab, TR_COMM *comm);
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);
+
+/* tr_config_comms.c */
+TR_IDP_REALM *tr_cfg_find_idp (TR_CFG *tr_cfg, TR_NAME *idp_id, TR_CFG_RC *rc);
+TR_RP_CLIENT *tr_cfg_find_rp (TR_CFG *tr_cfg, TR_NAME *rp_gss, TR_CFG_RC *rc);
+TR_CFG_RC tr_cfg_parse_comms (TR_CFG *trc, json_t *jcfg);
+TR_CFG_RC tr_cfg_parse_default_servers (TR_CFG *trc, json_t *jcfg);
+
+/* tr_config_filters.c */
+TR_FILTER_SET *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_CFG_RC *rc);
+
+/* tr_config_orgs.c */
+TR_CFG_RC tr_cfg_parse_local_orgs(TR_CFG *trc, json_t *jcfg);
+TR_CFG_RC tr_cfg_parse_peer_orgs(TR_CFG *trc, json_t *jcfg);
+
+/* tr_config_realms.c */
+TR_IDP_REALM *tr_cfg_parse_idp_realms(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc);
+TR_AAA_SERVER *tr_cfg_parse_one_aaa_server(TALLOC_CTX *mem_ctx, json_t *jaddr, TR_CFG_RC *rc);
+TR_APC *tr_cfg_parse_apcs(TALLOC_CTX *mem_ctx, json_t *japcs, TR_CFG_RC *rc);
+
+/* tr_config_rp_clients.c */
+TR_RP_CLIENT *tr_cfg_parse_rp_clients(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc);
+TR_CFG_RC tr_cfg_parse_gss_names(TALLOC_CTX *mem_ctx, json_t *jgss_names, TR_GSS_NAMES **gssn_out);
+
+/* tr_config_encoders.c */
+json_t *tr_cfg_files_to_json_array(TR_CFG *cfg);
#endif
/* 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 */
};
const char *tr_filter_type_to_string(TR_FILTER_TYPE ftype);
TR_FILTER_TYPE tr_filter_type_from_string(const char *s);
+/* tr_filter_encoders.c */
+json_t *tr_filter_set_to_json(TR_FILTER_SET *filter_set);
+
#endif
/*
- * 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 TR_MSG *(TR_GSS_HANDLE_REQ_FN)(TALLOC_CTX *, TR_MSG *, 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_service, const char *acceptor_hostname, 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
--- /dev/null
+/*
+ * 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_GSS_CLIENT_H
+#define TRUST_ROUTER_TR_GSS_CLIENT_H
+
+#include <gssapi.h>
+#include <trust_router/tr_dh.h>
+#include <tr_msg.h>
+
+typedef struct tr_gssc_instance TR_GSSC_INSTANCE;
+
+/* Client instance */
+struct tr_gssc_instance {
+ const char *service_name;
+ DH *client_dh;
+ gss_ctx_id_t *gss_ctx;
+ int conn;
+};
+
+/* tr_gss_client.c */
+TR_GSSC_INSTANCE *tr_gssc_instance_new(TALLOC_CTX *mem_ctx);
+void tr_gssc_instance_free(TR_GSSC_INSTANCE *tr_gssc);
+int tr_gssc_open_connection(TR_GSSC_INSTANCE *gssc, const char *server, unsigned int port);
+TR_MSG *tr_gssc_exchange_msgs(TALLOC_CTX *mem_ctx, TR_GSSC_INSTANCE *gssc, TR_MSG *req_msg);
+DH * tr_gssc_get_dh(TR_GSSC_INSTANCE *inst);
+DH *tr_gssc_set_dh(TR_GSSC_INSTANCE *inst, DH *dh);
+
+#endif //TRUST_ROUTER_TR_GSS_CLIENT_H
--- /dev/null
+/*
+ * 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);
+TR_GSS_NAMES *tr_gss_names_dup(TALLOC_CTX *mem_ctx, TR_GSS_NAMES *orig);
+int tr_gss_names_matches(TR_GSS_NAMES *gn, TR_NAME *name);
+
+TR_GSS_NAMES_ITER *tr_gss_names_iter_new(TALLOC_CTX *mem_ctx);
+TR_NAME *tr_gss_names_iter_first(TR_GSS_NAMES_ITER *iter, TR_GSS_NAMES *gn);
+TR_NAME *tr_gss_names_iter_next(TR_GSS_NAMES_ITER *iter);
+void tr_gss_names_iter_free(TR_GSS_NAMES_ITER *iter);
+
+json_t *tr_gss_names_to_json_array(TR_GSS_NAMES *gss_names);
+
+#endif /* __TR_GSS_H__ */
#define tr_idp_realm_remove(head,remove) ((head)=tr_idp_realm_remove_func((head),(remove)))
TR_IDP_REALM *tr_idp_realm_sweep_func(TR_IDP_REALM *head);
#define tr_idp_realm_sweep(head) ((head)=tr_idp_realm_sweep_func((head)))
-char *tr_idp_realm_to_str(TALLOC_CTX *mem_ctx, TR_IDP_REALM *idp);
+int tr_idp_realm_aaa_server_count(TR_IDP_REALM *idp);
+int tr_idp_realm_apc_count(TR_IDP_REALM *idp);
void tr_idp_realm_incref(TR_IDP_REALM *realm);
void tr_idp_realm_decref(TR_IDP_REALM *realm);
TR_AAA_SERVER *tr_idp_aaa_server_lookup(TR_IDP_REALM *idp_realms, TR_NAME *idp_realm_name, TR_NAME *comm, int *shared_out);
TR_AAA_SERVER *tr_default_server_lookup(TR_AAA_SERVER *default_servers, TR_NAME *comm);
+/* tr_idp_encoders.c */
+char *tr_idp_realm_to_str(TALLOC_CTX *mem_ctx, TR_IDP_REALM *idp);
+json_t *tr_idp_realms_to_json(TR_IDP_REALM *idp);
+
#endif
--- /dev/null
+/*
+ * 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>
+#include <mons_handlers.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 */
#include <jansson.h>
#include <trust_router/tid.h>
#include <trust_router/trp.h>
+#include <mon.h>
+
typedef struct tr_msg TR_MSG;
enum msg_type {
TID_REQUEST,
TID_RESPONSE,
TRP_UPDATE,
- TRP_REQUEST
+ TRP_REQUEST,
+ MON_REQUEST,
+ MON_RESPONSE
};
/* Union of TR message types to hold message of any type. */
void tr_msg_set_trp_upd(TR_MSG *msg, TRP_UPD *req);
TRP_REQ *tr_msg_get_trp_req(TR_MSG *msg);
void tr_msg_set_trp_req(TR_MSG *msg, TRP_REQ *req);
+MON_REQ *tr_msg_get_mon_req(TR_MSG *msg);
+void tr_msg_set_mon_req(TR_MSG *msg, MON_REQ *req);
+MON_RESP *tr_msg_get_mon_resp(TR_MSG *msg);
+void tr_msg_set_mon_resp(TR_MSG *msg, MON_RESP *resp);
/* Encoders/Decoders */
-char *tr_msg_encode(TR_MSG *msg);
-TR_MSG *tr_msg_decode(const char *jmsg, size_t len);
+char *tr_msg_encode(TALLOC_CTX *mem_ctx, TR_MSG *msg);
+TR_MSG *tr_msg_decode(TALLOC_CTX *mem_ctx, const char *jmsg, size_t len);
void tr_msg_free_encoded(char *jmsg);
void tr_msg_free_decoded(TR_MSG *msg);
#define TR_RP_H
#include <talloc.h>
-
-#include <tr_gss.h>
-#include <tr_filter.h>
-
-typedef struct tr_rp_client {
- struct tr_rp_client *next;
- struct tr_rp_client *comm_next;
- TR_GSS_NAMES *gss_names;
- TR_FILTER_SET *filters;
-} TR_RP_CLIENT;
-
-typedef struct tr_rp_client *TR_RP_CLIENT_ITER;
+#include <tr_name_internal.h>
/* Structure to make a linked list of RP realms by name for community config */
typedef struct tr_rp_realm {
} TR_RP_REALM;
/* prototypes */
-TR_RP_CLIENT *tr_rp_client_new(TALLOC_CTX *mem_ctx);
-void tr_rp_client_free(TR_RP_CLIENT *client);
-TR_RP_CLIENT *tr_rp_client_add_func(TR_RP_CLIENT *clients, TR_RP_CLIENT *new);
-#define tr_rp_client_add(clients,new) ((clients)=tr_rp_client_add_func((clients),(new)))
-int tr_rp_client_add_gss_name(TR_RP_CLIENT *client, TR_NAME *name);
-int tr_rp_client_set_filters(TR_RP_CLIENT *client, TR_FILTER_SET *filts);
-TR_RP_CLIENT_ITER *tr_rp_client_iter_new(TALLOC_CTX *memctx);
-void tr_rp_client_iter_free(TR_RP_CLIENT_ITER *iter);
-TR_RP_CLIENT *tr_rp_client_iter_first(TR_RP_CLIENT_ITER *iter, TR_RP_CLIENT *rp_clients);
-TR_RP_CLIENT *tr_rp_client_iter_next(TR_RP_CLIENT_ITER *iter);
-TR_RP_CLIENT *tr_rp_client_lookup(TR_RP_CLIENT *rp_clients, TR_NAME *gss_name);
-
TR_RP_REALM *tr_rp_realm_new(TALLOC_CTX *mem_ctx);
void tr_rp_realm_free(TR_RP_REALM *rp);
TR_NAME *tr_rp_realm_get_id(TR_RP_REALM *rp);
--- /dev/null
+/*
+ * 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.
+ *
+ */
+
+#ifndef TRUST_ROUTER_TR_RP_CLIENT_H
+#define TRUST_ROUTER_TR_RP_CLIENT_H
+
+#include <talloc.h>
+
+#include <tr_gss_names.h>
+#include <tr_filter.h>
+
+typedef struct tr_rp_client {
+ struct tr_rp_client *next;
+ struct tr_rp_client *comm_next;
+ TR_GSS_NAMES *gss_names;
+ TR_FILTER_SET *filters;
+} TR_RP_CLIENT;
+
+typedef struct tr_rp_client *TR_RP_CLIENT_ITER;
+
+/* tr_rp_client.c */
+TR_RP_CLIENT *tr_rp_client_new(TALLOC_CTX *mem_ctx);
+void tr_rp_client_free(TR_RP_CLIENT *client);
+TR_RP_CLIENT *tr_rp_client_add_func(TR_RP_CLIENT *clients, TR_RP_CLIENT *new);
+#define tr_rp_client_add(clients,new) ((clients)=tr_rp_client_add_func((clients),(new)))
+int tr_rp_client_add_gss_name(TR_RP_CLIENT *client, TR_NAME *name);
+int tr_rp_client_set_filters(TR_RP_CLIENT *client, TR_FILTER_SET *filts);
+TR_RP_CLIENT_ITER *tr_rp_client_iter_new(TALLOC_CTX *memctx);
+void tr_rp_client_iter_free(TR_RP_CLIENT_ITER *iter);
+TR_RP_CLIENT *tr_rp_client_iter_first(TR_RP_CLIENT_ITER *iter, TR_RP_CLIENT *rp_clients);
+TR_RP_CLIENT *tr_rp_client_iter_next(TR_RP_CLIENT_ITER *iter);
+TR_RP_CLIENT *tr_rp_client_lookup(TR_RP_CLIENT *rp_clients, TR_NAME *gss_name);
+
+/* tr_rp_client_encoders.c */
+json_t *tr_rp_clients_to_json(TR_RP_CLIENT *rp_clients);
+
+#endif //TRUST_ROUTER_TR_RP_CLIENT_H
--- /dev/null
+/*
+ * 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
#include <trp_internal.h>
#include <tr_event.h>
#include <tr_config.h>
+#include <mon.h>
#define TR_TID_MAX_AAA_SERVERS 10
-int tr_tids_event_init(struct event_base *base,
- TIDS_INSTANCE *tids,
- TR_CFG_MGR *cfg_mgr,
- TRPS_INSTANCE *trps,
- struct tr_socket_event *tids_ev);
+int tr_tids_event_init(struct event_base *base, TIDS_INSTANCE *tids, TR_CFG_MGR *cfg_mgr, TRPS_INSTANCE *trps,
+ struct tr_socket_event *tids_ev, struct event **sweep_ev);
+
+/* tr_tid_mons.c */
+void tr_tid_register_mons_handlers(TIDS_INSTANCE *tids, MONS_INSTANCE *mons);
#endif /* TR_TID_H */
#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;
TR_CFG_MGR *cfg_mgr;
TIDS_INSTANCE *tids;
TRPS_INSTANCE *trps;
+ MONS_INSTANCE *mons;
TR_CFGWATCH *cfgwatch;
TR_TRPS_EVENTS *events;
};
void tr_config_changed(TR_CFG *new_cfg, void *cookie);
TRP_RC tr_connect_to_peers(TRPS_INSTANCE *trps, struct event *ev);
void tr_peer_status_change(TRP_PEER *peer, void *cookie);
+
+/* tr_trp_mons.h */
+void tr_trp_register_mons_handlers(TRPS_INSTANCE *trps, MONS_INSTANCE *mons);
+
#endif /* TR_TRP_H */
#include <trust_router/tr_versioning.h>
+/* NB, tr_bin_to_hex() is also prototyped in trust_router/tr_dh.h */
+TR_EXPORT void tr_bin_to_hex(const unsigned char * bin, size_t binlen,
+ char * hex_out, size_t hex_len);
TR_EXPORT int tr_cmp_timespec(struct timespec *ts1, struct timespec *ts2);
+char *timespec_to_str(struct timespec *ts);
#endif /* TR_UTIL_H */
#include <gsscon.h>
#include <tr_mq.h>
#include <tr_msg.h>
+#include <trp_peer.h>
#include <trp_ptable.h>
+#include <trp_route.h>
#include <trp_rtable.h>
#include <tr_apc.h>
#include <tr_comm.h>
--- /dev/null
+/*
+ * 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.
+ *
+ */
+
+#ifndef TRUST_ROUTER_TRP_PEER_H
+#define TRUST_ROUTER_TRP_PEER_H
+
+#include <tr_gss_names.h>
+#include <tr_filter.h>
+
+typedef enum trp_peer_conn_status {
+ PEER_DISCONNECTED=0,
+ PEER_CONNECTED
+} TRP_PEER_CONN_STATUS;
+
+typedef struct trp_peer TRP_PEER;
+struct trp_peer {
+ TRP_PEER *next; /* for making a linked list */
+ TR_NAME *label; /* often null, set on first call to trp_peer_get_label or dup_label */
+ char *server;
+ TR_GSS_NAMES *gss_names;
+ TR_NAME *servicename;
+ unsigned int port;
+ unsigned int linkcost;
+ struct timespec last_conn_attempt;
+ TRP_PEER_CONN_STATUS outgoing_status;
+ TRP_PEER_CONN_STATUS incoming_status;
+ void (*conn_status_cb)(TRP_PEER *, void *); /* callback for connected status change */
+ void *conn_status_cookie;
+ TR_FILTER_SET *filters;
+};
+
+
+TRP_PEER *trp_peer_new(TALLOC_CTX *memctx);
+void trp_peer_free(TRP_PEER *peer);
+TRP_PEER *trp_peer_tail(TRP_PEER *peer);
+TR_NAME *trp_peer_get_label(TRP_PEER *peer);
+TR_NAME *trp_peer_dup_label(TRP_PEER *peer);
+char *trp_peer_get_server(TRP_PEER *peer);
+void trp_peer_set_server(TRP_PEER *peer, const char *server);
+void trp_peer_add_gss_name(TRP_PEER *peer, TR_NAME *gssname);
+void trp_peer_set_gss_names(TRP_PEER *peer, TR_GSS_NAMES *gss_names);
+TR_GSS_NAMES *trp_peer_get_gss_names(TRP_PEER *peer);
+TR_NAME *trp_peer_get_servicename(TRP_PEER *peer);
+TR_NAME *trp_peer_dup_servicename(TRP_PEER *peer);
+unsigned int trp_peer_get_port(TRP_PEER *peer);
+void trp_peer_set_port(TRP_PEER *peer, unsigned int port);
+unsigned int trp_peer_get_linkcost(TRP_PEER *peer);
+struct timespec *trp_peer_get_last_conn_attempt(TRP_PEER *peer);
+void trp_peer_set_last_conn_attempt(TRP_PEER *peer, struct timespec *time);
+TRP_PEER_CONN_STATUS trp_peer_get_outgoing_status(TRP_PEER *peer);
+void trp_peer_set_outgoing_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status);
+TRP_PEER_CONN_STATUS trp_peer_get_incoming_status(TRP_PEER *peer);
+void trp_peer_set_incoming_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status);
+int trp_peer_is_connected(TRP_PEER *peer);
+void trp_peer_set_linkcost(TRP_PEER *peer, unsigned int linkcost);
+void trp_peer_set_conn_status_cb(TRP_PEER *peer, void (*cb)(TRP_PEER *, void *), void *cookie);
+void trp_peer_set_filters(TRP_PEER *peer, TR_FILTER_SET *filts);
+TR_FILTER *trp_peer_get_filter(TRP_PEER *peer, TR_FILTER_TYPE ftype);
+
+/* trp_peer_encoders.c */
+char *trp_peer_to_str(TALLOC_CTX *memctx, TRP_PEER *peer, const char *sep);
+json_t *trp_peer_to_json(TRP_PEER *peer);
+
+#endif //TRUST_ROUTER_TRP_PEER_H
#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>
-
-typedef enum trp_peer_conn_status {
- PEER_DISCONNECTED=0,
- PEER_CONNECTED
-} TRP_PEER_CONN_STATUS;
-
-typedef struct trp_peer TRP_PEER;
-struct trp_peer {
- TRP_PEER *next; /* for making a linked list */
- TR_NAME *label; /* often null, set on first call to trp_peer_get_label or dup_label */
- char *server;
- TR_GSS_NAMES *gss_names;
- TR_NAME *servicename;
- unsigned int port;
- unsigned int linkcost;
- struct timespec last_conn_attempt;
- TRP_PEER_CONN_STATUS outgoing_status;
- TRP_PEER_CONN_STATUS incoming_status;
- void (*conn_status_cb)(TRP_PEER *, void *); /* callback for connected status change */
- void *conn_status_cookie;
- TR_FILTER_SET *filters;
-};
+#include <trp_peer.h>
typedef struct trp_ptable {
TRP_PEER *head; /* head of a peer table list */
TRP_RC trp_ptable_remove(TRP_PTABLE *ptbl, TRP_PEER *peer);
TRP_PEER *trp_ptable_find_gss_name(TRP_PTABLE *ptbl, TR_NAME *gssname);
TRP_PEER *trp_ptable_find_servicename(TRP_PTABLE *ptbl, TR_NAME *servicename);
-char *trp_ptable_to_str(TALLOC_CTX *memctx, TRP_PTABLE *ptbl, const char *sep, const char *lineterm);
TRP_PTABLE_ITER *trp_ptable_iter_new(TALLOC_CTX *mem_ctx);
TRP_PEER *trp_ptable_iter_first(TRP_PTABLE_ITER *iter, TRP_PTABLE *ptbl);
TRP_PEER *trp_ptable_iter_next(TRP_PTABLE_ITER *iter);
void trp_ptable_iter_free(TRP_PTABLE_ITER *iter);
-TRP_PEER *trp_peer_new(TALLOC_CTX *memctx);
-void trp_peer_free(TRP_PEER *peer);
-TR_NAME *trp_peer_get_label(TRP_PEER *peer);
-TR_NAME *trp_peer_dup_label(TRP_PEER *peer);
-char *trp_peer_get_server(TRP_PEER *peer);
-void trp_peer_set_server(TRP_PEER *peer, const char *server);
-void trp_peer_add_gss_name(TRP_PEER *peer, TR_NAME *gssname);
-void trp_peer_set_gss_names(TRP_PEER *peer, TR_GSS_NAMES *gss_names);
-TR_GSS_NAMES *trp_peer_get_gss_names(TRP_PEER *peer);
-TR_NAME *trp_peer_get_servicename(TRP_PEER *peer);
-TR_NAME *trp_peer_dup_servicename(TRP_PEER *peer);
-unsigned int trp_peer_get_port(TRP_PEER *peer);
-void trp_peer_set_port(TRP_PEER *peer, unsigned int port);
-unsigned int trp_peer_get_linkcost(TRP_PEER *peer);
-struct timespec *trp_peer_get_last_conn_attempt(TRP_PEER *peer);
-void trp_peer_set_last_conn_attempt(TRP_PEER *peer, struct timespec *time);
-TRP_PEER_CONN_STATUS trp_peer_get_outgoing_status(TRP_PEER *peer);
-void trp_peer_set_outgoing_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status);
-TRP_PEER_CONN_STATUS trp_peer_get_incoming_status(TRP_PEER *peer);
-void trp_peer_set_incoming_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status);
-int trp_peer_is_connected(TRP_PEER *peer);
-void trp_peer_set_linkcost(TRP_PEER *peer, unsigned int linkcost);
-void trp_peer_set_conn_status_cb(TRP_PEER *peer, void (*cb)(TRP_PEER *, void *), void *cookie);
-void trp_peer_set_filters(TRP_PEER *peer, TR_FILTER_SET *filts);
-TR_FILTER *trp_peer_get_filter(TRP_PEER *peer, TR_FILTER_TYPE ftype);
-char *trp_peer_to_str(TALLOC_CTX *memctx, TRP_PEER *peer, const char *sep);
+/* trp_ptable_encoders.c */
+char *trp_ptable_to_str(TALLOC_CTX *memctx, TRP_PTABLE *ptbl, const char *sep, const char *lineterm);
+json_t *trp_ptable_to_json(TRP_PTABLE *ptbl);
#endif /* _TRP_PTABLE_H_ */
--- /dev/null
+/*
+ * 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.
+ *
+ */
+
+
+#ifndef TRUST_ROUTER_TRP_ROUTE_H
+#define TRUST_ROUTER_TRP_ROUTE_H
+
+typedef struct trp_route {
+ TR_NAME *comm;
+ TR_NAME *realm;
+ TR_NAME *peer;
+ unsigned int metric;
+ TR_NAME *trust_router; /* hostname */
+ unsigned int trp_port;
+ unsigned int tid_port;
+ TR_NAME *next_hop;
+ int selected;
+ unsigned int interval; /* interval from route update */
+ struct timespec *expiry;
+ int local; /* is this a local route? */
+ int triggered;
+} TRP_ROUTE;
+
+/* trp_route.c */
+TRP_ROUTE *trp_route_new(TALLOC_CTX *mem_ctx);
+void trp_route_free(TRP_ROUTE *entry);
+void trp_route_set_comm(TRP_ROUTE *entry, TR_NAME *comm);
+TR_NAME *trp_route_get_comm(TRP_ROUTE *entry);
+TR_NAME *trp_route_dup_comm(TRP_ROUTE *entry);
+void trp_route_set_realm(TRP_ROUTE *entry, TR_NAME *realm);
+TR_NAME *trp_route_get_realm(TRP_ROUTE *entry);
+TR_NAME *trp_route_dup_realm(TRP_ROUTE *entry);
+void trp_route_set_trust_router(TRP_ROUTE *entry, TR_NAME *tr);
+TR_NAME *trp_route_get_trust_router(TRP_ROUTE *entry);
+TR_NAME *trp_route_dup_trust_router(TRP_ROUTE *entry);
+void trp_route_set_peer(TRP_ROUTE *entry, TR_NAME *peer);
+TR_NAME *trp_route_get_peer(TRP_ROUTE *entry);
+TR_NAME *trp_route_dup_peer(TRP_ROUTE *entry);
+void trp_route_set_metric(TRP_ROUTE *entry, unsigned int metric);
+unsigned int trp_route_get_metric(TRP_ROUTE *entry);
+void trp_route_set_next_hop(TRP_ROUTE *entry, TR_NAME *next_hop);
+TR_NAME *trp_route_get_next_hop(TRP_ROUTE *entry);
+TR_NAME *trp_route_dup_next_hop(TRP_ROUTE *entry);
+void trp_route_set_selected(TRP_ROUTE *entry, int sel);
+int trp_route_is_selected(TRP_ROUTE *entry);
+void trp_route_set_interval(TRP_ROUTE *entry, int interval);
+int trp_route_get_interval(TRP_ROUTE *entry);
+void trp_route_set_expiry(TRP_ROUTE *entry, struct timespec *exp);
+struct timespec *trp_route_get_expiry(TRP_ROUTE *entry);
+void trp_route_set_local(TRP_ROUTE *entry, int local);
+int trp_route_is_local(TRP_ROUTE *entry);
+void trp_route_set_triggered(TRP_ROUTE *entry, int trig);
+int trp_route_is_triggered(TRP_ROUTE *entry);
+
+/* trp_route_encoders.c */
+char *trp_route_to_str(TALLOC_CTX *mem_ctx, TRP_ROUTE *entry, const char *sep);
+json_t *trp_route_to_json(TRP_ROUTE *route);
+
+#endif //TRUST_ROUTER_TRP_ROUTE_H
#include <talloc.h>
#include <time.h>
+#include <trp_route.h>
#include <trp_internal.h>
-typedef struct trp_route {
- TR_NAME *comm;
- TR_NAME *realm;
- TR_NAME *peer;
- unsigned int metric;
- TR_NAME *trust_router; /* hostname */
- unsigned int trp_port;
- unsigned int tid_port;
- TR_NAME *next_hop;
- int selected;
- unsigned int interval; /* interval from route update */
- struct timespec *expiry;
- int local; /* is this a local route? */
- int triggered;
-} TRP_ROUTE;
typedef GHashTable TRP_RTABLE;
+/* trp_rtable.c */
TRP_RTABLE *trp_rtable_new(void);
void trp_rtable_free(TRP_RTABLE *rtbl);
void trp_rtable_add(TRP_RTABLE *rtbl, TRP_ROUTE *entry); /* adds or updates */
size_t trp_rtable_size(TRP_RTABLE *rtbl);
size_t trp_rtable_comm_size(TRP_RTABLE *rtbl, TR_NAME *comm);
size_t trp_rtable_realm_size(TRP_RTABLE *rtbl, TR_NAME *comm, TR_NAME *realm);
-TRP_ROUTE **trp_rtable_get_entries(TRP_RTABLE *rtbl, size_t *n_out);
+TRP_ROUTE **trp_rtable_get_entries(TALLOC_CTX *mem_ctx, TRP_RTABLE *rtbl, size_t *n_out);
TR_NAME **trp_rtable_get_comms(TRP_RTABLE *rtbl, size_t *n_out);
TRP_ROUTE **trp_rtable_get_comm_entries(TRP_RTABLE *rtbl, TR_NAME *comm, size_t *n_out);
TR_NAME **trp_rtable_get_comm_realms(TRP_RTABLE *rtbl, TR_NAME *comm, size_t *n_out);
TRP_ROUTE *trp_rtable_get_entry(TRP_RTABLE *rtbl, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer);
TRP_ROUTE *trp_rtable_get_selected_entry(TRP_RTABLE *rtbl, TR_NAME *comm, TR_NAME *realm);
void trp_rtable_clear_triggered(TRP_RTABLE *rtbl);
-char *trp_rtable_to_str(TALLOC_CTX *mem_ctx, TRP_RTABLE *rtbl, const char *sep, const char *lineterm);
-TRP_ROUTE *trp_route_new(TALLOC_CTX *mem_ctx);
-void trp_route_free(TRP_ROUTE *entry);
-void trp_route_set_comm(TRP_ROUTE *entry, TR_NAME *comm);
-TR_NAME *trp_route_get_comm(TRP_ROUTE *entry);
-TR_NAME *trp_route_dup_comm(TRP_ROUTE *entry);
-void trp_route_set_realm(TRP_ROUTE *entry, TR_NAME *realm);
-TR_NAME *trp_route_get_realm(TRP_ROUTE *entry);
-TR_NAME *trp_route_dup_realm(TRP_ROUTE *entry);
-void trp_route_set_trust_router(TRP_ROUTE *entry, TR_NAME *tr);
-TR_NAME *trp_route_get_trust_router(TRP_ROUTE *entry);
-TR_NAME *trp_route_dup_trust_router(TRP_ROUTE *entry);
-void trp_route_set_peer(TRP_ROUTE *entry, TR_NAME *peer);
-TR_NAME *trp_route_get_peer(TRP_ROUTE *entry);
-TR_NAME *trp_route_dup_peer(TRP_ROUTE *entry);
-void trp_route_set_metric(TRP_ROUTE *entry, unsigned int metric);
-unsigned int trp_route_get_metric(TRP_ROUTE *entry);
-void trp_route_set_next_hop(TRP_ROUTE *entry, TR_NAME *next_hop);
-TR_NAME *trp_route_get_next_hop(TRP_ROUTE *entry);
-TR_NAME *trp_route_dup_next_hop(TRP_ROUTE *entry);
-void trp_route_set_selected(TRP_ROUTE *entry, int sel);
-int trp_route_is_selected(TRP_ROUTE *entry);
-void trp_route_set_interval(TRP_ROUTE *entry, int interval);
-int trp_route_get_interval(TRP_ROUTE *entry);
-void trp_route_set_expiry(TRP_ROUTE *entry, struct timespec *exp);
-struct timespec *trp_route_get_expiry(TRP_ROUTE *entry);
-void trp_route_set_local(TRP_ROUTE *entry, int local);
-int trp_route_is_local(TRP_ROUTE *entry);
-void trp_route_set_triggered(TRP_ROUTE *entry, int trig);
-int trp_route_is_triggered(TRP_ROUTE *entry);
-char *trp_route_to_str(TALLOC_CTX *mem_ctx, TRP_ROUTE *entry, const char *sep);
+/* trp_rtable_encoders.c */
+char *trp_rtable_to_str(TALLOC_CTX *mem_ctx, TRP_RTABLE *rtbl, const char *sep, const char *lineterm);
+json_t *trp_rtable_to_json(TRP_RTABLE *rtbl);
#endif /* _TRP_RTABLE_H_ */
#include <trust_router/tr_versioning.h>
#include <gssapi.h>
+#include <poll.h>
#define TID_PORT 12309
TR_EXPORT TR_NAME *tid_req_get_comm(TID_REQ *req);
void tid_req_set_comm(TID_REQ *req, TR_NAME *comm);
TR_EXPORT TR_NAME *tid_req_get_orig_coi(TID_REQ *req);
-void tid_req_set_rp_orig_coi(TID_REQ *req, TR_NAME *orig_coi);
+void tid_req_set_orig_coi(TID_REQ *req, TR_NAME *orig_coi);
TR_EXPORT TR_NAME *tid_req_get_request_id(TID_REQ *req);
void tid_req_set_request_id(TID_REQ *req, TR_NAME *request_id);
TR_EXPORT TIDC_RESP_FUNC *tid_req_get_resp_func(TID_REQ *req);
TR_EXPORT int tid_srvr_get_key_expiration(const TID_SRVR_BLK *, struct timeval *tv_out);
#define tid_resp_servers_foreach(RESP, SERVER, INDEX) \
- for (INDEX=0,SERVER=NULL; \
- ((INDEX < tid_resp_get_num_servers(RESP))&&(SERVER = tid_resp_get_server(resp, INDEX))); \
- INDEX++)
+ for ((INDEX)=0,(SERVER)=NULL; \
+ (((INDEX) < tid_resp_get_num_servers(RESP))&&((SERVER) = tid_resp_get_server(resp, (INDEX)))); \
+ (INDEX)++)
/* TID Client functions, in tid/tidc.c */
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);
--- /dev/null
+/*
+ * 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 <gmodule.h>
+#include <string.h>
+
+#include <mon_internal.h>
+
+// Monitoring common code
+
+/**
+ * This method defines the command strings
+ */
+const char *mon_cmd_to_string(MON_CMD cmd)
+{
+ switch(cmd) {
+ case MON_CMD_UNKNOWN:
+ return NULL;
+
+ case MON_CMD_RECONFIGURE:
+ return "reconfigure";
+
+ case MON_CMD_SHOW:
+ return "show";
+ }
+ return NULL;
+}
+
+// Helper macro for the mon_cmd_from_string method
+#define return_if_matches(s, cmd) \
+ do { \
+ if (strcmp((s), mon_cmd_to_string(cmd))==0) \
+ return (cmd); \
+ } while(0)
+
+MON_CMD mon_cmd_from_string(const char *s)
+{
+ return_if_matches(s, MON_CMD_RECONFIGURE);
+ return_if_matches(s, MON_CMD_SHOW);
+ return MON_CMD_UNKNOWN;
+}
+#undef return_if_matches
+
+/**
+ * This method defines the option type strings
+ */
+const char *mon_opt_type_to_string(MON_OPT_TYPE opt_type)
+{
+ switch(opt_type) {
+ case OPT_TYPE_UNKNOWN:
+ case OPT_TYPE_ANY:
+ return NULL;
+
+ case OPT_TYPE_SHOW_VERSION:
+ return "version";
+
+ case OPT_TYPE_SHOW_CONFIG_FILES:
+ return "config_files";
+
+ case OPT_TYPE_SHOW_UPTIME:
+ return "uptime";
+
+ case OPT_TYPE_SHOW_TID_REQ_COUNT:
+ return "tid_req_count";
+
+ case OPT_TYPE_SHOW_TID_REQ_ERR_COUNT:
+ return "tid_req_error_count";
+
+ case OPT_TYPE_SHOW_TID_REQ_PENDING:
+ return "tid_req_pending";
+
+ case OPT_TYPE_SHOW_ROUTES:
+ return "routes";
+
+ case OPT_TYPE_SHOW_PEERS:
+ return "peers";
+
+ case OPT_TYPE_SHOW_COMMUNITIES:
+ return "communities";
+
+ case OPT_TYPE_SHOW_REALMS:
+ return "realms";
+
+ case OPT_TYPE_SHOW_RP_CLIENTS:
+ return "rp_clients";
+ }
+ return NULL;
+}
+
+// Helper macro for the mon_opt_type_from_string method
+#define return_if_matches(s, cmd) \
+ do { \
+ if (strcmp((s), mon_opt_type_to_string(cmd))==0) \
+ return (cmd); \
+ } while(0)
+
+MON_OPT_TYPE mon_opt_type_from_string(const char *s)
+{
+ return_if_matches(s, OPT_TYPE_SHOW_VERSION);
+ return_if_matches(s, OPT_TYPE_SHOW_CONFIG_FILES);
+ return_if_matches(s, OPT_TYPE_SHOW_UPTIME);
+ return_if_matches(s, OPT_TYPE_SHOW_TID_REQ_COUNT);
+ return_if_matches(s, OPT_TYPE_SHOW_TID_REQ_ERR_COUNT);
+ return_if_matches(s, OPT_TYPE_SHOW_TID_REQ_PENDING);
+ return_if_matches(s, OPT_TYPE_SHOW_ROUTES);
+ return_if_matches(s, OPT_TYPE_SHOW_PEERS);
+ return_if_matches(s, OPT_TYPE_SHOW_COMMUNITIES);
+ return_if_matches(s, OPT_TYPE_SHOW_REALMS);
+ return_if_matches(s, OPT_TYPE_SHOW_RP_CLIENTS);
+ return OPT_TYPE_UNKNOWN;
+}
+#undef return_if_matches
--- /dev/null
+/*
+ * 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 <gmodule.h>
+
+#include <mon_internal.h>
+
+// Monitoring request message common code
+
+/**
+ * Destructor used by talloc to ensure proper cleanup
+ */
+static int mon_req_destructor(void *object)
+{
+ MON_REQ *req = talloc_get_type_abort(object, MON_REQ);
+ if (req->options) {
+ g_array_unref(req->options);
+ }
+ return 0;
+}
+
+/**
+ * Allocate a new monitoring request
+ *
+ * @param mem_ctx talloc context for the new request
+ * @param cmd command for the request
+ * @return newly allocated request, or null on error
+ */
+MON_REQ *mon_req_new(TALLOC_CTX *mem_ctx, MON_CMD cmd)
+{
+ MON_REQ *req=talloc(mem_ctx, MON_REQ);
+ if (req) {
+ req->command = cmd;
+ req->options = g_array_new(FALSE, FALSE, sizeof(MON_OPT));
+ talloc_set_destructor((void *)req, mon_req_destructor);
+ }
+ return req;
+}
+
+/**
+ * Free a monitoring request
+ *
+ * @param req request to free, must not be null
+ */
+void mon_req_free(MON_REQ *req)
+{
+ talloc_free(req);
+}
+
+/**
+ * Add an option to a MON_REQ
+ * @param req request to operate on, not null
+ * @param opt_type type of option
+ * @return MON_SUCCESS on success, error code on error
+ */
+MON_RC mon_req_add_option(MON_REQ *req, MON_OPT_TYPE opt_type)
+{
+ MON_OPT new_opt; // not a pointer
+
+ /* Validate parameters */
+ if ((req == NULL) || (opt_type == OPT_TYPE_UNKNOWN)) {
+ return MON_BADARG;
+ }
+
+ new_opt.type = opt_type;
+
+ /* Add the new option to the list */
+ g_array_append_val(req->options, new_opt);
+ return MON_SUCCESS;
+}
+
+size_t mon_req_opt_count(MON_REQ *req)
+{
+ return req->options->len;
+}
+
+MON_OPT *mon_req_opt_index(MON_REQ *req, size_t index)
+{
+ MON_OPT *result = &g_array_index(req->options, MON_OPT, index);
+ return result;
+}
+
--- /dev/null
+/*
+ * 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 <jansson.h>
+
+#include <mon_internal.h>
+
+// Monitoring request decoders
+
+/**
+ * Decode a single option
+ *
+ * Format:
+ * { "type": "some_tpye" }
+ *
+ * @param opt_json JSON object reference
+ * @param dest allocated memory for the result
+ * @return MON_SUCCESS on success, error on error
+ */
+static MON_RC mon_decode_one_opt(json_t *opt_json, MON_OPT *dest)
+{
+ json_t *jstr = NULL;
+ MON_OPT_TYPE opt_type = OPT_TYPE_UNKNOWN;
+
+ if ( (opt_json == NULL) || (dest == NULL))
+ return MON_BADARG;
+
+ if (! json_is_object(opt_json))
+ return MON_NOPARSE;
+
+ jstr = json_object_get(opt_json, "type");
+ if ( (jstr == NULL) || (! json_is_string(jstr)) )
+ return MON_NOPARSE;
+
+ opt_type = mon_opt_type_from_string(json_string_value(jstr));
+ if (opt_type == OPT_TYPE_UNKNOWN)
+ return MON_NOPARSE;
+
+ dest->type = opt_type;
+ return MON_SUCCESS;
+}
+
+/**
+ * Decode options array
+ *
+ * Format:
+ * [{option}, {option}, ...]
+ *
+ */
+static MON_RC mon_options_decode(json_t *opts_json, MON_REQ *req)
+{
+ MON_OPT opt; // not a pointer
+ size_t n_opts=0;
+ size_t ii=0;
+
+ if ( (opts_json == NULL) || (req == NULL))
+ return MON_BADARG;
+
+ if (! json_is_array(opts_json))
+ return MON_NOPARSE;
+
+ n_opts = json_array_size(opts_json);
+ for (ii=0; ii < n_opts; ii++) {
+ if (mon_decode_one_opt(json_array_get(opts_json, ii),
+ &opt) != MON_SUCCESS) {
+ return MON_NOPARSE;
+ }
+ mon_req_add_option(req, opt.type);
+ }
+ return MON_SUCCESS;
+}
+
+/**
+ * Parse a JSON string into a request
+ */
+MON_REQ *mon_req_parse(TALLOC_CTX *mem_ctx, const char *input)
+{
+ json_t *parsed_json = NULL;
+ json_error_t json_error;
+
+ parsed_json = json_loads(input, JSON_REJECT_DUPLICATES, &json_error);
+ return mon_req_decode(mem_ctx, parsed_json);
+}
+
+/**
+ * Decode a JSON request
+ *
+ * Expected format:
+ * {
+ * "command": "some_command_name",
+ * "options": [{option1}, ...]
+ * }
+ *
+ * (options are optional)
+ *
+ * Caller must free the return value with mon_req_free().
+ *
+ * @param mem_ctx talloc context for the returned struct
+ * @param req_json reference to JSON request object
+ * @return decoded request struct or NULL on failure
+ */
+MON_REQ *mon_req_decode(TALLOC_CTX *mem_ctx, json_t *req_json)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ MON_REQ *req = NULL;
+ json_t *jval = NULL;
+ json_t *opts_json = NULL;
+ MON_CMD cmd = MON_CMD_UNKNOWN;
+
+ if (! json_is_object(req_json))
+ goto cleanup;
+
+ // Get the command and verify that it is a string value
+ jval = json_object_get(req_json, "command");
+ if (! json_is_string(jval))
+ goto cleanup;
+
+ cmd = mon_cmd_from_string(json_string_value(jval));
+ if (cmd == MON_CMD_UNKNOWN)
+ goto cleanup;
+
+ /* Command is good. Allocate the request in the tmp context */
+ req = mon_req_new(tmp_ctx, cmd);
+ if (req == NULL)
+ goto cleanup;
+
+ /* Parse options if we have any */
+ opts_json = json_object_get(req_json, "options");
+ if (opts_json) {
+ if (mon_options_decode(opts_json, req) != MON_SUCCESS) {
+ req = NULL; // memory still in tmp_ctx, so it will be cleaned up
+ goto cleanup;
+ }
+ }
+
+ /* Success! Put the request in the caller's talloc context */
+ talloc_steal(mem_ctx, req);
+
+cleanup:
+ talloc_free(tmp_ctx);
+
+ return req;
+}
--- /dev/null
+/*
+ * 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 <jansson.h>
+#include <glib.h>
+
+#include <mon_internal.h>
+
+// Monitoring request encoders
+
+/**
+ * Encode options array as a JSON array
+ *
+ * Format:
+ * [
+ * { "type": "first_type" },
+ * { "type": "second_type"},
+ * ...
+ * ]
+ *
+ * @param opts array of options
+ * @return reference to a JSON array of options
+ */
+static json_t *mon_opts_decode(GArray *opts)
+{
+ json_t *array_json = json_array(); // the array of options
+ json_t *opt_json = NULL; // individual option JSON object
+ json_t *type_json = NULL;
+ guint ii = 0;
+ MON_OPT this_opt;
+
+ if (array_json == NULL)
+ return NULL; // failed
+
+ /* Iterate over the options */
+ for (ii=0; ii < opts->len; ii++) {
+ this_opt = g_array_index(opts, MON_OPT, ii);
+
+ /* Create the JSON object for this option */
+ opt_json = json_object();
+ if (opt_json == NULL) {
+ json_decref(array_json);
+ return NULL;
+ }
+
+ /* Add to the array, making opt_json a borrowed ref if we succeed */
+ if (json_array_append_new(array_json, opt_json) == -1) {
+ json_decref(array_json);
+ json_decref(opt_json); // handle ourselves because the set failed
+ }
+
+ /* Create the type string for this option */
+ type_json = json_string(mon_opt_type_to_string(this_opt.type));
+ if (type_json == NULL) {
+ json_decref(array_json);
+ return NULL;
+ }
+
+ /* Add the type string to the JSON object, making type_json a borrowed ref */
+ if (json_object_set_new(opt_json, "type", type_json) == -1) {
+ json_decref(array_json);
+ json_decref(type_json); // must handle ourselves because the set failed
+ return NULL;
+ }
+ }
+
+ return array_json;
+}
+
+/**
+ * Encode a request as a JSON object
+ *
+ * Caller must free the return value using json_decref()
+ *
+ * Format:
+ * {
+ * "command": "some_command",
+ * "options": [...see mon_opts_to_json()...]
+ * }
+ *
+ * @param req request to encode
+ * @return reference to a JSON object
+ */
+json_t *mon_req_encode(MON_REQ *req)
+{
+ json_t *req_json = NULL;
+ json_t *cmd_json = NULL;
+ json_t *opts_json = NULL;
+
+ /* Allocate the base JSON object */
+ req_json = json_object();
+ if (req_json == NULL)
+ return NULL;
+
+ /* Allocate the JSON string for the command */
+ cmd_json = json_string(mon_cmd_to_string(req->command));
+ if (cmd_json == NULL) {
+ json_decref(req_json);
+ return NULL;
+ }
+
+ /* Add the command string to the base object. Steals the reference to
+ * the string if successful. */
+ if (json_object_set_new(req_json, "command", cmd_json) == -1) {
+ json_decref(cmd_json); // must clean this up ourselves because the set failed
+ json_decref(req_json);
+ return NULL;
+ }
+
+ /* If we have options, add them to the object */
+ if (req->options->len > 0) {
+ opts_json = mon_opts_decode(req->options);
+ if (opts_json == NULL) {
+ json_decref(req_json);
+ return NULL;
+ }
+
+ if (json_object_set_new(req_json, "options", opts_json) == -1) {
+ json_decref(req_json);
+ json_decref(opts_json); // must clean this up ourselves because set failed
+ return NULL;
+ }
+ }
+
+ /* That's it, we succeeded */
+ return req_json;
+}
+
--- /dev/null
+/*
+ * 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_name_internal.h>
+
+#include <mon_internal.h>
+
+// Monitoring request message common code
+
+/**
+ * Destructor used by talloc to ensure proper cleanup
+ */
+static int mon_resp_destructor(void *object)
+{
+ MON_RESP *resp = talloc_get_type_abort(object, MON_RESP);
+ /* free the message */
+ if (resp->message) {
+ tr_free_name(resp->message);
+ }
+ /* free the payload */
+ if (resp->payload) {
+ json_decref(resp->payload);
+ }
+ return 0;
+}
+
+/**
+ * Allocate a new monitoring response
+ *
+ * Caller must free using mon_resp_free().
+ *
+ * Makes its own copy of the message, so caller can dispose of
+ * that after allocating the response.
+ *
+ * Increments the reference count of the payload if it is not null.
+ *
+ * @param mem_ctx talloc context for allocation
+ * @param req MON_REQ this response corresponds to
+ * @param code numeric response code
+ * @param msg string description of response code
+ * @param payload JSON object to be send as payload, or null for no payload
+ * @return response allocated in the requested talloc context, null on failure
+ */
+MON_RESP *mon_resp_new(TALLOC_CTX *mem_ctx, MON_RESP_CODE code, const char *msg, json_t *payload)
+{
+ MON_RESP *resp = talloc(mem_ctx, MON_RESP);
+ if (resp) {
+ resp->code = code;
+ resp->message = tr_new_name(msg);
+
+ resp->payload = payload;
+ if (resp->payload)
+ json_incref(resp->payload);
+
+ talloc_set_destructor((void *)resp, mon_resp_destructor);
+ if (resp->message == NULL) {
+ talloc_free(resp); // destructor will be called
+ resp = NULL;
+ }
+ }
+ return resp;
+}
+
+/**
+ * Set or replace the response message
+ *
+ * Does not change the message if it fails
+ *
+ * @param resp
+ * @param new_msg
+ * @return 1 on success, 0 on error
+ */
+int mon_resp_set_message(MON_RESP *resp, const char *new_msg)
+{
+ TR_NAME *n = tr_new_name(new_msg);
+
+ if (n == NULL)
+ return 0; /* failed */
+
+ if (resp->message)
+ tr_free_name(resp->message);
+ resp->message = n;
+ return 1; /* succeeded */
+}
+
+/**
+ * Set or replace the payload
+ *
+ * Manages JSON reference counts
+ *
+ * @param resp
+ * @param new_payload
+ */
+void mon_resp_set_payload(MON_RESP *resp, json_t *new_payload)
+{
+ if (resp->payload)
+ json_decref(resp->payload);
+ resp->payload = new_payload;
+ if (resp->payload)
+ json_incref(new_payload);
+}
+
+/**
+ * Free a monitoring response
+ *
+ * @param resp request to free, must not be null
+ */
+void mon_resp_free(MON_RESP *resp)
+{
+ talloc_free(resp);
+}
--- /dev/null
+/*
+ * 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 <jansson.h>
+
+#include <mon_internal.h>
+
+// Monitoring response decoder
+
+/**
+ * Decode a JSON response
+ *
+ * Expected format:
+ * {
+ * "code": 0,
+ * "message": "success",
+ * "payload": {
+ * "serial": 12345,
+ * ...
+ * }
+ * }
+ *
+ * Caller must free the return value with MON_REQ_free().
+ *
+ * @param mem_ctx talloc context for the returned struct
+ * @param resp_json reference to JSON request object
+ * @return decoded request struct or NULL on failure
+ */
+MON_RESP *mon_resp_decode(TALLOC_CTX *mem_ctx, json_t *resp_json)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ MON_RESP *resp = NULL;
+ json_t *jcode = NULL;
+ json_t *jmessage = NULL;
+ json_t *jpayload = NULL;
+
+ if (! json_is_object(resp_json))
+ goto cleanup;
+
+ /* Get the response code, which is an integer */
+ jcode = json_object_get(resp_json, "code");
+ if (! json_is_integer(jcode))
+ goto cleanup;
+
+ /* Get the response message, which is a string */
+ jmessage = json_object_get(resp_json, "message");
+ if (! json_is_string(jmessage))
+ goto cleanup;
+
+ /* Get the payload if we have one */
+ jpayload = json_object_get(resp_json, "payload");
+
+ /* Get a response in the tmp_ctx context. The payload may be null. */
+ resp = mon_resp_new(tmp_ctx,
+ (MON_RESP_CODE) json_integer_value(jcode),
+ json_string_value(jmessage),
+ jpayload);
+ if (resp == NULL)
+ goto cleanup;
+
+ /* Success! Put the request in the caller's talloc context */
+ talloc_steal(mem_ctx, resp);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ if (resp_json)
+ json_decref(resp_json);
+
+ return resp;
+}
--- /dev/null
+/*
+ * 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 <jansson.h>
+
+#include <mon_internal.h>
+
+/* Helper for encoding. Adds a newly allocated JSON object to
+ * jobj. If the allocation or setting fails, returns NULL after
+ * cleaning up. */
+#define object_set_or_free_and_return(jobj, tmp_jval, key, jval) \
+ do { \
+ (tmp_jval) = (jval); \
+ if ( (tmp_jval) == NULL) { \
+ json_decref(jobj); \
+ return NULL; \
+ } \
+ if (json_object_set_new((jobj), (key), (tmp_jval)) == -1) { \
+ json_decref(tmp_jval); \
+ json_decref(jobj); \
+ return NULL; \
+ } \
+ } while(0)
+
+/**
+ * Encode a monitoring response as a JSON object
+ *
+ * Caller must ensure json_decref() is used to free the return value.
+ *
+ * @param resp response to encode
+ * @return response as a newly allocated JSON object
+ */
+json_t *mon_resp_encode(MON_RESP *resp)
+{
+ json_t *resp_json = NULL;
+ json_t *jval = NULL;
+
+ /* Get a JSON object */
+ resp_json = json_object();
+ if (resp_json == NULL)
+ return NULL;
+
+ /* Add properties, cleaning up and returning NULL on failure */
+ object_set_or_free_and_return(resp_json, jval, "code", json_integer(resp->code));
+ object_set_or_free_and_return(resp_json, jval, "message", tr_name_to_json_string(resp->message));
+
+ /* If we have a payload, add it */
+ if (resp->payload) {
+ object_set_or_free_and_return(resp_json, jval, "payload", resp->payload);
+ json_incref(resp->payload); /* we just created a second reference to the payload */
+ }
+
+ return resp_json;
+}
--- /dev/null
+/*
+ * Copyright (c) 2012, 2014-2018, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <jansson.h>
+#include <talloc.h>
+
+#include <trust_router/tr_dh.h>
+#include <mon_internal.h>
+#include <tr_msg.h>
+#include <gsscon.h>
+#include <tr_debug.h>
+
+
+MONC_INSTANCE *monc_new(TALLOC_CTX *mem_ctx)
+{
+ MONC_INSTANCE *monc=talloc(mem_ctx, MONC_INSTANCE);
+ if (monc!=NULL) {
+ monc->gssc = tr_gssc_instance_new(monc);
+ if (monc->gssc == NULL) {
+ talloc_free(monc);
+ return NULL;
+ }
+
+ monc->gssc->service_name = "trustmonitor";
+ }
+ return monc;
+}
+
+void monc_free(MONC_INSTANCE *monc)
+{
+ talloc_free(monc);
+}
+
+int monc_open_connection(MONC_INSTANCE *monc,
+ const char *server,
+ unsigned int port)
+{
+ return tr_gssc_open_connection(monc->gssc, server, port);
+}
+
+MON_RESP *monc_send_request(TALLOC_CTX *mem_ctx, MONC_INSTANCE *monc, MON_REQ *req)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ TR_MSG *msg = NULL;
+ TR_MSG *resp_msg = NULL;
+ MON_RESP *resp = NULL;
+
+ /* Create and populate a msg structure */
+ if (!(msg = talloc_zero(tmp_ctx, TR_MSG)))
+ goto cleanup;
+
+ msg->msg_type = MON_REQUEST;
+ tr_msg_set_mon_req(msg, req);
+
+ resp_msg = tr_gssc_exchange_msgs(tmp_ctx, monc->gssc, msg);
+ if (resp_msg == NULL)
+ goto cleanup;
+
+ resp = tr_msg_get_mon_resp(resp_msg);
+
+ /* if we got a response, steal it from resp_msg's context so we can return it */
+ if (resp)
+ talloc_steal(mem_ctx, resp);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return resp;
+}
+
+DH *monc_get_dh(MONC_INSTANCE *inst)
+{
+ return tr_gssc_get_dh(inst->gssc);
+}
+
+DH *monc_set_dh(MONC_INSTANCE *inst, DH *dh)
+{
+ return tr_gssc_set_dh(inst->gssc, dh);
+}
--- /dev/null
+/*
+ * 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>
+
+#include "mons_handlers.h"
+
+static void mons_sweep_procs(MONS_INSTANCE *mons);
+
+static int mons_destructor(void *object)
+{
+ MONS_INSTANCE *mons = talloc_get_type_abort(object, MONS_INSTANCE);
+ if (mons->handlers)
+ g_ptr_array_unref(mons->handlers);
+
+ if (mons->pids)
+ g_array_unref(mons->pids);
+
+ return 0;
+}
+
+/**
+ * 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;
+
+ /* Before any steps that may fail, install the destructor */
+ talloc_set_destructor((void *)mons, mons_destructor);
+
+ mons->authorized_gss_names = tr_gss_names_new(mons);
+ if (mons->authorized_gss_names == NULL) {
+ talloc_free(mons);
+ return NULL;
+ }
+
+ mons->handlers = g_ptr_array_new();
+ if (mons->handlers == NULL) {
+ talloc_free(mons);
+ return NULL;
+ }
+
+ mons->pids = g_array_new(FALSE, FALSE, sizeof(pid_t));
+ if (mons->pids == NULL) {
+ talloc_free(mons);
+ return 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 TR_MSG *mons_req_cb(TALLOC_CTX *mem_ctx, TR_MSG *req_msg, void *data)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ MONS_INSTANCE *mons = talloc_get_type_abort(data, MONS_INSTANCE);
+ MON_REQ *req = NULL;
+ MON_RESP *resp = NULL;
+ TR_MSG *resp_msg = NULL; /* This is the response value */
+
+ /* Validate inputs */
+ if (req_msg == NULL)
+ goto cleanup;
+
+ req = tr_msg_get_mon_req(req_msg);
+ if (req == NULL) {
+ /* this is an internal error */
+ tr_err("mons_req_cb: Received incorrect message type (was %d, expected %d)",
+ tr_msg_get_msg_type(req_msg),
+ MON_REQUEST);
+ /* TODO send an error response */
+ goto cleanup;
+ }
+
+ /* Allocate a response message */
+ resp_msg = talloc(tmp_ctx, TR_MSG);
+ if (resp_msg == NULL) {
+ /* can't return a message, just emit an error */
+ tr_crit("mons_req_cb: Error allocating response message.");
+ goto cleanup;
+ }
+
+ /* Handle the request */
+ resp = mons_handle_request(resp_msg, mons, req);
+ if (resp == NULL) {
+ /* error processing the request */
+ /* TODO send back an error */
+ goto cleanup;
+ }
+
+ /* Set the response message payload */
+ tr_msg_set_mon_resp(resp_msg, resp);
+
+ /* Put the response message in the caller's context so it does not get freed when we exit */
+ talloc_steal(mem_ctx, resp_msg);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return resp_msg;
+}
+
+/**
+ * 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 */
+ }
+
+ /* Only the parent process gets here */
+ close(conn);
+ g_array_append_val(mons->pids, pid);
+
+ /* clean up any processes that have completed */
+ mons_sweep_procs(mons);
+
+ return 0;
+}
+
+void mons_sweep_procs(MONS_INSTANCE *mons)
+{
+ guint ii;
+ pid_t pid;
+ int status;
+
+ /* loop backwards over the array so we can remove elements as we go */
+ for (ii=mons->pids->len; ii > 0; ii--) {
+ /* ii-1 is the current index */
+ pid = g_array_index(mons->pids, pid_t, ii-1);
+ if (waitpid(pid, &status, WNOHANG) > 0) {
+ /* the process exited */
+ tr_debug("mons_sweep_procs: monitoring process %d terminated.", pid);
+
+ g_array_remove_index_fast(mons->pids, ii-1); /* disturbs only indices >= ii-1 which we've already handled */
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) == 0)
+ tr_debug("mons_sweep_procs: monitoring process %d succeeded.", pid);
+ else
+ tr_debug("mons_sweep_procs: monitoring process %d exited with status %d.", pid, WTERMSIG(status));
+ } else if (WIFSIGNALED(status)) {
+ tr_debug("mons_sweep_procs: monitoring process %d terminated by signal %d.", pid, WTERMSIG(status));
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.
+ *
+ */
+
+/* Handlers for monitoring requests */
+
+#include <gmodule.h>
+
+#include <tr_debug.h>
+#include <mon_internal.h>
+#include <mons_handlers.h>
+
+
+/* Static Prototypes */
+static int dispatch_entry_matches(MONS_DISPATCH_TABLE_ENTRY *e, MON_CMD command, MON_OPT_TYPE opt_type);
+static MONS_HANDLER_FUNC *mons_find_handler(MONS_INSTANCE *mons, MON_CMD cmd, MON_OPT_TYPE opt_type);
+static void request_helper(void *element, void *data);
+
+struct request_helper_data {
+ MON_CMD command;
+ MON_OPT_TYPE opt_type;
+ json_t *payload; /* json object to add responses to */
+ GArray *results;
+};
+
+struct handler_result {
+ MON_OPT_TYPE opt_type; /* what opt type set this? */
+ MON_RC rc; /* what was its result code? */
+ json_t *json_data; /* what data, if any, is it returning? */
+};
+
+/**
+ * Call the appropriate handler for a request
+ *
+ * TODO: report errors from handlers
+ *
+ * @return a MON_RESP structure or null if there was a processing error
+ */
+MON_RESP *mons_handle_request(TALLOC_CTX *mem_ctx, MONS_INSTANCE *mons, MON_REQ *req)
+{
+ MON_RESP *resp = NULL;
+ json_t *payload = NULL;
+ struct request_helper_data cookie = {0};
+ size_t ii = 0;
+
+ tr_debug("mons_handle_request: Handling a request");
+
+ /* Start off by allocating our response with a generic error message */
+ resp = mon_resp_new(mem_ctx,
+ MON_RESP_ERROR,
+ "error processing request",
+ NULL);
+ if (resp == NULL) {
+ /* we can't respond, just return */
+ tr_crit("mons_handle_request: Error allocating response structure.");
+ goto cleanup;
+ }
+
+ /* Now get a JSON object for our return payload */
+ payload = json_object();
+ if (payload == NULL) {
+ tr_crit("mons_handle_request: Error allocating response payload.");
+ goto cleanup; /* This will return the generic error message set earlier */
+ }
+
+ /* Now call handlers */
+ cookie.command = req->command;
+ cookie.results = g_array_new(FALSE, TRUE, sizeof(struct handler_result));
+
+ if (mon_req_opt_count(req) == 0) {
+ /* call every handler that matches the command */
+ cookie.opt_type = OPT_TYPE_ANY;
+ g_ptr_array_foreach(mons->handlers, request_helper, &cookie);
+ } else {
+ /* call only those handlers that match an option */
+ for (ii=0; ii < mon_req_opt_count(req); ii++) {
+ cookie.opt_type = mon_req_opt_index(req, ii)->type;
+ /* Loop over all handlers - we know we can only have one match for each opt type */
+ g_ptr_array_foreach(mons->handlers, request_helper, &cookie);
+ }
+ }
+
+ /* We now have an array of results in cookie.results. If any of these failed, return an error. */
+ tr_debug("mons_handle_request: Examining %d handler results", cookie.results->len);
+ resp->code = MON_RESP_SUCCESS; /* tentatively set this to success */
+ for (ii=0; ii < cookie.results->len; ii++) {
+ struct handler_result *this = &g_array_index(cookie.results, struct handler_result, ii);
+ if (this->rc != MON_SUCCESS) {
+ tr_debug("mons_handle_request: Result %d was an error.", ii);
+ resp->code = MON_RESP_ERROR;
+ }
+
+ /* add the JSON response even if there was an error */
+ if (this->json_data) {
+ tr_debug("mons_handle_request: Result %d returned JSON data.", ii);
+ json_object_set_new(payload, mon_opt_type_to_string(this->opt_type), this->json_data);
+ }
+ }
+
+ if (resp->code == MON_RESP_SUCCESS) {
+ if (mon_resp_set_message(resp, "success") == 0) {
+ /* Failed to set the response message to success - fail ironically, don't send
+ * an inconsistent response. */
+ tr_crit("mons_handle_request: Error setting response message to 'success'.");
+ goto cleanup;
+ }
+ } else {
+ /* Failed - send a response indicating that the overall command succeeded */
+ if (mon_resp_set_message(resp, "request processed but an error occurred") == 0) {
+ tr_crit("mons_handle_request: Error setting response message after a handler error.");
+ goto cleanup;
+ }
+ }
+
+ /* Attach the accumulated payload to the response */
+ if (json_object_size(payload) > 0) {
+ tr_debug("mons_handle_request: Attaching payload to response.");
+ mon_resp_set_payload(resp, payload);
+ }
+
+ tr_debug("mons_handle_request: Successfully processed request.");
+
+cleanup:
+ if (payload)
+ json_decref(payload);
+ if (cookie.results)
+ g_array_free(cookie.results, TRUE);
+ return resp;
+}
+
+/**
+ * Register a handler for a command/option combination
+ *
+ * @param mons
+ * @param cmd
+ * @param opt_type
+ * @param f
+ * @param cookie
+ * @return
+ */
+MON_RC mons_register_handler(MONS_INSTANCE *mons,
+ MON_CMD cmd,
+ MON_OPT_TYPE opt_type,
+ MONS_HANDLER_FUNC *f,
+ void *cookie)
+{
+ MONS_DISPATCH_TABLE_ENTRY *entry = NULL;
+
+ if (mons_find_handler(mons, cmd, opt_type) != NULL) {
+ return MON_ERROR;
+ }
+
+ /* Put these in the mons talloc context so we don't have to muck about with
+ * a free function for the GPtrArray */
+ entry = talloc(mons, MONS_DISPATCH_TABLE_ENTRY);
+ if (entry == NULL) {
+ return MON_NOMEM;
+ }
+ entry->command = cmd;
+ entry->opt_type = opt_type;
+ entry->handler = f;
+ entry->cookie = cookie;
+
+ g_ptr_array_add(mons->handlers, entry);
+ return MON_SUCCESS;
+}
+
+/**
+ * Two table entries match if none of the commands or opt_types are unknown,
+ * if the commands match, and if the opt types either match or at least one is
+ * OPT_TYPE_ANY.
+ *
+ * No comparison of the handler pointer is included.
+ *
+ * @return 1 if the two match, 0 if not
+ */
+static int dispatch_entry_matches(MONS_DISPATCH_TABLE_ENTRY *e,
+ MON_CMD command,
+ MON_OPT_TYPE opt_type)
+{
+ if ((command == MON_CMD_UNKNOWN) || (opt_type == OPT_TYPE_UNKNOWN))
+ return 0; /* request is invalid */
+
+ if ((e->command == MON_CMD_UNKNOWN) || (e->opt_type == OPT_TYPE_UNKNOWN))
+ return 0; /* e1 is invalid */
+
+ if (e->command != command)
+ return 0; /* commands do not match */
+
+ if (e->opt_type == opt_type)
+ return 1; /* exact match */
+
+ if ( (e->opt_type == OPT_TYPE_ANY) || (opt_type == OPT_TYPE_ANY) )
+ return 1; /* one is a wildcard */
+
+ return 0; /* commands matched but opt_types did not */
+}
+
+static MONS_HANDLER_FUNC *mons_find_handler(MONS_INSTANCE *mons, MON_CMD cmd, MON_OPT_TYPE opt_type)
+{
+ guint index;
+
+ for (index=0; index < mons->handlers->len; index++) {
+ if (dispatch_entry_matches(g_ptr_array_index(mons->handlers, index), cmd, opt_type))
+ return g_ptr_array_index(mons->handlers, index);
+ }
+ return NULL;
+}
+
+/**
+ * This calls every request handler that matches a command/opt_type,
+ * gathering their results.
+ *
+ * @param element
+ * @param data
+ */
+static void request_helper(void *element, void *data)
+{
+ MONS_DISPATCH_TABLE_ENTRY *entry = talloc_get_type_abort(element, MONS_DISPATCH_TABLE_ENTRY);
+ struct request_helper_data *helper_data = data;
+ struct handler_result result = {0};
+
+ if (dispatch_entry_matches(entry, helper_data->command, helper_data->opt_type)) {
+ result.rc = entry->handler(entry->cookie, &(result.json_data));
+ result.opt_type = entry->opt_type;
+ g_array_append_val(helper_data->results, result);
+ }
+}
+
--- /dev/null
+{"command": "reconfigure"}
--- /dev/null
+{"command": "show", "options": [{"type": "serial"}, {"type": "version"}, {"type": "uptime"}, {"type": "tid_req_count"}, {"type": "tid_req_pending"}, {"type": "routes"}, {"type": "communities"}]}
--- /dev/null
+{"command": "show"}
--- /dev/null
+{"code": 1, "message": "error"}
--- /dev/null
+{"code": 0, "message": "success"}
--- /dev/null
+{"code": 0, "message": "success", "show": {"version": "1.2.3-4", "serial": 86400, "tid_req_pending": 13, "tid_req_count": 1432}}
--- /dev/null
+//
+// Created by jlr on 4/9/18.
+//
+
+#include <talloc.h>
+#include <jansson.h>
+#include <assert.h>
+#include <string.h>
+#include <glib.h>
+
+#include <mon_internal.h>
+
+/**
+ * @return reconfigure command
+ */
+static MON_REQ *reconfigure()
+{
+ MON_REQ *req = mon_req_new(NULL, MON_CMD_RECONFIGURE);
+ assert(req);
+ return req;
+}
+
+/**
+ * @return show command with no options
+ */
+static MON_REQ *show_plain()
+{
+ MON_REQ *req = mon_req_new(NULL, MON_CMD_SHOW);
+ assert(req);
+ return req;
+}
+
+/**
+ * @param opts array of option types, terminated with OPT_TYPE_UNKNOWN
+ * @return show command with the requested options, excluding the terminator
+ */
+static MON_REQ *show_options(const MON_OPT_TYPE *opts)
+{
+ MON_REQ *req = mon_req_new(NULL, MON_CMD_SHOW);
+ assert(req);
+
+ while (*opts != OPT_TYPE_UNKNOWN) {
+ assert(MON_SUCCESS == mon_req_add_option(req, *opts));
+ opts++;
+ }
+ return req;
+}
+
+/**
+ * @return show command with every option
+ */
+static MON_REQ *show_all_options()
+{
+ MON_OPT_TYPE opts[] = {
+ OPT_TYPE_SHOW_CONFIG_FILES,
+ OPT_TYPE_SHOW_VERSION,
+ OPT_TYPE_SHOW_UPTIME,
+ OPT_TYPE_SHOW_TID_REQ_COUNT,
+ OPT_TYPE_SHOW_TID_REQ_PENDING,
+ OPT_TYPE_SHOW_ROUTES,
+ OPT_TYPE_SHOW_COMMUNITIES,
+ OPT_TYPE_UNKNOWN // terminator
+ };
+
+ return show_options(opts);
+}
+
+static char *read_file(const char *filename)
+{
+ FILE *f = fopen(filename, "r");
+ char *s = NULL;
+ size_t nn = 0;
+ ssize_t n = getline(&s, &nn, f);
+
+ fclose(f);
+
+ if( (n > 0) && (s[n-1] == '\n'))
+ s[n-1] = 0;
+
+ return s;
+}
+
+static int equal(MON_REQ *r1, MON_REQ *r2)
+{
+ size_t ii;
+
+ if (r1->command != r2->command)
+ return 0;
+
+ if (mon_req_opt_count(r1) != mon_req_opt_count(r2))
+ return 0;
+
+ for (ii=0; ii < mon_req_opt_count(r1); ii++) {
+ if (mon_req_opt_index(r1, ii)->type != mon_req_opt_index(r2, ii)->type)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int run_test(const char *filename, MON_REQ *(generator)())
+{
+ MON_REQ *req = NULL;
+ MON_REQ *expected = NULL;
+ char *req_json_str = NULL;
+
+ expected = generator();
+ assert(expected);
+
+ req_json_str = read_file(filename);
+ assert(req_json_str);
+
+ req = mon_req_parse(NULL, req_json_str);
+ assert(req);
+ assert(equal(req, expected));
+
+ free(req_json_str);
+ mon_req_free(req);
+ mon_req_free(expected);
+
+ return 1;
+}
+
+int main(void)
+{
+
+ // Test reconfigure command
+ assert(run_test("req_reconfigure.test", reconfigure));
+
+ // Test show command with no options
+ assert(run_test("req_show_no_options.test", show_plain));
+
+ // Test show command with all the options
+ assert(run_test("req_show_all_options.test", show_all_options));
+
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+//
+// Created by jlr on 4/9/18.
+//
+
+#include <talloc.h>
+#include <jansson.h>
+#include <assert.h>
+#include <string.h>
+#include <glib.h>
+
+#include <mon_internal.h>
+
+#define JSON_DUMP_OPTS 0
+
+static char *reconfigure()
+{
+ MON_REQ *req = mon_req_new(NULL, MON_CMD_RECONFIGURE);
+ json_t *req_json = mon_req_encode(req);
+ char *result = json_dumps(req_json, JSON_DUMP_OPTS);
+ assert(req);
+ assert(req_json);
+ assert(result);
+ json_decref(req_json);
+ mon_req_free(req);
+ return result;
+}
+
+static char *show_plain()
+{
+ MON_REQ *req = mon_req_new(NULL, MON_CMD_SHOW);
+ json_t *req_json = mon_req_encode(req);
+ char *result = json_dumps(req_json, JSON_DUMP_OPTS);
+ assert(req);
+ assert(req_json);
+ assert(result);
+ json_decref(req_json);
+ mon_req_free(req);
+ return result;
+}
+
+static char *show_options(const MON_OPT_TYPE *opts)
+{
+ MON_REQ *req = mon_req_new(NULL, MON_CMD_SHOW);
+ json_t *req_json = NULL;
+ char *result = NULL;
+
+ assert(req);
+
+ while (*opts != OPT_TYPE_UNKNOWN) {
+ assert(MON_SUCCESS == mon_req_add_option(req, *opts));
+ opts++;
+ }
+
+ req_json = mon_req_encode(req);
+ assert(req_json);
+
+ result = json_dumps(req_json, JSON_DUMP_OPTS);
+ assert(result);
+
+ json_decref(req_json);
+ mon_req_free(req);
+ return result;
+}
+
+static char *read_file(const char *filename)
+{
+ FILE *f = fopen(filename, "r");
+ char *s = NULL;
+ size_t nn = 0;
+ ssize_t n = getline(&s, &nn, f);
+ fclose(f);
+
+ if( (n > 0) && (s[n-1] == '\n'))
+ s[n-1] = 0;
+
+ return s;
+}
+int main(void)
+{
+ char *s = NULL;
+ MON_OPT_TYPE opts[10];
+ char *expected = NULL;
+
+ // Test reconfigure command
+ s = reconfigure();
+ expected = read_file("req_reconfigure.test");
+ assert(expected);
+ assert(strcmp(expected, s) == 0);
+ free(s);
+ free(expected);
+
+ // Test show without options
+ s = show_plain();
+ expected = read_file("req_show_no_options.test");
+ assert(expected);
+ assert(strcmp(expected, s) == 0);
+ free(s);
+ free(expected);
+
+ // Test show with empty options (this mostly tests the test)
+ opts[0] = OPT_TYPE_UNKNOWN;
+ s = show_options(opts);
+ expected = read_file("req_show_no_options.test");
+ assert(expected);
+ assert(strcmp(expected, s) == 0);
+ free(s);
+ free(expected);
+
+ // Test show with many options
+ opts[0] = OPT_TYPE_SHOW_CONFIG_FILES;
+ opts[1] = OPT_TYPE_SHOW_VERSION;
+ opts[2] = OPT_TYPE_SHOW_UPTIME;
+ opts[3] = OPT_TYPE_SHOW_TID_REQ_COUNT;
+ opts[4] = OPT_TYPE_SHOW_TID_REQ_PENDING;
+ opts[5] = OPT_TYPE_SHOW_ROUTES;
+ opts[6] = OPT_TYPE_SHOW_COMMUNITIES;
+ opts[7] = OPT_TYPE_UNKNOWN;
+ s = show_options(opts);
+ expected = read_file("req_show_all_options.test");
+ assert(expected);
+ assert(strcmp(expected, s) == 0);
+ free(s);
+ free(expected);
+
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+//
+// Created by jlr on 4/9/18.
+//
+
+#include <talloc.h>
+#include <jansson.h>
+#include <assert.h>
+#include <string.h>
+
+#include <mon_internal.h>
+
+#define JSON_DUMP_OPTS 0
+
+static char *reconfigure(MON_RESP_CODE code, const char *message)
+{
+ MON_REQ *req = NULL;
+ MON_RESP *resp = NULL;
+ json_t *resp_json = NULL;
+ char *result = NULL;
+
+ req = mon_req_new(NULL, MON_CMD_RECONFIGURE);
+ assert(req);
+
+ resp = mon_resp_new(NULL, code, message, NULL);
+ assert(resp);
+
+ resp_json = mon_resp_encode(resp);
+ assert(resp_json);
+
+ result = json_dumps(resp_json, JSON_DUMP_OPTS);
+ assert(result);
+
+ json_decref(resp_json);
+ mon_resp_free(resp);
+ mon_req_free(req);
+ return result;
+}
+
+static char *reconfigure_success()
+{
+ return reconfigure(MON_RESP_SUCCESS, "success");
+}
+
+static char *reconfigure_error()
+{
+ return reconfigure(MON_RESP_ERROR, "error");
+}
+
+static char *show_success()
+{
+ MON_REQ *req = NULL;
+ MON_RESP *resp = NULL;
+ json_t *resp_json = NULL;
+ json_t *payload = NULL;
+ char *result = NULL;
+
+ req = mon_req_new(NULL, MON_CMD_SHOW);
+ // Only need the command to be set in req, don't actually need the options
+ assert(req);
+
+ payload = json_object();
+ assert(payload);
+ assert(! json_object_set_new(payload,
+ mon_opt_type_to_string(OPT_TYPE_SHOW_VERSION),
+ json_string("1.2.3-4")));
+ assert(! json_object_set_new(payload,
+ mon_opt_type_to_string(OPT_TYPE_SHOW_CONFIG_FILES),
+ json_integer(1234567890)));
+ assert(! json_object_set_new(payload,
+ mon_opt_type_to_string(OPT_TYPE_SHOW_CONFIG_FILES),
+ json_integer(86400)));
+ assert(! json_object_set_new(payload,
+ mon_opt_type_to_string(OPT_TYPE_SHOW_TID_REQ_PENDING),
+ json_integer(13)));
+ assert(! json_object_set_new(payload,
+ mon_opt_type_to_string(OPT_TYPE_SHOW_TID_REQ_COUNT),
+ json_integer(1432)));
+
+ resp = mon_resp_new(NULL, MON_RESP_SUCCESS, "success", payload);
+ assert(resp);
+
+ resp_json = mon_resp_encode(resp);
+ assert(resp_json);
+
+ result = json_dumps(resp_json, JSON_DUMP_OPTS);
+ assert(result);
+
+ json_decref(resp_json);
+ mon_resp_free(resp);
+ mon_req_free(req);
+ return result;
+}
+
+static char *read_file(const char *filename)
+{
+ FILE *f = fopen(filename, "r");
+ char *s = NULL;
+ size_t nn = 0;
+ ssize_t n = getline(&s, &nn, f);
+ fclose(f);
+
+ if( (n > 0) && (s[n-1] == '\n'))
+ s[n-1] = 0;
+
+ return s;
+}
+
+int run_test(const char *filename, char *(generator)())
+{
+ char *s = NULL;
+ char *expected = NULL;
+
+ // Test reconfigure command
+ s = generator();
+ expected = read_file(filename);
+ assert(expected);
+ assert(strcmp(expected, s) == 0);
+ free(s);
+ free(expected);
+
+ return 1;
+}
+
+int main(void)
+{
+ assert(run_test("resp_reconfigure_success.test", reconfigure_success));
+ assert(run_test("resp_reconfigure_error.test", reconfigure_error));
+ assert(run_test("resp_show_success.test", show_success));
+ return 0;
+}
/* Create a TID client instance & the client DH */
tidc = tidc_create();
- if (NULL == (tidc->client_dh = tr_create_dh_params(NULL, 0))) {
+ tidc_set_dh(tidc, tr_create_dh_params(NULL, 0));
+ if (tidc_get_dh(tidc) == NULL) {
printf("Error creating client DH params.\n");
return 1;
}
tr_debug("tids_req_handler: Request received! target_realm = %s, community = %s", req->realm->buf, req->comm->buf);
- if (tids)
- tids->req_count++;
-
if (!(resp) || !resp) {
tr_debug("tids_req_handler: No response structure.");
return -1;
return(req->orig_coi);
}
-void tid_req_set_rp_orig_coi(TID_REQ *req, TR_NAME *orig_coi)
+void tid_req_set_orig_coi(TID_REQ *req, TR_NAME *orig_coi)
{
req->orig_coi = orig_coi;
}
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;
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);
#include <jansson.h>
#include <talloc.h>
+#include <gsscon.h>
#include <trust_router/tr_dh.h>
#include <tid_internal.h>
#include <tr_msg.h>
-#include <gsscon.h>
#include <tr_debug.h>
#include <tr_rand_id.h>
int tmp_len = 32;
-static int tidc_destructor(void *obj)
-{
- TIDC_INSTANCE *tidc=talloc_get_type_abort(obj, TIDC_INSTANCE);
- if (NULL!=tidc) {
- if (NULL!=tidc->client_dh)
- tr_destroy_dh_params(tidc->client_dh);
- }
- return 0;
-}
-
/* creates struct in talloc null context */
TIDC_INSTANCE *tidc_create(void)
{
TIDC_INSTANCE *tidc=talloc(NULL, TIDC_INSTANCE);
if (tidc!=NULL) {
- tidc->client_dh=NULL;
- talloc_set_destructor((void *)tidc, tidc_destructor);
+ tidc->gssc = tr_gssc_instance_new(tidc);
+ if (tidc->gssc == NULL) {
+ talloc_free(tidc);
+ return NULL;
+ }
+
+ tidc->gssc->service_name = "trustidentity";
}
return tidc;
}
}
int tidc_open_connection (TIDC_INSTANCE *tidc,
- const char *server,
- unsigned int port,
- gss_ctx_id_t *gssctx)
+ const char *server,
+ unsigned int port,
+ gss_ctx_id_t *gssctx)
{
- int err = 0;
- int conn = -1;
unsigned int use_port = 0;
+ tidc->gssc->gss_ctx = gssctx;
if (0 == port)
use_port = TID_PORT;
else
use_port = port;
- tr_debug("tidc_open_connection: opening tidc connection to %s:%d", server, port);
- err = gsscon_connect(server, use_port, "trustidentity", &conn, gssctx);
-
- if (!err)
- return conn;
+ tr_debug("tidc_open_connection: opening tidc connection to %s:%d", server, use_port);
+ if (0 == tr_gssc_open_connection(tidc->gssc, server, use_port))
+ return tidc->gssc->conn;
else
return -1;
}
int tidc_send_request (TIDC_INSTANCE *tidc,
- int conn,
- gss_ctx_id_t gssctx,
- const char *rp_realm,
- const char *realm,
- const char *comm,
- TIDC_RESP_FUNC *resp_handler,
- void *cookie)
+ int conn,
+ gss_ctx_id_t gssctx,
+ const char *rp_realm,
+ const char *realm,
+ const char *comm,
+ TIDC_RESP_FUNC *resp_handler,
+ void *cookie)
{
TID_REQ *tid_req = NULL;
char *request_id = NULL;
int rc;
+ int orig_conn = 0;
+ gss_ctx_id_t *orig_gss_ctx = NULL;
+
+ /* For ABI compatibility, replace the generic GSS client parameters
+ * with the arguments we were passed. */
+ orig_conn = tidc->gssc->conn; /* save to restore later */
+ if (conn != tidc->gssc->conn) {
+ tr_warning("tidc_send_request: WARNING: socket connection FD does not match FD opened by tidc_open_connection()");
+ tidc->gssc->conn = conn;
+ }
+ orig_gss_ctx = tidc->gssc->gss_ctx; /* save to restore later */
+ if (gssctx != *(tidc->gssc->gss_ctx)) {
+ tr_warning("tidc_send_request: WARNING: sending request with different GSS context than used for tidc_open_connection()");
+ *tidc->gssc->gss_ctx = gssctx;
+ }
/* Create and populate a TID req structure */
if (!(tid_req = tid_req_new()))
- return -1;
+ goto error;
tid_req->conn = conn;
tid_req->gssctx = gssctx;
goto error;
}
- tid_req->tidc_dh = tr_dh_dup(tidc->client_dh);
+ tid_req->tidc_dh = tr_dh_dup(tidc->gssc->client_dh);
/* generate an ID */
request_id = tr_random_id(NULL);
error:
rc = -1;
cleanup:
- tid_req_free(tid_req);
+ if (tid_req)
+ tid_req_free(tid_req);
+
+ tidc->gssc->conn = orig_conn;
+ tidc->gssc->gss_ctx = orig_gss_ctx;
return rc;
}
TIDC_RESP_FUNC *resp_handler,
void *cookie)
{
- char *req_buf = NULL;
- char *resp_buf = NULL;
- size_t resp_buflen = 0;
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
TR_MSG *msg = NULL;
TR_MSG *resp_msg = NULL;
TID_RESP *tid_resp = NULL;
- int err;
int rc = 0;
/* Create and populate a TID msg structure */
- if (!(msg = talloc_zero(tid_req, TR_MSG)))
+ if (!(msg = talloc_zero(tmp_ctx, TR_MSG)))
goto error;
msg->msg_type = TID_REQUEST;
tr_msg_set_req(msg, tid_req);
- /* store the response function and cookie */
- // tid_req->resp_func = resp_handler;
- // tid_req->cookie = cookie;
-
- /* Encode the request into a json string */
- if (!(req_buf = tr_msg_encode(msg))) {
- tr_err("tidc_fwd_request: Error encoding TID request.\n");
- goto error;
- }
-
- tr_debug( "tidc_fwd_request: Sending TID request:\n");
- tr_debug( "%s\n", req_buf);
+ tr_debug( "tidc_fwd_request: Sending TID request\n");
/* Send the request over the connection */
- if (err = gsscon_write_encrypted_token (tid_req->conn, tid_req->gssctx, req_buf,
- strlen(req_buf))) {
- tr_err( "tidc_fwd_request: Error sending request over connection.\n");
+ resp_msg = tr_gssc_exchange_msgs(tmp_ctx, tidc->gssc, msg);
+ if (resp_msg == NULL)
goto error;
- }
-
- /* TBD -- queue request on instance, read resps in separate thread */
-
- /* Read the response from the connection */
- /* TBD -- timeout? */
- if (err = gsscon_read_encrypted_token(tid_req->conn, tid_req->gssctx, &resp_buf, &resp_buflen)) {
- if (resp_buf)
- free(resp_buf);
- goto error;
- }
-
- tr_debug( "tidc_fwd_request: Response Received (%u bytes).\n", (unsigned) resp_buflen);
- tr_debug( "%s\n", resp_buf);
-
- if (NULL == (resp_msg = tr_msg_decode(resp_buf, resp_buflen))) {
- tr_err( "tidc_fwd_request: Error decoding response.\n");
- goto error;
- }
/* TBD -- Check if this is actually a valid response */
tid_resp = tr_msg_get_resp(resp_msg);
error:
rc = -1;
cleanup:
- if (msg)
- talloc_free(msg);
- if (req_buf)
- free(req_buf);
- if (resp_buf)
- free(resp_buf);
- if (resp_msg)
- tr_msg_free_decoded(resp_msg);
+ talloc_free(tmp_ctx);
return rc;
}
DH * tidc_get_dh(TIDC_INSTANCE *inst)
{
- return inst->client_dh;
+ return tr_gssc_get_dh(inst->gssc);
}
DH *tidc_set_dh(TIDC_INSTANCE *inst, DH *dh)
{
- inst->client_dh = dh;
- return dh;
+ return tr_gssc_set_dh(inst->gssc, dh);
}
*
*/
-#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;
}
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;
}
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;
}
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 TR_MSG *tids_req_cb(TALLOC_CTX *mem_ctx, TR_MSG *mreq, void *data)
{
- TR_MSG *mreq = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ TIDS_INSTANCE *tids = talloc_get_type_abort(data, TIDS_INSTANCE);
+ TID_REQ *req = NULL;
TID_RESP *resp = NULL;
+ TR_MSG *resp_msg = NULL; /* this is the return value */
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;
+ /* If this isn't a TID Request, just drop it. */
+ if (mreq->msg_type != TID_REQUEST) {
+ tr_debug("tids_req_cb: Not a TID request, dropped.");
+ goto cleanup;
}
- tr_debug("tids_handle_connection: Connection authorized!");
+ /* Get a handle on the request itself. Don't free req - it belongs to mreq */
+ req = tr_msg_get_req(mreq);
- while (1) { /* continue until an error breaks us out */
+ /* Allocate a response message */
+ resp_msg = talloc(tmp_ctx, TR_MSG);
+ if (resp_msg == NULL) {
+ /* We cannot create a response message, so all we can really do is emit
+ * an error message and return. */
+ tr_crit("tids_req_cb: Error allocating response message.");
+ goto cleanup;
+ }
- 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;
- }
+ /* Allocate a response structure and populate common fields. Put it in the
+ * response message's talloc context. */
+ resp = tids_create_response(resp_msg, 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_crit("tids_req_cb: Error creating response structure.");
+ resp_msg = NULL; /* the contents are in tmp_ctx, so they will still be cleaned up */
+ goto cleanup;
+ }
+ /* Now officially assign the response to the message. */
+ tr_msg_set_resp(resp_msg, resp);
+
+ /* 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;
- }
+ /* put the response message in the caller's context */
+ talloc_steal(mem_ctx, resp_msg);
- 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 */
- }
+cleanup:
+ talloc_free(tmp_ctx);
+ return resp_msg;
+}
- 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. */
+static int tids_destructor(void *object)
+{
+ TIDS_INSTANCE *tids = talloc_get_type_abort(object, TIDS_INSTANCE);
+ if (tids->pids)
+ g_array_unref(tids->pids);
+ return 0;
+}
+
+TIDS_INSTANCE *tids_new(TALLOC_CTX *mem_ctx)
+{
+ TIDS_INSTANCE *tids = talloc_zero(mem_ctx, TIDS_INSTANCE);
+ if (tids) {
+ tids->pids = g_array_new(FALSE, FALSE, sizeof(struct tid_process));
+ if (tids->pids == NULL) {
+ talloc_free(tids);
+ return NULL;
}
-
- tr_msg_free_decoded(mreq); /* takes resp with it */
- return;
- }
+ talloc_set_destructor((void *)tids, tids_destructor);
+ }
+ return tids;
}
-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);
+ return tids_new(NULL);
}
/* 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 */
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;
tids->cookie = cookie;
}
- return n_fd;
+ return (int)n_fd;
}
/* Accept and process a connection on a port opened with tids_get_listener() */
{
int conn=-1;
int pid=-1;
+ int pipe_fd[2];
+ struct tid_process tp = {0};
if (0 > (conn = accept(listen, NULL, NULL))) {
perror("Error from TIDS Server accept()");
return 1;
}
+ if (0 > pipe(pipe_fd)) {
+ perror("Error on pipe()");
+ return 1;
+ }
+ /* pipe_fd[0] is for reading, pipe_fd[1] is for writing */
+
if (0 > (pid = fork())) {
perror("Error on fork()");
return 1;
}
if (pid == 0) {
+ close(pipe_fd[0]); /* child only writes */
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 */
+ );
+ if (write(pipe_fd[1], "OK\0", 3) < 0)
+ tr_crit("tids_accept: child process unable to write to pipe");
+ close(pipe_fd[1]);
close(conn);
exit(0); /* exit to kill forked child process */
- } else {
- close(conn);
}
- /* clean up any processes that have completed (TBD: move to main loop?) */
- while (waitpid(-1, 0, WNOHANG) > 0);
+ /* Only the parent process gets here */
+ close(pipe_fd[1]); /* parent only listens */
+ close(conn); /* connection belongs to the child */
+ tp.pid = pid;
+ tp.read_fd = pipe_fd[0];
+ g_array_append_val(tids->pids, tp); /* remember the PID of our child process */
+ /* clean up any processes that have completed */
+ tids_sweep_procs(tids);
return 0;
}
+/**
+ * Clean up any finished TID request processes
+ *
+ * This is called by the main process after forking each TID request. If you want to be
+ * sure finished processes are cleaned up promptly even during a lull in TID requests,
+ * this can be called from the main thread of the main process. It is not thread-safe,
+ * so should not be used from sub-threads. It should not be called by child processes -
+ * this would probably be harmless but ineffective.
+ *
+ * @param tids
+ */
+void tids_sweep_procs(TIDS_INSTANCE *tids)
+{
+ guint ii;
+ struct tid_process tp = {0};
+ char result[10] = {0};
+ ssize_t result_len;
+ int status;
+ int wait_rc;
+
+ /* loop backwards over the array so we can remove elements as we go */
+ for (ii=tids->pids->len; ii > 0; ii--) {
+ /* ii-1 is the current index - get our own copy, we may destroy the list's copy */
+ tp = g_array_index(tids->pids, struct tid_process, ii-1);
+
+ wait_rc = waitpid(tp.pid, &status, WNOHANG);
+ if (wait_rc == 0)
+ continue; /* process still running */
+
+ if (wait_rc < 0) {
+ /* invalid options will probably keep being invalid, report that condition */
+ if(errno == EINVAL)
+ tr_crit("tids_sweep_procs: waitpid called with invalid options");
+
+ /* If we got ECHILD, that means the PID was invalid; we'll assume the process was
+ * terminated and we missed it. For all other errors, move on
+ * to the next PID to check. */
+ if (errno != ECHILD)
+ continue;
+
+ tr_warning("tid_sweep_procs: TID process %d disappeared", tp.pid);
+ }
+
+ /* remove the item (we still have a copy of the data) */
+ g_array_remove_index_fast(tids->pids, ii-1); /* disturbs only indices >= ii-1 which we've already handled */
+
+ /* Report exit status unless we got ECHILD above or somehow waitpid returned the wrong pid */
+ if (wait_rc == tp.pid) {
+ if (WIFEXITED(status)) {
+ tr_debug("tids_sweep_procs: TID process %d exited with status %d.", tp.pid, WTERMSIG(status));
+ } else if (WIFSIGNALED(status)) {
+ tr_debug("tids_sweep_procs: TID process %d terminated by signal %d.", tp.pid, WTERMSIG(status));
+ }
+ } else if (wait_rc > 0) {
+ tr_err("tids_sweep_procs: waitpid returned pid %d, expected %d", wait_rc, tp.pid);
+ }
+
+ /* read the pipe - if the TID request worked, it will have written status before terminating */
+ result_len = read(tp.read_fd, result, sizeof(result)/sizeof(result[0]));
+ close(tp.read_fd);
+
+ if ((result_len > 0) && (strcmp(result, "OK") == 0)) {
+ tids->req_count++;
+ tr_debug("tids_sweep_procs: TID process %d succeeded", tp.pid);
+ } else {
+ tids->error_count++;
+ tr_debug("tids_sweep_procs: TID process %d failed", tp.pid);
+ }
+ }
+}
+
/* 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;
return 1; /* should never get here, loops "forever" */
}
-#undef MAX_SOCKETS
void tids_destroy (TIDS_INSTANCE *tids)
{
#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 <time.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>
pthread_sigmask(SIG_BLOCK, &signals, NULL);
}
+/* Monitoring handlers */
+static MON_RC tr_handle_version(void *cookie, json_t **result_ptr)
+{
+ *result_ptr = json_string(PACKAGE_VERSION);
+ return (*result_ptr == NULL) ? MON_NOMEM : MON_SUCCESS;
+}
+
+static MON_RC tr_handle_uptime(void *cookie, json_t **result_ptr)
+{
+ time_t *start_time = cookie;
+ *result_ptr = json_integer(time(NULL) - (*start_time));
+ return (*result_ptr == NULL) ? MON_NOMEM : MON_SUCCESS;
+}
+
+static MON_RC tr_handle_show_rp_clients(void *cookie, json_t **response_ptr)
+{
+ TR_CFG_MGR *cfg_mgr = talloc_get_type_abort(cookie, TR_CFG_MGR);
+
+ *response_ptr = tr_rp_clients_to_json(cfg_mgr->active->rp_clients);
+ return (*response_ptr == NULL) ? MON_NOMEM : MON_SUCCESS;
+}
+
+static MON_RC tr_handle_show_cfg_serial(void *cookie, json_t **response_ptr)
+{
+ TR_CFG_MGR *cfg_mgr = talloc_get_type_abort(cookie, TR_CFG_MGR);
+
+ *response_ptr = tr_cfg_files_to_json_array(cfg_mgr->active);
+ return (*response_ptr == NULL) ? MON_NOMEM : MON_SUCCESS;
+}
+
+
+
int main(int argc, char *argv[])
{
TALLOC_CTX *main_ctx=NULL;
struct cmdline_args opts;
struct event_base *ev_base;
struct tr_socket_event tids_ev = {0};
+ struct event *tids_sweep_ev;
+ struct tr_socket_event mon_ev = {0};
struct event *cfgwatch_ev;
+ time_t start_time = time(NULL); /* TODO move this? */
+
configure_signals();
/* we're going to be multithreaded, so disable null context tracking */
}
/***** 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))) {
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;
+
+ /* Register monitoring handlers */
+ mons_register_handler(tr->mons, MON_CMD_SHOW, OPT_TYPE_SHOW_VERSION, tr_handle_version, NULL);
+ mons_register_handler(tr->mons, MON_CMD_SHOW, OPT_TYPE_SHOW_CONFIG_FILES, tr_handle_show_cfg_serial, tr->cfg_mgr);
+ mons_register_handler(tr->mons, MON_CMD_SHOW, OPT_TYPE_SHOW_UPTIME, tr_handle_uptime, &start_time);
+ mons_register_handler(tr->mons, MON_CMD_SHOW, OPT_TYPE_SHOW_RP_CLIENTS, tr_handle_show_rp_clients, tr->cfg_mgr);
+ tr_tid_register_mons_handlers(tr->tids, tr->mons);
+ tr_trp_register_mons_handlers(tr->trps, tr->mons);
+
/***** process configuration *****/
tr->cfgwatch=tr_cfgwatch_create(tr);
if (tr->cfgwatch == NULL) {
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.");
- if (0 != tr_tids_event_init(ev_base,
- tr->tids,
- tr->cfg_mgr,
- tr->trps,
- &tids_ev)) {
+ if (0 != tr_tids_event_init(ev_base, tr->tids, tr->cfg_mgr, tr->trps, &tids_ev, &tids_sweep_ev)) {
tr_crit("Error initializing Trust Path Query Server instance.");
return 1;
}
--- /dev/null
+/*
+ * 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;
+
+ if ((!client_name) || (!gss_name) || (!mons)) {
+ 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;
+ }
+
+ if (cfg_mgr->active->internal->monitoring_port == 0) {
+ tr_notice("tr_mons_event_init: monitoring is disabled, not enabling events or opening sockets");
+ retval = 0;
+ 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;
+}
#include <tr_comm.h>
#include <tr_idp.h>
#include <tr_rp.h>
+#include <tr_rp_client.h>
#include <tr_event.h>
#include <tr_debug.h>
#include <gsscon.h>
+#include <trp_route.h>
#include <trp_internal.h>
#include <tr_config.h>
#include <tr_mq.h>
#include <tr_util.h>
#include <tr_tid.h>
+#include <tr_comm.h>
/* Structure to hold data for the tid response callback */
typedef struct tr_resp_cookie {
}
/* cookie->resp should now contain our copy of the response */
success=1;
- tr_debug("tr_tids_req_fwd_thread: thread %d received response.");
+ tr_debug("tr_tids_req_fwd_thread: thread %d received response.", cookie->thread_id);
cleanup:
/* Notify parent thread of the response, if it's still listening. */
if ((r1->result!=TID_SUCCESS) || (r2->result!=TID_SUCCESS))
return TID_ERROR;
- if ((0!=tr_name_cmp(r1->rp_realm, r2->rp_realm)) ||
- (0!=tr_name_cmp(r1->realm, r2->realm)) ||
- (0!=tr_name_cmp(r1->comm, r2->comm)))
- return TID_ERROR;
+ if ((0 == tr_name_cmp(r1->rp_realm, r2->rp_realm))
+ && (0 == tr_name_cmp(r1->realm, r2->realm))
+ && ( (0 == tr_name_cmp(r1->comm, r2->comm))
+ || (0 == tr_name_cmp(r1->comm, r2->orig_coi))
+ || (0 == tr_name_cmp(r1->orig_coi, r2->comm)))) {
+
+ tid_srvr_blk_add(r1->servers, tid_srvr_blk_dup(r1, r2->servers));
+ return TID_SUCCESS;
+ }
- tid_srvr_blk_add(r1->servers, tid_srvr_blk_dup(r1, r2->servers));
- return TID_SUCCESS;
+ return TID_ERROR;
}
+enum map_coi_result {
+ MAP_COI_SUCCESS = 0,
+ MAP_COI_MAP_NOT_REQUIRED,
+ MAP_COI_ALREADY_MAPPED,
+ MAP_COI_NO_APC,
+ MAP_COI_INVALID_APC,
+ MAP_COI_UNKNOWN_COMM,
+ MAP_COI_ERROR
+};
+
+static enum map_coi_result map_coi(TR_COMM_TABLE *ctable, TID_REQ *req)
+{
+ TR_COMM *orig_comm;
+ TR_NAME *apc_name;
+ TR_COMM *apc;
+ TR_APC *apcs;
+
+ if (tid_req_get_orig_coi(req) != NULL)
+ return MAP_COI_ALREADY_MAPPED;
+
+ /* look up the community */
+ orig_comm = tr_comm_table_find_comm(ctable, tid_req_get_comm(req));
+ if (orig_comm == NULL)
+ return MAP_COI_UNKNOWN_COMM;
+
+ if (tr_comm_get_type(orig_comm) == TR_COMM_APC)
+ return MAP_COI_MAP_NOT_REQUIRED; /* it was already an APC, no mapping to do */
+
+ /* use first (only) APC. These are just APC names */
+ apcs = tr_comm_get_apcs(orig_comm);
+ if ((!apcs) || (!tr_apc_get_id(apcs)))
+ return MAP_COI_NO_APC;
+
+ /* get our own copy of the APC name */
+ apc_name = tr_dup_name(tr_apc_get_id(apcs));
+ if (apc_name == NULL) {
+ tr_err("map_coi: Error allocating apc_name");
+ return MAP_COI_ERROR;
+ }
+
+ /* Check that the APC is configured */
+ apc = tr_comm_table_find_comm(ctable, apc_name);
+ if (apc == NULL) {
+ tr_free_name(apc_name);
+ return MAP_COI_INVALID_APC;
+ }
+
+ tid_req_set_orig_coi(req, tid_req_get_comm(req)); /* was null, so no need to free anything */
+ tid_req_set_comm(req, apc_name); /* original contents will be freed via orig_coi */
+
+ return MAP_COI_SUCCESS; /* successfully mapped */
+}
+
+/**
+ * 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,
TID_RESP *aaa_resp[TR_TID_MAX_AAA_SERVERS]={NULL};
TR_RP_CLIENT *rp_client=NULL;
TR_RP_CLIENT_ITER *rpc_iter=NULL;
- TR_NAME *apc = NULL;
TID_REQ *fwd_req = NULL;
TR_COMM *cfg_comm = NULL;
TR_COMM *cfg_apc = NULL;
goto cleanup;
}
- tr_debug("tr_tids_req_handler: Request received (conn = %d)! Realm = %s, Comm = %s", orig_req->conn,
+ tr_debug("tr_tids_req_handler: Request received (conn = %d)! Realm = %s, Comm = %s", orig_req->conn,
orig_req->realm->buf, orig_req->comm->buf);
if (orig_req->request_id)
tr_debug("tr_tids_req_handler: TID request ID: %.*s", orig_req->request_id->len, orig_req->request_id->buf);
/* 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);
+ /* cfg_comm is now the community (APC or CoI) of the incoming request */
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;
}
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;
}
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;
}
/* We get here whether or not a filter matched. If tr_filter_apply() doesn't match, it returns
* 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");
+ tr_notice("tr_tids_req_handler: Incoming TID request rejected by RP client filter for GSS name %.*s",
+ tids->gss_name->len, tids->gss_name->buf);
+ tid_resp_set_err_msg(resp, tr_new_name("Incoming TID request filter error"));
retval = -1;
goto cleanup;
}
/* 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");
+ tr_notice("tr_tids_req_handler: RP Realm (%s) not member of community (%s).",
+ orig_req->rp_realm->buf, orig_req->comm->buf);
+ tid_resp_set_err_msg(resp, tr_new_name("RP community membership error"));
retval=-1;
goto cleanup;
}
- /* Map the comm in the request from a COI to an APC, if needed */
- if (TR_COMM_COI == cfg_comm->type) {
- 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.");
- retval=-1;
- goto cleanup;
- }
-
- tr_debug("tr_tids_req_handler: Community was a COI, switching.");
- /* 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");
- retval=-1;
+ switch(map_coi(cfg_mgr->active->ctable, fwd_req)) {
+ case MAP_COI_MAP_NOT_REQUIRED:
+ cfg_apc = cfg_comm;
+ break;
+
+ case MAP_COI_SUCCESS:
+ cfg_apc = tr_comm_table_find_comm(cfg_mgr->active->ctable, tid_req_get_comm(fwd_req));
+ tr_debug("tr_tids_req_handler: Community %.*s is a COI, mapping to APC %.*s.",
+ tid_req_get_orig_coi(fwd_req)->len, tid_req_get_orig_coi(fwd_req)->buf,
+ tr_comm_get_id(cfg_apc)->len, tr_comm_get_id(cfg_apc)->buf);
+ break;
+
+ case MAP_COI_ALREADY_MAPPED:
+ tr_notice("tr_tids_req_handler: community %.*s is COI but COI to APC mapping already occurred. Dropping request.",
+ tid_req_get_comm(orig_req)->len, tid_req_get_comm(orig_req)->buf);
+ tid_resp_set_err_msg(resp, tr_new_name("Second COI to APC mapping would result, permitted only once."));
+ retval = -1;
goto cleanup;
- }
- apc = tr_dup_name(cfg_comm->apcs->id);
- /* 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");
- retval=-1;
+ case MAP_COI_NO_APC:
+ tr_notice("No valid APC for COI %.*s.",
+ tid_req_get_comm(orig_req)->len, tid_req_get_comm(orig_req)->buf);
+ tid_resp_set_err_msg(resp, tr_new_name("No valid APC for community"));
+ retval = -1;
goto cleanup;
- }
- fwd_req->comm = apc;
- fwd_req->orig_coi = orig_req->comm;
+ case MAP_COI_INVALID_APC:
+ tr_notice("tr_tids_req_hander: Request for unknown APC.");
+ tid_resp_set_err_msg(resp, tr_new_name("Unknown APC"));
+ retval = -1;
+ goto cleanup;
- /* 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");
- retval=-1;
+ default:
+ tr_notice("tr_tids_req_hander: Unexpected error mapping COI to APC.");
+ retval = -1;
goto cleanup;
- }
}
- /* Look up the route for this community/realm. */
+ /* cfg_comm is now the original community, and cfg_apc is the APC it belongs to. These
+ * may both be the same. If not, check that rp_realm is a member of the mapped APC */
+ if ((cfg_apc != cfg_comm)
+ && (NULL == tr_comm_find_rp(cfg_mgr->active->ctable,
+ cfg_apc,
+ tid_req_get_rp_realm(fwd_req)))) {
+ tr_notice("tr_tids_req_hander: RP Realm (%.*s) not member of mapped APC (%.*s).",
+ tid_req_get_rp_realm(fwd_req)->len, tid_req_get_rp_realm(fwd_req)->buf,
+ tr_comm_get_id(cfg_apc)->len, tr_comm_get_id(cfg_apc)->buf);
+ tid_resp_set_err_msg(resp, tr_new_name("RP community membership error"));
+ retval=-1;
+ goto cleanup;
+ }
+
+ /* Look up the route for forwarding request's community/realm. */
tr_debug("tr_tids_req_handler: looking up route.");
- route=trps_get_selected_route(trps, orig_req->comm, orig_req->realm);
+ route=trps_get_selected_route(trps, fwd_req->comm, fwd_req->realm);
if (route==NULL) {
/* No route. Use default AAA servers if we have them. */
- tr_debug("tr_tids_req_handler: No route for realm %s, defaulting.", orig_req->realm->buf);
+ tr_debug("tr_tids_req_handler: No route for realm %s, defaulting.", fwd_req->realm->buf);
if (NULL == (aaa_servers = tr_default_server_lookup(cfg_mgr->active->default_servers,
- orig_req->comm))) {
+ fwd_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;
}
idp_shared = 0;
} else {
- /* Found a route. Determine the AAA servers or next hop address. */
+ /* Found a route. Determine the AAA servers or next hop address for the request we are forwarding. */
tr_debug("tr_tids_req_handler: found route.");
if (trp_route_is_local(route)) {
tr_debug("tr_tids_req_handler: route is local.");
aaa_servers = tr_idp_aaa_server_lookup(cfg_mgr->active->ctable->idp_realms,
- orig_req->realm,
- orig_req->comm,
+ fwd_req->realm,
+ fwd_req->comm,
&idp_shared);
} else {
tr_debug("tr_tids_req_handler: route not local.");
idp_shared = 0;
}
- /* 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");
+ /* Since we aren't defaulting, check idp coi and apc membership of the original request */
+ if (NULL == (tr_comm_find_idp(cfg_mgr->active->ctable, cfg_comm, orig_req->realm))) {
+ tr_notice("tr_tids_req_handler: IDP Realm (%s) not member of community (%s).", orig_req->realm->buf, cfg_comm->id->buf);
+ 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");
+ if ( cfg_apc && (NULL == (tr_comm_find_idp(cfg_mgr->active->ctable, cfg_apc, orig_req->realm)))) {
+ tr_notice("tr_tids_req_handler: IDP Realm (%s) not member of APC (%s).", orig_req->realm->buf, cfg_apc->id->buf);
+ tid_resp_set_err_msg(resp, tr_new_name("IDP APC membership error"));
retval=-1;
goto cleanup;
}
}
- /* Make sure we came through with a AAA server. If not, we can't handle the request. */
+ /* Make sure we came through with a AAA server. If not, we can't handle the request.
+ * Report using the original request, not translated values. */
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;
}
/* send a TID request to the AAA server(s), and get the answer(s) */
tr_debug("tr_tids_req_handler: sending TID request(s).");
- if (cfg_apc)
- expiration_interval = cfg_apc->expiration_interval;
- else expiration_interval = cfg_comm->expiration_interval;
+ /* Use the smaller of the APC's expiration interval and the expiration interval of the incoming request */
+ expiration_interval = cfg_apc->expiration_interval;
if (fwd_req->expiration_interval)
fwd_req->expiration_interval = (expiration_interval < fwd_req->expiration_interval) ? expiration_interval : fwd_req->expiration_interval;
- else fwd_req->expiration_interval = expiration_interval;
+ else
+ fwd_req->expiration_interval = expiration_interval;
/* Set up message queue for replies from req forwarding threads */
mq=tr_mq_new(tmp_ctx);
}
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! */
/* called when a connection to the TIDS port is received */
static void tr_tids_event_cb(int listener, short event, void *arg)
{
- TIDS_INSTANCE *tids = (TIDS_INSTANCE *)arg;
+ TIDS_INSTANCE *tids = talloc_get_type_abort(arg, TIDS_INSTANCE);
if (0==(event & EV_READ))
tr_debug("tr_tids_event_cb: unexpected event on TIDS socket (event=0x%X)", event);
tids_accept(tids, listener);
}
-/* Configure the tids instance and set up its event handler.
+/* called when it's time to sweep for completed TID child processes */
+static void tr_tids_sweep_cb(int listener, short event, void *arg)
+{
+ TIDS_INSTANCE *tids = talloc_get_type_abort(arg, TIDS_INSTANCE);
+
+ if (0==(event & EV_TIMEOUT))
+ tr_debug("tr_tids_event_cb: unexpected event on TID process sweep timer (event=0x%X)", event);
+ else
+ tids_sweep_procs(tids);
+}
+
+/* Configure the tids instance and set up its event handlers.
* Returns 0 on success, nonzero on failure. Fills in
* *tids_event (which should be allocated by caller). */
-int tr_tids_event_init(struct event_base *base,
- TIDS_INSTANCE *tids,
- TR_CFG_MGR *cfg_mgr,
- TRPS_INSTANCE *trps,
- struct tr_socket_event *tids_ev)
+int tr_tids_event_init(struct event_base *base, TIDS_INSTANCE *tids, TR_CFG_MGR *cfg_mgr, TRPS_INSTANCE *trps,
+ struct tr_socket_event *tids_ev, struct event **sweep_ev)
{
TALLOC_CTX *tmp_ctx=talloc_new(NULL);
struct tr_tids_event_cookie *cookie=NULL;
+ struct timeval sweep_interval;
int retval=0;
- size_t ii=0;
+ int ii=0;
if (tids_ev == NULL) {
tr_debug("tr_tids_event_init: Null tids_ev.");
goto cleanup;
}
+ if (sweep_ev == NULL) {
+ tr_debug("tr_tids_event_init: Null sweep_ev.");
+ retval = 1;
+ goto cleanup;
+ }
+
/* Create the cookie for callbacks. We'll put it in the tids context, so it will
* be cleaned up when tids is freed by talloc_free. */
cookie=talloc(tmp_ctx, struct tr_tids_event_cookie);
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;
goto cleanup;
}
- /* Set up events */
+ /* Set up listener events */
for (ii=0; ii<tids_ev->n_sock_fd; ii++) {
tids_ev->ev[ii]=event_new(base,
tids_ev->sock_fd[ii],
event_add(tids_ev->ev[ii], NULL);
}
+ /* Set up a periodic check for completed TID handler processes */
+ *sweep_ev = event_new(base, -1, EV_TIMEOUT|EV_PERSIST, tr_tids_sweep_cb, tids);
+ sweep_interval.tv_sec = 10;
+ sweep_interval.tv_usec = 0;
+ event_add(*sweep_ev, &sweep_interval);
+
cleanup:
talloc_free(tmp_ctx);
return retval;
--- /dev/null
+/*
+ * 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.
+ *
+ */
+
+/* Monitoring handlers for trust router TID server */
+
+#include <jansson.h>
+#include <tid_internal.h>
+#include <tr_tid.h>
+#include <mon_internal.h>
+#include <mons_handlers.h>
+
+/**
+ * Get the count of completed TID requests
+ */
+static MON_RC handle_show_req_count(void *cookie, json_t **response_ptr)
+{
+ TIDS_INSTANCE *tids = talloc_get_type_abort(cookie, TIDS_INSTANCE);
+ *response_ptr = json_integer(tids->req_count);
+ return (*response_ptr == NULL) ? MON_NOMEM : MON_SUCCESS;
+}
+
+static MON_RC handle_show_req_err_count(void *cookie, json_t **response_ptr)
+{
+ TIDS_INSTANCE *tids = talloc_get_type_abort(cookie, TIDS_INSTANCE);
+ *response_ptr = json_integer(tids->error_count);
+ return (*response_ptr == NULL) ? MON_NOMEM : MON_SUCCESS;
+}
+
+static MON_RC handle_show_req_pending(void *cookie, json_t **response_ptr)
+{
+ TIDS_INSTANCE *tids = talloc_get_type_abort(cookie, TIDS_INSTANCE);
+ *response_ptr = json_integer(tids->pids->len);
+ return (*response_ptr == NULL) ? MON_NOMEM : MON_SUCCESS;
+}
+
+void tr_tid_register_mons_handlers(TIDS_INSTANCE *tids, MONS_INSTANCE *mons)
+{
+ mons_register_handler(mons,
+ MON_CMD_SHOW, OPT_TYPE_SHOW_TID_REQ_COUNT,
+ handle_show_req_count, tids);
+ mons_register_handler(mons,
+ MON_CMD_SHOW, OPT_TYPE_SHOW_TID_REQ_ERR_COUNT,
+ handle_show_req_err_count, tids);
+ mons_register_handler(mons,
+ MON_CMD_SHOW, OPT_TYPE_SHOW_TID_REQ_PENDING,
+ handle_show_req_pending, tids);
+}
#include <tr.h>
#include <tr_mq.h>
#include <tr_rp.h>
+#include <trp_route.h>
#include <trp_internal.h>
+#include <trp_peer.h>
#include <trp_ptable.h>
#include <trp_rtable.h>
#include <tr_config.h>
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;
+
+ /* Update the authorized monitoring gss names */
+ if (tr->mons->authorized_gss_names) {
+ tr_debug("tr_config_changed: freeing tr->mons->authorized_gss_names");
+ tr_gss_names_free(tr->mons->authorized_gss_names);
+ }
+ tr->mons->authorized_gss_names = tr_gss_names_dup(tr->mons, new_cfg->internal->monitoring_credentials);
+ if (tr->mons->authorized_gss_names == NULL) {
+ tr_err("tr_config_changed: Error configuring monitoring credentials");
+ }
+
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);
--- /dev/null
+/*
+ * 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.
+ *
+ */
+
+/* Monitoring handlers for trust router TID server */
+
+#include <jansson.h>
+#include <trp_internal.h>
+#include <tr_trp.h>
+#include <trp_rtable.h>
+#include <trp_ptable.h>
+#include <tr_comm.h>
+#include <tr_idp.h>
+#include <mon_internal.h>
+#include <mons_handlers.h>
+
+static MON_RC handle_show_routes(void *cookie, json_t **response_ptr)
+{
+ TRPS_INSTANCE *trps = talloc_get_type_abort(cookie, TRPS_INSTANCE);
+
+ *response_ptr = trp_rtable_to_json(trps->rtable);
+ return (*response_ptr == NULL) ? MON_NOMEM : MON_SUCCESS;
+}
+
+static MON_RC handle_show_peers(void *cookie, json_t **response_ptr)
+{
+ TRPS_INSTANCE *trps = talloc_get_type_abort(cookie, TRPS_INSTANCE);
+
+ *response_ptr = trp_ptable_to_json(trps->ptable);
+ return (*response_ptr == NULL) ? MON_NOMEM : MON_SUCCESS;
+}
+
+static MON_RC handle_show_communities(void *cookie, json_t **response_ptr)
+{
+ TRPS_INSTANCE *trps = talloc_get_type_abort(cookie, TRPS_INSTANCE);
+
+ *response_ptr = tr_comm_table_to_json(trps->ctable);
+ return (*response_ptr == NULL) ? MON_NOMEM : MON_SUCCESS;
+}
+
+static MON_RC handle_show_realms(void *cookie, json_t **response_ptr)
+{
+ TRPS_INSTANCE *trps = talloc_get_type_abort(cookie, TRPS_INSTANCE);
+
+ *response_ptr = tr_idp_realms_to_json(trps->ctable->idp_realms);
+ return (*response_ptr == NULL) ? MON_NOMEM : MON_SUCCESS;
+}
+
+void tr_trp_register_mons_handlers(TRPS_INSTANCE *trps, MONS_INSTANCE *mons)
+{
+ mons_register_handler(mons,
+ MON_CMD_SHOW, OPT_TYPE_SHOW_ROUTES,
+ handle_show_routes, trps);
+ mons_register_handler(mons,
+ MON_CMD_SHOW, OPT_TYPE_SHOW_PEERS,
+ handle_show_peers, trps);
+ mons_register_handler(mons,
+ MON_CMD_SHOW, OPT_TYPE_SHOW_COMMUNITIES,
+ handle_show_communities, trps);
+ mons_register_handler(mons,
+ MON_CMD_SHOW, OPT_TYPE_SHOW_REALMS,
+ handle_show_realms, trps);
+}
--- /dev/null
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <talloc.h>
+#include <argp.h>
+
+#include <mon_internal.h>
+#include <tr_debug.h>
+
+
+/* command-line option setup */
+static void print_version_info(void)
+{
+ printf("Moonshot TR Monitoring Client %s\n\n", PACKAGE_VERSION);
+}
+
+
+/* argp global parameters */
+const char *argp_program_bug_address=PACKAGE_BUGREPORT; /* bug reporting address */
+
+/* doc strings */
+static const char doc[]=PACKAGE_NAME " - Moonshot TR Monitoring Client";
+static const char arg_doc[]="<server> <port> <command> [<option> ...]"; /* string describing arguments, if any */
+
+/* define the options here. Fields are:
+ * { long-name, short-name, variable name, options, help description } */
+static const struct argp_option cmdline_options[] = {
+ { "version", 'v', NULL, 0, "Print version information and exit" },
+ {NULL}
+};
+
+#define MAX_OPTIONS 20
+/* structure for communicating with option parser */
+struct cmdline_args {
+ char *server;
+ unsigned int port;
+ MON_CMD command;
+ MON_OPT_TYPE options[MAX_OPTIONS];
+ unsigned int n_options;
+};
+
+/* parser for individual options - fills in a struct cmdline_args */
+static error_t parse_option(int key, char *arg, struct argp_state *state)
+{
+ long tmp_l = 0;
+
+ /* get a shorthand to the command line argument structure, part of state */
+ struct cmdline_args *arguments=state->input;
+
+ switch (key) {
+ case 'v':
+ print_version_info();
+ exit(0);
+ break;
+
+ case ARGP_KEY_ARG: /* handle argument (not option) */
+ switch (state->arg_num) {
+ case 0:
+ arguments->server = arg;
+ break;
+
+ case 1:
+ tmp_l = strtol(arg, NULL, 10);
+ if (errno || (tmp_l < 0) || (tmp_l > 65535)) /* max valid port */
+ argp_usage(state);
+
+ arguments->port=(unsigned int) tmp_l;
+ break;
+
+ case 2:
+ arguments->command=mon_cmd_from_string(arg);
+ if (arguments->command == MON_CMD_UNKNOWN) {
+ printf("\nUnknown command '%s'\n", arg);
+ argp_usage(state);
+ }
+ break;
+
+ default:
+ if (arguments->n_options >= MAX_OPTIONS) {
+ printf("\nToo many command options given, limit is %d\n", MAX_OPTIONS);
+ argp_usage(state);
+ }
+
+ arguments->options[arguments->n_options] = mon_opt_type_from_string(arg);
+ if (arguments->options[arguments->n_options] == OPT_TYPE_UNKNOWN) {
+ printf("\nUnknown command option '%s'\n", arg);
+ argp_usage(state);
+ }
+ arguments->n_options++;
+ break;
+ }
+ break;
+
+ case ARGP_KEY_END: /* no more arguments */
+ if (state->arg_num < 3) {
+ /* not enough arguments encountered */
+ argp_usage(state);
+ }
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0; /* success */
+}
+
+
+/* assemble the argp parser */
+static struct argp argp = {cmdline_options, parse_option, arg_doc, doc};
+
+int main(int argc, char *argv[])
+{
+ TALLOC_CTX *main_ctx=talloc_new(NULL);
+ MONC_INSTANCE *monc = NULL;
+ MON_REQ *req = NULL;
+ MON_RESP *resp = NULL;
+ unsigned int ii;
+
+ struct cmdline_args opts;
+ int retval=1; /* exit with an error status unless this gets set to zero */
+
+ /* parse the command line*/
+ /* set defaults */
+ opts.server = NULL;
+ opts.port = TRP_PORT;
+ opts.command = MON_CMD_UNKNOWN;
+ opts.n_options = 0;
+
+ argp_parse(&argp, argc, argv, 0, 0, &opts);
+
+ /* Use standalone logging */
+ tr_log_open();
+
+ /* set logging levels */
+ talloc_set_log_stderr();
+ tr_log_threshold(LOG_CRIT);
+ tr_console_threshold(LOG_WARNING);
+
+ /* Create a MON client instance & the client DH */
+ monc = monc_new(main_ctx);
+ if (monc == NULL) {
+ printf("Error allocating client instance.\n");
+ goto cleanup;
+ }
+
+
+ /* fill in the DH parameters */
+ monc_set_dh(monc, tr_create_dh_params(NULL, 0));
+ if (monc_get_dh(monc) == NULL) {
+ printf("Error creating client DH params.\n");
+ goto cleanup;
+ }
+
+ /* Set-up MON connection */
+ if (0 != monc_open_connection(monc, opts.server, opts.port)) {
+ /* Handle error */
+ printf("Error opening connection to %s:%d.\n", opts.server, opts.port);
+ goto cleanup;
+ };
+
+ req = mon_req_new(main_ctx, opts.command);
+ for (ii=0; ii < opts.n_options; ii++)
+ mon_req_add_option(req, opts.options[ii]);
+
+ /* Send a MON request and get the response */
+ resp = monc_send_request(main_ctx, monc, req);
+
+ if (resp == NULL) {
+ /* Handle error */
+ printf("Error executing monitoring request.\n");
+ goto cleanup;
+ }
+
+ /* Print the JSON to stdout */
+ json_dumpf(mon_resp_encode(resp), stdout, JSON_INDENT(4));
+ printf("\n");
+
+ /* success */
+ retval = 0;
+
+ /* Clean-up the MON client instance, and exit */
+cleanup:
+ talloc_free(main_ctx);
+ return retval;
+}
+
if (buflen>=MAX_MSG_LEN)
printf("Warning: file may exceed maximum message length (%d bytes).\n", MAX_MSG_LEN);
- msg=tr_msg_decode(buf, buflen);
+ msg= tr_msg_decode(NULL, buf, buflen);
/* if (rc==TRP_SUCCESS)
trp_msg_print(msg);*/
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);
#include <talloc.h>
#include <assert.h>
-#include <tr_gss.h>
+#include <tr_gss_names.h>
+#include <trp_route.h>
#include <trp_internal.h>
+#include <trp_peer.h>
#include <trp_ptable.h>
-
/* Can't do the updates test because trps_select_updates_for_peer() is now static */
#define VERIFY_UPDATES 0
#include <assert.h>
#include <tr_name_internal.h>
+#include <trp_route.h>
#include <trp_internal.h>
#include <trp_rtable.h>
TRP_ROUTE **entries=NULL;
size_t n=0, ii=0,jj=0,kk=0;
- entries=trp_rtable_get_entries(table, &n);
+ entries= trp_rtable_get_entries(NULL, table, &n);
while (n--) {
ii=get_index(trp_route_get_comm(entries[n])->buf, apc, n_apc);
jj=get_index(trp_route_get_realm(entries[n])->buf, realm, n_realm);
--- /dev/null
+/*
+ * 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 <time.h>
+#include <talloc.h>
+
+#include <tr_name_internal.h>
+#include <trp_internal.h>
+#include <tr_gss_names.h>
+#include <trp_ptable.h>
+#include <tr_debug.h>
+#include <trp_peer.h>
+
+static int trp_peer_destructor(void *object)
+{
+ TRP_PEER *peer=talloc_get_type_abort(object, TRP_PEER);
+ if (peer->label!=NULL)
+ tr_free_name(peer->label);
+ if (peer->servicename!=NULL)
+ tr_free_name(peer->servicename);
+ return 0;
+}
+TRP_PEER *trp_peer_new(TALLOC_CTX *memctx)
+{
+ TRP_PEER *peer=talloc(memctx, TRP_PEER);
+ if (peer!=NULL) {
+ peer->next=NULL;
+ peer->label=NULL;
+ peer->server=NULL;
+ peer->servicename=NULL;
+ peer->gss_names=NULL;
+ peer->port=0;
+ peer->linkcost=TRP_LINKCOST_DEFAULT;
+ peer->last_conn_attempt=(struct timespec){0,0};
+ peer->outgoing_status=PEER_DISCONNECTED;
+ peer->incoming_status=PEER_DISCONNECTED;
+ peer->conn_status_cb=NULL;
+ peer->conn_status_cookie=NULL;
+ peer->filters=NULL;
+ talloc_set_destructor((void *)peer, trp_peer_destructor);
+ }
+ return peer;
+}
+
+void trp_peer_free(TRP_PEER *peer)
+{
+ talloc_free(peer);
+}
+
+TRP_PEER *trp_peer_tail(TRP_PEER *peer)
+{
+ while (peer->next!=NULL) {
+ peer=peer->next;
+ }
+ return peer;
+}
+
+
+/* Get a name that identifies this peer for display to the user, etc.
+ * Do not modify or free the label. */
+TR_NAME *trp_peer_get_label(TRP_PEER *peer)
+{
+ char *s=NULL;
+
+ if (peer->label==NULL) {
+ s=talloc_asprintf(NULL, "%s:%u", peer->server, peer->port);
+ if (s!=NULL) {
+ peer->label=tr_new_name(s);
+ talloc_free(s);
+ }
+ }
+ return peer->label;
+}
+
+/* Get a name that identifies this peer for display to the user, etc.
+ * Makes a copy, caller is responsible for freeing. */
+TR_NAME *trp_peer_dup_label(TRP_PEER *peer)
+{
+ return tr_dup_name(trp_peer_get_label(peer));;
+}
+
+char *trp_peer_get_server(TRP_PEER *peer)
+{
+ return peer->server;
+}
+
+static void trp_peer_set_servicename(TRP_PEER *peer, const char *server)
+{
+ char *name=NULL;
+ if (peer->servicename !=NULL)
+ tr_free_name(peer->servicename);
+
+ if (server!=NULL)
+ name=talloc_asprintf(NULL, "trustrouter/%s", server);
+
+ if (name!=NULL) {
+ peer->servicename=tr_new_name(name);
+ talloc_free(name);
+ } else {
+ peer->servicename=NULL;
+ }
+}
+
+/* copies input; on error, peer->servicename will be null */
+void trp_peer_set_server(TRP_PEER *peer, const char *server)
+{
+ peer->server=talloc_strdup(peer, server); /* will be null on error */
+ trp_peer_set_servicename(peer, server);
+}
+
+void trp_peer_add_gss_name(TRP_PEER *peer, TR_NAME *gss_name)
+{
+ if (peer->gss_names==NULL)
+ trp_peer_set_gss_names(peer, tr_gss_names_new(peer));
+ tr_gss_names_add(peer->gss_names, gss_name);
+}
+
+void trp_peer_set_gss_names(TRP_PEER *peer, TR_GSS_NAMES *gss_names)
+{
+ if (peer->gss_names!=NULL)
+ tr_gss_names_free(peer->gss_names);
+
+ peer->gss_names=gss_names;
+ talloc_steal(peer, gss_names);
+}
+
+/* get the peer gss_names, caller must not free the result */
+TR_GSS_NAMES *trp_peer_get_gss_names(TRP_PEER *peer)
+{
+ return peer->gss_names;
+}
+
+/* get the service name (i.e., gssname we see when we connect to this peer) */
+TR_NAME *trp_peer_get_servicename(TRP_PEER *peer)
+{
+ return peer->servicename;
+}
+
+/* get a copy of the servicename, caller must free via tr_free_name */
+TR_NAME *trp_peer_dup_servicename(TRP_PEER *peer)
+{
+ return tr_dup_name(peer->servicename);
+}
+
+unsigned int trp_peer_get_port(TRP_PEER *peer)
+{
+ return peer->port;
+}
+
+void trp_peer_set_port(TRP_PEER *peer, unsigned int port)
+{
+ peer->port=port;
+}
+
+unsigned int trp_peer_get_linkcost(TRP_PEER *peer)
+{
+ if (peer!=NULL)
+ return peer->linkcost;
+ else
+ return 1;
+}
+
+void trp_peer_set_linkcost(TRP_PEER *peer, unsigned int linkcost)
+{
+ if ((linkcost>TRP_METRIC_INFINITY) && (linkcost!=TRP_METRIC_INVALID)) {
+ /* This indicates a programming error, but probably means an already infinite metric
+ * was (incorrectly) incremented. Issue a warning and proceed with an infinite metric. */
+ tr_warning("trp_peer_set_linkcost: link cost > infinity encountered, setting to infinity");
+ linkcost=TRP_METRIC_INFINITY;
+ }
+ peer->linkcost=linkcost;
+}
+
+void trp_peer_set_conn_status_cb(TRP_PEER *peer, void (*cb)(TRP_PEER *, void *), void *cookie)
+{
+ peer->conn_status_cb=cb;
+ peer->conn_status_cookie=cookie;
+}
+
+/**
+ * Set the filter associated with this peer. Any existing filter will be freed. Takes responsibility for
+ * freeing the new filter.
+ *
+ * @param peer Peer to modify
+ * @param filts New filter to attach to the peer
+ */
+void trp_peer_set_filters(TRP_PEER *peer, TR_FILTER_SET *filts)
+{
+ if (peer->filters!=NULL)
+ tr_filter_set_free(peer->filters);
+
+ peer->filters=filts;
+ talloc_steal(peer, filts);
+}
+
+TR_FILTER *trp_peer_get_filter(TRP_PEER *peer, TR_FILTER_TYPE ftype)
+{
+ return tr_filter_set_get(peer->filters, ftype);
+}
+
+struct timespec *trp_peer_get_last_conn_attempt(TRP_PEER *peer)
+{
+ return &(peer->last_conn_attempt);
+}
+
+void trp_peer_set_last_conn_attempt(TRP_PEER *peer, struct timespec *time)
+{
+ peer->last_conn_attempt=*time;
+}
+
+void trp_peer_set_outgoing_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status)
+{
+ TR_NAME *peer_label=trp_peer_get_label(peer);
+ int was_connected=trp_peer_is_connected(peer);
+ peer->outgoing_status=status;
+ tr_debug("trp_peer_set_outgoing_status: %s: status=%d peer connected was %d now %d.",
+ peer_label->buf, status, was_connected, trp_peer_is_connected(peer));
+ if ((trp_peer_is_connected(peer) != was_connected) && (peer->conn_status_cb!=NULL))
+ peer->conn_status_cb(peer, peer->conn_status_cookie);
+}
+
+TRP_PEER_CONN_STATUS trp_peer_get_outgoing_status(TRP_PEER *peer)
+{
+ return peer->outgoing_status;
+}
+
+void trp_peer_set_incoming_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status)
+{
+ TR_NAME *peer_label=trp_peer_get_label(peer);
+ int was_connected=trp_peer_is_connected(peer);
+ peer->incoming_status=status;
+ tr_debug("trp_peer_set_incoming_status: %s: status=%d peer connected was %d now %d.",
+ peer_label->buf, status, was_connected, trp_peer_is_connected(peer));
+ if ((trp_peer_is_connected(peer) != was_connected) && (peer->conn_status_cb!=NULL))
+ peer->conn_status_cb(peer, peer->conn_status_cookie);
+}
+
+TRP_PEER_CONN_STATUS trp_peer_get_incoming_status(TRP_PEER *peer)
+{
+ return peer->incoming_status;
+}
+
+int trp_peer_is_connected(TRP_PEER *peer)
+{
+ return (peer->outgoing_status==PEER_CONNECTED) && (peer->incoming_status==PEER_CONNECTED);
+}
--- /dev/null
+/*
+ * 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 <jansson.h>
+
+#include <tr_gss_names.h>
+#include <trp_peer.h>
+#include <tr_util.h>
+
+char *trp_peer_to_str(TALLOC_CTX *memctx, TRP_PEER *peer, const char *sep)
+{
+ if (sep==NULL)
+ sep=", ";
+ return talloc_asprintf(memctx,
+ "%s:%u%s0x%04X",
+ peer->server, peer->port, sep,
+ peer->linkcost);
+}
+
+/* helper for encoding to json */
+static json_t *server_to_json_string(const char *server, unsigned int port)
+{
+ char *s = talloc_asprintf(NULL, "%s:%u", server, port);
+ json_t *jstr = json_string(s);
+ talloc_free(s);
+ return jstr;
+}
+
+static json_t *last_attempt_to_json_string(TRP_PEER *peer)
+{
+ struct timespec ts_zero = {0, 0};
+ char *s = NULL;
+ json_t *jstr = NULL;
+
+ if (tr_cmp_timespec(trp_peer_get_last_conn_attempt(peer), &ts_zero) == 0) {
+ s = strdup("");
+ } else {
+ s = timespec_to_str(trp_peer_get_last_conn_attempt(peer));
+ }
+
+ if (s) {
+ jstr = json_string(s);
+ free(s);
+ }
+
+ return jstr;
+}
+
+/* helper for below */
+#define OBJECT_SET_OR_FAIL(jobj, key, val) \
+do { \
+ if (val) \
+ json_object_set_new((jobj),(key),(val)); \
+ else \
+ goto cleanup; \
+} while (0)
+
+json_t *trp_peer_to_json(TRP_PEER *peer)
+{
+ json_t *peer_json = NULL;
+ json_t *retval = NULL;
+
+ peer_json = json_object();
+ if (peer_json == NULL)
+ goto cleanup;
+
+
+ OBJECT_SET_OR_FAIL(peer_json, "server",
+ server_to_json_string(trp_peer_get_server(peer),
+ trp_peer_get_port(peer)));
+ OBJECT_SET_OR_FAIL(peer_json, "servicename",
+ tr_name_to_json_string(trp_peer_get_servicename(peer)));
+ OBJECT_SET_OR_FAIL(peer_json, "linkcost",
+ json_integer(trp_peer_get_linkcost(peer)));
+ OBJECT_SET_OR_FAIL(peer_json, "connected_to",
+ json_boolean(trp_peer_get_outgoing_status(peer) == PEER_CONNECTED));
+ OBJECT_SET_OR_FAIL(peer_json, "connected_from",
+ json_boolean(trp_peer_get_incoming_status(peer) == PEER_CONNECTED));
+ OBJECT_SET_OR_FAIL(peer_json, "last_connection_attempt",
+ last_attempt_to_json_string(peer));
+ OBJECT_SET_OR_FAIL(peer_json, "allowed_credentials",
+ tr_gss_names_to_json_array(trp_peer_get_gss_names(peer)));
+ OBJECT_SET_OR_FAIL(peer_json, "filters",
+ tr_filter_set_to_json(peer->filters));
+
+ /* succeeded - set the return value and increment the reference count */
+ retval = peer_json;
+ json_incref(retval);
+
+cleanup:
+ if (peer_json)
+ json_decref(peer_json);
+ return retval;
+}
#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>
+#include <trp_peer.h>
-static int trp_peer_destructor(void *object)
-{
- TRP_PEER *peer=talloc_get_type_abort(object, TRP_PEER);
- if (peer->label!=NULL)
- tr_free_name(peer->label);
- if (peer->servicename!=NULL)
- tr_free_name(peer->servicename);
- return 0;
-}
-TRP_PEER *trp_peer_new(TALLOC_CTX *memctx)
-{
- TRP_PEER *peer=talloc(memctx, TRP_PEER);
- if (peer!=NULL) {
- peer->next=NULL;
- peer->label=NULL;
- peer->server=NULL;
- peer->servicename=NULL;
- peer->gss_names=NULL;
- peer->port=0;
- peer->linkcost=TRP_LINKCOST_DEFAULT;
- peer->last_conn_attempt=(struct timespec){0,0};
- peer->outgoing_status=PEER_DISCONNECTED;
- peer->incoming_status=PEER_DISCONNECTED;
- peer->conn_status_cb=NULL;
- peer->conn_status_cookie=NULL;
- peer->filters=NULL;
- talloc_set_destructor((void *)peer, trp_peer_destructor);
- }
- return peer;
-}
-
-void trp_peer_free(TRP_PEER *peer)
-{
- talloc_free(peer);
-}
-
-static TRP_PEER *trp_peer_tail(TRP_PEER *peer)
-{
- while (peer->next!=NULL) {
- peer=peer->next;
- }
- return peer;
-}
-
-
-/* Get a name that identifies this peer for display to the user, etc.
- * Do not modify or free the label. */
-TR_NAME *trp_peer_get_label(TRP_PEER *peer)
-{
- char *s=NULL;
-
- if (peer->label==NULL) {
- s=talloc_asprintf(NULL, "%s:%u", peer->server, peer->port);
- if (s!=NULL) {
- peer->label=tr_new_name(s);
- talloc_free(s);
- }
- }
- return peer->label;
-}
-
-/* Get a name that identifies this peer for display to the user, etc.
- * Makes a copy, caller is responsible for freeing. */
-TR_NAME *trp_peer_dup_label(TRP_PEER *peer)
-{
- return tr_dup_name(trp_peer_get_label(peer));;
-}
-
-char *trp_peer_get_server(TRP_PEER *peer)
-{
- return peer->server;
-}
-
-static void trp_peer_set_servicename(TRP_PEER *peer, const char *server)
-{
- char *name=NULL;
- if (peer->servicename !=NULL)
- tr_free_name(peer->servicename);
-
- if (server!=NULL)
- name=talloc_asprintf(NULL, "trustrouter/%s", server);
-
- if (name!=NULL) {
- peer->servicename=tr_new_name(name);
- talloc_free(name);
- } else {
- peer->servicename=NULL;
- }
-}
-
-/* copies input; on error, peer->servicename will be null */
-void trp_peer_set_server(TRP_PEER *peer, const char *server)
-{
- peer->server=talloc_strdup(peer, server); /* will be null on error */
- trp_peer_set_servicename(peer, server);
-}
-
-void trp_peer_add_gss_name(TRP_PEER *peer, TR_NAME *gss_name)
-{
- if (peer->gss_names==NULL)
- trp_peer_set_gss_names(peer, tr_gss_names_new(peer));
- tr_gss_names_add(peer->gss_names, gss_name);
-}
-
-void trp_peer_set_gss_names(TRP_PEER *peer, TR_GSS_NAMES *gss_names)
-{
- if (peer->gss_names!=NULL)
- tr_gss_names_free(peer->gss_names);
-
- peer->gss_names=gss_names;
- talloc_steal(peer, gss_names);
-}
-
-/* get the peer gss_names, caller must not free the result */
-TR_GSS_NAMES *trp_peer_get_gss_names(TRP_PEER *peer)
-{
- return peer->gss_names;
-}
-
-/* get the service name (i.e., gssname we see when we connect to this peer) */
-TR_NAME *trp_peer_get_servicename(TRP_PEER *peer)
-{
- return peer->servicename;
-}
-
-/* get a copy of the servicename, caller must free via tr_free_name */
-TR_NAME *trp_peer_dup_servicename(TRP_PEER *peer)
-{
- return tr_dup_name(peer->servicename);
-}
-
-unsigned int trp_peer_get_port(TRP_PEER *peer)
-{
- return peer->port;
-}
-
-void trp_peer_set_port(TRP_PEER *peer, unsigned int port)
-{
- peer->port=port;
-}
-
-unsigned int trp_peer_get_linkcost(TRP_PEER *peer)
-{
- if (peer!=NULL)
- return peer->linkcost;
- else
- return 1;
-}
-
-void trp_peer_set_linkcost(TRP_PEER *peer, unsigned int linkcost)
-{
- if ((linkcost>TRP_METRIC_INFINITY) && (linkcost!=TRP_METRIC_INVALID)) {
- /* This indicates a programming error, but probably means an already infinite metric
- * was (incorrectly) incremented. Issue a warning and proceed with an infinite metric. */
- tr_warning("trp_peer_set_linkcost: link cost > infinity encountered, setting to infinity");
- linkcost=TRP_METRIC_INFINITY;
- }
- peer->linkcost=linkcost;
-}
-
-void trp_peer_set_conn_status_cb(TRP_PEER *peer, void (*cb)(TRP_PEER *, void *), void *cookie)
-{
- peer->conn_status_cb=cb;
- peer->conn_status_cookie=cookie;
-}
-
-/**
- * Set the filter associated with this peer. Any existing filter will be freed. Takes responsibility for
- * freeing the new filter.
- *
- * @param peer Peer to modify
- * @param filts New filter to attach to the peer
- */
-void trp_peer_set_filters(TRP_PEER *peer, TR_FILTER_SET *filts)
-{
- if (peer->filters!=NULL)
- tr_filter_set_free(peer->filters);
-
- peer->filters=filts;
- talloc_steal(peer, filts);
-}
-
-TR_FILTER *trp_peer_get_filter(TRP_PEER *peer, TR_FILTER_TYPE ftype)
-{
- return tr_filter_set_get(peer->filters, ftype);
-}
-
-struct timespec *trp_peer_get_last_conn_attempt(TRP_PEER *peer)
-{
- return &(peer->last_conn_attempt);
-}
-
-void trp_peer_set_last_conn_attempt(TRP_PEER *peer, struct timespec *time)
-{
- peer->last_conn_attempt=*time;
-}
TRP_PTABLE *trp_ptable_new(TALLOC_CTX *memctx)
{
return ptbl;
}
-void trp_peer_set_outgoing_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status)
-{
- TR_NAME *peer_label=trp_peer_get_label(peer);
- int was_connected=trp_peer_is_connected(peer);
- peer->outgoing_status=status;
- tr_debug("trp_peer_set_outgoing_status: %s: status=%d peer connected was %d now %d.",
- peer_label->buf, status, was_connected, trp_peer_is_connected(peer));
- if ((trp_peer_is_connected(peer) != was_connected) && (peer->conn_status_cb!=NULL))
- peer->conn_status_cb(peer, peer->conn_status_cookie);
-}
-
-TRP_PEER_CONN_STATUS trp_peer_get_outgoing_status(TRP_PEER *peer)
-{
- return peer->outgoing_status;
-}
-
-void trp_peer_set_incoming_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status)
-{
- TR_NAME *peer_label=trp_peer_get_label(peer);
- int was_connected=trp_peer_is_connected(peer);
- peer->incoming_status=status;
- tr_debug("trp_peer_set_incoming_status: %s: status=%d peer connected was %d now %d.",
- peer_label->buf, status, was_connected, trp_peer_is_connected(peer));
- if ((trp_peer_is_connected(peer) != was_connected) && (peer->conn_status_cb!=NULL))
- peer->conn_status_cb(peer, peer->conn_status_cookie);
-}
-
-TRP_PEER_CONN_STATUS trp_peer_get_incoming_status(TRP_PEER *peer)
-{
- return peer->incoming_status;
-}
-
-int trp_peer_is_connected(TRP_PEER *peer)
-{
- return (peer->outgoing_status==PEER_CONNECTED) && (peer->incoming_status==PEER_CONNECTED);
-}
-
void trp_ptable_free(TRP_PTABLE *ptbl)
{
talloc_free(ptbl);
return cur;
}
-char *trp_peer_to_str(TALLOC_CTX *memctx, TRP_PEER *peer, const char *sep)
-{
- if (sep==NULL)
- sep=", ";
- return talloc_asprintf(memctx,
- "%s:%u%s0x%04X",
- peer->server, peer->port, sep,
- peer->linkcost);
-}
-
-/* this is horribly inefficient but should be ok for small peer tables */
-char *trp_ptable_to_str(TALLOC_CTX *memctx, TRP_PTABLE *ptbl, const char *sep, const char *lineterm)
-{
- TALLOC_CTX *tmpctx=talloc_new(NULL);
- TRP_PEER *peer=NULL;
- char *result=talloc_strdup(tmpctx, "");
-
- if (lineterm==NULL)
- lineterm="\n";
-
- /* this leaves intermediate result strings in the tmpctx context, we'll free these when
- * we're done */
- for (peer=ptbl->head; peer!=NULL; peer=peer->next)
- result=talloc_asprintf(tmpctx, "%s%s%s", result, lineterm, trp_peer_to_str(tmpctx, peer, sep));
-
- talloc_steal(memctx, result); /* hand result over to caller */
- talloc_free(tmpctx); /* free detritus */
- return result;
-}
-
TRP_PTABLE_ITER *trp_ptable_iter_new(TALLOC_CTX *mem_ctx)
{
TRP_PTABLE_ITER *iter=talloc(mem_ctx, TRP_PTABLE_ITER);
--- /dev/null
+/*
+ * 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 <trp_peer.h>
+#include <trp_ptable.h>
+
+/* this is horribly inefficient but should be ok for small peer tables */
+char *trp_ptable_to_str(TALLOC_CTX *memctx, TRP_PTABLE *ptbl, const char *sep, const char *lineterm)
+{
+ TALLOC_CTX *tmpctx=talloc_new(NULL);
+ TRP_PEER *peer=NULL;
+ char *result=talloc_strdup(tmpctx, "");
+
+ if (lineterm==NULL)
+ lineterm="\n";
+
+ /* this leaves intermediate result strings in the tmpctx context, we'll free these when
+ * we're done */
+ for (peer=ptbl->head; peer!=NULL; peer=peer->next)
+ result=talloc_asprintf(tmpctx, "%s%s%s", result, lineterm, trp_peer_to_str(tmpctx, peer, sep));
+
+ talloc_steal(memctx, result); /* hand result over to caller */
+ talloc_free(tmpctx); /* free detritus */
+ return result;
+}
+
+json_t *trp_ptable_to_json(TRP_PTABLE *ptbl)
+{
+ TRP_PTABLE_ITER *iter = trp_ptable_iter_new(NULL);
+ json_t *ptbl_json = json_array();
+ TRP_PEER *peer = trp_ptable_iter_first(iter, ptbl);
+ while(peer) {
+ json_array_append_new(ptbl_json, trp_peer_to_json(peer));
+ peer = trp_ptable_iter_next(iter);
+ }
+ trp_ptable_iter_free(iter);
+ return ptbl_json;
+}
--- /dev/null
+/*
+ * 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 <stdlib.h>
+
+#include <glib.h>
+#include <talloc.h>
+#include <time.h>
+
+#include <tr_name_internal.h>
+#include <trp_route.h>
+#include <trp_internal.h>
+#include <trp_rtable.h>
+#include <tr_debug.h>
+#include <trust_router/trp.h>
+#include <trust_router/tid.h>
+
+
+/* Note: be careful mixing talloc with glib. */
+
+static int trp_route_destructor(void *obj)
+{
+ TRP_ROUTE *entry=talloc_get_type_abort(obj, TRP_ROUTE);
+ if (entry->comm!=NULL)
+ tr_free_name(entry->comm);
+ if (entry->realm!=NULL)
+ tr_free_name(entry->realm);
+ if (entry->trust_router!=NULL)
+ tr_free_name(entry->trust_router);
+ if (entry->peer!=NULL)
+ tr_free_name(entry->peer);
+ if (entry->next_hop!=NULL)
+ tr_free_name(entry->next_hop);
+ return 0;
+}
+
+TRP_ROUTE *trp_route_new(TALLOC_CTX *mem_ctx)
+{
+ TRP_ROUTE *entry=talloc(mem_ctx, TRP_ROUTE);
+ if (entry!=NULL) {
+ entry->comm=NULL;
+ entry->realm=NULL;
+ entry->trust_router=NULL;
+ entry->trp_port=TRP_PORT;
+ entry->tid_port=TID_PORT;
+ entry->peer=NULL;
+ entry->next_hop=NULL;
+ entry->selected=0;
+ entry->interval=0;
+ entry->expiry=talloc(entry, struct timespec);
+ if (entry->expiry==NULL) {
+ talloc_free(entry);
+ return NULL;
+ }
+ *(entry->expiry)=(struct timespec){0,0};
+ entry->local=0;
+ entry->triggered=0;
+ talloc_set_destructor((void *)entry, trp_route_destructor);
+ }
+ return entry;
+}
+
+void trp_route_free(TRP_ROUTE *entry)
+{
+ if (entry!=NULL)
+ talloc_free(entry);
+}
+
+void trp_route_set_comm(TRP_ROUTE *entry, TR_NAME *comm)
+{
+ if (entry->comm!=NULL)
+ tr_free_name(entry->comm);
+ entry->comm=comm;
+}
+
+TR_NAME *trp_route_get_comm(TRP_ROUTE *entry)
+{
+ return entry->comm;
+}
+
+TR_NAME *trp_route_dup_comm(TRP_ROUTE *entry)
+{
+ return tr_dup_name(trp_route_get_comm(entry));
+}
+
+void trp_route_set_realm(TRP_ROUTE *entry, TR_NAME *realm)
+{
+ if (entry->realm!=NULL)
+ tr_free_name(entry->realm);
+ entry->realm=realm;
+}
+
+TR_NAME *trp_route_get_realm(TRP_ROUTE *entry)
+{
+ return entry->realm;
+}
+
+TR_NAME *trp_route_dup_realm(TRP_ROUTE *entry)
+{
+ return tr_dup_name(trp_route_get_realm(entry));
+}
+
+void trp_route_set_trust_router(TRP_ROUTE *entry, TR_NAME *tr)
+{
+ if (entry->trust_router!=NULL)
+ tr_free_name(entry->trust_router);
+ entry->trust_router=tr;
+}
+
+TR_NAME *trp_route_get_trust_router(TRP_ROUTE *entry)
+{
+ return entry->trust_router;
+}
+
+TR_NAME *trp_route_dup_trust_router(TRP_ROUTE *entry)
+{
+ return tr_dup_name(trp_route_get_trust_router(entry));
+}
+
+void trp_route_set_peer(TRP_ROUTE *entry, TR_NAME *peer)
+{
+ if (entry->peer!=NULL)
+ tr_free_name(entry->peer);
+ entry->peer=peer;
+}
+
+TR_NAME *trp_route_get_peer(TRP_ROUTE *entry)
+{
+ return entry->peer;
+}
+
+TR_NAME *trp_route_dup_peer(TRP_ROUTE *entry)
+{
+ return tr_dup_name(trp_route_get_peer(entry));
+}
+
+void trp_route_set_metric(TRP_ROUTE *entry, unsigned int metric)
+{
+ entry->metric=metric;
+}
+
+unsigned int trp_route_get_metric(TRP_ROUTE *entry)
+{
+ return entry->metric;
+}
+
+/* TODO: set the hostname and port for the next hop. Currently assume default TID port. --jlr */
+void trp_route_set_next_hop(TRP_ROUTE *entry, TR_NAME *next_hop)
+{
+ if (entry->next_hop!=NULL)
+ tr_free_name(entry->next_hop);
+ entry->next_hop=next_hop;
+}
+
+TR_NAME *trp_route_get_next_hop(TRP_ROUTE *entry)
+{
+ return entry->next_hop;
+}
+
+TR_NAME *trp_route_dup_next_hop(TRP_ROUTE *entry)
+{
+ return tr_dup_name(trp_route_get_next_hop(entry));
+}
+
+void trp_route_set_selected(TRP_ROUTE *entry, int sel)
+{
+ entry->selected=sel;
+}
+
+int trp_route_is_selected(TRP_ROUTE *entry)
+{
+ return entry->selected;
+}
+
+void trp_route_set_interval(TRP_ROUTE *entry, int interval)
+{
+ entry->interval=interval;
+}
+
+int trp_route_get_interval(TRP_ROUTE *entry)
+{
+ return entry->interval;
+}
+
+/* copies incoming value, does not assume responsibility for freeing */
+void trp_route_set_expiry(TRP_ROUTE *entry, struct timespec *exp)
+{
+ entry->expiry->tv_sec=exp->tv_sec;
+ entry->expiry->tv_nsec=exp->tv_nsec;
+}
+
+struct timespec *trp_route_get_expiry(TRP_ROUTE *entry)
+{
+ return entry->expiry;
+}
+
+void trp_route_set_local(TRP_ROUTE *entry, int local)
+{
+ entry->local=local;
+}
+
+int trp_route_is_local(TRP_ROUTE *entry)
+{
+ return entry->local;
+}
+
+void trp_route_set_triggered(TRP_ROUTE *entry, int trig)
+{
+ tr_debug("trp_route_set_triggered: setting route to %.*s/%.*s through %.*s to %s",
+ entry->comm->len, entry->comm->buf,
+ entry->realm->len, entry->realm->buf,
+ entry->peer->len, entry->peer->buf,
+ trig ? "triggered" : "not triggered");
+ entry->triggered=trig;
+}
+
+int trp_route_is_triggered(TRP_ROUTE *entry)
+{
+ return entry->triggered;
+}
--- /dev/null
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <talloc.h>
+#include <jansson.h>
+
+#include <tr_name_internal.h>
+#include <trp_route.h>
+#include <trp_internal.h>
+#include <trp_rtable.h>
+#include <trust_router/trp.h>
+#include <tr_util.h>
+
+/* Pretty print a route table entry to a newly allocated string. If sep is NULL,
+ * returns comma+space separated string. */
+char *trp_route_to_str(TALLOC_CTX *mem_ctx, TRP_ROUTE *entry, const char *sep)
+{
+ char *comm=tr_name_strdup(entry->comm);
+ char *realm=tr_name_strdup(entry->realm);
+ char *peer=tr_name_strdup(entry->peer);
+ char *trust_router=tr_name_strdup(entry->trust_router);
+ char *next_hop=tr_name_strdup(entry->next_hop);
+ char *expiry=timespec_to_str(entry->expiry);
+ char *result=NULL;
+
+ if (sep==NULL)
+ sep=", ";
+
+ result=talloc_asprintf(mem_ctx,
+ "%s%s%s%s%s%s%u%s%s%s%s%s%u%s%u%s%s%s%u",
+ comm, sep,
+ realm, sep,
+ peer, sep,
+ entry->metric, sep,
+ trust_router, sep,
+ next_hop, sep,
+ entry->selected, sep,
+ entry->local, sep,
+ expiry, sep,
+ entry->triggered);
+ free(comm);
+ free(realm);
+ free(peer);
+ free(trust_router);
+ free(next_hop);
+ free(expiry);
+ return result;
+}
+
+/* helper */
+static json_t *expiry_to_json_string(TRP_ROUTE *route)
+{
+ struct timespec ts_zero = {0, 0};
+ char *s = NULL;
+ json_t *jstr = NULL;
+
+ if (tr_cmp_timespec(trp_route_get_expiry(route), &ts_zero) > 0) {
+ s = timespec_to_str(trp_route_get_expiry(route));
+
+ if (s) {
+ jstr = json_string(s);
+ free(s);
+ }
+ }
+
+ return jstr;
+}
+
+/* helper for below */
+#define OBJECT_SET_OR_FAIL(jobj, key, val) \
+do { \
+ if (val) \
+ json_object_set_new((jobj),(key),(val)); \
+ else \
+ goto cleanup; \
+} while (0)
+
+#define OBJECT_SET_OR_SKIP(jobj, key, val) \
+do { \
+ if (val) \
+ json_object_set_new((jobj),(key),(val)); \
+} while (0)
+
+json_t *trp_route_to_json(TRP_ROUTE *route)
+{
+ json_t *route_json = NULL;
+ json_t *retval = NULL;
+
+ route_json = json_object();
+ if (route_json == NULL)
+ goto cleanup;
+
+ OBJECT_SET_OR_FAIL(route_json, "community", tr_name_to_json_string(trp_route_get_comm(route)));
+ OBJECT_SET_OR_FAIL(route_json, "realm", tr_name_to_json_string(trp_route_get_realm(route)));
+ if (trp_route_get_peer(route)->len > 0)
+ OBJECT_SET_OR_FAIL(route_json, "peer", tr_name_to_json_string(trp_route_get_peer(route)));
+ OBJECT_SET_OR_FAIL(route_json, "metric", json_integer(trp_route_get_metric(route)));
+ OBJECT_SET_OR_FAIL(route_json, "trust_router", tr_name_to_json_string(trp_route_get_trust_router(route)));
+ if (trp_route_get_next_hop(route)->len > 0)
+ OBJECT_SET_OR_FAIL(route_json, "next_hop", tr_name_to_json_string(trp_route_get_next_hop(route)));
+ OBJECT_SET_OR_FAIL(route_json, "selected", json_boolean(trp_route_is_selected(route)));
+ OBJECT_SET_OR_FAIL(route_json, "local", json_boolean(trp_route_is_local(route)));
+ OBJECT_SET_OR_SKIP(route_json, "expires", expiry_to_json_string(route));
+
+ /* succeeded - set the return value and increment the reference count */
+ retval = route_json;
+ json_incref(retval);
+
+
+cleanup:
+ if (route_json)
+ json_decref(route_json);
+ return retval;
+}
\ No newline at end of file
#include <time.h>
#include <tr_name_internal.h>
+#include <trp_route.h>
#include <trp_internal.h>
#include <trp_rtable.h>
#include <tr_debug.h>
#include <trust_router/trp.h>
#include <trust_router/tid.h>
-/* Note: be careful mixing talloc with glib. */
-
-static int trp_route_destructor(void *obj)
-{
- TRP_ROUTE *entry=talloc_get_type_abort(obj, TRP_ROUTE);
- if (entry->comm!=NULL)
- tr_free_name(entry->comm);
- if (entry->realm!=NULL)
- tr_free_name(entry->realm);
- if (entry->trust_router!=NULL)
- tr_free_name(entry->trust_router);
- if (entry->peer!=NULL)
- tr_free_name(entry->peer);
- if (entry->next_hop!=NULL)
- tr_free_name(entry->next_hop);
- return 0;
-}
-
-TRP_ROUTE *trp_route_new(TALLOC_CTX *mem_ctx)
-{
- TRP_ROUTE *entry=talloc(mem_ctx, TRP_ROUTE);
- if (entry!=NULL) {
- entry->comm=NULL;
- entry->realm=NULL;
- entry->trust_router=NULL;
- entry->trp_port=TRP_PORT;
- entry->tid_port=TID_PORT;
- entry->peer=NULL;
- entry->next_hop=NULL;
- entry->selected=0;
- entry->interval=0;
- entry->expiry=talloc(entry, struct timespec);
- if (entry->expiry==NULL) {
- talloc_free(entry);
- return NULL;
- }
- *(entry->expiry)=(struct timespec){0,0};
- entry->local=0;
- entry->triggered=0;
- talloc_set_destructor((void *)entry, trp_route_destructor);
- }
- return entry;
-}
-
-void trp_route_free(TRP_ROUTE *entry)
-{
- if (entry!=NULL)
- talloc_free(entry);
-}
-
-void trp_route_set_comm(TRP_ROUTE *entry, TR_NAME *comm)
-{
- if (entry->comm!=NULL)
- tr_free_name(entry->comm);
- entry->comm=comm;
-}
-
-TR_NAME *trp_route_get_comm(TRP_ROUTE *entry)
-{
- return entry->comm;
-}
-
-TR_NAME *trp_route_dup_comm(TRP_ROUTE *entry)
-{
- return tr_dup_name(trp_route_get_comm(entry));
-}
-
-void trp_route_set_realm(TRP_ROUTE *entry, TR_NAME *realm)
-{
- if (entry->realm!=NULL)
- tr_free_name(entry->realm);
- entry->realm=realm;
-}
-
-TR_NAME *trp_route_get_realm(TRP_ROUTE *entry)
-{
- return entry->realm;
-}
-
-TR_NAME *trp_route_dup_realm(TRP_ROUTE *entry)
-{
- return tr_dup_name(trp_route_get_realm(entry));
-}
-
-void trp_route_set_trust_router(TRP_ROUTE *entry, TR_NAME *tr)
-{
- if (entry->trust_router!=NULL)
- tr_free_name(entry->trust_router);
- entry->trust_router=tr;
-}
-
-TR_NAME *trp_route_get_trust_router(TRP_ROUTE *entry)
-{
- return entry->trust_router;
-}
-
-TR_NAME *trp_route_dup_trust_router(TRP_ROUTE *entry)
-{
- return tr_dup_name(trp_route_get_trust_router(entry));
-}
-
-void trp_route_set_peer(TRP_ROUTE *entry, TR_NAME *peer)
-{
- if (entry->peer!=NULL)
- tr_free_name(entry->peer);
- entry->peer=peer;
-}
-
-TR_NAME *trp_route_get_peer(TRP_ROUTE *entry)
-{
- return entry->peer;
-}
-
-TR_NAME *trp_route_dup_peer(TRP_ROUTE *entry)
-{
- return tr_dup_name(trp_route_get_peer(entry));
-}
-
-void trp_route_set_metric(TRP_ROUTE *entry, unsigned int metric)
-{
- entry->metric=metric;
-}
-
-unsigned int trp_route_get_metric(TRP_ROUTE *entry)
-{
- return entry->metric;
-}
-
-/* TODO: set the hostname and port for the next hop. Currently assume default TID port. --jlr */
-void trp_route_set_next_hop(TRP_ROUTE *entry, TR_NAME *next_hop)
-{
- if (entry->next_hop!=NULL)
- tr_free_name(entry->next_hop);
- entry->next_hop=next_hop;
-}
-
-TR_NAME *trp_route_get_next_hop(TRP_ROUTE *entry)
-{
- return entry->next_hop;
-}
-
-TR_NAME *trp_route_dup_next_hop(TRP_ROUTE *entry)
-{
- return tr_dup_name(trp_route_get_next_hop(entry));
-}
-
-void trp_route_set_selected(TRP_ROUTE *entry, int sel)
-{
- entry->selected=sel;
-}
-
-int trp_route_is_selected(TRP_ROUTE *entry)
-{
- return entry->selected;
-}
-
-void trp_route_set_interval(TRP_ROUTE *entry, int interval)
-{
- entry->interval=interval;
-}
-
-int trp_route_get_interval(TRP_ROUTE *entry)
-{
- return entry->interval;
-}
-
-/* copies incoming value, does not assume responsibility for freeing */
-void trp_route_set_expiry(TRP_ROUTE *entry, struct timespec *exp)
-{
- entry->expiry->tv_sec=exp->tv_sec;
- entry->expiry->tv_nsec=exp->tv_nsec;
-}
-
-struct timespec *trp_route_get_expiry(TRP_ROUTE *entry)
-{
- return entry->expiry;
-}
-
-void trp_route_set_local(TRP_ROUTE *entry, int local)
-{
- entry->local=local;
-}
-
-int trp_route_is_local(TRP_ROUTE *entry)
-{
- return entry->local;
-}
-
-void trp_route_set_triggered(TRP_ROUTE *entry, int trig)
-{
- tr_debug("trp_route_set_triggered: setting route to %.*s/%.*s through %.*s to %s",
- entry->comm->len, entry->comm->buf,
- entry->realm->len, entry->realm->buf,
- entry->peer->len, entry->peer->buf,
- trig ? "triggered" : "not triggered");
- entry->triggered=trig;
-}
-
-int trp_route_is_triggered(TRP_ROUTE *entry)
-{
- return entry->triggered;
-}
-
/* result must be freed with g_free */
static gchar *tr_name_to_g_str(const TR_NAME *n)
}
/* Returns an array of pointers to TRP_ROUTE, length of array in n_out.
- * Caller must free the array (in the talloc NULL context), but must
+ * Caller must free the array (in the mem_ctx context), but must
* not free its contents. */
-TRP_ROUTE **trp_rtable_get_entries(TRP_RTABLE *rtbl, size_t *n_out)
+TRP_ROUTE **trp_rtable_get_entries(TALLOC_CTX *mem_ctx, TRP_RTABLE *rtbl, size_t *n_out)
{
TRP_ROUTE **ret=NULL;
TR_NAME **comm=NULL;
if (*n_out==0)
return NULL;
- ret=talloc_array(NULL, TRP_ROUTE *, *n_out);
+ ret=talloc_array(mem_ctx, TRP_ROUTE *, *n_out);
if (ret==NULL) {
tr_crit("trp_rtable_get_entries: unable to allocate return array.");
*n_out=0;
return g_hash_table_lookup(realm_tbl, peer); /* does not copy or increment ref count */
}
-static char *timespec_to_str(struct timespec *ts)
-{
- struct tm tm;
- char *s=NULL;
-
- if (localtime_r(&(ts->tv_sec), &tm)==NULL)
- return NULL;
-
- s=malloc(40); /* long enough to contain strftime result */
- if (s==NULL)
- return NULL;
-
- if (strftime(s, 40, "%F %T", &tm)==0) {
- free(s);
- return NULL;
- }
- return s;
-}
-
TRP_ROUTE *trp_rtable_get_selected_entry(TRP_RTABLE *rtbl, TR_NAME *comm, TR_NAME *realm)
{
size_t n=0;
return selected;
}
-/* Pretty print a route table entry to a newly allocated string. If sep is NULL,
- * returns comma+space separated string. */
-char *trp_route_to_str(TALLOC_CTX *mem_ctx, TRP_ROUTE *entry, const char *sep)
-{
- char *comm=tr_name_strdup(entry->comm);
- char *realm=tr_name_strdup(entry->realm);
- char *peer=tr_name_strdup(entry->peer);
- char *trust_router=tr_name_strdup(entry->trust_router);
- char *next_hop=tr_name_strdup(entry->next_hop);
- char *expiry=timespec_to_str(entry->expiry);
- char *result=NULL;
-
- if (sep==NULL)
- sep=", ";
-
- result=talloc_asprintf(mem_ctx,
- "%s%s%s%s%s%s%u%s%s%s%s%s%u%s%u%s%s%s%u",
- comm, sep,
- realm, sep,
- peer, sep,
- entry->metric, sep,
- trust_router, sep,
- next_hop, sep,
- entry->selected, sep,
- entry->local, sep,
- expiry, sep,
- entry->triggered);
- free(comm);
- free(realm);
- free(peer);
- free(trust_router);
- free(next_hop);
- free(expiry);
- return result;
-}
-
void trp_rtable_clear_triggered(TRP_RTABLE *rtbl)
{
size_t n_entries=0;
- TRP_ROUTE **entries=trp_rtable_get_entries(rtbl, &n_entries);
+ TRP_ROUTE **entries= trp_rtable_get_entries(NULL, rtbl, &n_entries);
size_t ii=0;
if (entries!=NULL) {
talloc_free(entries);
}
}
-
-static int sort_tr_names_cmp(const void *a, const void *b)
-{
- TR_NAME **n1=(TR_NAME **)a;
- TR_NAME **n2=(TR_NAME **)b;
- return tr_name_cmp(*n1, *n2);
-}
-
-static void sort_tr_names(TR_NAME **names, size_t n_names)
-{
- qsort(names, n_names, sizeof(TR_NAME *), sort_tr_names_cmp);
-}
-
-char *trp_rtable_to_str(TALLOC_CTX *mem_ctx, TRP_RTABLE *rtbl, const char *sep, const char *lineterm)
-{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- TR_NAME **comms=NULL;
- size_t n_comms=0;
- TR_NAME **realms=NULL;
- size_t n_realms=0;
- TRP_ROUTE **entries=NULL;
- size_t n_entries=0;
- char **tbl_strings=NULL;
- size_t ii_tbl=0; /* counts tbl_strings */
- size_t tbl_size=0;
- size_t len=0;
- size_t ii=0, jj=0, kk=0;
- char *p=NULL;
- char *result=NULL;
-
- if (lineterm==NULL)
- lineterm="\n";
-
- tbl_size=trp_rtable_size(rtbl);
- if (tbl_size==0) {
- result=talloc_strdup(mem_ctx, lineterm);
- goto cleanup;
- }
-
- tbl_strings=talloc_array(tmp_ctx, char *, tbl_size);
- if (tbl_strings==NULL) {
- result=talloc_strdup(mem_ctx, "error");
- goto cleanup;
- }
-
- comms=trp_rtable_get_comms(rtbl, &n_comms);
- talloc_steal(tmp_ctx, comms);
- sort_tr_names(comms, n_comms);
- ii_tbl=0;
- len=0;
- for (ii=0; ii<n_comms; ii++) {
- realms=trp_rtable_get_comm_realms(rtbl, comms[ii], &n_realms);
- talloc_steal(tmp_ctx, realms);
- sort_tr_names(realms, n_realms);
- for (jj=0; jj<n_realms; jj++) {
- entries=trp_rtable_get_realm_entries(rtbl, comms[ii], realms[jj], &n_entries);
- talloc_steal(tmp_ctx, entries);
- for (kk=0; kk<n_entries; kk++) {
- tbl_strings[ii_tbl]=trp_route_to_str(tmp_ctx, entries[kk], sep);
- len+=strlen(tbl_strings[ii_tbl]);
- ii_tbl++;
- }
- talloc_free(entries);
- }
- talloc_free(realms);
- }
- talloc_free(comms);
-
- /* now combine all the strings */
- len += tbl_size*strlen(lineterm); /* space for line terminations*/
- len += 1; /* nul terminator */
- result=(char *)talloc_size(tmp_ctx, len);
- for (p=result,ii=0; ii < tbl_size; ii++) {
- p+=sprintf(p, "%s%s", tbl_strings[ii], lineterm);
- }
- talloc_steal(mem_ctx, result);
-
-cleanup:
- talloc_free(tmp_ctx);
- return result;
-}
--- /dev/null
+/*
+ * 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 <stdlib.h>
+
+#include <talloc.h>
+#include <jansson.h>
+
+#include <tr_name_internal.h>
+#include <trp_route.h>
+#include <trp_internal.h>
+#include <trp_rtable.h>
+#include <trust_router/trp.h>
+
+
+static int sort_tr_names_cmp(const void *a, const void *b)
+{
+ TR_NAME **n1=(TR_NAME **)a;
+ TR_NAME **n2=(TR_NAME **)b;
+ return tr_name_cmp(*n1, *n2);
+}
+
+static void sort_tr_names(TR_NAME **names, size_t n_names)
+{
+ qsort(names, n_names, sizeof(TR_NAME *), sort_tr_names_cmp);
+}
+
+char *trp_rtable_to_str(TALLOC_CTX *mem_ctx, TRP_RTABLE *rtbl, const char *sep, const char *lineterm)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_NAME **comms=NULL;
+ size_t n_comms=0;
+ TR_NAME **realms=NULL;
+ size_t n_realms=0;
+ TRP_ROUTE **entries=NULL;
+ size_t n_entries=0;
+ char **tbl_strings=NULL;
+ size_t ii_tbl=0; /* counts tbl_strings */
+ size_t tbl_size=0;
+ size_t len=0;
+ size_t ii=0, jj=0, kk=0;
+ char *p=NULL;
+ char *result=NULL;
+
+ if (lineterm==NULL)
+ lineterm="\n";
+
+ tbl_size=trp_rtable_size(rtbl);
+ if (tbl_size==0) {
+ result=talloc_strdup(mem_ctx, lineterm);
+ goto cleanup;
+ }
+
+ tbl_strings=talloc_array(tmp_ctx, char *, tbl_size);
+ if (tbl_strings==NULL) {
+ result=talloc_strdup(mem_ctx, "error");
+ goto cleanup;
+ }
+
+ comms=trp_rtable_get_comms(rtbl, &n_comms);
+ talloc_steal(tmp_ctx, comms);
+ sort_tr_names(comms, n_comms);
+ ii_tbl=0;
+ len=0;
+ for (ii=0; ii<n_comms; ii++) {
+ realms=trp_rtable_get_comm_realms(rtbl, comms[ii], &n_realms);
+ talloc_steal(tmp_ctx, realms);
+ sort_tr_names(realms, n_realms);
+ for (jj=0; jj<n_realms; jj++) {
+ entries=trp_rtable_get_realm_entries(rtbl, comms[ii], realms[jj], &n_entries);
+ talloc_steal(tmp_ctx, entries);
+ for (kk=0; kk<n_entries; kk++) {
+ tbl_strings[ii_tbl]=trp_route_to_str(tmp_ctx, entries[kk], sep);
+ len+=strlen(tbl_strings[ii_tbl]);
+ ii_tbl++;
+ }
+ talloc_free(entries);
+ }
+ talloc_free(realms);
+ }
+ talloc_free(comms);
+
+ /* now combine all the strings */
+ len += tbl_size*strlen(lineterm); /* space for line terminations*/
+ len += 1; /* nul terminator */
+ result=(char *)talloc_size(tmp_ctx, len);
+ for (p=result,ii=0; ii < tbl_size; ii++) {
+ p+=sprintf(p, "%s%s", tbl_strings[ii], lineterm);
+ }
+ talloc_steal(mem_ctx, result);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return result;
+}
+
+
+json_t *trp_rtable_to_json(TRP_RTABLE *rtbl)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ json_t *rtable_json = NULL;
+ json_t *route_json = NULL;
+ TRP_ROUTE **routes = NULL;
+ size_t n_routes = 0;
+ json_t *retval = NULL;
+
+ /* Get the JSON array to return */
+ rtable_json = json_array();
+ if (rtable_json == NULL)
+ goto cleanup;
+
+ /* Get the array of routes */
+ routes = trp_rtable_get_entries(tmp_ctx, rtbl, &n_routes);
+ if (routes == NULL)
+ goto cleanup;
+
+ /* Gather JSON for each route */
+ while (n_routes > 0) {
+ route_json = trp_route_to_json(routes[--n_routes]);
+ if (route_json == NULL)
+ goto cleanup;
+ json_array_append_new(rtable_json, route_json);
+ }
+
+ /* Success - set the return value and increment the reference count */
+ retval = rtable_json;
+ json_incref(retval);
+
+cleanup:
+ if (rtable_json)
+ json_decref(rtable_json);
+ talloc_free(tmp_ctx);
+ return retval;
+}
#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_apc.h>
#include <tr_rp.h>
#include <tr_name_internal.h>
+#include <trp_route.h>
#include <trp_internal.h>
-#include <tr_gss.h>
+#include <tr_gss_names.h>
+#include <trp_peer.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)
{
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)
{
tr_debug("trps_read_message: message received, %u bytes.", (unsigned) buflen);
tr_debug("trps_read_message: %.*s", buflen, buf);
- *msg=tr_msg_decode(buf, buflen);
+ *msg= tr_msg_decode(NULL, buf, buflen);
free(buf);
if (*msg==NULL)
return TRP_NOPARSE;
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 */
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;
trps->cookie = cookie;
}
- return n_fd;
+ return (int) n_fd;
}
TRP_RC trps_authorize_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *conn)
return TRP_ERROR;
}
- entry=trp_rtable_get_entries(trps->rtable, &n_entry); /* must talloc_free *entry */
+ entry= trp_rtable_get_entries(NULL, trps->rtable, &n_entry); /* must talloc_free *entry */
/* loop over the entries */
for (ii=0; ii<n_entry; ii++) {
}
-static char *timespec_to_str(struct timespec *ts)
-{
- struct tm tm;
- char *s=NULL;
-
- if (localtime_r(&(ts->tv_sec), &tm)==NULL)
- return NULL;
-
- s=malloc(40); /* long enough to contain strftime result */
- if (s==NULL)
- return NULL;
-
- if (strftime(s, 40, "%F %T", &tm)==0) {
- free(s);
- return NULL;
- }
- return s;
-}
-
-
/* Sweep for expired communities/realms/memberships. */
TRP_RC trps_sweep_ctable(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;
}
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;
%global optflags %{optflags} -Wno-parentheses
Name: trust_router
-Version: 3.3.0
+Version: 3.4.0~1
Release: 1%{?dist}
Summary: Moonshot Trust Router