From e9332953189a29c0c52f703e4a3717b6141306d9 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Wed, 30 Nov 2016 17:12:20 -0500 Subject: [PATCH] Support multiple AAA servers. Compiles but untested. --- common/tr_config.c | 39 ++++ common/tr_constraint.c | 23 +++ common/tr_dh.c | 4 +- common/tr_idp.c | 34 +++- common/tr_mq.c | 45 +++-- common/tr_msg.c | 32 +++- common/tr_util.c | 24 ++- include/tid_internal.h | 16 +- include/tr_config.h | 6 + include/tr_idp.h | 11 +- include/tr_mq.h | 4 +- include/tr_tid.h | 2 + include/tr_util.h | 44 +++++ include/trust_router/tid.h | 14 +- include/trust_router/tr_constraint.h | 1 + include/trust_router/tr_dh.h | 3 - tid/example/tidc_main.c | 2 +- tid/example/tids_main.c | 13 +- tid/tid_req.c | 4 +- tid/tid_resp.c | 158 ++++++++++++++-- tid/tidc.c | 38 ++-- tid/tids.c | 4 +- tr/tr_tid.c | 358 ++++++++++++++++++++++++++++++----- trp/trpc.c | 2 +- trp/trps.c | 9 +- 25 files changed, 759 insertions(+), 131 deletions(-) create mode 100644 include/tr_util.h diff --git a/common/tr_config.c b/common/tr_config.c index bbbda1a..b451860 100644 --- a/common/tr_config.c +++ b/common/tr_config.c @@ -184,6 +184,9 @@ static TR_CFG_RC tr_cfg_parse_internal(TR_CFG *trc, json_t *jcfg) json_t *jcfgsettle = NULL; json_t *jroutesweep = NULL; json_t *jrouteupdate = NULL; + json_t *jtidreq_timeout = NULL; + json_t *jtidresp_numer = NULL; + json_t *jtidresp_denom = NULL; json_t *jrouteconnect = NULL; if ((!trc) || (!jcfg)) @@ -294,6 +297,42 @@ static TR_CFG_RC tr_cfg_parse_internal(TR_CFG *trc, json_t *jcfg) trc->internal->trp_update_interval=TR_DEFAULT_TRP_UPDATE_INTERVAL; } + if (NULL != (jtidreq_timeout = json_object_get(jint, "tid_request_timeout"))) { + if (json_is_number(jtidreq_timeout)) { + trc->internal->tid_req_timeout = json_integer_value(jtidreq_timeout); + } else { + tr_debug("tr_cfg_parse_internal: Parsing error, tid_request_timeout is not a number."); + return TR_CFG_NOPARSE; + } + } else { + /* if not configured, use the default */ + trc->internal->tid_req_timeout=TR_DEFAULT_TID_REQ_TIMEOUT; + } + + if (NULL != (jtidresp_numer = json_object_get(jint, "tid_response_numerator"))) { + if (json_is_number(jtidresp_numer)) { + trc->internal->tid_resp_numer = json_integer_value(jtidresp_numer); + } else { + tr_debug("tr_cfg_parse_internal: Parsing error, tid_response_numerator is not a number."); + return TR_CFG_NOPARSE; + } + } else { + /* if not configured, use the default */ + trc->internal->tid_resp_numer=TR_DEFAULT_TID_RESP_NUMER; + } + + if (NULL != (jtidresp_denom = json_object_get(jint, "tid_response_denominator"))) { + if (json_is_number(jtidresp_denom)) { + trc->internal->tid_resp_denom = json_integer_value(jtidresp_denom); + } else { + tr_debug("tr_cfg_parse_internal: Parsing error, tid_response_denominator is not a number."); + return TR_CFG_NOPARSE; + } + } else { + /* if not configured, use the default */ + trc->internal->tid_resp_denom=TR_DEFAULT_TID_RESP_DENOM; + } + if (NULL != (jlog = json_object_get(jint, "logging"))) { if (NULL != (jlogthres = json_object_get(jlog, "log_threshold"))) { if (json_is_string(jlogthres)) { diff --git a/common/tr_constraint.c b/common/tr_constraint.c index 44a60ba..a155566 100644 --- a/common/tr_constraint.c +++ b/common/tr_constraint.c @@ -76,6 +76,29 @@ void tr_constraint_free(TR_CONSTRAINT *cons) talloc_free(cons); } +TR_CONSTRAINT *tr_constraint_dup(TALLOC_CTX *mem_ctx, TR_CONSTRAINT *cons) +{ + TALLOC_CTX *tmp_ctx=NULL; + TR_CONSTRAINT *new=NULL; + int ii=0; + + if (cons==NULL) + return NULL; + + tmp_ctx=talloc_new(NULL); + new=tr_constraint_new(tmp_ctx); + + if (new!=NULL) { + new->type=tr_dup_name(cons->type); + for (ii=0; iimatches[ii]=tr_dup_name(cons->matches[ii]); + talloc_steal(mem_ctx, new); + } + + talloc_free(tmp_ctx); + return new; +} + /* Returns TRUE (1) if the the string (str) matchs the wildcard string (wc_str), FALSE (0) if not. */ int tr_prefix_wildcard_match (const char *str, const char *wc_str) { diff --git a/common/tr_dh.c b/common/tr_dh.c index 080b9a6..c76ab27 100644 --- a/common/tr_dh.c +++ b/common/tr_dh.c @@ -171,7 +171,9 @@ void tr_destroy_dh_params(DH *dh) { } DH *tr_dup_dh_params(DH *dh) { - return DHparams_dup(dh); + if (dh!=NULL) + return DHparams_dup(dh); + return NULL; } int tr_compute_dh_key(unsigned char **pbuf, diff --git a/common/tr_idp.c b/common/tr_idp.c index bcbbd8d..fc325dc 100644 --- a/common/tr_idp.c +++ b/common/tr_idp.c @@ -63,7 +63,33 @@ 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_AAA_SERVER_ITER *tr_aaa_server_iter_new(TALLOC_CTX *mem_ctx) +{ + return talloc(mem_ctx, TR_AAA_SERVER_ITER); +} + +void tr_aaa_server_iter_free(TR_AAA_SERVER_ITER *iter) +{ + talloc_free(iter); +} + +TR_AAA_SERVER *tr_aaa_server_iter_first(TR_AAA_SERVER_ITER *iter, TR_AAA_SERVER *aaa) +{ + iter->this=aaa; + return iter->this; +} + +TR_AAA_SERVER *tr_aaa_server_iter_next(TR_AAA_SERVER_ITER *iter) +{ + if (iter->this!=NULL) { + iter->this=iter->this->next; + } + return iter->this; +} + + +/* fills in shared if pointer not null */ +TR_AAA_SERVER *tr_idp_aaa_server_lookup(TR_IDP_REALM *idp_realms, TR_NAME *idp_realm_name, TR_NAME *comm, int *shared_out) { TR_IDP_REALM *idp = NULL; @@ -73,9 +99,11 @@ TR_AAA_SERVER *tr_idp_aaa_server_lookup(TR_IDP_REALM *idp_realms, TR_NAME *idp_r break; } } - if (idp) + if (idp) { + if (shared_out!=NULL) + *shared_out=idp->shared_config; return idp->aaa_servers; - else + } else return NULL; } diff --git a/common/tr_mq.c b/common/tr_mq.c index 6606be3..fd8a42c 100644 --- a/common/tr_mq.c +++ b/common/tr_mq.c @@ -34,6 +34,8 @@ #include #include +#include +#include #include #include @@ -107,9 +109,16 @@ static void tr_mq_msg_set_next(TR_MQ_MSG *msg, TR_MQ_MSG *next) TR_MQ *tr_mq_new(TALLOC_CTX *mem_ctx) { TR_MQ *mq=talloc(mem_ctx, TR_MQ); + pthread_condattr_t cattr; + if (mq!=NULL) { pthread_mutex_init(&(mq->mutex), 0); - pthread_cond_init(&(mq->have_msg_cond), 0); + pthread_condattr_init(&cattr); + + pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC); /* use the monotonic clock for timeouts */ + pthread_cond_init(&(mq->have_msg_cond), &cattr); + pthread_condattr_destroy(&cattr); + mq->head=NULL; mq->tail=NULL; mq->last_hi_prio=NULL; @@ -266,27 +275,35 @@ void tr_mq_add(TR_MQ *mq, TR_MQ_MSG *msg) notify_cb(mq, notify_cb_arg); } -/* Caller must free msg via tr_mq_msg_free, waiting up to maxwait seconds (0 for non-blocking). - * Not guaranteed to wait if an error occurs - immediately returns without a message. */ -TR_MQ_MSG *tr_mq_pop(TR_MQ *mq, time_t maxwait) +/* Compute an absolute time from a desired timeout interval for use with tr_mq_pop(). + * Fills in *ts and returns 0 on success. */ +int tr_mq_pop_timeout(time_t seconds, struct timespec *ts) +{ + if (0!=clock_gettime(CLOCK_MONOTONIC, ts)) + return -1; + + ts->tv_sec+=seconds; + return 0; +} + +/* Caller must free msg via tr_mq_msg_free, waiting until absolute + * time ts_abort before giving up (using CLOCK_MONOTONIC). If ts_abort + * has passed, returns an existing message but will not wait if one is + * not already available. If ts_abort is null, no blocking. Not + * guaranteed to wait if an error occurs - immediately returns without + * a message. */ +TR_MQ_MSG *tr_mq_pop(TR_MQ *mq, struct timespec *ts_abort) { TR_MQ_MSG *popped=NULL; int wait_err=0; - struct timespec expiration={0}; - + tr_mq_lock(mq); - if ((tr_mq_get_head(mq)==NULL) && (maxwait>0)) { + if ((tr_mq_get_head(mq)==NULL) && (ts_abort!=NULL)) { /* No msgs yet, and blocking was requested */ - if (0!=clock_gettime(CLOCK_REALTIME, &expiration)) { - tr_notice("tr_mq_pop: error reading realtime clock."); - return NULL; - } - expiration.tv_sec+=maxwait; - while ((wait_err==0) && (NULL==tr_mq_get_head(mq))) wait_err=pthread_cond_timedwait(&(mq->have_msg_cond), &(mq->mutex), - &expiration); + ts_abort); if ((wait_err!=0) && (wait_err!=ETIMEDOUT)) { tr_notice("tr_mq_pop: error waiting for message."); diff --git a/common/tr_msg.c b/common/tr_msg.c index fa3c71f..0d18466 100644 --- a/common/tr_msg.c +++ b/common/tr_msg.c @@ -387,9 +387,11 @@ static json_t *tr_msg_encode_servers(TID_RESP *resp) return jservers; } -static TID_SRVR_BLK *tr_msg_decode_servers(TALLOC_CTX *ctx, json_t *jservers, size_t *out_len) +static TID_SRVR_BLK *tr_msg_decode_servers(TALLOC_CTX *mem_ctx, json_t *jservers) { - TID_SRVR_BLK *servers = NULL; + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TID_SRVR_BLK *servers=NULL; + TID_SRVR_BLK *new_srvr=NULL; json_t *jsrvr; size_t i, num_servers; @@ -398,20 +400,30 @@ static TID_SRVR_BLK *tr_msg_decode_servers(TALLOC_CTX *ctx, json_t *jservers, si if (0 == num_servers) { tr_debug("tr_msg_decode_servers(): Server array is empty."); - return NULL; + goto cleanup; } - servers = talloc_zero_array(ctx, TID_SRVR_BLK, num_servers); for (i = 0; i < num_servers; i++) { jsrvr = json_array_get(jservers, i); - if (0 != tr_msg_decode_one_server(jsrvr, &servers[i])) { - talloc_free(servers); - return NULL; - } + new_srvr=tid_srvr_blk_new(NULL); + if (new_srvr==NULL) { + servers=NULL; /* it's all in tmp_ctx, so we can just let go */ + goto cleanup; + } + + if (0 != tr_msg_decode_one_server(jsrvr, new_srvr)) { + servers=NULL; /* it's all in tmp_ctx, so we can just let go */ + goto cleanup; + } + tid_srvr_blk_add(servers, new_srvr); } - *out_len = num_servers; + + talloc_steal(mem_ctx, servers); + +cleanup: + talloc_free(tmp_ctx); return servers; } @@ -502,7 +514,7 @@ static TID_RESP *tr_msg_decode_tidresp(json_t *jresp) tr_debug("tr_msg_decode_tidresp(): Success! result = %s.", json_string_value(jresult)); if ((NULL != (jservers = json_object_get(jresp, "servers"))) || (!json_is_array(jservers))) { - tresp->servers = tr_msg_decode_servers(tresp, jservers, &tresp->num_servers); + tresp->servers = tr_msg_decode_servers(tresp, jservers); } else { talloc_free(tresp); diff --git a/common/tr_util.c b/common/tr_util.c index 9562d9c..decac2f 100644 --- a/common/tr_util.c +++ b/common/tr_util.c @@ -35,7 +35,9 @@ #include #include #include -#include +#include +/*#include */ +#include void tr_bin_to_hex(const unsigned char * bin, size_t bin_len, char * hex_out, size_t hex_len) @@ -49,3 +51,23 @@ void tr_bin_to_hex(const unsigned char * bin, size_t bin_len, } } +/* Returns 0 if ts1==ts2, <0 if ts1= if ts1>ts2. + * Assumes that tv_nsec <= 1e9. */ +int tr_cmp_timespec(struct timespec *ts1, struct timespec *ts2) +{ + if (ts1->tv_sec > ts2->tv_sec) + return 1; + + if (ts1->tv_sec < ts2->tv_sec) + return -1; + + /* ts1->tv_sec==ts2->tv_sec */ + + if (ts1->tv_nsec > ts2->tv_nsec) + return 1; + + if (ts1->tv_nsec < ts2->tv_nsec) + return -1; + + return 0; +} diff --git a/include/tid_internal.h b/include/tid_internal.h index e61b395..bce7ab2 100644 --- a/include/tid_internal.h +++ b/include/tid_internal.h @@ -41,6 +41,7 @@ #include struct tid_srvr_blk { + TID_SRVR_BLK *next; char *aaa_server_addr; TR_NAME *key_name; DH *aaa_server_dh; /* AAA server's public dh information */ @@ -57,7 +58,6 @@ struct tid_resp { TR_CONSTRAINT_SET *cons; TR_NAME *orig_coi; TID_SRVR_BLK *servers; /* array of servers */ - size_t num_servers; json_t *error_path; /**< Path that a request generating an error traveled*/ }; @@ -82,7 +82,7 @@ struct tid_req { }; struct tidc_instance { - TID_REQ *req_list; + // TID_REQ *req_list; // TBD -- Do we still need a separate private key */ // char *priv_key; // int priv_len; @@ -101,11 +101,21 @@ struct tids_instance { struct tr_rp_client *rp_gss; /* Client matching GSS name */ }; - /** Decrement a reference to #json when this tid_req is cleaned up. A new reference is not created; in effect the caller is handing a reference they already hold to the TID_REQ.*/ void tid_req_cleanup_json(TID_REQ *, json_t *json); int tid_req_add_path(TID_REQ *, const char *this_system, unsigned port); + +TID_SRVR_BLK *tid_srvr_blk_new(TALLOC_CTX *mem_ctx); +void tid_srvr_blk_free(TID_SRVR_BLK *srvr); +TID_SRVR_BLK *tid_srvr_blk_dup(TALLOC_CTX *mem_ctx, TID_SRVR_BLK *srvr); +TID_SRVR_BLK *tid_srvr_blk_add_func(TID_SRVR_BLK *head, TID_SRVR_BLK *new); +#define tid_srvr_blk_add(head, new) ((head)=tid_srvr_blk_add_func((head),(new))) +void tid_srvr_blk_set_path(TID_SRVR_BLK *block, json_t *path); + +void tid_resp_set_cons(TID_RESP *resp, TR_CONSTRAINT_SET *cons); +void tid_resp_set_error_path(TID_RESP *resp, json_t *ep); + #endif diff --git a/include/tr_config.h b/include/tr_config.h index 743ff12..a554398 100644 --- a/include/tr_config.h +++ b/include/tr_config.h @@ -58,6 +58,9 @@ #define TR_DEFAULT_TRP_CONNECT_INTERVAL 10 #define TR_DEFAULT_TRP_UPDATE_INTERVAL 120 #define TR_DEFAULT_TRP_SWEEP_INTERVAL 30 +#define TR_DEFAULT_TID_REQ_TIMEOUT 5 +#define TR_DEFAULT_TID_RESP_NUMER 2 +#define TR_DEFAULT_TID_RESP_DENOM 3 typedef enum tr_cfg_rc { TR_CFG_SUCCESS = 0, /* No error */ @@ -79,6 +82,9 @@ typedef struct tr_cfg_internal { unsigned int trp_sweep_interval; unsigned int trp_update_interval; unsigned int trp_connect_interval; + unsigned int tid_req_timeout; + unsigned int tid_resp_numer; /* numerator of fraction of AAA servers to wait for in unshared mode */ + unsigned int tid_resp_denom; /* denominator of fraction of AAA servers to wait for in unshared mode */ } TR_CFG_INTERNAL; typedef struct tr_cfg { diff --git a/include/tr_idp.h b/include/tr_idp.h index 361439c..dbcb472 100644 --- a/include/tr_idp.h +++ b/include/tr_idp.h @@ -46,6 +46,10 @@ typedef struct tr_aaa_server { TR_NAME *hostname; } TR_AAA_SERVER; +typedef struct tr_aaa_server_iter { + TR_AAA_SERVER *this; +} TR_AAA_SERVER_ITER; + /* may also want to use in tr_rp.h */ typedef enum tr_realm_origin { TR_REALM_LOCAL=0, /* realm we were configured to contact */ @@ -86,7 +90,12 @@ void tr_idp_realm_decref(TR_IDP_REALM *realm); TR_AAA_SERVER *tr_aaa_server_new(TALLOC_CTX *mem_ctx, TR_NAME *hostname); void tr_aaa_server_free(TR_AAA_SERVER *aaa); -TR_AAA_SERVER *tr_idp_aaa_server_lookup(TR_IDP_REALM *idp_realms, TR_NAME *idp_realm_name, TR_NAME *comm); +TR_AAA_SERVER_ITER *tr_aaa_server_iter_new(TALLOC_CTX *mem_ctx); +void tr_aaa_server_iter_free(TR_AAA_SERVER_ITER *iter); +TR_AAA_SERVER *tr_aaa_server_iter_first(TR_AAA_SERVER_ITER *iter, TR_AAA_SERVER *aaa); +TR_AAA_SERVER *tr_aaa_server_iter_next(TR_AAA_SERVER_ITER *iter); + +TR_AAA_SERVER *tr_idp_aaa_server_lookup(TR_IDP_REALM *idp_realms, TR_NAME *idp_realm_name, TR_NAME *comm, int *shared_out); TR_AAA_SERVER *tr_default_server_lookup(TR_AAA_SERVER *default_servers, TR_NAME *comm); #endif diff --git a/include/tr_mq.h b/include/tr_mq.h index 9111f0f..f60c7af 100644 --- a/include/tr_mq.h +++ b/include/tr_mq.h @@ -37,6 +37,7 @@ #include #include +#include /* Note on mq priorities: High priority messages are guaranteed to be * processed before any normal priority messages. Otherwise, messages @@ -88,7 +89,8 @@ 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, time_t maxwait); +int tr_mq_pop_timeout(time_t seconds, struct timespec *ts); +TR_MQ_MSG *tr_mq_pop(TR_MQ *mq, struct timespec *ts_abort); void tr_mq_clear(TR_MQ *mq); #endif /*_TR_MQ_H_ */ diff --git a/include/tr_tid.h b/include/tr_tid.h index 5db395e..924293d 100644 --- a/include/tr_tid.h +++ b/include/tr_tid.h @@ -39,6 +39,8 @@ #include #include +#define TR_TID_MAX_AAA_SERVERS 10 + int tr_tids_event_init(struct event_base *base, TIDS_INSTANCE *tids, TR_CFG_MGR *cfg_mgr, diff --git a/include/tr_util.h b/include/tr_util.h new file mode 100644 index 0000000..3b0e597 --- /dev/null +++ b/include/tr_util.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef TR_UTIL_H +#define TR_UTIL_H + +#include + +void tr_bin_to_hex(const unsigned char * bin, size_t binlen, + char * hex_out, size_t hex_len); +TR_EXPORT int tr_cmp_timespec(struct timespec *ts1, struct timespec *ts2); + +#endif /* TR_UTIL_H */ diff --git a/include/trust_router/tid.h b/include/trust_router/tid.h index b491b6a..34ef426 100644 --- a/include/trust_router/tid.h +++ b/include/trust_router/tid.h @@ -57,7 +57,6 @@ typedef struct tid_srvr_blk TID_SRVR_BLK; typedef struct _tr_constraint_set TR_CONSTRAINT_SET; -typedef struct _tid_path TID_PATH; typedef struct tid_resp TID_RESP; @@ -99,13 +98,14 @@ TR_EXPORT TIDC_RESP_FUNC *tid_req_get_resp_func(TID_REQ *req); void tid_req_set_resp_func(TID_REQ *req, TIDC_RESP_FUNC *resp_func); TR_EXPORT void *tid_req_get_cookie(TID_REQ *req); void tid_req_set_cookie(TID_REQ *req, void *cookie); -TR_EXPORT TID_REQ *tid_dup_req (TID_REQ *orig_req); +TR_EXPORT TID_REQ *tid_dup_req (TALLOC_CTX *mem_ctx, TID_REQ *orig_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); +TID_RESP *tid_resp_dup(TALLOC_CTX *mem_ctx, TID_RESP *resp); TR_EXPORT int tid_resp_get_result(TID_RESP *resp); void tid_resp_set_result(TID_RESP *resp, int result); TR_EXPORT TR_NAME *tid_resp_get_err_msg(TID_RESP *resp); @@ -120,17 +120,17 @@ TR_EXPORT TR_NAME *tid_resp_get_orig_coi(TID_RESP *resp); void tid_resp_set_orig_coi(TID_RESP *resp, TR_NAME *orig_coi); TR_EXPORT TID_SRVR_BLK *tid_resp_get_server(TID_RESP *resp, size_t index); TR_EXPORT size_t tid_resp_get_num_servers(const TID_RESP *resp); -TR_EXPORT const TID_PATH *tid_resp_get_error_path(const TID_RESP *); +TR_EXPORT json_t *tid_resp_get_error_path(const TID_RESP *); /** Get either the error_path or the path of the first server block for * a successful response*/ -TR_EXPORT const TID_PATH *tid_resp_get_a_path(const TID_RESP *); +TR_EXPORT json_t *tid_resp_get_a_path(const TID_RESP *); /* Server blocks*/ TR_EXPORT void tid_srvr_get_address(const TID_SRVR_BLK *, const struct sockaddr **out_addr, size_t *out_sa_len); TR_EXPORT DH *tid_srvr_get_dh(TID_SRVR_BLK *); TR_EXPORT const TR_NAME *tid_srvr_get_key_name(const TID_SRVR_BLK *); -TR_EXPORT const TID_PATH *tid_srvr_get_path(const TID_SRVR_BLK *); +TR_EXPORT const json_t *tid_srvr_get_path(const TID_SRVR_BLK *); #define tid_resp_servers_foreach(RESP, SERVER, INDEX) \ @@ -140,13 +140,13 @@ TR_EXPORT const TID_PATH *tid_srvr_get_path(const TID_SRVR_BLK *); /* TID Client functions, in tid/tidc.c */ -TR_EXPORT TIDC_INSTANCE *tidc_create (void); +TR_EXPORT TIDC_INSTANCE *tidc_create (TALLOC_CTX *mem_ctx); TR_EXPORT int tidc_open_connection (TIDC_INSTANCE *tidc, const char *server, unsigned int port, gss_ctx_id_t *gssctx); TR_EXPORT int tidc_send_request (TIDC_INSTANCE *tidc, int conn, gss_ctx_id_t gssctx, const char *rp_realm, const char *realm, const char *coi, TIDC_RESP_FUNC *resp_handler, void *cookie); TR_EXPORT int tidc_fwd_request (TIDC_INSTANCE *tidc, TID_REQ *req, TIDC_RESP_FUNC *resp_handler, void *cookie); TR_EXPORT DH *tidc_get_dh(TIDC_INSTANCE *); TR_EXPORT DH *tidc_set_dh(TIDC_INSTANCE *, DH *); -TR_EXPORT void tidc_destroy (TIDC_INSTANCE *tidc); +TR_EXPORT void tidc_free(TIDC_INSTANCE *tidc); /* TID Server functions, in tid/tids.c */ TR_EXPORT TIDS_INSTANCE *tids_create (TALLOC_CTX *mem_ctx); diff --git a/include/trust_router/tr_constraint.h b/include/trust_router/tr_constraint.h index 58fbb67..9f76047 100644 --- a/include/trust_router/tr_constraint.h +++ b/include/trust_router/tr_constraint.h @@ -51,6 +51,7 @@ typedef struct tr_constraint { TR_CONSTRAINT *tr_constraint_new(TALLOC_CTX *mem_ctx); void tr_constraint_free(TR_CONSTRAINT *cons); +TR_CONSTRAINT *tr_constraint_dup(TALLOC_CTX *mem_ctx, TR_CONSTRAINT *cons); void TR_EXPORT tr_constraint_add_to_set (TR_CONSTRAINT_SET **cs, TR_CONSTRAINT *c); diff --git a/include/trust_router/tr_dh.h b/include/trust_router/tr_dh.h index 64bec52..dc4fbd9 100644 --- a/include/trust_router/tr_dh.h +++ b/include/trust_router/tr_dh.h @@ -53,7 +53,4 @@ int TR_EXPORT tr_dh_pub_hash(TID_REQ *request, size_t *out_llen); -TR_EXPORT void tr_bin_to_hex(const unsigned char * bin, size_t binlen, - char * hex_out, size_t hex_len); - #endif diff --git a/tid/example/tidc_main.c b/tid/example/tidc_main.c index 96e1d07..b4a7ece 100644 --- a/tid/example/tidc_main.c +++ b/tid/example/tidc_main.c @@ -212,7 +212,7 @@ int main (int argc, } /* Clean-up the TID client instance, and exit */ - tidc_destroy(tidc); + tidc_free(tidc); return 0; } diff --git a/tid/example/tids_main.c b/tid/example/tids_main.c index 9d4c879..d8f2345 100644 --- a/tid/example/tids_main.c +++ b/tid/example/tids_main.c @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -175,13 +176,12 @@ static int tids_req_handler (TIDS_INSTANCE *tids, /* Allocate a new server block */ - if (NULL == (resp->servers = talloc_zero(resp, TID_SRVR_BLK))){ - tr_crit("tids_req_handler(): malloc failed."); + tid_srvr_blk_add(resp->servers, tid_srvr_blk_new(resp)); + if (NULL==resp->servers) { + tr_crit("tids_req_handler(): unable to allocate server block."); return -1; } - resp->num_servers = 1; - /* TBD -- Set up the server IP Address */ if (!(req) || !(req->tidc_dh)) { @@ -203,7 +203,7 @@ static int tids_req_handler (TIDS_INSTANCE *tids, return -1; } - resp->servers->aaa_server_addr=tids->ipaddr; + resp->servers->aaa_server_addr=talloc_strdup(resp->servers, tids->ipaddr); /* Set the key name */ if (-1 == create_key_id(key_id, sizeof(key_id))) @@ -226,7 +226,8 @@ static int tids_req_handler (TIDS_INSTANCE *tids, } if (0 != handle_authorizations(req, pub_digest, pub_digest_len)) return -1; - resp->servers->path = req->path; + tid_srvr_blk_set_path(resp->servers, req->path); + if (req->expiration_interval < 1) req->expiration_interval = 1; g_get_current_time(&resp->servers->key_expiration); diff --git a/tid/tid_req.c b/tid/tid_req.c index 76e05cc..8f68e33 100644 --- a/tid/tid_req.c +++ b/tid/tid_req.c @@ -189,11 +189,11 @@ void tid_req_set_cookie(TID_REQ *req, void *cookie) req->cookie = cookie; } -TID_REQ *tid_dup_req (TID_REQ *orig_req) +TID_REQ *tid_dup_req (TALLOC_CTX *mem_ctx, TID_REQ *orig_req) { TID_REQ *new_req = NULL; - if (NULL == (new_req = talloc_zero(orig_req, TID_REQ))) { + if (NULL == (new_req = talloc_zero(mem_ctx, TID_REQ))) { tr_crit("tid_dup_req: Can't allocated duplicate request."); return NULL; } diff --git a/tid/tid_resp.c b/tid/tid_resp.c index 338c972..ad2f28f 100644 --- a/tid/tid_resp.c +++ b/tid/tid_resp.c @@ -37,6 +37,7 @@ #include #include +#include #include static int tid_resp_destructor(void *obj) @@ -67,7 +68,6 @@ TID_RESP *tid_resp_new(TALLOC_CTX *mem_ctx) 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); } @@ -80,6 +80,32 @@ void tid_resp_free(TID_RESP *resp) talloc_free(resp); } +TID_RESP *tid_resp_dup(TALLOC_CTX *mem_ctx, TID_RESP *resp) +{ + TALLOC_CTX *tmp_ctx=NULL; + TID_RESP *newresp=NULL; + + if (resp==NULL) + return NULL; + + tmp_ctx=talloc_new(NULL); + newresp=talloc(tmp_ctx, TID_RESP); + + if (NULL!=newresp) { + newresp->result=resp->result; + newresp->err_msg=tr_dup_name(resp->err_msg); + newresp->rp_realm=tr_dup_name(resp->err_msg); + newresp->realm=tr_dup_name(resp->realm); + newresp->comm=tr_dup_name(resp->comm); + newresp->orig_coi=tr_dup_name(resp->orig_coi); + newresp->servers=tid_srvr_blk_dup(newresp, resp->servers); + tid_resp_set_cons(newresp, resp->cons); + tid_resp_set_error_path(newresp, resp->error_path); + } + talloc_free(tmp_ctx); + return newresp; +} + TR_EXPORT int tid_resp_get_result(TID_RESP *resp) { return(resp->result); @@ -97,6 +123,9 @@ TR_EXPORT TR_NAME *tid_resp_get_err_msg(TID_RESP *resp) void tid_resp_set_err_msg(TID_RESP *resp, TR_NAME *err_msg) { + if (resp->err_msg!=NULL) + tr_free_name(resp->err_msg); + resp->err_msg = err_msg; } @@ -143,33 +172,138 @@ void tid_resp_set_orig_coi(TID_RESP *resp, TR_NAME *orig_coi) TR_EXPORT TID_SRVR_BLK *tid_resp_get_server(TID_RESP *resp, size_t index) { + TID_SRVR_BLK *this=NULL; assert(resp); - assert(index < resp->num_servers); - return(&(resp->servers[index])); + + for (this=resp->servers; index>0; index--, this=this->next) {} + + return this; } size_t tid_resp_get_num_servers(const TID_RESP *resp) { - assert(resp); - return resp->num_servers; + size_t count=0; + TID_SRVR_BLK *this=NULL; + + assert(resp!=NULL); + for (count=0, this=resp->servers; this!=NULL; count++, this=this->next) {} + return count; } +static int tid_srvr_blk_destructor(void *obj) +{ + TID_SRVR_BLK *srvr=talloc_get_type_abort(obj, TID_SRVR_BLK); -const TID_PATH *tid_srvr_get_path( const TID_SRVR_BLK *block) + if (srvr->key_name!=NULL) + tr_free_name(srvr->key_name); + if (srvr->aaa_server_dh!=NULL) + tr_destroy_dh_params(srvr->aaa_server_dh); + if (srvr->path!=NULL) + json_decref(srvr->path); + return 0; +} + +TID_SRVR_BLK *tid_srvr_blk_new(TALLOC_CTX *mem_ctx) +{ + TID_SRVR_BLK *srvr=talloc(mem_ctx, TID_SRVR_BLK); + + if (srvr!=NULL) { + srvr->next=NULL; + srvr->aaa_server_addr=NULL; + srvr->key_name=NULL; + srvr->aaa_server_dh=NULL; + srvr->key_expiration=(GTimeVal){0}; + srvr->path=NULL; + talloc_set_destructor((void *)srvr, tid_srvr_blk_destructor); + } + return srvr; +} + +void tid_srvr_blk_free(TID_SRVR_BLK *srvr) +{ + talloc_free(srvr); +} + +TID_SRVR_BLK *tid_srvr_blk_dup(TALLOC_CTX *mem_ctx, TID_SRVR_BLK *srvr) +{ + TID_SRVR_BLK *new=NULL; + + if (srvr==NULL) + return NULL; + + new=tid_srvr_blk_new(mem_ctx); + if (new!=NULL) { + if (srvr->aaa_server_addr!=NULL) + new->aaa_server_addr=talloc_strdup(new, srvr->aaa_server_addr); + new->key_name=tr_dup_name(srvr->key_name); + new->aaa_server_dh=tr_dup_dh_params(srvr->aaa_server_dh); + new->key_expiration=srvr->key_expiration; + tid_srvr_blk_set_path(new, srvr->path); + + tid_srvr_blk_add(new->next, tid_srvr_blk_dup(mem_ctx, srvr->next)); + } + return new; +} + +/* use the macro */ +TID_SRVR_BLK *tid_srvr_blk_add_func(TID_SRVR_BLK *head, TID_SRVR_BLK *new) +{ + TID_SRVR_BLK *this=head; + + if (head==NULL) + return new; + + while (this->next!=NULL) + this=this->next; + this->next=new; + return head; +} + +void tid_srvr_blk_set_path(TID_SRVR_BLK *block, json_t *path) +{ + if (block->path!=NULL) + json_decref(block->path); + block->path=path; + if (block->path!=NULL) + json_incref(block->path); +} + +const json_t *tid_srvr_get_path( const TID_SRVR_BLK *block) { if (!block) return NULL; - return (const TID_PATH *) block->path; + return block->path; +} + +void tid_resp_set_cons(TID_RESP *resp, TR_CONSTRAINT_SET *cons) +{ + json_t *jc=(json_t *)cons; + + if (resp->cons!=NULL) + json_decref((json_t *) (resp->cons)); + + resp->cons=(TR_CONSTRAINT_SET *)jc; + if (jc!=NULL) + json_incref(jc); +} + +void tid_resp_set_error_path(TID_RESP *resp, json_t *ep) +{ + if (resp->error_path!=NULL) + json_decref(resp->error_path); + resp->error_path=ep; + if (resp->error_path!=NULL) + json_incref(resp->error_path); } -const TID_PATH *tid_resp_get_error_path( const TID_RESP *resp) +json_t *tid_resp_get_error_path(const TID_RESP *resp) { if (!resp) return NULL; - return (const TID_PATH *) resp->error_path; + return resp->error_path; } -const TID_PATH *tid_resp_get_a_path( const TID_RESP *const_resp) +json_t *tid_resp_get_a_path(const TID_RESP *const_resp) { size_t index; TID_SRVR_BLK *server; @@ -179,10 +313,10 @@ const TID_PATH *tid_resp_get_a_path( const TID_RESP *const_resp) if (resp->error_path) - return (const TID_PATH *) resp->error_path; + return resp->error_path; tid_resp_servers_foreach( resp, server, index) { if (server->path) - return (const TID_PATH *) server->path; + return server->path; } return NULL; diff --git a/tid/tidc.c b/tid/tidc.c index 37a3712..fcc78c9 100644 --- a/tid/tidc.c +++ b/tid/tidc.c @@ -45,17 +45,27 @@ int tmp_len = 32; -TIDC_INSTANCE *tidc_create () +static int tidc_destructor(void *obj) { - TIDC_INSTANCE *tidc = NULL; - - if (NULL == (tidc = talloc_zero(NULL, TIDC_INSTANCE))) - return NULL; + TIDC_INSTANCE *tidc=talloc_get_type_abort(obj, TIDC_INSTANCE); + if (NULL!=tidc) { + if (NULL!=tidc->client_dh) + tr_destroy_dh_params(tidc->client_dh); + } + return 0; +} +TIDC_INSTANCE *tidc_create(TALLOC_CTX *mem_ctx) +{ + TIDC_INSTANCE *tidc=talloc(mem_ctx, TIDC_INSTANCE); + if (tidc!=NULL) { + tidc->client_dh=NULL; + talloc_set_destructor((void *)tidc, tidc_destructor); + } return tidc; } -void tidc_destroy (TIDC_INSTANCE *tidc) +void tidc_free(TIDC_INSTANCE *tidc) { talloc_free(tidc); } @@ -120,10 +130,10 @@ int tidc_send_request (TIDC_INSTANCE *tidc, return rc; } -int tidc_fwd_request (TIDC_INSTANCE *tidc, - TID_REQ *tid_req, - TIDC_RESP_FUNC *resp_handler, - void *cookie) +int tidc_fwd_request(TIDC_INSTANCE *tidc, + TID_REQ *tid_req, + TIDC_RESP_FUNC *resp_handler, + void *cookie) { char *req_buf = NULL; char *resp_buf = NULL; @@ -186,10 +196,11 @@ int tidc_fwd_request (TIDC_INSTANCE *tidc, } if (resp_handler) { - /* Call the caller's response function */ + /* Call the caller's response function. It must copy any data it needs before returning. */ tr_debug("tidc_fwd_request: calling response callback function."); (*resp_handler)(tidc, tid_req, tr_msg_get_resp(resp_msg), cookie); } + goto cleanup; error: @@ -201,9 +212,8 @@ int tidc_fwd_request (TIDC_INSTANCE *tidc, free(req_buf); if (resp_buf) free(resp_buf); - - /* TBD -- free the decoded response */ - + if (resp_msg) + tr_msg_free_decoded(resp_msg); return rc; } diff --git a/tid/tids.c b/tid/tids.c index 082904c..2e226ef 100644 --- a/tid/tids.c +++ b/tid/tids.c @@ -54,7 +54,7 @@ static TID_RESP *tids_create_response (TIDS_INSTANCE *tids, TID_REQ *req) TID_RESP *resp=NULL; int success=0; - if ((NULL == (resp = talloc_zero(req, TID_RESP)))) { + if (NULL == (resp = tid_resp_new(req))) { tr_crit("tids_create_response: Error allocating response structure."); return NULL; } @@ -421,7 +421,7 @@ static void tids_handle_connection (TIDS_INSTANCE *tids, int conn) tr_debug("tids_handle_connection: Error from tids_send_response(), rc = %d.", rc); /* if we didn't already send a response, try to send a generic error. */ if (!tr_msg_get_req(mreq)->resp_sent) - tids_send_err_response(tids, tr_msg_get_req(mreq), "Error sending response."); + tids_send_err_response(tids, tr_msg_get_req(mreq), "Error sending response."); /* Fall through to free the response, either way. */ } diff --git a/tr/tr_tid.c b/tr/tr_tid.c index 1ccc54f..ab836d3 100644 --- a/tr/tr_tid.c +++ b/tr/tr_tid.c @@ -34,6 +34,7 @@ #include +#include #include #include #include @@ -44,12 +45,14 @@ #include #include #include +#include +#include #include -/* Structure to hold TR instance and original request in one cookie */ +/* Structure to hold data for the tid response callback */ typedef struct tr_resp_cookie { - TIDS_INSTANCE *tids; - TID_REQ *orig_req; + int thread_id; + TID_RESP *resp; } TR_RESP_COOKIE; /* hold a tids instance and a config manager */ @@ -59,6 +62,22 @@ struct tr_tids_event_cookie { TRPS_INSTANCE *trps; }; +static void tr_tidc_resp_handler(TIDC_INSTANCE *tidc, + TID_REQ *req, + TID_RESP *resp, + void *resp_cookie) +{ + TR_RESP_COOKIE *cookie=talloc_get_type_abort(resp_cookie, TR_RESP_COOKIE); + + tr_debug("tr_tidc_resp_handler: Response received! Realm = %s, Community = %s.", + resp->realm->buf, + resp->comm->buf); + + cookie->resp=tid_resp_dup(cookie, resp); +} + +#if 0 +/* Old one, obsolete. */ static void tr_tidc_resp_handler (TIDC_INSTANCE *tidc, TID_REQ *req, @@ -75,27 +94,179 @@ static void tr_tidc_resp_handler (TIDC_INSTANCE *tidc, return; } +#endif /* 0 */ + + +/* data for AAA req forwarding threads */ +struct tr_tids_fwd_cookie { + int thread_id; + pthread_mutex_t mutex; /* lock on the mq (separate from the locking within the mq, see below) */ + TR_MQ *mq; /* messages from thread to main process; set to NULL to disable response */ + TR_NAME *aaa_hostname; + DH *dh_params; + TID_REQ *fwd_req; /* the req to duplicate */ +}; + +static int tr_tids_fwd_cookie_destructor(void *obj) +{ + struct tr_tids_fwd_cookie *c=talloc_get_type_abort(obj, struct tr_tids_fwd_cookie); + if (c->aaa_hostname!=NULL) + tr_free_name(c->aaa_hostname); + if (c->dh_params!=NULL) + tr_destroy_dh_params(c->dh_params); + return 0; +} + +/* Block until we get the lock, returns 0 on success. + * The mutex is used to protect changes to the mq pointer in + * a thread's cookie. The master thread sets this to null to indicate + * that it has abandoned the thread and the message queue is no longer + * valid. This is unrelated to the locking in the message queue + * implementation itself. */ +static int tr_tids_fwd_get_mutex(struct tr_tids_fwd_cookie *cookie) +{ + if (cookie==NULL) + return -1; + + return (pthread_mutex_lock(&(cookie->mutex))); +} + +static int tr_tids_fwd_release_mutex(struct tr_tids_fwd_cookie *cookie) +{ + if (cookie==NULL) + return -1; + + return (pthread_mutex_unlock(&(cookie->mutex))); +} + +/* values for messages */ +#define TR_TID_MQMSG_SUCCESS "tid success" +#define TR_TID_MQMSG_FAILURE "tid failure" + +/* Thread main for sending and receiving a request to a single AAA server */ +static void *tr_tids_req_fwd_thread(void *arg) +{ + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + struct tr_tids_fwd_cookie *args=talloc_get_type_abort(arg, struct tr_tids_fwd_cookie); + TIDC_INSTANCE *tidc=tidc_create(tmp_ctx); + TR_MQ_MSG *msg=NULL; + TR_RESP_COOKIE *cookie=NULL; + int rc=0; + int success=0; + + talloc_steal(tmp_ctx, args); /* take responsibility for the cookie */ + + /* Create a TID client instance */ + if (tidc==NULL) { + tr_crit("tr_tids_req_fwd_thread: Unable to allocate TIDC instance."); + /*tids_send_err_response(tids, orig_req, "Memory allocation failure");*/ + /* TODO: encode reason for failure */ + success=0; + goto cleanup; + } + + /* Set-up TID connection */ + if (-1==(args->fwd_req->conn = tidc_open_connection(tidc, + args->aaa_hostname->buf, + TID_PORT, /* TODO: make this configurable */ + &(args->fwd_req->gssctx)))) { + tr_notice("tr_tids_req_fwd_thread: Error in tidc_open_connection."); + /* tids_send_err_response(tids, orig_req, "Can't open connection to next hop TIDS"); */ + /* TODO: encode reason for failure */ + success=0; + goto cleanup; + }; + + /* Send a TID request. */ + cookie=talloc(tmp_ctx, TR_RESP_COOKIE); + if (cookie==NULL) { + tr_notice("tr_tids_req_fwd_thread: unable to allocate response cookie."); + success=0; + goto cleanup; + } + cookie->thread_id=args->thread_id; + if (0 > (rc = tidc_fwd_request(tidc, args->fwd_req, &tr_tidc_resp_handler, (void *)cookie))) { + tr_notice("Error from tidc_fwd_request, rc = %d.", rc); + success=0; + goto cleanup; + } + /* cookie->resp should now contain our copy of the response */ + success=1; + +cleanup: + /* Notify parent thread of the response, if it's still listening. */ + if (0!=tr_tids_fwd_get_mutex(args)) { + tr_notice("tr_tids_req_fwd_thread: Error acquiring mutex."); + } else if (NULL!=args->mq) { + /* mq is still valid, so we can queue our response */ + if (success) + msg=tr_mq_msg_new(tmp_ctx, TR_TID_MQMSG_SUCCESS, TR_MQ_PRIO_NORMAL); + else + msg=tr_mq_msg_new(tmp_ctx, TR_TID_MQMSG_FAILURE, TR_MQ_PRIO_NORMAL); + + if (msg==NULL) + tr_notice("tr_tids_req_fwd_thread: unable to allocate response msg."); + + tr_mq_msg_set_payload(msg, (void *)cookie, NULL); + if (NULL!=cookie) + talloc_steal(msg, cookie); /* attach this to the msg so we can forget about it */ + tr_mq_add(args->mq, msg); + talloc_steal(NULL, args); /* take out of our tmp_ctx; master thread now responsible for freeing */ + if (0!=tr_tids_fwd_release_mutex(args)) + tr_notice("tr_tids_req_fwd_thread: Error releasing mutex."); + } + + talloc_free(tmp_ctx); + return NULL; +} + +/* Merges r2 into r1 if they are compatible. */ +static TID_RC tr_tids_merge_resps(TID_RESP *r1, TID_RESP *r2) +{ + /* ensure these are compatible replies */ + if ((r1->result!=TID_SUCCESS) || (r2->result!=TID_SUCCESS)) + return TID_ERROR; + + if ((0!=tr_name_cmp(r1->rp_realm, r2->rp_realm)) || + (0!=tr_name_cmp(r1->realm, r2->realm)) || + (0!=tr_name_cmp(r1->comm, r2->comm))) + return TID_ERROR; + + tid_srvr_blk_add(r1->servers, tid_srvr_blk_dup(r1, r2->servers)); + return TID_SUCCESS; +} -static int tr_tids_req_handler (TIDS_INSTANCE *tids, - TID_REQ *orig_req, - TID_RESP *resp, - void *cookie_in) +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; + TALLOC_CTX *tmp_ctx=talloc_new(NULL); + TR_AAA_SERVER *aaa_servers=NULL, *this_aaa=NULL; + int n_aaa=0; + int idp_shared=0; + TR_AAA_SERVER_ITER *aaa_iter=NULL; + pthread_t aaa_thread[TR_TID_MAX_AAA_SERVERS]; + struct tr_tids_fwd_cookie *aaa_cookie[TR_TID_MAX_AAA_SERVERS]={NULL}; TR_NAME *apc = NULL; TID_REQ *fwd_req = NULL; TR_COMM *cfg_comm = NULL; TR_COMM *cfg_apc = NULL; int oaction = TR_FILTER_ACTION_REJECT; - int rc = 0; time_t expiration_interval=0; struct tr_tids_event_cookie *cookie=talloc_get_type_abort(cookie_in, struct tr_tids_event_cookie); TR_CFG_MGR *cfg_mgr=cookie->cfg_mgr; TRPS_INSTANCE *trps=cookie->trps; TRP_ROUTE *route=NULL; + TR_MQ *mq=NULL; + TR_MQ_MSG *msg=NULL; + unsigned int n_responses=0; + unsigned int n_failed=0; + struct timespec ts_abort={0}; + unsigned int resp_frac_numer=cfg_mgr->active->internal->tid_resp_numer; + unsigned int resp_frac_denom=cfg_mgr->active->internal->tid_resp_denom; + TR_RESP_COOKIE *payload=NULL; + int ii=0; int retval=-1; if ((!tids) || (!orig_req) || (!resp)) { @@ -109,13 +280,13 @@ static int tr_tids_req_handler (TIDS_INSTANCE *tids, tids->req_count++; /* Duplicate the request, so we can modify and forward it */ - if (NULL == (fwd_req = tid_dup_req(orig_req))) { + if (NULL == (fwd_req=tid_dup_req(tmp_ctx, orig_req))) { tr_debug("tr_tids_req_handler: Unable to duplicate request."); retval=-1; goto cleanup; } - if (NULL == (cfg_comm = tr_comm_table_find_comm(cfg_mgr->active->ctable, orig_req->comm))) { + if (NULL == (cfg_comm=tr_comm_table_find_comm(cfg_mgr->active->ctable, orig_req->comm))) { tr_notice("tr_tids_req_hander: Request for unknown comm: %s.", orig_req->comm->buf); tids_send_err_response(tids, orig_req, "Unknown community"); retval=-1; @@ -123,7 +294,9 @@ static int tr_tids_req_handler (TIDS_INSTANCE *tids, } /* Check that the rp_realm matches the filter for the GSS name that - * was received. */ + * was received. N.B. that tids->rp_gss was pointed at the correct + * rp_client when we received its GSS name. It is only set within + * the TIDS handler subprocess. */ if ((!tids->rp_gss) || (!tids->rp_gss->filter)) { @@ -145,7 +318,7 @@ static int tr_tids_req_handler (TIDS_INSTANCE *tids, goto cleanup; } /* Check that the rp_realm is a member of the community in the request */ - if (NULL == (tr_comm_find_rp(cfg_mgr->active->ctable, cfg_comm, orig_req->rp_realm))) { + if (NULL == tr_comm_find_rp(cfg_mgr->active->ctable, cfg_comm, orig_req->rp_realm)) { tr_notice("tr_tids_req_handler: RP Realm (%s) not member of community (%s).", orig_req->rp_realm->buf, orig_req->comm->buf); tids_send_err_response(tids, orig_req, "RP COI membership error"); retval=-1; @@ -207,10 +380,12 @@ static int tr_tids_req_handler (TIDS_INSTANCE *tids, tr_debug("tr_tids_req_handler: route is local."); aaa_servers = tr_idp_aaa_server_lookup(cfg_mgr->active->ctable->idp_realms, orig_req->realm, - orig_req->comm); + orig_req->comm, + &idp_shared); } else { tr_debug("tr_tids_req_handler: route not local."); aaa_servers = tr_aaa_server_new(tmp_ctx, trp_route_get_next_hop(route)); + idp_shared=0; } /* Find the AAA server(s) for this request */ @@ -223,6 +398,7 @@ static int tr_tids_req_handler (TIDS_INSTANCE *tids, retval=-1; goto cleanup; } + idp_shared=0; } else { /* if we aren't defaulting, check idp coi and apc membership */ if (NULL == (tr_comm_find_idp(cfg_mgr->active->ctable, cfg_comm, fwd_req->realm))) { @@ -240,48 +416,144 @@ static int tr_tids_req_handler (TIDS_INSTANCE *tids, } /* 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"); + + /* Set up message queue for replies from req forwarding threads */ + mq=tr_mq_new(tmp_ctx); + if (mq==NULL) { + tr_notice("tr_tids_req_handler: unable to allocate message queue."); retval=-1; goto cleanup; } - /* Use the DH parameters from the original request */ - /* TBD -- this needs to be fixed when we handle more than one req per conn */ - tidc->client_dh = orig_req->tidc_dh; - /* Save information about this request for the response */ - resp_cookie.tids = tids; - resp_cookie.orig_req = orig_req; - - /* Set-up TID connection */ - if (-1 == (fwd_req->conn = tidc_open_connection(tidc, - aaa_servers->hostname->buf, - TID_PORT, - &(fwd_req->gssctx)))) { - tr_notice("tr_tids_req_handler: Error in tidc_open_connection."); - tids_send_err_response(tids, orig_req, "Can't open connection to next hop TIDS"); + /* start threads */ + aaa_iter=tr_aaa_server_iter_new(tmp_ctx); + if (aaa_iter==NULL) { + tr_notice("tr_tids_req_handler: unable to allocate AAA server iterator."); retval=-1; goto cleanup; - }; - - /* 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"); + } + for (n_aaa=0, this_aaa=tr_aaa_server_iter_first(aaa_iter, aaa_servers); + this_aaa!=NULL; + n_aaa++, this_aaa=tr_aaa_server_iter_next(aaa_iter)) { + aaa_cookie[n_aaa]=talloc(tmp_ctx, struct tr_tids_fwd_cookie); + if (aaa_cookie[n_aaa]==NULL) { + tr_notice("tr_tids_req_handler: unable to allocate cookie for AAA thread %d.", n_aaa); + retval=-1; + goto cleanup; + } + talloc_set_destructor((void *)(aaa_cookie[n_aaa]), tr_tids_fwd_cookie_destructor); + /* fill in the cookie. To ensure the thread has valid data even if we exit first and + * abandon it, duplicate anything pointed to (except the mq). */ + aaa_cookie[n_aaa]->thread_id=n_aaa; + if (0!=pthread_mutex_init(&(aaa_cookie[n_aaa]->mutex), NULL)) { + tr_notice("tr_tids_req_handler: unable to init mutex for AAA thread %d.", n_aaa); + retval=-1; + goto cleanup; + } + aaa_cookie[n_aaa]->mq=mq; + aaa_cookie[n_aaa]->aaa_hostname=tr_dup_name(this_aaa->hostname); + aaa_cookie[n_aaa]->dh_params=tr_dup_dh_params(orig_req->tidc_dh); + aaa_cookie[n_aaa]->fwd_req=tid_dup_req(aaa_cookie, fwd_req); + + /* Take the cookie out of tmp_ctx before starting thread. If thread starts, it becomes + * responsible for freeing it until it queues a response. */ + talloc_steal(NULL, aaa_cookie[n_aaa]); + if (0!=pthread_create(&(aaa_thread[n_aaa]), NULL, tr_tids_req_fwd_thread, aaa_cookie[n_aaa])) { + talloc_steal(tmp_ctx, aaa_cookie[n_aaa]); /* thread start failed; steal this back */ + tr_notice("tr_tids_req_handler: unable to start AAA thread %d.", n_aaa); + retval=-1; + goto cleanup; + } + } + + /* determine expiration time */ + if (0!=tr_mq_pop_timeout(cfg_mgr->active->internal->tid_req_timeout, &ts_abort)) { + tr_notice("tr_tids_req_handler: unable to read clock for timeout."); retval=-1; goto cleanup; } + /* wait for responses */ + n_responses=0; + n_failed=0; + while (((n_responses+n_failed)resp->result==TID_SUCCESS) { + tr_tids_merge_resps(resp, payload->resp); + n_responses++; + } else { + n_failed++; + tr_notice("tr_tids_req_handler: TID error received from AAA server %d: %.*s", + payload->thread_id, + payload->resp->err_msg->len, + payload->resp->err_msg->buf); + } + } else if (0==strcmp(tr_mq_msg_get_message(msg), TR_TID_MQMSG_FAILURE)) { + /* failure */ + payload=talloc_get_type_abort(tr_mq_msg_get_payload(msg), TR_RESP_COOKIE); + n_failed++; + tr_notice("tr_tids_req_handler: TID request for AAA server %d failed.", + payload->thread_id); + } else { + /* unexpected message */ + tr_err("tr_tids_req_handler: Unexpected message received. Aborting!"); + retval=-1; + goto cleanup; + } + + /* Now free the cookie for this thread. Null it so we know we've dealt with it. */ + talloc_free(aaa_cookie[payload->thread_id]); + aaa_cookie[payload->thread_id]=NULL; + + tr_mq_msg_free(msg); + + /* check whether we've received enough responses to exit */ + if ((idp_shared && (n_responses>0)) || + (resp_frac_denom*n_responses>=resp_frac_numer*n_aaa)) + break; + } + + /* Inform any remaining threads that we will no longer handle their responses. */ + for (ii=0; iimq=NULL; /* threads will not try to respond through a null mq */ + + if (0!=tr_tids_fwd_release_mutex(aaa_cookie[ii])) + tr_notice("tr_tids_req_handler: unable to release mutex for AAA thread %d.", ii); + } + } + + /* Now all threads have either replied (and aaa_cookie[ii] is null) or have been told not to + * reply (by setting their mq pointer to null). However, some may have responded by placing + * a message on the mq after we last checked but before we set their mq pointer to null. These + * will not know that we gave up on them, so we must free their cookies for them. We can just + * go through any remaining messages on the mq to identify these threads. */ + while (NULL!=(msg=tr_mq_pop(mq, NULL))) { + payload=(TR_RESP_COOKIE *)tr_mq_msg_get_payload(msg); + if (aaa_cookie[payload->thread_id]!=NULL) + talloc_free(aaa_cookie[payload->thread_id]); + + tr_mq_msg_free(msg); + } + + if (n_responses==0) { + tid_resp_set_result(resp, TID_ERROR); + tid_resp_set_err_msg(resp, tr_new_name("No successful response from AAA server(s).")); + tid_resp_set_error_path(resp, orig_req->path); + } + /* success! */ retval=0; diff --git a/trp/trpc.c b/trp/trpc.c index 4f32584..b6a2cea 100644 --- a/trp/trpc.c +++ b/trp/trpc.c @@ -191,7 +191,7 @@ void trpc_mq_add(TRPC_INSTANCE *trpc, TR_MQ_MSG *msg) TR_MQ_MSG *trpc_mq_pop(TRPC_INSTANCE *trpc) { - return tr_mq_pop(trpc->mq); + return tr_mq_pop(trpc->mq, 0); } void trpc_mq_clear(TRPC_INSTANCE *trpc) diff --git a/trp/trps.c b/trp/trps.c index fcddf4f..cbe0397 100644 --- a/trp/trps.c +++ b/trp/trps.c @@ -50,7 +50,7 @@ #include #include #include - +#include static int trps_destructor(void *object) { @@ -120,7 +120,7 @@ void trps_free (TRPS_INSTANCE *trps) TR_MQ_MSG *trps_mq_pop(TRPS_INSTANCE *trps) { - return tr_mq_pop(trps->mq); + return tr_mq_pop(trps->mq, 0); } void trps_mq_add(TRPS_INSTANCE *trps, TR_MQ_MSG *msg) @@ -303,7 +303,6 @@ static size_t trps_listen(TRPS_INSTANCE *trps, int port, int *fd_out, size_t max getaddrinfo(NULL, port_str, &hints, &ai_head); talloc_free(port_str); - /* TODO: listen on all ports */ for (ai=ai_head,n_opened=0; (ai!=NULL)&&(n_openedai_next) { if (0 > (conn = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))) { tr_debug("trps_listen: unable to open socket."); @@ -1142,9 +1141,7 @@ TRP_RC trps_update_active_routes(TRPS_INSTANCE *trps) /* true if curtime >= expiry */ static int trps_expired(struct timespec *expiry, struct timespec *curtime) { - return ((curtime->tv_sec > expiry->tv_sec) - || ((curtime->tv_sec == expiry->tv_sec) - &&(curtime->tv_nsec >= expiry->tv_nsec))); + return (tr_cmp_timespec(curtime, expiry) >= 0); } /* Sweep for expired routes. For each expired route, if its metric is infinite, the route is flushed. -- 2.1.4