diff options
Diffstat (limited to 'src/libcharon/plugins/stroke')
-rw-r--r-- | src/libcharon/plugins/stroke/Makefile.in | 20 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_config.c | 25 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_control.c | 2 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_cred.c | 715 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_list.c | 41 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_socket.c | 59 |
6 files changed, 591 insertions, 271 deletions
diff --git a/src/libcharon/plugins/stroke/Makefile.in b/src/libcharon/plugins/stroke/Makefile.in index e094200ca..e6e98838b 100644 --- a/src/libcharon/plugins/stroke/Makefile.in +++ b/src/libcharon/plugins/stroke/Makefile.in @@ -44,6 +44,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ $(top_srcdir)/m4/config/lt~obsolete.m4 \ $(top_srcdir)/m4/macros/with.m4 \ $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/m4/macros/add-plugin.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) @@ -168,6 +169,8 @@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PTHREADLIB = @PTHREADLIB@ RANLIB = @RANLIB@ RTLIB = @RTLIB@ @@ -199,14 +202,17 @@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ +c_plugins = @c_plugins@ datadir = @datadir@ datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ default_pkcs11 = @default_pkcs11@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ gtk_CFLAGS = @gtk_CFLAGS@ gtk_LIBS = @gtk_LIBS@ +h_plugins = @h_plugins@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ @@ -221,24 +227,31 @@ ipsecgid = @ipsecgid@ ipsecgroup = @ipsecgroup@ ipsecuid = @ipsecuid@ ipsecuser = @ipsecuser@ +libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ -libhydra_plugins = @libhydra_plugins@ -libstrongswan_plugins = @libstrongswan_plugins@ linux_headers = @linux_headers@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ +maemo_CFLAGS = @maemo_CFLAGS@ +maemo_LIBS = @maemo_LIBS@ +manager_plugins = @manager_plugins@ mandir = @mandir@ +medsrv_plugins = @medsrv_plugins@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ oldincludedir = @oldincludedir@ +openac_plugins = @openac_plugins@ +p_plugins = @p_plugins@ pdfdir = @pdfdir@ piddir = @piddir@ +pki_plugins = @pki_plugins@ plugindir = @plugindir@ pluto_plugins = @pluto_plugins@ +pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ @@ -246,7 +259,10 @@ random_device = @random_device@ resolv_conf = @resolv_conf@ routing_table = @routing_table@ routing_table_prio = @routing_table_prio@ +s_plugins = @s_plugins@ sbindir = @sbindir@ +scepclient_plugins = @scepclient_plugins@ +scripts_plugins = @scripts_plugins@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ strongswan_conf = @strongswan_conf@ diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index 617069432..165212a5e 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -15,6 +15,7 @@ #include "stroke_config.h" +#include <hydra.h> #include <daemon.h> #include <threading/mutex.h> #include <utils/lexparser.h> @@ -199,8 +200,8 @@ static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg host = host_create_from_dns(msg->add_conn.other.address, 0, 0); if (host) { - interface = charon->kernel_interface->get_interface( - charon->kernel_interface, host); + interface = hydra->kernel_interface->get_interface( + hydra->kernel_interface, host); host->destroy(host); if (interface) { @@ -215,8 +216,8 @@ static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg host = host_create_from_dns(msg->add_conn.me.address, 0, 0); if (host) { - interface = charon->kernel_interface->get_interface( - charon->kernel_interface, host); + interface = hydra->kernel_interface->get_interface( + hydra->kernel_interface, host); host->destroy(host); if (!interface) { @@ -362,7 +363,16 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, } } else - { /* no second authentication round, fine */ + { /* no second authentication round, fine. But load certificates + * for other purposes (EAP-TLS) */ + if (cert) + { + certificate = this->cred->load_peer(this->cred, cert); + if (certificate) + { + certificate->destroy(certificate); + } + } return NULL; } } @@ -502,6 +512,11 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, } cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, identity); } + if (msg->add_conn.aaa_identity) + { + cfg->add(cfg, AUTH_RULE_AAA_IDENTITY, + identification_create_from_string(msg->add_conn.aaa_identity)); + } } else { diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c index f64421551..e0398ba78 100644 --- a/src/libcharon/plugins/stroke/stroke_control.c +++ b/src/libcharon/plugins/stroke/stroke_control.c @@ -354,7 +354,7 @@ static void terminate_srcip(private_stroke_control_t *this, } /* schedule delete asynchronously */ - charon->processor->queue_job(charon->processor, (job_t*) + lib->processor->queue_job(lib->processor, (job_t*) delete_ike_sa_job_create(ike_sa->get_id(ike_sa), TRUE)); } enumerator->destroy(enumerator); diff --git a/src/libcharon/plugins/stroke/stroke_cred.c b/src/libcharon/plugins/stroke/stroke_cred.c index 2816b9bb2..91e71f1f4 100644 --- a/src/libcharon/plugins/stroke/stroke_cred.c +++ b/src/libcharon/plugins/stroke/stroke_cred.c @@ -14,10 +14,15 @@ * for more details. */ +#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> #include "stroke_cred.h" #include "stroke_shared_key.h" @@ -25,6 +30,8 @@ #include <credentials/certificates/x509.h> #include <credentials/certificates/crl.h> #include <credentials/certificates/ac.h> +#include <credentials/sets/mem_cred.h> +#include <credentials/sets/callback_cred.h> #include <utils/linked_list.h> #include <utils/lexparser.h> #include <threading/rwlock.h> @@ -88,7 +95,8 @@ struct private_stroke_cred_t { typedef struct { private_stroke_cred_t *this; identification_t *id; - certificate_type_t type; + certificate_type_t cert; + key_type_t key; } id_data_t; /** @@ -109,15 +117,18 @@ static bool private_filter(id_data_t *data, private_key_t *key; key = *in; - if (data->id == NULL) + if (data->key == KEY_ANY || data->key == key->get_type(key)) { - *out = key; - return TRUE; - } - if (key->has_fingerprint(key, data->id->get_encoding(data->id))) - { - *out = key; - return TRUE; + if (data->id == NULL) + { + *out = key; + return TRUE; + } + if (key->has_fingerprint(key, data->id->get_encoding(data->id))) + { + *out = key; + return TRUE; + } } return FALSE; } @@ -133,6 +144,7 @@ static enumerator_t* create_private_enumerator(private_stroke_cred_t *this, data = malloc_thing(id_data_t); data->this = this; data->id = id; + data->key = type; this->lock->read_lock(this->lock); return enumerator_create_filter(this->private->create_enumerator(this->private), @@ -148,7 +160,7 @@ static bool certs_filter(id_data_t *data, certificate_t **in, certificate_t **ou public_key_t *public; certificate_t *cert = *in; - if (data->type != CERT_ANY && data->type != cert->get_type(cert)) + if (data->cert != CERT_ANY && data->cert != cert->get_type(cert)) { return FALSE; } @@ -161,11 +173,14 @@ static bool certs_filter(id_data_t *data, certificate_t **in, certificate_t **ou public = cert->get_public_key(cert); if (public) { - if (public->has_fingerprint(public, data->id->get_encoding(data->id))) + if (data->key == KEY_ANY || data->key != public->get_type(public)) { - public->destroy(public); - *out = *in; - return TRUE; + if (public->has_fingerprint(public, data->id->get_encoding(data->id))) + { + public->destroy(public); + *out = *in; + return TRUE; + } } public->destroy(public); } @@ -188,7 +203,8 @@ static enumerator_t* create_cert_enumerator(private_stroke_cred_t *this, data = malloc_thing(id_data_t); data->this = this; data->id = id; - data->type = cert; + data->cert = cert; + data->key = key; this->lock->read_lock(this->lock); return enumerator_create_filter(this->certs->create_enumerator(this->certs), @@ -667,47 +683,443 @@ static err_t extract_secret(chunk_t *secret, chunk_t *line) } /** - * Data to pass to passphrase_cb + * Data for passphrase callback */ typedef struct { /** socket we use for prompting */ FILE *prompt; /** private key file */ - char *file; - /** buffer for passphrase */ - char buf[256]; + char *path; + /** number of tries */ + int try; } passphrase_cb_data_t; /** - * Passphrase callback to read from whack fd + * Callback function to receive Passphrases */ -chunk_t passphrase_cb(passphrase_cb_data_t *data, int try) +static shared_key_t* passphrase_cb(passphrase_cb_data_t *data, + shared_key_type_t type, + identification_t *me, identification_t *other, + id_match_t *match_me, id_match_t *match_other) { - chunk_t secret = chunk_empty;; + chunk_t secret; + char buf[256]; - if (try > 5) + if (type != SHARED_ANY && type != SHARED_PRIVATE_KEY_PASS) { - fprintf(data->prompt, "invalid passphrase, too many trials\n"); - return chunk_empty; + return NULL; } - if (try == 1) + + if (data->try > 1) { - fprintf(data->prompt, "Private key '%s' is encrypted\n", data->file); + if (data->try > 5) + { + fprintf(data->prompt, "PIN invalid, giving up.\n"); + return NULL; + } + fprintf(data->prompt, "PIN invalid!\n"); } - else + data->try++; + fprintf(data->prompt, "Private key '%s' is encrypted.\n", data->path); + fprintf(data->prompt, "Passphrase:\n"); + if (fgets(buf, sizeof(buf), data->prompt)) { - fprintf(data->prompt, "invalid passphrase\n"); + secret = chunk_create(buf, strlen(buf)); + if (secret.len > 1) + { /* trim appended \n */ + secret.len--; + if (match_me) + { + *match_me = ID_MATCH_PERFECT; + } + if (match_other) + { + *match_other = ID_MATCH_NONE; + } + return shared_key_create(SHARED_PRIVATE_KEY_PASS, chunk_clone(secret)); + } } - fprintf(data->prompt, "Passphrase:\n"); - if (fgets(data->buf, sizeof(data->buf), data->prompt)) + return NULL; +} + +/** + * Data for PIN callback + */ +typedef struct { + /** socket we use for prompting */ + FILE *prompt; + /** card label */ + char *card; + /** card keyid */ + chunk_t keyid; + /** number of tries */ + int try; +} pin_cb_data_t; + +/** + * Callback function to receive PINs + */ +static shared_key_t* pin_cb(pin_cb_data_t *data, shared_key_type_t type, + identification_t *me, identification_t *other, + id_match_t *match_me, id_match_t *match_other) +{ + chunk_t secret; + char buf[256]; + + if (type != SHARED_ANY && type != SHARED_PIN) + { + return NULL; + } + + if (!me || !chunk_equals(me->get_encoding(me), data->keyid)) + { + return NULL; + } + + if (data->try > 1) + { + fprintf(data->prompt, "PIN invalid, aborting.\n"); + return NULL; + } + data->try++; + fprintf(data->prompt, "Login to '%s' required\n", data->card); + fprintf(data->prompt, "PIN:\n"); + if (fgets(buf, sizeof(buf), data->prompt)) { - secret = chunk_create(data->buf, strlen(data->buf)); - if (secret.len) + secret = chunk_create(buf, strlen(buf)); + if (secret.len > 1) { /* trim appended \n */ secret.len--; + if (match_me) + { + *match_me = ID_MATCH_PERFECT; + } + if (match_other) + { + *match_other = ID_MATCH_NONE; + } + return shared_key_create(SHARED_PIN, chunk_clone(secret)); + } + } + return NULL; +} + +/** + * Load a smartcard with a PIN + */ +static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr, + FILE *prompt) +{ + chunk_t sc = chunk_empty, secret = chunk_empty; + char smartcard[64], keyid[64], module[64], *pos; + private_key_t *key = NULL; + u_int slot; + chunk_t chunk; + shared_key_t *shared; + identification_t *id; + mem_cred_t *mem = NULL; + callback_cred_t *cb = NULL; + pin_cb_data_t pin_data; + enum { + SC_FORMAT_SLOT_MODULE_KEYID, + SC_FORMAT_SLOT_KEYID, + SC_FORMAT_KEYID, + } format; + + err_t ugh = extract_value(&sc, &line); + + if (ugh != NULL) + { + DBG1(DBG_CFG, "line %d: %s", line_nr, ugh); + return FALSE; + } + if (sc.len == 0) + { + DBG1(DBG_CFG, "line %d: expected %%smartcard specifier", line_nr); + return FALSE; + } + snprintf(smartcard, sizeof(smartcard), "%.*s", sc.len, sc.ptr); + smartcard[sizeof(smartcard) - 1] = '\0'; + + /* parse slot and key id. Three formats are supported: + * - %smartcard<slot>@<module>:<keyid> + * - %smartcard<slot>:<keyid> + * - %smartcard:<keyid> + */ + if (sscanf(smartcard, "%%smartcard%u@%s", &slot, module) == 2) + { + pos = strchr(module, ':'); + if (!pos) + { + DBG1(DBG_CFG, "line %d: the given %%smartcard specifier is " + "invalid", line_nr); + return FALSE; + } + *pos = '\0'; + strcpy(keyid, pos + 1); + format = SC_FORMAT_SLOT_MODULE_KEYID; + } + else if (sscanf(smartcard, "%%smartcard%u:%s", &slot, keyid) == 2) + { + format = SC_FORMAT_SLOT_KEYID; + } + else if (sscanf(smartcard, "%%smartcard:%s", keyid) == 1) + { + format = SC_FORMAT_KEYID; + } + else + { + DBG1(DBG_CFG, "line %d: the given %%smartcard specifier is not" + " supported or invalid", line_nr); + return FALSE; + } + + if (!eat_whitespace(&line)) + { + DBG1(DBG_CFG, "line %d: expected PIN", line_nr); + return FALSE; + } + ugh = extract_secret(&secret, &line); + if (ugh != NULL) + { + DBG1(DBG_CFG, "line %d: malformed PIN: %s", line_nr, ugh); + return FALSE; + } + + chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL); + if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7)) + { + free(secret.ptr); + if (!prompt) + { /* no IO channel to prompt, skip */ + free(chunk.ptr); + return TRUE; + } + /* use callback credential set to prompt for the pin */ + pin_data.prompt = prompt; + pin_data.card = smartcard; + pin_data.keyid = chunk; + pin_data.try = 1; + cb = callback_cred_create_shared((void*)pin_cb, &pin_data); + lib->credmgr->add_local_set(lib->credmgr, &cb->set); + } + else + { + /* provide our pin in a temporary credential set */ + shared = shared_key_create(SHARED_PIN, secret); + id = identification_create_from_encoding(ID_KEY_ID, chunk); + mem = mem_cred_create(); + mem->add_shared(mem, shared, id, NULL); + lib->credmgr->add_local_set(lib->credmgr, &mem->set); + } + + /* unlock: smartcard needs the pin and potentially calls public set */ + this->lock->unlock(this->lock); + switch (format) + { + case SC_FORMAT_SLOT_MODULE_KEYID: + key = lib->creds->create(lib->creds, + CRED_PRIVATE_KEY, KEY_ANY, + BUILD_PKCS11_SLOT, slot, + BUILD_PKCS11_MODULE, module, + BUILD_PKCS11_KEYID, chunk, BUILD_END); + break; + case SC_FORMAT_SLOT_KEYID: + key = lib->creds->create(lib->creds, + CRED_PRIVATE_KEY, KEY_ANY, + BUILD_PKCS11_SLOT, slot, + BUILD_PKCS11_KEYID, chunk, BUILD_END); + break; + case SC_FORMAT_KEYID: + key = lib->creds->create(lib->creds, + CRED_PRIVATE_KEY, KEY_ANY, + BUILD_PKCS11_KEYID, chunk, BUILD_END); + break; + } + this->lock->write_lock(this->lock); + if (mem) + { + lib->credmgr->remove_local_set(lib->credmgr, &mem->set); + mem->destroy(mem); + } + if (cb) + { + lib->credmgr->remove_local_set(lib->credmgr, &cb->set); + cb->destroy(cb); + } + + if (key) + { + DBG1(DBG_CFG, " loaded private key from %.*s", sc.len, sc.ptr); + this->private->insert_last(this->private, key); + } + return TRUE; +} + +/** + * Load a private key + */ +static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr, + FILE *prompt, key_type_t key_type) +{ + char path[PATH_MAX]; + chunk_t filename; + chunk_t secret = chunk_empty; + private_key_t *key; + + err_t ugh = extract_value(&filename, &line); + + if (ugh != NULL) + { + DBG1(DBG_CFG, "line %d: %s", line_nr, ugh); + return FALSE; + } + if (filename.len == 0) + { + DBG1(DBG_CFG, "line %d: empty filename", line_nr); + return FALSE; + } + if (*filename.ptr == '/') + { + /* absolute path name */ + snprintf(path, sizeof(path), "%.*s", filename.len, filename.ptr); + } + else + { + /* relative path name */ + snprintf(path, sizeof(path), "%s/%.*s", PRIVATE_KEY_DIR, + filename.len, filename.ptr); + } + + /* check for optional passphrase */ + if (eat_whitespace(&line)) + { + ugh = extract_secret(&secret, &line); + if (ugh != NULL) + { + DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh); + return FALSE; + } + } + if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7)) + { + callback_cred_t *cb = NULL; + passphrase_cb_data_t pp_data = { + .prompt = prompt, + .path = path, + .try = 1, + }; + + free(secret.ptr); + if (!prompt) + { + return TRUE; + } + /* use callback credential set to prompt for the passphrase */ + pp_data.prompt = prompt; + pp_data.path = path; + pp_data.try = 1; + cb = callback_cred_create_shared((void*)passphrase_cb, &pp_data); + lib->credmgr->add_local_set(lib->credmgr, &cb->set); + + /* unlock, as the builder might ask for a secret */ + this->lock->unlock(this->lock); + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type, + BUILD_FROM_FILE, path, BUILD_END); + this->lock->write_lock(this->lock); + + lib->credmgr->remove_local_set(lib->credmgr, &cb->set); + cb->destroy(cb); + } + else + { + mem_cred_t *mem = NULL; + shared_key_t *shared; + + /* provide our pin in a temporary credential set */ + shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret); + mem = mem_cred_create(); + mem->add_shared(mem, shared, NULL); + lib->credmgr->add_local_set(lib->credmgr, &mem->set); + + /* unlock, as the builder might ask for a secret */ + this->lock->unlock(this->lock); + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type, + BUILD_FROM_FILE, path, BUILD_END); + this->lock->write_lock(this->lock); + + lib->credmgr->remove_local_set(lib->credmgr, &mem->set); + mem->destroy(mem); + } + if (key) + { + DBG1(DBG_CFG, " loaded %N private key from '%s'", + key_type_names, key->get_type(key), path); + this->private->insert_last(this->private, key); + } + else + { + DBG1(DBG_CFG, " loading private key from '%s' failed", path); + } + return TRUE; +} + +/** + * Load a shared key + */ +static bool load_shared(private_stroke_cred_t *this, chunk_t line, int line_nr, + shared_key_type_t type, chunk_t ids) +{ + stroke_shared_key_t *shared_key; + chunk_t secret = chunk_empty; + bool any = TRUE; + + err_t ugh = extract_secret(&secret, &line); + if (ugh != NULL) + { + DBG1(DBG_CFG, "line %d: malformed secret: %s", line_nr, ugh); + return FALSE; + } + shared_key = stroke_shared_key_create(type, secret); + DBG1(DBG_CFG, " loaded %N secret for %s", shared_key_type_names, type, + ids.len > 0 ? (char*)ids.ptr : "%any"); + DBG4(DBG_CFG, " secret: %#B", &secret); + + this->shared->insert_last(this->shared, shared_key); + while (ids.len > 0) + { + chunk_t id; + identification_t *peer_id; + + ugh = extract_value(&id, &ids); + if (ugh != NULL) + { + DBG1(DBG_CFG, "line %d: %s", line_nr, ugh); + return FALSE; + } + if (id.len == 0) + { + continue; + } + + /* NULL terminate the ID string */ + *(id.ptr + id.len) = '\0'; + peer_id = identification_create_from_string(id.ptr); + if (peer_id->get_type(peer_id) == ID_ANY) + { + peer_id->destroy(peer_id); + continue; } + + shared_key->add_owner(shared_key, peer_id); + any = FALSE; + } + if (any) + { + shared_key->add_owner(shared_key, + identification_create_from_encoding(ID_ANY, chunk_empty)); } - return secret; + return TRUE; } /** @@ -716,30 +1128,36 @@ chunk_t passphrase_cb(passphrase_cb_data_t *data, int try) static void load_secrets(private_stroke_cred_t *this, char *file, int level, FILE *prompt) { - size_t bytes; - int line_nr = 0; - chunk_t chunk, src, line; - FILE *fd; + int line_nr = 0, fd; + chunk_t src, line; private_key_t *private; shared_key_t *shared; + struct stat sb; + void *addr; DBG1(DBG_CFG, "loading secrets from '%s'", file); - - fd = fopen(file, "r"); - if (fd == NULL) + fd = open(file, O_RDONLY); + if (fd == -1) { - DBG1(DBG_CFG, "opening secrets file '%s' failed", file); + DBG1(DBG_CFG, "opening secrets file '%s' failed: %s", file, + strerror(errno)); return; } - - /* TODO: do error checks */ - fseek(fd, 0, SEEK_END); - chunk.len = ftell(fd); - rewind(fd); - chunk.ptr = malloc(chunk.len); - bytes = fread(chunk.ptr, 1, chunk.len, fd); - fclose(fd); - src = chunk; + if (fstat(fd, &sb) == -1) + { + DBG1(DBG_LIB, "getting file size of '%s' failed: %s", file, + strerror(errno)); + close(fd); + return; + } + addr = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) + { + DBG1(DBG_LIB, "mapping '%s' failed: %s", file, strerror(errno)); + close(fd); + return; + } + src = chunk_create(addr, sb.st_size); if (level == 0) { @@ -844,223 +1262,52 @@ static void load_secrets(private_stroke_cred_t *this, char *file, int level, else { DBG1(DBG_CFG, "line %d: missing ' : ' separator", line_nr); - goto error; + break; } if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line)) { DBG1(DBG_CFG, "line %d: missing token", line_nr); - goto error; + break; } if (match("RSA", &token) || match("ECDSA", &token)) { - char path[PATH_MAX]; - chunk_t filename; - chunk_t secret = chunk_empty; - private_key_t *key = NULL; - key_type_t key_type = match("RSA", &token) ? KEY_RSA : KEY_ECDSA; - - err_t ugh = extract_value(&filename, &line); - - if (ugh != NULL) - { - DBG1(DBG_CFG, "line %d: %s", line_nr, ugh); - goto error; - } - if (filename.len == 0) - { - DBG1(DBG_CFG, "line %d: empty filename", line_nr); - goto error; - } - if (*filename.ptr == '/') - { - /* absolute path name */ - snprintf(path, sizeof(path), "%.*s", filename.len, filename.ptr); - } - else - { - /* relative path name */ - snprintf(path, sizeof(path), "%s/%.*s", PRIVATE_KEY_DIR, - filename.len, filename.ptr); - } - - /* check for optional passphrase */ - if (eat_whitespace(&line)) - { - ugh = extract_secret(&secret, &line); - if (ugh != NULL) - { - DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh); - goto error; - } - } - if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7)) - { - if (prompt) - { - passphrase_cb_data_t data; - - data.prompt = prompt; - data.file = path; - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, - key_type, BUILD_FROM_FILE, path, - BUILD_PASSPHRASE_CALLBACK, - passphrase_cb, &data, BUILD_END); - } - } - else - { - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type, - BUILD_FROM_FILE, path, - BUILD_PASSPHRASE, secret, BUILD_END); - } - if (key) + if (!load_private(this, line, line_nr, prompt, + match("RSA", &token) ? KEY_RSA : KEY_ECDSA)) { - DBG1(DBG_CFG, " loaded %N private key from '%s'", - key_type_names, key->get_type(key), path); - this->private->insert_last(this->private, key); - } - else - { - DBG1(DBG_CFG, " loading private key from '%s' failed", path); + break; } - chunk_clear(&secret); } else if (match("PIN", &token)) { - chunk_t sc = chunk_empty, secret = chunk_empty; - char smartcard[32], keyid[22], pin[32]; - private_key_t *key; - u_int slot; - - err_t ugh = extract_value(&sc, &line); - - if (ugh != NULL) - { - DBG1(DBG_CFG, "line %d: %s", line_nr, ugh); - goto error; - } - if (sc.len == 0) - { - DBG1(DBG_CFG, "line %d: expected %%smartcard specifier", line_nr); - goto error; - } - snprintf(smartcard, sizeof(smartcard), "%.*s", sc.len, sc.ptr); - smartcard[sizeof(smartcard) - 1] = '\0'; - - /* parse slot and key id. only two formats are supported. - * first try %smartcard<slot>:<keyid> */ - if (sscanf(smartcard, "%%smartcard%u:%s", &slot, keyid) == 2) - { - snprintf(smartcard, sizeof(smartcard), "%u:%s", slot, keyid); - } - /* then try %smartcard:<keyid> */ - else if (sscanf(smartcard, "%%smartcard:%s", keyid) == 1) - { - snprintf(smartcard, sizeof(smartcard), "%s", keyid); - } - else - { - DBG1(DBG_CFG, "line %d: the given %%smartcard specifier is not" - " supported or invalid", line_nr); - goto error; - } - - if (!eat_whitespace(&line)) - { - DBG1(DBG_CFG, "line %d: expected PIN", line_nr); - goto error; - } - ugh = extract_secret(&secret, &line); - if (ugh != NULL) + if (!load_pin(this, line, line_nr, prompt)) { - DBG1(DBG_CFG, "line %d: malformed PIN: %s", line_nr, ugh); - goto error; - } - snprintf(pin, sizeof(pin), "%.*s", secret.len, secret.ptr); - pin[sizeof(pin) - 1] = '\0'; - - /* we assume an RSA key */ - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, - BUILD_SMARTCARD_KEYID, smartcard, - BUILD_SMARTCARD_PIN, pin, BUILD_END); - - if (key) - { - DBG1(DBG_CFG, " loaded private key from %.*s", sc.len, sc.ptr); - this->private->insert_last(this->private, key); + break; } - memset(pin, 0, sizeof(pin)); - chunk_clear(&secret); } else if ((match("PSK", &token) && (type = SHARED_IKE)) || (match("EAP", &token) && (type = SHARED_EAP)) || (match("NTLM", &token) && (type = SHARED_NT_HASH)) || (match("XAUTH", &token) && (type = SHARED_EAP))) { - stroke_shared_key_t *shared_key; - chunk_t secret = chunk_empty; - bool any = TRUE; - - err_t ugh = extract_secret(&secret, &line); - if (ugh != NULL) - { - DBG1(DBG_CFG, "line %d: malformed secret: %s", line_nr, ugh); - goto error; - } - shared_key = stroke_shared_key_create(type, secret); - DBG1(DBG_CFG, " loaded %N secret for %s", shared_key_type_names, type, - ids.len > 0 ? (char*)ids.ptr : "%any"); - DBG4(DBG_CFG, " secret: %#B", &secret); - - this->shared->insert_last(this->shared, shared_key); - while (ids.len > 0) + if (!load_shared(this, line, line_nr, type, ids)) { - chunk_t id; - identification_t *peer_id; - - ugh = extract_value(&id, &ids); - if (ugh != NULL) - { - DBG1(DBG_CFG, "line %d: %s", line_nr, ugh); - goto error; - } - if (id.len == 0) - { - continue; - } - - /* NULL terminate the ID string */ - *(id.ptr + id.len) = '\0'; - peer_id = identification_create_from_string(id.ptr); - if (peer_id->get_type(peer_id) == ID_ANY) - { - peer_id->destroy(peer_id); - continue; - } - - shared_key->add_owner(shared_key, peer_id); - any = FALSE; - } - if (any) - { - shared_key->add_owner(shared_key, - identification_create_from_encoding(ID_ANY, chunk_empty)); + break; } } else { DBG1(DBG_CFG, "line %d: token must be either " "RSA, ECDSA, PSK, EAP, XAUTH or PIN", line_nr); - goto error; + break; } } -error: if (level == 0) { this->lock->unlock(this->lock); } - chunk_clear(&chunk); + munmap(addr, sb.st_size); + close(fd); } /** diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c index a6de35466..86deea490 100644 --- a/src/libcharon/plugins/stroke/stroke_list.c +++ b/src/libcharon/plugins/stroke/stroke_list.c @@ -21,6 +21,7 @@ #include <malloc.h> #endif /* HAVE_MALLINFO */ +#include <hydra.h> #include <daemon.h> #include <utils/linked_list.h> #include <credentials/certificates/x509.h> @@ -422,12 +423,12 @@ static void status(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bo } #endif /* HAVE_MALLINFO */ fprintf(out, " worker threads: %d idle of %d,", - charon->processor->get_idle_threads(charon->processor), - charon->processor->get_total_threads(charon->processor)); + lib->processor->get_idle_threads(lib->processor), + lib->processor->get_total_threads(lib->processor)); fprintf(out, " job queue load: %d,", - charon->processor->get_job_load(charon->processor)); + lib->processor->get_job_load(lib->processor)); fprintf(out, " scheduled events: %d\n", - charon->scheduler->get_job_load(charon->scheduler)); + lib->scheduler->get_job_load(lib->scheduler)); fprintf(out, " loaded plugins: "); enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); while (enumerator->enumerate(enumerator, &plugin)) @@ -454,8 +455,8 @@ static void status(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bo } enumerator->destroy(enumerator); - enumerator = charon->kernel_interface->create_address_enumerator( - charon->kernel_interface, FALSE, FALSE); + enumerator = hydra->kernel_interface->create_address_enumerator( + hydra->kernel_interface, FALSE, FALSE); fprintf(out, "Listening IP addresses:\n"); while (enumerator->enumerate(enumerator, (void**)&host)) { @@ -638,7 +639,7 @@ static void list_public_key(public_key_t *public, FILE *out) fprintf(out, " pubkey: %N %d bits%s\n", key_type_names, public->get_type(public), - public->get_keysize(public) * 8, + public->get_keysize(public), private ? ", has private key" : ""); if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid)) { @@ -1026,9 +1027,10 @@ static void stroke_list_crls(linked_list_t *list, bool utc, FILE *out) */ static void stroke_list_ocsp(linked_list_t* list, bool utc, FILE *out) { - bool first = TRUE; + bool first = TRUE, ok; enumerator_t *enumerator = list->create_enumerator(list); certificate_t *cert; + time_t produced, usable, now = time(NULL); while (enumerator->enumerate(enumerator, (void**)&cert)) { @@ -1039,8 +1041,20 @@ static void stroke_list_ocsp(linked_list_t* list, bool utc, FILE *out) fprintf(out, "\n"); first = FALSE; } - fprintf(out, " signer: \"%Y\"\n", cert->get_issuer(cert)); + + /* check validity */ + ok = cert->get_validity(cert, &now, &produced, &usable); + fprintf(out, " validity: produced at %T\n", &produced, utc); + fprintf(out, " usable till %T, ", &usable, utc); + if (ok) + { + fprintf(out, "ok\n"); + } + else + { + fprintf(out, "expired (%V ago)\n", &now, &usable); + } } enumerator->destroy(enumerator); } @@ -1073,6 +1087,13 @@ static void list_algs(FILE *out) fprintf(out, "%N ", integrity_algorithm_names, integrity); } enumerator->destroy(enumerator); + fprintf(out, "\n aead: "); + enumerator = lib->crypto->create_aead_enumerator(lib->crypto); + while (enumerator->enumerate(enumerator, &encryption)) + { + fprintf(out, "%N ", encryption_algorithm_names, encryption); + } + enumerator->destroy(enumerator); fprintf(out, "\n hasher: "); enumerator = lib->crypto->create_hasher_enumerator(lib->crypto); while (enumerator->enumerate(enumerator, &hash)) @@ -1184,7 +1205,7 @@ static void pool_leases(private_stroke_list_t *this, FILE *out, char *pool, bool on; int found = 0; - fprintf(out, "Leases in pool '%s', usage: %lu/%lu, %lu online\n", + fprintf(out, "Leases in pool '%s', usage: %u/%u, %u online\n", pool, online + offline, size, online); enumerator = this->attribute->create_lease_enumerator(this->attribute, pool); while (enumerator && enumerator->enumerate(enumerator, &id, &lease, &on)) diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c index 18afa5af4..0a5110fd3 100644 --- a/src/libcharon/plugins/stroke/stroke_socket.c +++ b/src/libcharon/plugins/stroke/stroke_socket.c @@ -24,10 +24,10 @@ #include <unistd.h> #include <errno.h> -#include <processing/jobs/callback_job.h> #include <hydra.h> #include <daemon.h> #include <threading/thread.h> +#include <processing/jobs/callback_job.h> #include "stroke_config.h" #include "stroke_control.h" @@ -180,11 +180,13 @@ static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg) pop_end(msg, "left", &msg->add_conn.me); pop_end(msg, "right", &msg->add_conn.other); pop_string(msg, &msg->add_conn.eap_identity); + pop_string(msg, &msg->add_conn.aaa_identity); pop_string(msg, &msg->add_conn.algorithms.ike); pop_string(msg, &msg->add_conn.algorithms.esp); pop_string(msg, &msg->add_conn.ikeme.mediated_by); pop_string(msg, &msg->add_conn.ikeme.peerid); DBG2(DBG_CFG, " eap_identity=%s", msg->add_conn.eap_identity); + 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, " mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no"); @@ -353,6 +355,37 @@ static void stroke_purge(private_stroke_socket_t *this, } /** + * Export in-memory credentials + */ +static void stroke_export(private_stroke_socket_t *this, + stroke_msg_t *msg, FILE *out) +{ + pop_string(msg, &msg->export.selector); + + if (msg->purge.flags & EXPORT_X509) + { + enumerator_t *enumerator; + identification_t *id; + certificate_t *cert; + chunk_t encoded; + + id = identification_create_from_string(msg->export.selector); + enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, + CERT_X509, KEY_ANY, id, FALSE); + while (enumerator->enumerate(enumerator, &cert)) + { + if (cert->get_encoding(cert, CERT_PEM, &encoded)) + { + fprintf(out, "%.*s", encoded.len, encoded.ptr); + free(encoded.ptr); + } + } + enumerator->destroy(enumerator); + id->destroy(id); + } +} + +/** * list pool leases */ static void stroke_leases(private_stroke_socket_t *this, @@ -364,21 +397,6 @@ static void stroke_leases(private_stroke_socket_t *this, this->list->leases(this->list, msg, out); } -debug_t get_group_from_name(char *type) -{ - if (strcaseeq(type, "any")) return DBG_ANY; - else if (strcaseeq(type, "mgr")) return DBG_MGR; - else if (strcaseeq(type, "ike")) return DBG_IKE; - else if (strcaseeq(type, "chd")) return DBG_CHD; - else if (strcaseeq(type, "job")) return DBG_JOB; - else if (strcaseeq(type, "cfg")) return DBG_CFG; - else if (strcaseeq(type, "knl")) return DBG_KNL; - else if (strcaseeq(type, "net")) return DBG_NET; - else if (strcaseeq(type, "enc")) return DBG_ENC; - else if (strcaseeq(type, "lib")) return DBG_LIB; - else return -1; -} - /** * set the verbosity debug output */ @@ -394,7 +412,7 @@ static void stroke_loglevel(private_stroke_socket_t *this, DBG1(DBG_CFG, "received stroke: loglevel %d for %s", msg->loglevel.level, msg->loglevel.type); - group = get_group_from_name(msg->loglevel.type); + group = enum_from_name(debug_names, msg->loglevel.type); if (group < 0) { fprintf(out, "invalid type (%s)!\n", msg->loglevel.type); @@ -525,6 +543,9 @@ static job_requeue_t process(stroke_job_context_t *ctx) case STR_PURGE: stroke_purge(this, msg, out); break; + case STR_EXPORT: + stroke_export(this, msg, out); + break; case STR_LEASES: stroke_leases(this, msg, out); break; @@ -565,7 +586,7 @@ static job_requeue_t receive(private_stroke_socket_t *this) ctx->this = this; job = callback_job_create((callback_job_cb_t)process, ctx, (void*)stroke_job_context_destroy, this->job); - charon->processor->queue_job(charon->processor, (job_t*)job); + lib->processor->queue_job(lib->processor, (job_t*)job); return JOB_REQUEUE_FAIR; } @@ -663,7 +684,7 @@ stroke_socket_t *stroke_socket_create() this->job = callback_job_create((callback_job_cb_t)receive, this, NULL, NULL); - charon->processor->queue_job(charon->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, (job_t*)this->job); return &this->public; } |