+static void tr_tidc_resp_handler(TIDC_INSTANCE *tidc,
+ TID_REQ *req,
+ TID_RESP *resp,
+ void *resp_cookie)
+{
+ TR_RESP_COOKIE *cookie=talloc_get_type_abort(resp_cookie, TR_RESP_COOKIE);
+
+ tr_debug("tr_tidc_resp_handler: Response received! Realm = %s, Community = %s, result = %s.",
+ resp->realm->buf,
+ resp->comm->buf,
+ (TID_SUCCESS==resp->result)?"success":"error");
+
+ if (resp->error_path!=NULL)
+ tr_debug("tr_tids_resp_handler: error_path is set.");
+ cookie->resp=tid_resp_dup(cookie, resp);
+}
+
+/* data for AAA req forwarding threads */
+struct tr_tids_fwd_cookie {
+ int thread_id;
+ pthread_mutex_t mutex; /* lock on the mq (separate from the locking within the mq, see below) */
+ TR_MQ *mq; /* messages from thread to main process; set to NULL to disable response */
+ TR_NAME *aaa_hostname;
+ DH *dh_params;
+ TID_REQ *fwd_req; /* the req to duplicate */
+};
+
+static 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();
+ TR_MQ_MSG *msg=NULL;
+ TR_RESP_COOKIE *cookie=NULL;
+ int rc=0;
+ int success=0;
+
+ talloc_steal(tmp_ctx, args); /* take responsibility for the cookie */
+
+ if (tidc!=NULL)
+ talloc_steal(tmp_ctx, tidc);
+
+ /* create the cookie we will use for our response */
+ cookie=talloc(tmp_ctx, TR_RESP_COOKIE);
+ if (cookie==NULL) {
+ tr_notice("tr_tids_req_fwd_thread: unable to allocate response cookie.");
+ success=0;
+ goto cleanup;
+ }
+ cookie->thread_id=args->thread_id;
+ tr_debug("tr_tids_req_fwd_thread: thread %d started.", cookie->thread_id);
+
+ /* Create a TID client instance */
+ if (tidc==NULL) {
+ tr_crit("tr_tids_req_fwd_thread: Unable to allocate TIDC instance.");
+ /*tids_send_err_response(tids, orig_req, "Memory allocation failure");*/
+ /* TODO: encode reason for failure */
+ success=0;
+ goto cleanup;
+ }
+
+ /* Set-up TID connection */
+ if (-1==(args->fwd_req->conn = tidc_open_connection(tidc,
+ args->aaa_hostname->buf,
+ TID_PORT, /* TODO: make this configurable */
+ &(args->fwd_req->gssctx)))) {
+ tr_notice("tr_tids_req_fwd_thread: Error in tidc_open_connection.");
+ /* tids_send_err_response(tids, orig_req, "Can't open connection to next hop TIDS"); */
+ /* TODO: encode reason for failure */
+ success=0;
+ goto cleanup;
+ };
+ tr_debug("tr_tids_req_fwd_thread: thread %d opened TID connection to %s.",
+ cookie->thread_id,
+ args->aaa_hostname->buf);
+
+ /* Send a TID request. */
+ if (0 > (rc = tidc_fwd_request(tidc, args->fwd_req, tr_tidc_resp_handler, (void *)cookie))) {
+ tr_notice("Error from tidc_fwd_request, rc = %d.", rc);
+ success=0;
+ goto cleanup;
+ }
+ /* cookie->resp should now contain our copy of the response */
+ success=1;
+ tr_debug("tr_tids_req_fwd_thread: thread %d received response.", cookie->thread_id);
+
+cleanup:
+ /* Notify parent thread of the response, if it's still listening. */
+ if (0!=tr_tids_fwd_get_mutex(args)) {
+ tr_notice("tr_tids_req_fwd_thread: thread %d unable to acquire mutex.", cookie->thread_id);
+ } else if (NULL!=args->mq) {
+ /* mq is still valid, so we can queue our response */
+ tr_debug("tr_tids_req_fwd_thread: thread %d using valid msg queue.", cookie->thread_id);
+ if (success)
+ msg=tr_mq_msg_new(tmp_ctx, TR_TID_MQMSG_SUCCESS, TR_MQ_PRIO_NORMAL);
+ else
+ msg=tr_mq_msg_new(tmp_ctx, TR_TID_MQMSG_FAILURE, TR_MQ_PRIO_NORMAL);
+
+ if (msg==NULL)
+ tr_notice("tr_tids_req_fwd_thread: thread %d unable to allocate response msg.", cookie->thread_id);
+
+ tr_mq_msg_set_payload(msg, (void *)cookie, NULL);
+ if (NULL!=cookie)
+ talloc_steal(msg, cookie); /* attach this to the msg so we can forget about it */
+ tr_mq_add(args->mq, msg);
+ talloc_steal(NULL, args); /* take out of our tmp_ctx; master thread now responsible for freeing */
+ tr_debug("tr_tids_req_fwd_thread: thread %d queued response message.", cookie->thread_id);
+ if (0!=tr_tids_fwd_release_mutex(args))
+ tr_notice("tr_tids_req_fwd_thread: Error releasing mutex.");
+ }