From: Jennifer Richards Date: Thu, 3 May 2018 20:50:54 +0000 (-0400) Subject: Merge branch 'milestone/monitoring' into jennifer/request_id X-Git-Tag: 3.4.0~1^2~38^2~1 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=trust_router.git;a=commitdiff_plain;h=3c5fb17459ff56d5e23cea059503f46a42150a1e;hp=-c Merge branch 'milestone/monitoring' into jennifer/request_id # Conflicts: # include/trust_router/tid.h # tid/tidc.c # tr/tr_tid.c --- 3c5fb17459ff56d5e23cea059503f46a42150a1e diff --combined Makefile.am index fbc763c,1c933d6..1231793 --- a/Makefile.am +++ b/Makefile.am @@@ -1,8 -1,10 +1,10 @@@ + ACLOCAL_AMFLAGS = -I m4 DISTCHECK_CONFIGURE_FLAGS = \ --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) bin_PROGRAMS= tr/trust_router tr/trpc tid/example/tidc tid/example/tids common/tests/tr_dh_test common/tests/mq_test \ common/tests/thread_test trp/msgtst trp/test/rtbl_test trp/test/ptbl_test common/tests/cfg_test \ - common/tests/commtest common/tests/name_test common/tests/filt_test + common/tests/commtest common/tests/name_test common/tests/filt_test mon/tests/test_mon_req_encode \ + mon/tests/test_mon_req_decode mon/tests/test_mon_resp_encode tr/trmon AM_CPPFLAGS=-I$(srcdir)/include $(GLIB_CFLAGS) AM_CFLAGS = -Wall -Werror=missing-prototypes -Werror -Wno-parentheses $(GLIB_CFLAGS) SUBDIRS = gsscon @@@ -15,26 -17,64 +17,65 @@@ common_srcs = common/tr_name.c common/tr_util.c \ common/tr_apc.c \ common/tr_comm.c \ + common/tr_comm_encoders.c \ common/tr_rp.c \ + common/tr_rp_client.c \ + common/tr_rp_client_encoders.c \ common/tr_idp.c \ + common/tr_idp_encoders.c \ common/tr_filter.c \ - common/tr_gss.c + common/tr_filter_encoders.c \ + common/tr_gss_names.c \ + common/tr_socket.c \ + $(mon_srcs) tid_srcs = tid/tid_resp.c \ tid/tid_req.c \ tid/tids.c \ -tid/tidc.c +tid/tidc.c \ +common/tr_rand_id.c trp_srcs = trp/trp_conn.c \ trp/trps.c \ trp/trpc.c \ + trp/trp_peer.c \ + trp/trp_peer_encoders.c \ trp/trp_ptable.c \ + trp/trp_ptable_encoders.c \ + trp/trp_route.c \ + trp/trp_route_encoders.c \ trp/trp_rtable.c \ + trp/trp_rtable_encoders.c \ trp/trp_req.c \ trp/trp_upd.c \ - common/tr_config.c \ - common/tr_mq.c + common/tr_mq.c \ + $(config_srcs) + + # configuration parsing sources + config_srcs = \ + common/tr_config.c \ + common/tr_config_comms.c \ + common/tr_config_encoders.c \ + common/tr_config_filters.c \ + common/tr_config_internal.c \ + common/tr_config_orgs.c \ + common/tr_config_realms.c \ + common/tr_config_rp_clients.c + + # general monitoring message sources + mon_srcs = \ + mon/mon_common.c \ + mon/mon_req.c \ + mon/mon_req_encode.c \ + mon/mon_req_decode.c \ + mon/mon_resp.c \ + mon/mon_resp_decode.c \ + mon/mon_resp_encode.c + + # monitoring server sources + mons_srcs = \ + mon/mons.c \ + mon/mons_handlers.c check_PROGRAMS = common/t_constraint TESTS = common/t_constraint @@@ -56,7 -96,6 +97,7 @@@ common/tr_debug.c common/tr_name.c \ common/tr_constraint.c \ common/tr_dh.c \ +common/tr_rand_id.c \ tid/tid_req.c \ tid/tid_resp.c @@@ -68,15 -107,24 +109,24 @@@ tr/tr.c tr/tr_event.c \ tr/tr_cfgwatch.c \ tr/tr_tid.c \ + tr/tr_tid_mons.c \ tr/tr_trp.c \ + tr/tr_trp_mons.c \ + tr/tr_mon.c \ + common/tr_gss.c \ + common/tr_gss_client.c \ $(tid_srcs) \ $(trp_srcs) \ - $(common_srcs) + $(common_srcs) \ + $(mons_srcs) tr_trust_router_LDFLAGS = $(AM_LDFLAGS) -levent_pthreads -pthread tr_trust_router_LDADD = gsscon/libgsscon.la $(GLIB_LIBS) + tr_trpc_SOURCES =tr/trpc_main.c \ tr/tr_trp.c \ + common/tr_gss.c \ + common/tr_gss_client.c \ $(trp_srcs) \ $(tid_srcs) \ $(common_srcs) @@@ -84,9 -132,19 +134,20 @@@ tr_trpc_LDADD = gsscon/libgsscon.la $(GLIB_LIBS) tr_trpc_LDFLAGS = $(AM_LDFLAGS) -pthread + tr_trmon_SOURCES = tr/trmon_main.c \ + common/tr_gss.c \ + common/tr_gss_client.c \ + $(tid_srcs) \ + $(trp_srcs) \ + $(common_srcs) \ + mon/monc.c + + tr_trmon_LDADD = gsscon/libgsscon.la $(GLIB_LIBS) + tr_trmon_LDFLAGS = $(AM_LDFLAGS) -pthread + trp_msgtst_SOURCES = trp/msgtst.c \ $(common_srcs) \ +common/tr_rand_id.c \ trp/trp_req.c \ trp/trp_upd.c \ tid/tid_resp.c \ @@@ -95,12 -153,18 +156,18 @@@ trp_msgtst_LDADD = $(GLIB_LIBS trp_test_rtbl_test_SOURCES = trp/test/rtbl_test.c \ common/tr_name.c \ - common/tr_gss.c \ + common/tr_gss_names.c \ common/tr_debug.c \ - trp/trp_rtable.c + common/tr_util.c \ + trp/trp_route.c \ + trp/trp_route_encoders.c \ + trp/trp_rtable.c \ + trp/trp_rtable_encoders.c trp_test_rtbl_test_LDADD = $(GLIB_LIBS) trp_test_ptbl_test_SOURCES = trp/test/ptbl_test.c \ + common/tr_gss.c \ + common/tr_gss_client.c \ $(tid_srcs) \ $(trp_srcs) \ $(common_srcs) @@@ -108,6 -172,8 +175,8 @@@ trp_test_ptbl_test_LDADD = gsscon/libgs trp_test_ptbl_test_LDFLAGS = $(AM_LDFLAGS) -pthread tid_example_tidc_SOURCES = tid/example/tidc_main.c \ + common/tr_gss.c \ + common/tr_gss_client.c \ $(tid_srcs) \ $(trp_srcs) \ $(common_srcs) @@@ -115,6 -181,8 +184,8 @@@ tid_example_tidc_LDADD = gsscon/libgssc tid_example_tidc_LDFLAGS = $(AM_LDFLAGS) -pthread tid_example_tids_SOURCES = tid/example/tids_main.c \ + common/tr_gss.c \ + common/tr_gss_client.c \ $(tid_srcs) \ $(trp_srcs) \ $(common_srcs) @@@ -133,6 -201,8 +204,8 @@@ common_tests_mq_test_LDFLAGS = $(AM_LDF common_tests_cfg_test_SOURCES = common/tests/cfg_test.c \ $(common_srcs) \ + common/tr_gss.c \ + common/tr_gss_client.c \ $(tid_srcs) \ $(trp_srcs) common_tests_cfg_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS) @@@ -144,6 -214,8 +217,8 @@@ common/tests/thread_test. common_tests_commtest_SOURCES = common/tests/commtest.c \ $(common_srcs) \ + common/tr_gss.c \ + common/tr_gss_client.c \ $(tid_srcs) \ $(trp_srcs) common_tests_commtest_LDADD = gsscon/libgsscon.la $(GLIB_LIBS) @@@ -153,6 -225,8 +228,8 @@@ common_tests_thread_test_LDFLAGS = $(AM common_tests_name_test_SOURCES = common/tests/name_test.c \ $(common_srcs) \ + common/tr_gss.c \ + common/tr_gss_client.c \ $(tid_srcs) \ $(trp_srcs) common_tests_name_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS) @@@ -161,12 -235,32 +238,32 @@@ common_tests_name_test_CFLAGS = $(AM_CF common_tests_filt_test_SOURCES = common/tests/filt_test.c \ $(common_srcs) \ + common/tr_gss.c \ + common/tr_gss_client.c \ $(tid_srcs) \ $(trp_srcs) common_tests_filt_test_LDADD = gsscon/libgsscon.la $(GLIB_LIBS) common_tests_filt_test_LDFLAGS = $(AM_LDFLAGS) -ltalloc -pthread common_tests_filt_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + mon_tests_test_mon_req_encode_SOURCES = mon/tests/test_mon_req_encode.c \ + $(mon_srcs) \ + common/tr_name.c + mon_tests_test_mon_req_encode_LDADD = $(GLIB_LIBS) + mon_tests_test_mon_req_encode_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + + mon_tests_test_mon_req_decode_SOURCES = mon/tests/test_mon_req_decode.c \ + $(mon_srcs) \ + common/tr_name.c + mon_tests_test_mon_req_decode_LDADD = $(GLIB_LIBS) + mon_tests_test_mon_req_decode_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + + mon_tests_test_mon_resp_encode_SOURCES = mon/tests/test_mon_resp_encode.c \ + $(mon_srcs) \ + common/tr_name.c + mon_tests_test_mon_resp_encode_LDADD = $(GLIB_LIBS) + mon_tests_test_mon_resp_encode_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + pkginclude_HEADERS = include/trust_router/tid.h include/trust_router/tr_name.h \ include/tr_debug.h include/trust_router/trp.h \ include/trust_router/tr_dh.h \ @@@ -177,13 -271,13 +274,13 @@@ noinst_HEADERS = include/gsscon.h inclu include/tr_msg.h include/tr.h \ include/tr_idp.h include/tr_rp.h \ include/tr_comm.h include/tr_apc.h \ - include/tr_tid.h include/tr_trp.h \ - include/tr_filter.h include/tr_gss.h \ - include/tid_internal.h include/trp_internal.h \ + include/tr_tid.h include/tr_trp.h include/tr_mon.h \ + include/tr_filter.h include/tr_gss_names.h \ + include/tid_internal.h include/trp_internal.h include/trp_route.h \ include/tr_cfgwatch.h include/tr_event.h \ - include/tr_mq.h include/trp_ptable.h \ + include/tr_mq.h include/trp_peer.h include/trp_ptable.h \ include/trp_rtable.h include/tr_util.h \ - include/tr_name_internal.h + include/tr_name_internal.h include/tr_gss.h pkgdata_DATA=schema.sql nobase_dist_pkgdata_DATA=redhat/init redhat/sysconfig redhat/organizations.cfg redhat/tidc-wrapper redhat/trust_router-wrapper redhat/tr-test-internal.cfg redhat/default-internal.cfg redhat/tids-wrapper redhat/sysconfig.tids diff --combined common/tr_msg.c index 66972e0,ab80345..50e8bc9 --- a/common/tr_msg.c +++ b/common/tr_msg.c @@@ -41,12 -41,12 +41,12 @@@ #include #include - #include #include + #include + #include #include #include - #include #include #include #include @@@ -101,6 -101,17 +101,17 @@@ void tr_msg_set_msg_type(TR_MSG *msg, e msg->msg_type = type; } + /* NOTE: If you are manipulating messages with these getters/setters, the msg_rep + * objects are *not* put in the talloc context of the msg. If you are allocating + * the message directly with talloc, then you can talloc_steal() the rep into the + * message's context, but this is not handled automatically. */ + + /** + * Get a TID_REQ message payload + * + * @param msg + * @return the message payload, or null if it is not a TID_REQUEST message + */ TID_REQ *tr_msg_get_req(TR_MSG *msg) { if (msg->msg_type == TID_REQUEST) @@@ -108,12 -119,24 +119,24 @@@ return NULL; } + /** + * Set message's payload + * + * Does not manage talloc contexts, works with any means of allocating + * the objects. + */ void tr_msg_set_req(TR_MSG *msg, TID_REQ *req) { msg->msg_rep = req; msg->msg_type = TID_REQUEST; } + /** + * Get a TID_RESP message payload + * + * @param msg + * @return the message payload, or null if it is not a TID_RESPONSE message + */ TID_RESP *tr_msg_get_resp(TR_MSG *msg) { if (msg->msg_type == TID_RESPONSE) @@@ -121,12 -144,74 +144,74 @@@ return NULL; } + /** + * Set message's payload + * + * Does not manage talloc contexts, works with any means of allocating + * the objects. + */ void tr_msg_set_resp(TR_MSG *msg, TID_RESP *resp) { msg->msg_rep = resp; msg->msg_type = TID_RESPONSE; } + /** + * Get a MON_REQ message payload + * + * @param msg + * @return the message payload, or null if it is not a MON_REQUEST message + */ + MON_REQ *tr_msg_get_mon_req(TR_MSG *msg) + { + if (msg->msg_type == MON_REQUEST) + return (MON_REQ *)msg->msg_rep; + return NULL; + } + + /** + * Set message's payload + * + * Does not manage talloc contexts, works with any means of allocating + * the objects. + */ + void tr_msg_set_mon_req(TR_MSG *msg, MON_REQ *req) + { + msg->msg_rep = req; + msg->msg_type = MON_REQUEST; + } + + /** + * Get a MON_RESP message payload + * + * @param msg + * @return the message payload, or null if it is not a MON_RESPONSE message + */ + MON_RESP *tr_msg_get_mon_resp(TR_MSG *msg) + { + if (msg->msg_type == MON_RESPONSE) + return (MON_RESP *)msg->msg_rep; + return NULL; + } + + /** + * Set message's payload + * + * Does not manage talloc contexts, works with any means of allocating + * the objects. + */ + void tr_msg_set_mon_resp(TR_MSG *msg, MON_RESP *resp) + { + msg->msg_rep = resp; + msg->msg_type = MON_RESPONSE; + } + + /** + * Get a TRP_UPD message payload + * + * @param msg + * @return the message payload, or null if it is not a TRP_UPDATE message + */ TRP_UPD *tr_msg_get_trp_upd(TR_MSG *msg) { if (msg->msg_type == TRP_UPDATE) @@@ -134,13 -219,24 +219,24 @@@ return NULL; } + /** + * Set message's payload + * + * Does not manage talloc contexts, works with any means of allocating + * the objects. + */ void tr_msg_set_trp_upd(TR_MSG *msg, TRP_UPD *update) { msg->msg_rep=update; - talloc_steal(NULL, update); /* should attach to msg, but TR_MSG not usually talloc'ed */ msg->msg_type=TRP_UPDATE; } + /** + * Get a TRP_REQ message payload + * + * @param msg + * @return the message payload, or null if it is not a TRP_REQUEST message + */ TRP_REQ *tr_msg_get_trp_req(TR_MSG *msg) { if (msg->msg_type == TRP_REQUEST) @@@ -148,6 -244,12 +244,12 @@@ return NULL; } + /** + * Set message's payload + * + * Does not manage talloc contexts, works with any means of allocating + * the objects. + */ void tr_msg_set_trp_req(TR_MSG *msg, TRP_REQ *req) { msg->msg_rep=req; @@@ -216,7 -318,8 +318,8 @@@ static json_t * tr_msg_encode_tidreq(TI if ((!req) || (!req->rp_realm) || (!req->realm) || !(req->comm)) return NULL; - assert(jreq = json_object()); + jreq = json_object(); + assert(jreq); jstr = tr_name_to_json_string(req->rp_realm); json_object_set_new(jreq, "rp_realm", jstr); @@@ -226,17 -329,12 +329,17 @@@ jstr = tr_name_to_json_string(req->comm); json_object_set_new(jreq, "community", jstr); - + if (req->orig_coi) { jstr = tr_name_to_json_string(req->orig_coi); json_object_set_new(jreq, "orig_coi", jstr); } + if (tid_req_get_request_id(req)) { + jstr = tr_name_to_json_string(tid_req_get_request_id(req)); + json_object_set_new(jreq, "request_id", jstr); + } + json_object_set_new(jreq, "dh_info", tr_msg_encode_dh(req->tidc_dh)); if (req->cons) @@@ -251,14 -349,13 +354,14 @@@ return jreq; } - static TID_REQ *tr_msg_decode_tidreq(json_t *jreq) + static TID_REQ *tr_msg_decode_tidreq(TALLOC_CTX *mem_ctx, json_t *jreq) { TID_REQ *treq = NULL; json_t *jrp_realm = NULL; json_t *jrealm = NULL; json_t *jcomm = NULL; json_t *jorig_coi = NULL; + json_t *jrequest_id = NULL; json_t *jdh = NULL; json_t *jpath = NULL; json_t *jexpire_interval = NULL; @@@ -267,7 -364,8 +370,8 @@@ tr_crit("tr_msg_decode_tidreq(): Error allocating TID_REQ structure."); return NULL; } - + talloc_steal(mem_ctx, treq); + /* store required fields from request */ if ((NULL == (jrp_realm = json_object_get(jreq, "rp_realm"))) || (NULL == (jrealm = json_object_get(jreq, "target_realm"))) || @@@ -280,9 -378,9 +384,9 @@@ jpath = json_object_get(jreq, "path"); jexpire_interval = json_object_get(jreq, "expiration_interval"); - treq->rp_realm = tr_new_name((char *)json_string_value(jrp_realm)); - treq->realm = tr_new_name((char *)json_string_value(jrealm)); - treq->comm = tr_new_name((char *)json_string_value(jcomm)); + treq->rp_realm = tr_new_name(json_string_value(jrp_realm)); + treq->realm = tr_new_name(json_string_value(jrealm)); + treq->comm = tr_new_name(json_string_value(jcomm)); /* Get DH Info from the request */ if (NULL == (jdh = json_object_get(jreq, "dh_info"))) { @@@ -294,12 -392,7 +398,12 @@@ /* store optional "orig_coi" field */ if (NULL != (jorig_coi = json_object_get(jreq, "orig_coi"))) { - treq->orig_coi = tr_new_name((char *)json_string_value(jorig_coi)); + treq->orig_coi = tr_new_name(json_string_value(jorig_coi)); + } + + /* store optional "request_id" field */ + if (NULL != (jrequest_id = json_object_get(jreq, "request_id"))) { + tid_req_set_request_id(treq, tr_new_name(json_string_value(jrequest_id))); } treq->cons = (TR_CONSTRAINT_SET *) json_object_get(jreq, "constraints"); @@@ -480,11 -573,6 +584,11 @@@ static json_t * tr_msg_encode_tidresp(T json_object_set_new(jresp, "orig_coi", jstr); } + if (tid_resp_get_request_id(resp)) { + jstr = tr_name_to_json_string(tid_resp_get_request_id(resp)); + json_object_set_new(jresp, "request_id", jstr); + } + if (NULL == resp->servers) { tr_debug("tr_msg_encode_tidresp(): No servers to encode."); } @@@ -499,7 -587,7 +603,7 @@@ return jresp; } - static TID_RESP *tr_msg_decode_tidresp(json_t *jresp) + static TID_RESP *tr_msg_decode_tidresp(TALLOC_CTX *mem_ctx, json_t *jresp) { TID_RESP *tresp = NULL; json_t *jresult = NULL; @@@ -507,15 -595,13 +611,14 @@@ json_t *jrealm = NULL; json_t *jcomm = NULL; json_t *jorig_coi = NULL; + json_t *jrequest_id = NULL; json_t *jservers = NULL; json_t *jerr_msg = NULL; - if (!(tresp=tid_resp_new(NULL))) { + if (!(tresp=tid_resp_new(mem_ctx))) { tr_crit("tr_msg_decode_tidresp(): Error allocating TID_RESP structure."); return NULL; } - /* store required fields from response */ if ((NULL == (jresult = json_object_get(jresp, "result"))) || @@@ -562,16 -648,10 +665,16 @@@ /* store optional "orig_coi" field */ if ((NULL != (jorig_coi = json_object_get(jresp, "orig_coi"))) && - (!json_is_object(jorig_coi))) { + json_is_string(jorig_coi)) { tresp->orig_coi = tr_new_name(json_string_value(jorig_coi)); } - + + /* store optional "request_id" field */ + if ((NULL != (jrequest_id = json_object_get(jresp, "request_id"))) && + json_is_string(jrequest_id)) { + tid_resp_set_request_id(tresp, tr_new_name(json_string_value(jrequest_id))); + } + return tresp; } @@@ -1167,21 -1247,23 +1270,23 @@@ cleanup return req; } - char *tr_msg_encode(TR_MSG *msg) + char *tr_msg_encode(TALLOC_CTX *mem_ctx, TR_MSG *msg) { json_t *jmsg=NULL; json_t *jmsg_type=NULL; + char *encoded_tmp=NULL; char *encoded=NULL; TID_RESP *tidresp=NULL; TID_REQ *tidreq=NULL; TRP_UPD *trpupd=NULL; TRP_REQ *trpreq=NULL; + MON_REQ *monreq=NULL; + MON_RESP *monresp=NULL; /* TBD -- add error handling */ jmsg = json_object(); - switch (msg->msg_type) - { + switch (msg->msg_type) { case TID_REQUEST: jmsg_type = json_string("tid_request"); json_object_set_new(jmsg, "msg_type", jmsg_type); @@@ -1210,18 -1292,37 +1315,37 @@@ json_object_set_new(jmsg, "msg_body", tr_msg_encode_trp_req(trpreq)); break; + case MON_REQUEST: + jmsg_type = json_string("mon_request"); + json_object_set_new(jmsg, "msg_type", jmsg_type); + monreq=tr_msg_get_mon_req(msg); + json_object_set_new(jmsg, "msg_body", mon_req_encode(monreq)); + break; + + case MON_RESPONSE: + jmsg_type = json_string("mon_response"); + json_object_set_new(jmsg, "msg_type", jmsg_type); + monresp=tr_msg_get_mon_resp(msg); + json_object_set_new(jmsg, "msg_body", mon_resp_encode(monresp)); + break; + default: json_decref(jmsg); return NULL; - } + } + + /* We should perhaps use json_set_alloc_funcs to automatically use talloc, but for + * now, we'll encode to a malloc'ed buffer, then copy that to a talloc'ed buffer. */ + encoded_tmp=json_dumps(jmsg, 0); // malloc'ed version + json_decref(jmsg); // free the JSON structure + encoded = talloc_strdup(mem_ctx, encoded_tmp); // get the talloc'ed version + free(encoded_tmp); // free the malloc'ed version - encoded=json_dumps(jmsg, 0); tr_debug("tr_msg_encode: outgoing msg=%s", encoded); - json_decref(jmsg); return encoded; } - TR_MSG *tr_msg_decode(const char *jbuf, size_t buflen) + TR_MSG *tr_msg_decode(TALLOC_CTX *mem_ctx, const char *jbuf, size_t buflen) { TR_MSG *msg=NULL; json_t *jmsg = NULL; @@@ -1235,14 -1336,12 +1359,12 @@@ return NULL; } - if (!(msg = malloc(sizeof(TR_MSG)))) { + if (!(msg = talloc_zero(mem_ctx, TR_MSG))) { tr_debug("tr_msg_decode(): Error allocating TR_MSG structure."); json_decref(jmsg); return NULL; } - memset(msg, 0, sizeof(TR_MSG)); - if ((NULL == (jtype = json_object_get(jmsg, "msg_type"))) || (NULL == (jbody = json_object_get(jmsg, "msg_body")))) { tr_debug("tr_msg_decode(): Error parsing message header."); @@@ -1255,19 -1354,28 +1377,28 @@@ if (0 == strcmp(mtype, "tid_request")) { msg->msg_type = TID_REQUEST; - tr_msg_set_req(msg, tr_msg_decode_tidreq(jbody)); + tr_msg_set_req(msg, tr_msg_decode_tidreq(msg, jbody)); } else if (0 == strcmp(mtype, "tid_response")) { msg->msg_type = TID_RESPONSE; - tr_msg_set_resp(msg, tr_msg_decode_tidresp(jbody)); + tr_msg_set_resp(msg, tr_msg_decode_tidresp(msg, jbody)); } else if (0 == strcmp(mtype, "trp_update")) { msg->msg_type = TRP_UPDATE; - tr_msg_set_trp_upd(msg, tr_msg_decode_trp_upd(NULL, jbody)); /* null talloc context for now */ + tr_msg_set_trp_upd(msg, tr_msg_decode_trp_upd(msg, jbody)); } else if (0 == strcmp(mtype, "trp_request")) { msg->msg_type = TRP_UPDATE; - tr_msg_set_trp_req(msg, tr_msg_decode_trp_req(NULL, jbody)); /* null talloc context for now */ + tr_msg_set_trp_req(msg, tr_msg_decode_trp_req(msg, jbody)); + } + else if (0 == strcmp(mtype, "mon_request")) { + msg->msg_type = MON_REQUEST; + tr_msg_set_mon_req(msg, mon_req_decode(msg, jbody)); + } + /* We do not currently handle monitoring responses */ + else if (0 == strcmp(mtype, "mon_response")) { + msg->msg_type = MON_RESPONSE; + tr_msg_set_mon_resp(msg, mon_resp_decode(msg, jbody)); } else { msg->msg_type = TR_UNKNOWN; @@@ -1282,29 -1390,11 +1413,11 @@@ void tr_msg_free_encoded(char *jmsg) { if (jmsg) - free (jmsg); + talloc_free(jmsg); } void tr_msg_free_decoded(TR_MSG *msg) { - if (msg) { - if (msg->msg_rep!=NULL) { - switch (msg->msg_type) { - case TID_REQUEST: - tid_req_free(tr_msg_get_req(msg)); - break; - case TID_RESPONSE: - tid_resp_free(tr_msg_get_resp(msg)); - break; - case TRP_UPDATE: - trp_upd_free(tr_msg_get_trp_upd(msg)); - break; - case TRP_REQUEST: - trp_req_free(tr_msg_get_trp_req(msg)); - default: - break; - } - } - free (msg); - } + if (msg) + talloc_free(msg); } diff --combined include/tid_internal.h index 855df0a,6b6fb78..8613eb8 --- a/include/tid_internal.h +++ b/include/tid_internal.h @@@ -39,6 -39,7 +39,7 @@@ #include #include #include + #include "tr_gss_client.h" struct tid_srvr_blk { TID_SRVR_BLK *next; @@@ -51,7 -52,6 +52,7 @@@ struct tid_resp { TID_RC result; + TR_NAME *request_id; TR_NAME *err_msg; TR_NAME *rp_realm; TR_NAME *realm; @@@ -67,7 -67,6 +68,7 @@@ struct tid_req int resp_sent; int conn; int free_conn; /* free conn and gss ctx*/ + TR_NAME *request_id; gss_ctx_id_t gssctx; int resp_rcvd; TR_NAME *rp_realm; @@@ -84,23 -83,26 +85,26 @@@ }; struct tidc_instance { - // TID_REQ *req_list; - // TBD -- Do we still need a separate private key */ - // char *priv_key; - // int priv_len; - DH *client_dh; /* Client's DH struct with priv and pub keys */ + TR_GSSC_INSTANCE *gssc; + }; + + struct tid_process { + pid_t pid; + int read_fd; }; struct tids_instance { int req_count; + int error_count; char *priv_key; char *ipaddr; const char *hostname; TIDS_REQ_FUNC *req_handler; tids_auth_func *auth_handler; void *cookie; - uint16_t tids_port; + unsigned int tids_port; TR_NAME *gss_name; /* GSS name client used for authentication */ + GArray *pids; /* PIDs of active tids processes */ }; /** Decrement a reference to #json when this tid_req is cleaned up. A @@@ -117,7 -119,10 +121,10 @@@ TID_SRVR_BLK *tid_srvr_blk_add_func(TID #define tid_srvr_blk_add(head, new) ((head)=tid_srvr_blk_add_func((head),(new))) void tid_srvr_blk_set_path(TID_SRVR_BLK *block, TID_PATH *path); + TID_RC tid_resp_cpy(TID_RESP *dst, TID_RESP *src); void tid_resp_set_cons(TID_RESP *resp, TR_CONSTRAINT_SET *cons); void tid_resp_set_error_path(TID_RESP *resp, json_t *ep); + void tids_sweep_procs(TIDS_INSTANCE *tids); + #endif diff --combined include/trust_router/tid.h index 42b97f3,35ec577..38833f1 --- a/include/trust_router/tid.h +++ b/include/trust_router/tid.h @@@ -44,6 -44,7 +44,7 @@@ #include #include + #include #define TID_PORT 12309 @@@ -94,9 -95,7 +95,9 @@@ void tid_req_set_realm(TID_REQ *req, TR TR_EXPORT TR_NAME *tid_req_get_comm(TID_REQ *req); void tid_req_set_comm(TID_REQ *req, TR_NAME *comm); TR_EXPORT TR_NAME *tid_req_get_orig_coi(TID_REQ *req); - void tid_req_set_rp_orig_coi(TID_REQ *req, TR_NAME *orig_coi); + void tid_req_set_orig_coi(TID_REQ *req, TR_NAME *orig_coi); +TR_EXPORT TR_NAME *tid_req_get_request_id(TID_REQ *req); +void tid_req_set_request_id(TID_REQ *req, TR_NAME *request_id); TR_EXPORT TIDC_RESP_FUNC *tid_req_get_resp_func(TID_REQ *req); void tid_req_set_resp_func(TID_REQ *req, TIDC_RESP_FUNC *resp_func); TR_EXPORT void *tid_req_get_cookie(TID_REQ *req); @@@ -121,8 -120,6 +122,8 @@@ TR_EXPORT TR_NAME *tid_resp_get_comm(TI void tid_resp_set_comm(TID_RESP *resp, TR_NAME *comm); 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 TR_NAME *tid_resp_get_request_id(TID_RESP *resp); +void tid_resp_set_request_id(TID_RESP *resp, TR_NAME *request_id); 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 *); @@@ -140,9 -137,9 +141,9 @@@ TR_EXPORT const TID_PATH *tid_srvr_get_ TR_EXPORT int tid_srvr_get_key_expiration(const TID_SRVR_BLK *, struct timeval *tv_out); #define tid_resp_servers_foreach(RESP, SERVER, INDEX) \ - for (INDEX=0,SERVER=NULL; \ - ((INDEX < tid_resp_get_num_servers(RESP))&&(SERVER = tid_resp_get_server(resp, INDEX))); \ - INDEX++) + for ((INDEX)=0,(SERVER)=NULL; \ + (((INDEX) < tid_resp_get_num_servers(RESP))&&((SERVER) = tid_resp_get_server(resp, (INDEX)))); \ + (INDEX)++) /* TID Client functions, in tid/tidc.c */ @@@ -155,13 -152,14 +156,14 @@@ TR_EXPORT DH *tidc_set_dh(TIDC_INSTANC TR_EXPORT void tidc_destroy(TIDC_INSTANCE *tidc); /* TID Server functions, in tid/tids.c */ + TIDS_INSTANCE *tids_new(TALLOC_CTX *mem_ctx); TR_EXPORT TIDS_INSTANCE *tids_create (void); TR_EXPORT int tids_start (TIDS_INSTANCE *tids, TIDS_REQ_FUNC *req_handler, tids_auth_func *auth_handler, const char *hostname, unsigned int port, void *cookie); - TR_EXPORT int tids_get_listener (TIDS_INSTANCE *tids, TIDS_REQ_FUNC *req_handler, - tids_auth_func *auth_handler, const char *hostname, - unsigned int port, void *cookie, int *fd_out, size_t max_fd); + TR_EXPORT nfds_t tids_get_listener(TIDS_INSTANCE *tids, TIDS_REQ_FUNC *req_handler, + tids_auth_func *auth_handler, const char *hostname, + unsigned int port, void *cookie, int *fd_out, size_t max_fd); TR_EXPORT int tids_accept(TIDS_INSTANCE *tids, int listen); TR_EXPORT int tids_send_response (TIDS_INSTANCE *tids, TID_REQ *req, TID_RESP *resp); TR_EXPORT int tids_send_err_response (TIDS_INSTANCE *tids, TID_REQ *req, const char *err_msg); diff --combined tid/tid_req.c index 967b1fc,88dd991..002b720 --- a/tid/tid_req.c +++ b/tid/tid_req.c @@@ -63,8 -63,6 +63,8 @@@ static int destroy_tid_req(TID_REQ *req tr_free_name(req->comm); if (req->orig_coi!=NULL) tr_free_name(req->orig_coi); + if (req->request_id!=NULL) + tr_free_name(req->request_id); return 0; } @@@ -78,7 -76,6 +78,7 @@@ TID_REQ *tid_req_new( assert(req->json_references); req->conn = -1; req->free_conn = 1; + req->request_id = NULL; return req; } @@@ -167,21 -164,11 +167,21 @@@ TR_NAME *tid_req_get_orig_coi(TID_REQ * return(req->orig_coi); } - void tid_req_set_rp_orig_coi(TID_REQ *req, TR_NAME *orig_coi) + void tid_req_set_orig_coi(TID_REQ *req, TR_NAME *orig_coi) { req->orig_coi = orig_coi; } +void tid_req_set_request_id(TID_REQ *req, TR_NAME *request_id) +{ + req->request_id = request_id; +} + +TR_NAME *tid_req_get_request_id(TID_REQ *req) +{ + return(req->request_id); +} + TIDC_RESP_FUNC *tid_req_get_resp_func(TID_REQ *req) { return(req->resp_func); @@@ -228,13 -215,7 +228,13 @@@ TID_REQ *tid_dup_req (TID_REQ *orig_req tr_crit("tid_dup_req: Can't duplicate request (orig_coi)."); } } - + + if (orig_req->request_id) { + if (NULL == (new_req->request_id = tr_dup_name(orig_req->request_id))) { + tr_crit("tid_dup_req: Can't duplicate request (request_id)."); + } + } + return new_req; } diff --combined tid/tid_resp.c index 4f46b12,dbbc906..3ff3d02 --- a/tid/tid_resp.c +++ b/tid/tid_resp.c @@@ -53,8 -53,6 +53,8 @@@ static int tid_resp_destructor(void *ob tr_free_name(resp->comm); if (resp->orig_coi!=NULL) tr_free_name(resp->orig_coi); + if (resp->request_id!=NULL) + tr_free_name(resp->request_id); return 0; } @@@ -70,7 -68,6 +70,7 @@@ TID_RESP *tid_resp_new(TALLOC_CTX *mem_ resp->cons=NULL; resp->orig_coi=NULL; resp->servers=NULL; + resp->request_id=NULL; resp->error_path=NULL; talloc_set_destructor((void *)resp, tid_resp_destructor); } @@@ -83,6 -80,13 +83,13 @@@ void tid_resp_free(TID_RESP *resp talloc_free(resp); } + /** + * Allocate a new copy of a TID_RESP + * + * @param mem_ctx + * @param resp + * @return + */ TID_RESP *tid_resp_dup(TALLOC_CTX *mem_ctx, TID_RESP *resp) { TID_RESP *newresp=NULL; @@@ -93,18 -97,37 +100,37 @@@ newresp=tid_resp_new(mem_ctx); if (NULL!=newresp) { - newresp->result=resp->result; - newresp->err_msg=tr_dup_name(resp->err_msg); - newresp->rp_realm=tr_dup_name(resp->rp_realm); - newresp->realm=tr_dup_name(resp->realm); - newresp->comm=tr_dup_name(resp->comm); - newresp->orig_coi=tr_dup_name(resp->orig_coi); - newresp->servers=tid_srvr_blk_dup(newresp, resp->servers); - tid_resp_set_cons(newresp, resp->cons); - tid_resp_set_error_path(newresp, resp->error_path); + tid_resp_cpy(newresp, resp); } return newresp; } + + /** + * Copy contents of one TID_RESP to an existing TID_RESP + * + * @param dst + * @param src + * @return TID_SUCCESS on success, error code on error + */ + TID_RC tid_resp_cpy(TID_RESP *dst, TID_RESP *src) + { + tid_resp_set_result(dst, tid_resp_get_result(src)); + tid_resp_set_err_msg(dst, + tr_dup_name(tid_resp_get_err_msg(src))); + tid_resp_set_rp_realm(dst, + tr_dup_name(tid_resp_get_rp_realm(src))); + tid_resp_set_realm(dst, + tr_dup_name(tid_resp_get_realm(src))); + tid_resp_set_comm(dst, + tr_dup_name(tid_resp_get_comm(src))); + tid_resp_set_cons(dst, src->cons); + tid_resp_set_orig_coi(dst, + tr_dup_name(tid_resp_get_orig_coi(src))); + dst->servers = tid_srvr_blk_dup(dst, src->servers); + tid_resp_set_error_path(dst, src->error_path); + + return TID_SUCCESS; + } TR_EXPORT int tid_resp_get_result(TID_RESP *resp) { @@@ -169,16 -192,6 +195,16 @@@ void tid_resp_set_orig_coi(TID_RESP *re resp->orig_coi = orig_coi; } +TR_EXPORT TR_NAME *tid_resp_get_request_id(TID_RESP *resp) +{ + return(resp->request_id); +} + +void tid_resp_set_request_id(TID_RESP *resp, TR_NAME *request_id) +{ + resp->request_id = request_id; +} + TR_EXPORT TID_SRVR_BLK *tid_resp_get_server(TID_RESP *resp, size_t index) { diff --combined tid/tidc.c index 320ded6,94cd98d..90335f0 --- a/tid/tidc.c +++ b/tid/tidc.c @@@ -36,33 -36,27 +36,28 @@@ #include #include + #include #include #include #include - #include #include +#include int tmp_len = 32; - static int tidc_destructor(void *obj) - { - TIDC_INSTANCE *tidc=talloc_get_type_abort(obj, TIDC_INSTANCE); - if (NULL!=tidc) { - if (NULL!=tidc->client_dh) - tr_destroy_dh_params(tidc->client_dh); - } - return 0; - } - /* creates struct in talloc null context */ TIDC_INSTANCE *tidc_create(void) { TIDC_INSTANCE *tidc=talloc(NULL, TIDC_INSTANCE); if (tidc!=NULL) { - tidc->client_dh=NULL; - talloc_set_destructor((void *)tidc, tidc_destructor); + tidc->gssc = tr_gssc_instance_new(tidc); + if (tidc->gssc == NULL) { + talloc_free(tidc); + return NULL; + } + + tidc->gssc->service_name = "trustidentity"; } return tidc; } @@@ -73,44 -67,55 +68,56 @@@ void tidc_destroy(TIDC_INSTANCE *tidc } int tidc_open_connection (TIDC_INSTANCE *tidc, - const char *server, - unsigned int port, - gss_ctx_id_t *gssctx) + const char *server, + unsigned int port, + gss_ctx_id_t *gssctx) { - int err = 0; - int conn = -1; unsigned int use_port = 0; + tidc->gssc->gss_ctx = gssctx; if (0 == port) use_port = TID_PORT; else use_port = port; - tr_debug("tidc_open_connection: opening tidc connection to %s:%d", server, port); - err = gsscon_connect(server, use_port, "trustidentity", &conn, gssctx); - - if (!err) - return conn; + tr_debug("tidc_open_connection: opening tidc connection to %s:%d", server, use_port); + if (0 == tr_gssc_open_connection(tidc->gssc, server, use_port)) + return tidc->gssc->conn; else return -1; } int tidc_send_request (TIDC_INSTANCE *tidc, - int conn, - gss_ctx_id_t gssctx, - const char *rp_realm, - const char *realm, - const char *comm, - TIDC_RESP_FUNC *resp_handler, - void *cookie) + int conn, + gss_ctx_id_t gssctx, + const char *rp_realm, + const char *realm, + const char *comm, + TIDC_RESP_FUNC *resp_handler, + void *cookie) { TID_REQ *tid_req = NULL; + char *request_id = NULL; int rc; + int orig_conn = 0; + gss_ctx_id_t *orig_gss_ctx = NULL; + + /* For ABI compatibility, replace the generic GSS client parameters + * with the arguments we were passed. */ + orig_conn = tidc->gssc->conn; /* save to restore later */ + if (conn != tidc->gssc->conn) { + tr_warning("tidc_send_request: WARNING: socket connection FD does not match FD opened by tidc_open_connection()"); + tidc->gssc->conn = conn; + } + orig_gss_ctx = tidc->gssc->gss_ctx; /* save to restore later */ + if (gssctx != *(tidc->gssc->gss_ctx)) { + tr_warning("tidc_send_request: WARNING: sending request with different GSS context than used for tidc_open_connection()"); + *tidc->gssc->gss_ctx = gssctx; + } /* Create and populate a TID req structure */ if (!(tid_req = tid_req_new())) - return -1; + goto error; tid_req->conn = conn; tid_req->gssctx = gssctx; @@@ -122,25 -127,18 +129,29 @@@ goto error; } - tid_req->tidc_dh = tr_dh_dup(tidc->client_dh); + tid_req->tidc_dh = tr_dh_dup(tidc->gssc->client_dh); + /* generate an ID */ + request_id = tr_random_id(NULL); + if (request_id) { + if (tid_req->request_id = tr_new_name(request_id)) + tr_debug("tidc_send_request: Created TID request ID: %s", request_id); + else + tr_debug("tidc_send_request: Unable to set request ID, proceeding without one"); + talloc_free(request_id); + } else + tr_debug("tidc_send_request: Failed to generate a TID request ID, proceeding without one"); + rc = tidc_fwd_request(tidc, tid_req, resp_handler, cookie); goto cleanup; error: rc = -1; cleanup: - tid_req_free(tid_req); + if (tid_req) + tid_req_free(tid_req); + + tidc->gssc->conn = orig_conn; + tidc->gssc->gss_ctx = orig_gss_ctx; return rc; } @@@ -149,83 -147,32 +160,49 @@@ int tidc_fwd_request(TIDC_INSTANCE *tid TIDC_RESP_FUNC *resp_handler, void *cookie) { - char *req_buf = NULL; - char *resp_buf = NULL; - size_t resp_buflen = 0; + TALLOC_CTX *tmp_ctx = talloc_new(NULL); TR_MSG *msg = NULL; TR_MSG *resp_msg = NULL; + TID_RESP *tid_resp = NULL; - int err; int rc = 0; /* Create and populate a TID msg structure */ - if (!(msg = talloc_zero(tid_req, TR_MSG))) + if (!(msg = talloc_zero(tmp_ctx, TR_MSG))) goto error; msg->msg_type = TID_REQUEST; tr_msg_set_req(msg, tid_req); - /* store the response function and cookie */ - // tid_req->resp_func = resp_handler; - // tid_req->cookie = cookie; - - /* Encode the request into a json string */ - if (!(req_buf = tr_msg_encode(msg))) { - tr_err("tidc_fwd_request: Error encoding TID request.\n"); - goto error; - } - - tr_debug( "tidc_fwd_request: Sending TID request:\n"); - tr_debug( "%s\n", req_buf); + tr_debug( "tidc_fwd_request: Sending TID request\n"); /* Send the request over the connection */ - if (err = gsscon_write_encrypted_token (tid_req->conn, tid_req->gssctx, req_buf, - strlen(req_buf))) { - tr_err( "tidc_fwd_request: Error sending request over connection.\n"); + resp_msg = tr_gssc_exchange_msgs(tmp_ctx, tidc->gssc, msg); + if (resp_msg == NULL) goto error; - } - - /* TBD -- queue request on instance, read resps in separate thread */ - - /* Read the response from the connection */ - /* TBD -- timeout? */ - if (err = gsscon_read_encrypted_token(tid_req->conn, tid_req->gssctx, &resp_buf, &resp_buflen)) { - if (resp_buf) - free(resp_buf); - goto error; - } - - tr_debug( "tidc_fwd_request: Response Received (%u bytes).\n", (unsigned) resp_buflen); - tr_debug( "%s\n", resp_buf); - - if (NULL == (resp_msg = tr_msg_decode(resp_buf, resp_buflen))) { - tr_err( "tidc_fwd_request: Error decoding response.\n"); - goto error; - } /* TBD -- Check if this is actually a valid response */ - if (TID_RESPONSE != tr_msg_get_msg_type(resp_msg)) { + tid_resp = tr_msg_get_resp(resp_msg); + if (tid_resp == NULL) { tr_err( "tidc_fwd_request: Error, no response in the response!\n"); goto error; } + /* Check whether the request IDs matched and warn if not. Do nothing if we don't get + * an ID on the return - it is not mandatory to preserve that field. */ + if (tid_req->request_id) { + if ((tid_resp->request_id) + && (tr_name_cmp(tid_resp->request_id, tid_req->request_id) != 0)) { + /* Requests present but do not match */ + tr_warning("tidc_fwd_request: Sent request ID %.*s, received response for %.*s", + tid_req->request_id->len, tid_req->request_id->buf, + tid_resp->request_id->len, tid_resp->request_id->buf); + } + } else if (tid_resp->request_id) { + tr_warning("tidc_fwd_request: Sent request without ID, received response for %.*s", + tid_resp->request_id->len, tid_resp->request_id->buf); + } + if (resp_handler) { /* Call the caller's response function. It must copy any data it needs before returning. */ tr_debug("tidc_fwd_request: calling response callback function."); @@@ -237,25 -184,17 +214,17 @@@ error: rc = -1; cleanup: - if (msg) - talloc_free(msg); - if (req_buf) - free(req_buf); - if (resp_buf) - free(resp_buf); - if (resp_msg) - tr_msg_free_decoded(resp_msg); + talloc_free(tmp_ctx); return rc; } DH * tidc_get_dh(TIDC_INSTANCE *inst) { - return inst->client_dh; + return tr_gssc_get_dh(inst->gssc); } DH *tidc_set_dh(TIDC_INSTANCE *inst, DH *dh) { - inst->client_dh = dh; - return dh; + return tr_gssc_set_dh(inst->gssc, dh); } diff --combined tid/tids.c index 8d22749,6a5b172..9b9d51f --- a/tid/tids.c +++ b/tid/tids.c @@@ -32,16 -32,13 +32,13 @@@ * */ - #include #include #include #include #include #include - #include #include #include - #include #include #include #include @@@ -49,13 -46,23 +46,23 @@@ #include #include #include + #include + #include + #include - static TID_RESP *tids_create_response (TIDS_INSTANCE *tids, TID_REQ *req) + /** + * Create a response with minimal fields filled in + * + * @param mem_ctx talloc context for the return value + * @param req request to respond to + * @return new response structure allocated in the mem_ctx context + */ + static TID_RESP *tids_create_response(TALLOC_CTX *mem_ctx, TID_REQ *req) { TID_RESP *resp=NULL; int success=0; - if (NULL == (resp = tid_resp_new(req))) { + if (NULL == (resp = tid_resp_new(mem_ctx))) { tr_crit("tids_create_response: Error allocating response structure."); return NULL; } @@@ -73,12 -80,6 +80,12 @@@ goto cleanup; } } + if (req->request_id) { + if (NULL == (resp->request_id = tr_dup_name(req->request_id))) { + tr_crit("tids_create_response: Error allocating fields in response."); + goto cleanup; + } + } success=1; @@@ -90,250 -91,137 +97,137 @@@ cleanup return resp; } - static int tids_listen(TIDS_INSTANCE *tids, int port, int *fd_out, size_t max_fd) - { - int rc = 0; - int conn = -1; - int optval = 1; - struct addrinfo *ai=NULL; - struct addrinfo *ai_head=NULL; - struct addrinfo hints={.ai_flags=AI_PASSIVE, - .ai_family=AF_UNSPEC, - .ai_socktype=SOCK_STREAM, - .ai_protocol=IPPROTO_TCP}; - char *port_str=NULL; - size_t n_opened=0; - - tr_debug("tids_listen: started!"); - port_str=talloc_asprintf(NULL, "%d", port); - if (port_str==NULL) { - tr_debug("tids_listen: unable to allocate port."); - return -1; - } - - tr_debug("getaddrinfo()=%d", getaddrinfo(NULL, port_str, &hints, &ai_head)); - talloc_free(port_str); - tr_debug("tids_listen: got address info"); - - /* TODO: listen on all ports */ - for (ai=ai_head,n_opened=0; (ai!=NULL)&&(n_openedai_next) { - if (0 > (conn = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))) { - tr_debug("tids_listen: unable to open socket."); - continue; - } - - optval=1; - if (0!=setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))) - tr_debug("tids_listen: unable to set SO_REUSEADDR."); /* not fatal? */ - - if (ai->ai_family==AF_INET6) { - /* don't allow IPv4-mapped IPv6 addresses (per RFC4942, not sure - * if still relevant) */ - if (0!=setsockopt(conn, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval))) { - tr_debug("tids_listen: unable to set IPV6_V6ONLY. Skipping interface."); - close(conn); - continue; - } - } - - rc=bind(conn, ai->ai_addr, ai->ai_addrlen); - if (rc<0) { - tr_debug("tids_listen: unable to bind to socket."); - close(conn); - continue; - } - - if (0>listen(conn, 512)) { - tr_debug("tids_listen: unable to listen on bound socket."); - close(conn); - continue; - } - - /* ok, this one worked. Save it */ - fd_out[n_opened++]=conn; - } - freeaddrinfo(ai_head); - - if (n_opened==0) { - tr_debug("tids_listen: no addresses available for listening."); - return -1; - } - - tr_debug("tids_listen: TRP Server listening on port %d on %d socket%s", - port, - n_opened, - (n_opened==1)?"":"s"); - - return n_opened; - } - - /* returns EACCES if authorization is denied */ - static int tids_auth_cb(gss_name_t clientName, gss_buffer_t displayName, - void *data) - { - struct tids_instance *inst = (struct tids_instance *) data; - TR_NAME name ={(char *) displayName->value, - displayName->length}; - int result=0; - - if (0!=inst->auth_handler(clientName, &name, inst->cookie)) { - tr_debug("tids_auth_cb: client '%.*s' denied authorization.", name.len, name.buf); - result=EACCES; /* denied */ - } - - return result; - } - - /* returns 0 on authorization success, 1 on failure, or -1 in case of error */ - static int tids_auth_connection (TIDS_INSTANCE *inst, - int conn, - gss_ctx_id_t *gssctx) - { - int rc = 0; - int auth, autherr = 0; - gss_buffer_desc nameBuffer = {0, NULL}; - char *name = 0; - int nameLen = 0; - - nameLen = asprintf(&name, "trustidentity@%s", inst->hostname); - nameBuffer.length = nameLen; - nameBuffer.value = name; - - if (rc = gsscon_passive_authenticate(conn, nameBuffer, gssctx, tids_auth_cb, inst)) { - tr_debug("tids_auth_connection: Error from gsscon_passive_authenticate(), rc = %d.", rc); - free(name); - return -1; - } - free(name); - nameBuffer.value=NULL; nameBuffer.length=0; - - if (rc = gsscon_authorize(*gssctx, &auth, &autherr)) { - tr_debug("tids_auth_connection: Error from gsscon_authorize, rc = %d, autherr = %d.", - rc, autherr); - return -1; - } - - if (auth) - tr_debug("tids_auth_connection: Connection authenticated, conn = %d.", conn); - else - tr_debug("tids_auth_connection: Authentication failed, conn %d.", conn); - - return !auth; - } - - static int tids_read_request (TIDS_INSTANCE *tids, int conn, gss_ctx_id_t *gssctx, TR_MSG **mreq) - { - int err; - char *buf; - size_t buflen = 0; - - if (err = gsscon_read_encrypted_token(conn, *gssctx, &buf, &buflen)) { - if (buf) - free(buf); - return -1; - } - - tr_debug("tids_read_request():Request Received, %u bytes.", (unsigned) buflen); - - /* Parse request */ - if (NULL == ((*mreq) = tr_msg_decode(buf, buflen))) { - tr_debug("tids_read_request():Error decoding request."); - free (buf); - return -1; - } - - /* If this isn't a TID Request, just drop it. */ - if (TID_REQUEST != (*mreq)->msg_type) { - tr_debug("tids_read_request(): Not a TID Request, dropped."); - return -1; - } - - free (buf); - return buflen; - } - - static int tids_handle_request (TIDS_INSTANCE *tids, TR_MSG *mreq, TID_RESP *resp) + static int tids_handle_request(TIDS_INSTANCE *tids, TID_REQ *req, TID_RESP *resp) { int rc=-1; /* Check that this is a valid TID Request. If not, send an error return. */ - if ((!tr_msg_get_req(mreq)) || - (!tr_msg_get_req(mreq)->rp_realm) || - (!tr_msg_get_req(mreq)->realm) || - (!tr_msg_get_req(mreq)->comm)) { + if ((!req) || + (!(req->rp_realm)) || + (!(req->realm)) || + (!(req->comm))) { tr_notice("tids_handle_request(): Not a valid TID Request."); - resp->result = TID_ERROR; - resp->err_msg = tr_new_name("Bad request format"); + tid_resp_set_result(resp, TID_ERROR); + tid_resp_set_err_msg(resp, tr_new_name("Bad request format")); return -1; } tr_debug("tids_handle_request: adding self to req path."); - tid_req_add_path(tr_msg_get_req(mreq), tids->hostname, tids->tids_port); + tid_req_add_path(req, tids->hostname, tids->tids_port); /* Call the caller's request handler */ /* TBD -- Handle different error returns/msgs */ - if (0 > (rc = (*tids->req_handler)(tids, tr_msg_get_req(mreq), resp, tids->cookie))) { + if (0 > (rc = (*tids->req_handler)(tids, req, resp, tids->cookie))) { /* set-up an error response */ tr_debug("tids_handle_request: req_handler returned error."); - resp->result = TID_ERROR; - if (!resp->err_msg) /* Use msg set by handler, if any */ - resp->err_msg = tr_new_name("Internal processing error"); - } - else { + tid_resp_set_result(resp, TID_ERROR); + if (!tid_resp_get_err_msg(resp)) /* Use msg set by handler, if any */ + tid_resp_set_err_msg(resp, tr_new_name("Internal processing error")); + } else { /* set-up a success response */ tr_debug("tids_handle_request: req_handler returned success."); - resp->result = TID_SUCCESS; + tid_resp_set_result(resp, TID_SUCCESS); resp->err_msg = NULL; /* No error msg on successful return */ } return rc; } + /** + * Produces a JSON-encoded msg containing the TID response + * + * @param mem_ctx talloc context for the return value + * @param resp outgoing response + * @return JSON-encoded message containing the TID response + */ + static char *tids_encode_response(TALLOC_CTX *mem_ctx, TID_RESP *resp) + { + TR_MSG mresp; + char *resp_buf = NULL; + + /* Construct the response message */ + mresp.msg_type = TID_RESPONSE; + tr_msg_set_resp(&mresp, resp); + + /* Encode the message to JSON */ + resp_buf = tr_msg_encode(mem_ctx, &mresp); + if (resp_buf == NULL) { + tr_err("tids_encode_response: Error encoding json response."); + return NULL; + } + tr_debug("tids_encode_response: Encoded response: %s", resp_buf); + + /* Success */ + return resp_buf; + } + + /** + * Encode/send an error response + * + * Part of the public interface + * + * @param tids + * @param req + * @param err_msg + * @return + */ int tids_send_err_response (TIDS_INSTANCE *tids, TID_REQ *req, const char *err_msg) { TID_RESP *resp = NULL; int rc = 0; + if ((!tids) || (!req) || (!err_msg)) { + tr_debug("tids_send_err_response: Invalid parameters."); + return -1; + } + /* If we already sent a response, don't send another no matter what. */ if (req->resp_sent) return 0; - if (NULL == (resp = tids_create_response(tids, req))) { + if (NULL == (resp = tids_create_response(req, req))) { tr_crit("tids_send_err_response: Can't create response."); return -1; } - + /* mark this as an error response, and include the error message */ resp->result = TID_ERROR; resp->err_msg = tr_new_name((char *)err_msg); resp->error_path = req->path; rc = tids_send_response(tids, req, resp); - + tid_resp_free(resp); return rc; } + /** + * Encode/send a response + * + * Part of the public interface + * + * @param tids not actually used, but kept for ABI compatibility + * @param req + * @param resp + * @return + */ int tids_send_response (TIDS_INSTANCE *tids, TID_REQ *req, TID_RESP *resp) { int err; - TR_MSG mresp; char *resp_buf; - if ((!tids) || (!req) || (!resp)) + if ((!tids) || (!req) || (!resp)) { tr_debug("tids_send_response: Invalid parameters."); + return -1; + } /* Never send a second response if we already sent one. */ if (req->resp_sent) return 0; - mresp.msg_type = TID_RESPONSE; - tr_msg_set_resp(&mresp, resp); - - if (NULL == (resp_buf = tr_msg_encode(&mresp))) { - + resp_buf = tids_encode_response(NULL, NULL); + if (resp_buf == NULL) { tr_err("tids_send_response: Error encoding json response."); tr_audit_req(req); - return -1; } @@@ -344,12 -232,11 +238,11 @@@ tr_audit_resp(resp); /* Send the response over the connection */ - if (err = gsscon_write_encrypted_token (req->conn, req->gssctx, resp_buf, - strlen(resp_buf) + 1)) { + err = gsscon_write_encrypted_token (req->conn, req->gssctx, resp_buf, + strlen(resp_buf) + 1); + if (err) { tr_notice("tids_send_response: Error sending response over connection."); - tr_audit_req(req); - return -1; } @@@ -361,83 -248,119 +254,119 @@@ return 0; } - static void tids_handle_connection (TIDS_INSTANCE *tids, int conn) + /** + * Callback to process a request and produce a response + * + * @param req_str JSON-encoded request + * @param data pointer to a TIDS_INSTANCE + * @return pointer to the response string or null to send no response + */ + static TR_MSG *tids_req_cb(TALLOC_CTX *mem_ctx, TR_MSG *mreq, void *data) { - TR_MSG *mreq = NULL; + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + TIDS_INSTANCE *tids = talloc_get_type_abort(data, TIDS_INSTANCE); + TID_REQ *req = NULL; TID_RESP *resp = NULL; + TR_MSG *resp_msg = NULL; /* this is the return value */ int rc = 0; - gss_ctx_id_t gssctx = GSS_C_NO_CONTEXT; - if (tids_auth_connection(tids, conn, &gssctx)) { - tr_notice("tids_handle_connection: Error authorizing TID Server connection."); - close(conn); - return; + /* If this isn't a TID Request, just drop it. */ + if (mreq->msg_type != TID_REQUEST) { + tr_debug("tids_req_cb: Not a TID request, dropped."); + goto cleanup; } - tr_debug("tids_handle_connection: Connection authorized!"); + /* Get a handle on the request itself. Don't free req - it belongs to mreq */ + req = tr_msg_get_req(mreq); - while (1) { /* continue until an error breaks us out */ + /* Allocate a response message */ + resp_msg = talloc(tmp_ctx, TR_MSG); + if (resp_msg == NULL) { + /* We cannot create a response message, so all we can really do is emit + * an error message and return. */ + tr_crit("tids_req_cb: Error allocating response message."); + goto cleanup; + } - if (0 > (rc = tids_read_request(tids, conn, &gssctx, &mreq))) { - tr_debug("tids_handle_connection: Error from tids_read_request(), rc = %d.", rc); - return; - } else if (0 == rc) { - continue; - } + /* Allocate a response structure and populate common fields. Put it in the + * response message's talloc context. */ + resp = tids_create_response(resp_msg, req); + if (resp == NULL) { + /* If we were unable to create a response, we cannot reply. Log an + * error if we can, then drop the request. */ + tr_crit("tids_req_cb: Error creating response structure."); + resp_msg = NULL; /* the contents are in tmp_ctx, so they will still be cleaned up */ + goto cleanup; + } + /* Now officially assign the response to the message. */ + tr_msg_set_resp(resp_msg, resp); + + /* Handle the request and fill in resp */ + rc = tids_handle_request(tids, req, resp); + if (rc < 0) { + tr_debug("tids_req_cb: Error from tids_handle_request(), rc = %d.", rc); + /* Fall through, to send the response, either way */ + } - /* Put connection information into the request structure */ - tr_msg_get_req(mreq)->conn = conn; - tr_msg_get_req(mreq)->gssctx = gssctx; - - /* Allocate a response structure and populate common fields */ - if (NULL == (resp = tids_create_response (tids, tr_msg_get_req(mreq)))) { - tr_crit("tids_handle_connection: Error creating response structure."); - /* try to send an error */ - tids_send_err_response(tids, tr_msg_get_req(mreq), "Error creating response."); - tr_msg_free_decoded(mreq); - return; - } + /* put the response message in the caller's context */ + talloc_steal(mem_ctx, resp_msg); - if (0 > (rc = tids_handle_request(tids, mreq, resp))) { - tr_debug("tids_handle_connection: Error from tids_handle_request(), rc = %d.", rc); - /* Fall through, to send the response, either way */ - } + cleanup: + talloc_free(tmp_ctx); + return resp_msg; + } - if (0 > (rc = tids_send_response(tids, tr_msg_get_req(mreq), resp))) { - tr_debug("tids_handle_connection: Error from tids_send_response(), rc = %d.", rc); - /* if we didn't already send a response, try to send a generic error. */ - if (!tr_msg_get_req(mreq)->resp_sent) - tids_send_err_response(tids, tr_msg_get_req(mreq), "Error sending response."); - /* Fall through to free the response, either way. */ + static int tids_destructor(void *object) + { + TIDS_INSTANCE *tids = talloc_get_type_abort(object, TIDS_INSTANCE); + if (tids->pids) + g_array_unref(tids->pids); + return 0; + } + + TIDS_INSTANCE *tids_new(TALLOC_CTX *mem_ctx) + { + TIDS_INSTANCE *tids = talloc_zero(mem_ctx, TIDS_INSTANCE); + if (tids) { + tids->pids = g_array_new(FALSE, FALSE, sizeof(struct tid_process)); + if (tids->pids == NULL) { + talloc_free(tids); + return NULL; } - - tr_msg_free_decoded(mreq); /* takes resp with it */ - return; - } + talloc_set_destructor((void *)tids, tids_destructor); + } + return tids; } - TIDS_INSTANCE *tids_create (void) + /** + * Create a new TIDS instance + * + * Deprecated: exists for ABI compatibility, but tids_new() should be used instead + * + */ + TIDS_INSTANCE *tids_create(void) { - return talloc_zero(NULL, TIDS_INSTANCE); + return tids_new(NULL); } /* Get a listener for tids requests, returns its socket fd. Accept * connections with tids_accept() */ - int tids_get_listener(TIDS_INSTANCE *tids, - TIDS_REQ_FUNC *req_handler, - tids_auth_func *auth_handler, - const char *hostname, - unsigned int port, - void *cookie, - int *fd_out, - size_t max_fd) + nfds_t tids_get_listener(TIDS_INSTANCE *tids, + TIDS_REQ_FUNC *req_handler, + tids_auth_func *auth_handler, + const char *hostname, + unsigned int port, + void *cookie, + int *fd_out, + size_t max_fd) { - size_t n_fd=0; - size_t ii=0; + nfds_t n_fd = 0; + nfds_t ii = 0; tids->tids_port = port; - n_fd=tids_listen(tids, port, fd_out, max_fd); - if (n_fd<=0) + n_fd = tr_sock_listen_all(port, fd_out, max_fd); + + if (n_fd == 0) tr_err("tids_get_listener: Error opening port %d"); else { /* opening port succeeded */ @@@ -451,13 -374,13 +380,13 @@@ close(fd_out[ii]); fd_out[ii]=-1; } - n_fd=0; + n_fd = 0; break; } } } - if (n_fd>0) { + if (n_fd > 0) { /* store the caller's request handler & cookie */ tids->req_handler = req_handler; tids->auth_handler = auth_handler; @@@ -465,7 -388,7 +394,7 @@@ tids->cookie = cookie; } - return n_fd; + return (int)n_fd; } /* Accept and process a connection on a port opened with tids_get_listener() */ @@@ -473,47 -396,137 +402,137 @@@ int tids_accept(TIDS_INSTANCE *tids, in { int conn=-1; int pid=-1; + int pipe_fd[2]; + struct tid_process tp = {0}; if (0 > (conn = accept(listen, NULL, NULL))) { perror("Error from TIDS Server accept()"); return 1; } + if (0 > pipe(pipe_fd)) { + perror("Error on pipe()"); + return 1; + } + /* pipe_fd[0] is for reading, pipe_fd[1] is for writing */ + if (0 > (pid = fork())) { perror("Error on fork()"); return 1; } if (pid == 0) { + close(pipe_fd[0]); /* child only writes */ close(listen); - tids_handle_connection(tids, conn); + tr_gss_handle_connection(conn, + "trustidentity", tids->hostname, /* acceptor name */ + tids->auth_handler, tids->cookie, /* auth callback and cookie */ + tids_req_cb, tids /* req callback and cookie */ + ); + if (write(pipe_fd[1], "OK\0", 3) < 0) + tr_crit("tids_accept: child process unable to write to pipe"); + close(pipe_fd[1]); close(conn); exit(0); /* exit to kill forked child process */ - } else { - close(conn); } - /* clean up any processes that have completed (TBD: move to main loop?) */ - while (waitpid(-1, 0, WNOHANG) > 0); + /* Only the parent process gets here */ + close(pipe_fd[1]); /* parent only listens */ + close(conn); /* connection belongs to the child */ + tp.pid = pid; + tp.read_fd = pipe_fd[0]; + g_array_append_val(tids->pids, tp); /* remember the PID of our child process */ + /* clean up any processes that have completed */ + tids_sweep_procs(tids); return 0; } + /** + * Clean up any finished TID request processes + * + * This is called by the main process after forking each TID request. If you want to be + * sure finished processes are cleaned up promptly even during a lull in TID requests, + * this can be called from the main thread of the main process. It is not thread-safe, + * so should not be used from sub-threads. It should not be called by child processes - + * this would probably be harmless but ineffective. + * + * @param tids + */ + void tids_sweep_procs(TIDS_INSTANCE *tids) + { + guint ii; + struct tid_process tp = {0}; + char result[10] = {0}; + ssize_t result_len; + int status; + int wait_rc; + + /* loop backwards over the array so we can remove elements as we go */ + for (ii=tids->pids->len; ii > 0; ii--) { + /* ii-1 is the current index - get our own copy, we may destroy the list's copy */ + tp = g_array_index(tids->pids, struct tid_process, ii-1); + + wait_rc = waitpid(tp.pid, &status, WNOHANG); + if (wait_rc == 0) + continue; /* process still running */ + + if (wait_rc < 0) { + /* invalid options will probably keep being invalid, report that condition */ + if(errno == EINVAL) + tr_crit("tids_sweep_procs: waitpid called with invalid options"); + + /* If we got ECHILD, that means the PID was invalid; we'll assume the process was + * terminated and we missed it. For all other errors, move on + * to the next PID to check. */ + if (errno != ECHILD) + continue; + + tr_warning("tid_sweep_procs: TID process %d disappeared", tp.pid); + } + + /* remove the item (we still have a copy of the data) */ + g_array_remove_index_fast(tids->pids, ii-1); /* disturbs only indices >= ii-1 which we've already handled */ + + /* Report exit status unless we got ECHILD above or somehow waitpid returned the wrong pid */ + if (wait_rc == tp.pid) { + if (WIFEXITED(status)) { + tr_debug("tids_sweep_procs: TID process %d exited with status %d.", tp.pid, WTERMSIG(status)); + } else if (WIFSIGNALED(status)) { + tr_debug("tids_sweep_procs: TID process %d terminated by signal %d.", tp.pid, WTERMSIG(status)); + } + } else if (wait_rc > 0) { + tr_err("tids_sweep_procs: waitpid returned pid %d, expected %d", wait_rc, tp.pid); + } + + /* read the pipe - if the TID request worked, it will have written status before terminating */ + result_len = read(tp.read_fd, result, sizeof(result)/sizeof(result[0])); + close(tp.read_fd); + + if ((result_len > 0) && (strcmp(result, "OK") == 0)) { + tids->req_count++; + tr_debug("tids_sweep_procs: TID process %d succeeded", tp.pid); + } else { + tids->error_count++; + tr_debug("tids_sweep_procs: TID process %d failed", tp.pid); + } + } + } + /* Process tids requests forever. Should not return except on error. */ - #define MAX_SOCKETS 10 - int tids_start (TIDS_INSTANCE *tids, + int tids_start (TIDS_INSTANCE *tids, TIDS_REQ_FUNC *req_handler, tids_auth_func *auth_handler, const char *hostname, unsigned int port, void *cookie) { - int fd[MAX_SOCKETS]={0}; - size_t n_fd=0; - struct pollfd poll_fd[MAX_SOCKETS]={{0}}; + int fd[TR_MAX_SOCKETS]={0}; + nfds_t n_fd=0; + struct pollfd poll_fd[TR_MAX_SOCKETS]={{0}}; int ii=0; - n_fd=tids_get_listener(tids, req_handler, auth_handler, hostname, port, cookie, fd, MAX_SOCKETS); + n_fd = tids_get_listener(tids, req_handler, auth_handler, hostname, port, cookie, fd, TR_MAX_SOCKETS); if (n_fd <= 0) { perror ("Error from tids_listen()"); return 1; @@@ -557,7 -570,6 +576,6 @@@ return 1; /* should never get here, loops "forever" */ } - #undef MAX_SOCKETS void tids_destroy (TIDS_INSTANCE *tids) { diff --combined tr/tr_tid.c index c4ac9fb,038cc3c..62722e8 --- a/tr/tr_tid.c +++ b/tr/tr_tid.c @@@ -40,14 -40,17 +40,17 @@@ #include #include #include + #include #include #include #include + #include #include #include #include #include #include + #include /* Structure to hold data for the tid response callback */ typedef struct tr_resp_cookie { @@@ -183,7 -186,7 +186,7 @@@ static void *tr_tids_req_fwd_thread(voi } /* cookie->resp should now contain our copy of the response */ success=1; - tr_debug("tr_tids_req_fwd_thread: thread %d received response."); + tr_debug("tr_tids_req_fwd_thread: thread %d received response.", cookie->thread_id); cleanup: /* Notify parent thread of the response, if it's still listening. */ @@@ -221,15 -224,84 +224,84 @@@ static TID_RC tr_tids_merge_resps(TID_R if ((r1->result!=TID_SUCCESS) || (r2->result!=TID_SUCCESS)) return TID_ERROR; - if ((0!=tr_name_cmp(r1->rp_realm, r2->rp_realm)) || - (0!=tr_name_cmp(r1->realm, r2->realm)) || - (0!=tr_name_cmp(r1->comm, r2->comm))) - return TID_ERROR; + if ((0 == tr_name_cmp(r1->rp_realm, r2->rp_realm)) + && (0 == tr_name_cmp(r1->realm, r2->realm)) + && ( (0 == tr_name_cmp(r1->comm, r2->comm)) + || (0 == tr_name_cmp(r1->comm, r2->orig_coi)) + || (0 == tr_name_cmp(r1->orig_coi, r2->comm)))) { + + tid_srvr_blk_add(r1->servers, tid_srvr_blk_dup(r1, r2->servers)); + return TID_SUCCESS; + } - tid_srvr_blk_add(r1->servers, tid_srvr_blk_dup(r1, r2->servers)); - return TID_SUCCESS; + return TID_ERROR; } + enum map_coi_result { + MAP_COI_SUCCESS = 0, + MAP_COI_MAP_NOT_REQUIRED, + MAP_COI_ALREADY_MAPPED, + MAP_COI_NO_APC, + MAP_COI_INVALID_APC, + MAP_COI_UNKNOWN_COMM, + MAP_COI_ERROR + }; + + static enum map_coi_result map_coi(TR_COMM_TABLE *ctable, TID_REQ *req) + { + TR_COMM *orig_comm; + TR_NAME *apc_name; + TR_COMM *apc; + TR_APC *apcs; + + if (tid_req_get_orig_coi(req) != NULL) + return MAP_COI_ALREADY_MAPPED; + + /* look up the community */ + orig_comm = tr_comm_table_find_comm(ctable, tid_req_get_comm(req)); + if (orig_comm == NULL) + return MAP_COI_UNKNOWN_COMM; + + if (tr_comm_get_type(orig_comm) == TR_COMM_APC) + return MAP_COI_MAP_NOT_REQUIRED; /* it was already an APC, no mapping to do */ + + /* use first (only) APC. These are just APC names */ + apcs = tr_comm_get_apcs(orig_comm); + if ((!apcs) || (!tr_apc_get_id(apcs))) + return MAP_COI_NO_APC; + + /* get our own copy of the APC name */ + apc_name = tr_dup_name(tr_apc_get_id(apcs)); + if (apc_name == NULL) { + tr_err("map_coi: Error allocating apc_name"); + return MAP_COI_ERROR; + } + + /* Check that the APC is configured */ + apc = tr_comm_table_find_comm(ctable, apc_name); + if (apc == NULL) { + tr_free_name(apc_name); + return MAP_COI_INVALID_APC; + } + + tid_req_set_orig_coi(req, tid_req_get_comm(req)); /* was null, so no need to free anything */ + tid_req_set_comm(req, apc_name); /* original contents will be freed via orig_coi */ + + return MAP_COI_SUCCESS; /* successfully mapped */ + } + + /** + * Process a TID request + * + * Return value of -1 means to send a TID_ERROR response. Fill in resp->err_msg or it will + * be returned as a generic error. + * + * @param tids + * @param orig_req + * @param resp + * @param cookie_in + * @return + */ static int tr_tids_req_handler(TIDS_INSTANCE *tids, TID_REQ *orig_req, TID_RESP *resp, @@@ -245,7 -317,6 +317,6 @@@ TID_RESP *aaa_resp[TR_TID_MAX_AAA_SERVERS]={NULL}; TR_RP_CLIENT *rp_client=NULL; TR_RP_CLIENT_ITER *rpc_iter=NULL; - TR_NAME *apc = NULL; TID_REQ *fwd_req = NULL; TR_COMM *cfg_comm = NULL; TR_COMM *cfg_apc = NULL; @@@ -273,26 -344,21 +344,27 @@@ goto cleanup; } - tr_debug("tr_tids_req_handler: Request received (conn = %d)! Realm = %s, Comm = %s", orig_req->conn, + tr_debug("tr_tids_req_handler: Request received (conn = %d)! Realm = %s, Comm = %s", orig_req->conn, orig_req->realm->buf, orig_req->comm->buf); + if (orig_req->request_id) + tr_debug("tr_tids_req_handler: TID request ID: %.*s", orig_req->request_id->len, orig_req->request_id->buf); + else + tr_debug("tr_tids_req_handler: TID request ID: none"); + + 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; + retval=-1; /* response will be a generic internal error */ goto cleanup; } talloc_steal(tmp_ctx, fwd_req); + /* cfg_comm is now the community (APC or CoI) of the incoming request */ if (NULL == (cfg_comm=tr_comm_table_find_comm(cfg_mgr->active->ctable, orig_req->comm))) { tr_notice("tr_tids_req_hander: Request for unknown comm: %s.", orig_req->comm->buf); - tids_send_err_response(tids, orig_req, "Unknown community"); + tid_resp_set_err_msg(resp, tr_new_name("Unknown community")); retval=-1; goto cleanup; } @@@ -305,7 -371,7 +377,7 @@@ if (!tids->gss_name) { tr_notice("tr_tids_req_handler: No GSS name for incoming request."); - tids_send_err_response(tids, orig_req, "No GSS name for request"); + tid_resp_set_err_msg(resp, tr_new_name("No GSS name for request")); retval=-1; goto cleanup; } @@@ -317,7 -383,7 +389,7 @@@ target=tr_filter_target_tid_req(tmp_ctx, orig_req); if (target==NULL) { tr_crit("tid_req_handler: Unable to allocate filter target, cannot apply filter!"); - tids_send_err_response(tids, orig_req, "Incoming TID request filter error"); + tid_resp_set_err_msg(resp, tr_new_name("Incoming TID request filter error")); retval=-1; goto cleanup; } @@@ -346,82 -412,96 +418,96 @@@ /* We get here whether or not a filter matched. If tr_filter_apply() doesn't match, it returns * a default action of reject, so we don't have to check why we exited the loop. */ if (oaction != TR_FILTER_ACTION_ACCEPT) { - tr_notice("tr_tids_req_handler: Incoming TID request rejected by filter for GSS name", orig_req->rp_realm->buf); - tids_send_err_response(tids, orig_req, "Incoming TID request filter error"); + tr_notice("tr_tids_req_handler: Incoming TID request rejected by RP client filter for GSS name %.*s", + tids->gss_name->len, tids->gss_name->buf); + tid_resp_set_err_msg(resp, tr_new_name("Incoming TID request filter error")); retval = -1; goto cleanup; } /* Check that the rp_realm is a member of the community in the request */ if (NULL == tr_comm_find_rp(cfg_mgr->active->ctable, cfg_comm, orig_req->rp_realm)) { - tr_notice("tr_tids_req_handler: RP Realm (%s) not member of community (%s).", orig_req->rp_realm->buf, orig_req->comm->buf); - tids_send_err_response(tids, orig_req, "RP COI membership error"); + tr_notice("tr_tids_req_handler: RP Realm (%s) not member of community (%s).", + orig_req->rp_realm->buf, orig_req->comm->buf); + tid_resp_set_err_msg(resp, tr_new_name("RP community membership error")); retval=-1; goto cleanup; } - /* Map the comm in the request from a COI to an APC, if needed */ - if (TR_COMM_COI == cfg_comm->type) { - if (orig_req->orig_coi!=NULL) { - tr_notice("tr_tids_req_handler: community %s is COI but COI to APC mapping already occurred. Dropping request.", - orig_req->comm->buf); - tids_send_err_response(tids, orig_req, "Second COI to APC mapping would result, permitted only once."); - retval=-1; - goto cleanup; - } - - tr_debug("tr_tids_req_handler: Community was a COI, switching."); - /* TBD -- In theory there can be more than one? How would that work? */ - if ((!cfg_comm->apcs) || (!cfg_comm->apcs->id)) { - tr_notice("No valid APC for COI %s.", orig_req->comm->buf); - tids_send_err_response(tids, orig_req, "No valid APC for community"); - retval=-1; + switch(map_coi(cfg_mgr->active->ctable, fwd_req)) { + case MAP_COI_MAP_NOT_REQUIRED: + cfg_apc = cfg_comm; + break; + + case MAP_COI_SUCCESS: + cfg_apc = tr_comm_table_find_comm(cfg_mgr->active->ctable, tid_req_get_comm(fwd_req)); + tr_debug("tr_tids_req_handler: Community %.*s is a COI, mapping to APC %.*s.", + tid_req_get_orig_coi(fwd_req)->len, tid_req_get_orig_coi(fwd_req)->buf, + tr_comm_get_id(cfg_apc)->len, tr_comm_get_id(cfg_apc)->buf); + break; + + case MAP_COI_ALREADY_MAPPED: + tr_notice("tr_tids_req_handler: community %.*s is COI but COI to APC mapping already occurred. Dropping request.", + tid_req_get_comm(orig_req)->len, tid_req_get_comm(orig_req)->buf); + tid_resp_set_err_msg(resp, tr_new_name("Second COI to APC mapping would result, permitted only once.")); + retval = -1; goto cleanup; - } - apc = tr_dup_name(cfg_comm->apcs->id); - /* Check that the APC is configured */ - if (NULL == (cfg_apc = tr_comm_table_find_comm(cfg_mgr->active->ctable, apc))) { - tr_notice("tr_tids_req_hander: Request for unknown comm: %s.", apc->buf); - tids_send_err_response(tids, orig_req, "Unknown APC"); - retval=-1; + case MAP_COI_NO_APC: + tr_notice("No valid APC for COI %.*s.", + tid_req_get_comm(orig_req)->len, tid_req_get_comm(orig_req)->buf); + tid_resp_set_err_msg(resp, tr_new_name("No valid APC for community")); + retval = -1; goto cleanup; - } - fwd_req->comm = apc; - fwd_req->orig_coi = orig_req->comm; + case MAP_COI_INVALID_APC: + tr_notice("tr_tids_req_hander: Request for unknown APC."); + tid_resp_set_err_msg(resp, tr_new_name("Unknown APC")); + retval = -1; + goto cleanup; - /* Check that rp_realm is a member of this APC */ - if (NULL == (tr_comm_find_rp(cfg_mgr->active->ctable, cfg_apc, orig_req->rp_realm))) { - tr_notice("tr_tids_req_hander: RP Realm (%s) not member of community (%s).", orig_req->rp_realm->buf, orig_req->comm->buf); - tids_send_err_response(tids, orig_req, "RP APC membership error"); - retval=-1; + default: + tr_notice("tr_tids_req_hander: Unexpected error mapping COI to APC."); + retval = -1; goto cleanup; - } } - /* Look up the route for this community/realm. */ + /* cfg_comm is now the original community, and cfg_apc is the APC it belongs to. These + * may both be the same. If not, check that rp_realm is a member of the mapped APC */ + if ((cfg_apc != cfg_comm) + && (NULL == tr_comm_find_rp(cfg_mgr->active->ctable, + cfg_apc, + tid_req_get_rp_realm(fwd_req)))) { + tr_notice("tr_tids_req_hander: RP Realm (%.*s) not member of mapped APC (%.*s).", + tid_req_get_rp_realm(fwd_req)->len, tid_req_get_rp_realm(fwd_req)->buf, + tr_comm_get_id(cfg_apc)->len, tr_comm_get_id(cfg_apc)->buf); + tid_resp_set_err_msg(resp, tr_new_name("RP community membership error")); + retval=-1; + goto cleanup; + } + + /* Look up the route for forwarding request's community/realm. */ tr_debug("tr_tids_req_handler: looking up route."); - route=trps_get_selected_route(trps, orig_req->comm, orig_req->realm); + route=trps_get_selected_route(trps, fwd_req->comm, fwd_req->realm); if (route==NULL) { /* No route. Use default AAA servers if we have them. */ - tr_debug("tr_tids_req_handler: No route for realm %s, defaulting.", orig_req->realm->buf); + tr_debug("tr_tids_req_handler: No route for realm %s, defaulting.", fwd_req->realm->buf); if (NULL == (aaa_servers = tr_default_server_lookup(cfg_mgr->active->default_servers, - orig_req->comm))) { + fwd_req->comm))) { tr_notice("tr_tids_req_handler: No default AAA servers, discarded."); - tids_send_err_response(tids, orig_req, "No path to AAA Server(s) for realm"); + tid_resp_set_err_msg(resp, tr_new_name("No path to AAA Server(s) for realm")); retval = -1; goto cleanup; } idp_shared = 0; } else { - /* Found a route. Determine the AAA servers or next hop address. */ + /* Found a route. Determine the AAA servers or next hop address for the request we are forwarding. */ tr_debug("tr_tids_req_handler: found route."); if (trp_route_is_local(route)) { tr_debug("tr_tids_req_handler: route is local."); aaa_servers = tr_idp_aaa_server_lookup(cfg_mgr->active->ctable->idp_realms, - orig_req->realm, - orig_req->comm, + fwd_req->realm, + fwd_req->comm, &idp_shared); } else { tr_debug("tr_tids_req_handler: route not local."); @@@ -429,38 -509,39 +515,39 @@@ idp_shared = 0; } - /* Since we aren't defaulting, check idp coi and apc membership */ - if (NULL == (tr_comm_find_idp(cfg_mgr->active->ctable, cfg_comm, fwd_req->realm))) { - tr_notice("tr_tids_req_handler: IDP Realm (%s) not member of community (%s).", orig_req->realm->buf, orig_req->comm->buf); - tids_send_err_response(tids, orig_req, "IDP community membership error"); + /* Since we aren't defaulting, check idp coi and apc membership of the original request */ + if (NULL == (tr_comm_find_idp(cfg_mgr->active->ctable, cfg_comm, orig_req->realm))) { + tr_notice("tr_tids_req_handler: IDP Realm (%s) not member of community (%s).", orig_req->realm->buf, cfg_comm->id->buf); + tid_resp_set_err_msg(resp, tr_new_name("IDP community membership error")); retval=-1; goto cleanup; } - if ( cfg_apc && (NULL == (tr_comm_find_idp(cfg_mgr->active->ctable, cfg_apc, fwd_req->realm)))) { - tr_notice("tr_tids_req_handler: IDP Realm (%s) not member of APC (%s).", orig_req->realm->buf, orig_req->comm->buf); - tids_send_err_response(tids, orig_req, "IDP APC membership error"); + if ( cfg_apc && (NULL == (tr_comm_find_idp(cfg_mgr->active->ctable, cfg_apc, orig_req->realm)))) { + tr_notice("tr_tids_req_handler: IDP Realm (%s) not member of APC (%s).", orig_req->realm->buf, cfg_apc->id->buf); + tid_resp_set_err_msg(resp, tr_new_name("IDP APC membership error")); retval=-1; goto cleanup; } } - /* Make sure we came through with a AAA server. If not, we can't handle the request. */ + /* Make sure we came through with a AAA server. If not, we can't handle the request. + * Report using the original request, not translated values. */ if (NULL == aaa_servers) { tr_notice("tr_tids_req_handler: no route or AAA server for realm (%s) in community (%s).", orig_req->realm->buf, orig_req->comm->buf); - tids_send_err_response(tids, orig_req, "Missing trust route error"); + tid_resp_set_err_msg(resp, tr_new_name("Missing trust route error")); retval = -1; goto cleanup; } /* send a TID request to the AAA server(s), and get the answer(s) */ tr_debug("tr_tids_req_handler: sending TID request(s)."); - if (cfg_apc) - expiration_interval = cfg_apc->expiration_interval; - else expiration_interval = cfg_comm->expiration_interval; + /* Use the smaller of the APC's expiration interval and the expiration interval of the incoming request */ + expiration_interval = cfg_apc->expiration_interval; if (fwd_req->expiration_interval) fwd_req->expiration_interval = (expiration_interval < fwd_req->expiration_interval) ? expiration_interval : fwd_req->expiration_interval; - else fwd_req->expiration_interval = expiration_interval; + else + fwd_req->expiration_interval = expiration_interval; /* Set up message queue for replies from req forwarding threads */ mq=tr_mq_new(tmp_ctx); @@@ -613,13 -694,19 +700,19 @@@ } if (n_responses==0) { - /* No requests succeeded. Forward an error if we got any error responses. */ + /* No requests succeeded, so this will be an error */ + retval = -1; + + /* If we got any error responses, send an arbitrarily chosen one. */ for (ii=0; iin_sock_fd=tids_get_listener(tids, - tr_tids_req_handler, - tr_tids_gss_handler, - cfg_mgr->active->internal->hostname, - cfg_mgr->active->internal->tids_port, - (void *)cookie, - tids_ev->sock_fd, - TR_MAX_SOCKETS); + tids_ev->n_sock_fd = (int)tids_get_listener(tids, + tr_tids_req_handler, + tr_tids_gss_handler, + cfg_mgr->active->internal->hostname, + cfg_mgr->active->internal->tids_port, + (void *)cookie, + tids_ev->sock_fd, + TR_MAX_SOCKETS); if (tids_ev->n_sock_fd==0) { tr_crit("Error opening TID server socket."); retval=1; goto cleanup; } - /* Set up events */ + /* Set up listener events */ for (ii=0; iin_sock_fd; ii++) { tids_ev->ev[ii]=event_new(base, tids_ev->sock_fd[ii], @@@ -727,6 -829,12 +835,12 @@@ event_add(tids_ev->ev[ii], NULL); } + /* Set up a periodic check for completed TID handler processes */ + *sweep_ev = event_new(base, -1, EV_TIMEOUT|EV_PERSIST, tr_tids_sweep_cb, tids); + sweep_interval.tv_sec = 10; + sweep_interval.tv_usec = 0; + event_add(*sweep_ev, &sweep_interval); + cleanup: talloc_free(tmp_ctx); return retval;