diff options
Diffstat (limited to 'src/libcharon/plugins/medcli')
-rw-r--r-- | src/libcharon/plugins/medcli/Makefile.am | 18 | ||||
-rw-r--r-- | src/libcharon/plugins/medcli/medcli_config.c | 407 | ||||
-rw-r--r-- | src/libcharon/plugins/medcli/medcli_config.h | 53 | ||||
-rw-r--r-- | src/libcharon/plugins/medcli/medcli_creds.c | 243 | ||||
-rw-r--r-- | src/libcharon/plugins/medcli/medcli_creds.h | 53 | ||||
-rw-r--r-- | src/libcharon/plugins/medcli/medcli_listener.c | 133 | ||||
-rw-r--r-- | src/libcharon/plugins/medcli/medcli_listener.h | 53 | ||||
-rw-r--r-- | src/libcharon/plugins/medcli/medcli_plugin.c | 109 | ||||
-rw-r--r-- | src/libcharon/plugins/medcli/medcli_plugin.h | 42 | ||||
-rw-r--r-- | src/libcharon/plugins/medcli/mysql.sql | 32 |
10 files changed, 1143 insertions, 0 deletions
diff --git a/src/libcharon/plugins/medcli/Makefile.am b/src/libcharon/plugins/medcli/Makefile.am new file mode 100644 index 000000000..e1e3dc53a --- /dev/null +++ b/src/libcharon/plugins/medcli/Makefile.am @@ -0,0 +1,18 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-medcli.la +else +plugin_LTLIBRARIES = libstrongswan-medcli.la +endif + +libstrongswan_medcli_la_SOURCES = \ + medcli_plugin.h medcli_plugin.c \ + medcli_creds.h medcli_creds.c \ + medcli_config.h medcli_config.c \ + medcli_listener.h medcli_listener.c + +libstrongswan_medcli_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c new file mode 100644 index 000000000..e355d55f7 --- /dev/null +++ b/src/libcharon/plugins/medcli/medcli_config.c @@ -0,0 +1,407 @@ +/* + * 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 <string.h> + +#include "medcli_config.h" + +#include <daemon.h> +#include <processing/jobs/callback_job.h> + +typedef struct private_medcli_config_t private_medcli_config_t; + +/** + * Private data of an medcli_config_t object + */ +struct private_medcli_config_t { + + /** + * Public part + */ + medcli_config_t public; + + /** + * database connection + */ + database_t *db; + + /** + * rekey time + */ + int rekey; + + /** + * dpd delay + */ + int dpd; + + /** + * default ike config + */ + ike_cfg_t *ike; +}; + +/** + * create a traffic selector from a CIDR notation string + */ +static traffic_selector_t *ts_from_string(char *str) +{ + if (str) + { + int netbits = 32; + host_t *net; + char *pos; + + str = strdupa(str); + pos = strchr(str, '/'); + if (pos) + { + *pos++ = '\0'; + netbits = atoi(pos); + } + else + { + if (strchr(str, ':')) + { + netbits = 128; + } + } + net = host_create_from_string(str, 0); + if (net) + { + return traffic_selector_create_from_subnet(net, netbits, 0, 0); + } + } + return traffic_selector_create_dynamic(0, 0, 65535); +} + +/** + * implements backend_t.get_peer_cfg_by_name. + */ +static peer_cfg_t *get_peer_cfg_by_name(private_medcli_config_t *this, char *name) +{ + enumerator_t *e; + peer_cfg_t *peer_cfg, *med_cfg; + auth_cfg_t *auth; + ike_cfg_t *ike_cfg; + child_cfg_t *child_cfg; + chunk_t me, other; + char *address, *local_net, *remote_net; + lifetime_cfg_t lifetime = { + .time = { + .life = this->rekey * 60 + this->rekey, + .rekey = this->rekey, + .jitter = this->rekey + } + }; + + /* query mediation server config: + * - build ike_cfg/peer_cfg for mediation connection on-the-fly + */ + e = this->db->query(this->db, + "SELECT Address, ClientConfig.KeyId, MediationServerConfig.KeyId " + "FROM MediationServerConfig JOIN ClientConfig", + DB_TEXT, DB_BLOB, DB_BLOB); + if (!e || !e->enumerate(e, &address, &me, &other)) + { + DESTROY_IF(e); + return NULL; + } + ike_cfg = ike_cfg_create(FALSE, FALSE, + "0.0.0.0", IKEV2_UDP_PORT, address, IKEV2_UDP_PORT); + ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); + med_cfg = peer_cfg_create( + "mediation", 2, ike_cfg, + CERT_NEVER_SEND, UNIQUE_REPLACE, + 1, this->rekey*60, 0, /* keytries, rekey, reauth */ + this->rekey*5, this->rekey*3, /* jitter, overtime */ + TRUE, this->dpd, /* mobike, dpddelay */ + NULL, NULL, /* vip, pool */ + TRUE, NULL, NULL); /* mediation, med by, peer id */ + e->destroy(e); + + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + auth->add(auth, AUTH_RULE_IDENTITY, + identification_create_from_encoding(ID_KEY_ID, me)); + med_cfg->add_auth_cfg(med_cfg, auth, TRUE); + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + auth->add(auth, AUTH_RULE_IDENTITY, + identification_create_from_encoding(ID_KEY_ID, other)); + med_cfg->add_auth_cfg(med_cfg, auth, FALSE); + + /* query mediated config: + * - use any-any ike_cfg + * - build peer_cfg on-the-fly using med_cfg + * - add a child_cfg + */ + e = this->db->query(this->db, + "SELECT ClientConfig.KeyId, Connection.KeyId, " + "Connection.LocalSubnet, Connection.RemoteSubnet " + "FROM ClientConfig JOIN Connection " + "WHERE Active AND Alias = ?", DB_TEXT, name, + DB_BLOB, DB_BLOB, DB_TEXT, DB_TEXT); + if (!e || !e->enumerate(e, &me, &other, &local_net, &remote_net)) + { + DESTROY_IF(e); + return NULL; + } + peer_cfg = peer_cfg_create( + name, 2, this->ike->get_ref(this->ike), + CERT_NEVER_SEND, UNIQUE_REPLACE, + 1, this->rekey*60, 0, /* keytries, rekey, reauth */ + this->rekey*5, this->rekey*3, /* jitter, overtime */ + TRUE, this->dpd, /* mobike, dpddelay */ + NULL, NULL, /* vip, pool */ + FALSE, med_cfg, /* mediation, med by */ + identification_create_from_encoding(ID_KEY_ID, other)); + + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + auth->add(auth, AUTH_RULE_IDENTITY, + identification_create_from_encoding(ID_KEY_ID, me)); + peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE); + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + auth->add(auth, AUTH_RULE_IDENTITY, + identification_create_from_encoding(ID_KEY_ID, other)); + peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE); + + child_cfg = child_cfg_create(name, &lifetime, NULL, TRUE, + MODE_TUNNEL, ACTION_NONE, ACTION_NONE, FALSE, 0); + child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + child_cfg->add_traffic_selector(child_cfg, TRUE, ts_from_string(local_net)); + child_cfg->add_traffic_selector(child_cfg, FALSE, ts_from_string(remote_net)); + peer_cfg->add_child_cfg(peer_cfg, child_cfg); + e->destroy(e); + return peer_cfg; +} + +/** + * Implementation of backend_t.create_ike_cfg_enumerator. + */ +static enumerator_t* create_ike_cfg_enumerator(private_medcli_config_t *this, + host_t *me, host_t *other) +{ + return enumerator_create_single(this->ike, NULL); +} + +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** inner SQL enumerator */ + enumerator_t *inner; + /** currently enumerated peer config */ + peer_cfg_t *current; + /** ike cfg to use in peer cfg */ + ike_cfg_t *ike; + /** rekey time */ + int rekey; + /** dpd time */ + int dpd; +} peer_enumerator_t; + +/** + * Implementation of peer_enumerator_t.public.enumerate + */ +static bool peer_enumerator_enumerate(peer_enumerator_t *this, peer_cfg_t **cfg) +{ + char *name, *local_net, *remote_net; + chunk_t me, other; + child_cfg_t *child_cfg; + auth_cfg_t *auth; + lifetime_cfg_t lifetime = { + .time = { + .life = this->rekey * 60 + this->rekey, + .rekey = this->rekey, + .jitter = this->rekey + } + }; + + DESTROY_IF(this->current); + if (!this->inner->enumerate(this->inner, &name, &me, &other, + &local_net, &remote_net)) + { + this->current = NULL; + return FALSE; + } + this->current = peer_cfg_create( + name, 2, this->ike->get_ref(this->ike), + CERT_NEVER_SEND, UNIQUE_REPLACE, + 1, this->rekey*60, 0, /* keytries, rekey, reauth */ + this->rekey*5, this->rekey*3, /* jitter, overtime */ + TRUE, this->dpd, /* mobike, dpddelay */ + NULL, NULL, /* vip, pool */ + FALSE, NULL, NULL); /* mediation, med by, peer id */ + + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + auth->add(auth, AUTH_RULE_IDENTITY, + identification_create_from_encoding(ID_KEY_ID, me)); + this->current->add_auth_cfg(this->current, auth, TRUE); + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + auth->add(auth, AUTH_RULE_IDENTITY, + identification_create_from_encoding(ID_KEY_ID, other)); + this->current->add_auth_cfg(this->current, auth, FALSE); + + child_cfg = child_cfg_create(name, &lifetime, NULL, TRUE, MODE_TUNNEL, + ACTION_NONE, ACTION_NONE, FALSE, 0); + child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + child_cfg->add_traffic_selector(child_cfg, TRUE, ts_from_string(local_net)); + child_cfg->add_traffic_selector(child_cfg, FALSE, ts_from_string(remote_net)); + this->current->add_child_cfg(this->current, child_cfg); + *cfg = this->current; + return TRUE; +} + +/** + * Implementation of peer_enumerator_t.public.destroy + */ +static void peer_enumerator_destroy(peer_enumerator_t *this) +{ + DESTROY_IF(this->current); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of backend_t.create_peer_cfg_enumerator. + */ +static enumerator_t* create_peer_cfg_enumerator(private_medcli_config_t *this, + identification_t *me, + identification_t *other) +{ + peer_enumerator_t *e = malloc_thing(peer_enumerator_t); + + e->current = NULL; + e->ike = this->ike; + e->rekey = this->rekey; + e->dpd = this->dpd; + e->public.enumerate = (void*)peer_enumerator_enumerate; + e->public.destroy = (void*)peer_enumerator_destroy; + + /* filter on IDs: NULL or ANY or matching KEY_ID */ + e->inner = this->db->query(this->db, + "SELECT Alias, ClientConfig.KeyId, Connection.KeyId, " + "Connection.LocalSubnet, Connection.RemoteSubnet " + "FROM ClientConfig JOIN Connection " + "WHERE Active AND " + "(? OR ClientConfig.KeyId = ?) AND (? OR Connection.KeyId = ?)", + DB_INT, me == NULL || me->get_type(me) == ID_ANY, + DB_BLOB, me && me->get_type(me) == ID_KEY_ID ? + me->get_encoding(me) : chunk_empty, + DB_INT, other == NULL || other->get_type(other) == ID_ANY, + DB_BLOB, other && other->get_type(other) == ID_KEY_ID ? + other->get_encoding(other) : chunk_empty, + DB_TEXT, DB_BLOB, DB_BLOB, DB_TEXT, DB_TEXT); + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + +/** + * initiate a peer config + */ +static job_requeue_t initiate_config(peer_cfg_t *peer_cfg) +{ + enumerator_t *enumerator; + child_cfg_t *child_cfg = NULL;; + + enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg); + enumerator->enumerate(enumerator, &child_cfg); + if (child_cfg) + { + child_cfg->get_ref(child_cfg); + peer_cfg->get_ref(peer_cfg); + enumerator->destroy(enumerator); + charon->controller->initiate(charon->controller, + peer_cfg, child_cfg, NULL, NULL); + } + else + { + enumerator->destroy(enumerator); + } + return JOB_REQUEUE_NONE; +} + +/** + * schedule initation of all "active" connections + */ +static void schedule_autoinit(private_medcli_config_t *this) +{ + enumerator_t *e; + char *name; + + e = this->db->query(this->db, "SELECT Alias FROM Connection WHERE Active", + DB_TEXT); + if (e) + { + while (e->enumerate(e, &name)) + { + peer_cfg_t *peer_cfg; + + peer_cfg = get_peer_cfg_by_name(this, name); + if (peer_cfg) + { + /* schedule asynchronous initiation job */ + charon->processor->queue_job(charon->processor, + (job_t*)callback_job_create( + (callback_job_cb_t)initiate_config, + peer_cfg, (void*)peer_cfg->destroy, NULL)); + } + } + e->destroy(e); + } +} + +/** + * Implementation of medcli_config_t.destroy. + */ +static void destroy(private_medcli_config_t *this) +{ + this->ike->destroy(this->ike); + free(this); +} + +/** + * Described in header. + */ +medcli_config_t *medcli_config_create(database_t *db) +{ + private_medcli_config_t *this = malloc_thing(private_medcli_config_t); + + this->public.backend.create_peer_cfg_enumerator = (enumerator_t*(*)(backend_t*, identification_t *me, identification_t *other))create_peer_cfg_enumerator; + this->public.backend.create_ike_cfg_enumerator = (enumerator_t*(*)(backend_t*, host_t *me, host_t *other))create_ike_cfg_enumerator; + this->public.backend.get_peer_cfg_by_name = (peer_cfg_t* (*)(backend_t*,char*))get_peer_cfg_by_name; + this->public.destroy = (void(*)(medcli_config_t*))destroy; + + this->db = db; + this->rekey = lib->settings->get_time(lib->settings, "medcli.rekey", 1200); + this->dpd = lib->settings->get_time(lib->settings, "medcli.dpd", 300); + this->ike = ike_cfg_create(FALSE, FALSE, + "0.0.0.0", IKEV2_UDP_PORT, "0.0.0.0", IKEV2_UDP_PORT); + this->ike->add_proposal(this->ike, proposal_create_default(PROTO_IKE)); + + schedule_autoinit(this); + + return &this->public; +} + diff --git a/src/libcharon/plugins/medcli/medcli_config.h b/src/libcharon/plugins/medcli/medcli_config.h new file mode 100644 index 000000000..36c20adf7 --- /dev/null +++ b/src/libcharon/plugins/medcli/medcli_config.h @@ -0,0 +1,53 @@ +/* + * 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 medcli_config_i medcli_config + * @{ @ingroup medcli + */ + +#ifndef MEDCLI_CONFIG_H_ +#define MEDCLI_CONFIG_H_ + +#include <config/backend.h> +#include <database/database.h> + +typedef struct medcli_config_t medcli_config_t; + +/** + * Mediation client configuration backend. + */ +struct medcli_config_t { + + /** + * Implements backend_t interface + */ + backend_t backend; + + /** + * Destroy the backend. + */ + void (*destroy)(medcli_config_t *this); +}; + +/** + * Create a medcli_config backend instance. + * + * @param db underlying database + * @return backend instance + */ +medcli_config_t *medcli_config_create(database_t *db); + +#endif /** MEDCLI_CONFIG_H_ @}*/ diff --git a/src/libcharon/plugins/medcli/medcli_creds.c b/src/libcharon/plugins/medcli/medcli_creds.c new file mode 100644 index 000000000..9729df3f5 --- /dev/null +++ b/src/libcharon/plugins/medcli/medcli_creds.c @@ -0,0 +1,243 @@ +/* + * 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 "medcli_creds.h" + +#include <daemon.h> +#include <library.h> +#include <utils/enumerator.h> + +typedef struct private_medcli_creds_t private_medcli_creds_t; + +/** + * Private data of an medcli_creds_t object + */ +struct private_medcli_creds_t { + + /** + * Public part + */ + medcli_creds_t public; + + /** + * underlying database handle + */ + database_t *db; +}; + +/** + * enumerator over private keys + */ +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** inner SQL enumerator */ + enumerator_t *inner; + /** currently enumerated private key */ + private_key_t *current; +} private_enumerator_t; + +/** + * Implementation of private_enumerator_t.public.enumerate + */ +static bool private_enumerator_enumerate(private_enumerator_t *this, + private_key_t **key) +{ + chunk_t chunk; + + DESTROY_IF(this->current); + while (this->inner->enumerate(this->inner, &chunk)) + { + this->current = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, + BUILD_BLOB_ASN1_DER, chunk, + BUILD_END); + if (this->current) + { + *key = this->current; + return TRUE; + } + } + this->current = NULL; + return FALSE; +} + +/** + * Implementation of private_enumerator_t.public.destroy + */ +static void private_enumerator_destroy(private_enumerator_t *this) +{ + DESTROY_IF(this->current); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of credential_set_t.create_private_enumerator. + */ +static enumerator_t* create_private_enumerator(private_medcli_creds_t *this, + key_type_t type, identification_t *id) +{ + private_enumerator_t *e; + + if ((type != KEY_RSA && type != KEY_ANY) || + id == NULL || id->get_type(id) != ID_KEY_ID) + { + DBG1(DBG_CFG, "%N - %Y", key_type_names, type, id); + return NULL; + } + + e = malloc_thing(private_enumerator_t); + e->current = NULL; + e->public.enumerate = (void*)private_enumerator_enumerate; + e->public.destroy = (void*)private_enumerator_destroy; + e->inner = this->db->query(this->db, + "SELECT PrivateKey FROM ClientConfig WHERE KeyId = ?", + DB_BLOB, id->get_encoding(id), + DB_BLOB); + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + +/** + * enumerator over certificates + */ +typedef struct { + /** implements enumerator */ + enumerator_t public; + /** inner SQL enumerator */ + enumerator_t *inner; + /** currently enumerated cert */ + certificate_t *current; + /** type of requested key */ + key_type_t type; +} cert_enumerator_t; + +/** + * Implementation of cert_enumerator_t.public.enumerate + */ +static bool cert_enumerator_enumerate(cert_enumerator_t *this, + certificate_t **cert) +{ + public_key_t *public; + chunk_t chunk; + + DESTROY_IF(this->current); + while (this->inner->enumerate(this->inner, &chunk)) + { + public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, + BUILD_BLOB_ASN1_DER, chunk, + BUILD_END); + if (public) + { + if (this->type == KEY_ANY || this->type == public->get_type(public)) + { + this->current = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY, + BUILD_PUBLIC_KEY, public, BUILD_END); + public->destroy(public); + if (this->current) + { + *cert = this->current; + return TRUE; + } + } + else + { + public->destroy(public); + } + } + } + this->current = NULL; + return FALSE; +} + +/** + * Implementation of cert_enumerator_t.public.destroy + */ +static void cert_enumerator_destroy(cert_enumerator_t *this) +{ + DESTROY_IF(this->current); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of credential_set_t.create_cert_enumerator. + */ +static enumerator_t* create_cert_enumerator(private_medcli_creds_t *this, + certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted) +{ + cert_enumerator_t *e; + + if ((cert != CERT_TRUSTED_PUBKEY && cert != CERT_ANY) || + id == NULL || id->get_type(id) != ID_KEY_ID) + { + return NULL; + } + + e = malloc_thing(cert_enumerator_t); + e->current = NULL; + e->type = key; + e->public.enumerate = (void*)cert_enumerator_enumerate; + e->public.destroy = (void*)cert_enumerator_destroy; + e->inner = this->db->query(this->db, + "SELECT PublicKey FROM ClientConfig WHERE KeyId = ? UNION " + "SELECT PublicKey FROM MediationServerConfig WHERE KeyId = ? UNION " + "SELECT PublicKey FROM Connection WHERE KeyId = ?", + DB_BLOB, id->get_encoding(id), + DB_BLOB, id->get_encoding(id), + DB_BLOB, id->get_encoding(id), + DB_BLOB); + if (!e->inner) + { + free(e); + return NULL; + } + return &e->public; +} + +/** + * Implementation of backend_t.destroy. + */ +static void destroy(private_medcli_creds_t *this) +{ + free(this); +} + +/** + * Described in header. + */ +medcli_creds_t *medcli_creds_create(database_t *db) +{ + private_medcli_creds_t *this = malloc_thing(private_medcli_creds_t); + + this->public.set.create_private_enumerator = (void*)create_private_enumerator; + this->public.set.create_cert_enumerator = (void*)create_cert_enumerator; + this->public.set.create_shared_enumerator = (void*)return_null; + this->public.set.create_cdp_enumerator = (void*)return_null; + this->public.set.cache_cert = (void*)nop; + + this->public.destroy = (void (*)(medcli_creds_t*))destroy; + + this->db = db; + + return &this->public; +} + diff --git a/src/libcharon/plugins/medcli/medcli_creds.h b/src/libcharon/plugins/medcli/medcli_creds.h new file mode 100644 index 000000000..4b5402653 --- /dev/null +++ b/src/libcharon/plugins/medcli/medcli_creds.h @@ -0,0 +1,53 @@ +/* + * 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 medcli_creds_i medcli_creds + * @{ @ingroup medcli + */ + +#ifndef MEDCLI_CREDS_H_ +#define MEDCLI_CREDS_H_ + +#include <credentials/credential_set.h> +#include <database/database.h> + +typedef struct medcli_creds_t medcli_creds_t; + +/** + * Mediation client credentials database. + */ +struct medcli_creds_t { + + /** + * Implements credential_set_t interface + */ + credential_set_t set; + + /** + * Destroy the credentials databse. + */ + void (*destroy)(medcli_creds_t *this); +}; + +/** + * Create the medcli credential set. + * + * @param database underlying database + * @return credential set implementation on that database + */ +medcli_creds_t *medcli_creds_create(database_t *database); + +#endif /** MEDCLI_CREDS_H_ @}*/ diff --git a/src/libcharon/plugins/medcli/medcli_listener.c b/src/libcharon/plugins/medcli/medcli_listener.c new file mode 100644 index 000000000..142f02e6c --- /dev/null +++ b/src/libcharon/plugins/medcli/medcli_listener.c @@ -0,0 +1,133 @@ +/* + * 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 "medcli_listener.h" + +#include <daemon.h> +#include <library.h> + +typedef struct private_medcli_listener_t private_medcli_listener_t; +typedef enum mediated_state_t mediated_state_t; + +/** + * state of a mediated connection + */ +enum mediated_state_t { + STATE_DOWN = 1, + STATE_CONNECTING = 2, + STATE_UP = 3, +}; + +/** + * Private data of an medcli_listener_t object + */ +struct private_medcli_listener_t { + + /** + * Public part + */ + medcli_listener_t public; + + /** + * underlying database handle + */ + database_t *db; +}; + +/** + * Implementation of bus_listener_t.signal. + */ +static void set_state(private_medcli_listener_t *this, char *alias, + mediated_state_t state) +{ + this->db->execute(this->db, NULL, + "UPDATE Connection SET Status = ? WHERE Alias = ?", + DB_UINT, state, DB_TEXT, alias); +} +/** + * Implementation of listener_t.ike_state_change + */ +static bool ike_state_change(private_medcli_listener_t *this, + ike_sa_t *ike_sa, ike_sa_state_t state) +{ + if (ike_sa) + { + switch (state) + { + case IKE_CONNECTING: + set_state(this, ike_sa->get_name(ike_sa), STATE_CONNECTING); + break; + case IKE_DESTROYING: + set_state(this, ike_sa->get_name(ike_sa), STATE_DOWN); + default: + break; + } + } + return TRUE; +} + +/** + * Implementation of listener_t.child_state_change + */ +static bool child_state_change(private_medcli_listener_t *this, + ike_sa_t *ike_sa, child_sa_t *child_sa, child_sa_state_t state) +{ + if (ike_sa && child_sa) + { + switch (state) + { + case CHILD_INSTALLED: + set_state(this, child_sa->get_name(child_sa), STATE_UP); + break; + case CHILD_DESTROYING: + set_state(this, child_sa->get_name(child_sa), STATE_DOWN); + break; + default: + break; + } + } + return TRUE; +} + +/** + * Implementation of backend_t.destroy. + */ +static void destroy(private_medcli_listener_t *this) +{ + this->db->execute(this->db, NULL, "UPDATE Connection SET Status = ?", + DB_UINT, STATE_DOWN); + free(this); +} + +/** + * Described in header. + */ +medcli_listener_t *medcli_listener_create(database_t *db) +{ + private_medcli_listener_t *this = malloc_thing(private_medcli_listener_t); + + memset(&this->public.listener, 0, sizeof(listener_t)); + + this->public.listener.ike_state_change = (void*)ike_state_change; + this->public.listener.child_state_change = (void*)child_state_change; + this->public.destroy = (void (*)(medcli_listener_t*))destroy; + + this->db = db; + db->execute(db, NULL, "UPDATE Connection SET Status = ?", + DB_UINT, STATE_DOWN); + + return &this->public; +} + diff --git a/src/libcharon/plugins/medcli/medcli_listener.h b/src/libcharon/plugins/medcli/medcli_listener.h new file mode 100644 index 000000000..4768beccd --- /dev/null +++ b/src/libcharon/plugins/medcli/medcli_listener.h @@ -0,0 +1,53 @@ +/* + * 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 medcli_listener_i medcli_listener + * @{ @ingroup medcli + */ + +#ifndef MEDCLI_LISTENER_H_ +#define MEDCLI_LISTENER_H_ + +#include <bus/bus.h> +#include <database/database.h> + +typedef struct medcli_listener_t medcli_listener_t; + +/** + * Mediation client listener, writes connection status to database + */ +struct medcli_listener_t { + + /** + * Implements bus_listener_t interface + */ + listener_t listener; + + /** + * Destroy the credentials databse. + */ + void (*destroy)(medcli_listener_t *this); +}; + +/** + * Create the medcli credential set. + * + * @param database underlying database + * @return listener + */ +medcli_listener_t *medcli_listener_create(database_t *database); + +#endif /** MEDCLI_LISTENER_H_ @}*/ diff --git a/src/libcharon/plugins/medcli/medcli_plugin.c b/src/libcharon/plugins/medcli/medcli_plugin.c new file mode 100644 index 000000000..397168d46 --- /dev/null +++ b/src/libcharon/plugins/medcli/medcli_plugin.c @@ -0,0 +1,109 @@ +/* + * 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 "medcli_plugin.h" + +#include "medcli_creds.h" +#include "medcli_config.h" +#include "medcli_listener.h" + +#include <daemon.h> + +typedef struct private_medcli_plugin_t private_medcli_plugin_t; + +/** + * private data of medcli plugin + */ +struct private_medcli_plugin_t { + + /** + * implements plugin interface + */ + medcli_plugin_t public; + + /** + * database connection instance + */ + database_t *db; + + /** + * medcli credential set instance + */ + medcli_creds_t *creds; + + /** + * medcli config database + */ + medcli_config_t *config; + + /** + * Listener to update database connection state + */ + medcli_listener_t *listener; +}; + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(private_medcli_plugin_t *this) +{ + charon->bus->remove_listener(charon->bus, &this->listener->listener); + charon->backends->remove_backend(charon->backends, &this->config->backend); + charon->credentials->remove_set(charon->credentials, &this->creds->set); + this->listener->destroy(this->listener); + this->config->destroy(this->config); + this->creds->destroy(this->creds); + this->db->destroy(this->db); + free(this); +} + +/* + * see header file + */ +plugin_t *medcli_plugin_create() +{ + char *uri; + private_medcli_plugin_t *this = malloc_thing(private_medcli_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + uri = lib->settings->get_str(lib->settings, + "medcli.database", NULL); + if (!uri) + { + DBG1(DBG_CFG, "mediation client database URI not defined, skipped"); + free(this); + return NULL; + } + + this->db = lib->db->create(lib->db, uri); + if (this->db == NULL) + { + DBG1(DBG_CFG, "opening mediation client database failed"); + free(this); + return NULL; + } + + this->creds = medcli_creds_create(this->db); + this->config = medcli_config_create(this->db); + this->listener = medcli_listener_create(this->db); + + charon->credentials->add_set(charon->credentials, &this->creds->set); + charon->backends->add_backend(charon->backends, &this->config->backend); + charon->bus->add_listener(charon->bus, &this->listener->listener); + + return &this->public.plugin; +} + diff --git a/src/libcharon/plugins/medcli/medcli_plugin.h b/src/libcharon/plugins/medcli/medcli_plugin.h new file mode 100644 index 000000000..44e7bb525 --- /dev/null +++ b/src/libcharon/plugins/medcli/medcli_plugin.h @@ -0,0 +1,42 @@ +/* + * 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 medcli medcli + * @ingroup cplugins + * + * @defgroup medcli_plugin medcli_plugin + * @{ @ingroup medcli + */ + +#ifndef MEDCLI_PLUGIN_H_ +#define MEDCLI_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct medcli_plugin_t medcli_plugin_t; + +/** + * Mediation client database plugin. + */ +struct medcli_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** MEDCLI_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/medcli/mysql.sql b/src/libcharon/plugins/medcli/mysql.sql new file mode 100644 index 000000000..0107ad35a --- /dev/null +++ b/src/libcharon/plugins/medcli/mysql.sql @@ -0,0 +1,32 @@ + +CREATE TABLE `ClientConfig` ( + `IdClientConfig` int(11) NOT NULL, + `KeyId` varbinary(20) NOT NULL, + `PublicKey` blob NOT NULL, + `PrivateKey` blob NOT NULL, + PRIMARY KEY (`IdClientConfig`) +); + + +CREATE TABLE `MediationServerConfig` ( + `IdMediationServerConfig` int(11) NOT NULL, + `Address` varchar(200) NOT NULL, + `KeyId` varbinary(20) NOT NULL, + `PublicKey` blob NOT NULL, + PRIMARY KEY (`IdMediationServerConfig`) +); + + +CREATE TABLE `Connection` ( + `IdConnection` int(11) NOT NULL auto_increment, + `Active` tinyint(1) NOT NULL, + `Alias` varchar(50) NOT NULL, + `KeyId` varbinary(20) NOT NULL, + `PublicKey` blob NOT NULL, + `LocalSubnet` varchar(20), + `RemoteSubnet` varchar(20), + `Status` int(11) NOT NULL, + PRIMARY KEY (`IdConnection`), + UNIQUE (`Alias`), + UNIQUE (`KeyId`) +); |