diff options
Diffstat (limited to 'src/libcharon/plugins/stroke')
-rw-r--r-- | src/libcharon/plugins/stroke/Makefile.in | 7 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_ca.c | 2 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_config.c | 225 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_config.h | 10 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_control.c | 100 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_cred.c | 223 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_cred.h | 24 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_list.c | 232 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_list.h | 4 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_socket.c | 199 |
10 files changed, 838 insertions, 188 deletions
diff --git a/src/libcharon/plugins/stroke/Makefile.in b/src/libcharon/plugins/stroke/Makefile.in index fd859daeb..60f5f535a 100644 --- a/src/libcharon/plugins/stroke/Makefile.in +++ b/src/libcharon/plugins/stroke/Makefile.in @@ -195,6 +195,9 @@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ +attest_plugins = @attest_plugins@ +axis2c_CFLAGS = @axis2c_CFLAGS@ +axis2c_LIBS = @axis2c_LIBS@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ @@ -203,6 +206,7 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ @@ -219,11 +223,13 @@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ +imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ +ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ @@ -267,6 +273,7 @@ sharedstatedir = @sharedstatedir@ soup_CFLAGS = @soup_CFLAGS@ soup_LIBS = @soup_LIBS@ srcdir = @srcdir@ +starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ diff --git a/src/libcharon/plugins/stroke/stroke_ca.c b/src/libcharon/plugins/stroke/stroke_ca.c index 69e13deb9..bec35a661 100644 --- a/src/libcharon/plugins/stroke/stroke_ca.c +++ b/src/libcharon/plugins/stroke/stroke_ca.c @@ -319,7 +319,7 @@ static void list_uris(linked_list_t *list, char *label, FILE *out) { if (first) { - fprintf(out, label); + fprintf(out, "%s", label); first = FALSE; } else diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index 2b3164384..483e3d253 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -263,7 +264,7 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, { identification_t *identity; certificate_t *certificate; - char *auth, *id, *cert, *ca; + char *auth, *id, *pubkey, *cert, *ca; stroke_end_t *end, *other_end; auth_cfg_t *cfg; char eap_buf[32]; @@ -328,6 +329,9 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, case AUTH_CLASS_EAP: auth = "eap"; break; + case AUTH_CLASS_ANY: + auth = "any"; + break; } } else @@ -396,6 +400,18 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, } cfg->add(cfg, AUTH_RULE_IDENTITY, identity); + /* add raw RSA public key */ + pubkey = end->rsakey; + if (pubkey && !streq(pubkey, "") && !streq(pubkey, "%cert")) + { + certificate = this->cred->load_pubkey(this->cred, KEY_RSA, pubkey, + identity); + if (certificate) + { + cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate); + } + } + /* CA constraint */ if (ca) { @@ -775,13 +791,28 @@ static void add_ts(private_stroke_config_t *this, } /** + * map starter magic values to our action type + */ +static action_t map_action(int starter_action) +{ + switch (starter_action) + { + case 2: /* =hold */ + return ACTION_ROUTE; + case 3: /* =restart */ + return ACTION_RESTART; + default: + return ACTION_NONE; + } +} + +/** * build a child config from the stroke message */ static child_cfg_t *build_child_cfg(private_stroke_config_t *this, stroke_msg_t *msg) { child_cfg_t *child_cfg; - action_t dpd; lifetime_cfg_t lifetime = { .time = { .life = msg->add_conn.rekey.ipsec_lifetime, @@ -808,23 +839,11 @@ static child_cfg_t *build_child_cfg(private_stroke_config_t *this, .mask = msg->add_conn.mark_out.mask }; - switch (msg->add_conn.dpd.action) - { /* map startes magic values to our action type */ - case 2: /* =hold */ - dpd = ACTION_ROUTE; - break; - case 3: /* =restart */ - dpd = ACTION_RESTART; - break; - default: - dpd = ACTION_NONE; - break; - } - child_cfg = child_cfg_create( - msg->add_conn.name, &lifetime, - msg->add_conn.me.updown, msg->add_conn.me.hostaccess, - msg->add_conn.mode, ACTION_NONE, dpd, dpd, msg->add_conn.ipcomp, + msg->add_conn.name, &lifetime, msg->add_conn.me.updown, + msg->add_conn.me.hostaccess, msg->add_conn.mode, ACTION_NONE, + map_action(msg->add_conn.dpd.action), + map_action(msg->add_conn.close_action), msg->add_conn.ipcomp, msg->add_conn.inactivity, msg->add_conn.reqid, &mark_in, &mark_out, msg->add_conn.tfc); child_cfg->set_mipv6_options(child_cfg, msg->add_conn.proxy_mode, @@ -950,6 +969,175 @@ METHOD(stroke_config_t, del, void, } } +METHOD(stroke_config_t, set_user_credentials, void, + private_stroke_config_t *this, stroke_msg_t *msg, FILE *prompt) +{ + enumerator_t *enumerator, *children, *remote_auth; + peer_cfg_t *peer, *found = NULL; + auth_cfg_t *auth_cfg, *remote_cfg; + auth_class_t auth_class; + child_cfg_t *child; + identification_t *id, *identity, *gw = NULL; + shared_key_type_t type = SHARED_ANY; + chunk_t password = chunk_empty; + + this->mutex->lock(this->mutex); + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, (void**)&peer)) + { /* find the peer (or child) config with the given name */ + if (streq(peer->get_name(peer), msg->user_creds.name)) + { + found = peer; + } + else + { + children = peer->create_child_cfg_enumerator(peer); + while (children->enumerate(children, &child)) + { + if (streq(child->get_name(child), msg->user_creds.name)) + { + found = peer; + break; + } + } + children->destroy(children); + } + + if (found) + { + break; + } + } + enumerator->destroy(enumerator); + + if (!found) + { + DBG1(DBG_CFG, " no config named '%s'", msg->user_creds.name); + fprintf(prompt, "no config named '%s'\n", msg->user_creds.name); + this->mutex->unlock(this->mutex); + return; + } + + id = identification_create_from_string(msg->user_creds.username); + if (strlen(msg->user_creds.username) == 0 || + !id || id->get_type(id) == ID_ANY) + { + DBG1(DBG_CFG, " invalid username '%s'", msg->user_creds.username); + fprintf(prompt, "invalid username '%s'\n", msg->user_creds.username); + this->mutex->unlock(this->mutex); + DESTROY_IF(id); + return; + } + + /* replace/set the username in the first EAP auth_cfg, also look for a + * suitable remote ID. + * note that adding the identity here is not fully thread-safe as the + * peer_cfg and in turn the auth_cfg could be in use. for the default use + * case (setting user credentials before upping the connection) this will + * not be a problem, though. */ + enumerator = found->create_auth_cfg_enumerator(found, TRUE); + remote_auth = found->create_auth_cfg_enumerator(found, FALSE); + while (enumerator->enumerate(enumerator, (void**)&auth_cfg)) + { + if (remote_auth->enumerate(remote_auth, (void**)&remote_cfg)) + { /* fall back on rightid, in case aaa_identity is not specified */ + identity = remote_cfg->get(remote_cfg, AUTH_RULE_IDENTITY); + if (identity && identity->get_type(identity) != ID_ANY) + { + gw = identity; + } + } + + auth_class = (uintptr_t)auth_cfg->get(auth_cfg, AUTH_RULE_AUTH_CLASS); + if (auth_class == AUTH_CLASS_EAP) + { + auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id)); + /* if aaa_identity is specified use that as remote ID */ + identity = auth_cfg->get(auth_cfg, AUTH_RULE_AAA_IDENTITY); + if (identity && identity->get_type(identity) != ID_ANY) + { + gw = identity; + } + DBG1(DBG_CFG, " configured EAP-Identity %Y", id); + type = SHARED_EAP; + break; + } + } + enumerator->destroy(enumerator); + remote_auth->destroy(remote_auth); + /* clone the gw ID before unlocking the mutex */ + if (gw) + { + gw = gw->clone(gw); + } + this->mutex->unlock(this->mutex); + + if (type == SHARED_ANY) + { + DBG1(DBG_CFG, " config '%s' unsuitable for user credentials", + msg->user_creds.name); + fprintf(prompt, "config '%s' unsuitable for user credentials\n", + msg->user_creds.name); + id->destroy(id); + DESTROY_IF(gw); + return; + } + + if (msg->user_creds.password) + { + char *pass; + + pass = msg->user_creds.password; + password = chunk_clone(chunk_create(pass, strlen(pass))); + memwipe(pass, strlen(pass)); + } + else + { /* prompt the user for the password */ + char buf[256]; + + fprintf(prompt, "Password:\n"); + if (fgets(buf, sizeof(buf), prompt)) + { + password = chunk_clone(chunk_create(buf, strlen(buf))); + if (password.len > 0) + { /* trim trailing \n */ + password.len--; + } + memwipe(buf, sizeof(buf)); + } + } + + if (password.len) + { + shared_key_t *shared; + linked_list_t *owners; + + shared = shared_key_create(type, password); + + owners = linked_list_create(); + owners->insert_last(owners, id->clone(id)); + if (gw && gw->get_type(gw) != ID_ANY) + { + owners->insert_last(owners, gw->clone(gw)); + DBG1(DBG_CFG, " added %N secret for %Y %Y", shared_key_type_names, + type, id, gw); + } + else + { + DBG1(DBG_CFG, " added %N secret for %Y", shared_key_type_names, + type, id); + } + this->cred->add_shared(this->cred, shared, owners); + DBG4(DBG_CFG, " secret: %#B", &password); + } + else + { /* in case a user answers the password prompt by just pressing enter */ + chunk_clear(&password); + } + id->destroy(id); + DESTROY_IF(gw); +} + METHOD(stroke_config_t, destroy, void, private_stroke_config_t *this) { @@ -974,6 +1162,7 @@ stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred) }, .add = _add, .del = _del, + .set_user_credentials = _set_user_credentials, .destroy = _destroy, }, .list = linked_list_create(), diff --git a/src/libcharon/plugins/stroke/stroke_config.h b/src/libcharon/plugins/stroke/stroke_config.h index 05e4665ca..450d517f3 100644 --- a/src/libcharon/plugins/stroke/stroke_config.h +++ b/src/libcharon/plugins/stroke/stroke_config.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -53,6 +54,15 @@ struct stroke_config_t { void (*del)(stroke_config_t *this, stroke_msg_t *msg); /** + * Set the username and password for a connection in this backend. + * + * @param msg received stroke message + * @param prompt I/O channel to prompt for the password + */ + void (*set_user_credentials)(stroke_config_t *this, stroke_msg_t *msg, + FILE *prompt); + + /** * Destroy a stroke_config instance. */ void (*destroy)(stroke_config_t *this); diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c index 4943ee670..729e9d757 100644 --- a/src/libcharon/plugins/stroke/stroke_control.c +++ b/src/libcharon/plugins/stroke/stroke_control.c @@ -15,7 +15,9 @@ #include "stroke_control.h" +#include <hydra.h> #include <daemon.h> + #include <processing/jobs/delete_ike_sa_job.h> #include <processing/jobs/rekey_ike_sa_job.h> #include <processing/jobs/rekey_child_sa_job.h> @@ -101,14 +103,14 @@ static void charon_initiate(peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, if (msg->output_verbosity < 0) { charon->controller->initiate(charon->controller, peer_cfg, child_cfg, - NULL, NULL); + NULL, NULL, 0); } else { stroke_log_info_t info = { msg->output_verbosity, out }; charon->controller->initiate(charon->controller, peer_cfg, child_cfg, - (controller_cb_t)stroke_log, &info); + (controller_cb_t)stroke_log, &info, 0); } } @@ -275,28 +277,29 @@ METHOD(stroke_control_t, terminate, void, if (child) { charon->controller->terminate_child(charon->controller, id, - (controller_cb_t)stroke_log, &info); + (controller_cb_t)stroke_log, &info, 0); } else { charon->controller->terminate_ike(charon->controller, id, - (controller_cb_t)stroke_log, &info); + (controller_cb_t)stroke_log, &info, 0); } return; } ike_list = linked_list_create(); child_list = linked_list_create(); - enumerator = charon->controller->create_ike_sa_enumerator(charon->controller); + enumerator = charon->controller->create_ike_sa_enumerator( + charon->controller, TRUE); while (enumerator->enumerate(enumerator, &ike_sa)) { child_sa_t *child_sa; - iterator_t *children; + enumerator_t *children; if (child) { - children = ike_sa->create_child_sa_iterator(ike_sa); - while (children->iterate(children, (void**)&child_sa)) + children = ike_sa->create_child_sa_enumerator(ike_sa); + while (children->enumerate(children, (void**)&child_sa)) { if (streq(name, child_sa->get_name(child_sa))) { @@ -330,7 +333,7 @@ METHOD(stroke_control_t, terminate, void, while (enumerator->enumerate(enumerator, &del)) { charon->controller->terminate_child(charon->controller, del, - (controller_cb_t)stroke_log, &info); + (controller_cb_t)stroke_log, &info, 0); } enumerator->destroy(enumerator); @@ -338,7 +341,7 @@ METHOD(stroke_control_t, terminate, void, while (enumerator->enumerate(enumerator, &del)) { charon->controller->terminate_ike(charon->controller, del, - (controller_cb_t)stroke_log, &info); + (controller_cb_t)stroke_log, &info, 0); } enumerator->destroy(enumerator); @@ -366,16 +369,17 @@ METHOD(stroke_control_t, rekey, void, DBG1(DBG_CFG, "error parsing specifier string"); return; } - enumerator = charon->controller->create_ike_sa_enumerator(charon->controller); + enumerator = charon->controller->create_ike_sa_enumerator( + charon->controller, TRUE); while (enumerator->enumerate(enumerator, &ike_sa)) { child_sa_t *child_sa; - iterator_t *children; + enumerator_t *children; if (child) { - children = ike_sa->create_child_sa_iterator(ike_sa); - while (children->iterate(children, (void**)&child_sa)) + children = ike_sa->create_child_sa_enumerator(ike_sa); + while (children->enumerate(children, (void**)&child_sa)) { if ((name && streq(name, child_sa->get_name(child_sa))) || (id && id == child_sa->get_reqid(child_sa))) @@ -442,7 +446,8 @@ METHOD(stroke_control_t, terminate_srcip, void, chunk_end = end->get_address(end); } - enumerator = charon->controller->create_ike_sa_enumerator(charon->controller); + enumerator = charon->controller->create_ike_sa_enumerator( + charon->controller, TRUE); while (enumerator->enumerate(enumerator, &ike_sa)) { vip = ike_sa->get_virtual_ip(ike_sa, FALSE); @@ -481,8 +486,7 @@ METHOD(stroke_control_t, terminate_srcip, void, METHOD(stroke_control_t, purge_ike, void, private_stroke_control_t *this, stroke_msg_t *msg, FILE *out) { - enumerator_t *enumerator; - iterator_t *iterator; + enumerator_t *enumerator, *children; ike_sa_t *ike_sa; child_sa_t *child_sa; linked_list_t *list; @@ -493,16 +497,17 @@ METHOD(stroke_control_t, purge_ike, void, info.level = msg->output_verbosity; list = linked_list_create(); - enumerator = charon->controller->create_ike_sa_enumerator(charon->controller); + enumerator = charon->controller->create_ike_sa_enumerator( + charon->controller, TRUE); while (enumerator->enumerate(enumerator, &ike_sa)) { - iterator = ike_sa->create_child_sa_iterator(ike_sa); - if (!iterator->iterate(iterator, (void**)&child_sa)) + children = ike_sa->create_child_sa_enumerator(ike_sa); + if (!children->enumerate(children, (void**)&child_sa)) { list->insert_last(list, (void*)(uintptr_t)ike_sa->get_unique_id(ike_sa)); } - iterator->destroy(iterator); + children->destroy(children); } enumerator->destroy(enumerator); @@ -510,25 +515,44 @@ METHOD(stroke_control_t, purge_ike, void, while (enumerator->enumerate(enumerator, &del)) { charon->controller->terminate_ike(charon->controller, del, - (controller_cb_t)stroke_log, &info); + (controller_cb_t)stroke_log, &info, 0); } enumerator->destroy(enumerator); list->destroy(list); } /** - * call charon to install a trap + * call charon to install a shunt or trap */ static void charon_route(peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, char *name, FILE *out) { - if (charon->traps->install(charon->traps, peer_cfg, child_cfg)) + ipsec_mode_t mode; + + mode = child_cfg->get_mode(child_cfg); + if (mode == MODE_PASS || mode == MODE_DROP) { - fprintf(out, "'%s' routed\n", name); + if (charon->shunts->install(charon->shunts, child_cfg)) + { + fprintf(out, "'%s' shunt %N policy installed\n", + name, ipsec_mode_names, mode); + } + else + { + fprintf(out, "'%s' shunt %N policy installation failed\n", + name, ipsec_mode_names, mode); + } } else { - fprintf(out, "routing '%s' failed\n", name); + if (charon->traps->install(charon->traps, peer_cfg, child_cfg)) + { + fprintf(out, "'%s' routed\n", name); + } + else + { + fprintf(out, "routing '%s' failed\n", name); + } } } @@ -609,7 +633,13 @@ METHOD(stroke_control_t, unroute, void, { child_sa_t *child_sa; enumerator_t *enumerator; - u_int32_t id; + u_int32_t id = 0; + + if (charon->shunts->uninstall(charon->shunts, msg->unroute.name)) + { + fprintf(out, "shunt policy '%s' uninstalled\n", msg->unroute.name); + return; + } enumerator = charon->traps->create_enumerator(charon->traps); while (enumerator->enumerate(enumerator, NULL, &child_sa)) @@ -617,14 +647,20 @@ METHOD(stroke_control_t, unroute, void, if (streq(msg->unroute.name, child_sa->get_name(child_sa))) { id = child_sa->get_reqid(child_sa); - enumerator->destroy(enumerator); - charon->traps->uninstall(charon->traps, id); - fprintf(out, "configuration '%s' unrouted\n", msg->unroute.name); - return; + break; } } enumerator->destroy(enumerator); - fprintf(out, "configuration '%s' not found\n", msg->unroute.name); + + if (id) + { + charon->traps->uninstall(charon->traps, id); + fprintf(out, "configuration '%s' unrouted\n", msg->unroute.name); + } + else + { + fprintf(out, "configuration '%s' not found\n", msg->unroute.name); + } } METHOD(stroke_control_t, destroy, void, diff --git a/src/libcharon/plugins/stroke/stroke_cred.c b/src/libcharon/plugins/stroke/stroke_cred.c index baf02a6da..a2a6d6d9f 100644 --- a/src/libcharon/plugins/stroke/stroke_cred.c +++ b/src/libcharon/plugins/stroke/stroke_cred.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2010 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -17,13 +17,16 @@ #include <sys/types.h> #include <sys/stat.h> #include <limits.h> -#include <glob.h> #include <libgen.h> #include <sys/mman.h> #include <fcntl.h> #include <errno.h> #include <unistd.h> +#ifdef HAVE_GLOB_H +#include <glob.h> +#endif + #include "stroke_cred.h" #include <credentials/certificates/x509.h> @@ -68,15 +71,19 @@ struct private_stroke_cred_t { mem_cred_t *creds; /** + * ignore missing CA basic constraint (i.e. treat all certificates in + * ipsec.conf ca sections and ipsec.d/cacert as CA certificates) + */ + bool force_ca_cert; + + /** * cache CRLs to disk? */ bool cachecrl; }; -/** - * Implementation of stroke_cred_t.load_ca. - */ -static certificate_t* load_ca(private_stroke_cred_t *this, char *filename) +METHOD(stroke_cred_t, load_ca, certificate_t*, + private_stroke_cred_t *this, char *filename) { certificate_t *cert; char path[PATH_MAX]; @@ -90,10 +97,21 @@ static certificate_t* load_ca(private_stroke_cred_t *this, char *filename) snprintf(path, sizeof(path), "%s/%s", CA_CERTIFICATE_DIR, filename); } - cert = lib->creds->create(lib->creds, + if (this->force_ca_cert) + { /* we treat this certificate as a CA certificate even if it has no + * CA basic constraint */ + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_FROM_FILE, path, BUILD_X509_FLAG, X509_CA, + BUILD_END); + } + else + { + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, path, BUILD_END); + } if (cert) { x509_t *x509 = (x509_t*)cert; @@ -110,10 +128,8 @@ static certificate_t* load_ca(private_stroke_cred_t *this, char *filename) return NULL; } -/** - * Implementation of stroke_cred_t.load_peer. - */ -static certificate_t* load_peer(private_stroke_cred_t *this, char *filename) +METHOD(stroke_cred_t, load_peer, certificate_t*, + private_stroke_cred_t *this, char *filename) { certificate_t *cert; char path[PATH_MAX]; @@ -142,6 +158,78 @@ static certificate_t* load_peer(private_stroke_cred_t *this, char *filename) return NULL; } +METHOD(stroke_cred_t, load_pubkey, certificate_t*, + private_stroke_cred_t *this, key_type_t type, char *filename, + identification_t *identity) +{ + certificate_t *cert; + char path[PATH_MAX]; + + if (streq(filename, "%dns")) + { + + } + else if (strncaseeq(filename, "0x", 2) || strncaseeq(filename, "0s", 2)) + { + chunk_t printable_key, rfc3110_key; + public_key_t *key; + + printable_key = chunk_create(filename + 2, strlen(filename) - 2); + rfc3110_key = strncaseeq(filename, "0x", 2) ? + chunk_from_hex(printable_key, NULL) : + chunk_from_base64(printable_key, NULL); + key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, + BUILD_BLOB_DNSKEY, rfc3110_key, + BUILD_END); + free(rfc3110_key.ptr); + if (key) + { + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, + CERT_TRUSTED_PUBKEY, + BUILD_PUBLIC_KEY, key, + BUILD_SUBJECT, identity, + BUILD_END); + key->destroy(key); + if (cert) + { + cert = this->creds->add_cert_ref(this->creds, TRUE, cert); + DBG1(DBG_CFG, " loaded %N public key for \"%Y\"", + key_type_names, type, identity); + return cert; + } + } + DBG1(DBG_CFG, " loading %N public key for \"%Y\" failed", + key_type_names, type, identity); + } + else + { + if (*filename == '/') + { + snprintf(path, sizeof(path), "%s", filename); + } + else + { + snprintf(path, sizeof(path), "%s/%s", CERTIFICATE_DIR, filename); + } + + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY, + BUILD_FROM_FILE, path, + BUILD_SUBJECT, identity, + BUILD_END); + if (cert) + { + cert = this->creds->add_cert_ref(this->creds, TRUE, cert); + DBG1(DBG_CFG, " loaded %N public key for \"%Y\" from '%s'", + key_type_names, type, identity, filename); + return cert; + } + DBG1(DBG_CFG, " loading %N public key for \"%Y\" from '%s' failed", + key_type_names, type, identity, filename); + } + return NULL; +} + /** * load trusted certificates from a directory */ @@ -172,11 +260,21 @@ static void load_certdir(private_stroke_cred_t *this, char *path, { case CERT_X509: if (flag & X509_CA) - { /* for CA certificates, we strictly require - * the CA basic constraint to be set */ - cert = lib->creds->create(lib->creds, + { + if (this->force_ca_cert) + { /* treat this certificate as CA cert even it has no + * CA basic constraint */ + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_FROM_FILE, file, BUILD_X509_FLAG, + X509_CA, BUILD_END); + } + else + { + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, file, BUILD_END); + } if (cert) { x509_t *x509 = (x509_t*)cert; @@ -262,10 +360,8 @@ static void load_certdir(private_stroke_cred_t *this, char *path, enumerator->destroy(enumerator); } -/** - * Implementation of credential_set_t.cache_cert. - */ -static void cache_cert(private_stroke_cred_t *this, certificate_t *cert) +METHOD(stroke_cred_t, cache_cert, void, + private_stroke_cred_t *this, certificate_t *cert) { if (cert->get_type(cert) == CERT_X509_CRL && this->cachecrl) { @@ -292,10 +388,8 @@ static void cache_cert(private_stroke_cred_t *this, certificate_t *cert) } } -/** - * Implementation of stroke_cred_t.cachecrl. - */ -static void cachecrl(private_stroke_cred_t *this, bool enabled) +METHOD(stroke_cred_t, cachecrl, void, + private_stroke_cred_t *this, bool enabled) { DBG1(DBG_CFG, "crl caching to %s %s", CRL_DIR, enabled ? "enabled" : "disabled"); @@ -852,7 +946,6 @@ static void load_secrets(private_stroke_cred_t *this, char *file, int level, if (line.len > strlen("include ") && strneq(line.ptr, "include ", strlen("include "))) { - glob_t buf; char **expanded, *dir, pattern[PATH_MAX]; u_char *pos; @@ -894,18 +987,27 @@ static void load_secrets(private_stroke_cred_t *this, char *file, int level, dir, (int)line.len, line.ptr); free(dir); } - if (glob(pattern, GLOB_ERR, NULL, &buf) != 0) +#ifdef HAVE_GLOB_H { - DBG1(DBG_CFG, "expanding file expression '%s' failed", pattern); - } - else - { - for (expanded = buf.gl_pathv; *expanded != NULL; expanded++) + glob_t buf; + if (glob(pattern, GLOB_ERR, NULL, &buf) != 0) { - load_secrets(this, *expanded, level + 1, prompt); + DBG1(DBG_CFG, "expanding file expression '%s' failed", + pattern); } + else + { + for (expanded = buf.gl_pathv; *expanded != NULL; expanded++) + { + load_secrets(this, *expanded, level + 1, prompt); + } + } + globfree(&buf); } - globfree(&buf); +#else /* HAVE_GLOB_H */ + /* if glob(3) is not available, try to load pattern directly */ + load_secrets(this, pattern, level + 1, prompt); +#endif /* HAVE_GLOB_H */ continue; } @@ -994,10 +1096,8 @@ static void load_certs(private_stroke_cred_t *this) load_certdir(this, CRL_DIR, CERT_X509_CRL, 0); } -/** - * Implementation of stroke_cred_t.reread. - */ -static void reread(private_stroke_cred_t *this, stroke_msg_t *msg, FILE *prompt) +METHOD(stroke_cred_t, reread, void, + private_stroke_cred_t *this, stroke_msg_t *msg, FILE *prompt) { if (msg->reread.flags & REREAD_SECRETS) { @@ -1037,10 +1137,14 @@ static void reread(private_stroke_cred_t *this, stroke_msg_t *msg, FILE *prompt) } } -/** - * Implementation of stroke_cred_t.destroy - */ -static void destroy(private_stroke_cred_t *this) +METHOD(stroke_cred_t, add_shared, void, + private_stroke_cred_t *this, shared_key_t *shared, linked_list_t *owners) +{ + this->creds->add_shared_list(this->creds, shared, owners); +} + +METHOD(stroke_cred_t, destroy, void, + private_stroke_cred_t *this) { lib->credmgr->remove_set(lib->credmgr, &this->creds->set); this->creds->destroy(this->creds); @@ -1052,27 +1156,36 @@ static void destroy(private_stroke_cred_t *this) */ stroke_cred_t *stroke_cred_create() { - private_stroke_cred_t *this = malloc_thing(private_stroke_cred_t); - - this->public.set.create_private_enumerator = (void*)return_null; - this->public.set.create_cert_enumerator = (void*)return_null; - this->public.set.create_shared_enumerator = (void*)return_null; - this->public.set.create_cdp_enumerator = (void*)return_null; - this->public.set.cache_cert = (void*)cache_cert; - this->public.reread = (void(*)(stroke_cred_t*, stroke_msg_t *msg, FILE*))reread; - this->public.load_ca = (certificate_t*(*)(stroke_cred_t*, char *filename))load_ca; - this->public.load_peer = (certificate_t*(*)(stroke_cred_t*, char *filename))load_peer; - this->public.cachecrl = (void(*)(stroke_cred_t*, bool enabled))cachecrl; - this->public.destroy = (void(*)(stroke_cred_t*))destroy; - - this->creds = mem_cred_create(); + private_stroke_cred_t *this; + + INIT(this, + .public = { + .set = { + .create_private_enumerator = (void*)return_null, + .create_cert_enumerator = (void*)return_null, + .create_shared_enumerator = (void*)return_null, + .create_cdp_enumerator = (void*)return_null, + .cache_cert = (void*)_cache_cert, + }, + .reread = _reread, + .load_ca = _load_ca, + .load_peer = _load_peer, + .load_pubkey = _load_pubkey, + .add_shared = _add_shared, + .cachecrl = _cachecrl, + .destroy = _destroy, + }, + .creds = mem_cred_create(), + ); + lib->credmgr->add_set(lib->credmgr, &this->creds->set); + this->force_ca_cert = lib->settings->get_bool(lib->settings, + "charon.plugins.stroke.ignore_missing_ca_basic_constraint", FALSE); + load_certs(this); load_secrets(this, SECRETS_FILE, 0, NULL); - this->cachecrl = FALSE; - return &this->public; } diff --git a/src/libcharon/plugins/stroke/stroke_cred.h b/src/libcharon/plugins/stroke/stroke_cred.h index ccee7d87c..83e648819 100644 --- a/src/libcharon/plugins/stroke/stroke_cred.h +++ b/src/libcharon/plugins/stroke/stroke_cred.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -26,6 +27,7 @@ #include <stroke_msg.h> #include <credentials/credential_set.h> #include <credentials/certificates/certificate.h> +#include <utils/linked_list.h> typedef struct stroke_cred_t stroke_cred_t; @@ -56,7 +58,7 @@ struct stroke_cred_t { certificate_t* (*load_ca)(stroke_cred_t *this, char *filename); /** - * Load a peer certificate and serve it rhrough the credential_set. + * Load a peer certificate and serve it through the credential_set. * * @param filename file to load peer cert from * @return reference to loaded certificate, or NULL @@ -64,6 +66,26 @@ struct stroke_cred_t { certificate_t* (*load_peer)(stroke_cred_t *this, char *filename); /** + * Load a raw public key and serve it through the credential_set. + * + * @param type type of the raw public key (RSA or ECDSA) + * @param filename file to load raw public key from + * @param identity identity of the raw public key owner + * @return reference to loaded raw public key, or NULL + */ + certificate_t* (*load_pubkey)(stroke_cred_t *this, key_type_t type, + char *filename, identification_t *identity); + + /** + * Add a shared secret to serve through the credential_set. + * + * @param shared shared key to add, gets owned + * @param owners list of owners (identification_t*), gets owned + */ + void (*add_shared)(stroke_cred_t *this, shared_key_t *shared, + linked_list_t *owners); + + /** * Enable/Disable CRL caching to disk. * * @param enabled TRUE to enable, FALSE to disable diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c index 6c42f8f8a..514a91e2b 100644 --- a/src/libcharon/plugins/stroke/stroke_list.c +++ b/src/libcharon/plugins/stroke/stroke_list.c @@ -15,6 +15,7 @@ #include "stroke_list.h" +#include <inttypes.h> #include <time.h> #ifdef HAVE_MALLINFO @@ -24,6 +25,7 @@ #include <hydra.h> #include <daemon.h> #include <utils/linked_list.h> +#include <plugins/plugin.h> #include <credentials/certificates/x509.h> #include <credentials/certificates/ac.h> #include <credentials/certificates/crl.h> @@ -116,7 +118,7 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all) ike_proposal = ike_sa->get_proposal(ike_sa); - fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s", + fprintf(out, "%12s[%d]: IKE SPIs: %.16"PRIx64"_i%s %.16"PRIx64"_r%s", ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "", id->get_responder_spi(id), id->is_initiator(id) ? "" : "*"); @@ -221,11 +223,14 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) { u_int16_t encr_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED; u_int16_t encr_size = 0, int_size = 0; + u_int16_t esn = NO_EXT_SEQ_NUMBERS; proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &encr_alg, &encr_size); proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_alg, &int_size); + proposal->get_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, + &esn, NULL); if (encr_alg != ENCR_UNDEFINED) { @@ -243,21 +248,25 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) fprintf(out, "_%u", int_size); } } + if (esn == EXT_SEQ_NUMBERS) + { + fprintf(out, "/ESN"); + } } now = time_monotonic(NULL); child_sa->get_usestats(child_sa, TRUE, &use_in, &bytes_in); - fprintf(out, ", %llu bytes_i", bytes_in); + fprintf(out, ", %" PRIu64 " bytes_i", bytes_in); if (use_in) { - fprintf(out, " (%ds ago)", now - use_in); + fprintf(out, " (%" PRIu64 "s ago)", (u_int64_t)(now - use_in)); } child_sa->get_usestats(child_sa, FALSE, &use_out, &bytes_out); - fprintf(out, ", %llu bytes_o", bytes_out); + fprintf(out, ", %" PRIu64 " bytes_o", bytes_out); if (use_out) { - fprintf(out, " (%ds ago)", now - use_out); + fprintf(out, " (%" PRIu64 "s ago)", (u_int64_t)(now - use_out)); } fprintf(out, ", rekeying "); @@ -324,7 +333,7 @@ static void log_auth_cfgs(FILE *out, peer_cfg_t *peer_cfg, bool local) { if ((uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR)) { - fprintf(out, "EAP_%d-%d authentication", + fprintf(out, "EAP_%" PRIuPTR "-%" PRIuPTR " authentication", (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE), (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR)); } @@ -389,25 +398,27 @@ static void log_auth_cfgs(FILE *out, peer_cfg_t *peer_cfg, bool local) } METHOD(stroke_list_t, status, void, - private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bool all) + private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, + bool all, bool wait) { enumerator_t *enumerator, *children; ike_cfg_t *ike_cfg; child_cfg_t *child_cfg; child_sa_t *child_sa; ike_sa_t *ike_sa; + linked_list_t *my_ts, *other_ts; bool first, found = FALSE; char *name = msg->status.name; + u_int half_open; if (all) { peer_cfg_t *peer_cfg; - plugin_t *plugin; char *pool; host_t *host; u_int32_t dpd; time_t since, now; - u_int size, online, offline; + u_int size, online, offline, i; now = time_monotonic(NULL); since = time(NULL) - (now - this->uptime); @@ -421,21 +432,24 @@ METHOD(stroke_list_t, status, void, mi.arena, mi.hblkhd, mi.uordblks, mi.fordblks); } #endif /* HAVE_MALLINFO */ - fprintf(out, " worker threads: %d idle of %d,", + fprintf(out, " worker threads: %d of %d idle, ", lib->processor->get_idle_threads(lib->processor), lib->processor->get_total_threads(lib->processor)); - fprintf(out, " job queue load: %d,", - lib->processor->get_job_load(lib->processor)); - fprintf(out, " scheduled events: %d\n", - lib->scheduler->get_job_load(lib->scheduler)); - fprintf(out, " loaded plugins: "); - enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); - while (enumerator->enumerate(enumerator, &plugin)) + for (i = 0; i < JOB_PRIO_MAX; i++) { - fprintf(out, "%s ", plugin->get_name(plugin)); + fprintf(out, "%s%d", i == 0 ? "" : "/", + lib->processor->get_working_threads(lib->processor, i)); } - enumerator->destroy(enumerator); - fprintf(out, "\n"); + fprintf(out, " working, job queue: "); + for (i = 0; i < JOB_PRIO_MAX; i++) + { + fprintf(out, "%s%d", i == 0 ? "" : "/", + lib->processor->get_job_load(lib->processor, i)); + } + fprintf(out, ", scheduled: %d\n", + lib->scheduler->get_job_load(lib->scheduler)); + fprintf(out, " loaded plugins: %s\n", + lib->plugins->loaded_plugins(lib->plugins)); first = TRUE; enumerator = this->attribute->create_pool_enumerator(this->attribute); @@ -491,12 +505,11 @@ METHOD(stroke_list_t, status, void, children = peer_cfg->create_child_cfg_enumerator(peer_cfg); while (children->enumerate(children, &child_cfg)) { - linked_list_t *my_ts, *other_ts; - my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL); other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL); - fprintf(out, "%12s: child: %#R=== %#R", child_cfg->get_name(child_cfg), - my_ts, other_ts); + fprintf(out, "%12s: child: %#R=== %#R%N", + child_cfg->get_name(child_cfg), my_ts, other_ts, + ipsec_mode_names, child_cfg->get_mode(child_cfg)); my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); @@ -512,10 +525,39 @@ METHOD(stroke_list_t, status, void, enumerator->destroy(enumerator); } + /* Enumerate shunt policies */ + first = TRUE; + enumerator = charon->shunts->create_enumerator(charon->shunts); + while (enumerator->enumerate(enumerator, &child_cfg)) + { + if (name && !streq(name, child_cfg->get_name(child_cfg))) + { + continue; + } + if (first) + { + fprintf(out, "Shunted Connections:\n"); + first = FALSE; + } + my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL); + other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL); + fprintf(out, "%12s: %#R=== %#R%N\n", + child_cfg->get_name(child_cfg), my_ts, other_ts, + ipsec_mode_names, child_cfg->get_mode(child_cfg)); + my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); + other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); + } + enumerator->destroy(enumerator); + + /* Enumerate traps */ first = TRUE; enumerator = charon->traps->create_enumerator(charon->traps); while (enumerator->enumerate(enumerator, NULL, &child_sa)) { + if (name && !streq(name, child_sa->get_name(child_sa))) + { + continue; + } if (first) { fprintf(out, "Routed Connections:\n"); @@ -525,12 +567,17 @@ METHOD(stroke_list_t, status, void, } enumerator->destroy(enumerator); - fprintf(out, "Security Associations:\n"); - enumerator = charon->controller->create_ike_sa_enumerator(charon->controller); + half_open = charon->ike_sa_manager->get_half_open_count( + charon->ike_sa_manager, NULL); + fprintf(out, "Security Associations (%u up, %u connecting):\n", + charon->ike_sa_manager->get_count(charon->ike_sa_manager) - half_open, + half_open); + enumerator = charon->controller->create_ike_sa_enumerator( + charon->controller, wait); while (enumerator->enumerate(enumerator, &ike_sa)) { bool ike_printed = FALSE; - iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa); + enumerator_t *children = ike_sa->create_child_sa_enumerator(ike_sa); if (name == NULL || streq(name, ike_sa->get_name(ike_sa))) { @@ -539,7 +586,7 @@ METHOD(stroke_list_t, status, void, ike_printed = TRUE; } - while (children->iterate(children, (void**)&child_sa)) + while (children->enumerate(children, (void**)&child_sa)) { if (name == NULL || streq(name, child_sa->get_name(child_sa))) { @@ -582,35 +629,30 @@ static linked_list_t* create_unique_cert_list(certificate_type_t type) while (enumerator->enumerate(enumerator, (void**)&cert)) { - iterator_t *iterator = list->create_iterator(list, TRUE); + enumerator_t *added = list->create_enumerator(list); identification_t *issuer = cert->get_issuer(cert); - bool previous_same, same = FALSE, last = TRUE; + bool previous_same, same = FALSE, found = FALSE; certificate_t *list_cert; - while (iterator->iterate(iterator, (void**)&list_cert)) + while (added->enumerate(added, (void**)&list_cert)) { - /* exit if we have a duplicate? */ if (list_cert->equals(list_cert, cert)) - { - last = FALSE; + { /* stop if we found a duplicate*/ + found = TRUE; break; } - /* group certificates with same issuer */ previous_same = same; same = list_cert->has_issuer(list_cert, issuer); if (previous_same && !same) - { - iterator->insert_before(iterator, (void *)cert->get_ref(cert)); - last = FALSE; + { /* group certificates with same issuer */ break; } } - iterator->destroy(iterator); - - if (last) + if (!found) { - list->insert_last(list, (void *)cert->get_ref(cert)); + list->insert_before(list, added, cert->get_ref(cert)); } + added->destroy(added); } enumerator->destroy(enumerator); return list; @@ -657,12 +699,14 @@ static void list_public_key(public_key_t *public, FILE *out) static void stroke_list_pubkeys(linked_list_t *list, bool utc, FILE *out) { bool first = TRUE; - - enumerator_t *enumerator = list->create_enumerator(list); + time_t now = time(NULL), notBefore, notAfter; + enumerator_t *enumerator; certificate_t *cert; + enumerator = list->create_enumerator(list); while (enumerator->enumerate(enumerator, (void**)&cert)) { + identification_t *subject = cert->get_subject(cert); public_key_t *public = cert->get_public_key(cert); if (public) @@ -675,6 +719,41 @@ static void stroke_list_pubkeys(linked_list_t *list, bool utc, FILE *out) } fprintf(out, "\n"); + /* list subject if available */ + if (subject->get_type(subject) != ID_KEY_ID) + { + fprintf(out, " subject: %#Y\n", subject); + } + + /* list validity if available*/ + cert->get_validity(cert, &now, ¬Before, ¬After); + if (notBefore != UNDEFINED_TIME && notAfter != UNDEFINED_TIME) + { + fprintf(out, " validity: not before %T, ", ¬Before, utc); + if (now < notBefore) + { + fprintf(out, "not valid yet (valid in %V)\n", &now, ¬Before); + } + else + { + fprintf(out, "ok\n"); + } + fprintf(out, " not after %T, ", ¬After, utc); + if (now > notAfter) + { + fprintf(out, "expired (%V ago)\n", &now, ¬After); + } + else + { + fprintf(out, "ok"); + if (now > notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24) + { + fprintf(out, " (expires in %V)", &now, ¬After); + } + fprintf(out, " \n"); + } + } + list_public_key(public, out); public->destroy(public); } @@ -791,7 +870,7 @@ static void stroke_list_certs(linked_list_t *list, char *label, fprintf(out, " subject: \"%Y\"\n", cert->get_subject(cert)); fprintf(out, " issuer: \"%Y\"\n", cert->get_issuer(cert)); - serial = x509->get_serial(x509); + serial = chunk_skip_zero(x509->get_serial(x509)); fprintf(out, " serial: %#B\n", &serial); /* list validity */ @@ -904,7 +983,7 @@ static void stroke_list_acerts(linked_list_t *list, bool utc, FILE *out) { fprintf(out, " hissuer: \"%Y\"\n", id); } - chunk = ac->get_holderSerial(ac); + chunk = chunk_skip_zero(ac->get_holderSerial(ac)); if (chunk.ptr) { fprintf(out, " hserial: %#B\n", &chunk); @@ -916,7 +995,7 @@ static void stroke_list_acerts(linked_list_t *list, bool utc, FILE *out) groups->destroy(groups); } fprintf(out, " issuer: \"%Y\"\n", cert->get_issuer(cert)); - chunk = ac->get_serial(ac); + chunk = chunk_skip_zero(ac->get_serial(ac)); fprintf(out, " serial: %#B\n", &chunk); /* list validity */ @@ -973,13 +1052,14 @@ static void stroke_list_crls(linked_list_t *list, bool utc, FILE *out) fprintf(out, " issuer: \"%Y\"\n", cert->get_issuer(cert)); /* list optional crlNumber */ - chunk = crl->get_serial(crl); + chunk = chunk_skip_zero(crl->get_serial(crl)); if (chunk.ptr) { fprintf(out, " serial: %#B\n", &chunk); } if (crl->is_delta_crl(crl, &chunk)) { + chunk = chunk_skip_zero(chunk); fprintf(out, " delta for: %#B\n", &chunk); } @@ -1157,6 +1237,58 @@ static void list_algs(FILE *out) fprintf(out, "\n"); } +/** + * List loaded plugin information + */ +static void list_plugins(FILE *out) +{ + plugin_feature_t *features, *fp; + enumerator_t *enumerator; + linked_list_t *list; + plugin_t *plugin; + int count, i; + bool loaded; + char *str; + + fprintf(out, "\n"); + fprintf(out, "List of loaded Plugins:\n"); + fprintf(out, "\n"); + + enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); + while (enumerator->enumerate(enumerator, &plugin, &list)) + { + fprintf(out, "%s:\n", plugin->get_name(plugin)); + if (plugin->get_features) + { + count = plugin->get_features(plugin, &features); + for (i = 0; i < count; i++) + { + str = plugin_feature_get_string(&features[i]); + switch (features[i].kind) + { + case FEATURE_PROVIDE: + fp = &features[i]; + loaded = list->find_first(list, NULL, + (void**)&fp) == SUCCESS; + fprintf(out, " %s%s\n", + str, loaded ? "" : " (not loaded)"); + break; + case FEATURE_DEPENDS: + fprintf(out, " %s\n", str); + break; + case FEATURE_SDEPEND: + fprintf(out, " %s(soft)\n", str); + break; + default: + break; + } + free(str); + } + } + } + enumerator->destroy(enumerator); +} + METHOD(stroke_list_t, list, void, private_stroke_list_t *this, stroke_msg_t *msg, FILE *out) { @@ -1228,6 +1360,10 @@ METHOD(stroke_list_t, list, void, { list_algs(out); } + if (msg->list.flags & LIST_PLUGINS) + { + list_plugins(out); + } } /** diff --git a/src/libcharon/plugins/stroke/stroke_list.h b/src/libcharon/plugins/stroke/stroke_list.h index b5bedc6c2..a0d2d18cc 100644 --- a/src/libcharon/plugins/stroke/stroke_list.h +++ b/src/libcharon/plugins/stroke/stroke_list.h @@ -47,8 +47,10 @@ struct stroke_list_t { * @param msg stroke message * @param out stroke console stream * @param all TRUE for "statusall" + * @param wait TRUE to wait for IKE_SA entries, FALSE to skip if locked */ - void (*status)(stroke_list_t *this, stroke_msg_t *msg, FILE *out, bool all); + void (*status)(stroke_list_t *this, stroke_msg_t *msg, FILE *out, + bool all, bool wait); /** * Log pool leases to stroke console. diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c index 88d0270d8..57648feb8 100644 --- a/src/libcharon/plugins/stroke/stroke_socket.c +++ b/src/libcharon/plugins/stroke/stroke_socket.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2011-2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -20,13 +21,15 @@ #include <sys/stat.h> #include <sys/socket.h> #include <sys/un.h> -#include <sys/fcntl.h> #include <unistd.h> #include <errno.h> #include <hydra.h> #include <daemon.h> +#include <threading/mutex.h> #include <threading/thread.h> +#include <threading/condvar.h> +#include <utils/linked_list.h> #include <processing/jobs/callback_job.h> #include "stroke_config.h" @@ -36,6 +39,12 @@ #include "stroke_attribute.h" #include "stroke_list.h" +/** + * To avoid clogging the thread pool with (blocking) jobs, we limit the number + * of concurrently handled stroke commands. + */ +#define MAX_CONCURRENT_DEFAULT 4 + typedef struct stroke_job_context_t stroke_job_context_t; typedef struct private_stroke_socket_t private_stroke_socket_t; @@ -57,7 +66,37 @@ struct private_stroke_socket_t { /** * job accepting stroke messages */ - callback_job_t *job; + callback_job_t *receiver; + + /** + * job handling stroke messages + */ + callback_job_t *handler; + + /** + * queued stroke commands + */ + linked_list_t *commands; + + /** + * lock for command list + */ + mutex_t *mutex; + + /** + * condvar to signal the arrival or completion of commands + */ + condvar_t *condvar; + + /** + * the number of currently handled commands + */ + u_int handling; + + /** + * the maximum number of concurrently handled commands + */ + u_int max_concurrent; /** * configuration backend @@ -85,7 +124,7 @@ struct private_stroke_socket_t { stroke_ca_t *ca; /** - * Status information logging + * status information logging */ stroke_list_t *list; }; @@ -146,6 +185,7 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end) pop_string(msg, &end->auth2); pop_string(msg, &end->id); pop_string(msg, &end->id2); + pop_string(msg, &end->rsakey); pop_string(msg, &end->cert); pop_string(msg, &end->cert2); pop_string(msg, &end->ca); @@ -161,6 +201,7 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end) DBG2(DBG_CFG, " %sauth2=%s", label, end->auth2); DBG2(DBG_CFG, " %sid=%s", label, end->id); DBG2(DBG_CFG, " %sid2=%s", label, end->id2); + DBG2(DBG_CFG, " %srsakey=%s", label, end->rsakey); DBG2(DBG_CFG, " %scert=%s", label, end->cert); DBG2(DBG_CFG, " %scert2=%s", label, end->cert2); DBG2(DBG_CFG, " %sca=%s", label, end->ca); @@ -190,6 +231,9 @@ static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg) DBG2(DBG_CFG, " aaa_identity=%s", msg->add_conn.aaa_identity); DBG2(DBG_CFG, " ike=%s", msg->add_conn.algorithms.ike); DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp); + DBG2(DBG_CFG, " dpddelay=%d", msg->add_conn.dpd.delay); + DBG2(DBG_CFG, " dpdaction=%d", msg->add_conn.dpd.action); + DBG2(DBG_CFG, " closeaction=%d", msg->add_conn.close_action); DBG2(DBG_CFG, " mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no"); DBG2(DBG_CFG, " mediated_by=%s", msg->add_conn.ikeme.mediated_by); DBG2(DBG_CFG, " me_peerid=%s", msg->add_conn.ikeme.peerid); @@ -322,11 +366,11 @@ static void stroke_del_ca(private_stroke_socket_t *this, * show status of daemon */ static void stroke_status(private_stroke_socket_t *this, - stroke_msg_t *msg, FILE *out, bool all) + stroke_msg_t *msg, FILE *out, bool all, bool wait) { pop_string(msg, &(msg->status.name)); - this->list->status(this->list, msg, out, all); + this->list->status(this->list, msg, out, all, wait); } /** @@ -382,7 +426,7 @@ static void stroke_export(private_stroke_socket_t *this, { pop_string(msg, &msg->export.selector); - if (msg->purge.flags & EXPORT_X509) + if (msg->export.flags & EXPORT_X509) { enumerator_t *enumerator; identification_t *id; @@ -418,6 +462,33 @@ static void stroke_leases(private_stroke_socket_t *this, } /** + * Show memory usage + */ +static void stroke_memusage(private_stroke_socket_t *this, + stroke_msg_t *msg, FILE *out) +{ + if (lib->leak_detective) + { + lib->leak_detective->usage(lib->leak_detective, out); + } +} + +/** + * Set username and password for a connection + */ +static void stroke_user_creds(private_stroke_socket_t *this, + stroke_msg_t *msg, FILE *out) +{ + pop_string(msg, &msg->user_creds.name); + pop_string(msg, &msg->user_creds.username); + pop_string(msg, &msg->user_creds.password); + + DBG1(DBG_CFG, "received stroke: user-creds '%s'", msg->user_creds.name); + + this->config->set_user_credentials(this->config, msg, out); +} + +/** * set the verbosity debug output */ static void stroke_loglevel(private_stroke_socket_t *this, @@ -433,7 +504,7 @@ static void stroke_loglevel(private_stroke_socket_t *this, msg->loglevel.level, msg->loglevel.type); group = enum_from_name(debug_names, msg->loglevel.type); - if (group < 0) + if ((int)group < 0) { fprintf(out, "invalid type (%s)!\n", msg->loglevel.type); return; @@ -475,6 +546,18 @@ static void stroke_job_context_destroy(stroke_job_context_t *this) } /** + * called to signal the completion of a command + */ +static inline job_requeue_t job_processed(private_stroke_socket_t *this) +{ + this->mutex->lock(this->mutex); + this->handling--; + this->condvar->signal(this->condvar); + this->mutex->unlock(this->mutex); + return JOB_REQUEUE_NONE; +} + +/** * process a stroke request from the socket pointed by "fd" */ static job_requeue_t process(stroke_job_context_t *ctx) @@ -492,7 +575,7 @@ static job_requeue_t process(stroke_job_context_t *ctx) { DBG1(DBG_CFG, "reading length of stroke message failed: %s", strerror(errno)); - return JOB_REQUEUE_NONE; + return job_processed(this); } /* read message */ @@ -501,14 +584,14 @@ static job_requeue_t process(stroke_job_context_t *ctx) if (bytes_read != msg_length) { DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno)); - return JOB_REQUEUE_NONE; + return job_processed(this); } out = fdopen(strokefd, "w+"); if (out == NULL) { DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno)); - return JOB_REQUEUE_NONE; + return job_processed(this); } DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length); @@ -534,10 +617,13 @@ static job_requeue_t process(stroke_job_context_t *ctx) stroke_rekey(this, msg, out); break; case STR_STATUS: - stroke_status(this, msg, out, FALSE); + stroke_status(this, msg, out, FALSE, TRUE); break; case STR_STATUS_ALL: - stroke_status(this, msg, out, TRUE); + stroke_status(this, msg, out, TRUE, TRUE); + break; + case STR_STATUS_ALL_NOBLK: + stroke_status(this, msg, out, TRUE, FALSE); break; case STR_ADD_CONN: stroke_add_conn(this, msg); @@ -572,6 +658,12 @@ static job_requeue_t process(stroke_job_context_t *ctx) case STR_LEASES: stroke_leases(this, msg, out); break; + case STR_MEMUSAGE: + stroke_memusage(this, msg, out); + break; + case STR_USER_CREDS: + stroke_user_creds(this, msg, out); + break; default: DBG1(DBG_CFG, "received unknown stroke"); break; @@ -579,11 +671,38 @@ static job_requeue_t process(stroke_job_context_t *ctx) fclose(out); /* fclose() closes underlying FD */ ctx->fd = 0; - return JOB_REQUEUE_NONE; + return job_processed(this); +} + +/** + * Handle queued stroke commands + */ +static job_requeue_t handle(private_stroke_socket_t *this) +{ + stroke_job_context_t *ctx; + callback_job_t *job; + bool oldstate; + + this->mutex->lock(this->mutex); + thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex); + oldstate = thread_cancelability(TRUE); + while (this->commands->get_count(this->commands) == 0 || + this->handling >= this->max_concurrent) + { + this->condvar->wait(this->condvar, this->mutex); + } + thread_cancelability(oldstate); + this->commands->remove_first(this->commands, (void**)&ctx); + this->handling++; + thread_cleanup_pop(TRUE); + job = callback_job_create_with_prio((callback_job_cb_t)process, ctx, + (void*)stroke_job_context_destroy, this->handler, JOB_PRIO_HIGH); + lib->processor->queue_job(lib->processor, (job_t*)job); + return JOB_REQUEUE_DIRECT; } /** - * Implementation of private_stroke_socket_t.stroke_receive. + * Accept stroke commands and queue them to be handled */ static job_requeue_t receive(private_stroke_socket_t *this) { @@ -591,7 +710,6 @@ static job_requeue_t receive(private_stroke_socket_t *this) int strokeaddrlen = sizeof(strokeaddr); int strokefd; bool oldstate; - callback_job_t *job; stroke_job_context_t *ctx; oldstate = thread_cancelability(TRUE); @@ -604,17 +722,18 @@ static job_requeue_t receive(private_stroke_socket_t *this) return JOB_REQUEUE_FAIR; } - ctx = malloc_thing(stroke_job_context_t); - ctx->fd = strokefd; - ctx->this = this; - job = callback_job_create((callback_job_cb_t)process, - ctx, (void*)stroke_job_context_destroy, this->job); - lib->processor->queue_job(lib->processor, (job_t*)job); + INIT(ctx, + .fd = strokefd, + .this = this, + ); + this->mutex->lock(this->mutex); + this->commands->insert_last(this->commands, ctx); + this->condvar->signal(this->condvar); + this->mutex->unlock(this->mutex); return JOB_REQUEUE_FAIR; } - /** * initialize and open stroke socket */ @@ -659,12 +778,14 @@ static bool open_socket(private_stroke_socket_t *this) return TRUE; } -/** - * Implementation of stroke_socket_t.destroy - */ -static void destroy(private_stroke_socket_t *this) +METHOD(stroke_socket_t, destroy, void, + private_stroke_socket_t *this) { - this->job->cancel(this->job); + this->handler->cancel(this->handler); + this->receiver->cancel(this->receiver); + this->commands->destroy_function(this->commands, (void*)stroke_job_context_destroy); + this->condvar->destroy(this->condvar); + this->mutex->destroy(this->mutex); lib->credmgr->remove_set(lib->credmgr, &this->ca->set); lib->credmgr->remove_set(lib->credmgr, &this->cred->set); charon->backends->remove_backend(charon->backends, &this->config->backend); @@ -683,9 +804,13 @@ static void destroy(private_stroke_socket_t *this) */ stroke_socket_t *stroke_socket_create() { - private_stroke_socket_t *this = malloc_thing(private_stroke_socket_t); + private_stroke_socket_t *this; - this->public.destroy = (void(*)(stroke_socket_t*))destroy; + INIT(this, + .public = { + .destroy = _destroy, + }, + ); if (!open_socket(this)) { @@ -700,14 +825,24 @@ stroke_socket_t *stroke_socket_create() this->control = stroke_control_create(); this->list = stroke_list_create(this->attribute); + this->mutex = mutex_create(MUTEX_TYPE_DEFAULT); + this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT); + this->commands = linked_list_create(); + this->max_concurrent = lib->settings->get_int(lib->settings, + "charon.plugins.stroke.max_concurrent", MAX_CONCURRENT_DEFAULT); + lib->credmgr->add_set(lib->credmgr, &this->ca->set); lib->credmgr->add_set(lib->credmgr, &this->cred->set); charon->backends->add_backend(charon->backends, &this->config->backend); hydra->attributes->add_provider(hydra->attributes, &this->attribute->provider); - this->job = callback_job_create((callback_job_cb_t)receive, - this, NULL, NULL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + this->receiver = callback_job_create_with_prio((callback_job_cb_t)receive, + this, NULL, NULL, JOB_PRIO_CRITICAL); + lib->processor->queue_job(lib->processor, (job_t*)this->receiver); + + this->handler = callback_job_create_with_prio((callback_job_cb_t)handle, + this, NULL, NULL, JOB_PRIO_CRITICAL); + lib->processor->queue_job(lib->processor, (job_t*)this->handler); return &this->public; } |