DISTCHECK_CONFIGURE_FLAGS = \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
-bin_PROGRAMS= tr/trust_router tr/trpc tid/example/tidc tid/example/tids common/dh_test/tr_dh_test common/mq_test/mq_test common/mq_test/thread_test trp/msgtst trp/test/rtbl_test trp/test/ptbl_test common/cfg_test/cfg_test
+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
AM_CPPFLAGS=-I$(srcdir)/include $(GLIB_CFLAGS)
AM_CFLAGS = -Wall -Werror=missing-prototypes -Werror -Wno-parentheses $(GLIB_CFLAGS)
SUBDIRS = gsscon
common/tr_msg.c \
common/tr_dh.c \
common/tr_debug.c \
- common/tr_util.c
+ common/tr_util.c \
+ common/tr_apc.c \
+ common/tr_comm.c \
+ common/tr_rp.c \
+ common/tr_idp.c \
+ common/tr_filter.c \
+ common/tr_gss.c
tid_srcs = tid/tid_resp.c \
tid/tid_req.c \
trp/trp_rtable.c \
trp/trp_req.c \
trp/trp_upd.c \
-tid/tid_resp.c \
-tid/tid_req.c \
-common/tr_gss.c \
common/tr_config.c \
-common/tr_idp.c \
-common/tr_apc.c \
-common/tr_comm.c \
-common/tr_filter.c \
-common/tr_rp.c \
-common/tr_msg.c \
-common/tr_constraint.c \
-common/tr_name.c \
common/tr_mq.c
check_PROGRAMS = common/t_constraint
libtr_tid_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden
libtr_tid_la_LIBADD = gsscon/libgsscon.la $(GLIB_LIBS)
-libtr_tid_la_LDFLAGS = $(AM_LDFLAGS) -version-info 2 -no-undefined
+libtr_tid_la_LDFLAGS = $(AM_LDFLAGS) -version-info 3:0:1 -no-undefined
common_t_constraint_SOURCES = common/t_constraint.c \
common/tr_debug.c \
tr/tr_cfgwatch.c \
tr/tr_tid.c \
tr/tr_trp.c \
-$(trp_srcs)
+$(tid_srcs) \
+$(trp_srcs) \
+$(common_srcs)
-tr_trust_router_CFLAGS = $(AM_CFLAGS) -pthread
tr_trust_router_LDFLAGS = $(AM_LDFLAGS) -levent_pthreads -pthread
-tr_trust_router_LDADD = gsscon/libgsscon.la libtr_tid.la $(GLIB_LIBS)
-
+tr_trust_router_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
tr_trpc_SOURCES =tr/trpc_main.c \
tr/tr_trp.c \
-$(trp_srcs)
-tr_trpc_LDADD = gsscon/libgsscon.la libtr_tid.la $(GLIB_LIBS)
+$(trp_srcs) \
+$(tid_srcs) \
+$(common_srcs)
+
+tr_trpc_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
tr_trpc_LDFLAGS = $(AM_LDFLAGS) -pthread
-tr_trpc_CFLAGS = $(AM_CFLAGS) -pthread
trp_msgtst_SOURCES = trp/msgtst.c \
-common/tr_msg.c \
+$(common_srcs) \
trp/trp_req.c \
trp/trp_upd.c \
tid/tid_resp.c \
tid/tid_req.c
-trp_msgtst_LDADD = libtr_tid.la $(GLIB_LIBS)
+trp_msgtst_LDADD = $(GLIB_LIBS)
trp_test_rtbl_test_SOURCES = trp/test/rtbl_test.c \
common/tr_name.c \
trp_test_rtbl_test_LDADD = $(GLIB_LIBS)
trp_test_ptbl_test_SOURCES = trp/test/ptbl_test.c \
-$(trp_srcs)
-trp_test_ptbl_test_LDADD = gsscon/libgsscon.la libtr_tid.la $(GLIB_LIBS)
-
-tid_example_tidc_SOURCES = tid/example/tidc_main.c
-tid_example_tidc_LDADD = gsscon/libgsscon.la libtr_tid.la $(GLIB_LIBS)
-
-tid_example_tids_SOURCES = tid/example/tids_main.c
-tid_example_tids_LDADD = gsscon/libgsscon.la libtr_tid.la $(GLIB_LIBS)
-
-common_dh_test_tr_dh_test_SOURCES = common/tr_dh.c \
+$(tid_srcs) \
+$(trp_srcs) \
+$(common_srcs)
+trp_test_ptbl_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
+trp_test_ptbl_test_LDFLAGS = $(AM_LDFLAGS) -pthread
+
+tid_example_tidc_SOURCES = tid/example/tidc_main.c \
+$(tid_srcs) \
+$(trp_srcs) \
+$(common_srcs)
+tid_example_tidc_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
+tid_example_tidc_LDFLAGS = $(AM_LDFLAGS) -pthread
+
+tid_example_tids_SOURCES = tid/example/tids_main.c \
+$(tid_srcs) \
+$(trp_srcs) \
+$(common_srcs)
+tid_example_tids_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
+tid_example_tids_LDFLAGS = $(AM_LDFLAGS) -pthread
+
+common_tests_tr_dh_test_SOURCES = common/tr_dh.c \
common/tr_debug.c \
-common/dh_test/dh_test.c
+common/tests/dh_test.c
-common_mq_test_mq_test_SOURCES = common/tr_mq.c \
-common/mq_test/mq_test.c
+common_tests_mq_test_SOURCES = common/tr_mq.c \
+common/tests/mq_test.c \
+common/tr_debug.c
-common_mq_test_mq_test_CFLAGS = -pthread
-common_mq_test_mq_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc
+common_tests_mq_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc -pthread
-common_cfg_test_cfg_test_SOURCES = common/cfg_test/cfg_test.c \
+common_tests_cfg_test_SOURCES = common/tests/cfg_test.c \
+$(common_srcs) \
+$(tid_srcs) \
$(trp_srcs)
+common_tests_cfg_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
+common_tests_cfg_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc -pthread
-common_cfg_test_cfg_test_LDADD = gsscon/libgsscon.la libtr_tid.la $(GLIB_LIBS)
-common_cfg_test_cfg_test_CFLAGS = -pthread
-common_cfg_test_cfg_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc
-
-common_mq_test_thread_test_SOURCES = common/tr_mq.c \
+common_tests_thread_test_SOURCES = common/tr_mq.c \
common/tr_debug.c \
-common/mq_test/thread_test.c
+common/tests/thread_test.c
+
+common_tests_commtest_SOURCES = common/tests/commtest.c \
+$(common_srcs) \
+$(tid_srcs) \
+$(trp_srcs)
+common_tests_commtest_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
+common_tests_commtest_LDFLAGS = $(AM_LDFLAGS) -ltalloc -pthread
-common_mq_test_thread_test_CFLAGS = -pthread
-common_mq_test_thread_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc
+common_tests_thread_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc -pthread
pkginclude_HEADERS = include/trust_router/tid.h include/trust_router/tr_name.h \
- include/tr_debug.h \
+ include/tr_debug.h include/trust_router/trp.h \
include/trust_router/tr_dh.h \
include/trust_router/tr_constraint.h \
include/trust_router/tr_versioning.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/tid_internal.h
+ include/tr_filter.h include/tr_gss.h \
+ include/tid_internal.h include/trp_internal.h \
+ include/tr_cfgwatch.h include/tr_event.h \
+ include/tr_mq.h include/trp_ptable.h \
+ include/trp_rtable.h include/tr_util.h
pkgdata_DATA=schema.sql
-nobase_dist_pkgdata_DATA=redhat/init redhat/sysconfig redhat/trusts.cfg redhat/tidc-wrapper redhat/trust_router-wrapper redhat/tr-test-main.cfg redhat/default-main.cfg redhat/tids-wrapper redhat/sysconfig.tids
+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
if HAVE_SYSTEMD
systemdsystemunit_DATA = tids.service
endif
EXTRA_DIST = trust_router.spec common/tests.json schema.sql tids.service \
- tr/manual.cfg tr/portal.cfg \
+ tr/internal.cfg tr/organizations.cfg \
redhat/tids.init
+++ /dev/null
-{
- "local_organizations": [
- {"organization_name": "idp.cfg test org",
- "realms": [
- {"realm": "A.idp.cfg",
- "identity_provider": {
- "aaa_servers": ["rad1.A.idp.cfg",
- "rad2.A.idp.cfg"],
- "apc": "apc.example.com",
- "shared_config": "no"
- },
- "gss_names": ["gss@example.com"]
- }
- ]
- }
- ]
-}
{
TR_COMM *comm=NULL;
TR_NAME *name=NULL;
- TR_APC *apc=NULL;
TR_IDP_REALM *idp_realm=NULL;
TR_AAA_SERVER *aaa=NULL;
assert(cfg!=NULL);
/* test the comms attribute */
- assert(cfg->comms!=NULL);
+ assert(cfg->ctable!=NULL);
name=tr_new_name("apc.example.com");
- comm=tr_comm_lookup(cfg->comms, name);
+ comm=tr_comm_table_find_comm(cfg->ctable, name);
tr_free_name(name);
assert(comm!=NULL);
assert(comm->apcs==NULL);
name=tr_new_name("A.idp.cfg");
- for (idp_realm=comm->idp_realms;
- (idp_realm!=NULL) && (tr_name_cmp(name, idp_realm->realm_id)!=0);
- idp_realm=idp_realm->comm_next) { }
+ assert(name!=NULL);
+ idp_realm=tr_comm_find_idp(cfg->ctable, comm, name);
assert(idp_realm!=NULL);
assert(idp_realm->shared_config==0);
assert(idp_realm->origin==TR_REALM_LOCAL);
assert(cfg->rp_clients!=NULL);
assert(cfg->rp_clients->next==NULL);
assert(cfg->rp_clients->comm_next==NULL);
- /* need to update next test to use TR_GSS_NAMES structure */
-#if 0
+
+ assert(cfg->rp_clients->gss_names!=NULL);
for (ii=1; ii<TR_MAX_GSS_NAMES; ii++)
- assert(cfg->rp_clients->gss_names[ii]==NULL);
- assert(cfg->rp_clients->gss_names[0]!=NULL);
+ assert(cfg->rp_clients->gss_names->names[ii]==NULL);
+ assert(cfg->rp_clients->gss_names->names[0]!=NULL);
name=tr_new_name("gss@example.com");
- assert(tr_name_cmp(name, cfg->rp_clients->gss_names[0])==0);
-#endif
+ assert(tr_name_cmp(name, cfg->rp_clients->gss_names->names[0])==0);
return 0;
}
--- /dev/null
+#include <talloc.h>
+#include <assert.h>
+#include <jansson.h>
+
+#include <tr_apc.h>
+#include <tr_comm.h>
+#include <tr_rp.h>
+#include <trust_router/tr_name.h>
+
+/**********************************************************************/
+/* APC test stuff */
+struct apc_entry {
+ const char *id; /* only allows a single entry for now */
+};
+
+static TR_APC *apc_entry_to_apc(TALLOC_CTX *mem_ctx, struct apc_entry *ae)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_APC *apcs=NULL;
+
+ apcs=tr_apc_new(tmp_ctx);
+ if (apcs!=NULL) {
+ tr_apc_set_id(apcs, tr_new_name(ae->id));
+ talloc_steal(mem_ctx, apcs);
+ }
+
+ talloc_free(tmp_ctx);
+ return apcs;
+}
+
+/**********************************************************************/
+/* TR_COMM test stuff */
+
+struct comm_entry {
+ const char *id;
+ TR_COMM_TYPE type;
+ struct apc_entry *apcs;
+};
+
+static TR_COMM *comm_entry_to_comm(TALLOC_CTX *mem_ctx, struct comm_entry *ce)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_COMM *comm=tr_comm_new(tmp_ctx);
+
+ if (comm!=NULL) {
+ tr_comm_set_id(comm, tr_new_name(ce->id));
+ tr_comm_set_type(comm, ce->type);
+ if (ce->apcs!=NULL)
+ tr_comm_set_apcs(comm, apc_entry_to_apc(tmp_ctx, ce->apcs));
+
+ if ((tr_comm_get_id(comm)==NULL) ||
+ ((ce->apcs!=NULL)&&(tr_comm_get_apcs(comm)==NULL)))
+ comm=NULL; /* it's in tmp_ctx, so will be freed */
+ else
+ talloc_steal(mem_ctx, comm);
+ }
+
+ talloc_free(tmp_ctx);
+ return comm;
+}
+
+static int add_comm_set(TR_COMM_TABLE *ctab, struct comm_entry *entries)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ struct comm_entry *this=NULL;
+ size_t ii=0;
+ TR_COMM *new=NULL;
+ int rc=-1;
+
+ for (this=entries,ii=0; this->id!=NULL; this++, ii++) {
+ new=comm_entry_to_comm(tmp_ctx, this);
+ if (new==NULL) {
+ printf("Error creating community %u.\n", (unsigned int)ii+1);
+ rc=1;
+ goto cleanup;
+ }
+ tr_comm_table_add_comm(ctab, new);
+ }
+ /* success */
+ rc=0;
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static int verify_comm_set(TR_COMM_TABLE *ctab, struct comm_entry *entries)
+{
+ struct comm_entry *this=NULL;
+ TR_COMM *comm=NULL;
+ TR_NAME *this_id=NULL;
+
+ for (this=entries; this->id!=NULL; this++) {
+ this_id=tr_new_name(this->id);
+ comm=tr_comm_table_find_comm(ctab, this_id);
+ tr_free_name(this_id); this_id=NULL;
+
+ if (comm==NULL) {
+ printf("Error, community %s missing from community table.\n", this->id);
+ return -1;
+ }
+ if (tr_comm_get_type(comm)!=this->type) {
+ printf("Error, community %s has wrong type (was %s, expected %s).\n",
+ this->id,
+ tr_comm_type_to_str(tr_comm_get_type(comm)),
+ tr_comm_type_to_str(this->type));
+ return -1;
+ }
+ /* TODO: verify apcs */
+ }
+ return 0;
+}
+
+/* removes entry n from ctab */
+static int remove_comm_set_member(TR_COMM_TABLE *ctab, struct comm_entry *entries, size_t n)
+{
+ TR_NAME *comm_name=tr_new_name(entries[n].id);
+ TR_COMM *comm=tr_comm_table_find_comm(ctab, comm_name);
+ TR_COMM *comm2=NULL;
+
+ if (comm==NULL) {
+ printf("Can't remove community %s, not in table.\n", entries[n].id);
+ tr_free_name(comm_name);
+ return 1;
+ }
+
+ tr_comm_table_remove_comm(ctab, comm);
+ comm2=tr_comm_table_find_comm(ctab, comm_name);
+ if (comm2!=NULL) {
+ printf("Community %s still in table after removal.\n", entries[n].id);
+ tr_comm_free(comm);
+ tr_free_name(comm_name);
+ return 2;
+ }
+
+ tr_comm_free(comm);
+ tr_free_name(comm_name);
+ return 0;
+}
+
+/**********************************************************************/
+/* TR_RP_REALM test stuff */
+
+struct rp_realm_entry {
+ const char *id;
+};
+
+static TR_RP_REALM *rp_realm_entry_to_rp_realm(TALLOC_CTX *mem_ctx, struct rp_realm_entry *re)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_RP_REALM *realm=NULL;
+
+ realm=tr_rp_realm_new(tmp_ctx);
+ if (realm!=NULL) {
+ tr_rp_realm_set_id(realm, tr_new_name(re->id));
+ talloc_steal(mem_ctx, realm);
+ }
+
+ talloc_free(tmp_ctx);
+ return realm;
+}
+
+static int add_rp_realm_set(TR_COMM_TABLE *ctab, struct rp_realm_entry *entries)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ struct rp_realm_entry *this=NULL;
+ TR_RP_REALM *realm=NULL;
+ int rc=-1;
+
+ for (this=entries; this->id!=NULL; this++) {
+ realm=rp_realm_entry_to_rp_realm(tmp_ctx, this);
+ if (realm==NULL) {
+ printf("Error creating RP realm %s.\n", this->id);
+ rc=1;
+ goto cleanup;
+ }
+ tr_comm_table_add_rp_realm(ctab, realm);
+ }
+ rc=0;
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static int verify_rp_realm_set(TR_COMM_TABLE *ctab, struct rp_realm_entry *entries)
+{
+ struct rp_realm_entry *this=NULL;
+ TR_RP_REALM *rp_realm=NULL;
+ TR_NAME *this_id=NULL;
+
+ for (this=entries; this->id!=NULL; this++) {
+ this_id=tr_new_name(this->id);
+ rp_realm=tr_comm_table_find_rp_realm(ctab, this_id);
+ tr_free_name(this_id); this_id=NULL;
+
+ if (rp_realm==NULL) {
+ printf("Error, RP realm %s missing from community table.\n", this->id);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* removes entry n from ctab */
+static int remove_rp_realm_set_member(TR_COMM_TABLE *ctab, struct rp_realm_entry *entries, size_t n)
+{
+ TR_NAME *rp_realm_name=tr_new_name(entries[n].id);
+ TR_RP_REALM *rp_realm=tr_comm_table_find_rp_realm(ctab, rp_realm_name);
+ TR_RP_REALM *rp_realm2=NULL;
+
+ if (rp_realm==NULL) {
+ printf("Can't remove RP realm %s, not in table.\n", entries[n].id);
+ tr_free_name(rp_realm_name);
+ return 1;
+ }
+
+ tr_comm_table_remove_rp_realm(ctab, rp_realm);
+ rp_realm2=tr_comm_table_find_rp_realm(ctab, rp_realm_name);
+ if (rp_realm2!=NULL) {
+ printf("RP realm %s still in table after removal.\n", entries[n].id);
+ tr_rp_realm_free(rp_realm);
+ tr_free_name(rp_realm_name);
+ return 2;
+ }
+
+ tr_rp_realm_free(rp_realm);
+ tr_free_name(rp_realm_name);
+ return 0;
+}
+
+/**********************************************************************/
+/* TR_AAA_SERVER test stuff */
+
+struct aaa_entry {
+ const char *hostname; /* only supports one for testing right now */
+};
+
+static TR_AAA_SERVER *aaa_entry_to_aaa_server(TALLOC_CTX *mem_ctx, struct aaa_entry *ae)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_AAA_SERVER *aaa=tr_aaa_server_new(tmp_ctx, tr_new_name(ae->hostname));
+
+ if ((aaa==NULL) || (aaa->hostname==NULL))
+ aaa=NULL;
+ else
+ talloc_steal(mem_ctx, aaa);
+
+ talloc_free(tmp_ctx);
+ return aaa;
+}
+
+
+/**********************************************************************/
+/* TR_IDP_REALM test stuff */
+
+struct idp_realm_entry {
+ const char *id;
+ struct aaa_entry *aaa_servers;
+ struct apc_entry *apcs;
+};
+
+static TR_IDP_REALM *idp_realm_entry_to_idp_realm(TALLOC_CTX *mem_ctx, struct idp_realm_entry *re)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_IDP_REALM *realm=NULL;
+
+ realm=tr_idp_realm_new(tmp_ctx);
+ if (realm!=NULL) {
+ tr_idp_realm_set_id(realm, tr_new_name(re->id));
+ realm->aaa_servers=aaa_entry_to_aaa_server(realm, re->aaa_servers);
+ if (realm->aaa_servers==NULL)
+ realm=NULL; /* still in tmp_ctx so will be freed */
+ else {
+ tr_idp_realm_set_apcs(realm, apc_entry_to_apc(tmp_ctx, re->apcs));
+ if (tr_idp_realm_get_apcs(realm)==NULL)
+ realm=NULL;
+ }
+ }
+
+ if (realm!=NULL)
+ talloc_steal(mem_ctx, realm);
+
+ talloc_free(tmp_ctx);
+ return realm;
+}
+
+static int add_idp_realm_set(TR_COMM_TABLE *ctab, struct idp_realm_entry *entries)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ struct idp_realm_entry *this=NULL;
+ TR_IDP_REALM *realm=NULL;
+ int rc=-1;
+
+ for (this=entries; this->id!=NULL; this++) {
+ realm=idp_realm_entry_to_idp_realm(tmp_ctx, this);
+ if (realm==NULL) {
+ printf("Error creating IDP realm %s.\n", this->id);
+ rc=1;
+ goto cleanup;
+ }
+ tr_comm_table_add_idp_realm(ctab, realm);
+ }
+ rc=0;
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static int verify_idp_realm_set(TR_COMM_TABLE *ctab, struct idp_realm_entry *entries)
+{
+ struct idp_realm_entry *this=NULL;
+ TR_IDP_REALM *idp_realm=NULL;
+ TR_NAME *this_id=NULL;
+
+ for (this=entries; this->id!=NULL; this++) {
+ this_id=tr_new_name(this->id);
+ idp_realm=tr_comm_table_find_idp_realm(ctab, this_id);
+ tr_free_name(this_id); this_id=NULL;
+
+ if (idp_realm==NULL) {
+ printf("Error, IDP realm %s missing from community table.\n", this->id);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* removes entry n from ctab */
+static int remove_idp_realm_set_member(TR_COMM_TABLE *ctab, struct idp_realm_entry *entries, size_t n)
+{
+ TR_NAME *idp_realm_name=tr_new_name(entries[n].id);
+ TR_IDP_REALM *idp_realm=tr_comm_table_find_idp_realm(ctab, idp_realm_name);
+ TR_IDP_REALM *idp_realm2=NULL;
+
+ if (idp_realm==NULL) {
+ printf("Can't remove IDP realm %s, not in table.\n", entries[n].id);
+ tr_free_name(idp_realm_name);
+ return 1;
+ }
+
+ tr_comm_table_remove_idp_realm(ctab, idp_realm);
+ idp_realm2=tr_comm_table_find_idp_realm(ctab, idp_realm_name);
+ if (idp_realm2!=NULL) {
+ printf("IDP realm %s still in table after removal.\n", entries[n].id);
+ tr_idp_realm_free(idp_realm);
+ tr_free_name(idp_realm_name);
+ return 2;
+ }
+
+ tr_idp_realm_free(idp_realm);
+ tr_free_name(idp_realm_name);
+ return 0;
+}
+
+/**********************************************************************/
+/* Community Membership test stuff */
+
+struct comm_memb_entry {
+ TR_REALM_ROLE role;
+ const char *realm_name;
+ const char *comm_name;
+ const char *origin;
+ /* TODO: test provenance */
+};
+
+/* add an existing realm to an existing community (these must
+ * exist in the community table lists) */
+static int add_comm_membership(TR_COMM_TABLE *ctab, struct comm_memb_entry *entry)
+{
+ TR_NAME *comm_name=tr_new_name(entry->comm_name);
+ TR_NAME *realm_name=tr_new_name(entry->realm_name);
+ TR_COMM *comm=tr_comm_table_find_comm(ctab, comm_name);
+ TR_RP_REALM *rp_realm=(entry->role==TR_ROLE_RP)?(tr_comm_table_find_rp_realm(ctab, realm_name)):(NULL);
+ TR_IDP_REALM *idp_realm=(entry->role==TR_ROLE_IDP)?(tr_comm_table_find_idp_realm(ctab, realm_name)):(NULL);
+ json_t *prov=NULL;
+
+ if ((comm==NULL) || ((rp_realm==NULL)&&(idp_realm==NULL)))
+ return 1;
+
+ prov=json_array();
+ if (entry->origin!=NULL)
+ json_array_append(prov, json_string(entry->origin));
+
+ switch (entry->role) {
+ case TR_ROLE_IDP:
+ tr_comm_add_idp_realm(ctab, comm, idp_realm, 0, prov, NULL); /* Expiry!? */
+ break;
+ case TR_ROLE_RP:
+ tr_comm_add_rp_realm(ctab, comm, rp_realm, 0, prov, NULL); /* Expiry!? */
+ break;
+ default:
+ return 2;
+ }
+
+ return 0;
+}
+
+static int add_member_set(TR_COMM_TABLE *ctab, struct comm_memb_entry *entries)
+{
+ struct comm_memb_entry *this=NULL;
+
+ for (this=entries; this->role!=TR_ROLE_UNKNOWN; this++) {
+ if (0!=add_comm_membership(ctab, this)) {
+ printf("Error adding %s realm %s to community %s (origin %s).\n",
+ (this->role==TR_ROLE_RP)?"RP":"IDP",
+ this->realm_name,
+ this->comm_name,
+ (this->origin!=NULL)?(this->origin):"null");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int remove_membership(TR_COMM_TABLE *ctab, struct comm_memb_entry *entries, size_t n)
+{
+ TR_NAME *realm_name=tr_new_name(entries[n].realm_name);
+ TR_NAME *comm_name=tr_new_name(entries[n].comm_name);
+ TR_NAME *origin=(entries[n].origin!=NULL)?(tr_new_name(entries[n].origin)):NULL;
+ TR_COMM_MEMB *memb=NULL;
+ int rc=-1;
+
+ switch (entries[n].role) {
+ case TR_ROLE_IDP:
+ memb=tr_comm_table_find_idp_memb_origin(ctab, realm_name, comm_name, origin);
+ break;
+ case TR_ROLE_RP:
+ memb=tr_comm_table_find_rp_memb_origin(ctab, realm_name, comm_name, origin);
+ break;
+ default:
+ rc=1;
+ goto cleanup;
+ }
+
+ if (memb==NULL) {
+ printf("%s realm %s not in comm %s from origin %s, can't remove membership.\n",
+ (entries[n].role==TR_ROLE_RP)?"RP":"IDP",
+ entries[n].realm_name,
+ entries[n].comm_name,
+ (entries[n].origin!=NULL)?(entries[n].origin):"null");
+ rc=2;
+ goto cleanup;
+ }
+ tr_comm_table_remove_memb(ctab, memb);
+ tr_comm_memb_free(memb);
+ rc=0;
+
+cleanup:
+ tr_free_name(realm_name);
+ tr_free_name(comm_name);
+ if (origin!=NULL)
+ tr_free_name(origin);
+ return rc;
+}
+
+/**********************************************************************/
+/* Test data */
+
+struct apc_entry apc_1={ "apc" };
+
+struct comm_entry comm_set_1[]={
+ { "apc", TR_COMM_APC, NULL },
+ { "comm 1", TR_COMM_COI, &apc_1 },
+ { "comm 2", TR_COMM_COI, &apc_1 },
+ { NULL }
+};
+
+struct rp_realm_entry rp_realm_set_1[]={
+ { "rp 1" },
+ { "rp 2" },
+ { "rp 3" },
+ { NULL }
+};
+
+struct aaa_entry aaa_1= { "aaa 1" };
+struct aaa_entry aaa_2= { "aaa 2" };
+struct aaa_entry aaa_3= { "aaa 3" };
+
+struct idp_realm_entry idp_realm_set_1[]={
+ { "idp 1", &aaa_1, &apc_1 },
+ { "idp 2", &aaa_2, &apc_1 },
+ { "idp 3", &aaa_3, &apc_1 },
+ { NULL }
+};
+
+struct comm_memb_entry member_set_1[]={
+ { TR_ROLE_RP, "rp 1", "apc", NULL },
+ { TR_ROLE_RP, "rp 2", "apc", NULL },
+ { TR_ROLE_RP, "rp 3", "apc", NULL },
+ { TR_ROLE_IDP, "idp 1", "apc", NULL },
+ { TR_ROLE_IDP, "idp 2", "apc", NULL },
+ { TR_ROLE_IDP, "idp 3", "apc", NULL },
+ { TR_ROLE_RP, "rp 1", "comm 1", NULL },
+ { TR_ROLE_RP, "rp 2", "comm 1", NULL },
+ { TR_ROLE_RP, "rp 2", "comm 1", "peer 1" },
+ { TR_ROLE_RP, "rp 2", "comm 1", "peer 2" },
+ { TR_ROLE_IDP, "idp 1", "comm 1", NULL },
+ { TR_ROLE_IDP, "idp 1", "comm 1", "peer 1" },
+ { TR_ROLE_IDP, "idp 1", "comm 1", "peer 2" },
+ { TR_ROLE_IDP, "idp 2", "comm 1", NULL },
+ { TR_ROLE_RP, "rp 1", "comm 2", NULL },
+ { TR_ROLE_RP, "rp 2", "comm 2", NULL },
+ { TR_ROLE_RP, "rp 2", "comm 2", "peer 1" },
+ { TR_ROLE_RP, "rp 2", "comm 2", "peer 2" },
+ { TR_ROLE_IDP, "idp 1", "comm 2", NULL },
+ { TR_ROLE_IDP, "idp 1", "comm 2", "peer 1" },
+ { TR_ROLE_IDP, "idp 1", "comm 2", "peer 2" },
+ { TR_ROLE_IDP, "idp 2", "comm 2", NULL },
+ { TR_ROLE_UNKNOWN }
+};
+
+
+/**********************************************************************/
+/* Test routines */
+
+/* the first few tests here insert a few things into the community table (comms,
+ * rp_realms, or idp_realms), then verify that they're all there. They
+ * then remove them in various orders, put them back, try removing
+ * things that are not present, etc. */
+
+static int community_test(void)
+{
+ TALLOC_CTX *mem_ctx=talloc_new(NULL);
+ TR_COMM_TABLE *ctab=tr_comm_table_new(mem_ctx);
+
+ assert(0==tr_comm_table_size(ctab));
+
+ /* add communities */
+ assert(ctab!=NULL);
+ assert(0==add_comm_set(ctab, comm_set_1));
+ assert(3==tr_comm_table_size(ctab));
+ assert(0==verify_comm_set(ctab, comm_set_1));
+
+ /* remove */
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 0));
+ assert(2==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 1));
+ assert(1==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 2));
+ assert(0==tr_comm_table_size(ctab));
+
+ /* add communities */
+ assert(ctab!=NULL);
+ assert(0==add_comm_set(ctab, comm_set_1));
+ assert(3==tr_comm_table_size(ctab));
+ assert(0==verify_comm_set(ctab, comm_set_1));
+
+ /* remove */
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 0));
+ assert(2==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 2));
+ assert(1==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 1));
+ assert(0==tr_comm_table_size(ctab));
+
+ /* add communities */
+ assert(ctab!=NULL);
+ assert(0==add_comm_set(ctab, comm_set_1));
+ assert(3==tr_comm_table_size(ctab));
+ assert(0==verify_comm_set(ctab, comm_set_1));
+
+ /* remove */
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 1));
+ assert(2==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 0));
+ assert(1==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 2));
+ assert(0==tr_comm_table_size(ctab));
+
+ assert(1==remove_comm_set_member(ctab, comm_set_1, 1)); /* should not be in the table */
+ assert(0==tr_comm_table_size(ctab));
+
+ /* add communities */
+ assert(ctab!=NULL);
+ assert(0==add_comm_set(ctab, comm_set_1));
+ assert(3==tr_comm_table_size(ctab));
+ assert(0==verify_comm_set(ctab, comm_set_1));
+
+ /* remove */
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 1));
+ assert(2==tr_comm_table_size(ctab));
+ assert(1==remove_comm_set_member(ctab, comm_set_1, 1)); /* should not be in the table */
+ assert(2==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 2));
+ assert(1==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 0));
+ assert(0==tr_comm_table_size(ctab));
+
+ /* add communities */
+ assert(ctab!=NULL);
+ assert(0==add_comm_set(ctab, comm_set_1));
+ assert(3==tr_comm_table_size(ctab));
+ assert(0==verify_comm_set(ctab, comm_set_1));
+
+ /* remove */
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 2));
+ assert(2==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 0));
+ assert(1==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 1));
+ assert(0==tr_comm_table_size(ctab));
+ assert(1==remove_comm_set_member(ctab, comm_set_1, 1)); /* should not be in the table */
+ assert(0==tr_comm_table_size(ctab));
+
+ /* add communities */
+ assert(ctab!=NULL);
+ assert(0==add_comm_set(ctab, comm_set_1));
+ assert(3==tr_comm_table_size(ctab));
+ assert(0==verify_comm_set(ctab, comm_set_1));
+
+ /* remove */
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 2));
+ assert(2==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 1));
+ assert(1==tr_comm_table_size(ctab));
+ assert(1==remove_comm_set_member(ctab, comm_set_1, 1)); /* should not be in the table */
+ assert(1==tr_comm_table_size(ctab));
+ assert(0==remove_comm_set_member(ctab, comm_set_1, 0));
+ assert(0==tr_comm_table_size(ctab));
+
+ talloc_free(mem_ctx);
+ return 0;
+}
+
+static int rp_realm_test(void)
+{
+ TALLOC_CTX *mem_ctx=talloc_new(NULL);
+ TR_COMM_TABLE *ctab=tr_comm_table_new(mem_ctx);
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_rp_realm_set(ctab, rp_realm_set_1));
+ assert(0==verify_rp_realm_set(ctab, rp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 0));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 2));
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_rp_realm_set(ctab, rp_realm_set_1));
+ assert(0==verify_rp_realm_set(ctab, rp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 0));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 2));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1));
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_rp_realm_set(ctab, rp_realm_set_1));
+ assert(0==verify_rp_realm_set(ctab, rp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 0));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 2));
+
+ assert(1==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1)); /* should not be in the table */
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_rp_realm_set(ctab, rp_realm_set_1));
+ assert(0==verify_rp_realm_set(ctab, rp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1));
+ assert(1==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1)); /* should not be in the table */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 2));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 0));
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_rp_realm_set(ctab, rp_realm_set_1));
+ assert(0==verify_rp_realm_set(ctab, rp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 2));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 0));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1));
+ assert(1==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1)); /* should not be in the table */
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_rp_realm_set(ctab, rp_realm_set_1));
+ assert(0==verify_rp_realm_set(ctab, rp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 2));
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1));
+ assert(1==remove_rp_realm_set_member(ctab, rp_realm_set_1, 1)); /* should not be in the table */
+ assert(0==remove_rp_realm_set_member(ctab, rp_realm_set_1, 0));
+
+ talloc_free(mem_ctx);
+ return 0;
+}
+
+static int idp_realm_test(void)
+{
+ TALLOC_CTX *mem_ctx=talloc_new(NULL);
+ TR_COMM_TABLE *ctab=tr_comm_table_new(mem_ctx);
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_idp_realm_set(ctab, idp_realm_set_1));
+ assert(0==verify_idp_realm_set(ctab, idp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 0));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 2));
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_idp_realm_set(ctab, idp_realm_set_1));
+ assert(0==verify_idp_realm_set(ctab, idp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 0));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 2));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1));
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_idp_realm_set(ctab, idp_realm_set_1));
+ assert(0==verify_idp_realm_set(ctab, idp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 0));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 2));
+
+ assert(1==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1)); /* should not be in the table */
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_idp_realm_set(ctab, idp_realm_set_1));
+ assert(0==verify_idp_realm_set(ctab, idp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1));
+ assert(1==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1)); /* should not be in the table */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 2));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 0));
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_idp_realm_set(ctab, idp_realm_set_1));
+ assert(0==verify_idp_realm_set(ctab, idp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 2));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 0));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1));
+ assert(1==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1)); /* should not be in the table */
+
+ /* add realms */
+ assert(ctab!=NULL);
+ assert(0==add_idp_realm_set(ctab, idp_realm_set_1));
+ assert(0==verify_idp_realm_set(ctab, idp_realm_set_1));
+
+ /* remove */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 2));
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1));
+ assert(1==remove_idp_realm_set_member(ctab, idp_realm_set_1, 1)); /* should not be in the table */
+ assert(0==remove_idp_realm_set_member(ctab, idp_realm_set_1, 0));
+
+ talloc_free(mem_ctx);
+ return 0;
+}
+
+static int membership_test(void)
+{
+ TALLOC_CTX *mem_ctx=talloc_new(NULL);
+ TR_COMM_TABLE *ctab=tr_comm_table_new(mem_ctx);
+ size_t ii=0;
+ size_t size=0;
+
+ assert(ctab!=NULL);
+ assert(0==add_comm_set(ctab, comm_set_1));
+ assert(0==add_rp_realm_set(ctab, rp_realm_set_1));
+ assert(0==add_idp_realm_set(ctab, idp_realm_set_1));
+ assert(0==add_member_set(ctab, member_set_1));
+
+ size=tr_comm_table_size(ctab);
+ tr_comm_table_sweep(ctab);
+ assert(size==tr_comm_table_size(ctab));
+
+ /* now remove memberships */
+ for (ii=0; member_set_1[ii].role!=TR_ROLE_UNKNOWN; ii++) {
+ assert(0==remove_membership(ctab, member_set_1, ii));
+ assert(2==remove_membership(ctab, member_set_1, ii)); /* should not be in the table */
+ }
+
+ assert(NULL==ctab->memberships);
+
+ /* put them back */
+ assert(0==add_member_set(ctab, member_set_1));
+ /* tr_comm_table_print(stdout, ctab); */
+
+ tr_comm_table_sweep(ctab);
+ assert(size==tr_comm_table_size(ctab));
+
+ /* remove in the reverse order */
+ for(; ii>0; ii--) {
+ assert(0==remove_membership(ctab, member_set_1, ii-1));
+ assert(2==remove_membership(ctab, member_set_1, ii-1)); /* should not be in the table */
+ /* tr_comm_table_print(stdout, ctab); */
+ }
+
+ assert(NULL==ctab->memberships);
+
+ assert(size==tr_comm_table_size(ctab));
+ tr_comm_table_sweep(ctab);
+ assert(0==tr_comm_table_size(ctab));
+
+ talloc_free(mem_ctx);
+ return 0;
+}
+
+
+/**********************************************************************/
+/* main */
+int main(void)
+{
+ assert(0==community_test());
+ printf("Community tests passed.\n");
+ assert(0==rp_realm_test());
+ printf("RP realm tests passed.\n");
+ assert(0==idp_realm_test());
+ printf("IDP realm tests passed.\n");
+ assert(0==membership_test());
+ printf("Membership tests passed.\n");
+ return 0;
+}
--- /dev/null
+{
+ "communities": [
+ {
+ "apcs": [],
+ "community_id": "apc.example.com",
+ "idp_realms": ["A.idp.cfg"],
+ "rp_realms": ["A.idp.cfg"],
+ "type": "apc"
+ }
+ ],
+ "local_organizations": [
+ {"organization_name": "idp.cfg test org",
+ "realms": [
+ {
+ "realm": "A.idp.cfg",
+ "identity_provider": {
+ "aaa_servers": ["rad1.A.idp.cfg",
+ "rad2.A.idp.cfg"],
+ "apcs": ["apc.example.com"],
+ "shared_config": "no"
+ },
+ "gss_names": ["gss@example.com"]
+ }
+ ]
+ }
+ ]
+}
mq->notify_cb_arg=mq_name;
msg1=tr_mq_msg_new(NULL,"Message 1", TR_MQ_PRIO_NORMAL);
- assert(asprintf((char **)&(msg2->p), "First message.\n")!=-1);
+ assert(asprintf((char **)&(msg1->p), "First message.\n")!=-1);
msg1->p_free=free;
tr_mq_add(mq, msg1);
assert(mq->head==msg1);
assert(mq->tail==msg2);
assert(msg2->next==NULL);
- msg=tr_mq_pop(mq);
+ msg=tr_mq_pop(mq, NULL);
assert(msg==msg1);
assert(mq->head==msg2);
assert(mq->tail==msg2);
printf("no message to pop\n");
msg3=tr_mq_msg_new(NULL, "Message 3", TR_MQ_PRIO_NORMAL);
- assert(asprintf("%s",(char **)&(msg3->p), "Third message.\n")!=-1);
+ assert(asprintf((char **)&(msg3->p), "%s", "Third message.\n")!=-1);
msg3->p_free=free;
tr_mq_add(mq, msg3);
assert(mq->head==msg2);
assert(msg2->next==msg3);
assert(msg3->next==NULL);
- msg=tr_mq_pop(mq);
+ msg=tr_mq_pop(mq, NULL);
assert(msg==msg2);
assert(mq->head==msg3);
assert(mq->tail==msg3);
} else
printf("no message to pop\n");
- msg=tr_mq_pop(mq);
+ msg=tr_mq_pop(mq, NULL);
assert(msg==msg3);
assert(mq->head==NULL);
assert(mq->tail==NULL);
} else
printf("no message to pop\n");
- msg=tr_mq_pop(mq);
+ msg=tr_mq_pop(mq, NULL);
assert(msg==NULL);
assert(mq->head==NULL);
assert(mq->tail==NULL);
printf("no message to pop\n");
msg4=tr_mq_msg_new(NULL, "Message 4", TR_MQ_PRIO_NORMAL);
- assert(asprintf("%s",(char **)&(msg4->p), "Fourth message.\n")!=-1);
+ assert(asprintf((char **)&(msg4->p), "%s", "Fourth message.\n")!=-1);
msg4->p_free=free;
tr_mq_add(mq, msg4);
assert(mq->head==msg4);
assert(mq->tail==msg4);
assert(msg4->next==NULL);
- msg=tr_mq_pop(mq);
+ msg=tr_mq_pop(mq, NULL);
assert(msg==msg4);
assert(mq->head==NULL);
assert(mq->tail==NULL);
} else
printf("no message to pop\n");
- msg=tr_mq_pop(mq);
+ msg=tr_mq_pop(mq, NULL);
assert(msg==NULL);
assert(mq->head==NULL);
assert(mq->tail==NULL);
tr_mq_free(mq);
+ printf("success\n");
return 0;
}
#include <talloc.h>
#include <time.h>
#include <errno.h>
+#include <assert.h>
#include <tr_mq.h>
char *label;
};
-TR_MQ_MSG *make_msg(label, n)
+static TR_MQ_MSG *make_msg(char *label, int n)
{
TR_MQ_MSG *msg=NULL;
msg=tr_mq_msg_new(NULL, "Message", TR_MQ_PRIO_NORMAL);
- asprintf((char **)&(msg->p), "%s: %d messages to go...", label, n);
+ assert(-1!=asprintf((char **)&(msg->p), "%s: %d messages to go...", label, n));
msg->p_free=free;
return msg;
}
-void *thread_start(void *arg)
+static void *thread_start(void *arg)
{
TR_MQ *mq=((struct thread_data *)arg)->mq;
int n_msgs=((struct thread_data *)arg)->n_msgs;
useconds_t msg_dly=((struct thread_data *)arg)->msg_dly;
- const char *label=((struct thread_data *)arg)->label;
+ char *label=((struct thread_data *)arg)->label;
while (n_msgs>=0) {
usleep(msg_dly);
int ready;
};
-void handle_messages(TR_MQ *mq, void *arg)
+static void handle_messages(TR_MQ *mq, void *arg)
{
struct message_data *status=(struct message_data *)arg;
pthread_mutex_lock(&(status->lock));
pthread_mutex_unlock(&(status->lock));
}
-void output_messages(TR_MQ *mq)
+static void output_messages(TR_MQ *mq)
{
TR_MQ_MSG *msg=NULL;
printf("\n* handle_messages notified of new messages in queue.\n");
- for (msg=tr_mq_pop(mq); msg!=NULL; msg=tr_mq_pop(mq)) {
+ for (msg=tr_mq_pop(mq, NULL); msg!=NULL; msg=tr_mq_pop(mq, NULL)) {
printf(" > %s\n", (char *)msg->p);
tr_mq_msg_free(msg);
}
thread_data[ii].mq=mq;
thread_data[ii].msg_dly=dly[ii];
thread_data[ii].n_msgs=10;
- asprintf(&(thread_data[ii].label), "thread %d", ii+1);
+ assert(-1!=asprintf(&(thread_data[ii].label), "thread %d", ii+1));
pthread_create(&(thread[ii]), NULL, thread_start, &thread_data[ii]);
printf("%s started.\n", thread_data[ii].label);
}
for (ii=0; ii<N_THREADS; ii++)
pthread_join(thread[ii], NULL);
+ printf("success\n");
return 0;
}
#include <trust_router/tr_name.h>
#include <tr_apc.h>
+#include <tr_debug.h>
static int tr_apc_destructor(void *obj)
{
return apc;
}
-TR_APC *tr_apc_add(TR_APC *head, TR_APC *new)
+/* do not call this directly, use the tr_apc_add() macro */
+TR_APC *tr_apc_add_func(TR_APC *head, TR_APC *new)
{
if (head==NULL)
head=new;
}
/* does not copy next pointer */
-TR_APC *tr_apc_dup(TALLOC_CTX *mem_ctx, TR_APC *apc)
+TR_APC *tr_apc_dup_one(TALLOC_CTX *mem_ctx, TR_APC *apc)
{
TR_APC *new=tr_apc_new(mem_ctx);
- tr_apc_set_id(new, tr_apc_dup_id(apc));
+ if (new!=NULL)
+ tr_apc_set_id(new, tr_apc_dup_id(apc));
+ return new;
+}
+
+/* copies next pointer */
+TR_APC *tr_apc_dup(TALLOC_CTX *mem_ctx, TR_APC *apc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_APC *cur=NULL;
+ TR_APC *new=NULL;
+
+ if (apc==NULL)
+ return NULL;
+
+ if (NULL==(new=tr_apc_dup_one(tmp_ctx, apc)))
+ return NULL;
+
+ for (cur=new,apc=apc->next; apc!=NULL; cur=cur->next,apc=apc->next) {
+ cur->next=tr_apc_dup_one(new, apc);
+ if (cur->next==NULL) {
+ new=NULL;
+ goto cleanup;
+ }
+ }
+
+ talloc_steal(mem_ctx, new);
+
+cleanup:
+ talloc_free(tmp_ctx);
return new;
}
TR_NAME *tr_apc_dup_id(TR_APC *apc)
{
- return tr_dup_name(apc->id);;
+ return tr_dup_name(apc->id);
}
{
return talloc_strndup(mem_ctx, apc->id->buf, apc->id->len);
}
+
+TR_APC_ITER *tr_apc_iter_new(TALLOC_CTX *mem_ctx)
+{
+ return talloc(mem_ctx, TR_APC_ITER);
+}
+
+TR_APC *tr_apc_iter_first(TR_APC_ITER *iter, TR_APC *apc)
+{
+ *iter=apc;
+ return *iter;
+}
+
+TR_APC *tr_apc_iter_next(TR_APC_ITER *iter)
+{
+ (*iter)=(*iter)->next;
+ return *iter;
+}
+
+void tr_apc_iter_free(TR_APC_ITER *iter)
+{
+ talloc_free(iter);
+}
+
+/* 1 on match, 0 on no match, -1 on error */
+int tr_apc_in_common(TR_APC *one, TR_APC *two)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_APC_ITER *i_one=tr_apc_iter_new(tmp_ctx);
+ TR_APC_ITER *i_two=tr_apc_iter_new(tmp_ctx);
+ TR_APC *cur_one=NULL;
+ TR_APC *cur_two=NULL;
+
+ if ((i_one==NULL) || (i_two==NULL)) {
+ tr_err("tr_apc_in_common: unable to allocate iterators.");
+ talloc_free(tmp_ctx);
+ return -1;
+ }
+ for (cur_one=tr_apc_iter_first(i_one, one); cur_one!=NULL; cur_one=tr_apc_iter_next(i_one)) {
+ for (cur_two=tr_apc_iter_first(i_two, two); cur_two!=NULL; cur_two=tr_apc_iter_next(i_two)) {
+ if (cur_one==cur_two)
+ return 1;
+ }
+ }
+ return 0;
+}
*
*/
+#include <stdio.h>
+#include <jansson.h>
#include <talloc.h>
+#include <sys/time.h>
#include <tr_rp.h>
+#include <tr_idp.h>
#include <trust_router/tr_name.h>
#include <tr_comm.h>
#include <tr_debug.h>
+
static int tr_comm_destructor(void *obj)
{
TR_COMM *comm=talloc_get_type_abort(obj, TR_COMM);
if (comm->id!=NULL)
tr_free_name(comm->id);
+ if (comm->owner_realm!=NULL)
+ tr_free_name(comm->owner_realm);
+ if (comm->owner_contact!=NULL)
+ tr_free_name(comm->owner_contact);
return 0;
}
comm->id=NULL;
comm->type=TR_COMM_UNKNOWN;
comm->apcs=NULL;
- comm->idp_realms=NULL;
- comm->rp_realms=NULL;
+ comm->owner_realm=NULL;
+ comm->owner_contact=NULL;
+ comm->expiration_interval=0;
+ comm->refcount=0;
talloc_set_destructor((void *)comm, tr_comm_destructor);
}
return comm;
talloc_free(comm);
}
+void tr_comm_set_id(TR_COMM *comm, TR_NAME *id)
+{
+ if (comm->id != NULL)
+ tr_free_name(comm->id);
+ comm->id=id;
+}
+
+void tr_comm_incref(TR_COMM *comm)
+{
+ comm->refcount++;
+}
+
+void tr_comm_decref(TR_COMM *comm)
+{
+ if (comm->refcount>0)
+ comm->refcount--;
+}
+
+void tr_comm_set_apcs(TR_COMM *comm, TR_APC *apc)
+{
+ if (comm->apcs!=NULL)
+ tr_apc_free(comm->apcs);
+ comm->apcs=apc;
+ talloc_steal(comm, apc);
+}
+
+TR_APC *tr_comm_get_apcs(TR_COMM *comm)
+{
+ return comm->apcs;
+}
+
+TR_NAME *tr_comm_get_id(TR_COMM *comm)
+{
+ return comm->id;
+}
+
+TR_NAME *tr_comm_dup_id(TR_COMM *comm)
+{
+ return tr_dup_name(comm->id);
+}
+
+void tr_comm_set_type(TR_COMM *comm, TR_COMM_TYPE type)
+{
+ comm->type=type;
+}
+
+TR_COMM_TYPE tr_comm_get_type(TR_COMM *comm)
+{
+ return comm->type;
+}
+
+void tr_comm_set_owner_realm(TR_COMM *comm, TR_NAME *realm)
+{
+ if (comm->owner_realm!=NULL)
+ tr_free_name(comm->owner_realm);
+ comm->owner_realm=realm;
+}
+
+TR_NAME *tr_comm_get_owner_realm(TR_COMM *comm)
+{
+ return comm->owner_realm;
+}
+
+TR_NAME *tr_comm_dup_owner_realm(TR_COMM *comm)
+{
+ return tr_dup_name(comm->owner_realm);
+}
+
+void tr_comm_set_owner_contact(TR_COMM *comm, TR_NAME *contact)
+{
+ if (comm->owner_contact != NULL)
+ tr_free_name(comm->owner_contact);
+ comm->owner_contact=contact;
+}
+
+TR_NAME *tr_comm_get_owner_contact(TR_COMM *comm)
+{
+ return comm->owner_contact;
+}
+
+TR_NAME *tr_comm_dup_owner_contact(TR_COMM *comm)
+{
+ return tr_dup_name(comm->owner_contact);
+}
+
+unsigned int tr_comm_get_refcount(TR_COMM *comm)
+{
+ return comm->refcount;
+}
+
+/* 0 if equivalent, nonzero if different, only considers
+ * nhops last hops (nhops==0 means consider all, nhops==1
+ * only considers last hop) */
+static int tr_comm_memb_provenance_cmp(TR_COMM_MEMB *m1, TR_COMM_MEMB *m2, int nhops)
+{
+ size_t ii;
+
+ if ((m1->provenance==NULL) || (m2->provenance==NULL))
+ return m1->provenance!=m2->provenance; /* return 0 if both null, 1 if only one null */
+
+ if (json_array_size(m1->provenance)!=json_array_size(m2->provenance))
+ return 1;
+
+ if (nhops==0)
+ nhops=json_array_size(m1->provenance); /* same as size(m2->provenance) */
+
+ for (ii=0; ii<json_array_size(m1->provenance); ii++) {
+ if (0==strcmp(json_string_value(json_array_get(m1->provenance, ii)),
+ json_string_value(json_array_get(m2->provenance, ii)))) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Accepts an update that either came from the same peer as the previous
+ * origin, has a shorter provenance list, or can replace an expired
+ * membership. Otherwise keeps the existing one.
+ * On replacement, frees the old member and moves new member to ctab's
+ * context. Caller should not free newmemb except by freeing its original
+ * context. */
+static void tr_comm_add_if_shorter(TR_COMM_TABLE *ctab, TR_COMM_MEMB *existing, TR_COMM_MEMB *newmemb)
+{
+ int accept=0;
+
+ if (existing==NULL) {
+ /* not in the table */
+ tr_comm_table_add_memb(ctab, newmemb);
+ } else {
+ if (0==tr_comm_memb_provenance_cmp(existing, newmemb, 1))
+ accept=1; /* always accept a replacement from the same peer */
+ else if (tr_comm_memb_provenance_len(newmemb) < tr_comm_memb_provenance_len(existing))
+ accept=1; /* accept a shorter provenance */
+ else if (existing->times_expired>0)
+ accept=1;
+ else
+ accept=0;
+
+ if (accept) {
+ tr_comm_table_remove_memb(ctab, existing);
+ tr_comm_memb_free(existing);
+ tr_comm_table_add_memb(ctab, newmemb);
+ }
+ }
+}
+
/* does not take responsibility for freeing IDP realm */
-void tr_comm_add_idp_realm(TR_COMM *comm, TR_IDP_REALM *realm)
+void tr_comm_add_idp_realm(TR_COMM_TABLE *ctab,
+ TR_COMM *comm,
+ TR_IDP_REALM *realm,
+ unsigned int interval,
+ json_t *provenance,
+ struct timespec *expiry)
{
- TR_IDP_REALM *cur=NULL;
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_COMM_MEMB *newmemb=tr_comm_memb_new(tmp_ctx);
+ TR_COMM_MEMB *existing=NULL;
- if (comm->idp_realms==NULL)
- comm->idp_realms=realm;
- else {
- for (cur=comm->idp_realms; cur->comm_next!=NULL; cur=cur->comm_next) { }
- cur->comm_next=realm;
+ if (newmemb==NULL) {
+ tr_err("tr_comm_add_idp_realm: unable to allocate new membership record.");
+ talloc_free(tmp_ctx);
+ return;
}
+
+ tr_comm_memb_set_idp_realm(newmemb, realm);
+ tr_comm_memb_set_comm(newmemb, comm);
+ tr_comm_memb_set_interval(newmemb, interval);
+ tr_comm_memb_set_provenance(newmemb, provenance);
+ tr_comm_memb_set_expiry(newmemb, expiry);
+
+ existing=tr_comm_table_find_idp_memb_origin(ctab,
+ tr_idp_realm_get_id(realm),
+ tr_comm_get_id(comm),
+ tr_comm_memb_get_origin(newmemb));
+ tr_comm_add_if_shorter(ctab, existing, newmemb); /* takes newmemb out of tmp_ctx if needed */
+
+ talloc_free(tmp_ctx);
}
/* does not take responsibility for freeing RP realm */
-void tr_comm_add_rp_realm(TR_COMM *comm, TR_RP_REALM *realm)
+void tr_comm_add_rp_realm(TR_COMM_TABLE *ctab,
+ TR_COMM *comm,
+ TR_RP_REALM *realm,
+ unsigned int interval,
+ json_t *provenance,
+ struct timespec *expiry)
{
- TR_RP_REALM *cur=NULL;
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_COMM_MEMB *newmemb=tr_comm_memb_new(tmp_ctx);
+ TR_COMM_MEMB *existing=NULL;
- if (comm->rp_realms==NULL)
- comm->rp_realms=realm;
- else {
- for (cur=comm->rp_realms; cur->next!=NULL; cur=cur->next) { }
- cur->next=realm;
+ if (newmemb==NULL) {
+ tr_err("tr_comm_add_idp_realm: unable to allocate new membership record.");
+ talloc_free(tmp_ctx);
+ return;
}
+
+ tr_comm_memb_set_rp_realm(newmemb, realm);
+ tr_comm_memb_set_comm(newmemb, comm);
+ tr_comm_memb_set_interval(newmemb, interval);
+ tr_comm_memb_set_provenance(newmemb, provenance);
+ tr_comm_memb_set_expiry(newmemb, expiry);
+
+ existing=tr_comm_table_find_rp_memb_origin(ctab,
+ tr_rp_realm_get_id(realm),
+ tr_comm_get_id(comm),
+ tr_comm_memb_get_origin(newmemb));
+ tr_comm_add_if_shorter(ctab, existing, newmemb); /* takes newmemb out of tmp_ctx if needed */
+ talloc_free(tmp_ctx);
}
static TR_COMM *tr_comm_tail(TR_COMM *comm)
/* All list members are in the talloc context of the head.
* This will require careful thought if entries are ever removed
- * or shuffled between lists.
- * Call like comms=tr_comm_add(comms, new_comm); */
-TR_COMM *tr_comm_add(TR_COMM *comms, TR_COMM *new)
+ * Call like comms=tr_comm_add_func(comms, new_comm);
+ * or just use the tr_comm_add(comms, new) macro. */
+#define tr_comm_add(comms, new) ((comms)=tr_comm_add_func((comms), (new)))
+static TR_COMM *tr_comm_add_func(TR_COMM *comms, TR_COMM *new)
{
if (comms==NULL)
comms=new;
return comms;
}
-TR_IDP_REALM *tr_find_comm_idp (TR_COMM *comm, TR_NAME *idp_realm)
+/* Guarantees comm is not in the list, not an error if it was't there.
+ * Does not free the removed element, nor change its talloc context. */
+#define tr_comm_remove(comms, c) ((comms)=tr_comm_remove_func((comms), (c)))
+static TR_COMM *tr_comm_remove_func(TR_COMM *comms, TR_COMM *remove)
+{
+ TALLOC_CTX *list_ctx=talloc_parent(comms); /* in case we need to remove the head */
+ TR_COMM *this=NULL;
+
+ if (comms==NULL)
+ return NULL;
+
+ if (comms==remove) {
+ /* if we're removing the head, put the next element (if present) into the context
+ * the list head was in. */
+ comms=comms->next;
+ if (comms!=NULL) {
+ talloc_steal(list_ctx, comms);
+ /* now put all the other elements in the context of the list head */
+ for (this=comms->next; this!=NULL; this=this->next)
+ talloc_steal(comms, this);
+ }
+ } else {
+ /* not removing the head; no need to play with contexts */
+ for (this=comms; this->next!=NULL; this=this->next) {
+ if (this->next==remove) {
+ this->next=remove->next;
+ break;
+ }
+ }
+ }
+ return comms;
+}
+
+/* remove any with zero refcount
+ * Call via macro. */
+#define tr_comm_sweep(head) ((head)=tr_comm_sweep_func((head)))
+static TR_COMM *tr_comm_sweep_func(TR_COMM *head)
{
- TR_IDP_REALM *idp;
+ TR_COMM *comm=NULL;
+ TR_COMM *old_next=NULL;
- if ((!comm) || (!idp_realm)) {
+ if (head==NULL)
return NULL;
+
+ while ((head!=NULL) && (head->refcount==0)) {
+ comm=head; /* keep a pointer so we can remove it */
+ tr_comm_remove(head, comm); /* use this to get talloc contexts right */
+ tr_comm_free(comm);
}
- for (idp = comm->idp_realms; NULL != idp; idp = idp->comm_next) {
- if (!tr_name_cmp (idp_realm, idp->realm_id)) {
- tr_debug("tr_find_comm_idp: Found IdP %s in community %s.", idp_realm->buf, comm->id->buf);
- return idp;
+ if (head==NULL)
+ return NULL;
+
+ /* will not remove the head here, that has already been done */
+ for (comm=head; comm->next!=NULL; comm=comm->next) {
+ if (comm->next->refcount==0) {
+ old_next=comm->next;
+ tr_comm_remove(head, comm->next); /* changes comm->next */
+ tr_comm_free(old_next);
}
}
- /* if we didn't find one, return NULL */
+
+ return head;
+}
+
+TR_IDP_REALM *tr_comm_find_idp(TR_COMM_TABLE *ctab, TR_COMM *comm, TR_NAME *idp_realm)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_COMM_ITER *iter=NULL;
+ TR_IDP_REALM *this_idp=NULL;
+
+ if ((NULL==ctab) || (NULL==comm) || (NULL==idp_realm)) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+
+ iter=tr_comm_iter_new(tmp_ctx);
+ for (this_idp=tr_idp_realm_iter_first(iter, ctab, tr_comm_get_id(comm));
+ this_idp!=NULL;
+ this_idp=tr_idp_realm_iter_next(iter)) {
+ if (0==tr_name_cmp(idp_realm, tr_idp_realm_get_id(this_idp))) {
+ tr_debug("tr_comm_find_idp: Found IdP %s in community %s.", idp_realm->buf, tr_comm_get_id(comm)->buf);
+ talloc_free(tmp_ctx);
+ return this_idp;
+ }
+ }
+ tr_debug("tr_comm_find_idp: Unable to find IdP %s in community %s.", idp_realm->buf, tr_comm_get_id(comm)->buf);
+ talloc_free(tmp_ctx);
return NULL;
}
-TR_RP_REALM *tr_find_comm_rp (TR_COMM *comm, TR_NAME *rp_realm)
+TR_RP_REALM *tr_comm_find_rp (TR_COMM_TABLE *ctab, TR_COMM *comm, TR_NAME *rp_realm)
{
- TR_RP_REALM *rp;
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_COMM_ITER *iter=NULL;
+ TR_RP_REALM *this_rp=NULL;
- if ((!comm) || (!rp_realm)) {
+ if ((NULL==ctab) || (NULL==comm) || (NULL==rp_realm)) {
+ talloc_free(tmp_ctx);
return NULL;
}
- for (rp = comm->rp_realms; NULL != rp; rp = rp->next) {
- if (!tr_name_cmp (rp_realm, rp->realm_name)) {
- tr_debug("tr_find_comm_rp: Found RP %s in community %s.", rp_realm->buf, comm->id->buf);
- return rp;
+ iter=tr_comm_iter_new(tmp_ctx);
+ for (this_rp=tr_rp_realm_iter_first(iter, ctab, tr_comm_get_id(comm));
+ this_rp!=NULL;
+ this_rp=tr_rp_realm_iter_next(iter)) {
+ if (0==tr_name_cmp(rp_realm, tr_rp_realm_get_id(this_rp))) {
+ tr_debug("tr_comm_find_rp: Found RP %s in community %s.", rp_realm->buf, tr_comm_get_id(comm)->buf);
+ talloc_free(tmp_ctx);
+ return this_rp;
}
}
- /* if we didn't find one, return NULL */
+ tr_debug("tr_comm_find_rp: Unable to find RP %s in community %s.", rp_realm->buf, tr_comm_get_id(comm)->buf);
+ talloc_free(tmp_ctx);
return NULL;
}
-TR_COMM *tr_comm_lookup(TR_COMM *comms, TR_NAME *comm_name)
+static TR_COMM *tr_comm_lookup(TR_COMM *comms, TR_NAME *comm_name)
{
TR_COMM *cfg_comm = NULL;
for (cfg_comm = comms; NULL != cfg_comm; cfg_comm = cfg_comm->next) {
- if ((cfg_comm->id->len == comm_name->len) &&
- (!strncmp(cfg_comm->id->buf, comm_name->buf, comm_name->len)))
+ if (0==tr_name_cmp(cfg_comm->id, comm_name))
return cfg_comm;
}
return NULL;
}
+
+TR_COMM_ITER *tr_comm_iter_new(TALLOC_CTX *mem_ctx)
+{
+ TR_COMM_ITER *iter=talloc(mem_ctx, TR_COMM_ITER);
+ if (iter!=NULL) {
+ iter->cur_comm=NULL;
+ iter->cur_memb=NULL;
+ iter->cur_orig_head=NULL;
+ iter->match=NULL;
+ iter->realm=NULL;
+ }
+ return iter;
+}
+
+void tr_comm_iter_free(TR_COMM_ITER *iter)
+{
+ talloc_free(iter);
+}
+
+
+TR_COMM *tr_comm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *realm)
+{
+ iter->match=realm;
+
+ /* find memberships for this realm */
+ for (iter->cur_memb=ctab->memberships;
+ iter->cur_memb!=NULL;
+ iter->cur_memb=iter->cur_memb->next) {
+ if (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb)))
+ return tr_comm_memb_get_comm(iter->cur_memb);
+ }
+ return NULL;
+}
+
+TR_COMM *tr_comm_iter_next(TR_COMM_ITER *iter)
+{
+ for (iter->cur_memb=iter->cur_memb->next;
+ iter->cur_memb!=NULL;
+ iter->cur_memb=iter->cur_memb->next) {
+ if (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb)))
+ return tr_comm_memb_get_comm(iter->cur_memb);
+ }
+ return NULL;
+}
+
+/* iterate only over RPs */
+TR_COMM *tr_comm_iter_first_rp(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *realm)
+{
+ iter->match=realm;
+
+ /* find memberships for this realm */
+ for (iter->cur_memb=ctab->memberships;
+ iter->cur_memb!=NULL;
+ iter->cur_memb=iter->cur_memb->next) {
+ if ((tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL) &&
+ (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb))))
+ return tr_comm_memb_get_comm(iter->cur_memb);
+ }
+ return NULL;
+}
+
+TR_COMM *tr_comm_iter_next_rp(TR_COMM_ITER *iter)
+{
+ for (iter->cur_memb=iter->cur_memb->next;
+ iter->cur_memb!=NULL;
+ iter->cur_memb=iter->cur_memb->next) {
+ if ((tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL) &&
+ (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb))))
+ return tr_comm_memb_get_comm(iter->cur_memb);
+ }
+ return NULL;
+}
+
+/* iterate only over IDPs */
+TR_COMM *tr_comm_iter_first_idp(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *realm)
+{
+ iter->match=realm;
+
+ /* find memberships for this realm */
+ for (iter->cur_memb=ctab->memberships;
+ iter->cur_memb!=NULL;
+ iter->cur_memb=iter->cur_memb->next) {
+ if ((tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL) &&
+ (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb))))
+ return tr_comm_memb_get_comm(iter->cur_memb);
+ }
+ return NULL;
+}
+
+TR_COMM *tr_comm_iter_next_idp(TR_COMM_ITER *iter)
+{
+ for (iter->cur_memb=iter->cur_memb->next;
+ iter->cur_memb!=NULL;
+ iter->cur_memb=iter->cur_memb->next) {
+ if ((tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL) &&
+ (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb))))
+ return tr_comm_memb_get_comm(iter->cur_memb);
+ }
+ return NULL;
+}
+
+static TR_REALM *tr_realm_new(TALLOC_CTX *mem_ctx)
+{
+ TR_REALM *realm=talloc(mem_ctx, TR_REALM);
+ if (realm!=NULL) {
+ realm->role=TR_ROLE_UNKNOWN;
+ realm->rp=NULL;
+ realm->idp=NULL;
+ }
+ return realm;
+}
+
+static void tr_realm_free(TR_REALM *realm)
+{
+ talloc_free(realm);
+}
+
+static void tr_realm_set_rp(TR_REALM *realm, TR_RP_REALM *rp)
+{
+ if (realm->idp!=NULL)
+ realm->idp=NULL;
+ realm->role=TR_ROLE_RP;
+ realm->rp=rp;
+}
+
+static void tr_realm_set_idp(TR_REALM *realm, TR_IDP_REALM *idp)
+{
+ if (realm->rp!=NULL)
+ realm->rp=NULL;
+ realm->role=TR_ROLE_IDP;
+ realm->idp=idp;
+}
+
+TR_NAME *tr_realm_get_id(TR_REALM *realm)
+{
+ switch (realm->role) {
+ case TR_ROLE_RP:
+ return tr_rp_realm_get_id(realm->rp);
+ case TR_ROLE_IDP:
+ return tr_idp_realm_get_id(realm->idp);
+ default:
+ break;
+ }
+ return NULL;
+}
+
+TR_NAME *tr_realm_dup_id(TR_REALM *realm)
+{
+ return tr_dup_name(tr_realm_get_id(realm));
+}
+
+/* Iterate over either sort of realm. Do not free the TR_REALM returned. It becomes
+ * undefined/invalid after the next operation affecting the iterator. */
+TR_REALM *tr_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm)
+{
+ iter->match=comm;
+ if (iter->realm==NULL)
+ iter->realm=tr_realm_new(iter);
+ if (iter->realm==NULL)
+ return NULL;
+
+ /* find memberships for this comm */
+ for (iter->cur_memb=ctab->memberships;
+ iter->cur_memb!=NULL;
+ iter->cur_memb=iter->cur_memb->next) {
+ if (0==tr_name_cmp(iter->match,
+ tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))) {
+ /* found a match, determine whether it's an rp realm or an idp realm */
+ if (tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL)
+ tr_realm_set_rp(iter->realm, tr_comm_memb_get_rp_realm(iter->cur_memb));
+ else if (tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL)
+ tr_realm_set_idp(iter->realm, tr_comm_memb_get_idp_realm(iter->cur_memb));
+ else {
+ if (iter->realm!=NULL)
+ tr_realm_free(iter->realm);
+ iter->realm=NULL;
+ }
+ return iter->realm;
+ }
+ }
+ if (iter->realm!=NULL)
+ tr_realm_free(iter->realm);
+ iter->realm=NULL;
+ return NULL;
+}
+
+TR_REALM *tr_realm_iter_next(TR_COMM_ITER *iter)
+{
+ if (iter->realm==NULL)
+ return NULL;
+
+ /* find memberships for this comm */
+ for (iter->cur_memb=iter->cur_memb->next;
+ iter->cur_memb!=NULL;
+ iter->cur_memb=iter->cur_memb->next) {
+ if (0==tr_name_cmp(iter->match,
+ tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))) {
+ /* found a match, determine whether it's an rp realm or an idp realm */
+ if (tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL)
+ tr_realm_set_rp(iter->realm, tr_comm_memb_get_rp_realm(iter->cur_memb));
+ else if (tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL)
+ tr_realm_set_idp(iter->realm, tr_comm_memb_get_idp_realm(iter->cur_memb));
+ else {
+ if (iter->realm!=NULL)
+ tr_realm_free(iter->realm);
+ iter->realm=NULL;
+ }
+ return iter->realm;
+ }
+ }
+ if (iter->realm!=NULL)
+ tr_realm_free(iter->realm);
+ iter->realm=NULL;
+ return NULL;
+}
+
+TR_RP_REALM *tr_rp_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm)
+{
+ iter->match=comm;
+
+ /* find memberships for this comm */
+ for (iter->cur_memb=ctab->memberships;
+ iter->cur_memb!=NULL;
+ iter->cur_memb=iter->cur_memb->next) {
+ if ((tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL) &&
+ (0==tr_name_cmp(iter->match, tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))))
+ return tr_comm_memb_get_rp_realm(iter->cur_memb);
+ }
+ return NULL;
+}
+
+TR_RP_REALM *tr_rp_realm_iter_next(TR_COMM_ITER *iter)
+{
+ for (iter->cur_memb=iter->cur_memb->next;
+ iter->cur_memb!=NULL;
+ iter->cur_memb=iter->cur_memb->next) {
+ if ((tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL) &&
+ (0==tr_name_cmp(iter->match, tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))))
+ return tr_comm_memb_get_rp_realm(iter->cur_memb);
+ }
+ return NULL;
+}
+
+TR_IDP_REALM *tr_idp_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm)
+{
+ iter->match=comm;
+
+ /* find memberships for this comm */
+ for (iter->cur_memb=ctab->memberships;
+ iter->cur_memb!=NULL;
+ iter->cur_memb=iter->cur_memb->next) {
+ if ((tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL) &&
+ (0==tr_name_cmp(iter->match, tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))))
+ return tr_comm_memb_get_idp_realm(iter->cur_memb);
+ }
+ return NULL;
+}
+
+TR_IDP_REALM *tr_idp_realm_iter_next(TR_COMM_ITER *iter)
+{
+ for (iter->cur_memb=iter->cur_memb->next;
+ iter->cur_memb!=NULL;
+ iter->cur_memb=iter->cur_memb->next) {
+ if ((tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL) &&
+ (0==tr_name_cmp(iter->match, tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))))
+ return tr_comm_memb_get_idp_realm(iter->cur_memb);
+ }
+ return NULL;
+}
+
+/* iterators for all communities in a table */
+TR_COMM *tr_comm_table_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab)
+{
+ iter->cur_comm=ctab->comms;
+ return iter->cur_comm;
+}
+
+TR_COMM *tr_comm_table_iter_next(TR_COMM_ITER *iter)
+{
+ return iter->cur_comm=iter->cur_comm->next;
+}
+
+const char *tr_comm_type_to_str(TR_COMM_TYPE type)
+{
+ const char *s=NULL;
+ switch(type) {
+ case TR_COMM_UNKNOWN:
+ s="unknown";
+ break;
+ case TR_COMM_APC:
+ s="apc";
+ break;
+ case TR_COMM_COI:
+ s="coi";
+ break;
+ default:
+ s="invalid";
+ }
+ return s;
+}
+
+/* iterate along the origin list for this member */
+TR_COMM_MEMB *tr_comm_memb_iter_first(TR_COMM_ITER *iter, TR_COMM_MEMB *memb)
+{
+ iter->cur_memb=memb;
+ return iter->cur_memb;
+}
+
+TR_COMM_MEMB *tr_comm_memb_iter_next(TR_COMM_ITER *iter)
+{
+ if (iter->cur_memb!=NULL)
+ iter->cur_memb=iter->cur_memb->origin_next;
+ return iter->cur_memb;
+}
+
+
+/* iterate over all memberships in the table */
+TR_COMM_MEMB *tr_comm_memb_iter_all_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab)
+{
+ iter->cur_memb=ctab->memberships;
+ iter->cur_orig_head=ctab->memberships;
+ return iter->cur_memb;
+}
+
+TR_COMM_MEMB *tr_comm_memb_iter_all_next(TR_COMM_ITER *iter)
+{
+ if (iter->cur_memb->next==NULL) {
+ if (iter->cur_orig_head->next==NULL) {
+ /* we're done */
+ return NULL;
+ } else {
+ iter->cur_memb=iter->cur_orig_head->next;
+ iter->cur_orig_head=iter->cur_orig_head->next;
+ }
+ } else {
+ iter->cur_memb=iter->cur_memb->origin_next;
+ }
+ return iter->cur_memb;
+}
+
+
+TR_COMM_TYPE tr_comm_type_from_str(const char *s)
+{
+ if (strcmp(s, "apc")==0)
+ return TR_COMM_APC;
+ if (strcmp(s,"coi")==0)
+ return TR_COMM_COI;
+ return TR_COMM_UNKNOWN;
+}
+
+
+static int tr_comm_memb_destructor(void *obj)
+{
+ TR_COMM_MEMB *memb=talloc_get_type_abort(obj, TR_COMM_MEMB);
+ if (memb->origin!=NULL)
+ tr_free_name(memb->origin);
+
+ if (memb->rp!=NULL)
+ tr_rp_realm_decref(memb->rp);
+ if (memb->idp!=NULL)
+ tr_idp_realm_decref(memb->idp);
+ if (memb->comm!=NULL)
+ tr_comm_decref(memb->comm);
+ if (memb->provenance!=NULL)
+ json_decref(memb->provenance);
+ return 0;
+}
+
+TR_COMM_MEMB *tr_comm_memb_new(TALLOC_CTX *mem_ctx)
+{
+ TR_COMM_MEMB *memb=talloc(mem_ctx, TR_COMM_MEMB);
+ if (memb!=NULL) {
+ memb->next=NULL;
+ memb->origin_next=NULL;
+ memb->idp=NULL;
+ memb->rp=NULL;
+ memb->comm=NULL;
+ memb->origin=NULL;
+ memb->provenance=NULL;
+ memb->interval=0;
+ memb->triggered=0;
+ memb->times_expired=0;
+ memb->expiry=talloc(memb, struct timespec);
+ if (memb->expiry==NULL) {
+ talloc_free(memb);
+ return NULL;
+ }
+ *(memb->expiry)=(struct timespec){0,0};
+ talloc_set_destructor((void *)memb, tr_comm_memb_destructor);
+ }
+ return memb;
+}
+
+void tr_comm_memb_free(TR_COMM_MEMB *memb)
+{
+ talloc_free(memb);
+}
+
+/* Returns 0 if they are the same, nonzero if they differ.
+ * Ignores expiry, triggered, and times_expired, next pointers */
+int tr_comm_memb_cmp(TR_COMM_MEMB *m1, TR_COMM_MEMB *m2)
+{
+ if ((m1->idp==m2->idp) &&
+ (m1->rp==m2->rp) &&
+ (m1->comm==m2->comm) &&
+ (tr_comm_memb_provenance_cmp(m1, m2, 0)==0) &&
+ (m1->interval==m2->interval))
+ return 0;
+ return 1;
+}
+
+TR_REALM_ROLE tr_comm_memb_get_role(TR_COMM_MEMB *memb)
+{
+ if (memb->rp!=NULL)
+ return TR_ROLE_RP;
+ if (memb->idp!=NULL)
+ return TR_ROLE_IDP;
+ return TR_ROLE_UNKNOWN;
+}
+
+void tr_comm_memb_set_rp_realm(TR_COMM_MEMB *memb, TR_RP_REALM *realm)
+{
+ if (memb->idp!=NULL) {
+ tr_idp_realm_decref(memb->idp);
+ memb->idp=NULL;
+ }
+ if (memb->rp!=NULL)
+ tr_rp_realm_decref(memb->rp);
+
+
+ memb->rp=realm;
+ tr_rp_realm_incref(realm);
+}
+
+TR_RP_REALM *tr_comm_memb_get_rp_realm(TR_COMM_MEMB *memb)
+{
+ return memb->rp;
+}
+
+void tr_comm_memb_set_idp_realm(TR_COMM_MEMB *memb, TR_IDP_REALM *realm)
+{
+ if (memb->rp!=NULL) {
+ tr_rp_realm_decref(memb->rp);
+ memb->rp=NULL;
+ }
+ if (memb->idp!=NULL)
+ tr_idp_realm_decref(memb->idp);
+
+ memb->idp=realm;
+ tr_idp_realm_incref(realm);
+}
+
+TR_IDP_REALM *tr_comm_memb_get_idp_realm(TR_COMM_MEMB *memb)
+{
+ return memb->idp;
+}
+
+void tr_comm_memb_set_comm(TR_COMM_MEMB *memb, TR_COMM *comm)
+{
+ if (memb->comm!=NULL)
+ tr_comm_decref(memb->comm);
+ memb->comm=comm;
+ tr_comm_incref(comm);
+}
+
+TR_COMM *tr_comm_memb_get_comm(TR_COMM_MEMB *memb)
+{
+ return memb->comm;
+}
+
+static void tr_comm_memb_set_origin(TR_COMM_MEMB *memb, TR_NAME *origin)
+{
+ if (memb->origin!=NULL)
+ tr_free_name(memb->origin);
+ memb->origin=origin;
+}
+
+TR_NAME *tr_comm_memb_get_origin(TR_COMM_MEMB *memb)
+{
+ return memb->origin;
+}
+
+TR_NAME *tr_comm_memb_dup_origin(TR_COMM_MEMB *memb)
+{
+ if (memb->origin!=NULL)
+ return tr_dup_name(memb->origin);
+ return NULL;
+}
+
+json_t *tr_comm_memb_get_provenance(TR_COMM_MEMB *memb)
+{
+ if (memb!=NULL)
+ return memb->provenance;
+ return NULL;
+}
+
+void tr_comm_memb_set_provenance(TR_COMM_MEMB *memb, json_t *prov)
+{
+ const char *s=NULL;
+
+ if (memb->provenance)
+ json_decref(memb->provenance);
+
+ memb->provenance=prov;
+ if (prov!=NULL) {
+ json_incref(prov);
+
+ /* next line sets origin to NULL if provenance is empty because jansson
+ * routines return NULL on error */
+ s=json_string_value(json_array_get(prov, 0));
+ if (s==NULL)
+ tr_comm_memb_set_origin(memb, NULL);
+ else
+ memb->origin=tr_new_name(s);
+ } else {
+ tr_comm_memb_set_origin(memb, NULL);
+ }
+}
+
+void tr_comm_memb_add_to_provenance(TR_COMM_MEMB *memb, TR_NAME *hop)
+{
+ if (memb->provenance==NULL) {
+ memb->provenance=json_array();
+ if (memb->provenance==NULL) {
+ tr_err("tr_comm_memb_add_to_provenance: unable to allocate provenance list.");
+ return;
+ }
+ /* this is the first entry in the provenance, so it is the origin */
+ tr_comm_memb_set_origin(memb,tr_dup_name(hop));
+ if (memb->origin==NULL) {
+ tr_err("tr_comm_memb_add_to_provenance: unable to allocate origin.");
+ json_decref(memb->provenance);
+ memb->provenance=NULL;
+ return;
+ }
+ }
+ if (0!=json_array_append_new(memb->provenance, tr_name_to_json_string(hop)))
+ tr_err("tr_comm_memb_add_to_provenance: unable to extend provenance list.");
+}
+
+size_t tr_comm_memb_provenance_len(TR_COMM_MEMB *memb)
+{
+ if (memb->provenance==NULL)
+ return 0;
+ return json_array_size(memb->provenance);
+}
+
+void tr_comm_memb_set_interval(TR_COMM_MEMB *memb, unsigned int interval)
+{
+ memb->interval=interval;
+}
+
+unsigned int tr_comm_memb_get_interval(TR_COMM_MEMB *memb)
+{
+ return memb->interval;
+}
+
+void tr_comm_memb_set_expiry(TR_COMM_MEMB *memb, struct timespec *time)
+{
+ if (time==NULL)
+ *(memb->expiry)=(struct timespec){0,0};
+ else {
+ memb->expiry->tv_sec=time->tv_sec;
+ memb->expiry->tv_nsec=time->tv_nsec;
+ }
+}
+
+struct timespec *tr_comm_memb_get_expiry(TR_COMM_MEMB *memb)
+{
+ return memb->expiry;
+}
+
+int tr_comm_memb_is_expired(TR_COMM_MEMB *memb, struct timespec *curtime)
+{
+ tr_debug("tr_comm_memb_is_expired: (cur->tv_sec>memb->expiry->tv_sec)=(%u > %u)=%s",
+ curtime->tv_sec,
+ memb->expiry->tv_sec,
+ (curtime->tv_sec > memb->expiry->tv_sec)?"true":"false");
+
+ return ((curtime->tv_sec > memb->expiry->tv_sec)
+ || ((curtime->tv_sec == memb->expiry->tv_sec)
+ &&(curtime->tv_nsec >= memb->expiry->tv_nsec)));
+}
+
+void tr_comm_memb_set_triggered(TR_COMM_MEMB *memb, int trig)
+{
+ memb->triggered=trig;
+}
+
+int tr_comm_memb_is_triggered(TR_COMM_MEMB *memb)
+{
+ return memb->triggered;
+}
+
+void tr_comm_memb_reset_times_expired(TR_COMM_MEMB *memb)
+{
+ memb->times_expired=0;
+}
+
+/* bumps the expiration count */
+void tr_comm_memb_expire(TR_COMM_MEMB *memb)
+{
+ /* avoid overflow */
+ if (memb->times_expired+1>memb->times_expired)
+ memb->times_expired++;
+}
+
+unsigned int tr_comm_memb_get_times_expired(TR_COMM_MEMB *memb)
+{
+ return memb->times_expired;
+}
+
+TR_COMM_TABLE *tr_comm_table_new(TALLOC_CTX *mem_ctx)
+{
+ TR_COMM_TABLE *ctab=talloc(mem_ctx, TR_COMM_TABLE);
+ if (ctab!=NULL) {
+ ctab->comms=NULL;
+ ctab->memberships=NULL;
+ ctab->idp_realms=NULL;
+ ctab->rp_realms=NULL;
+ }
+ return ctab;
+}
+
+void tr_comm_table_free(TR_COMM_TABLE *ctab)
+{
+ talloc_free(ctab);
+}
+
+static TR_REALM_ROLE tr_comm_memb_role(TR_COMM_MEMB *memb)
+{
+ if (memb->rp!=NULL)
+ return TR_ROLE_RP;
+ if (memb->idp!=NULL)
+ return TR_ROLE_IDP;
+
+ return TR_ROLE_UNKNOWN;
+}
+
+void tr_comm_table_add_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *new)
+{
+ TR_COMM_MEMB *cur=NULL;
+
+ /* TODO: further validate the member (must have valid comm and realm) */
+ if ((new->next!=NULL) || (new->origin_next!=NULL)) {
+ tr_debug("tr_comm_table_add_memb: attempting to add member already in a list.");
+ }
+
+ /* handle the empty list case */
+ if (ctab->memberships==NULL) {
+ ctab->memberships=new;
+ talloc_steal(ctab, new);
+ return;
+ }
+
+ /* The list was not empty. See if we already have a membership for this realm/comm/role */
+ switch (tr_comm_memb_role(new)) {
+ case TR_ROLE_RP:
+ cur=tr_comm_table_find_rp_memb(ctab,
+ tr_rp_realm_get_id(tr_comm_memb_get_rp_realm(new)),
+ tr_comm_get_id(tr_comm_memb_get_comm(new)));
+ break;
+ case TR_ROLE_IDP:
+ cur=tr_comm_table_find_idp_memb(ctab,
+ tr_idp_realm_get_id(tr_comm_memb_get_idp_realm(new)),
+ tr_comm_get_id(tr_comm_memb_get_comm(new)));
+ break;
+ case TR_ROLE_UNKNOWN:
+ default:
+ tr_err("tr_comm_table_add_memb: realm with unknown role added.");
+ cur=NULL;
+ }
+
+ if (cur==NULL) {
+ /* no entry for this realm/comm/role, tack it on the end */
+ for (cur=ctab->memberships; cur->next!=NULL; cur=cur->next) { }
+ cur->next=new;
+ } else {
+ /* Found an entry. Add to the end of its same-origin list. */
+ while (cur->origin_next!=NULL) {
+ cur=cur->origin_next;
+ }
+ cur->origin_next=new;
+ }
+
+ talloc_steal(ctab, new);
+}
+
+/* Remove memb from ctab. Do not free anything. Do nothing if memb not in ctab. */
+void tr_comm_table_remove_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *memb)
+{
+ TR_COMM_MEMB *cur=NULL; /* for walking the main list */
+ TR_COMM_MEMB *orig_cur=NULL; /* for walking the origin list */
+
+ if ((memb==NULL) || (ctab->memberships==NULL))
+ return;
+
+ /* see if it's the first member */
+ if (ctab->memberships==memb) {
+ if (memb->origin_next!=NULL) {
+ memb->origin_next->next=memb->next;
+ ctab->memberships=memb->origin_next;
+ } else
+ ctab->memberships=memb->next;
+
+ return;
+ }
+
+ /* see if it's in first member's origin list */
+ for (orig_cur=ctab->memberships;
+ orig_cur->origin_next!=NULL;
+ orig_cur=orig_cur->origin_next) {
+ if (orig_cur->origin_next==memb) {
+ orig_cur->origin_next=memb->origin_next;
+ return;
+ }
+ }
+
+ /* now we have to walk the rest of the tree */
+ for (cur=ctab->memberships; cur->next!=NULL; cur=cur->next) {
+ if (cur->next==memb) {
+ /* it matched an entry on the main list */
+ if (memb->origin_next==NULL)
+ cur->next=memb->next; /* no origin list, just drop memb */
+ else {
+ /* replace the entry in the main list with the next element on the origin list */
+ memb->origin_next->next=memb->next;
+ cur->next=memb->origin_next;
+ }
+ return;
+ } else {
+ /* it was not on the main list, walk the origin list */
+ for (orig_cur=cur; orig_cur->origin_next!=NULL; orig_cur=orig_cur->origin_next) {
+ if (orig_cur->origin_next==memb) {
+ orig_cur->origin_next=memb->origin_next;
+ return; /* just drop the element from the origin list */
+ }
+ }
+ }
+ }
+ /* if we got here, cur->next was null. Still have to check the origin_next list */
+ for (orig_cur=cur; orig_cur->origin_next!=NULL; orig_cur=orig_cur->origin_next) {
+ if (orig_cur->origin_next==memb) {
+ orig_cur->origin_next=memb->origin_next;
+ return; /* just drop the element from the origin list */
+ }
+ }
+}
+
+TR_NAME *tr_comm_memb_get_realm_id(TR_COMM_MEMB *memb)
+{
+ if (memb->rp!=NULL)
+ return tr_rp_realm_get_id(memb->rp);
+ else
+ return tr_idp_realm_get_id(memb->idp);
+}
+
+/* find a membership from any origin */
+TR_COMM_MEMB *tr_comm_table_find_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm)
+{
+ TR_COMM_MEMB *cur=NULL;
+ TR_NAME *cur_realm_name=NULL;
+
+ for (cur=ctab->memberships; cur!=NULL; cur=cur->next) {
+ cur_realm_name=tr_comm_memb_get_realm_id(cur);
+ if (cur_realm_name==NULL) {
+ tr_warning("tr_comm_table_find: encountered realm with no name.");
+ continue;
+ }
+ if ((0==tr_name_cmp(realm, cur_realm_name)) &&
+ (0==tr_name_cmp(comm, tr_comm_get_id(tr_comm_memb_get_comm(cur))))) {
+ return cur;
+ }
+ }
+ return NULL;
+}
+
+/* find a membership from a particular origin */
+TR_COMM_MEMB *tr_comm_table_find_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin)
+{
+ TR_NAME *cur_orig=NULL;
+ TR_COMM_MEMB *cur=tr_comm_table_find_memb(ctab, realm, comm);
+ if (cur==NULL)
+ return NULL; /* no match */
+
+ /* had a match for comm/realm; find origin match */
+ while (cur!=NULL) {
+ if (((origin==NULL) && (cur_orig==NULL)) ||
+ ((origin!=NULL) && (cur_orig!=NULL) && (0==tr_name_cmp(origin, cur_orig))))
+ return cur; /* found a match */
+ cur=cur->origin_next;
+ }
+ return NULL; /* no match */
+}
+
+
+/* find an idp membership regardless of its origin */
+TR_COMM_MEMB *tr_comm_table_find_idp_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm)
+{
+ TR_COMM_MEMB *cur=NULL;
+ TR_IDP_REALM *idp_realm=NULL;
+
+ for (cur=ctab->memberships; cur!=NULL; cur=cur->next) {
+ idp_realm=tr_comm_memb_get_idp_realm(cur);
+ if (idp_realm==NULL)
+ continue; /* was not an idp */
+
+ if ((0==tr_name_cmp(realm, idp_realm->realm_id)) &&
+ (0==tr_name_cmp(comm, tr_comm_get_id(tr_comm_memb_get_comm(cur))))) {
+ return cur;
+ }
+ }
+ return NULL;
+}
+
+/* find an idp membership from a particular origin */
+TR_COMM_MEMB *tr_comm_table_find_idp_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin)
+{
+ TR_NAME *cur_orig=NULL;
+ TR_COMM_MEMB *cur=tr_comm_table_find_idp_memb(ctab, realm, comm);
+ if (cur==NULL)
+ return NULL; /* no match */
+
+ /* had a match for comm/realm; find origin match */
+ while (cur!=NULL) {
+ cur_orig=tr_comm_memb_get_origin(cur);
+ if (((origin==NULL) && (cur_orig==NULL)) ||
+ ((origin!=NULL) && (cur_orig!=NULL) && (0==tr_name_cmp(origin, cur_orig))))
+ return cur; /* found a match */
+ cur=cur->origin_next;
+ }
+ return NULL; /* no match */
+}
+
+/* find an rp membership from any origin */
+TR_COMM_MEMB *tr_comm_table_find_rp_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm)
+{
+ TR_COMM_MEMB *cur=NULL;
+ TR_RP_REALM *rp_realm=NULL;
+
+ for (cur=ctab->memberships; cur!=NULL; cur=cur->next) {
+ rp_realm=tr_comm_memb_get_rp_realm(cur);
+ if (rp_realm==NULL)
+ continue; /* was not an rp */
+
+ if ((0==tr_name_cmp(realm, tr_rp_realm_get_id(rp_realm))) &&
+ (0==tr_name_cmp(comm, tr_comm_get_id(tr_comm_memb_get_comm(cur))))) {
+ return cur;
+ }
+ }
+ return NULL;
+}
+
+/* find an rp membership from a particular origin */
+TR_COMM_MEMB *tr_comm_table_find_rp_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin)
+{
+ TR_NAME *cur_orig=NULL;
+ TR_COMM_MEMB *cur=tr_comm_table_find_rp_memb(ctab, realm, comm);
+ if (cur==NULL)
+ return NULL; /* no match */
+
+ /* had a match for comm/realm; find origin match */
+ while (cur!=NULL) {
+ cur_orig=tr_comm_memb_get_origin(cur);
+ if (((origin==NULL) && (cur_orig==NULL)) ||
+ ((origin!=NULL) && (cur_orig!=NULL) && (0==tr_name_cmp(origin, cur_orig))))
+ return cur; /* found a match */
+ cur=cur->origin_next;
+ }
+ return NULL; /* no match */
+}
+
+TR_COMM *tr_comm_table_find_comm(TR_COMM_TABLE *ctab, TR_NAME *comm_id)
+{
+ return tr_comm_lookup(ctab->comms, comm_id);
+}
+
+void tr_comm_table_add_comm(TR_COMM_TABLE *ctab, TR_COMM *new)
+{
+ tr_comm_add(ctab->comms, new);
+ if (ctab->comms!=NULL)
+ talloc_steal(ctab, ctab->comms); /* make sure it's in the right context */
+}
+
+void tr_comm_table_remove_comm(TR_COMM_TABLE *ctab, TR_COMM *comm)
+{
+ tr_comm_remove(ctab->comms, comm);
+}
+
+TR_RP_REALM *tr_comm_table_find_rp_realm(TR_COMM_TABLE *ctab, TR_NAME *realm_id)
+{
+ return tr_rp_realm_lookup(ctab->rp_realms, realm_id);
+}
+
+void tr_comm_table_add_rp_realm(TR_COMM_TABLE *ctab, TR_RP_REALM *new)
+{
+ tr_rp_realm_add(ctab->rp_realms, new);
+ if (ctab->rp_realms!=NULL)
+ talloc_steal(ctab, ctab->rp_realms); /* make sure it's in the right context */
+}
+
+void tr_comm_table_remove_rp_realm(TR_COMM_TABLE *ctab, TR_RP_REALM *realm)
+{
+ tr_rp_realm_remove(ctab->rp_realms, realm);
+}
+
+TR_IDP_REALM *tr_comm_table_find_idp_realm(TR_COMM_TABLE *ctab, TR_NAME *realm_id)
+{
+ return tr_idp_realm_lookup(ctab->idp_realms, realm_id);
+}
+
+void tr_comm_table_add_idp_realm(TR_COMM_TABLE *ctab, TR_IDP_REALM *new)
+{
+ tr_idp_realm_add(ctab->idp_realms, new);
+ if (ctab->idp_realms!=NULL)
+ talloc_steal(ctab, ctab->idp_realms); /* make sure it's in the right context */
+}
+
+void tr_comm_table_remove_idp_realm(TR_COMM_TABLE *ctab, TR_IDP_REALM *realm)
+{
+ tr_idp_realm_remove(ctab->idp_realms, realm);
+}
+
+
+/* how many communities in the table? */
+size_t tr_comm_table_size(TR_COMM_TABLE *ctab)
+{
+ size_t count=0;
+ TR_COMM *this=ctab->comms;
+ while(this!=NULL) {
+ this=this->next;
+ count++;
+ }
+ return count;
+}
+
+/* clean up unreferenced realms, etc */
+void tr_comm_table_sweep(TR_COMM_TABLE *ctab)
+{
+ tr_rp_realm_sweep(ctab->rp_realms);
+ tr_idp_realm_sweep(ctab->idp_realms);
+ tr_comm_sweep(ctab->comms);
+}
+
+
+const char *tr_realm_role_to_str(TR_REALM_ROLE role)
+{
+ switch(role) {
+ case TR_ROLE_IDP:
+ return "idp";
+ case TR_ROLE_RP:
+ return "rp";
+ default:
+ return NULL;
+ }
+}
+
+TR_REALM_ROLE tr_realm_role_from_str(const char *s)
+{
+ if (strcmp(s, "idp")==0)
+ return TR_ROLE_IDP;
+ if (strcmp(s, "rp")==0)
+ return TR_ROLE_RP;
+ return TR_ROLE_UNKNOWN;
+}
+
+static void tr_comm_table_print_provenance(FILE *f, json_t *prov)
+{
+ const char *s=NULL;
+ size_t ii=0;
+
+ for (ii=0; ii<json_array_size(prov); ii++) {
+ s=json_string_value(json_array_get(prov, ii));
+ if (s!=NULL)
+ fprintf(f, "%s%s", s, ((ii+1)==json_array_size(prov))?"":", ");
+ }
+}
+
+void tr_comm_table_print(FILE *f, TR_COMM_TABLE *ctab)
+{
+ TR_COMM_MEMB *p1=NULL; /* for walking the main list */
+ TR_COMM_MEMB *p2=NULL; /* for walking the same-origin lists */
+
+ fprintf(f, ">> Membership table start <<\n");
+ for (p1=ctab->memberships; p1!=NULL; p1=p1->next) {
+ fprintf(f, "* %s %s/%s\n %s (%p) - prov: ",
+ tr_realm_role_to_str(tr_comm_memb_get_role(p1)),
+ tr_comm_memb_get_realm_id(p1)->buf,
+ tr_comm_get_id(tr_comm_memb_get_comm(p1))->buf,
+ (tr_comm_memb_get_origin(p1)==NULL)?"null origin":(tr_comm_memb_get_origin(p1)->buf),
+ p1);
+ tr_comm_table_print_provenance(f, p1->provenance);
+ fprintf(f, "\n");
+ for (p2=p1->origin_next; p2!=NULL; p2=p2->origin_next) {
+ fprintf(f, " %s (%p) - prov: ",
+ (tr_comm_memb_get_origin(p2)==NULL)?"null origin":(tr_comm_memb_get_origin(p2)->buf),
+ p2);
+ tr_comm_table_print_provenance(f, p2->provenance);
+ fprintf(f, "\n");
+ }
+ fprintf(f, "\n");
+ }
+}
void tr_print_config (TR_CFG *cfg) {
tr_notice("tr_print_config: Logging running trust router configuration.");
- tr_print_comms(cfg->comms);
+ tr_print_comms(cfg->ctable);
}
-void tr_print_comms (TR_COMM *comm_list) {
+void tr_print_comms (TR_COMM_TABLE *ctab)
+{
TR_COMM *comm = NULL;
- for (comm = comm_list; NULL != comm; comm = comm->next) {
+ for (comm = ctab->comms; NULL != comm; comm = comm->next) {
tr_notice("tr_print_config: Community %s:", comm->id->buf);
tr_notice("tr_print_config: - Member IdPs:");
- tr_print_comm_idps(comm->idp_realms);
+ tr_print_comm_idps(ctab, comm);
tr_notice("tr_print_config: - Member RPs:");
- tr_print_comm_rps(comm->rp_realms);
+ tr_print_comm_rps(ctab, comm);
}
}
-void tr_print_comm_idps (TR_IDP_REALM *idp_list) {
+void tr_print_comm_idps(TR_COMM_TABLE *ctab, TR_COMM *comm)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_COMM_ITER *iter=NULL;
TR_IDP_REALM *idp = NULL;
char *s=NULL;
- for (idp = idp_list; NULL != idp; idp = idp->comm_next) {
- s=tr_idp_realm_to_str(NULL, idp);
+ iter=tr_comm_iter_new(tmp_ctx);
+ if (iter==NULL) {
+ tr_notice("tr_print_config: unable to allocate IdP iterator.");
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ for (idp=tr_idp_realm_iter_first(iter, ctab, tr_comm_get_id(comm));
+ NULL!=idp;
+ idp=tr_idp_realm_iter_next(iter)) {
+ s=tr_idp_realm_to_str(tmp_ctx, idp);
if (s!=NULL)
tr_notice("tr_print_config: - @%s", s);
else
- tr_notice("tr_print_config: unable to allocate idp output string.");
+ tr_notice("tr_print_config: unable to allocate IdP output string.");
}
+ talloc_free(tmp_ctx);
}
-void tr_print_comm_rps(TR_RP_REALM *rp_list) {
+void tr_print_comm_rps(TR_COMM_TABLE *ctab, TR_COMM *comm)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_COMM_ITER *iter=NULL;
TR_RP_REALM *rp = NULL;
+ char *s=NULL;
- for (rp = rp_list; NULL != rp; rp = rp->next) {
- tr_notice("tr_print_config: - %s", rp->realm_name->buf);
+ iter=tr_comm_iter_new(tmp_ctx);
+ if (iter==NULL) {
+ tr_notice("tr_print_config: unable to allocate RP iterator.");
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ for (rp=tr_rp_realm_iter_first(iter, ctab, tr_comm_get_id(comm));
+ NULL!=rp;
+ rp=tr_rp_realm_iter_next(iter)) {
+ s=tr_rp_realm_to_str(tmp_ctx, rp);
+ if (s!=NULL)
+ tr_notice("tr_print_config: - @%s", s);
+ else
+ tr_notice("tr_print_config: unable to allocate RP output string.");
}
+ talloc_free(tmp_ctx);
}
TR_CFG *tr_cfg_new(TALLOC_CTX *mem_ctx)
{
- return talloc_zero(mem_ctx, TR_CFG);
+ 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) {
+void tr_cfg_free (TR_CFG *cfg)
+{
talloc_free(cfg);
}
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))
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)) {
*rc=TR_CFG_NOPARSE;
goto cleanup;
}
- apcs=tr_apc_add(apcs, new_apc);
+ tr_apc_add(apcs, new_apc);
}
talloc_steal(mem_ctx, apcs);
*rc=TR_CFG_NOPARSE;
goto cleanup;
}
- realms=tr_idp_realm_add(realms, new_realm);
+ 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) {
*rc=TR_CFG_NOPARSE;
goto cleanup;
}
- realms=tr_idp_realm_add(realms, new_realm);
+ tr_idp_realm_add(realms, new_realm);
}
}
return realms;
}
-#if 0
-static TR_IDP_REALM *tr_cfg_parse_remote_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_remote_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_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_remote_realms: error decoding remote realm entry %d", ii+1);
- *rc=TR_CFG_NOPARSE;
- goto cleanup;
- }
- realms=tr_idp_realm_add(realms, new_realm);
- }
- }
-
- *rc=TR_CFG_SUCCESS;
- talloc_steal(mem_ctx, realms);
-
-cleanup:
- talloc_free(tmp_ctx);
- return realms;
-}
-#endif /* 0 */
-
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);
*rc=TR_CFG_NOPARSE;
goto cleanup;
}
- clients=tr_rp_client_add(clients, new_client);
+ tr_rp_client_add(clients, new_client);
}
}
}
#if 0
+/* TODO: are we using this? JLR */
/* Update the community information with data from a new batch of IDP realms.
* May partially add realms if there is a failure, no guarantees.
* Call like comms=tr_comm_idp_update(comms, new_realms, &rc) */
-static TR_COMM *tr_cfg_comm_idp_update(TALLOC_CTX *mem_ctx, TR_COMM *comms, TR_IDP_REALM *new_realms, TR_CFG_RC *rc)
+static TR_COMM *tr_cfg_comm_idp_update(TALLOC_CTX *mem_ctx,
+ TR_COMM_TABLE *ctab,
+ TR_IDP_REALM *new_realms,
+ TR_CFG_RC *rc)
{
TALLOC_CTX *tmp_ctx=talloc_new(NULL);
TR_COMM *comm=NULL; /* community looked up in comms table */
/* fill in the community with info */
comm->type=TR_COMM_APC; /* realms added this way are in APCs */
comm->expiration_interval=TR_DEFAULT_APC_EXPIRATION_INTERVAL;
- comm->id=tr_dup_name(apc->id);
+ tr_comm_set_id(comm, tr_dup_name(apc->id));
tr_comm_add_idp_realm(comm, realm);
- new_comms=tr_comm_add(new_comms, comm);
+ tr_comm_add(new_comms, comm);
} else {
/* add this realm to the comm */
tr_comm_add_idp_realm(comm, realm);
}
/* we successfully built a list, add it to the other list */
- comms=tr_comm_add(comms, new_comms);
+ tr_comm_add(comms, new_comms);
talloc_steal(mem_ctx, comms);
cleanup:
talloc_free(tmp_ctx);
/* if we succeeded, link things to the configuration and move out of tmp context */
if (retval==TR_CFG_SUCCESS) {
if (new_idp_realms!=NULL) {
- trc->idp_realms=tr_idp_realm_add(trc->idp_realms, new_idp_realms); /* fixes talloc contexts except for head*/
- talloc_steal(trc, trc->idp_realms); /* make sure the head is in the right context */
+ 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) {
- trc->rp_clients=tr_rp_client_add(trc->rp_clients, new_rp_clients); /* fixes talloc contexts */
+ 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 */
}
}
return rc;
}
-static TR_IDP_REALM *tr_cfg_parse_comm_idps (TR_CFG *trc, json_t *jidps, TR_CFG_RC *rc)
+static void tr_cfg_parse_comm_idps(TR_CFG *trc, json_t *jidps, TR_COMM *comm, TR_CFG_RC *rc)
{
- TR_IDP_REALM *idp = NULL;
- TR_IDP_REALM *found_idp = NULL;
- TR_IDP_REALM *temp_idp = NULL;
+ TR_IDP_REALM *found_idp=NULL;
int i = 0;
if ((!trc) ||
(!json_is_array(jidps))) {
if (rc)
*rc = TR_CFG_BAD_PARAMS;
- return NULL;
+ return;
}
- for (i = 0; i < json_array_size(jidps); i++) {
- if (NULL == (temp_idp = talloc(trc, TR_IDP_REALM))) {
- tr_debug("tr_cfg_parse_comm_idps: Can't allocate memory for IdP Realm.");
- if (rc)
- *rc = TR_CFG_NOMEM;
- return NULL;
- }
- memset (temp_idp, 0, sizeof(TR_IDP_REALM));
-
- if (NULL == (found_idp = (tr_cfg_find_idp(trc,
- tr_new_name((char *)json_string_value(json_array_get(jidps, i))),
- rc)))) {
+ for (i=0; i < json_array_size(jidps); i++) {
+ found_idp=tr_cfg_find_idp(trc,
+ tr_new_name((char *)json_string_value(json_array_get(jidps, i))),
+ rc);
+ if ((found_idp==NULL) || (*rc!=TR_CFG_SUCCESS)) {
tr_debug("tr_cfg_parse_comm_idps: Unknown IDP %s.",
(char *)json_string_value(json_array_get(jidps, i)));
- return NULL;
+ *rc=TR_CFG_ERROR;
+ return;
}
-
- // We *MUST* do a dereferenced copy here or the second community will corrupt the linked list we create here.
- *temp_idp = *found_idp;
-
- temp_idp->comm_next = idp;
- idp = temp_idp;
+ tr_comm_add_idp_realm(trc->ctable, comm, found_idp, 0, NULL, NULL); /* no provenance, never expires */
}
- return idp;
+ *rc=TR_CFG_SUCCESS;
+ return;
}
-static TR_RP_REALM *tr_cfg_parse_comm_rps (TR_CFG *trc, json_t *jrps, TR_CFG_RC *rc)
+static void tr_cfg_parse_comm_rps(TR_CFG *trc, json_t *jrps, TR_COMM *comm, TR_CFG_RC *rc)
{
- TR_RP_REALM *rp = NULL;
- TR_RP_REALM *temp_rp = NULL;
- int i = 0;
+ 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 NULL;
+ return;
}
- for (i = (json_array_size(jrps)-1); i >= 0; i--) {
- if (NULL == (temp_rp = talloc_zero(trc, TR_RP_REALM))) {
- tr_debug("tr_cfg_parse_comm_rps: Can't allocate memory for RP Realm.");
- if (rc)
- *rc = TR_CFG_NOMEM;
- return NULL;
+ 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;
}
- if (NULL == (temp_rp->realm_name = tr_new_name((char *)json_string_value(json_array_get(jrps, i))))) {
- tr_debug("tr_cfg_parse_comm_rps: No memory for RP Realm Name.");
- if (rc)
- *rc = TR_CFG_NOMEM;
- return NULL;
+ /* 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);
}
- temp_rp->next = rp;
- rp = temp_rp;
- }
+ /* 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;
+ }
- return rp;
+ /* 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 (TR_CFG *trc, json_t *jcomm, TR_CFG_RC *rc) {
+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;
tr_debug("tr_cfg_parse_one_comm: Bad parameters.");
if (rc)
*rc = TR_CFG_BAD_PARAMS;
- return NULL;
+ goto cleanup;
}
- if (NULL == (comm = talloc_zero(trc, TR_COMM))) {
+ comm=tr_comm_new(tmp_ctx);
+ if (comm==NULL) {
tr_crit("tr_cfg_parse_one_comm: Out of memory.");
*rc = TR_CFG_NOMEM;
- return NULL;
+ goto cleanup;
}
(!json_is_array(jrps))) {
tr_debug("tr_cfg_parse_one_comm: Error parsing Communities configuration.");
*rc = TR_CFG_NOPARSE;
- return NULL;
+ comm=NULL;
+ goto cleanup;
}
- if (NULL == (comm->id = tr_new_name((char *)json_string_value(jid)))) {
+ 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;
- return NULL;
+ comm=NULL;
+ goto cleanup;
}
if (0 == strcmp(json_string_value(jtype), "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.", comm->id->buf);
- tr_free_name(comm->id);
- return NULL;
+ 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", comm->id->buf, json_string_value(jtype));
- tr_free_name(comm->id);
+ 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;
- return NULL;
+ comm=NULL;
+ goto cleanup;
}
- comm->idp_realms = tr_cfg_parse_comm_idps(trc, jidps, rc);
+ 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.", comm->id->buf);
- tr_free_name(comm->id);
- return NULL;
+ 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;
}
- comm->rp_realms = tr_cfg_parse_comm_rps(trc, jrps, rc);
+ tr_cfg_parse_comm_rps(trc, jrps, comm, rc);
if (TR_CFG_SUCCESS != *rc) {
- tr_debug("tr_cfg_parse_comm: Can't parse RP realms for comm %s .", comm->id->buf);
- tr_free_name(comm->id);
- return NULL;
+ 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) {
comm->expiration_interval = 43200; /*30 days*/
if (jexpire) {
if (!json_is_integer(jexpire)) {
- fprintf(stderr, "tr_parse_comm: expirae_interval is not an integer\n");
- return NULL;
+ fprintf(stderr, "tr_parse_one_comm: expiration_interval is not an integer\n");
+ comm=NULL;
+ goto cleanup;
}
comm->expiration_interval = json_integer_value(jexpire);
if (comm->expiration_interval <= 10)
comm->expiration_interval = 129600;
}
}
-
+
+cleanup:
+ if (comm!=NULL)
+ talloc_steal(mem_ctx, comm);
+ talloc_free(tmp_ctx);
return comm;
}
}
for (i = 0; i < json_array_size(jcomms); i++) {
- if (NULL == (comm = tr_cfg_parse_one_comm(trc,
- json_array_get(jcomms, i),
- &rc))) {
- return rc;
+ 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.", comm->id->buf);
- comm->next = trc->comms;
- trc->comms = comm;
+ 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);
rc = TR_CFG_ERROR;
}
- if (NULL == trc->comms) {
+ if (0==tr_comm_table_size(trc->ctable)) {
tr_debug("tr_cfg_validate: Error: No Communities configured");
rc = TR_CFG_ERROR;
}
- if ((NULL == trc->default_servers) && (NULL == trc->idp_realms)) {
+ if ((NULL == trc->default_servers) && (NULL == trc->ctable->idp_realms)) {
tr_debug("tr_cfg_validate: Error: No default servers or IDPs configured.");
rc = TR_CFG_ERROR;
}
return NULL;
}
- for (cfg_idp = tr_cfg->idp_realms; NULL != cfg_idp; cfg_idp = cfg_idp->next) {
+ 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;
talloc_free(cons);
}
+TR_CONSTRAINT *tr_constraint_dup(TALLOC_CTX *mem_ctx, TR_CONSTRAINT *cons)
+{
+ TALLOC_CTX *tmp_ctx=NULL;
+ TR_CONSTRAINT *new=NULL;
+ int ii=0;
+
+ if (cons==NULL)
+ return NULL;
+
+ tmp_ctx=talloc_new(NULL);
+ new=tr_constraint_new(tmp_ctx);
+
+ if (new!=NULL) {
+ new->type=tr_dup_name(cons->type);
+ for (ii=0; ii<TR_MAX_CONST_MATCHES; ii++)
+ new->matches[ii]=tr_dup_name(cons->matches[ii]);
+ talloc_steal(mem_ctx, new);
+ }
+
+ talloc_free(tmp_ctx);
+ return new;
+}
+
/* Returns TRUE (1) if the the string (str) matchs the wildcard string (wc_str), FALSE (0) if not.
*/
int tr_prefix_wildcard_match (const char *str, const char *wc_str) {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+DH *tr_dh_new(void)
+{
+ return DH_new();
+}
+
DH *tr_create_dh_params(unsigned char *priv_key,
size_t keylen) {
}
}
+DH *tr_dh_dup(DH *in)
+{
+ DH *out=DH_new();
+
+ if (out==NULL)
+ return NULL;
+
+ if (in->g==NULL)
+ out->g=NULL;
+ else {
+ out->g=BN_dup(in->g);
+ if (out->g==NULL) {
+ DH_free(out);
+ return NULL;
+ }
+ }
+
+ if (in->p==NULL)
+ out->p=NULL;
+ else {
+ out->p=BN_dup(in->p);
+ if (out->p==NULL) {
+ DH_free(out);
+ return NULL;
+ }
+ }
+
+ if (in->q==NULL)
+ out->q=NULL;
+ else {
+ out->q=BN_dup(in->q);
+ if (out->q==NULL) {
+ DH_free(out);
+ return NULL;
+ }
+ }
+
+ if (in->priv_key==NULL)
+ out->priv_key=NULL;
+ else {
+ out->priv_key=BN_dup(in->priv_key);
+ if (out->priv_key==NULL) {
+ DH_free(out);
+ return NULL;
+ }
+ }
+
+ if (in->pub_key==NULL)
+ out->pub_key=NULL;
+ else {
+ out->pub_key=BN_dup(in->pub_key);
+ if (out->g==NULL) {
+ DH_free(out);
+ return NULL;
+ }
+ }
+
+ return out;
+}
+
int tr_compute_dh_key(unsigned char **pbuf,
BIGNUM *pub_key,
DH *priv_dh) {
unsigned char *bn_bytes = talloc_zero_size(request, BN_num_bytes(pub));
unsigned char *digest = talloc_zero_size(request, SHA_DIGEST_LENGTH+1);
assert(bn_bytes && digest);
- BN_bn2bin(pub, bn_bytes);
- SHA1(bn_bytes, BN_num_bytes(pub), digest);
- *out_digest = digest;
- *out_len = SHA_DIGEST_LENGTH;
- return 0;
+ BN_bn2bin(pub, bn_bytes);
+ SHA1(bn_bytes, BN_num_bytes(pub), digest);
+ *out_digest = digest;
+ *out_len = SHA_DIGEST_LENGTH;
+
+ talloc_free(bn_bytes);
+ return 0;
}
void tr_dh_free(unsigned char *dh_buf)
{
free(dh_buf);
}
+
+void tr_dh_destroy(DH *dh)
+{
+ DH_free(dh);
+}
*/
#include <talloc.h>
+#include <time.h>
#include <trust_router/tr_name.h>
#include <tr_idp.h>
#include <tr_config.h>
+#include <tr_debug.h>
static int tr_aaa_server_destructor(void *obj)
{
{
TR_AAA_SERVER *aaa=talloc(mem_ctx, TR_AAA_SERVER);
if (aaa!=NULL) {
+ aaa->next=NULL;
aaa->hostname=hostname;
talloc_set_destructor((void *)aaa, tr_aaa_server_destructor);
}
talloc_free(aaa);
}
-TR_AAA_SERVER *tr_idp_aaa_server_lookup(TR_IDP_REALM *idp_realms, TR_NAME *idp_realm_name, TR_NAME *comm)
+TR_AAA_SERVER_ITER *tr_aaa_server_iter_new(TALLOC_CTX *mem_ctx)
+{
+ return talloc(mem_ctx, TR_AAA_SERVER_ITER);
+}
+
+void tr_aaa_server_iter_free(TR_AAA_SERVER_ITER *iter)
+{
+ talloc_free(iter);
+}
+
+TR_AAA_SERVER *tr_aaa_server_iter_first(TR_AAA_SERVER_ITER *iter, TR_AAA_SERVER *aaa)
+{
+ iter->this=aaa;
+ return iter->this;
+}
+
+TR_AAA_SERVER *tr_aaa_server_iter_next(TR_AAA_SERVER_ITER *iter)
+{
+ if (iter->this!=NULL) {
+ iter->this=iter->this->next;
+ }
+ return iter->this;
+}
+
+
+/* fills in shared if pointer not null */
+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_IDP_REALM *idp = NULL;
break;
}
}
- if (idp)
+ if (idp) {
+ if (shared_out!=NULL)
+ *shared_out=idp->shared_config;
return idp->aaa_servers;
- else
+ } else
return NULL;
}
return idp;
}
+void tr_idp_realm_free(TR_IDP_REALM *idp)
+{
+ talloc_free(idp);
+}
+
+TR_NAME *tr_idp_realm_get_id(TR_IDP_REALM *idp)
+{
+ if (idp==NULL)
+ return NULL;
+
+ return idp->realm_id;
+}
+
+TR_NAME *tr_idp_realm_dup_id(TR_IDP_REALM *idp)
+{
+ if (idp==NULL)
+ return NULL;
+
+ return tr_dup_name(tr_idp_realm_get_id(idp));
+}
+
+void tr_idp_realm_set_id(TR_IDP_REALM *idp, TR_NAME *id)
+{
+ if (idp->realm_id!=NULL)
+ tr_free_name(idp->realm_id);
+ idp->realm_id=id;
+}
+
+void tr_idp_realm_set_apcs(TR_IDP_REALM *idp, TR_APC *apc)
+{
+ if (idp->apcs!=NULL)
+ tr_apc_free(idp->apcs);
+ idp->apcs=apc;
+ talloc_steal(idp, apc);
+}
+
+TR_APC *tr_idp_realm_get_apcs(TR_IDP_REALM *idp)
+{
+ return idp->apcs;
+}
+
+TR_IDP_REALM *tr_idp_realm_lookup(TR_IDP_REALM *idp_realms, TR_NAME *idp_name)
+{
+ TR_IDP_REALM *idp = NULL;
+
+ if (!idp_name) {
+ tr_debug("tr_idp_realm_lookup: Bad parameters.");
+ return NULL;
+ }
+
+ for (idp=idp_realms; NULL!=idp; idp=idp->next) {
+ if (0==tr_name_cmp(tr_idp_realm_get_id(idp), idp_name))
+ return idp;
+ }
+ return NULL;
+}
+
+
static TR_IDP_REALM *tr_idp_realm_tail(TR_IDP_REALM *idp)
{
if (idp==NULL)
return idp;
}
-/* for correct behavior, call like: idp_realms=tr_idp_realm_add(idp_realms, new_realm); */
-TR_IDP_REALM *tr_idp_realm_add(TR_IDP_REALM *head, TR_IDP_REALM *new)
+/* do not call directly, use the tr_idp_realm_add() macro */
+TR_IDP_REALM *tr_idp_realm_add_func(TR_IDP_REALM *head, TR_IDP_REALM *new)
{
if (head==NULL)
head=new;
return head;
}
+/* use the macro */
+TR_IDP_REALM *tr_idp_realm_remove_func(TR_IDP_REALM *head, TR_IDP_REALM *remove)
+{
+ TALLOC_CTX *list_ctx=talloc_parent(head);
+ TR_IDP_REALM *this=NULL;
+
+ if (head==NULL)
+ return NULL;
+
+ if (head==remove) {
+ /* if we're removing the head, put the next element (if present) into the context
+ * the list head was in. */
+ head=head->next;
+ if (head!=NULL) {
+ talloc_steal(list_ctx, head);
+ /* now put all the other elements in the context of the list head */
+ for (this=head->next; this!=NULL; this=this->next)
+ talloc_steal(head, this);
+ }
+ } else {
+ /* not removing the head; no need to play with contexts */
+ for (this=head; this->next!=NULL; this=this->next) {
+ if (this->next==remove) {
+ this->next=remove->next;
+ break;
+ }
+ }
+ }
+ return head;
+}
+
static int tr_idp_realm_apc_count(TR_IDP_REALM *idp)
{
int ii=0;
talloc_free(tmp_ctx);
return result;
}
+
+void tr_idp_realm_incref(TR_IDP_REALM *realm)
+{
+ realm->refcount++;
+}
+
+void tr_idp_realm_decref(TR_IDP_REALM *realm)
+{
+ if (realm->refcount>0)
+ realm->refcount--;
+}
+
+/* remove any with zero refcount
+ * Call via macro. */
+TR_IDP_REALM *tr_idp_realm_sweep_func(TR_IDP_REALM *head)
+{
+ TR_IDP_REALM *idp=NULL;
+ TR_IDP_REALM *old_next=NULL;
+
+ if (head==NULL)
+ return NULL;
+
+ while ((head!=NULL) && (head->refcount==0)) {
+ idp=head; /* keep a pointer so we can remove it */
+ tr_idp_realm_remove(head, idp); /* use this to get talloc contexts right */
+ tr_idp_realm_free(idp);
+ }
+
+ if (head==NULL)
+ return NULL;
+
+ /* will not remove the head here, that has already been done */
+ for (idp=head; idp->next!=NULL; idp=idp->next) {
+ if (idp->next->refcount==0) {
+ old_next=idp->next;
+ tr_idp_realm_remove(head, idp->next); /* changes idp->next */
+ tr_idp_realm_free(old_next);
+ }
+ }
+
+ return head;
+}
+
#include <talloc.h>
#include <pthread.h>
+#include <time.h>
+#include <errno.h>
#include <tr_mq.h>
#include <tr_debug.h>
TR_MQ *tr_mq_new(TALLOC_CTX *mem_ctx)
{
TR_MQ *mq=talloc(mem_ctx, TR_MQ);
+ pthread_condattr_t cattr;
+
if (mq!=NULL) {
pthread_mutex_init(&(mq->mutex), 0);
+ pthread_condattr_init(&cattr);
+
+ pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC); /* use the monotonic clock for timeouts */
+ pthread_cond_init(&(mq->have_msg_cond), &cattr);
+ pthread_condattr_destroy(&cattr);
+
mq->head=NULL;
mq->tail=NULL;
mq->last_hi_prio=NULL;
+
+ mq->notify_cb=NULL;
+ mq->notify_cb_arg=NULL;
}
return mq;
}
tr_mq_print(mq);
#endif
+ /* Before releasing the lock, signal any waiting threads that there's now
+ * something in the queue. Used for blocking tr_mq_pop() call. */
+
+ if (was_empty)
+ pthread_cond_broadcast(&(mq->have_msg_cond));
+
tr_mq_unlock(mq);
/* see if we need to tell someone we became non-empty */
notify_cb(mq, notify_cb_arg);
}
-/* caller must free msg via tr_mq_msg_free */
-TR_MQ_MSG *tr_mq_pop(TR_MQ *mq)
+/* Compute an absolute time from a desired timeout interval for use with tr_mq_pop().
+ * Fills in *ts and returns 0 on success. */
+int tr_mq_pop_timeout(time_t seconds, struct timespec *ts)
{
- TR_MQ_MSG *popped=NULL;
+ if (0!=clock_gettime(CLOCK_MONOTONIC, ts))
+ return -1;
+ ts->tv_sec+=seconds;
+ return 0;
+}
+
+/* Caller must free msg via tr_mq_msg_free, waiting until absolute
+ * time ts_abort before giving up (using CLOCK_MONOTONIC). If ts_abort
+ * has passed, returns an existing message but will not wait if one is
+ * not already available. If ts_abort is null, no blocking. Not
+ * guaranteed to wait if an error occurs - immediately returns without
+ * a message. Use tr_mq_pop_timeout() to get an absolute time that
+ * is guaranteed compatible with this function. */
+TR_MQ_MSG *tr_mq_pop(TR_MQ *mq, struct timespec *ts_abort)
+{
+ TR_MQ_MSG *popped=NULL;
+ int wait_err=0;
+
tr_mq_lock(mq);
+ if ((tr_mq_get_head(mq)==NULL) && (ts_abort!=NULL)) {
+ /* No msgs yet, and blocking was requested */
+ while ((wait_err==0) && (NULL==tr_mq_get_head(mq)))
+ wait_err=pthread_cond_timedwait(&(mq->have_msg_cond),
+ &(mq->mutex),
+ ts_abort);
+
+ if ((wait_err!=0) && (wait_err!=ETIMEDOUT)) {
+ tr_notice("tr_mq_pop: error waiting for message.");
+ return NULL;
+ }
+ /* if it timed out, ok to go ahead and check once more for a message, so no special exit */
+ }
+
if (tr_mq_get_head(mq)!=NULL) {
popped=tr_mq_get_head(mq);
tr_mq_set_head(mq, tr_mq_msg_get_next(popped)); /* popped is the old head */
#include <arpa/inet.h>
#include <string.h>
#include <openssl/dh.h>
+#include <openssl/crypto.h>
#include <jansson.h>
#include <assert.h>
#include <talloc.h>
+#include <tr_apc.h>
+#include <tr_comm.h>
#include <tr_msg.h>
#include <trust_router/tr_name.h>
#include <trp_internal.h>
#include <trust_router/tr_constraint.h>
+#include <trust_router/tr_dh.h>
#include <tr_debug.h>
/* JSON helpers */
/* Read attribute attr from msg as a string. Copies string into mem_ctx context so jmsg can
* be destroyed safely. Returns nonzero on error. */
-static int tr_msg_get_json_string(json_t *jmsg, const char *attr, char **dest, TALLOC_CTX *mem_ctx)
+static TRP_RC tr_msg_get_json_string(json_t *jmsg, const char *attr, char **dest, TALLOC_CTX *mem_ctx)
{
json_t *obj;
obj=json_object_get(jmsg, attr);
if (obj == NULL)
- return -1;
+ return TRP_ERROR;
/* check type */
if (!json_is_string(obj))
- return -1;
+ return TRP_ERROR;
*dest=talloc_strdup(mem_ctx, json_string_value(obj));
if (*dest==NULL)
- return -1;
+ return TRP_ERROR;
- return 0;
+ return TRP_SUCCESS;
}
enum msg_type tr_msg_get_msg_type(TR_MSG *msg)
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;
}
{
json_t *jdh = NULL;
json_t *jbn = NULL;
+ char *s=NULL;
if ((!dh) || (!dh->p) || (!dh->g) || (!dh->pub_key))
return NULL;
jdh = json_object();
- jbn = json_string(BN_bn2hex(dh->p));
+ jbn = json_string(s=BN_bn2hex(dh->p));
+ OPENSSL_free(s);
json_object_set_new(jdh, "dh_p", jbn);
- jbn = json_string(BN_bn2hex(dh->g));
+ jbn = json_string(s=BN_bn2hex(dh->g));
+ OPENSSL_free(s);
json_object_set_new(jdh, "dh_g", jbn);
- jbn = json_string(BN_bn2hex(dh->pub_key));
+ jbn = json_string(s=BN_bn2hex(dh->pub_key));
+ OPENSSL_free(s);
json_object_set_new(jdh, "dh_pub_key", jbn);
return jdh;
json_t *jg = NULL;
json_t *jpub_key = NULL;
- if (!(dh = malloc(sizeof(DH)))) {
+ if (!(dh=tr_dh_new())) {
tr_crit("tr_msg_decode_dh(): Error allocating DH structure.");
return NULL;
}
- memset(dh, 0, sizeof(DH));
-
/* store required fields from dh object */
if ((NULL == (jp = json_object_get(jdh, "dh_p"))) ||
(NULL == (jg = json_object_get(jdh, "dh_g"))) ||
(NULL == (jpub_key = json_object_get(jdh, "dh_pub_key")))) {
tr_debug("tr_msg_decode_dh(): Error parsing dh_info.");
- free(dh);
+ tr_dh_destroy(dh);
return NULL;
}
jsrvr = json_object();
- /* Server IP Address -- TBD handle IPv6 */
- jstr = json_string(inet_ntoa(srvr->aaa_server_addr));
+ jstr = json_string(srvr->aaa_server_addr);
json_object_set_new(jsrvr, "server_addr", jstr);
json_object_set_new(jsrvr,
json_object_set_new(jsrvr, "server_dh", tr_msg_encode_dh(srvr->aaa_server_dh));
if (srvr->path)
/* The path is owned by the srvr, so grab an extra ref*/
- json_object_set(jsrvr, "path", srvr->path);
+ json_object_set(jsrvr, "path", (json_t *)(srvr->path));
return jsrvr;
}
tr_notice("tr_msg_decode_one_server(): Error parsing required fields.");
return -1;
}
-
- /* TBD -- handle IPv6 Addresses */
- inet_aton(json_string_value(jsrvr_addr), &(srvr->aaa_server_addr));
+
+ srvr->aaa_server_addr=talloc_strdup(srvr, json_string_value(jsrvr_addr));
srvr->key_name = tr_new_name((char *)json_string_value(jsrvr_kn));
srvr->aaa_server_dh = tr_msg_decode_dh(jsrvr_dh);
- srvr->path = json_object_get(jsrvr, "path");
+ tid_srvr_blk_set_path(srvr, (TID_PATH *) json_object_get(jsrvr, "path"));
jsrvr_expire = json_object_get(jsrvr, "key_expiration");
if (jsrvr_expire && json_is_string(jsrvr_expire)) {
if (!g_time_val_from_iso8601(json_string_value(jsrvr_expire),
return jservers;
}
-static TID_SRVR_BLK *tr_msg_decode_servers(void * ctx, json_t *jservers, size_t *out_len)
+static TID_SRVR_BLK *tr_msg_decode_servers(TALLOC_CTX *mem_ctx, json_t *jservers)
{
- TID_SRVR_BLK *servers = NULL;
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TID_SRVR_BLK *servers=NULL;
+ TID_SRVR_BLK *new_srvr=NULL;
json_t *jsrvr;
size_t i, num_servers;
if (0 == num_servers) {
tr_debug("tr_msg_decode_servers(): Server array is empty.");
- return NULL;
+ goto cleanup;
}
- servers = talloc_zero_array(ctx, TID_SRVR_BLK, num_servers);
for (i = 0; i < num_servers; i++) {
jsrvr = json_array_get(jservers, i);
- if (0 != tr_msg_decode_one_server(jsrvr, &servers[i])) {
- talloc_free(servers);
- return NULL;
- }
+ new_srvr=tid_srvr_blk_new(tmp_ctx);
+ if (new_srvr==NULL) {
+ servers=NULL; /* it's all in tmp_ctx, so we can just let go */
+ goto cleanup;
+ }
+
+ if (0 != tr_msg_decode_one_server(jsrvr, new_srvr)) {
+ servers=NULL; /* it's all in tmp_ctx, so we can just let go */
+ goto cleanup;
+ }
+ tid_srvr_blk_add(servers, new_srvr);
}
- *out_len = num_servers;
+
+ talloc_steal(mem_ctx, servers);
+
+cleanup:
+ talloc_free(tmp_ctx);
return servers;
}
tr_debug("tr_msg_decode_tidresp(): Success! result = %s.", json_string_value(jresult));
if ((NULL != (jservers = json_object_get(jresp, "servers"))) ||
(!json_is_array(jservers))) {
- tresp->servers = tr_msg_decode_servers(tresp, jservers, &tresp->num_servers);
+ tresp->servers = tr_msg_decode_servers(tresp, jservers);
}
else {
talloc_free(tresp);
tr_debug("tr_msg_decode_tidresp(): Error! result = %s.", json_string_value(jresult));
if ((NULL != (jerr_msg = json_object_get(jresp, "err_msg"))) ||
(!json_is_string(jerr_msg))) {
- tresp->err_msg = tr_new_name((char *)json_string_value(jerr_msg));
- }
+ tresp->err_msg = tr_new_name(json_string_value(jerr_msg));
+ } else
+ tresp->err_msg = tr_new_name("No error message set.");
+
+ if (NULL !=(tresp->error_path = json_object_get(jresp, "error_path")))
+ json_incref(tresp->error_path);
}
- tresp->rp_realm = tr_new_name((char *)json_string_value(jrp_realm));
- tresp->realm = tr_new_name((char *)json_string_value(jrealm));
- tresp->comm = tr_new_name((char *)json_string_value(jcomm));
+ tresp->rp_realm = tr_new_name(json_string_value(jrp_realm));
+ tresp->realm = tr_new_name(json_string_value(jrealm));
+ tresp->comm = tr_new_name(json_string_value(jcomm));
/* store optional "orig_coi" field */
if ((NULL != (jorig_coi = json_object_get(jresp, "orig_coi"))) &&
(!json_is_object(jorig_coi))) {
- tresp->orig_coi = tr_new_name((char *)json_string_value(jorig_coi));
+ tresp->orig_coi = tr_new_name(json_string_value(jorig_coi));
}
return tresp;
/* Information records for TRP update msg
* requires that jrec already be allocated */
-static TRP_RC tr_msg_encode_inforec_route(json_t *jrec, TRP_INFOREC *rec )
+static TRP_RC tr_msg_encode_inforec_route(json_t *jrec, TRP_INFOREC *rec)
{
json_t *jstr=NULL;
json_t *jint=NULL;
if (rec==NULL)
return TRP_BADTYPE;
- if ((trp_inforec_get_comm(rec)==NULL)
- || (trp_inforec_get_realm(rec)==NULL)
- || (trp_inforec_get_trust_router(rec)==NULL)) {
+ if (trp_inforec_get_trust_router(rec)==NULL)
return TRP_ERROR;
- }
- s=tr_name_strdup(trp_inforec_get_comm(rec));
+ s=tr_name_strdup(trp_inforec_get_trust_router(rec));
if (s==NULL)
return TRP_NOMEM;
jstr=json_string(s);
free(s);s=NULL;
if(jstr==NULL)
return TRP_ERROR;
- json_object_set_new(jrec, "community", jstr);
+ json_object_set_new(jrec, "trust_router", jstr);
+
+ jint=json_integer(trp_inforec_get_metric(rec));
+ if(jint==NULL)
+ return TRP_ERROR;
+ json_object_set_new(jrec, "metric", jint);
- s=tr_name_strdup(trp_inforec_get_realm(rec));
- if (s==NULL)
- return TRP_NOMEM;
- jstr=json_string(s);
- free(s);s=NULL;
+ jint=json_integer(trp_inforec_get_interval(rec));
+ if(jint==NULL)
+ return TRP_ERROR;
+ json_object_set_new(jrec, "interval", jint);
+
+ return TRP_SUCCESS;
+}
+
+/* returns a json array */
+static json_t *tr_msg_encode_apcs(TR_APC *apcs)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_APC_ITER *iter=tr_apc_iter_new(tmp_ctx);
+ TR_APC *apc=NULL;
+ json_t *jarray=NULL;
+ json_t *jid=NULL;
+
+ if (iter==NULL)
+ goto cleanup;
+
+ jarray=json_array();
+ if (jarray==NULL)
+ goto cleanup;
+
+ for (apc=tr_apc_iter_first(iter, apcs); apc!=NULL; apc=tr_apc_iter_next(iter)) {
+ jid=tr_name_to_json_string(tr_apc_get_id(apc));
+ if ((jid==NULL) || (json_array_append_new(jarray, jid)!=0)) {
+ json_decref(jarray);
+ jarray=NULL;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return jarray;
+}
+
+static TR_APC *tr_msg_decode_apcs(TALLOC_CTX *mem_ctx, json_t *jarray, TRP_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ size_t ii=0;
+ TR_APC *apc_list=NULL;
+ TR_APC *new=NULL;
+ json_t *jstr=NULL;
+
+ *rc=TRP_ERROR;
+
+ for (ii=0; ii<json_array_size(jarray); ii++) {
+ jstr=json_array_get(jarray, ii);
+ new=tr_apc_new(tmp_ctx);
+ if ((jstr==NULL) || (new==NULL) || (!json_is_string(jstr))) {
+ apc_list=NULL; /* these are all in tmp_ctx, so they'll still get cleaned up */
+ goto cleanup;
+ }
+
+ tr_apc_set_id(new, tr_new_name(json_string_value(jstr)));
+ if (tr_apc_get_id(new)==NULL) {
+ apc_list=NULL; /* these are all in tmp_ctx, so they'll still get cleaned up */
+ goto cleanup;
+ }
+
+ tr_apc_add(apc_list, new);
+ }
+
+ *rc=TRP_SUCCESS;
+
+ if (apc_list!=NULL)
+ talloc_steal(mem_ctx, apc_list);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return apc_list;
+}
+
+static TRP_RC tr_msg_encode_inforec_comm(json_t *jrec, TRP_INFOREC *rec)
+{
+ json_t *jstr=NULL;
+ json_t *jint=NULL;
+ json_t *japcs=NULL;
+ const char *sconst=NULL;
+ TR_COMM_TYPE commtype=TR_COMM_UNKNOWN;
+
+ if (rec==NULL)
+ return TRP_BADTYPE;
+
+ commtype=trp_inforec_get_comm_type(rec);
+ if (commtype==TR_COMM_UNKNOWN) {
+ tr_notice("tr_msg_encode_inforec_comm: unknown community type.");
+ return TRP_ERROR;
+ }
+ sconst=tr_comm_type_to_str(commtype);
+ if (sconst==NULL)
+ return TRP_ERROR;
+ jstr=json_string(sconst);
if(jstr==NULL)
return TRP_ERROR;
- json_object_set_new(jrec, "realm", jstr);
+ json_object_set_new(jrec, "type", jstr);
- s=tr_name_strdup(trp_inforec_get_trust_router(rec));
- if (s==NULL)
- return TRP_NOMEM;
- jstr=json_string(s);
- free(s);s=NULL;
+ sconst=tr_realm_role_to_str(trp_inforec_get_role(rec));
+ if (sconst==NULL) {
+ tr_notice("tr_msg_encode_inforec_comm: unknown realm role.");
+ return TRP_ERROR;
+ }
+ jstr=json_string(sconst);
if(jstr==NULL)
return TRP_ERROR;
- json_object_set_new(jrec, "trust_router", jstr);
+ json_object_set_new(jrec, "role", jstr);
- jint=json_integer(trp_inforec_get_metric(rec));
- if(jint==NULL)
+ japcs=tr_msg_encode_apcs(trp_inforec_get_apcs(rec));
+ if (japcs==NULL) {
+ tr_notice("tr_msg_encode_inforec_comm: error encoding APCs.");
return TRP_ERROR;
- json_object_set_new(jrec, "metric", jint);
+ }
+ json_object_set_new(jrec, "apcs", japcs);
+
+
+ if (trp_inforec_get_owner_realm(rec)!=NULL) {
+ jstr=tr_name_to_json_string(trp_inforec_get_owner_realm(rec));
+ if(jstr==NULL)
+ return TRP_ERROR;
+ json_object_set_new(jrec, "owner_realm", jstr);
+ }
+
+ if (trp_inforec_get_owner_contact(rec)!=NULL) {
+ jstr=tr_name_to_json_string(trp_inforec_get_owner_contact(rec));
+ if(jstr==NULL)
+ return TRP_ERROR;
+ json_object_set_new(jrec, "owner_contact", jstr);
+ }
+
+ json_object_set(jrec, "provenance", trp_inforec_get_provenance(rec));
jint=json_integer(trp_inforec_get_interval(rec));
if(jint==NULL)
return NULL;
}
break;
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (TRP_SUCCESS!=tr_msg_encode_inforec_comm(jrec, rec)) {
+ json_decref(jrec);
+ return NULL;
+ }
+ break;
default:
json_decref(jrec);
return NULL;
return jrec;
}
-/* decode a single record */
-static TRP_INFOREC *tr_msg_decode_trp_inforec(TALLOC_CTX *mem_ctx, json_t *jrecord)
+static TRP_RC tr_msg_decode_trp_inforec_route(json_t *jrecord, TRP_INFOREC *rec)
{
TALLOC_CTX *tmp_ctx=talloc_new(NULL);
- TRP_INFOREC_TYPE rectype;
- TRP_INFOREC *rec=NULL;
TRP_RC rc=TRP_ERROR;
char *s=NULL;
int num=0;
-
- if (0!=tr_msg_get_json_string(jrecord, "record_type", &s, tmp_ctx))
- goto cleanup;
- rectype=trp_inforec_type_from_string(s);
+ rc=tr_msg_get_json_string(jrecord, "trust_router", &s, tmp_ctx);
+ if (rc != TRP_SUCCESS)
+ goto cleanup;
+ if (TRP_SUCCESS!=trp_inforec_set_trust_router(rec, tr_new_name(s))) {
+ rc=TRP_ERROR;
+ goto cleanup;
+ }
talloc_free(s); s=NULL;
- rec=trp_inforec_new(tmp_ctx, rectype);
- if (rec==NULL) {
- rc=TRP_NOMEM;
+ trp_inforec_set_next_hop(rec, NULL); /* make sure this is null (filled in later) */
+
+ rc=tr_msg_get_json_integer(jrecord, "metric", &num);
+ if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_metric(rec,num)))
goto cleanup;
- }
- /* We only support route_info records for now*/
- if (trp_inforec_get_type(rec)!=TRP_INFOREC_TYPE_ROUTE) {
- rc=TRP_UNSUPPORTED;
+ rc=tr_msg_get_json_integer(jrecord, "interval", &num);
+ if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_interval(rec,num)))
goto cleanup;
- }
- tr_debug("tr_msg_decode_trp_inforec: '%s' record found.", trp_inforec_type_to_string(rec->type));
+cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static TRP_RC tr_msg_decode_trp_inforec_comm(json_t *jrecord, TRP_INFOREC *rec)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TRP_RC rc=TRP_ERROR;
+ char *s=NULL;
+ int num=0;
+ TR_APC *apcs=NULL;
- rc=tr_msg_get_json_string(jrecord, "community", &s, tmp_ctx);
+ rc=tr_msg_get_json_string(jrecord, "type", &s, tmp_ctx);
if (rc != TRP_SUCCESS)
goto cleanup;
- if (TRP_SUCCESS!=trp_inforec_set_comm(rec, tr_new_name(s)))
+ if (TRP_SUCCESS!=trp_inforec_set_comm_type(rec, tr_comm_type_from_str(s))) {
+ rc=TRP_ERROR;
goto cleanup;
+ }
talloc_free(s); s=NULL;
- rc=tr_msg_get_json_string(jrecord, "realm", &s, tmp_ctx);
+ rc=tr_msg_get_json_string(jrecord, "role", &s, tmp_ctx);
if (rc != TRP_SUCCESS)
goto cleanup;
- if (TRP_SUCCESS!=trp_inforec_set_realm(rec, tr_new_name(s)))
+ if (TRP_SUCCESS!=trp_inforec_set_role(rec, tr_realm_role_from_str(s))) {
+ rc=TRP_ERROR;
goto cleanup;
+ }
talloc_free(s); s=NULL;
- rc=tr_msg_get_json_string(jrecord, "trust_router", &s, tmp_ctx);
- if (rc != TRP_SUCCESS)
+ apcs=tr_msg_decode_apcs(rec, json_object_get(jrecord, "apcs"), &rc);
+ if (rc!=TRP_SUCCESS) {
+ rc=TRP_ERROR;
goto cleanup;
- if (TRP_SUCCESS!=trp_inforec_set_trust_router(rec, tr_new_name(s)))
+ }
+ trp_inforec_set_apcs(rec, apcs);
+
+ rc=tr_msg_get_json_integer(jrecord, "interval", &num);
+ tr_debug("tr_msg_decode_trp_inforec_comm: interval=%u", num);
+ if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_interval(rec,num)))
goto cleanup;
- talloc_free(s); s=NULL;
- trp_inforec_set_next_hop(rec, NULL); /* make sure this is null (filled in later) */
+ trp_inforec_set_provenance(rec, json_object_get(jrecord, "provenance"));
- rc=tr_msg_get_json_integer(jrecord, "metric", &num);
- if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_metric(rec,num)))
+ /* optional */
+ rc=tr_msg_get_json_string(jrecord, "owner_realm", &s, tmp_ctx);
+ if (rc == TRP_SUCCESS) {
+ if (TRP_SUCCESS!=trp_inforec_set_owner_realm(rec, tr_new_name(s))) {
+ rc=TRP_ERROR;
+ goto cleanup;
+ }
+ if (s!=NULL) {
+ talloc_free(s);
+ s=NULL;
+ }
+ }
+
+ rc=tr_msg_get_json_string(jrecord, "owner_contact", &s, tmp_ctx);
+ if (rc == TRP_SUCCESS) {
+ if (TRP_SUCCESS!=trp_inforec_set_owner_contact(rec, tr_new_name(s))) {
+ rc=TRP_ERROR;
+ goto cleanup;
+ }
+ if (s!=NULL) {
+ talloc_free(s);
+ s=NULL;
+ }
+ }
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+/* decode a single record */
+static TRP_INFOREC *tr_msg_decode_trp_inforec(TALLOC_CTX *mem_ctx, json_t *jrecord)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TRP_INFOREC_TYPE rectype;
+ TRP_INFOREC *rec=NULL;
+ TRP_RC rc=TRP_ERROR;
+ char *s=NULL;
+
+ if (TRP_SUCCESS!=tr_msg_get_json_string(jrecord, "record_type", &s, tmp_ctx))
goto cleanup;
- rc=tr_msg_get_json_integer(jrecord, "interval", &num);
- if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_interval(rec,num)))
+ rectype=trp_inforec_type_from_string(s);
+ talloc_free(s); s=NULL;
+
+ rec=trp_inforec_new(tmp_ctx, rectype);
+ if (rec==NULL) {
+ rc=TRP_NOMEM;
goto cleanup;
+ }
+
+ tr_debug("tr_msg_decode_trp_inforec: '%s' record found.", trp_inforec_type_to_string(rec->type));
+
+ switch(trp_inforec_get_type(rec)) {
+ case TRP_INFOREC_TYPE_ROUTE:
+ rc=tr_msg_decode_trp_inforec_route(jrecord, rec);
+ break;
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ rc=tr_msg_decode_trp_inforec_comm(jrecord, rec);
+ break;
+ default:
+ rc=TRP_UNSUPPORTED;
+ goto cleanup;
+ }
talloc_steal(mem_ctx, rec);
rc=TRP_SUCCESS;
json_t *jupdate=NULL;
json_t *jrecords=NULL;
json_t *jrec=NULL;
+ json_t *jstr=NULL;
TRP_INFOREC *rec;
+ char *s=NULL;
if (update==NULL)
return NULL;
if (jupdate==NULL)
return NULL;
+ s=tr_name_strdup(trp_upd_get_comm(update));
+ if (s==NULL) {
+ json_decref(jupdate);
+ return NULL;
+ }
+ jstr=json_string(s);
+ free(s);s=NULL;
+ if(jstr==NULL) {
+ json_decref(jupdate);
+ return NULL;
+ }
+ json_object_set_new(jupdate, "community", jstr);
+
+ s=tr_name_strdup(trp_upd_get_realm(update));
+ if (s==NULL) {
+ json_decref(jupdate);
+ return NULL;
+ }
+ jstr=json_string(s);
+ free(s);s=NULL;
+ if(jstr==NULL) {
+ json_decref(jupdate);
+ return NULL;
+ }
+ json_object_set_new(jupdate, "realm", jstr);
+
jrecords=json_array();
if (jrecords==NULL) {
json_decref(jupdate);
return jupdate;
}
-/*Creates a linked list of records in the msg->body talloc context.
+/* Creates a linked list of records in the msg->body talloc context.
* An error will be returned if any unparseable records are encountered.
*/
static TRP_UPD *tr_msg_decode_trp_upd(TALLOC_CTX *mem_ctx, json_t *jupdate)
TRP_UPD *update=NULL;
TRP_INFOREC *new_rec=NULL;
TRP_INFOREC *list_tail=NULL;
+ char *s=NULL;
+ TR_NAME *name;
TRP_RC rc=TRP_ERROR;
update=trp_upd_new(tmp_ctx);
goto cleanup;
}
+ rc=tr_msg_get_json_string(jupdate, "community", &s, tmp_ctx);
+ if (rc != TRP_SUCCESS) {
+ tr_debug("tr_msg_decode_trp_upd: no community in TRP update message.");
+ rc=TRP_NOPARSE;
+ goto cleanup;
+ }
+ name=tr_new_name(s);
+ if (name==NULL) {
+ tr_debug("tr_msg_decode_trp_upd: could not allocate community name.");
+ rc=TRP_NOMEM;
+ goto cleanup;
+ }
+ talloc_free(s); s=NULL;
+ trp_upd_set_comm(update, name);
+
+ rc=tr_msg_get_json_string(jupdate, "realm", &s, tmp_ctx);
+ if (rc != TRP_SUCCESS) {
+ tr_debug("tr_msg_decode_trp_upd: no realm in TRP update message.");
+ rc=TRP_NOPARSE;
+ goto cleanup;
+ }
+ name=tr_new_name(s);
+ if (name==NULL) {
+ tr_debug("tr_msg_decode_trp_upd: could not allocate realm name.");
+ rc=TRP_NOMEM;
+ goto cleanup;
+ }
+ talloc_free(s); s=NULL;
+ trp_upd_set_realm(update, name);
+
jrecords=json_object_get(jupdate, "records");
if ((jrecords==NULL) || (!json_is_array(jrecords))) {
rc=TRP_NOPARSE;
}
encoded=json_dumps(jmsg, 0);
+ tr_debug("tr_msg_encode: outgoing msg=%s", encoded);
json_decref(jmsg);
return encoded;
}
msg->msg_type = TR_UNKNOWN;
msg->msg_rep = NULL;
}
+
+ json_decref(jmsg);
+
return msg;
}
#include <stdlib.h>
#include <string.h>
+#include <jansson.h>
#include <trust_router/tr_name.h>
return s;
}
+json_t *tr_name_to_json_string(TR_NAME *src)
+{
+ char *s=tr_name_strdup(src);
+ json_t *js=json_string(s);
+ if (s!=NULL)
+ free(s);
+ return js;
+}
+
TR_NAME *tr_name_cat(TR_NAME *n1, TR_NAME *n2)
{
char *s=malloc(n1->len+n2->len+1);
return client;
}
-TR_RP_CLIENT *tr_rp_client_add(TR_RP_CLIENT *clients, TR_RP_CLIENT *new)
+/* 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;
return NULL;
}
+TR_RP_REALM *tr_rp_realm_lookup(TR_RP_REALM *rp_realms, TR_NAME *rp_name)
+{
+ TR_RP_REALM *rp = NULL;
+
+ if (!rp_name) {
+ tr_debug("tr_rp_realm_lookup: Bad parameters.");
+ return NULL;
+ }
+
+ for (rp=rp_realms; NULL!=rp; rp=rp->next) {
+ if (0==tr_name_cmp(tr_rp_realm_get_id(rp), rp_name))
+ return rp;
+ }
+ return NULL;
+}
+
+static int tr_rp_realm_destructor(void *obj)
+{
+ TR_RP_REALM *rp=talloc_get_type_abort(obj, TR_RP_REALM);
+ if (rp->realm_id!=NULL)
+ tr_free_name(rp->realm_id);
+ return 0;
+}
+
+TR_RP_REALM *tr_rp_realm_new(TALLOC_CTX *mem_ctx)
+{
+ TR_RP_REALM *rp=talloc(mem_ctx, TR_RP_REALM);
+ if (rp!=NULL) {
+ rp->next=NULL;
+ rp->realm_id=NULL;
+ rp->refcount=0;
+ talloc_set_destructor((void *)rp, tr_rp_realm_destructor);
+ }
+ return rp;
+}
+
+void tr_rp_realm_free(TR_RP_REALM *rp)
+{
+ talloc_free(rp);
+}
+
/* talloc note: lists of idp realms should be assembled using
* tr_idp_realm_add(). This will put all of the elements in the
* list, other than the head, as children of the head context.
static TR_RP_REALM *tr_rp_realm_tail(TR_RP_REALM *realm)
{
- while (realm!=NULL)
+ if (realm==NULL)
+ return NULL;
+
+ while (realm->next!=NULL)
realm=realm->next;
return realm;
}
-/* for correct behavior, call like: rp_realms=tr_rp_realm_add(rp_realms, new_realm); */
-TR_RP_REALM *tr_rp_realm_add(TR_RP_REALM *head, TR_RP_REALM *new)
+/* for correct behavior, call like: rp_realms=tr_rp_realm_add_func(rp_realms, new_realm);
+ * or better yet, use the macro */
+TR_RP_REALM *tr_rp_realm_add_func(TR_RP_REALM *head, TR_RP_REALM *new)
{
if (head==NULL)
head=new;
}
return head;
}
+
+/* use the macro */
+TR_RP_REALM *tr_rp_realm_remove_func(TR_RP_REALM *head, TR_RP_REALM *remove)
+{
+ TALLOC_CTX *list_ctx=talloc_parent(head);
+ TR_RP_REALM *this=NULL;
+
+ if (head==NULL)
+ return NULL;
+
+ if (head==remove) {
+ /* if we're removing the head, put the next element (if present) into the context
+ * the list head was in. */
+ head=head->next;
+ if (head!=NULL) {
+ talloc_steal(list_ctx, head);
+ /* now put all the other elements in the context of the list head */
+ for (this=head->next; this!=NULL; this=this->next)
+ talloc_steal(head, this);
+ }
+ } else {
+ /* not removing the head; no need to play with contexts */
+ for (this=head; this->next!=NULL; this=this->next) {
+ if (this->next==remove) {
+ this->next=remove->next;
+ break;
+ }
+ }
+ }
+ return head;
+}
+
+void tr_rp_realm_incref(TR_RP_REALM *realm)
+{
+ realm->refcount++;
+}
+
+void tr_rp_realm_decref(TR_RP_REALM *realm)
+{
+ if (realm->refcount>0)
+ realm->refcount--;
+}
+
+/* remove any with zero refcount
+ * Call via macro. */
+TR_RP_REALM *tr_rp_realm_sweep_func(TR_RP_REALM *head)
+{
+ TR_RP_REALM *rp=NULL;
+ TR_RP_REALM *old_next=NULL;
+
+ if (head==NULL)
+ return NULL;
+
+ while ((head!=NULL) && (head->refcount==0)) {
+ rp=head; /* keep a pointer so we can remove it */
+ tr_rp_realm_remove(head, rp); /* use this to get talloc contexts right */
+ tr_rp_realm_free(rp);
+ }
+
+ if (head==NULL)
+ return NULL;
+
+ /* will not remove the head here, that has already been done */
+ for (rp=head; rp->next!=NULL; rp=rp->next) {
+ if (rp->next->refcount==0) {
+ old_next=rp->next;
+ tr_rp_realm_remove(head, rp->next); /* changes rp->next */
+ tr_rp_realm_free(old_next);
+ }
+ }
+
+ return head;
+}
+
+TR_NAME *tr_rp_realm_get_id(TR_RP_REALM *rp)
+{
+ if (rp==NULL)
+ return NULL;
+
+ return rp->realm_id;
+}
+
+TR_NAME *tr_rp_realm_dup_id(TR_RP_REALM *rp)
+{
+ if (rp==NULL)
+ return NULL;
+
+ return tr_dup_name(tr_rp_realm_get_id(rp));
+}
+
+void tr_rp_realm_set_id(TR_RP_REALM *rp, TR_NAME *id)
+{
+ if (rp->realm_id!=NULL)
+ tr_free_name(rp->realm_id);
+ rp->realm_id=id;
+}
+
+char *tr_rp_realm_to_str(TALLOC_CTX *mem_ctx, TR_RP_REALM *rp)
+{
+ return talloc_asprintf(mem_ctx,
+ "RP realm: \"%.*s\"\n",
+ rp->realm_id->len, rp->realm_id->buf);
+}
#include <assert.h>
#include <stdio.h>
#include <string.h>
+#include <time.h>
#include <trust_router/tr_dh.h>
+#include <tr_util.h>
void tr_bin_to_hex(const unsigned char * bin, size_t bin_len,
char * hex_out, size_t hex_len)
}
}
+/* Returns 0 if ts1==ts2, <0 if ts1<ts2, >= if ts1>ts2.
+ * Assumes that tv_nsec <= 1e9. */
+int tr_cmp_timespec(struct timespec *ts1, struct timespec *ts2)
+{
+ if (ts1->tv_sec > ts2->tv_sec)
+ return 1;
+
+ if (ts1->tv_sec < ts2->tv_sec)
+ return -1;
+
+ /* ts1->tv_sec==ts2->tv_sec */
+
+ if (ts1->tv_nsec > ts2->tv_nsec)
+ return 1;
+
+ if (ts1->tv_nsec < ts2->tv_nsec)
+ return -1;
+
+ return 0;
+}
AC_PREREQ(2.63)
-AC_INIT([trust_router],[1.5.2],
+AC_INIT([trust_router],[2.1.1],
[bugs@project-moonshot.org])
AC_CONFIG_MACRO_DIR(m4)
AC_CONFIG_AUX_DIR(build-aux)
#include <gsscon.h>
/* ---------------------------------------------------------------------------
-*/
+ */
int gsscon_connect (const char *inHost, unsigned int inPort, const char *inServiceName, int *outFD, gss_ctx_id_t *outGSSContext)
{
- int err = 0;
- int fd = -1;
- OM_uint32 majorStatus;
- OM_uint32 minorStatus = 0, minorStatusToo = 0;
- struct hostent *hp = NULL;
- struct sockaddr_in saddr;
- gss_name_t serviceName = NULL;
- gss_name_t clientName = NULL;
- gss_cred_id_t clientCredentials = GSS_C_NO_CREDENTIAL;
- gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT;
- OM_uint32 actualFlags = 0;
- char *inputTokenBuffer = NULL;
- size_t inputTokenBufferLength = 0;
- gss_buffer_desc inputToken; /* buffer received from the server */
- gss_buffer_desc nameBuffer;
- gss_buffer_t inputTokenPtr = GSS_C_NO_BUFFER;
- char *name;
+ int err = 0;
+ int fd = -1;
+ OM_uint32 majorStatus;
+ OM_uint32 minorStatus = 0, minorStatusToo = 0;
+ struct addrinfo *ai=NULL;
+ struct addrinfo *ai_head=NULL;
+ struct addrinfo hints={.ai_family=AF_UNSPEC, .ai_socktype=SOCK_STREAM, .ai_protocol=IPPROTO_TCP};
+ struct sockaddr_in saddr;
+ char *port=NULL;
+ gss_name_t serviceName = NULL;
+ gss_name_t clientName = NULL;
+ gss_cred_id_t clientCredentials = GSS_C_NO_CREDENTIAL;
+ gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT;
+ OM_uint32 actualFlags = 0;
+ char *inputTokenBuffer = NULL;
+ size_t inputTokenBufferLength = 0;
+ gss_buffer_desc inputToken; /* buffer received from the server */
+ gss_buffer_desc nameBuffer;
+ gss_buffer_t inputTokenPtr = GSS_C_NO_BUFFER;
+ char *name;
- if (!inServiceName) { err = EINVAL; }
- if (!outGSSContext) { err = EINVAL; }
-
- if (!err) {
- hp = gethostbyname (inHost);
- if (hp == NULL) { err = h_errno; }
- }
+ if (!inServiceName) { err = EINVAL; }
+ if (!outGSSContext) { err = EINVAL; }
- if (!err) {
- saddr.sin_family = hp->h_addrtype;
- memcpy ((char *) &saddr.sin_addr, hp->h_addr, sizeof (saddr.sin_addr));
- saddr.sin_port = htons(inPort);
-
- fd = socket (AF_INET, SOCK_STREAM, 0);
- if (fd < 0) { err = errno; }
- }
+ if (!err) {
+ /* get a string for getaddrinfo */
+ if (asprintf(&port, "%d", inPort)>0) {
+ err=getaddrinfo(inHost, port, &hints, &ai_head);
+ free(port);
+ } else
+ err=1;
+ }
- if (!err) {
- fprintf (stderr, "gss_connect: Connecting to host '%s' on port %d\n", inHost, inPort);
- err = connect (fd, (struct sockaddr *) &saddr, sizeof (saddr));
- if (err < 0) { err = errno; }
+ if (!err) {
+ /* try all options returned until one works */
+ for (ai=ai_head,fd=-1; (ai!=NULL) && (fd==-1); ai=ai->ai_next) {
+ fd=socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (fd < 0) {
+ fd=-1;
+ continue;
+ }
+
+ fprintf(stderr, "gss_connect: Connecting to host '%s' on port %d\n", inHost, inPort);
+ err=connect(fd, ai->ai_addr, ai->ai_addrlen);
+ if (err!=0) {
+ close(fd);
+ fd=-1;
+ continue;
+ }
}
+
+ if (fd==-1)
+ err=1;
+ }
- if (!err) {
- *outFD = fd;
- fd = -1; /* takes ownership */
- } else {
- gsscon_print_error (err, "OpenConnection failed");
- }
+ if (!err) {
+ *outFD = fd;
+ fd = -1; /* takes ownership */
+ } else {
+ gsscon_print_error (err, "OpenConnection failed");
+ }
- if (fd >= 0) { close (fd); }
+ if (fd >= 0) { close (fd); }
- if (!err) {
- majorStatus = gss_acquire_cred (&minorStatus, clientName, GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
- GSS_C_INITIATE, &clientCredentials, NULL, NULL);
- if (majorStatus != GSS_S_COMPLETE) {
- gsscon_print_gss_errors ("gss_acquire_cred", majorStatus, minorStatus);
- err = minorStatus ? minorStatus : majorStatus;
- }
+ if (!err) {
+ majorStatus = gss_acquire_cred (&minorStatus, clientName, GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
+ GSS_C_INITIATE, &clientCredentials, NULL, NULL);
+ if (majorStatus != GSS_S_COMPLETE) {
+ gsscon_print_gss_errors ("gss_acquire_cred", majorStatus, minorStatus);
+ err = minorStatus ? minorStatus : majorStatus;
}
+ }
- /*
- * Here is where the client picks the service principal it will
- * try to use to connect to the server. In the case of the
- * gssClientSample, the service principal is passed in on the
- * command line, however, in a real world example, this would be
- * unacceptable from a user interface standpoint since the user
- * shouldn't need to know the server's service principal.
- *
- * In traditional Kerberos setups, the service principal would be
- * constructed from the type of the service (eg: "imap"), the DNS
- * hostname of the server (eg: "mailserver.domain.com") and the
- * client's local realm (eg: "DOMAIN.COM") to form a full
- * principal string (eg: "imap/mailserver.domain.com@DOMAIN.COM").
- *
- * Now that many sites do not have DNS, this setup is becoming
- * less common. However you decide to generate the service
- * principal, you need to adhere to the following constraint: The
- * service principal must be constructed by the client, typed in
- * by the user or administrator, or transmitted to the client in a
- * secure manner from a trusted third party -- such as through an
- * encrypted connection to a directory server. You should not
- * have the server send the client the service principal name as
- * part of the authentication negotiation.
- *
- * The reason you can't let the server tell the client which
- * principal to use is that many machines at a site will have
- * their own service principal and keytab which identifies the
- * machine -- in a Windows Active Directory environment all
- * machines have a service principal and keytab. Some of these
- * machines (such as a financial services server) will be more
- * trustworthy than others (such as a random machine on a
- * coworker's desk). If the owner of one of these untrustworthy
- * machines can trick the client into using the untrustworthy
- * machine's principal instead of the financial services server's
- * principal, then he can trick the client into authenticating and
- * connecting to the untrustworthy machine. The untrustworthy
- * machine can then harvest any confidential information the
- * client sends to it, such as credit card information or social
- * security numbers.
- *
- * If your protocol already involves sending the service principal
- * as part of your authentication negotiation, your client should
- * cache the name it gets after the first successful
- * authentication so that the problem above can only happen on the
- * first connection attempt -- similar to what ssh does with host
- * keys.
- */
+ /*
+ * Here is where the client picks the service principal it will
+ * try to use to connect to the server. In the case of the
+ * gssClientSample, the service principal is passed in on the
+ * command line, however, in a real world example, this would be
+ * unacceptable from a user interface standpoint since the user
+ * shouldn't need to know the server's service principal.
+ *
+ * In traditional Kerberos setups, the service principal would be
+ * constructed from the type of the service (eg: "imap"), the DNS
+ * hostname of the server (eg: "mailserver.domain.com") and the
+ * client's local realm (eg: "DOMAIN.COM") to form a full
+ * principal string (eg: "imap/mailserver.domain.com@DOMAIN.COM").
+ *
+ * Now that many sites do not have DNS, this setup is becoming
+ * less common. However you decide to generate the service
+ * principal, you need to adhere to the following constraint: The
+ * service principal must be constructed by the client, typed in
+ * by the user or administrator, or transmitted to the client in a
+ * secure manner from a trusted third party -- such as through an
+ * encrypted connection to a directory server. You should not
+ * have the server send the client the service principal name as
+ * part of the authentication negotiation.
+ *
+ * The reason you can't let the server tell the client which
+ * principal to use is that many machines at a site will have
+ * their own service principal and keytab which identifies the
+ * machine -- in a Windows Active Directory environment all
+ * machines have a service principal and keytab. Some of these
+ * machines (such as a financial services server) will be more
+ * trustworthy than others (such as a random machine on a
+ * coworker's desk). If the owner of one of these untrustworthy
+ * machines can trick the client into using the untrustworthy
+ * machine's principal instead of the financial services server's
+ * principal, then he can trick the client into authenticating and
+ * connecting to the untrustworthy machine. The untrustworthy
+ * machine can then harvest any confidential information the
+ * client sends to it, such as credit card information or social
+ * security numbers.
+ *
+ * If your protocol already involves sending the service principal
+ * as part of your authentication negotiation, your client should
+ * cache the name it gets after the first successful
+ * authentication so that the problem above can only happen on the
+ * first connection attempt -- similar to what ssh does with host
+ * keys.
+ */
- if (!err) {
- nameBuffer.length = asprintf(&name, "%s@%s", inServiceName, inHost);
- nameBuffer.value = name;
+ if (!err) {
+ nameBuffer.length = asprintf(&name, "%s@%s", inServiceName, inHost);
+ nameBuffer.value = name;
- majorStatus = gss_import_name (&minorStatus, &nameBuffer, (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &serviceName);
- if (majorStatus != GSS_S_COMPLETE) {
- gsscon_print_gss_errors ("gss_import_name(inServiceName)", majorStatus, minorStatus);
- err = minorStatus ? minorStatus : majorStatus;
- }
+ majorStatus = gss_import_name (&minorStatus, &nameBuffer, (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &serviceName);
+ if (majorStatus != GSS_S_COMPLETE) {
+ gsscon_print_gss_errors ("gss_import_name(inServiceName)", majorStatus, minorStatus);
+ err = minorStatus ? minorStatus : majorStatus;
}
+ }
- /*
- * The main authentication loop:
- *
- * GSS is a multimechanism API. Because the number of packet
- * exchanges required to authenticate can vary between mechanisms,
- * we need to loop calling gss_init_sec_context, passing the
- * "input tokens" received from the server and send the resulting
- * "output tokens" back until we get GSS_S_COMPLETE or an error.
- */
+ /*
+ * The main authentication loop:
+ *
+ * GSS is a multimechanism API. Because the number of packet
+ * exchanges required to authenticate can vary between mechanisms,
+ * we need to loop calling gss_init_sec_context, passing the
+ * "input tokens" received from the server and send the resulting
+ * "output tokens" back until we get GSS_S_COMPLETE or an error.
+ */
- majorStatus = GSS_S_CONTINUE_NEEDED;
+ majorStatus = GSS_S_CONTINUE_NEEDED;
- gss_OID_desc EAP_OID = { 9, "\x2B\x06\x01\x05\x05\x0F\x01\x01\x11" };
+ gss_OID_desc EAP_OID = { 9, "\x2B\x06\x01\x05\x05\x0F\x01\x01\x11" };
- while (!err && (majorStatus != GSS_S_COMPLETE)) {
- gss_buffer_desc outputToken = { 0, NULL }; /* buffer to send to the server */
- OM_uint32 requestedFlags = (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG |
- GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG);
+ while (!err && (majorStatus != GSS_S_COMPLETE)) {
+ gss_buffer_desc outputToken = { 0, NULL }; /* buffer to send to the server */
+ OM_uint32 requestedFlags = (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG |
+ GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG);
- majorStatus = gss_init_sec_context (&minorStatus,
- clientCredentials,
- &gssContext,
- serviceName,
- &EAP_OID /* mech_type */,
- requestedFlags,
- GSS_C_INDEFINITE,
- GSS_C_NO_CHANNEL_BINDINGS,
- inputTokenPtr,
- NULL /* actual_mech_type */,
- &outputToken,
- &actualFlags,
- NULL /* time_rec */);
+ majorStatus = gss_init_sec_context (&minorStatus,
+ clientCredentials,
+ &gssContext,
+ serviceName,
+ &EAP_OID /* mech_type */,
+ requestedFlags,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ inputTokenPtr,
+ NULL /* actual_mech_type */,
+ &outputToken,
+ &actualFlags,
+ NULL /* time_rec */);
- /* Send the output token to the server (even on error) */
- if ((outputToken.length > 0) && (outputToken.value != NULL)) {
- err = gsscon_write_token (*outFD, outputToken.value, outputToken.length);
+ /* Send the output token to the server (even on error) */
+ if ((outputToken.length > 0) && (outputToken.value != NULL)) {
+ err = gsscon_write_token (*outFD, outputToken.value, outputToken.length);
- /* free the output token */
- gss_release_buffer (&minorStatusToo, &outputToken);
- }
+ /* free the output token */
+ gss_release_buffer (&minorStatusToo, &outputToken);
+ }
- if (!err) {
- if (majorStatus == GSS_S_CONTINUE_NEEDED) {
- /* Protocol requires another packet exchange */
+ if (!err) {
+ if (majorStatus == GSS_S_CONTINUE_NEEDED) {
+ /* Protocol requires another packet exchange */
- /* Clean up old input buffer */
- if (inputTokenBuffer) {
- free (inputTokenBuffer);
- inputTokenBuffer = NULL; /* don't double-free */
- }
+ /* Clean up old input buffer */
+ if (inputTokenBuffer) {
+ free (inputTokenBuffer);
+ inputTokenBuffer = NULL; /* don't double-free */
+ }
- /* Read another input token from the server */
- err = gsscon_read_token (*outFD, &inputTokenBuffer, &inputTokenBufferLength);
+ /* Read another input token from the server */
+ err = gsscon_read_token (*outFD, &inputTokenBuffer, &inputTokenBufferLength);
- if (!err) {
- /* Set up input buffers for the next run through the loop */
- inputToken.value = inputTokenBuffer;
- inputToken.length = inputTokenBufferLength;
- inputTokenPtr = &inputToken;
- }
- } else if (majorStatus != GSS_S_COMPLETE) {
- gsscon_print_gss_errors ("gss_init_sec_context", majorStatus, minorStatus);
- err = minorStatus ? minorStatus : majorStatus;
- }
+ if (!err) {
+ /* Set up input buffers for the next run through the loop */
+ inputToken.value = inputTokenBuffer;
+ inputToken.length = inputTokenBufferLength;
+ inputTokenPtr = &inputToken;
}
+ } else if (majorStatus != GSS_S_COMPLETE) {
+ gsscon_print_gss_errors ("gss_init_sec_context", majorStatus, minorStatus);
+ err = minorStatus ? minorStatus : majorStatus;
+ }
}
+ }
- if (!err) {
- *outGSSContext = gssContext;
- gssContext = NULL;
- } else {
- gsscon_print_error (err, "AuthenticateToServer failed");
- }
+ if (!err) {
+ *outGSSContext = gssContext;
+ gssContext = NULL;
+ } else {
+ gsscon_print_error (err, "AuthenticateToServer failed");
+ }
- if (inputTokenBuffer) { free (inputTokenBuffer); }
- if (serviceName ) { gss_release_name (&minorStatus, &serviceName); }
- if (clientName ) { gss_release_name (&minorStatus, &clientName); }
-
- if (clientCredentials != GSS_C_NO_CREDENTIAL) {
- gss_release_cred (&minorStatus, &clientCredentials); }
- if (gssContext != GSS_C_NO_CONTEXT) {
- gss_delete_sec_context (&minorStatus, &gssContext, GSS_C_NO_BUFFER); }
+ if (inputTokenBuffer) { free (inputTokenBuffer); }
+ if (serviceName ) { gss_release_name (&minorStatus, &serviceName); }
+ if (clientName ) { gss_release_name (&minorStatus, &clientName); }
+ if (ai_head ) { freeaddrinfo(ai_head); }
+
+ if (clientCredentials != GSS_C_NO_CREDENTIAL) {
+ gss_release_cred (&minorStatus, &clientCredentials); }
+ if (gssContext != GSS_C_NO_CONTEXT) {
+ gss_delete_sec_context (&minorStatus, &gssContext, GSS_C_NO_BUFFER); }
- return err;
+ return err;
}
const char *gServiceName = NULL;
-int gsscon_passive_authenticate (int inSocket,
- gss_buffer_desc inNameBuffer,
- gss_ctx_id_t *outGSSContext,
- client_cb_fn clientCb,
- void *clientCbData)
+int gsscon_passive_authenticate (int inSocket,
+ gss_buffer_desc inNameBuffer,
+ gss_ctx_id_t *outGSSContext,
+ client_cb_fn clientCb,
+ void *clientCbData)
{
- int err = 0;
- OM_uint32 majorStatus;
- OM_uint32 minorStatus = 0, minorStatusToo = 0;
- gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT;
- gss_name_t clientName = GSS_C_NO_NAME, serviceName = GSS_C_NO_NAME;
- gss_cred_id_t acceptorCredentials = NULL;
- gss_buffer_desc clientDisplayName = {0, NULL};
- char *inputTokenBuffer = NULL;
- size_t inputTokenBufferLength = 0;
- gss_buffer_desc inputToken; /* buffer received from the server */
+ int err = 0;
+ OM_uint32 majorStatus;
+ OM_uint32 minorStatus = 0, minorStatusToo = 0;
+ gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT;
+ gss_name_t clientName = GSS_C_NO_NAME, serviceName = GSS_C_NO_NAME;
+ gss_cred_id_t acceptorCredentials = NULL;
+ gss_buffer_desc clientDisplayName = {0, NULL};
+ char *inputTokenBuffer = NULL;
+ size_t inputTokenBufferLength = 0;
+ gss_buffer_desc inputToken; /* buffer received from the server */
- if (inSocket < 0 ) { err = EINVAL; }
- if (!outGSSContext) { err = EINVAL; }
+ if (inSocket < 0 ) { err = EINVAL; }
+ if (!outGSSContext) { err = EINVAL; }
- if (!err) {
- majorStatus = gss_import_name (&minorStatus, &inNameBuffer, (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &serviceName);
- if (majorStatus != GSS_S_COMPLETE) {
- gsscon_print_gss_errors ("gss_import_name(serviceName)", majorStatus, minorStatus);
- err = minorStatus ? minorStatus : majorStatus;
- }
+ if (!err) {
+ majorStatus = gss_import_name (&minorStatus, &inNameBuffer, (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &serviceName);
+ if (majorStatus != GSS_S_COMPLETE) {
+ gsscon_print_gss_errors ("gss_import_name(serviceName)", majorStatus, minorStatus);
+ err = minorStatus ? minorStatus : majorStatus;
}
+ }
- if (!err) {
- majorStatus = gss_acquire_cred ( &minorStatus, serviceName,
- GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
- GSS_C_ACCEPT, &acceptorCredentials,
- NULL /*mechs out*/, NULL /*time out*/);
- if (majorStatus != GSS_S_COMPLETE) {
- gsscon_print_gss_errors ("gss_acquire_cred", majorStatus, minorStatus);
- err = minorStatus ? minorStatus : majorStatus;
- }
+ if (!err) {
+ majorStatus = gss_acquire_cred ( &minorStatus, serviceName,
+ GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
+ GSS_C_ACCEPT, &acceptorCredentials,
+ NULL /*mechs out*/, NULL /*time out*/);
+ if (majorStatus != GSS_S_COMPLETE) {
+ gsscon_print_gss_errors ("gss_acquire_cred", majorStatus, minorStatus);
+ err = minorStatus ? minorStatus : majorStatus;
}
+ }
- /*
- * The main authentication loop:
- *
- * GSS is a multimechanism API. The number of packet exchanges required to
- * authenticatevaries between mechanisms. As a result, we need to loop reading
- * input tokens from the client, calling gss_accept_sec_context on the input
- * tokens and send the resulting output tokens back to the client until we
- * get GSS_S_COMPLETE or an error.
- *
- * When we are done, save the client principal so we can make authorization
- * checks.
- */
+ /*
+ * The main authentication loop:
+ *
+ * GSS is a multimechanism API. The number of packet exchanges required to
+ * authenticatevaries between mechanisms. As a result, we need to loop reading
+ * input tokens from the client, calling gss_accept_sec_context on the input
+ * tokens and send the resulting output tokens back to the client until we
+ * get GSS_S_COMPLETE or an error.
+ *
+ * When we are done, save the client principal so we can make authorization
+ * checks.
+ */
- majorStatus = GSS_S_CONTINUE_NEEDED;
- while (!err && (majorStatus != GSS_S_COMPLETE)) {
- /* Clean up old input buffer */
- if (inputTokenBuffer != NULL) {
- free (inputTokenBuffer);
- inputTokenBuffer = NULL; /* don't double-free */
- }
+ majorStatus = GSS_S_CONTINUE_NEEDED;
+ while (!err && (majorStatus != GSS_S_COMPLETE)) {
+ /* Clean up old input buffer */
+ if (inputTokenBuffer != NULL) {
+ free (inputTokenBuffer);
+ inputTokenBuffer = NULL; /* don't double-free */
+ }
- err = gsscon_read_token (inSocket, &inputTokenBuffer, &inputTokenBufferLength);
+ err = gsscon_read_token (inSocket, &inputTokenBuffer, &inputTokenBufferLength);
- if (!err) {
- /* Set up input buffers for the next run through the loop */
- inputToken.value = inputTokenBuffer;
- inputToken.length = inputTokenBufferLength;
- }
+ if (!err) {
+ /* Set up input buffers for the next run through the loop */
+ inputToken.value = inputTokenBuffer;
+ inputToken.length = inputTokenBufferLength;
+ }
- if (!err) {
- /* buffer to send to the server */
- gss_buffer_desc outputToken = { 0, NULL };
+ if (!err) {
+ /* buffer to send to the server */
+ gss_buffer_desc outputToken = { 0, NULL };
- /*
- * accept_sec_context does the actual work of taking the client's
- * request and generating an appropriate reply. */
- majorStatus = gss_accept_sec_context (&minorStatus,
- &gssContext,
- acceptorCredentials,
- &inputToken,
- GSS_C_NO_CHANNEL_BINDINGS,
- &clientName,
- NULL /* actual_mech_type */,
- &outputToken,
- NULL /* req_flags */,
- NULL /* time_rec */,
- NULL /* delegated_cred_handle */);
+ /*
+ * accept_sec_context does the actual work of taking the client's
+ * request and generating an appropriate reply. */
+ majorStatus = gss_accept_sec_context (&minorStatus,
+ &gssContext,
+ acceptorCredentials,
+ &inputToken,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &clientName,
+ NULL /* actual_mech_type */,
+ &outputToken,
+ NULL /* req_flags */,
+ NULL /* time_rec */,
+ NULL /* delegated_cred_handle */);
- if ((outputToken.length > 0) && (outputToken.value != NULL)) {
- /* Send the output token to the client (even on error) */
- err = gsscon_write_token (inSocket, outputToken.value, outputToken.length);
+ if ((outputToken.length > 0) && (outputToken.value != NULL)) {
+ /* Send the output token to the client (even on error) */
+ err = gsscon_write_token (inSocket, outputToken.value, outputToken.length);
- /* free the output token */
- gss_release_buffer (&minorStatusToo, &outputToken);
- }
- }
+ /* free the output token */
+ gss_release_buffer (&minorStatusToo, &outputToken);
+ }
+ }
- if ((majorStatus != GSS_S_COMPLETE) && (majorStatus != GSS_S_CONTINUE_NEEDED)) {
- gsscon_print_gss_errors ("gss_accept_sec_context", majorStatus, minorStatus);
- err = minorStatus ? minorStatus : majorStatus;
- }
+ if ((majorStatus != GSS_S_COMPLETE) && (majorStatus != GSS_S_CONTINUE_NEEDED)) {
+ gsscon_print_gss_errors ("gss_accept_sec_context", majorStatus, minorStatus);
+ err = minorStatus ? minorStatus : majorStatus;
}
+ }
- if (!err) {
- majorStatus = gss_display_name(&minorStatus, clientName, &clientDisplayName, NULL);
- if (GSS_ERROR(majorStatus)) {
- gsscon_print_gss_errors("gss_display_name", majorStatus, minorStatus);
- err = EINVAL;
- }
- if (!err)
- err = clientCb(clientName, &clientDisplayName, clientCbData);
+ if (!err) {
+ majorStatus = gss_display_name(&minorStatus, clientName, &clientDisplayName, NULL);
+ if (GSS_ERROR(majorStatus)) {
+ gsscon_print_gss_errors("gss_display_name", majorStatus, minorStatus);
+ err = EINVAL;
}
+ if (!err)
+ err = clientCb(clientName, &clientDisplayName, clientCbData);
+ }
- if (!err) {
- *outGSSContext = gssContext;
- gssContext = NULL;
- } else {
- gsscon_print_error (err, "Authenticate failed");
- }
+ if (!err) {
+ *outGSSContext = gssContext;
+ gssContext = NULL;
+ } else {
+ gsscon_print_error (err, "Authenticate failed");
+ }
- if (inputTokenBuffer) { free (inputTokenBuffer); }
- if (gssContext != GSS_C_NO_CONTEXT) {
- gss_delete_sec_context (&minorStatus, &gssContext, GSS_C_NO_BUFFER); }
-if (clientName != GSS_C_NO_NAME)
- gss_release_name(&minorStatus, &clientName);
-if (clientDisplayName.value != NULL)
- gss_release_buffer(&minorStatus, &clientDisplayName);
- gss_release_name( &minorStatus, &serviceName);
- gss_release_cred( &minorStatus, &acceptorCredentials);
+ if (inputTokenBuffer) { free (inputTokenBuffer); }
+ if (gssContext != GSS_C_NO_CONTEXT) {
+ gss_delete_sec_context (&minorStatus, &gssContext, GSS_C_NO_BUFFER); }
+ if (clientName != GSS_C_NO_NAME)
+ gss_release_name(&minorStatus, &clientName);
+ if (clientDisplayName.value != NULL)
+ gss_release_buffer(&minorStatus, &clientDisplayName);
+ gss_release_name( &minorStatus, &serviceName);
+ gss_release_cred( &minorStatus, &acceptorCredentials);
- return err;
+ return err;
}
static int ClientPrincipalIsAuthorizedForService (const char *inClientPrincipal)
{
- int err = 0;
- /*
- * Here is where the server checks to see if the client principal should
- * be allowed to use your service. Typically it should check both the name
- * and the realm, since with cross-realm shared keys, a user at another
- * realm may be trying to contact your service.
- */
- err = 0;
+ int err = 0;
+ /*
+ * Here is where the server checks to see if the client principal should
+ * be allowed to use your service. Typically it should check both the name
+ * and the realm, since with cross-realm shared keys, a user at another
+ * realm may be trying to contact your service.
+ */
+ err = 0;
- return err;
+ return err;
}
/* --------------------------------------------------------------------------- */
int *outAuthorized,
int *outAuthorizationError)
{
- int err = 0;
- OM_uint32 majorStatus;
- OM_uint32 minorStatus = 0;
- gss_name_t clientName = NULL;
- gss_name_t serviceName = NULL;
- char *clientPrincipal = NULL;
- char *servicePrincipal = NULL;
+ int err = 0;
+ OM_uint32 majorStatus;
+ OM_uint32 minorStatus = 0;
+ gss_name_t clientName = NULL;
+ gss_name_t serviceName = NULL;
+ char *clientPrincipal = NULL;
+ char *servicePrincipal = NULL;
- if (!inContext ) { err = EINVAL; }
- if (!outAuthorized ) { err = EINVAL; }
- if (!outAuthorizationError) { err = EINVAL; }
+ if (!inContext ) { err = EINVAL; }
+ if (!outAuthorized ) { err = EINVAL; }
+ if (!outAuthorizationError) { err = EINVAL; }
- if (!err) {
- /* Get the client and service principals used to authenticate */
- majorStatus = gss_inquire_context (&minorStatus,
- inContext,
- &clientName,
- &serviceName,
- NULL, NULL, NULL, NULL, NULL);
- if (majorStatus != GSS_S_COMPLETE) {
- err = minorStatus ? minorStatus : majorStatus;
- }
+ if (!err) {
+ /* Get the client and service principals used to authenticate */
+ majorStatus = gss_inquire_context (&minorStatus,
+ inContext,
+ &clientName,
+ &serviceName,
+ NULL, NULL, NULL, NULL, NULL);
+ if (majorStatus != GSS_S_COMPLETE) {
+ err = minorStatus ? minorStatus : majorStatus;
}
+ }
- if (!err) {
- /* Pull the client principal string out of the gss name */
- gss_buffer_desc nameToken;
+ if (!err) {
+ /* Pull the client principal string out of the gss name */
+ gss_buffer_desc nameToken;
- majorStatus = gss_display_name (&minorStatus,
- clientName,
- &nameToken,
- NULL);
- if (majorStatus != GSS_S_COMPLETE) {
- err = minorStatus ? minorStatus : majorStatus;
- }
+ majorStatus = gss_display_name (&minorStatus,
+ clientName,
+ &nameToken,
+ NULL);
+ if (majorStatus != GSS_S_COMPLETE) {
+ err = minorStatus ? minorStatus : majorStatus;
+ }
- if (!err) {
- clientPrincipal = malloc (nameToken.length + 1);
- if (clientPrincipal == NULL) { err = ENOMEM; }
- }
+ if (!err) {
+ clientPrincipal = malloc (nameToken.length + 1);
+ if (clientPrincipal == NULL) { err = ENOMEM; }
+ }
- if (!err) {
- memcpy (clientPrincipal, nameToken.value, nameToken.length);
- clientPrincipal[nameToken.length] = '\0';
- }
+ if (!err) {
+ memcpy (clientPrincipal, nameToken.value, nameToken.length);
+ clientPrincipal[nameToken.length] = '\0';
+ }
- if (nameToken.value) { gss_release_buffer (&minorStatus, &nameToken); }
- }
+ if (nameToken.value) { gss_release_buffer (&minorStatus, &nameToken); }
+ }
- if (!err) {
+ if (!err) {
// /* Pull the service principal string out of the gss name */
// gss_buffer_desc nameToken;
//
// }
- int authorizationErr = 0;
- authorizationErr = ClientPrincipalIsAuthorizedForService (clientPrincipal);
+ int authorizationErr = 0;
+ authorizationErr = ClientPrincipalIsAuthorizedForService (clientPrincipal);
// printf ("'%s' is%s authorized for service '%s'\n",
// clientPrincipal, authorizationErr ? " NOT" : "", servicePrincipal);
//
- *outAuthorized = !authorizationErr;
- *outAuthorizationError = authorizationErr;
- }
+ *outAuthorized = !authorizationErr;
+ *outAuthorizationError = authorizationErr;
+ }
- if (serviceName ) { gss_release_name (&minorStatus, &serviceName); }
- if (clientName ) { gss_release_name (&minorStatus, &clientName); }
- if (clientPrincipal ) { free (clientPrincipal); }
- if (servicePrincipal) { free (servicePrincipal); }
+ if (serviceName ) { gss_release_name (&minorStatus, &serviceName); }
+ if (clientName ) { gss_release_name (&minorStatus, &clientName); }
+ if (clientPrincipal ) { free (clientPrincipal); }
+ if (servicePrincipal) { free (servicePrincipal); }
- return err;
+ return err;
}
#include <jansson.h>
struct tid_srvr_blk {
- struct in_addr aaa_server_addr;
+ TID_SRVR_BLK *next;
+ char *aaa_server_addr;
TR_NAME *key_name;
DH *aaa_server_dh; /* AAA server's public dh information */
GTimeVal key_expiration; /**< absolute time at which key expires*/
- json_t *path;/**< Path of trust routers that the request traversed*/
+ TID_PATH *path;/**< Path of trust routers that the request traversed*/
};
struct tid_resp {
TR_CONSTRAINT_SET *cons;
TR_NAME *orig_coi;
TID_SRVR_BLK *servers; /* array of servers */
- size_t num_servers;
json_t *error_path; /**< Path that a request generating an error traveled*/
};
};
struct tidc_instance {
- TID_REQ *req_list;
+ // TID_REQ *req_list;
// TBD -- Do we still need a separate private key */
// char *priv_key;
// int priv_len;
char *ipaddr;
const char *hostname;
TIDS_REQ_FUNC *req_handler;
- TIDS_AUTH_FUNC *auth_handler;
+ tids_auth_func *auth_handler;
void *cookie;
uint16_t tids_port;
struct tr_rp_client *rp_gss; /* Client matching GSS name */
};
-
/** Decrement a reference to #json when this tid_req is cleaned up. A
new reference is not created; in effect the caller is handing a
reference they already hold to the TID_REQ.*/
void tid_req_cleanup_json(TID_REQ *, json_t *json);
int tid_req_add_path(TID_REQ *, const char *this_system, unsigned port);
+
+TID_SRVR_BLK *tid_srvr_blk_new(TALLOC_CTX *mem_ctx);
+void tid_srvr_blk_free(TID_SRVR_BLK *srvr);
+TID_SRVR_BLK *tid_srvr_blk_dup(TALLOC_CTX *mem_ctx, TID_SRVR_BLK *srvr);
+TID_SRVR_BLK *tid_srvr_blk_add_func(TID_SRVR_BLK *head, TID_SRVR_BLK *new);
+#define tid_srvr_blk_add(head, new) ((head)=tid_srvr_blk_add_func((head),(new)))
+void tid_srvr_blk_set_path(TID_SRVR_BLK *block, TID_PATH *path);
+
+void tid_resp_set_cons(TID_RESP *resp, TR_CONSTRAINT_SET *cons);
+void tid_resp_set_error_path(TID_RESP *resp, json_t *ep);
+
#endif
TR_NAME *id;
} TR_APC;
+/* iterator is just a pointer to a TR_APC */
+typedef TR_APC *TR_APC_ITER;
+
TR_APC *tr_apc_new(TALLOC_CTX *mem_ctx);
void tr_apc_free(TR_APC *apc);
-TR_APC *tr_apc_add(TR_APC *apcs, TR_APC *new);
+TR_APC *tr_apc_add_func(TR_APC *apcs, TR_APC *new);
+#define tr_apc_add(apcs,new) ((apcs)=tr_apc_add_func((apcs),(new)))
+TR_APC *tr_apc_dup_one(TALLOC_CTX *mem_ctx, TR_APC *apc);
TR_APC *tr_apc_dup(TALLOC_CTX *mem_ctx, TR_APC *apc);
void tr_apc_set_id(TR_APC *apc, TR_NAME *id);
char *tr_apc_to_str(TALLOC_CTX *mem_ctx, TR_APC *apc);
+TR_APC_ITER *tr_apc_iter_new(TALLOC_CTX *mem_ctx);
+TR_APC *tr_apc_iter_first(TR_APC_ITER *iter, TR_APC *apc);
+TR_APC *tr_apc_iter_next(TR_APC_ITER *iter);
+void tr_apc_iter_free(TR_APC_ITER *iter);
+
+int tr_apc_in_common(TR_APC *one, TR_APC *two);
+
#endif
#ifndef TR_COMM_H
#define TR_COMM_H
+#include <stdio.h>
+#include <talloc.h>
+#include <time.h>
+
#include <tr_idp.h>
#include <tr_rp.h>
#include <tr_apc.h>
+typedef struct tr_comm_table TR_COMM_TABLE;
+
typedef enum tr_comm_type {
TR_COMM_UNKNOWN,
TR_COMM_APC,
TR_NAME *id;
TR_COMM_TYPE type;
TR_APC *apcs;
- TR_IDP_REALM *idp_realms;
- TR_RP_REALM *rp_realms;
+ TR_NAME *owner_realm; /* what realm owns this community? */
+ TR_NAME *owner_contact; /* contact email */
time_t expiration_interval; /*Minutes to key expiration; only valid for an APC*/
+ unsigned int refcount; /* how many TR_COMM_MEMBs refer to this community? */
} TR_COMM;
+/* community membership - link realms to their communities */
+typedef struct tr_comm_memb {
+ struct tr_comm_memb *next;
+ struct tr_comm_memb *origin_next; /* for multiple copies from different origins */
+ TR_IDP_REALM *idp; /* only set one of idp and rp, other null */
+ TR_RP_REALM *rp; /* only set one of idp and rp, other null */
+ TR_COMM *comm;
+ TR_NAME *origin;
+ json_t *provenance; /* array of names of systems traversed */
+ unsigned int interval;
+ struct timespec *expiry;
+ unsigned int times_expired; /* how many times has this expired? */
+ int triggered; /* do we need to send this with triggered updates? */
+} TR_COMM_MEMB;
+
+/* table of communities/memberships */
+struct tr_comm_table {
+ TR_COMM *comms; /* all communities */
+ TR_IDP_REALM *idp_realms; /* all idp realms */
+ TR_RP_REALM *rp_realms; /* all rp realms */
+ TR_COMM_MEMB *memberships; /* head of the linked list of membership records */
+};
+
+typedef enum tr_realm_role {
+ TR_ROLE_UNKNOWN=0,
+ TR_ROLE_IDP,
+ TR_ROLE_RP
+} TR_REALM_ROLE;
+
+typedef struct tr_realm {
+ TR_REALM_ROLE role;
+ TR_RP_REALM *rp;
+ TR_IDP_REALM *idp;
+} TR_REALM;
+
+/* nb, not all iterator routines use all members */
+typedef struct tr_comm_iter {
+ TR_COMM *cur_comm;
+ TR_COMM_MEMB *cur_memb;
+ TR_COMM_MEMB *cur_orig_head; /* for iterating along orig_next list */
+ TR_NAME *match; /* realm or comm to match */
+ TR_REALM *realm; /* handle so caller does not have to manage memory, private */
+} TR_COMM_ITER;
+
+
+TR_COMM_TABLE *tr_comm_table_new(TALLOC_CTX *mem_ctx);
+void tr_comm_table_free(TR_COMM_TABLE *ctab);
+
+TR_COMM_TABLE *tr_comm_table_new(TALLOC_CTX *mem_ctx);
+void tr_comm_table_free(TR_COMM_TABLE *ctab);
+void tr_comm_table_sweep(TR_COMM_TABLE *ctab);
+void tr_comm_table_add_comm(TR_COMM_TABLE *ctab, TR_COMM *new);
+void tr_comm_table_remove_comm(TR_COMM_TABLE *ctab, TR_COMM *comm);
+TR_RP_REALM *tr_comm_table_find_rp_realm(TR_COMM_TABLE *ctab, TR_NAME *realm_id);
+void tr_comm_table_add_rp_realm(TR_COMM_TABLE *ctab, TR_RP_REALM *new);
+void tr_comm_table_remove_rp_realm(TR_COMM_TABLE *ctab, TR_RP_REALM *realm);
+TR_IDP_REALM *tr_comm_table_find_idp_realm(TR_COMM_TABLE *ctab, TR_NAME *realm_id);
+void tr_comm_table_add_idp_realm(TR_COMM_TABLE *ctab, TR_IDP_REALM *new);
+void tr_comm_table_remove_idp_realm(TR_COMM_TABLE *ctab, TR_IDP_REALM *realm);
+void tr_comm_table_add_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *new);
+void tr_comm_table_remove_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *memb);
+TR_COMM_MEMB *tr_comm_table_find_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin);
+TR_COMM_MEMB *tr_comm_table_find_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm);
+TR_COMM_MEMB *tr_comm_table_find_rp_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *rp_realm, TR_NAME *comm, TR_NAME *origin);
+TR_COMM_MEMB *tr_comm_table_find_rp_memb(TR_COMM_TABLE *ctab, TR_NAME *rp_realm, TR_NAME *comm);
+TR_COMM_MEMB *tr_comm_table_find_idp_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *idp_realm, TR_NAME *comm, TR_NAME *origin);
+TR_COMM_MEMB *tr_comm_table_find_idp_memb(TR_COMM_TABLE *ctab, TR_NAME *idp_realm, TR_NAME *comm);
+TR_COMM *tr_comm_table_find_comm(TR_COMM_TABLE *ctab, TR_NAME *comm_id);
+size_t tr_comm_table_size(TR_COMM_TABLE *ctab);
+void tr_comm_table_print(FILE *f, TR_COMM_TABLE *ctab);
+
+TR_COMM_MEMB *tr_comm_memb_new(TALLOC_CTX *mem_ctx);
+void tr_comm_memb_free(TR_COMM_MEMB *memb);
+int tr_comm_memb_cmp(TR_COMM_MEMB *m1, TR_COMM_MEMB *m2);
+TR_REALM_ROLE tr_comm_memb_get_role(TR_COMM_MEMB *memb);
+void tr_comm_memb_set_rp_realm(TR_COMM_MEMB *memb, TR_RP_REALM *realm);
+TR_RP_REALM *tr_comm_memb_get_rp_realm(TR_COMM_MEMB *memb);
+void tr_comm_memb_set_idp_realm(TR_COMM_MEMB *memb, TR_IDP_REALM *realm);
+TR_IDP_REALM *tr_comm_memb_get_idp_realm(TR_COMM_MEMB *memb);
+TR_NAME *tr_comm_memb_get_realm_id(TR_COMM_MEMB *memb);
+void tr_comm_memb_set_comm(TR_COMM_MEMB *memb, TR_COMM *comm);
+TR_COMM *tr_comm_memb_get_comm(TR_COMM_MEMB *memb);
+TR_NAME *tr_comm_memb_get_origin(TR_COMM_MEMB *memb);
+TR_NAME *tr_comm_memb_dup_origin(TR_COMM_MEMB *memb);
+json_t *tr_comm_memb_get_provenance(TR_COMM_MEMB *memb);
+void tr_comm_memb_set_provenance(TR_COMM_MEMB *memb, json_t *prov);
+void tr_comm_memb_add_to_provenance(TR_COMM_MEMB *memb, TR_NAME *hop);
+size_t tr_comm_memb_provenance_len(TR_COMM_MEMB *memb);
+void tr_comm_memb_set_interval(TR_COMM_MEMB *memb, unsigned int interval);
+unsigned int tr_comm_memb_get_interval(TR_COMM_MEMB *memb);
+void tr_comm_memb_set_expiry(TR_COMM_MEMB *memb, struct timespec *time);
+struct timespec *tr_comm_memb_get_expiry(TR_COMM_MEMB *memb);
+int tr_comm_memb_is_expired(TR_COMM_MEMB *memb, struct timespec *curtime);
+void tr_comm_memb_set_triggered(TR_COMM_MEMB *memb, int trig);
+int tr_comm_memb_is_triggered(TR_COMM_MEMB *memb);
+void tr_comm_memb_reset_times_expired(TR_COMM_MEMB *memb);
+void tr_comm_memb_expire(TR_COMM_MEMB *memb);
+unsigned int tr_comm_memb_get_times_expired(TR_COMM_MEMB *memb);
+
TR_COMM *tr_comm_new(TALLOC_CTX *mem_ctx);
void tr_comm_free(TR_COMM *comm);
-TR_COMM *tr_comm_add(TR_COMM *comms, TR_COMM *new);
-void tr_comm_add_idp_realm(TR_COMM *comm, TR_IDP_REALM *realm);
-void tr_comm_add_rp_realm(TR_COMM *comm, TR_RP_REALM *realm);
-TR_COMM *tr_comm_lookup(TR_COMM *comms, TR_NAME *comm_name);
-TR_RP_REALM *tr_find_comm_rp (TR_COMM *comm, TR_NAME *rp_realm);
-TR_IDP_REALM *tr_find_comm_idp (TR_COMM *comm, TR_NAME *idp_realm);
+void tr_comm_set_id(TR_COMM *comm, TR_NAME *id);
+TR_NAME *tr_comm_get_id(TR_COMM *comm);
+TR_NAME *tr_comm_dup_id(TR_COMM *comm);
+void tr_comm_set_apcs(TR_COMM *comm, TR_APC *apc);
+TR_APC *tr_comm_get_apcs(TR_COMM *comm);
+void tr_comm_set_type(TR_COMM *comm, TR_COMM_TYPE type);
+TR_COMM_TYPE tr_comm_get_type(TR_COMM *comm);
+void tr_comm_set_owner_realm(TR_COMM *comm, TR_NAME *realm);
+TR_NAME *tr_comm_get_owner_realm(TR_COMM *comm);
+TR_NAME *tr_comm_dup_owner_realm(TR_COMM *comm);
+void tr_comm_set_owner_contact(TR_COMM *comm, TR_NAME *contact);
+TR_NAME *tr_comm_get_owner_contact(TR_COMM *comm);
+TR_NAME *tr_comm_dup_owner_contact(TR_COMM *comm);
+void tr_comm_add_idp_realm(TR_COMM_TABLE *ctab, TR_COMM *comm, TR_IDP_REALM *realm, unsigned int interval, json_t *provenance, struct timespec *expiry);
+void tr_comm_add_rp_realm(TR_COMM_TABLE *ctab, TR_COMM *comm, TR_RP_REALM *realm, unsigned int interval, json_t *provenance, struct timespec *expiry);
+TR_RP_REALM *tr_comm_find_rp(TR_COMM_TABLE *ctab, TR_COMM *comm, TR_NAME *rp_realm);
+TR_IDP_REALM *tr_comm_find_idp(TR_COMM_TABLE *ctab, TR_COMM *comm, TR_NAME *idp_realm);
+const char *tr_comm_type_to_str(TR_COMM_TYPE type);
+TR_COMM_TYPE tr_comm_type_from_str(const char *s);
+void tr_comm_incref(TR_COMM *comm);
+void tr_comm_decref(TR_COMM *comm);
+unsigned int tr_comm_get_refcount(TR_COMM *comm);
+
+/* for iterating over communities within a realm or realms within a community */
+TR_COMM_ITER *tr_comm_iter_new(TALLOC_CTX *mem_ctx);
+void tr_comm_iter_free(TR_COMM_ITER *iter);
+
+/* iterate over all communities in a table */
+TR_COMM *tr_comm_table_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab);
+TR_COMM *tr_comm_table_iter_next(TR_COMM_ITER *);
+
+/* these iterate over communities for a realm */
+TR_COMM *tr_comm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *realm);
+TR_COMM *tr_comm_iter_next(TR_COMM_ITER *iter);
+TR_COMM *tr_comm_iter_first_rp(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *realm);
+TR_COMM *tr_comm_iter_next_rp(TR_COMM_ITER *iter);
+TR_COMM *tr_comm_iter_first_idp(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *realm);
+TR_COMM *tr_comm_iter_next_idp(TR_COMM_ITER *iter);
+
+/* iterate over realms for a community */
+TR_REALM *tr_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm);
+TR_REALM *tr_realm_iter_next(TR_COMM_ITER *iter);
+TR_RP_REALM *tr_rp_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm);
+TR_RP_REALM *tr_rp_realm_iter_next(TR_COMM_ITER *iter);
+TR_IDP_REALM *tr_idp_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm);
+TR_IDP_REALM *tr_idp_realm_iter_next(TR_COMM_ITER *iter);
+
+/* iterate over members with different origins */
+TR_COMM_MEMB *tr_comm_memb_iter_first(TR_COMM_ITER *iter, TR_COMM_MEMB *memb);
+TR_COMM_MEMB *tr_comm_memb_iter_next(TR_COMM_ITER *iter);
+
+/* iterate over all members */
+TR_COMM_MEMB *tr_comm_memb_iter_all_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab);
+TR_COMM_MEMB *tr_comm_memb_iter_all_next(TR_COMM_ITER *iter);
+
+/* general realm stuff, should probably move */
+TR_NAME *tr_realm_get_id(TR_REALM *realm);
+TR_NAME *tr_realm_dup_id(TR_REALM *realm);
+
+const char *tr_realm_role_to_str(TR_REALM_ROLE role);
+TR_REALM_ROLE tr_realm_role_from_str(const char *s);
#endif
#include <trp_internal.h>
#define TR_DEFAULT_MAX_TREE_DEPTH 12
-#define TR_DEFAULT_TR_PORT 12308
+#define TR_DEFAULT_TRPS_PORT 12308
#define TR_DEFAULT_TIDS_PORT 12309
-#define TR_DEFAULT_TRPS_PORT 12310
#define TR_DEFAULT_LOG_THRESHOLD LOG_INFO
#define TR_DEFAULT_CONSOLE_THRESHOLD LOG_NOTICE
#define TR_DEFAULT_APC_EXPIRATION_INTERVAL 43200
#define TR_DEFAULT_TRP_CONNECT_INTERVAL 10
-#define TR_DEFAULT_TRP_UPDATE_INTERVAL 120
+#define TR_DEFAULT_TRP_UPDATE_INTERVAL 30
#define TR_DEFAULT_TRP_SWEEP_INTERVAL 30
+#define TR_DEFAULT_TID_REQ_TIMEOUT 5
+#define TR_DEFAULT_TID_RESP_NUMER 2
+#define TR_DEFAULT_TID_RESP_DENOM 3
typedef enum tr_cfg_rc {
TR_CFG_SUCCESS = 0, /* No error */
unsigned int trp_sweep_interval;
unsigned int trp_update_interval;
unsigned int trp_connect_interval;
+ 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_CFG_INTERNAL;
typedef struct tr_cfg {
TR_CFG_INTERNAL *internal; /* internal trust router config */
- TR_IDP_REALM *idp_realms; /* locally associated IDP Realms */
TR_RP_CLIENT *rp_clients; /* locally associated RP Clients */
TRP_PTABLE *peers; /* TRP peer table */
- TR_COMM *comms; /* locally-known communities */
+ TR_COMM_TABLE *ctable; /* communities/realms */
TR_AAA_SERVER *default_servers; /* default server list */
/* TBD -- Global Filters */
} TR_CFG;
void tr_cfg_mgr_free(TR_CFG_MGR *cfg);
void tr_print_config(TR_CFG *cfg);
-void tr_print_comms(TR_COMM *comm_list);
-void tr_print_comm_idps(TR_IDP_REALM *idp_list);
-void tr_print_comm_rps(TR_RP_REALM *rp_list);
+void tr_print_comms(TR_COMM_TABLE *ctab);
+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);
#include <event2/event.h>
+#define TR_MAX_SOCKETS 10
+
/* struct for hanging on to a socket listener event */
struct tr_socket_event {
- int sock_fd; /* the fd for the socket */
- struct event *ev; /* its event */
+ size_t 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 */
};
/* prototypes */
#define TR_IDP_H
#include <talloc.h>
+#include <time.h>
#include <trust_router/tr_name.h>
#include <tr_apc.h>
TR_NAME *hostname;
} TR_AAA_SERVER;
+typedef struct tr_aaa_server_iter {
+ TR_AAA_SERVER *this;
+} TR_AAA_SERVER_ITER;
+
/* may also want to use in tr_rp.h */
typedef enum tr_realm_origin {
TR_REALM_LOCAL=0, /* realm we were configured to contact */
TR_AAA_SERVER *aaa_servers;
TR_APC *apcs;
TR_REALM_ORIGIN origin; /* how did we learn about this realm? */
+ unsigned int refcount; /* how many TR_COMM_MEMBs refer to this realm */
} TR_IDP_REALM;
TR_IDP_REALM *tr_idp_realm_new(TALLOC_CTX *mem_ctx);
-TR_IDP_REALM *tr_idp_realm_add(TR_IDP_REALM *head, TR_IDP_REALM *new);
+void tr_idp_realm_free(TR_IDP_REALM *idp);
+TR_NAME *tr_idp_realm_get_id(TR_IDP_REALM *idp);
+TR_NAME *tr_idp_realm_dup_id(TR_IDP_REALM *idp);
+void tr_idp_realm_set_id(TR_IDP_REALM *idp, TR_NAME *id);
+void tr_idp_realm_set_apcs(TR_IDP_REALM *idp, TR_APC *apc);
+TR_APC *tr_idp_realm_get_apcs(TR_IDP_REALM *idp);
+TR_IDP_REALM *tr_idp_realm_lookup(TR_IDP_REALM *idp_realms, TR_NAME *idp_name);
+TR_IDP_REALM *tr_idp_realm_add_func(TR_IDP_REALM *head, TR_IDP_REALM *new);
+#define tr_idp_realm_add(head,new) ((head)=tr_idp_realm_add_func((head),(new)))
+TR_IDP_REALM *tr_idp_realm_remove_func(TR_IDP_REALM *head, TR_IDP_REALM *remove);
+#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);
+void tr_idp_realm_incref(TR_IDP_REALM *realm);
+void tr_idp_realm_decref(TR_IDP_REALM *realm);
TR_AAA_SERVER *tr_aaa_server_new(TALLOC_CTX *mem_ctx, TR_NAME *hostname);
void tr_aaa_server_free(TR_AAA_SERVER *aaa);
-TR_AAA_SERVER *tr_idp_aaa_server_lookup(TR_IDP_REALM *idp_realms, TR_NAME *idp_realm_name, TR_NAME *comm);
+TR_AAA_SERVER_ITER *tr_aaa_server_iter_new(TALLOC_CTX *mem_ctx);
+void tr_aaa_server_iter_free(TR_AAA_SERVER_ITER *iter);
+TR_AAA_SERVER *tr_aaa_server_iter_first(TR_AAA_SERVER_ITER *iter, TR_AAA_SERVER *aaa);
+TR_AAA_SERVER *tr_aaa_server_iter_next(TR_AAA_SERVER_ITER *iter);
+
+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);
#endif
#include <talloc.h>
#include <pthread.h>
+#include <time.h>
/* Note on mq priorities: High priority messages are guaranteed to be
* processed before any normal priority messages. Otherwise, messages
typedef void (*TR_MQ_NOTIFY_FN)(TR_MQ *, void *);
struct tr_mq {
pthread_mutex_t mutex;
+ pthread_cond_t have_msg_cond;
TR_MQ_MSG *head;
TR_MQ_MSG *tail;
TR_MQ_MSG *last_hi_prio;
int tr_mq_unlock(TR_MQ *mq);
void tr_mq_set_notify_cb(TR_MQ *mq, TR_MQ_NOTIFY_FN cb, void *arg);
void tr_mq_add(TR_MQ *mq, TR_MQ_MSG *msg);
-TR_MQ_MSG *tr_mq_pop(TR_MQ *mq);
+int tr_mq_pop_timeout(time_t seconds, struct timespec *ts);
+TR_MQ_MSG *tr_mq_pop(TR_MQ *mq, struct timespec *ts_abort);
void tr_mq_clear(TR_MQ *mq);
#endif /*_TR_MQ_H_ */
/* Structure to make a linked list of RP realms by name for community config */
typedef struct tr_rp_realm {
struct tr_rp_realm *next;
- TR_NAME *realm_name;
+ TR_NAME *realm_id;
+ unsigned int refcount; /* how many TR_COMM_MEMBs refer to this 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(TR_RP_CLIENT *clients, TR_RP_CLIENT *new);
+TR_RP_CLIENT *tr_rp_client_add_func(TR_RP_CLIENT *clients, TR_RP_CLIENT *new);
+#define tr_rp_client_add(clients,new) ((clients)=tr_rp_client_add_func((clients),(new)))
int tr_rp_client_add_gss_name(TR_RP_CLIENT *client, TR_NAME *name);
int tr_rp_client_set_filter(TR_RP_CLIENT *client, TR_FILTER *filt);
-
TR_RP_CLIENT *tr_rp_client_lookup(TR_RP_CLIENT *rp_clients, TR_NAME *gss_name);
-TR_RP_REALM *tr_rp_realm_add(TR_RP_REALM *head, TR_RP_REALM *new);
+
+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);
+TR_NAME *tr_rp_realm_dup_id(TR_RP_REALM *rp);
+void tr_rp_realm_set_id(TR_RP_REALM *rp, TR_NAME *id);
+TR_RP_REALM *tr_rp_realm_lookup(TR_RP_REALM *rp_realms, TR_NAME *rp_name);
+TR_RP_REALM *tr_rp_realm_add_func(TR_RP_REALM *head, TR_RP_REALM *new);
+#define tr_rp_realm_add(head,new) ((head)=tr_rp_realm_add_func((head),(new)))
+TR_RP_REALM *tr_rp_realm_remove_func(TR_RP_REALM *head, TR_RP_REALM *remove);
+#define tr_rp_realm_remove(head,remove) ((head)=tr_rp_realm_remove_func((head),(remove)))
+TR_RP_REALM *tr_rp_realm_sweep_func(TR_RP_REALM *head);
+#define tr_rp_realm_sweep(head) ((head)=tr_rp_realm_sweep_func((head)))
+void tr_rp_realm_incref(TR_RP_REALM *realm);
+void tr_rp_realm_decref(TR_RP_REALM *realm);
+
+char *tr_rp_realm_to_str(TALLOC_CTX *mem_ctx, TR_RP_REALM *rp);
+
#endif
#include <tr_event.h>
#include <tr_config.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,
--- /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_UTIL_H
+#define TR_UTIL_H
+
+#include <trust_router/tr_versioning.h>
+
+TR_EXPORT int tr_cmp_timespec(struct timespec *ts1, struct timespec *ts2);
+
+#endif /* TR_UTIL_H */
#ifndef TRP_INTERNAL_H
#define TRP_INTERNAL_H
+#include <jansson.h>
#include <pthread.h>
#include <talloc.h>
+#include <time.h>
#include <gsscon.h>
#include <tr_mq.h>
#include <tr_msg.h>
#include <trp_ptable.h>
#include <trp_rtable.h>
+#include <tr_apc.h>
+#include <tr_comm.h>
#include <trust_router/trp.h>
+/* what clock do we use with clock_gettime() ? */
+#define TRP_CLOCK CLOCK_MONOTONIC
+
/* info records */
/* TRP update record types */
typedef struct trp_inforec_route {
- TR_NAME *comm;
- TR_NAME *realm;
TR_NAME *trust_router;
TR_NAME *next_hop;
unsigned int next_hop_port;
unsigned int interval;
} TRP_INFOREC_ROUTE;
-/* TODO: define struct trp_msg_info_community */
+typedef struct trp_inforec_comm {
+ TR_COMM_TYPE comm_type;
+ TR_REALM_ROLE role;
+ TR_APC *apcs;
+ TR_NAME *owner_realm;
+ TR_NAME *owner_contact;
+ time_t expiration_interval; /* Minutes to key expiration; only valid for an APC */
+ json_t *provenance;
+ unsigned int interval;
+} TRP_INFOREC_COMM;
typedef union trp_inforec_data {
TRP_INFOREC_ROUTE *route;
- /* TRP_INFOREC_COMM *comm; */
+ TRP_INFOREC_COMM *comm;
} TRP_INFOREC_DATA;
struct trp_inforec {
TRP_INFOREC *next;
TRP_INFOREC_TYPE type;
- TRP_INFOREC_DATA data; /* contains pointer to one of the record types */
+ TRP_INFOREC_DATA *data; /* contains pointer to one of the record types */
};
struct trp_update {
+ TR_NAME *realm;
+ TR_NAME *comm;
TRP_INFOREC *records;
TR_NAME *peer; /* who did this update come from? */
};
TR_MQ *mq; /* incoming message queue */
TRP_PTABLE *ptable; /* peer table */
TRP_RTABLE *rtable; /* route table */
+ TR_COMM_TABLE *ctable; /* community table */
struct timeval connect_interval; /* interval between connection refreshes */
struct timeval update_interval; /* interval between scheduled updates */
struct timeval sweep_interval; /* interval between route table sweeps */
TRPS_INSTANCE *trps_new (TALLOC_CTX *mem_ctx);
void trps_free (TRPS_INSTANCE *trps);
+void trps_set_ctable(TRPS_INSTANCE *trps, TR_COMM_TABLE *comm);
void trps_set_ptable(TRPS_INSTANCE *trps, TRP_PTABLE *ptable);
void trps_set_peer_status_callback(TRPS_INSTANCE *trps, void (*cb)(TRP_PEER *, void *), void *cookie);
+TR_NAME *trps_dup_label(TRPS_INSTANCE *trps);
TRP_RC trps_init_rtable(TRPS_INSTANCE *trps);
void trps_clear_rtable(TRPS_INSTANCE *trps);
void trps_set_connect_interval(TRPS_INSTANCE *trps, unsigned int interval);
TRP_AUTH_FUNC auth_handler,
const char *hostname,
unsigned int port,
- void *cookie);
+ void *cookie,
+ int *fd_out,
+ size_t max_fd);
TR_MQ_MSG *trps_mq_pop(TRPS_INSTANCE *trps);
void trps_mq_add(TRPS_INSTANCE *trps, TR_MQ_MSG *msg);
TRP_RC trps_authorize_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *conn);
TRP_ROUTE *trps_get_selected_route(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm);
TR_NAME *trps_get_next_hop(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm);
TRP_RC trps_sweep_routes(TRPS_INSTANCE *trps);
+TRP_RC trps_sweep_ctable(TRPS_INSTANCE *trps);
TRP_RC trps_add_route(TRPS_INSTANCE *trps, TRP_ROUTE *route);
TRP_RC trps_add_peer(TRPS_INSTANCE *trps, TRP_PEER *peer);
TRP_PEER *trps_get_peer_by_gssname(TRPS_INSTANCE *trps, TR_NAME *gssname);
TRP_RC trps_update(TRPS_INSTANCE *trps, TRP_UPDATE_TYPE type);
int trps_peer_connected(TRPS_INSTANCE *trps, TRP_PEER *peer);
TRP_RC trps_wildcard_route_req(TRPS_INSTANCE *trps, TR_NAME *peer_gssname);
+
+TRP_INFOREC *trp_inforec_new(TALLOC_CTX *mem_ctx, TRP_INFOREC_TYPE type);
+void trp_inforec_free(TRP_INFOREC *rec);
+TRP_INFOREC *trp_inforec_get_next(TRP_INFOREC *rec);
+void trp_inforec_set_next(TRP_INFOREC *rec, TRP_INFOREC *next_rec);
+TRP_INFOREC_TYPE trp_inforec_get_type(TRP_INFOREC *rec);
+void trp_inforec_set_type(TRP_INFOREC *rec, TRP_INFOREC_TYPE type);
+TR_NAME *trp_inforec_get_comm(TRP_INFOREC *rec);
+TR_NAME *trp_inforec_dup_comm(TRP_INFOREC *rec);
+TRP_RC trp_inforec_set_comm(TRP_INFOREC *rec, TR_NAME *comm);
+TR_NAME *trp_inforec_get_realm(TRP_INFOREC *rec);
+TR_NAME *trp_inforec_dup_realm(TRP_INFOREC *rec);
+TRP_RC trp_inforec_set_realm(TRP_INFOREC *rec, TR_NAME *realm);
+TR_NAME *trp_inforec_get_trust_router(TRP_INFOREC *rec);
+TR_NAME *trp_inforec_dup_trust_router(TRP_INFOREC *rec);
+TRP_RC trp_inforec_set_trust_router(TRP_INFOREC *rec, TR_NAME *trust_router);
+TR_NAME *trp_inforec_get_next_hop(TRP_INFOREC *rec);
+TR_NAME *trp_inforec_dup_next_hop(TRP_INFOREC *rec);
+TRP_RC trp_inforec_set_next_hop(TRP_INFOREC *rec, TR_NAME *next_hop);
+unsigned int trp_inforec_get_metric(TRP_INFOREC *rec);
+TRP_RC trp_inforec_set_metric(TRP_INFOREC *rec, unsigned int metric);
+unsigned int trp_inforec_get_interval(TRP_INFOREC *rec);
+TRP_RC trp_inforec_set_interval(TRP_INFOREC *rec, unsigned int interval);
+TR_NAME *trp_inforec_get_owner_realm(TRP_INFOREC *rec);
+TRP_RC trp_inforec_set_owner_realm(TRP_INFOREC *rec, TR_NAME *name);
+TR_NAME *trp_inforec_get_owner_contact(TRP_INFOREC *rec);
+TRP_RC trp_inforec_set_owner_contact(TRP_INFOREC *rec, TR_NAME *name);
+json_t *trp_inforec_get_provenance(TRP_INFOREC *rec);
+TRP_RC trp_inforec_set_provenance(TRP_INFOREC *rec, json_t *prov);
+TRP_INFOREC_TYPE trp_inforec_type_from_string(const char *s);
+const char *trp_inforec_type_to_string(TRP_INFOREC_TYPE msgtype);
+time_t trp_inforec_get_exp_interval(TRP_INFOREC *rec);
+TRP_RC trp_inforec_set_exp_interval(TRP_INFOREC *rec, time_t expint);
+TR_COMM_TYPE trp_inforec_get_comm_type(TRP_INFOREC *rec);
+TRP_RC trp_inforec_set_comm_type(TRP_INFOREC *rec, TR_COMM_TYPE type);
+TR_REALM_ROLE trp_inforec_get_role(TRP_INFOREC *rec);
+TRP_RC trp_inforec_set_role(TRP_INFOREC *rec, TR_REALM_ROLE role);
+TR_APC *trp_inforec_get_apcs(TRP_INFOREC *rec);
+TRP_RC trp_inforec_set_apcs(TRP_INFOREC *rec, TR_APC *apcs);
+TR_NAME *trp_inforec_dup_origin(TRP_INFOREC *rec);
+
#endif /* TRP_INTERNAL_H */
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;
typedef int (TIDS_REQ_FUNC)(TIDS_INSTANCE *, TID_REQ *, TID_RESP *, void *);
-typedef int (TIDS_AUTH_FUNC)(gss_name_t client_name, TR_NAME *display_name, void *cookie);
+typedef int (tids_auth_func)(gss_name_t client_name, TR_NAME *display_name, void *cookie);
TID_RESP *tid_resp_new(TALLOC_CTX *mem_ctx);
void tid_resp_free(TID_RESP *resp);
+TID_RESP *tid_resp_dup(TALLOC_CTX *mem_ctx, TID_RESP *resp);
TR_EXPORT int tid_resp_get_result(TID_RESP *resp);
void tid_resp_set_result(TID_RESP *resp, int result);
TR_EXPORT TR_NAME *tid_resp_get_err_msg(TID_RESP *resp);
TR_EXPORT int tidc_fwd_request (TIDC_INSTANCE *tidc, TID_REQ *req, TIDC_RESP_FUNC *resp_handler, void *cookie);
TR_EXPORT DH *tidc_get_dh(TIDC_INSTANCE *);
TR_EXPORT DH *tidc_set_dh(TIDC_INSTANCE *, DH *);
-TR_EXPORT void tidc_destroy (TIDC_INSTANCE *tidc);
+TR_EXPORT void tidc_destroy(TIDC_INSTANCE *tidc);
/* TID Server functions, in tid/tids.c */
-TR_EXPORT TIDS_INSTANCE *tids_create (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);
+ 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);
+ 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);
TR_CONSTRAINT *tr_constraint_new(TALLOC_CTX *mem_ctx);
void tr_constraint_free(TR_CONSTRAINT *cons);
+TR_CONSTRAINT *tr_constraint_dup(TALLOC_CTX *mem_ctx, TR_CONSTRAINT *cons);
void TR_EXPORT tr_constraint_add_to_set (TR_CONSTRAINT_SET **cs, TR_CONSTRAINT *c);
#include <trust_router/tr_versioning.h>
#include <trust_router/tid.h>
-
+TR_EXPORT DH *tr_dh_new(void);
+TR_EXPORT void tr_dh_destroy(DH *dh); /* called destroy because free is already used */
TR_EXPORT DH *tr_create_dh_params(unsigned char *key, size_t len);
TR_EXPORT DH *tr_create_matching_dh(unsigned char *key, size_t len, DH *in_dh);
TR_EXPORT void tr_destroy_dh_params(DH *dh);
+TR_EXPORT DH *tr_dh_dup(DH *in);
TR_EXPORT int tr_compute_dh_key(unsigned char **pbuf, BIGNUM *pub_key, DH *priv_dh);
TR_EXPORT void tr_dh_free(unsigned char *dh_buf);
unsigned char **out_digest,
size_t *out_llen);
-
TR_EXPORT void tr_bin_to_hex(const unsigned char * bin, size_t binlen,
- char * hex_out, size_t hex_len);
+ char * hex_out, size_t hex_len);
+
#endif
#ifndef TR_NAME_H
#define TR_NAME_H
#include <string.h>
+#include <jansson.h>
#include <trust_router/tr_versioning.h>
typedef const char *tr_const_string;
TR_EXPORT int tr_name_cmp (TR_NAME *one, TR_NAME *two);
TR_EXPORT void tr_name_strlcat(char *dest, const TR_NAME *src, size_t len);
TR_EXPORT char *tr_name_strdup(TR_NAME *);
-TR_NAME *tr_name_cat(TR_NAME *n1, TR_NAME *n2);
+TR_EXPORT json_t *tr_name_to_json_string(TR_NAME *src);
+TR_EXPORT TR_NAME *tr_name_cat(TR_NAME *n1, TR_NAME *n2);
#endif
typedef enum trp_inforec_type {
TRP_INFOREC_TYPE_UNKNOWN=0, /* conveniently, JSON parser returns 0 if a non-integer number is specified */
TRP_INFOREC_TYPE_ROUTE,
- TRP_INFOREC_TYPE_COMMUNITY, /* not yet implemented (2016-06-14) */
+ TRP_INFOREC_TYPE_COMMUNITY
} TRP_INFOREC_TYPE;
typedef struct trp_inforec TRP_INFOREC;
TR_EXPORT TRP_INFOREC *trp_upd_get_inforec(TRP_UPD *upd);
void trp_upd_set_inforec(TRP_UPD *upd, TRP_INFOREC *rec);
void trp_upd_add_inforec(TRP_UPD *upd, TRP_INFOREC *rec);
+TR_EXPORT TR_NAME *trp_upd_get_realm(TRP_UPD *upd);
+TR_NAME *trp_upd_dup_realm(TRP_UPD *upd);
+void trp_upd_set_realm(TRP_UPD *upd, TR_NAME *realm);
+TR_EXPORT TR_NAME *trp_upd_get_comm(TRP_UPD *upd);
+TR_NAME *trp_upd_dup_comm(TRP_UPD *upd);
+void trp_upd_set_comm(TRP_UPD *upd, TR_NAME *comm);
TR_EXPORT TR_NAME *trp_upd_get_peer(TRP_UPD *upd);
TR_NAME *trp_upd_dup_peer(TRP_UPD *upd);
void trp_upd_set_peer(TRP_UPD *upd, TR_NAME *peer);
void trp_upd_set_next_hop(TRP_UPD *upd, const char *hostname, unsigned int port);
-TR_EXPORT TRP_INFOREC *trp_inforec_new(TALLOC_CTX *mem_ctx, TRP_INFOREC_TYPE type);
-void trp_inforec_free(TRP_INFOREC *rec);
-TR_EXPORT TRP_INFOREC *trp_inforec_get_next(TRP_INFOREC *rec);
-void trp_inforec_set_next(TRP_INFOREC *rec, TRP_INFOREC *next_rec);
-TR_EXPORT TRP_INFOREC_TYPE trp_inforec_get_type(TRP_INFOREC *rec);
-void trp_inforec_set_type(TRP_INFOREC *rec, TRP_INFOREC_TYPE type);
-TR_EXPORT TR_NAME *trp_inforec_get_comm(TRP_INFOREC *rec);
-TR_EXPORT TR_NAME *trp_inforec_dup_comm(TRP_INFOREC *rec);
-TRP_RC trp_inforec_set_comm(TRP_INFOREC *rec, TR_NAME *comm);
-TR_EXPORT TR_NAME *trp_inforec_get_realm(TRP_INFOREC *rec);
-TR_EXPORT TR_NAME *trp_inforec_dup_realm(TRP_INFOREC *rec);
-TRP_RC trp_inforec_set_realm(TRP_INFOREC *rec, TR_NAME *realm);
-TR_EXPORT TR_NAME *trp_inforec_get_trust_router(TRP_INFOREC *rec);
-TR_EXPORT TR_NAME *trp_inforec_dup_trust_router(TRP_INFOREC *rec);
-TRP_RC trp_inforec_set_trust_router(TRP_INFOREC *rec, TR_NAME *trust_router);
-TR_EXPORT TR_NAME *trp_inforec_get_next_hop(TRP_INFOREC *rec);
-TR_EXPORT TR_NAME *trp_inforec_dup_next_hop(TRP_INFOREC *rec);
-TRP_RC trp_inforec_set_next_hop(TRP_INFOREC *rec, TR_NAME *next_hop);
-TR_EXPORT unsigned int trp_inforec_get_metric(TRP_INFOREC *rec);
-TRP_RC trp_inforec_set_metric(TRP_INFOREC *rec, unsigned int metric);
-TR_EXPORT unsigned int trp_inforec_get_interval(TRP_INFOREC *rec);
-TRP_RC trp_inforec_set_interval(TRP_INFOREC *rec, unsigned int interval);
-TR_EXPORT TRP_INFOREC_TYPE trp_inforec_type_from_string(const char *s);
-TR_EXPORT const char *trp_inforec_type_to_string(TRP_INFOREC_TYPE msgtype);
+void trp_upd_add_to_provenance(TRP_UPD *upd, TR_NAME *name);
/* Functions for TRP_REQ structures */
TR_EXPORT TRP_REQ *trp_req_new(TALLOC_CTX *mem_ctx);
--- /dev/null
+{
+ "tr_internal": {
+ "max_tree_depth": 12,
+ "hostname":"beta.example.com",
+ "trps_port":25308,
+ "tids_port":25309,
+ "cfg_poll_interval": 1,
+ "cfg_settling_time": 5,
+ "trp_sweep_interval": 30,
+ "trp_update_interval": 30,
+ "trp_connect_interval": 10,
+ "tid_request_timeout": 5,
+ "tid_response_numerator": 2,
+ "tid_response_denominator": 3,
+ "logging": {
+ "log_threshold": "info",
+ "console_threshold":"notice"
+ }
+ }
+}
+++ /dev/null
-{"tr_internal": {"max_tree_depth": 4,
- "hostname":"tr.moonshot.local",
- "tids_port": 12309,
-
- "logging": { "console_threshold": "debug",
- "log_threshold": "info"
- }
- }
-}
--- /dev/null
+{
+ "communities": [
+ {
+ "apcs": [],
+ "community_id": "apc.x",
+ "idp_realms": ["idp.x", "other.idp.x"],
+ "rp_realms": ["rp.x", "other.rp.x"],
+ "type": "apc",
+ "expiration_interval": 10
+ },
+ {
+ "apcs": ["apc."],
+ "community_id": "coi.x",
+ "idp_realms": ["idp.x"],
+ "rp_realms": ["rp.x"],
+ "type": "coi"
+ }
+ ],
+ "local_organizations": [
+ {
+ "organization_name": "Demo Organization",
+ "realms": [
+ {
+ "realm": "rp.x",
+ "gss_names": ["alpha-cred@apc.x",
+ "beta-cred@apc.x",
+ "gamma-cred@apc.x"],
+ "filters": {
+ "tid_inbound": [
+ {
+ "action": "accept",
+ "domain_constraints": [
+ "*.local"
+ ],
+ "specs": [
+ {
+ "field": "rp_realm",
+ "match": "rp.x"
+ },
+ {
+ "field": "rp_realm",
+ "match": "*.rp.x"
+ }
+ ],
+ "realm_constraints": [
+ "rp.x", "*.rp.x"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "realm": "other.rp.x",
+ "gss_names": ["something@apc.x"]
+ },
+ {
+ "realm": "idp.x",
+ "gss_names": ["alpha-cred@apc.x"],
+ "identity_provider": {
+ "aaa_servers": ["alpha.local"],
+ "apcs": ["apc.x"],
+ "shared_config": "no"
+ }
+ },
+ {
+ "realm": "other.idp.x",
+ "gss_names": ["beta-cred@apc.x"],
+ "identity_provider": {
+ "aaa_servers": ["alpha.local"],
+ "apcs": ["apc.x"],
+ "shared_config": "no"
+ }
+ }
+ ]
+ }
+ ],
+ "peer_organizations": [
+ {
+ "hostname": "gamma.local",
+ "port": 12310,
+ "gss_names": ["gamma-cred@apc.x"]
+ }
+ ]
+}
+++ /dev/null
-{
- "communities": [
- {
- "apcs": [
- "pci-community.ja.net"
- ],
- "community_id": "comm.offcenter.org",
- "idp_realms": [
- "idr2.offcenter.org"
- ],
- "rp_realms": [
- "sr3.offcenter.org"
- ],
- "type": "coi"
- },
- {
- "apcs": [
-
- ],
- "community_id": "pci-community.ja.net",
- "idp_realms": [
- "idr1.offcenter.org",
- "idr2.offcenter.org",
- "ja.net",
- "no-longer-untitled.offcenter.org"
- ],
- "rp_realms": [
- "exchange.ja.net",
- "sr3.offcenter.org"
- ],
- "type": "apc"
- }
- ],
- "idp_realms": [
- {
- "aaa_servers": [
- "127.0.0.1"
- ],
- "apcs": [
- "pci-community.ja.net"
- ],
- "realm_id": "idr1.offcenter.org",
- "shared_config": "yes"
- },
- {
- "aaa_servers": [
- "127.0.0.1"
- ],
- "apcs": [
- "pci-community.ja.net"
- ],
- "realm_id": "idr2.offcenter.org",
- "shared_config": "no"
- },
- {
- "aaa_servers": [
- "10.1.10.90"
- ],
- "apcs": [
- "pci-community.ja.net"
- ],
- "realm_id": "ja.net",
- "shared_config": "no"
- },
- {
- "aaa_servers": [
- "127.0.0.1"
- ],
- "apcs": [
- "pci-community.ja.net"
- ],
- "realm_id": "no-longer-untitled.offcenter.org",
- "shared_config": "yes"
- }
- ],
- "rp_clients": [
- {
- "filter": {
- "filter_lines": [
- {
- "action": "accept",
- "domain_constraints": ["*.exchange.ja.net"],
- "filter_specs": [
- {
- "field": "rp_realm",
- "match": "exchange.ja.net"
- },
- {
- "field": "rp_realm",
- "match": "*.exchange.ja.net"
- }
- ],
- "realm_constraints": ["*.exchange.ja.net", "a.com"]
- }
- ],
- "type": "rp_permitted"
- },
- "gss_names": [
- "01b80aa9-8753-4691-8f8a-f49f7793546f@portal-realm.ja.net"
- ]
- },
- {
- "filter": {
- "filter_lines": [
- {
- "action": "accept",
- "domain_constraints": ["*.bob.sr3.offcenter.org"],
- "filter_specs": [
- {
- "field": "rp_realm",
- "match": "sr3.offcenter.org"
- },
- {
- "field": "rp_realm",
- "match": "*.sr3.offcenter.org"
- }
- ],
- "realm_constraints": ["*.sr3.offcenter.org" ]
- }
- ],
- "type": "rp_permitted"
- },
- "gss_names": [
- "895c308a-5624-4055-bb4f-ea24b77e6637@portal-realm.ja.net"
- ]
- }
- ]
-}
#include <poll.h>
#include <tr_debug.h>
+#include <tr_util.h>
#include <tid_internal.h>
#include <trust_router/tr_constraint.h>
#include <trust_router/tr_dh.h>
if (SQLITE_DONE != sqlite3_result)
tr_crit("sqlite3: failed to write to database");
sqlite3_reset(authorization_insert);
+ sqlite3_clear_bindings(authorization_insert);
}
return 0;
}
unsigned char *s_keybuf = NULL;
int s_keylen = 0;
char key_id[12];
- unsigned char *pub_digest;
+ unsigned char *pub_digest=NULL;
size_t pub_digest_len;
/* Allocate a new server block */
- if (NULL == (resp->servers = talloc_zero(resp, TID_SRVR_BLK))){
- tr_crit("tids_req_handler(): malloc failed.");
+ tid_srvr_blk_add(resp->servers, tid_srvr_blk_new(resp));
+ if (NULL==resp->servers) {
+ tr_crit("tids_req_handler(): unable to allocate server block.");
return -1;
}
- resp->num_servers = 1;
-
/* TBD -- Set up the server IP Address */
if (!(req) || !(req->tidc_dh)) {
return -1;
}
- if (0 == inet_aton(tids->ipaddr, &(resp->servers->aaa_server_addr))) {
- tr_debug("tids_req_handler: inet_aton() failed.");
- return -1;
- }
+ resp->servers->aaa_server_addr=talloc_strdup(resp->servers, tids->ipaddr);
/* Set the key name */
if (-1 == create_key_id(key_id, sizeof(key_id)))
}
if (0 != handle_authorizations(req, pub_digest, pub_digest_len))
return -1;
- resp->servers->path = req->path;
+ tid_srvr_blk_set_path(resp->servers, (TID_PATH *)(req->path));
+
if (req->expiration_interval < 1)
req->expiration_interval = 1;
g_get_current_time(&resp->servers->key_expiration);
if (NULL != insert_stmt) {
int sqlite3_result;
gchar *expiration_str = g_time_val_to_iso8601(&resp->servers->key_expiration);
- sqlite3_bind_text(insert_stmt, 1, key_id, -1, SQLITE_TRANSIENT);
+ sqlite3_bind_text(insert_stmt, 1, key_id, -1, SQLITE_TRANSIENT);
sqlite3_bind_blob(insert_stmt, 2, s_keybuf, s_keylen, SQLITE_TRANSIENT);
sqlite3_bind_blob(insert_stmt, 3, pub_digest, pub_digest_len, SQLITE_TRANSIENT);
- sqlite3_bind_text(insert_stmt, 4, expiration_str, -1, SQLITE_TRANSIENT);
+ sqlite3_bind_text(insert_stmt, 4, expiration_str, -1, SQLITE_TRANSIENT);
+ g_free(expiration_str); /* bind_text already made its own copy */
sqlite3_result = sqlite3_step(insert_stmt);
if (SQLITE_DONE != sqlite3_result)
tr_crit("sqlite3: failed to write to database");
sqlite3_reset(insert_stmt);
+ sqlite3_clear_bindings(insert_stmt);
}
/* Print out the key. */
// }
// fprintf(stderr, "\n");
+ if (s_keybuf!=NULL)
+ free(s_keybuf);
+
+ if (pub_digest!=NULL)
+ talloc_free(pub_digest);
+
return s_keylen;
}
TIDS_INSTANCE *tids;
TR_NAME *gssname = NULL;
struct cmdline_args opts={NULL};
- int tids_socket=-1;
- struct pollfd *poll_fds=NULL;
/* parse the command line*/
argp_parse(&argp, argc, argv, 0, 0, &opts);
-1, &authorization_insert, NULL);
/* Create a TID server instance */
- if (NULL == (tids = tids_create(NULL))) {
+ if (NULL == (tids = tids_create())) {
tr_crit("Unable to create TIDS instance, exiting.");
return 1;
}
tids->ipaddr = opts.ip_address;
-
- /* get listener for tids port */
- tids_socket = tids_get_listener(tids, &tids_req_handler , auth_handler, opts.hostname, TID_PORT, gssname);
-
- poll_fds=malloc(sizeof(*poll_fds));
- if (poll_fds == NULL) {
- tr_crit("Could not allocate event polling list, exiting.");
- return 1;
- }
-
- poll_fds[0].fd=tids_socket;
- poll_fds[0].events=POLLIN; /* poll on ready for reading */
- poll_fds[0].revents=0;
-
- /* main event loop */
- while (1) {
- /* wait up to 100 ms for an event, then handle any idle work */
- if(poll(poll_fds, 1, 100) > 0) {
- if (poll_fds[0].revents & POLLIN) {
- if (0 != tids_accept(tids, tids_socket)) {
- tr_err("Error handling tids request.");
- }
- }
- }
- /* idle loop stuff here */
- }
+ (void) tids_start(tids, &tids_req_handler, auth_handler, opts.hostname, TID_PORT, gssname);
/* Clean-up the TID server instance */
tids_destroy(tids);
req->cookie = cookie;
}
+/* struct is allocated in talloc null context */
TID_REQ *tid_dup_req (TID_REQ *orig_req)
{
TID_REQ *new_req = NULL;
- if (NULL == (new_req = talloc_zero(orig_req, TID_REQ))) {
+ if (NULL == (new_req = talloc_zero(NULL, TID_REQ))) {
tr_crit("tid_dup_req: Can't allocated duplicate request.");
return NULL;
}
assert(blk);
sa = talloc_zero(blk, struct sockaddr_in);
sa->sin_family = AF_INET;
- sa->sin_addr = blk->aaa_server_addr;
- sa->sin_port = htons(2083);
+ inet_aton(blk->aaa_server_addr, &(sa->sin_addr));
+ sa->sin_port = htons(2083); /* radsec port */
*out_addr = (struct sockaddr *) sa;
*out_len = sizeof( struct sockaddr_in);
}
#include <assert.h>
#include <talloc.h>
+#include <trust_router/tr_dh.h>
#include <tid_internal.h>
static int tid_resp_destructor(void *obj)
resp->cons=NULL;
resp->orig_coi=NULL;
resp->servers=NULL;
- resp->num_servers=0;
resp->error_path=NULL;
talloc_set_destructor((void *)resp, tid_resp_destructor);
}
talloc_free(resp);
}
+TID_RESP *tid_resp_dup(TALLOC_CTX *mem_ctx, TID_RESP *resp)
+{
+ TID_RESP *newresp=NULL;
+
+ if (resp==NULL)
+ return 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);
+ }
+ return newresp;
+}
+
TR_EXPORT int tid_resp_get_result(TID_RESP *resp)
{
return(resp->result);
void tid_resp_set_err_msg(TID_RESP *resp, TR_NAME *err_msg)
{
+ if (resp->err_msg!=NULL)
+ tr_free_name(resp->err_msg);
+
resp->err_msg = err_msg;
}
TR_EXPORT TID_SRVR_BLK *tid_resp_get_server(TID_RESP *resp,
size_t index)
{
+ TID_SRVR_BLK *this=NULL;
assert(resp);
- assert(index < resp->num_servers);
- return(&(resp->servers[index]));
+
+ for (this=resp->servers; index>0; index--, this=this->next) {}
+
+ return this;
}
size_t tid_resp_get_num_servers(const TID_RESP *resp)
{
- assert(resp);
- return resp->num_servers;
+ size_t count=0;
+ TID_SRVR_BLK *this=NULL;
+
+ assert(resp!=NULL);
+ for (count=0, this=resp->servers; this!=NULL; count++, this=this->next) {}
+ return count;
+}
+
+static int tid_srvr_blk_destructor(void *obj)
+{
+ TID_SRVR_BLK *srvr=talloc_get_type_abort(obj, TID_SRVR_BLK);
+
+ if (srvr->key_name!=NULL)
+ tr_free_name(srvr->key_name);
+ if (srvr->aaa_server_dh!=NULL)
+ tr_destroy_dh_params(srvr->aaa_server_dh);
+ if (srvr->path!=NULL)
+ json_decref((json_t *)(srvr->path));
+ return 0;
+}
+
+TR_EXPORT TID_SRVR_BLK *tid_srvr_blk_new(TALLOC_CTX *mem_ctx)
+{
+ TID_SRVR_BLK *srvr=talloc(mem_ctx, TID_SRVR_BLK);
+
+ if (srvr!=NULL) {
+ srvr->next=NULL;
+ srvr->aaa_server_addr=NULL;
+ srvr->key_name=NULL;
+ srvr->aaa_server_dh=NULL;
+ srvr->key_expiration=(GTimeVal){0};
+ srvr->path=NULL;
+ talloc_set_destructor((void *)srvr, tid_srvr_blk_destructor);
+ }
+ return srvr;
+}
+
+TR_EXPORT void tid_srvr_blk_free(TID_SRVR_BLK *srvr)
+{
+ talloc_free(srvr);
}
+TR_EXPORT TID_SRVR_BLK *tid_srvr_blk_dup(TALLOC_CTX *mem_ctx, TID_SRVR_BLK *srvr)
+{
+ TID_SRVR_BLK *new=NULL;
+
+ if (srvr==NULL)
+ return NULL;
+
+ new=tid_srvr_blk_new(mem_ctx);
+ if (new!=NULL) {
+ if (srvr->aaa_server_addr!=NULL)
+ new->aaa_server_addr=talloc_strdup(new, srvr->aaa_server_addr);
+ new->key_name=tr_dup_name(srvr->key_name);
+ new->aaa_server_dh=tr_dh_dup(srvr->aaa_server_dh);
+ new->key_expiration=srvr->key_expiration;
+
+ tid_srvr_blk_set_path(new, srvr->path);
+
+ tid_srvr_blk_add(new->next, tid_srvr_blk_dup(mem_ctx, srvr->next));
+ }
+ return new;
+}
-const TID_PATH *tid_srvr_get_path( const TID_SRVR_BLK *block)
+/* use the macro */
+TR_EXPORT TID_SRVR_BLK *tid_srvr_blk_add_func(TID_SRVR_BLK *head, TID_SRVR_BLK *new)
+{
+ TID_SRVR_BLK *this=head;
+
+ if (head==NULL)
+ return new;
+
+ while (this->next!=NULL)
+ this=this->next;
+
+ this->next=new;
+ while (this!=NULL) {
+ talloc_steal(head, this);
+ this=this->next;
+ }
+ return head;
+}
+
+TR_EXPORT void tid_srvr_blk_set_path(TID_SRVR_BLK *block, TID_PATH *path)
+{
+ if (block->path!=NULL)
+ json_decref((json_t *)(block->path));
+ block->path=path;
+ if (block->path!=NULL)
+ json_incref((json_t *)(block->path));
+}
+
+TR_EXPORT const TID_PATH *tid_srvr_get_path( const TID_SRVR_BLK *block)
{
if (!block)
return NULL;
- return (const TID_PATH *) block->path;
+ return block->path;
}
-const TID_PATH *tid_resp_get_error_path( const TID_RESP *resp)
+TR_EXPORT void tid_resp_set_cons(TID_RESP *resp, TR_CONSTRAINT_SET *cons)
+{
+ json_t *jc=(json_t *)cons;
+
+ if (resp->cons!=NULL)
+ json_decref((json_t *) (resp->cons));
+
+ resp->cons=(TR_CONSTRAINT_SET *)jc;
+ if (jc!=NULL)
+ json_incref(jc);
+}
+
+TR_EXPORT void tid_resp_set_error_path(TID_RESP *resp, json_t *ep)
+{
+ if (resp->error_path!=NULL)
+ json_decref(resp->error_path);
+ resp->error_path=ep;
+ if (resp->error_path!=NULL)
+ json_incref(resp->error_path);
+}
+
+TR_EXPORT const TID_PATH *tid_resp_get_error_path(const TID_RESP *resp)
{
if (!resp)
return NULL;
- return (const TID_PATH *) resp->error_path;
+ return (const TID_PATH *)(resp->error_path);
}
-const TID_PATH *tid_resp_get_a_path( const TID_RESP *const_resp)
+TR_EXPORT const TID_PATH *tid_resp_get_a_path(const TID_RESP *const_resp)
{
size_t index;
TID_SRVR_BLK *server;
if (!resp)
return NULL;
-
if (resp->error_path)
- return (const TID_PATH *) resp->error_path;
+ return (const TID_PATH *)(resp->error_path);
tid_resp_servers_foreach( resp, server, index) {
if (server->path)
- return (const TID_PATH *) server->path;
+ return server->path;
}
return NULL;
int tmp_len = 32;
-TIDC_INSTANCE *tidc_create ()
+static int tidc_destructor(void *obj)
{
- TIDC_INSTANCE *tidc = NULL;
-
- if (NULL == (tidc = talloc_zero(NULL, TIDC_INSTANCE)))
- return NULL;
+ 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);
+ }
return tidc;
}
-void tidc_destroy (TIDC_INSTANCE *tidc)
+void tidc_destroy(TIDC_INSTANCE *tidc)
{
talloc_free(tidc);
}
goto error;
}
- tid_req->tidc_dh = tidc->client_dh;
+ tid_req->tidc_dh = tr_dh_dup(tidc->client_dh);
rc = tidc_fwd_request(tidc, tid_req, resp_handler, cookie);
goto cleanup;
return rc;
}
-int tidc_fwd_request (TIDC_INSTANCE *tidc,
- TID_REQ *tid_req,
- TIDC_RESP_FUNC *resp_handler,
- void *cookie)
+int tidc_fwd_request(TIDC_INSTANCE *tidc,
+ TID_REQ *tid_req,
+ TIDC_RESP_FUNC *resp_handler,
+ void *cookie)
{
char *req_buf = NULL;
char *resp_buf = NULL;
}
if (resp_handler) {
- /* Call the caller's response function */
+ /* Call the caller's response function. It must copy any data it needs before returning. */
tr_debug("tidc_fwd_request: calling response callback function.");
(*resp_handler)(tidc, tid_req, tr_msg_get_resp(resp_msg), cookie);
}
+
goto cleanup;
error:
free(req_buf);
if (resp_buf)
free(resp_buf);
-
- /* TBD -- free the decoded response */
-
+ if (resp_msg)
+ tr_msg_free_decoded(resp_msg);
return rc;
}
#include <netinet/in.h>
#include <jansson.h>
#include <talloc.h>
+#include <poll.h>
#include <tid_internal.h>
#include <gsscon.h>
#include <tr_debug.h>
TID_RESP *resp=NULL;
int success=0;
- if ((NULL == (resp = talloc_zero(req, TID_RESP)))) {
+ if (NULL == (resp = tid_resp_new(req))) {
tr_crit("tids_create_response: Error allocating response structure.");
return NULL;
}
cleanup:
if ((!success) && (resp!=NULL)) {
- if (resp->rp_realm!=NULL)
- tr_free_name(resp->rp_realm);
- if (resp->realm!=NULL)
- tr_free_name(resp->realm);
- if (resp->comm!=NULL)
- tr_free_name(resp->comm);
- if (resp->orig_coi!=NULL)
- tr_free_name(resp->orig_coi);
talloc_free(resp);
resp=NULL;
}
return resp;
}
-static void tids_destroy_response(TIDS_INSTANCE *tids, TID_RESP *resp)
+static int tids_listen(TIDS_INSTANCE *tids, int port, int *fd_out, size_t max_fd)
{
- if (resp) {
- if (resp->err_msg)
- tr_free_name(resp->err_msg);
- if (resp->rp_realm)
- tr_free_name(resp->rp_realm);
- if (resp->realm)
- tr_free_name(resp->realm);
- if (resp->comm)
- tr_free_name(resp->comm);
- if (resp->orig_coi)
- tr_free_name(resp->orig_coi);
- talloc_free(resp);
+ 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;
}
-}
-static int tids_listen (TIDS_INSTANCE *tids, int port)
-{
- int rc = 0;
- int conn = -1;
- int optval = 1;
+ tr_debug("getaddrinfo()=%d", getaddrinfo(NULL, port_str, &hints, &ai_head));
+ talloc_free(port_str);
+ tr_debug("tids_listen: got address info");
- union {
- struct sockaddr_storage storage;
- struct sockaddr_in in4;
- } addr;
+ /* 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;
+ }
- struct sockaddr_in *saddr = (struct sockaddr_in *) &addr.in4;
+ 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;
+ }
+ }
- saddr->sin_port = htons (port);
- saddr->sin_family = AF_INET;
- saddr->sin_addr.s_addr = INADDR_ANY;
+ 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 > (conn = socket (AF_INET, SOCK_STREAM, 0)))
- return conn;
+ if (0>listen(conn, 512)) {
+ tr_debug("tids_listen: unable to listen on bound socket.");
+ close(conn);
+ continue;
+ }
- setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
+ /* ok, this one worked. Save it */
+ fd_out[n_opened++]=conn;
+ }
+ freeaddrinfo(ai_head);
- if (0 > (rc = bind (conn, (struct sockaddr *) saddr, sizeof(struct sockaddr_in))))
- return rc;
+ if (n_opened==0) {
+ tr_debug("tids_listen: no addresses available for listening.");
+ return -1;
+ }
- if (0 > (rc = listen(conn, 512)))
- return rc;
+ tr_debug("tids_listen: TRP Server listening on port %d on %d socket%s",
+ port,
+ n_opened,
+ (n_opened==1)?"":"s");
- tr_debug("tids_listen: TID Server listening on port %d", port);
- return conn;
+ return n_opened;
}
/* returns EACCES if authorization is denied */
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.",
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;
rc = tids_send_response(tids, req, resp);
- tids_destroy_response(tids, resp);
+ tid_resp_free(resp);
return rc;
}
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.");
+ tids_send_err_response(tids, tr_msg_get_req(mreq), "Error sending response.");
/* Fall through to free the response, either way. */
}
- tids_destroy_response(tids, resp);
- tr_msg_free_decoded(mreq);
+ tr_msg_free_decoded(mreq); /* takes resp with it */
return;
}
}
-TIDS_INSTANCE *tids_create (TALLOC_CTX *mem_ctx)
+TIDS_INSTANCE *tids_create (void)
{
- return talloc_zero(mem_ctx, TIDS_INSTANCE);
+ return talloc_zero(NULL, TIDS_INSTANCE);
}
/* Get a listener for tids requests, returns its socket fd. Accept
* connections with tids_accept() */
int tids_get_listener(TIDS_INSTANCE *tids,
TIDS_REQ_FUNC *req_handler,
- TIDS_AUTH_FUNC *auth_handler,
+ tids_auth_func *auth_handler,
const char *hostname,
unsigned int port,
- void *cookie)
+ void *cookie,
+ int *fd_out,
+ size_t max_fd)
{
- int listen = -1;
+ size_t n_fd=0;
+ size_t ii=0;
tids->tids_port = port;
- if (0 > (listen = tids_listen(tids, port))) {
- char errbuf[256];
- if (0 == strerror_r(errno, errbuf, 256)) {
- tr_debug("tids_get_listener: Error opening port %d: %s.", port, errbuf);
- } else {
- tr_debug("tids_get_listener: Unknown error openining port %d.", port);
- }
- }
-
- if (listen > 0) {
+ n_fd=tids_listen(tids, port, fd_out, max_fd);
+ if (n_fd<=0)
+ tr_debug("tids_get_listener: Error opening port %d");
+ else {
/* opening port succeeded */
tr_debug("tids_get_listener: Opened port %d.", port);
/* make this socket non-blocking */
- if (0 != fcntl(listen, F_SETFL, O_NONBLOCK)) {
- tr_debug("tids_get_listener: Error setting O_NONBLOCK.");
- close(listen);
- listen=-1;
+ for (ii=0; ii<n_fd; ii++) {
+ if (0 != fcntl(fd_out[ii], F_SETFL, O_NONBLOCK)) {
+ tr_debug("tids_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 (listen > 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 listen;
+ return n_fd;
}
/* Accept and process a connection on a port opened with tids_get_listener() */
}
/* Process tids requests forever. Should not return except on error. */
+#define MAX_SOCKETS 10
int tids_start (TIDS_INSTANCE *tids,
- TIDS_REQ_FUNC *req_handler,
- TIDS_AUTH_FUNC *auth_handler,
- const char *hostname,
- unsigned int port,
- void *cookie)
+ TIDS_REQ_FUNC *req_handler,
+ tids_auth_func *auth_handler,
+ const char *hostname,
+ unsigned int port,
+ void *cookie)
{
- int listen = -1;
- int conn = -1;
- pid_t pid;
+ int fd[MAX_SOCKETS]={0};
+ size_t n_fd=0;
+ struct pollfd poll_fd[MAX_SOCKETS]={{0}};
+ int ii=0;
- tids->tids_port = port;
- if (0 > (listen = tids_listen(tids, port)))
+ n_fd=tids_get_listener(tids, req_handler, auth_handler, hostname, port, cookie, fd, MAX_SOCKETS);
+ if (n_fd <= 0) {
perror ("Error from tids_listen()");
-
- /* store the caller's request handler & cookie */
- tids->req_handler = req_handler;
- tids->auth_handler = auth_handler;
- tids->hostname = hostname;
- tids->cookie = cookie;
+ return 1;
+ }
tr_info("Trust Path Query Server starting on host %s:%d.", hostname, port);
+ /* set up the poll structs */
+ for (ii=0; ii<n_fd; ii++) {
+ poll_fd[ii].fd=fd[ii];
+ poll_fd[ii].events=POLLIN;
+ }
+
while(1) { /* accept incoming conns until we are stopped */
+ /* clear out events from previous iteration */
+ for (ii=0; ii<n_fd; ii++)
+ poll_fd[ii].revents=0;
- if (0 > (conn = accept(listen, NULL, NULL))) {
- perror("Error from TIDS Server accept()");
+ /* wait indefinitely for a connection */
+ if (poll(poll_fd, n_fd, -1) < 0) {
+ perror("Error from poll()");
return 1;
}
- if (0 > (pid = fork())) {
- perror("Error on fork()");
- return 1;
- }
+ /* fork handlers for any sockets that have data */
+ for (ii=0; ii<n_fd; ii++) {
+ if (poll_fd[ii].revents == 0)
+ continue;
- if (pid == 0) {
- close(listen);
- tids_handle_connection(tids, conn);
- close(conn);
- exit(0); /* exit to kill forked child process */
- } else {
- close(conn);
- }
+ if ((poll_fd[ii].revents & POLLERR) || (poll_fd[ii].revents & POLLNVAL)) {
+ perror("Error polling fd");
+ continue;
+ }
- /* clean up any processes that have completed */
- while (waitpid(-1, 0, WNOHANG) > 0);
+ if (poll_fd[ii].revents & POLLIN) {
+ if (tids_accept(tids, poll_fd[ii].fd))
+ tr_err("tids_start: error in tids_accept().");
+ }
+ }
}
return 1; /* should never get here, loops "forever" */
}
+#undef MAX_SOCKETS
void tids_destroy (TIDS_INSTANCE *tids)
{
--- /dev/null
+{
+ "tr_internal": {
+ "max_tree_depth": 12,
+ "hostname":"beta.example.com",
+ "trps_port":25308,
+ "tids_port":25309,
+ "cfg_poll_interval": 1,
+ "cfg_settling_time": 5,
+ "trp_sweep_interval": 30,
+ "trp_update_interval": 30,
+ "trp_connect_interval": 10,
+ "tid_request_timeout": 5,
+ "tid_response_numerator": 2,
+ "tid_response_denominator": 3,
+ "logging": {
+ "log_threshold": "info",
+ "console_threshold":"notice"
+ }
+ }
+}
+++ /dev/null
-{"tr_internal":{"max_tree_depth": 4,
- "hostname":"margaret-moonshot3.local"}}
\ No newline at end of file
--- /dev/null
+{
+ "communities": [
+ {
+ "apcs": [],
+ "community_id": "apc.x",
+ "idp_realms": ["idp.x", "other.idp.x"],
+ "rp_realms": ["rp.x", "other.rp.x"],
+ "type": "apc",
+ "expiration_interval": 10
+ },
+ {
+ "apcs": ["apc."],
+ "community_id": "coi.x",
+ "idp_realms": ["idp.x"],
+ "rp_realms": ["rp.x"],
+ "type": "coi"
+ }
+ ],
+ "local_organizations": [
+ {
+ "organization_name": "Demo Organization",
+ "realms": [
+ {
+ "realm": "rp.x",
+ "gss_names": ["alpha-cred@apc.x",
+ "beta-cred@apc.x",
+ "gamma-cred@apc.x"],
+ "filters": {
+ "tid_inbound": [
+ {
+ "action": "accept",
+ "domain_constraints": [
+ "*.local"
+ ],
+ "specs": [
+ {
+ "field": "rp_realm",
+ "match": "rp.x"
+ },
+ {
+ "field": "rp_realm",
+ "match": "*.rp.x"
+ }
+ ],
+ "realm_constraints": [
+ "rp.x", "*.rp.x"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "realm": "other.rp.x",
+ "gss_names": ["something@apc.x"]
+ },
+ {
+ "realm": "idp.x",
+ "gss_names": ["alpha-cred@apc.x"],
+ "identity_provider": {
+ "aaa_servers": ["alpha.local"],
+ "apcs": ["apc.x"],
+ "shared_config": "no"
+ }
+ },
+ {
+ "realm": "other.idp.x",
+ "gss_names": ["beta-cred@apc.x"],
+ "identity_provider": {
+ "aaa_servers": ["alpha.local"],
+ "apcs": ["apc.x"],
+ "shared_config": "no"
+ }
+ }
+ ]
+ }
+ ],
+ "peer_organizations": [
+ {
+ "hostname": "gamma.local",
+ "port": 12310,
+ "gss_names": ["gamma-cred@apc.x"]
+ }
+ ]
+}
+++ /dev/null
-{
- "communities": [
- {
- "apcs": [
- ],
- "community_id": "apc.painless-security.com",
- "idp_realms": [
- ],
- "rp_realms": [
- "margaret-2.painless-security.com"
- ],
- "type": "apc"
- }
- ],
- "idp_realms": [
- {
- "aaa_servers": [
- "127.0.0.1"
- ],
- "apcs": [
- "pci-community.ja.net"
- ],
- "realm_id": "idr1.offcenter.org",
- "shared_config": "yes"
- },
- {
- "aaa_servers": [
- "127.0.0.1"
- ],
- "apcs": [
- "pci-community.ja.net"
- ],
- "realm_id": "idr2.offcenter.org",
- "shared_config": "no"
- },
- {
- "aaa_servers": [
- "10.1.10.90"
- ],
- "apcs": [
- "pci-community.ja.net"
- ],
- "realm_id": "ja.net",
- "shared_config": "no"
- },
- {
- "aaa_servers": [
- "127.0.0.1"
- ],
- "apcs": [
- "pci-community.ja.net"
- ],
- "realm_id": "no-longer-untitled.offcenter.org",
- "shared_config": "yes"
- }
- ],
- "rp_clients": [
- {
- "filter": {
- "filter_lines": [
- {
- "action": "accept",
- "domain_constraints": ["*.painless-security.com"],
- "filter_specs": [
- {
- "field": "rp_realm",
- "match": "margaret-2.painless-security.com"
- },
- {
- "field": "rp_realm",
- "match": "*.margaret-2.painless-security.com"
- }
- ],
- "realm_constraints": ["*.painless-security.com", "a.com"]
- }
- ],
- "type": "rp_permitted"
- },
- "gss_names": [
- "4b95cd61-616f-48f2-9713-7d2cbe19ce69@apc.painless-security.com"
- ]
- }
- ]
-}
TR_INSTANCE *tr = NULL;
struct cmdline_args opts;
struct event_base *ev_base;
- struct tr_socket_event tids_ev;
+ struct tr_socket_event tids_ev = {0};
struct event *cfgwatch_ev;
configure_signals();
}
/***** initialize the trust path query server instance *****/
- if (NULL == (tr->tids = tids_create (tr))) {
+ if (NULL == (tr->tids = tids_create())) {
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))) {
/*tr_status_event_init();*/ /* install status reporting events */
/* install TID server events */
+ tr_debug("Initializing TID server events.");
if (0 != tr_tids_event_init(ev_base,
tr->tids,
tr->cfg_mgr,
}
/* install TRP handler events */
+ tr_debug("Initializing Dynamic Trust Router Protocol events.");
if (TRP_SUCCESS != tr_trps_event_init(ev_base, tr)) {
tr_crit("Error initializing Trust Path Query Server instance.");
return 1;
}
+ tr_debug("Starting event loop.");
tr_event_loop_run(ev_base); /* does not return until we are done */
tr_destroy(tr); /* thanks to talloc, should destroy everything */
#include <talloc.h>
+#include <trust_router/tr_dh.h>
#include <tid_internal.h>
#include <tr_filter.h>
#include <tr_comm.h>
#include <gsscon.h>
#include <trp_internal.h>
#include <tr_config.h>
+#include <tr_mq.h>
+#include <tr_util.h>
#include <tr_tid.h>
-/* Structure to hold TR instance and original request in one cookie */
+/* Structure to hold data for the tid response callback */
typedef struct tr_resp_cookie {
- TIDS_INSTANCE *tids;
- TID_REQ *orig_req;
+ int thread_id;
+ TID_RESP *resp;
} TR_RESP_COOKIE;
/* hold a tids instance and a config manager */
TRPS_INSTANCE *trps;
};
+static void tr_tidc_resp_handler(TIDC_INSTANCE *tidc,
+ TID_REQ *req,
+ TID_RESP *resp,
+ void *resp_cookie)
+{
+ TR_RESP_COOKIE *cookie=talloc_get_type_abort(resp_cookie, TR_RESP_COOKIE);
+
+ tr_debug("tr_tidc_resp_handler: Response received! Realm = %s, Community = %s, result = %s.",
+ resp->realm->buf,
+ resp->comm->buf,
+ (TID_SUCCESS==resp->result)?"success":"error");
+
+ if (resp->error_path!=NULL)
+ tr_debug("tr_tids_resp_handler: error_path is set.");
+ cookie->resp=tid_resp_dup(cookie, resp);
+}
+
+/* data for AAA req forwarding threads */
+struct tr_tids_fwd_cookie {
+ int thread_id;
+ pthread_mutex_t mutex; /* lock on the mq (separate from the locking within the mq, see below) */
+ TR_MQ *mq; /* messages from thread to main process; set to NULL to disable response */
+ TR_NAME *aaa_hostname;
+ DH *dh_params;
+ TID_REQ *fwd_req; /* the req to duplicate */
+};
-static void tr_tidc_resp_handler (TIDC_INSTANCE *tidc,
- TID_REQ *req,
- TID_RESP *resp,
- void *resp_cookie)
+static int tr_tids_fwd_cookie_destructor(void *obj)
{
- tr_debug("tr_tidc_resp_handler: Response received (conn = %d)! Realm = %s, Community = %s.", ((TR_RESP_COOKIE *)resp_cookie)->orig_req->conn, resp->realm->buf, resp->comm->buf);
- req->resp_rcvd = 1;
-
- /* TBD -- handle concatentation of multiple responses to single req */
- tids_send_response(((TR_RESP_COOKIE *)resp_cookie)->tids,
- ((TR_RESP_COOKIE *)resp_cookie)->orig_req,
- resp);
-
- return;
+ struct tr_tids_fwd_cookie *c=talloc_get_type_abort(obj, struct tr_tids_fwd_cookie);
+ if (c->aaa_hostname!=NULL)
+ tr_free_name(c->aaa_hostname);
+ if (c->dh_params!=NULL)
+ tr_destroy_dh_params(c->dh_params);
+ return 0;
}
-static int tr_tids_req_handler (TIDS_INSTANCE *tids,
- TID_REQ *orig_req,
- TID_RESP *resp,
- void *cookie_in)
+/* Block until we get the lock, returns 0 on success.
+ * The mutex is used to protect changes to the mq pointer in
+ * a thread's cookie. The master thread sets this to null to indicate
+ * that it has abandoned the thread and the message queue is no longer
+ * valid. This is unrelated to the locking in the message queue
+ * implementation itself. */
+static int tr_tids_fwd_get_mutex(struct tr_tids_fwd_cookie *cookie)
{
- TALLOC_CTX *tmp_ctx=talloc_new(NULL);;
- TIDC_INSTANCE *tidc = NULL;
- TR_RESP_COOKIE resp_cookie;
- TR_AAA_SERVER *aaa_servers = NULL;
+ if (cookie==NULL)
+ return -1;
+
+ return (pthread_mutex_lock(&(cookie->mutex)));
+}
+
+static int tr_tids_fwd_release_mutex(struct tr_tids_fwd_cookie *cookie)
+{
+ if (cookie==NULL)
+ return -1;
+
+ return (pthread_mutex_unlock(&(cookie->mutex)));
+}
+
+/* values for messages */
+#define TR_TID_MQMSG_SUCCESS "tid success"
+#define TR_TID_MQMSG_FAILURE "tid failure"
+
+/* Thread main for sending and receiving a request to a single AAA server */
+static void *tr_tids_req_fwd_thread(void *arg)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ struct tr_tids_fwd_cookie *args=talloc_get_type_abort(arg, struct tr_tids_fwd_cookie);
+ TIDC_INSTANCE *tidc=tidc_create();
+ TR_MQ_MSG *msg=NULL;
+ TR_RESP_COOKIE *cookie=NULL;
+ int rc=0;
+ int success=0;
+
+ talloc_steal(tmp_ctx, args); /* take responsibility for the cookie */
+
+ if (tidc!=NULL)
+ talloc_steal(tmp_ctx, tidc);
+
+ /* create the cookie we will use for our response */
+ cookie=talloc(tmp_ctx, TR_RESP_COOKIE);
+ if (cookie==NULL) {
+ tr_notice("tr_tids_req_fwd_thread: unable to allocate response cookie.");
+ success=0;
+ goto cleanup;
+ }
+ cookie->thread_id=args->thread_id;
+ tr_debug("tr_tids_req_fwd_thread: thread %d started.", cookie->thread_id);
+
+ /* Create a TID client instance */
+ if (tidc==NULL) {
+ tr_crit("tr_tids_req_fwd_thread: Unable to allocate TIDC instance.");
+ /*tids_send_err_response(tids, orig_req, "Memory allocation failure");*/
+ /* TODO: encode reason for failure */
+ success=0;
+ goto cleanup;
+ }
+
+ /* Set-up TID connection */
+ if (-1==(args->fwd_req->conn = tidc_open_connection(tidc,
+ args->aaa_hostname->buf,
+ TID_PORT, /* TODO: make this configurable */
+ &(args->fwd_req->gssctx)))) {
+ tr_notice("tr_tids_req_fwd_thread: Error in tidc_open_connection.");
+ /* tids_send_err_response(tids, orig_req, "Can't open connection to next hop TIDS"); */
+ /* TODO: encode reason for failure */
+ success=0;
+ goto cleanup;
+ };
+ tr_debug("tr_tids_req_fwd_thread: thread %d opened TID connection to %s.",
+ cookie->thread_id,
+ args->aaa_hostname->buf);
+
+ /* Send a TID request. */
+ if (0 > (rc = tidc_fwd_request(tidc, args->fwd_req, tr_tidc_resp_handler, (void *)cookie))) {
+ tr_notice("Error from tidc_fwd_request, rc = %d.", rc);
+ success=0;
+ goto cleanup;
+ }
+ /* cookie->resp should now contain our copy of the response */
+ success=1;
+ tr_debug("tr_tids_req_fwd_thread: thread %d received response.");
+
+cleanup:
+ /* Notify parent thread of the response, if it's still listening. */
+ if (0!=tr_tids_fwd_get_mutex(args)) {
+ tr_notice("tr_tids_req_fwd_thread: thread %d unable to acquire mutex.", cookie->thread_id);
+ } else if (NULL!=args->mq) {
+ /* mq is still valid, so we can queue our response */
+ tr_debug("tr_tids_req_fwd_thread: thread %d using valid msg queue.", cookie->thread_id);
+ if (success)
+ msg=tr_mq_msg_new(tmp_ctx, TR_TID_MQMSG_SUCCESS, TR_MQ_PRIO_NORMAL);
+ else
+ msg=tr_mq_msg_new(tmp_ctx, TR_TID_MQMSG_FAILURE, TR_MQ_PRIO_NORMAL);
+
+ if (msg==NULL)
+ tr_notice("tr_tids_req_fwd_thread: thread %d unable to allocate response msg.", cookie->thread_id);
+
+ tr_mq_msg_set_payload(msg, (void *)cookie, NULL);
+ if (NULL!=cookie)
+ talloc_steal(msg, cookie); /* attach this to the msg so we can forget about it */
+ tr_mq_add(args->mq, msg);
+ talloc_steal(NULL, args); /* take out of our tmp_ctx; master thread now responsible for freeing */
+ tr_debug("tr_tids_req_fwd_thread: thread %d queued response message.", cookie->thread_id);
+ if (0!=tr_tids_fwd_release_mutex(args))
+ tr_notice("tr_tids_req_fwd_thread: Error releasing mutex.");
+ }
+
+ talloc_free(tmp_ctx);
+ return NULL;
+}
+
+/* Merges r2 into r1 if they are compatible. */
+static TID_RC tr_tids_merge_resps(TID_RESP *r1, TID_RESP *r2)
+{
+ /* ensure these are compatible replies */
+ 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;
+
+ tid_srvr_blk_add(r1->servers, tid_srvr_blk_dup(r1, r2->servers));
+ return TID_SUCCESS;
+}
+
+static int tr_tids_req_handler(TIDS_INSTANCE *tids,
+ TID_REQ *orig_req,
+ TID_RESP *resp,
+ void *cookie_in)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_AAA_SERVER *aaa_servers=NULL, *this_aaa=NULL;
+ int n_aaa=0;
+ int idp_shared=0;
+ TR_AAA_SERVER_ITER *aaa_iter=NULL;
+ pthread_t aaa_thread[TR_TID_MAX_AAA_SERVERS];
+ struct tr_tids_fwd_cookie *aaa_cookie[TR_TID_MAX_AAA_SERVERS]={NULL};
+ TID_RESP *aaa_resp[TR_TID_MAX_AAA_SERVERS]={NULL};
TR_NAME *apc = NULL;
TID_REQ *fwd_req = NULL;
TR_COMM *cfg_comm = NULL;
TR_COMM *cfg_apc = NULL;
int oaction = TR_FILTER_ACTION_REJECT;
- int rc = 0;
time_t expiration_interval=0;
struct tr_tids_event_cookie *cookie=talloc_get_type_abort(cookie_in, struct tr_tids_event_cookie);
TR_CFG_MGR *cfg_mgr=cookie->cfg_mgr;
TRPS_INSTANCE *trps=cookie->trps;
TRP_ROUTE *route=NULL;
+ TR_MQ *mq=NULL;
+ TR_MQ_MSG *msg=NULL;
+ unsigned int n_responses=0;
+ unsigned int n_failed=0;
+ struct timespec ts_abort={0};
+ unsigned int resp_frac_numer=cfg_mgr->active->internal->tid_resp_numer;
+ unsigned int resp_frac_denom=cfg_mgr->active->internal->tid_resp_denom;
+ TR_RESP_COOKIE *payload=NULL;
+ int ii=0;
int retval=-1;
if ((!tids) || (!orig_req) || (!resp)) {
tids->req_count++;
/* Duplicate the request, so we can modify and forward it */
- if (NULL == (fwd_req = tid_dup_req(orig_req))) {
+ if (NULL == (fwd_req=tid_dup_req(orig_req))) {
tr_debug("tr_tids_req_handler: Unable to duplicate request.");
retval=-1;
goto cleanup;
}
+ talloc_steal(tmp_ctx, fwd_req);
- if (NULL == (cfg_comm = tr_comm_lookup(cfg_mgr->active->comms, orig_req->comm))) {
+ 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");
retval=-1;
}
/* Check that the rp_realm matches the filter for the GSS name that
- * was received. */
+ * was received. N.B. that tids->rp_gss was pointed at the correct
+ * rp_client when we received its GSS name. It is only set within
+ * the TIDS handler subprocess. */
if ((!tids->rp_gss) ||
(!tids->rp_gss->filter)) {
goto cleanup;
}
/* Check that the rp_realm is a member of the community in the request */
- if (NULL == (tr_find_comm_rp(cfg_comm, orig_req->rp_realm))) {
+ 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");
retval=-1;
/* 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)) {
apc = tr_dup_name(cfg_comm->apcs->id);
/* Check that the APC is configured */
- if (NULL == (cfg_apc = tr_comm_lookup(cfg_mgr->active->comms, apc))) {
+ 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;
fwd_req->orig_coi = orig_req->comm;
/* Check that rp_realm is a member of this APC */
- if (NULL == (tr_find_comm_rp(cfg_apc, orig_req->rp_realm))) {
+ 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;
}
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->idp_realms,
+ 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);
+ orig_req->comm,
+ &idp_shared);
} else {
tr_debug("tr_tids_req_handler: route not local.");
aaa_servers = tr_aaa_server_new(tmp_ctx, trp_route_get_next_hop(route));
+ idp_shared=0;
}
/* Find the AAA server(s) for this request */
retval=-1;
goto cleanup;
}
+ idp_shared=0;
} else {
/* if we aren't defaulting, check idp coi and apc membership */
- if (NULL == (tr_find_comm_idp(cfg_comm, fwd_req->realm))) {
+ 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");
retval=-1;
goto cleanup;
}
- if ( cfg_apc && (NULL == (tr_find_comm_idp(cfg_apc, fwd_req->realm)))) {
+ 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");
retval=-1;
}
/* send a TID request to the AAA server(s), and get the answer(s) */
- /* TBD -- Handle multiple servers */
-
+ 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;
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;
- /* Create a TID client instance */
- if (NULL == (tidc = tidc_create())) {
- tr_crit("tr_tids_req_hander: Unable to allocate TIDC instance.");
- tids_send_err_response(tids, orig_req, "Memory allocation failure");
+
+ /* Set up message queue for replies from req forwarding threads */
+ mq=tr_mq_new(tmp_ctx);
+ if (mq==NULL) {
+ tr_notice("tr_tids_req_handler: unable to allocate message queue.");
retval=-1;
goto cleanup;
}
- /* Use the DH parameters from the original request */
- /* TBD -- this needs to be fixed when we handle more than one req per conn */
- tidc->client_dh = orig_req->tidc_dh;
-
- /* Save information about this request for the response */
- resp_cookie.tids = tids;
- resp_cookie.orig_req = orig_req;
+ tr_debug("tr_tids_req_handler: message queue allocated.");
- /* Set-up TID connection */
- if (-1 == (fwd_req->conn = tidc_open_connection(tidc,
- aaa_servers->hostname->buf,
- TID_PORT,
- &(fwd_req->gssctx)))) {
- tr_notice("tr_tids_req_handler: Error in tidc_open_connection.");
- tids_send_err_response(tids, orig_req, "Can't open connection to next hop TIDS");
+ /* start threads */
+ aaa_iter=tr_aaa_server_iter_new(tmp_ctx);
+ if (aaa_iter==NULL) {
+ tr_notice("tr_tids_req_handler: unable to allocate AAA server iterator.");
retval=-1;
goto cleanup;
- };
+ }
+ for (n_aaa=0, this_aaa=tr_aaa_server_iter_first(aaa_iter, aaa_servers);
+ this_aaa!=NULL;
+ n_aaa++, this_aaa=tr_aaa_server_iter_next(aaa_iter)) {
+ tr_debug("tr_tids_req_handler: Preparing to start thread %d.", n_aaa);
+
+ aaa_cookie[n_aaa]=talloc(tmp_ctx, struct tr_tids_fwd_cookie);
+ if (aaa_cookie[n_aaa]==NULL) {
+ tr_notice("tr_tids_req_handler: unable to allocate cookie for AAA thread %d.", n_aaa);
+ retval=-1;
+ goto cleanup;
+ }
+ talloc_set_destructor((void *)(aaa_cookie[n_aaa]), tr_tids_fwd_cookie_destructor);
+ /* fill in the cookie. To ensure the thread has valid data even if we exit first and
+ * abandon it, duplicate anything pointed to (except the mq). */
+ aaa_cookie[n_aaa]->thread_id=n_aaa;
+ if (0!=pthread_mutex_init(&(aaa_cookie[n_aaa]->mutex), NULL)) {
+ tr_notice("tr_tids_req_handler: unable to init mutex for AAA thread %d.", n_aaa);
+ retval=-1;
+ goto cleanup;
+ }
+ aaa_cookie[n_aaa]->mq=mq;
+ aaa_cookie[n_aaa]->aaa_hostname=tr_dup_name(this_aaa->hostname);
+ aaa_cookie[n_aaa]->dh_params=tr_dh_dup(orig_req->tidc_dh);
+ aaa_cookie[n_aaa]->fwd_req=tid_dup_req(fwd_req);
+ talloc_steal(aaa_cookie[n_aaa], aaa_cookie[n_aaa]->fwd_req);
+ tr_debug("tr_tids_req_handler: cookie %d initialized.", n_aaa);
+
+ /* Take the cookie out of tmp_ctx before starting thread. If thread starts, it becomes
+ * responsible for freeing it until it queues a response. If we did not do this, the possibility
+ * exists that this function exits, freeing the cookie, before the thread takes the cookie
+ * out of our tmp_ctx. This would cause a segfault or talloc error in the thread. */
+ talloc_steal(NULL, aaa_cookie[n_aaa]);
+ if (0!=pthread_create(&(aaa_thread[n_aaa]), NULL, tr_tids_req_fwd_thread, aaa_cookie[n_aaa])) {
+ talloc_steal(tmp_ctx, aaa_cookie[n_aaa]); /* thread start failed; steal this back */
+ tr_notice("tr_tids_req_handler: unable to start AAA thread %d.", n_aaa);
+ retval=-1;
+ goto cleanup;
+ }
+ tr_debug("tr_tids_req_handler: thread %d started.", n_aaa);
+ }
- /* Send a TID request */
- if (0 > (rc = tidc_fwd_request(tidc, fwd_req, &tr_tidc_resp_handler, (void *)&resp_cookie))) {
- tr_notice("Error from tidc_fwd_request, rc = %d.", rc);
- tids_send_err_response(tids, orig_req, "Can't forward request to next hop TIDS");
+ /* determine expiration time */
+ if (0!=tr_mq_pop_timeout(cfg_mgr->active->internal->tid_req_timeout, &ts_abort)) {
+ tr_notice("tr_tids_req_handler: unable to read clock for timeout.");
retval=-1;
goto cleanup;
}
+ /* wait for responses */
+ tr_debug("tr_tids_req_handler: waiting for response(s).");
+ n_responses=0;
+ n_failed=0;
+ while (((n_responses+n_failed)<n_aaa) &&
+ (NULL!=(msg=tr_mq_pop(mq, &ts_abort)))) {
+ /* process message */
+ if (0==strcmp(tr_mq_msg_get_message(msg), TR_TID_MQMSG_SUCCESS)) {
+ payload=talloc_get_type_abort(tr_mq_msg_get_payload(msg), TR_RESP_COOKIE);
+ talloc_steal(tmp_ctx, payload); /* put this back in our context */
+ aaa_resp[payload->thread_id]=payload->resp; /* save pointers to these */
+
+ if (payload->resp->result==TID_SUCCESS) {
+ tr_tids_merge_resps(resp, payload->resp);
+ n_responses++;
+ } else {
+ n_failed++;
+ tr_notice("tr_tids_req_handler: TID error received from AAA server %d: %.*s",
+ payload->thread_id,
+ payload->resp->err_msg->len,
+ payload->resp->err_msg->buf);
+ }
+ } else if (0==strcmp(tr_mq_msg_get_message(msg), TR_TID_MQMSG_FAILURE)) {
+ /* failure */
+ n_failed++;
+ payload=talloc_get_type(tr_mq_msg_get_payload(msg), TR_RESP_COOKIE);
+ if (payload!=NULL)
+ talloc_steal(tmp_ctx, payload); /* put this back in our context */
+ else {
+ /* this means the thread was unable to allocate a response cookie, and we thus cannot determine which thread it was. This is bad and should never happen in a working system.. Give up. */
+ tr_notice("tr_tids_req_handler: TID request thread sent invalid reply. Aborting!");
+ retval=-1;
+ goto cleanup;
+ }
+ tr_notice("tr_tids_req_handler: TID request for AAA server %d failed.",
+ payload->thread_id);
+ } else {
+ /* unexpected message */
+ tr_err("tr_tids_req_handler: Unexpected message received. Aborting!");
+ retval=-1;
+ goto cleanup;
+ }
+
+ /* Set the cookie pointer to NULL so we know we've dealt with this one. The
+ * cookie itself is in our tmp_ctx, which we'll free before exiting. Let it hang
+ * around in case we are still using pointers to elements of the cookie. */
+ aaa_cookie[payload->thread_id]=NULL;
+
+ tr_mq_msg_free(msg);
+
+ /* check whether we've received enough responses to exit */
+ if ((idp_shared && (n_responses>0)) ||
+ (resp_frac_denom*n_responses>=resp_frac_numer*n_aaa))
+ break;
+ }
+
+ tr_debug("tr_tids_req_handler: done waiting for responses. %d responses, %d failures.",
+ n_responses, n_failed);
+ /* Inform any remaining threads that we will no longer handle their responses. */
+ for (ii=0; ii<n_aaa; ii++) {
+ if (aaa_cookie[ii]!=NULL) {
+ if (0!=tr_tids_fwd_get_mutex(aaa_cookie[ii]))
+ tr_notice("tr_tids_req_handler: unable to get mutex for AAA thread %d.", ii);
+
+ aaa_cookie[ii]->mq=NULL; /* threads will not try to respond through a null mq */
+
+ if (0!=tr_tids_fwd_release_mutex(aaa_cookie[ii]))
+ tr_notice("tr_tids_req_handler: unable to release mutex for AAA thread %d.", ii);
+ }
+ }
+
+ /* Now all threads have either replied (and aaa_cookie[ii] is null) or have been told not to
+ * reply (by setting their mq pointer to null). However, some may have responded by placing
+ * a message on the mq after we last checked but before we set their mq pointer to null. These
+ * will not know that we gave up on them, so we must free their cookies for them. We can just
+ * go through any remaining messages on the mq to identify these threads. By putting them in
+ * our context instead of freeing them directly, we ensure we don't accidentally invalidate
+ * any of our own pointers into the structure before this function exits. */
+ while (NULL!=(msg=tr_mq_pop(mq, NULL))) {
+ payload=(TR_RESP_COOKIE *)tr_mq_msg_get_payload(msg);
+ if (aaa_cookie[payload->thread_id]!=NULL)
+ talloc_steal(tmp_ctx, aaa_cookie[payload->thread_id]);
+
+ tr_mq_msg_free(msg);
+ }
+
+ if (n_responses==0) {
+ /* No requests succeeded. Forward an error if we got any error responses. */
+ 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).");
+ }
+ }
+
/* success! */
retval=0;
TALLOC_CTX *tmp_ctx=talloc_new(NULL);
struct tr_tids_event_cookie *cookie=NULL;
int retval=0;
+ size_t ii=0;
if (tids_ev == NULL) {
tr_debug("tr_tids_event_init: Null tids_ev.");
talloc_steal(tids, cookie);
/* get a tids listener */
- tids_ev->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);
- if (tids_ev->sock_fd < 0) {
+ 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);
+ if (tids_ev->n_sock_fd==0) {
tr_crit("Error opening TID server socket.");
retval=1;
goto cleanup;
}
- /* and its event */
- tids_ev->ev=event_new(base,
- tids_ev->sock_fd,
- EV_READ|EV_PERSIST,
- tr_tids_event_cb,
- (void *)tids);
- event_add(tids_ev->ev, NULL);
+ /* Set up events */
+ for (ii=0; ii<tids_ev->n_sock_fd; ii++) {
+ tids_ev->ev[ii]=event_new(base,
+ tids_ev->sock_fd[ii],
+ EV_READ|EV_PERSIST,
+ tr_tids_event_cb,
+ (void *)tids);
+ event_add(tids_ev->ev[ii], NULL);
+ }
cleanup:
talloc_free(tmp_ctx);
tr_debug("tr_trps_cleanup_conn: freeing %p", conn);
pthread_join(*trp_connection_get_thread(conn), NULL);
trps_remove_connection(trps, conn);
- talloc_report_full(conn, stderr);
trp_connection_free(conn);
tr_debug("tr_trps_cleanup_conn: deleted connection");
}
TR_MQ_MSG *msg=NULL;
const char *s=NULL;
- talloc_report_full(trps->mq, stderr);
msg=trps_mq_pop(trps);
while (msg!=NULL) {
s=tr_mq_msg_get_message(msg);
TRPS_INSTANCE *trps=cookie->trps;
struct event *ev=cookie->ev;
- tr_debug("tr_trps_update: sending scheduled route updates.");
+ tr_debug("tr_trps_update: sending scheduled route/community updates.");
trps_update(trps, TRP_UPDATE_SCHEDULED);
event_add(ev, &(trps->update_interval));
+ tr_debug("tr_trps_update: update interval=%d", trps->update_interval.tv_sec);
}
static void tr_trps_sweep(int listener, short event, void *arg)
tr_debug("tr_trps_sweep: sweeping routes.");
trps_sweep_routes(trps);
+ tr_debug("tr_trps_sweep: sweeping communities.");
+ trps_sweep_ctable(trps);
tr_trps_print_route_table(trps, stderr);
/* schedule the event to run again */
event_add(ev, &(trps->sweep_interval));
struct tr_trps_event_cookie *sweep_cookie=NULL;
struct timeval zero_time={0,0};
TRP_RC retval=TRP_ERROR;
+ size_t ii=0;
if (tr->events != NULL) {
tr_notice("tr_trps_event_init: tr->events was not null. Freeing before reallocating..");
trps_cookie->cfg_mgr=tr->cfg_mgr;
/* get a trps listener */
- listen_ev->sock_fd=trps_get_listener(tr->trps,
- tr_trps_msg_handler,
- tr_trps_gss_handler,
- tr->cfg_mgr->active->internal->hostname,
- tr->cfg_mgr->active->internal->trps_port,
- (void *)trps_cookie);
- if (listen_ev->sock_fd < 0) {
+ listen_ev->n_sock_fd=trps_get_listener(tr->trps,
+ tr_trps_msg_handler,
+ tr_trps_gss_handler,
+ tr->cfg_mgr->active->internal->hostname,
+ tr->cfg_mgr->active->internal->trps_port,
+ (void *)trps_cookie,
+ listen_ev->sock_fd,
+ TR_MAX_SOCKETS);
+ if (listen_ev->n_sock_fd==0) {
tr_crit("Error opening TRP server socket.");
retval=TRP_ERROR;
tr_trps_events_free(tr->events);
tr->events=NULL;
goto cleanup;
}
- trps_cookie->ev=listen_ev->ev; /* in case it needs to frob the event */
-
- /* and its event */
- listen_ev->ev=event_new(base,
- listen_ev->sock_fd,
- EV_READ|EV_PERSIST,
- tr_trps_event_cb,
- (void *)(tr->trps));
- event_add(listen_ev->ev, NULL);
+
+ /* Set up events for the sockets */
+ for (ii=0; ii<listen_ev->n_sock_fd; ii++) {
+ listen_ev->ev[ii]=event_new(base,
+ listen_ev->sock_fd[ii],
+ EV_READ|EV_PERSIST,
+ tr_trps_event_cb,
+ (void *)(tr->trps));
+ event_add(listen_ev->ev[ii], NULL);
+ }
/* now set up message queue processing event, only triggered by
* tr_trps_mq_cb() */
const char *msg_type=NULL;
char *encoded_msg=NULL;
TR_NAME *peer_gssname=NULL;
+ int n_sent=0;
+ int exit_loop=0;
struct trpc_notify_cb_data cb_data={0,
PTHREAD_COND_INITIALIZER,
trps_mq_add(trps, msg); /* steals msg context */
msg=NULL;
- while(1) {
+ while(!exit_loop) {
cb_data.msg_ready=0;
pthread_cond_wait(&(cb_data.cond), &(cb_data.mutex));
/* verify the condition */
if (cb_data.msg_ready) {
- msg=trpc_mq_pop(trpc);
- if (msg==NULL) {
- /* no message in the queue */
- tr_err("tr_trpc_thread: notified of msg, but queue empty");
- break;
- }
-
- msg_type=tr_mq_msg_get_message(msg);
+ for (msg=trpc_mq_pop(trpc),n_sent=0; msg!=NULL; msg=trpc_mq_pop(trpc),n_sent++) {
+ msg_type=tr_mq_msg_get_message(msg);
- if (0==strcmp(msg_type, TR_MQMSG_ABORT)) {
- tr_mq_msg_free(msg);
- break; /* exit loop */
- }
- else if (0==strcmp(msg_type, TR_MQMSG_TRPC_SEND)) {
- encoded_msg=tr_mq_msg_get_payload(msg);
- if (encoded_msg==NULL)
- tr_notice("tr_trpc_thread: null outgoing TRP message.");
- else {
- rc = trpc_send_msg(trpc, encoded_msg);
- if (rc!=TRP_SUCCESS) {
- tr_notice("tr_trpc_thread: trpc_send_msg failed.");
- tr_mq_msg_free(msg);
- break;
+ if (0==strcmp(msg_type, TR_MQMSG_ABORT)) {
+ exit_loop=1;
+ break;
+ }
+ else if (0==strcmp(msg_type, TR_MQMSG_TRPC_SEND)) {
+ encoded_msg=tr_mq_msg_get_payload(msg);
+ if (encoded_msg==NULL)
+ tr_notice("tr_trpc_thread: null outgoing TRP message.");
+ else {
+ rc = trpc_send_msg(trpc, encoded_msg);
+ if (rc!=TRP_SUCCESS) {
+ tr_notice("tr_trpc_thread: trpc_send_msg failed.");
+ exit_loop=1;
+ break;
+ }
}
}
- }
- else
- tr_notice("tr_trpc_thread: unknown message '%s' received.", msg_type);
+ else
+ tr_notice("tr_trpc_thread: unknown message '%s' received.", msg_type);
- tr_mq_msg_free(msg);
+ tr_mq_msg_free(msg);
+ }
+ if (n_sent==0)
+ tr_err("tr_trpc_thread: notified of msg, but queue empty");
+ else
+ tr_debug("tr_trpc_thread: sent %d messages.", n_sent);
}
}
}
if (trust_router_name==NULL)
return TRP_NOMEM;
- for (cur=cfg->idp_realms; cur!=NULL; cur=cur->next) {
+ for (cur=cfg->ctable->idp_realms; cur!=NULL; cur=cur->next) {
local_routes=tr_make_local_routes(tmp_ctx, cur, trust_router_name, &n_routes);
for (ii=0; ii<n_routes; ii++)
trps_add_route(trps, local_routes[ii]);
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);
+ trps_set_ctable(trps, new_cfg->ctable);
trps_set_ptable(trps, new_cfg->peers);
trps_set_peer_status_callback(trps, tr_peer_status_change, (void *)trps);
trps_clear_rtable(trps); /* should we do this every time??? */
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 *peer=talloc(memctx, TRP_PEER);
if (peer!=NULL) {
peer->next=NULL;
+ peer->label=NULL;
peer->server=NULL;
peer->servicename=NULL;
peer->gss_names=NULL;
* Do not modify or free the label. */
TR_NAME *trp_peer_get_label(TRP_PEER *peer)
{
- TR_GSS_NAMES_ITER *iter=tr_gss_names_iter_new(NULL);
- TR_NAME *name=NULL;
+ char *s=NULL;
- /* for now, use the first gss name */
- if (iter!=NULL) {
- name=tr_gss_names_iter_first(iter, peer->gss_names);
- talloc_free(iter);
+ 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 name;
+ return peer->label;
}
/* Get a name that identifies this peer for display to the user, etc.
#include <trust_router/tr_name.h>
#include <trp_internal.h>
+#include <tr_comm.h>
+#include <tr_apc.h>
#include <tr_debug.h>
/* static prototypes */
-static void *trp_inforec_route_new(TALLOC_CTX *mem_ctx);
-static void trp_inforec_route_print(TRP_INFOREC_DATA);
+static TRP_INFOREC_DATA *trp_inforec_route_new(TALLOC_CTX *mem_ctx);
+static void trp_inforec_route_print(TRP_INFOREC_DATA *);
+static TRP_INFOREC_DATA *trp_inforec_comm_new(TALLOC_CTX *mem_ctx);
+static void trp_inforec_comm_print(TRP_INFOREC_DATA *);
struct trp_inforec_type_entry {
const char *name;
TRP_INFOREC_TYPE type;
- void *(*allocate)(TALLOC_CTX *);
- void (*print)(TRP_INFOREC_DATA);
+ TRP_INFOREC_DATA *(*allocate)(TALLOC_CTX *);
+ void (*print)(TRP_INFOREC_DATA *);
};
static struct trp_inforec_type_entry trp_inforec_type_table[] = {
{ "route", TRP_INFOREC_TYPE_ROUTE, trp_inforec_route_new, trp_inforec_route_print },
- { "comm", TRP_INFOREC_TYPE_COMMUNITY, NULL, NULL },
+ { "comm", TRP_INFOREC_TYPE_COMMUNITY, trp_inforec_comm_new, trp_inforec_comm_print },
{ NULL, TRP_INFOREC_TYPE_UNKNOWN, NULL, NULL } /* must be the last entry */
};
TRP_INFOREC_ROUTE *body=talloc_get_type_abort(object, TRP_INFOREC_ROUTE);
/* clean up TR_NAME data, which are not managed by talloc */
- if (body->comm != NULL) {
- tr_free_name(body->comm);
- body->comm=NULL;
- tr_debug("trp_inforec_route_destructor: freed community");
- }
- if (body->realm != NULL) {
- tr_free_name(body->realm);
- body->realm=NULL;
- tr_debug("trp_inforec_route_destructor: freed realm");
- }
- if (body->trust_router != NULL) {
+ if (body->trust_router != NULL)
tr_free_name(body->trust_router);
- body->trust_router=NULL;
- tr_debug("trp_inforec_route_destructor: freed trust_router");
- }
- if (body->next_hop != NULL) {
+ if (body->next_hop != NULL)
tr_free_name(body->next_hop);
- body->next_hop=NULL;
- tr_debug("trp_inforec_route_destructor: freed next_hop");
- }
-
return 0;
}
-static void *trp_inforec_route_new(TALLOC_CTX *mem_ctx)
+static TRP_INFOREC_DATA *trp_inforec_route_new(TALLOC_CTX *mem_ctx)
{
- TRP_INFOREC_ROUTE *new_rec=talloc(mem_ctx, TRP_INFOREC_ROUTE);
+ TRP_INFOREC_DATA *new_data=talloc(mem_ctx, TRP_INFOREC_DATA);
+ TRP_INFOREC_ROUTE *new_rec=NULL;
+
+ if (new_data==NULL)
+ return NULL;
- if (new_rec != NULL) {
- new_rec->comm=NULL;
- new_rec->realm=NULL;
+ new_rec=talloc(new_data, TRP_INFOREC_ROUTE);
+ if (new_rec == NULL) {
+ talloc_free(new_data);
+ new_data=NULL;
+ } else {
new_rec->trust_router=NULL;
new_rec->next_hop=NULL;
new_rec->next_hop_port=0;
new_rec->metric=TRP_METRIC_INFINITY;
new_rec->interval=0;
talloc_set_destructor((void *)new_rec, trp_inforec_route_destructor);
+ new_data->route=new_rec;
}
- return new_rec;
+
+ return new_data;
+}
+
+
+static int trp_inforec_comm_destructor(void *obj)
+{
+ TRP_INFOREC_COMM *rec=talloc_get_type_abort(obj, TRP_INFOREC_COMM);
+ if (rec->owner_realm!=NULL)
+ tr_free_name(rec->owner_realm);
+ if (rec->owner_contact!=NULL)
+ tr_free_name(rec->owner_contact);
+ if (rec->provenance!=NULL)
+ json_decref(rec->provenance);
+ return 0;
+}
+
+static TRP_INFOREC_DATA *trp_inforec_comm_new(TALLOC_CTX *mem_ctx)
+{
+ TRP_INFOREC_DATA *new_data=talloc(mem_ctx, TRP_INFOREC_DATA);
+ TRP_INFOREC_COMM *new_rec=NULL;
+
+ if (new_data==NULL)
+ return NULL;
+
+ new_rec=talloc(new_data, TRP_INFOREC_COMM);
+ if (new_rec==NULL) {
+ talloc_free(new_data);
+ new_data=NULL;
+ } else {
+ new_rec->comm_type=TR_COMM_UNKNOWN;
+ new_rec->role=TR_ROLE_UNKNOWN;
+ new_rec->apcs=NULL;
+ new_rec->owner_realm=NULL;
+ new_rec->owner_contact=NULL;
+ new_rec->expiration_interval=0;
+ new_rec->provenance=NULL;
+ new_rec->interval=0;
+ talloc_set_destructor((void *)new_rec, trp_inforec_comm_destructor);
+ new_data->comm=new_rec;
+ }
+
+ return new_data;
}
TRP_INFOREC *trp_inforec_get_next(TRP_INFOREC *rec)
TRP_INFOREC_TYPE trp_inforec_get_type(TRP_INFOREC *rec)
{
- if (rec)
+ if (rec!=NULL)
return rec->type;
else
return TRP_INFOREC_TYPE_UNKNOWN;
rec->type=type;
}
-TR_NAME *trp_inforec_get_comm(TRP_INFOREC *rec)
+TR_NAME *trp_inforec_get_trust_router(TRP_INFOREC *rec)
{
switch (rec->type) {
case TRP_INFOREC_TYPE_ROUTE:
- if (rec->data.route!=NULL)
- return rec->data.route->comm;
+ if (rec->data->route!=NULL)
+ return rec->data->route->trust_router;
break;
default:
break;
return NULL;
}
-TR_NAME *trp_inforec_dup_comm(TRP_INFOREC *rec)
+TR_NAME *trp_inforec_dup_trust_router(TRP_INFOREC *rec)
{
- return tr_dup_name(trp_inforec_get_comm(rec));
+ return tr_dup_name(trp_inforec_get_trust_router(rec));
}
-TRP_RC trp_inforec_set_comm(TRP_INFOREC *rec, TR_NAME *comm)
+TRP_RC trp_inforec_set_trust_router(TRP_INFOREC *rec, TR_NAME *trust_router)
{
switch (rec->type) {
case TRP_INFOREC_TYPE_ROUTE:
- if (rec->data.route!=NULL) {
- rec->data.route->comm=comm;
+ if (rec->data->route!=NULL) {
+ rec->data->route->trust_router=trust_router;
return TRP_SUCCESS;
}
break;
return TRP_ERROR;
}
-TR_NAME *trp_inforec_get_realm(TRP_INFOREC *rec)
+/* TODO: need to return hostname/port --jlr */
+TR_NAME *trp_inforec_get_next_hop(TRP_INFOREC *rec)
{
switch (rec->type) {
case TRP_INFOREC_TYPE_ROUTE:
- if (rec->data.route!=NULL)
- return rec->data.route->realm;
+ if (rec->data->route!=NULL)
+ return rec->data->route->next_hop;
break;
default:
break;
return NULL;
}
-TR_NAME *trp_inforec_dup_realm(TRP_INFOREC *rec)
+TR_NAME *trp_inforec_dup_next_hop(TRP_INFOREC *rec)
{
- return tr_dup_name(trp_inforec_get_realm(rec));
+ return tr_dup_name(trp_inforec_get_next_hop(rec));
}
-TRP_RC trp_inforec_set_realm(TRP_INFOREC *rec, TR_NAME *realm)
+TRP_RC trp_inforec_set_next_hop(TRP_INFOREC *rec, TR_NAME *next_hop)
{
switch (rec->type) {
case TRP_INFOREC_TYPE_ROUTE:
- if (rec->data.route!=NULL) {
- rec->data.route->realm=realm;
- return TRP_SUCCESS;
- }
+ if (rec->data->route==NULL)
+ return TRP_ERROR;
+ rec->data->route->next_hop=next_hop;
+ break;
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ /* next hop not used for community records */
break;
default:
break;
}
- return TRP_ERROR;
+ return TRP_SUCCESS;
}
-TR_NAME *trp_inforec_get_trust_router(TRP_INFOREC *rec)
+unsigned int trp_inforec_get_metric(TRP_INFOREC *rec)
{
switch (rec->type) {
case TRP_INFOREC_TYPE_ROUTE:
- if (rec->data.route!=NULL)
- return rec->data.route->trust_router;
+ if (rec->data->route!=NULL)
+ return rec->data->route->metric;
break;
default:
break;
}
- return NULL;
+ return TRP_METRIC_INVALID;
}
-TR_NAME *trp_inforec_dup_trust_router(TRP_INFOREC *rec)
+TRP_RC trp_inforec_set_metric(TRP_INFOREC *rec, unsigned int metric)
{
- return tr_dup_name(trp_inforec_get_trust_router(rec));
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_ROUTE:
+ if (rec->data->route!=NULL) {
+ rec->data->route->metric=metric;
+ return TRP_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+ return TRP_ERROR;
}
-TRP_RC trp_inforec_set_trust_router(TRP_INFOREC *rec, TR_NAME *trust_router)
+unsigned int trp_inforec_get_interval(TRP_INFOREC *rec)
+{
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_ROUTE:
+ if (rec->data->route!=NULL)
+ return rec->data->route->interval;
+ break;
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL)
+ return rec->data->comm->interval;
+ break;
+ default:
+ break;
+ }
+ return TRP_INTERVAL_INVALID;
+}
+
+TRP_RC trp_inforec_set_interval(TRP_INFOREC *rec, unsigned int interval)
{
switch (rec->type) {
case TRP_INFOREC_TYPE_ROUTE:
- if (rec->data.route!=NULL) {
- rec->data.route->trust_router=trust_router;
+ if (rec->data->route!=NULL) {
+ rec->data->route->interval=interval;
return TRP_SUCCESS;
}
break;
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL) {
+ rec->data->comm->interval=interval;
+ return TRP_SUCCESS;
+ }
default:
break;
}
return TRP_ERROR;
}
-/* TODO: need to return hostname/port --jlr */
-TR_NAME *trp_inforec_get_next_hop(TRP_INFOREC *rec)
+time_t trp_inforec_get_exp_interval(TRP_INFOREC *rec)
{
switch (rec->type) {
- case TRP_INFOREC_TYPE_ROUTE:
- if (rec->data.route!=NULL)
- return rec->data.route->next_hop;
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL)
+ return rec->data->comm->expiration_interval;
break;
default:
break;
}
- return NULL;
+ return 0;
}
-TR_NAME *trp_inforec_dup_next_hop(TRP_INFOREC *rec)
+TRP_RC trp_inforec_set_exp_interval(TRP_INFOREC *rec, time_t expint)
{
- return tr_dup_name(trp_inforec_get_next_hop(rec));
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL) {
+ rec->data->comm->expiration_interval=expint;
+ return TRP_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+ return TRP_ERROR;
}
-TRP_RC trp_inforec_set_next_hop(TRP_INFOREC *rec, TR_NAME *next_hop)
+TR_COMM_TYPE trp_inforec_get_comm_type(TRP_INFOREC *rec)
{
switch (rec->type) {
- case TRP_INFOREC_TYPE_ROUTE:
- if (rec->data.route!=NULL) {
- rec->data.route->next_hop=next_hop;
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL)
+ return rec->data->comm->comm_type;
+ break;
+ default:
+ break;
+ }
+ return TR_COMM_UNKNOWN;
+}
+
+TRP_RC trp_inforec_set_comm_type(TRP_INFOREC *rec, TR_COMM_TYPE type)
+{
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL) {
+ rec->data->comm->comm_type=type;
return TRP_SUCCESS;
}
break;
return TRP_ERROR;
}
-unsigned int trp_inforec_get_metric(TRP_INFOREC *rec)
+TR_REALM_ROLE trp_inforec_get_role(TRP_INFOREC *rec)
{
switch (rec->type) {
- case TRP_INFOREC_TYPE_ROUTE:
- if (rec->data.route!=NULL)
- return rec->data.route->metric;
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL)
+ return rec->data->comm->role;
break;
default:
break;
}
- return TRP_METRIC_INVALID;
+ return TR_ROLE_UNKNOWN;
}
-TRP_RC trp_inforec_set_metric(TRP_INFOREC *rec, unsigned int metric)
+TRP_RC trp_inforec_set_role(TRP_INFOREC *rec, TR_REALM_ROLE role)
{
switch (rec->type) {
- case TRP_INFOREC_TYPE_ROUTE:
- if (rec->data.route!=NULL) {
- rec->data.route->metric=metric;
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL) {
+ rec->data->comm->role=role;
return TRP_SUCCESS;
+ break;
}
+ default:
break;
+ }
+ return TRP_ERROR;
+}
+
+TR_APC *trp_inforec_get_apcs(TRP_INFOREC *rec)
+{
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL)
+ return rec->data->comm->apcs;
+ break;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+TRP_RC trp_inforec_set_apcs(TRP_INFOREC *rec, TR_APC *apcs)
+{
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL) {
+ rec->data->comm->apcs=apcs;
+ talloc_steal(rec, apcs);
+ return TRP_SUCCESS;
+ }
+ break;
+
default:
break;
}
return TRP_ERROR;
}
-unsigned int trp_inforec_get_interval(TRP_INFOREC *rec)
+TR_NAME *trp_inforec_get_owner_realm(TRP_INFOREC *rec)
{
switch (rec->type) {
- case TRP_INFOREC_TYPE_ROUTE:
- if (rec->data.route!=NULL)
- return rec->data.route->interval;
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL)
+ return rec->data->comm->owner_realm;
break;
default:
break;
}
- return TRP_INTERVAL_INVALID;
+ return NULL;
}
-TRP_RC trp_inforec_set_interval(TRP_INFOREC *rec, unsigned int interval)
+TRP_RC trp_inforec_set_owner_realm(TRP_INFOREC *rec, TR_NAME *name)
{
switch (rec->type) {
- case TRP_INFOREC_TYPE_ROUTE:
- if (rec->data.route!=NULL) {
- rec->data.route->interval=interval;
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL) {
+ rec->data->comm->owner_realm=name;
return TRP_SUCCESS;
default:
break;
return TRP_ERROR;
}
-/* for internal use only; must set rec->type before calling this */
-static TRP_RC trp_inforec_set_data(TRP_INFOREC *rec, void *data)
+TR_NAME *trp_inforec_get_owner_contact(TRP_INFOREC *rec)
+{
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL)
+ return rec->data->comm->owner_contact;
+ break;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+TRP_RC trp_inforec_set_owner_contact(TRP_INFOREC *rec, TR_NAME *name)
+{
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL) {
+ rec->data->comm->owner_contact=name;
+ return TRP_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+ return TRP_ERROR;
+}
+
+/* caller needs to incref the output if they're going to hang on to it */
+json_t *trp_inforec_get_provenance(TRP_INFOREC *rec)
+{
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL)
+ return rec->data->comm->provenance;
+ break;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+/* increments the reference count */
+TRP_RC trp_inforec_set_provenance(TRP_INFOREC *rec, json_t *prov)
+{
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL) {
+ if (rec->data->comm->provenance!=NULL)
+ json_decref(rec->data->comm->provenance);
+ rec->data->comm->provenance=prov;
+ json_incref(prov);
+ return TRP_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+ return TRP_ERROR;
+}
+
+static TRP_RC trp_inforec_add_to_provenance(TRP_INFOREC *rec, TR_NAME *name)
{
- if (data==NULL)
- return TRP_ERROR;
+ json_t *jname=NULL;
switch (rec->type) {
case TRP_INFOREC_TYPE_ROUTE:
- rec->data.route=talloc_get_type(data, TRP_INFOREC_ROUTE);
+ /* no provenance list */
+ break;
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ jname=tr_name_to_json_string(name);
+ if (jname==NULL)
+ return TRP_ERROR;
+ if (rec->data->comm->provenance==NULL) {
+ rec->data->comm->provenance=json_array();
+ if (rec->data->comm->provenance==NULL) {
+ json_decref(jname);
+ return TRP_ERROR;
+ }
+ }
+ if (0!=json_array_append_new(rec->data->comm->provenance, jname)) {
+ json_decref(jname);
+ return TRP_ERROR;
+ }
break;
default:
- return TRP_BADTYPE;
+ break;
}
return TRP_SUCCESS;
}
+TR_NAME *trp_inforec_dup_origin(TRP_INFOREC *rec)
+{
+ TR_NAME *origin=NULL;
+ json_t *prov=trp_inforec_get_provenance(rec);
+ const char *s=NULL;
+
+ if (prov==NULL)
+ return NULL;
+
+ s=json_string_value(json_array_get(prov, 0));
+ if (s==NULL) {
+ tr_debug("trp_inforec_dup_origin: empty origin in provenance list.");
+ return NULL;
+ }
+ origin=tr_new_name(s);
+ return origin;
+}
+
/* generic record type */
TRP_INFOREC *trp_inforec_new(TALLOC_CTX *mem_ctx, TRP_INFOREC_TYPE type)
{
TRP_INFOREC *new_rec=talloc(mem_ctx, TRP_INFOREC);
+ TRP_INFOREC_DATA *data=NULL;
struct trp_inforec_type_entry *dtype=get_trp_inforec_type_entry(type);
if ((new_rec != NULL) && (dtype->type != TRP_INFOREC_TYPE_UNKNOWN)) {
trp_inforec_set_type(new_rec, type);
trp_inforec_set_next(new_rec, NULL);
if (dtype->allocate!=NULL) {
- if (TRP_SUCCESS!=trp_inforec_set_data(new_rec, dtype->allocate(new_rec))) {
+ data=dtype->allocate(new_rec);
+ if (data!=NULL)
+ new_rec->data=data;
+ else {
talloc_free(new_rec);
- new_rec=NULL;
+ return NULL;
}
}
}
static int trp_upd_destructor(void *object)
{
TRP_UPD *upd=talloc_get_type_abort(object, TRP_UPD);
+ if (upd->realm!=NULL)
+ tr_free_name(upd->realm);
+ if (upd->comm!=NULL)
+ tr_free_name(upd->comm);
if (upd->peer!=NULL)
tr_free_name(upd->peer);
return 0;
TRP_UPD *new_body=talloc(mem_ctx, TRP_UPD);
if (new_body!=NULL) {
+ new_body->realm=NULL;
+ new_body->comm=NULL;
new_body->records=NULL;
new_body->peer=NULL;
talloc_set_destructor((void *)new_body, trp_upd_destructor);
talloc_steal(upd, rec);
}
+TR_NAME *trp_upd_get_realm(TRP_UPD *upd)
+{
+ return upd->realm;
+}
+
+TR_NAME *trp_upd_dup_realm(TRP_UPD *upd)
+{
+ return tr_dup_name(upd->realm);
+}
+
+void trp_upd_set_realm(TRP_UPD *upd, TR_NAME *realm)
+{
+ if (upd->realm!=NULL)
+ tr_free_name(upd->realm);
+ upd->realm=realm;
+}
+
+TR_NAME *trp_upd_get_comm(TRP_UPD *upd)
+{
+ return upd->comm;
+}
+
+TR_NAME *trp_upd_dup_comm(TRP_UPD *upd)
+{
+ return tr_dup_name(upd->comm);
+}
+
+void trp_upd_set_comm(TRP_UPD *upd, TR_NAME *comm)
+{
+ if (upd->comm!=NULL)
+ tr_free_name(upd->comm);
+ upd->comm=comm;
+}
+
TR_NAME *trp_upd_get_peer(TRP_UPD *upd)
{
return upd->peer;
for (rec=trp_upd_get_inforec(upd); rec!=NULL; rec=trp_inforec_get_next(rec)) {
if (trp_inforec_set_next_hop(rec, cpy=tr_new_name(hostname)) != TRP_SUCCESS) {
- tr_err("trp_upd_set_peer: error setting peer.");
+ tr_err("trp_upd_set_next_hop: error setting next hop.");
tr_free_name(cpy);
}
}
}
+void trp_upd_add_to_provenance(TRP_UPD *upd, TR_NAME *name)
+{
+ TRP_INFOREC *rec=NULL;
+
+ /* add it to all inforecs */
+ for (rec=trp_upd_get_inforec(upd); rec!=NULL; rec=trp_inforec_get_next(rec)) {
+ if (TRP_SUCCESS!=trp_inforec_add_to_provenance(rec, name))
+ tr_err("trp_upd_set_peer: error adding peer to provenance list.");
+ }
+}
+
/* pretty print */
-static void trp_inforec_route_print(TRP_INFOREC_DATA data)
+static void trp_inforec_route_print(TRP_INFOREC_DATA *data)
{
- if (data.route!=NULL) {
- printf(" community=%.*s\n realm=%.*s\n trust_router=%.*s\n metric=%d\n interval=%d]\n",
- data.route->comm->len, data.route->comm->buf,
- data.route->realm->len, data.route->realm->buf,
- data.route->trust_router->len, data.route->trust_router->buf,
- data.route->metric, data.route->interval);
+ if (data->route!=NULL) {
+ printf(" trust_router=%.*s\n metric=%d\n interval=%d]\n",
+ data->route->trust_router->len, data->route->trust_router->buf,
+ data->route->metric, data->route->interval);
}
}
+static void trp_inforec_comm_print(TRP_INFOREC_DATA *data)
+{
+ if (data->comm!=NULL) {
+ printf(" type=%s\n role=%s\n owner=%.*s\n contact=%.*s]\n",
+ tr_comm_type_to_str(data->comm->comm_type),
+ tr_realm_role_to_str(data->comm->role),
+ data->comm->owner_realm->len, data->comm->owner_realm->buf,
+ data->comm->owner_contact->len, data->comm->owner_contact->buf);
+ /* TODO: print apcs */
+ }
+}
TR_MQ_MSG *trpc_mq_pop(TRPC_INSTANCE *trpc)
{
- return tr_mq_pop(trpc->mq);
+ return tr_mq_pop(trpc->mq, 0);
}
void trpc_mq_clear(TRPC_INSTANCE *trpc)
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
+#include <glib.h>
+#include <string.h>
#include <gsscon.h>
+#include <tr_comm.h>
+#include <tr_apc.h>
#include <tr_rp.h>
#include <trust_router/tr_name.h>
#include <trp_internal.h>
#include <trp_ptable.h>
#include <trp_rtable.h>
#include <tr_debug.h>
-
+#include <tr_util.h>
static int trps_destructor(void *object)
{
TR_MQ_MSG *trps_mq_pop(TRPS_INSTANCE *trps)
{
- return tr_mq_pop(trps->mq);
+ return tr_mq_pop(trps->mq, 0);
}
void trps_mq_add(TRPS_INSTANCE *trps, TR_MQ_MSG *msg)
trps->sweep_interval.tv_usec=0;
}
+void trps_set_ctable(TRPS_INSTANCE *trps, TR_COMM_TABLE *comm)
+{
+ trps->ctable=comm;
+}
+
void trps_set_ptable(TRPS_INSTANCE *trps, TRP_PTABLE *ptable)
{
if (trps->ptable!=NULL)
trp_ptable_iter_free(iter);
}
+/* Get the label peers will know us by - needs to match trp_peer_get_label() output.
+ * There is no get, only dup, because we don't store the label except when requested. */
+TR_NAME *trps_dup_label(TRPS_INSTANCE *trps)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_NAME *label=NULL;
+ char *s=talloc_asprintf(tmp_ctx, "%s:%u", trps->hostname, trps->port);
+ if (s==NULL)
+ goto cleanup;
+ label=tr_new_name(s);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return label;
+}
+
TRPC_INSTANCE *trps_find_trpc(TRPS_INSTANCE *trps, TRP_PEER *peer)
{
TRPC_INSTANCE *cur=NULL;
return rc;
}
-static int trps_listen (TRPS_INSTANCE *trps, int port)
+/* 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 = 1;
-
- union {
- struct sockaddr_storage storage;
- struct sockaddr_in in4;
- } addr;
+ 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);
- struct sockaddr_in *saddr = (struct sockaddr_in *) &addr.in4;
+ 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;
+ }
- saddr->sin_port = htons (port);
- saddr->sin_family = AF_INET;
- saddr->sin_addr.s_addr = INADDR_ANY;
+ 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;
+ }
+ }
- if (0 > (conn = socket (AF_INET, SOCK_STREAM, 0)))
- return conn;
+ rc=bind(conn, ai->ai_addr, ai->ai_addrlen);
+ if (rc<0) {
+ tr_debug("trps_listen: unable to bind to socket.");
+ close(conn);
+ continue;
+ }
- setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
+ if (0>listen(conn, 512)) {
+ tr_debug("trps_listen: unable to listen on bound socket.");
+ close(conn);
+ continue;
+ }
- if (0 > (rc = bind (conn, (struct sockaddr *) saddr, sizeof(struct sockaddr_in))))
- return rc;
+ /* ok, this one worked. Save it */
+ fd_out[n_opened++]=conn;
+ }
+ freeaddrinfo(ai_head);
- if (0 > (rc = listen(conn, 512)))
- return rc;
+ 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");
- tr_debug("trps_listen: TRP Server listening on port %d", port);
- return conn;
+ return n_opened;
}
/* get the currently selected route if available */
case TRP_UPDATE:
trp_upd_set_peer(tr_msg_get_trp_upd(*msg), tr_dup_name(conn_peer));
trp_upd_set_next_hop(tr_msg_get_trp_upd(*msg), trp_peer_get_server(peer), 0); /* TODO: 0 should be the configured TID port */
+ /* update provenance if necessary */
+ trp_upd_add_to_provenance(tr_msg_get_trp_upd(*msg), trp_peer_get_label(peer));
break;
case TRP_REQUEST:
TRP_AUTH_FUNC auth_handler,
const char *hostname,
unsigned int port,
- void *cookie)
+ void *cookie,
+ int *fd_out,
+ size_t max_fd)
{
- int listen = -1;
-
- if (0 > (listen = trps_listen(trps, port))) {
- char errbuf[256];
- if (0 == strerror_r(errno, errbuf, 256)) {
- tr_debug("trps_get_listener: Error opening port %d: %s.", port, errbuf);
- } else {
- tr_debug("trps_get_listener: Unknown error openining port %d.", port);
- }
- }
+ size_t n_fd=0;
+ size_t ii=0;
- if (listen > 0) {
+ n_fd=trps_listen(trps, port, fd_out, max_fd);
+ if (n_fd==0)
+ tr_debug("trps_get_listener: Error opening port %d.");
+ else {
/* opening port succeeded */
tr_debug("trps_get_listener: Opened port %d.", port);
- /* make this socket non-blocking */
- if (0 != fcntl(listen, F_SETFL, O_NONBLOCK)) {
- tr_debug("trps_get_listener: Error setting O_NONBLOCK.");
- close(listen);
- listen=-1;
+ /* make the sockets non-blocking */
+ for (ii=0; ii<n_fd; ii++) {
+ if (0 != fcntl(fd_out[ii], F_SETFL, O_NONBLOCK)) {
+ tr_debug("trps_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 (listen > 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 listen;
+ return n_fd;
}
TRP_RC trps_authorize_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *conn)
tr_debug("trps_handle_connection: connection closed.");
}
+/* TODO: check realm/comm, now part of the update instead of inforec */
static TRP_RC trps_validate_update(TRPS_INSTANCE *trps, TRP_UPD *upd)
{
if (upd==NULL) {
return TRP_BADARG;
}
+ if (trp_upd_get_realm(upd)==NULL) {
+ tr_notice("trps_validate_update: received TRP update without realm.");
+ return TRP_ERROR;
+ }
+
+ if (trp_upd_get_comm(upd)==NULL) {
+ tr_notice("trps_validate_update: received TRP update without community.");
+ return TRP_ERROR;
+ }
+
if (trp_upd_get_inforec(upd)==NULL) {
tr_notice("trps_validate_update: received TRP update with no info records.");
return TRP_ERROR;
tr_notice("trps_validate_update: received TRP update without origin peer information.");
return TRP_ERROR;
}
+
return TRP_SUCCESS;
}
{
switch(trp_inforec_get_type(rec)) {
case TRP_INFOREC_TYPE_ROUTE:
- if ((trp_inforec_get_comm(rec)==NULL)
- || (trp_inforec_get_realm(rec)==NULL)
- || (trp_inforec_get_trust_router(rec)==NULL)
+ if ((trp_inforec_get_trust_router(rec)==NULL)
|| (trp_inforec_get_next_hop(rec)==NULL)) {
tr_debug("trps_validate_inforec: missing record info.");
return TRP_ERROR;
}
break;
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ /* TODO: validate community updates */
+ break;
+
default:
tr_notice("trps_validate_inforec: unsupported record type.");
return TRP_UNSUPPORTED;
return trp_route_get_metric(entry) + trps_cost(trps, peer);
}
-static int trps_check_feasibility(TRPS_INSTANCE *trps, TRP_INFOREC *rec)
+static int trps_check_feasibility(TRPS_INSTANCE *trps, TR_NAME *realm, TR_NAME *comm, TRP_INFOREC *rec)
{
unsigned int rec_metric=trp_inforec_get_metric(rec);
unsigned int new_metric=0;
return 1;
/* updates from our current next hop are always feasible*/
- next_hop=trps_get_next_hop(trps,
- trp_inforec_get_comm(rec),
- trp_inforec_get_realm(rec));;
+ next_hop=trps_get_next_hop(trps, comm, realm);
if ((next_hop!=NULL)
&& (0==tr_name_cmp(next_hop,trp_inforec_get_next_hop(rec)))) {
return 1;
/* compare the existing metric we advertise to what we would advertise
* if we accept this update */
- current_metric=trps_advertised_metric(trps,
- trp_inforec_get_comm(rec),
- trp_inforec_get_realm(rec),
- trp_inforec_get_next_hop(rec));
+ current_metric=trps_advertised_metric(trps, comm, realm, trp_inforec_get_next_hop(rec));
new_metric=rec_metric + trps_cost(trps, trp_inforec_get_next_hop(rec));
if (new_metric <= current_metric)
return 1;
static struct timespec *trps_compute_expiry(TRPS_INSTANCE *trps, unsigned int interval, struct timespec *ts)
{
const unsigned int small_factor=3; /* how many intervals we wait before expiring */
- if (0!=clock_gettime(CLOCK_REALTIME, ts)) {
+ if (0!=clock_gettime(TRP_CLOCK, ts)) {
tr_err("trps_compute_expiry: could not read realtime clock.");
ts->tv_sec=0;
ts->tv_nsec=0;
}
+ tr_debug("trps_compute_expiry: tv_sec=%u, interval=%u, small_factor*interval=%u", ts->tv_sec, interval, small_factor*interval);
ts->tv_sec += small_factor*interval;
return ts;
}
TRP_ROUTE *entry=NULL;
entry=trp_rtable_get_entry(trps->rtable,
- trp_inforec_get_comm(rec),
- trp_inforec_get_realm(rec),
+ trp_upd_get_comm(upd),
+ trp_upd_get_realm(upd),
trp_inforec_get_next_hop(rec));
if (entry==NULL) {
entry=trp_route_new(NULL);
return TRP_NOMEM;
}
- trp_route_set_comm(entry, trp_inforec_dup_comm(rec));
- trp_route_set_realm(entry, trp_inforec_dup_realm(rec));
+ trp_route_set_comm(entry, trp_upd_dup_comm(upd));
+ trp_route_set_realm(entry, trp_upd_dup_realm(upd));
trp_route_set_peer(entry, trp_upd_dup_peer(upd));
trp_route_set_trust_router(entry, trp_inforec_dup_trust_router(rec));
trp_route_set_next_hop(entry, trp_inforec_dup_next_hop(rec));
return TRP_SUCCESS;
}
-static TRP_RC trps_handle_update(TRPS_INSTANCE *trps, TRP_UPD *upd)
+
+static TRP_RC trps_handle_inforec_route(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_INFOREC *rec)
{
+ TRP_ROUTE *route=NULL;
unsigned int feas=0;
+
+ /* determine feasibility */
+ feas=trps_check_feasibility(trps, trp_upd_get_realm(upd), trp_upd_get_comm(upd), rec);
+ tr_debug("trps_handle_update: record feasibility=%d", feas);
+
+ /* do we have an existing route? */
+ route=trps_get_route(trps,
+ trp_upd_get_comm(upd),
+ trp_upd_get_realm(upd),
+ trp_upd_get_peer(upd));
+ if (route!=NULL) {
+ /* there was a route table entry already */
+ tr_debug("trps_handle_updates: route entry already exists.");
+ if (feas) {
+ /* Update is feasible. Accept it. */
+ trps_accept_update(trps, upd, rec);
+ } else {
+ /* Update is infeasible. Ignore it unless the trust router has changed. */
+ if (0!=tr_name_cmp(trp_route_get_trust_router(route),
+ trp_inforec_get_trust_router(rec))) {
+ /* the trust router associated with the route has changed, treat update as a retraction */
+ trps_retract_route(trps, route);
+ }
+ }
+ } else {
+ /* No existing route table entry. Ignore it unless it is feasible and not a retraction. */
+ tr_debug("trps_handle_update: no route entry exists yet.");
+ if (feas && trp_metric_is_finite(trp_inforec_get_metric(rec)))
+ trps_accept_update(trps, upd, rec);
+ }
+
+ return TRP_SUCCESS;
+}
+
+static int trps_name_in_provenance(TR_NAME *name, json_t *prov)
+{
+ size_t ii=0;
+ TR_NAME *this_name=NULL;
+ const char *s=NULL;
+
+ if (prov==NULL)
+ return 0; /* no provenance list, so it has no names in it */
+
+ /* now check to see if name is in the provenance */
+ for (ii=0; ii<json_array_size(prov); ii++) {
+ s=json_string_value(json_array_get(prov, ii));
+ if (s==NULL) {
+ tr_debug("trps_name_in_provenance: empty entry in provenance list.");
+ continue;
+ }
+
+ this_name=tr_new_name(s);
+ if (this_name==NULL) {
+ tr_debug("trps_name_in_provenance: unable to allocate name.");
+ return -1;
+ }
+ if (0==tr_name_cmp(name, this_name)) {
+ tr_free_name(this_name);
+ return 1;
+ }
+ tr_free_name(this_name);
+ }
+ return 0;
+}
+
+static TR_COMM *trps_create_new_comm(TALLOC_CTX *mem_ctx, TR_NAME *comm_id, TRP_INFOREC *rec)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_COMM *comm=tr_comm_new(tmp_ctx);
+
+ if (comm==NULL) {
+ tr_debug("trps_create_new_comm: unable to allocate new community.");
+ goto cleanup;
+ }
+ /* fill in the community with info */
+ tr_comm_set_id(comm, tr_dup_name(comm_id));
+ if (tr_comm_get_id(comm)==NULL) {
+ tr_debug("trps_create_new_comm: unable to allocate community name.");
+ comm=NULL;
+ goto cleanup;
+ }
+ tr_comm_set_type(comm, trp_inforec_get_comm_type(rec));
+ if (trp_inforec_get_apcs(rec)!=NULL) {
+ tr_comm_set_apcs(comm, tr_apc_dup(tmp_ctx, trp_inforec_get_apcs(rec)));
+ if (tr_comm_get_apcs(comm)==NULL) {
+ tr_debug("trps_create_new_comm: unable to allocate APC list.");
+ comm=NULL;
+ goto cleanup;
+ }
+ }
+ if (trp_inforec_get_owner_realm(rec)!=NULL) {
+ tr_comm_set_owner_realm(comm, tr_dup_name(trp_inforec_get_owner_realm(rec)));
+ if (tr_comm_get_owner_realm(comm)==NULL) {
+ tr_debug("trps_create_new_comm: unable to allocate owner realm name.");
+ comm=NULL;
+ goto cleanup;
+ }
+ }
+ if (trp_inforec_get_owner_contact(rec)!=NULL) {
+ tr_comm_set_owner_contact(comm, tr_dup_name(trp_inforec_get_owner_contact(rec)));
+ if (tr_comm_get_owner_contact(comm)==NULL) {
+ tr_debug("trps_create_new_comm: unable to allocate owner contact.");
+ comm=NULL;
+ goto cleanup;
+ }
+ }
+ comm->expiration_interval=trp_inforec_get_exp_interval(rec);
+ talloc_steal(mem_ctx, comm);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return comm;
+}
+
+static TR_RP_REALM *trps_create_new_rp_realm(TALLOC_CTX *mem_ctx, TR_NAME *realm_id, TRP_INFOREC *rec)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_RP_REALM *rp=tr_rp_realm_new(tmp_ctx);
+
+ if (rp==NULL) {
+ tr_debug("trps_create_new_rp_realm: unable to allocate new realm.");
+ goto cleanup;
+ }
+ /* fill in the realm */
+ tr_rp_realm_set_id(rp, tr_dup_name(realm_id));
+ if (tr_rp_realm_get_id(rp)==NULL) {
+ tr_debug("trps_create_new_rp_realm: unable to allocate realm name.");
+ rp=NULL;
+ goto cleanup;
+ }
+ talloc_steal(mem_ctx, rp);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rp;
+}
+
+static TR_IDP_REALM *trps_create_new_idp_realm(TALLOC_CTX *mem_ctx, TR_NAME *realm_id, TRP_INFOREC *rec)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_IDP_REALM *idp=tr_idp_realm_new(tmp_ctx);
+
+ if (idp==NULL) {
+ tr_debug("trps_create_new_idp_realm: unable to allocate new realm.");
+ goto cleanup;
+ }
+ /* fill in the realm */
+ tr_idp_realm_set_id(idp, tr_dup_name(realm_id));
+ if (tr_idp_realm_get_id(idp)==NULL) {
+ tr_debug("trps_create_new_idp_realm: unable to allocate realm name.");
+ idp=NULL;
+ goto cleanup;
+ }
+ if (trp_inforec_get_apcs(rec)!=NULL) {
+ tr_idp_realm_set_apcs(idp, tr_apc_dup(tmp_ctx, trp_inforec_get_apcs(rec)));
+ if (tr_idp_realm_get_apcs(idp)==NULL) {
+ tr_debug("trps_create_new_idp_realm: unable to allocate APC list.");
+ idp=NULL;
+ goto cleanup;
+ }
+ }
+ idp->origin=TR_REALM_DISCOVERED;
+
+ talloc_steal(mem_ctx, idp);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return idp;
+}
+
+static TRP_RC trps_handle_inforec_comm(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_INFOREC *rec)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_NAME *comm_id=trp_upd_get_comm(upd);
+ TR_NAME *realm_id=trp_upd_get_realm(upd);
+ TR_NAME *origin_id=NULL;
+ TR_NAME *our_peer_label=NULL;
+ TR_COMM *comm=NULL;
+ TR_RP_REALM *rp_realm=NULL;
+ TR_IDP_REALM *idp_realm=NULL;
+ struct timespec expiry={0,0};
+ TRP_RC rc=TRP_ERROR;
+
+ if ((comm_id==NULL) || (realm_id==NULL))
+ goto cleanup;
+
+ origin_id=trp_inforec_dup_origin(rec);
+ if (origin_id==NULL)
+ goto cleanup;
+
+ /* see whether we want to add this */
+ our_peer_label=trps_dup_label(trps);
+ if (our_peer_label==NULL) {
+ tr_debug("trps_handle_inforec_comm: unable to allocate peer label.");
+ goto cleanup;
+ }
+
+ if (trps_name_in_provenance(our_peer_label, trp_inforec_get_provenance(rec)))
+ tr_debug("trps_handle_inforec_comm: rejecting community inforec to avoid provenance loop.");
+ else {
+ /* no loop occurring, accept the update */
+ comm=tr_comm_table_find_comm(trps->ctable, comm_id);
+ if (comm==NULL) {
+ tr_debug("trps_handle_inforec_comm: unknown community %.*s in inforec, creating it.",
+ comm_id->len, comm_id->buf);
+ comm=trps_create_new_comm(tmp_ctx, comm_id, rec);
+ if (comm==NULL) {
+ tr_debug("trps_handle_inforec_comm: unable to create new community.");
+ goto cleanup;
+ }
+ tr_comm_table_add_comm(trps->ctable, comm);
+ }
+ /* TODO: see if other comm data match the new inforec and update or complain */
+
+ trps_compute_expiry(trps, trp_inforec_get_interval(rec), &expiry);
+ if ((expiry.tv_sec==0)&&(expiry.tv_nsec==0))
+ goto cleanup;
+
+ switch (trp_inforec_get_role(rec)) {
+ case TR_ROLE_RP:
+ rp_realm=tr_rp_realm_lookup(trps->ctable->rp_realms, realm_id);
+ if (rp_realm==NULL) {
+ tr_debug("trps_handle_inforec_comm: unknown RP realm %.*s in inforec, creating it.",
+ realm_id->len, realm_id->buf);
+ rp_realm=trps_create_new_rp_realm(tmp_ctx, realm_id, rec);
+ if (rp_realm==NULL) {
+ tr_debug("trps_handle_inforec_comm: unable to create new RP realm.");
+ /* we may leave an unused community in the table, but it will only last until
+ * the next table sweep if it does not get any realms before that happens */
+ goto cleanup;
+ }
+ tr_comm_table_add_rp_realm(trps->ctable, rp_realm);
+ }
+ /* TODO: if realm existed, see if data match the new inforec and update or complain */
+ tr_comm_add_rp_realm(trps->ctable, comm, rp_realm, trp_inforec_get_interval(rec), trp_inforec_get_provenance(rec), &expiry);
+ tr_debug("trps_handle_inforec_comm: added RP realm %.*s to comm %.*s (origin %.*s).",
+ realm_id->len, realm_id->buf,
+ comm_id->len, comm_id->buf,
+ origin_id->len, origin_id->buf);
+ break;
+ case TR_ROLE_IDP:
+ idp_realm=tr_idp_realm_lookup(trps->ctable->idp_realms, realm_id);
+ if (idp_realm==NULL) {
+ tr_debug("trps_handle_inforec_comm: unknown IDP realm %.*s in inforec, creating it.",
+ realm_id->len, realm_id->buf);
+ idp_realm=trps_create_new_idp_realm(tmp_ctx, realm_id, rec);
+ if (idp_realm==NULL) {
+ tr_debug("trps_handle_inforec_comm: unable to create new IDP realm.");
+ /* we may leave an unused community in the table, but it will only last until
+ * the next table sweep if it does not get any realms before that happens */
+ goto cleanup;
+ }
+ tr_comm_table_add_idp_realm(trps->ctable, idp_realm);
+ }
+ /* TODO: if realm existed, see if data match the new inforec and update or complain */
+ tr_comm_add_idp_realm(trps->ctable, comm, idp_realm, trp_inforec_get_interval(rec), trp_inforec_get_provenance(rec), &expiry);
+ tr_debug("trps_handle_inforec_comm: added IDP realm %.*s to comm %.*s (origin %.*s).",
+ realm_id->len, realm_id->buf,
+ comm_id->len, comm_id->buf,
+ origin_id->len, origin_id->buf);
+ break;
+ default:
+ tr_debug("trps_handle_inforec_comm: unable to add realm.");
+ goto cleanup;
+ }
+ }
+
+ rc=TRP_SUCCESS;
+
+cleanup:
+ if (our_peer_label!=NULL)
+ tr_free_name(our_peer_label);
+ if (origin_id!=NULL)
+ tr_free_name(origin_id);
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static TRP_RC trps_handle_update(TRPS_INSTANCE *trps, TRP_UPD *upd)
+{
TRP_INFOREC *rec=NULL;
- TRP_ROUTE *route=NULL;
if (trps_validate_update(trps, upd) != TRP_SUCCESS) {
tr_notice("trps_handle_update: received invalid TRP update.");
for (rec=trp_upd_get_inforec(upd); rec!=NULL; rec=trp_inforec_get_next(rec)) {
/* validate/sanity check the record update */
if (trps_validate_inforec(trps, rec) != TRP_SUCCESS) {
- tr_notice("trps_handle_update: invalid record in TRP update, discarding entire update.");
+ tr_notice("trps_handle_update: invalid inforec in TRP update, discarding entire update.");
return TRP_ERROR;
}
}
for (rec=trp_upd_get_inforec(upd); rec!=NULL; rec=trp_inforec_get_next(rec)) {
- /* determine feasibility */
- feas=trps_check_feasibility(trps, rec);
- tr_debug("trps_handle_update: record feasibility=%d", feas);
-
- /* do we have an existing route? */
- route=trps_get_route(trps,
- trp_inforec_get_comm(rec),
- trp_inforec_get_realm(rec),
- trp_upd_get_peer(upd));
- if (route!=NULL) {
- /* there was a route table entry already */
- tr_debug("trps_handle_updates: route entry already exists.");
- if (feas) {
- /* Update is feasible. Accept it. */
- trps_accept_update(trps, upd, rec);
- } else {
- /* Update is infeasible. Ignore it unless the trust router has changed. */
- if (0!=tr_name_cmp(trp_route_get_trust_router(route),
- trp_inforec_get_trust_router(rec))) {
- /* the trust router associated with the route has changed, treat update as a retraction */
- trps_retract_route(trps, route);
- }
- }
- } else {
- /* No existing route table entry. Ignore it unless it is feasible and not a retraction. */
- tr_debug("trps_handle_update: no route entry exists yet.");
- if (feas && trp_metric_is_finite(trp_inforec_get_metric(rec)))
- trps_accept_update(trps, upd, rec);
+ switch (trp_inforec_get_type(rec)) {
+ case TRP_INFOREC_TYPE_ROUTE:
+ tr_debug("trps_handle_update: handling route inforec.");
+ if (TRP_SUCCESS!=trps_handle_inforec_route(trps, upd, rec))
+ tr_notice("trps_handle_update: error handling route inforec.");
+ break;
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ tr_debug("trps_handle_update: handling community inforec.");
+ if (TRP_SUCCESS!=trps_handle_inforec_comm(trps, upd, rec))
+ tr_notice("trps_handle_update: error handling community inforec.");
+
+ break;
+ default:
+ tr_notice("trps_handle_update: unsupported inforec in TRP update.");
+ break;
}
}
return TRP_SUCCESS;
/* true if curtime >= expiry */
static int trps_expired(struct timespec *expiry, struct timespec *curtime)
{
- return ((curtime->tv_sec > expiry->tv_sec)
- || ((curtime->tv_sec == expiry->tv_sec)
- &&(curtime->tv_nsec > expiry->tv_nsec)));
+ return (tr_cmp_timespec(curtime, expiry) >= 0);
}
/* Sweep for expired routes. For each expired route, if its metric is infinite, the route is flushed.
size_t ii=0;
/* use a single time for the entire sweep */
- if (0!=clock_gettime(CLOCK_REALTIME, &sweep_time)) {
+ if (0!=clock_gettime(TRP_CLOCK, &sweep_time)) {
tr_err("trps_sweep_routes: could not read realtime clock.");
sweep_time.tv_sec=0;
sweep_time.tv_nsec=0;
return TRP_SUCCESS;
}
+
+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)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ struct timespec sweep_time={0,0};
+ TR_COMM_MEMB *memb=NULL;
+ TR_COMM_ITER *iter=NULL;
+ TRP_RC rc=TRP_ERROR;
+
+ /* use a single time for the entire sweep */
+ if (0!=clock_gettime(TRP_CLOCK, &sweep_time)) {
+ tr_err("trps_sweep_ctable: could not read realtime clock.");
+ sweep_time.tv_sec=0;
+ sweep_time.tv_nsec=0;
+ goto cleanup;
+ }
+
+ /* iterate all memberships */
+ iter=tr_comm_iter_new(tmp_ctx);
+ if (iter==NULL) {
+ tr_err("trps_sweep_ctable: unable to allocate iterator.");
+ rc=TRP_NOMEM;
+ goto cleanup;
+ }
+ for (memb=tr_comm_memb_iter_all_first(iter, trps->ctable);
+ memb!=NULL;
+ memb=tr_comm_memb_iter_all_next(iter)) {
+ if (tr_comm_memb_get_origin(memb)==NULL)
+ continue; /* do not expire local entries */
+
+ if (tr_comm_memb_is_expired(memb, &sweep_time)) {
+ if (tr_comm_memb_get_times_expired(memb)>0) {
+ /* Already expired once; flush. */
+ tr_debug("trps_sweep_ctable: flushing expired community membership (%.*s in %.*s, origin %.*s, expired %s).",
+ tr_comm_memb_get_realm_id(memb)->len, tr_comm_memb_get_realm_id(memb)->buf,
+ tr_comm_get_id(tr_comm_memb_get_comm(memb))->len, tr_comm_get_id(tr_comm_memb_get_comm(memb))->buf,
+ tr_comm_memb_get_origin(memb)->len, tr_comm_memb_get_origin(memb)->buf,
+ timespec_to_str(tr_comm_memb_get_expiry(memb)));
+ tr_comm_table_remove_memb(trps->ctable, memb);
+ tr_comm_memb_free(memb);
+ } else {
+ /* This is the first expiration. Note this and reset the expiry time. */
+ tr_comm_memb_expire(memb);
+ trps_compute_expiry(trps, tr_comm_memb_get_interval(memb), tr_comm_memb_get_expiry(memb));
+ tr_debug("trps_sweep_ctable: community membership expired at %s, resetting expiry to %s (%.*s in %.*s, origin %.*s).",
+ timespec_to_str(&sweep_time),
+ timespec_to_str(tr_comm_memb_get_expiry(memb)),
+ tr_comm_memb_get_realm_id(memb)->len, tr_comm_memb_get_realm_id(memb)->buf,
+ tr_comm_get_id(tr_comm_memb_get_comm(memb))->len, tr_comm_get_id(tr_comm_memb_get_comm(memb))->buf,
+ tr_comm_memb_get_origin(memb)->len, tr_comm_memb_get_origin(memb)->buf);
+ }
+ }
+ }
+
+ /* get rid of any unreferenced realms, etc */
+ tr_comm_table_sweep(trps->ctable);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+/* add metrics */
+static unsigned int trps_metric_add(unsigned int m1, unsigned int m2)
+{
+ if (trp_metric_is_invalid(m1) || trp_metric_is_invalid(m2))
+ return TRP_METRIC_INVALID;
+
+ if (trp_metric_is_infinite(m1) || trp_metric_is_infinite(m2))
+ return TRP_METRIC_INFINITY;
+
+ if (trp_metric_is_finite(m1+m2))
+ return m1+m2;
+ else
+ return TRP_METRIC_INFINITY;
+}
+
+/* convert an rentry into a new trp update info record */
+static TRP_INFOREC *trps_route_to_inforec(TALLOC_CTX *mem_ctx, TRPS_INSTANCE *trps, TRP_ROUTE *route)
+{
+ TRP_INFOREC *rec=trp_inforec_new(mem_ctx, TRP_INFOREC_TYPE_ROUTE);
+ unsigned int linkcost=0;
+
+ if (rec!=NULL) {
+ if (trp_route_is_local(route))
+ linkcost=0;
+ else {
+ linkcost=trp_peer_get_linkcost(trps_get_peer_by_gssname(trps,
+ trp_route_get_peer(route)));
+ }
+
+ /* Note that we leave the next hop empty since the recipient fills that in.
+ * This is where we add the link cost (currently always 1) to the next peer. */
+ if ((trp_inforec_set_trust_router(rec, trp_route_dup_trust_router(route)) != TRP_SUCCESS)
+ ||(trp_inforec_set_metric(rec,
+ trps_metric_add(trp_route_get_metric(route),
+ linkcost)) != TRP_SUCCESS)
+ ||(trp_inforec_set_interval(rec, trps_get_update_interval(trps)) != TRP_SUCCESS)) {
+ tr_err("trps_route_to_inforec: error creating route update.");
+ talloc_free(rec);
+ rec=NULL;
+ }
+ }
+ return rec;
+}
+
+static TRP_UPD *trps_route_to_upd(TALLOC_CTX *mem_ctx, TRPS_INSTANCE *trps, TRP_ROUTE *route)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TRP_UPD *upd=trp_upd_new(tmp_ctx);
+ TRP_INFOREC *rec=NULL;
+
+ if (upd==NULL) {
+ tr_err("trps_route_to_upd: could not create update message.");
+ goto cleanup;
+ }
+ trp_upd_set_realm(upd, trp_route_dup_realm(route));
+ if (trp_upd_get_realm(upd)==NULL) {
+ tr_err("trps_route_to_upd: could not copy realm.");
+ upd=NULL; /* it's still in tmp_ctx, so it will be freed */
+ goto cleanup;
+ }
+ trp_upd_set_comm(upd, trp_route_dup_comm(route));
+ if (trp_upd_get_comm(upd)==NULL) {
+ tr_err("trps_route_to_upd: could not copy comm.");
+ upd=NULL; /* it's still in tmp_ctx, so it will be freed */
+ goto cleanup;
+ }
+ rec=trps_route_to_inforec(tmp_ctx, trps, route);
+ if (rec==NULL) {
+ tr_err("trps_route_to_upd: could not create route info record for realm %.*s in comm %.*s.",
+ trp_route_get_realm(route)->len, trp_route_get_realm(route)->buf,
+ trp_route_get_comm(route)->len, trp_route_get_comm(route)->buf);
+ upd=NULL; /* it's till in tmp_ctx, so it will be freed */
+ goto cleanup;
+ }
+ trp_upd_add_inforec(upd, rec);
+
+ /* sucess */
+ talloc_steal(mem_ctx, upd);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return upd;
+}
+
/* select the correct route to comm/realm to be announced to peer */
static TRP_ROUTE *trps_select_realm_update(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer_gssname)
{
return route;
}
-/* returns an array of pointers to updates (*not* an array of updates). Returns number of entries
- * via n_update parameter. (The allocated space will generally be larger than required, see note in
- * the code.) If triggered is set, sends only triggered updates. */
-static TRP_ROUTE **trps_select_updates_for_peer(TALLOC_CTX *memctx,
+/* Add TRP_UPD msgs to the updates GPtrArray. Caller needs to arrange for these to be freed. */
+static TRP_RC trps_select_route_updates_for_peer(TALLOC_CTX *mem_ctx,
+ GPtrArray *updates,
TRPS_INSTANCE *trps,
TR_NAME *peer_gssname,
- int triggered,
- size_t *n_update)
+ int triggered)
{
size_t n_comm=0;
TR_NAME **comm=trp_rtable_get_comms(trps->rtable, &n_comm);
size_t n_realm=0;
size_t ii=0, jj=0;
TRP_ROUTE *best=NULL;
- TRP_ROUTE **result=NULL;
- size_t n_used=0;
-
- /* Need to allocate space for the results. For simplicity, we just allocate a block
- * with space for every route table entry to be returned. This is guaranteed to be large
- * enough. If the routing table gets very large, this may be wasteful, but that seems
- * unlikely to be significant in the near future. */
- result=talloc_array(memctx, TRP_ROUTE *, trp_rtable_size(trps->rtable));
- if (result==NULL) {
- talloc_free(comm);
- *n_update=0;
- return NULL;
- }
-
+ TRP_UPD *upd=NULL;
+
+ if (updates==NULL)
+ return TRP_BADARG;
+
for (ii=0; ii<n_comm; ii++) {
realm=trp_rtable_get_comm_realms(trps->rtable, comm[ii], &n_realm);
for (jj=0; jj<n_realm; jj++) {
best=trps_select_realm_update(trps, comm[ii], realm[jj], peer_gssname);
/* If we found a route, add it to the list. If triggered!=0, then only
* add triggered routes. */
- if ((best!=NULL) && ((!triggered) || trp_route_is_triggered(best)))
- result[n_used++]=best;
+ if ((best!=NULL) && ((!triggered) || trp_route_is_triggered(best))) {
+ upd=trps_route_to_upd(mem_ctx, trps, best);
+ if (upd==NULL) {
+ tr_err("trps_select_route_updates_for_peer: unable to create update message.");
+ continue;
+ }
+ g_ptr_array_add(updates, upd);
+ }
}
+
if (realm!=NULL)
talloc_free(realm);
realm=NULL;
n_realm=0;
}
+
if (comm!=NULL)
talloc_free(comm);
+
+ return TRP_SUCCESS;
+}
+
+static TRP_INFOREC *trps_memb_to_inforec(TALLOC_CTX *mem_ctx, TRPS_INSTANCE *trps, TR_COMM_MEMB *memb)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TRP_INFOREC *rec=NULL;
+ TR_COMM *comm=NULL;
+
+ if (memb==NULL)
+ goto cleanup;
- *n_update=n_used;
- return result;
+ comm=tr_comm_memb_get_comm(memb);
+ rec=trp_inforec_new(tmp_ctx, TRP_INFOREC_TYPE_COMMUNITY);
+ if (rec==NULL)
+ goto cleanup;
+
+ if (TRP_SUCCESS!=trp_inforec_set_comm_type(rec, tr_comm_get_type(comm))) {
+ rec=NULL;
+ goto cleanup;
+ }
+
+ if (TRP_SUCCESS!=trp_inforec_set_role(rec, tr_comm_memb_get_role(memb))) {
+ rec=NULL;
+ goto cleanup;
+ }
+
+ if ((NULL!=tr_comm_get_apcs(comm)) &&
+ ( (TRP_SUCCESS!=trp_inforec_set_apcs(rec,
+ tr_apc_dup(rec, tr_comm_get_apcs(comm)))) ||
+ (NULL==trp_inforec_get_apcs(rec)))) {
+ rec=NULL;
+ goto cleanup;
+ }
+
+ if ((NULL!=tr_comm_get_owner_realm(comm)) &&
+ ( (TRP_SUCCESS!=trp_inforec_set_owner_realm(rec, tr_dup_name(tr_comm_get_owner_realm(comm)))) ||
+ (NULL==trp_inforec_get_owner_realm(rec)))) {
+ rec=NULL;
+ goto cleanup;
+ }
+
+ if ((NULL!=tr_comm_get_owner_contact(comm)) &&
+ ( (TRP_SUCCESS!=trp_inforec_set_owner_contact(rec, tr_dup_name(tr_comm_get_owner_contact(comm)))) ||
+ (NULL==trp_inforec_get_owner_contact(rec)))) {
+ rec=NULL;
+ goto cleanup;
+ }
+
+ if ((NULL!=tr_comm_memb_get_provenance(memb)) &&
+ (TRP_SUCCESS!=trp_inforec_set_provenance(rec, tr_comm_memb_get_provenance(memb)))) {
+ rec=NULL;
+ goto cleanup;
+ }
+
+ if (TRP_SUCCESS!=trp_inforec_set_interval(rec, trps_get_update_interval(trps))) {
+ rec=NULL;
+ goto cleanup;
+ }
+
+ /* success! */
+ talloc_steal(mem_ctx, rec);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rec;
}
-/* add metrics */
-static unsigned int trps_metric_add(unsigned int m1, unsigned int m2)
+/* construct an update with all the inforecs for comm/realm/role to be sent to peer */
+static TRP_UPD *trps_comm_update(TALLOC_CTX *mem_ctx, TRPS_INSTANCE *trps, TR_NAME *peer_gssname, TR_COMM *comm, TR_REALM *realm)
{
- if (trp_metric_is_invalid(m1) || trp_metric_is_invalid(m2))
- return TRP_METRIC_INVALID;
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TRP_UPD *upd=trp_upd_new(tmp_ctx);
+ TRP_INFOREC *rec=NULL;
+ TR_COMM_ITER *iter=NULL;
+ TR_COMM_MEMB *memb=NULL;
- if (trp_metric_is_infinite(m1) || trp_metric_is_infinite(m2))
- return TRP_METRIC_INFINITY;
+ if (upd==NULL)
+ goto cleanup;
+
+ trp_upd_set_comm(upd, tr_comm_dup_id(comm));
+ trp_upd_set_realm(upd, tr_realm_dup_id(realm));
+ /* leave peer empty */
- if (trp_metric_is_finite(m1+m2))
- return m1+m2;
+ iter=tr_comm_iter_new(tmp_ctx);
+ if (iter==NULL) {
+ tr_err("trps_comm_update: unable to allocate iterator.");
+ upd=NULL;
+ goto cleanup;
+ }
+
+ /* now add inforecs */
+ switch (realm->role) {
+ case TR_ROLE_IDP:
+ memb=tr_comm_table_find_idp_memb(trps->ctable,
+ tr_realm_get_id(realm),
+ tr_comm_get_id(comm));
+ break;
+ case TR_ROLE_RP:
+ memb=tr_comm_table_find_rp_memb(trps->ctable,
+ tr_realm_get_id(realm),
+ tr_comm_get_id(comm));
+ break;
+ default:
+ break;
+ }
+ if (memb!=NULL) {
+ for (memb=tr_comm_memb_iter_first(iter, memb);
+ memb!=NULL;
+ memb=tr_comm_memb_iter_next(iter)) {
+ rec=trps_memb_to_inforec(tmp_ctx, trps, memb);
+ if (rec==NULL) {
+ tr_err("trps_comm_update: unable to allocate inforec.");
+ upd=NULL;
+ goto cleanup;
+ }
+ trp_upd_add_inforec(upd, rec);
+ }
+ }
+
+ if (trp_upd_get_inforec(upd)==NULL)
+ upd=NULL; /* no inforecs, no reason to send the update */
else
- return TRP_METRIC_INFINITY;
+ talloc_steal(mem_ctx, upd); /* success! */
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return upd;
}
-/* convert an rentry into a new trp update info record */
-static TRP_INFOREC *trps_route_to_inforec(TALLOC_CTX *mem_ctx, TRPS_INSTANCE *trps, TRP_ROUTE *route)
+/* Find all community updates to send to a peer and add these as TR_UPD records
+ * to the updates GPtrArray. */
+static TRP_RC trps_select_comm_updates_for_peer(TALLOC_CTX *mem_ctx,
+ GPtrArray *updates,
+ TRPS_INSTANCE *trps,
+ TR_NAME *peer_gssname,
+ int triggered)
{
- TRP_INFOREC *rec=trp_inforec_new(mem_ctx, TRP_INFOREC_TYPE_ROUTE);
- unsigned int linkcost=0;
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_COMM_ITER *comm_iter=NULL;
+ TR_COMM *comm=NULL;
+ TR_COMM_ITER *realm_iter=NULL;
+ TR_REALM *realm=NULL;
+ TRP_UPD *upd=NULL;
+ TRP_RC rc=TRP_ERROR;
- if (rec!=NULL) {
- if (trp_route_is_local(route))
- linkcost=0;
- else {
- linkcost=trp_peer_get_linkcost(trps_get_peer_by_gssname(trps,
- trp_route_get_peer(route)));
- }
+ /* currently do not send any communities on triggered updates */
+ if (triggered) {
+ rc=TRP_SUCCESS;
+ goto cleanup;
+ }
- /* Note that we leave the next hop empty since the recipient fills that in.
- * This is where we add the link cost (currently always 1) to the next peer. */
- if ((trp_inforec_set_comm(rec, trp_route_dup_comm(route)) != TRP_SUCCESS)
- ||(trp_inforec_set_realm(rec, trp_route_dup_realm(route)) != TRP_SUCCESS)
- ||(trp_inforec_set_trust_router(rec, trp_route_dup_trust_router(route)) != TRP_SUCCESS)
- ||(trp_inforec_set_metric(rec,
- trps_metric_add(trp_route_get_metric(route),
- linkcost)) != TRP_SUCCESS)
- ||(trp_inforec_set_interval(rec, trps_get_update_interval(trps)) != TRP_SUCCESS)) {
- tr_err("trps_route_to_inforec: error creating route update.");
- talloc_free(rec);
- rec=NULL;
+ comm_iter=tr_comm_iter_new(tmp_ctx);
+ realm_iter=tr_comm_iter_new(tmp_ctx);
+ if ((comm_iter==NULL) || (realm_iter==NULL)) {
+ tr_err("trps_select_comm_updates_for_peer: unable to allocate iterator.");
+ rc=TRP_NOMEM;
+ goto cleanup;
+ }
+
+ /* do every community */
+ for (comm=tr_comm_table_iter_first(comm_iter, trps->ctable);
+ comm!=NULL;
+ comm=tr_comm_table_iter_next(comm_iter)) {
+ /* do every realm in this community */
+ tr_debug("trps_select_comm_updates_for_peer: looking through community %.*s",
+ tr_comm_get_id(comm)->len,
+ tr_comm_get_id(comm)->buf);
+ for (realm=tr_realm_iter_first(realm_iter, trps->ctable, tr_comm_get_id(comm));
+ realm!=NULL;
+ realm=tr_realm_iter_next(realm_iter)) {
+ /* get the update for this comm/realm */
+ tr_debug("trps_select_comm_updates_for_peer: adding realm %.*s",
+ tr_realm_get_id(realm)->len,
+ tr_realm_get_id(realm)->buf);
+ upd=trps_comm_update(mem_ctx, trps, peer_gssname, comm, realm);
+ if (upd!=NULL)
+ g_ptr_array_add(updates, upd);
}
}
- return rec;
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
}
-/* all routes to a single peer, unless comm/realm are specified (both or neither must be NULL) */
+
+/* helper for trps_update_one_peer. Frees the TRP_UPD pointed to by a GPtrArray element */
+static void trps_trp_upd_destroy(gpointer data)
+{
+ trp_upd_free((TRP_UPD *)data);
+}
+
+/* all routes/communities to a single peer, unless comm/realm are specified (both or neither must be NULL) */
static TRP_RC trps_update_one_peer(TRPS_INSTANCE *trps,
TRP_PEER *peer,
TRP_UPDATE_TYPE update_type,
TALLOC_CTX *tmp_ctx=talloc_new(NULL);
TR_MSG msg; /* not a pointer! */
TRP_UPD *upd=NULL;
- TRP_ROUTE **update_list=NULL;
- TRP_INFOREC *rec=NULL;
- size_t n_updates=0, ii=0;
+ TRP_ROUTE *route=NULL;
+ size_t ii=0;
char *encoded=NULL;
TRP_RC rc=TRP_ERROR;
TR_NAME *peer_label=trp_peer_get_label(peer);
+ GPtrArray *updates=g_ptr_array_new_with_free_func(trps_trp_upd_destroy);
+
+ if (updates==NULL) {
+ tr_err("trps_update_one_peer: unable to allocate updates array.");
+ rc=TRP_NOMEM;
+ goto cleanup;
+ }
switch (update_type) {
case TRP_UPDATE_TRIGGERED:
- tr_debug("trps_update_one_peer: preparing triggered route update for %.*s",
+ tr_debug("trps_update_one_peer: preparing triggered update for %.*s",
peer_label->len, peer_label->buf);
break;
case TRP_UPDATE_SCHEDULED:
- tr_debug("trps_update_one_peer: preparing scheduled route update for %.*s",
+ tr_debug("trps_update_one_peer: preparing scheduled update for %.*s",
peer_label->len, peer_label->buf);
break;
case TRP_UPDATE_REQUESTED:
- tr_debug("trps_update_one_peer: preparing requested route update for %.*s",
+ tr_debug("trps_update_one_peer: preparing requested update for %.*s",
peer_label->len, peer_label->buf);
+ break;
+ default:
+ tr_err("trps_update_one_peer: invalid update type requested.");
+ rc=TRP_BADARG;
+ goto cleanup;
}
- /* do not fill in peer, recipient does that */
+ /* First, gather route updates. */
+ tr_debug("trps_update_one_peer: selecting route updates for %.*s.", peer_label->len, peer_label->buf);
if ((comm==NULL) && (realm==NULL)) {
/* do all realms */
- update_list=trps_select_updates_for_peer(tmp_ctx,
- trps,
- peer_label,
- update_type==TRP_UPDATE_TRIGGERED,
- &n_updates);
+ rc=trps_select_route_updates_for_peer(tmp_ctx,
+ updates,
+ trps,
+ peer_label,
+ update_type==TRP_UPDATE_TRIGGERED);
} else if ((comm!=NULL) && (realm!=NULL)) {
/* a single community/realm was requested */
- update_list=talloc(tmp_ctx, TRP_ROUTE *);
- if (update_list==NULL) {
- tr_err("trps_update_one_peer: could not allocate update_list.");
- rc=TRP_NOMEM;
- goto cleanup;
- }
- *update_list=trps_select_realm_update(trps, comm, realm, peer_label);
- if (*update_list==NULL) {
+ route=trps_select_realm_update(trps, comm, realm, peer_label);
+ if (route==NULL) {
/* we have no actual update to send back, MUST send a retraction */
tr_debug("trps_update_one_peer: community/realm without route requested, sending mandatory retraction.");
- *update_list=trp_route_new(update_list);
- trp_route_set_comm(*update_list, tr_dup_name(comm));
- trp_route_set_realm(*update_list, tr_dup_name(realm));
- trp_route_set_peer(*update_list, tr_new_name(""));
- trp_route_set_metric(*update_list, TRP_METRIC_INFINITY);
- trp_route_set_trust_router(*update_list, tr_new_name(""));
- trp_route_set_next_hop(*update_list, tr_new_name(""));
+ route=trp_route_new(tmp_ctx);
+ trp_route_set_comm(route, tr_dup_name(comm));
+ trp_route_set_realm(route, tr_dup_name(realm));
+ trp_route_set_peer(route, tr_new_name(""));
+ trp_route_set_metric(route, TRP_METRIC_INFINITY);
+ trp_route_set_trust_router(route, tr_new_name(""));
+ trp_route_set_next_hop(route, tr_new_name(""));
+ }
+ upd=trps_route_to_upd(tmp_ctx, trps, route);
+ if (upd==NULL) {
+ tr_err("trps_update_one_peer: unable to allocate route update.");
+ rc=TRP_NOMEM;
+ goto cleanup;
}
- n_updates=1;
+ g_ptr_array_add(updates, upd);
} else {
- tr_err("trps_update_one_peer: error: only comm or realm was specified.");
+ tr_err("trps_update_one_peer: error: only comm or realm was specified. Need both or neither.");
rc=TRP_ERROR;
goto cleanup;
}
- if ((n_updates>0) && (update_list!=NULL)) {
- tr_debug("trps_update_one_peer: sending %u update records.", (unsigned int)n_updates);
- upd=trp_upd_new(tmp_ctx);
- for (ii=0; ii<n_updates; ii++) {
- rec=trps_route_to_inforec(tmp_ctx, trps, update_list[ii]);
- if (rec==NULL) {
- tr_err("trps_update_one_peer: could not create all update records.");
+ /* Second, gather community updates */
+ tr_debug("trps_update_one_peer: selecting community updates for %.*s.", peer_label->len, peer_label->buf);
+ rc=trps_select_comm_updates_for_peer(tmp_ctx, updates, trps, peer_label, update_type==TRP_UPDATE_TRIGGERED);
+
+ /* see if we have anything to send */
+ if (updates->len<=0)
+ tr_debug("trps_update_one_peer: no updates for %.*s", peer_label->len, peer_label->buf);
+ else {
+ tr_debug("trps_update_one_peer: sending %d update messages.", updates->len);
+ for (ii=0; ii<updates->len; ii++) {
+ 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);
+ if (encoded==NULL) {
+ tr_err("trps_update_one_peer: error encoding update.");
rc=TRP_ERROR;
goto cleanup;
}
- trp_upd_add_inforec(upd, rec);
- }
- talloc_free(update_list);
- update_list=NULL;
-
- /* now encode the update message */
- tr_msg_set_trp_upd(&msg, upd);
- encoded=tr_msg_encode(&msg);
- if (encoded==NULL) {
- tr_err("trps_update_one_peer: error encoding update.");
- rc=TRP_ERROR;
- goto cleanup;
- }
- tr_debug("trps_update_one_peer: adding message to queue.");
- if (trps_send_msg(trps, peer, encoded) != TRP_SUCCESS)
- tr_err("trps_update_one_peer: error queueing update.");
- else
- tr_debug("trps_update_one_peer: update queued successfully.");
+ tr_debug("trps_update_one_peer: adding message to queue.");
+ if (trps_send_msg(trps, peer, encoded) != TRP_SUCCESS)
+ tr_err("trps_update_one_peer: error queueing update.");
+ else
+ tr_debug("trps_update_one_peer: update queued successfully.");
- tr_msg_free_encoded(encoded);
- encoded=NULL;
- trp_upd_free(upd);
- upd=NULL;
- } else if (n_updates==0)
- tr_debug("trps_update_one_peer: no updates for %.*s", peer_label->len, peer_label->buf);
+ tr_msg_free_encoded(encoded);
+ encoded=NULL;
+ }
+ }
rc=TRP_SUCCESS;
cleanup:
+ if (updates!=NULL)
+ g_ptr_array_free(updates, TRUE); /* frees any TRP_UPD records */
talloc_free(tmp_ctx);
return rc;
}
-/* all routes to all peers */
+/* all routes/communities to all peers */
TRP_RC trps_update(TRPS_INSTANCE *trps, TRP_UPDATE_TYPE update_type)
{
TALLOC_CTX *tmp_ctx=talloc_new(NULL);
}
for (peer=trp_ptable_iter_first(iter, trps->ptable);
- peer!=NULL && rc==TRP_SUCCESS;
+ (peer!=NULL) && (rc==TRP_SUCCESS);
peer=trp_ptable_iter_next(iter))
{
if (!trps_peer_connected(trps, peer)) {
%global optflags %{optflags} -Wno-parentheses
Name: trust_router
-Version: 1.5.2
+Version: 2.1.1
Release: 1%{?dist}
Summary: Moonshot Trust Router
BuildRequires: krb5-devel, glib2-devel
BuildRequires: jansson-devel >= 2.4
-BuildRequires: sqlite-devel, openssl-devel, libtalloc-devel
+BuildRequires: sqlite-devel, openssl-devel, libtalloc-devel, libevent-devel
%{?el7:BuildRequires: systemd}
Requires: moonshot-gss-eap >= 0.9.3, sqlite
%prep
%setup -q
-
+autoreconf -f -i
%build
%configure --disable-static
# Install config files
install -D -m 755 redhat/init $RPM_BUILD_ROOT/%{_initrddir}/trust_router
-install -D -m 640 redhat/trusts.cfg $RPM_BUILD_ROOT/%{_sysconfdir}/trust_router/trusts.cfg
-install -D -m 640 redhat/default-main.cfg $RPM_BUILD_ROOT/%{_sysconfdir}/trust_router/conf.d/default/main.cfg
-install -D -m 640 redhat/tr-test-main.cfg $RPM_BUILD_ROOT/%{_sysconfdir}/trust_router/conf.d/tr-test/main.cfg
+install -D -m 640 redhat/organizations.cfg $RPM_BUILD_ROOT/%{_sysconfdir}/trust_router/organizations.cfg
+install -D -m 640 redhat/default-internal.cfg $RPM_BUILD_ROOT/%{_sysconfdir}/trust_router/conf.d/default/internal.cfg
+install -D -m 640 redhat/tr-test-internal.cfg $RPM_BUILD_ROOT/%{_sysconfdir}/trust_router/conf.d/tr-test/internal.cfg
install -D -m 640 redhat/sysconfig $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/trust_router
install -D -m 640 redhat/sysconfig.tids $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/tids
install -D -m 755 redhat/tids.init $RPM_BUILD_ROOT/%{_initrddir}/tids
# Link shared config
-ln -s ../../trusts.cfg $RPM_BUILD_ROOT/%{_sysconfdir}/trust_router/conf.d/default/trusts.cfg
-ln -s ../../trusts.cfg $RPM_BUILD_ROOT/%{_sysconfdir}/trust_router/conf.d/tr-test/trusts.cfg
+ln -s ../../organizations.cfg $RPM_BUILD_ROOT/%{_sysconfdir}/trust_router/conf.d/default/organizations.cfg
+ln -s ../../organizations.cfg $RPM_BUILD_ROOT/%{_sysconfdir}/trust_router/conf.d/tr-test/organizations.cfg
# Install wrapper scripts
install -D -m 755 redhat/tidc-wrapper $RPM_BUILD_ROOT/%{_bindir}/tidc-wrapper
%files
%defattr(-,root,root,-)
%doc README
+#%{_bindir}/tidc
+#%{_bindir}/tidc-wrapper
+#%{_bindir}/tids
+#%{_bindir}/tids-wrapper
+#%{_bindir}/trust_router
+#%{_bindir}/trust_router-wrapper
%{_bindir}/*
%{_datadir}/trust_router/schema.sql
%dir %attr(755,root,trustrouter) %{_sysconfdir}/trust_router/conf.d/default
%dir %attr(755,root,trustrouter) %{_sysconfdir}/trust_router/conf.d/tr-test
-%attr(640,root,trustrouter) %config(noreplace) %{_sysconfdir}/trust_router/trusts.cfg
-%attr(640,root,trustrouter) %config(noreplace) %{_sysconfdir}/trust_router/conf.d/default/main.cfg
-%attr(640,root,trustrouter) %config(noreplace) %{_sysconfdir}/trust_router/conf.d/tr-test/main.cfg
-%attr(640,root,trustrouter) %config(noreplace) %{_sysconfdir}/trust_router/conf.d/default/trusts.cfg
-%attr(640,root,trustrouter) %config(noreplace) %{_sysconfdir}/trust_router/conf.d/tr-test/trusts.cfg
+%attr(640,root,trustrouter) %config(noreplace) %{_sysconfdir}/trust_router/organizations.cfg
+%attr(640,root,trustrouter) %config(noreplace) %{_sysconfdir}/trust_router/conf.d/default/internal.cfg
+%attr(640,root,trustrouter) %config(noreplace) %{_sysconfdir}/trust_router/conf.d/tr-test/internal.cfg
+%attr(640,root,trustrouter) %config(noreplace) %{_sysconfdir}/trust_router/conf.d/default/organizations.cfg
+%attr(640,root,trustrouter) %config(noreplace) %{_sysconfdir}/trust_router/conf.d/tr-test/organizations.cfg
%files libs
%defattr(-,root,root,-)