Apply all filters applicable to a GSS name to a TID req
authorJennifer Richards <jennifer@painless-security.com>
Fri, 14 Jul 2017 02:41:31 +0000 (22:41 -0400)
committerJennifer Richards <jennifer@painless-security.com>
Fri, 14 Jul 2017 02:41:31 +0000 (22:41 -0400)
common/tr_rp.c
include/tid_internal.h
include/tr_filter.h
include/tr_rp.h
tr/tr_tid.c

index 35c2714..f54a5a5 100644 (file)
@@ -105,20 +105,55 @@ int tr_rp_client_set_filters(TR_RP_CLIENT *client, TR_FILTER_SET *filts)
   return 0; /* success */
 }
 
-TR_RP_CLIENT *tr_rp_client_lookup(TR_RP_CLIENT *rp_clients, TR_NAME *gss_name)
+TR_RP_CLIENT_ITER *tr_rp_client_iter_new(TALLOC_CTX *memctx)
+{
+  return talloc(memctx, TR_RP_CLIENT_ITER);
+}
+
+void tr_rp_client_iter_free(TR_RP_CLIENT_ITER *iter)
 {
-  TR_RP_CLIENT *rp = NULL;
+  talloc_free(iter);
+}
 
-  if ((!rp_clients) || (!gss_name)) {
-    tr_debug("tr_rp_client_lookup: Bad parameters.");
+TR_RP_CLIENT *tr_rp_client_iter_first(TR_RP_CLIENT_ITER *iter, TR_RP_CLIENT *rp_clients)
+{
+  if (!iter) {
+    tr_err("tr_rp_client_iter_first: Iterator is null, failing.");
     return NULL;
   }
+  *iter=rp_clients;
+  return *iter;
+}
 
-  for (rp = rp_clients; NULL != rp; rp = rp->next) {
-    if (tr_gss_names_matches(rp->gss_names, gss_name))
-      return rp;
-  } 
-  return NULL;
+TR_RP_CLIENT *tr_rp_client_iter_next(TR_RP_CLIENT_ITER *iter)
+{
+  if (*iter)
+    *iter=(*iter)->next;
+  return *iter;
+}
+
+/**
+ * Find a client associated with a GSS name. It's possible there are other clients that match as well.
+ *
+ * @param rp_clients List of RP clients to search
+ * @param gss_name GSS name to search for
+ * @return Borrowed reference to an RP client linked to the GSS name
+ */
+TR_RP_CLIENT *tr_rp_client_lookup(TR_RP_CLIENT *rp_clients, TR_NAME *gss_name)
+{
+  TR_RP_CLIENT_ITER *iter=tr_rp_client_iter_new(NULL);
+  TR_RP_CLIENT *client=NULL;
+
+  if (iter==NULL) {
+    tr_err("tr_rp_client_lookup: Unable to allocate iterator");
+    return NULL;
+  }
+  for (client=tr_rp_client_iter_first(iter, rp_clients); client != NULL; client=tr_rp_client_iter_next(iter)) {
+    if (tr_gss_names_matches(client->gss_names, gss_name))
+      break;
+  }
+  tr_rp_client_iter_free(iter);
+  return client;
 }
 
 TR_RP_REALM *tr_rp_realm_lookup(TR_RP_REALM *rp_realms, TR_NAME *rp_name)
index 10c6eac..f02c4d1 100644 (file)
@@ -98,7 +98,7 @@ struct tids_instance {
   tids_auth_func *auth_handler;
   void *cookie;
   uint16_t tids_port;
-  struct tr_rp_client *rp_gss;         /* Client matching GSS name */
+  TR_NAME *gss_name;           /* GSS name client used for authentication */
 };
 
 /** Decrement a reference to #json when this tid_req is cleaned up. A
index 45b8fdc..63b23dd 100644 (file)
@@ -49,7 +49,7 @@
 #define TR_MAX_FILTER_SPEC_MATCHES 64
 
 /* Filter actions */
-typedef enum {
+typedef enum tr_filter_action {
   TR_FILTER_ACTION_REJECT = 0,
   TR_FILTER_ACTION_ACCEPT,
   TR_FILTER_ACTION_UNKNOWN
index e150f9a..fa6b84e 100644 (file)
@@ -47,6 +47,8 @@ typedef struct tr_rp_client {
   TR_FILTER_SET *filters;
 } TR_RP_CLIENT;
 
+typedef struct tr_rp_client *TR_RP_CLIENT_ITER;
+
 /* Structure to make a linked list of RP realms by name for community config */
 typedef struct tr_rp_realm {
   struct tr_rp_realm *next;
@@ -61,6 +63,10 @@ TR_RP_CLIENT *tr_rp_client_add_func(TR_RP_CLIENT *clients, TR_RP_CLIENT *new);
 #define tr_rp_client_add(clients,new) ((clients)=tr_rp_client_add_func((clients),(new)))
 int tr_rp_client_add_gss_name(TR_RP_CLIENT *client, TR_NAME *name);
 int tr_rp_client_set_filters(TR_RP_CLIENT *client, TR_FILTER_SET *filts);
+TR_RP_CLIENT_ITER *tr_rp_client_iter_new(TALLOC_CTX *memctx);
+void tr_rp_client_iter_free(TR_RP_CLIENT_ITER *iter);
+TR_RP_CLIENT *tr_rp_client_iter_first(TR_RP_CLIENT_ITER *iter, TR_RP_CLIENT *rp_clients);
+TR_RP_CLIENT *tr_rp_client_iter_next(TR_RP_CLIENT_ITER *iter);
 TR_RP_CLIENT *tr_rp_client_lookup(TR_RP_CLIENT *rp_clients, TR_NAME *gss_name);
 
 TR_RP_REALM *tr_rp_realm_new(TALLOC_CTX *mem_ctx);
index 37ee89f..dffa46b 100644 (file)
@@ -243,6 +243,8 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
   pthread_t aaa_thread[TR_TID_MAX_AAA_SERVERS];
   struct tr_tids_fwd_cookie *aaa_cookie[TR_TID_MAX_AAA_SERVERS]={NULL};
   TID_RESP *aaa_resp[TR_TID_MAX_AAA_SERVERS]={NULL};
+  TR_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;
@@ -290,13 +292,13 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
     goto cleanup;
   }
 
-  /* Check that the rp_realm matches the filter for the GSS name that 
-   * 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. */
+  /* We now need to apply the filters associated with the RP client handing us the request.
+   * It is possible (or even likely) that more than one client is associated with the GSS
+   * name we got from the authentication. We will apply all of them in an arbitrary order.
+   * For this to result in well-defined behavior, either only accept or only reject filter
+   * lines should be used, or a unique GSS name must be given for each RP realm. */
 
-  if ((!tids->rp_gss) || 
-      (!tids->rp_gss->filters)) {
+  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");
     retval=-1;
@@ -309,21 +311,42 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
 
   target=tr_filter_target_tid_req(tmp_ctx, orig_req);
   if (target==NULL) {
-    /* TODO: signal that filtering failed. Until then, just filter everything and give an error message. */
     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");
+    retval=-1;
+    goto cleanup;
   }
-  if ((target==NULL)
-      || (TR_FILTER_NO_MATCH == tr_filter_apply(target,
-                                                tr_filter_set_get(tids->rp_gss->filters,
-                                                                  TR_FILTER_TYPE_TID_INBOUND),
-                                                &(fwd_req->cons),
-                                                &oaction))
-      || (TR_FILTER_ACTION_ACCEPT != oaction)) {
+
+  rpc_iter=tr_rp_client_iter_new(tmp_ctx);
+  if (rpc_iter==NULL) {
+    tr_err("tid_req_handler: Unable to allocate RP client iterator.");
+    retval=-1;
+    goto cleanup;
+  }
+  for (rp_client=tr_rp_client_iter_first(rpc_iter, cfg_mgr->active->rp_clients);
+       rp_client != NULL;
+       rp_client=tr_rp_client_iter_next(rpc_iter)) {
+
+    if (!tr_gss_names_matches(rp_client->gss_names, tids->gss_name))
+      continue; /* skip any that don't match the GSS name */
+
+    if (TR_FILTER_MATCH == tr_filter_apply(target,
+                                           tr_filter_set_get(rp_client->filters,
+                                                             TR_FILTER_TYPE_TID_INBOUND),
+                                           &(fwd_req->cons),
+                                           &oaction))
+      break; /* Stop looking, oaction is set */
+  }
+
+  /* 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");
-    retval=-1;
+    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);
@@ -602,7 +625,6 @@ cleanup:
 static int tr_tids_gss_handler(gss_name_t client_name, TR_NAME *gss_name,
                                void *data)
 {
-  TR_RP_CLIENT *rp;
   struct tr_tids_event_cookie *cookie=talloc_get_type_abort(data, struct tr_tids_event_cookie);
   TIDS_INSTANCE *tids = cookie->tids;
   TR_CFG_MGR *cfg_mgr = cookie->cfg_mgr;
@@ -612,15 +634,15 @@ static int tr_tids_gss_handler(gss_name_t client_name, TR_NAME *gss_name,
     return -1;
   }
 
-  /* look up the RP client matching the GSS name */
-  if ((NULL == (rp = tr_rp_client_lookup(cfg_mgr->active->rp_clients, gss_name)))) {
-    tr_debug("tr_tids_gss_handler: Unknown GSS name %s", gss_name->buf);
+  /* Ensure at least one client exists using this GSS name */
+  if (NULL == tr_rp_client_lookup(cfg_mgr->active->rp_clients, gss_name)) {
+    tr_debug("tr_tids_gss_handler: Unknown GSS name %.*s", gss_name->len, gss_name->buf);
     return -1;
   }
 
-  /* Store the rp client */
-  tids->rp_gss = rp;
-  tr_debug("Client's GSS Name: %s", gss_name->buf);
+  /* Store the GSS name */
+  tids->gss_name = tr_dup_name(gss_name);
+  tr_debug("Client's GSS Name: %.*s", gss_name->len, gss_name->buf);
 
   return 0;
 }