Allow inforec filter to have access to realm and community
authorJennifer Richards <jennifer@painless-security.com>
Tue, 13 Jun 2017 16:32:58 +0000 (12:32 -0400)
committerJennifer Richards <jennifer@painless-security.com>
Tue, 13 Jun 2017 16:32:58 +0000 (12:32 -0400)
common/tests/filt_test.c
common/tr_filter.c
include/tr_filter.h
tr/tr_tid.c
trp/trps.c

index 7dc5094..6d246da 100644 (file)
@@ -178,7 +178,7 @@ int test_one_filter(const char *filt_fname,
                     int expected_match,
                     TR_FILTER_ACTION expected_action)
 {
-  void *target=NULL;
+  TR_FILTER_TARGET *target=NULL;
   TR_FILTER_SET *filts=NULL;
   TR_FILTER_ACTION action=TR_FILTER_ACTION_UNKNOWN;
 
@@ -188,12 +188,13 @@ int test_one_filter(const char *filt_fname,
   /* load the target req or inforec */
   switch(ftype) {
     case TR_FILTER_TYPE_TID_INBOUND:
-      target=load_tid_req(target_fname);
+      target=tr_filter_target_tid_req(NULL, load_tid_req(target_fname));
       break;
 
     case TR_FILTER_TYPE_TRP_INBOUND:
     case TR_FILTER_TYPE_TRP_OUTBOUND:
-      target=load_inforec(target_fname);
+      /* TODO: read realm and community */
+      target=tr_filter_target_trp_inforec(NULL, load_inforec(target_fname), NULL, NULL);
       break;
 
     default:
@@ -208,17 +209,22 @@ int test_one_filter(const char *filt_fname,
   tr_filter_set_free(filts);
   switch(ftype) {
     case TR_FILTER_TYPE_TID_INBOUND:
-      tid_req_free((TID_REQ *)target);
+      tid_req_free(target->tid_req);
       break;
 
     case TR_FILTER_TYPE_TRP_INBOUND:
     case TR_FILTER_TYPE_TRP_OUTBOUND:
-      trp_inforec_free((TRP_INFOREC *)target);
+      trp_inforec_free(target->trp_inforec);
+      if (target->realm!=NULL)
+        tr_free_name(target->realm);
+      if (target->comm!=NULL)
+        tr_free_name(target->comm);
       break;
 
     default:
       printf("Unknown filter type.\n");
   }
+  tr_filter_target_free(target);
   return 1;
 }
 
index 39a0fd7..892eb81 100644 (file)
@@ -35,7 +35,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <strings.h>
 #include <talloc.h>
 #include <assert.h>
 
 /* Function types for handling filter fields generally. All target values
  * are represented as strings in a TR_NAME.
  */
-typedef int (*TR_FILTER_FIELD_CMP)(void *target, TR_NAME *val); /* returns 1 on match, 0 on no match */
-typedef TR_NAME *(*TR_FILTER_FIELD_GET)(void *target); /* returns string form of the field value */
+typedef int (*TR_FILTER_FIELD_CMP)(TR_FILTER_TARGET *target, TR_NAME *val); /* returns 1 on match, 0 on no match */
+typedef TR_NAME *(*TR_FILTER_FIELD_GET)(TR_FILTER_TARGET *target); /* returns string form of the field value */
 
 /* static handler prototypes */
-static int tr_ff_cmp_tid_rp_realm(void *rp_req_arg, TR_NAME *val);
-static TR_NAME *tr_ff_get_tid_rp_realm(void *rp_req_arg);
-static int tr_ff_cmp_trp_info_type(void *inforec_arg, TR_NAME *val);
-static TR_NAME *tr_ff_get_trp_info_type(void *inforec_arg);
+static int tr_ff_cmp_tid_rp_realm(TR_FILTER_TARGET *target, TR_NAME *val);
+static TR_NAME *tr_ff_get_tid_rp_realm(TR_FILTER_TARGET *target);
+static int tr_ff_cmp_trp_info_type(TR_FILTER_TARGET *target, TR_NAME *val);
+static TR_NAME *tr_ff_get_trp_info_type(TR_FILTER_TARGET *target);
 
 /**
  * Filter field handler table
@@ -84,23 +83,76 @@ static struct tr_filter_field_entry *tr_filter_field_entry(TR_FILTER_TYPE filter
   return NULL;
 }
 
-static int tr_ff_cmp_tid_rp_realm(void *rp_req_arg, TR_NAME *val)
+static TR_FILTER_TARGET *tr_filter_target_new(TALLOC_CTX *mem_ctx)
 {
-  TID_REQ *req=talloc_get_type_abort(rp_req_arg, TID_REQ);
+  TR_FILTER_TARGET *target=talloc(mem_ctx, TR_FILTER_TARGET);
+  if (target) {
+    target->trp_inforec=NULL;
+    target->comm=NULL;
+    target->realm=NULL;
+    target->tid_req=NULL;
+  }
+  return target;
+}
+void tr_filter_target_free(TR_FILTER_TARGET *target)
+{
+  talloc_free(target);
+}
+
+/**
+ * Create a filter target for a TID request. Does not change the context of the request,
+ * so this is only valid until that is freed.
+ *
+ * @param mem_ctx talloc context for the object
+ * @param req TID request object
+ * @return pointer to a TR_FILTER_TARGET structure, or null on allocation failure
+ */
+TR_FILTER_TARGET *tr_filter_target_tid_req(TALLOC_CTX *mem_ctx, TID_REQ *req)
+{
+  TR_FILTER_TARGET *target=tr_filter_target_new(mem_ctx);
+  if (target)
+    target->tid_req=req; /* borrowed, not adding to our context */
+  return target;
+}
+
+/**
+ * Create a filter target for a TRP inforec. Does not change the context of the inforec or duplicate TR_NAMEs,
+ * so this is only valid until those are freed.
+ *
+ * @param mem_ctx talloc context for the object
+ * @param inforec TRP inforec
+ * @param realm realm name
+ * @param comm community name
+ * @return pointer to a TR_FILTER_TARGET structure, or null on allocation failure
+ */
+TR_FILTER_TARGET *tr_filter_target_trp_inforec(TALLOC_CTX *mem_ctx, TRP_INFOREC *inforec, TR_NAME *realm, TR_NAME *comm)
+{
+  TR_FILTER_TARGET *target=tr_filter_target_new(mem_ctx);
+  if (target) {
+    target->trp_inforec = inforec; /* borrowed, not adding to our context */
+    target->realm=realm;
+    target->comm=comm;
+  }
+  return target;
+}
+
+static int tr_ff_cmp_tid_rp_realm(TR_FILTER_TARGET *target, TR_NAME *val)
+{
+  TID_REQ *req=target->tid_req;
   assert(req);
   return 0==tr_name_cmp(val, req->rp_realm);
 }
 
-static TR_NAME *tr_ff_get_tid_rp_realm(void *rp_req_arg)
+static TR_NAME *tr_ff_get_tid_rp_realm(TR_FILTER_TARGET *target)
 {
-  TID_REQ *req=talloc_get_type_abort(rp_req_arg, TID_REQ);
+  TID_REQ *req=target->tid_req;
   assert(req);
   return tr_dup_name(req->rp_realm);
 }
 
-static int tr_ff_cmp_trp_info_type(void *inforec_arg, TR_NAME *val)
+static int tr_ff_cmp_trp_info_type(TR_FILTER_TARGET *target, TR_NAME *val)
 {
-  TRP_INFOREC *inforec=talloc_get_type_abort(inforec_arg, TRP_INFOREC);
+  TRP_INFOREC *inforec=target->trp_inforec;
   char *valstr=NULL;
   int val_type=0;
 
@@ -118,9 +170,9 @@ static int tr_ff_cmp_trp_info_type(void *inforec_arg, TR_NAME *val)
   return (val_type==inforec->type);
 }
 
-static TR_NAME *tr_ff_get_trp_info_type(void *inforec_arg)
+static TR_NAME *tr_ff_get_trp_info_type(TR_FILTER_TARGET *target)
 {
-  TRP_INFOREC *inforec=talloc_get_type_abort(inforec_arg, TRP_INFOREC);
+  TRP_INFOREC *inforec=target->trp_inforec;
   return tr_new_name(trp_inforec_type_to_string(inforec->type));
 }
 
@@ -141,7 +193,7 @@ static TR_NAME *tr_ff_get_trp_info_type(void *inforec_arg)
  * @param out_action Action to be carried out (output)
  * @return TR_FILTER_MATCH or TR_FILTER_NO_MATCH
  */
-int tr_filter_apply(void *target,
+int tr_filter_apply(TR_FILTER_TARGET *target,
                     TR_FILTER *filt,
                     TR_CONSTRAINT_SET **constraints,
                     TR_FILTER_ACTION *out_action)
@@ -243,7 +295,7 @@ void tr_fspec_add_match(TR_FSPEC *fspec, TR_NAME *match)
 }
 
 /* returns 1 if the spec matches */
-int tr_fspec_matches(TR_FSPEC *fspec, TR_FILTER_TYPE ftype, void *target)
+int tr_fspec_matches(TR_FSPEC *fspec, TR_FILTER_TYPE ftype, TR_FILTER_TARGET *target)
 {
   struct tr_filter_field_entry *field=NULL;
   TR_NAME *name=NULL;
index bbee2dc..0fe8dbd 100644 (file)
@@ -91,6 +91,19 @@ struct tr_filter_set {
   TR_FILTER_SET *next;
 };
 
+/**
+ * Structure to hold information needed to filter different targets.
+ */
+typedef struct tr_filter_target {
+  /* An inforec also needs realm and community information */
+  TRP_INFOREC *trp_inforec;
+  TR_NAME *realm;
+  TR_NAME *comm;
+
+  /* a TID request has all the data it needs to be filtered */
+  TID_REQ *tid_req;
+} TR_FILTER_TARGET;
+
 TR_FILTER_SET *tr_filter_set_new(TALLOC_CTX *mem_ctx);
 void tr_filter_set_free(TR_FILTER_SET *fs);
 int tr_filter_set_add(TR_FILTER_SET *set, TR_FILTER *new);
@@ -114,13 +127,16 @@ void tr_fspec_free(TR_FSPEC *fspec);
 
 void tr_fspec_add_match(TR_FSPEC *fspec, TR_NAME *match);
 
-int tr_fspec_matches(TR_FSPEC *fspec, TR_FILTER_TYPE ftype, void *target);
+int tr_fspec_matches(TR_FSPEC *fspec, TR_FILTER_TYPE ftype, TR_FILTER_TARGET *target);
 
 
 /*In tr_constraint.c and exported, but not really a public symbol; needed by tr_filter.c and by tr_constraint.c*/
 int TR_EXPORT tr_prefix_wildcard_match(const char *str, const char *wc_str);
 
-int tr_filter_apply(void *target, TR_FILTER *filt, TR_CONSTRAINT_SET **constraints, TR_FILTER_ACTION *out_action);
+int tr_filter_apply(TR_FILTER_TARGET *target, TR_FILTER *filt, TR_CONSTRAINT_SET **constraints, TR_FILTER_ACTION *out_action);
+void tr_filter_target_free(TR_FILTER_TARGET *target);
+TR_FILTER_TARGET *tr_filter_target_tid_req(TALLOC_CTX *mem_ctx, TID_REQ *req);
+TR_FILTER_TARGET *tr_filter_target_trp_inforec(TALLOC_CTX *mem_ctx, TRP_INFOREC *inforec, TR_NAME *realm, TR_NAME *comm);
 
 TR_CONSTRAINT_SET *tr_constraint_set_from_fline(TR_FLINE *fline);
 
index ee3fe1c..6bc002a 100644 (file)
@@ -261,6 +261,7 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
   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;
+  TR_FILTER_TARGET *target=NULL;
   int ii=0;
   int retval=-1;
 
@@ -306,12 +307,18 @@ static int tr_tids_req_handler(TIDS_INSTANCE *tids,
    * well. Need to verify that this is acceptable behavior, but it's what we've always done. */
   fwd_req->cons=orig_req->cons;
 
-  if ((TR_FILTER_NO_MATCH == tr_filter_apply(orig_req,
-                                             tr_filter_set_get(tids->rp_gss->filters,
-                                                               TR_FILTER_TYPE_TID_INBOUND),
-                                             &(fwd_req->cons),
-                                             &oaction)) ||
-      (TR_FILTER_ACTION_ACCEPT != oaction)) {
+  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!");
+  }
+  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)) {
     tr_notice("tr_tids_req_handler: RP realm (%s) does not match RP Realm filter for GSS name", orig_req->rp_realm->buf);
     tids_send_err_response(tids, orig_req, "RP Realm filter error");
     retval=-1;
index aef4b36..61c02e8 100644 (file)
@@ -1009,12 +1009,16 @@ cleanup:
  * @param trps Active TRPS instance
  * @param peer_name Name of peer that sent this inforec
  * @param rec Inforec to filter
+ * @param realm Name of realm
+ * @param comm Name of community
  * @return 1 if accepted by the filter, 0 otherwise
  */
-static int trps_filter_inbound_inforec(TRPS_INSTANCE *trps, TR_NAME *peer_name, TRP_INFOREC *rec)
+static int trps_filter_inbound_inforec(TRPS_INSTANCE *trps, TR_NAME *peer_name, TRP_INFOREC *rec, TR_NAME *realm, TR_NAME *comm)
 {
   TRP_PEER *peer=NULL;
   TR_FILTER_ACTION action=TR_FILTER_ACTION_REJECT;
+  TR_FILTER_TARGET *target=NULL;
+  int retval=0;
 
   /* Look up the peer. For inbound messages, the peer is identified by its GSS name */
   peer=trps_get_peer_by_gssname(trps, peer_name);
@@ -1026,17 +1030,26 @@ static int trps_filter_inbound_inforec(TRPS_INSTANCE *trps, TR_NAME *peer_name,
   }
 
   /* tr_filter_apply() and tr_filter_set_get() handle null filter sets/filters by rejecting */
-  if ((TR_FILTER_NO_MATCH==tr_filter_apply(rec,
-                                           tr_filter_set_get(peer->filters, TR_FILTER_TYPE_TRP_INBOUND),
-                                           NULL,
-                                           &action))
+  target=tr_filter_target_trp_inforec(NULL, rec, realm, comm);
+  if (target==NULL) {
+    /* TODO: signal that filtering failed. Until then, just filter everything and give an error message. */
+    tr_crit("trps_filter_inbound_inforec: Unable to allocate filter target, cannot apply filter!");
+  }
+  if ((target==NULL)
+      || (TR_FILTER_NO_MATCH==tr_filter_apply(target,
+                                              tr_filter_set_get(peer->filters, TR_FILTER_TYPE_TRP_INBOUND),
+                                              NULL,
+                                              &action))
       || (action!=TR_FILTER_ACTION_ACCEPT)) {
-    /* either the filter did not match or it matched a reject rule */
-    return 0;
-  }
+    /* either the filter did not match or it matched a reject rule or allocating the target failed */
+    retval=0;
+  } else
+    retval=1;
+  if (target!=NULL)
+    tr_filter_target_free(target);
 
   /* filter matched an accept rule */
-  return 1;
+  return retval;
 }
 
 
@@ -1058,7 +1071,11 @@ static TRP_RC trps_handle_update(TRPS_INSTANCE *trps, TRP_UPD *upd)
   }
 
   for (rec=trp_upd_get_inforec(upd); rec!=NULL; rec=trp_inforec_get_next(rec)) {
-    if (!trps_filter_inbound_inforec(trps, trp_upd_get_peer(upd), rec)) {
+    if (!trps_filter_inbound_inforec(trps,
+                                     trp_upd_get_peer(upd),
+                                     rec,
+                                     trp_upd_get_realm(upd),
+                                     trp_upd_get_comm(upd))) {
       tr_debug("trps_handle_update: inforec rejected by filter.");
       continue; /* just go on to the next record */
     }
@@ -1662,14 +1679,24 @@ static void trps_filter_one_outbound_update(TR_FILTER *filt, TRP_UPD *upd)
 {
   TRP_INFOREC *this=NULL, *next=NULL;
   TR_FILTER_ACTION action=TR_FILTER_ACTION_REJECT;
+  TR_FILTER_TARGET *target=NULL;
 
   for(this=trp_upd_get_inforec(upd); this!=NULL; this=next) {
     next=this->next;
-    if ((TR_FILTER_NO_MATCH==tr_filter_apply(this, filt, NULL, &action))
+    target=tr_filter_target_trp_inforec(NULL, this, trp_upd_get_realm(upd), trp_upd_get_comm(upd));
+    if (target==NULL) {
+      /* TODO: signal that filtering failed. Until then, just filter everything and give an error message. */
+      tr_crit("trps_filter_one_outbound_update: Unable to allocate filter target, cannot apply filter!");
+    }
+    if ((target==NULL)
+        || (TR_FILTER_NO_MATCH==tr_filter_apply(target, filt, NULL, &action))
         || (action!=TR_FILTER_ACTION_ACCEPT)) {
-      /* Either no filter matched or one matched and rejected this record */
+      /* Either no filter matched or one matched and rejected this record.
+       * Also filter out record if we were unable to allocate a target. */
       trp_upd_remove_inforec(upd, this); /* "this" is now invalid */
     }
+    if (target!=NULL)
+      tr_filter_target_free(target);
   }
 }
 
@@ -1704,8 +1731,8 @@ static void trps_trp_upd_destroy(gpointer data)
 static TRP_RC trps_update_one_peer(TRPS_INSTANCE *trps,
                                    TRP_PEER *peer,
                                    TRP_UPDATE_TYPE update_type,
-                                   TR_NAME *comm,
-                                   TR_NAME *realm)
+                                   TR_NAME *realm,
+                                   TR_NAME *comm)
 {
   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
   TR_MSG msg; /* not a pointer! */
@@ -1932,8 +1959,8 @@ static TRP_RC trps_handle_request(TRPS_INSTANCE *trps, TRP_REQ *req)
   return trps_update_one_peer(trps,
                               trps_get_peer_by_gssname(trps, trp_req_get_peer(req)),
                               TRP_UPDATE_REQUESTED,
-                              comm,
-                              realm);
+                              realm,
+                              comm);
 }