DISTCHECK_CONFIGURE_FLAGS = \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
-bin_PROGRAMS= tr/trust_router tid/example/tidc tid/example/tids common/dh_test/tr_dh_test
+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
AM_CPPFLAGS=-I$(srcdir)/include $(GLIB_CFLAGS)
AM_CFLAGS = -Wall -Werror=missing-prototypes -Werror -Wno-parentheses $(GLIB_CFLAGS)
SUBDIRS = gsscon
common_srcs = common/tr_name.c \
+ common/tr_gss.c \
common/tr_constraint.c \
common/jansson_iterators.h \
common/tr_msg.c \
common/tr_debug.c \
common/tr_util.c
+tid_srcs = trp/trpc.c \
+tid/tid_resp.c \
+tid/tid_req.c \
+tid/tids.c \
+tid/tidc.c
+
+trp_srcs = trp/trp_upd.c \
+trp/trp_req.c \
+trp/trp_conn.c \
+trp/trps.c \
+trp/trp_ptable.c \
+trp/trp_rtable.c
+
check_PROGRAMS = common/t_constraint
TESTS = common/t_constraint
-lib_LTLIBRARIES = libtr_tid.la
+#lib_LTLIBRARIES = libtr_tid.la libtr_trp.la
common_t_constraint_SOURCES = common/t_constraint.c
common_t_constraint_CPPFLAGS = $(AM_CPPFLAGS) -DTESTS=\"$(srcdir)/common/tests.json\"
common_t_constraint_LDADD = gsscon/libgsscon.la libtr_tid.la
-tr_trust_router_SOURCES = tr/tr_main.c \
+tr_trust_router_SOURCES = $(common_srcs) \
+tr/tr_main.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 \
-tr/tr.c
+common/tr_mq.c \
+tr/tr.c \
+tr/tr_event.c \
+tr/tr_cfgwatch.c \
+tr/tr_tid.c \
+tr/tr_trp.c \
+$(trp_srcs) \
+$(tid_srcs)
+
+tr_trust_router_CFLAGS = $(AM_CFLAGS) -pthread -v -da -Q
+tr_trust_router_LDFLAGS = $(AM_LDFLAGS) -levent_pthreads
+#tr_trust_router_LDADD = gsscon/libgsscon.la libtr_tid.la libtr_trp.la $(GLIB_LIBS)
+tr_trust_router_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
+
+tr_trpc_SOURCES = $(common_srcs) \
+tr/trpc_main.c \
+common/tr_rp.c \
+common/tr_mq.c \
+tr/tr_trp.c \
+$(trp_srcs) \
+$(tid_srcs)
+
+#tr_trpc_LDADD = gsscon/libgsscon.la libtr_tid.la libtr_trp.la $(GLIB_LIBS)
+tr_trpc_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
+
+trp_msgtst_SOURCES = trp/msgtst.c \
+trp/trp_upd.c \
+trp/trp_req.c \
+tid/tid_req.c \
+tid/tid_resp.c \
+common/tr_msg.c \
+common/tr_name.c \
+common/tr_gss.c \
+common/tr_idp.c \
+common/tr_apc.c \
+common/tr_comm.c \
+common/tr_filter.c \
+common/tr_rp.c \
+common/tr_config.c \
+common/tr_debug.c
+
+trp_msgtst_LDADD = $(GLIB_LIBS)
+
+trp_test_rtbl_test_SOURCES = trp/test/rtbl_test.c \
+common/tr_name.c \
+common/tr_gss.c \
+common/tr_debug.c \
+trp/trp_rtable.c
-tr_trust_router_LDADD = gsscon/libgsscon.la libtr_tid.la $(GLIB_LIBS)
+trp_test_rtbl_test_LDADD = $(GLIB_LIBS)
+
+trp_test_ptbl_test_SOURCES = trp/test/ptbl_test.c \
+$(common_srcs) \
+$(trp_srcs) \
+$(tid_srcs) \
+common/tr_mq.c
+
+trp_test_ptbl_test_LDADD = gsscon/libgsscon.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_tidc_LDADD = gsscon/libgsscon.la libtr_tid.la $(GLIB_LIBS)
+tid_example_tidc_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
tid_example_tids_SOURCES = tid/example/tids_main.c
-tid_example_tids_LDADD = gsscon/libgsscon.la libtr_tid.la $(GLIB_LIBS)
+#tid_example_tids_LDADD = gsscon/libgsscon.la libtr_tid.la $(GLIB_LIBS)
+tid_example_tids_LDADD = gsscon/libgsscon.la $(GLIB_LIBS)
common_dh_test_tr_dh_test_SOURCES = common/tr_dh.c \
common/tr_debug.c \
common/dh_test/dh_test.c
-libtr_tid_la_SOURCES = tid/tids.c tid/tidc.c tid/tid_req.c tid/tid_resp.c \
-$(common_srcs)
+common_mq_test_mq_test_SOURCES = common/tr_mq.c \
+common/mq_test/mq_test.c
+
+common_mq_test_mq_test_CFLAGS = -pthread
+common_mq_test_mq_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc
-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
+common_cfg_test_cfg_test_SOURCES = common/tr_config.c \
+common/tr_rp.c \
+common/tr_idp.c \
+common/tr_filter.c \
+common/tr_constraint.c \
+common/tr_debug.c \
+common/tr_name.c \
+common/tr_gss.c \
+common/tr_apc.c \
+common/tr_comm.c \
+tid/tid_req.c \
+common/cfg_test/cfg_test.c
+
+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/tr_debug.c \
+common/mq_test/thread_test.c
+
+common_mq_test_thread_test_CFLAGS = -pthread
+common_mq_test_thread_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc
+
+# libtr_tid_la_SOURCES = tid/tids.c tid/tidc.c tid/tid_req.c tid/tid_resp.c \
+# $(common_srcs)
+#
+# 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_trp_la_SOURCES = trp/trps.c trp/trpc.c trp/trp_req.c trp/trp_upd.c trp/trp_conn.c \
+# $(common_srcs)
+#
+# libtr_trp_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden
+# libtr_trp_la_LIBADD = gsscon/libgsscon.la $(GLIB_LIBS)
+# libtr_trp_la_LDFLAGS = $(AM_LDFLAGS) -version-info 2 -no-undefined
pkginclude_HEADERS = include/trust_router/tid.h include/trust_router/tr_name.h \
include/tr_debug.h \
include/tr_msg.h include/tr.h \
include/tr_idp.h include/tr_rp.h \
include/tr_comm.h include/tr_apc.h \
+ include/tr_tid.h include/tr_trp.h \
include/tr_filter.h \
include/tid_internal.h
--- /dev/null
+/* test suite for tr_config.c */
+#include <stdio.h>
+#include <talloc.h>
+#include <assert.h>
+
+#include <trust_router/tr_name.h>
+#include <tr_comm.h>
+#include <tr_idp.h>
+#include <tr_config.h>
+#include <tr_debug.h>
+
+static void tr_talloc_log(const char *msg)
+{
+ tr_debug("talloc: %s", msg);
+}
+
+static int verify_idp_cfg(TR_CFG *cfg)
+{
+ 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);
+ name=tr_new_name("apc.example.com");
+ comm=tr_comm_lookup(cfg->comms, name);
+ tr_free_name(name);
+ assert(comm!=NULL);
+
+ assert(comm->type==TR_COMM_APC);
+ assert(comm->expiration_interval==TR_DEFAULT_APC_EXPIRATION_INTERVAL);
+ 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(idp_realm!=NULL);
+ assert(idp_realm->shared_config==0);
+ assert(idp_realm->origin==TR_REALM_LOCAL);
+ tr_free_name(name);
+ name=tr_new_name("apc.example.com");
+ assert(tr_name_cmp(idp_realm->apcs->id, name)==0);
+ tr_free_name(name);
+
+ assert(idp_realm->aaa_servers!=NULL);
+ name=tr_new_name("rad1.A.idp.cfg");
+ for (aaa=idp_realm->aaa_servers;
+ (aaa!=NULL) && (tr_name_cmp(name, aaa->hostname)!=0);
+ aaa=aaa->next) { }
+ assert(aaa!=NULL);
+ tr_free_name(name);
+
+ name=tr_new_name("rad2.A.idp.cfg");
+ for (aaa=idp_realm->aaa_servers;
+ (aaa!=NULL) && (tr_name_cmp(name, aaa->hostname)!=0);
+ aaa=aaa->next) { }
+ assert(aaa!=NULL);
+ tr_free_name(name);
+
+ return 0;
+}
+
+static int verify_rp_cfg(TR_CFG *cfg)
+{
+ int ii=0;
+ TR_NAME *name=NULL;
+
+ assert(cfg!=NULL);
+ assert(cfg->rp_clients!=NULL);
+ assert(cfg->rp_clients->next==NULL);
+ assert(cfg->rp_clients->comm_next==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);
+ name=tr_new_name("gss@example.com");
+ assert(tr_name_cmp(name, cfg->rp_clients->gss_names[0])==0);
+ return 0;
+}
+
+int main(void)
+{
+ TALLOC_CTX *mem_ctx=talloc_new(NULL);
+ TR_CFG *cfg=NULL;
+ TR_CFG_RC rc=TR_CFG_ERROR;
+
+ tr_log_open();
+
+ talloc_set_log_fn(tr_talloc_log);
+ cfg=tr_cfg_new(mem_ctx);
+
+ printf("Parsing idp.cfg.\n");
+ rc=tr_cfg_parse_one_config_file(cfg, "idp.cfg");
+ switch(rc) {
+ case TR_CFG_SUCCESS:
+ tr_debug("main: TR_CFG_SUCCESS");
+ break;
+ case TR_CFG_ERROR:
+ tr_debug("main: TR_CFG_ERROR");
+ break;
+ case TR_CFG_BAD_PARAMS:
+ tr_debug("main: TR_CFG_BAD_PARAMS");
+ break;
+ case TR_CFG_NOPARSE:
+ tr_debug("main: TR_CFG_NOPARSE");
+ break;
+ case TR_CFG_NOMEM:
+ tr_debug("main: TR_CFG_NOMEM");
+ break;
+ }
+
+ printf("Verifying IDP parse results... ");
+ if (verify_idp_cfg(cfg)!=0) {
+ printf("Error!\n");
+ exit(-1);
+ }
+ printf("success!\n");
+
+ printf("Verifying RP parse results... ");
+ if (verify_rp_cfg(cfg)!=0) {
+ printf("Error!\n");
+ exit(-1);
+ }
+ printf("success!\n");
+
+ talloc_report_full(mem_ctx, stderr);
+ tr_cfg_free(cfg);
+
+ printf("Cleared configuration for next test.\n\n");
+
+ cfg=tr_cfg_new(mem_ctx);
+
+ printf("Parsing rp.cfg.\n");
+ rc=tr_cfg_parse_one_config_file(cfg, "rp.cfg");
+ switch(rc) {
+ case TR_CFG_SUCCESS:
+ tr_debug("main: TR_CFG_SUCCESS");
+ break;
+ case TR_CFG_ERROR:
+ tr_debug("main: TR_CFG_ERROR");
+ break;
+ case TR_CFG_BAD_PARAMS:
+ tr_debug("main: TR_CFG_BAD_PARAMS");
+ break;
+ case TR_CFG_NOPARSE:
+ tr_debug("main: TR_CFG_NOPARSE");
+ break;
+ case TR_CFG_NOMEM:
+ tr_debug("main: TR_CFG_NOMEM");
+ break;
+ }
+
+#if 0
+ printf("Verifying RP parse results... ");
+ if (verify_rp_cfg(cfg)!=0) {
+ printf("Error!\n");
+ exit(-1);
+ }
+ printf("success!\n");
+#endif
+
+ talloc_free(mem_ctx);
+ return 0;
+}
--- /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"]
+ }
+ ]
+ }
+ ]
+}
--- /dev/null
+/*
+ * Copyright (c) 2016, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <tr_mq.h>
+
+static void notify_cb(TR_MQ *mq, void *arg)
+{
+ char *s=(char *)arg;
+
+ printf("MQ %s no longer empty.\n", s);
+}
+
+int main(void)
+{
+ TR_MQ *mq=NULL;
+ TR_MQ_MSG *msg=NULL;
+ TR_MQ_MSG *msg1=NULL;
+ TR_MQ_MSG *msg2=NULL;
+ TR_MQ_MSG *msg3=NULL;
+ TR_MQ_MSG *msg4=NULL;
+ char *mq_name="1";
+
+ mq=tr_mq_new(NULL);
+ mq->notify_cb=notify_cb;
+ mq->notify_cb_arg=mq_name;
+
+ msg1=tr_mq_msg_new(NULL);
+ asprintf((char **)&(msg1->p), "First message.\n");
+ msg1->p_free=free;
+ tr_mq_append(mq, msg1);
+ assert(mq->head==msg1);
+ assert(mq->tail==msg1);
+ assert(msg1->next==NULL);
+
+ msg2=tr_mq_msg_new(NULL);
+ asprintf((char **)&(msg2->p), "Second message.\n");
+ msg2->p_free=free;
+ tr_mq_append(mq, msg2);
+ assert(mq->head==msg1);
+ assert(msg1->next==msg2);
+ assert(mq->tail==msg2);
+ assert(msg2->next==NULL);
+
+ msg=tr_mq_pop(mq);
+ assert(msg==msg1);
+ assert(mq->head==msg2);
+ assert(mq->tail==msg2);
+ assert(msg2->next==NULL);
+ if ((msg!=NULL) && (msg->p!=NULL)) {
+ printf((char *)msg->p);
+ tr_mq_msg_free(msg);
+ } else
+ printf("no message to pop\n");
+
+ msg3=tr_mq_msg_new(NULL);
+ asprintf((char **)&(msg3->p), "Third message.\n");
+ msg3->p_free=free;
+ tr_mq_append(mq, msg3);
+ assert(mq->head==msg2);
+ assert(mq->tail==msg3);
+ assert(msg2->next==msg3);
+ assert(msg3->next==NULL);
+
+ msg=tr_mq_pop(mq);
+ assert(msg==msg2);
+ assert(mq->head==msg3);
+ assert(mq->tail==msg3);
+ assert(msg3->next==NULL);
+ if ((msg!=NULL) && (msg->p!=NULL)) {
+ printf((char *)msg->p);
+ tr_mq_msg_free(msg);
+ } else
+ printf("no message to pop\n");
+
+ msg=tr_mq_pop(mq);
+ assert(msg==msg3);
+ assert(mq->head==NULL);
+ assert(mq->tail==NULL);
+ if ((msg!=NULL) && (msg->p!=NULL)) {
+ printf((char *)msg->p);
+ tr_mq_msg_free(msg);
+ } else
+ printf("no message to pop\n");
+
+ msg=tr_mq_pop(mq);
+ assert(msg==NULL);
+ assert(mq->head==NULL);
+ assert(mq->tail==NULL);
+ if ((msg!=NULL) && (msg->p!=NULL)) {
+ printf((char *)msg->p);
+ tr_mq_msg_free(msg);
+ } else
+ printf("no message to pop\n");
+
+ msg4=tr_mq_msg_new(NULL);
+ asprintf((char **)&(msg4->p), "Fourth message.\n");
+ msg4->p_free=free;
+ tr_mq_append(mq, msg4);
+ assert(mq->head==msg4);
+ assert(mq->tail==msg4);
+ assert(msg4->next==NULL);
+
+ msg=tr_mq_pop(mq);
+ assert(msg==msg4);
+ assert(mq->head==NULL);
+ assert(mq->tail==NULL);
+ if ((msg!=NULL) && (msg->p!=NULL)) {
+ printf((char *)msg->p);
+ tr_mq_msg_free(msg);
+ } else
+ printf("no message to pop\n");
+
+ msg=tr_mq_pop(mq);
+ assert(msg==NULL);
+ assert(mq->head==NULL);
+ assert(mq->tail==NULL);
+ if ((msg!=NULL) && (msg->p!=NULL)) {
+ printf((char *)msg->p);
+ tr_mq_msg_free(msg);
+ } else
+ printf("no message to pop\n");
+
+ tr_mq_free(mq);
+
+ return 0;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <talloc.h>
+#include <time.h>
+#include <errno.h>
+
+#include <tr_mq.h>
+
+struct thread_data {
+ TR_MQ *mq;
+ useconds_t msg_dly;
+ int n_msgs;
+ char *label;
+};
+
+TR_MQ_MSG *make_msg(label, n)
+{
+ TR_MQ_MSG *msg=NULL;
+ msg=tr_mq_msg_new(NULL);
+ asprintf((char **)&(msg->p), "%s: %d messages to go...", label, n);
+ msg->p_free=free;
+ return msg;
+}
+
+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;
+
+ while (n_msgs>=0) {
+ usleep(msg_dly);
+ tr_mq_append(mq, make_msg(label, n_msgs));
+ n_msgs--;
+ }
+ tr_mq_append(mq, make_msg(label, -9999));
+ return NULL;
+}
+
+struct message_data {
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+ int ready;
+};
+
+void handle_messages(TR_MQ *mq, void *arg)
+{
+ struct message_data *status=(struct message_data *)arg;
+ pthread_mutex_lock(&(status->lock));
+ status->ready=1;
+ pthread_cond_signal(&(status->cond));
+ pthread_mutex_unlock(&(status->lock));
+}
+
+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)) {
+ printf(" > %s\n", (char *)msg->p);
+ tr_mq_msg_free(msg);
+ }
+ printf("* all messages handled\n");
+ fflush(stdout);
+}
+
+#define N_THREADS 2
+
+int main(void)
+{
+ TR_MQ *mq=NULL;
+ pthread_t thread[N_THREADS];
+ struct thread_data thread_data[N_THREADS];
+ useconds_t dly[N_THREADS]={100000, 1000000}; /* must be N_THREADS long */
+ int ii=0;
+ struct message_data status;
+ struct timespec timeout={0,0};
+ int wait_result=0;
+
+ mq=tr_mq_new(NULL);
+ mq->notify_cb=handle_messages;
+ mq->notify_cb_arg=(void *)&status;
+
+ pthread_cond_init(&(status.cond), 0);
+ pthread_mutex_init(&(status.lock), 0);
+ status.ready=0;
+
+ printf("Starting threads\n");
+ for (ii=0; ii<N_THREADS; ii++) {
+ 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);
+ pthread_create(&(thread[ii]), NULL, thread_start, &thread_data[ii]);
+ printf("%s started.\n", thread_data[ii].label);
+ }
+
+ while (1) {
+ pthread_mutex_lock(&(status.lock));
+ while ((!status.ready) && (wait_result!=ETIMEDOUT)) {
+ clock_gettime(CLOCK_REALTIME, &timeout);
+ timeout.tv_sec+=1;
+ wait_result=pthread_cond_timedwait(&(status.cond), &(status.lock), &timeout);
+ }
+
+ if (wait_result==ETIMEDOUT)
+ break;
+
+ output_messages(mq);
+ status.ready=0;
+ pthread_mutex_unlock(&(status.lock));
+ usleep(2000000);
+ }
+ printf("\n*** Timeout expired with no new messages. Joining threads and terminating.\n");
+ for (ii=0; ii<N_THREADS; ii++)
+ pthread_join(thread[ii], NULL);
+
+ return 0;
+}
--- /dev/null
+#include <talloc.h>
+
+#include <trust_router/tr_name.h>
+#include <tr_apc.h>
+
+static int tr_apc_destructor(void *obj)
+{
+ TR_APC *apc=talloc_get_type_abort(obj, TR_APC);
+ if (apc->id!=NULL)
+ tr_free_name(apc->id);
+ return 0;
+}
+
+TR_APC *tr_apc_new(TALLOC_CTX *mem_ctx)
+{
+ TR_APC *apc=talloc(mem_ctx, TR_APC);
+ if (apc!=NULL) {
+ apc->id=NULL;
+ apc->next=NULL;
+ talloc_set_destructor((void *)apc, tr_apc_destructor);
+ }
+ return apc;
+}
+
+void tr_apc_free(TR_APC *apc)
+{
+ talloc_free(apc);
+}
+
+static TR_APC *tr_apc_tail(TR_APC *apc)
+{
+ if (apc==NULL)
+ return NULL;
+
+ while (apc->next!=NULL)
+ apc=apc->next;
+ return apc;
+}
+
+TR_APC *tr_apc_add(TR_APC *head, TR_APC *new)
+{
+ if (head==NULL)
+ head=new;
+ else {
+ tr_apc_tail(head)->next=new;
+ while (new!=NULL) {
+ talloc_steal(head, new);
+ new=new->next;
+ }
+ }
+ return head;
+}
+
+/* does not copy next pointer */
+TR_APC *tr_apc_dup(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));
+ return new;
+}
+
+void tr_apc_set_id(TR_APC *apc, TR_NAME *id)
+{
+ if (apc->id)
+ tr_free_name(apc->id);
+ apc->id=id;
+}
+
+TR_NAME *tr_apc_get_id(TR_APC *apc)
+{
+ return apc->id;
+}
+
+TR_NAME *tr_apc_dup_id(TR_APC *apc)
+{
+ return tr_dup_name(apc->id);;
+}
+
+
+char *tr_apc_to_str(TALLOC_CTX *mem_ctx, TR_APC *apc)
+{
+ return talloc_strndup(mem_ctx, apc->id->buf, apc->id->len);
+}
*
*/
+#include <talloc.h>
+
+#include <tr_rp.h>
#include <trust_router/tr_name.h>
-#include <tr_config.h>
-#include <tr.h>
#include <tr_comm.h>
-#include <tr_rp.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);
+ return 0;
+}
+
+TR_COMM *tr_comm_new(TALLOC_CTX *mem_ctx)
+{
+ TR_COMM *comm=talloc(mem_ctx, TR_COMM);
+ if (comm!=NULL) {
+ comm->next=NULL;
+ comm->id=NULL;
+ comm->type=TR_COMM_UNKNOWN;
+ comm->apcs=NULL;
+ comm->idp_realms=NULL;
+ comm->rp_realms=NULL;
+ talloc_set_destructor((void *)comm, tr_comm_destructor);
+ }
+ return comm;
+}
+
+void tr_comm_free(TR_COMM *comm)
+{
+ talloc_free(comm);
+}
+
+/* does not take responsibility for freeing IDP realm */
+void tr_comm_add_idp_realm(TR_COMM *comm, TR_IDP_REALM *realm)
+{
+ TR_IDP_REALM *cur=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;
+ }
+}
+
+/* does not take responsibility for freeing RP realm */
+void tr_comm_add_rp_realm(TR_COMM *comm, TR_RP_REALM *realm)
+{
+ TR_RP_REALM *cur=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;
+ }
+}
+
+static TR_COMM *tr_comm_tail(TR_COMM *comm)
+{
+ if (comm==NULL)
+ return comm;
+
+ while (comm->next!=NULL)
+ comm=comm->next;
+ return 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)
+{
+ if (comms==NULL)
+ comms=new;
+ else {
+ tr_comm_tail(comms)->next=new;
+ while(new!=NULL) {
+ talloc_steal(comms, new);
+ new=new->next;
+ }
+ }
+ return comms;
+}
+
TR_IDP_REALM *tr_find_comm_idp (TR_COMM *comm, TR_NAME *idp_realm)
{
TR_IDP_REALM *idp;
return NULL;
}
-TR_COMM *tr_comm_lookup(TR_INSTANCE *tr, TR_NAME *comm)
+TR_COMM *tr_comm_lookup(TR_COMM *comms, TR_NAME *comm_name)
{
TR_COMM *cfg_comm = NULL;
- for (cfg_comm = tr->active_cfg->comms; NULL != cfg_comm; cfg_comm = cfg_comm->next) {
- if ((cfg_comm->id->len == comm->len) &&
- (!strncmp(cfg_comm->id->buf, comm->buf, comm->len)))
+ 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)))
return cfg_comm;
}
return NULL;
#include <dirent.h>
#include <talloc.h>
+#include <tr_cfgwatch.h>
+#include <tr_comm.h>
#include <tr_config.h>
+#include <tr_gss.h>
#include <tr_debug.h>
-#include <tr.h>
#include <tr_filter.h>
#include <trust_router/tr_constraint.h>
+#include <tr_idp.h>
+#include <tr.h>
+#include <trust_router/trp.h>
void tr_print_config (TR_CFG *cfg) {
tr_notice("tr_print_config: Logging running trust router configuration.");
void tr_print_comm_idps (TR_IDP_REALM *idp_list) {
TR_IDP_REALM *idp = NULL;
+ char *s=NULL;
for (idp = idp_list; NULL != idp; idp = idp->comm_next) {
- tr_notice("tr_print_config: - @%s", idp->realm_id->buf);
+ s=tr_idp_realm_to_str(NULL, idp);
+ if (s!=NULL)
+ tr_notice("tr_print_config: - @%s", s);
+ else
+ tr_notice("tr_print_config: unable to allocate idp output string.");
}
}
}
}
+TR_CFG *tr_cfg_new(TALLOC_CTX *mem_ctx)
+{
+ return talloc_zero(mem_ctx, TR_CFG);
+}
+
void tr_cfg_free (TR_CFG *cfg) {
talloc_free(cfg);
- return;
}
-TR_CFG_RC tr_apply_new_config (TR_INSTANCE *tr) {
- if (!tr)
+TR_CFG_MGR *tr_cfg_mgr_new(TALLOC_CTX *mem_ctx)
+{
+ return talloc_zero(mem_ctx, TR_CFG_MGR);
+}
+
+void tr_cfg_mgr_free (TR_CFG_MGR *cfg_mgr) {
+ talloc_free(cfg_mgr);
+}
+
+TR_CFG_RC tr_apply_new_config (TR_CFG_MGR *cfg_mgr)
+{
+ /* cfg_mgr->active is allowed to be null, but new cannot be */
+ if ((cfg_mgr==NULL) || (cfg_mgr->new==NULL))
return TR_CFG_BAD_PARAMS;
- if (tr->active_cfg)
- tr_cfg_free(tr->active_cfg);
+ if (cfg_mgr->active != NULL)
+ tr_cfg_free(cfg_mgr->active);
- tr->active_cfg = tr->new_cfg;
+ cfg_mgr->active = cfg_mgr->new;
+ cfg_mgr->new=NULL; /* only keep a single handle on the new configuration */
- tr_log_threshold(tr->active_cfg->internal->log_threshold);
- tr_console_threshold(tr->active_cfg->internal->console_threshold);
+ tr_log_threshold(cfg_mgr->active->internal->log_threshold);
+ tr_console_threshold(cfg_mgr->active->internal->console_threshold);
return TR_CFG_SUCCESS;
}
-static TR_CFG_RC tr_cfg_parse_internal (TR_CFG *trc, json_t *jcfg) {
+static TR_CFG_RC tr_cfg_parse_internal(TR_CFG *trc, json_t *jcfg)
+{
json_t *jint = NULL;
json_t *jmtd = NULL;
- json_t *jtp = NULL;
+ json_t *jtidsp = NULL;
+ json_t *jtrpsp = NULL;
json_t *jhname = NULL;
json_t *jlog = NULL;
json_t *jconthres = NULL;
json_t *jlogthres = NULL;
+ json_t *jcfgpoll = NULL;
+ json_t *jcfgsettle = NULL;
+ json_t *jroutesweep = NULL;
+ json_t *jrouteupdate = NULL;
+ json_t *jrouteconnect = NULL;
if ((!trc) || (!jcfg))
return TR_CFG_BAD_PARAMS;
if (NULL == trc->internal) {
- if (NULL == (trc->internal = talloc(trc, TR_CFG_INTERNAL)))
+ if (NULL == (trc->internal = talloc_zero(trc, TR_CFG_INTERNAL)))
return TR_CFG_NOMEM;
-
- memset(trc->internal, 0, sizeof(TR_CFG_INTERNAL));
}
if (NULL != (jint = json_object_get(jcfg, "tr_internal"))) {
if (NULL != (jmtd = json_object_get(jint, "max_tree_depth"))) {
if (json_is_number(jmtd)) {
- trc->internal->max_tree_depth = json_integer_value(jmtd);
+ trc->internal->max_tree_depth = json_integer_value(jmtd);
} else {
- tr_debug("tr_cfg_parse_internal: Parsing error, max_tree_depth is not a number.");
- return TR_CFG_NOPARSE;
+ tr_debug("tr_cfg_parse_internal: Parsing error, max_tree_depth is not a number.");
+ return TR_CFG_NOPARSE;
}
} else {
/* If not configured, use the default */
trc->internal->max_tree_depth = TR_DEFAULT_MAX_TREE_DEPTH;
}
- if (NULL != (jtp = json_object_get(jint, "tids_port"))) {
- if (json_is_number(jtp)) {
- trc->internal->tids_port = json_integer_value(jtp);
+ if (NULL != (jtidsp = json_object_get(jint, "tids_port"))) {
+ if (json_is_number(jtidsp)) {
+ trc->internal->tids_port = json_integer_value(jtidsp);
} else {
- tr_debug("tr_cfg_parse_internal: Parsing error, port is not a number.");
- return TR_CFG_NOPARSE;
+ tr_debug("tr_cfg_parse_internal: Parsing error, tids_port is not a number.");
+ return TR_CFG_NOPARSE;
}
} else {
/* If not configured, use the default */
trc->internal->tids_port = TR_DEFAULT_TIDS_PORT;
}
+ if (NULL != (jtrpsp = json_object_get(jint, "trps_port"))) {
+ if (json_is_number(jtrpsp)) {
+ trc->internal->trps_port = json_integer_value(jtrpsp);
+ } else {
+ tr_debug("tr_cfg_parse_internal: Parsing error, trps_port is not a number.");
+ return TR_CFG_NOPARSE;
+ }
+ } else {
+ /* If not configured, use the default */
+ trc->internal->trps_port = TR_DEFAULT_TRPS_PORT;
+ }
if (NULL != (jhname = json_object_get(jint, "hostname"))) {
if (json_is_string(jhname)) {
- trc->internal->hostname = json_string_value(jhname);
+ trc->internal->hostname = json_string_value(jhname);
+ } else {
+ tr_debug("tr_cfg_parse_internal: Parsing error, hostname is not a string.");
+ return TR_CFG_NOPARSE;
+ }
+ }
+ if (NULL != (jcfgpoll = json_object_get(jint, "cfg_poll_interval"))) {
+ if (json_is_number(jcfgpoll)) {
+ trc->internal->cfg_poll_interval = json_integer_value(jcfgpoll);
} else {
- tr_debug("tr_cfg_parse_internal: Parsing error, hostname is not a string.");
- return TR_CFG_NOPARSE;
+ tr_debug("tr_cfg_parse_internal: Parsing error, cfg_poll_interval is not a number.");
+ return TR_CFG_NOPARSE;
}
+ } else {
+ trc->internal->cfg_poll_interval = TR_CFGWATCH_DEFAULT_POLL;
+ }
+
+ if (NULL != (jcfgsettle = json_object_get(jint, "cfg_settling_time"))) {
+ if (json_is_number(jcfgsettle)) {
+ trc->internal->cfg_settling_time = json_integer_value(jcfgsettle);
+ } else {
+ tr_debug("tr_cfg_parse_internal: Parsing error, cfg_settling_time is not a number.");
+ return TR_CFG_NOPARSE;
+ }
+ } else {
+ trc->internal->cfg_settling_time = TR_CFGWATCH_DEFAULT_SETTLE;
+ }
+
+ if (NULL != (jrouteconnect = json_object_get(jint, "trp_connect_interval"))) {
+ if (json_is_number(jrouteconnect)) {
+ trc->internal->trp_connect_interval = json_integer_value(jrouteconnect);
+ } else {
+ tr_debug("tr_cfg_parse_internal: Parsing error, trp_connect_interval is not a number.");
+ return TR_CFG_NOPARSE;
+ }
+ } else {
+ /* if not configured, use the default */
+ trc->internal->trp_connect_interval=TR_DEFAULT_TRP_CONNECT_INTERVAL;
+ }
+
+ if (NULL != (jroutesweep = json_object_get(jint, "trp_sweep_interval"))) {
+ if (json_is_number(jroutesweep)) {
+ trc->internal->trp_sweep_interval = json_integer_value(jroutesweep);
+ } else {
+ tr_debug("tr_cfg_parse_internal: Parsing error, trp_sweep_interval is not a number.");
+ return TR_CFG_NOPARSE;
+ }
+ } else {
+ /* if not configured, use the default */
+ trc->internal->trp_sweep_interval=TR_DEFAULT_TRP_SWEEP_INTERVAL;
+ }
+
+ if (NULL != (jrouteupdate = json_object_get(jint, "trp_update_interval"))) {
+ if (json_is_number(jrouteupdate)) {
+ trc->internal->trp_update_interval = json_integer_value(jrouteupdate);
+ } else {
+ tr_debug("tr_cfg_parse_internal: Parsing error, trp_update_interval is not a number.");
+ return TR_CFG_NOPARSE;
+ }
+ } else {
+ /* if not configured, use the default */
+ trc->internal->trp_update_interval=TR_DEFAULT_TRP_UPDATE_INTERVAL;
}
if (NULL != (jlog = json_object_get(jint, "logging"))) {
if (NULL != (jlogthres = json_object_get(jlog, "log_threshold"))) {
if (json_is_string(jlogthres)) {
- trc->internal->log_threshold = str2sev(json_string_value(jlogthres));
+ trc->internal->log_threshold = str2sev(json_string_value(jlogthres));
} else {
tr_debug("tr_cfg_parse_internal: Parsing error, log_threshold is not a string.");
return TR_CFG_NOPARSE;
return TR_CFG_SUCCESS;
}
-static TR_CONSTRAINT *tr_cfg_parse_one_constraint (TR_CFG *trc, char *ctype, json_t *jc, TR_CFG_RC *rc)
+static TR_CONSTRAINT *tr_cfg_parse_one_constraint(TALLOC_CTX *mem_ctx, char *ctype, json_t *jc, TR_CFG_RC *rc)
{
- TR_CONSTRAINT *cons;
- int i;
+ TR_CONSTRAINT *cons=NULL;
+ int i=0;
- if ((!trc) || (!ctype) || (!jc) || (!rc) ||
+ if ((!ctype) || (!jc) || (!rc) ||
(!json_is_array(jc)) ||
(0 >= json_array_size(jc)) ||
(TR_MAX_CONST_MATCHES < json_array_size(jc)) ||
(!json_is_string(json_array_get(jc, 0)))) {
- tr_debug("tr_cfg_parse_one_constraint: config error.");
- *rc = TR_CFG_NOPARSE;
+ tr_err("tr_cfg_parse_one_constraint: config error.");
+ *rc=TR_CFG_NOPARSE;
return NULL;
}
- if (NULL == (cons = talloc(trc, TR_CONSTRAINT))) {
+ if (NULL==(cons=tr_constraint_new(mem_ctx))) {
tr_debug("tr_cfg_parse_one_constraint: Out of memory (cons).");
- *rc = TR_CFG_NOMEM;
+ *rc=TR_CFG_NOMEM;
return NULL;
}
- memset(cons, 0, sizeof(TR_CONSTRAINT));
-
- if (NULL == (cons->type = tr_new_name(ctype))) {
- tr_debug("tr_cfg_parse_one_constraint: Out of memory (type).");
- *rc = TR_CFG_NOMEM;
+ if (NULL==(cons->type=tr_new_name(ctype))) {
+ tr_err("tr_cfg_parse_one_constraint: Out of memory (type).");
+ *rc=TR_CFG_NOMEM;
+ tr_constraint_free(cons);
return NULL;
}
- for (i = 0; i < json_array_size(jc); i++) {
- cons->matches[i] = tr_new_name((char *)(json_string_value(json_array_get(jc, i))));
+ for (i=0; i < json_array_size(jc); i++) {
+ cons->matches[i]=tr_new_name(json_string_value(json_array_get(jc, i)));
+ if (cons->matches[i]==NULL) {
+ tr_err("tr_cfg_parse_one_constraint: Out of memory (match %d).", i+1);
+ *rc=TR_CFG_NOMEM;
+ tr_constraint_free(cons);
+ return NULL;
+ }
}
return cons;
}
-static TR_FILTER *tr_cfg_parse_one_filter (TR_CFG *trc, json_t *jfilt, TR_CFG_RC *rc)
+static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR_FILTER_TYPE ftype, TR_CFG_RC *rc)
{
- TR_FILTER *filt = NULL;
- json_t *jftype = NULL;
- json_t *jfls = NULL;
- json_t *jfaction = NULL;
- json_t *jfspecs = NULL;
- json_t *jffield = NULL;
- json_t *jfmatch = NULL;
- json_t *jrc = NULL;
- json_t *jdc = NULL;
- int i = 0, j = 0;
-
- if ((NULL == (jftype = json_object_get(jfilt, "type"))) ||
- (!json_is_string(jftype))) {
- tr_debug("tr_cfg_parse_one_filter: Error parsing filter type.");
- *rc = TR_CFG_NOPARSE;
- return NULL;
- }
-
- if ((NULL == (jfls = json_object_get(jfilt, "filter_lines"))) ||
- (!json_is_array(jfls))) {
- tr_debug("tr_cfg_parse_one_filter: Error parsing filter type.");
- *rc = TR_CFG_NOPARSE;
- return NULL;
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_FILTER *filt=NULL;
+ json_t *jfaction=NULL;
+ json_t *jfspecs=NULL;
+ json_t *jffield=NULL;
+ json_t *jfmatches=NULL;
+ json_t *jfmatch=NULL;
+ json_t *jrc=NULL;
+ json_t *jdc=NULL;
+ TR_NAME *name=NULL;
+ int i=0, j=0, k=0;
+
+ *rc=TR_CFG_ERROR;
+
+ if ((jfilt==NULL) || (rc==NULL)) {
+ tr_err("tr_cfg_parse_one_filter: null argument");
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
}
-
- if (TR_MAX_FILTER_LINES < json_array_size(jfls)) {
- tr_debug("tr_cfg_parse_one_filter: Filter has too many filter_lines, maximimum of %d.", TR_MAX_FILTER_LINES);
- *rc = TR_CFG_NOPARSE;
- return NULL;
- }
-
- if (NULL == (filt = talloc(trc, TR_FILTER))) {
- tr_debug("tr_cfg_parse_one_filter: Out of memory.");
- *rc = TR_CFG_NOMEM;
- return NULL;
+
+ if (NULL==(filt=tr_filter_new(tmp_ctx))) {
+ tr_err("tr_cfg_parse_one_filter: Out of memory.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
}
+ tr_filter_set_type(filt, ftype);
- memset(filt, 0, sizeof(TR_FILTER));
-
- if (!strcmp(json_string_value(jftype), "rp_permitted")) {
- filt->type = TR_FILTER_TYPE_RP_PERMITTED;
+ /* make sure we have space to represent the filter */
+ if (json_array_size(jfilt) > TR_MAX_FILTER_LINES) {
+ tr_err("tr_cfg_parse_one_filter: Filter has too many lines, maximum of %d.", TR_MAX_FILTER_LINES);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
}
- else {
- tr_debug("tr_cfg_parse_one_filter: Error parsing filter type, unknown type '%s'.", json_string_value(jftype));
- *rc = TR_CFG_NOPARSE;
- tr_filter_free(filt);
- return NULL;
- }
-
- /* For each filter line... */
- for (i = 0; i < json_array_size(jfls); i++) {
- if ((NULL == (jfaction = json_object_get(json_array_get(jfls, i), "action"))) ||
- (!json_is_string(jfaction))) {
+ /* For each entry in the filter... */
+ for (i=0; i < json_array_size(jfilt); i++) {
+ if ((NULL==(jfaction=json_object_get(json_array_get(jfilt, i), "action"))) ||
+ (!json_is_string(jfaction))) {
tr_debug("tr_cfg_parse_one_filter: Error parsing filter action.");
- *rc = TR_CFG_NOPARSE;
- tr_filter_free(filt);
- return NULL;
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
}
- if ((NULL == (jfspecs = json_object_get(json_array_get(jfls, i), "filter_specs"))) ||
- (!json_is_array(jfspecs)) ||
- (0 == json_array_size(jfspecs))) {
+ if ((NULL==(jfspecs=json_object_get(json_array_get(jfilt, i), "specs"))) ||
+ (!json_is_array(jfspecs)) ||
+ (0==json_array_size(jfspecs))) {
tr_debug("tr_cfg_parse_one_filter: Error parsing filter specs.");
- *rc = TR_CFG_NOPARSE;
- tr_filter_free(filt);
- return NULL;
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
}
if (TR_MAX_FILTER_SPECS < json_array_size(jfspecs)) {
- tr_debug("tr_cfg_parse_one_filter: Filter has too many filter_specs, maximimum of %d.", TR_MAX_FILTER_SPECS);
- *rc = TR_CFG_NOPARSE;
- tr_filter_free(filt);
- return NULL;
+ tr_debug("tr_cfg_parse_one_filter: Filter has too many specs, maximimum of %d.", TR_MAX_FILTER_SPECS);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
}
- if (NULL == (filt->lines[i] = talloc(trc, TR_FLINE))) {
- tr_debug("tr_cfg_parse_one_filter: Out of memory (fline).");
- *rc = TR_CFG_NOMEM;
- tr_filter_free(filt);
- return NULL;
+ if (NULL==(filt->lines[i]=tr_fline_new(filt))) {
+ tr_debug("tr_cfg_parse_one_filter: Out of memory allocating filter line %d.", i+1);
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
}
- memset(filt->lines[i], 0, sizeof(TR_FLINE));
-
if (!strcmp(json_string_value(jfaction), "accept")) {
- filt->lines[i]->action = TR_FILTER_ACTION_ACCEPT;
+ filt->lines[i]->action=TR_FILTER_ACTION_ACCEPT;
}
else if (!strcmp(json_string_value(jfaction), "reject")) {
- filt->lines[i]->action = TR_FILTER_ACTION_REJECT;
+ filt->lines[i]->action=TR_FILTER_ACTION_REJECT;
}
else {
tr_debug("tr_cfg_parse_one_filter: Error parsing filter action, unknown action' %s'.", json_string_value(jfaction));
- *rc = TR_CFG_NOPARSE;
- tr_filter_free(filt);
- return NULL;
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
}
- if ((NULL != (jrc = json_object_get(json_array_get(jfls, i), "realm_constraints"))) &&
- (json_is_array(jrc)) &&
- (0 != json_array_size(jrc)) &&
- (TR_MAX_CONST_MATCHES >= json_array_size(jrc))) {
-
- if (NULL == (filt->lines[i]->realm_cons = tr_cfg_parse_one_constraint(trc, "realm", jrc, rc))) {
- tr_debug("tr_cfg_parse_one_filter: Error parsing realm constraint");
- tr_filter_free(filt);
- return NULL;
+ if (NULL!=(jrc=json_object_get(json_array_get(jfilt, i), "realm_constraints"))) {
+ if (!json_is_array(jrc)) {
+ tr_err("tr_cfg_parse_one_filter: cannot parse realm_constraints, not an array.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ } else if (json_array_size(jrc)>TR_MAX_CONST_MATCHES) {
+ tr_err("tr_cfg_parse_one_filter: realm_constraints has too many entries, maximum of %d.",
+ TR_MAX_CONST_MATCHES);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ } else if (json_array_size(jrc)>0) {
+ /* ok we actually have entries to process */
+ if (NULL==(filt->lines[i]->realm_cons=tr_cfg_parse_one_constraint(filt->lines[i], "realm", jrc, rc))) {
+ tr_debug("tr_cfg_parse_one_filter: Error parsing realm constraint");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
}
}
- if ((NULL != (jdc = json_object_get(json_array_get(jfls, i), "domain_constraints"))) &&
- (json_is_array(jdc)) &&
- (0 != json_array_size(jdc)) &&
- (TR_MAX_CONST_MATCHES >= json_array_size(jdc))) {
-
- if (NULL == (filt->lines[i]->domain_cons = tr_cfg_parse_one_constraint(trc, "domain", jdc, rc))) {
- tr_debug("tr_cfg_parse_one_filter: Error parsing domain constraint");
- tr_filter_free(filt);
- return NULL;
+ if (NULL!=(jdc=json_object_get(json_array_get(jfilt, i), "domain_constraints"))) {
+ if (!json_is_array(jdc)) {
+ tr_err("tr_cfg_parse_one_filter: cannot parse domain_constraints, not an array.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ } else if (json_array_size(jdc)>TR_MAX_CONST_MATCHES) {
+ tr_err("tr_cfg_parse_one_filter: domain_constraints has too many entries, maximum of %d.",
+ TR_MAX_CONST_MATCHES);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ } else if (json_array_size(jdc)>0) {
+ if (NULL==(filt->lines[i]->domain_cons=tr_cfg_parse_one_constraint(filt->lines[i], "domain", jdc, rc))) {
+ tr_debug("tr_cfg_parse_one_filter: Error parsing domain constraint");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
}
}
/*For each filter spec within the filter line... */
- for (j = 0; j <json_array_size(jfspecs); j++) {
-
- if ((NULL == (jffield = json_object_get(json_array_get(jfspecs, j), "field"))) ||
- (!json_is_string(jffield)) ||
- (NULL == (jfmatch = json_object_get(json_array_get(jfspecs, j), "match"))) ||
- (!json_is_string(jfmatch))) {
- tr_debug("tr_cfg_parse_one_filter: Error parsing filter field and match for filter spec %d, filter line %d.", i, j);
- *rc = TR_CFG_NOPARSE;
- tr_filter_free(filt);
- return NULL;
+ for (j=0; j <json_array_size(jfspecs); j++) {
+ if ((NULL==(jffield=json_object_get(json_array_get(jfspecs, j), "field"))) ||
+ (!json_is_string(jffield))) {
+ tr_debug("tr_cfg_parse_one_filter: Error parsing filter: missing field for filer spec %d, filter line %d.", i, j);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
}
- if (NULL == (filt->lines[i]->specs[j] = talloc(trc, TR_FSPEC))) {
- tr_debug("tr_cfg_parse_one_filter: Out of memory.");
- *rc = TR_CFG_NOMEM;
- tr_filter_free(filt);
- return NULL;
+ /* check that we have a match attribute */
+ if (NULL==(jfmatches=json_object_get(json_array_get(jfspecs, j), "match"))) {
+ tr_debug("tr_cfg_parse_one_filter: Error parsing filter: missing match for filer spec %d, filter line %d.", i, j);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
}
- memset(filt->lines[i]->specs[j], 0, sizeof(TR_FSPEC));
-
- if ((NULL == (filt->lines[i]->specs[j]->field = tr_new_name((char *)json_string_value(jffield)))) ||
- (NULL == (filt->lines[i]->specs[j]->match = tr_new_name((char *)json_string_value(jfmatch))))) {
- tr_debug("tr_cfg_parse_one_filter: Out of memory.");
- *rc = TR_CFG_NOMEM;
- tr_filter_free(filt);
- return NULL;
+ /* check that match is an array */
+ if (!json_is_array(jfmatches)) {
+ tr_debug("tr_cfg_parse_one_filter: Error parsing filter: match not an array for filter spec %d, filter line %d.", i, j);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ /* allocate the filter spec */
+ if (NULL==(filt->lines[i]->specs[j]=tr_fspec_new(filt->lines[i]))) {
+ tr_debug("tr_cfg_parse_one_filter: Out of memory.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ /* fill in the field */
+ if (NULL==(filt->lines[i]->specs[j]->field=tr_new_name(json_string_value(jffield)))) {
+ tr_debug("tr_cfg_parse_one_filter: Out of memory.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ /* fill in the matches */
+ for (k=0; k<json_array_size(jfmatches); k++) {
+ if (NULL==(jfmatch=json_array_get(jfmatches, k))) {
+ tr_debug("tr_cfg_parse_one_filter: Error parsing filter: unable to load match %d for filter spec %d, filter line %d.", k, i, j);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ if (NULL==(name=tr_new_name(json_string_value(jfmatch)))) {
+ tr_debug("tr_cfg_parse_one_filter: Out of memory.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ if (0!=tr_fspec_add_match(filt->lines[i]->specs[j], name)) {
+ tr_debug("tr_cfg_parse_one_filter: Could not add match %d to filter spec %d, filter line %d.", k, i, j);
+ tr_free_name(name);
+ *rc=TR_CFG_ERROR;
+ goto cleanup;
+ }
}
+
}
}
+ *rc=TR_CFG_SUCCESS;
+ talloc_steal(mem_ctx, filt);
+
+ cleanup:
+ talloc_free(tmp_ctx);
+ if (*rc!=TR_CFG_SUCCESS)
+ filt=NULL;
+ return filt;
+}
+static TR_FILTER *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ json_t *jfilt;
+ TR_FILTER *filt=NULL;
+
+ *rc=TR_CFG_ERROR;
+
+ /* no filters */
+ if (jfilts==NULL) {
+ *rc=TR_CFG_SUCCESS;
+ goto cleanup;
+ }
+
+ jfilt=json_object_get(jfilts, "tid_inbound");
+ if (jfilt!=NULL) {
+ filt=tr_cfg_parse_one_filter(tmp_ctx, jfilt, TR_FILTER_TYPE_TID_INCOMING, rc);
+ if (*rc!=TR_CFG_SUCCESS) {
+ tr_debug("tr_cfg_parse_filters: Error parsing tid_inbound filter.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ } else {
+ tr_debug("tr_cfg_parse_filters: Unknown filter types in filter block.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ *rc=TR_CFG_SUCCESS;
+
+ cleanup:
+ if (*rc==TR_CFG_SUCCESS)
+ talloc_steal(mem_ctx, filt);
+ else if (filt!=NULL) {
+ talloc_free(filt);
+ filt=NULL;
+ }
+
+ talloc_free(tmp_ctx);
return filt;
}
-static TR_RP_CLIENT *tr_cfg_parse_one_rp_client (TR_CFG *trc, json_t *jrp, TR_CFG_RC *rc)
+static TR_AAA_SERVER *tr_cfg_parse_one_aaa_server(TALLOC_CTX *mem_ctx, json_t *jaddr, TR_CFG_RC *rc)
{
- TR_RP_CLIENT *rp = NULL;
- json_t *jgns = NULL;
- json_t *jfilt = NULL;
- json_t *jftype = NULL;
- int i = 0;
+ TR_AAA_SERVER *aaa = NULL;
+ TR_NAME *name=NULL;
- if ((!trc) || (!jrp) || (!rc)) {
- tr_debug("tr_cfg_parse_one_rp_realm: Bad parameters.");
- if (rc)
- *rc = TR_CFG_BAD_PARAMS;
+ if ((!jaddr) || (!json_is_string(jaddr))) {
+ tr_debug("tr_cfg_parse_one_aaa_server: Bad parameters.");
+ *rc = TR_CFG_BAD_PARAMS;
return NULL;
}
- if ((NULL == (jgns = json_object_get(jrp, "gss_names"))) ||
- (!json_is_array(jgns))) {
- tr_debug("tr_cfg_parse_one_rp_client: Error parsing RP client configuration, no GSS names.");
- *rc = TR_CFG_NOPARSE;
+ name=tr_new_name(json_string_value(jaddr));
+ if (name==NULL) {
+ tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating hostname.");
+ *rc = TR_CFG_NOMEM;
return NULL;
}
- /* TBD -- Support more than one filter per RP client? */
- if (NULL == (jfilt = json_object_get(jrp, "filter"))) {
- tr_debug("tr_cfg_parse_one_rp_client: Error parsing RP client configuration, no filter.");
- *rc = TR_CFG_NOPARSE;
+ aaa=tr_aaa_server_new(mem_ctx, name);
+ if (aaa==NULL) {
+ tr_free_name(name);
+ tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating AAA server.");
+ *rc = TR_CFG_NOMEM;
return NULL;
}
- /* We only support rp_permitted filters for RP clients */
- if ((NULL == (jftype = json_object_get(jfilt, "type"))) ||
- (!json_is_string(jftype)) ||
- (strcmp(json_string_value(jftype), "rp_permitted"))) {
- tr_debug("tr_cfg_parse_one_rp_client: Error parsing RP client filter type.");
- *rc = TR_CFG_NOPARSE;
+ return aaa;
+}
+
+static TR_AAA_SERVER *tr_cfg_parse_aaa_servers(TALLOC_CTX *mem_ctx, json_t *jaaas, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=NULL;
+ TR_AAA_SERVER *aaa = NULL;
+ TR_AAA_SERVER *temp_aaa = NULL;
+ int i = 0;
+
+ for (i = 0; i < json_array_size(jaaas); i++) {
+ /* rc gets set in here */
+ if (NULL == (temp_aaa = tr_cfg_parse_one_aaa_server(tmp_ctx, json_array_get(jaaas, i), rc))) {
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ /* TBD -- IPv6 addresses */
+ // tr_debug("tr_cfg_parse_aaa_servers: Configuring AAA Server: ip_addr = %s.", inet_ntoa(temp_aaa->aaa_server_addr));
+ temp_aaa->next = aaa;
+ aaa = temp_aaa;
+ }
+ tr_debug("tr_cfg_parse_aaa_servers: Finished (rc=%d)", *rc);
+
+ for (temp_aaa=aaa; temp_aaa!=NULL; temp_aaa=temp_aaa->next)
+ talloc_steal(mem_ctx, temp_aaa);
+ talloc_free(tmp_ctx);
+ return aaa;
+}
+
+static TR_APC *tr_cfg_parse_one_apc(TALLOC_CTX *mem_ctx, json_t *japc, TR_CFG_RC *rc)
+{
+ TR_APC *apc=NULL;
+ TR_NAME *name=NULL;
+
+ *rc = TR_CFG_SUCCESS; /* presume success */
+
+ if ((!japc) || (!rc) || (!json_is_string(japc))) {
+ tr_debug("tr_cfg_parse_one_apc: Bad parameters.");
+ if (rc)
+ *rc = TR_CFG_BAD_PARAMS;
return NULL;
}
- if (TR_MAX_GSS_NAMES < json_array_size(jgns)) {
- tr_debug("tr_cfg_parse_one_rp_client: RP Client has too many GSS Names.");
- *rc = TR_CFG_NOPARSE;
+ apc=tr_apc_new(mem_ctx);
+ if (apc==NULL) {
+ tr_debug("tr_cfg_parse_one_apc: Out of memory.");
+ *rc = TR_CFG_NOMEM;
return NULL;
}
- if (NULL == (rp = talloc(trc, TR_RP_CLIENT))) {
- tr_debug("tr_cfg_parse_one_rp_realm: Out of memory.");
+ name=tr_new_name(json_string_value(japc));
+ if (name==NULL) {
+ tr_debug("tr_cfg_parse_one_apc: No memory for APC name.");
+ tr_apc_free(apc);
*rc = TR_CFG_NOMEM;
return NULL;
}
+ tr_apc_set_id(apc, name); /* apc is now responsible for freeing the name */
+
+ return apc;
+}
+
+static TR_APC *tr_cfg_parse_apcs(TALLOC_CTX *mem_ctx, json_t *japcs, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_APC *apcs=NULL;
+ TR_APC *new_apc=NULL;
+ int ii=0;
+ TR_CFG_RC call_rc=TR_CFG_ERROR;
- memset(rp, 0, sizeof(TR_RP_CLIENT));
+ *rc = TR_CFG_SUCCESS; /* presume success */
- /* TBD -- support more than one filter entry per RP Client? */
- if (NULL == (rp->filter = tr_cfg_parse_one_filter(trc, jfilt, rc))) {
- tr_debug("tr_cfg_parse_one_rp_client: Error parsing filter.");
- *rc = TR_CFG_NOPARSE;
+ if ((!japcs) || (!rc) || (!json_is_array(japcs))) {
+ tr_debug("tr_cfg_parse_one_apc: Bad parameters.");
+ if (rc)
+ *rc = TR_CFG_BAD_PARAMS;
return NULL;
}
-
- for (i = 0; i < json_array_size(jgns); i++) {
- if (NULL == (rp->gss_names[i] = tr_new_name ((char *)json_string_value(json_array_get(jgns, i))))) {
- tr_debug("tr_cfg_parse_one_rp_client: No memory for GSS Name.");
- *rc = TR_CFG_NOMEM;
- return NULL;
+
+ for (ii=0; ii<json_array_size(japcs); ii++) {
+ new_apc=tr_cfg_parse_one_apc(tmp_ctx, json_array_get(japcs, ii), &call_rc);
+ if ((call_rc!=TR_CFG_SUCCESS) || (new_apc==NULL)) {
+ tr_debug("tr_cfg_parse_apcs: Error parsing APC %d.", ii+1);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
}
+ apcs=tr_apc_add(apcs, new_apc);
}
-
- return rp;
-}
-static TR_CFG_RC tr_cfg_parse_rp_clients (TR_CFG *trc, json_t *jcfg) {
- json_t *jrps = NULL;
- TR_RP_CLIENT *rp = NULL;
- TR_CFG_RC rc = TR_CFG_SUCCESS;
- int i = 0;
+ talloc_steal(mem_ctx, apcs);
+ *rc=TR_CFG_SUCCESS;
- if ((!trc) || (!jcfg))
- return TR_CFG_BAD_PARAMS;
+ cleanup:
+ talloc_free(tmp_ctx);
+ return apcs;
+}
- if (NULL != (jrps = json_object_get(jcfg, "rp_clients"))) {
+static TR_NAME *tr_cfg_parse_name(TALLOC_CTX *mem_ctx, json_t *jname, TR_CFG_RC *rc)
+{
+ TR_NAME *name=NULL;
+ *rc=TR_CFG_ERROR;
- if (!json_is_array(jrps)) {
- return TR_CFG_NOPARSE;
+ if ((jname==NULL) || (!json_is_string(jname))) {
+ tr_err("tr_cfg_parse_name: name missing or not a string");
+ *rc=TR_CFG_BAD_PARAMS;
+ name=NULL;
+ } else {
+ name=tr_new_name(json_string_value(jname));
+ if (name==NULL) {
+ tr_err("tr_cfg_parse_name: could not allocate name");
+ *rc=TR_CFG_NOMEM;
+ } else {
+ *rc=TR_CFG_SUCCESS;
}
+ }
+ return name;
+}
- for (i = 0; i < json_array_size(jrps); i++) {
- if (NULL == (rp = tr_cfg_parse_one_rp_client(trc,
- json_array_get(jrps, i),
- &rc))) {
- return rc;
- }
- tr_debug("tr_cfg_parse_rp_clients: RP client configured -- first gss: %s", rp->gss_names[0]->buf);
- rp->next = trc->rp_clients;
- trc->rp_clients = rp;
- }
+static int tr_cfg_parse_shared_config(json_t *jsc, TR_CFG_RC *rc)
+{
+ const char *shared=NULL;
+ *rc=TR_CFG_SUCCESS;
+
+ if ((jsc==NULL) ||
+ (!json_is_string(jsc)) ||
+ (NULL==(shared=json_string_value(jsc)))) {
+ *rc=TR_CFG_BAD_PARAMS;
+ return -1;
+ }
+
+ if (0==strcmp(shared, "no"))
+ return 0;
+ else if (0==strcmp(shared, "yes"))
+ return 1;
+
+ /* any other value is an error */
+ tr_debug("tr_cfg_parse_shared_config: invalid shared_config value \"%s\" (should be \"yes\" or \"no\")",
+ shared);
+ *rc=TR_CFG_NOPARSE;
+ return -1;
+}
+
+static TR_REALM_ORIGIN tr_cfg_realm_origin(json_t *jrealm)
+{
+ json_t *jremote=json_object_get(jrealm, "remote");
+ const char *s=NULL;
+
+ if (jremote==NULL)
+ return TR_REALM_LOCAL;
+ if (!json_is_string(jremote)) {
+ tr_warning("tr_cfg_realm_origin: \"remote\" is not a string, assuming this is a local realm.");
+ return TR_REALM_LOCAL;
+ }
+ s=json_string_value(jremote);
+ if (strcasecmp(s, "yes")==0)
+ return TR_REALM_REMOTE_INCOMPLETE;
+ else if (strcasecmp(s, "no")!=0)
+ tr_warning("tr_cfg_realm_origin: \"remote\" is neither 'yes' nor 'no', assuming this is a local realm.");
+
+ return TR_REALM_LOCAL;
+}
+
+/* Parse the identity provider object from a realm and fill in the given TR_IDP_REALM. */
+static TR_CFG_RC tr_cfg_parse_idp(TR_IDP_REALM *idp, json_t *jidp)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_APC *apcs=NULL;
+ TR_AAA_SERVER *aaa=NULL;
+ TR_CFG_RC rc=TR_CFG_ERROR;
+
+ if (jidp==NULL)
+ goto cleanup;
+
+ idp->shared_config=tr_cfg_parse_shared_config(json_object_get(jidp, "shared_config"), &rc);
+ if (rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_idp: missing or malformed shared_config specification");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ apcs=tr_cfg_parse_apcs(tmp_ctx, json_object_get(jidp, "apcs"), &rc);
+ if ((rc!=TR_CFG_SUCCESS) || (apcs==NULL)) {
+ tr_err("tr_cfg_parse_idp: unable to parse APC");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ aaa=tr_cfg_parse_aaa_servers(idp, json_object_get(jidp, "aaa_servers"), &rc);
+ if (rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_idp: unable to parse AAA servers");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ tr_debug("tr_cfg_parse_idp: APC=\"%.*s\"",
+ apcs->id->len,
+ apcs->id->buf);
+
+ /* done, fill in the idp structures */
+ idp->apcs=apcs;
+ talloc_steal(idp, apcs);
+ idp->aaa_servers=aaa;
+ rc=TR_CFG_SUCCESS;
+
+cleanup:
+ if (rc!=TR_CFG_SUCCESS) {
+ if (apcs!=NULL)
+ tr_apc_free(apcs);
+ if (aaa!=NULL)
+ tr_aaa_server_free(aaa);
}
+
+ talloc_free(tmp_ctx);
return rc;
}
-static TR_AAA_SERVER *tr_cfg_parse_one_aaa_server (TR_CFG *trc, json_t *jaddr, TR_CFG_RC *rc) {
- TR_AAA_SERVER *aaa = NULL;
+/* parses idp realm */
+static TR_IDP_REALM *tr_cfg_parse_one_idp_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_IDP_REALM *realm=NULL;
+ TR_CFG_RC call_rc=TR_CFG_ERROR;
- if ((!trc) || (!jaddr) || (!json_is_string(jaddr))) {
- tr_debug("tr_cfg_parse_one_aaa_server: Bad parameters.");
- *rc = TR_CFG_BAD_PARAMS;
- return NULL;
+ *rc=TR_CFG_ERROR; /* default to error if not set */
+
+ if ((!jrealm) || (!rc)) {
+ tr_err("tr_cfg_parse_one_idp_realm: Bad parameters.");
+ if (rc)
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) {
+ tr_err("tr_cfg_parse_one_idp_realm: could not allocate idp realm.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ realm->origin=tr_cfg_realm_origin(jrealm);
+ if (realm->origin!=TR_REALM_LOCAL) {
+ tr_debug("tr_cfg_parse_one_idp_realm: realm is remote, should not have full IdP info.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ /* must have a name */
+ realm->realm_id=tr_cfg_parse_name(realm,
+ json_object_get(jrealm, "realm"),
+ &call_rc);
+ if ((call_rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) {
+ tr_err("tr_cfg_parse_one_idp_realm: could not parse realm name");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ tr_debug("tr_cfg_parse_one_idp_realm: realm_id=\"%.*s\"",
+ realm->realm_id->len,
+ realm->realm_id->buf);
+
+ call_rc=tr_cfg_parse_idp(realm, json_object_get(jrealm, "identity_provider"));
+ if (call_rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_one_idp_realm: could not parse identity_provider.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
}
+
+ *rc=TR_CFG_SUCCESS;
- if (NULL == (aaa = talloc(trc, TR_AAA_SERVER))) {
- tr_debug("tr_cfg_parse_one_aaa_server: Out of memory.");
- *rc = TR_CFG_NOMEM;
- return NULL;
+cleanup:
+ if (*rc==TR_CFG_SUCCESS)
+ talloc_steal(mem_ctx, realm);
+ else {
+ talloc_free(realm);
+ realm=NULL;
}
+
+ talloc_free(tmp_ctx);
+ return realm;
+}
- memset(aaa, 0, sizeof(TR_AAA_SERVER));
+ /* Determine whether the realm is an IDP realm */
+static int tr_cfg_is_idp_realm(json_t *jrealm)
+{
+ /* If a realm spec contains an identity_provider, it's an IDP realm. */
+ if (NULL != json_object_get(jrealm, "identity_provider"))
+ return 1;
+ else
+ return 0;
+}
- aaa->hostname = tr_new_name((char *)(json_string_value(jaddr)));
+static TR_IDP_REALM *tr_cfg_parse_one_remote_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_IDP_REALM *realm=talloc(mem_ctx, TR_IDP_REALM);
+
+ *rc=TR_CFG_ERROR; /* default to error if not set */
- return aaa;
+ if ((!jrealm) || (!rc)) {
+ tr_err("tr_cfg_parse_one_remote_realm: Bad parameters.");
+ if (rc)
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) {
+ tr_err("tr_cfg_parse_one_remote_realm: could not allocate idp realm.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ /* must have a name */
+ realm->realm_id=tr_cfg_parse_name(realm,
+ json_object_get(jrealm, "realm"),
+ rc);
+ if ((*rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) {
+ tr_err("tr_cfg_parse_one_remote_realm: could not parse realm name");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ tr_debug("tr_cfg_parse_one_remote_realm: realm_id=\"%.*s\"",
+ realm->realm_id->len,
+ realm->realm_id->buf);
+
+ realm->origin=tr_cfg_realm_origin(jrealm);
+ *rc=TR_CFG_SUCCESS;
+
+cleanup:
+ if (*rc==TR_CFG_SUCCESS)
+ talloc_steal(mem_ctx, realm);
+ else {
+ talloc_free(realm);
+ realm=NULL;
+ }
+
+ talloc_free(tmp_ctx);
+ return realm;
}
-static TR_AAA_SERVER *tr_cfg_parse_aaa_servers (TR_CFG *trc, json_t *jaaas, TR_CFG_RC *rc)
+static int tr_cfg_is_remote_realm(json_t *jrealm)
{
- TR_AAA_SERVER *aaa = NULL;
- TR_AAA_SERVER *temp_aaa = NULL;
- int i = 0;
+ return (tr_cfg_realm_origin(jrealm)!=TR_REALM_LOCAL);
+}
- for (i = 0; i < json_array_size(jaaas); i++) {
- if (NULL == (temp_aaa = tr_cfg_parse_one_aaa_server(trc, json_array_get(jaaas, i), rc))) {
- return NULL;
+/* Parse any idp realms in the j_realms object. Ignores other realm types. */
+static TR_IDP_REALM *tr_cfg_parse_idp_realms(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_IDP_REALM *realms=NULL;
+ TR_IDP_REALM *new_realm=NULL;
+ json_t *this_jrealm=NULL;
+ int ii=0;
+
+ *rc=TR_CFG_ERROR;
+ if ((jrealms==NULL) || (!json_is_array(jrealms))) {
+ tr_err("tr_cfg_parse_idp_realms: realms not an array");
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ for (ii=0; ii<json_array_size(jrealms); ii++) {
+ this_jrealm=json_array_get(jrealms, ii);
+ if (tr_cfg_is_idp_realm(this_jrealm)) {
+ new_realm=tr_cfg_parse_one_idp_realm(tmp_ctx, this_jrealm, rc);
+ if ((*rc)!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_idp_realms: error decoding realm entry %d", ii+1);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ realms=tr_idp_realm_add(realms, new_realm);
+ } else if (tr_cfg_is_remote_realm(this_jrealm)) {
+ new_realm=tr_cfg_parse_one_remote_realm(tmp_ctx, this_jrealm, rc);
+ if ((*rc)!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_idp_realms: error decoding remote realm entry %d", ii+1);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ realms=tr_idp_realm_add(realms, new_realm);
}
- /* TBD -- IPv6 addresses */
- // tr_debug("tr_cfg_parse_aaa_servers: Configuring AAA Server: ip_addr = %s.", inet_ntoa(temp_aaa->aaa_server_addr));
- temp_aaa->next = aaa;
- aaa = temp_aaa;
}
- return aaa;
+
+ *rc=TR_CFG_SUCCESS;
+ talloc_steal(mem_ctx, realms);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return realms;
}
-static TR_APC *tr_cfg_parse_apcs (TR_CFG *trc, json_t *japcs, TR_CFG_RC *rc)
+#if 0
+static TR_IDP_REALM *tr_cfg_parse_remote_realms(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc)
{
- TR_APC *apc;
+ 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);
- *rc = TR_CFG_SUCCESS; /* presume success */
+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);
+ TR_GSS_NAMES *gn=NULL;
+ json_t *jname=NULL;
+ int ii=0;
+ TR_NAME *name=NULL;
+
+ if ((rc==NULL) || (jgss_names==NULL)) {
+ tr_err("tr_cfg_parse_gss_names: Bad parameters.");
+ *rc=TR_CFG_BAD_PARAMS;
- if ((!trc) || (!japcs) || (!rc)) {
- tr_debug("tr_cfg_parse_apcs: Bad parameters.");
- if (rc)
- *rc = TR_CFG_BAD_PARAMS;
- return NULL;
}
- if (NULL == (apc = talloc(trc, TR_APC))) {
- tr_debug("tr_cfg_parse_apcs: Out of memory.");
- *rc = TR_CFG_NOMEM;
- return NULL;
+ if (!json_is_array(jgss_names)) {
+ tr_err("tr_cfg_parse_gss_names: gss_names not an array.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
}
- memset(apc, 0, sizeof(TR_APC));
+ gn=tr_gss_names_new(tmp_ctx);
+ for (ii=0; ii<json_array_size(jgss_names); ii++) {
+ jname=json_array_get(jgss_names, ii);
+ if (!json_is_string(jname)) {
+ tr_err("tr_cfg_parse_gss_names: Encountered non-string gss name.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
- /* TBD, deal with more than one APC. In the meantime, though... */
- /* Only parse the first APC, because we only know how to deal with one, anyway. */
- if (0 == json_array_size(japcs))
- return NULL;
+ name=tr_new_name(json_string_value(jname));
+ if (name==NULL) {
+ tr_err("tr_cfg_parse_gss_names: Out of memory allocating gss name.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
- if (NULL == (apc->id = tr_new_name((char *)json_string_value(json_array_get(japcs, 0))))) {
- tr_debug("tr_cfg_parse_apcs: No memory for APC name.");
- *rc = TR_CFG_NOMEM;
- return NULL;
+ if (tr_gss_names_add(gn, name)!=0) {
+ tr_free_name(name);
+ tr_err("tr_cfg_parse_gss_names: Unable to add gss name to RP client.");
+ *rc=TR_CFG_ERROR;
+ goto cleanup;
+ }
}
- return apc;
+ talloc_steal(mem_ctx, gn);
+ *rc=TR_CFG_SUCCESS;
+
+ cleanup:
+ talloc_free(tmp_ctx);
+ if ((*rc!=TR_CFG_SUCCESS) && (gn!=NULL))
+ gn=NULL;
+ return gn;
}
-static TR_IDP_REALM *tr_cfg_parse_one_idp_realm (TR_CFG *trc, json_t *jidp, TR_CFG_RC *rc) {
- TR_IDP_REALM *idp = NULL;
- json_t *jrid = NULL;
- json_t *jscfg = NULL;
- json_t *jsrvrs = NULL;
- json_t *japcs = NULL;
+/* default filter accepts realm and *.realm */
+static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_FILTER *filt=NULL;
+ TR_CONSTRAINT *cons=NULL;
+ TR_NAME *name=NULL;
+ TR_NAME *n_prefix=tr_new_name("*.");
+ TR_NAME *n_rp_realm=tr_new_name("rp_realm");
+ TR_NAME *n_domain=tr_new_name("domain");
+ TR_NAME *n_realm=tr_new_name("realm");
+
+
+ if ((realm==NULL) || (rc==NULL)) {
+ tr_debug("tr_cfg_default_filter: invalid arguments.");
+ if (rc!=NULL)
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ if ((n_prefix==NULL) || (n_rp_realm==NULL) || (n_domain==NULL) || (n_realm==NULL)) {
+ tr_debug("tr_cfg_default_filter: unable to allocate names.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ filt=tr_filter_new(tmp_ctx);
+ if (filt==NULL) {
+ tr_debug("tr_cfg_default_filter: could not allocate filter.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ tr_filter_set_type(filt, TR_FILTER_TYPE_TID_INCOMING);
+ filt->lines[0]=tr_fline_new(filt);
+ if (filt->lines[0]==NULL) {
+ tr_debug("tr_cfg_default_filter: could not allocate filter line.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ filt->lines[0]->action=TR_FILTER_ACTION_ACCEPT;
+ filt->lines[0]->specs[0]=tr_fspec_new(filt->lines[0]);
+ filt->lines[0]->specs[0]->field=n_rp_realm;
+ n_rp_realm=NULL; /* we don't own this name any more */
+
+ name=tr_dup_name(realm);
+ if (name==NULL) {
+ tr_debug("tr_cfg_default_filter: could not allocate realm name.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ if (0!=tr_fspec_add_match(filt->lines[0]->specs[0], name)) {
+ tr_debug("tr_cfg_default_filter: could not add realm name to filter spec.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ name=NULL; /* we no longer own the name */
+
+ if (NULL==(name=tr_name_cat(n_prefix, realm))) {
+ tr_debug("tr_cfg_default_filter: could not allocate wildcard realm name.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ if (0!=tr_fspec_add_match(filt->lines[0]->specs[0], name)) {
+ tr_debug("tr_cfg_default_filter: could not add wildcard realm name to filter spec.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ name=NULL; /* we no longer own the name */
+
+ /* domain constraint */
+ if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
+ tr_debug("tr_cfg_default_filter: could not allocate domain constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ cons->type=n_domain;
+ n_domain=NULL; /* belongs to the constraint now */
+ name=tr_dup_name(realm);
+ if (name==NULL) {
+ tr_debug("tr_cfg_default_filter: could not allocate realm name for domain constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ cons->matches[0]=name;
+ name=tr_name_cat(n_prefix, realm);
+ if (name==NULL) {
+ tr_debug("tr_cfg_default_filter: could not allocate wildcard realm name for domain constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ cons->matches[1]=name;
+ name=NULL;
+ filt->lines[0]->domain_cons=cons;
+
+
+ /* realm constraint */
+ if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
+ tr_debug("tr_cfg_default_filter: could not allocate realm constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ cons->type=n_realm;
+ n_realm=NULL; /* belongs to the constraint now */
+ name=tr_dup_name(realm);
+ if (name==NULL) {
+ tr_debug("tr_cfg_default_filter: could not allocate realm name for realm constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ cons->matches[0]=name;
+ name=tr_name_cat(n_prefix, realm);
+ if (name==NULL) {
+ tr_debug("tr_cfg_default_filter: could not allocate wildcard realm name for realm constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ cons->matches[1]=name;
+ name=NULL;
+ filt->lines[0]->realm_cons=cons;
+
+ talloc_steal(mem_ctx, filt);
+cleanup:
+ talloc_free(tmp_ctx);
+
+ if (*rc!=TR_CFG_SUCCESS)
+ filt=NULL;
+
+ if (n_prefix!=NULL)
+ tr_free_name(n_prefix);
+ if (n_rp_realm!=NULL)
+ tr_free_name(n_rp_realm);
+ if (n_realm!=NULL)
+ tr_free_name(n_realm);
+ if (n_domain!=NULL)
+ tr_free_name(n_domain);
+ if (name!=NULL)
+ tr_free_name(name);
- if ((!trc) || (!jidp) || (!rc)) {
- tr_debug("tr_cfg_parse_one_idp_realm: Bad parameters.");
+ return filt;
+}
+
+/* parses rp client */
+static TR_RP_CLIENT *tr_cfg_parse_one_rp_client(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_RP_CLIENT *client=NULL;
+ TR_CFG_RC call_rc=TR_CFG_ERROR;
+ TR_FILTER *new_filt=NULL;
+ TR_NAME *realm=NULL;
+ json_t *jfilt=NULL;
+ json_t *jrealm_id=NULL;
+
+ *rc=TR_CFG_ERROR; /* default to error if not set */
+
+ if ((!jrealm) || (!rc)) {
+ tr_err("tr_cfg_parse_one_rp_client: Bad parameters.");
if (rc)
- *rc = TR_CFG_BAD_PARAMS;
- return NULL;
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
}
- if (NULL == (idp = talloc(trc, TR_IDP_REALM))) {
- tr_debug("tr_cfg_parse_one_idp_realm: Out of memory.");
- *rc = TR_CFG_NOMEM;
- return NULL;
+ if ((NULL==(jrealm_id=json_object_get(jrealm, "realm"))) || (!json_is_string(jrealm_id))) {
+ tr_debug("tr_cfg_parse_one_rp_client: no realm ID found.");
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ tr_debug("tr_cfg_parse_one_rp_client: realm_id=\"%s\"", json_string_value(jrealm_id));
+ realm=tr_new_name(json_string_value(jrealm_id));
+ if (realm==NULL) {
+ tr_err("tr_cfg_parse_one_rp_client: could not allocate realm ID.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
}
- memset(idp, 0, sizeof(TR_IDP_REALM));
+ if (NULL==(client=tr_rp_client_new(tmp_ctx))) {
+ tr_err("tr_cfg_parse_one_rp_client: could not allocate rp client.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
- if ((NULL == (jrid = json_object_get(jidp, "realm_id"))) ||
- (!json_is_string(jrid)) ||
- (NULL == (jscfg = json_object_get(jidp, "shared_config"))) ||
- (!json_is_string(jscfg)) ||
- (NULL == (jsrvrs = json_object_get(jidp, "aaa_servers"))) ||
- (!json_is_array(jsrvrs))) {
- tr_debug("tr_cfg_parse_one_idp_realm: Error parsing IDP realm configuration.");
- *rc = TR_CFG_NOPARSE;
- return NULL;
+ client->gss_names=tr_cfg_parse_gss_names(client, json_object_get(jrealm, "gss_names"), &call_rc);
+
+ if (call_rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_one_rp_client: could not parse gss_names.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
}
- if (0 == strcmp(json_string_value(jscfg), "no")) {
- idp->shared_config = 0;
+ /* parse filters */
+ jfilt=json_object_get(jrealm, "filters");
+ if (jfilt!=NULL) {
+ new_filt=tr_cfg_parse_filters(tmp_ctx, jfilt, &call_rc);
+ if (call_rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_one_rp_client: could not parse filters.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
} else {
- idp->shared_config = 1;
+ tr_debug("tr_cfg_parse_one_rp_client: no filters specified, using default filters.");
+ new_filt=tr_cfg_default_filter(tmp_ctx, realm, &call_rc);
+ if (call_rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_one_rp_client: could not set default filters.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
}
- if (NULL == (idp->realm_id = tr_new_name((char *)json_string_value(jrid)))) {
- tr_debug("tr_cfg_parse_one_idp_realm: No memory for realm id.");
- *rc = TR_CFG_NOMEM;
- return NULL;
+ tr_rp_client_set_filter(client, new_filt);
+ *rc=TR_CFG_SUCCESS;
+
+ cleanup:
+ if (realm!=NULL)
+ tr_free_name(realm);
+
+ if (*rc==TR_CFG_SUCCESS)
+ talloc_steal(mem_ctx, client);
+ else {
+ talloc_free(client);
+ client=NULL;
+ }
+
+ talloc_free(tmp_ctx);
+ return client;
+ }
+
+ /* Determine whether the realm is an RP realm */
+static int tr_cfg_is_rp_realm(json_t *jrealm)
+{
+ /* Check that we have a gss name. */
+ if (NULL != json_object_get(jrealm, "gss_names"))
+ return 1;
+ else
+ return 0;
+}
+
+/* Parse any rp clients in the j_realms object. Ignores other realms. */
+static TR_RP_CLIENT *tr_cfg_parse_rp_clients(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_RP_CLIENT *clients=NULL;
+ TR_RP_CLIENT *new_client=NULL;
+ json_t *this_jrealm=NULL;
+ int ii=0;
+
+ *rc=TR_CFG_ERROR;
+ if ((jrealms==NULL) || (!json_is_array(jrealms))) {
+ tr_err("tr_cfg_parse_rp_clients: realms not an array");
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ for (ii=0; ii<json_array_size(jrealms); ii++) {
+ this_jrealm=json_array_get(jrealms, ii);
+ if (tr_cfg_is_rp_realm(this_jrealm)) {
+ new_client=tr_cfg_parse_one_rp_client(tmp_ctx, this_jrealm, rc);
+ if ((*rc)!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_rp_clients: error decoding realm entry %d", ii+1);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ clients=tr_rp_client_add(clients, new_client);
+ }
}
+
+ *rc=TR_CFG_SUCCESS;
+ talloc_steal(mem_ctx, clients);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return clients;
+}
+
+/* takes a talloc context, but currently does not use it */
+static TR_NAME *tr_cfg_parse_org_name(TALLOC_CTX *mem_ctx, json_t *j_org, TR_CFG_RC *rc)
+{
+ TR_NAME *name=NULL;
- if (NULL == (idp->aaa_servers = tr_cfg_parse_aaa_servers(trc, jsrvrs, rc))) {
- tr_debug("tr_cfg_parse_one_idp_realm: Can't parse AAA servers for realm %s.", idp->realm_id->buf);
- tr_free_name(idp->realm_id);
+ if ((j_org==NULL) || (rc==NULL) || (!json_is_string(j_org))) {
+ tr_debug("tr_cfg_parse_org_name: Bad parameters.");
+ if (rc!=NULL)
+ *rc = TR_CFG_BAD_PARAMS; /* fill in return value if we can */
return NULL;
}
- if ((NULL != (japcs = json_object_get(jidp, "apcs"))) &&
- (json_is_array(japcs))) {
- if (NULL == (idp->apcs = tr_cfg_parse_apcs(trc, japcs, rc))) {
- tr_debug("tr_cfg_parse_one_idp_realm: Can't parse APCs for realm %s .", idp->realm_id->buf);
- tr_free_name(idp->realm_id);
- /* TBD -- free aaa_servers */;
- return NULL;
+ name=tr_new_name(json_string_value(j_org));
+ if (name==NULL)
+ *rc=TR_CFG_NOMEM;
+ else
+ *rc=TR_CFG_SUCCESS;
+ return name;
+}
+
+#if 0
+/* 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)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_COMM *comm=NULL; /* community looked up in comms table */
+ TR_COMM *new_comms=NULL; /* new communities as we create them */
+ TR_IDP_REALM *realm=NULL;
+ TR_APC *apc=NULL; /* apc of one realm */
+
+ if (rc==NULL) {
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ /* start with an empty list communities, then fill that in */
+ for (realm=new_realms; realm!=NULL; realm=realm->next) {
+ for (apc=realm->apcs; apc!=NULL; apc=apc->next) {
+ comm=tr_comm_lookup(comms, apc->id);
+ if (comm==NULL) {
+ comm=tr_comm_new(tmp_ctx);
+ if (comm==NULL) {
+ tr_debug("tr_cfg_comm_idp_update: unable to allocate new community.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ /* 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_add_idp_realm(comm, realm);
+ new_comms=tr_comm_add(new_comms, comm);
+ } else {
+ /* add this realm to the comm */
+ tr_comm_add_idp_realm(comm, realm);
+ }
}
- }
- return idp;
+ }
+
+ /* we successfully built a list, add it to the other list */
+ comms=tr_comm_add(comms, new_comms);
+ talloc_steal(mem_ctx, comms);
+ cleanup:
+ talloc_free(tmp_ctx);
+ return comms;
}
+#endif
+static TR_CFG_RC tr_cfg_parse_one_local_org(TR_CFG *trc, json_t *jlorg)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_CFG_RC retval=TR_CFG_ERROR; /* our return code */
+ TR_CFG_RC rc=TR_CFG_ERROR; /* return code from functions we call */
+ TR_NAME *org_name=NULL;
+ json_t *j_org=NULL;
+ json_t *j_realms=NULL;
+ TR_IDP_REALM *new_idp_realms=NULL;
+ TR_RP_CLIENT *new_rp_clients=NULL;
+
+ tr_debug("tr_cfg_parse_one_local_org: parsing local organization");
+
+ /* get organization_name (optional) */
+ if (NULL==(j_org=json_object_get(jlorg, "organization_name"))) {
+ tr_debug("tr_cfg_parse_one_local_org: organization_name unspecified");
+ } else {
+ org_name=tr_cfg_parse_org_name(tmp_ctx, j_org, &rc);
+ if (rc==TR_CFG_SUCCESS) {
+ tr_debug("tr_cfg_parse_one_local_org: organization_name=\"%.*s\"",
+ org_name->len,
+ org_name->buf);
+ /* we don't actually do anything with this, but we could */
+ tr_free_name(org_name);
+ org_name=NULL;
+ }
+ }
+
+ /* Now get realms. Allow this to be missing; even though that is a pointless organization entry,
+ * it's harmless. Report a warning because that might be unintentional. */
+ if (NULL==(j_realms=json_object_get(jlorg, "realms"))) {
+ tr_warning("tr_cfg_parse_one_local_org: warning - no realms in this local organization");
+ } else {
+ /* Allocate in the tmp_ctx so these will be cleaned up if we do not complete successfully. */
+ new_idp_realms=tr_cfg_parse_idp_realms(tmp_ctx, j_realms, &rc);
+ if (rc!=TR_CFG_SUCCESS)
+ goto cleanup;
+
+ new_rp_clients=tr_cfg_parse_rp_clients(tmp_ctx, j_realms, &rc);
+ if (rc!=TR_CFG_SUCCESS)
+ goto cleanup;
+ }
+ retval=TR_CFG_SUCCESS;
+
+cleanup:
+ /* if we succeeded, link things to the configuration and move out of tmp context */
+ if (retval==TR_CFG_SUCCESS) {
+ if (new_idp_realms!=NULL) {
+ 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 */
+ }
+
+ if (new_rp_clients!=NULL) {
+ trc->rp_clients=tr_rp_client_add(trc->rp_clients, new_rp_clients); /* fixes talloc contexts */
+ talloc_steal(trc, trc->rp_clients); /* make sure head is in the right context */
+ }
+ }
+
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+/* Parse local organizations if present. Returns success if there are none. On failure, the configuration is unreliable. */
+static TR_CFG_RC tr_cfg_parse_local_orgs(TR_CFG *trc, json_t *jcfg)
+{
+ json_t *jlocorgs=NULL;
+ int ii=0;
+
+ jlocorgs=json_object_get(jcfg, "local_organizations");
+ if (jlocorgs==NULL)
+ return TR_CFG_SUCCESS;
+
+ if (!json_is_array(jlocorgs)) {
+ tr_err("tr_cfg_parse_local_orgs: local_organizations is not an array.");
+ return TR_CFG_NOPARSE;
+ }
+
+ for (ii=0; ii<json_array_size(jlocorgs); ii++) {
+ if (tr_cfg_parse_one_local_org(trc, json_array_get(jlocorgs, ii))!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_local_orgs: error parsing local_organization %d.", ii+1);
+ return TR_CFG_NOPARSE;
+ }
+ }
+
+ return TR_CFG_SUCCESS;
+}
+
+static TR_CFG_RC tr_cfg_parse_one_peer_org(TR_CFG *trc, json_t *jporg)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ json_t *jhost=NULL;
+ json_t *jport=NULL;
+ json_t *jgss=NULL;
+ TRP_PEER *new_peer=NULL;
+ TR_GSS_NAMES *names=NULL;
+ TR_CFG_RC rc=TR_CFG_ERROR;
+
+ jhost=json_object_get(jporg, "hostname");
+ jport=json_object_get(jporg, "port");
+ jgss=json_object_get(jporg, "gss_names");
+
+ if ((jhost==NULL) || (!json_is_string(jhost))) {
+ tr_err("tr_cfg_parse_one_peer_org: hostname not specified or not a string.");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ if ((jport!=NULL) && (!json_is_number(jport))) {
+ /* note that not specifying the port is allowed, but if set it must be a number */
+ tr_err("tr_cfg_parse_one_peer_org: port is not a number.");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ if ((jgss==NULL) || (!json_is_array(jgss))) {
+ tr_err("tr_cfg_parse_one_peer_org: gss_names not specified or not an array.");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ new_peer=trp_peer_new(tmp_ctx);
+ if (new_peer==NULL) {
+ tr_err("tr_cfg_parse_one_peer_org: could not allocate new peer.");
+ rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ trp_peer_set_server(new_peer, json_string_value(jhost));
+ if (jport==NULL)
+ trp_peer_set_port(new_peer, TRP_PORT);
+ else
+ trp_peer_set_port(new_peer, json_integer_value(jport));
+
+ names=tr_cfg_parse_gss_names(tmp_ctx, jgss, &rc);
+ if (rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_one_peer_org: unable to parse gss names.");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ trp_peer_set_gss_names(new_peer, names);
+
+ /* success! */
+ trp_ptable_add(trc->peers, new_peer);
+ rc=TR_CFG_SUCCESS;
+
+ cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+/* Parse peer organizations, if present. Returns success if there are none. */
+static TR_CFG_RC tr_cfg_parse_peer_orgs(TR_CFG *trc, json_t *jcfg)
+{
+ json_t *jpeerorgs=NULL;
+ int ii=0;
+
+ jpeerorgs=json_object_get(jcfg, "peer_organizations");
+ if (jpeerorgs==NULL)
+ return TR_CFG_SUCCESS;
+
+ if (!json_is_array(jpeerorgs)) {
+ tr_err("tr_cfg_parse_peer_orgs: peer_organizations is not an array.");
+ return TR_CFG_NOPARSE;
+ }
+
+ for (ii=0; ii<json_array_size(jpeerorgs); ii++) {
+ if (tr_cfg_parse_one_peer_org(trc, json_array_get(jpeerorgs, ii))!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_peer_orgs: error parsing peer_organization %d.", ii+1);
+ return TR_CFG_NOPARSE;
+ }
+ }
+
+ return TR_CFG_SUCCESS;
+}
+
static TR_CFG_RC tr_cfg_parse_default_servers (TR_CFG *trc, json_t *jcfg)
{
json_t *jdss = NULL;
(0 < json_array_size(jdss))) {
for (i = 0; i < json_array_size(jdss); i++) {
- if (NULL == (ds = tr_cfg_parse_one_aaa_server(trc,
- json_array_get(jdss, i),
- &rc))) {
+ if (NULL == (ds = tr_cfg_parse_one_aaa_server(trc,
+ json_array_get(jdss, i),
+ &rc))) {
return rc;
}
tr_debug("tr_cfg_parse_default_servers: Default server configured: %s", ds->hostname->buf);
}
}
- return rc;
-}
-
-static TR_CFG_RC tr_cfg_parse_idp_realms (TR_CFG *trc, json_t *jcfg)
-{
- json_t *jidps = NULL;
- TR_CFG_RC rc = TR_CFG_SUCCESS;
- TR_IDP_REALM *idp = NULL;
- int i = 0;
-
- if ((!trc) || (!jcfg))
- return TR_CFG_BAD_PARAMS;
-
- /* If there are any IDP Realms, parse them */
- if ((NULL != (jidps = json_object_get(jcfg, "idp_realms"))) &&
- (json_is_array(jidps))) {
- for (i = 0; i < json_array_size(jidps); i++) {
- if (NULL == (idp = tr_cfg_parse_one_idp_realm(trc,
- json_array_get(jidps, i),
- &rc))) {
- return rc;
- }
- tr_debug("tr_cfg_parse_idp_realms: IDP realm configured: %s.", idp->realm_id->buf);
- idp->next = trc->idp_realms;
- trc->idp_realms = idp;
- }
- }
-
+ tr_debug("tr_cfg_parse_default_servers: Finished (rc=%d)", rc);
return rc;
}
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;
+ *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)))) {
+ tr_new_name((char *)json_string_value(json_array_get(jidps, i))),
+ rc)))) {
tr_debug("tr_cfg_parse_comm_idps: Unknown IDP %s.",
- (char *)json_string_value(json_array_get(jidps, i)));
+ (char *)json_string_value(json_array_get(jidps, i)));
return NULL;
}
}
for (i = (json_array_size(jrps)-1); i >= 0; i--) {
- if (NULL == (temp_rp = talloc(trc, TR_RP_REALM))) {
+ 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;
}
- memset (temp_rp, 0, sizeof(TR_RP_REALM));
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.");
trc->comms = comm;
}
}
+ tr_debug("tr_cfg_parse_comms: Finished (rc=%d)", rc);
return rc;
}
-TR_CFG_RC tr_cfg_validate (TR_CFG *trc) {
+TR_CFG_RC tr_cfg_validate(TR_CFG *trc)
+{
TR_CFG_RC rc = TR_CFG_SUCCESS;
if (!trc)
/* Join two paths and return a pointer to the result. This should be freed
* via talloc_free. Returns NULL on failure. */
-static char *join_paths(const char *p1, const char *p2) {
- return talloc_asprintf(NULL, "%s/%s", p1, p2); /* returns NULL on a failure */
+static char *join_paths(TALLOC_CTX *mem_ctx, const char *p1, const char *p2)
+{
+ return talloc_asprintf(mem_ctx, "%s/%s", p1, p2); /* returns NULL on a failure */
+}
+
+static void tr_cfg_log_json_error(const char *label, json_error_t *rc)
+{
+ tr_debug("%s: JSON parse error on line %d: %s",
+ label,
+ rc->line,
+ rc->text);
}
-/* Reads configuration files in config_dir ("" or "./" will use the current directory) */
-TR_CFG_RC tr_parse_config (TR_INSTANCE *tr, const char *config_dir, int n, struct dirent **cfg_files) {
- json_t *jcfg;
- json_t *jser;
+TR_CFG_RC tr_cfg_parse_one_config_file(TR_CFG *cfg, const char *file_with_path)
+{
+ json_t *jcfg=NULL;
+ json_t *jser=NULL;
json_error_t rc;
+
+ if (NULL==(jcfg=json_load_file(file_with_path,
+ JSON_DISABLE_EOF_CHECK, &rc))) {
+ tr_debug("tr_cfg_parse_one_config_file: Error parsing config file %s.",
+ file_with_path);
+ tr_cfg_log_json_error("tr_cfg_parse_one_config_file", &rc);
+ return TR_CFG_NOPARSE;
+ }
+
+ // Look for serial number and log it if it exists
+ if (NULL!=(jser=json_object_get(jcfg, "serial_number"))) {
+ if (json_is_number(jser)) {
+ tr_notice("tr_parse_one_config_file: Attempting to load revision %" JSON_INTEGER_FORMAT " of '%s'.",
+ json_integer_value(jser),
+ file_with_path);
+ }
+ }
+
+ if ((TR_CFG_SUCCESS != tr_cfg_parse_internal(cfg, jcfg)) ||
+ (TR_CFG_SUCCESS != tr_cfg_parse_local_orgs(cfg, jcfg)) ||
+ (TR_CFG_SUCCESS != tr_cfg_parse_peer_orgs(cfg, jcfg)) ||
+ (TR_CFG_SUCCESS != tr_cfg_parse_default_servers(cfg, jcfg)) ||
+ (TR_CFG_SUCCESS != tr_cfg_parse_comms(cfg, jcfg)))
+ return TR_CFG_ERROR;
+
+ return TR_CFG_SUCCESS;
+}
+
+/* Reads configuration files in config_dir ("" or "./" will use the current directory). */
+TR_CFG_RC tr_parse_config(TR_CFG_MGR *cfg_mgr, const char *config_dir, int n, struct dirent **cfg_files)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
char *file_with_path;
+ int ii;
+ TR_CFG_RC cfg_rc=TR_CFG_ERROR;
- if ((!tr) || (!cfg_files) || (n<=0))
- return TR_CFG_BAD_PARAMS;
+ if ((!cfg_mgr) || (!cfg_files) || (n<=0)) {
+ cfg_rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
- /* If there is a partial/abandoned config lying around, free it */
- if (tr->new_cfg)
- tr_cfg_free(tr->new_cfg);
-
- if (NULL == (tr->new_cfg = talloc(NULL, TR_CFG)))
- return TR_CFG_NOMEM;
+ if (cfg_mgr->new != NULL)
+ tr_cfg_free(cfg_mgr->new);
+ cfg_mgr->new=tr_cfg_new(tmp_ctx); /* belongs to the temporary context for now */
+ if (cfg_mgr->new == NULL) {
+ cfg_rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
- memset(tr->new_cfg, 0, sizeof(TR_CFG));
+ cfg_mgr->new->peers=trp_ptable_new(cfg_mgr);
/* Parse configuration information from each config file */
- while (n--) {
- file_with_path=join_paths(config_dir, cfg_files[n]->d_name); /* must free result with talloc_free */
+ for (ii=0; ii<n; ii++) {
+ file_with_path=join_paths(tmp_ctx, config_dir, cfg_files[ii]->d_name); /* must free result with talloc_free */
if(file_with_path == NULL) {
tr_crit("tr_parse_config: error joining path.");
- return TR_CFG_NOMEM;
+ cfg_rc=TR_CFG_NOMEM;
+ goto cleanup;
}
- tr_debug("tr_parse_config: Parsing %s.", cfg_files[n]->d_name); /* print the filename without the path */
- if (NULL == (jcfg = json_load_file(file_with_path,
- JSON_DISABLE_EOF_CHECK, &rc))) {
- tr_debug("tr_parse_config: Error parsing config file %s.",
- cfg_files[n]->d_name);
- talloc_free(file_with_path);
- return TR_CFG_NOPARSE;
+ tr_debug("tr_parse_config: Parsing %s.", cfg_files[ii]->d_name); /* print the filename without the path */
+ cfg_rc=tr_cfg_parse_one_config_file(cfg_mgr->new, file_with_path);
+ if (cfg_rc!=TR_CFG_SUCCESS) {
+ tr_crit("tr_parse_config: Error parsing %s", file_with_path);
+ goto cleanup;
}
talloc_free(file_with_path); /* done with filename */
-
- // Look for serial number and log it if it exists
- if (NULL != (jser = json_object_get(jcfg, "serial_number"))) {
- if (json_is_number(jser)) {
- tr_notice("tr_read_config: Attempting to load revision %" JSON_INTEGER_FORMAT " of '%s'.",
- json_integer_value(jser),
- cfg_files[n]->d_name);
- }
- }
-
- if ((TR_CFG_SUCCESS != tr_cfg_parse_internal(tr->new_cfg, jcfg)) ||
- (TR_CFG_SUCCESS != tr_cfg_parse_rp_clients(tr->new_cfg, jcfg)) ||
- (TR_CFG_SUCCESS != tr_cfg_parse_idp_realms(tr->new_cfg, jcfg)) ||
- (TR_CFG_SUCCESS != tr_cfg_parse_default_servers(tr->new_cfg, jcfg)) ||
- (TR_CFG_SUCCESS != tr_cfg_parse_comms(tr->new_cfg, jcfg))) {
- tr_cfg_free(tr->new_cfg);
- return TR_CFG_ERROR;
- }
}
/* make sure we got a complete, consistent configuration */
- if (TR_CFG_SUCCESS != tr_cfg_validate(tr->new_cfg)) {
- tr_debug("tr_parse_config: Error: INVALID CONFIGURATION, EXITING");
- return TR_CFG_ERROR;
+ if (TR_CFG_SUCCESS != tr_cfg_validate(cfg_mgr->new)) {
+ tr_err("tr_parse_config: Error: INVALID CONFIGURATION");
+ cfg_rc=TR_CFG_ERROR;
+ goto cleanup;
}
- return TR_CFG_SUCCESS;
+ /* success! */
+ talloc_steal(cfg_mgr, cfg_mgr->new); /* hand this over to the cfg_mgr context */
+ cfg_rc=TR_CFG_SUCCESS;
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return cfg_rc;
}
TR_IDP_REALM *tr_cfg_find_idp (TR_CFG *tr_cfg, TR_NAME *idp_id, TR_CFG_RC *rc)
TR_RP_CLIENT *tr_cfg_find_rp (TR_CFG *tr_cfg, TR_NAME *rp_gss, TR_CFG_RC *rc)
{
TR_RP_CLIENT *cfg_rp;
- int i;
if ((!tr_cfg) || (!rp_gss)) {
if (rc)
}
for (cfg_rp = tr_cfg->rp_clients; NULL != cfg_rp; cfg_rp = cfg_rp->next) {
- for (i = 0; i < TR_MAX_GSS_NAMES; i++) {
- if (!tr_name_cmp (rp_gss, cfg_rp->gss_names[i])) {
- tr_debug("tr_cfg_find_rp: Found %s.", rp_gss->buf);
- return cfg_rp;
- }
+ if (tr_gss_names_matches(cfg_rp->gss_names, rp_gss)) {
+ tr_debug("tr_cfg_find_rp: Found %s.", rp_gss->buf);
+ return cfg_rp;
}
}
/* if we didn't find one, return NULL */
* by scandir(). These can be freed with tr_free_config_file_list().
*/
int tr_find_config_files (const char *config_dir, struct dirent ***cfg_files) {
- int n = 0, i = 0;
+ int n = 0;
- n = scandir(config_dir, cfg_files, &is_cfg_file, 0);
+ n = scandir(config_dir, cfg_files, is_cfg_file, alphasort);
if (n < 0) {
perror("scandir");
tr_debug("tr_find_config: scandir error trying to scan %s.", config_dir);
- } else if (n == 0) {
- tr_debug("tr_find_config: No config files found.");
- } else {
- i = n;
- while(i--) {
- tr_debug("tr_find_config: Config file found (%s).", (*cfg_files)[i]->d_name);
- }
- }
+ }
return n;
}
#include <trust_router/tr_constraint.h>
#include <tid_internal.h>
+
+static int tr_constraint_destructor(void *obj)
+{
+ TR_CONSTRAINT *cons=talloc_get_type_abort(obj, TR_CONSTRAINT);
+ int ii=0;
+
+ if (cons->type!=NULL)
+ tr_free_name(cons->type);
+ for (ii=0; ii<TR_MAX_CONST_MATCHES; ii++) {
+ if (cons->matches[ii]!=NULL)
+ tr_free_name(cons->matches[ii]);
+ }
+ return 0;
+}
+
+TR_CONSTRAINT *tr_constraint_new(TALLOC_CTX *mem_ctx)
+{
+ TR_CONSTRAINT *cons=talloc(mem_ctx, TR_CONSTRAINT);
+ int ii=0;
+
+ if (cons!=NULL) {
+ cons->type=NULL;
+ for (ii=0; ii<TR_MAX_CONST_MATCHES; ii++)
+ cons->matches[ii]=NULL;
+ talloc_set_destructor((void *)cons, tr_constraint_destructor);
+ }
+ return cons;
+}
+
+void tr_constraint_free(TR_CONSTRAINT *cons)
+{
+ talloc_free(cons);
+}
+
/* 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) {
return buf;
}
+const char *sev2str(int sev)
+{
+ switch (sev) {
+ case LOG_DEBUG: return "debug";
+ case LOG_INFO: return "info";
+ case LOG_NOTICE: return "notice";
+ case LOG_WARNING: return "warning";
+ case LOG_ERR: return "err";
+ case LOG_CRIT: return "crit";
+ case LOG_ALERT: return "alert";
+ default: return "invalid";
+ }
+}
+
int str2sev(const char* sev) {
if (strcmp(sev, "debug") ==0 ) {
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <talloc.h>
+
#include <tr_filter.h>
if ((rpp_filter->lines[i]) &&
(rpp_filter->lines[i]->specs[j]) &&
- (tr_prefix_wildcard_match(rp_realm->buf, rpp_filter->lines[i]->specs[j]->match->buf))) {
+ (tr_fspec_matches(rpp_filter->lines[i]->specs[j], rp_realm))) {
*out_action = rpp_filter->lines[i]->action;
*out_constraints = in_constraints;
if (rpp_filter->lines[i]->realm_cons)
return TR_FILTER_NO_MATCH;
}
-void tr_filter_free (TR_FILTER *filt) {
- int i = 0, j = 0;
+void tr_fspec_free(TR_FSPEC *fspec)
+{
+ talloc_free(fspec);
+}
- if (!filt)
- return;
+static int tr_fspec_destructor(void *obj)
+{
+ TR_FSPEC *fspec=talloc_get_type_abort(obj, TR_FSPEC);
+ int ii=0;
- for (i = 0; i < TR_MAX_FILTER_LINES; i++) {
- if (filt->lines[i]) {
- for (j = 0; j < TR_MAX_FILTER_SPECS; j++) {
- if (filt->lines[i]->specs[j])
- free(filt->lines[i]->specs[j]);
- }
- if (filt->lines[i]->realm_cons)
- free(filt->lines[i]->realm_cons);
- if (filt->lines[i]->domain_cons)
- free(filt->lines[i]->domain_cons);
+ if (fspec->field!=NULL)
+ tr_free_name(fspec->field);
+ for (ii=0; ii<TR_MAX_FILTER_MATCHES; ii++) {
+ if (fspec->match[ii]!=NULL)
+ tr_free_name(fspec->match[ii]);
+ }
+ return 0;
+}
- free(filt->lines[i]);
- }
+TR_FSPEC *tr_fspec_new(TALLOC_CTX *mem_ctx)
+{
+ TR_FSPEC *fspec=talloc(mem_ctx, TR_FSPEC);
+ int ii=0;
+
+ if (fspec!=NULL) {
+ fspec->field=NULL;
+ for (ii=0; ii<TR_MAX_FILTER_MATCHES; ii++)
+ fspec->match[ii]=NULL;
+ talloc_set_destructor((void *)fspec, tr_fspec_destructor);
+ }
+ return fspec;
+}
+
+/* returns 0 on success */
+int tr_fspec_add_match(TR_FSPEC *fspec, TR_NAME *match)
+{
+ int ii=0;
+
+ for (ii=0; ii<TR_MAX_FILTER_MATCHES; ii++) {
+ if (fspec->match[ii]==NULL)
+ break;
+ }
+ if (ii<TR_MAX_FILTER_MATCHES) {
+ fspec->match[ii]=match;
+ return 0;
+ } else
+ return -1; /* no space left */
+}
+
+/* returns 1 if the spec matches */
+int tr_fspec_matches(TR_FSPEC *fspec, TR_NAME *name)
+{
+ int ii=0;
+
+ for (ii=0; ii<TR_MAX_FILTER_MATCHES; ii++) {
+ if ((fspec->match[ii]!=NULL) &&
+ (0!=tr_prefix_wildcard_match(name->buf, fspec->match[ii]->buf)))
+ return 1;
}
+ return 0;
+}
- free (filt);
+void tr_fline_free(TR_FLINE *fline)
+{
+ talloc_free(fline);
}
+TR_FLINE *tr_fline_new(TALLOC_CTX *mem_ctx)
+{
+ TR_FLINE *fl=talloc(mem_ctx, TR_FLINE);
+ int ii=0;
+
+ if (fl!=NULL) {
+ fl->action=TR_FILTER_ACTION_UNKNOWN;
+ fl->realm_cons=NULL;
+ fl->domain_cons=NULL;
+ for (ii=0; ii<TR_MAX_FILTER_SPECS; ii++)
+ fl->specs[ii]=NULL;
+ }
+ return fl;
+}
+
+TR_FILTER *tr_filter_new(TALLOC_CTX *mem_ctx)
+{
+ TR_FILTER *f=talloc(mem_ctx, TR_FILTER);
+ int ii=0;
+
+ if (f!=NULL) {
+ f->type=TR_FILTER_TYPE_UNKNOWN;
+ for (ii=0; ii<TR_MAX_FILTER_LINES; ii++)
+ f->lines[ii]=NULL;
+ }
+ return f;
+}
+
+void tr_filter_free(TR_FILTER *filt)
+{
+ talloc_free(filt);
+}
+
+void tr_filter_set_type(TR_FILTER *filt, TR_FILTER_TYPE type)
+{
+ filt->type=type;
+}
+
+TR_FILTER_TYPE tr_filter_get_type(TR_FILTER *filt)
+{
+ return filt->type;
+}
--- /dev/null
+#include <talloc.h>
+
+#include <tr_gss.h>
+
+static int tr_gss_names_destructor(void *obj)
+{
+ TR_GSS_NAMES *gss_names=talloc_get_type_abort(obj, TR_GSS_NAMES);
+ int ii=0;
+
+ for (ii=0; ii<TR_MAX_GSS_NAMES; ii++) {
+ if (gss_names->names[ii]!=NULL)
+ tr_free_name(gss_names->names[ii]);
+ }
+ return 0;
+}
+TR_GSS_NAMES *tr_gss_names_new(TALLOC_CTX *mem_ctx)
+{
+ TR_GSS_NAMES *gn=talloc(mem_ctx, TR_GSS_NAMES);
+ int ii=0;
+
+ if (gn!=NULL) {
+ for (ii=0; ii<TR_MAX_GSS_NAMES; ii++)
+ gn->names[ii]=NULL;
+ talloc_set_destructor((void *)gn, tr_gss_names_destructor);
+ }
+ return gn;
+}
+
+void tr_gss_names_free(TR_GSS_NAMES *gn)
+{
+ talloc_free(gn);
+}
+
+/* returns 0 on success */
+int tr_gss_names_add(TR_GSS_NAMES *gn, TR_NAME *new)
+{
+ int ii=0;
+
+ for (ii=0; ii<TR_MAX_GSS_NAMES; ii++) {
+ if (gn->names[ii]==NULL)
+ break;
+ }
+ if (ii!=TR_MAX_GSS_NAMES) {
+ gn->names[ii]=new;
+ return 0;
+ } else
+ return -1;
+}
+
+int tr_gss_names_matches(TR_GSS_NAMES *gn, TR_NAME *name)
+{
+ int ii=0;
+
+ for (ii=0; ii<TR_MAX_GSS_NAMES; ii++) {
+ if ((gn->names[ii]!=NULL) &&
+ (0==tr_name_cmp(gn->names[ii], name)))
+ return 1;
+ }
+ return 0;
+}
+
+/* iterators */
+TR_GSS_NAMES_ITER *tr_gss_names_iter_new(TALLOC_CTX *mem_ctx)
+{
+ TR_GSS_NAMES_ITER *iter=talloc(mem_ctx, TR_GSS_NAMES_ITER);
+ if (iter!=NULL) {
+ iter->gn=NULL;
+ iter->ii=0;
+ }
+ return iter;
+}
+
+TR_NAME *tr_gss_names_iter_first(TR_GSS_NAMES_ITER *iter, TR_GSS_NAMES *gn)
+{
+ iter->gn=gn;
+ iter->ii=-1;
+ return tr_gss_names_iter_next(iter);
+}
+
+TR_NAME *tr_gss_names_iter_next(TR_GSS_NAMES_ITER *iter)
+{
+ for (iter->ii++;
+ (iter->ii < TR_MAX_GSS_NAMES) && (iter->gn->names[iter->ii]==NULL);
+ iter->ii++) { }
+
+ if (iter->ii<TR_MAX_GSS_NAMES)
+ return iter->gn->names[iter->ii];
+
+ return NULL;
+}
+
+void tr_gss_names_iter_free(TR_GSS_NAMES_ITER *iter)
+{
+ talloc_free(iter);
+}
*
*/
+#include <talloc.h>
+
#include <trust_router/tr_name.h>
#include <tr_idp.h>
-#include <tr.h>
#include <tr_config.h>
-TR_AAA_SERVER *tr_idp_aaa_server_lookup(TR_INSTANCE *tr, TR_NAME *idp_realm, TR_NAME *comm)
+static int tr_aaa_server_destructor(void *obj)
+{
+ TR_AAA_SERVER *aaa=talloc_get_type_abort(obj, TR_AAA_SERVER);
+ if (aaa->hostname!=NULL)
+ tr_free_name(aaa->hostname);
+ return 0;
+}
+
+TR_AAA_SERVER *tr_aaa_server_new(TALLOC_CTX *mem_ctx, TR_NAME *hostname)
+{
+ TR_AAA_SERVER *aaa=talloc(mem_ctx, TR_AAA_SERVER);
+ if (aaa!=NULL) {
+ aaa->hostname=hostname;
+ talloc_set_destructor((void *)aaa, tr_aaa_server_destructor);
+ }
+ return aaa;
+}
+
+void tr_aaa_server_free(TR_AAA_SERVER *aaa)
+{
+ 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_IDP_REALM *idp = NULL;
- for (idp = tr->active_cfg->idp_realms; idp != NULL; idp = idp->next) {
- if (!tr_name_cmp(idp_realm, idp->realm_id)) {
+ for (idp = idp_realms; idp != NULL; idp = idp->next) {
+ if (!tr_name_cmp(idp_realm_name, idp->realm_id)) {
/* TBD -- check that the community is one of the APCs for the IDP */
break;
}
return NULL;
}
-TR_AAA_SERVER *tr_default_server_lookup(TR_INSTANCE *tr, TR_NAME *comm)
+TR_AAA_SERVER *tr_default_server_lookup(TR_AAA_SERVER *default_servers, TR_NAME *comm)
+{
+ if (!default_servers)
+ return NULL;
+
+ return(default_servers);
+}
+
+static int tr_idp_realm_destructor(void *obj)
+{
+ TR_IDP_REALM *idp=talloc_get_type_abort(obj, TR_IDP_REALM);
+ if (idp->realm_id!=NULL)
+ tr_free_name(idp->realm_id);
+ return 0;
+}
+
+/* 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.
+ * The head can then be placed in whatever context is desired. */
+TR_IDP_REALM *tr_idp_realm_new(TALLOC_CTX *mem_ctx)
+{
+ TR_IDP_REALM *idp=talloc(mem_ctx, TR_IDP_REALM);
+ if (idp!=NULL) {
+ idp->next=NULL;
+ idp->comm_next=NULL;
+ idp->realm_id=NULL;
+ idp->shared_config=0;
+ idp->aaa_servers=NULL;
+ idp->apcs=NULL;
+ idp->origin=TR_REALM_LOCAL;
+ talloc_set_destructor((void *)idp, tr_idp_realm_destructor);
+ }
+ return idp;
+}
+
+static TR_IDP_REALM *tr_idp_realm_tail(TR_IDP_REALM *idp)
{
- if ((!tr) || (!(tr->active_cfg)))
+ if (idp==NULL)
return NULL;
- return(tr->active_cfg->default_servers);
+ while (idp->next!=NULL)
+ idp=idp->next;
+ 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)
+{
+ if (head==NULL)
+ head=new;
+ else {
+ tr_idp_realm_tail(head)->next=new;
+ while (new!=NULL) {
+ talloc_steal(head, new); /* put it in the right context */
+ new=new->next;
+ }
+ }
+ return head;
+}
+
+static int tr_idp_realm_apc_count(TR_IDP_REALM *idp)
+{
+ int ii=0;
+ TR_APC *apc=idp->apcs;
+ while (apc!=NULL) {
+ apc=apc->next;
+ ii++;
+ }
+ return ii;
+}
+
+static int tr_idp_realm_aaa_server_count(TR_IDP_REALM *idp)
+{
+ int ii=0;
+ TR_AAA_SERVER *aaa=idp->aaa_servers;
+ while (aaa!=NULL) {
+ aaa=aaa->next;
+ ii++;
+ }
+ return ii;
+}
+
+static char *tr_aaa_server_to_str(TALLOC_CTX *mem_ctx, TR_AAA_SERVER *aaa)
+{
+ return talloc_strndup(mem_ctx, aaa->hostname->buf, aaa->hostname->len);
+}
+
+char *tr_idp_realm_to_str(TALLOC_CTX *mem_ctx, TR_IDP_REALM *idp)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ char **s_aaa=NULL, *aaa_servers=NULL;
+ char **s_apc=NULL, *apcs=NULL;
+ int ii=0, aaa_servers_strlen=0, apcs_strlen=0;
+ int n_aaa_servers=tr_idp_realm_aaa_server_count(idp);
+ int n_apcs=tr_idp_realm_apc_count(idp);
+ TR_AAA_SERVER *aaa=NULL;
+ TR_APC *apc=NULL;
+ char *result=NULL;
+
+ /* get the AAA servers */
+ if (n_aaa_servers<=0)
+ aaa_servers=talloc_strdup(tmp_ctx, "");
+ else {
+ s_aaa=talloc_array(tmp_ctx, char *, n_aaa_servers);
+ for (aaa=idp->aaa_servers,ii=0; aaa!=NULL; aaa=aaa->next,ii++) {
+ s_aaa[ii]=tr_aaa_server_to_str(s_aaa, aaa);
+ aaa_servers_strlen+=strlen(s_aaa[ii]);
+ }
+
+ /* add space for comma-space separators */
+ aaa_servers_strlen+=2*(n_aaa_servers-1);
+
+ aaa_servers=talloc_array(tmp_ctx, char, aaa_servers_strlen+1);
+ aaa_servers[0]='\0';
+ for (ii=0; ii<n_aaa_servers; ii++) {
+ strcat(aaa_servers, s_aaa[ii]);
+ if (ii<(n_aaa_servers-1))
+ strcat(aaa_servers, ", ");
+ }
+ talloc_free(s_aaa);
+ }
+
+ /* get the APCs */
+ if (n_apcs<=0)
+ apcs=talloc_strdup(tmp_ctx, "");
+ else {
+ s_apc=talloc_array(tmp_ctx, char *, n_apcs);
+ for (apc=idp->apcs,ii=0; apc!=NULL; apc=apc->next,ii++) {
+ s_apc[ii]=tr_apc_to_str(s_apc, apc);
+ apcs_strlen+=strlen(s_apc[ii]);
+ }
+
+ /* add space for comma-space separators */
+ apcs_strlen+=2*(n_apcs-1);
+
+ apcs=talloc_array(tmp_ctx, char, apcs_strlen+1);
+ apcs[0]='\0';
+ for (ii=0; ii<n_apcs; ii++) {
+ strcat(apcs, s_apc[ii]);
+ if (ii<(n_apcs-1))
+ strcat(apcs, ", ");
+ }
+ talloc_free(s_apc);
+ }
+
+ result=talloc_asprintf(mem_ctx,
+ "IDP realm: \"%.*s\"\n"
+ " shared: %s\n"
+ " local: %s\n"
+ " AAA servers: %s\n"
+ " APCs: %s\n",
+ idp->realm_id->len, idp->realm_id->buf,
+ (idp->shared_config)?"yes":"no",
+ (idp->origin==TR_REALM_LOCAL)?"yes":"no",
+ aaa_servers,
+ apcs);
+ talloc_free(tmp_ctx);
+ return result;
}
--- /dev/null
+#include <talloc.h>
+#include <pthread.h>
+
+#include <tr_mq.h>
+#include <tr_debug.h>
+
+/* Messages */
+static int tr_mq_msg_destructor(void *object)
+{
+ TR_MQ_MSG *msg=talloc_get_type_abort(object, TR_MQ_MSG);
+ if ( (msg->p!=NULL) && (msg->p_free!=NULL))
+ msg->p_free(msg->p);
+ return 0;
+}
+
+TR_MQ_MSG *tr_mq_msg_new(TALLOC_CTX *mem_ctx, const char *message, TR_MQ_PRIORITY prio)
+{
+ TR_MQ_MSG *msg=talloc(mem_ctx, TR_MQ_MSG);
+ if (msg!=NULL) {
+ msg->next=NULL;
+ msg->prio=prio;
+ msg->message=talloc_strdup(msg, message);
+ if (msg->message==NULL) {
+ talloc_free(msg);
+ return NULL;
+ }
+ msg->p=NULL;
+ talloc_set_destructor((void *)msg, tr_mq_msg_destructor);
+ }
+ return msg;
+}
+
+void tr_mq_msg_free(TR_MQ_MSG *msg)
+{
+ if (msg!=NULL)
+ talloc_free(msg);
+}
+
+TR_MQ_PRIORITY tr_mq_msg_get_prio(TR_MQ_MSG *msg)
+{
+ return msg->prio;
+}
+
+const char *tr_mq_msg_get_message(TR_MQ_MSG *msg)
+{
+ return msg->message;
+}
+
+void *tr_mq_msg_get_payload(TR_MQ_MSG *msg)
+{
+ return msg->p;
+}
+
+/* call with a pointer to the payload and a function to free it later */
+void tr_mq_msg_set_payload(TR_MQ_MSG *msg, void *p, void (*p_free)(void *))
+{
+ msg->p=p;
+ msg->p_free=p_free;
+}
+
+
+static TR_MQ_MSG *tr_mq_msg_get_next(TR_MQ_MSG *msg)
+{
+ return msg->next;
+}
+
+static void tr_mq_msg_set_next(TR_MQ_MSG *msg, TR_MQ_MSG *next)
+{
+ msg->next=next;
+}
+
+/* Message Queues */
+TR_MQ *tr_mq_new(TALLOC_CTX *mem_ctx)
+{
+ TR_MQ *mq=talloc(mem_ctx, TR_MQ);
+ if (mq!=NULL) {
+ pthread_mutex_init(&(mq->mutex), 0);
+ mq->head=NULL;
+ mq->tail=NULL;
+ mq->last_hi_prio=NULL;
+ }
+ return mq;
+}
+
+void tr_mq_free(TR_MQ *mq)
+{
+ if (mq!=NULL) {
+ tr_mq_lock(mq); /* don't pull the rug out from under someone */
+ talloc_free(mq);
+ }
+}
+
+int tr_mq_lock(TR_MQ *mq)
+{
+ return pthread_mutex_lock(&(mq->mutex));
+}
+
+int tr_mq_unlock(TR_MQ *mq)
+{
+ return pthread_mutex_unlock(&(mq->mutex));
+}
+
+static TR_MQ_MSG *tr_mq_get_head(TR_MQ *mq)
+{
+ return mq->head;
+}
+
+static void tr_mq_set_head(TR_MQ *mq, TR_MQ_MSG *msg)
+{
+ mq->head=msg;
+}
+
+static TR_MQ_MSG *tr_mq_get_tail(TR_MQ *mq)
+{
+ return mq->tail;
+}
+
+static void tr_mq_set_tail(TR_MQ *mq, TR_MQ_MSG *msg)
+{
+ mq->tail=msg;
+}
+
+void tr_mq_set_notify_cb(TR_MQ *mq, TR_MQ_NOTIFY_FN cb, void *arg)
+{
+ mq->notify_cb=cb;
+ mq->notify_cb_arg=arg;
+}
+
+void tr_mq_clear(TR_MQ *mq)
+{
+ TR_MQ_MSG *m=NULL;
+ TR_MQ_MSG *n=NULL;
+
+ tr_mq_lock(mq);
+ m=tr_mq_get_head(mq);
+ while (m!=NULL) {
+ n=tr_mq_msg_get_next(m);
+ tr_mq_msg_free(m);
+ m=n;
+ }
+ tr_mq_set_head(mq, NULL);
+ tr_mq_set_tail(mq, NULL);
+ tr_mq_unlock(mq);
+}
+
+static int tr_mq_empty(TR_MQ *mq)
+{
+ return tr_mq_get_head(mq)==NULL;
+}
+
+/* puts msg in mq's talloc context */
+static void tr_mq_append(TR_MQ *mq, TR_MQ_MSG *msg)
+{
+ if (tr_mq_get_head(mq)==NULL) {
+ tr_mq_set_head(mq, msg);
+ tr_mq_set_tail(mq, msg);
+ } else {
+ tr_mq_msg_set_next(tr_mq_get_tail(mq), msg); /* add to list */
+ tr_mq_set_tail(mq, msg); /* update tail of list */
+ }
+ talloc_steal(mq, msg);
+}
+
+static void tr_mq_append_high_prio(TR_MQ *mq, TR_MQ_MSG *new)
+{
+ if (tr_mq_get_head(mq)==NULL) {
+ tr_mq_set_head(mq, new);
+ tr_mq_set_tail(mq, new);
+ } else if (mq->last_hi_prio==NULL) {
+ tr_mq_msg_set_next(new, tr_mq_get_head(mq)); /* add to front of list */
+ tr_mq_set_head(mq, new); /* update head of list */
+ } else {
+ tr_mq_msg_set_next(new, tr_mq_msg_get_next(mq->last_hi_prio));
+ tr_mq_msg_set_next(mq->last_hi_prio, new); /* add to end of hi prio msgs */
+ }
+ mq->last_hi_prio=new; /* in any case, this is now the last high priority msg */
+ talloc_steal(mq,new);
+}
+
+#define DEBUG_TR_MQ 0
+#if DEBUG_TR_MQ
+static void tr_mq_print(TR_MQ *mq)
+{
+ TR_MQ_MSG *m=mq->head;
+ int ii=0;
+
+ tr_debug("tr_mq_print: mq contents:");
+ while(m!=NULL) {
+ ii++;
+ tr_debug("tr_mq_print: Entry %02d: %-15s (prio %d)",
+ ii, tr_mq_msg_get_message(m), tr_mq_msg_get_prio(m));
+ m=tr_mq_msg_get_next(m);
+ }
+}
+#endif
+void tr_mq_add(TR_MQ *mq, TR_MQ_MSG *msg)
+{
+ int was_empty=0;
+ TR_MQ_NOTIFY_FN notify_cb=NULL;
+ void *notify_cb_arg=NULL;
+
+ tr_mq_lock(mq);
+
+ was_empty=tr_mq_empty(mq);
+ switch (tr_mq_msg_get_prio(msg)) {
+ case TR_MQ_PRIO_HIGH:
+ tr_mq_append_high_prio(mq, msg);
+ break;
+ default:
+ tr_mq_append(mq, msg);
+ break;
+ }
+ /* before releasing the mutex, get notify_cb data out of mq */
+ notify_cb=mq->notify_cb;
+ notify_cb_arg=mq->notify_cb_arg;
+
+#if DEBUG_TR_MQ
+ tr_mq_print(mq);
+#endif
+
+ tr_mq_unlock(mq);
+
+ /* see if we need to tell someone we became non-empty */
+ if (was_empty && (notify_cb!=NULL))
+ notify_cb(mq, notify_cb_arg);
+}
+
+/* caller must free msg via tr_mq_msg_free */
+TR_MQ_MSG *tr_mq_pop(TR_MQ *mq)
+{
+ TR_MQ_MSG *popped=NULL;
+
+ tr_mq_lock(mq);
+ 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 */
+
+ if (popped==mq->last_hi_prio)
+ mq->last_hi_prio=NULL;
+
+ if (tr_mq_get_head(mq)==NULL)
+ tr_mq_set_tail(mq, NULL); /* just popped the last element */
+ }
+ tr_mq_unlock(mq);
+ if (popped!=NULL)
+ tr_mq_msg_set_next(popped, NULL); /* disconnect from list */
+ return popped;
+}
+
#include <tr_msg.h>
#include <trust_router/tr_name.h>
-#include <tid_internal.h>
+#include <trp_internal.h>
#include <trust_router/tr_constraint.h>
#include <tr_debug.h>
+/* JSON helpers */
+/* Read attribute attr from msg as an integer. Returns nonzero on error. */
+static int tr_msg_get_json_integer(json_t *jmsg, const char *attr, int *dest)
+{
+ json_t *obj;
+
+ obj=json_object_get(jmsg, attr);
+ if (obj == NULL) {
+ return -1;
+ }
+ /* check type */
+ if (!json_is_integer(obj)) {
+ return -1;
+ }
+
+ (*dest)=json_integer_value(obj);
+ return 0;
+}
+
+/* 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)
+{
+ json_t *obj;
+
+ obj=json_object_get(jmsg, attr);
+ if (obj == NULL)
+ return -1;
+
+ /* check type */
+ if (!json_is_string(obj))
+ return -1;
+
+ *dest=talloc_strdup(mem_ctx, json_string_value(obj));
+ if (*dest==NULL)
+ return -1;
+
+ return 0;
+}
+
enum msg_type tr_msg_get_msg_type(TR_MSG *msg)
{
return msg->msg_type;
msg->msg_type = TID_RESPONSE;
}
+TRP_UPD *tr_msg_get_trp_upd(TR_MSG *msg)
+{
+ if (msg->msg_type == TRP_UPDATE)
+ return (TRP_UPD *)msg->msg_rep;
+ return NULL;
+}
+
+void tr_msg_set_trp_upd(TR_MSG *msg, TRP_UPD *update)
+{
+ msg->msg_rep=update;
+ msg->msg_type=TRP_UPDATE;
+}
+
+TRP_REQ *tr_msg_get_trp_req(TR_MSG *msg)
+{
+ if (msg->msg_type == TRP_REQUEST)
+ return (TRP_REQ *)msg->msg_rep;
+ return NULL;
+}
+
+void tr_msg_set_trp_req(TR_MSG *msg, TRP_REQ *req)
+{
+ msg->msg_rep=req;
+ msg->msg_type=TRP_REQUEST;
+}
+
static json_t *tr_msg_encode_dh(DH *dh)
{
json_t *jdh = NULL;
json_t *jservers = NULL;
json_t *jerr_msg = NULL;
- if (!(tresp = talloc_zero(NULL, TID_RESP))) {
+ if (!(tresp=tid_resp_new(NULL))) {
tr_crit("tr_msg_decode_tidresp(): Error allocating TID_RESP structure.");
return NULL;
}
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 )
+{
+ json_t *jstr=NULL;
+ json_t *jint=NULL;
+ char *s=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)) {
+ return TRP_ERROR;
+ }
+
+ s=tr_name_strdup(trp_inforec_get_comm(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);
+
+ s=tr_name_strdup(trp_inforec_get_realm(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, "realm", 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;
+ if(jstr==NULL)
+ return TRP_ERROR;
+ 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);
+
+ jint=json_integer(trp_inforec_get_interval(rec));
+ if(jint==NULL)
+ return TRP_ERROR;
+ json_object_set_new(jrec, "interval", jint);
+
+ return TRP_SUCCESS;
+}
+
+static json_t *tr_msg_encode_inforec(TRP_INFOREC *rec)
+{
+ json_t *jrec=NULL;
+ json_t *jstr=NULL;
+
+ if ((rec==NULL) || (trp_inforec_get_type(rec)==TRP_INFOREC_TYPE_UNKNOWN))
+ return NULL;
+
+ jrec=json_object();
+ if (jrec==NULL)
+ return NULL;
+
+ jstr=json_string(trp_inforec_type_to_string(trp_inforec_get_type(rec)));
+ if (jstr==NULL) {
+ json_decref(jrec);
+ return NULL;
+ }
+ json_object_set_new(jrec, "record_type", jstr);
+
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_ROUTE:
+ if (TRP_SUCCESS!=tr_msg_encode_inforec_route(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)
+{
+ 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);
+ talloc_free(s); s=NULL;
+
+ rec=trp_inforec_new(tmp_ctx, rectype);
+ if (rec==NULL) {
+ rc=TRP_NOMEM;
+ goto cleanup;
+ }
+
+ /* We only support route_info records for now*/
+ if (trp_inforec_get_type(rec)!=TRP_INFOREC_TYPE_ROUTE) {
+ rc=TRP_UNSUPPORTED;
+ goto cleanup;
+ }
+
+ tr_debug("tr_msg_decode_trp_inforec: '%s' record found.", trp_inforec_type_to_string(rec->type));
+
+ rc=tr_msg_get_json_string(jrecord, "community", &s, tmp_ctx);
+ if (rc != TRP_SUCCESS)
+ goto cleanup;
+ if (TRP_SUCCESS!=trp_inforec_set_comm(rec, tr_new_name(s)))
+ goto cleanup;
+ talloc_free(s); s=NULL;
+
+ rc=tr_msg_get_json_string(jrecord, "realm", &s, tmp_ctx);
+ if (rc != TRP_SUCCESS)
+ goto cleanup;
+ if (TRP_SUCCESS!=trp_inforec_set_realm(rec, tr_new_name(s)))
+ goto cleanup;
+ talloc_free(s); s=NULL;
+
+ 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)))
+ goto cleanup;
+ talloc_free(s); s=NULL;
+
+ 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;
+
+ rc=tr_msg_get_json_integer(jrecord, "interval", &num);
+ if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_interval(rec,num)))
+ goto cleanup;
+
+ talloc_steal(mem_ctx, rec);
+ rc=TRP_SUCCESS;
+
+cleanup:
+ if (rc != TRP_SUCCESS) {
+ trp_inforec_free(rec);
+ rec=NULL;
+ }
+ talloc_free(tmp_ctx);
+ return rec;
+}
+
+/* TRP update msg */
+static json_t *tr_msg_encode_trp_upd(TRP_UPD *update)
+{
+ json_t *jupdate=NULL;
+ json_t *jrecords=NULL;
+ json_t *jrec=NULL;
+ TRP_INFOREC *rec;
+
+ if (update==NULL)
+ return NULL;
+
+ jupdate=json_object();
+ if (jupdate==NULL)
+ return NULL;
+
+ jrecords=json_array();
+ if (jrecords==NULL) {
+ json_decref(jupdate);
+ return NULL;
+ }
+ json_object_set_new(jupdate, "records", jrecords); /* jrecords now a "borrowed" reference */
+ for (rec=trp_upd_get_inforec(update); rec!=NULL; rec=trp_inforec_get_next(rec)) {
+ tr_debug("tr_msg_encode_trp_upd: encoding inforec.");
+ jrec=tr_msg_encode_inforec(rec);
+ if (jrec==NULL) {
+ json_decref(jupdate); /* also decs jrecords and any elements */
+ return NULL;
+ }
+ if (0!=json_array_append_new(jrecords, jrec)) {
+ json_decref(jupdate); /* also decs jrecords and any elements */
+ json_decref(jrec); /* this one did not get added so dec explicitly */
+ return NULL;
+ }
+ }
+
+ return jupdate;
+}
+
+/*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)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ json_t *jrecords=NULL;
+ size_t ii=0;
+ TRP_UPD *update=NULL;
+ TRP_INFOREC *new_rec=NULL;
+ TRP_INFOREC *list_tail=NULL;
+ TRP_RC rc=TRP_ERROR;
+
+ update=trp_upd_new(tmp_ctx);
+ if (update==NULL) {
+ rc=TRP_NOMEM;
+ goto cleanup;
+ }
+
+ jrecords=json_object_get(jupdate, "records");
+ if ((jrecords==NULL) || (!json_is_array(jrecords))) {
+ rc=TRP_NOPARSE;
+ goto cleanup;
+ }
+
+ tr_debug("tr_msg_decode_trp_upd: found %d records", json_array_size(jrecords));
+ /* process the array */
+ for (ii=0; ii<json_array_size(jrecords); ii++) {
+ new_rec=tr_msg_decode_trp_inforec(update, json_array_get(jrecords, ii));
+ if (new_rec==NULL) {
+ rc=TRP_NOPARSE;
+ goto cleanup;
+ }
+
+ if (list_tail==NULL)
+ trp_upd_set_inforec(update, new_rec); /* first is a special case */
+ else
+ trp_inforec_set_next(list_tail, new_rec);
+
+ list_tail=new_rec;
+ }
+
+ /* Succeeded. Move new allocations into the correct talloc context */
+ talloc_steal(mem_ctx, update);
+ rc=TRP_SUCCESS;
+
+cleanup:
+ talloc_free(tmp_ctx);
+ if (rc!=TRP_SUCCESS)
+ return NULL;
+ return update;
+}
+
+static json_t *tr_msg_encode_trp_req(TRP_REQ *req)
+{
+ json_t *jbody=NULL;
+ json_t *jstr=NULL;
+ char *s=NULL;
+
+ if (req==NULL)
+ return NULL;
+
+ jbody=json_object();
+ if (jbody==NULL)
+ return NULL;
+
+ if ((NULL==trp_req_get_comm(req))
+ || (NULL==trp_req_get_realm(req))) {
+ json_decref(jbody);
+ return NULL;
+ }
+
+ s=tr_name_strdup(trp_req_get_comm(req)); /* ensures null termination */
+ if (s==NULL) {
+ json_decref(jbody);
+ return NULL;
+ }
+ jstr=json_string(s);
+ free(s); s=NULL;
+ if (jstr==NULL) {
+ json_decref(jbody);
+ return NULL;
+ }
+ json_object_set_new(jbody, "community", jstr);
+
+ s=tr_name_strdup(trp_req_get_realm(req)); /* ensures null termination */
+ if (s==NULL) {
+ json_decref(jbody);
+ return NULL;
+ }
+ jstr=json_string(s);
+ free(s); s=NULL;
+ if (jstr==NULL) {
+ json_decref(jbody);
+ return NULL;
+ }
+ json_object_set_new(jbody, "realm", jstr);
+
+ return jbody;
+}
+
+static TRP_REQ *tr_msg_decode_trp_req(TALLOC_CTX *mem_ctx, json_t *jreq)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TRP_REQ *req=NULL;
+ char *s=NULL;
+ TRP_RC rc=TRP_ERROR;
+
+ /* check message type and body type for agreement */
+ req=trp_req_new(tmp_ctx);
+ if (req==NULL) {
+ rc=TRP_NOMEM;
+ goto cleanup;
+ }
+
+ rc=tr_msg_get_json_string(jreq, "community", &s, tmp_ctx);
+ if (rc!=TRP_SUCCESS)
+ goto cleanup;
+ trp_req_set_comm(req, tr_new_name(s));
+ talloc_free(s); s=NULL;
+
+ rc=tr_msg_get_json_string(jreq, "realm", &s, tmp_ctx);
+ if (rc!=TRP_SUCCESS)
+ goto cleanup;
+ trp_req_set_realm(req, tr_new_name(s));
+ talloc_free(s); s=NULL;
+
+ rc=TRP_SUCCESS;
+ talloc_steal(mem_ctx, req);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ if (rc!=TRP_SUCCESS)
+ return NULL;
+ return req;
+}
+
char *tr_msg_encode(TR_MSG *msg)
{
- json_t *jmsg;
- json_t *jmsg_type;
+ json_t *jmsg=NULL;
+ json_t *jmsg_type=NULL;
+ char *encoded=NULL;
+ TID_RESP *tidresp=NULL;
+ TID_REQ *tidreq=NULL;
+ TRP_UPD *trpupd=NULL;
+ TRP_REQ *trpreq=NULL;
/* TBD -- add error handling */
jmsg = json_object();
case TID_REQUEST:
jmsg_type = json_string("tid_request");
json_object_set_new(jmsg, "msg_type", jmsg_type);
- json_object_set_new(jmsg, "msg_body", tr_msg_encode_tidreq(tr_msg_get_req(msg)));
+ tidreq=tr_msg_get_req(msg);
+ json_object_set_new(jmsg, "msg_body", tr_msg_encode_tidreq(tidreq));
break;
case TID_RESPONSE:
jmsg_type = json_string("tid_response");
json_object_set_new(jmsg, "msg_type", jmsg_type);
- json_object_set_new(jmsg, "msg_body", tr_msg_encode_tidresp(tr_msg_get_resp(msg)));
+ tidresp=tr_msg_get_resp(msg);
+ json_object_set_new(jmsg, "msg_body", tr_msg_encode_tidresp(tidresp));
break;
- /* TBD -- Add TR message types */
+ case TRP_UPDATE:
+ jmsg_type = json_string("trp_update");
+ json_object_set_new(jmsg, "msg_type", jmsg_type);
+ trpupd=tr_msg_get_trp_upd(msg);
+ json_object_set_new(jmsg, "msg_body", tr_msg_encode_trp_upd(trpupd));
+ break;
+
+ case TRP_REQUEST:
+ jmsg_type = json_string("trp_request");
+ json_object_set_new(jmsg, "msg_type", jmsg_type);
+ trpreq=tr_msg_get_trp_req(msg);
+ json_object_set_new(jmsg, "msg_body", tr_msg_encode_trp_req(trpreq));
+ break;
default:
json_decref(jmsg);
return NULL;
}
-
- return(json_dumps(jmsg, 0));
+
+ encoded=json_dumps(jmsg, 0);
+ json_decref(jmsg);
+ return encoded;
}
TR_MSG *tr_msg_decode(char *jbuf, size_t buflen)
{
- TR_MSG *msg;
+ TR_MSG *msg=NULL;
json_t *jmsg = NULL;
json_error_t rc;
- json_t *jtype;
- json_t *jbody;
+ json_t *jtype=NULL;
+ json_t *jbody=NULL;
const char *mtype = NULL;
if (NULL == (jmsg = json_loadb(jbuf, buflen, JSON_DISABLE_EOF_CHECK, &rc))) {
msg->msg_type = TID_RESPONSE;
tr_msg_set_resp(msg, tr_msg_decode_tidresp(jbody));
}
+ else if (0 == strcmp(mtype, "trp_update")) {
+ msg->msg_type = TRP_UPDATE;
+ tr_msg_set_trp_upd(msg, tr_msg_decode_trp_upd(NULL, jbody)); /* null talloc context for now */
+ }
+ else if (0 == strcmp(mtype, "trp_request")) {
+ msg->msg_type = TRP_UPDATE;
+ tr_msg_set_trp_req(msg, tr_msg_decode_trp_req(NULL, jbody)); /* null talloc context for now */
+ }
else {
msg->msg_type = TR_UNKNOWN;
msg->msg_rep = NULL;
void tr_msg_free_decoded(TR_MSG *msg)
{
- if (msg)
+ if (msg) {
+ switch (msg->msg_type) {
+ case TID_REQUEST:
+ tid_req_free(tr_msg_get_req(msg));
+ break;
+ case TID_RESPONSE:
+ tid_resp_free(tr_msg_get_resp(msg));
+ break;
+ case TRP_UPDATE:
+ trp_upd_free(tr_msg_get_trp_upd(msg));
+ break;
+ case TRP_REQUEST:
+ trp_req_free(tr_msg_get_trp_req(msg));
+ default:
+ break;
+ }
free (msg);
+ }
}
-
-
new->len = strlen(name);
if (new->buf = malloc((new->len)+1)) {
strcpy(new->buf, name);
+ } else {
+ free(new);
+ new=NULL;
}
}
return new;
int tr_name_cmp(TR_NAME *one, TR_NAME *two)
{
- if (one->len != two->len)
- return 1;
- else {
- /* lengths equal */
- return strncmp(one->buf, two->buf, one->len);
+ int len=one->len;
+ int cmp=0;
+
+ if (two->len<one->len)
+ len=two->len; /* len now min(one->len,two->len) */
+
+ cmp=strncmp(one->buf, two->buf, len);
+ if (cmp==0) {
+ if (one->len<two->len)
+ return -1;
+ else if (one->len==two->len)
+ return 0;
+ else
+ return 1;
}
+ return cmp;
}
void tr_name_strlcat(char *dest, const TR_NAME *src, size_t len)
return s;
}
+TR_NAME *tr_name_cat(TR_NAME *n1, TR_NAME *n2)
+{
+ char *s=malloc(n1->len+n2->len+1);
+ TR_NAME *name=NULL;
+ if (s==NULL)
+ return NULL;
+ *s=0;
+ strncat(s, n1->buf, n1->len);
+ strncat(s, n2->buf, n2->len);
+ name=tr_new_name(s);
+ free(s);
+ return name;
+}
*
*/
+#include <talloc.h>
+
+#include <tr.h>
#include <trust_router/tr_name.h>
-#include <tr_rp.h>
+#include <tr_gss.h>
#include <tr_config.h>
-#include <tr.h>
+#include <tr_rp.h>
#include <tr_debug.h>
-TR_RP_CLIENT *tr_rp_client_lookup(TR_INSTANCE *tr, TR_NAME *gss_name) {
+static int tr_rp_client_destructor(void *obj)
+{
+ return 0;
+}
+
+TR_RP_CLIENT *tr_rp_client_new(TALLOC_CTX *mem_ctx)
+{
+ TR_RP_CLIENT *client=talloc(mem_ctx, TR_RP_CLIENT);
+
+ if (client!=NULL) {
+ client->next=NULL;
+ client->comm_next=NULL;
+ client->gss_names=NULL;
+ client->filter=NULL;
+ talloc_set_destructor((void *)client, tr_rp_client_destructor);
+ }
+ return client;
+}
+
+void tr_rp_client_free(TR_RP_CLIENT *client)
+{
+ talloc_free(client);
+}
+
+static TR_RP_CLIENT *tr_rp_client_tail(TR_RP_CLIENT *client)
+{
+ if (client==NULL)
+ return NULL;
+
+ while (client->next!=NULL)
+ client=client->next;
+ return client;
+}
+
+TR_RP_CLIENT *tr_rp_client_add(TR_RP_CLIENT *clients, TR_RP_CLIENT *new)
+{
+ if (clients==NULL)
+ clients=new;
+ else {
+ tr_rp_client_tail(clients)->next=new;
+ while (new!=NULL) {
+ talloc_steal(clients, new); /* put it in the right context */
+ new=new->next;
+ }
+ }
+ return clients;
+}
+
+
+int tr_rp_client_add_gss_name(TR_RP_CLIENT *rp_client, TR_NAME *gss_name)
+{
+ return tr_gss_names_add(rp_client->gss_names, gss_name);
+}
+
+int tr_rp_client_set_filter(TR_RP_CLIENT *client, TR_FILTER *filt)
+{
+ if (client->filter!=NULL)
+ tr_filter_free(client->filter);
+ client->filter=filt;
+ talloc_steal(client, filt);
+ return 0; /* success */
+}
+
+TR_RP_CLIENT *tr_rp_client_lookup(TR_RP_CLIENT *rp_clients, TR_NAME *gss_name)
+{
TR_RP_CLIENT *rp = NULL;
- int i = 0;
- if ((!tr) || (!tr->active_cfg) || (!gss_name)) {
+ if ((!rp_clients) || (!gss_name)) {
tr_debug("tr_rp_client_lookup: Bad parameters.");
return NULL;
}
- for (rp = tr->active_cfg->rp_clients; NULL != rp; rp = rp->next) {
- for (i = 0; ((i < TR_MAX_GSS_NAMES) && (NULL != (rp->gss_names[i]))); i++) {
- if (!tr_name_cmp(gss_name, rp->gss_names[i])) {
- return rp;
- }
- }
+ for (rp = rp_clients; NULL != rp; rp = rp->next) {
+ if (tr_gss_names_matches(rp->gss_names, gss_name))
+ return rp;
}
return NULL;
- }
+}
+
+/* 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.
+ * The head can then be placed in whatever context is desired. */
+
+static TR_RP_REALM *tr_rp_realm_tail(TR_RP_REALM *realm)
+{
+ while (realm!=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)
+{
+ if (head==NULL)
+ head=new;
+ else {
+ tr_rp_realm_tail(head)->next=new;
+ while (new!=NULL) {
+ talloc_steal(head, new); /* put it in the right context */
+ new=new->next;
+ }
+ }
+ return head;
+}
[AC_MSG_ERROR([Please install sqlite3 development])])
AC_CHECK_LIB([jansson], [json_object])
AC_CHECK_LIB([crypto], [DH_new])
-AC_CHECK_HEADERS(gssapi.h gssapi_ext.h jansson.h talloc.h openssl/dh.h openssl/bn.h syslog.h)
+AC_CHECK_LIB([event], [event_base_new])
+AC_CHECK_HEADERS(gssapi.h gssapi_ext.h jansson.h talloc.h openssl/dh.h openssl/bn.h syslog.h event2/event.h)
AC_CONFIG_FILES([Makefile gsscon/Makefile])
AC_OUTPUT
OM_uint32 requestedFlags = (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG |
GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG);
- // printf ("Calling gss_init_sec_context...\n");
majorStatus = gss_init_sec_context (&minorStatus,
clientCredentials,
&gssContext,
* or implied warranty.
*/
-#include <signal.h>
-
#include <gsscon.h>
/* --------------------------------------------------------------------------- */
do {
ssize_t count;
- /* disable the SIGPIPE signal while we write so that we can handle a
- * broken pipe error gracefully */
- signal(SIGPIPE, SIG_IGN); /* temporarily disable */
count = write (inSocket, ptr, inBufferLength - bytesWritten);
- signal(SIGPIPE, SIG_DFL); /* reenable */
if (count < 0) {
/* Try again on EINTR */
if (!err) {
tokenLength = ntohl (tokenLength);
token = malloc (tokenLength);
- memset (token, 0, tokenLength);
+ if (token==NULL) {
+ err=EIO;
+ } else {
+ memset (token, 0, tokenLength);
- err = ReadBuffer (inSocket, tokenLength, token);
+ err = ReadBuffer (inSocket, tokenLength, token);
+ }
}
if (!err) {
- // printf ("Read token:\n");
- // PrintBuffer (token, tokenLength);
-
*outTokenLength = tokenLength;
*outTokenValue = token;
token = NULL; /* only free on error */
size_t inputTokenBufferLength = 0;
gss_buffer_desc inputToken; /* buffer received from the server */
- printf("In gsscon_passive_authenticate(), inNameBuffer = %s\n", inNameBuffer.value);
-
if (inSocket < 0 ) { err = EINVAL; }
if (!outGSSContext) { err = EINVAL; }
- if (!err)
+ if (!err) {
majorStatus = gss_import_name (&minorStatus, &inNameBuffer, (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &serviceName);
- if (majorStatus != GSS_S_COMPLETE) {
+ 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,
#ifndef TID_INTERNAL_H
#define TID_INTERNAL_H
#include <glib.h>
-#include <trust_router/tid.h>
+#include <tr_rp.h>
+#include <trust_router/tid.h>
#include <jansson.h>
struct tid_srvr_blk {
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 */
};
#ifndef TR_H
#define TR_H
+#include <talloc.h>
+
#include <tid_internal.h>
#include <trust_router/tr_name.h>
#include <tr_msg.h>
#include <tr_rp.h>
+#include <tr_trp.h>
+#include <tr_cfgwatch.h>
+#include <tr_config.h>
-typedef struct tr_instance {
- struct tr_cfg *new_cfg; /* unapplied configuration */
- struct tr_cfg *active_cfg;
- TIDS_INSTANCE *tids;
- struct tr_rp_client *rp_gss; /* Client matching GSS name, TBD -- FIX ME */
-} TR_INSTANCE;
+/* struct defined in tr_trp.h */
+typedef struct tr_instance TR_INSTANCE;
-TR_INSTANCE *tr_create(void);
+TR_INSTANCE *tr_create(TALLOC_CTX *mem_ctx);
void tr_destroy(TR_INSTANCE *tr);
#endif
#ifndef TR_APC_H
#define TR_APC_H
+#include <talloc.h>
+
+#include <trust_router/tr_name.h>
+
/* Used to hold lists of APC names in cfg. */
typedef struct tr_apc {
struct tr_apc *next;
TR_NAME *id;
} TR_APC;
+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_dup(TALLOC_CTX *mem_ctx, TR_APC *apc);
+
+void tr_apc_set_id(TR_APC *apc, TR_NAME *id);
+TR_NAME *tr_apc_get_id(TR_APC *apc);
+TR_NAME *tr_apc_dup_id(TR_APC *apc);
+
+char *tr_apc_to_str(TALLOC_CTX *mem_ctx, TR_APC *apc);
+
#endif
--- /dev/null
+#ifndef TR_CFGWATCH_H
+#define TR_CFGWATCH_H
+
+#include <talloc.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include <tr_config.h>
+#include <tr_event.h>
+/* interval in seconds */
+#define TR_CFGWATCH_DEFAULT_POLL 1
+#define TR_CFGWATCH_DEFAULT_SETTLE 5
+/* note: settling time is minimum - only checked on poll intervals */
+
+struct tr_fstat {
+ char *name;
+ struct timespec mtime;
+};
+
+typedef struct tr_cfgwatch_data {
+ struct timeval poll_interval; /* how often should we check for updates? */
+ struct timeval settling_time; /* how long should we wait for changes to settle before updating? */
+ char *config_dir; /* what directory are we watching? */
+ struct tr_fstat *fstat_list; /* file names and mtimes */
+ int n_files; /* number of files in fstat_list */
+ int change_detected; /* have we detected a change? */
+ struct timeval last_change_detected; /* when did we last note a changed mtime? */
+ TR_CFG_MGR *cfg_mgr; /* what trust router config are we updating? */
+ void (*update_cb)(TR_CFG *new_cfg, void *cookie); /* callback after config updated */
+ void *update_cookie; /* data for the update_cb() */
+} TR_CFGWATCH;
+
+
+/* prototypes */
+TR_CFGWATCH *tr_cfgwatch_create(TALLOC_CTX *mem_ctx);
+int tr_read_and_apply_config(TR_CFGWATCH *cfgwatch);
+int tr_cfgwatch_event_init(struct event_base *base, TR_CFGWATCH *cfg_status, struct event **cfgwatch_ev);
+
+#endif /* TR_CFGWATCH_H */
time_t expiration_interval; /*Minutes to key expiration; only valid for an APC*/
} TR_COMM;
-TR_COMM *tr_comm_lookup(TR_INSTANCE *tr, TR_NAME *comm);
+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);
#include <dirent.h>
#include <jansson.h>
#include <syslog.h>
+#include <sys/time.h>
+#include <talloc.h>
-#include <tr.h>
+#include <tr_comm.h>
#include <tr_rp.h>
#include <tr_idp.h>
-#include <tr_comm.h>
+#include <trp_ptable.h>
+#include <trp_internal.h>
#define TR_DEFAULT_MAX_TREE_DEPTH 12
#define TR_DEFAULT_TR_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_SWEEP_INTERVAL 30
typedef enum tr_cfg_rc {
TR_CFG_SUCCESS = 0, /* No error */
TR_CFG_ERROR, /* General processing error */
TR_CFG_BAD_PARAMS, /* Bad parameters passed to tr_config function */
TR_CFG_NOPARSE, /* Parsing error */
- TR_CFG_NOMEM /* Memory allocation error */
+ TR_CFG_NOMEM, /* Memory allocation error */
} TR_CFG_RC;
typedef struct tr_cfg_internal {
unsigned int max_tree_depth;
unsigned int tids_port;
+ unsigned int trps_port;
const char *hostname;
int log_threshold;
int console_threshold;
+ unsigned int cfg_poll_interval;
+ unsigned int cfg_settling_time;
+ unsigned int trp_sweep_interval;
+ unsigned int trp_update_interval;
+ unsigned int trp_connect_interval;
} 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_AAA_SERVER *default_servers; /* default server list */
/* TBD -- Global Filters */
- /* TBD -- Trust Router Peers */
- /* TBD -- Trust Links */
} TR_CFG;
+typedef struct tr_cfg_mgr {
+ TR_CFG *active;
+ TR_CFG *new;
+} TR_CFG_MGR;
+
int tr_find_config_files (const char *config_dir, struct dirent ***cfg_files);
void tr_free_config_file_list(int n, struct dirent ***cfg_files);
-TR_CFG_RC tr_parse_config (TR_INSTANCE *tr, const char *config_dir, int n, struct dirent **cfg_files);
-TR_CFG_RC tr_apply_new_config (TR_INSTANCE *tr);
+TR_CFG_RC tr_parse_config (TR_CFG_MGR *cfg_mgr, const char *config_dir, int n, struct dirent **cfg_files);
+TR_CFG_RC tr_cfg_parse_one_config_file(TR_CFG *cfg, const char *file_with_path);
+TR_CFG_RC tr_apply_new_config (TR_CFG_MGR *cfg_mgr);
TR_CFG_RC tr_cfg_validate (TR_CFG *trc);
+TR_CFG *tr_cfg_new(TALLOC_CTX *mem_ctx);
+TR_CFG_MGR *tr_cfg_mgr_new(TALLOC_CTX *mem_ctx);
void tr_cfg_free(TR_CFG *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);
-TR_IDP_REALM *tr_cfg_find_idp (TR_CFG *tr_cfg, TR_NAME *idp_id, TR_CFG_RC *rc);
-TR_RP_CLIENT *tr_cfg_find_rp (TR_CFG *tr_cfg, TR_NAME *rp_gss, TR_CFG_RC *rc);
-TR_RP_CLIENT *tr_rp_client_lookup(TR_INSTANCE *tr, TR_NAME *gss_name);
+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);
#endif
#define tr_info(...) tr_log(LOG_INFO, __VA_ARGS__)
#define tr_debug(...) tr_log(LOG_DEBUG, __VA_ARGS__)
+TR_EXPORT const char *sev2str(int sev);
TR_EXPORT int str2sev(const char *sev);
TR_EXPORT void tr_log_threshold(const int sev);
TR_EXPORT void tr_console_threshold(const int sev);
--- /dev/null
+#ifndef TR_EVENT_H
+#define TR_EVENT_H
+
+#include <event2/event.h>
+
+/* 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 */
+};
+
+/* prototypes */
+struct event_base *tr_event_loop_init(void);
+int tr_event_loop_run(struct event_base *base);
+
+#endif /* TR_EVENT_H */
#ifndef TR_FILTER_H
#define TR_FILTER_H
+#include <talloc.h>
+#include <jansson.h>
+
#include <trust_router/tr_name.h>
#include <trust_router/tr_constraint.h>
-#include <jansson.h>
#define TR_MAX_FILTERS 5
#define TR_MAX_FILTER_LINES 8
#define TR_MAX_FILTER_SPECS 8
+#define TR_MAX_FILTER_MATCHES 8
/* Filter actions */
-#define TR_FILTER_ACTION_REJECT 0
-#define TR_FILTER_ACTION_ACCEPT 1
+typedef enum {
+ TR_FILTER_ACTION_REJECT=0,
+ TR_FILTER_ACTION_ACCEPT,
+ TR_FILTER_ACTION_UNKNOWN
+} TR_FILTER_ACTION;
/* Match codes */
#define TR_FILTER_MATCH 0
#define TR_FILTER_NO_MATCH 1
/* Filter types */
-#define TR_FILTER_TYPE_RP_PERMITTED 0
-/* Other types TBD */
+typedef enum {
+ TR_FILTER_TYPE_TID_INCOMING=0,
+ TR_FILTER_TYPE_UNKNOWN
+} TR_FILTER_TYPE;
+/* #define for backward compatibility, TODO: get rid of this -jlr */
+#define TR_FILTER_TYPE_RP_PERMITTED TR_FILTER_TYPE_TID_INCOMING
+
typedef struct tr_fspec {
TR_NAME *field;
- TR_NAME *match;
+ TR_NAME *match[TR_MAX_FILTER_MATCHES];
} TR_FSPEC;
typedef struct tr_fline {
- int action;
+ TR_FILTER_ACTION action;
TR_FSPEC *specs[TR_MAX_FILTER_SPECS];
TR_CONSTRAINT *realm_cons;
TR_CONSTRAINT *domain_cons;
} TR_FLINE;
typedef struct tr_filter {
- int type;
+ TR_FILTER_TYPE type;
TR_FLINE *lines[TR_MAX_FILTER_LINES];
} TR_FILTER;
-void tr_filter_free (TR_FILTER *filt);
+TR_FILTER *tr_filter_new(TALLOC_CTX *mem_ctx);
+void tr_filter_free(TR_FILTER *filt);
+void tr_filter_set_type(TR_FILTER *filt, TR_FILTER_TYPE type);
+TR_FILTER_TYPE tr_filter_get_type(TR_FILTER *filt);
+
+TR_FLINE *tr_fline_new(TALLOC_CTX *mem_ctx);
+void tr_fline_free(TR_FLINE *fline);
+TR_FSPEC *tr_fspec_new(TALLOC_CTX *mem_ctx);
+void tr_fspec_free(TR_FSPEC *fspec);
+int tr_fspec_add_match(TR_FSPEC *fspec, TR_NAME *match);
+int tr_fspec_matches(TR_FSPEC *fspec, TR_NAME *name);
+
+
/*In tr_constraint.c and exported, but not really a public symbol; needed by tr_filter.c and by tr_constraint.c*/
int TR_EXPORT tr_prefix_wildcard_match (const char *str, const char *wc_str);
int tr_filter_process_rp_permitted (TR_NAME *rp_realm, TR_FILTER *rpp_filter, TR_CONSTRAINT_SET *in_constraints, TR_CONSTRAINT_SET **out_constraints, int *out_action);
--- /dev/null
+#ifndef __TR_GSS_H__
+#define __TR_GSS_H__
+
+#include <talloc.h>
+#include <trust_router/tr_name.h>
+
+#define TR_MAX_GSS_NAMES 5
+
+typedef struct tr_gss_names {
+ TR_NAME *names[TR_MAX_GSS_NAMES];
+} TR_GSS_NAMES;
+
+typedef struct tr_gss_names_iter {
+ TR_GSS_NAMES *gn;
+ int ii; /* which entry did we last output? */
+} TR_GSS_NAMES_ITER;
+
+TR_GSS_NAMES *tr_gss_names_new(TALLOC_CTX *mem_ctx);
+void tr_gss_names_free(TR_GSS_NAMES *gn);
+int tr_gss_names_add(TR_GSS_NAMES *gn, TR_NAME *new);
+int tr_gss_names_matches(TR_GSS_NAMES *gn, TR_NAME *name);
+
+TR_GSS_NAMES_ITER *tr_gss_names_iter_new(TALLOC_CTX *mem_ctx);
+TR_NAME *tr_gss_names_iter_first(TR_GSS_NAMES_ITER *iter, TR_GSS_NAMES *gn);
+TR_NAME *tr_gss_names_iter_next(TR_GSS_NAMES_ITER *iter);
+void tr_gss_names_iter_free(TR_GSS_NAMES_ITER *iter);
+
+#endif /* __TR_GSS_H__ */
#ifndef TR_IDP_H
#define TR_IDP_H
+#include <talloc.h>
+
#include <trust_router/tr_name.h>
-#include <tr.h>
#include <tr_apc.h>
typedef struct tr_aaa_server {
TR_NAME *hostname;
} TR_AAA_SERVER;
+/* 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_REALM_REMOTE_INCOMPLETE, /* realm we were configured to know about, without contact info yet */
+ TR_REALM_REMOTE, /* realm we were configured to know about, with discovered contact info */
+ TR_REALM_DISCOVERED /* realm we learned about from a peer */
+} TR_REALM_ORIGIN;
+
typedef struct tr_idp_realm {
struct tr_idp_realm *next;
struct tr_idp_realm *comm_next; /* for linked list in comm config */
int shared_config;
TR_AAA_SERVER *aaa_servers;
TR_APC *apcs;
+ TR_REALM_ORIGIN origin; /* how did we learn about this realm? */
} TR_IDP_REALM;
-TR_AAA_SERVER *tr_idp_aaa_server_lookup(TR_INSTANCE *tr, TR_NAME *idp_realm, TR_NAME *comm);
-TR_AAA_SERVER *tr_default_server_lookup(TR_INSTANCE *tr, TR_NAME *comm);
+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);
+char *tr_idp_realm_to_str(TALLOC_CTX *mem_ctx, TR_IDP_REALM *idp);
+
+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 *tr_default_server_lookup(TR_AAA_SERVER *default_servers, TR_NAME *comm);
+
#endif
--- /dev/null
+#ifndef _TR_MQ_H_
+#define _TR_MQ_H_
+
+#include <talloc.h>
+#include <pthread.h>
+
+/* Note on mq priorities: High priority messages are guaranteed to be
+ * processed before any normal priority messages. Otherwise, messages
+ * will be processed in the order they are added to the queue. */
+
+typedef enum tr_mq_priority {
+ TR_MQ_PRIO_NORMAL=0,
+ TR_MQ_PRIO_HIGH
+} TR_MQ_PRIORITY;
+
+/* msg for inter-thread messaging */
+typedef struct tr_mq_msg TR_MQ_MSG;
+struct tr_mq_msg {
+ TR_MQ_MSG *next;
+ TR_MQ_PRIORITY prio;
+ char *message;
+ void *p; /* payload */
+ void (*p_free)(void *); /* function to free payload */
+};
+
+/* message queue for inter-thread messaging */
+
+typedef struct tr_mq TR_MQ;
+typedef void (*TR_MQ_NOTIFY_FN)(TR_MQ *, void *);
+struct tr_mq {
+ pthread_mutex_t mutex;
+ TR_MQ_MSG *head;
+ TR_MQ_MSG *tail;
+ TR_MQ_MSG *last_hi_prio;
+ TR_MQ_NOTIFY_FN notify_cb; /* callback when queue becomes non-empty */
+ void *notify_cb_arg;
+};
+
+/* message string for sending trpc messages */
+#define TR_MQMSG_TRPC_SEND "trpc send msg"
+
+TR_MQ_MSG *tr_mq_msg_new(TALLOC_CTX *mem_ctx, const char *msg, TR_MQ_PRIORITY prio);
+void tr_mq_msg_free(TR_MQ_MSG *msg);
+TR_MQ_PRIORITY tr_mq_msg_get_prio(TR_MQ_MSG *msg);
+const char *tr_mq_msg_get_message(TR_MQ_MSG *msg);
+void *tr_mq_msg_get_payload(TR_MQ_MSG *msg);
+void tr_mq_msg_set_payload(TR_MQ_MSG *msg, void *p, void (*p_free)(void *));
+
+
+TR_MQ *tr_mq_new(TALLOC_CTX *mem_ctx);
+void tr_mq_free(TR_MQ *mq);
+int tr_mq_lock(TR_MQ *mq);
+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);
+void tr_mq_clear(TR_MQ *mq);
+
+#endif /*_TR_MQ_H_ */
#include <jansson.h>
#include <trust_router/tid.h>
-
+#include <trust_router/trp.h>
typedef struct tr_msg TR_MSG;
enum msg_type {
TR_UNKNOWN = 0,
TID_REQUEST,
- TID_RESPONSE
+ TID_RESPONSE,
+ TRP_UPDATE,
+ TRP_REQUEST
};
/* Union of TR message types to hold message of any type. */
void tr_msg_set_req(TR_MSG *msg, TID_REQ *req);
TID_RESP *tr_msg_get_resp(TR_MSG *msg);
void tr_msg_set_resp(TR_MSG *msg, TID_RESP *resp);
+TRP_UPD *tr_msg_get_trp_upd(TR_MSG *msg);
+void tr_msg_set_trp_upd(TR_MSG *msg, TRP_UPD *req);
+TRP_REQ *tr_msg_get_trp_req(TR_MSG *msg);
+void tr_msg_set_trp_req(TR_MSG *msg, TRP_REQ *req);
+
/* Encoders/Decoders */
char *tr_msg_encode(TR_MSG *msg);
#ifndef TR_RP_H
#define TR_RP_H
-#include <tr.h>
-#include <tr_filter.h>
+#include <talloc.h>
-#define TR_MAX_GSS_NAMES 5
+#include <tr_gss.h>
+#include <tr_filter.h>
typedef struct tr_rp_client {
struct tr_rp_client *next;
struct tr_rp_client *comm_next;
- TR_NAME *gss_names[TR_MAX_GSS_NAMES];
+ TR_GSS_NAMES *gss_names;
TR_FILTER *filter;
} TR_RP_CLIENT;
TR_NAME *realm_name;
} 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);
+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);
#endif
--- /dev/null
+#ifndef TR_TID_H
+#define TR_TID_H
+
+#include <trp_internal.h>
+#include <tr_event.h>
+#include <tr_config.h>
+
+int tr_tids_event_init(struct event_base *base,
+ TIDS_INSTANCE *tids,
+ TR_CFG_MGR *cfg_mgr,
+ TRPS_INSTANCE *trps,
+ struct tr_socket_event *tids_ev);
+
+#endif /* TR_TID_H */
--- /dev/null
+#ifndef TR_TRP_H
+#define TR_TRP_H
+
+#include <event2/event.h>
+#include <talloc.h>
+#include <pthread.h>
+
+#include <tr.h>
+#include <trp_internal.h>
+#include <tr_config.h>
+#include <tr_cfgwatch.h>
+#include <tr_event.h>
+
+typedef struct tr_trps_events {
+ struct event *trps_ev;
+ struct tr_socket_event *listen_ev;
+ struct event *mq_ev;
+ struct event *connect_ev;
+ struct event *update_ev;
+ struct event *sweep_ev;
+} TR_TRPS_EVENTS;
+
+/* typedef'ed as TR_INSTANCE in tr.h */
+struct tr_instance {
+ TR_CFG_MGR *cfg_mgr;
+ TIDS_INSTANCE *tids;
+ TRPS_INSTANCE *trps;
+ TR_CFGWATCH *cfgwatch;
+ TR_TRPS_EVENTS *events;
+};
+
+/* messages between threads */
+#define TR_MQMSG_MSG_RECEIVED "msg received"
+#define TR_MQMSG_TRPC_DISCONNECTED "trpc disconnected"
+#define TR_MQMSG_TRPC_CONNECTED "trpc connected"
+#define TR_MQMSG_TRPS_DISCONNECTED "trps disconnected"
+#define TR_MQMSG_TRPS_CONNECTED "trps connected"
+#define TR_MQMSG_ABORT "abort"
+
+/* prototypes */
+TRP_RC tr_trps_event_init(struct event_base *base, struct tr_instance *tr);
+TRP_RC tr_add_local_routes(TRPS_INSTANCE *trps, TR_CFG *cfg);
+TRP_RC tr_trpc_initiate(TRPS_INSTANCE *trps, TRP_PEER *peer, struct event *ev);
+void tr_config_changed(TR_CFG *new_cfg, void *cookie);
+TRP_RC tr_connect_to_peers(TRPS_INSTANCE *trps, struct event *ev);
+void tr_peer_status_change(TRP_PEER *peer, void *cookie);
+#endif /* TR_TRP_H */
--- /dev/null
+#ifndef TRP_INTERNAL_H
+#define TRP_INTERNAL_H
+
+#include <pthread.h>
+#include <talloc.h>
+
+#include <gsscon.h>
+#include <tr_mq.h>
+#include <tr_msg.h>
+#include <trp_ptable.h>
+#include <trp_rtable.h>
+#include <trust_router/trp.h>
+
+/* 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 metric;
+ unsigned int interval;
+} TRP_INFOREC_ROUTE;
+
+/* TODO: define struct trp_msg_info_community */
+
+typedef union trp_inforec_data {
+ TRP_INFOREC_ROUTE *route;
+ /* 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 */
+};
+
+struct trp_update {
+ TRP_INFOREC *records;
+ TR_NAME *peer; /* who did this update come from? */
+};
+
+struct trp_req {
+ TR_NAME *comm;
+ TR_NAME *realm;
+ TR_NAME *peer; /* who did this req come from? */
+};
+
+
+typedef struct trps_instance TRPS_INSTANCE;
+
+typedef enum trp_connection_status {
+ TRP_CONNECTION_CLOSED=0,
+ TRP_CONNECTION_DOWN,
+ TRP_CONNECTION_AUTHORIZING,
+ TRP_CONNECTION_UP,
+ TRP_CONNECTION_UNKNOWN,
+} TRP_CONNECTION_STATUS;
+
+typedef struct trp_connection TRP_CONNECTION;
+struct trp_connection {
+ pthread_mutex_t mutex; /* protects status attribute */
+ TRP_CONNECTION *next;
+ pthread_t *thread; /* thread servicing this connection */
+ int fd;
+ TR_NAME *gssname;
+ TR_NAME *peer; /* TODO: why is there a peer and a gssname? jlr */
+ gss_ctx_id_t *gssctx;
+ TRP_CONNECTION_STATUS status;
+ void (*status_change_cb)(TRP_CONNECTION *conn, void *cookie);
+ void *status_change_cookie;
+};
+
+typedef TRP_RC (*TRPS_MSG_FUNC)(TRPS_INSTANCE *, TRP_CONNECTION *, TR_MSG *);
+typedef void (*TRP_RESP_FUNC)();
+/*typedef int (*TRP_AUTH_FUNC)(gss_name_t client_name, TR_NAME *display_name, void *cookie);*/
+typedef client_cb_fn TRP_AUTH_FUNC;
+
+/* function to look up comm/realm entries */
+typedef TRP_ROUTE *(TRP_LOOKUP_FUNC)(TR_NAME *, TR_NAME *, void *);
+
+
+/* TRP Client Instance Data */
+typedef struct trpc_instance TRPC_INSTANCE;
+struct trpc_instance {
+ TRPC_INSTANCE *next;
+ TR_NAME *gssname;
+ char *server;
+ unsigned int port;
+ TRP_CONNECTION *conn;
+ TR_MQ *mq; /* msgs from master to trpc */
+};
+
+/* TRP Server Instance Data */
+struct trps_instance {
+ char *hostname;
+ unsigned int port;
+ TRP_AUTH_FUNC auth_handler;
+ TRPS_MSG_FUNC msg_handler;
+ void *cookie;
+ TRP_CONNECTION *conn; /* connections from peers */
+ TRPC_INSTANCE *trpc; /* connections to peers */
+ TR_MQ *mq; /* incoming message queue */
+ TRP_PTABLE *ptable; /* peer table */
+ TRP_RTABLE *rtable; /* route 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 */
+};
+
+typedef enum trp_update_type {
+ TRP_UPDATE_SCHEDULED=0,
+ TRP_UPDATE_TRIGGERED,
+ TRP_UPDATE_REQUESTED
+} TRP_UPDATE_TYPE;
+
+TRP_CONNECTION *trp_connection_new(TALLOC_CTX *mem_ctx);
+void trp_connection_free(TRP_CONNECTION *conn);
+void trp_connection_close(TRP_CONNECTION *conn);
+int trp_connection_lock(TRP_CONNECTION *conn);
+int trp_connection_unlock(TRP_CONNECTION *conn);
+int trp_connection_get_fd(TRP_CONNECTION *conn);
+void trp_connection_set_fd(TRP_CONNECTION *conn, int fd);
+TR_NAME *trp_connection_get_peer(TRP_CONNECTION *conn);
+TR_NAME *trp_connection_get_gssname(TRP_CONNECTION *conn);
+void trp_connection_set_gssname(TRP_CONNECTION *conn, TR_NAME *gssname);
+gss_ctx_id_t *trp_connection_get_gssctx(TRP_CONNECTION *conn);
+void trp_connection_set_gssctx(TRP_CONNECTION *conn, gss_ctx_id_t *gssctx);
+TRP_CONNECTION_STATUS trp_connection_get_status(TRP_CONNECTION *conn);
+pthread_t *trp_connection_get_thread(TRP_CONNECTION *conn);
+void trp_connection_set_thread(TRP_CONNECTION *conn, pthread_t *thread);
+TRP_CONNECTION *trp_connection_get_next(TRP_CONNECTION *conn);
+TRP_CONNECTION *trp_connection_remove(TRP_CONNECTION *conn, TRP_CONNECTION *remove);
+void trp_connection_append(TRP_CONNECTION *conn, TRP_CONNECTION *new);
+int trp_connection_auth(TRP_CONNECTION *conn, TRP_AUTH_FUNC auth_callback, void *callback_data);
+TRP_CONNECTION *trp_connection_accept(TALLOC_CTX *mem_ctx, int listen, TR_NAME *gssname);
+TRP_RC trp_connection_initiate(TRP_CONNECTION *conn, char *server, unsigned int port);
+
+TRPC_INSTANCE *trpc_new (TALLOC_CTX *mem_ctx);
+void trpc_free (TRPC_INSTANCE *trpc);
+TRP_CONNECTION *trpc_get_conn(TRPC_INSTANCE *trpc);
+void trpc_set_conn(TRPC_INSTANCE *trpc, TRP_CONNECTION *conn);
+TRPC_INSTANCE *trpc_get_next(TRPC_INSTANCE *trpc);
+void trpc_set_next(TRPC_INSTANCE *trpc, TRPC_INSTANCE *next);
+TRPC_INSTANCE *trpc_remove(TRPC_INSTANCE *trpc, TRPC_INSTANCE *remove);
+void trpc_append(TRPC_INSTANCE *trpc, TRPC_INSTANCE *new);
+char *trpc_get_server(TRPC_INSTANCE *trpc);
+void trpc_set_server(TRPC_INSTANCE *trpc, char *server);
+TR_NAME *trpc_get_gssname(TRPC_INSTANCE *trpc);
+void trpc_set_gssname(TRPC_INSTANCE *trpc, TR_NAME *gssname);
+unsigned int trpc_get_port(TRPC_INSTANCE *trpc);
+void trpc_set_port(TRPC_INSTANCE *trpc, unsigned int port);
+TRP_CONNECTION_STATUS trpc_get_status(TRPC_INSTANCE *trpc);
+TR_MQ *trpc_get_mq(TRPC_INSTANCE *trpc);
+void trpc_set_mq(TRPC_INSTANCE *trpc, TR_MQ *mq);
+void trpc_mq_add(TRPC_INSTANCE *trpc, TR_MQ_MSG *msg);
+TR_MQ_MSG *trpc_mq_pop(TRPC_INSTANCE *trpc);
+void trpc_mq_clear(TRPC_INSTANCE *trpc);
+void trpc_master_mq_add(TRPC_INSTANCE *trpc, TR_MQ_MSG *msg);
+TR_MQ_MSG *trpc_master_mq_pop(TRPC_INSTANCE *trpc);
+TRP_RC trpc_connect(TRPC_INSTANCE *trpc);
+TRP_RC trpc_send_msg(TRPC_INSTANCE *trpc, const char *msg_content);
+
+TRPS_INSTANCE *trps_new (TALLOC_CTX *mem_ctx);
+void trps_free (TRPS_INSTANCE *trps);
+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);
+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);
+unsigned int trps_get_connect_interval(TRPS_INSTANCE *trps);
+void trps_set_update_interval(TRPS_INSTANCE *trps, unsigned int interval);
+unsigned int trps_get_update_interval(TRPS_INSTANCE *trps);
+void trps_set_sweep_interval(TRPS_INSTANCE *trps, unsigned int interval);
+unsigned int trps_get_sweep_interval(TRPS_INSTANCE *trps);
+TRPC_INSTANCE *trps_find_trpc(TRPS_INSTANCE *trps, TRP_PEER *peer);
+TRP_RC trps_send_msg (TRPS_INSTANCE *trps, TRP_PEER *peer, const char *msg);
+void trps_add_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *new);
+void trps_remove_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *remove);
+void trps_add_trpc(TRPS_INSTANCE *trps, TRPC_INSTANCE *trpc);
+void trps_remove_trpc(TRPS_INSTANCE *trps, TRPC_INSTANCE *remove);
+int trps_get_listener(TRPS_INSTANCE *trps,
+ TRPS_MSG_FUNC msg_handler,
+ TRP_AUTH_FUNC auth_handler,
+ const char *hostname,
+ unsigned int port,
+ void *cookie);
+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);
+void trps_handle_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *conn);
+TRP_RC trps_update_active_routes(TRPS_INSTANCE *trps);
+TRP_RC trps_handle_tr_msg(TRPS_INSTANCE *trps, TR_MSG *tr_msg);
+TRP_ROUTE *trps_get_route(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer);
+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_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_PEER *trps_get_peer_by_servicename(TRPS_INSTANCE *trps, TR_NAME *servicename);
+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);
+#endif /* TRP_INTERNAL_H */
--- /dev/null
+#ifndef _TRP_PTABLE_H_
+#define _TRP_PTABLE_H_
+
+#include <time.h>
+#include <talloc.h>
+
+#include <trust_router/tr_name.h>
+#include <tr_gss.h>
+#include <trust_router/trp.h>
+
+typedef enum trp_peer_conn_status {
+ PEER_DISCONNECTED=0,
+ PEER_CONNECTED
+} TRP_PEER_CONN_STATUS;
+
+typedef struct trp_peer TRP_PEER;
+struct trp_peer {
+ TRP_PEER *next; /* for making a linked list */
+ char *server;
+ TR_GSS_NAMES *gss_names;
+ TR_NAME *servicename;
+ unsigned int port;
+ unsigned int linkcost;
+ struct timespec last_conn_attempt;
+ TRP_PEER_CONN_STATUS outgoing_status;
+ TRP_PEER_CONN_STATUS incoming_status;
+ void (*conn_status_cb)(TRP_PEER *, void *); /* callback for connected status change */
+ void *conn_status_cookie;
+};
+
+typedef struct trp_ptable {
+ TRP_PEER *head; /* head of a peer table list */
+} TRP_PTABLE;
+
+/* iterator for the peer table */
+typedef TRP_PEER *TRP_PTABLE_ITER;
+
+TRP_PTABLE *trp_ptable_new(TALLOC_CTX *memctx);
+void trp_ptable_free(TRP_PTABLE *ptbl);
+TRP_RC trp_ptable_add(TRP_PTABLE *ptbl, TRP_PEER *newpeer);
+TRP_RC trp_ptable_remove(TRP_PTABLE *ptbl, TRP_PEER *peer);
+TRP_PEER *trp_ptable_find_gss_name(TRP_PTABLE *ptbl, TR_NAME *gssname);
+TRP_PEER *trp_ptable_find_servicename(TRP_PTABLE *ptbl, TR_NAME *servicename);
+char *trp_ptable_to_str(TALLOC_CTX *memctx, TRP_PTABLE *ptbl, const char *sep, const char *lineterm);
+
+TRP_PTABLE_ITER *trp_ptable_iter_new(TALLOC_CTX *mem_ctx);
+TRP_PEER *trp_ptable_iter_first(TRP_PTABLE_ITER *iter, TRP_PTABLE *ptbl);
+TRP_PEER *trp_ptable_iter_next(TRP_PTABLE_ITER *iter);
+void trp_ptable_iter_free(TRP_PTABLE_ITER *iter);
+
+TRP_PEER *trp_peer_new(TALLOC_CTX *memctx);
+void trp_peer_free(TRP_PEER *peer);
+TR_NAME *trp_peer_get_label(TRP_PEER *peer);
+TR_NAME *trp_peer_dup_label(TRP_PEER *peer);
+char *trp_peer_get_server(TRP_PEER *peer);
+void trp_peer_set_server(TRP_PEER *peer, const char *server);
+void trp_peer_add_gss_name(TRP_PEER *peer, TR_NAME *gssname);
+void trp_peer_set_gss_names(TRP_PEER *peer, TR_GSS_NAMES *gss_names);
+TR_GSS_NAMES *trp_peer_get_gss_names(TRP_PEER *peer);
+TR_NAME *trp_peer_get_servicename(TRP_PEER *peer);
+TR_NAME *trp_peer_dup_servicename(TRP_PEER *peer);
+unsigned int trp_peer_get_port(TRP_PEER *peer);
+void trp_peer_set_port(TRP_PEER *peer, unsigned int port);
+unsigned int trp_peer_get_linkcost(TRP_PEER *peer);
+struct timespec *trp_peer_get_last_conn_attempt(TRP_PEER *peer);
+void trp_peer_set_last_conn_attempt(TRP_PEER *peer, struct timespec *time);
+TRP_PEER_CONN_STATUS trp_peer_get_outgoing_status(TRP_PEER *peer);
+void trp_peer_set_outgoing_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status);
+TRP_PEER_CONN_STATUS trp_peer_get_incoming_status(TRP_PEER *peer);
+void trp_peer_set_incoming_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status);
+int trp_peer_is_connected(TRP_PEER *peer);
+void trp_peer_set_linkcost(TRP_PEER *peer, unsigned int linkcost);
+void trp_peer_set_conn_status_cb(TRP_PEER *peer, void (*cb)(TRP_PEER *, void *), void *cookie);
+char *trp_peer_to_str(TALLOC_CTX *memctx, TRP_PEER *peer, const char *sep);
+
+#endif /* _TRP_PTABLE_H_ */
--- /dev/null
+#ifndef _TRP_RTABLE_H_
+#define _TRP_RTABLE_H_
+
+#include <glib.h>
+#include <talloc.h>
+#include <time.h>
+
+#include <trp_internal.h>
+
+typedef struct trp_route {
+ TR_NAME *comm;
+ TR_NAME *realm;
+ TR_NAME *peer;
+ unsigned int metric;
+ TR_NAME *trust_router; /* hostname */
+ unsigned int trp_port;
+ unsigned int tid_port;
+ TR_NAME *next_hop;
+ int selected;
+ unsigned int interval; /* interval from route update */
+ struct timespec *expiry;
+ int local; /* is this a local route? */
+ int triggered;
+} TRP_ROUTE;
+
+typedef GHashTable TRP_RTABLE;
+
+TRP_RTABLE *trp_rtable_new(void);
+void trp_rtable_free(TRP_RTABLE *rtbl);
+void trp_rtable_add(TRP_RTABLE *rtbl, TRP_ROUTE *entry); /* adds or updates */
+void trp_rtable_remove(TRP_RTABLE *rtbl, TRP_ROUTE *entry);
+void trp_rtable_clear(TRP_RTABLE *rtbl);
+size_t trp_rtable_size(TRP_RTABLE *rtbl);
+size_t trp_rtable_comm_size(TRP_RTABLE *rtbl, TR_NAME *comm);
+size_t trp_rtable_realm_size(TRP_RTABLE *rtbl, TR_NAME *comm, TR_NAME *realm);
+TRP_ROUTE **trp_rtable_get_entries(TRP_RTABLE *rtbl, size_t *n_out);
+TR_NAME **trp_rtable_get_comms(TRP_RTABLE *rtbl, size_t *n_out);
+TRP_ROUTE **trp_rtable_get_comm_entries(TRP_RTABLE *rtbl, TR_NAME *comm, size_t *n_out);
+TR_NAME **trp_rtable_get_comm_realms(TRP_RTABLE *rtbl, TR_NAME *comm, size_t *n_out);
+TRP_ROUTE **trp_rtable_get_realm_entries(TRP_RTABLE *rtbl, TR_NAME *comm, TR_NAME *realm, size_t *n_out);
+TR_NAME **trp_rtable_get_comm_realm_peers(TRP_RTABLE *rtbl, TR_NAME *comm, TR_NAME *realm, size_t *n_out);
+TRP_ROUTE *trp_rtable_get_entry(TRP_RTABLE *rtbl, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer);
+TRP_ROUTE *trp_rtable_get_selected_entry(TRP_RTABLE *rtbl, TR_NAME *comm, TR_NAME *realm);
+void trp_rtable_clear_triggered(TRP_RTABLE *rtbl);
+char *trp_rtable_to_str(TALLOC_CTX *mem_ctx, TRP_RTABLE *rtbl, const char *sep, const char *lineterm);
+
+TRP_ROUTE *trp_route_new(TALLOC_CTX *mem_ctx);
+void trp_route_free(TRP_ROUTE *entry);
+void trp_route_set_comm(TRP_ROUTE *entry, TR_NAME *comm);
+TR_NAME *trp_route_get_comm(TRP_ROUTE *entry);
+TR_NAME *trp_route_dup_comm(TRP_ROUTE *entry);
+void trp_route_set_realm(TRP_ROUTE *entry, TR_NAME *realm);
+TR_NAME *trp_route_get_realm(TRP_ROUTE *entry);
+TR_NAME *trp_route_dup_realm(TRP_ROUTE *entry);
+void trp_route_set_trust_router(TRP_ROUTE *entry, TR_NAME *tr);
+TR_NAME *trp_route_get_trust_router(TRP_ROUTE *entry);
+TR_NAME *trp_route_dup_trust_router(TRP_ROUTE *entry);
+void trp_route_set_peer(TRP_ROUTE *entry, TR_NAME *peer);
+TR_NAME *trp_route_get_peer(TRP_ROUTE *entry);
+TR_NAME *trp_route_dup_peer(TRP_ROUTE *entry);
+void trp_route_set_metric(TRP_ROUTE *entry, unsigned int metric);
+unsigned int trp_route_get_metric(TRP_ROUTE *entry);
+void trp_route_set_next_hop(TRP_ROUTE *entry, TR_NAME *next_hop);
+TR_NAME *trp_route_get_next_hop(TRP_ROUTE *entry);
+TR_NAME *trp_route_dup_next_hop(TRP_ROUTE *entry);
+void trp_route_set_selected(TRP_ROUTE *entry, int sel);
+int trp_route_is_selected(TRP_ROUTE *entry);
+void trp_route_set_interval(TRP_ROUTE *entry, int interval);
+int trp_route_get_interval(TRP_ROUTE *entry);
+void trp_route_set_expiry(TRP_ROUTE *entry, struct timespec *exp);
+struct timespec *trp_route_get_expiry(TRP_ROUTE *entry);
+void trp_route_set_local(TRP_ROUTE *entry, int local);
+int trp_route_is_local(TRP_ROUTE *entry);
+void trp_route_set_triggered(TRP_ROUTE *entry, int trig);
+int trp_route_is_triggered(TRP_ROUTE *entry);
+char *trp_route_to_str(TALLOC_CTX *mem_ctx, TRP_ROUTE *entry, const char *sep);
+
+#endif /* _TRP_RTABLE_H_ */
#ifndef TID_H
#define TID_H
+#include <talloc.h>
+
#include <arpa/inet.h>
#include <openssl/dh.h>
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);
TR_EXPORT void *tid_req_get_cookie(TID_REQ *req);
void tid_req_set_cookie(TID_REQ *req, void *cookie);
TR_EXPORT TID_REQ *tid_dup_req (TID_REQ *orig_req);
-void TR_EXPORT tid_req_free( TID_REQ *req);
+TR_EXPORT void tid_req_free( TID_REQ *req);
/* Utility functions for TID_RESP structure, in tid/tid_resp.c */
+
+TID_RESP *tid_resp_new(TALLOC_CTX *mem_ctx);
+void tid_resp_free(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 void tidc_destroy (TIDC_INSTANCE *tidc);
/* TID Server functions, in tid/tids.c */
-TR_EXPORT TIDS_INSTANCE *tids_create (void);
+TR_EXPORT TIDS_INSTANCE *tids_create (TALLOC_CTX *mem_ctx);
TR_EXPORT int tids_start (TIDS_INSTANCE *tids, TIDS_REQ_FUNC *req_handler,
- tids_auth_func *auth_handler, const char *hostname,
+ 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);
+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_EXPORT void tids_destroy (TIDS_INSTANCE *tids);
#ifndef TR_CONSTRAINT_H
#define TR_CONSTRAINT_H
+
+#include <talloc.h>
+
#include <trust_router/tr_name.h>
#include <trust_router/tid.h>
TR_NAME *matches[TR_MAX_CONST_MATCHES];
} TR_CONSTRAINT;
+TR_CONSTRAINT *tr_constraint_new(TALLOC_CTX *mem_ctx);
+void tr_constraint_free(TR_CONSTRAINT *cons);
+
void TR_EXPORT tr_constraint_add_to_set (TR_CONSTRAINT_SET **cs, TR_CONSTRAINT *c);
int TR_EXPORT tr_constraint_set_validate( TR_CONSTRAINT_SET *);
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);
#endif
--- /dev/null
+#ifndef TRP_H
+#define TRP_H
+
+#include <talloc.h>
+
+#define TRP_PORT 12308
+#define TRP_METRIC_INFINITY 0xFFFF
+#define TRP_METRIC_INVALID 0xFFFFFFFF
+#define trp_metric_is_finite(x) (((x)<TRP_METRIC_INFINITY) && ((x)!=TRP_METRIC_INVALID))
+#define trp_metric_is_infinite(x) ((x)==TRP_METRIC_INFINITY)
+#define trp_metric_is_valid(x) (((x)<=TRP_METRIC_INFINITY) && ((x)!=TRP_METRIC_INVALID))
+#define trp_metric_is_invalid(x) (((x)>TRP_METRIC_INFINITY) || ((x)==TRP_METRIC_INVALID))
+#define TRP_INTERVAL_INVALID 0
+
+#define TRP_LINKCOST_DEFAULT 1
+
+typedef enum trp_rc {
+ TRP_SUCCESS=0,
+ TRP_ERROR, /* generic error */
+ TRP_NOPARSE, /* parse error */
+ TRP_NOMEM, /* allocation error */
+ TRP_BADTYPE, /* typing error */
+ TRP_UNSUPPORTED, /* unsupported feature */
+ TRP_BADARG, /* bad argument */
+ TRP_CLOCKERR, /* error reading time */
+} TRP_RC;
+
+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;
+
+typedef struct trp_inforec TRP_INFOREC;
+
+typedef struct trp_update TRP_UPD;
+typedef struct trp_req TRP_REQ;
+
+/* Functions for TRP_UPD structures */
+TR_EXPORT TRP_UPD *trp_upd_new(TALLOC_CTX *mem_ctx);
+void trp_upd_free(TRP_UPD *update);
+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_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);
+
+/* Functions for TRP_REQ structures */
+TR_EXPORT TRP_REQ *trp_req_new(TALLOC_CTX *mem_ctx);
+TR_EXPORT void trp_req_free(TRP_REQ *req);
+TR_EXPORT TR_NAME *trp_req_get_comm(TRP_REQ *req);
+void trp_req_set_comm(TRP_REQ *req, TR_NAME *comm);
+TR_EXPORT TR_NAME *trp_req_get_realm(TRP_REQ *req);
+void trp_req_set_realm(TRP_REQ *req, TR_NAME *realm);
+TR_EXPORT TR_NAME *trp_req_get_peer(TRP_REQ *req);
+void trp_req_set_peer(TRP_REQ *req, TR_NAME *peer);
+int trp_req_is_wildcard(TRP_REQ *req);
+TRP_RC trp_req_make_wildcard(TRP_REQ *req);
+
+#endif /* TRP_H */
#include <talloc.h>
#include <sqlite3.h>
#include <argp.h>
+#include <poll.h>
#include <tr_debug.h>
#include <tid_internal.h>
char *argv[])
{
TIDS_INSTANCE *tids;
- int rc = 0;
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())) {
+ if (NULL == (tids = tids_create(NULL))) {
tr_crit("Unable to create TIDS instance, exiting.");
return 1;
}
tids->ipaddr = opts.ip_address;
- /* Start-up the server, won't return unless there is an error. */
- rc = tids_start(tids, &tids_req_handler , auth_handler, opts.hostname, TID_PORT, gssname);
-
- tr_crit("Error in tids_start(), rc = %d. Exiting.", rc);
+ /* 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 */
+ }
/* Clean-up the TID server instance */
tids_destroy(tids);
gss_delete_sec_context( &minor, &req->gssctx, NULL);
}
}
+ if (req->rp_realm!=NULL)
+ tr_free_name(req->rp_realm);
+ if (req->realm!=NULL)
+ tr_free_name(req->realm);
+ if (req->comm!=NULL)
+ tr_free_name(req->comm);
+ if (req->orig_coi!=NULL)
+ tr_free_name(req->orig_coi);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
+#include <talloc.h>
#include <tid_internal.h>
+static int tid_resp_destructor(void *obj)
+{
+ TID_RESP *resp=talloc_get_type_abort(obj, TID_RESP);
+ if (resp->err_msg!=NULL)
+ tr_free_name(resp->err_msg);
+ 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);
+ return 0;
+}
+
+TID_RESP *tid_resp_new(TALLOC_CTX *mem_ctx)
+{
+ TID_RESP *resp=talloc(mem_ctx, TID_RESP);
+ if (resp!=NULL) {
+ resp->result=TID_ERROR;
+ resp->err_msg=NULL;
+ resp->rp_realm=NULL;
+ resp->realm=NULL;
+ resp->comm=NULL;
+ 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);
+ }
+ return resp;
+}
+
+void tid_resp_free(TID_RESP *resp)
+{
+ if (resp)
+ talloc_free(resp);
+}
+
TR_EXPORT int tid_resp_get_result(TID_RESP *resp)
{
return(resp->result);
else
use_port = port;
+ tr_debug("tidc_open_connection: opening tidc connection to %s:%d", server, port);
err = gsscon_connect(server, use_port, "trustidentity", &conn, gssctx);
if (!err)
goto error;
}
- if (resp_handler)
+ if (resp_handler) {
/* Call the caller's response function */
+ tr_debug("tidc_fwd_request: calling response callback function.");
(*resp_handler)(tidc, tid_req, tr_msg_get_resp(resp_msg), cookie);
+ }
goto cleanup;
error:
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
+#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
static TID_RESP *tids_create_response (TIDS_INSTANCE *tids, TID_REQ *req)
{
- TID_RESP *resp;
+ TID_RESP *resp=NULL;
+ int success=0;
if ((NULL == (resp = talloc_zero(req, TID_RESP)))) {
tr_crit("tids_create_response: Error allocating response structure.");
(NULL == (resp->realm = tr_dup_name(req->realm))) ||
(NULL == (resp->comm = tr_dup_name(req->comm)))) {
tr_crit("tids_create_response: Error allocating fields in response.");
- return NULL;
+ goto cleanup;
}
if (req->orig_coi) {
if (NULL == (resp->orig_coi = tr_dup_name(req->orig_coi))) {
tr_crit("tids_create_response: Error allocating fields in response.");
- return NULL;
+ goto cleanup;
}
}
+
+ success=1;
+
+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;
}
}
/* returns 0 on authorization success, 1 on failure, or -1 in case of error */
-static int tids_auth_connection (struct tids_instance *inst,
- int conn, gss_ctx_id_t *gssctx)
+static int tids_auth_connection (TIDS_INSTANCE *inst,
+ int conn,
+ gss_ctx_id_t *gssctx)
{
int rc = 0;
int auth, autherr = 0;
nameLen = asprintf(&name, "trustidentity@%s", inst->hostname);
nameBuffer.length = nameLen;
nameBuffer.value = name;
-
+
if (rc = gsscon_passive_authenticate(conn, nameBuffer, gssctx, tids_auth_cb, inst)) {
tr_debug("tids_auth_connection: Error from gsscon_passive_authenticate(), rc = %d.", rc);
return -1;
static int tids_handle_request (TIDS_INSTANCE *tids, TR_MSG *mreq, TID_RESP *resp)
{
- int rc;
+ int rc=-1;
/* Check that this is a valid TID Request. If not, send an error return. */
if ((!tr_msg_get_req(mreq)) ||
return -1;
}
+ tr_debug("tids_handle_request: adding self to req path.");
tid_req_add_path(tr_msg_get_req(mreq), tids->hostname, tids->tids_port);
/* Call the caller's request handler */
/* TBD -- Handle different error returns/msgs */
if (0 > (rc = (*tids->req_handler)(tids, tr_msg_get_req(mreq), resp, tids->cookie))) {
/* set-up an error response */
+ tr_debug("tids_handle_request: req_handler returned error.");
resp->result = TID_ERROR;
if (!resp->err_msg) /* Use msg set by handler, if any */
resp->err_msg = tr_new_name("Internal processing error");
}
else {
/* set-up a success response */
+ tr_debug("tids_handle_request: req_handler returned success.");
resp->result = TID_SUCCESS;
resp->err_msg = NULL; /* No error msg on successful return */
}
tr_crit("tids_handle_connection: Error creating response structure.");
/* try to send an error */
tids_send_err_response(tids, tr_msg_get_req(mreq), "Error creating response.");
+ tr_msg_free_decoded(mreq);
return;
}
}
tids_destroy_response(tids, resp);
+ tr_msg_free_decoded(mreq);
return;
}
}
-TIDS_INSTANCE *tids_create (void)
+TIDS_INSTANCE *tids_create (TALLOC_CTX *mem_ctx)
+{
+ return talloc_zero(mem_ctx, TIDS_INSTANCE);
+}
+
+/* Get a listener for tids requests, returns its socket fd. Accept
+ * connections with tids_accept() */
+int tids_get_listener(TIDS_INSTANCE *tids,
+ TIDS_REQ_FUNC *req_handler,
+ TIDS_AUTH_FUNC *auth_handler,
+ const char *hostname,
+ unsigned int port,
+ void *cookie)
+{
+ int listen = -1;
+
+ 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) {
+ /* 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;
+ }
+ }
+
+ if (listen > 0) {
+ /* store the caller's request handler & cookie */
+ tids->req_handler = req_handler;
+ tids->auth_handler = auth_handler;
+ tids->hostname = hostname;
+ tids->cookie = cookie;
+ }
+
+ return listen;
+}
+
+/* Accept and process a connection on a port opened with tids_get_listener() */
+int tids_accept(TIDS_INSTANCE *tids, int listen)
{
- TIDS_INSTANCE *tids = NULL;
- if (tids = malloc(sizeof(TIDS_INSTANCE)))
- memset(tids, 0, sizeof(TIDS_INSTANCE));
- return tids;
+ int conn=-1;
+ int pid=-1;
+
+ if (0 > (conn = accept(listen, NULL, NULL))) {
+ perror("Error from TIDS Server accept()");
+ return 1;
+ }
+
+ if (0 > (pid = fork())) {
+ perror("Error on fork()");
+ return 1;
+ }
+
+ if (pid == 0) {
+ close(listen);
+ tids_handle_connection(tids, conn);
+ close(conn);
+ exit(0); /* exit to kill forked child process */
+ } else {
+ close(conn);
+ }
+
+ /* clean up any processes that have completed (TBD: move to main loop?) */
+ while (waitpid(-1, 0, WNOHANG) > 0);
+
+ return 0;
}
/* Process tids requests forever. Should not return except on error. */
int tids_start (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)
#include <stdlib.h>
#include <string.h>
+#include <talloc.h>
+#include <tr_config.h>
#include <tr.h>
-TR_INSTANCE *tr_create() {
- TR_INSTANCE *tr = NULL;
- if (tr = malloc(sizeof(TR_INSTANCE)))
- memset(tr, 0, sizeof(TR_INSTANCE));
+TR_INSTANCE *tr_create(TALLOC_CTX *mem_ctx) {
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_INSTANCE *tr=talloc_zero(tmp_ctx, TR_INSTANCE);
+ if (tr != NULL) {
+ tr->cfg_mgr=tr_cfg_mgr_new(tr);
+ if (tr->cfg_mgr != NULL) {
+ /* success, hand over ownership */
+ talloc_steal(mem_ctx, tr);
+ }
+ }
+ talloc_free(tmp_ctx);
return tr;
}
void tr_destroy(TR_INSTANCE *tr) {
- free (tr);
+ talloc_free (tr);
}
--- /dev/null
+/***** config file watching *****/
+
+#include <sys/stat.h>
+#include <talloc.h>
+
+#include <tr_config.h>
+#include <tr_debug.h>
+#include <tr_event.h>
+#include <tr_cfgwatch.h>
+
+/* Initialize a new tr_cfgwatch_data struct. Free this with talloc. */
+TR_CFGWATCH *tr_cfgwatch_create(TALLOC_CTX *mem_ctx)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_CFGWATCH *new_cfg;
+
+ new_cfg=talloc_zero(tmp_ctx, TR_CFGWATCH);
+ if (new_cfg == NULL) {
+ tr_debug("tr_cfgwatch_create: Allocation failed.");
+ }
+ talloc_steal(mem_ctx, new_cfg);
+ talloc_free(tmp_ctx);
+ return new_cfg;
+}
+
+/* Obtain the file modification time as seconds since epoch. Returns 0 on success. */
+static int tr_get_mtime(const char *path, struct timespec *ts)
+{
+ struct stat file_status;
+
+ if (stat(path, &file_status) != 0) {
+ return -1;
+ } else {
+ (*ts)=file_status.st_mtim;
+ }
+ return 0;
+}
+
+static char *tr_join_paths(TALLOC_CTX *mem_ctx, const char *p1, const char *p2)
+{
+ return talloc_asprintf(mem_ctx, "%s/%s", p1, p2); /* returns NULL on a failure */
+}
+
+static int tr_fstat_namecmp(const void *p1_arg, const void *p2_arg)
+{
+ struct tr_fstat *p1=(struct tr_fstat *) p1_arg;
+ struct tr_fstat *p2=(struct tr_fstat *) p2_arg;
+
+ return strcmp(p1->name, p2->name);
+}
+
+static int tr_fstat_mtimecmp(const void *p1_arg, const void *p2_arg)
+{
+ struct tr_fstat *p1=(struct tr_fstat *) p1_arg;
+ struct tr_fstat *p2=(struct tr_fstat *) p2_arg;
+
+ if (p1->mtime.tv_sec == p2->mtime.tv_sec)
+ return (p1->mtime.tv_nsec) - (p2->mtime.tv_nsec);
+ else
+ return (p1->mtime.tv_sec) - (p2->mtime.tv_sec);
+}
+
+/* Get status of all files in cfg_files. Returns list, or NULL on error.
+ * Files are sorted by filename.
+ * After success, caller must eventually free result with talloc_free. */
+static struct tr_fstat *tr_fstat_get_all(TALLOC_CTX *mem_ctx,
+ const char *config_path,
+ struct dirent **cfg_files,
+ int n_files)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ struct tr_fstat *fstat_list=NULL;
+ int ii=0;
+
+ /* create a new fstat list (may be discarded) */
+ fstat_list=talloc_array(tmp_ctx, struct tr_fstat, n_files);
+ if (fstat_list==NULL) {
+ tr_err("tr_fstat_get_all: Could not allocate fstat list.");
+ goto cleanup;
+ }
+
+ for (ii=0; ii<n_files; ii++) {
+ fstat_list[ii].name=talloc_strdup(fstat_list, cfg_files[ii]->d_name);
+ if (0 != tr_get_mtime(tr_join_paths(tmp_ctx, config_path, fstat_list[ii].name),
+ &(fstat_list[ii].mtime))) {
+ tr_warning("tr_fstat_get_all: Could not obtain mtime for file %s", fstat_list[ii].name);
+ }
+ }
+
+ /* sort the list */
+ qsort(fstat_list, n_files, sizeof(struct tr_fstat), tr_fstat_namecmp);
+
+ /* put list in the caller's context and return it */
+ talloc_steal(mem_ctx, fstat_list);
+ cleanup:
+ talloc_free(tmp_ctx);
+ return fstat_list;
+}
+
+/* Checks whether any config files have appeared/disappeared/modified.
+ * Returns 1 if so, 0 otherwise. */
+static int tr_cfgwatch_update_needed(TR_CFGWATCH *cfg_status)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ struct tr_fstat *fstat_list=NULL;
+ int n_files=0;
+ int ii=0;
+ struct dirent **cfg_files=NULL;
+ int update_needed=0; /* return value */
+
+ /* get the list, must free cfg_files later with tr_free_cfg_file_list */
+ n_files = tr_find_config_files(cfg_status->config_dir, &cfg_files);
+ if (n_files <= 0) {
+ tr_warning("tr_cfgwatch_update: configuration files disappeared, skipping update.");
+ goto cleanup;
+ }
+
+ /* create a new fstat list (will be discarded) */
+ fstat_list=tr_fstat_get_all(tmp_ctx, cfg_status->config_dir, cfg_files, n_files);
+ if (fstat_list==NULL) {
+ tr_err("tr_cfgwatch_update: Error getting fstat list.");
+ goto cleanup;
+ }
+
+ /* see if the number of files change, if so need to update */
+ if (n_files != cfg_status->n_files) {
+ tr_debug("tr_cfgwatch_update: Changed number of config files (was %d, now %d).",
+ cfg_status->n_files,
+ n_files);
+ update_needed=1;
+ talloc_free(cfg_status->fstat_list);
+ cfg_status->n_files=n_files;
+ cfg_status->fstat_list=fstat_list;
+ talloc_steal(cfg_status, fstat_list);
+ goto cleanup;
+ }
+
+ /* See if any files have a changed mtime. Both are sorted by name so this is easy. */
+ for (ii=0; ii<n_files; ii++) {
+ if ((0 != tr_fstat_mtimecmp(&fstat_list[ii], &cfg_status->fstat_list[ii]))
+ || (0 != tr_fstat_namecmp(&fstat_list[ii], &cfg_status->fstat_list[ii]))){
+ update_needed=1;
+ talloc_free(cfg_status->fstat_list);
+ cfg_status->n_files=n_files;
+ cfg_status->fstat_list=fstat_list;
+ talloc_steal(cfg_status, fstat_list);
+ goto cleanup;
+ }
+ }
+
+ cleanup:
+ tr_free_config_file_list(n_files, &cfg_files);
+ talloc_free(tmp_ctx);
+ return update_needed;
+}
+
+/* must specify the ctx and tr in cfgwatch! */
+int tr_read_and_apply_config(TR_CFGWATCH *cfgwatch)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ char *config_dir=cfgwatch->config_dir;
+ int n_files = 0;
+ struct dirent **cfg_files=NULL;
+ TR_CFG_RC rc = TR_CFG_SUCCESS; /* presume success */
+ struct tr_fstat *new_fstat_list=NULL;
+ int retval=0;
+
+ /* find the configuration files -- n.b., tr_find_config_files()
+ * allocates memory to cfg_files which we must later free */
+ tr_debug("Reading configuration files from %s/", config_dir);
+ n_files = tr_find_config_files(config_dir, &cfg_files);
+ if (n_files <= 0) {
+ tr_debug("tr_read_and_apply_config: No configuration files.");
+ retval=1; goto cleanup;
+ }
+
+ /* Get the list of update times.
+ * Do this before loading in case they change between obtaining their timestamp
+ * and reading the file---this way they will immediately reload if this happens. */
+ new_fstat_list=tr_fstat_get_all(tmp_ctx, config_dir, cfg_files, n_files);
+ if (new_fstat_list==NULL) {
+ tr_debug("tr_read_and_apply_config: Could not allocate config file status list.");
+ retval=1; goto cleanup;
+ }
+
+ /* now fill it in (tr_parse_config allocates space for new config) */
+ if (TR_CFG_SUCCESS != (rc = tr_parse_config(cfgwatch->cfg_mgr, config_dir, n_files, cfg_files))) {
+ tr_debug("tr_read_and_apply_config: Error parsing configuration information, rc=%d.", rc);
+ retval=1; goto cleanup;
+ }
+
+ /* apply new configuration (nulls new, manages context ownership) */
+ if (TR_CFG_SUCCESS != (rc = tr_apply_new_config(cfgwatch->cfg_mgr))) {
+ tr_debug("tr_read_and_apply_config: Error applying configuration, rc = %d.", rc);
+ retval=1; goto cleanup;
+ }
+
+ /* call callback to notify system of new configuration */
+ tr_debug("tr_read_and_apply_config: calling update callback function.");
+ if (cfgwatch->update_cb!=NULL)
+ cfgwatch->update_cb(cfgwatch->cfg_mgr->active, cfgwatch->update_cookie);
+
+ /* give ownership of the new_fstat_list to caller's context */
+ if (cfgwatch->fstat_list != NULL) {
+ /* free the old one */
+ talloc_free(cfgwatch->fstat_list);
+ }
+ cfgwatch->n_files=n_files;
+ cfgwatch->fstat_list=new_fstat_list;
+ talloc_steal(cfgwatch, new_fstat_list);
+ new_fstat_list=NULL;
+
+ cleanup:
+ tr_free_config_file_list(n_files, &cfg_files);
+ talloc_free(tmp_ctx);
+ cfgwatch->cfg_mgr->new=NULL; /* this has been freed, either explicitly or with tmp_ctx */
+ return retval;
+}
+
+
+static void tr_cfgwatch_event_cb(int listener, short event, void *arg)
+{
+ TR_CFGWATCH *cfg_status=(TR_CFGWATCH *) arg;
+ struct timeval now, diff;;
+
+ if (tr_cfgwatch_update_needed(cfg_status)) {
+ tr_notice("Configuration file change detected, waiting for changes to settle.");
+ cfg_status->change_detected=1;
+
+ if (0 != gettimeofday(&cfg_status->last_change_detected, NULL)) {
+ tr_err("tr_cfgwatch_event_cb: gettimeofday() failed (1).");
+ }
+ }
+
+ if (cfg_status->change_detected) {
+ if (0 != gettimeofday(&now, NULL)) {
+ tr_err("tr_cfgwatch_event_cb: gettimeofday() failed (2).");
+ }
+ timersub(&now, &cfg_status->last_change_detected, &diff);
+ if (!timercmp(&diff, &cfg_status->settling_time, <)) {
+ tr_notice("Configuration file change settled, attempting to update configuration.");
+ if (0 != tr_read_and_apply_config(cfg_status))
+ tr_warning("Configuration file update failed. Using previous configuration.");
+ else
+ tr_notice("Configuration updated successfully.");
+ cfg_status->change_detected=0;
+ }
+ }
+}
+
+
+/* Configure the cfgwatch instance and set up its event handler.
+ * Returns 0 on success, nonzero on failure. Points
+ * *cfgwatch_ev to the event struct. */
+int tr_cfgwatch_event_init(struct event_base *base,
+ TR_CFGWATCH *cfg_status,
+ struct event **cfgwatch_ev)
+{
+ if (cfgwatch_ev == NULL) {
+ tr_debug("tr_cfgwatch_event_init: Null cfgwatch_ev.");
+ return 1;
+ }
+
+ /* zero out the change detection fields */
+ cfg_status->change_detected=0;
+ cfg_status->last_change_detected.tv_sec=0;
+ cfg_status->last_change_detected.tv_usec=0;
+
+ /* create the event and enable it */
+ *cfgwatch_ev=event_new(base, -1, EV_TIMEOUT|EV_PERSIST, tr_cfgwatch_event_cb, (void *)cfg_status);
+ event_add(*cfgwatch_ev, &(cfg_status->poll_interval));
+
+ tr_info("tr_cfgwatch_event_init: Added configuration file watcher with %0d.%06d second poll interval.",
+ cfg_status->poll_interval.tv_sec,
+ cfg_status->poll_interval.tv_usec);
+ return 0;
+}
+
--- /dev/null
+#include <event2/event.h>
+#include <event2/thread.h>
+
+#include <tr.h>
+#include <tid_internal.h>
+#include <tr_debug.h>
+#include <tr_event.h>
+
+/* Allocate and set up the event base, return a pointer
+ * to the new event_base or NULL on failure.
+ * Enables thread-safe mode. */
+struct event_base *tr_event_loop_init(void)
+{
+ struct event_base *base=NULL;
+
+ evthread_use_pthreads(); /* enable pthreads support */
+ base=event_base_new();
+ return base;
+}
+
+/* run the loop, does not normally return */
+int tr_event_loop_run(struct event_base *base)
+{
+ return event_base_dispatch(base);
+}
#include <stdlib.h>
#include <jansson.h>
#include <argp.h>
+#include <event2/event.h>
+#include <talloc.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <pthread.h>
-#include <tr.h>
-#include <tr_filter.h>
#include <tid_internal.h>
+#include <tr_tid.h>
+#include <tr_trp.h>
#include <tr_config.h>
-#include <tr_comm.h>
-#include <tr_idp.h>
-#include <tr_rp.h>
+#include <tr_event.h>
+#include <tr_cfgwatch.h>
+#include <tr.h>
#include <tr_debug.h>
-/* Structure to hold TR instance and original request in one cookie */
-typedef struct tr_resp_cookie {
- TR_INSTANCE *tr;
- TID_REQ *orig_req;
-} TR_RESP_COOKIE;
-
-
-static void tr_tidc_resp_handler (TIDC_INSTANCE *tidc,
- TID_REQ *req,
- TID_RESP *resp,
- void *resp_cookie)
-{
- 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)->tr->tids,
- ((TR_RESP_COOKIE *)resp_cookie)->orig_req,
- resp);
-
- return;
-}
-
-static int tr_tids_req_handler (TIDS_INSTANCE *tids,
- TID_REQ *orig_req,
- TID_RESP *resp,
- void *tr_in)
-{
- TIDC_INSTANCE *tidc = NULL;
- TR_RESP_COOKIE resp_cookie;
- TR_AAA_SERVER *aaa_servers = NULL;
- TR_NAME *apc = NULL;
- TID_REQ *fwd_req = NULL;
- TR_COMM *cfg_comm = NULL;
- TR_COMM *cfg_apc = NULL;
- TR_INSTANCE *tr = (TR_INSTANCE *) tr_in;
- int oaction = TR_FILTER_ACTION_REJECT;
- int rc = 0;
- time_t expiration_interval;
-
- if ((!tids) || (!orig_req) || (!resp) || (!tr)) {
- tr_debug("tr_tids_req_handler: Bad parameters");
- return -1;
- }
-
- tr_debug("tr_tids_req_handler: Request received (conn = %d)! Realm = %s, Comm = %s", orig_req->conn,
- orig_req->realm->buf, orig_req->comm->buf);
- if (tids)
- tids->req_count++;
+#define TALLOC_DEBUG_ENABLE 1
- /* Duplicate the request, so we can modify and forward it */
- if (NULL == (fwd_req = tid_dup_req(orig_req))) {
- tr_debug("tr_tids_req_handler: Unable to duplicate request.");
- return -1;
- }
-
- if (NULL == (cfg_comm = tr_comm_lookup(tids->cookie, 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");
- return -1;
- }
-
- /* Check that the rp_realm matches the filter for the GSS name that
- * was received. */
-
- if ((!(tr)->rp_gss) ||
- (!(tr)->rp_gss->filter)) {
- tr_notice("tr_tids_req_handler: No GSS name for incoming request.");
- tids_send_err_response(tids, orig_req, "No GSS name for request");
- return -1;
- }
-
- if ((TR_FILTER_NO_MATCH == tr_filter_process_rp_permitted(orig_req->rp_realm, (tr)->rp_gss->filter, orig_req->cons, &fwd_req->cons, &oaction)) ||
- (TR_FILTER_ACTION_REJECT == oaction)) {
- tr_notice("tr_tids_req_handler: RP realm (%s) does not match RP Realm filter for GSS name", orig_req->rp_realm->buf);
- tids_send_err_response(tids, orig_req, "RP Realm filter error");
- return -1;
- }
- /* 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))) {
- 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");
- return -1;
- }
-
- /* Map the comm in the request from a COI to an APC, if needed */
- if (TR_COMM_COI == cfg_comm->type) {
- tr_debug("tr_tids_req_handler: Community was a COI, switching.");
- /* TBD -- In theory there can be more than one? How would that work? */
- if ((!cfg_comm->apcs) || (!cfg_comm->apcs->id)) {
- tr_notice("No valid APC for COI %s.", orig_req->comm->buf);
- tids_send_err_response(tids, orig_req, "No valid APC for community");
- return -1;
- }
- apc = tr_dup_name(cfg_comm->apcs->id);
-
- /* Check that the APC is configured */
- if (NULL == (cfg_apc = tr_comm_lookup(tids->cookie, apc))) {
- tr_notice("tr_tids_req_hander: Request for unknown comm: %s.", apc->buf);
- tids_send_err_response(tids, orig_req, "Unknown APC");
- return -1;
- }
-
- fwd_req->comm = apc;
- 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))) {
- 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");
- return -1;
- }
- }
-
- /* Find the AAA server(s) for this request */
- if (NULL == (aaa_servers = tr_idp_aaa_server_lookup((TR_INSTANCE *)tids->cookie,
- orig_req->realm,
- orig_req->comm))) {
- tr_debug("tr_tids_req_handler: No AAA Servers for realm %s, defaulting.", orig_req->realm->buf);
- if (NULL == (aaa_servers = tr_default_server_lookup ((TR_INSTANCE *)tids->cookie,
- orig_req->comm))) {
- tr_notice("tr_tids_req_handler: No default AAA servers, discarded.");
- tids_send_err_response(tids, orig_req, "No path to AAA Server(s) for realm");
- return -1;
- }
- } else {
- /* if we aren't defaulting, check idp coi and apc membership */
- if (NULL == (tr_find_comm_idp(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");
- return -1;
- }
- if ( cfg_apc && (NULL == (tr_find_comm_idp(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");
- return -1;
- }
- }
-
- /* send a TID request to the AAA server(s), and get the answer(s) */
- /* TBD -- Handle multiple servers */
-
- 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");
- return -1;
- }
- /* 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.tr = tr;
- resp_cookie.orig_req = orig_req;
-
- /* 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");
- return -1;
- };
-
- /* 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");
- tid_req_free(orig_req);
- return -1;
- }
-
- tid_req_free(orig_req);
- return 0;
-}
-
-static int tr_tids_gss_handler(gss_name_t client_name, TR_NAME *gss_name,
- void *tr_in)
-{
- TR_RP_CLIENT *rp;
- TR_INSTANCE *tr = (TR_INSTANCE *) tr_in;
-
- if ((!client_name) || (!gss_name) || (!tr)) {
- tr_debug("tr_tidc_gss_handler: Bad parameters.");
- return -1;
- }
-
- /* look up the RP client matching the GSS name */
- if ((NULL == (rp = tr_rp_client_lookup(tr, gss_name)))) {
- tr_debug("tr_tids_gss_handler: Unknown GSS name %s", gss_name->buf);
- return -1;
- }
-
- /* Store the rp client in the TR_INSTANCE structure for now...
- * TBD -- fix me for new tasking model. */
- (tr)->rp_gss = rp;
- tr_debug("Client's GSS Name: %s", gss_name->buf);
-
- return 0;
-}
+/***** command-line option handling / setup *****/
/* Strip trailing / from a path name.*/
static void remove_trailing_slash(char *s) {
}
}
-/* command-line option setup */
-
/* argp global parameters */
const char *argp_program_bug_address=PACKAGE_BUGREPORT; /* bug reporting address */
static struct argp argp = {cmdline_options, parse_option, arg_doc, doc};
-int main (int argc, char *argv[])
+/***** talloc error handling *****/
+/* called when talloc tries to abort */
+static void tr_abort(const char *reason)
+{
+ tr_crit("tr_abort: Critical error, talloc aborted. Reason: %s", reason);
+ abort();
+}
+
+#if TALLOC_DEBUG_ENABLE
+static void tr_talloc_log(const char *msg)
{
+ tr_debug("talloc: %s", msg);
+}
+#endif /* TALLOC_DEBUG_ENABLE */
+
+static void configure_signals(void)
+{
+ sigset_t signals;
+ /* ignore SIGPIPE */
+ sigemptyset(&signals);
+ sigaddset(&signals, SIGPIPE);
+ pthread_sigmask(SIG_BLOCK, &signals, NULL);
+}
+
+int main(int argc, char *argv[])
+{
+ TALLOC_CTX *main_ctx=NULL;
+
TR_INSTANCE *tr = NULL;
- struct dirent **cfg_files = NULL;
- TR_CFG_RC rc = TR_CFG_SUCCESS; /* presume success */
- int err = 0, n = 0;
struct cmdline_args opts;
+ struct event_base *ev_base;
+ struct tr_socket_event tids_ev;
+ struct event *cfgwatch_ev;
+
+ configure_signals();
+
+ /* we're going to be multithreaded, so disable null context tracking */
+ talloc_set_abort_fn(tr_abort);
+ talloc_disable_null_tracking();
+#if TALLOC_DEBUG_ENABLE
+ talloc_set_log_fn(tr_talloc_log);
+#endif /* TALLOC_DEBUG_ENABLE */
+ main_ctx=talloc_new(NULL);
/* Use standalone logging */
tr_log_open();
- /* parse command-line arguments */
+ /***** parse command-line arguments *****/
/* set defaults */
opts.config_dir=".";
/* process options */
remove_trailing_slash(opts.config_dir);
- /* create a Trust Router instance */
- if (NULL == (tr = tr_create())) {
+ /***** create a Trust Router instance *****/
+ if (NULL == (tr = tr_create(main_ctx))) {
tr_crit("Unable to create Trust Router instance, exiting.");
return 1;
}
- /* find the configuration files -- n.b., tr_find_config_files()
- * allocates memory to cfg_files which we must later free */
- tr_debug("Reading configuration files from %s/", opts.config_dir);
- n = tr_find_config_files(opts.config_dir, &cfg_files);
- if (n <= 0) {
- tr_crit("Can't locate configuration files, exiting.");
- tr_free_config_file_list(n, &cfg_files);
- exit(1);
+ /***** initialize the trust path query server instance *****/
+ if (NULL == (tr->tids = tids_create (tr))) {
+ tr_crit("Error initializing Trust Path Query Server instance.");
+ return 1;
+ }
+
+ /***** initialize the trust router protocol server instance *****/
+ if (NULL == (tr->trps = trps_new(tr))) {
+ tr_crit("Error initializing Trust Router Protocol Server instance.");
+ return 1;
}
- if (TR_CFG_SUCCESS != tr_parse_config(tr, opts.config_dir, n, cfg_files)) {
- tr_crit("Error decoding configuration information, exiting.");
- tr_free_config_file_list(n, &cfg_files);
- exit(1);
+ /***** process configuration *****/
+ tr->cfgwatch=tr_cfgwatch_create(tr);
+ if (tr->cfgwatch == NULL) {
+ tr_crit("Unable to create configuration watcher object, exiting.");
+ return 1;
}
-
- /* we are now done with the config filenames, free those */
- tr_free_config_file_list(n, &cfg_files);
-
- /* apply initial configuration */
- if (TR_CFG_SUCCESS != (rc = tr_apply_new_config(tr))) {
- tr_crit("Error applying configuration, rc = %d.", rc);
- exit(1);
+ tr->cfgwatch->config_dir=opts.config_dir;
+ tr->cfgwatch->cfg_mgr=tr->cfg_mgr;
+ tr->cfgwatch->update_cb=tr_config_changed; /* handle configuration changes */
+ tr->cfgwatch->update_cookie=(void *)tr;
+ if (0 != tr_read_and_apply_config(tr->cfgwatch)) {
+ tr_crit("Error reading configuration, exiting.");
+ return 1;
}
- /* print the loaded configuration */
- tr_print_config(tr->active_cfg);
+ /***** Set up the event loop *****/
+ ev_base=tr_event_loop_init(); /* Set up the event loop */
+ if (ev_base==NULL) {
+ tr_crit("Error initializing event loop.");
+ return 1;
+ }
- /* initialize the trust path query server instance */
- if (0 == (tr->tids = tids_create ())) {
+ /* already set config_dir, fstat_list and n_files earlier */
+ if (0 != tr_cfgwatch_event_init(ev_base, tr->cfgwatch, &cfgwatch_ev)) {
+ tr_crit("Error initializing configuration file watcher.");
+ return 1;
+ }
+
+ /*tr_status_event_init();*/ /* install status reporting events */
+
+ /* install TID server events */
+ if (0 != tr_tids_event_init(ev_base,
+ tr->tids,
+ tr->cfg_mgr,
+ tr->trps,
+ &tids_ev)) {
tr_crit("Error initializing Trust Path Query Server instance.");
- exit(1);
+ return 1;
}
- /* start the trust path query server, won't return unless fatal error. */
- if (0 != (err = tids_start(tr->tids, &tr_tids_req_handler, &tr_tids_gss_handler, tr->active_cfg->internal->hostname, tr->active_cfg->internal->tids_port, (void *)tr))) {
- tr_crit("Error from Trust Path Query Server, err = %d.", err);
- exit(err);
+ /* install TRP handler events */
+ if (TRP_SUCCESS != tr_trps_event_init(ev_base, tr)) {
+ tr_crit("Error initializing Trust Path Query Server instance.");
+ return 1;
}
- tids_destroy(tr->tids);
- tr_destroy(tr);
- exit(0);
+ tr_event_loop_run(ev_base); /* does not return until we are done */
+
+ tr_destroy(tr); /* thanks to talloc, should destroy everything */
+
+ talloc_free(main_ctx);
+ return 0;
}
--- /dev/null
+#include <talloc.h>
+
+#include <tid_internal.h>
+#include <tr_filter.h>
+#include <tr_comm.h>
+#include <tr_idp.h>
+#include <tr_rp.h>
+#include <tr_event.h>
+#include <tr_debug.h>
+#include <gsscon.h>
+#include <trp_internal.h>
+#include <tr_config.h>
+#include <tr_tid.h>
+
+/* Structure to hold TR instance and original request in one cookie */
+typedef struct tr_resp_cookie {
+ TIDS_INSTANCE *tids;
+ TID_REQ *orig_req;
+} TR_RESP_COOKIE;
+
+/* hold a tids instance and a config manager */
+struct tr_tids_event_cookie {
+ TIDS_INSTANCE *tids;
+ TR_CFG_MGR *cfg_mgr;
+ TRPS_INSTANCE *trps;
+};
+
+
+static void tr_tidc_resp_handler (TIDC_INSTANCE *tidc,
+ TID_REQ *req,
+ TID_RESP *resp,
+ void *resp_cookie)
+{
+ 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;
+}
+
+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);;
+ TIDC_INSTANCE *tidc = NULL;
+ TR_RESP_COOKIE resp_cookie;
+ TR_AAA_SERVER *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;
+ int retval=-1;
+
+ if ((!tids) || (!orig_req) || (!resp)) {
+ tr_debug("tr_tids_req_handler: Bad parameters");
+ retval=-1;
+ goto cleanup;
+ }
+
+ tr_debug("tr_tids_req_handler: Request received (conn = %d)! Realm = %s, Comm = %s", orig_req->conn,
+ orig_req->realm->buf, orig_req->comm->buf);
+ tids->req_count++;
+
+ /* Duplicate the request, so we can modify and forward it */
+ if (NULL == (fwd_req = tid_dup_req(orig_req))) {
+ tr_debug("tr_tids_req_handler: Unable to duplicate request.");
+ retval=-1;
+ goto cleanup;
+ }
+
+ if (NULL == (cfg_comm = tr_comm_lookup(cfg_mgr->active->comms, 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;
+ goto cleanup;
+ }
+
+ /* Check that the rp_realm matches the filter for the GSS name that
+ * was received. */
+
+ if ((!tids->rp_gss) ||
+ (!tids->rp_gss->filter)) {
+ tr_notice("tr_tids_req_handler: No GSS name for incoming request.");
+ tids_send_err_response(tids, orig_req, "No GSS name for request");
+ retval=-1;
+ goto cleanup;
+ }
+
+ if ((TR_FILTER_NO_MATCH == tr_filter_process_rp_permitted(orig_req->rp_realm,
+ tids->rp_gss->filter,
+ orig_req->cons,
+ &fwd_req->cons,
+ &oaction)) ||
+ (TR_FILTER_ACTION_REJECT == oaction)) {
+ tr_notice("tr_tids_req_handler: RP realm (%s) does not match RP Realm filter for GSS name", orig_req->rp_realm->buf);
+ tids_send_err_response(tids, orig_req, "RP Realm filter error");
+ retval=-1;
+ 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))) {
+ 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;
+ goto cleanup;
+ }
+
+ /* Map the comm in the request from a COI to an APC, if needed */
+ if (TR_COMM_COI == cfg_comm->type) {
+ tr_debug("tr_tids_req_handler: Community was a COI, switching.");
+ /* TBD -- In theory there can be more than one? How would that work? */
+ if ((!cfg_comm->apcs) || (!cfg_comm->apcs->id)) {
+ tr_notice("No valid APC for COI %s.", orig_req->comm->buf);
+ tids_send_err_response(tids, orig_req, "No valid APC for community");
+ retval=-1;
+ goto cleanup;
+ }
+ 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))) {
+ tr_notice("tr_tids_req_hander: Request for unknown comm: %s.", apc->buf);
+ tids_send_err_response(tids, orig_req, "Unknown APC");
+ retval=-1;
+ goto cleanup;
+ }
+
+ fwd_req->comm = apc;
+ 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))) {
+ 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;
+ goto cleanup;
+ }
+ }
+
+ /* Look up the route for this community/realm. */
+ tr_debug("tr_tids_req_handler: looking up route.");
+ route=trps_get_selected_route(trps, orig_req->comm, orig_req->realm);
+ if (route==NULL) {
+ tr_notice("tr_tids_req_handler: no route table entry found for realm (%s) in community (%s).",
+ orig_req->realm->buf, orig_req->comm->buf);
+ tids_send_err_response(tids, orig_req, "Missing trust route error");
+ retval=-1;
+ goto cleanup;
+ }
+ 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,
+ orig_req->realm,
+ orig_req->comm);
+ } else {
+ tr_debug("tr_tids_req_handler: route not local.");
+ aaa_servers = tr_aaa_server_new(tmp_ctx, trp_route_get_next_hop(route));
+ }
+
+ /* Find the AAA server(s) for this request */
+ if (NULL == aaa_servers) {
+ tr_debug("tr_tids_req_handler: No AAA Servers for realm %s, defaulting.", orig_req->realm->buf);
+ if (NULL == (aaa_servers = tr_default_server_lookup (cfg_mgr->active->default_servers,
+ orig_req->comm))) {
+ tr_notice("tr_tids_req_handler: No default AAA servers, discarded.");
+ tids_send_err_response(tids, orig_req, "No path to AAA Server(s) for realm");
+ retval=-1;
+ goto cleanup;
+ }
+ } else {
+ /* if we aren't defaulting, check idp coi and apc membership */
+ if (NULL == (tr_find_comm_idp(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)))) {
+ 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;
+ goto cleanup;
+ }
+ }
+
+ /* send a TID request to the AAA server(s), and get the answer(s) */
+ /* TBD -- Handle multiple servers */
+
+ 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");
+ 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;
+
+ /* 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");
+ retval=-1;
+ goto cleanup;
+ };
+
+ /* 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");
+ retval=-1;
+ goto cleanup;
+ }
+
+ /* success! */
+ retval=0;
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return retval;
+}
+
+static int tr_tids_gss_handler(gss_name_t client_name, TR_NAME *gss_name,
+ void *data)
+{
+ TR_RP_CLIENT *rp;
+ struct tr_tids_event_cookie *cookie=talloc_get_type_abort(data, struct tr_tids_event_cookie);
+ TIDS_INSTANCE *tids = cookie->tids;
+ TR_CFG_MGR *cfg_mgr = cookie->cfg_mgr;
+
+ if ((!client_name) || (!gss_name) || (!tids) || (!cfg_mgr)) {
+ tr_debug("tr_tidc_gss_handler: Bad parameters.");
+ return -1;
+ }
+
+ /* look up the RP client matching the GSS name */
+ if ((NULL == (rp = tr_rp_client_lookup(cfg_mgr->active->rp_clients, gss_name)))) {
+ tr_debug("tr_tids_gss_handler: Unknown GSS name %s", gss_name->buf);
+ return -1;
+ }
+
+ /* Store the rp client */
+ tids->rp_gss = rp;
+ tr_debug("Client's GSS Name: %s", gss_name->buf);
+
+ return 0;
+}
+
+
+/***** TIDS event handling *****/
+
+/* called when a connection to the TIDS port is received */
+static void tr_tids_event_cb(int listener, short event, void *arg)
+{
+ TIDS_INSTANCE *tids = (TIDS_INSTANCE *)arg;
+
+ if (0==(event & EV_READ))
+ tr_debug("tr_tids_event_cb: unexpected event on TIDS socket (event=0x%X)", event);
+ else
+ tids_accept(tids, listener);
+}
+
+/* Configure the tids instance and set up its event handler.
+ * Returns 0 on success, nonzero on failure. Fills in
+ * *tids_event (which should be allocated by caller). */
+int tr_tids_event_init(struct event_base *base,
+ TIDS_INSTANCE *tids,
+ TR_CFG_MGR *cfg_mgr,
+ TRPS_INSTANCE *trps,
+ struct tr_socket_event *tids_ev)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ struct tr_tids_event_cookie *cookie=NULL;
+ int retval=0;
+
+ if (tids_ev == NULL) {
+ tr_debug("tr_tids_event_init: Null tids_ev.");
+ retval=1;
+ goto cleanup;
+ }
+
+ /* Create the cookie for callbacks. We'll put it in the tids context, so it will
+ * be cleaned up when tids is freed by talloc_free. */
+ cookie=talloc(tmp_ctx, struct tr_tids_event_cookie);
+ if (cookie == NULL) {
+ tr_debug("tr_tids_event_init: Unable to allocate cookie.");
+ retval=1;
+ goto cleanup;
+ }
+ cookie->tids=tids;
+ cookie->cfg_mgr=cfg_mgr;
+ cookie->trps=trps;
+ 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) {
+ 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);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return retval;
+}
--- /dev/null
+#include <stdio.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <event2/event.h>
+#include <talloc.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <gsscon.h>
+#include <tr.h>
+#include <tr_mq.h>
+#include <tr_rp.h>
+#include <trp_internal.h>
+#include <trp_ptable.h>
+#include <trp_rtable.h>
+#include <tr_config.h>
+#include <tr_event.h>
+#include <tr_msg.h>
+#include <tr_trp.h>
+#include <tr_debug.h>
+
+/* data for event callbacks */
+struct tr_trps_event_cookie {
+ TRPS_INSTANCE *trps;
+ TR_CFG_MGR *cfg_mgr;
+ struct event *ev;
+};
+
+/* callback to schedule event to process messages */
+static void tr_trps_mq_cb(TR_MQ *mq, void *arg)
+{
+ struct event *mq_ev=(struct event *)arg;
+ event_active(mq_ev, 0, 0);
+}
+
+static void msg_free_helper(void *p)
+{
+ tr_msg_free_decoded((TR_MSG *)p);
+}
+
+static void tr_free_name_helper(void *arg)
+{
+ tr_free_name((TR_NAME *)arg);
+}
+
+/* takes a TR_MSG and puts it in a TR_MQ_MSG for processing by the main thread */
+static TRP_RC tr_trps_msg_handler(TRPS_INSTANCE *trps,
+ TRP_CONNECTION *conn,
+ TR_MSG *tr_msg)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_MQ_MSG *mq_msg=NULL;
+
+ /* n.b., conn is available here, but do not hold onto the reference
+ * because it may be cleaned up if the originating connection goes
+ * down before the message is processed */
+ mq_msg=tr_mq_msg_new(tmp_ctx, TR_MQMSG_MSG_RECEIVED, TR_MQ_PRIO_NORMAL);
+ if (mq_msg==NULL) {
+ return TRP_NOMEM;
+ }
+ tr_mq_msg_set_payload(mq_msg, (void *)tr_msg, msg_free_helper);
+ trps_mq_add(trps, mq_msg);
+ talloc_free(tmp_ctx); /* cleans up the message if it did not get appended correctly */
+ return TRP_SUCCESS;
+}
+
+
+static int tr_trps_gss_handler(gss_name_t client_name, gss_buffer_t gss_name,
+ void *cookie_in)
+{
+ struct tr_trps_event_cookie *cookie=(struct tr_trps_event_cookie *)cookie_in;
+ TRPS_INSTANCE *trps = cookie->trps;
+ TR_CFG_MGR *cfg_mgr = cookie->cfg_mgr;
+ TR_NAME name={gss_name->value, gss_name->length};
+
+ tr_debug("tr_trps_gss_handler()");
+
+ if ((!client_name) || (!gss_name) || (!trps) || (!cfg_mgr)) {
+ tr_debug("tr_trps_gss_handler: Bad parameters.");
+ return -1;
+ }
+
+ /* look up the TRPS peer matching the GSS name */
+ if (NULL==trps_get_peer_by_gssname(trps, &name)) {
+ tr_warning("tr_trps_gss_handler: Connection attempt from unknown peer (GSS name: %.*s).", name.len, name.buf);
+ return -1;
+ }
+
+ tr_debug("Client's GSS Name: %.*s", name.len, name.buf);
+ return 0;
+}
+
+/* data passed to thread */
+struct trps_thread_data {
+ TRP_CONNECTION *conn;
+ TRPS_INSTANCE *trps;
+};
+/* thread to handle GSS connections from peers */
+static void *tr_trps_thread(void *arg)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ struct trps_thread_data *thread_data=talloc_get_type_abort(arg, struct trps_thread_data);
+ TRP_CONNECTION *conn=thread_data->conn;
+ TRPS_INSTANCE *trps=thread_data->trps;
+ TR_MQ_MSG *msg=NULL;
+
+ tr_debug("tr_trps_thread: started");
+ if (trps_authorize_connection(trps, conn)!=TRP_SUCCESS)
+ goto cleanup;
+
+ msg=tr_mq_msg_new(tmp_ctx, TR_MQMSG_TRPS_CONNECTED, TR_MQ_PRIO_HIGH);
+ tr_mq_msg_set_payload(msg, (void *)tr_dup_name(trp_connection_get_peer(conn)), tr_free_name_helper);
+ if (msg==NULL) {
+ tr_err("tr_trps_thread: error allocating TR_MQ_MSG");
+ goto cleanup;
+ }
+ trps_mq_add(trps, msg); /* steals msg context */
+ msg=NULL;
+
+ trps_handle_connection(trps, conn);
+
+cleanup:
+ msg=tr_mq_msg_new(tmp_ctx, TR_MQMSG_TRPS_DISCONNECTED, TR_MQ_PRIO_HIGH);
+ tr_mq_msg_set_payload(msg, (void *)conn, NULL); /* do not pass a free routine */
+ if (msg==NULL)
+ tr_err("tr_trps_thread: error allocating TR_MQ_MSG");
+ else
+ trps_mq_add(trps, msg);
+ tr_debug("tr_trps_thread: exit");
+ talloc_free(tmp_ctx);
+ return NULL;
+}
+
+/* called when a connection to the TRPS port is received */
+static void tr_trps_event_cb(int listener, short event, void *arg)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TRPS_INSTANCE *trps = talloc_get_type_abort(arg, TRPS_INSTANCE); /* aborts on wrong type */
+ TRP_CONNECTION *conn=NULL;
+ TR_NAME *gssname=NULL;
+ char *name=NULL;
+ struct trps_thread_data *thread_data=NULL;
+
+ if (0==(event & EV_READ)) {
+ tr_debug("tr_trps_event_cb: unexpected event on TRPS socket (event=0x%X)", event);
+ } else {
+ /* create a thread to handle this connection */
+ asprintf(&name, "trustrouter@%s", trps->hostname);
+ gssname=tr_new_name(name);
+ free(name); name=NULL;
+ conn=trp_connection_accept(tmp_ctx, listener, gssname);
+ if (conn!=NULL) {
+ /* need to monitor this fd and trigger events when read becomes possible */
+ thread_data=talloc(conn, struct trps_thread_data);
+ if (thread_data==NULL) {
+ tr_err("tr_trps_event_cb: unable to allocate trps_thread_data");
+ talloc_free(tmp_ctx);
+ return;
+ }
+ thread_data->conn=conn;
+ thread_data->trps=trps;
+ trps_add_connection(trps, conn); /* remember the connection */
+ pthread_create(trp_connection_get_thread(conn), NULL, tr_trps_thread, thread_data);
+ }
+ }
+ talloc_free(tmp_ctx);
+}
+
+static void tr_trps_cleanup_conn(TRPS_INSTANCE *trps, TRP_CONNECTION *conn)
+{
+ /* everything belonging to the thread is in the TRP_CONNECTION
+ * associated with it */
+ 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");
+}
+
+static void tr_trps_cleanup_trpc(TRPS_INSTANCE *trps, TRPC_INSTANCE *trpc)
+{
+ pthread_join(*trp_connection_get_thread(trpc_get_conn(trpc)), NULL);
+ trps_remove_trpc(trps, trpc);
+ trpc_free(trpc);
+ tr_debug("tr_trps_cleanup_trpc: deleted connection");
+}
+
+static void tr_trps_print_route_table(TRPS_INSTANCE *trps, FILE *f)
+{
+ char *table=trp_rtable_to_str(NULL, trps->rtable, " | ", NULL);
+ if (table==NULL)
+ fprintf(f, "Unable to print route table.\n");
+ else {
+ fprintf(f, "%s\n", table);
+ talloc_free(table);
+ }
+}
+
+static void tr_trps_process_mq(int socket, short event, void *arg)
+{
+ TRPS_INSTANCE *trps=talloc_get_type_abort(arg, TRPS_INSTANCE);
+ 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);
+ if (0==strcmp(s, TR_MQMSG_TRPS_CONNECTED)) {
+ TR_NAME *gssname=(TR_NAME *)tr_mq_msg_get_payload(msg);
+ TRP_PEER *peer=trps_get_peer_by_gssname(trps, gssname);
+ if (peer==NULL)
+ tr_err("tr_trps_process_mq: incoming connection from unknown peer (%s) reported.", gssname->buf);
+ else {
+ trp_peer_set_incoming_status(peer, PEER_CONNECTED);
+ tr_err("tr_trps_process_mq: incoming connection from %s established.", gssname->buf);
+ }
+ }
+ else if (0==strcmp(s, TR_MQMSG_TRPS_DISCONNECTED)) {
+ TRP_CONNECTION *conn=talloc_get_type_abort(tr_mq_msg_get_payload(msg), TRP_CONNECTION);
+ TR_NAME *gssname=trp_connection_get_gssname(conn);
+ TRP_PEER *peer=trps_get_peer_by_gssname(trps, gssname);
+ if (peer==NULL) {
+ tr_err("tr_trps_process_mq: incoming connection from unknown peer (%s) lost.",
+ trp_connection_get_gssname(conn)->buf);
+ } else {
+ trp_peer_set_incoming_status(peer, PEER_DISCONNECTED);
+ tr_trps_cleanup_conn(trps, conn);
+ tr_err("tr_trps_process_mq: incoming connection from %s lost.", gssname->buf);
+ }
+ }
+ else if (0==strcmp(s, TR_MQMSG_TRPC_CONNECTED)) {
+ TR_NAME *svcname=(TR_NAME *)tr_mq_msg_get_payload(msg);
+ TRP_PEER *peer=trps_get_peer_by_servicename(trps, svcname);
+ if (peer==NULL)
+ tr_err("tr_trps_process_mq: outgoing connection to unknown peer (%s) reported.", svcname->buf);
+ else {
+ trp_peer_set_outgoing_status(peer, PEER_CONNECTED);
+ tr_err("tr_trps_process_mq: outgoing connection to %s established.", svcname->buf);
+ }
+ }
+ else if (0==strcmp(s, TR_MQMSG_TRPC_DISCONNECTED)) {
+ /* trpc connection died */
+ TRPC_INSTANCE *trpc=talloc_get_type_abort(tr_mq_msg_get_payload(msg), TRPC_INSTANCE);
+ TR_NAME *gssname=trpc_get_gssname(trpc);
+ TRP_PEER *peer=trps_get_peer_by_servicename(trps, gssname);
+ if (peer==NULL)
+ tr_err("tr_trps_process_mq: outgoing connection to unknown peer (%s) lost.", gssname->buf);
+ else {
+ trp_peer_set_outgoing_status(peer, PEER_DISCONNECTED);
+ tr_err("tr_trps_process_mq: outgoing connection to %s lost.", gssname->buf);
+ tr_trps_cleanup_trpc(trps, trpc);
+ }
+ }
+
+ else if (0==strcmp(s, TR_MQMSG_MSG_RECEIVED)) {
+ if (trps_handle_tr_msg(trps, tr_mq_msg_get_payload(msg))!=TRP_SUCCESS)
+ tr_notice("tr_trps_process_mq: error handling message.");
+ else {
+ tr_trps_print_route_table(trps, stderr);
+ }
+ }
+ else
+ tr_notice("tr_trps_process_mq: unknown message '%s' received.", tr_mq_msg_get_message(msg));
+
+ tr_mq_msg_free(msg);
+ msg=trps_mq_pop(trps);
+ }
+}
+
+static void tr_trps_update(int listener, short event, void *arg)
+{
+ struct tr_trps_event_cookie *cookie=talloc_get_type_abort(arg, struct tr_trps_event_cookie);
+ TRPS_INSTANCE *trps=cookie->trps;
+ struct event *ev=cookie->ev;
+
+ tr_debug("tr_trps_update: sending scheduled route updates.");
+ trps_update(trps, TRP_UPDATE_SCHEDULED);
+ event_add(ev, &(trps->update_interval));
+}
+
+static void tr_trps_sweep(int listener, short event, void *arg)
+{
+ struct tr_trps_event_cookie *cookie=talloc_get_type_abort(arg, struct tr_trps_event_cookie);
+ TRPS_INSTANCE *trps=cookie->trps;
+ struct event *ev=cookie->ev;
+
+ tr_debug("tr_trps_sweep: sweeping routes.");
+ trps_sweep_routes(trps);
+ tr_trps_print_route_table(trps, stderr);
+ /* schedule the event to run again */
+ event_add(ev, &(trps->sweep_interval));
+}
+
+static void tr_connection_update(int listener, short event, void *arg)
+{
+ struct tr_trps_event_cookie *cookie=talloc_get_type_abort(arg, struct tr_trps_event_cookie);
+ TRPS_INSTANCE *trps=cookie->trps;
+ struct event *ev=cookie->ev;
+
+ tr_debug("tr_connection_update: checking peer connections.");
+ tr_connect_to_peers(trps, ev);
+ /* schedule the event to run again */
+ event_add(ev, &(trps->connect_interval));
+}
+
+static int tr_trps_events_destructor(void *obj)
+{
+ TR_TRPS_EVENTS *ev=talloc_get_type_abort(obj, TR_TRPS_EVENTS);
+ if (ev->mq_ev!=NULL)
+ event_free(ev->mq_ev);
+ if (ev->connect_ev!=NULL)
+ event_free(ev->connect_ev);
+ if (ev->update_ev!=NULL)
+ event_free(ev->update_ev);
+ if (ev->sweep_ev!=NULL)
+ event_free(ev->sweep_ev);
+ return 0;
+}
+static TR_TRPS_EVENTS *tr_trps_events_new(TALLOC_CTX *mem_ctx)
+{
+ TR_TRPS_EVENTS *ev=talloc(mem_ctx, TR_TRPS_EVENTS);
+ if (ev!=NULL) {
+ ev->listen_ev=talloc(ev, struct tr_socket_event);
+ ev->mq_ev=NULL;
+ ev->connect_ev=NULL;
+ ev->update_ev=NULL;
+ ev->sweep_ev=NULL;
+ if (ev->listen_ev==NULL) {
+ talloc_free(ev);
+ ev=NULL;
+ } else {
+ talloc_set_destructor((void *)ev, tr_trps_events_destructor);
+ }
+ }
+ return ev;
+}
+
+static void tr_trps_events_free(TR_TRPS_EVENTS *ev)
+{
+ talloc_free(ev);
+}
+
+/* Configure the trps instance and set up its event handler.
+ * Fills in trps_ev, which should be allocated by caller. */
+TRP_RC tr_trps_event_init(struct event_base *base, TR_INSTANCE *tr)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ struct tr_socket_event *listen_ev=NULL;
+ struct tr_trps_event_cookie *trps_cookie=NULL;
+ struct tr_trps_event_cookie *connection_cookie=NULL;
+ struct tr_trps_event_cookie *update_cookie=NULL;
+ struct tr_trps_event_cookie *sweep_cookie=NULL;
+ struct timeval zero_time={0,0};
+ TRP_RC retval=TRP_ERROR;
+
+ if (tr->events != NULL) {
+ tr_notice("tr_trps_event_init: tr->events was not null. Freeing before reallocating..");
+ tr_trps_events_free(tr->events);
+ }
+
+ tr->events=tr_trps_events_new(tmp_ctx);
+ if (tr->events == NULL) {
+ tr_debug("tr_trps_event_init: unable to allocate event handles.");
+ retval=TRP_NOMEM;
+ goto cleanup;
+ }
+
+ /* get convenient handles */
+ listen_ev=tr->events->listen_ev;
+
+ /* Create the cookie for callbacks. It will end up part of the trps context, so it will
+ * be cleaned up when trps is freed by talloc_free. */
+ trps_cookie=talloc(tr->events, struct tr_trps_event_cookie);
+ if (trps_cookie == NULL) {
+ tr_debug("tr_trps_event_init: Unable to allocate trps_cookie.");
+ retval=TRP_NOMEM;
+ tr_trps_events_free(tr->events);
+ tr->events=NULL;
+ goto cleanup;
+ }
+ trps_cookie->trps=tr->trps;
+ 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) {
+ 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);
+
+ /* now set up message queue processing event, only triggered by
+ * tr_trps_mq_cb() */
+ tr->events->mq_ev=event_new(base,
+ 0,
+ EV_PERSIST,
+ tr_trps_process_mq,
+ (void *)(tr->trps));
+ tr_mq_set_notify_cb(tr->trps->mq, tr_trps_mq_cb, tr->events->mq_ev);
+
+ /* now set up the peer connection timer event */
+ connection_cookie=talloc(tr->events, struct tr_trps_event_cookie);
+ if (connection_cookie == NULL) {
+ tr_debug("tr_trps_event_init: Unable to allocate connection_cookie.");
+ retval=TRP_NOMEM;
+ tr_trps_events_free(tr->events);
+ tr->events=NULL;
+ goto cleanup;
+ }
+ connection_cookie->trps=tr->trps;
+ connection_cookie->cfg_mgr=tr->cfg_mgr;
+ tr->events->connect_ev=event_new(base, -1, EV_TIMEOUT, tr_connection_update, (void *)connection_cookie);
+ connection_cookie->ev=tr->events->connect_ev; /* in case it needs to frob the event */
+ /* The first time, do this immediately. Thereafter, it will retrigger every trps->connect_interval */
+ event_add(tr->events->connect_ev, &zero_time);
+
+ /* now set up the route update timer event */
+ update_cookie=talloc(tr->events, struct tr_trps_event_cookie);
+ if (update_cookie == NULL) {
+ tr_debug("tr_trps_event_init: Unable to allocate update_cookie.");
+ retval=TRP_NOMEM;
+ tr_trps_events_free(tr->events);
+ tr->events=NULL;
+ goto cleanup;
+ }
+ update_cookie->trps=tr->trps;
+ update_cookie->cfg_mgr=tr->cfg_mgr;
+ tr->events->update_ev=event_new(base, -1, EV_TIMEOUT, tr_trps_update, (void *)update_cookie);
+ update_cookie->ev=tr->events->update_ev; /* in case it needs to frob the event */
+ event_add(tr->events->update_ev, &(tr->trps->update_interval));
+
+ /* now set up the route table sweep timer event */
+ sweep_cookie=talloc(tr->events, struct tr_trps_event_cookie);
+ if (sweep_cookie == NULL) {
+ tr_debug("tr_trps_event_init: Unable to allocate sweep_cookie.");
+ retval=TRP_NOMEM;
+ tr_trps_events_free(tr->events);
+ tr->events=NULL;
+ goto cleanup;
+ }
+ sweep_cookie->trps=tr->trps;
+ sweep_cookie->cfg_mgr=tr->cfg_mgr;
+ tr->events->sweep_ev=event_new(base, -1, EV_TIMEOUT, tr_trps_sweep, (void *)sweep_cookie);
+ sweep_cookie->ev=tr->events->sweep_ev; /* in case it needs to frob the event */
+ event_add(tr->events->sweep_ev, &(tr->trps->sweep_interval));
+
+ talloc_steal(tr, tr->events);
+ retval=TRP_SUCCESS;
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return retval;
+}
+
+
+struct trpc_notify_cb_data {
+ int msg_ready;
+ pthread_cond_t cond;
+ pthread_mutex_t mutex;
+};
+
+static void tr_trpc_mq_cb(TR_MQ *mq, void *arg)
+{
+ struct trpc_notify_cb_data *cb_data=(struct trpc_notify_cb_data *) arg;
+ pthread_mutex_lock(&(cb_data->mutex));
+ if (!cb_data->msg_ready) {
+ cb_data->msg_ready=1;
+ pthread_cond_signal(&(cb_data->cond));
+ }
+ pthread_mutex_unlock(&(cb_data->mutex));
+}
+
+/* data passed to thread */
+struct trpc_thread_data {
+ TRPC_INSTANCE *trpc;
+ TRPS_INSTANCE *trps;
+};
+static void *tr_trpc_thread(void *arg)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ struct trpc_thread_data *thread_data=talloc_get_type_abort(arg, struct trpc_thread_data);
+ TRPC_INSTANCE *trpc=thread_data->trpc;
+ TRPS_INSTANCE *trps=thread_data->trps;
+ TRP_RC rc=TRP_ERROR;
+ TR_MQ_MSG *msg=NULL;
+ const char *msg_type=NULL;
+ char *encoded_msg=NULL;
+ TR_NAME *peer_gssname=NULL;
+
+ struct trpc_notify_cb_data cb_data={0,
+ PTHREAD_COND_INITIALIZER,
+ PTHREAD_MUTEX_INITIALIZER};
+
+ tr_debug("tr_trpc_thread: started");
+
+ /* set up the mq for receiving */
+ pthread_mutex_lock(&(cb_data.mutex)); /* hold this lock until we enter the main loop */
+
+ tr_mq_lock(trpc->mq);
+ tr_mq_set_notify_cb(trpc->mq, tr_trpc_mq_cb, (void *) &cb_data);
+ tr_mq_unlock(trpc->mq);
+
+ rc=trpc_connect(trpc);
+ if (rc!=TRP_SUCCESS) {
+ tr_notice("tr_trpc_thread: failed to initiate connection to %s:%d.",
+ trpc_get_server(trpc),
+ trpc_get_port(trpc));
+ } else {
+ peer_gssname=trp_connection_get_peer(trpc_get_conn(trpc));
+ if (peer_gssname==NULL) {
+ tr_err("tr_trpc_thread: could not duplicate peer_gssname.");
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ tr_debug("tr_trpc_thread: connected to peer %s", peer_gssname->buf);
+
+ msg=tr_mq_msg_new(tmp_ctx, TR_MQMSG_TRPC_CONNECTED, TR_MQ_PRIO_HIGH);
+ tr_mq_msg_set_payload(msg, (void *)tr_dup_name(peer_gssname), tr_free_name_helper);
+ if (msg==NULL) {
+ tr_err("tr_trpc_thread: error allocating TR_MQ_MSG");
+ talloc_free(tmp_ctx);
+ return NULL;
+ }
+ trps_mq_add(trps, msg); /* steals msg context */
+ msg=NULL;
+
+ while(1) {
+ 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);
+
+ 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;
+ }
+ }
+ }
+ else
+ tr_notice("tr_trpc_thread: unknown message '%s' received.", msg_type);
+
+ tr_mq_msg_free(msg);
+ }
+ }
+ }
+
+ tr_debug("tr_trpc_thread: exiting.");
+ msg=tr_mq_msg_new(tmp_ctx, TR_MQMSG_TRPC_DISCONNECTED, TR_MQ_PRIO_HIGH);
+ tr_mq_msg_set_payload(msg, (void *)trpc, NULL); /* do not pass a free routine */
+ if (msg==NULL)
+ tr_err("tr_trpc_thread: error allocating TR_MQ_MSG");
+ else
+ trps_mq_add(trps, msg);
+
+ trpc_mq_clear(trpc); /* clear any queued messages */
+
+ talloc_free(tmp_ctx);
+ return NULL;
+}
+
+/* convert an IDP realm into routing table entries. Outputs number in *n_routes */
+static TRP_ROUTE **tr_make_local_routes(TALLOC_CTX *mem_ctx,
+ TR_IDP_REALM *realm,
+ char *trust_router,
+ size_t *n_routes)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_APC *comm=NULL;
+ TRP_ROUTE *new_entry=NULL;
+ TRP_ROUTE **entries=NULL;
+ size_t n_comms=0, ii=0;
+
+ *n_routes=0;
+
+ if ((realm==NULL) || (realm->origin!=TR_REALM_LOCAL))
+ goto cleanup;
+
+ /* count comms */
+ for (comm=realm->apcs, n_comms=0; comm!=NULL; comm=comm->next,n_comms++) {}
+
+ entries=talloc_array(tmp_ctx, TRP_ROUTE *, n_comms);
+ for (comm=realm->apcs,ii=0; comm!=NULL; comm=comm->next, ii++) {
+ new_entry=trp_route_new(entries);
+ if (new_entry==NULL) {
+ tr_crit("tr_make_local_routes: unable to allocate entry.");
+ talloc_free(entries);
+ goto cleanup;
+ }
+ trp_route_set_comm(new_entry, tr_dup_name(comm->id));
+ trp_route_set_realm(new_entry, tr_dup_name(realm->realm_id));
+ trp_route_set_peer(new_entry, tr_new_name("")); /* no peer, it's us */
+ trp_route_set_metric(new_entry, 0);
+ trp_route_set_trust_router(new_entry, tr_new_name(trust_router));
+ trp_route_set_next_hop(new_entry, tr_new_name(""));
+ trp_route_set_local(new_entry, 1);
+ entries[ii]=new_entry;
+ }
+
+ talloc_steal(mem_ctx, entries);
+ *n_routes=n_comms;
+ cleanup:
+ talloc_free(tmp_ctx);
+ return entries;
+}
+
+void tr_peer_status_change(TRP_PEER *peer, void *cookie)
+{
+ TRPS_INSTANCE *trps=talloc_get_type_abort(cookie, TRPS_INSTANCE);
+
+ if (TRP_SUCCESS!=trps_wildcard_route_req(trps, trp_peer_get_servicename(peer)))
+ tr_err("tr_send_wildcard: error sending wildcard route request.");
+}
+
+/* starts a trpc thread to connect to server:port */
+TRP_RC tr_trpc_initiate(TRPS_INSTANCE *trps, TRP_PEER *peer, struct event *ev)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TRPC_INSTANCE *trpc=NULL;
+ TRP_CONNECTION *conn=NULL;
+ struct trpc_thread_data *thread_data=NULL;
+ TRP_RC rc=TRP_ERROR;
+
+ tr_debug("tr_trpc_initiate entered");
+ trpc=trpc_new(tmp_ctx);
+ if (trpc==NULL) {
+ tr_crit("tr_trpc_initiate: could not allocate TRPC_INSTANCE.");
+ rc=TRP_NOMEM;
+ goto cleanup;
+ }
+ tr_debug("tr_trpc_initiate: allocated trpc");
+
+ conn=trp_connection_new(trpc);
+ if (conn==NULL) {
+ tr_crit("tr_trpc_initiate: could not allocate TRP_CONNECTION.");
+ rc=TRP_NOMEM;
+ goto cleanup;
+ }
+
+ trpc_set_conn(trpc, conn);
+ trpc_set_server(trpc, talloc_strdup(trpc, trp_peer_get_server(peer)));
+ trpc_set_port(trpc, trp_peer_get_port(peer));
+ trpc_set_gssname(trpc, trp_peer_dup_servicename(peer));
+ tr_debug("tr_trpc_initiate: allocated connection");
+
+ /* start thread */
+ thread_data=talloc(trpc, struct trpc_thread_data);
+ if (thread_data==NULL) {
+ tr_crit("tr_trpc_initiate: could not allocate struct trpc_thread_data.");
+ rc=TRP_NOMEM;
+ goto cleanup;
+ }
+ thread_data->trpc=trpc;
+ thread_data->trps=trps;
+
+ trps_add_trpc(trps, trpc); /* must add before starting thread */
+ pthread_create(trp_connection_get_thread(conn), NULL, tr_trpc_thread, thread_data);
+
+ tr_debug("tr_trpc_initiate: started trpc thread");
+ rc=TRP_SUCCESS;
+
+ cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+/* Add local routes to the route table. */
+TRP_RC tr_add_local_routes(TRPS_INSTANCE *trps, TR_CFG *cfg)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_IDP_REALM *cur=NULL;
+ TRP_ROUTE **local_routes=NULL;
+ size_t n_routes=0;
+ size_t ii=0;
+ char *trust_router_name=talloc_asprintf(tmp_ctx, "%s:%d", cfg->internal->hostname, cfg->internal->trps_port);
+
+ /* determine our trust router name */
+ if (trust_router_name==NULL)
+ return TRP_NOMEM;
+
+ for (cur=cfg->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]);
+
+ talloc_free(local_routes);
+ local_routes=NULL;
+ n_routes=0;
+ }
+
+ talloc_free(tmp_ctx);
+ return TRP_SUCCESS;
+}
+
+/* decide how often to attempt to connect to a peer */
+static int tr_conn_attempt_due(TRPS_INSTANCE *trps, TRP_PEER *peer, struct timespec *when)
+{
+ return 1; /* currently make an attempt every cycle */
+}
+
+/* open missing connections to peers */
+TRP_RC tr_connect_to_peers(TRPS_INSTANCE *trps, struct event *ev)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TRP_PTABLE_ITER *iter=trp_ptable_iter_new(tmp_ctx);
+ TRP_PEER *peer=NULL;
+ struct timespec curtime={0,0};
+ TRP_RC rc=TRP_ERROR;
+
+ if (clock_gettime(CLOCK_REALTIME, &curtime)) {
+ tr_err("tr_connect_to_peers: failed to read time.");
+ rc=TRP_CLOCKERR;
+ goto cleanup;
+ }
+
+ for (peer=trp_ptable_iter_first(iter, trps->ptable);
+ peer!=NULL;
+ peer=trp_ptable_iter_next(iter))
+ {
+ if (trps_find_trpc(trps, peer)==NULL) {
+ TR_NAME *label=trp_peer_get_label(peer);
+ tr_debug("tr_connect_to_peers: %.*s missing connection.",
+ label->len, label->buf);
+ /* has it been long enough since we last tried? */
+ if (tr_conn_attempt_due(trps, peer, &curtime)) {
+ trp_peer_set_last_conn_attempt(peer, &curtime); /* we are trying again now */
+ if (tr_trpc_initiate(trps, peer, ev)!=TRP_SUCCESS) {
+ tr_err("tr_connect_to_peers: unable to initiate TRP connection to %s:%u.",
+ trp_peer_get_server(peer),
+ trp_peer_get_port(peer));
+ }
+ }
+ }
+ }
+ rc=TRP_SUCCESS;
+
+cleanup:
+ trp_ptable_iter_free(iter);
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+
+/* Called by the config manager after a change to the active configuration.
+ * Updates configuration of objects that do not know about the config manager. */
+void tr_config_changed(TR_CFG *new_cfg, void *cookie)
+{
+ TR_INSTANCE *tr=talloc_get_type_abort(cookie, TR_INSTANCE);
+ TRPS_INSTANCE *trps=tr->trps;
+
+ tr->cfgwatch->poll_interval.tv_sec=new_cfg->internal->cfg_poll_interval;
+ tr->cfgwatch->poll_interval.tv_usec=0;
+
+ tr->cfgwatch->settling_time.tv_sec=new_cfg->internal->cfg_settling_time;
+ tr->cfgwatch->settling_time.tv_usec=0;
+
+ 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_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??? */
+ tr_add_local_routes(trps, new_cfg); /* should we do this every time??? */
+ trps_update_active_routes(trps); /* find new routes */
+ trps_update(trps, TRP_UPDATE_TRIGGERED); /* send any triggered routes */
+ tr_print_config(new_cfg);
+ tr_trps_print_route_table(trps, stderr);
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2012, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <talloc.h>
+#include <argp.h>
+#include <unistd.h>
+
+#include <gsscon.h>
+#include <tr_debug.h>
+#include <tr_trp.h>
+
+
+/* command-line option setup */
+
+/* argp global parameters */
+const char *argp_program_bug_address=PACKAGE_BUGREPORT; /* bug reporting address */
+
+/* doc strings */
+static const char doc[]=PACKAGE_NAME " - TRP Client";
+static const char arg_doc[]="<message> <server> [<port>]"; /* string describing arguments, if any */
+
+/* define the options here. Fields are:
+ * { long-name, short-name, variable name, options, help description } */
+static const struct argp_option cmdline_options[] = {
+ { "repeat", 'r', "N", OPTION_ARG_OPTIONAL, "Repeat message until terminated, or N times." },
+ {NULL}
+};
+
+/* structure for communicating with option parser */
+struct cmdline_args {
+ char *msg;
+ char *server;
+ int port; /* optional */
+ int repeat; /* how many times to repeat, or -1 for infinite */
+};
+
+/* parser for individual options - fills in a struct cmdline_args */
+static error_t parse_option(int key, char *arg, struct argp_state *state)
+{
+ /* get a shorthand to the command line argument structure, part of state */
+ struct cmdline_args *arguments=state->input;
+
+ switch (key) {
+ case 'r':
+ if (arg==NULL)
+ arguments->repeat=-1;
+ else
+ arguments->repeat=strtol(arg, NULL, 10);
+ break;
+
+ case ARGP_KEY_ARG: /* handle argument (not option) */
+ switch (state->arg_num) {
+ case 0:
+ arguments->msg=arg;
+ break;
+
+ case 1:
+ arguments->server=arg;
+ break;
+
+ case 2:
+ arguments->port=strtol(arg, NULL, 10); /* optional */
+ break;
+
+ default:
+ /* too many arguments */
+ argp_usage(state);
+ }
+ break;
+
+ case ARGP_KEY_END: /* no more arguments */
+ if (state->arg_num < 2) {
+ /* not enough arguments encountered */
+ argp_usage(state);
+ }
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0; /* success */
+}
+
+/* assemble the argp parser */
+static struct argp argp = {cmdline_options, parse_option, arg_doc, doc};
+
+int main (int argc,
+ char *argv[])
+{
+ TALLOC_CTX *main_ctx=talloc_new(NULL);
+ TRPC_INSTANCE *trpc=NULL;
+ TRP_CONNECTION *conn=NULL;
+ struct cmdline_args opts;
+
+ /* parse the command line*/
+ /* set defaults */
+ opts.msg=NULL;
+ opts.server=NULL;
+ opts.port=TRP_PORT;
+ opts.repeat=1;
+
+ argp_parse(&argp, argc, argv, 0, 0, &opts);
+
+ /* Use standalone logging */
+ tr_log_open();
+
+ /* set logging levels */
+ talloc_set_log_stderr();
+ tr_log_threshold(LOG_CRIT);
+ tr_console_threshold(LOG_DEBUG);
+
+ printf("TRPC Client:\nServer = %s, port = %i\n", opts.server, opts.port);
+
+ conn=trp_connection_new(trpc);
+ if (conn==NULL) {
+ printf("Could not allocate TRP_CONNECTION.\n");
+ return 1;
+ }
+ trpc = trpc_new(main_ctx);
+ trpc_set_server(trpc, opts.server);
+ trpc_set_port(trpc, opts.port);
+ trpc_set_conn(trpc, conn);
+ /* Set-up TRP connection */
+ if (TRP_SUCCESS != trpc_connect(trpc)) {
+ /* Handle error */
+ printf("Error in trpc_connect.\n");
+ return 1;
+ }
+
+ /* Send a TRP message */
+ while ((opts.repeat==-1) || (opts.repeat-->0)) {
+ if (TRP_SUCCESS != trpc_send_msg(trpc, opts.msg)) {
+ /* Handle error */
+ printf("Error in trpc_send_request.");
+ return 1;
+ }
+ usleep(1000000);
+ }
+
+ /* Clean-up the TRP client instance, and exit */
+ trpc_free(trpc);
+
+ return 0;
+}
+
--- /dev/null
+/* Testing trp message encoding / decoding */
+
+/* compiles with: gcc -o msgtst -I../include msgtst.c trp_msg.c $(pkg-config --cflags --libs glib-2.0) ../common/tr_debug.c ../common/tr_name.c ../common/tr_msg.c -ltalloc -ljansson */
+
+#include <stdio.h>
+#include <talloc.h>
+
+#include <trust_router/trp.h>
+#include <tr_msg.h>
+#include <tr_debug.h>
+
+#define MAX_MSG_LEN 8192
+
+int main(int argc, const char *argv[])
+{
+ TALLOC_CTX *main_ctx=talloc_new(NULL);
+ FILE *f;
+ char *buf;
+ size_t buflen;
+ TR_MSG *msg;
+
+ if (argc != 2) {
+ printf("Usage: %s <input file>\n\n", argv[0]);
+ exit(-1);
+ }
+
+ buf=malloc(MAX_MSG_LEN);
+ if (!buf) {
+ printf("Allocation error.\n\n");
+ exit(-1);
+ }
+
+ f=fopen(argv[1], "r");
+ if (!f) {
+ printf("Error opening %s for reading.\n\n", argv[1]);
+ exit(-1);
+ }
+
+ printf("Reading from %s...\n", argv[1]);
+
+ buflen=fread(buf, sizeof(char), MAX_MSG_LEN, f);
+ if (buflen==0) {
+ printf("File empty.\n\n");
+ exit(0);
+ }
+
+ if (buflen>=MAX_MSG_LEN)
+ printf("Warning: file may exceed maximum message length (%d bytes).\n", MAX_MSG_LEN);
+
+ msg=tr_msg_decode(buf, buflen);
+
+/* if (rc==TRP_SUCCESS)
+ trp_msg_print(msg);*/
+
+ printf("\nEncoding...\n");
+
+ printf("Result: \n%s\n\n", tr_msg_encode(msg));
+
+ talloc_report_full(main_ctx, stdout);
+
+ return 0;
+}
--- /dev/null
+#include <stdio.h>
+#include <talloc.h>
+#include <assert.h>
+
+#include <trp_internal.h>
+#include <trp_ptable.h>
+
+struct peer_entry {
+ char *server;
+ unsigned int port;
+ unsigned int linkcost;
+};
+
+static struct peer_entry peer_data[]={
+ {"peer0", 10000, 0x0001},
+ {"peer1", 15000, 0x0002},
+ {"peer2", 20000, 0x0004},
+ {"peer3", 25000, 0x0008},
+ {"peer4", 30000, 0x0010}
+};
+static size_t n_peers=sizeof(peer_data)/sizeof(peer_data[0]);
+
+static void populate_ptable(TRPS_INSTANCE *trps)
+{
+ TRP_PEER *new_peer;
+ int i;
+
+ for (i=0; i<n_peers; i++) {
+ new_peer=trp_peer_new(NULL);
+ assert(new_peer!=NULL);
+ trp_peer_set_server(new_peer, peer_data[i].server);
+ assert(trp_peer_get_server(new_peer)!=NULL);
+ trp_peer_set_port(new_peer, peer_data[i].port);
+ trp_peer_set_linkcost(new_peer, peer_data[i].linkcost);
+ assert(trps_add_peer(trps, new_peer)==TRP_SUCCESS);
+ }
+}
+
+static struct peer_entry *find_peer_entry(char *server)
+{
+ int i;
+ for (i=0; i<n_peers; i++) {
+ if (0==strcmp(server, peer_data[i].server)) {
+ return (peer_data+i);
+ }
+ }
+ return NULL;
+}
+
+static void verify_ptable(TRPS_INSTANCE *trps)
+{
+ struct peer_entry *peer_entry=NULL;
+ TRP_PEER *peer;
+ char *s;
+ TR_NAME *gssname;
+
+ peer=trps->ptable->head;
+ while (peer!=NULL) {
+ peer_entry=find_peer_entry(trp_peer_get_server(peer));
+ assert(peer_entry!=NULL);
+ assert(!strcmp(trp_peer_get_server(peer), peer_entry->server));
+ assert(trp_peer_get_port(peer)==peer_entry->port);
+ assert(trp_peer_get_linkcost(peer)==peer_entry->linkcost);
+ assert(0<asprintf(&s, "trustrouter@%s", peer_entry->server));
+ gssname=tr_new_name(s);
+ free(s);
+ assert(gssname!=NULL);
+ assert(!tr_name_cmp(trp_peer_get_gssname(peer), gssname));
+ tr_free_name(gssname);
+ peer=peer->next;
+ }
+}
+
+struct route_data {
+ char *apc;
+ char *realm;
+ char *peer;
+ unsigned int metric;
+ char *trust_router;
+ char *next_hop;
+ int selected;
+ unsigned int interval;
+ int verified; /* for testing */
+};
+static struct route_data route_table[]={
+ {"apc0", "realm0", "", 0, "tr.r0.apc0", "", 1, 60, 0},
+ {"apc0", "realm1", "", 0, "tr.r1.apc0", "", 1, 60, 0},
+ {"apc0", "realm0", "trustrouter@peer0", 1, "tr.r0.apc0", "trustrouter@peer0", 0, 60, 0},
+ {"apc0", "realm1", "trustrouter@peer0", 0, "tr.r1.apc0", "trustrouter@peer0", 0, 60, 0},
+ {"apc0", "realm2", "trustrouter@peer0", 0, "tr.r2.apc0", "trustrouter@peer0", 1, 60, 0},
+ {"apc0", "realm3", "trustrouter@peer0", 1, "tr.r3.apc0", "trustrouter@peer0", 0, 60, 0},
+ {"apc0", "realm4", "trustrouter@peer0", 2, "tr.r4.apc0", "trustrouter@peer0", 0, 60, 0},
+ {"apc0", "realm0", "trustrouter@peer1", 0, "tr.r0.apc0", "trustrouter@peer1", 0, 60, 0},
+ {"apc0", "realm1", "trustrouter@peer1", 1, "tr.r1.apc0", "trustrouter@peer1", 0, 60, 0},
+ {"apc0", "realm2", "trustrouter@peer1", 1, "tr.r2.apc0", "trustrouter@peer1", 0, 60, 0},
+ {"apc0", "realm3", "trustrouter@peer1", 0, "tr.r3.apc0", "trustrouter@peer1", 1, 60, 0},
+ {"apc0", "realm4", "trustrouter@peer1", 2, "tr.r4.apc0", "trustrouter@peer1", 0, 60, 0},
+ {"apc0", "realm0", "trustrouter@peer2", 0, "tr.r0.apc0", "trustrouter@peer2", 0, 60, 0},
+ {"apc0", "realm1", "trustrouter@peer2", 2, "tr.r1.apc0", "trustrouter@peer2", 0, 60, 0},
+ {"apc0", "realm2", "trustrouter@peer2", 2, "tr.r2.apc0", "trustrouter@peer2", 0, 60, 0},
+ {"apc0", "realm3", "trustrouter@peer2", 1, "tr.r3.apc0", "trustrouter@peer2", 0, 60, 0},
+ {"apc0", "realm4", "trustrouter@peer2", 0, "tr.r4.apc0", "trustrouter@peer2", 1, 60, 0},
+};
+static size_t n_routes=sizeof(route_table)/sizeof(route_table[0]);
+
+/* These are the correct updates to select from the above route table for each peer.
+ * The rule is: send selected route unless it is through that peer, otherwise send
+ * the best (lowest metric) alternative route.
+ *
+ * In a few cases there are multiple valid options (when a two non-selected routes
+ * exist). If these tests are failing, it may be that the trps code is selecting another
+ * valid option, so check that. Probably ought to tweak metrics to avoid that ambiguity. */
+static struct route_data update_table[][10]={
+ { /* peer0 */
+ {"apc0", "realm0", "", 0, "tr.r0.apc0", "", 1, 60, 0},
+ {"apc0", "realm1", "", 0, "tr.r1.apc0", "", 1, 60, 0},
+ {"apc0", "realm2", "trustrouter@peer1", 1, "tr.r2.apc0", "trustrouter@peer1", 0, 60, 0},
+ {"apc0", "realm3", "trustrouter@peer1", 0, "tr.r3.apc0", "trustrouter@peer1", 1, 60, 0},
+ {"apc0", "realm4", "trustrouter@peer2", 0, "tr.r4.apc0", "trustrouter@peer2", 1, 60, 0},
+ {NULL}
+ },
+ { /* peer1 */
+ {"apc0", "realm0", "", 0, "tr.r0.apc0", "", 1, 60, 0},
+ {"apc0", "realm1", "", 0, "tr.r1.apc0", "", 1, 60, 0},
+ {"apc0", "realm2", "trustrouter@peer0", 0, "tr.r2.apc0", "trustrouter@peer0", 1, 60, 0},
+ {"apc0", "realm3", "trustrouter@peer2", 1, "tr.r3.apc0", "trustrouter@peer2", 0, 60, 0},
+ {"apc0", "realm4", "trustrouter@peer2", 0, "tr.r4.apc0", "trustrouter@peer2", 1, 60, 0},
+ {NULL}
+ },
+ { /* peer2 */
+ {"apc0", "realm0", "", 0, "tr.r0.apc0", "", 1, 60, 0},
+ {"apc0", "realm1", "", 0, "tr.r1.apc0", "", 1, 60, 0},
+ {"apc0", "realm2", "trustrouter@peer0", 0, "tr.r2.apc0", "trustrouter@peer0", 1, 60, 0},
+ {"apc0", "realm3", "trustrouter@peer1", 0, "tr.r3.apc0", "trustrouter@peer1", 1, 60, 0},
+ {"apc0", "realm4", "trustrouter@peer1", 2, "tr.r4.apc0", "trustrouter@peer1", 0, 60, 0},
+ {NULL}
+ },
+ { /* peer3 */
+ {"apc0", "realm0", "", 0, "tr.r0.apc0", "", 1, 60, 0},
+ {"apc0", "realm1", "", 0, "tr.r1.apc0", "", 1, 60, 0},
+ {"apc0", "realm2", "trustrouter@peer0", 0, "tr.r2.apc0", "trustrouter@peer0", 1, 60, 0},
+ {"apc0", "realm3", "trustrouter@peer1", 0, "tr.r3.apc0", "trustrouter@peer1", 1, 60, 0},
+ {"apc0", "realm4", "trustrouter@peer2", 0, "tr.r4.apc0", "trustrouter@peer2", 1, 60, 0},
+ {NULL}
+ },
+ { /* peer4 */
+ {"apc0", "realm0", "", 0, "tr.r0.apc0", "", 1, 60, 0},
+ {"apc0", "realm1", "", 0, "tr.r1.apc0", "", 1, 60, 0},
+ {"apc0", "realm2", "trustrouter@peer0", 0, "tr.r2.apc0", "trustrouter@peer0", 1, 60, 0},
+ {"apc0", "realm3", "trustrouter@peer1", 0, "tr.r3.apc0", "trustrouter@peer1", 1, 60, 0},
+ {"apc0", "realm4", "trustrouter@peer2", 0, "tr.r4.apc0", "trustrouter@peer2", 1, 60, 0},
+ {NULL}
+ }
+};
+
+static void populate_rtable(TRPS_INSTANCE *trps)
+{
+ int i;
+ TRP_RENTRY *new;
+
+ for (i=0; i<n_routes; i++) {
+ new=trp_rentry_new(NULL);
+ assert(new!=NULL);
+ trp_rentry_set_apc(new, tr_new_name(route_table[i].apc));
+ trp_rentry_set_realm(new, tr_new_name(route_table[i].realm));
+ trp_rentry_set_peer(new, tr_new_name(route_table[i].peer));
+ trp_rentry_set_metric(new, route_table[i].metric);
+ trp_rentry_set_trust_router(new, tr_new_name(route_table[i].trust_router));
+ trp_rentry_set_next_hop(new, tr_new_name(route_table[i].next_hop));
+ trp_rentry_set_selected(new, route_table[i].selected);
+ trp_rentry_set_interval(new, route_table[i].interval);
+ /* do not set expiry */
+ trp_rtable_add(trps->rtable, new);
+ new=NULL;
+ }
+}
+
+static void verify_update(TRP_RENTRY **updates, size_t n_updates, struct route_data *expected)
+{
+ int ii,jj;
+ int found;
+
+ for(jj=0; jj<n_updates; jj++) {
+ found=0;
+ for (ii=0; expected[ii].apc!=NULL; ii++) {
+ if ((0==strcmp(expected[ii].apc, updates[jj]->apc->buf))
+ &&(0==strcmp(expected[ii].realm, updates[jj]->realm->buf))
+ &&(0==strcmp(expected[ii].peer, updates[jj]->peer->buf))
+ &&(expected[ii].metric==updates[jj]->metric)
+ &&(0==strcmp(expected[ii].trust_router, updates[jj]->trust_router->buf))
+ &&(0==strcmp(expected[ii].next_hop, updates[jj]->next_hop->buf))
+ &&(expected[ii].selected==updates[jj]->selected)
+ &&(expected[ii].interval==updates[jj]->interval)) {
+ assert(expected[ii].verified==0); /* should only encounter each entry once */
+ expected[ii].verified=1;
+ found=1;
+ continue;
+ }
+ }
+ if (!found) {
+ printf("missing:\n%s\n", trp_rentry_to_str(NULL,updates[jj], " | "));
+ assert(0);
+ }
+ }
+ for(ii=0; expected[ii].apc!=NULL; ii++)
+ assert(expected[ii].verified==1);
+}
+
+static void verify_update_selection(TRPS_INSTANCE *trps)
+{
+ int ii;
+ TRP_RENTRY **updates=NULL;
+ size_t n_updates;
+ TR_NAME *gssname=NULL;
+ char *s;
+
+ for (ii=0; ii<n_peers; ii++) {
+ assert(0<asprintf(&s, "trustrouter@%s", peer_data[ii].server));
+ assert(NULL!=(gssname=tr_new_name(s)));
+ free(s);
+ updates=trps_select_updates_for_peer(NULL, trps, gssname, &n_updates);
+ tr_free_name(gssname);
+ verify_update(updates, n_updates, update_table[ii]);
+ talloc_free(updates);
+ }
+}
+
+int main(void)
+{
+ TALLOC_CTX *main_ctx=talloc_new(NULL);
+ TRPS_INSTANCE *trps;
+ char *s;
+
+ trps=trps_new(main_ctx);
+
+ printf("\nPopulating peer table...\n");
+ populate_ptable(trps);
+
+ printf("\nVerifying peer table...\n");
+ verify_ptable(trps);
+
+ printf("\nPopulating route table...\n");
+ populate_rtable(trps);
+ s=trp_rtable_to_str(main_ctx, trps->rtable, " | ", NULL);
+ printf("Route Table:\n%s---\n", s);
+
+ printf("\nVerifying route update selection...\n");
+ verify_update_selection(trps);
+
+ printf("\nDone\n\n");
+ talloc_report_full(main_ctx, stderr);
+ talloc_free(main_ctx);
+ talloc_report_full(NULL, stderr);
+ return 0;
+}
--- /dev/null
+#include <stdio.h>
+#include <talloc.h>
+#include <string.h>
+#include <assert.h>
+
+#include <trust_router/tr_name.h>
+#include <trp_internal.h>
+#include <trp_rtable.h>
+
+char *apc[]={"apc1", "apc2", "apc3"};
+size_t n_apc=sizeof(apc)/sizeof(apc[0]);
+char *realm[]={"realm1", "realm2", "realm3"};
+size_t n_realm=sizeof(realm)/sizeof(realm[0]);
+char *peer[]={"peer1", "peer2", "peer3"};
+size_t n_peer=sizeof(peer)/sizeof(peer[0]);
+
+static unsigned int metric1(size_t a, size_t b, size_t c)
+{
+ return a+b+c;
+}
+
+static unsigned int metric2(size_t a, size_t b, size_t c)
+{
+ return a+b+c+25;
+}
+
+static unsigned int metric3(size_t a, size_t b, size_t c)
+{
+ return a*(b+c)+b*c;
+}
+
+static void populate_rtable(TRP_RTABLE *table, unsigned int (*metric)(size_t, size_t, size_t))
+{
+ TRP_RENTRY *entry=NULL;
+ size_t ii=0, jj=0, kk=0;
+ struct timespec ts={0,0};
+
+ for (ii=0; ii<n_apc; ii++) {
+ for (jj=0; jj<n_realm; jj++) {
+ for (kk=0; kk<n_peer; kk++) {
+ entry=trp_rentry_new(NULL);
+ trp_rentry_set_apc(entry, tr_new_name(apc[ii]));
+ trp_rentry_set_realm(entry, tr_new_name(realm[jj]));
+ trp_rentry_set_trust_router(entry, tr_new_name(realm[jj]));
+ trp_rentry_set_peer(entry, tr_new_name(peer[kk]));
+ trp_rentry_set_metric(entry, metric(ii,jj,kk));
+ trp_rentry_set_next_hop(entry, tr_new_name(peer[kk]));
+ ts=(struct timespec){jj+1,ii+kk+1};
+ trp_rentry_set_expiry(entry, &ts);
+ trp_rtable_add(table, entry);
+ entry=NULL; /* entry belongs to the table now */
+ }
+ }
+ }
+}
+
+static void verify_rtable(TRP_RTABLE *table, unsigned int (*metric)(size_t, size_t, size_t))
+{
+ TRP_RENTRY *entry=NULL;
+ size_t ii=0, jj=0, kk=0;
+ size_t len=0;
+ TR_NAME *apc_n, *realm_n, *peer_n;
+
+ for (ii=0; ii<n_apc; ii++) {
+ for (jj=0; jj<n_realm; jj++) {
+ for (kk=0; kk<n_peer; kk++) {
+ apc_n=tr_new_name(apc[ii]);
+ realm_n=tr_new_name(realm[jj]);
+ peer_n=tr_new_name(peer[kk]);
+ entry=trp_rtable_get_entry(table, apc_n, realm_n, peer_n);
+ tr_free_name(apc_n);
+ tr_free_name(realm_n);
+ tr_free_name(peer_n);
+
+ assert(entry!=NULL);
+
+ len=trp_rentry_get_apc(entry)->len;
+ assert(len==strlen(apc[ii]));
+ assert(0==strncmp(trp_rentry_get_apc(entry)->buf, apc[ii], len));
+
+ len=trp_rentry_get_realm(entry)->len;
+ assert(len==strlen(realm[jj]));
+ assert(0==strncmp(trp_rentry_get_realm(entry)->buf, realm[jj], len));
+
+ len=trp_rentry_get_peer(entry)->len;
+ assert(len==strlen(peer[kk]));
+ assert(0==strncmp(trp_rentry_get_peer(entry)->buf, peer[kk], len));
+
+ len=trp_rentry_get_trust_router(entry)->len;
+ assert(len==strlen(realm[jj]));
+ assert(0==strncmp(trp_rentry_get_trust_router(entry)->buf, realm[jj], len));
+
+ assert(trp_rentry_get_metric(entry)==metric(ii,jj,kk));
+
+ len=trp_rentry_get_next_hop(entry)->len;
+ assert(len==strlen(peer[kk]));
+ assert(0==strncmp(trp_rentry_get_next_hop(entry)->buf, peer[kk], len));
+
+ assert(trp_rentry_get_selected(entry)==0);
+ assert(trp_rentry_get_expiry(entry)->tv_sec==jj+1);
+ assert(trp_rentry_get_expiry(entry)->tv_nsec==ii+kk+1);
+
+ printf("{%s %s %s} entry OK!\n", apc[ii], realm[jj], peer[kk]);
+ }
+ }
+ }
+}
+
+static int is_in(char *a, char *b[], size_t n_b)
+{
+ size_t count=0;
+
+ while (n_b--) {
+ if (0==strcmp(a, b[n_b]))
+ count++;
+ }
+ return count;
+}
+static void verify_apc_list(TRP_RTABLE *table)
+{
+ size_t n=0;
+ TR_NAME **apcs_found=trp_rtable_get_apcs(table, &n);
+ assert(n==n_apc);
+ while(n--)
+ assert(1==is_in(apcs_found[n]->buf, apc, n_apc));
+}
+
+static void verify_apc_realm_lists(TRP_RTABLE *table)
+{
+ size_t n=0, ii=0;
+ TR_NAME *apc_n=NULL, **realms_found=NULL;
+
+ for (ii=0; ii<n_apc; ii++) {
+ apc_n=tr_new_name(apc[ii]);
+ realms_found=trp_rtable_get_apc_realms(table, apc_n, &n);
+ tr_free_name(apc_n);
+ assert(n==n_realm);
+ while (n--)
+ assert(1==is_in(realms_found[n]->buf, realm, n_realm));
+ talloc_free(realms_found);
+ printf("APC %s ok!\n", apc[ii]);
+ }
+}
+
+static void verify_get_apc_entries(TRP_RTABLE *table)
+{
+ size_t n=0, ii=0;
+ TRP_RENTRY **apc_entries=NULL;
+ TR_NAME *apc_n=NULL;
+
+ for (ii=0; ii<n_apc; ii++) {
+ apc_n=tr_new_name(apc[ii]);
+ apc_entries=trp_rtable_get_apc_entries(table, apc_n, &n);
+ tr_free_name(apc_n);
+ assert(n==n_realm*n_peer);
+ while (n--) {
+ assert(0==strncmp(trp_rentry_get_apc(apc_entries[n])->buf,
+ apc[ii],
+ trp_rentry_get_apc(apc_entries[n])->len));
+ assert(1==is_in(trp_rentry_get_realm(apc_entries[n])->buf, realm, n_realm));
+ assert(1==is_in(trp_rentry_get_peer(apc_entries[n])->buf, peer, n_peer));
+ }
+ printf("APC %s ok!\n", apc[ii]);
+ talloc_free(apc_entries);
+ }
+}
+
+static void verify_get_realm_entries(TRP_RTABLE *table)
+{
+ size_t n=0, ii=0, jj=0;
+ TRP_RENTRY **realm_entries=NULL;
+ TR_NAME *apc_n=NULL, *realm_n=NULL;
+
+ for (ii=0; ii<n_apc; ii++) {
+ for (jj=0; jj<n_realm; jj++) {
+ apc_n=tr_new_name(apc[ii]);
+ realm_n=tr_new_name(realm[jj]);
+ realm_entries=trp_rtable_get_realm_entries(table, apc_n, realm_n, &n);
+ tr_free_name(apc_n);
+ tr_free_name(realm_n);
+ assert(n==n_peer);
+ while (n--) {
+ assert(0==strncmp(trp_rentry_get_apc(realm_entries[n])->buf,
+ apc[ii],
+ trp_rentry_get_apc(realm_entries[n])->len));
+ assert(0==strncmp(trp_rentry_get_realm(realm_entries[n])->buf,
+ realm[jj],
+ trp_rentry_get_realm(realm_entries[n])->len));
+ assert(1==is_in(trp_rentry_get_peer(realm_entries[n])->buf, peer, n_peer));
+ }
+ printf("APC %s realm %s ok!\n", apc[ii], realm[jj]);
+ talloc_free(realm_entries);
+ }
+ }
+}
+
+/* doesn't work if c not in a */
+static size_t get_index(char *c, char **a, size_t n_a)
+{
+ while(n_a--) {
+ if (0==strcmp(c, a[n_a]))
+ return n_a;
+ }
+ return 0;
+}
+
+static void update_metric(TRP_RTABLE *table, unsigned int (*new_metric)(size_t, size_t, size_t))
+{
+ TRP_RENTRY **entries=NULL;
+ size_t n=0, ii=0,jj=0,kk=0;
+
+ entries=trp_rtable_get_entries(table, &n);
+ while (n--) {
+ ii=get_index(trp_rentry_get_apc(entries[n])->buf, apc, n_apc);
+ jj=get_index(trp_rentry_get_realm(entries[n])->buf, realm, n_realm);
+ kk=get_index(trp_rentry_get_peer(entries[n])->buf, peer, n_peer);
+ trp_rentry_set_metric(entries[n],
+ new_metric(ii,jj,kk));
+ }
+ talloc_free(entries);
+}
+
+static void remove_entries(TRP_RTABLE *table)
+{
+ size_t n=trp_rtable_size(table);
+ size_t ii,jj,kk;
+ TR_NAME *apc_n, *realm_n, *peer_n;
+ TRP_RENTRY *entry=NULL;
+
+ for (ii=0; ii<n_apc; ii++) {
+ for (jj=0; jj<n_realm; jj++) {
+ for (kk=0; kk<n_realm; kk++) {
+ apc_n=tr_new_name(apc[ii]);
+ realm_n=tr_new_name(realm[jj]);
+ peer_n=tr_new_name(peer[kk]);
+ entry=trp_rtable_get_entry(table, apc_n, realm_n, peer_n);
+ assert(entry !=NULL);
+ tr_free_name(apc_n);
+ tr_free_name(realm_n);
+ tr_free_name(peer_n);
+ trp_rtable_remove(table, entry);
+ entry=NULL;
+ assert(trp_rtable_size(table)==--n);
+ }
+ }
+ }
+}
+
+
+static void print_rtable(TRP_RTABLE *table)
+{
+ char *s=trp_rtable_to_str(NULL, table, NULL, NULL);
+ printf(s);
+ talloc_free(s);
+}
+
+int main(void)
+{
+ TRP_RTABLE *table=NULL;
+ table=trp_rtable_new();
+ populate_rtable(table, metric1);
+ print_rtable(table);
+
+ printf("\nVerifying routing table...\n");
+ verify_rtable(table, metric1);
+ printf(" ...success!\n");
+
+ printf("\nVerifying APC list...\n");
+ verify_apc_list(table);
+ printf(" ...success!\n");
+
+ printf("\nVerifying APC realm lists...\n");
+ verify_apc_realm_lists(table);
+ printf(" ...success!\n");
+
+ printf("\nVerifying APC entry lists...\n");
+ verify_get_apc_entries(table);
+ printf(" ...success!\n");
+
+ printf("\nVerifying realm entry lists...\n");
+ verify_get_realm_entries(table);
+ printf(" ...success!\n");
+
+ printf("\nVerifying table value update...\n");
+ update_metric(table, metric2); /* changes the metric value in each element in-place */
+ verify_rtable(table, metric2);
+ printf(" ...success!\n");
+
+ printf("\nVerifying element replacement...\n");
+ populate_rtable(table, metric3); /* replaces all the elements with new ones */
+ verify_rtable(table, metric3);
+ printf(" ...success!\n");
+
+ printf("\nVerifying element removal...\n");
+ remove_entries(table);
+ print_rtable(table);
+ printf(" ...success!\n");
+
+ printf("\nRepopulating table...\n");
+ populate_rtable(table, metric3);
+ verify_rtable(table, metric3);
+ printf(" ...success!\n");
+
+ trp_rtable_free(table);
+ return 0;
+}
--- /dev/null
+#include <gsscon.h>
+#include <gssapi.h>
+#include <fcntl.h>
+#include <talloc.h>
+#include <unistd.h>
+
+#include <tr_debug.h>
+#include <trp_internal.h>
+
+/* Threading note: mutex lock is only used for protecting get_status() and set_status().
+ * If needed, locking for other operations (notably adding/removing connections) must be managed
+ * by whomever is holding on to the connection list. */
+
+int trp_connection_lock(TRP_CONNECTION *conn)
+{
+ return pthread_mutex_lock(&(conn->mutex));
+}
+
+int trp_connection_unlock(TRP_CONNECTION *conn)
+{
+ return pthread_mutex_unlock(&(conn->mutex));
+}
+
+int trp_connection_get_fd(TRP_CONNECTION *conn)
+{
+ return conn->fd;
+}
+
+void trp_connection_set_fd(TRP_CONNECTION *conn, int fd)
+{
+ conn->fd=fd;
+}
+
+/* we use the gss name of the peer to identify it */
+static TRP_RC trp_connection_set_peer(TRP_CONNECTION *conn)
+{
+ OM_uint32 major_status=0;
+ OM_uint32 minor_status=0;
+ gss_name_t source_name=GSS_C_NO_NAME;
+ gss_name_t target_name=GSS_C_NO_NAME;
+ gss_buffer_desc peer_display_name={0,NULL};
+ int local=0;
+
+ major_status=gss_inquire_context(&minor_status,
+ *trp_connection_get_gssctx(conn),
+ &source_name,
+ &target_name,
+ NULL,
+ NULL,
+ NULL,
+ &local,
+ NULL);
+
+ if (major_status != GSS_S_COMPLETE) {
+ tr_err("trp_connection_set_peer: unable to identify GSS peer.");
+ if (source_name!=GSS_C_NO_NAME)
+ gss_release_name(&minor_status, &source_name);
+ if (target_name!=GSS_C_NO_NAME)
+ gss_release_name(&minor_status, &target_name);
+ return TRP_ERROR;
+ }
+
+ if (local) {
+ /* we are the source, peer is the target */
+ major_status=gss_display_name(&minor_status, target_name, &peer_display_name, NULL);
+ } else {
+ /* we are the target, peer is the source */
+ major_status=gss_display_name(&minor_status, source_name, &peer_display_name, NULL);
+ }
+ gss_release_name(&minor_status, &source_name);
+ gss_release_name(&minor_status, &target_name);
+
+ conn->peer=tr_new_name(peer_display_name.value);
+ if (conn->peer==NULL)
+ tr_err("trp_connection_set_peer: unable to allocate peer name.");
+ else {
+ if (conn->peer->len != peer_display_name.length) {
+ tr_err("trp_connection_set_peer: error converting GSS display name to TR_NAME.");
+ tr_free_name(conn->peer);
+ conn->peer=NULL;
+ }
+ }
+ gss_release_buffer(&minor_status, &peer_display_name);
+
+ if (conn->peer==NULL)
+ return TRP_ERROR;
+
+ tr_debug("trp_connection_set_peer: set peer for %p to %.*s (%p).", conn, conn->peer->len, conn->peer->buf, conn->peer);
+ return TRP_SUCCESS;
+}
+
+TR_NAME *trp_connection_get_peer(TRP_CONNECTION *conn)
+{
+ return conn->peer;
+}
+
+TR_NAME *trp_connection_get_gssname(TRP_CONNECTION *conn)
+{
+ return conn->gssname;
+}
+
+void trp_connection_set_gssname(TRP_CONNECTION *conn, TR_NAME *gssname)
+{
+ conn->gssname=gssname;
+}
+
+gss_ctx_id_t *trp_connection_get_gssctx(TRP_CONNECTION *conn)
+{
+ return conn->gssctx;
+}
+
+void trp_connection_set_gssctx(TRP_CONNECTION *conn, gss_ctx_id_t *gssctx)
+{
+ conn->gssctx=gssctx;
+}
+
+TRP_CONNECTION_STATUS trp_connection_get_status(TRP_CONNECTION *conn)
+{
+ TRP_CONNECTION_STATUS status=TRP_CONNECTION_UNKNOWN;
+ trp_connection_lock(conn);
+ status=conn->status;
+ trp_connection_unlock(conn);
+ return status;
+}
+
+static void trp_connection_set_status(TRP_CONNECTION *conn, TRP_CONNECTION_STATUS status)
+{
+ TRP_CONNECTION_STATUS old_status=TRP_CONNECTION_UNKNOWN;
+ trp_connection_lock(conn);
+ old_status=conn->status;
+ conn->status=status;
+ trp_connection_unlock(conn);
+ if ((status!=old_status) && (conn->status_change_cb!=NULL))
+ conn->status_change_cb(conn, conn->status_change_cookie);
+}
+
+pthread_t *trp_connection_get_thread(TRP_CONNECTION *conn)
+{
+ return conn->thread;
+}
+
+void trp_connection_set_thread(TRP_CONNECTION *conn, pthread_t *thread)
+{
+ conn->thread=thread;
+}
+
+TRP_CONNECTION *trp_connection_get_next(TRP_CONNECTION *conn)
+{
+ return conn->next;
+}
+
+static void trp_connection_set_next(TRP_CONNECTION *conn, TRP_CONNECTION *next)
+{
+ conn->next=next;
+}
+
+/* Ok to call more than once; guarantees connection no longer in the list. Does not free removed element.
+ * Returns handle to new list, you must replace your old handle on the list with this. */
+TRP_CONNECTION *trp_connection_remove(TRP_CONNECTION *conn, TRP_CONNECTION *remove)
+{
+ TRP_CONNECTION *cur=conn;
+ TRP_CONNECTION *last=NULL;
+
+ if (cur==NULL)
+ return NULL;
+
+ /* first element is a special case */
+ if (cur==remove) {
+ conn=trp_connection_get_next(cur); /* advance list head */
+ } else {
+ /* it was not the first element */
+ last=cur;
+ cur=trp_connection_get_next(cur);
+ while (cur!=NULL) {
+ if (cur==remove) {
+ trp_connection_set_next(last, trp_connection_get_next(cur));
+ break;
+ }
+ last=cur;
+ cur=trp_connection_get_next(cur);
+ }
+ }
+ return conn;
+}
+
+static TRP_CONNECTION *trp_connection_get_tail(TRP_CONNECTION *conn)
+{
+ while((conn!=NULL)&&(trp_connection_get_next(conn)!=NULL))
+ conn=trp_connection_get_next(conn);
+ return conn;
+}
+
+void trp_connection_append(TRP_CONNECTION *conn, TRP_CONNECTION *new)
+{
+ trp_connection_set_next(trp_connection_get_tail(conn), new);
+}
+
+static void trp_connection_mutex_init(TRP_CONNECTION *conn)
+{
+ pthread_mutex_init(&(conn->mutex), NULL);
+}
+
+/* talloc destructor for a connection: ensures connection is closed, memory freed */
+static int trp_connection_destructor(void *object)
+{
+ TRP_CONNECTION *conn=talloc_get_type_abort(object, TRP_CONNECTION); /* aborts on wrong type */
+ if ((trp_connection_get_status(conn)!=TRP_CONNECTION_CLOSED)
+ && (trp_connection_get_fd(conn)!=-1))
+ close(trp_connection_get_fd(conn));
+ if (conn->peer!=NULL)
+ tr_free_name(conn->peer);
+ if (conn->gssname!=NULL)
+ tr_free_name(conn->gssname);
+ return 0;
+}
+
+TRP_CONNECTION *trp_connection_new(TALLOC_CTX *mem_ctx)
+{
+ TRP_CONNECTION *new_conn=talloc(mem_ctx, TRP_CONNECTION);
+ gss_ctx_id_t *gssctx=NULL;
+ pthread_t *thread=NULL;
+
+
+ if (new_conn != NULL) {
+ trp_connection_set_next(new_conn, NULL);
+ trp_connection_set_fd(new_conn, -1);
+ trp_connection_set_gssname(new_conn, NULL);
+ trp_connection_mutex_init(new_conn);
+ new_conn->peer=NULL; /* no true set function for this */
+ new_conn->status_change_cb=NULL;
+ new_conn->status_change_cookie=NULL;
+ new_conn->status=TRP_CONNECTION_CLOSED;
+
+ thread=talloc(new_conn, pthread_t);
+ if (thread==NULL) {
+ talloc_free(new_conn);
+ return NULL;
+ }
+ trp_connection_set_thread(new_conn, thread);
+
+ gssctx=talloc(new_conn, gss_ctx_id_t);
+ if (gssctx==NULL) {
+ talloc_free(new_conn);
+ return NULL;
+ }
+ trp_connection_set_gssctx(new_conn, gssctx);
+ talloc_set_destructor((void *)new_conn, trp_connection_destructor);
+ }
+ return new_conn;
+}
+
+void trp_connection_free(TRP_CONNECTION *conn)
+{
+ talloc_free(conn);
+}
+
+void trp_connection_close(TRP_CONNECTION *conn)
+{
+ if ((conn->status!=TRP_CONNECTION_DOWN) && (conn->fd>0))
+ close(trp_connection_get_fd(conn));
+ trp_connection_set_fd(conn, -1);
+ trp_connection_set_status(conn, TRP_CONNECTION_DOWN);
+}
+
+/* returns 0 on authorization success, 1 on failure, or -1 in case of error */
+int trp_connection_auth(TRP_CONNECTION *conn, TRP_AUTH_FUNC auth_callback, void *callback_data)
+{
+ int rc = 0;
+ int auth, autherr = 0;
+ gss_buffer_desc nameBuffer = {0, NULL};
+ gss_ctx_id_t *gssctx=trp_connection_get_gssctx(conn);
+
+ nameBuffer.length = trp_connection_get_gssname(conn)->len;
+ nameBuffer.value = tr_name_strdup(trp_connection_get_gssname(conn));
+
+ tr_debug("trp_connection_auth: beginning passive authentication");
+ if (trp_connection_get_status(conn)!=TRP_CONNECTION_AUTHORIZING)
+ tr_warning("trp_connection_auth: warning: connection was not in TRP_CONNECTION_AUTHORIZING state.");
+
+ rc = gsscon_passive_authenticate(trp_connection_get_fd(conn), nameBuffer, gssctx, auth_callback, callback_data);
+ gss_release_buffer(NULL, &nameBuffer);
+ if (rc!=0) {
+ tr_debug("trp_connection_auth: Error from gsscon_passive_authenticate(), rc = 0x%08X.", rc);
+ trp_connection_set_status(conn, TRP_CONNECTION_DOWN);
+ return -1;
+ }
+
+ tr_debug("trp_connection_auth: beginning second stage authentication");
+ if (rc = gsscon_authorize(*gssctx, &auth, &autherr)) {
+ tr_debug("trp_connection_auth: Error from gsscon_authorize, rc = %d, autherr = %d.",
+ rc, autherr);
+ trp_connection_set_status(conn, TRP_CONNECTION_DOWN);
+ return -1;
+ }
+
+ trp_connection_set_peer(conn);
+ trp_connection_set_status(conn, TRP_CONNECTION_UP);
+
+ if (auth)
+ tr_debug("trp_connection_auth: Connection authenticated, fd = %d.", trp_connection_get_fd(conn));
+ else
+ tr_debug("trp_connection_auth: Authentication failed, fd = %d.", trp_connection_get_fd(conn));
+
+ return !auth;
+}
+
+/* Accept connection */
+TRP_CONNECTION *trp_connection_accept(TALLOC_CTX *mem_ctx, int listen, TR_NAME *gssname)
+{
+ int conn_fd=-1;
+ TRP_CONNECTION *conn=NULL;
+
+ conn_fd = accept(listen, NULL, NULL);
+
+ if (0 > conn_fd) {
+ tr_notice("trp_connection_accept: accept() returned error.");
+ return NULL;
+ }
+ conn=trp_connection_new(mem_ctx);
+ trp_connection_set_fd(conn, conn_fd);
+ trp_connection_set_gssname(conn, gssname);
+ trp_connection_set_status(conn, TRP_CONNECTION_AUTHORIZING);
+ return conn;
+}
+
+/* Initiate connection */
+TRP_RC trp_connection_initiate(TRP_CONNECTION *conn, char *server, unsigned int port)
+{
+ int err = 0;
+ int fd=-1;
+ unsigned int use_port=0;
+
+ if (0 == port)
+ use_port = TRP_PORT;
+ else
+ use_port = port;
+
+ if (conn==NULL) {
+ tr_err("trp_connection_initiate: null TRP_CONNECTION");
+ return TRP_BADARG;
+ }
+
+ tr_debug("trp_connection_initiate: opening GSS connection to %s:%d",
+ server,
+ use_port);
+ err = gsscon_connect(server,
+ use_port,
+ "trustrouter",
+ &fd,
+ trp_connection_get_gssctx(conn));
+ if (err) {
+ tr_err("trp_connection_initiate: connection failed.");
+ return TRP_ERROR;
+ } else {
+ tr_debug("trp_connection_initiate: connected.");
+ trp_connection_set_fd(conn, fd);
+ if (trp_connection_set_peer(conn)!=TRP_SUCCESS) {
+ tr_err("trp_connection_initiate: error setting peer gssname.");
+ trp_connection_close(conn);
+ return TRP_ERROR;
+ }
+ trp_connection_set_status(conn, TRP_CONNECTION_UP);
+ return TRP_SUCCESS;
+ }
+}
--- /dev/null
+#include <time.h>
+#include <talloc.h>
+
+#include <trust_router/tr_name.h>
+#include <trp_internal.h>
+#include <tr_gss.h>
+#include <trp_ptable.h>
+#include <tr_debug.h>
+
+static int trp_peer_destructor(void *object)
+{
+ TRP_PEER *peer=talloc_get_type_abort(object, TRP_PEER);
+ if (peer->servicename!=NULL)
+ tr_free_name(peer->servicename);
+ return 0;
+}
+TRP_PEER *trp_peer_new(TALLOC_CTX *memctx)
+{
+ TRP_PEER *peer=talloc(memctx, TRP_PEER);
+ if (peer!=NULL) {
+ peer->next=NULL;
+ peer->server=NULL;
+ peer->servicename=NULL;
+ peer->gss_names=NULL;
+ peer->port=0;
+ peer->linkcost=TRP_LINKCOST_DEFAULT;
+ peer->last_conn_attempt=(struct timespec){0,0};
+ peer->outgoing_status=PEER_DISCONNECTED;
+ peer->incoming_status=PEER_DISCONNECTED;
+ peer->conn_status_cb=NULL;
+ peer->conn_status_cookie=NULL;
+ talloc_set_destructor((void *)peer, trp_peer_destructor);
+ }
+ return peer;
+}
+
+void trp_peer_free(TRP_PEER *peer)
+{
+ talloc_free(peer);
+}
+
+static TRP_PEER *trp_peer_tail(TRP_PEER *peer)
+{
+ while (peer->next!=NULL) {
+ peer=peer->next;
+ }
+ return peer;
+}
+
+
+/* Get a name that identifies this peer for display to the user, etc.
+ * Do not modify or free the label. */
+TR_NAME *trp_peer_get_label(TRP_PEER *peer)
+{
+ TR_GSS_NAMES_ITER *iter=tr_gss_names_iter_new(NULL);
+ TR_NAME *name=NULL;
+
+ /* for now, use the first gss name */
+ if (iter!=NULL) {
+ name=tr_gss_names_iter_first(iter, peer->gss_names);
+ talloc_free(iter);
+ }
+ return name;
+}
+
+/* Get a name that identifies this peer for display to the user, etc.
+ * Makes a copy, caller is responsible for freeing. */
+TR_NAME *trp_peer_dup_label(TRP_PEER *peer)
+{
+ return tr_dup_name(trp_peer_get_label(peer));;
+}
+
+char *trp_peer_get_server(TRP_PEER *peer)
+{
+ return peer->server;
+}
+
+static void trp_peer_set_servicename(TRP_PEER *peer, const char *server)
+{
+ char *name=NULL;
+ if (peer->servicename !=NULL)
+ tr_free_name(peer->servicename);
+
+ if (server!=NULL)
+ name=talloc_asprintf(NULL, "trustrouter/%s", server);
+
+ if (name!=NULL) {
+ peer->servicename=tr_new_name(name);
+ talloc_free(name);
+ } else {
+ peer->servicename=NULL;
+ }
+}
+
+/* copies input; on error, peer->servicename will be null */
+void trp_peer_set_server(TRP_PEER *peer, const char *server)
+{
+ peer->server=talloc_strdup(peer, server); /* will be null on error */
+ trp_peer_set_servicename(peer, server);
+}
+
+void trp_peer_add_gss_name(TRP_PEER *peer, TR_NAME *gss_name)
+{
+ if (peer->gss_names==NULL)
+ trp_peer_set_gss_names(peer, tr_gss_names_new(peer));
+ tr_gss_names_add(peer->gss_names, gss_name);
+}
+
+void trp_peer_set_gss_names(TRP_PEER *peer, TR_GSS_NAMES *gss_names)
+{
+ if (peer->gss_names!=NULL)
+ talloc_free(peer->gss_names);
+
+ peer->gss_names=gss_names;
+ talloc_steal(peer, gss_names);
+}
+
+/* get the peer gss_names, caller must not free the result */
+TR_GSS_NAMES *trp_peer_get_gss_names(TRP_PEER *peer)
+{
+ return peer->gss_names;
+}
+
+/* get the service name (i.e., gssname we see when we connect to this peer) */
+TR_NAME *trp_peer_get_servicename(TRP_PEER *peer)
+{
+ return peer->servicename;
+}
+
+/* get a copy of the servicename, caller must free via tr_free_name */
+TR_NAME *trp_peer_dup_servicename(TRP_PEER *peer)
+{
+ return tr_dup_name(peer->servicename);
+}
+
+unsigned int trp_peer_get_port(TRP_PEER *peer)
+{
+ return peer->port;
+}
+
+void trp_peer_set_port(TRP_PEER *peer, unsigned int port)
+{
+ peer->port=port;
+}
+
+unsigned int trp_peer_get_linkcost(TRP_PEER *peer)
+{
+ if (peer!=NULL)
+ return peer->linkcost;
+ else
+ return 1;
+}
+
+void trp_peer_set_linkcost(TRP_PEER *peer, unsigned int linkcost)
+{
+ if ((linkcost>TRP_METRIC_INFINITY) && (linkcost!=TRP_METRIC_INVALID)) {
+ /* This indicates a programming error, but probably means an already infinite metric
+ * was (incorrectly) incremented. Issue a warning and proceed with an infinite metric. */
+ tr_warning("trp_peer_set_linkcost: link cost > infinity encountered, setting to infinity");
+ linkcost=TRP_METRIC_INFINITY;
+ }
+ peer->linkcost=linkcost;
+}
+
+void trp_peer_set_conn_status_cb(TRP_PEER *peer, void (*cb)(TRP_PEER *, void *), void *cookie)
+{
+ peer->conn_status_cb=cb;
+ peer->conn_status_cookie=cookie;
+}
+
+struct timespec *trp_peer_get_last_conn_attempt(TRP_PEER *peer)
+{
+ return &(peer->last_conn_attempt);
+}
+
+void trp_peer_set_last_conn_attempt(TRP_PEER *peer, struct timespec *time)
+{
+ peer->last_conn_attempt=*time;
+}
+
+TRP_PTABLE *trp_ptable_new(TALLOC_CTX *memctx)
+{
+ TRP_PTABLE *ptbl=talloc(memctx, TRP_PTABLE);
+ if (ptbl!=NULL) {
+ ptbl->head=NULL;
+ }
+ return ptbl;
+}
+
+void trp_peer_set_outgoing_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status)
+{
+ TR_NAME *peer_label=trp_peer_get_label(peer);
+ int was_connected=trp_peer_is_connected(peer);
+ peer->outgoing_status=status;
+ tr_debug("trp_peer_set_outgoing_status: %s: status=%d peer connected was %d now %d.",
+ peer_label->buf, status, was_connected, trp_peer_is_connected(peer));
+ if ((trp_peer_is_connected(peer) != was_connected) && (peer->conn_status_cb!=NULL))
+ peer->conn_status_cb(peer, peer->conn_status_cookie);
+}
+
+TRP_PEER_CONN_STATUS trp_peer_get_outgoing_status(TRP_PEER *peer)
+{
+ return peer->outgoing_status;
+}
+
+void trp_peer_set_incoming_status(TRP_PEER *peer, TRP_PEER_CONN_STATUS status)
+{
+ TR_NAME *peer_label=trp_peer_get_label(peer);
+ int was_connected=trp_peer_is_connected(peer);
+ peer->incoming_status=status;
+ tr_debug("trp_peer_set_incoming_status: %s: status=%d peer connected was %d now %d.",
+ peer_label->buf, status, was_connected, trp_peer_is_connected(peer));
+ if ((trp_peer_is_connected(peer) != was_connected) && (peer->conn_status_cb!=NULL))
+ peer->conn_status_cb(peer, peer->conn_status_cookie);
+}
+
+TRP_PEER_CONN_STATUS trp_peer_get_incoming_status(TRP_PEER *peer)
+{
+ return peer->incoming_status;
+}
+
+int trp_peer_is_connected(TRP_PEER *peer)
+{
+ return (peer->outgoing_status==PEER_CONNECTED) && (peer->incoming_status==PEER_CONNECTED);
+}
+
+void trp_ptable_free(TRP_PTABLE *ptbl)
+{
+ talloc_free(ptbl);
+}
+
+TRP_RC trp_ptable_add(TRP_PTABLE *ptbl, TRP_PEER *newpeer)
+{
+ if (ptbl->head==NULL)
+ ptbl->head=newpeer;
+ else
+ trp_peer_tail(ptbl->head)->next=newpeer;
+
+ talloc_steal(ptbl, newpeer);
+ return TRP_SUCCESS;
+}
+
+/* peer pointer is invalid after successful removal. Does nothing and returns
+ * TRP_ERROR if peer is not in the list. */
+TRP_RC trp_ptable_remove(TRP_PTABLE *ptbl, TRP_PEER *peer)
+{
+ TRP_PEER *cur=NULL;
+ TRP_PEER *last=NULL;
+ if (ptbl->head!=NULL) {
+ if (ptbl->head==peer) {
+ /* special case for removing head of list */
+ cur=ptbl->head;
+ ptbl->head=ptbl->head->next; /* advance the head */
+ trp_peer_free(cur);
+ }
+ for (cur=ptbl->head->next; cur!=NULL; last=cur,cur=cur->next) {
+ if (cur==peer) {
+ if (last!=NULL)
+ last->next=cur->next;
+ trp_peer_free(cur);
+ return TRP_SUCCESS;
+ }
+ }
+ }
+ return TRP_ERROR;
+}
+
+TRP_PEER *trp_ptable_find_gss_name(TRP_PTABLE *ptbl, TR_NAME *gssname)
+{
+ TRP_PEER *cur=ptbl->head;
+ while ((cur!=NULL) && (!tr_gss_names_matches(trp_peer_get_gss_names(cur), gssname)))
+ cur=cur->next;
+ return cur;
+}
+
+TRP_PEER *trp_ptable_find_servicename(TRP_PTABLE *ptbl, TR_NAME *servicename)
+{
+ TRP_PEER *cur=ptbl->head;
+ while ((cur!=NULL) && (0 != tr_name_cmp(trp_peer_get_servicename(cur), servicename)))
+ cur=cur->next;
+ return cur;
+}
+
+char *trp_peer_to_str(TALLOC_CTX *memctx, TRP_PEER *peer, const char *sep)
+{
+ if (sep==NULL)
+ sep=", ";
+ return talloc_asprintf(memctx,
+ "%s:%u%s0x%04X",
+ peer->server, peer->port, sep,
+ peer->linkcost);
+}
+
+/* this is horribly inefficient but should be ok for small peer tables */
+char *trp_ptable_to_str(TALLOC_CTX *memctx, TRP_PTABLE *ptbl, const char *sep, const char *lineterm)
+{
+ TALLOC_CTX *tmpctx=talloc_new(NULL);
+ TRP_PEER *peer=NULL;
+ char *result=talloc_strdup(tmpctx, "");
+
+ if (lineterm==NULL)
+ lineterm="\n";
+
+ /* this leaves intermediate result strings in the tmpctx context, we'll free these when
+ * we're done */
+ for (peer=ptbl->head; peer!=NULL; peer=peer->next)
+ result=talloc_asprintf(tmpctx, "%s%s%s", result, lineterm, trp_peer_to_str(tmpctx, peer, sep));
+
+ talloc_steal(memctx, result); /* hand result over to caller */
+ talloc_free(tmpctx); /* free detritus */
+ return result;
+}
+
+TRP_PTABLE_ITER *trp_ptable_iter_new(TALLOC_CTX *mem_ctx)
+{
+ TRP_PTABLE_ITER *iter=talloc(mem_ctx, TRP_PTABLE_ITER);
+ *iter=NULL;
+ return iter;
+}
+
+TRP_PEER *trp_ptable_iter_first(TRP_PTABLE_ITER *iter, TRP_PTABLE *ptbl)
+{
+ if (ptbl==NULL)
+ *iter=NULL;
+ else
+ *iter=ptbl->head;
+ return *iter;
+}
+
+TRP_PEER *trp_ptable_iter_next(TRP_PTABLE_ITER *iter)
+{
+ if (*iter!=NULL)
+ *iter=(*iter)->next;
+ return *iter;
+}
+
+void trp_ptable_iter_free(TRP_PTABLE_ITER *iter)
+{
+ talloc_free(iter);
+}
+
--- /dev/null
+#include <jansson.h>
+#include <talloc.h>
+
+#include <trust_router/tr_name.h>
+#include <trp_internal.h>
+#include <tr_debug.h>
+
+static int trp_req_destructor(void *object)
+{
+ TRP_REQ *req=talloc_get_type_abort(object, TRP_REQ);
+
+ /* clean up TR_NAME data, which are not managed by talloc */
+ if (req->comm != NULL)
+ tr_free_name(req->comm);
+
+ if (req->realm != NULL)
+ tr_free_name(req->realm);
+
+ if (req->peer != NULL)
+ tr_free_name(req->peer);
+
+ return 0;
+}
+
+TRP_REQ *trp_req_new(TALLOC_CTX *mem_ctx)
+{
+ TRP_REQ *new_req=talloc(mem_ctx, TRP_REQ);
+
+ if (new_req != NULL) {
+ new_req->comm=NULL;
+ new_req->realm=NULL;
+ new_req->peer=NULL;
+ }
+
+ talloc_set_destructor((void *)new_req, trp_req_destructor);
+ return new_req;
+}
+
+void trp_req_free(TRP_REQ *req)
+{
+ if (req!=NULL)
+ talloc_free(req);
+}
+
+TR_NAME *trp_req_get_comm(TRP_REQ *req)
+{
+ if (req!=NULL)
+ return req->comm;
+ else
+ return NULL;
+}
+
+void trp_req_set_comm(TRP_REQ *req, TR_NAME *comm)
+{
+ if (req)
+ req->comm=comm;
+}
+
+TR_NAME *trp_req_get_realm(TRP_REQ *req)
+{
+ if (req!=NULL)
+ return req->realm;
+ else
+ return NULL;
+}
+
+
+void trp_req_set_realm(TRP_REQ *req, TR_NAME *realm)
+{
+ if (req)
+ req->realm=realm;
+}
+
+TR_NAME *trp_req_get_peer(TRP_REQ *req)
+{
+ if (req!=NULL)
+ return req->peer;
+ else
+ return NULL;
+}
+
+
+void trp_req_set_peer(TRP_REQ *req, TR_NAME *peer)
+{
+ if (req)
+ req->peer=peer;
+}
+
+/* Defines what we use as a wildcard for realm or community name.
+ * Must not be a valid name for either of those. Currently, we
+ * use the empty string. */
+static int trp_req_name_is_wildcard(TR_NAME *name)
+{
+ return (name!=NULL) && (name->len==0);
+}
+
+int trp_req_is_wildcard(TRP_REQ *req)
+{
+ return (req!=NULL) && trp_req_name_is_wildcard(req->comm) && trp_req_name_is_wildcard(req->realm);
+}
+
+TRP_RC trp_req_make_wildcard(TRP_REQ *req)
+{
+ if (req==NULL)
+ return TRP_BADARG;
+
+ req->comm=tr_new_name("");
+ if (req->comm==NULL)
+ return TRP_NOMEM;
+
+ req->realm=tr_new_name("");
+ if (req->realm==NULL) {
+ tr_free_name(req->comm);
+ req->comm=NULL;
+ return TRP_NOMEM;
+ }
+
+ return TRP_SUCCESS;
+}
--- /dev/null
+#include <stdlib.h>
+
+#include <glib.h>
+#include <talloc.h>
+#include <time.h>
+
+#include <trust_router/tr_name.h>
+#include <trp_internal.h>
+#include <trp_rtable.h>
+#include <tr_debug.h>
+#include <trust_router/trp.h>
+#include <trust_router/tid.h>
+
+/* Note: be careful mixing talloc with glib. */
+
+static int trp_route_destructor(void *obj)
+{
+ TRP_ROUTE *entry=talloc_get_type_abort(obj, TRP_ROUTE);
+ if (entry->comm!=NULL)
+ tr_free_name(entry->comm);
+ if (entry->realm!=NULL)
+ tr_free_name(entry->realm);
+ if (entry->trust_router!=NULL)
+ tr_free_name(entry->trust_router);
+ if (entry->peer!=NULL)
+ tr_free_name(entry->peer);
+ if (entry->next_hop!=NULL)
+ tr_free_name(entry->next_hop);
+ return 0;
+}
+
+TRP_ROUTE *trp_route_new(TALLOC_CTX *mem_ctx)
+{
+ TRP_ROUTE *entry=talloc(mem_ctx, TRP_ROUTE);
+ if (entry!=NULL) {
+ entry->comm=NULL;
+ entry->realm=NULL;
+ entry->trust_router=NULL;
+ entry->trp_port=TRP_PORT;
+ entry->tid_port=TID_PORT;
+ entry->peer=NULL;
+ entry->next_hop=NULL;
+ entry->selected=0;
+ entry->interval=0;
+ entry->expiry=talloc(entry, struct timespec);
+ if (entry->expiry==NULL) {
+ talloc_free(entry);
+ return NULL;
+ }
+ *(entry->expiry)=(struct timespec){0,0};
+ entry->local=0;
+ entry->triggered=0;
+ talloc_set_destructor((void *)entry, trp_route_destructor);
+ }
+ return entry;
+}
+
+void trp_route_free(TRP_ROUTE *entry)
+{
+ if (entry!=NULL)
+ talloc_free(entry);
+}
+
+void trp_route_set_comm(TRP_ROUTE *entry, TR_NAME *comm)
+{
+ if (entry->comm!=NULL)
+ tr_free_name(entry->comm);
+ entry->comm=comm;
+}
+
+TR_NAME *trp_route_get_comm(TRP_ROUTE *entry)
+{
+ return entry->comm;
+}
+
+TR_NAME *trp_route_dup_comm(TRP_ROUTE *entry)
+{
+ return tr_dup_name(trp_route_get_comm(entry));
+}
+
+void trp_route_set_realm(TRP_ROUTE *entry, TR_NAME *realm)
+{
+ if (entry->realm!=NULL)
+ tr_free_name(entry->realm);
+ entry->realm=realm;
+}
+
+TR_NAME *trp_route_get_realm(TRP_ROUTE *entry)
+{
+ return entry->realm;
+}
+
+TR_NAME *trp_route_dup_realm(TRP_ROUTE *entry)
+{
+ return tr_dup_name(trp_route_get_realm(entry));
+}
+
+void trp_route_set_trust_router(TRP_ROUTE *entry, TR_NAME *tr)
+{
+ if (entry->trust_router!=NULL)
+ tr_free_name(entry->trust_router);
+ entry->trust_router=tr;
+}
+
+TR_NAME *trp_route_get_trust_router(TRP_ROUTE *entry)
+{
+ return entry->trust_router;
+}
+
+TR_NAME *trp_route_dup_trust_router(TRP_ROUTE *entry)
+{
+ return tr_dup_name(trp_route_get_trust_router(entry));
+}
+
+void trp_route_set_peer(TRP_ROUTE *entry, TR_NAME *peer)
+{
+ if (entry->peer!=NULL)
+ tr_free_name(entry->peer);
+ entry->peer=peer;
+}
+
+TR_NAME *trp_route_get_peer(TRP_ROUTE *entry)
+{
+ return entry->peer;
+}
+
+TR_NAME *trp_route_dup_peer(TRP_ROUTE *entry)
+{
+ return tr_dup_name(trp_route_get_peer(entry));
+}
+
+void trp_route_set_metric(TRP_ROUTE *entry, unsigned int metric)
+{
+ entry->metric=metric;
+}
+
+unsigned int trp_route_get_metric(TRP_ROUTE *entry)
+{
+ return entry->metric;
+}
+
+/* TODO: set the hostname and port for the next hop. Currently assume default TID port. --jlr */
+void trp_route_set_next_hop(TRP_ROUTE *entry, TR_NAME *next_hop)
+{
+ if (entry->next_hop!=NULL)
+ tr_free_name(entry->next_hop);
+ entry->next_hop=next_hop;
+}
+
+TR_NAME *trp_route_get_next_hop(TRP_ROUTE *entry)
+{
+ return entry->next_hop;
+}
+
+TR_NAME *trp_route_dup_next_hop(TRP_ROUTE *entry)
+{
+ return tr_dup_name(trp_route_get_next_hop(entry));
+}
+
+void trp_route_set_selected(TRP_ROUTE *entry, int sel)
+{
+ entry->selected=sel;
+}
+
+int trp_route_is_selected(TRP_ROUTE *entry)
+{
+ return entry->selected;
+}
+
+void trp_route_set_interval(TRP_ROUTE *entry, int interval)
+{
+ entry->interval=interval;
+}
+
+int trp_route_get_interval(TRP_ROUTE *entry)
+{
+ return entry->interval;
+}
+
+/* copies incoming value, does not assume responsibility for freeing */
+void trp_route_set_expiry(TRP_ROUTE *entry, struct timespec *exp)
+{
+ entry->expiry->tv_sec=exp->tv_sec;
+ entry->expiry->tv_nsec=exp->tv_nsec;
+}
+
+struct timespec *trp_route_get_expiry(TRP_ROUTE *entry)
+{
+ return entry->expiry;
+}
+
+void trp_route_set_local(TRP_ROUTE *entry, int local)
+{
+ entry->local=local;
+}
+
+int trp_route_is_local(TRP_ROUTE *entry)
+{
+ return entry->local;
+}
+
+void trp_route_set_triggered(TRP_ROUTE *entry, int trig)
+{
+ tr_debug("trp_route_set_triggered: setting route to %.*s/%.*s through %.*s to %s",
+ entry->comm->len, entry->comm->buf,
+ entry->realm->len, entry->realm->buf,
+ entry->peer->len, entry->peer->buf,
+ trig ? "triggered" : "not triggered");
+ entry->triggered=trig;
+}
+
+int trp_route_is_triggered(TRP_ROUTE *entry)
+{
+ return entry->triggered;
+}
+
+
+/* result must be freed with g_free */
+static gchar *tr_name_to_g_str(const TR_NAME *n)
+{
+ gchar *s=g_strndup(n->buf, n->len);
+ if (s==NULL)
+ tr_debug("tr_name_to_g_str: allocation failure.");
+ return s;
+}
+
+/* hash function for TR_NAME keys */
+static guint trp_tr_name_hash(gconstpointer key)
+{
+ const TR_NAME *name=(TR_NAME *)key;
+ gchar *s=tr_name_to_g_str(name);
+ guint hash=g_str_hash(s);
+ g_free(s);
+ return hash;
+}
+
+/* hash equality function for TR_NAME keys */
+static gboolean trp_tr_name_equal(gconstpointer key1, gconstpointer key2)
+{
+ const TR_NAME *n1=(TR_NAME *)key1;
+ const TR_NAME *n2=(TR_NAME *)key2;
+ gchar *s1=tr_name_to_g_str(n1);
+ gchar *s2=tr_name_to_g_str(n2);
+ gboolean equal=g_str_equal(s1, s2);
+ g_free(s1);
+ g_free(s2);
+ return equal;
+}
+
+/* free a value to the top level rtable (a hash of all entries in the comm) */
+static void trp_rtable_destroy_table(gpointer data)
+{
+ g_hash_table_destroy(data);
+}
+
+static void trp_rtable_destroy_rentry(gpointer data)
+{
+ trp_route_free(data);
+}
+
+static void trp_rtable_destroy_tr_name(gpointer data)
+{
+ tr_free_name(data);
+}
+
+TRP_RTABLE *trp_rtable_new(void)
+{
+ GHashTable *new=g_hash_table_new_full(trp_tr_name_hash,
+ trp_tr_name_equal,
+ trp_rtable_destroy_tr_name,
+ trp_rtable_destroy_table);
+ return new;
+}
+
+void trp_rtable_free(TRP_RTABLE *rtbl)
+{
+ g_hash_table_destroy(rtbl);
+}
+
+static GHashTable *trp_rtbl_get_or_add_table(GHashTable *tbl, TR_NAME *key, GDestroyNotify destroy)
+{
+ GHashTable *val_tbl=NULL;
+
+ val_tbl=g_hash_table_lookup(tbl, key);
+ if (val_tbl==NULL) {
+ val_tbl=g_hash_table_new_full(trp_tr_name_hash,
+ trp_tr_name_equal,
+ trp_rtable_destroy_tr_name,
+ destroy);
+ g_hash_table_insert(tbl, tr_dup_name(key), val_tbl);
+ }
+ return val_tbl;
+}
+
+void trp_rtable_add(TRP_RTABLE *rtbl, TRP_ROUTE *entry)
+{
+ GHashTable *comm_tbl=NULL;
+ GHashTable *realm_tbl=NULL;
+
+ comm_tbl=trp_rtbl_get_or_add_table(rtbl, entry->comm, trp_rtable_destroy_table);
+ realm_tbl=trp_rtbl_get_or_add_table(comm_tbl, entry->realm, trp_rtable_destroy_rentry);
+ g_hash_table_insert(realm_tbl, tr_dup_name(entry->peer), entry); /* destroys and replaces a duplicate */
+ /* the route entry should not belong to any context, we will manage it ourselves */
+ talloc_steal(NULL, entry);
+}
+
+/* note: the entry pointer passed in is invalid after calling this because the entry is freed */
+void trp_rtable_remove(TRP_RTABLE *rtbl, TRP_ROUTE *entry)
+{
+ GHashTable *comm_tbl=NULL;
+ GHashTable *realm_tbl=NULL;
+
+ comm_tbl=g_hash_table_lookup(rtbl, entry->comm);
+ if (comm_tbl==NULL)
+ return;
+
+ realm_tbl=g_hash_table_lookup(comm_tbl, entry->realm);
+ if (realm_tbl==NULL)
+ return;
+
+ /* remove the element */
+ g_hash_table_remove(realm_tbl, entry->peer);
+ /* if that was the last entry in the realm, remove the realm table */
+ if (g_hash_table_size(realm_tbl)==0)
+ g_hash_table_remove(comm_tbl, entry->realm);
+ /* if that was the last realm in the comm, remove the comm table */
+ if (g_hash_table_size(comm_tbl)==0)
+ g_hash_table_remove(rtbl, entry->comm);
+}
+
+void trp_rtable_clear(TRP_RTABLE *rtbl)
+{
+ g_hash_table_remove_all(rtbl); /* destructors should do all the cleanup */
+}
+
+/* gets the actual hash table, for internal use only */
+static GHashTable *trp_rtable_get_comm_table(TRP_RTABLE *rtbl, TR_NAME *comm)
+{
+ return g_hash_table_lookup(rtbl, comm);
+}
+
+/* gets the actual hash table, for internal use only */
+static GHashTable *trp_rtable_get_realm_table(TRP_RTABLE *rtbl, TR_NAME *comm, TR_NAME *realm)
+{
+ GHashTable *comm_tbl=trp_rtable_get_comm_table(rtbl, comm);
+ if (comm_tbl==NULL)
+ return NULL;
+ else
+ return g_hash_table_lookup(comm_tbl, realm);
+}
+
+struct table_size_cookie {
+ TRP_RTABLE *rtbl;
+ size_t size;
+};
+static void trp_rtable_size_helper(gpointer key, gpointer value, gpointer user_data)
+{
+ struct table_size_cookie *data=(struct table_size_cookie *)user_data;
+ data->size += trp_rtable_comm_size(data->rtbl, (TR_NAME *)key);
+};
+size_t trp_rtable_size(TRP_RTABLE *rtbl)
+{
+ struct table_size_cookie data={rtbl, 0};
+ g_hash_table_foreach(rtbl, trp_rtable_size_helper, &data);
+ return data.size;
+}
+
+struct table_comm_size_cookie {
+ TR_NAME *comm;
+ TRP_RTABLE *rtbl;
+ size_t size;
+};
+static void table_comm_size_helper(gpointer key, gpointer value, gpointer user_data)
+{
+ struct table_comm_size_cookie *data=(struct table_comm_size_cookie *)user_data;
+ data->size += trp_rtable_realm_size(data->rtbl, data->comm, (TR_NAME *)key);
+}
+size_t trp_rtable_comm_size(TRP_RTABLE *rtbl, TR_NAME *comm)
+{
+ struct table_comm_size_cookie data={comm, rtbl, 0};
+ GHashTable *comm_tbl=trp_rtable_get_comm_table(rtbl, comm);
+ if (comm_tbl==NULL)
+ return 0;;
+ g_hash_table_foreach(comm_tbl, table_comm_size_helper, &data);
+ return data.size;
+}
+
+size_t trp_rtable_realm_size(TRP_RTABLE *rtbl, TR_NAME *comm, TR_NAME *realm)
+{
+ GHashTable *realm_tbl=trp_rtable_get_realm_table(rtbl, comm, realm);
+ if (realm_tbl==NULL)
+ return 0;
+ else
+ return g_hash_table_size(g_hash_table_lookup(
+ g_hash_table_lookup(rtbl, comm),
+ realm));
+}
+
+/* Returns an array of pointers to TRP_ROUTE, length of array in n_out.
+ * Caller must free the array (in the talloc NULL context), but must
+ * not free its contents. */
+TRP_ROUTE **trp_rtable_get_entries(TRP_RTABLE *rtbl, size_t *n_out)
+{
+ TRP_ROUTE **ret=NULL;
+ TR_NAME **comm=NULL;
+ size_t n_comm=0;
+ TRP_ROUTE **comm_entries=NULL;
+ size_t n_entries=0;
+ size_t ii_ret=0;
+
+ *n_out=trp_rtable_size(rtbl);
+ if (*n_out==0)
+ return NULL;
+
+ ret=talloc_array(NULL, TRP_ROUTE *, *n_out);
+ if (ret==NULL) {
+ tr_crit("trp_rtable_get_entries: unable to allocate return array.");
+ *n_out=0;
+ return NULL;
+ }
+
+ ii_ret=0; /* counts output entries */
+ comm=trp_rtable_get_comms(rtbl, &n_comm);
+ while(n_comm--) {
+ comm_entries=trp_rtable_get_comm_entries(rtbl, comm[n_comm], &n_entries);
+ while (n_entries--)
+ ret[ii_ret++]=comm_entries[n_entries];
+ talloc_free(comm_entries);
+ }
+ talloc_free(comm);
+
+ if (ii_ret!=*n_out) {
+ tr_crit("trp_rtable_get_entries: found incorrect number of entries.");
+ talloc_free(ret);
+ *n_out=0;
+ return NULL;
+ }
+ return ret;
+}
+
+/* Returns an array of pointers to TR_NAME, length of array in n_out.
+ * Caller must free the array (in the talloc NULL context). */
+TR_NAME **trp_rtable_get_comms(TRP_RTABLE *rtbl, size_t *n_out)
+{
+ size_t len=g_hash_table_size(rtbl); /* known comms are keys in top level hash table */
+ size_t ii=0;
+ GList *comms=NULL;;
+ GList *p=NULL;
+ TR_NAME **ret=NULL;
+
+ if (len==0) {
+ *n_out=0;
+ return NULL;
+ }
+
+ ret=talloc_array(NULL, TR_NAME *, len);
+ if (ret==NULL) {
+ tr_crit("trp_rtable_get_comms: unable to allocate return array.");
+ *n_out=0;
+ return NULL;
+ }
+ comms=g_hash_table_get_keys(rtbl);
+ for (ii=0,p=comms; p!=NULL; ii++,p=g_list_next(p))
+ ret[ii]=(TR_NAME *)p->data;
+
+ g_list_free(comms);
+
+ *n_out=len;
+ return ret;
+}
+
+/* Returns an array of pointers to TR_NAME, length of array in n_out.
+ * Caller must free the array (in the talloc NULL context). */
+TR_NAME **trp_rtable_get_comm_realms(TRP_RTABLE *rtbl, TR_NAME *comm, size_t *n_out)
+{
+ size_t ii=0;
+ TRP_RTABLE *comm_tbl=g_hash_table_lookup(rtbl, comm);;
+ GList *entries=NULL;
+ GList *p=NULL;
+ TR_NAME **ret=NULL;
+
+ if (comm_tbl==NULL) {
+ *n_out=0;
+ return NULL;
+ }
+ *n_out=g_hash_table_size(comm_tbl); /* set output length */
+ ret=talloc_array(NULL, TR_NAME *, *n_out);
+ entries=g_hash_table_get_keys(comm_tbl);
+ for (ii=0,p=entries; p!=NULL; ii++,p=g_list_next(p))
+ ret[ii]=(TR_NAME *)p->data;
+
+ g_list_free(entries);
+ return ret;
+}
+
+/* Get all entries in an comm. Returns an array of pointers in NULL talloc context.
+ * Caller must free this list with talloc_free, but must not free the entries in the
+ * list.. */
+TRP_ROUTE **trp_rtable_get_comm_entries(TRP_RTABLE *rtbl, TR_NAME *comm, size_t *n_out)
+{
+ size_t ii=0, jj=0;
+ TR_NAME **realm=NULL;
+ size_t n_realms=0;
+ TRP_ROUTE **realm_entries=NULL;
+ size_t n_entries=0;
+ TRP_ROUTE **ret=NULL;
+ size_t ii_ret=0;
+
+ *n_out=trp_rtable_comm_size(rtbl, comm);
+ if (*n_out==0)
+ return NULL;
+
+ ret=talloc_array(NULL, TRP_ROUTE *, *n_out);
+ if (ret==NULL) {
+ tr_crit("trp_rtable_get_comm_entries: could not allocate return array.");
+ *n_out=0;
+ return NULL;
+ }
+
+ ii_ret=0; /* counts entries in the output array */
+ realm=trp_rtable_get_comm_realms(rtbl, comm, &n_realms);
+ for (ii=0; ii<n_realms; ii++) {
+ realm_entries=trp_rtable_get_realm_entries(rtbl, comm, realm[ii], &n_entries);
+ for (jj=0; jj<n_entries; jj++)
+ ret[ii_ret++]=realm_entries[jj];
+ talloc_free(realm_entries);
+ }
+ talloc_free(realm);
+
+ if (ii_ret!=*n_out) {
+ tr_crit("trp_rtable_get_comm_entries: found incorrect number of entries.");
+ talloc_free(ret);
+ *n_out=0;
+ return NULL;
+ }
+
+ return ret;
+}
+
+/* Get all entries in an comm/realm. Returns an array of pointers in NULL talloc context.
+ * Caller must free this list with talloc_free, but must not free the entries in the
+ * list.. */
+TRP_ROUTE **trp_rtable_get_realm_entries(TRP_RTABLE *rtbl, TR_NAME *comm, TR_NAME *realm, size_t *n_out)
+{
+ size_t ii=0;
+ TRP_ROUTE **ret=NULL;
+ TR_NAME **peer=NULL;
+
+ tr_debug("trp_rtable_get_realm_entries: entered.");
+ peer=trp_rtable_get_comm_realm_peers(rtbl, comm, realm, n_out);
+ ret=talloc_array(NULL, TRP_ROUTE *, *n_out);
+ if (ret==NULL) {
+ tr_crit("trp_rtable_get_realm_entries: could not allocate return array.");
+ talloc_free(peer);
+ n_out=0;
+ return NULL;
+ }
+ for (ii=0; ii<*n_out; ii++)
+ ret[ii]=trp_rtable_get_entry(rtbl, comm, realm, peer[ii]);
+ talloc_free(peer);
+ return ret;
+}
+
+TR_NAME **trp_rtable_get_comm_realm_peers(TRP_RTABLE *rtbl, TR_NAME *comm, TR_NAME *realm, size_t *n_out)
+{
+ TR_NAME **ret=NULL;
+ GHashTable *realm_tbl=NULL;
+ GList *keys=NULL;
+ GList *p=NULL;
+ size_t ii=0;
+
+ *n_out=trp_rtable_realm_size(rtbl, comm, realm);
+ if (*n_out==0)
+ return NULL;
+ realm_tbl=trp_rtable_get_realm_table(rtbl, comm, realm);
+ ret=talloc_array(NULL, TR_NAME *, *n_out);
+ if (ret==NULL) {
+ tr_crit("trp_rtable_get_comm_realm_peers: could not allocate return array.");
+ *n_out=0;
+ return NULL;
+ }
+ keys=g_hash_table_get_keys(realm_tbl);
+ for (ii=0,p=keys; p!=NULL; ii++,p=g_list_next(p))
+ ret[ii]=(TR_NAME *)p->data;
+ g_list_free(keys);
+ return ret;
+}
+
+/* Gets a single entry. Do not free it. */
+TRP_ROUTE *trp_rtable_get_entry(TRP_RTABLE *rtbl, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer)
+{
+ GHashTable *realm_tbl=NULL;
+
+ realm_tbl=trp_rtable_get_realm_table(rtbl, comm, realm);
+ if (realm_tbl==NULL)
+ return NULL;
+
+ return g_hash_table_lookup(realm_tbl, peer); /* does not copy or increment ref count */
+}
+
+static char *timespec_to_str(struct timespec *ts)
+{
+ struct tm tm;
+ char *s=NULL;
+
+ if (localtime_r(&(ts->tv_sec), &tm)==NULL)
+ return NULL;
+
+ s=malloc(40); /* long enough to contain strftime result */
+ if (s==NULL)
+ return NULL;
+
+ if (strftime(s, 40, "%F %T", &tm)==0) {
+ free(s);
+ return NULL;
+ }
+ return s;
+}
+
+TRP_ROUTE *trp_rtable_get_selected_entry(TRP_RTABLE *rtbl, TR_NAME *comm, TR_NAME *realm)
+{
+ size_t n=0;
+ int ii=0;
+ TRP_ROUTE **entry=trp_rtable_get_realm_entries(rtbl, comm, realm, &n);
+ TRP_ROUTE *selected=NULL;
+
+ if (n==0)
+ return NULL;
+
+ tr_debug("trp_rtable_get_selected_entry: looking through route table entries for realm %.*s.",
+ realm->len, realm->buf);
+ for(ii=0; ii<n; ii++) {
+ if (trp_route_is_selected(entry[ii])) {
+ selected=entry[ii];
+ break;
+ }
+ }
+ tr_debug("trp_rtable_get_selected_entry: ii=%d.", ii);
+
+ talloc_free(entry);
+ return selected;
+}
+
+/* Pretty print a route table entry to a newly allocated string. If sep is NULL,
+ * returns comma+space separated string. */
+char *trp_route_to_str(TALLOC_CTX *mem_ctx, TRP_ROUTE *entry, const char *sep)
+{
+ char *comm=tr_name_strdup(entry->comm);
+ char *realm=tr_name_strdup(entry->realm);
+ char *peer=tr_name_strdup(entry->peer);
+ char *trust_router=tr_name_strdup(entry->trust_router);
+ char *next_hop=tr_name_strdup(entry->next_hop);
+ char *expiry=timespec_to_str(entry->expiry);
+ char *result=NULL;
+
+ if (sep==NULL)
+ sep=", ";
+
+ result=talloc_asprintf(mem_ctx,
+ "%s%s%s%s%s%s%u%s%s%s%s%s%u%s%u%s%s%s%u",
+ comm, sep,
+ realm, sep,
+ peer, sep,
+ entry->metric, sep,
+ trust_router, sep,
+ next_hop, sep,
+ entry->selected, sep,
+ entry->local, sep,
+ expiry, sep,
+ entry->triggered);
+ free(comm);
+ free(realm);
+ free(peer);
+ free(trust_router);
+ free(next_hop);
+ free(expiry);
+ return result;
+}
+
+void trp_rtable_clear_triggered(TRP_RTABLE *rtbl)
+{
+ size_t n_entries=0;
+ TRP_ROUTE **entries=trp_rtable_get_entries(rtbl, &n_entries);
+ size_t ii=0;
+
+ if (entries!=NULL) {
+ for (ii=0; ii<n_entries; ii++)
+ trp_route_set_triggered(entries[ii], 0);
+ talloc_free(entries);
+ }
+}
+
+static int sort_tr_names_cmp(const void *a, const void *b)
+{
+ TR_NAME **n1=(TR_NAME **)a;
+ TR_NAME **n2=(TR_NAME **)b;
+ return tr_name_cmp(*n1, *n2);
+}
+
+static void sort_tr_names(TR_NAME **names, size_t n_names)
+{
+ qsort(names, n_names, sizeof(TR_NAME *), sort_tr_names_cmp);
+}
+
+char *trp_rtable_to_str(TALLOC_CTX *mem_ctx, TRP_RTABLE *rtbl, const char *sep, const char *lineterm)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_NAME **comms=NULL;
+ size_t n_comms=0;
+ TR_NAME **realms=NULL;
+ size_t n_realms=0;
+ TRP_ROUTE **entries=NULL;
+ size_t n_entries=0;
+ char **tbl_strings=NULL;
+ size_t ii_tbl=0; /* counts tbl_strings */
+ size_t tbl_size=0;
+ size_t len=0;
+ size_t ii=0, jj=0, kk=0;
+ char *p=NULL;
+ char *result=NULL;
+
+ if (lineterm==NULL)
+ lineterm="\n";
+
+ tbl_size=trp_rtable_size(rtbl);
+ if (tbl_size==0) {
+ result=talloc_strdup(mem_ctx, lineterm);
+ goto cleanup;
+ }
+
+ tbl_strings=talloc_array(tmp_ctx, char *, tbl_size);
+ if (tbl_strings==NULL) {
+ result=talloc_strdup(mem_ctx, "error");
+ goto cleanup;
+ }
+
+ comms=trp_rtable_get_comms(rtbl, &n_comms);
+ talloc_steal(tmp_ctx, comms);
+ sort_tr_names(comms, n_comms);
+ ii_tbl=0;
+ len=0;
+ for (ii=0; ii<n_comms; ii++) {
+ realms=trp_rtable_get_comm_realms(rtbl, comms[ii], &n_realms);
+ talloc_steal(tmp_ctx, realms);
+ sort_tr_names(realms, n_realms);
+ for (jj=0; jj<n_realms; jj++) {
+ entries=trp_rtable_get_realm_entries(rtbl, comms[ii], realms[jj], &n_entries);
+ talloc_steal(tmp_ctx, entries);
+ for (kk=0; kk<n_entries; kk++) {
+ tbl_strings[ii_tbl]=trp_route_to_str(tmp_ctx, entries[kk], sep);
+ len+=strlen(tbl_strings[ii_tbl]);
+ ii_tbl++;
+ }
+ talloc_free(entries);
+ }
+ talloc_free(realms);
+ }
+ talloc_free(comms);
+
+ /* now combine all the strings */
+ len += tbl_size*strlen(lineterm); /* space for line terminations*/
+ len += 1; /* nul terminator */
+ result=(char *)talloc_size(tmp_ctx, len);
+ for (p=result,ii=0; ii < tbl_size; ii++) {
+ p+=sprintf(p, "%s%s", tbl_strings[ii], lineterm);
+ }
+ talloc_steal(mem_ctx, result);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return result;
+}
--- /dev/null
+#include <jansson.h>
+#include <talloc.h>
+
+#include <trust_router/tr_name.h>
+#include <trp_internal.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);
+
+
+struct trp_inforec_type_entry {
+ const char *name;
+ TRP_INFOREC_TYPE type;
+ void *(*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 },
+ { NULL, TRP_INFOREC_TYPE_UNKNOWN, NULL, NULL } /* must be the last entry */
+};
+
+
+/* look up an entry in the trp_inforec_type_table */
+static struct trp_inforec_type_entry *get_trp_inforec_type_entry(TRP_INFOREC_TYPE msgtype)
+{
+ struct trp_inforec_type_entry *entry=trp_inforec_type_table;
+
+ while ((entry->type != TRP_INFOREC_TYPE_UNKNOWN)
+ && (entry->type != msgtype)) {
+ entry ++;
+ }
+ return entry;
+}
+
+/* translate strings to codes */
+TRP_INFOREC_TYPE trp_inforec_type_from_string(const char *s)
+{
+ struct trp_inforec_type_entry *entry=trp_inforec_type_table;
+
+ while ((entry->type != TRP_INFOREC_TYPE_UNKNOWN)
+ && (strcmp(s, entry->name)!=0)) {
+ entry++;
+ }
+ return entry->type;
+}
+/* translate codes to strings (do not need to be freed)
+ * Returns NULL on an unknown code */
+const char *trp_inforec_type_to_string(TRP_INFOREC_TYPE msgtype)
+{
+ struct trp_inforec_type_entry *entry=get_trp_inforec_type_entry(msgtype);
+ return entry->name;
+}
+
+/* called by talloc when destroying an update message body */
+static int trp_inforec_route_destructor(void *object)
+{
+ 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) {
+ tr_free_name(body->trust_router);
+ body->trust_router=NULL;
+ tr_debug("trp_inforec_route_destructor: freed trust_router");
+ }
+ 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)
+{
+ TRP_INFOREC_ROUTE *new_rec=talloc(mem_ctx, TRP_INFOREC_ROUTE);
+
+ if (new_rec != NULL) {
+ new_rec->comm=NULL;
+ new_rec->realm=NULL;
+ 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);
+ }
+ return new_rec;
+}
+
+TRP_INFOREC *trp_inforec_get_next(TRP_INFOREC *rec)
+{
+ if (rec!=NULL)
+ return rec->next;
+ else
+ return NULL;
+}
+
+static TRP_INFOREC *trp_inforec_get_tail(TRP_INFOREC *rec)
+{
+ while ((rec->next)!=NULL)
+ rec=trp_inforec_get_next(rec);
+ return rec;
+}
+
+void trp_inforec_set_next(TRP_INFOREC *rec, TRP_INFOREC *next_rec)
+{
+ if (rec !=NULL)
+ rec->next=next_rec;
+}
+
+TRP_INFOREC_TYPE trp_inforec_get_type(TRP_INFOREC *rec)
+{
+ if (rec)
+ return rec->type;
+ else
+ return TRP_INFOREC_TYPE_UNKNOWN;
+}
+
+void trp_inforec_set_type(TRP_INFOREC *rec, TRP_INFOREC_TYPE type)
+{
+ if (rec!=NULL)
+ rec->type=type;
+}
+
+TR_NAME *trp_inforec_get_comm(TRP_INFOREC *rec)
+{
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_ROUTE:
+ if (rec->data.route!=NULL)
+ return rec->data.route->comm;
+ break;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+TR_NAME *trp_inforec_dup_comm(TRP_INFOREC *rec)
+{
+ return tr_dup_name(trp_inforec_get_comm(rec));
+}
+
+TRP_RC trp_inforec_set_comm(TRP_INFOREC *rec, TR_NAME *comm)
+{
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_ROUTE:
+ if (rec->data.route!=NULL) {
+ rec->data.route->comm=comm;
+ return TRP_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+ return TRP_ERROR;
+}
+
+TR_NAME *trp_inforec_get_realm(TRP_INFOREC *rec)
+{
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_ROUTE:
+ if (rec->data.route!=NULL)
+ return rec->data.route->realm;
+ break;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+TR_NAME *trp_inforec_dup_realm(TRP_INFOREC *rec)
+{
+ return tr_dup_name(trp_inforec_get_realm(rec));
+}
+
+TRP_RC trp_inforec_set_realm(TRP_INFOREC *rec, TR_NAME *realm)
+{
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_ROUTE:
+ if (rec->data.route!=NULL) {
+ rec->data.route->realm=realm;
+ return TRP_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+ return TRP_ERROR;
+}
+
+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->trust_router;
+ break;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+TR_NAME *trp_inforec_dup_trust_router(TRP_INFOREC *rec)
+{
+ return tr_dup_name(trp_inforec_get_trust_router(rec));
+}
+
+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->trust_router=trust_router;
+ return TRP_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+ return TRP_ERROR;
+}
+
+/* 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->next_hop;
+ break;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+TR_NAME *trp_inforec_dup_next_hop(TRP_INFOREC *rec)
+{
+ return tr_dup_name(trp_inforec_get_next_hop(rec));
+}
+
+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->next_hop=next_hop;
+ return TRP_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+ return TRP_ERROR;
+}
+
+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->metric;
+ break;
+ default:
+ break;
+ }
+ return TRP_METRIC_INVALID;
+}
+
+TRP_RC trp_inforec_set_metric(TRP_INFOREC *rec, unsigned int metric)
+{
+ 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;
+}
+
+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;
+ 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->interval=interval;
+ return TRP_SUCCESS;
+ default:
+ break;
+ }
+ 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)
+{
+ if (data==NULL)
+ return TRP_ERROR;
+
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_ROUTE:
+ rec->data.route=talloc_get_type(data, TRP_INFOREC_ROUTE);
+ break;
+ default:
+ return TRP_BADTYPE;
+ }
+ return TRP_SUCCESS;
+}
+
+/* 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);
+ 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))) {
+ talloc_free(new_rec);
+ new_rec=NULL;
+ }
+ }
+ }
+ return new_rec;
+}
+
+void trp_inforec_free(TRP_INFOREC *rec)
+{
+ if (rec!=NULL)
+ talloc_free(rec);
+}
+
+static int trp_upd_destructor(void *object)
+{
+ TRP_UPD *upd=talloc_get_type_abort(object, TRP_UPD);
+ if (upd->peer!=NULL)
+ tr_free_name(upd->peer);
+ return 0;
+}
+
+TRP_UPD *trp_upd_new(TALLOC_CTX *mem_ctx)
+{
+ TRP_UPD *new_body=talloc(mem_ctx, TRP_UPD);
+
+ if (new_body!=NULL) {
+ new_body->records=NULL;
+ new_body->peer=NULL;
+ talloc_set_destructor((void *)new_body, trp_upd_destructor);
+ }
+ return new_body;
+}
+
+void trp_upd_free(TRP_UPD *update)
+{
+ if (update!=NULL)
+ talloc_free(update);
+}
+
+TRP_INFOREC *trp_upd_get_inforec(TRP_UPD *upd)
+{
+ if (upd!=NULL)
+ return upd->records;
+ else
+ return NULL;
+}
+
+void trp_upd_set_inforec(TRP_UPD *upd, TRP_INFOREC *rec)
+{
+ if (upd!=NULL)
+ upd->records=rec;
+}
+
+void trp_upd_add_inforec(TRP_UPD *upd, TRP_INFOREC *rec)
+{
+ tr_debug("trp_upd_add_inforec: adding record.");
+ if (upd->records==NULL)
+ upd->records=rec;
+ else
+ trp_inforec_set_next(trp_inforec_get_tail(upd->records), rec);
+ talloc_steal(upd, rec);
+}
+
+TR_NAME *trp_upd_get_peer(TRP_UPD *upd)
+{
+ return upd->peer;
+}
+
+TR_NAME *trp_upd_dup_peer(TRP_UPD *upd)
+{
+ return tr_dup_name(upd->peer);
+}
+
+void trp_upd_set_peer(TRP_UPD *upd, TR_NAME *peer)
+{
+ upd->peer=peer;
+}
+
+void trp_upd_set_next_hop(TRP_UPD *upd, const char *hostname, unsigned int port)
+{
+ TRP_INFOREC *rec=NULL;
+ TR_NAME *cpy=NULL;
+
+ 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_free_name(cpy);
+ }
+ }
+}
+
+/* pretty print */
+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);
+ }
+}
+
--- /dev/null
+#include <fcntl.h>
+#include <talloc.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <gsscon.h>
+#include <tr_rp.h>
+#include <tr_debug.h>
+#include <trp_internal.h>
+
+static int trpc_destructor(void *object)
+{
+ TRPC_INSTANCE *trpc=talloc_get_type_abort(object, TRPC_INSTANCE);
+ if (trpc->gssname!=NULL)
+ tr_free_name(trpc->gssname);
+ return 0;
+}
+
+/* also allocates the incoming mq */
+TRPC_INSTANCE *trpc_new (TALLOC_CTX *mem_ctx)
+{
+ TRPC_INSTANCE *trpc=talloc(mem_ctx, TRPC_INSTANCE);
+ if (trpc!=NULL) {
+ trpc->next=NULL;
+ trpc->server=NULL;
+ trpc->port=0;
+ trpc->conn=NULL;
+ trpc->mq=tr_mq_new(trpc);
+ if (trpc->mq==NULL) {
+ talloc_free(trpc);
+ trpc=NULL;
+ } else
+ talloc_set_destructor((void *)trpc, trpc_destructor);
+
+ }
+ return trpc;
+}
+
+void trpc_free (TRPC_INSTANCE *trpc)
+{
+ if (trpc)
+ talloc_free(trpc);
+}
+
+TRPC_INSTANCE *trpc_get_next(TRPC_INSTANCE *trpc)
+{
+ return trpc->next;
+}
+
+void trpc_set_next(TRPC_INSTANCE *trpc, TRPC_INSTANCE *next)
+{
+ trpc->next=next;
+}
+
+/* Ok to call more than once; guarantees trpc no longer in the list. Does not free removed element.
+ * Returns handle to new list, you must replace your old handle on the list with this. */
+TRPC_INSTANCE *trpc_remove(TRPC_INSTANCE *trpc, TRPC_INSTANCE *remove)
+{
+ TRPC_INSTANCE *cur=trpc;
+ TRPC_INSTANCE *last=NULL;
+
+ if (cur==NULL)
+ return NULL;
+
+ /* first element is a special case */
+ if (cur==remove) {
+ trpc=trpc_get_next(cur); /* advance list head */
+ } else {
+ /* it was not the first element */
+ last=cur;
+ cur=trpc_get_next(cur);
+ while (cur!=NULL) {
+ if (cur==remove) {
+ trpc_set_next(last, trpc_get_next(cur));
+ break;
+ }
+ last=cur;
+ cur=trpc_get_next(cur);
+ }
+ }
+ return trpc;
+}
+
+static TRPC_INSTANCE *trpc_get_tail(TRPC_INSTANCE *trpc)
+{
+ while((trpc!=NULL)&&(trpc_get_next(trpc)!=NULL))
+ trpc=trpc_get_next(trpc);
+ return trpc;
+}
+
+void trpc_append(TRPC_INSTANCE *trpc, TRPC_INSTANCE *new)
+{
+ trpc_set_next(trpc_get_tail(trpc), new);
+}
+
+char *trpc_get_server(TRPC_INSTANCE *trpc)
+{
+ return trpc->server;
+}
+
+void trpc_set_server(TRPC_INSTANCE *trpc, char *server)
+{
+ trpc->server=server;
+}
+
+TR_NAME *trpc_get_gssname(TRPC_INSTANCE *trpc)
+{
+ return trpc->gssname;
+}
+
+/* takes responsibility for freeing gssname */
+void trpc_set_gssname(TRPC_INSTANCE *trpc, TR_NAME *gssname)
+{
+ trpc->gssname=gssname;
+}
+
+unsigned int trpc_get_port(TRPC_INSTANCE *trpc)
+{
+ return trpc->port;
+}
+
+void trpc_set_port(TRPC_INSTANCE *trpc, unsigned int port)
+{
+ trpc->port=port;
+}
+
+TRP_CONNECTION *trpc_get_conn(TRPC_INSTANCE *trpc)
+{
+ return trpc->conn;
+}
+
+void trpc_set_conn(TRPC_INSTANCE *trpc, TRP_CONNECTION *conn)
+{
+ trpc->conn=conn;
+}
+
+TRP_CONNECTION_STATUS trpc_get_status(TRPC_INSTANCE *trpc)
+{
+ return trp_connection_get_status(trpc_get_conn(trpc));
+}
+
+TR_MQ *trpc_get_mq(TRPC_INSTANCE *trpc)
+{
+ return trpc->mq;
+}
+
+void trpc_set_mq(TRPC_INSTANCE *trpc, TR_MQ *mq)
+{
+ trpc->mq=mq;
+}
+
+/* submit msg to trpc for transmission */
+void trpc_mq_add(TRPC_INSTANCE *trpc, TR_MQ_MSG *msg)
+{
+ tr_mq_add(trpc->mq, msg);
+}
+
+TR_MQ_MSG *trpc_mq_pop(TRPC_INSTANCE *trpc)
+{
+ return tr_mq_pop(trpc->mq);
+}
+
+void trpc_mq_clear(TRPC_INSTANCE *trpc)
+{
+ tr_mq_clear(trpc->mq);
+}
+
+TRP_RC trpc_connect(TRPC_INSTANCE *trpc)
+{
+ return trp_connection_initiate(trpc_get_conn(trpc), trpc_get_server(trpc), trpc_get_port(trpc));
+}
+
+/* simple function, based on tidc_send_req */
+TRP_RC trpc_send_msg (TRPC_INSTANCE *trpc,
+ const char *msg_content)
+{
+ int err=0;
+ TRP_RC rc=TRP_SUCCESS;
+
+ /* Send the request over the connection */
+ if (err = gsscon_write_encrypted_token(trp_connection_get_fd(trpc_get_conn(trpc)),
+ *trp_connection_get_gssctx(trpc_get_conn(trpc)),
+ msg_content,
+ strlen(msg_content))) {
+ tr_err( "trpc_send_msg: Error sending message over connection.\n");
+ rc=TRP_ERROR;
+ }
+ return rc;
+}
--- /dev/null
+#include <fcntl.h>
+#include <talloc.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include <gsscon.h>
+#include <tr_rp.h>
+#include <trust_router/tr_name.h>
+#include <trp_internal.h>
+#include <tr_gss.h>
+#include <trp_ptable.h>
+#include <trp_rtable.h>
+#include <tr_debug.h>
+
+
+static int trps_destructor(void *object)
+{
+ TRPS_INSTANCE *trps=talloc_get_type_abort(object, TRPS_INSTANCE);
+ if (trps->rtable!=NULL)
+ trp_rtable_free(trps->rtable);
+ return 0;
+}
+
+TRPS_INSTANCE *trps_new (TALLOC_CTX *mem_ctx)
+{
+ TRPS_INSTANCE *trps=talloc(mem_ctx, TRPS_INSTANCE);
+ if (trps!=NULL) {
+ trps->hostname=NULL;
+ trps->port=0;
+ trps->cookie=NULL;
+ trps->conn=NULL;
+ trps->trpc=NULL;
+ trps->update_interval=(struct timeval){0,0};
+ trps->sweep_interval=(struct timeval){0,0};
+ trps->ptable=NULL;
+
+ trps->mq=tr_mq_new(trps);
+ if (trps->mq==NULL) {
+ /* failed to allocate mq */
+ talloc_free(trps);
+ return NULL;
+ }
+
+ trps->rtable=NULL;
+ if (trps_init_rtable(trps) != TRP_SUCCESS) {
+ /* failed to allocate rtable */
+ talloc_free(trps);
+ return NULL;
+ }
+
+ talloc_set_destructor((void *)trps, trps_destructor);
+ }
+ return trps;
+}
+
+/* create a new route table, first discarding an old one if necessary */
+TRP_RC trps_init_rtable(TRPS_INSTANCE *trps)
+{
+ if (trps->rtable != NULL) {
+ trp_rtable_free(trps->rtable);
+ trps->rtable=NULL;
+ }
+
+ trps->rtable=trp_rtable_new();
+ if (trps->rtable==NULL) {
+ return TRP_NOMEM;
+ }
+ return TRP_SUCCESS;
+}
+
+void trps_clear_rtable(TRPS_INSTANCE *trps)
+{
+ trp_rtable_clear(trps->rtable);
+}
+
+void trps_free (TRPS_INSTANCE *trps)
+{
+ if (trps!=NULL)
+ talloc_free(trps);
+}
+
+TR_MQ_MSG *trps_mq_pop(TRPS_INSTANCE *trps)
+{
+ return tr_mq_pop(trps->mq);
+}
+
+void trps_mq_add(TRPS_INSTANCE *trps, TR_MQ_MSG *msg)
+{
+ tr_mq_add(trps->mq, msg);
+}
+
+unsigned int trps_get_connect_interval(TRPS_INSTANCE *trps)
+{
+ return trps->connect_interval.tv_sec;
+}
+
+void trps_set_connect_interval(TRPS_INSTANCE *trps, unsigned int interval)
+{
+ trps->connect_interval.tv_sec=interval;
+ trps->connect_interval.tv_usec=0;
+}
+
+unsigned int trps_get_update_interval(TRPS_INSTANCE *trps)
+{
+ return trps->update_interval.tv_sec;
+}
+
+void trps_set_update_interval(TRPS_INSTANCE *trps, unsigned int interval)
+{
+ trps->update_interval.tv_sec=interval;
+ trps->update_interval.tv_usec=0;
+}
+
+unsigned int trps_get_sweep_interval(TRPS_INSTANCE *trps)
+{
+ return trps->sweep_interval.tv_sec;
+}
+
+void trps_set_sweep_interval(TRPS_INSTANCE *trps, unsigned int interval)
+{
+ trps->sweep_interval.tv_sec=interval;
+ trps->sweep_interval.tv_usec=0;
+}
+
+void trps_set_ptable(TRPS_INSTANCE *trps, TRP_PTABLE *ptable)
+{
+ if (trps->ptable!=NULL)
+ trp_ptable_free(trps->ptable);
+ trps->ptable=ptable;
+}
+
+void trps_set_peer_status_callback(TRPS_INSTANCE *trps, void (*cb)(TRP_PEER *, void *), void *cookie)
+{
+ TRP_PTABLE_ITER *iter=NULL;
+ TRP_PEER *peer=NULL;
+ if (trps->ptable==NULL)
+ return;
+
+ iter=trp_ptable_iter_new(NULL);
+ for (peer=trp_ptable_iter_first(iter, trps->ptable); peer!=NULL; peer=trp_ptable_iter_next(iter))
+ trp_peer_set_conn_status_cb(peer, cb, cookie);
+ trp_ptable_iter_free(iter);
+}
+
+TRPC_INSTANCE *trps_find_trpc(TRPS_INSTANCE *trps, TRP_PEER *peer)
+{
+ TRPC_INSTANCE *cur=NULL;
+ TR_NAME *name=NULL;
+ TR_NAME *peer_servicename=trp_peer_get_servicename(peer);
+
+ for (cur=trps->trpc; cur!=NULL; cur=trpc_get_next(cur)) {
+ name=trpc_get_gssname(cur);
+ if ((name!=NULL) && (0==tr_name_cmp(peer_servicename, name))) {
+ break;
+ }
+ }
+ return cur;
+}
+
+void trps_add_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *new)
+{
+ if (trps->conn==NULL)
+ trps->conn=new;
+ else
+ trp_connection_append(trps->conn, new);
+
+ talloc_steal(trps, new);
+}
+
+/* ok to call more than once; guarantees connection no longer in the list.
+ * Caller is responsible for freeing the removed element afterwards. */
+void trps_remove_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *remove)
+{
+ trps->conn=trp_connection_remove(trps->conn, remove);
+}
+
+void trps_add_trpc(TRPS_INSTANCE *trps, TRPC_INSTANCE *trpc)
+{
+ if (trps->trpc==NULL)
+ trps->trpc=trpc;
+ else
+ trpc_append(trps->trpc, trpc);
+
+ talloc_steal(trps, trpc);
+}
+
+/* ok to call more than once; guarantees trpc no longer in the list.
+ * Caller is responsible for freeing the removed element afterwards. */
+void trps_remove_trpc(TRPS_INSTANCE *trps, TRPC_INSTANCE *remove)
+{
+ trps->trpc=trpc_remove(trps->trpc, remove);
+}
+
+TRP_RC trps_send_msg(TRPS_INSTANCE *trps, TRP_PEER *peer, const char *msg)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_MQ_MSG *mq_msg=NULL;
+ char *msg_dup=NULL;
+ TRP_RC rc=TRP_ERROR;
+ TRPC_INSTANCE *trpc=NULL;
+
+ /* get the connection for this peer */
+ trpc=trps_find_trpc(trps, peer);
+ /* instead, let's let that happen and then clear the queue when an attempt to
+ * connect fails */
+ if (trpc==NULL) {
+ tr_warning("trps_send_msg: skipping message queued for missing TRP client entry.");
+ } else {
+ mq_msg=tr_mq_msg_new(tmp_ctx, TR_MQMSG_TRPC_SEND, TR_MQ_PRIO_NORMAL);
+ msg_dup=talloc_strdup(mq_msg, msg); /* get local copy in mq_msg context */
+ tr_mq_msg_set_payload(mq_msg, msg_dup, NULL); /* no need for a free() func */
+ trpc_mq_add(trpc, mq_msg);
+ rc=TRP_SUCCESS;
+ }
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static int trps_listen (TRPS_INSTANCE *trps, int port)
+{
+ int rc = 0;
+ int conn = -1;
+ int optval = 1;
+
+ union {
+ struct sockaddr_storage storage;
+ struct sockaddr_in in4;
+ } addr;
+
+ struct sockaddr_in *saddr = (struct sockaddr_in *) &addr.in4;
+
+ saddr->sin_port = htons (port);
+ saddr->sin_family = AF_INET;
+ saddr->sin_addr.s_addr = INADDR_ANY;
+
+ if (0 > (conn = socket (AF_INET, SOCK_STREAM, 0)))
+ return conn;
+
+ setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
+
+ if (0 > (rc = bind (conn, (struct sockaddr *) saddr, sizeof(struct sockaddr_in))))
+ return rc;
+
+ if (0 > (rc = listen(conn, 512)))
+ return rc;
+
+ tr_debug("trps_listen: TRP Server listening on port %d", port);
+ return conn;
+}
+
+/* get the currently selected route if available */
+TRP_ROUTE *trps_get_route(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer)
+{
+ return trp_rtable_get_entry(trps->rtable, comm, realm, peer);
+}
+
+TRP_ROUTE *trps_get_selected_route(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm)
+{
+ tr_debug("trps_get_selected_route: entered. trps=%p, comm=%p, realm=%p", trps, comm, realm);
+ return trp_rtable_get_selected_entry(trps->rtable, comm, realm);
+}
+
+/* copy the result if you want to keep it */
+TR_NAME *trps_get_next_hop(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm)
+{
+ TRP_ROUTE *route=trps_get_selected_route(trps, comm, realm);
+ if (route==NULL)
+ return NULL;
+
+ return trp_route_get_next_hop(route);
+}
+
+
+/* mark a route as retracted */
+static void trps_retract_route(TRPS_INSTANCE *trps, TRP_ROUTE *entry)
+{
+ trp_route_set_metric(entry, TRP_METRIC_INFINITY);
+ trp_route_set_triggered(entry, 1);
+}
+
+/* is this route retracted? */
+static int trps_route_retracted(TRPS_INSTANCE *trps, TRP_ROUTE *entry)
+{
+ return (trp_metric_is_infinite(trp_route_get_metric(entry)));
+}
+
+static TRP_RC trps_read_message(TRPS_INSTANCE *trps, TRP_CONNECTION *conn, TR_MSG **msg)
+{
+ int err=0;
+ char *buf=NULL;
+ size_t buflen = 0;
+ TRP_PEER *peer=NULL; /* entry in the peer table */
+ TR_NAME *conn_peer=NULL; /* name from the TRP_CONN, which comes from the gss context */
+
+ tr_debug("trps_read_message: started");
+ if (err = gsscon_read_encrypted_token(trp_connection_get_fd(conn),
+ *(trp_connection_get_gssctx(conn)),
+ &buf,
+ &buflen)) {
+ tr_debug("trps_read_message: error");
+ if (buf)
+ free(buf);
+ return TRP_ERROR;
+ }
+
+ tr_debug("trps_read_message: message received, %u bytes.", (unsigned) buflen);
+ tr_debug("trps_read_message: %.*s", buflen, buf);
+
+ *msg=tr_msg_decode(buf, buflen);
+ free(buf);
+ if (*msg==NULL)
+ return TRP_NOPARSE;
+
+ conn_peer=trp_connection_get_peer(conn);
+ if (conn_peer==NULL) {
+ tr_err("trps_read_message: connection has no peer name");
+ return TRP_ERROR;
+ }
+
+ peer=trps_get_peer_by_gssname(trps, conn_peer);
+ if (peer==NULL) {
+ tr_err("trps_read_message: could not find peer with gssname=%s", trp_connection_get_gssname(conn));
+ return TRP_ERROR;
+ }
+
+ /* verify we received a message we support, otherwise drop it now */
+ switch (tr_msg_get_msg_type(*msg)) {
+ 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 */
+ break;
+
+ case TRP_REQUEST:
+ trp_req_set_peer(tr_msg_get_trp_req(*msg), tr_dup_name(conn_peer));
+ break;
+
+ default:
+ tr_debug("trps_read_message: received unsupported message from %.*s", conn_peer->len, conn_peer->buf);
+ tr_msg_free_decoded(*msg);
+ *msg=NULL;
+ return TRP_UNSUPPORTED;
+ }
+
+ return TRP_SUCCESS;
+}
+
+int trps_get_listener(TRPS_INSTANCE *trps,
+ TRPS_MSG_FUNC msg_handler,
+ TRP_AUTH_FUNC auth_handler,
+ const char *hostname,
+ unsigned int port,
+ void *cookie)
+{
+ 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);
+ }
+ }
+
+ if (listen > 0) {
+ /* 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;
+ }
+ }
+
+ if (listen > 0) {
+ /* store the caller's request handler & cookie */
+ trps->msg_handler = msg_handler;
+ trps->auth_handler = auth_handler;
+ trps->hostname = talloc_strdup(trps, hostname);
+ trps->port = port;
+ trps->cookie = cookie;
+ }
+
+ return listen;
+}
+
+TRP_RC trps_authorize_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *conn)
+{
+ /* try to establish a GSS context */
+ if (0!=trp_connection_auth(conn, trps->auth_handler, trps->cookie)) {
+ tr_notice("trps_authorize_connection: failed to authorize connection");
+ trp_connection_close(conn);
+ return TRP_ERROR;
+ }
+ tr_notice("trps_authorize_connection: authorized connection");
+ return TRP_SUCCESS;
+}
+
+void trps_handle_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *conn)
+{
+ TR_MSG *msg=NULL;
+ TRP_RC rc=TRP_ERROR;
+
+ /* loop as long as the connection exists */
+ while (trp_connection_get_status(conn)==TRP_CONNECTION_UP) {
+ rc=trps_read_message(trps, conn, &msg);
+ switch(rc) {
+ case TRP_SUCCESS:
+ trps->msg_handler(trps, conn, msg); /* send the TR_MSG off to the callback */
+ break;
+
+ case TRP_ERROR:
+ trp_connection_close(conn);
+ break;
+
+ default:
+ tr_debug("trps_handle_connection: trps_read_message failed (%d)", rc);
+ }
+ }
+
+ tr_debug("trps_handle_connection: connection closed.");
+}
+
+static TRP_RC trps_validate_update(TRPS_INSTANCE *trps, TRP_UPD *upd)
+{
+ if (upd==NULL) {
+ tr_notice("trps_validate_update: null TRP update.");
+ return TRP_BADARG;
+ }
+
+ if (trp_upd_get_inforec(upd)==NULL) {
+ tr_notice("trps_validate_update: received TRP update with no info records.");
+ return TRP_ERROR;
+ }
+
+ if (trp_upd_get_peer(upd)==NULL) {
+ tr_notice("trps_validate_update: received TRP update without origin peer information.");
+ return TRP_ERROR;
+ }
+
+ return TRP_SUCCESS;
+}
+
+/* ensure that the update could be accepted if feasible */
+static TRP_RC trps_validate_inforec(TRPS_INSTANCE *trps, TRP_INFOREC *rec)
+{
+ 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)
+ || (trp_inforec_get_next_hop(rec)==NULL)) {
+ tr_debug("trps_validate_inforec: missing record info.");
+ return TRP_ERROR;
+ }
+
+ /* check for valid metric */
+ if (trp_metric_is_invalid(trp_inforec_get_metric(rec))) {
+ tr_debug("trps_validate_inforec: invalid metric (%u).", trp_inforec_get_metric(rec));
+ return TRP_ERROR;
+ }
+
+ /* check for valid interval */
+ if (trp_inforec_get_interval(rec)==TRP_INTERVAL_INVALID) {
+ tr_debug("trps_validate_inforec: invalid interval.");
+ return TRP_ERROR;
+ }
+ break;
+
+ default:
+ tr_notice("trps_validate_inforec: unsupported record type.");
+ return TRP_UNSUPPORTED;
+ }
+
+ return TRP_SUCCESS;
+}
+
+/* link cost to a peer */
+static unsigned int trps_cost(TRPS_INSTANCE *trps, TR_NAME *peer)
+{
+ return 1;
+}
+
+static unsigned int trps_advertised_metric(TRPS_INSTANCE *trps, TR_NAME *comm, TR_NAME *realm, TR_NAME *peer)
+{
+ TRP_ROUTE *entry=trp_rtable_get_entry(trps->rtable, comm, realm, peer);
+ if (entry==NULL)
+ return TRP_METRIC_INFINITY;
+ return trp_route_get_metric(entry) + trps_cost(trps, peer);
+}
+
+static int trps_check_feasibility(TRPS_INSTANCE *trps, TRP_INFOREC *rec)
+{
+ unsigned int rec_metric=trp_inforec_get_metric(rec);
+ unsigned int new_metric=0;
+ unsigned int current_metric=0;
+ TR_NAME *next_hop=NULL;
+
+ /* we check these in the validation stage, but just in case... */
+ if (trp_metric_is_invalid(rec_metric))
+ return 0;
+
+ /* retractions (aka infinite metrics) are always feasible */
+ if (trp_metric_is_infinite(rec_metric))
+ 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));;
+ 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));
+ new_metric=rec_metric + trps_cost(trps, trp_inforec_get_next_hop(rec));
+ if (new_metric <= current_metric)
+ return 1;
+ else
+ return 0;
+}
+
+/* uses memory pointed to by *ts, also returns that value. On error, its contents are {0,0} */
+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)) {
+ tr_err("trps_compute_expiry: could not read realtime clock.");
+ ts->tv_sec=0;
+ ts->tv_nsec=0;
+ }
+ ts->tv_sec += small_factor*interval;
+ return ts;
+}
+
+static TRP_RC trps_accept_update(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_INFOREC *rec)
+{
+ TRP_ROUTE *entry=NULL;
+
+ entry=trp_rtable_get_entry(trps->rtable,
+ trp_inforec_get_comm(rec),
+ trp_inforec_get_realm(rec),
+ trp_inforec_get_next_hop(rec));
+ if (entry==NULL) {
+ entry=trp_route_new(NULL);
+ if (entry==NULL) {
+ tr_err("trps_accept_update: unable to allocate new entry.");
+ 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_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));
+ /* TODO: pass next hop port (now defaults to TID_PORT) --jlr */
+ if ((trp_route_get_comm(entry)==NULL)
+ ||(trp_route_get_realm(entry)==NULL)
+ ||(trp_route_get_peer(entry)==NULL)
+ ||(trp_route_get_trust_router(entry)==NULL)
+ ||(trp_route_get_next_hop(entry)==NULL)) {
+ /* at least one field could not be allocated */
+ tr_err("trps_accept_update: unable to allocate all fields for entry.");
+ trp_route_free(entry);
+ return TRP_NOMEM;
+ }
+ trp_rtable_add(trps->rtable, entry);
+ }
+
+ /* We now have an entry in the table, whether it's new or not. Update metric and expiry, unless
+ * the metric is infinity. An infinite metric can only occur here if we just retracted an existing
+ * route (we never accept retractions as new routes), so there is no risk of leaving the expiry
+ * time unset on a new route entry. */
+ tr_debug("trps_accept_update: accepting route update.");
+ trp_route_set_metric(entry, trp_inforec_get_metric(rec));
+ trp_route_set_interval(entry, trp_inforec_get_interval(rec));
+
+ /* check whether the trust router has changed */
+ if (0!=tr_name_cmp(trp_route_get_trust_router(entry),
+ trp_inforec_get_trust_router(rec))) {
+ /* The name changed. Set this route as triggered. */
+ tr_debug("trps_accept_update: trust router for route changed.");
+ trp_route_set_triggered(entry, 1);
+ trp_route_set_trust_router(entry, trp_inforec_dup_trust_router(rec)); /* frees old name */
+ }
+ if (!trps_route_retracted(trps, entry)) {
+ tr_debug("trps_accept_update: route not retracted, setting expiry timer.");
+ trp_route_set_expiry(entry, trps_compute_expiry(trps,
+ trp_route_get_interval(entry),
+ trp_route_get_expiry(entry)));
+ }
+ return TRP_SUCCESS;
+}
+
+static TRP_RC trps_handle_update(TRPS_INSTANCE *trps, TRP_UPD *upd)
+{
+ unsigned int feas=0;
+ 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.");
+ return TRP_ERROR;
+ }
+
+ 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.");
+ 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);
+ }
+ }
+ return TRP_SUCCESS;
+}
+
+static TRP_RC trps_validate_request(TRPS_INSTANCE *trps, TRP_REQ *req)
+{
+ if (req==NULL) {
+ tr_notice("trps_validate_request: null TRP request.");
+ return TRP_BADARG;
+ }
+
+ if (trp_req_get_comm(req)==NULL) {
+ tr_notice("trps_validate_request: received TRP request with null community.");
+ return TRP_ERROR;
+ }
+
+ if (trp_req_get_realm(req)==NULL) {
+ tr_notice("trps_validate_request: received TRP request with null realm.");
+ return TRP_ERROR;
+ }
+
+ if (trp_req_get_peer(req)==NULL) {
+ tr_notice("trps_validate_request: received TRP request without origin peer information.");
+ return TRP_ERROR;
+ }
+
+ return TRP_SUCCESS;
+}
+
+/* choose the best route to comm/realm, optionally excluding routes to a particular peer */
+static TRP_ROUTE *trps_find_best_route(TRPS_INSTANCE *trps,
+ TR_NAME *comm,
+ TR_NAME *realm,
+ TR_NAME *exclude_peer)
+{
+ TRP_ROUTE **entry=NULL;
+ TRP_ROUTE *best=NULL;
+ size_t n_entry=0;
+ unsigned int kk=0;
+ unsigned int kk_min=0;
+ unsigned int min_metric=TRP_METRIC_INFINITY;
+
+ entry=trp_rtable_get_realm_entries(trps->rtable, comm, realm, &n_entry);
+ for (kk=0; kk<n_entry; kk++) {
+ if (trp_route_get_metric(entry[kk]) < min_metric) {
+ if ((exclude_peer==NULL) || (0!=tr_name_cmp(trp_route_get_peer(entry[kk]),
+ exclude_peer))) {
+ kk_min=kk;
+ min_metric=trp_route_get_metric(entry[kk]);
+ }
+ }
+ }
+ if (trp_metric_is_finite(min_metric))
+ best=entry[kk_min];
+
+ talloc_free(entry);
+ return best;
+}
+
+/* TODO: think this through more carefully. At least ought to add hysteresis
+ * to avoid flapping between routers or routes. */
+TRP_RC trps_update_active_routes(TRPS_INSTANCE *trps)
+{
+ size_t n_comm=0, ii=0;
+ TR_NAME **comm=trp_rtable_get_comms(trps->rtable, &n_comm);
+ size_t n_realm=0, jj=0;
+ TR_NAME **realm=NULL;
+ TRP_ROUTE *best_route=NULL, *cur_route=NULL;
+ unsigned int best_metric=0, cur_metric=0;
+
+ 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_route=trps_find_best_route(trps, comm[ii], realm[jj], NULL);
+ if (best_route==NULL)
+ best_metric=TRP_METRIC_INFINITY;
+ else
+ best_metric=trp_route_get_metric(best_route);
+
+ cur_route=trps_get_selected_route(trps, comm[ii], realm[jj]);
+ if (cur_route!=NULL) {
+ cur_metric=trp_route_get_metric(cur_route);
+ if ((best_metric < cur_metric) && (trp_metric_is_finite(best_metric))) {
+ /* The new route has a lower metric than the previous, and is finite. Accept. */
+ trp_route_set_selected(cur_route, 0);
+ trp_route_set_selected(best_route, 1);
+ } else if (!trp_metric_is_finite(cur_metric)) /* rejects infinite or invalid metrics */
+ trp_route_set_selected(cur_route, 0);
+ } else if (trp_metric_is_finite(best_metric)) {
+ trp_route_set_selected(best_route, 1);
+ }
+ }
+ if (realm!=NULL)
+ talloc_free(realm);
+ realm=NULL; n_realm=0;
+ }
+ if (comm!=NULL)
+ talloc_free(comm);
+ comm=NULL; n_comm=0;
+
+ 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)));
+}
+
+/* Sweep for expired routes. For each expired route, if its metric is infinite, the route is flushed.
+ * If its metric is finite, the metric is set to infinite and the route's expiration time is updated. */
+TRP_RC trps_sweep_routes(TRPS_INSTANCE *trps)
+{
+ struct timespec sweep_time={0,0};
+ TRP_ROUTE **entry=NULL;
+ size_t n_entry=0;
+ size_t ii=0;
+
+ /* use a single time for the entire sweep */
+ if (0!=clock_gettime(CLOCK_REALTIME, &sweep_time)) {
+ tr_err("trps_sweep_routes: could not read realtime clock.");
+ sweep_time.tv_sec=0;
+ sweep_time.tv_nsec=0;
+ return TRP_ERROR;
+ }
+
+ entry=trp_rtable_get_entries(trps->rtable, &n_entry); /* must talloc_free *entry */
+
+ /* loop over the entries */
+ for (ii=0; ii<n_entry; ii++) {
+ if (!trp_route_is_local(entry[ii]) && trps_expired(trp_route_get_expiry(entry[ii]), &sweep_time)) {
+ tr_debug("trps_sweep_routes: route expired.");
+ if (!trp_metric_is_finite(trp_route_get_metric(entry[ii]))) {
+ /* flush route */
+ tr_debug("trps_sweep_routes: metric was infinity, flushing route.");
+ trp_rtable_remove(trps->rtable, entry[ii]); /* entry[ii] is no longer valid */
+ entry[ii]=NULL;
+ } else {
+ /* set metric to infinity and reset timer */
+ tr_debug("trps_sweep_routes: setting metric to infinity and resetting expiry.");
+ trp_route_set_metric(entry[ii], TRP_METRIC_INFINITY);
+ trp_route_set_expiry(entry[ii], trps_compute_expiry(trps,
+ trp_route_get_interval(entry[ii]),
+ trp_route_get_expiry(entry[ii])));
+ }
+ }
+ }
+
+ talloc_free(entry);
+ return TRP_SUCCESS;
+}
+
+/* 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)
+{
+ TRP_ROUTE *route;
+
+ /* Take the currently selected route unless it is through the peer we're sending the update to.
+ * I.e., enforce the split horizon rule. */
+ route=trp_rtable_get_selected_entry(trps->rtable, comm, realm);
+ if (route==NULL) {
+ /* No selected route, this should only happen if the only route has been retracted,
+ * in which case we do not want to advertise it. */
+ return NULL;
+ }
+ tr_debug("trps_select_realm_update: %s vs %s", peer_gssname->buf,
+ trp_route_get_peer(route)->buf);
+ if (0==tr_name_cmp(peer_gssname, trp_route_get_peer(route))) {
+ tr_debug("trps_select_realm_update: matched, finding alternate route");
+ /* the selected entry goes through the peer we're reporting to, choose an alternate */
+ route=trps_find_best_route(trps, comm, realm, peer_gssname);
+ if ((route==NULL) || (!trp_metric_is_finite(trp_route_get_metric(route))))
+ return NULL; /* don't advertise a nonexistent or retracted route */
+ }
+ 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,
+ TRPS_INSTANCE *trps,
+ TR_NAME *peer_gssname,
+ int triggered,
+ size_t *n_update)
+{
+ size_t n_comm=0;
+ TR_NAME **comm=trp_rtable_get_comms(trps->rtable, &n_comm);
+ TR_NAME **realm=NULL;
+ 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;
+ }
+
+ 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 (realm!=NULL)
+ talloc_free(realm);
+ realm=NULL;
+ n_realm=0;
+ }
+ if (comm!=NULL)
+ talloc_free(comm);
+
+ *n_update=n_used;
+ return result;
+}
+
+/* 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_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;
+ }
+ }
+ return rec;
+}
+
+/* all routes 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,
+ TR_NAME *comm,
+ TR_NAME *realm)
+{
+ 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;
+ char *encoded=NULL;
+ TRP_RC rc=TRP_ERROR;
+ TR_NAME *peer_label=trp_peer_get_label(peer);
+
+ switch (update_type) {
+ case TRP_UPDATE_TRIGGERED:
+ tr_debug("trps_update_one_peer: preparing triggered route 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",
+ peer_label->len, peer_label->buf);
+ break;
+ case TRP_UPDATE_REQUESTED:
+ tr_debug("trps_update_one_peer: preparing requested route update for %.*s",
+ peer_label->len, peer_label->buf);
+ }
+
+ /* do not fill in peer, recipient does that */
+ 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);
+ } 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) {
+ /* 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(""));
+ }
+ n_updates=1;
+ } else {
+ tr_err("trps_update_one_peer: error: only comm or realm was specified.");
+ 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.");
+ 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_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);
+
+ rc=TRP_SUCCESS;
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+/* all routes to all peers */
+TRP_RC trps_update(TRPS_INSTANCE *trps, TRP_UPDATE_TYPE update_type)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TRP_PTABLE_ITER *iter=trp_ptable_iter_new(tmp_ctx);
+ TRP_PEER *peer=NULL;
+ TRP_RC rc=TRP_SUCCESS;
+
+ if (trps->ptable==NULL)
+ return TRP_SUCCESS; /* no peers, nothing to do */
+
+ if (iter==NULL) {
+ tr_err("trps_update: failed to allocate peer table iterator.");
+ talloc_free(tmp_ctx);
+ return TRP_NOMEM;
+ }
+
+ for (peer=trp_ptable_iter_first(iter, trps->ptable);
+ peer!=NULL && rc==TRP_SUCCESS;
+ peer=trp_ptable_iter_next(iter))
+ {
+ if (!trps_peer_connected(trps, peer)) {
+ TR_NAME *peer_label=trp_peer_get_label(peer);
+ tr_debug("trps_update: no TRP connection to %.*s, skipping.",
+ peer_label->len, peer_label->buf);
+ continue;
+ }
+ rc=trps_update_one_peer(trps, peer, update_type, NULL, NULL);
+ }
+
+ tr_debug("trps_update: rc=%u after attempting update.", rc);
+ trp_ptable_iter_free(iter);
+ trp_rtable_clear_triggered(trps->rtable); /* don't re-send triggered updates */
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+TRP_RC trps_add_route(TRPS_INSTANCE *trps, TRP_ROUTE *route)
+{
+ trp_rtable_add(trps->rtable, route); /* should return status */
+ return TRP_SUCCESS;
+}
+
+/* steals the peer object */
+TRP_RC trps_add_peer(TRPS_INSTANCE *trps, TRP_PEER *peer)
+{
+ if (trps->ptable==NULL) {
+ trps->ptable=trp_ptable_new(trps);
+ if (trps->ptable==NULL)
+ return TRP_NOMEM;
+ }
+ return trp_ptable_add(trps->ptable, peer);
+}
+
+TRP_PEER *trps_get_peer_by_gssname(TRPS_INSTANCE *trps, TR_NAME *gssname)
+{
+ if (trps->ptable==NULL)
+ return NULL;
+
+ return trp_ptable_find_gss_name(trps->ptable, gssname);
+}
+
+TRP_PEER *trps_get_peer_by_servicename(TRPS_INSTANCE *trps, TR_NAME *servicename)
+{
+ if (trps->ptable==NULL)
+ return NULL;
+
+ return trp_ptable_find_servicename(trps->ptable, servicename);
+}
+
+int trps_peer_connected(TRPS_INSTANCE *trps, TRP_PEER *peer)
+{
+ TRPC_INSTANCE *trpc=trps_find_trpc(trps, peer);
+ if (trpc==NULL)
+ return 0;
+
+ if (trpc_get_status(trpc)==TRP_CONNECTION_UP)
+ return 1;
+ else
+ return 0;
+}
+
+
+static TRP_RC trps_handle_request(TRPS_INSTANCE *trps, TRP_REQ *req)
+{
+ TR_NAME *comm=NULL;
+ TR_NAME *realm=NULL;
+
+ tr_debug("trps_handle_request: handling TRP request.");
+
+ if (trps_validate_request(trps, req) != TRP_SUCCESS) {
+ tr_notice("trps_handle_request: received invalid TRP request.");
+ return TRP_ERROR;
+ }
+
+ if (!trp_req_is_wildcard(req)) {
+ comm=trp_req_get_comm(req);
+ realm=trp_req_get_realm(req);
+ tr_debug("trps_handle_request: route for %.*s/%.*s requested.",
+ comm->len, comm->buf, realm->len, realm->buf);
+ } else {
+ tr_debug("trps_handle_request: all routes requested.");
+ /* leave comm/realm NULL */
+ }
+ return trps_update_one_peer(trps,
+ trps_get_peer_by_gssname(trps, trp_req_get_peer(req)),
+ TRP_UPDATE_REQUESTED,
+ comm,
+ realm);
+}
+
+
+TRP_RC trps_handle_tr_msg(TRPS_INSTANCE *trps, TR_MSG *tr_msg)
+{
+ TRP_RC rc=TRP_ERROR;
+
+ switch (tr_msg_get_msg_type(tr_msg)) {
+ case TRP_UPDATE:
+ rc=trps_handle_update(trps, tr_msg_get_trp_upd(tr_msg));
+ if (rc==TRP_SUCCESS) {
+ rc=trps_update_active_routes(trps);
+ trps_update(trps, TRP_UPDATE_TRIGGERED); /* send any triggered routes */
+ }
+ return rc;
+
+ case TRP_REQUEST:
+ rc=trps_handle_request(trps, tr_msg_get_trp_req(tr_msg));
+ return rc;
+
+ default:
+ /* unknown error or one we don't care about (e.g., TID messages) */
+ return TRP_ERROR;
+ }
+}
+
+/* send wildcard route request to a peer */
+TRP_RC trps_wildcard_route_req(TRPS_INSTANCE *trps, TR_NAME *peer_servicename)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TRP_PEER *peer=trps_get_peer_by_servicename(trps, peer_servicename);
+ TR_MSG msg; /* not a pointer */
+ TRP_REQ *req=trp_req_new(tmp_ctx);
+ char *encoded=NULL;
+ TRP_RC rc=TRP_ERROR;
+
+ if (peer==NULL) {
+ tr_err("trps_wildcard_route_req: unknown peer (%.*s).", peer_servicename->len, peer_servicename->buf);
+ rc=TRP_BADARG;
+ goto cleanup;
+ }
+ if ((req==NULL) || (trp_req_make_wildcard(req)!=TRP_SUCCESS)) {
+ tr_err("trps_wildcard_route_req: unable to create wildcard TRP request.");
+ rc=TRP_NOMEM;
+ goto cleanup;
+ }
+
+ tr_msg_set_trp_req(&msg, req);
+ encoded=tr_msg_encode(&msg);
+ if (encoded==NULL) {
+ tr_err("trps_wildcard_route_req: error encoding wildcard TRP request.");
+ rc=TRP_ERROR;
+ goto cleanup;
+ }
+
+ tr_debug("trps_wildcard_route_req: adding message to queue.");
+ if (trps_send_msg(trps, peer, encoded) != TRP_SUCCESS) {
+ tr_err("trps_wildcard_route_req: error queueing request.");
+ rc=TRP_ERROR;
+ } else {
+ tr_debug("trps_wildcard_route_req: request queued successfully.");
+ rc=TRP_SUCCESS;
+ }
+
+cleanup:
+ if (encoded!=NULL)
+ tr_msg_free_encoded(encoded);
+ if (req!=NULL)
+ trp_req_free(req);
+
+ talloc_free(tmp_ctx);
+ return rc;
+}