identification_t.matches() supports multiple wildcard counts
authorAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 11 Jul 2006 06:11:59 +0000 (06:11 -0000)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 11 Jul 2006 06:11:59 +0000 (06:11 -0000)
src/libstrongswan/utils/identification.c
src/libstrongswan/utils/identification.h

index 69de9b3..f80e21c 100644 (file)
 /** 
  * String mappings for id_type_t.
  */
-mapping_t id_type_m[] = {
-       {ID_IPV4_ADDR,   "ID_IPV4_ADDR"},
-       {ID_FQDN,                "ID_FQDN"},
-       {ID_RFC822_ADDR, "ID_RFC822_ADDR"},
-       {ID_IPV6_ADDR,   "ID_IPV6_ADDR"},
-       {ID_DER_ASN1_DN, "ID_DER_ASN1_DN"},
-       {ID_DER_ASN1_GN, "ID_DER_ASN1_GN"},
-       {ID_KEY_ID,              "ID_KEY_ID"},
-       {ID_ANY,                 "ID_ANY"},
-       {MAPPING_END, NULL}
+
+static const char *const id_type_name[] = {
+       "ID_ANY",
+       "ID_IPV4_ADDR",
+       "ID_FQDN",
+       "ID_RFC822_ADDR",
+       "ID_IPV4_ADDR_SUBNET",
+       "ID_IPV6_ADDR",
+       "ID_IPV6_ADDR_SUBNET",
+       "ID_IPV4_ADDR_RANGE",
+       "ID_IPV6_ADDR_RANGE",
+       "ID_DER_ASN1_DN",
+       "ID_DER_ASN1_GN",
+       "ID_KEY_ID",
 };
 
+enum_names id_type_names =
+    { ID_ANY, ID_KEY_ID, id_type_name, NULL };
+
 /**
  * X.501 acronyms for well known object identifiers (OIDs)
  */
@@ -513,7 +520,9 @@ bool match_dn(chunk_t a, chunk_t b, int *wildcards)
        {
                return FALSE;
        }
+
        /* the two DNs match! */
+       *wildcards = min(*wildcards, MAX_WILDCARDS);
        return TRUE;
 }
 
@@ -680,11 +689,11 @@ static char *get_string(private_identification_t *this)
  */
 static bool contains_wildcards(private_identification_t *this)
 {
-       return this->type == ID_ANY || memchr(this->encoded.ptr, '*', this->encoded.len) != NULL;
+       return this->type == ID_ANY || strchr(this->string, '*') != NULL;
 }
 
 /**
- * Default implementation of identification_t.equals and identification_t.belongs_to.
+ * Default implementation of identification_t.equals.
  * compares encoded chunk for equality.
  */
 static bool equals_binary(private_identification_t *this, private_identification_t *other)
@@ -693,7 +702,7 @@ static bool equals_binary(private_identification_t *this, private_identification
 }
 
 /**
- * Special implementation of identification_t.equals for ID_DER_ASN1_DN
+ * Special implementation of identification_t.equals for ID_DER_ASN1_DN.
  */
 static bool equals_dn(private_identification_t *this, private_identification_t *other)
 {
@@ -701,76 +710,86 @@ static bool equals_dn(private_identification_t *this, private_identification_t *
 }
 
 /**
- * Special implementation of identification_t.belongs_to for ID_RFC822_ADDR/ID_FQDN.
- * checks for a wildcard in other-string, and compares it against this-string.
+ * Default implementation of identification_t.matches.
  */
-static bool belongs_to_wc_string(private_identification_t *this, private_identification_t *other)
+static bool matches_binary(private_identification_t *this, private_identification_t *other,
+       int *wildcards)
+{      
+       *wildcards = 0;
+       return this->type == other->type && chunk_equals(this->encoded, other->encoded);
+}
+
+/**
+ * Special implementation of identification_t.matches for ID_RFC822_ADDR/ID_FQDN.
+ * Checks for a wildcard in other-string, and compares it against this-string.
+ */
+static bool matches_string(private_identification_t *this, private_identification_t *other,
+       int *wildcards)
 {
-       char *this_str, *other_str, *pos;
+       u_int len = other->encoded.len;
        
        if (other->type == ID_ANY)
        {
+               *wildcards = MAX_WILDCARDS;
                return TRUE;
        }
        
-       if (this->type == other->type)
+       if (this->type != other->type)
+               return FALSE;
+
+       /* try a binary comparison first */
+       if (equals_binary(this, other))
        {
-               /* try a binary comparison first */
-               if (equals_binary(this, other))
-               {
-                       return TRUE;
-               }
+               *wildcards = 0;
+               return TRUE;
        }
-       if (other->encoded.len > 0 &&
-                  *(other->encoded.ptr) == '*')
+       
+       if (len == 0 || this->encoded.len < len)
+               return FALSE;
+
+       /* check for single wildcard at the head of the string */
+       if (*other->encoded.ptr == '*')
        {
-               if (other->encoded.len == 1)
-               {
-                       /* other contains just a wildcard, and therefore matches anything */
+               *wildcards = 1;
+
+               /* single asterisk matches any string */
+               if (len-- == 1)
+                       return TRUE;
+
+               if (memeq(this->encoded.ptr + this->encoded.len - len, other->encoded.ptr + 1, len))
                        return TRUE;
-               }
-               /* We strdup chunks, since they are NOT null-terminated */
-               this_str = strndupa(this->encoded.ptr, this->encoded.len);
-               other_str = strndupa(other->encoded.ptr + 1, other->encoded.len - 1);
-               pos = strstr(this_str, other_str);
-               if (pos != NULL)
-               {
-                       /* ok, other is contained in this, but there may be more characters, so check it */
-                       if (strlen(pos) == strlen(other_str))
-                       {
-                               return TRUE;
-                       }
-               }
        }
        
        return FALSE;
 }
 
 /**
- * Special implementation of identification_t.belongs_to for ID_ANY.
+ * Special implementation of identification_t.matches for ID_ANY.
  * ANY matches only another ANY, but nothing other
  */
-static bool belongs_to_any(private_identification_t *this, private_identification_t *other)
+static bool matches_any(private_identification_t *this, private_identification_t *other,
+       int *wildcards)
 {      
+       *wildcards = 0;
        return other->type == ID_ANY;
 }
 
 /**
- * Special implementation of identification_t.belongs_to for ID_DER_ASN1_DN.
+ * Special implementation of identification_t.matches for ID_DER_ASN1_DN.
  * ANY matches any, even ANY, thats why its there...
  */
-static bool belongs_to_dn(private_identification_t *this, private_identification_t *other)
+static bool matches_dn(private_identification_t *this, private_identification_t *other,
+       int *wildcards)
 {
-       int wildcards;
-       
        if (other->type == ID_ANY)
        {
+               *wildcards = MAX_WILDCARDS;
                return TRUE;
        }
        
        if (this->type == other->type)
        {
-               return match_dn(this->encoded, other->encoded, &wildcards);
+               return match_dn(this->encoded, other->encoded, wildcards);
        }
        return FALSE;
 }
@@ -788,7 +807,7 @@ static identification_t *clone(private_identification_t *this)
        strcpy(clone->string, this->string);
        
        clone->public.equals = this->public.equals;
-       clone->public.belongs_to = this->public.belongs_to;
+       clone->public.matches = this->public.matches;
        
        return &clone->public;
 }
@@ -818,7 +837,7 @@ static private_identification_t *identification_create(void)
        this->public.destroy = (void (*) (identification_t*))destroy;
        /* we use these as defaults, the may be overloaded for special ID types */
        this->public.equals = (bool (*) (identification_t*,identification_t*))equals_binary;
-       this->public.belongs_to = (bool (*) (identification_t*,identification_t*))equals_binary;
+       this->public.matches = (bool (*) (identification_t*,identification_t*,int*))matches_binary;
        
        this->string = NULL;
        this->encoded = CHUNK_INITIALIZER;
@@ -849,7 +868,7 @@ identification_t *identification_create_from_string(char *string)
                this->string = strdup(string);
                this->type = ID_DER_ASN1_DN;
                this->public.equals = (bool (*) (identification_t*,identification_t*))equals_dn;
-               this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_dn;
+               this->public.matches = (bool (*) (identification_t*,identification_t*,int*))matches_dn;
                return &this->public;
        }
        else if (strchr(string, '@') == NULL)
@@ -863,7 +882,7 @@ identification_t *identification_create_from_string(char *string)
                        /* any ID will be accepted */
                        this->type = ID_ANY;
                        this->string = strdup("%any");
-                       this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_any;
+                       this->public.matches = (bool (*) (identification_t*,identification_t*,int*))matches_any;
                        return &this->public;
                }
                else
@@ -908,8 +927,7 @@ identification_t *identification_create_from_string(char *string)
                {
                        if (*(string + 1) == '#')
                        {
-                               /* TODO: Pluto handles '#' as hex encoded ASN1/KEY ID. Do we need this, too?
-                   Yes, key IDs are needed */
+                               /* TODO: Pluto handles '#' as hex encoded ID_KEY_ID. */
                                free(this);
                                return NULL;
                        }
@@ -919,7 +937,7 @@ identification_t *identification_create_from_string(char *string)
                                this->string = strdup(string);
                                this->encoded.ptr = strdup(string + 1);
                                this->encoded.len = strlen(string + 1);
-                               this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
+                               this->public.matches = (bool (*) (identification_t*,identification_t*,int*))matches_string;
                                return &(this->public);
                        }
                }
@@ -929,7 +947,7 @@ identification_t *identification_create_from_string(char *string)
                        this->string = strdup(string);
                        this->encoded.ptr = strdup(string);
                        this->encoded.len = strlen(string);
-                       this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
+                       this->public.matches = (bool (*) (identification_t*,identification_t*,int*))matches_string;
                        return &(this->public);
                }
        }
@@ -946,11 +964,12 @@ identification_t *identification_create_from_encoding(id_type_t type, chunk_t en
        private_identification_t *this = identification_create();
        
        this->type = type;
+
        switch (type)
        {
                case ID_ANY:
                        this->string = strdup("%any");
-                       this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_any;
+                       this->public.matches = (bool (*) (identification_t*,identification_t*,int*))matches_any;
                        break;
                case ID_IPV4_ADDR:
                        if (encoded.len < sizeof(struct in_addr) ||
@@ -977,12 +996,12 @@ identification_t *identification_create_from_encoding(id_type_t type, chunk_t en
                case ID_FQDN:
                        snprintf(buf, sizeof(buf), "@%.*s", encoded.len, encoded.ptr);
                        this->string = strdup(buf);
-                       this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
+                       this->public.matches = (bool (*) (identification_t*,identification_t*,int*))matches_string;
                        break;
                case ID_RFC822_ADDR:
                        snprintf(buf, sizeof(buf), "%.*s", encoded.len, encoded.ptr);
                        this->string = strdup(buf);
-                       this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
+                       this->public.matches = (bool (*) (identification_t*,identification_t*,int*))matches_string;
                        break;
                case ID_DER_ASN1_DN:
                        snprintf(buf, sizeof(buf), "%.*s", encoded.len, encoded.ptr);
@@ -990,7 +1009,7 @@ identification_t *identification_create_from_encoding(id_type_t type, chunk_t en
                        dntoa(encoded, &buf_chunk);
                        this->string = strdup(buf);
                        this->public.equals = (bool (*) (identification_t*,identification_t*))equals_dn;
-                       this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_dn;
+                       this->public.matches = (bool (*) (identification_t*,identification_t*,int*))matches_dn;
                        break;
                case ID_DER_ASN1_GN:
                        this->string = strdup("ASN.1 coded generalName");
index f6b82e9..5b13d02 100644 (file)
 #ifndef IDENTIFICATION_H_
 #define IDENTIFICATION_H_
 
-
 #include "types.h"
 
+#define MAX_WILDCARDS     14
+
 typedef enum id_type_t id_type_t;
 
 /**
@@ -36,7 +37,7 @@ typedef enum id_type_t id_type_t;
  * @ingroup utils
  */
 enum id_type_t {
-       
+
        /**
         * private type which matches any other id.
         */
@@ -49,40 +50,58 @@ enum id_type_t {
 
        /**
         * ID data is a fully-qualified domain name string.
-        * An example of a ID_FQDN is, "example.com".
+        * An example of a ID_FQDN is "example.com".
         * The string MUST not contain any terminators (e.g., NULL, CR, etc.).
         */
        ID_FQDN = 2,
-       
+
        /**
-        * ID data is a fully-qualified RFC822 email address string, An example of
-        * a ID_RFC822_ADDR is, "jsmith@example.com".  The string MUST
-        * not contain any terminators.
+        * ID data is a fully-qualified RFC822 email address string.
+        * An example of an ID_RFC822_ADDR is "jsmith@example.com".
+        * The string MUST NOT contain any terminators.
         */
        ID_RFC822_ADDR = 3,
-       
+
+       /**
+        * ID data is an IPv4 subnet (IKEv1 only)
+        */
+       ID_IPV4_ADDR_SUBNET = 4,
+
        /**
         * ID data is a single sixteen (16) octet IPv6 address.
         */
        ID_IPV6_ADDR = 5,
-       
+
        /**
-        * ID data is the binary DER encoding of an ASN.1 X.500 Distinguished Name
-     * [X.501].
-     */
+        * ID data is an IPv6 subnet (IKEv1 only)
+        */
+       ID_IPV6_ADDR_SUBNET = 6,
+
+       /**
+        * ID data is an IPv4 address range (IKEv1 only)
+        */
+       ID_IPV4_ADDR_RANGE = 7,
+
+       /**
+        * ID data is an IPv6 address range (IKEv1 only)
+        */
+       ID_IPV6_ADDR_RANGE = 8,
+
+       /**
+        * ID data is the binary DER encoding of an ASN.1 X.501 Distinguished Name
+        */
        ID_DER_ASN1_DN = 9,
-       
+
        /**
-        * ID data is the binary DER encoding of an ASN.1 X.500 GeneralName
-     * [X.509].
-     */
+        * ID data is the binary DER encoding of an ASN.1 X.509 GeneralName
+        */
        ID_DER_ASN1_GN = 10,
-       
+
        /**
         * ID data is an opaque octet stream which may be used to pass vendor-
-     * specific information necessary to do certain proprietary
-     * types of identification.
-     */
+        * specific information necessary to do certain proprietary
+        * types of identification.
+        */
        ID_KEY_ID = 11,
 
        /**
@@ -95,7 +114,7 @@ enum id_type_t {
 /**
  * String mappings for id_type_t.
  */
-extern mapping_t id_type_m[];
+extern enum_names id_type_names;
 
 typedef struct identification_t identification_t;
 
@@ -162,7 +181,7 @@ struct identification_t {
        bool (*equals) (identification_t *this, identification_t *other);
        
        /**
-        * @brief Check if an ID belongs to a wildcard ID.
+        * @brief Check if an ID matches a wildcard ID.
         * 
         * An identification_t may contain wildcards, such as
         * *@strongswan.org. This call checks if a given ID
@@ -174,9 +193,10 @@ struct identification_t {
         * 
         * @param this          the ID without wildcard
         * @param other         the ID containing a wildcard
-        * @return                      TRUE if other belongs to this
+        * @param wildcards     returns the number of wildcards
+        * @return                      TRUE if match is found
         */
-       bool (*belongs_to) (identification_t *this, identification_t *other);
+       bool (*matches) (identification_t *this, identification_t *other, int *wildcards);
        
        /**
         * @brief Check if an ID is a wildcard ID.
@@ -243,7 +263,7 @@ identification_t * identification_create_from_string(char *string);
  * @return                     identification_t object
  *
  * In contrast to identification_create_from_string(), this constructor never
- * returns NULL, even when the conversion to a sring representation fails.
+ * returns NULL, even when the conversion to a string representation fails.
  *
  * @ingroup utils
  */