move SQL-based pool functionality to new attr-sql libstrongswan plugin
authorAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 13 Oct 2009 15:02:29 +0000 (17:02 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 13 Oct 2009 15:02:29 +0000 (17:02 +0200)
23 files changed:
configure.in
src/charon/plugins/sql/Makefile.am
src/charon/plugins/sql/pool.c [deleted file]
src/charon/plugins/sql/sql_attribute.c [deleted file]
src/charon/plugins/sql/sql_attribute.h [deleted file]
src/charon/plugins/sql/sql_plugin.c
src/checksum/Makefile.am
src/libstrongswan/Makefile.am
src/libstrongswan/plugins/attr_sql/Makefile.am [new file with mode: 0644]
src/libstrongswan/plugins/attr_sql/attr_sql_plugin.c [new file with mode: 0644]
src/libstrongswan/plugins/attr_sql/attr_sql_plugin.h [new file with mode: 0644]
src/libstrongswan/plugins/attr_sql/pool.c [new file with mode: 0644]
src/libstrongswan/plugins/attr_sql/sql_attribute.c [new file with mode: 0644]
src/libstrongswan/plugins/attr_sql/sql_attribute.h [new file with mode: 0644]
testing/tests/ikev2/ip-pool-db/hosts/moon/etc/strongswan.conf
testing/tests/ikev2/ip-split-pools-db/hosts/moon/etc/strongswan.conf
testing/tests/ikev2/ip-two-pools-db/hosts/moon/etc/strongswan.conf
testing/tests/ikev2/ip-two-pools-mixed/hosts/moon/etc/strongswan.conf
testing/tests/sql/ip-pool-db-expired/hosts/moon/etc/strongswan.conf
testing/tests/sql/ip-pool-db-restart/hosts/moon/etc/strongswan.conf
testing/tests/sql/ip-pool-db/hosts/moon/etc/strongswan.conf
testing/tests/sql/ip-split-pools-db-restart/hosts/moon/etc/strongswan.conf
testing/tests/sql/ip-split-pools-db/hosts/moon/etc/strongswan.conf

index 6086af2..057152d 100644 (file)
@@ -127,6 +127,7 @@ ARG_DISBL_SET([tools],          [disable additional utilities (openac, scepclien
 ARG_DISBL_SET([scripts],        [disable additional utilities (found in directory scripts).])
 ARG_DISBL_SET([updown],         [disable updown firewall script plugin.])
 ARG_DISBL_SET([attr],           [disable strongswan.conf based configuration attribute plugin.])
+ARG_ENABL_SET([attr-sql],       [enable SQL based configuration attribute plugin.])
 ARG_DISBL_SET([resolve],        [disable resolve DNS handler plugin.])
 ARG_ENABL_SET([padlock],        [enables VIA Padlock crypto plugin.])
 ARG_ENABL_SET([openssl],        [enables the OpenSSL crypto plugin.])
@@ -618,6 +619,10 @@ fi
 if test x$sqlite = xtrue; then
        libstrongswan_plugins=${libstrongswan_plugins}" sqlite"
 fi
+if test x$attr_sql = xtrue -o x$sql = xtrue; then
+       libstrongswan_plugins=${libstrongswan_plugins}" attr-sql"
+       pluto_plugins=${pluto_plugins}" attr-sql"
+fi
 if test x$padlock = xtrue; then
        libstrongswan_plugins=${libstrongswan_plugins}" padlock"
 fi
@@ -676,6 +681,7 @@ AM_CONDITIONAL(USE_HMAC, test x$hmac = xtrue)
 AM_CONDITIONAL(USE_XCBC, test x$xcbc = xtrue)
 AM_CONDITIONAL(USE_MYSQL, test x$mysql = xtrue)
 AM_CONDITIONAL(USE_SQLITE, test x$sqlite = xtrue)
+AM_CONDITIONAL(USE_ATTR_SQL, test x$attr_sql = xtrue -o x$sql = xtrue)
 AM_CONDITIONAL(USE_PADLOCK, test x$padlock = xtrue)
 AM_CONDITIONAL(USE_OPENSSL, test x$openssl = xtrue)
 AM_CONDITIONAL(USE_GCRYPT, test x$gcrypt = xtrue)
@@ -775,6 +781,7 @@ AC_OUTPUT(
        src/libstrongswan/plugins/ldap/Makefile
        src/libstrongswan/plugins/mysql/Makefile
        src/libstrongswan/plugins/sqlite/Makefile
+       src/libstrongswan/plugins/attr_sql/Makefile
        src/libstrongswan/plugins/padlock/Makefile
        src/libstrongswan/plugins/openssl/Makefile
        src/libstrongswan/plugins/gcrypt/Makefile
index c6a382c..60135bf 100644 (file)
@@ -5,11 +5,8 @@ AM_CFLAGS = -rdynamic \
   -DPLUGINS=\""${libstrongswan_plugins}\""
 
 plugin_LTLIBRARIES = libstrongswan-sql.la
-libstrongswan_sql_la_SOURCES = sql_plugin.h sql_plugin.c \
-  sql_config.h sql_config.c sql_cred.h sql_cred.c \
-  sql_attribute.h sql_attribute.c sql_logger.h sql_logger.c
+libstrongswan_sql_la_SOURCES = \
+  sql_plugin.h sql_plugin.c sql_config.h sql_config.c \
+  sql_cred.h sql_cred.c sql_logger.h sql_logger.c
 libstrongswan_sql_la_LDFLAGS = -module -avoid-version
 
-ipsec_PROGRAMS = pool
-pool_SOURCES = pool.c
-pool_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
diff --git a/src/charon/plugins/sql/pool.c b/src/charon/plugins/sql/pool.c
deleted file mode 100644 (file)
index 68c2dac..0000000
+++ /dev/null
@@ -1,767 +0,0 @@
-/*
- * Copyright (C) 2008 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-#define _GNU_SOURCE
-#include <getopt.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <time.h>
-
-#include <debug.h>
-#include <library.h>
-#include <utils/host.h>
-#include <utils/identification.h>
-
-/**
- * global database handle
- */
-database_t *db;
-
-/**
- * --start/--end addresses of various subcommands
- */
-host_t *start = NULL, *end = NULL;
-
-/**
- * calculate the size of a pool using start and end address chunk
- */
-static u_int get_pool_size(chunk_t start, chunk_t end)
-{
-       u_int *start_ptr, *end_ptr;
-
-       if (start.len < sizeof(u_int) || end.len < sizeof(u_int))
-       {
-               return 0;
-       }
-       start_ptr = (u_int*)(start.ptr + start.len - sizeof(u_int));
-       end_ptr = (u_int*)(end.ptr + end.len - sizeof(u_int));
-       return ntohl(*end_ptr) -  ntohl(*start_ptr) + 1;
-}
-
-/**
- * print usage info
- */
-static void usage(void)
-{
-       printf("\
-Usage:\n\
-  ipsec pool --status|--add|--del|--resize|--purge [options]\n\
-  \n\
-  ipsec pool --status\n\
-    Show a list of installed pools with statistics.\n\
-  \n\
-  ipsec pool --add <name> --start <start> --end <end> [--timeout <timeout>]\n\
-    Add a new pool to the database.\n\
-      name:    Name of the pool, as used in ipsec.conf rightsourceip=%%name\n\
-      start:   Start address of the pool\n\
-      end:     End address of the pool\n\
-      timeout: Lease time in hours, 0 for static leases\n\
-  \n\
-  ipsec pool --del <name>\n\
-    Delete a pool from the database.\n\
-      name:   Name of the pool to delete\n\
-  \n\
-  ipsec pool --resize <name> --end <end>\n\
-    Grow or shrink an existing pool.\n\
-      name:   Name of the pool to resize\n\
-      end:    New end address for the pool\n\
-  \n\
-  ipsec pool --leases [--filter <filter>] [--utc]\n\
-    Show lease information using filters:\n\
-      filter: Filter string containing comma separated key=value filters,\n\
-              e.g. id=alice@strongswan.org,addr=1.1.1.1\n\
-                  pool:   name of the pool\n\
-                  id:     assigned identity of the lease\n\
-                  addr:   lease IP address\n\
-                  tstamp: UNIX timestamp when lease was valid, as integer\n\
-                  status: status of the lease: online|valid|expired\n\
-      utc:    Show times in UTC instead of local time\n\
-  \n\
-  ipsec pool --purge <name>\n\
-    Delete lease history of a pool:\n\
-      name:   Name of the pool to purge\n\
-  \n");
-       exit(0);
-}
-
-/**
- * ipsec pool --status - show pool overview
- */
-static void status(void)
-{
-       enumerator_t *pool, *lease;
-       bool found = FALSE;
-
-       pool = db->query(db, "SELECT id, name, start, end, timeout FROM pools",
-                                        DB_INT, DB_TEXT, DB_BLOB, DB_BLOB, DB_UINT);
-       if (pool)
-       {
-               char *name;
-               chunk_t start_chunk, end_chunk;
-               host_t *start, *end;
-               u_int id, timeout, online = 0, used = 0, size = 0;
-
-               while (pool->enumerate(pool, &id, &name,
-                                                          &start_chunk, &end_chunk, &timeout))
-               {
-                       if (!found)
-                       {
-                               printf("%8s %15s %15s %8s %6s %11s %11s\n", "name", "start",
-                                          "end", "timeout", "size", "online", "usage");
-                               found = TRUE;
-                       }
-
-                       start = host_create_from_chunk(AF_UNSPEC, start_chunk, 0);
-                       end = host_create_from_chunk(AF_UNSPEC, end_chunk, 0);
-                       size = get_pool_size(start_chunk, end_chunk);
-                       printf("%8s %15H %15H ", name, start, end);
-                       if (timeout)
-                       {
-                               printf("%7dh ", timeout/3600);
-                       }
-                       else
-                       {
-                               printf("%8s ", "static");
-                       }
-                       printf("%6d ", size);
-                       /* get number of online hosts */
-                       lease = db->query(db, "SELECT COUNT(*) FROM addresses "
-                                                         "WHERE pool = ? AND released = 0",
-                                                         DB_UINT, id, DB_INT);
-                       if (lease)
-                       {
-                               lease->enumerate(lease, &online);
-                               lease->destroy(lease);
-                       }
-                       printf("%5d (%2d%%) ", online, online*100/size);
-                       /* get number of online or valid lieases */
-                       lease = db->query(db, "SELECT COUNT(*) FROM addresses "
-                                                         "WHERE addresses.pool = ? "
-                                                         "AND ((? AND acquired != 0) "
-                                                         "     OR released = 0 OR released > ?) ",
-                                                         DB_UINT, id, DB_UINT, !timeout,
-                                                         DB_UINT, time(NULL) - timeout, DB_UINT);
-                       if (lease)
-                       {
-                               lease->enumerate(lease, &used);
-                               lease->destroy(lease);
-                       }
-                       printf("%5d (%2d%%) ", used, used*100/size);
-
-                       printf("\n");
-                       DESTROY_IF(start);
-                       DESTROY_IF(end);
-               }
-               pool->destroy(pool);
-       }
-       if (!found)
-       {
-               printf("no pools found.\n");
-       }
-       exit(0);
-}
-
-/**
- * ipsec pool --add - add a new pool
- */
-static void add(char *name, host_t *start, host_t *end, int timeout)
-{
-       chunk_t start_addr, end_addr, cur_addr;
-       u_int id, count;
-
-       start_addr = start->get_address(start);
-       end_addr = end->get_address(end);
-       cur_addr = chunk_clonea(start_addr);
-       count = get_pool_size(start_addr, end_addr);
-
-       if (start_addr.len != end_addr.len ||
-               memcmp(start_addr.ptr, end_addr.ptr, start_addr.len) > 0)
-       {
-               fprintf(stderr, "invalid start/end pair specified.\n");
-               exit(-1);
-       }
-       if (db->execute(db, &id,
-                       "INSERT INTO pools (name, start, end, timeout) "
-                       "VALUES (?, ?, ?, ?)",
-                       DB_TEXT, name, DB_BLOB, start_addr,
-                       DB_BLOB, end_addr, DB_INT, timeout*3600) != 1)
-       {
-               fprintf(stderr, "creating pool failed.\n");
-               exit(-1);
-       }
-       printf("allocating %d addresses... ", count);
-       fflush(stdout);
-       if (db->get_driver(db) == DB_SQLITE)
-       {       /* run population in a transaction for sqlite */
-               db->execute(db, NULL, "BEGIN TRANSACTION");
-       }
-       while (TRUE)
-       {
-               db->execute(db, NULL,
-                       "INSERT INTO addresses (pool, address, identity, acquired, released) "
-                       "VALUES (?, ?, ?, ?, ?)",
-                       DB_UINT, id, DB_BLOB, cur_addr, DB_UINT, 0, DB_UINT, 0, DB_UINT, 1);
-               if (chunk_equals(cur_addr, end_addr))
-               {
-                       break;
-               }
-               chunk_increment(cur_addr);
-       }
-       if (db->get_driver(db) == DB_SQLITE)
-       {
-               db->execute(db, NULL, "END TRANSACTION");
-       }
-       printf("done.\n", count);
-
-       exit(0);
-}
-
-/**
- * ipsec pool --del - delete a pool
- */
-static void del(char *name)
-{
-       enumerator_t *query;
-       u_int id;
-       bool found = FALSE;
-
-       query = db->query(db, "SELECT id FROM pools WHERE name = ?",
-                                         DB_TEXT, name, DB_UINT);
-       if (!query)
-       {
-               fprintf(stderr, "deleting pool failed.\n");
-               exit(-1);
-       }
-       while (query->enumerate(query, &id))
-       {
-               found = TRUE;
-               if (db->execute(db, NULL,
-                               "DELETE FROM leases WHERE address IN ("
-                               " SELECT id FROM addresses WHERE pool = ?)", DB_UINT, id) < 0 ||
-                       db->execute(db, NULL,
-                               "DELETE FROM addresses WHERE pool = ?", DB_UINT, id) < 0 ||
-                       db->execute(db, NULL,
-                               "DELETE FROM pools WHERE id = ?", DB_UINT, id) < 0)
-               {
-                       fprintf(stderr, "deleting pool failed.\n");
-                       query->destroy(query);
-                       exit(-1);
-               }
-       }
-       query->destroy(query);
-       if (!found)
-       {
-               fprintf(stderr, "pool '%s' not found.\n", name);
-               exit(-1);
-       }
-       exit(0);
-}
-
-/**
- * ipsec pool --resize - resize a pool
- */
-static void resize(char *name, host_t *end)
-{
-       enumerator_t *query;
-       chunk_t old_addr, new_addr, cur_addr;
-       u_int id, count;
-
-       new_addr = end->get_address(end);
-
-       query = db->query(db, "SELECT id, end FROM pools WHERE name = ?",
-                                         DB_TEXT, name, DB_UINT, DB_BLOB);
-       if (!query || !query->enumerate(query, &id, &old_addr))
-       {
-               DESTROY_IF(query);
-               fprintf(stderr, "resizing pool failed.\n");
-               exit(-1);
-       }
-       if (old_addr.len != new_addr.len ||
-               memcmp(new_addr.ptr, old_addr.ptr, old_addr.len) < 0)
-       {
-               fprintf(stderr, "shrinking of pools not supported.\n");
-               query->destroy(query);
-               exit(-1);
-       }
-       cur_addr = chunk_clonea(old_addr);
-       count = get_pool_size(old_addr, new_addr) - 1;
-       query->destroy(query);
-
-       if (db->execute(db, NULL,
-                       "UPDATE pools SET end = ? WHERE name = ?",
-                       DB_BLOB, new_addr, DB_TEXT, name) <= 0)
-       {
-               fprintf(stderr, "pool '%s' not found.\n", name);
-               exit(-1);
-       }
-
-       printf("allocating %d new addresses... ", count);
-       fflush(stdout);
-       if (db->get_driver(db) == DB_SQLITE)
-       {       /* run population in a transaction for sqlite */
-               db->execute(db, NULL, "BEGIN TRANSACTION");
-       }
-       while (count-- > 0)
-       {
-               chunk_increment(cur_addr);
-               db->execute(db, NULL,
-                       "INSERT INTO addresses (pool, address, identity, acquired, released) "
-                       "VALUES (?, ?, ?, ?, ?)",
-                       DB_UINT, id, DB_BLOB, cur_addr, DB_UINT, 0, DB_UINT, 0, DB_UINT, 1);
-       }
-       if (db->get_driver(db) == DB_SQLITE)
-       {
-               db->execute(db, NULL, "END TRANSACTION");
-       }
-       printf("done.\n", count);
-
-       exit(0);
-}
-
-/**
- * create the lease query using the filter string
- */
-static enumerator_t *create_lease_query(char *filter)
-{
-       enumerator_t *query;
-       identification_t *id = NULL;
-       host_t *addr = NULL;
-       u_int tstamp = 0;
-       bool online = FALSE, valid = FALSE, expired = FALSE;
-       char *value, *pos, *pool = NULL;
-       enum {
-               FIL_POOL = 0,
-               FIL_ID,
-               FIL_ADDR,
-               FIL_TSTAMP,
-               FIL_STATE,
-       };
-       char *const token[] = {
-               [FIL_POOL] = "pool",
-               [FIL_ID] = "id",
-               [FIL_ADDR] = "addr",
-               [FIL_TSTAMP] = "tstamp",
-               [FIL_STATE] = "status",
-               NULL
-       };
-
-       /* if the filter string contains a distinguished name as a ID, we replace
-        * ", " by "/ " in order to not confuse the getsubopt parser */
-       pos = filter;
-       while ((pos = strchr(pos, ',')))
-       {
-               if (pos[1] == ' ')
-               {
-                       pos[0] = '/';
-               }
-               pos++;
-       }
-
-       while (filter && *filter != '\0')
-       {
-               switch (getsubopt(&filter, token, &value))
-               {
-                       case FIL_POOL:
-                               if (value)
-                               {
-                                       pool = value;
-                               }
-                               break;
-                       case FIL_ID:
-                               if (value)
-                               {
-                                       id = identification_create_from_string(value);
-                               }
-                               break;
-                       case FIL_ADDR:
-                               if (value)
-                               {
-                                       addr = host_create_from_string(value, 0);
-                               }
-                               if (!addr)
-                               {
-                                       fprintf(stderr, "invalid 'addr' in filter string.\n");
-                                       exit(-1);
-                               }
-                               break;
-                       case FIL_TSTAMP:
-                               if (value)
-                               {
-                                       tstamp = atoi(value);
-                               }
-                               if (tstamp == 0)
-                               {
-                                       online = TRUE;
-                               }
-                               break;
-                       case FIL_STATE:
-                               if (value)
-                               {
-                                       if (streq(value, "online"))
-                                       {
-                                               online = TRUE;
-                                       }
-                                       else if (streq(value, "valid"))
-                                       {
-                                               valid = TRUE;
-                                       }
-                                       else if (streq(value, "expired"))
-                                       {
-                                               expired = TRUE;
-                                       }
-                                       else
-                                       {
-                                               fprintf(stderr, "invalid 'state' in filter string.\n");
-                                               exit(-1);
-                                       }
-                               }
-                               break;
-                       default:
-                               fprintf(stderr, "invalid filter string.\n");
-                               exit(-1);
-                               break;
-               }
-       }
-       query = db->query(db,
-                               "SELECT name, addresses.address, identities.type, "
-                               "identities.data, leases.acquired, leases.released, timeout "
-                               "FROM leases JOIN addresses ON leases.address = addresses.id "
-                               "JOIN pools ON addresses.pool = pools.id "
-                               "JOIN identities ON leases.identity = identities.id "
-                               "WHERE (? OR name = ?) "
-                               "AND (? OR (identities.type = ? AND identities.data = ?)) "
-                               "AND (? OR addresses.address = ?) "
-                               "AND (? OR (? >= leases.acquired AND (? <= leases.released))) "
-                               "AND (? OR leases.released > ? - timeout) "
-                               "AND (? OR leases.released < ? - timeout) "
-                               "AND ? "
-                               "UNION "
-                               "SELECT name, address, identities.type, identities.data, "
-                               "acquired, released, timeout FROM addresses "
-                               "JOIN pools ON addresses.pool = pools.id "
-                               "JOIN identities ON addresses.identity = identities.id "
-                               "WHERE ? AND released = 0 "
-                               "AND (? OR name = ?) "
-                               "AND (? OR (identities.type = ? AND identities.data = ?)) "
-                               "AND (? OR address = ?)",
-                               DB_INT, pool == NULL, DB_TEXT, pool,
-                               DB_INT, id == NULL,
-                                       DB_INT, id ? id->get_type(id) : 0,
-                                       DB_BLOB, id ? id->get_encoding(id) : chunk_empty,
-                               DB_INT, addr == NULL,
-                                       DB_BLOB, addr ? addr->get_address(addr) : chunk_empty,
-                               DB_INT, tstamp == 0, DB_UINT, tstamp, DB_UINT, tstamp,
-                               DB_INT, !valid, DB_INT, time(NULL),
-                               DB_INT, !expired, DB_INT, time(NULL),
-                               DB_INT, !online,
-                               /* union */
-                               DB_INT, !(valid || expired),
-                               DB_INT, pool == NULL, DB_TEXT, pool,
-                               DB_INT, id == NULL,
-                                       DB_INT, id ? id->get_type(id) : 0,
-                                       DB_BLOB, id ? id->get_encoding(id) : chunk_empty,
-                               DB_INT, addr == NULL,
-                                       DB_BLOB, addr ? addr->get_address(addr) : chunk_empty,
-                               /* res */
-                               DB_TEXT, DB_BLOB, DB_INT, DB_BLOB, DB_UINT, DB_UINT, DB_UINT);
-       /* id and addr leak but we can't destroy them until query is destroyed. */
-       return query;
-}
-
-/**
- * ipsec pool --leases - show lease information of a pool
- */
-static void leases(char *filter, bool utc)
-{
-       enumerator_t *query;
-       chunk_t address_chunk, identity_chunk;
-       int identity_type;
-       char *name;
-       u_int acquired, released, timeout;
-       host_t *address;
-       identification_t *identity;
-       bool found = FALSE;
-
-       query = create_lease_query(filter);
-       if (!query)
-       {
-               fprintf(stderr, "querying leases failed.\n");
-               exit(-1);
-       }
-       while (query->enumerate(query, &name, &address_chunk, &identity_type,
-                                                       &identity_chunk, &acquired, &released, &timeout))
-       {
-               if (!found)
-               {
-                       int len = utc ? 25 : 21;
-
-                       found = TRUE;
-                       printf("%-8s %-15s %-7s  %-*s %-*s %s\n",
-                                  "name", "address", "status", len, "start", len, "end", "identity");
-               }
-               address = host_create_from_chunk(AF_UNSPEC, address_chunk, 0);
-               identity = identification_create_from_encoding(identity_type, identity_chunk);
-
-               printf("%-8s %-15H ", name, address);
-               if (released == 0)
-               {
-                       printf("%-7s ", "online");
-               }
-               else if (timeout == 0)
-               {
-                       printf("%-7s ", "static");
-               }
-               else if (released >= time(NULL) - timeout)
-               {
-                       printf("%-7s ", "valid");
-               }
-               else
-               {
-                       printf("%-7s ", "expired");
-               }
-
-               printf(" %T  ", &acquired, utc);
-               if (released)
-               {
-                       printf("%T  ", &released, utc);
-               }
-               else
-               {
-                       printf("                      ");
-                       if (utc)
-                       {
-                               printf("    ");
-                       }
-               }
-               printf("%Y\n", identity);
-               DESTROY_IF(address);
-               identity->destroy(identity);
-       }
-       query->destroy(query);
-       if (!found)
-       {
-               fprintf(stderr, "no matching leases found.\n");
-               exit(-1);
-       }
-       exit(0);
-}
-
-/**
- * ipsec pool --purge - delete expired leases
- */
-static void purge(char *name)
-{
-       int purged = 0;
-
-       purged = db->execute(db, NULL,
-                               "DELETE FROM leases WHERE address IN ("
-                               " SELECT id FROM addresses WHERE pool IN ("
-                               "  SELECT id FROM pools WHERE name = ?))",
-                               DB_TEXT, name);
-       if (purged < 0)
-       {
-               fprintf(stderr, "purging pool '%s' failed.\n", name);
-               exit(-1);
-       }
-       fprintf(stderr, "purged %d leases in pool '%s'.\n", purged, name);
-       exit(0);
-}
-
-/**
- * atexit handler to close db on shutdown
- */
-static void cleanup(void)
-{
-       db->destroy(db);
-       DESTROY_IF(start);
-       DESTROY_IF(end);
-}
-
-int main(int argc, char *argv[])
-{
-       char *uri, *name = "", *filter = "";
-       int timeout = 0;
-       bool utc = FALSE;
-       enum {
-               OP_USAGE,
-               OP_STATUS,
-               OP_ADD,
-               OP_DEL,
-               OP_RESIZE,
-               OP_LEASES,
-               OP_PURGE,
-       } operation = OP_USAGE;
-
-       atexit(library_deinit);
-
-       /* initialize library */
-       if (!library_init(NULL))
-       {
-               exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
-       }
-       if (lib->integrity &&
-               !lib->integrity->check_file(lib->integrity, "pool", argv[0]))
-       {
-               fprintf(stderr, "integrity check of pool failed\n");
-               exit(SS_RC_DAEMON_INTEGRITY);
-       }
-       if (!lib->plugins->load(lib->plugins, NULL,
-                       lib->settings->get_str(lib->settings, "pool.load", PLUGINS)))
-       {
-               exit(SS_RC_INITIALIZATION_FAILED);
-       }
-
-       uri = lib->settings->get_str(lib->settings, "charon.plugins.sql.database", NULL);
-       if (!uri)
-       {
-               fprintf(stderr, "database URI charon.plugins.sql.database not set.\n");
-               exit(SS_RC_INITIALIZATION_FAILED);
-       }
-       db = lib->db->create(lib->db, uri);
-       if (!db)
-       {
-               fprintf(stderr, "opening database failed.\n");
-               exit(SS_RC_INITIALIZATION_FAILED);
-       }
-       atexit(cleanup);
-
-       while (TRUE)
-       {
-               int c;
-
-               struct option long_opts[] = {
-                       { "help", no_argument, NULL, 'h' },
-
-                       { "utc", no_argument, NULL, 'u' },
-                       { "status", no_argument, NULL, 'w' },
-                       { "add", required_argument, NULL, 'a' },
-                       { "del", required_argument, NULL, 'd' },
-                       { "resize", required_argument, NULL, 'r' },
-                       { "leases", no_argument, NULL, 'l' },
-                       { "purge", required_argument, NULL, 'p' },
-
-                       { "start", required_argument, NULL, 's' },
-                       { "end", required_argument, NULL, 'e' },
-                       { "timeout", required_argument, NULL, 't' },
-                       { "filter", required_argument, NULL, 'f' },
-                       { 0,0,0,0 }
-               };
-
-               c = getopt_long(argc, argv, "", long_opts, NULL);
-               switch (c)
-               {
-                       case EOF:
-                               break;
-                       case 'h':
-                               break;
-                       case 'w':
-                               operation = OP_STATUS;
-                               break;
-                       case 'u':
-                               utc = TRUE;
-                               continue;
-                       case 'a':
-                               operation = OP_ADD;
-                               name = optarg;
-                               continue;
-                       case 'd':
-                               operation = OP_DEL;
-                               name = optarg;
-                               continue;
-                       case 'r':
-                               operation = OP_RESIZE;
-                               name = optarg;
-                               continue;
-                       case 'l':
-                               operation = OP_LEASES;
-                               continue;
-                       case 'p':
-                               operation = OP_PURGE;
-                               name = optarg;
-                               continue;
-                       case 's':
-                               start = host_create_from_string(optarg, 0);
-                               if (start == NULL)
-                               {
-                                       fprintf(stderr, "invalid start address: '%s'.\n", optarg);
-                                       operation = OP_USAGE;
-                                       break;
-                               }
-                               continue;
-                       case 'e':
-                               end = host_create_from_string(optarg, 0);
-                               if (end == NULL)
-                               {
-                                       fprintf(stderr, "invalid end address: '%s'.\n", optarg);
-                                       operation = OP_USAGE;
-                                       break;
-                               }
-                               continue;
-                       case 't':
-                               timeout = atoi(optarg);
-                               if (timeout == 0 && strcmp(optarg, "0") != 0)
-                               {
-                                       fprintf(stderr, "invalid timeout '%s'.\n", optarg);
-                                       operation = OP_USAGE;
-                                       break;
-                               }
-                               continue;
-                       case 'f':
-                               filter = optarg;
-                               continue;
-                       default:
-                               operation = OP_USAGE;
-                               break;
-               }
-               break;
-       }
-
-       switch (operation)
-       {
-               case OP_USAGE:
-                       usage();
-                       break;
-               case OP_STATUS:
-                       status();
-                       break;
-               case OP_ADD:
-                       if (start == NULL || end == NULL)
-                       {
-                               fprintf(stderr, "missing arguments.\n");
-                               usage();
-                       }
-                       add(name, start, end, timeout);
-                       break;
-               case OP_DEL:
-                       del(name);
-                       break;
-               case OP_RESIZE:
-                       if (end == NULL)
-                       {
-                               fprintf(stderr, "missing arguments.\n");
-                               usage();
-                       }
-                       resize(name, end);
-                       break;
-               case OP_LEASES:
-                       leases(filter, utc);
-                       break;
-               case OP_PURGE:
-                       purge(name);
-                       break;
-       }
-       exit(0);
-}
-
diff --git a/src/charon/plugins/sql/sql_attribute.c b/src/charon/plugins/sql/sql_attribute.c
deleted file mode 100644 (file)
index 9045f77..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright (C) 2008 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-#include "sql_attribute.h"
-
-#include <time.h>
-
-#include <daemon.h>
-
-typedef struct private_sql_attribute_t private_sql_attribute_t;
-
-/**
- * private data of sql_attribute
- */
-struct private_sql_attribute_t {
-
-       /**
-        * public functions
-        */
-       sql_attribute_t public;
-
-       /**
-        * database connection
-        */
-       database_t *db;
-
-       /**
-        * wheter to record lease history in lease table
-        */
-       bool history;
-};
-
-/**
- * lookup/insert an identity
- */
-static u_int get_identity(private_sql_attribute_t *this, identification_t *id)
-{
-       enumerator_t *e;
-       u_int row;
-
-       /* look for peer identity in the identities table */
-       e = this->db->query(this->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 (this->db->execute(this->db, &row,
-                                 "INSERT INTO identities (type, data) VALUES (?, ?)",
-                                 DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id)) == 1)
-       {
-               return row;
-       }
-       return 0;
-}
-
-/**
- * Lookup pool by name
- */
-static u_int get_pool(private_sql_attribute_t *this, char *name, u_int *timeout)
-{
-       enumerator_t *e;
-       u_int pool;
-
-       e = this->db->query(this->db, "SELECT id, timeout FROM pools WHERE name = ?",
-                                               DB_TEXT, name, DB_UINT, DB_UINT);
-       if (e && e->enumerate(e, &pool, timeout))
-       {
-               e->destroy(e);
-               return pool;
-       }
-       DESTROY_IF(e);
-       return 0;
-}
-
-/**
- * Look up an existing lease
- */
-static host_t* check_lease(private_sql_attribute_t *this, char *name,
-                                                  u_int pool, u_int identity)
-{
-       while (TRUE)
-       {
-               u_int id;
-               chunk_t address;
-               enumerator_t *e;
-               time_t now = time(NULL);
-
-               e = this->db->query(this->db,
-                               "SELECT id, address FROM addresses "
-                               "WHERE pool = ? AND identity = ? AND released != 0 LIMIT 1",
-                               DB_UINT, pool, DB_UINT, identity, DB_UINT, DB_BLOB);
-               if (!e || !e->enumerate(e, &id, &address))
-               {
-                       DESTROY_IF(e);
-                       break;
-               }
-               address = chunk_clonea(address);
-               e->destroy(e);
-
-               if (this->db->execute(this->db, NULL,
-                               "UPDATE addresses SET acquired = ?, released = 0 "
-                               "WHERE id = ? AND identity = ? AND released != 0",
-                               DB_UINT, now, DB_UINT, id, DB_UINT, identity) > 0)
-               {
-                       host_t *host;
-
-                       host = host_create_from_chunk(AF_UNSPEC, address, 0);
-                       if (host)
-                       {
-                               DBG1(DBG_CFG, "acquired existing lease "
-                                        "for address %H in pool '%s'", host, name);
-                               return host;
-                       }
-               }
-       }
-       return NULL;
-}
-
-/**
- * We check for unallocated addresses or expired leases. First we select an
- * address as a candidate, but double check later on if it is still available
- * during the update operation. This allows us to work without locking.
- */
-static host_t* get_lease(private_sql_attribute_t *this, char *name,
-                                                u_int pool, u_int timeout, u_int identity)
-{
-       while (TRUE)
-       {
-               u_int id;
-               chunk_t address;
-               enumerator_t *e;
-               time_t now = time(NULL);
-               int hits;
-
-               if (timeout)
-               {
-                       /* check for an expired lease */
-                       e = this->db->query(this->db,
-                               "SELECT id, address FROM addresses "
-                               "WHERE pool = ? AND released != 0 AND released < ? LIMIT 1",
-                               DB_UINT, pool, DB_UINT, now - timeout, DB_UINT, DB_BLOB);
-               }
-               else
-               {
-                       /* with static leases, check for an unallocated address */
-                       e = this->db->query(this->db,
-                               "SELECT id, address FROM addresses "
-                               "WHERE pool = ? AND identity = 0 LIMIT 1",
-                               DB_UINT, pool, DB_UINT, DB_BLOB);
-
-               }
-
-               if (!e || !e->enumerate(e, &id, &address))
-               {
-                       DESTROY_IF(e);
-                       break;
-               }
-               address = chunk_clonea(address);
-               e->destroy(e);
-
-               if (timeout)
-               {
-                       hits = this->db->execute(this->db, NULL,
-                                               "UPDATE addresses SET "
-                                               "acquired = ?, released = 0, identity = ? "
-                                               "WHERE id = ? AND released != 0 AND released < ?",
-                                               DB_UINT, now, DB_UINT, identity,
-                                               DB_UINT, id, DB_UINT, now - timeout);
-               }
-               else
-               {
-                       hits = this->db->execute(this->db, NULL,
-                                               "UPDATE addresses SET "
-                                               "acquired = ?, released = 0, identity = ? "
-                                               "WHERE id = ? AND identity = 0",
-                                               DB_UINT, now, DB_UINT, identity, DB_UINT, id);
-               }
-               if (hits > 0)
-               {
-                       host_t *host;
-
-                       host = host_create_from_chunk(AF_UNSPEC, address, 0);
-                       if (host)
-                       {
-                               DBG1(DBG_CFG, "acquired new lease "
-                                        "for address %H in pool '%s'", host, name);
-                               return host;
-                       }
-               }
-       }
-       DBG1(DBG_CFG, "no available address found in pool '%s'", name);
-       return NULL;
-}
-
-/**
- * Implementation of attribute_provider_t.acquire_address
- */
-static host_t* acquire_address(private_sql_attribute_t *this,
-                                                          char *names, identification_t *id,
-                                                          host_t *requested)
-{
-       host_t *address = NULL;
-       u_int identity, pool, timeout;
-
-       identity = get_identity(this, id);
-       if (identity)
-       {
-               /* check for a single pool first (no concatenation and enumeration) */
-               if (strchr(names, ',') == NULL)
-               {
-                       pool = get_pool(this, names, &timeout);
-                       if (pool)
-                       {
-                               /* check for an existing lease */
-                               address = check_lease(this, names, pool, identity);
-                               if (address == NULL)
-                               {
-                                       /* get an unallocated address or expired lease */
-                                       address = get_lease(this, names, pool, timeout, identity);
-                               }
-                       }
-               }
-               else
-               {
-                       enumerator_t *enumerator;
-                       char *name;
-
-                       /* in a first step check for an existing lease over all pools */
-                       enumerator = enumerator_create_token(names, ",", " ");
-                       while (enumerator->enumerate(enumerator, &name))
-                       {
-                               pool = get_pool(this, name, &timeout);
-                               if (pool)
-                               {
-                                       address = check_lease(this, name, pool, identity);
-                                       if (address)
-                                       {
-                                               enumerator->destroy(enumerator);
-                                               return address;
-                                       }
-                               }
-                       }
-                       enumerator->destroy(enumerator);
-
-                       /* in a second step get an unallocated address or expired lease */
-                       enumerator = enumerator_create_token(names, ",", " ");
-                       while (enumerator->enumerate(enumerator, &name))
-                       {
-                               pool = get_pool(this, name, &timeout);
-                               if (pool)
-                               {
-                                       address = get_lease(this, name, pool, timeout, identity);
-                                       if (address)
-                                       {
-                                               break;
-                                       }
-                               }
-                       }
-                       enumerator->destroy(enumerator);
-               }
-       }
-       return address;
-}
-
-/**
- * Implementation of attribute_provider_t.release_address
- */
-static bool release_address(private_sql_attribute_t *this,
-                                                       char *name, host_t *address, identification_t *id)
-{
-       enumerator_t *enumerator;
-       bool found = FALSE;
-       time_t now = time(NULL);
-
-       enumerator = enumerator_create_token(name, ",", " ");
-       while (enumerator->enumerate(enumerator, &name))
-       {
-               u_int pool, timeout;
-
-               pool = get_pool(this, name, &timeout);
-               if (pool)
-               {
-                       if (this->history)
-                       {
-                               this->db->execute(this->db, NULL,
-                                       "INSERT INTO leases (address, identity, acquired, released)"
-                                       " SELECT id, identity, acquired, ? FROM addresses "
-                                       " WHERE pool = ? AND address = ?",
-                                       DB_UINT, now, DB_UINT, pool,
-                                       DB_BLOB, address->get_address(address));
-                       }
-                       if (this->db->execute(this->db, NULL,
-                                       "UPDATE addresses SET released = ? WHERE "
-                                       "pool = ? AND address = ?", DB_UINT, time(NULL),
-                                       DB_UINT, pool, DB_BLOB, address->get_address(address)) > 0)
-                       {
-                               found = TRUE;
-                               break;
-                       }
-               }
-       }
-       enumerator->destroy(enumerator);
-       return found;
-}
-
-/**
- * Implementation of sql_attribute_t.destroy
- */
-static void destroy(private_sql_attribute_t *this)
-{
-       free(this);
-}
-
-/*
- * see header file
- */
-sql_attribute_t *sql_attribute_create(database_t *db)
-{
-       private_sql_attribute_t *this = malloc_thing(private_sql_attribute_t);
-       time_t now = time(NULL);
-
-       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))enumerator_create_empty;
-       this->public.destroy = (void(*)(sql_attribute_t*))destroy;
-
-       this->db = db;
-       this->history = lib->settings->get_bool(lib->settings,
-                                                                       "charon.plugins.sql.lease_history", TRUE);
-
-       /* close any "online" leases in the case we crashed */
-       if (this->history)
-       {
-               this->db->execute(this->db, NULL,
-                                       "INSERT INTO leases (address, identity, acquired, released)"
-                                       " SELECT id, identity, acquired, ? FROM addresses "
-                                       " WHERE released = 0", DB_UINT, now);
-       }
-       this->db->execute(this->db, NULL,
-                                         "UPDATE addresses SET released = ? WHERE released = 0",
-                                         DB_UINT, now);
-       return &this->public;
-}
-
diff --git a/src/charon/plugins/sql/sql_attribute.h b/src/charon/plugins/sql/sql_attribute.h
deleted file mode 100644 (file)
index 27a3965..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2008 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-/**
- * @defgroup sql_attribute sql_attribute
- * @{ @ingroup sql
- */
-
-#ifndef SQL_ATTRIBUTE_H_
-#define SQL_ATTRIBUTE_H_
-
-#include <attributes/attribute_provider.h>
-#include <database/database.h>
-
-typedef struct sql_attribute_t sql_attribute_t;
-
-/**
- * SQL database based IKEv2 cfg attribute provider.
- */
-struct sql_attribute_t {
-
-       /**
-        * Implements attribute provider interface
-        */
-       attribute_provider_t provider;
-
-       /**
-        * Destroy a sql_attribute instance.
-        */
-       void (*destroy)(sql_attribute_t *this);
-};
-
-/**
- * Create a sql_attribute instance.
- */
-sql_attribute_t *sql_attribute_create(database_t *db);
-
-#endif /** SQL_ATTRIBUTE_H_ @}*/
index 05cdad5..e2e410a 100644 (file)
@@ -18,7 +18,6 @@
 #include <daemon.h>
 #include "sql_config.h"
 #include "sql_cred.h"
-#include "sql_attribute.h"
 #include "sql_logger.h"
 
 typedef struct private_sql_plugin_t private_sql_plugin_t;
@@ -49,11 +48,6 @@ struct private_sql_plugin_t {
        sql_cred_t *cred;
 
        /**
-        * CFG attributes
-        */
-       sql_attribute_t *attribute;
-
-       /**
         * bus listener/logger
         */
        sql_logger_t *logger;
@@ -67,10 +61,8 @@ static void destroy(private_sql_plugin_t *this)
        charon->backends->remove_backend(charon->backends, &this->config->backend);
        charon->credentials->remove_set(charon->credentials, &this->cred->set);
        charon->bus->remove_listener(charon->bus, &this->logger->listener);
-       lib->attributes->remove_provider(lib->attributes, &this->attribute->provider);
        this->config->destroy(this->config);
        this->cred->destroy(this->cred);
-       this->attribute->destroy(this->attribute);
        this->logger->destroy(this->logger);
        this->db->destroy(this->db);
        free(this);
@@ -104,10 +96,8 @@ plugin_t *plugin_create()
        }
        this->config = sql_config_create(this->db);
        this->cred = sql_cred_create(this->db);
-       this->attribute = sql_attribute_create(this->db);
        this->logger = sql_logger_create(this->db);
 
-       lib->attributes->add_provider(lib->attributes, &this->attribute->provider);
        charon->backends->add_backend(charon->backends, &this->config->backend);
        charon->credentials->add_set(charon->credentials, &this->cred->set);
        charon->bus->add_listener(charon->bus, &this->logger->listener);
index 7a8a7a3..d0413e6 100644 (file)
@@ -29,8 +29,8 @@ if USE_TOOLS
   libs += $(top_builddir)/src/scepclient/.libs/scepclient
 endif
 
-if USE_SQL
-  libs += $(top_builddir)/src/charon/plugins/sql/.libs/pool
+if USE_ATTR_SQL
+  libs += $(top_builddir)/src/libstrongswan/plugins/attr_sql/.libs/pool
 endif
 
 checksum.c : checksum_builder $(libs)
index b956588..d8d027e 100644 (file)
@@ -200,6 +200,10 @@ if USE_SQLITE
   SUBDIRS += plugins/sqlite
 endif
 
+if USE_ATTR_SQL
+  SUBDIRS += plugins/attr_sql
+endif
+
 if USE_PADLOCK
   SUBDIRS += plugins/padlock
 endif
diff --git a/src/libstrongswan/plugins/attr_sql/Makefile.am b/src/libstrongswan/plugins/attr_sql/Makefile.am
new file mode 100644 (file)
index 0000000..5be310a
--- /dev/null
@@ -0,0 +1,15 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan
+
+AM_CFLAGS = -rdynamic \
+  -DPLUGINS=\""${libstrongswan_plugins}\""
+
+plugin_LTLIBRARIES = libstrongswan-attr-sql.la
+libstrongswan_attr_sql_la_SOURCES = \
+  attr_sql_plugin.h attr_sql_plugin.c \
+  sql_attribute.h sql_attribute.c
+libstrongswan_attr_sql_la_LDFLAGS = -module -avoid-version
+
+ipsec_PROGRAMS = pool
+pool_SOURCES = pool.c
+pool_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la
diff --git a/src/libstrongswan/plugins/attr_sql/attr_sql_plugin.c b/src/libstrongswan/plugins/attr_sql/attr_sql_plugin.c
new file mode 100644 (file)
index 0000000..cb57af8
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <library.h>
+
+#include "attr_sql_plugin.h"
+#include "sql_attribute.h"
+
+typedef struct private_attr_sql_plugin_t private_attr_sql_plugin_t;
+
+/**
+ * private data of attr_sql plugin
+ */
+struct private_attr_sql_plugin_t {
+
+       /**
+        * implements plugin interface
+        */
+       attr_sql_plugin_t public;
+
+       /**
+        * database connection instance
+        */
+       database_t *db;
+
+       /**
+        * configuration attributes
+        */
+       sql_attribute_t *attribute;
+
+};
+
+/**
+ * Implementation of plugin_t.destroy
+ */
+static void destroy(private_attr_sql_plugin_t *this)
+{
+       lib->attributes->remove_provider(lib->attributes, &this->attribute->provider);
+       this->attribute->destroy(this->attribute);
+       this->db->destroy(this->db);
+       free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *plugin_create()
+{
+       char *uri;
+       private_attr_sql_plugin_t *this;
+
+       uri = lib->settings->get_str(lib->settings, "libstrongswan.plugins.attr-sql.database", NULL);
+       if (!uri)
+       {
+               DBG1("attr-sql plugin: database URI not set");
+               return NULL;
+       }
+
+       this = malloc_thing(private_attr_sql_plugin_t);
+
+       this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
+
+       this->db = lib->db->create(lib->db, uri);
+       if (!this->db)
+       {
+               DBG1("attr-sql plugin failed to connect to database");
+               free(this);
+               return NULL;
+       }
+       this->attribute = sql_attribute_create(this->db);
+       lib->attributes->add_provider(lib->attributes, &this->attribute->provider);
+
+       return &this->public.plugin;
+}
+
diff --git a/src/libstrongswan/plugins/attr_sql/attr_sql_plugin.h b/src/libstrongswan/plugins/attr_sql/attr_sql_plugin.h
new file mode 100644 (file)
index 0000000..3a7b842
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup sql sql
+ * @ingroup cplugins
+ *
+ * @defgroup sql_plugin sql_plugin
+ * @{ @ingroup sql
+ */
+
+#ifndef ATTR_SQL_PLUGIN_H_
+#define ATTR_SQL_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct attr_sql_plugin_t attr_sql_plugin_t;
+
+/**
+ * SQL database attribute configuration plugin
+ */
+struct attr_sql_plugin_t {
+
+       /**
+        * implements plugin interface
+        */
+       plugin_t plugin;
+};
+
+/**
+ * Create a sql_plugin instance.
+ */
+plugin_t *plugin_create();
+
+#endif /** ATTR_SQL_PLUGIN_H_ @}*/
diff --git a/src/libstrongswan/plugins/attr_sql/pool.c b/src/libstrongswan/plugins/attr_sql/pool.c
new file mode 100644 (file)
index 0000000..f4ccbd1
--- /dev/null
@@ -0,0 +1,767 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <getopt.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <debug.h>
+#include <library.h>
+#include <utils/host.h>
+#include <utils/identification.h>
+
+/**
+ * global database handle
+ */
+database_t *db;
+
+/**
+ * --start/--end addresses of various subcommands
+ */
+host_t *start = NULL, *end = NULL;
+
+/**
+ * calculate the size of a pool using start and end address chunk
+ */
+static u_int get_pool_size(chunk_t start, chunk_t end)
+{
+       u_int *start_ptr, *end_ptr;
+
+       if (start.len < sizeof(u_int) || end.len < sizeof(u_int))
+       {
+               return 0;
+       }
+       start_ptr = (u_int*)(start.ptr + start.len - sizeof(u_int));
+       end_ptr = (u_int*)(end.ptr + end.len - sizeof(u_int));
+       return ntohl(*end_ptr) -  ntohl(*start_ptr) + 1;
+}
+
+/**
+ * print usage info
+ */
+static void usage(void)
+{
+       printf("\
+Usage:\n\
+  ipsec pool --status|--add|--del|--resize|--purge [options]\n\
+  \n\
+  ipsec pool --status\n\
+    Show a list of installed pools with statistics.\n\
+  \n\
+  ipsec pool --add <name> --start <start> --end <end> [--timeout <timeout>]\n\
+    Add a new pool to the database.\n\
+      name:    Name of the pool, as used in ipsec.conf rightsourceip=%%name\n\
+      start:   Start address of the pool\n\
+      end:     End address of the pool\n\
+      timeout: Lease time in hours, 0 for static leases\n\
+  \n\
+  ipsec pool --del <name>\n\
+    Delete a pool from the database.\n\
+      name:   Name of the pool to delete\n\
+  \n\
+  ipsec pool --resize <name> --end <end>\n\
+    Grow or shrink an existing pool.\n\
+      name:   Name of the pool to resize\n\
+      end:    New end address for the pool\n\
+  \n\
+  ipsec pool --leases [--filter <filter>] [--utc]\n\
+    Show lease information using filters:\n\
+      filter: Filter string containing comma separated key=value filters,\n\
+              e.g. id=alice@strongswan.org,addr=1.1.1.1\n\
+                  pool:   name of the pool\n\
+                  id:     assigned identity of the lease\n\
+                  addr:   lease IP address\n\
+                  tstamp: UNIX timestamp when lease was valid, as integer\n\
+                  status: status of the lease: online|valid|expired\n\
+      utc:    Show times in UTC instead of local time\n\
+  \n\
+  ipsec pool --purge <name>\n\
+    Delete lease history of a pool:\n\
+      name:   Name of the pool to purge\n\
+  \n");
+       exit(0);
+}
+
+/**
+ * ipsec pool --status - show pool overview
+ */
+static void status(void)
+{
+       enumerator_t *pool, *lease;
+       bool found = FALSE;
+
+       pool = db->query(db, "SELECT id, name, start, end, timeout FROM pools",
+                                        DB_INT, DB_TEXT, DB_BLOB, DB_BLOB, DB_UINT);
+       if (pool)
+       {
+               char *name;
+               chunk_t start_chunk, end_chunk;
+               host_t *start, *end;
+               u_int id, timeout, online = 0, used = 0, size = 0;
+
+               while (pool->enumerate(pool, &id, &name,
+                                                          &start_chunk, &end_chunk, &timeout))
+               {
+                       if (!found)
+                       {
+                               printf("%8s %15s %15s %8s %6s %11s %11s\n", "name", "start",
+                                          "end", "timeout", "size", "online", "usage");
+                               found = TRUE;
+                       }
+
+                       start = host_create_from_chunk(AF_UNSPEC, start_chunk, 0);
+                       end = host_create_from_chunk(AF_UNSPEC, end_chunk, 0);
+                       size = get_pool_size(start_chunk, end_chunk);
+                       printf("%8s %15H %15H ", name, start, end);
+                       if (timeout)
+                       {
+                               printf("%7dh ", timeout/3600);
+                       }
+                       else
+                       {
+                               printf("%8s ", "static");
+                       }
+                       printf("%6d ", size);
+                       /* get number of online hosts */
+                       lease = db->query(db, "SELECT COUNT(*) FROM addresses "
+                                                         "WHERE pool = ? AND released = 0",
+                                                         DB_UINT, id, DB_INT);
+                       if (lease)
+                       {
+                               lease->enumerate(lease, &online);
+                               lease->destroy(lease);
+                       }
+                       printf("%5d (%2d%%) ", online, online*100/size);
+                       /* get number of online or valid lieases */
+                       lease = db->query(db, "SELECT COUNT(*) FROM addresses "
+                                                         "WHERE addresses.pool = ? "
+                                                         "AND ((? AND acquired != 0) "
+                                                         "     OR released = 0 OR released > ?) ",
+                                                         DB_UINT, id, DB_UINT, !timeout,
+                                                         DB_UINT, time(NULL) - timeout, DB_UINT);
+                       if (lease)
+                       {
+                               lease->enumerate(lease, &used);
+                               lease->destroy(lease);
+                       }
+                       printf("%5d (%2d%%) ", used, used*100/size);
+
+                       printf("\n");
+                       DESTROY_IF(start);
+                       DESTROY_IF(end);
+               }
+               pool->destroy(pool);
+       }
+       if (!found)
+       {
+               printf("no pools found.\n");
+       }
+       exit(0);
+}
+
+/**
+ * ipsec pool --add - add a new pool
+ */
+static void add(char *name, host_t *start, host_t *end, int timeout)
+{
+       chunk_t start_addr, end_addr, cur_addr;
+       u_int id, count;
+
+       start_addr = start->get_address(start);
+       end_addr = end->get_address(end);
+       cur_addr = chunk_clonea(start_addr);
+       count = get_pool_size(start_addr, end_addr);
+
+       if (start_addr.len != end_addr.len ||
+               memcmp(start_addr.ptr, end_addr.ptr, start_addr.len) > 0)
+       {
+               fprintf(stderr, "invalid start/end pair specified.\n");
+               exit(-1);
+       }
+       if (db->execute(db, &id,
+                       "INSERT INTO pools (name, start, end, timeout) "
+                       "VALUES (?, ?, ?, ?)",
+                       DB_TEXT, name, DB_BLOB, start_addr,
+                       DB_BLOB, end_addr, DB_INT, timeout*3600) != 1)
+       {
+               fprintf(stderr, "creating pool failed.\n");
+               exit(-1);
+       }
+       printf("allocating %d addresses... ", count);
+       fflush(stdout);
+       if (db->get_driver(db) == DB_SQLITE)
+       {       /* run population in a transaction for sqlite */
+               db->execute(db, NULL, "BEGIN TRANSACTION");
+       }
+       while (TRUE)
+       {
+               db->execute(db, NULL,
+                       "INSERT INTO addresses (pool, address, identity, acquired, released) "
+                       "VALUES (?, ?, ?, ?, ?)",
+                       DB_UINT, id, DB_BLOB, cur_addr, DB_UINT, 0, DB_UINT, 0, DB_UINT, 1);
+               if (chunk_equals(cur_addr, end_addr))
+               {
+                       break;
+               }
+               chunk_increment(cur_addr);
+       }
+       if (db->get_driver(db) == DB_SQLITE)
+       {
+               db->execute(db, NULL, "END TRANSACTION");
+       }
+       printf("done.\n", count);
+
+       exit(0);
+}
+
+/**
+ * ipsec pool --del - delete a pool
+ */
+static void del(char *name)
+{
+       enumerator_t *query;
+       u_int id;
+       bool found = FALSE;
+
+       query = db->query(db, "SELECT id FROM pools WHERE name = ?",
+                                         DB_TEXT, name, DB_UINT);
+       if (!query)
+       {
+               fprintf(stderr, "deleting pool failed.\n");
+               exit(-1);
+       }
+       while (query->enumerate(query, &id))
+       {
+               found = TRUE;
+               if (db->execute(db, NULL,
+                               "DELETE FROM leases WHERE address IN ("
+                               " SELECT id FROM addresses WHERE pool = ?)", DB_UINT, id) < 0 ||
+                       db->execute(db, NULL,
+                               "DELETE FROM addresses WHERE pool = ?", DB_UINT, id) < 0 ||
+                       db->execute(db, NULL,
+                               "DELETE FROM pools WHERE id = ?", DB_UINT, id) < 0)
+               {
+                       fprintf(stderr, "deleting pool failed.\n");
+                       query->destroy(query);
+                       exit(-1);
+               }
+       }
+       query->destroy(query);
+       if (!found)
+       {
+               fprintf(stderr, "pool '%s' not found.\n", name);
+               exit(-1);
+       }
+       exit(0);
+}
+
+/**
+ * ipsec pool --resize - resize a pool
+ */
+static void resize(char *name, host_t *end)
+{
+       enumerator_t *query;
+       chunk_t old_addr, new_addr, cur_addr;
+       u_int id, count;
+
+       new_addr = end->get_address(end);
+
+       query = db->query(db, "SELECT id, end FROM pools WHERE name = ?",
+                                         DB_TEXT, name, DB_UINT, DB_BLOB);
+       if (!query || !query->enumerate(query, &id, &old_addr))
+       {
+               DESTROY_IF(query);
+               fprintf(stderr, "resizing pool failed.\n");
+               exit(-1);
+       }
+       if (old_addr.len != new_addr.len ||
+               memcmp(new_addr.ptr, old_addr.ptr, old_addr.len) < 0)
+       {
+               fprintf(stderr, "shrinking of pools not supported.\n");
+               query->destroy(query);
+               exit(-1);
+       }
+       cur_addr = chunk_clonea(old_addr);
+       count = get_pool_size(old_addr, new_addr) - 1;
+       query->destroy(query);
+
+       if (db->execute(db, NULL,
+                       "UPDATE pools SET end = ? WHERE name = ?",
+                       DB_BLOB, new_addr, DB_TEXT, name) <= 0)
+       {
+               fprintf(stderr, "pool '%s' not found.\n", name);
+               exit(-1);
+       }
+
+       printf("allocating %d new addresses... ", count);
+       fflush(stdout);
+       if (db->get_driver(db) == DB_SQLITE)
+       {       /* run population in a transaction for sqlite */
+               db->execute(db, NULL, "BEGIN TRANSACTION");
+       }
+       while (count-- > 0)
+       {
+               chunk_increment(cur_addr);
+               db->execute(db, NULL,
+                       "INSERT INTO addresses (pool, address, identity, acquired, released) "
+                       "VALUES (?, ?, ?, ?, ?)",
+                       DB_UINT, id, DB_BLOB, cur_addr, DB_UINT, 0, DB_UINT, 0, DB_UINT, 1);
+       }
+       if (db->get_driver(db) == DB_SQLITE)
+       {
+               db->execute(db, NULL, "END TRANSACTION");
+       }
+       printf("done.\n", count);
+
+       exit(0);
+}
+
+/**
+ * create the lease query using the filter string
+ */
+static enumerator_t *create_lease_query(char *filter)
+{
+       enumerator_t *query;
+       identification_t *id = NULL;
+       host_t *addr = NULL;
+       u_int tstamp = 0;
+       bool online = FALSE, valid = FALSE, expired = FALSE;
+       char *value, *pos, *pool = NULL;
+       enum {
+               FIL_POOL = 0,
+               FIL_ID,
+               FIL_ADDR,
+               FIL_TSTAMP,
+               FIL_STATE,
+       };
+       char *const token[] = {
+               [FIL_POOL] = "pool",
+               [FIL_ID] = "id",
+               [FIL_ADDR] = "addr",
+               [FIL_TSTAMP] = "tstamp",
+               [FIL_STATE] = "status",
+               NULL
+       };
+
+       /* if the filter string contains a distinguished name as a ID, we replace
+        * ", " by "/ " in order to not confuse the getsubopt parser */
+       pos = filter;
+       while ((pos = strchr(pos, ',')))
+       {
+               if (pos[1] == ' ')
+               {
+                       pos[0] = '/';
+               }
+               pos++;
+       }
+
+       while (filter && *filter != '\0')
+       {
+               switch (getsubopt(&filter, token, &value))
+               {
+                       case FIL_POOL:
+                               if (value)
+                               {
+                                       pool = value;
+                               }
+                               break;
+                       case FIL_ID:
+                               if (value)
+                               {
+                                       id = identification_create_from_string(value);
+                               }
+                               break;
+                       case FIL_ADDR:
+                               if (value)
+                               {
+                                       addr = host_create_from_string(value, 0);
+                               }
+                               if (!addr)
+                               {
+                                       fprintf(stderr, "invalid 'addr' in filter string.\n");
+                                       exit(-1);
+                               }
+                               break;
+                       case FIL_TSTAMP:
+                               if (value)
+                               {
+                                       tstamp = atoi(value);
+                               }
+                               if (tstamp == 0)
+                               {
+                                       online = TRUE;
+                               }
+                               break;
+                       case FIL_STATE:
+                               if (value)
+                               {
+                                       if (streq(value, "online"))
+                                       {
+                                               online = TRUE;
+                                       }
+                                       else if (streq(value, "valid"))
+                                       {
+                                               valid = TRUE;
+                                       }
+                                       else if (streq(value, "expired"))
+                                       {
+                                               expired = TRUE;
+                                       }
+                                       else
+                                       {
+                                               fprintf(stderr, "invalid 'state' in filter string.\n");
+                                               exit(-1);
+                                       }
+                               }
+                               break;
+                       default:
+                               fprintf(stderr, "invalid filter string.\n");
+                               exit(-1);
+                               break;
+               }
+       }
+       query = db->query(db,
+                               "SELECT name, addresses.address, identities.type, "
+                               "identities.data, leases.acquired, leases.released, timeout "
+                               "FROM leases JOIN addresses ON leases.address = addresses.id "
+                               "JOIN pools ON addresses.pool = pools.id "
+                               "JOIN identities ON leases.identity = identities.id "
+                               "WHERE (? OR name = ?) "
+                               "AND (? OR (identities.type = ? AND identities.data = ?)) "
+                               "AND (? OR addresses.address = ?) "
+                               "AND (? OR (? >= leases.acquired AND (? <= leases.released))) "
+                               "AND (? OR leases.released > ? - timeout) "
+                               "AND (? OR leases.released < ? - timeout) "
+                               "AND ? "
+                               "UNION "
+                               "SELECT name, address, identities.type, identities.data, "
+                               "acquired, released, timeout FROM addresses "
+                               "JOIN pools ON addresses.pool = pools.id "
+                               "JOIN identities ON addresses.identity = identities.id "
+                               "WHERE ? AND released = 0 "
+                               "AND (? OR name = ?) "
+                               "AND (? OR (identities.type = ? AND identities.data = ?)) "
+                               "AND (? OR address = ?)",
+                               DB_INT, pool == NULL, DB_TEXT, pool,
+                               DB_INT, id == NULL,
+                                       DB_INT, id ? id->get_type(id) : 0,
+                                       DB_BLOB, id ? id->get_encoding(id) : chunk_empty,
+                               DB_INT, addr == NULL,
+                                       DB_BLOB, addr ? addr->get_address(addr) : chunk_empty,
+                               DB_INT, tstamp == 0, DB_UINT, tstamp, DB_UINT, tstamp,
+                               DB_INT, !valid, DB_INT, time(NULL),
+                               DB_INT, !expired, DB_INT, time(NULL),
+                               DB_INT, !online,
+                               /* union */
+                               DB_INT, !(valid || expired),
+                               DB_INT, pool == NULL, DB_TEXT, pool,
+                               DB_INT, id == NULL,
+                                       DB_INT, id ? id->get_type(id) : 0,
+                                       DB_BLOB, id ? id->get_encoding(id) : chunk_empty,
+                               DB_INT, addr == NULL,
+                                       DB_BLOB, addr ? addr->get_address(addr) : chunk_empty,
+                               /* res */
+                               DB_TEXT, DB_BLOB, DB_INT, DB_BLOB, DB_UINT, DB_UINT, DB_UINT);
+       /* id and addr leak but we can't destroy them until query is destroyed. */
+       return query;
+}
+
+/**
+ * ipsec pool --leases - show lease information of a pool
+ */
+static void leases(char *filter, bool utc)
+{
+       enumerator_t *query;
+       chunk_t address_chunk, identity_chunk;
+       int identity_type;
+       char *name;
+       u_int acquired, released, timeout;
+       host_t *address;
+       identification_t *identity;
+       bool found = FALSE;
+
+       query = create_lease_query(filter);
+       if (!query)
+       {
+               fprintf(stderr, "querying leases failed.\n");
+               exit(-1);
+       }
+       while (query->enumerate(query, &name, &address_chunk, &identity_type,
+                                                       &identity_chunk, &acquired, &released, &timeout))
+       {
+               if (!found)
+               {
+                       int len = utc ? 25 : 21;
+
+                       found = TRUE;
+                       printf("%-8s %-15s %-7s  %-*s %-*s %s\n",
+                                  "name", "address", "status", len, "start", len, "end", "identity");
+               }
+               address = host_create_from_chunk(AF_UNSPEC, address_chunk, 0);
+               identity = identification_create_from_encoding(identity_type, identity_chunk);
+
+               printf("%-8s %-15H ", name, address);
+               if (released == 0)
+               {
+                       printf("%-7s ", "online");
+               }
+               else if (timeout == 0)
+               {
+                       printf("%-7s ", "static");
+               }
+               else if (released >= time(NULL) - timeout)
+               {
+                       printf("%-7s ", "valid");
+               }
+               else
+               {
+                       printf("%-7s ", "expired");
+               }
+
+               printf(" %T  ", &acquired, utc);
+               if (released)
+               {
+                       printf("%T  ", &released, utc);
+               }
+               else
+               {
+                       printf("                      ");
+                       if (utc)
+                       {
+                               printf("    ");
+                       }
+               }
+               printf("%Y\n", identity);
+               DESTROY_IF(address);
+               identity->destroy(identity);
+       }
+       query->destroy(query);
+       if (!found)
+       {
+               fprintf(stderr, "no matching leases found.\n");
+               exit(-1);
+       }
+       exit(0);
+}
+
+/**
+ * ipsec pool --purge - delete expired leases
+ */
+static void purge(char *name)
+{
+       int purged = 0;
+
+       purged = db->execute(db, NULL,
+                               "DELETE FROM leases WHERE address IN ("
+                               " SELECT id FROM addresses WHERE pool IN ("
+                               "  SELECT id FROM pools WHERE name = ?))",
+                               DB_TEXT, name);
+       if (purged < 0)
+       {
+               fprintf(stderr, "purging pool '%s' failed.\n", name);
+               exit(-1);
+       }
+       fprintf(stderr, "purged %d leases in pool '%s'.\n", purged, name);
+       exit(0);
+}
+
+/**
+ * atexit handler to close db on shutdown
+ */
+static void cleanup(void)
+{
+       db->destroy(db);
+       DESTROY_IF(start);
+       DESTROY_IF(end);
+}
+
+int main(int argc, char *argv[])
+{
+       char *uri, *name = "", *filter = "";
+       int timeout = 0;
+       bool utc = FALSE;
+       enum {
+               OP_USAGE,
+               OP_STATUS,
+               OP_ADD,
+               OP_DEL,
+               OP_RESIZE,
+               OP_LEASES,
+               OP_PURGE,
+       } operation = OP_USAGE;
+
+       atexit(library_deinit);
+
+       /* initialize library */
+       if (!library_init(NULL))
+       {
+               exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
+       }
+       if (lib->integrity &&
+               !lib->integrity->check_file(lib->integrity, "pool", argv[0]))
+       {
+               fprintf(stderr, "integrity check of pool failed\n");
+               exit(SS_RC_DAEMON_INTEGRITY);
+       }
+       if (!lib->plugins->load(lib->plugins, NULL,
+                       lib->settings->get_str(lib->settings, "pool.load", PLUGINS)))
+       {
+               exit(SS_RC_INITIALIZATION_FAILED);
+       }
+
+       uri = lib->settings->get_str(lib->settings, "libstrongswan.plugins.attr-sql.database", NULL);
+       if (!uri)
+       {
+               fprintf(stderr, "database URI libstrongswan.plugins.attr-sql.database not set.\n");
+               exit(SS_RC_INITIALIZATION_FAILED);
+       }
+       db = lib->db->create(lib->db, uri);
+       if (!db)
+       {
+               fprintf(stderr, "opening database failed.\n");
+               exit(SS_RC_INITIALIZATION_FAILED);
+       }
+       atexit(cleanup);
+
+       while (TRUE)
+       {
+               int c;
+
+               struct option long_opts[] = {
+                       { "help", no_argument, NULL, 'h' },
+
+                       { "utc", no_argument, NULL, 'u' },
+                       { "status", no_argument, NULL, 'w' },
+                       { "add", required_argument, NULL, 'a' },
+                       { "del", required_argument, NULL, 'd' },
+                       { "resize", required_argument, NULL, 'r' },
+                       { "leases", no_argument, NULL, 'l' },
+                       { "purge", required_argument, NULL, 'p' },
+
+                       { "start", required_argument, NULL, 's' },
+                       { "end", required_argument, NULL, 'e' },
+                       { "timeout", required_argument, NULL, 't' },
+                       { "filter", required_argument, NULL, 'f' },
+                       { 0,0,0,0 }
+               };
+
+               c = getopt_long(argc, argv, "", long_opts, NULL);
+               switch (c)
+               {
+                       case EOF:
+                               break;
+                       case 'h':
+                               break;
+                       case 'w':
+                               operation = OP_STATUS;
+                               break;
+                       case 'u':
+                               utc = TRUE;
+                               continue;
+                       case 'a':
+                               operation = OP_ADD;
+                               name = optarg;
+                               continue;
+                       case 'd':
+                               operation = OP_DEL;
+                               name = optarg;
+                               continue;
+                       case 'r':
+                               operation = OP_RESIZE;
+                               name = optarg;
+                               continue;
+                       case 'l':
+                               operation = OP_LEASES;
+                               continue;
+                       case 'p':
+                               operation = OP_PURGE;
+                               name = optarg;
+                               continue;
+                       case 's':
+                               start = host_create_from_string(optarg, 0);
+                               if (start == NULL)
+                               {
+                                       fprintf(stderr, "invalid start address: '%s'.\n", optarg);
+                                       operation = OP_USAGE;
+                                       break;
+                               }
+                               continue;
+                       case 'e':
+                               end = host_create_from_string(optarg, 0);
+                               if (end == NULL)
+                               {
+                                       fprintf(stderr, "invalid end address: '%s'.\n", optarg);
+                                       operation = OP_USAGE;
+                                       break;
+                               }
+                               continue;
+                       case 't':
+                               timeout = atoi(optarg);
+                               if (timeout == 0 && strcmp(optarg, "0") != 0)
+                               {
+                                       fprintf(stderr, "invalid timeout '%s'.\n", optarg);
+                                       operation = OP_USAGE;
+                                       break;
+                               }
+                               continue;
+                       case 'f':
+                               filter = optarg;
+                               continue;
+                       default:
+                               operation = OP_USAGE;
+                               break;
+               }
+               break;
+       }
+
+       switch (operation)
+       {
+               case OP_USAGE:
+                       usage();
+                       break;
+               case OP_STATUS:
+                       status();
+                       break;
+               case OP_ADD:
+                       if (start == NULL || end == NULL)
+                       {
+                               fprintf(stderr, "missing arguments.\n");
+                               usage();
+                       }
+                       add(name, start, end, timeout);
+                       break;
+               case OP_DEL:
+                       del(name);
+                       break;
+               case OP_RESIZE:
+                       if (end == NULL)
+                       {
+                               fprintf(stderr, "missing arguments.\n");
+                               usage();
+                       }
+                       resize(name, end);
+                       break;
+               case OP_LEASES:
+                       leases(filter, utc);
+                       break;
+               case OP_PURGE:
+                       purge(name);
+                       break;
+       }
+       exit(0);
+}
+
diff --git a/src/libstrongswan/plugins/attr_sql/sql_attribute.c b/src/libstrongswan/plugins/attr_sql/sql_attribute.c
new file mode 100644 (file)
index 0000000..4053516
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <time.h>
+
+#include <debug.h>
+#include <library.h>
+
+#include "sql_attribute.h"
+
+typedef struct private_sql_attribute_t private_sql_attribute_t;
+
+/**
+ * private data of sql_attribute
+ */
+struct private_sql_attribute_t {
+
+       /**
+        * public functions
+        */
+       sql_attribute_t public;
+
+       /**
+        * database connection
+        */
+       database_t *db;
+
+       /**
+        * wheter to record lease history in lease table
+        */
+       bool history;
+};
+
+/**
+ * lookup/insert an identity
+ */
+static u_int get_identity(private_sql_attribute_t *this, identification_t *id)
+{
+       enumerator_t *e;
+       u_int row;
+
+       /* look for peer identity in the identities table */
+       e = this->db->query(this->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 (this->db->execute(this->db, &row,
+                                 "INSERT INTO identities (type, data) VALUES (?, ?)",
+                                 DB_INT, id->get_type(id), DB_BLOB, id->get_encoding(id)) == 1)
+       {
+               return row;
+       }
+       return 0;
+}
+
+/**
+ * Lookup pool by name
+ */
+static u_int get_pool(private_sql_attribute_t *this, char *name, u_int *timeout)
+{
+       enumerator_t *e;
+       u_int pool;
+
+       e = this->db->query(this->db, "SELECT id, timeout FROM pools WHERE name = ?",
+                                               DB_TEXT, name, DB_UINT, DB_UINT);
+       if (e && e->enumerate(e, &pool, timeout))
+       {
+               e->destroy(e);
+               return pool;
+       }
+       DESTROY_IF(e);
+       return 0;
+}
+
+/**
+ * Look up an existing lease
+ */
+static host_t* check_lease(private_sql_attribute_t *this, char *name,
+                                                  u_int pool, u_int identity)
+{
+       while (TRUE)
+       {
+               u_int id;
+               chunk_t address;
+               enumerator_t *e;
+               time_t now = time(NULL);
+
+               e = this->db->query(this->db,
+                               "SELECT id, address FROM addresses "
+                               "WHERE pool = ? AND identity = ? AND released != 0 LIMIT 1",
+                               DB_UINT, pool, DB_UINT, identity, DB_UINT, DB_BLOB);
+               if (!e || !e->enumerate(e, &id, &address))
+               {
+                       DESTROY_IF(e);
+                       break;
+               }
+               address = chunk_clonea(address);
+               e->destroy(e);
+
+               if (this->db->execute(this->db, NULL,
+                               "UPDATE addresses SET acquired = ?, released = 0 "
+                               "WHERE id = ? AND identity = ? AND released != 0",
+                               DB_UINT, now, DB_UINT, id, DB_UINT, identity) > 0)
+               {
+                       host_t *host;
+
+                       host = host_create_from_chunk(AF_UNSPEC, address, 0);
+                       if (host)
+                       {
+                               DBG1("acquired existing lease for address %H in pool '%s'",
+                                        host, name);
+                               return host;
+                       }
+               }
+       }
+       return NULL;
+}
+
+/**
+ * We check for unallocated addresses or expired leases. First we select an
+ * address as a candidate, but double check later on if it is still available
+ * during the update operation. This allows us to work without locking.
+ */
+static host_t* get_lease(private_sql_attribute_t *this, char *name,
+                                                u_int pool, u_int timeout, u_int identity)
+{
+       while (TRUE)
+       {
+               u_int id;
+               chunk_t address;
+               enumerator_t *e;
+               time_t now = time(NULL);
+               int hits;
+
+               if (timeout)
+               {
+                       /* check for an expired lease */
+                       e = this->db->query(this->db,
+                               "SELECT id, address FROM addresses "
+                               "WHERE pool = ? AND released != 0 AND released < ? LIMIT 1",
+                               DB_UINT, pool, DB_UINT, now - timeout, DB_UINT, DB_BLOB);
+               }
+               else
+               {
+                       /* with static leases, check for an unallocated address */
+                       e = this->db->query(this->db,
+                               "SELECT id, address FROM addresses "
+                               "WHERE pool = ? AND identity = 0 LIMIT 1",
+                               DB_UINT, pool, DB_UINT, DB_BLOB);
+
+               }
+
+               if (!e || !e->enumerate(e, &id, &address))
+               {
+                       DESTROY_IF(e);
+                       break;
+               }
+               address = chunk_clonea(address);
+               e->destroy(e);
+
+               if (timeout)
+               {
+                       hits = this->db->execute(this->db, NULL,
+                                               "UPDATE addresses SET "
+                                               "acquired = ?, released = 0, identity = ? "
+                                               "WHERE id = ? AND released != 0 AND released < ?",
+                                               DB_UINT, now, DB_UINT, identity,
+                                               DB_UINT, id, DB_UINT, now - timeout);
+               }
+               else
+               {
+                       hits = this->db->execute(this->db, NULL,
+                                               "UPDATE addresses SET "
+                                               "acquired = ?, released = 0, identity = ? "
+                                               "WHERE id = ? AND identity = 0",
+                                               DB_UINT, now, DB_UINT, identity, DB_UINT, id);
+               }
+               if (hits > 0)
+               {
+                       host_t *host;
+
+                       host = host_create_from_chunk(AF_UNSPEC, address, 0);
+                       if (host)
+                       {
+                               DBG1("acquired new lease for address %H in pool '%s'",
+                                        host, name);
+                               return host;
+                       }
+               }
+       }
+       DBG1("no available address found in pool '%s'", name);
+       return NULL;
+}
+
+/**
+ * Implementation of attribute_provider_t.acquire_address
+ */
+static host_t* acquire_address(private_sql_attribute_t *this,
+                                                          char *names, identification_t *id,
+                                                          host_t *requested)
+{
+       host_t *address = NULL;
+       u_int identity, pool, timeout;
+
+       identity = get_identity(this, id);
+       if (identity)
+       {
+               /* check for a single pool first (no concatenation and enumeration) */
+               if (strchr(names, ',') == NULL)
+               {
+                       pool = get_pool(this, names, &timeout);
+                       if (pool)
+                       {
+                               /* check for an existing lease */
+                               address = check_lease(this, names, pool, identity);
+                               if (address == NULL)
+                               {
+                                       /* get an unallocated address or expired lease */
+                                       address = get_lease(this, names, pool, timeout, identity);
+                               }
+                       }
+               }
+               else
+               {
+                       enumerator_t *enumerator;
+                       char *name;
+
+                       /* in a first step check for an existing lease over all pools */
+                       enumerator = enumerator_create_token(names, ",", " ");
+                       while (enumerator->enumerate(enumerator, &name))
+                       {
+                               pool = get_pool(this, name, &timeout);
+                               if (pool)
+                               {
+                                       address = check_lease(this, name, pool, identity);
+                                       if (address)
+                                       {
+                                               enumerator->destroy(enumerator);
+                                               return address;
+                                       }
+                               }
+                       }
+                       enumerator->destroy(enumerator);
+
+                       /* in a second step get an unallocated address or expired lease */
+                       enumerator = enumerator_create_token(names, ",", " ");
+                       while (enumerator->enumerate(enumerator, &name))
+                       {
+                               pool = get_pool(this, name, &timeout);
+                               if (pool)
+                               {
+                                       address = get_lease(this, name, pool, timeout, identity);
+                                       if (address)
+                                       {
+                                               break;
+                                       }
+                               }
+                       }
+                       enumerator->destroy(enumerator);
+               }
+       }
+       return address;
+}
+
+/**
+ * Implementation of attribute_provider_t.release_address
+ */
+static bool release_address(private_sql_attribute_t *this,
+                                                       char *name, host_t *address, identification_t *id)
+{
+       enumerator_t *enumerator;
+       bool found = FALSE;
+       time_t now = time(NULL);
+
+       enumerator = enumerator_create_token(name, ",", " ");
+       while (enumerator->enumerate(enumerator, &name))
+       {
+               u_int pool, timeout;
+
+               pool = get_pool(this, name, &timeout);
+               if (pool)
+               {
+                       if (this->history)
+                       {
+                               this->db->execute(this->db, NULL,
+                                       "INSERT INTO leases (address, identity, acquired, released)"
+                                       " SELECT id, identity, acquired, ? FROM addresses "
+                                       " WHERE pool = ? AND address = ?",
+                                       DB_UINT, now, DB_UINT, pool,
+                                       DB_BLOB, address->get_address(address));
+                       }
+                       if (this->db->execute(this->db, NULL,
+                                       "UPDATE addresses SET released = ? WHERE "
+                                       "pool = ? AND address = ?", DB_UINT, time(NULL),
+                                       DB_UINT, pool, DB_BLOB, address->get_address(address)) > 0)
+                       {
+                               found = TRUE;
+                               break;
+                       }
+               }
+       }
+       enumerator->destroy(enumerator);
+       return found;
+}
+
+/**
+ * Implementation of sql_attribute_t.destroy
+ */
+static void destroy(private_sql_attribute_t *this)
+{
+       free(this);
+}
+
+/*
+ * see header file
+ */
+sql_attribute_t *sql_attribute_create(database_t *db)
+{
+       private_sql_attribute_t *this = malloc_thing(private_sql_attribute_t);
+       time_t now = time(NULL);
+
+       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))enumerator_create_empty;
+       this->public.destroy = (void(*)(sql_attribute_t*))destroy;
+
+       this->db = db;
+       this->history = lib->settings->get_bool(lib->settings,
+                                                                       "charon.plugins.sql.lease_history", TRUE);
+
+       /* close any "online" leases in the case we crashed */
+       if (this->history)
+       {
+               this->db->execute(this->db, NULL,
+                                       "INSERT INTO leases (address, identity, acquired, released)"
+                                       " SELECT id, identity, acquired, ? FROM addresses "
+                                       " WHERE released = 0", DB_UINT, now);
+       }
+       this->db->execute(this->db, NULL,
+                                         "UPDATE addresses SET released = ? WHERE released = 0",
+                                         DB_UINT, now);
+       return &this->public;
+}
+
diff --git a/src/libstrongswan/plugins/attr_sql/sql_attribute.h b/src/libstrongswan/plugins/attr_sql/sql_attribute.h
new file mode 100644 (file)
index 0000000..27a3965
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup sql_attribute sql_attribute
+ * @{ @ingroup sql
+ */
+
+#ifndef SQL_ATTRIBUTE_H_
+#define SQL_ATTRIBUTE_H_
+
+#include <attributes/attribute_provider.h>
+#include <database/database.h>
+
+typedef struct sql_attribute_t sql_attribute_t;
+
+/**
+ * SQL database based IKEv2 cfg attribute provider.
+ */
+struct sql_attribute_t {
+
+       /**
+        * Implements attribute provider interface
+        */
+       attribute_provider_t provider;
+
+       /**
+        * Destroy a sql_attribute instance.
+        */
+       void (*destroy)(sql_attribute_t *this);
+};
+
+/**
+ * Create a sql_attribute instance.
+ */
+sql_attribute_t *sql_attribute_create(database_t *db);
+
+#endif /** SQL_ATTRIBUTE_H_ @}*/
index 5f66bae..b7c598f 100644 (file)
@@ -1,12 +1,15 @@
 # /etc/strongswan.conf - strongSwan configuration file
 
 charon {
+  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke kernel-netlink sqlite attr-sql updown
+}
+
+libstrongswan {
   plugins {
-    sql {
-      database = sqlite:///etc/ipsec.d/ipsec.db 
+    attr-sql {
+      database = sqlite:///etc/ipsec.d/ipsec.db
     }
   }
-  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke kernel-netlink sqlite sql updown
 }
 
 pool {
index 5f66bae..b7c598f 100644 (file)
@@ -1,12 +1,15 @@
 # /etc/strongswan.conf - strongSwan configuration file
 
 charon {
+  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke kernel-netlink sqlite attr-sql updown
+}
+
+libstrongswan {
   plugins {
-    sql {
-      database = sqlite:///etc/ipsec.d/ipsec.db 
+    attr-sql {
+      database = sqlite:///etc/ipsec.d/ipsec.db
     }
   }
-  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke kernel-netlink sqlite sql updown
 }
 
 pool {
index c4c4357..1ce52a8 100644 (file)
@@ -1,12 +1,15 @@
 # /etc/strongswan.conf - strongSwan configuration file
 
 charon {
+  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke sqlite attr-sql kernel-netlink updown
+}
+
+libstrongswan {
   plugins {
-    sql {
-      database = sqlite:///etc/ipsec.d/ipsec.db 
+    attr-sql {
+      database = sqlite:///etc/ipsec.d/ipsec.db
     }
   }
-  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke sqlite sql kernel-netlink updown
 }
 
 pool {
index c4c4357..1ce52a8 100644 (file)
@@ -1,12 +1,15 @@
 # /etc/strongswan.conf - strongSwan configuration file
 
 charon {
+  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke sqlite attr-sql kernel-netlink updown
+}
+
+libstrongswan {
   plugins {
-    sql {
-      database = sqlite:///etc/ipsec.d/ipsec.db 
+    attr-sql {
+      database = sqlite:///etc/ipsec.d/ipsec.db
     }
   }
-  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke sqlite sql kernel-netlink updown
 }
 
 pool {
index ca78d0f..e377047 100644 (file)
@@ -6,7 +6,15 @@ charon {
       database = sqlite:///etc/ipsec.d/ipsec.db 
     }
   }
-  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke kernel-netlink updown sqlite sql
+  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke kernel-netlink updown sqlite sql attr-sql
+}
+
+libstrongswan {
+  plugins {
+    attr-sql {
+      database = sqlite:///etc/ipsec.d/ipsec.db
+    }
+  }
 }
 
 pool {
index ca78d0f..e377047 100644 (file)
@@ -6,7 +6,15 @@ charon {
       database = sqlite:///etc/ipsec.d/ipsec.db 
     }
   }
-  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke kernel-netlink updown sqlite sql
+  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke kernel-netlink updown sqlite sql attr-sql
+}
+
+libstrongswan {
+  plugins {
+    attr-sql {
+      database = sqlite:///etc/ipsec.d/ipsec.db
+    }
+  }
 }
 
 pool {
index ca78d0f..e377047 100644 (file)
@@ -6,7 +6,15 @@ charon {
       database = sqlite:///etc/ipsec.d/ipsec.db 
     }
   }
-  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke kernel-netlink updown sqlite sql
+  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke kernel-netlink updown sqlite sql attr-sql
+}
+
+libstrongswan {
+  plugins {
+    attr-sql {
+      database = sqlite:///etc/ipsec.d/ipsec.db
+    }
+  }
 }
 
 pool {
index ca78d0f..e377047 100644 (file)
@@ -6,7 +6,15 @@ charon {
       database = sqlite:///etc/ipsec.d/ipsec.db 
     }
   }
-  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke kernel-netlink updown sqlite sql
+  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke kernel-netlink updown sqlite sql attr-sql
+}
+
+libstrongswan {
+  plugins {
+    attr-sql {
+      database = sqlite:///etc/ipsec.d/ipsec.db
+    }
+  }
 }
 
 pool {
index ca78d0f..e377047 100644 (file)
@@ -6,7 +6,15 @@ charon {
       database = sqlite:///etc/ipsec.d/ipsec.db 
     }
   }
-  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke kernel-netlink updown sqlite sql
+  load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random x509 hmac xcbc stroke kernel-netlink updown sqlite sql attr-sql
+}
+
+libstrongswan {
+  plugins {
+    attr-sql {
+      database = sqlite:///etc/ipsec.d/ipsec.db
+    }
+  }
 }
 
 pool {