Added support for named attribute groups
authorHeiko Hund <hhund@astaro.com>
Wed, 7 Jul 2010 14:45:36 +0000 (16:45 +0200)
committerMartin Willi <martin@revosec.ch>
Fri, 9 Jul 2010 11:09:31 +0000 (13:09 +0200)
Add the possibility to group attributes by a name and assign these
groups to connections. This allows a more granular configuration of
which client will receive what atrributes.

12 files changed:
src/libcharon/sa/tasks/ike_config.c
src/libhydra/attributes/attribute_manager.c
src/libhydra/attributes/attribute_manager.h
src/libhydra/attributes/attribute_provider.h
src/libhydra/plugins/attr/attr_provider.c
src/libhydra/plugins/attr_sql/pool.c
src/libhydra/plugins/attr_sql/pool_attributes.c
src/libhydra/plugins/attr_sql/pool_attributes.h
src/libhydra/plugins/attr_sql/pool_usage.c
src/libhydra/plugins/attr_sql/sql_attribute.c
src/pluto/modecfg.c
testing/hosts/default/etc/ipsec.d/tables.sql

index c980b20..c92b5bc 100644 (file)
@@ -342,7 +342,7 @@ static status_t build_r(private_ike_config_t *this, message_t *message)
 
                /* query registered providers for additional attributes to include */
                enumerator = hydra->attributes->create_responder_enumerator(
-                                                                                                       hydra->attributes, id, vip);
+                                               hydra->attributes, config->get_pool(config), id, vip);
                while (enumerator->enumerate(enumerator, &type, &value))
                {
                        if (!cp)
index 3080b56..0d4cbda 100644 (file)
@@ -51,6 +51,8 @@ struct private_attribute_manager_t {
  * Data to pass to enumerator filters
  */
 typedef struct {
+       /** attribute group pool */
+       char *pool;
        /** server/peer identity */
        identification_t *id;
        /** requesting/assigned virtual IP */
@@ -123,17 +125,20 @@ static void release_address(private_attribute_manager_t *this,
 static enumerator_t *responder_enum_create(attribute_provider_t *provider,
                                                                                   enum_data_t *data)
 {
-       return provider->create_attribute_enumerator(provider, data->id, data->vip);
+       return provider->create_attribute_enumerator(provider, data->pool,
+                                                                                                data->id, data->vip);
 }
 
 /**
  * Implementation of attribute_manager_t.create_responder_enumerator
  */
 static enumerator_t* create_responder_enumerator(
-                       private_attribute_manager_t *this, identification_t *id, host_t *vip)
+                                                               private_attribute_manager_t *this, char *pool,
+                                                               identification_t *id, host_t *vip)
 {
        enum_data_t *data = malloc_thing(enum_data_t);
 
+       data->pool = pool;
        data->id = id;
        data->vip = vip;
        this->lock->read_lock(this->lock);
@@ -355,7 +360,7 @@ attribute_manager_t *attribute_manager_create()
 
        this->public.acquire_address = (host_t*(*)(attribute_manager_t*, char*, identification_t*,host_t*))acquire_address;
        this->public.release_address = (void(*)(attribute_manager_t*, char *, host_t*, identification_t*))release_address;
-       this->public.create_responder_enumerator = (enumerator_t*(*)(attribute_manager_t*, identification_t*, host_t*))create_responder_enumerator;
+       this->public.create_responder_enumerator = (enumerator_t*(*)(attribute_manager_t*, char *name, identification_t*, host_t*))create_responder_enumerator;
        this->public.add_provider = (void(*)(attribute_manager_t*, attribute_provider_t *provider))add_provider;
        this->public.remove_provider = (void(*)(attribute_manager_t*, attribute_provider_t *provider))remove_provider;
        this->public.handle = (attribute_handler_t*(*)(attribute_manager_t*,identification_t*, attribute_handler_t*, configuration_attribute_type_t, chunk_t))handle;
index 6426623..56afef7 100644 (file)
@@ -61,12 +61,13 @@ struct attribute_manager_t {
        /**
         * Create an enumerator over attributes to hand out to a peer.
         *
+        * @param pool                  pool name to get attributes from
         * @param id                    peer identity to hand out attributes to
         * @param vip                   virtual IP to assign to peer, if any
         * @return                              enumerator (configuration_attribute_type_t, chunk_t)
         */
        enumerator_t* (*create_responder_enumerator)(attribute_manager_t *this,
-                                                                                       identification_t *id, host_t *vip);
+                                                               char *pool, identification_t *id, host_t *vip);
 
        /**
         * Register an attribute provider to the manager.
index f8485cc..e4b4e13 100644 (file)
@@ -56,12 +56,13 @@ struct attribute_provider_t {
        /**
         * Create an enumerator over attributes to hand out to a peer.
         *
+        * @param pool                  pool name to get attributes from
         * @param id                    peer ID
         * @param vip                   virtual IP to assign to peer, if any
         * @return                              enumerator (configuration_attribute_type_t, chunk_t)
         */
        enumerator_t* (*create_attribute_enumerator)(attribute_provider_t *this,
-                                                                                       identification_t *id, host_t *vip);
+                                                       char *pool, identification_t *id, host_t *vip);
 };
 
 #endif /** ATTRIBUTE_PROVIDER_H_ @}*/
index cd504e0..b3c0cc0 100644 (file)
@@ -65,7 +65,7 @@ static bool attr_enum_filter(void *null, attribute_entry_t **in,
  * Implementation of attribute_provider_t.create_attribute_enumerator
  */
 static enumerator_t* create_attribute_enumerator(private_attr_provider_t *this,
-                                                                                       identification_t *id, host_t *vip)
+                                                               char *pool, identification_t *id, host_t *vip)
 {
        if (vip)
        {
@@ -250,7 +250,7 @@ attr_provider_t *attr_provider_create(database_t *db)
 
        this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *, host_t *))return_null;
        this->public.provider.release_address = (bool(*)(attribute_provider_t *this, char*,host_t *, identification_t*))return_false;
-       this->public.provider.create_attribute_enumerator = (enumerator_t*(*)(attribute_provider_t*, identification_t *id, host_t *vip))create_attribute_enumerator;
+       this->public.provider.create_attribute_enumerator = (enumerator_t*(*)(attribute_provider_t*, char *names, identification_t *id, host_t *vip))create_attribute_enumerator;
        this->public.destroy = (void(*)(attr_provider_t*))destroy;
 
        this->attributes = linked_list_create();
index e54d764..b4bdfc6 100644 (file)
@@ -390,29 +390,14 @@ static bool add_address(u_int pool_id, char *address_str, int *family)
        char *pos_eq = strchr(address_str, '=');
        if (pos_eq != NULL)
        {
-               enumerator_t *e;
                identification_t *id = identification_create_from_string(pos_eq + 1);
+               user_id = get_identity(id);
+               id->destroy(id);
 
-               /* look for peer identity in the identities table */
-               e = db->query(db,
-                               "SELECT id FROM identities WHERE type = ? AND data = ?",
-                               DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id),
-                               DB_UINT);
-
-               if (!e || !e->enumerate(e, &user_id))
+               if (user_id == 0)
                {
-                       /* not found, insert new one */
-                       if (db->execute(db, &user_id,
-                                       "INSERT INTO identities (type, data) VALUES (?, ?)",
-                                       DB_INT, id->get_type(id),
-                                       DB_BLOB, id->get_encoding(id)) != 1)
-                       {
-                               fprintf(stderr, "creating id '%s' failed.\n", pos_eq + 1);
-                               return FALSE;
-                       }
+                       return FALSE;
                }
-               DESTROY_IF(e);
-               id->destroy(id);
                *pos_eq = '\0';
        }
 
@@ -943,7 +928,8 @@ static void cleanup(void)
 
 static void do_args(int argc, char *argv[])
 {
-       char *name = "", *value = "", *filter = "", *addresses = NULL;
+       char *name = "", *value = "", *filter = "";
+       char *pool = NULL, *identity = NULL, *addresses = NULL;
        value_type_t value_type = VALUE_NONE;
        int timeout = 0;
        bool utc = FALSE, hexout = FALSE;
@@ -1000,6 +986,8 @@ static void do_args(int argc, char *argv[])
                        { "string", required_argument, NULL, 'g' },
                        { "hex", required_argument, NULL, 'x' },
                        { "hexout", no_argument, NULL, '5' },
+                       { "pool", required_argument, NULL, '6' },
+                       { "identity", required_argument, NULL, '7' },
                        { 0,0,0,0 }
                };
 
@@ -1122,6 +1110,12 @@ static void do_args(int argc, char *argv[])
                        case '5':
                                hexout = TRUE;
                                continue;
+                       case '6':
+                               pool = optarg;
+                               continue;
+                       case '7':
+                               identity = optarg;
+                               continue;
                        default:
                                usage();
                                exit(EXIT_FAILURE);
@@ -1164,14 +1158,25 @@ static void do_args(int argc, char *argv[])
                                usage();
                                exit(EXIT_FAILURE);
                        }
-                       add_attr(name, value, value_type);
+                       if (identity && !pool)
+                       {
+                               fprintf(stderr, "--identity option can't be used without --pool.\n");
+                               usage();
+                               exit(EXIT_FAILURE);
+                       }
+                       add_attr(name, pool, identity, value, value_type);
                        break;
                case OP_DEL:
                        del(name);
                        break;
                case OP_DEL_ATTR:
-                       
-                       del_attr(name, value, value_type);
+                       if (identity && !pool)
+                       {
+                               fprintf(stderr, "--identity option can't be used without --pool.\n");
+                               usage();
+                               exit(EXIT_FAILURE);
+                       }
+                       del_attr(name, pool, identity, value, value_type);
                        break;
                case OP_SHOW_ATTR:
                        show_attr();
index 0ef1b4a..52efc63 100644 (file)
@@ -264,54 +264,165 @@ static bool parse_attributes(char *name, char *value, value_type_t *value_type,
 }
  
 /**
- * ipsec pool --addattr <type> --string|server|subnet - add attribute entry
+ * Lookup/insert an attribute pool by name
  */
-void add_attr(char *name, char *value, value_type_t value_type)
+static u_int get_attr_pool(char *name)
+{
+       enumerator_t *e;
+       u_int row = 0;
+
+       /* look for an existing attribute pool in the table */
+       e = db->query(db, "SELECT id FROM attribute_pools WHERE name = ?",
+                                 DB_TEXT, name, DB_UINT);
+       if (e && e->enumerate(e, &row))
+       {
+               e->destroy(e);
+               return row;
+       }
+       DESTROY_IF(e);
+       /* not found, insert new one */
+       if (db->execute(db, &row, "INSERT INTO attribute_pools (name) VALUES (?)",
+                                       DB_TEXT, name) != 1)
+       {
+               fprintf(stderr, "creating attribute pool '%s' failed.\n", name);
+               return 0;
+       }
+       return row;
+}
+
+/**
+ * Lookup/insert an identity
+ */
+u_int get_identity(identification_t *id)
+{
+       enumerator_t *e;
+       u_int row;
+
+       /* look for peer identity in the identities table */
+       e = db->query(db, "SELECT id FROM identities WHERE type = ? AND data = ?",
+                       DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id), DB_UINT);
+       if (e && e->enumerate(e, &row))
+       {
+               e->destroy(e);
+               return row;
+       }
+       DESTROY_IF(e);
+       /* not found, insert new one */
+       if (db->execute(db, &row, "INSERT INTO identities (type,data) VALUES (?,?)",
+                                 DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id)) != 1)
+       {
+               fprintf(stderr, "creating id '%Y' failed.\n", id);
+               return 0;
+       }
+       return row;
+}
+
+/**
+ * ipsec pool --addattr <type> - add attribute entry
+ */
+void add_attr(char *name, char *pool, char *identity,
+                         char *value, value_type_t value_type)
 {
        configuration_attribute_type_t type, type_ip6;
+       u_int pool_id = 0, identity_id = 0;
+       char id_pool_str[128] = "";
        chunk_t blob;
        bool success;
 
+       if (pool)
+       {
+               pool_id = get_attr_pool(pool);
+               if (pool_id == 0)
+               {
+                       exit(EXIT_FAILURE);
+               }
+
+               if (identity)
+               {
+                       identification_t *id = identification_create_from_string(identity);
+                       identity_id = get_identity(id);
+                       id->destroy(id);
+                       if (identity_id == 0)
+                       {
+                               exit(EXIT_FAILURE);
+                       }
+                       snprintf(id_pool_str, sizeof(id_pool_str),
+                                        " for '%Y' in pool '%s'", identity, pool);
+               }
+               else
+               {
+                       snprintf(id_pool_str, sizeof(id_pool_str), " in pool '%s'", pool);
+               }
+       }
+
        if (value_type == VALUE_NONE)
        {
                fprintf(stderr, "the value of the %s attribute is missing.\n", name);
                usage();
-               exit(EXIT_FAILURE);
-       }       
+       }
        if (!parse_attributes(name, value, &value_type, &type, &type_ip6, &blob))
        {
                exit(EXIT_FAILURE);
        }
 
        success = db->execute(db, NULL,
-                               "INSERT INTO attributes (type, value) VALUES (?, ?)",
+                               "INSERT INTO attributes (identity, pool, type, value) "
+                               "VALUES (?, ?, ?, ?)", DB_UINT, identity_id, DB_UINT, pool_id,
                                DB_INT, type, DB_BLOB, blob) == 1;
        free(blob.ptr);
 
        if (success)
        {
-               printf("added %s attribute (%N).\n", name,
-                               configuration_attribute_type_names, type);
+               printf("added %s attribute (%N)%s.\n", name,
+                          configuration_attribute_type_names, type, id_pool_str);
        }
        else
        {
-               fprintf(stderr, "adding %s attribute (%N) failed.\n", name,
-                                                configuration_attribute_type_names, type);
-               exit(EXIT_FAILURE);
+               fprintf(stderr, "adding %s attribute (%N)%s failed.\n", name,
+                                               configuration_attribute_type_names, type, id_pool_str);
        }
 }
 
 /**
- * ipsec pool --delattr <type> --string|server|subnet - delete attribute entry
+ * ipsec pool --delattr <type> - delete attribute entry
  */
-void del_attr(char *name, char *value, value_type_t value_type)
+void del_attr(char *name, char *pool, char *identity,
+                         char *value, value_type_t value_type)
 {
        configuration_attribute_type_t type, type_ip6, type_db;
+       u_int pool_id = 0, identity_id = 0;
+       char id_pool_str[128] = "";
        chunk_t blob, blob_db;
        u_int id;
        enumerator_t *query;
        bool found = FALSE;
 
+       if (pool)
+       {
+               pool_id = get_attr_pool(pool);
+               if (pool_id == 0)
+               {
+                       exit(EXIT_FAILURE);
+               }
+
+               if (identity)
+               {
+                       identification_t *id = identification_create_from_string(identity);
+                       identity_id = get_identity(id);
+                       id->destroy(id);
+                       if (identity_id == 0)
+                       {
+                               exit(EXIT_FAILURE);
+                       }
+                       snprintf(id_pool_str, sizeof(id_pool_str),
+                                        " for '%Y' in pool '%s'", identity, pool);
+               }
+               else
+               {
+                       snprintf(id_pool_str, sizeof(id_pool_str), " in pool '%s'", pool);
+               }
+       }
+
        if (!parse_attributes(name, value, &value_type, &type, &type_ip6, &blob))
        {
                exit(EXIT_FAILURE);
@@ -321,31 +432,31 @@ void del_attr(char *name, char *value, value_type_t value_type)
        {
                query = db->query(db,
                                        "SELECT id, type, value FROM attributes "
-                                       "WHERE type = ? AND value = ?",
-                                       DB_INT, type, DB_BLOB, blob,
-                                       DB_UINT, DB_INT, DB_BLOB);
+                                       "WHERE identity = ? AND pool = ? AND type = ? AND value = ?",
+                                       DB_UINT, identity_id, DB_UINT, pool_id, DB_INT, type,
+                                       DB_BLOB, blob, DB_UINT, DB_INT, DB_BLOB);
        }
        else if (type_ip6 == 0)
        {
                query = db->query(db,
                                        "SELECT id, type, value FROM attributes "
-                                       "WHERE type = ?",
-                                       DB_INT, type, 
+                                       "WHERE identity = ? AND pool = ? AND type = ?",
+                                       DB_UINT, identity_id, DB_UINT, pool_id, DB_INT, type,
                                        DB_UINT, DB_INT, DB_BLOB);
        }
        else
        {
                query = db->query(db,
                                        "SELECT id, type, value FROM attributes "
-                                       "WHERE type = ? OR type = ?",
-                                       DB_INT, type, DB_INT, type_ip6,
-                                       DB_UINT, DB_INT, DB_BLOB);
+                                       "WHERE identity = ? AND pool = ? AND (type = ? OR type = ?)",
+                                       DB_UINT, identity_id, DB_UINT, pool_id, DB_INT, type,
+                                       DB_INT, type_ip6, DB_UINT, DB_INT, DB_BLOB);
        }
 
        if (!query)
        {
-               fprintf(stderr, "deleting '%s' attribute (%N) failed.\n",
-                                                name, configuration_attribute_type_names, type);
+               fprintf(stderr, "deleting '%s' attribute (%N)%s failed.\n",
+                               name, configuration_attribute_type_names, type, id_pool_str);
                free(blob.ptr);
                exit(EXIT_FAILURE);
        }
@@ -369,21 +480,22 @@ void del_attr(char *name, char *value, value_type_t value_type)
                {
                        if (server)
                        {
-                               fprintf(stderr, "deleting %s server %H failed\n", name, server);
+                               fprintf(stderr, "deleting %s server %H%s failed\n",
+                                               name, server, id_pool_str);
                                server->destroy(server);
                        }
                        else if (value_type == VALUE_STRING)
                        {
-                               fprintf(stderr, "deleting %s attribute (%N) with value '%.*s' failed.\n",
+                               fprintf(stderr, "deleting %s attribute (%N) with value '%.*s'%s failed.\n",
                                                                name, configuration_attribute_type_names, type,
-                                                               blob_db.len, blob_db.ptr);
+                                                               blob_db.len, blob_db.ptr, id_pool_str);
                        }
 
                        else
                        {
-                               fprintf(stderr, "deleting %s attribute (%N) with value %#B failed.\n",
+                               fprintf(stderr, "deleting %s attribute (%N) with value %#B%s failed.\n",
                                                                name, configuration_attribute_type_names, type,
-                                                               &blob_db);
+                                                               &blob_db, id_pool_str);
                        }
                        query->destroy(query);
                        free(blob.ptr);
@@ -391,20 +503,20 @@ void del_attr(char *name, char *value, value_type_t value_type)
                }
                if (server)
                {
-                       printf("deleted %s server %H\n", name, server);
+                       printf("deleted %s server %H%s\n", name, server, id_pool_str);
                        server->destroy(server);
                }
                else if (value_type == VALUE_STRING)
                {
-                       printf("deleted %s attribute (%N) with value '%.*s'.\n",
+                       printf("deleted %s attribute (%N) with value '%.*s'%s.\n",
                                   name, configuration_attribute_type_names, type,
-                                  blob_db.len, blob_db.ptr);
+                                  blob_db.len, blob_db.ptr, id_pool_str);
                }
                else
                {
-                       printf("deleted %s attribute (%N) with value %#B.\n",
+                       printf("deleted %s attribute (%N) with value %#B%s.\n",
                                   name, configuration_attribute_type_names, type,
-                                  &blob_db);
+                                  &blob_db, id_pool_str);
                }
        }
        query->destroy(query);
@@ -415,12 +527,13 @@ void del_attr(char *name, char *value, value_type_t value_type)
                {
                        if (type_ip6 == 0)
                        {
-                               fprintf(stderr, "no %s attribute (%N) was found.\n", name,
-                                                                configuration_attribute_type_names, type);
+                               fprintf(stderr, "no %s attribute (%N) was found%s.\n", name,
+                                               configuration_attribute_type_names, type, id_pool_str);
                        }
                        else
                        {
-                               fprintf(stderr, "no %s attribute was found.\n", name);
+                               fprintf(stderr, "no %s attribute%s was found.\n",
+                                               name, id_pool_str);
                        }
                }
                else
@@ -429,16 +542,16 @@ void del_attr(char *name, char *value, value_type_t value_type)
                        {
                                host_t *server = host_create_from_chunk(AF_UNSPEC, blob, 0);
        
-                               fprintf(stderr, "the %s server %H was not found.\n", name,
-                                                                server);
+                               fprintf(stderr, "the %s server %H%s was not found.\n", name,
+                                                                server, id_pool_str);
                                server->destroy(server);
                        }
                        else
                        {
-                               fprintf(stderr, "the %s attribute (%N) with value '%.*s' "
+                               fprintf(stderr, "the %s attribute (%N) with value '%.*s'%s "
                                                                "was not found.\n", name,
                                                                 configuration_attribute_type_names, type,
-                                                                blob.len, blob.ptr);
+                                                                blob.len, blob.ptr, id_pool_str);
                        }
                }
        }
@@ -452,23 +565,36 @@ void status_attr(bool hexout)
 {
        configuration_attribute_type_t type;
        value_type_t value_type;
-       chunk_t value, addr_chunk, mask_chunk;
+       chunk_t value, addr_chunk, mask_chunk, identity_chunk;
+       identification_t *identity;
        enumerator_t *enumerator;
        host_t *addr, *mask;
        char type_name[30];
        bool first = TRUE;
-       int i;
+       int i, identity_type;
+       char *pool_name;
 
        /* enumerate over all attributes */
-       enumerator = db->query(db, "SELECT type, value FROM attributes ORDER BY type",
-                                                               DB_INT, DB_BLOB);
+       enumerator = db->query(db,
+                                       "SELECT identities.type, identities.data, "
+                                       "attribute_pools.name, attributes.type, attributes.value "
+                                       "FROM attributes "
+                                       "LEFT OUTER JOIN identities "
+                                       "ON attributes.identity = identities.id "
+                                       "LEFT OUTER JOIN attribute_pools "
+                                       "ON attributes.pool = attribute_pools.id "
+                                       "ORDER BY identities.type, identities.data, "
+                                       "attribute_pools.name, attributes.type",
+                                       DB_INT, DB_BLOB, DB_TEXT, DB_INT, DB_BLOB);
        if (enumerator)
        {
-               while (enumerator->enumerate(enumerator, &type, &value))
+               while (enumerator->enumerate(enumerator, &identity_type,
+                                                       &identity_chunk, &pool_name, &type, &value))
                {
                        if (first)
                        {
-                               printf(" type  description           value\n");
+                               printf(" type  description           pool             "
+                                          " identity        value\n");
                                first = FALSE;
                        }
                        snprintf(type_name, sizeof(type_name), "%N",
@@ -479,6 +605,19 @@ void status_attr(bool hexout)
                        }
                        printf("%5d  %-20s ",type, type_name);
 
+                       printf(" %-15.15s ", (pool_name ? pool_name : ""));
+
+                       if (identity_type)
+                       {
+                               identity = identification_create_from_encoding(identity_type, identity_chunk);
+                               printf(" %-15.15Y ", identity);
+                               identity->destroy(identity);
+                       }
+                       else
+                       {
+                               printf("                 ");
+                       }
+
                        value_type = VALUE_HEX;
                        if (!hexout)
                        {
index 04cfbf9..a42291f 100644 (file)
@@ -34,14 +34,21 @@ enum value_type_t {
 extern enum_name_t *value_type_names;
 
 /**
+ * lookup/insert an identity
+ */
+u_int get_identity(identification_t *id);
+
+/**
  * ipsec pool --addattr <type>  - add attribute entry
  */
-void add_attr(char *name, char *value, value_type_t value_type);
+void add_attr(char *name, char *pool, char *identity,
+                         char *value, value_type_t value_type);
 
 /**
  * ipsec pool --delattr <type>  - delete attribute entry
  */
-void del_attr(char *name, char *value, value_type_t value_type);
+void del_attr(char *name, char *pool, char *identity,
+                         char *value, value_type_t value_type);
 
 /**
  * ipsec pool --statusattr      - show all attribute entries
index b28c8ae..985bc3a 100644 (file)
@@ -59,9 +59,14 @@ Usage:\n\
                resized.\n\
       timeout: Lease time in hours, 0 for static leases\n\
   \n\
-  ipsec pool --addattr <type> --addr|--mask|--server|--subnet|--string|--hex <value>\n\
-    Add a new attribute to the database.\n\
+  ipsec pool --addattr <type> [--pool <name> [--identity <id>]]\n\
+             --addr|--mask|--server|--subnet|--string|--hex <value>\n\
+    Add a new attribute to the database. Attributes can be bundled by using\n\
+    the --pool and --identity options. If a bundle matches a peer the contained\n\
+    attributes are sent to that peer instead of the global ones.\n\
       type:    a keyword from --showattr or a number from the range 1..32767\n\
+      name:    the name of the pool this attribute is added to\n\
+      id:      identity of the peer this attribute is bound to\n\
       addr:    IPv4 or IPv6 address\n\
       mask:    IPv4 or IPv6 netmask (synonym for --addr)\n\
       server:  IPv4 or IPv6 address of a server (synonym for --addr)\n\
@@ -73,9 +78,12 @@ Usage:\n\
     Delete a pool from the database.\n\
       name:    Name of the pool to delete\n\
   \n\
-  ipsec pool --delattr <type> [--addr|--mask|--server|--subnet|--string|--hex <value>]\n\
+  ipsec pool --delattr <type> [--pool <name> [--identity <id>]]\n\
+             [--addr|--mask|--server|--subnet|--string|--hex <value>]\n\
     Delete a specific or all attributes of a given type from the database.\n\
       type:    a keyword from --showattr or a number from the range 1..32767\n\
+      name:    the name of the pool this attribute is added to\n\
+      id:      identity of the peer this attribute is bound to\n\
       addr:    IPv4 or IPv6 address\n\
       mask:    IPv4 or IPv6 netmask (synonym for --addr)\n\
       server:  IPv4 or IPv6 address of a server (synonym for --addr)\n\
index a7cfde6..7f7bb19 100644 (file)
@@ -74,6 +74,26 @@ static u_int get_identity(private_sql_attribute_t *this, identification_t *id)
 }
 
 /**
+ * Lookup an attribute pool by name
+ */
+static u_int get_attr_pool(private_sql_attribute_t *this, char *name)
+{
+       enumerator_t *e;
+       u_int row = 0;
+
+       e = this->db->query(this->db,
+                                               "SELECT id FROM attribute_pools WHERE name = ?",
+                                               DB_TEXT, name, DB_UINT);
+       if (e)
+       {
+               e->enumerate(e, &row);
+       }
+       DESTROY_IF(e);
+
+       return row;
+}
+
+/**
  * Lookup pool by name
  */
 static u_int get_pool(private_sql_attribute_t *this, char *name, u_int *timeout)
@@ -327,20 +347,101 @@ static bool release_address(private_sql_attribute_t *this,
  * Implementation of sql_attribute_t.create_attribute_enumerator
  */
 static enumerator_t* create_attribute_enumerator(private_sql_attribute_t *this,
-                                                                                       identification_t *id, host_t *vip)
+                                                               char *names, identification_t *id, host_t *vip)
 {
+       enumerator_t *attr_enumerator = NULL;
+
        if (vip)
        {
-               enumerator_t *enumerator;
+               enumerator_t *names_enumerator;
+               u_int count;
+               char *name;
 
-               enumerator = this->db->query(this->db,
-                                               "SELECT type, value FROM attributes", DB_INT, DB_BLOB);
-               if (enumerator)
+               this->db->execute(this->db, NULL, "BEGIN EXCLUSIVE TRANSACTION");
+
+               /* in a first step check for attributes that match name and id */
+               if (id)
                {
-                       return enumerator;
+                       u_int identity = get_identity(this, id);
+
+                       names_enumerator = enumerator_create_token(names, ",", " ");
+                       while (names_enumerator->enumerate(names_enumerator, &name))
+                       {
+                               u_int attr_pool = get_attr_pool(this, name);
+                               if (!attr_pool)
+                               {
+                                       continue;
+                               }
+
+                               attr_enumerator = this->db->query(this->db,
+                                                               "SELECT count(*) FROM attributes "
+                                                               "WHERE pool = ? AND identity = ?",
+                                                               DB_UINT, attr_pool, DB_UINT, identity, DB_UINT);
+
+                               if (attr_enumerator &&
+                                       attr_enumerator->enumerate(attr_enumerator, &count) &&
+                                       count != 0)
+                               {
+                                       attr_enumerator->destroy(attr_enumerator);
+                                       attr_enumerator = this->db->query(this->db,
+                                                               "SELECT type, value FROM attributes "
+                                                               "WHERE pool = ? AND identity = ?", DB_UINT,
+                                                               attr_pool, DB_UINT, identity, DB_INT, DB_BLOB);
+                                       break;
+                               }
+                               DESTROY_IF(attr_enumerator);
+                               attr_enumerator = NULL;
+                       }
+                       names_enumerator->destroy(names_enumerator);
+               }
+
+               /* in a second step check for attributes that match name */
+               if (!attr_enumerator)
+               {
+                       names_enumerator = enumerator_create_token(names, ",", " ");
+                       while (names_enumerator->enumerate(names_enumerator, &name))
+                       {
+                               u_int attr_pool = get_attr_pool(this, name);
+                               if (!attr_pool)
+                               {
+                                       continue;
+                               }
+
+                               attr_enumerator = this->db->query(this->db,
+                                                                       "SELECT count(*) FROM attributes "
+                                                                       "WHERE pool = ? AND identity = 0",
+                                                                       DB_UINT, attr_pool, DB_UINT);
+
+                               if (attr_enumerator &&
+                                       attr_enumerator->enumerate(attr_enumerator, &count) &&
+                                       count != 0)
+                               {
+                                       attr_enumerator->destroy(attr_enumerator);
+                                       attr_enumerator = this->db->query(this->db,
+                                                                       "SELECT type, value FROM attributes "
+                                                                       "WHERE pool = ? AND identity = 0",
+                                                                       DB_UINT, attr_pool, DB_INT, DB_BLOB);
+                                       break;
+                               }
+                               DESTROY_IF(attr_enumerator);
+                               attr_enumerator = NULL;
+                       }
+                       names_enumerator->destroy(names_enumerator);
+               }
+
+               this->db->execute(this->db, NULL, "END TRANSACTION");
+
+               /* lastly try to find global attributes */
+               if (!attr_enumerator)
+               {
+                       attr_enumerator = this->db->query(this->db,
+                                                                       "SELECT type, value FROM attributes "
+                                                                       "WHERE pool = 0 AND identity = 0",
+                                                                       DB_INT, DB_BLOB);
                }
        }
-       return enumerator_create_empty();
+
+       return (attr_enumerator ? attr_enumerator : enumerator_create_empty());
 }
 
 /**
@@ -361,7 +462,7 @@ sql_attribute_t *sql_attribute_create(database_t *db)
 
        this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *, host_t *))acquire_address;
        this->public.provider.release_address = (bool(*)(attribute_provider_t *this, char*,host_t *, identification_t*))release_address;
-       this->public.provider.create_attribute_enumerator = (enumerator_t*(*)(attribute_provider_t*, identification_t *id, host_t *host))create_attribute_enumerator;
+       this->public.provider.create_attribute_enumerator = (enumerator_t*(*)(attribute_provider_t*, char *names, identification_t *id, host_t *host))create_attribute_enumerator;
        this->public.destroy = (void(*)(sql_attribute_t*))destroy;
 
        this->db = db;
index 50e14fa..0d0cd89 100644 (file)
@@ -93,6 +93,7 @@ void modecfg_attribute_destroy(modecfg_attribute_t *this)
 static void get_attributes(connection_t *c, linked_list_t *ca_list)
 {
        configuration_attribute_type_t type;
+       identification_t *client_id;
        modecfg_attribute_t *ca;
        enumerator_t *enumerator;
        chunk_t value;
@@ -141,14 +142,13 @@ static void get_attributes(connection_t *c, linked_list_t *ca_list)
                requested_vip = host_create_any(AF_INET);
        }
 
+       client_id = (c->xauth_identity) ? c->xauth_identity : c->spd.that.id;
+
        /* if no virtual IP has been assigned yet - acquire one */
        if (c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip))
        {
                if (c->spd.that.pool)
                {
-                       identification_t *client_id;
-
-                       client_id = (c->xauth_identity) ? c->xauth_identity : c->spd.that.id;
                        vip = hydra->attributes->acquire_address(hydra->attributes,
                                                                c->spd.that.pool, client_id, requested_vip);
                        if (vip)
@@ -185,7 +185,7 @@ static void get_attributes(connection_t *c, linked_list_t *ca_list)
 
        /* assign attributes from registered providers */
        enumerator = hydra->attributes->create_responder_enumerator(hydra->attributes,
-                                                                                       c->spd.that.id, vip);
+                                                                                       c->spd.that.pool, client_id, vip);
        while (enumerator->enumerate(enumerator, &type, &value))
        {
                ca = modecfg_attribute_create(type, value);
index f7820a1..eb5f0e4 100644 (file)
@@ -183,12 +183,27 @@ CREATE TABLE leases (
   released INTEGER NOT NULL
 );
 
+DROP TABLE IF EXISTS attribute_pools;
+CREATE TABLE attribute_pools (
+  id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+  name TEXT NOT NULL
+);
 DROP TABLE IF EXISTS attributes;
 CREATE TABLE attributes (
   id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+  identity INTEGER NOT NULL DEFAULT 0,
+  pool INTEGER NOT NULL DEFAULT 0,
   type INTEGER NOT NULL,
   value BLOB NOT NULL
 );
+DROP INDEX IF EXISTS attributes_identity;
+CREATE INDEX attributes_identity ON attributes (
+  identity
+);
+DROP INDEX IF EXISTS attributes_pool;
+CREATE INDEX attributes_pool ON attributes (
+  pool
+);
 
 DROP TABLE IF EXISTS ike_sas;
 CREATE TABLE ike_sas (