From 01c0267778ff137e6d841cda1382091055cf276d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 26 Apr 2013 16:59:34 +0200 Subject: [PATCH 01/39] thread: implicitly create thread_t if an external thread calls thread_current() --- src/libstrongswan/threading/thread.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/libstrongswan/threading/thread.c b/src/libstrongswan/threading/thread.c index d6d98d1ef..eb167d6a4 100644 --- a/src/libstrongswan/threading/thread.c +++ b/src/libstrongswan/threading/thread.c @@ -341,7 +341,20 @@ thread_t *thread_create(thread_main_t main, void *arg) */ thread_t *thread_current() { - return current_thread->get(current_thread); + private_thread_t *this; + + this = (private_thread_t*)current_thread->get(current_thread); + if (!this) + { + this = thread_create_internal(); + + id_mutex->lock(id_mutex); + this->id = next_id++; + id_mutex->unlock(id_mutex); + + current_thread->set(current_thread, (void*)this); + } + return &this->public; } /** From 437a6feb07eaf515c9384bb04aa1609ddb391a6d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 1 May 2013 12:13:28 +0200 Subject: [PATCH 02/39] hashtable: add common hashtable hash/equals functions for pointer/string keys --- src/libstrongswan/collections/hashtable.c | 36 +++++++++++++++++++++-- src/libstrongswan/collections/hashtable.h | 35 +++++++++++++++++++++- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/src/libstrongswan/collections/hashtable.c b/src/libstrongswan/collections/hashtable.c index d181d8ec8..1003aa0fa 100644 --- a/src/libstrongswan/collections/hashtable.c +++ b/src/libstrongswan/collections/hashtable.c @@ -16,6 +16,8 @@ #include "hashtable.h" +#include + /** The maximum capacity of the hash table (MUST be a power of 2) */ #define MAX_CAPACITY (1 << 30) @@ -146,9 +148,40 @@ struct private_enumerator_t { * previous pair (used by remove_at) */ pair_t *prev; - }; +/* + * See header. + */ +u_int hashtable_hash_ptr(void *key) +{ + return chunk_hash(chunk_from_thing(key)); +} + +/* + * See header. + */ +u_int hashtable_hash_str(void *key) +{ + return chunk_hash(chunk_from_str((char*)key)); +} + +/* + * See header. + */ +bool hashtable_equals_ptr(void *key, void *other_key) +{ + return key == other_key; +} + +/* + * See header. + */ +bool hashtable_equals_str(void *key, void *other_key) +{ + return streq(key, other_key); +} + /** * This function returns the next-highest power of two for the given number. * The algorithm works by setting all bits on the right-hand side of the most @@ -441,4 +474,3 @@ hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals, return &this->public; } - diff --git a/src/libstrongswan/collections/hashtable.h b/src/libstrongswan/collections/hashtable.h index e38850ded..520a86c90 100644 --- a/src/libstrongswan/collections/hashtable.h +++ b/src/libstrongswan/collections/hashtable.h @@ -33,6 +33,22 @@ typedef struct hashtable_t hashtable_t; */ typedef u_int (*hashtable_hash_t)(void *key); +/** + * Hashtable hash function calculation the hash solely based on the key pointer. + * + * @param key key to hash + * @return hash of key + */ +u_int hashtable_hash_ptr(void *key); + +/** + * Hashtable hash function calculation the hash for char* keys. + * + * @param key key to hash, a char* + * @return hash of key + */ +u_int hashtable_hash_str(void *key); + /** * Prototype for a function that compares the two keys for equality. * @@ -42,6 +58,24 @@ typedef u_int (*hashtable_hash_t)(void *key); */ typedef bool (*hashtable_equals_t)(void *key, void *other_key); +/** + * Hashtable equals function comparing pointers. + * + * @param key key to compare + * @param other_key other key to compare + * @return TRUE if key == other_key + */ +bool hashtable_equals_ptr(void *key, void *other_key); + +/** + * Hashtable equals function comparing char* keys. + * + * @param key key to compare + * @param other_key other key to compare + * @return TRUE if streq(key, other_key) + */ +bool hashtable_equals_str(void *key, void *other_key); + /** * Class implementing a hash table. * @@ -121,7 +155,6 @@ struct hashtable_t { * Destroys a hash table object. */ void (*destroy) (hashtable_t *this); - }; /** From 3f55f203ee89e04511dc37b6a8ee7fe889b74c04 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 30 Apr 2013 11:46:11 +0200 Subject: [PATCH 03/39] openssl: show which critical X.509 extension is not supported --- src/libstrongswan/plugins/openssl/openssl_x509.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libstrongswan/plugins/openssl/openssl_x509.c b/src/libstrongswan/plugins/openssl/openssl_x509.c index c98e8055d..f15f511e7 100644 --- a/src/libstrongswan/plugins/openssl/openssl_x509.c +++ b/src/libstrongswan/plugins/openssl/openssl_x509.c @@ -977,7 +977,12 @@ static bool parse_extensions(private_openssl_x509_t *this) "libstrongswan.x509.enforce_critical", TRUE); if (!ok) { - DBG1(DBG_LIB, "found unsupported critical X.509 extension"); + char buf[80] = ""; + + OBJ_obj2txt(buf, sizeof(buf), + X509_EXTENSION_get_object(ext), 0); + DBG1(DBG_LIB, "found unsupported critical X.509 " + "extension: %s", buf); } break; } From c3e7b3de0b1ffb1647315733e13c47abd5d1d2b6 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 30 Apr 2013 11:55:38 +0200 Subject: [PATCH 04/39] openssl: parse X.509 extended key usage from extension parsing loop Otherwise parsing gets aborted if unknown critical extensions are handled as error. --- .../plugins/openssl/openssl_x509.c | 71 ++++++++++--------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/src/libstrongswan/plugins/openssl/openssl_x509.c b/src/libstrongswan/plugins/openssl/openssl_x509.c index f15f511e7..24b12d50c 100644 --- a/src/libstrongswan/plugins/openssl/openssl_x509.c +++ b/src/libstrongswan/plugins/openssl/openssl_x509.c @@ -678,6 +678,41 @@ static bool parse_keyUsage_ext(private_openssl_x509_t *this, return FALSE; } +/** + * Parse ExtendedKeyUsage + */ +static bool parse_extKeyUsage_ext(private_openssl_x509_t *this, + X509_EXTENSION *ext) +{ + EXTENDED_KEY_USAGE *usage; + int i; + + usage = X509V3_EXT_d2i(ext); + if (usage) + { + for (i = 0; i < sk_ASN1_OBJECT_num(usage); i++) + { + switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(usage, i))) + { + case NID_server_auth: + this->flags |= X509_SERVER_AUTH; + break; + case NID_client_auth: + this->flags |= X509_CLIENT_AUTH; + break; + case NID_OCSP_sign: + this->flags |= X509_OCSP_SIGNER; + break; + default: + break; + } + } + sk_ASN1_OBJECT_pop_free(usage, ASN1_OBJECT_free); + return TRUE; + } + return FALSE; +} + /** * Parse CRL distribution points */ @@ -963,6 +998,9 @@ static bool parse_extensions(private_openssl_x509_t *this) case NID_key_usage: ok = parse_keyUsage_ext(this, ext); break; + case NID_ext_key_usage: + ok = parse_extKeyUsage_ext(this, ext); + break; case NID_crl_distribution_points: ok = parse_crlDistributionPoints_ext(this, ext); break; @@ -995,38 +1033,6 @@ static bool parse_extensions(private_openssl_x509_t *this) return TRUE; } -/** - * Parse ExtendedKeyUsage - */ -static void parse_extKeyUsage(private_openssl_x509_t *this) -{ - EXTENDED_KEY_USAGE *usage; - int i; - - usage = X509_get_ext_d2i(this->x509, NID_ext_key_usage, NULL, NULL); - if (usage) - { - for (i = 0; i < sk_ASN1_OBJECT_num(usage); i++) - { - switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(usage, i))) - { - case NID_server_auth: - this->flags |= X509_SERVER_AUTH; - break; - case NID_client_auth: - this->flags |= X509_CLIENT_AUTH; - break; - case NID_OCSP_sign: - this->flags |= X509_OCSP_SIGNER; - break; - default: - break; - } - } - sk_ASN1_OBJECT_pop_free(usage, ASN1_OBJECT_free); - } -} - /** * Parse a DER encoded x509 certificate */ @@ -1093,7 +1099,6 @@ static bool parse_certificate(private_openssl_x509_t *this) { return FALSE; } - parse_extKeyUsage(this); hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); if (!hasher || !hasher->allocate_hash(hasher, this->encoding, &this->hash)) From 69039e83f824604de5356dd6ba06b3cd1167e49a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 2 May 2013 10:03:57 +0200 Subject: [PATCH 05/39] credmgr: don't use pointers for id_match_t enum values --- src/libstrongswan/credentials/credential_manager.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c index f4cd9b9e6..35d98458c 100644 --- a/src/libstrongswan/credentials/credential_manager.c +++ b/src/libstrongswan/credentials/credential_manager.c @@ -378,8 +378,8 @@ METHOD(credential_manager_t, get_shared, shared_key_t*, identification_t *me, identification_t *other) { shared_key_t *current, *found = NULL; - id_match_t *best_me = ID_MATCH_NONE, *best_other = ID_MATCH_NONE; - id_match_t *match_me, *match_other; + id_match_t best_me = ID_MATCH_NONE, best_other = ID_MATCH_NONE; + id_match_t match_me, match_other; enumerator_t *enumerator; enumerator = create_shared_enumerator(this, type, me, other); From 5d36f04ee27ad6324ec3d81b7cb47577d87476de Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 2 May 2013 10:07:36 +0200 Subject: [PATCH 06/39] credmgr: stop querying for secrets once we get a perfect match --- src/libstrongswan/credentials/credential_manager.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c index 35d98458c..fa255551b 100644 --- a/src/libstrongswan/credentials/credential_manager.c +++ b/src/libstrongswan/credentials/credential_manager.c @@ -393,6 +393,10 @@ METHOD(credential_manager_t, get_shared, shared_key_t*, best_me = match_me; best_other = match_other; } + if (best_me == ID_MATCH_PERFECT && best_other == ID_MATCH_PERFECT) + { + break; + } } enumerator->destroy(enumerator); return found; From 7b8edabd8a6ff47d33f3ca47915179b073c72ec7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 29 Apr 2013 11:19:57 +0200 Subject: [PATCH 07/39] keychain: add a stub for a credential plugin using OS X Keychain Services --- configure.in | 4 + src/libstrongswan/Makefile.am | 7 ++ .../plugins/keychain/Makefile.am | 16 ++++ .../plugins/keychain/keychain_creds.c | 67 +++++++++++++++++ .../plugins/keychain/keychain_creds.h | 49 +++++++++++++ .../plugins/keychain/keychain_plugin.c | 73 +++++++++++++++++++ .../plugins/keychain/keychain_plugin.h | 42 +++++++++++ 7 files changed, 258 insertions(+) create mode 100644 src/libstrongswan/plugins/keychain/Makefile.am create mode 100644 src/libstrongswan/plugins/keychain/keychain_creds.c create mode 100644 src/libstrongswan/plugins/keychain/keychain_creds.h create mode 100644 src/libstrongswan/plugins/keychain/keychain_plugin.c create mode 100644 src/libstrongswan/plugins/keychain/keychain_plugin.h diff --git a/configure.in b/configure.in index 53d06a3b4..f1524c24b 100644 --- a/configure.in +++ b/configure.in @@ -218,6 +218,7 @@ ARG_ENABL_SET([padlock], [enables VIA Padlock crypto plugin.]) ARG_ENABL_SET([openssl], [enables the OpenSSL crypto plugin.]) ARG_ENABL_SET([gcrypt], [enables the libgcrypt plugin.]) ARG_ENABL_SET([agent], [enables the ssh-agent signing plugin.]) +ARG_ENABL_SET([keychain], [enables OS X Keychain Services credential set.]) ARG_ENABL_SET([pkcs11], [enables the PKCS11 token support plugin.]) ARG_ENABL_SET([ctr], [enables the Counter Mode wrapper crypto plugin.]) ARG_ENABL_SET([ccm], [enables the CCM AEAD wrapper crypto plugin.]) @@ -1012,6 +1013,7 @@ ADD_PLUGIN([af-alg], [s charon openac scepclient pki scripts medsr ADD_PLUGIN([fips-prf], [s charon nm cmd]) ADD_PLUGIN([gmp], [s charon openac scepclient pki scripts manager medsrv attest nm cmd]) ADD_PLUGIN([agent], [s charon nm cmd]) +ADD_PLUGIN([keychain], [s charon cmd]) ADD_PLUGIN([xcbc], [s charon nm cmd]) ADD_PLUGIN([cmac], [s charon nm cmd]) ADD_PLUGIN([hmac], [s charon scripts nm cmd]) @@ -1148,6 +1150,7 @@ AM_CONDITIONAL(USE_PADLOCK, test x$padlock = xtrue) AM_CONDITIONAL(USE_OPENSSL, test x$openssl = xtrue) AM_CONDITIONAL(USE_GCRYPT, test x$gcrypt = xtrue) AM_CONDITIONAL(USE_AGENT, test x$agent = xtrue) +AM_CONDITIONAL(USE_KEYCHAIN, test x$keychain = xtrue) AM_CONDITIONAL(USE_PKCS11, test x$pkcs11 = xtrue) AM_CONDITIONAL(USE_CTR, test x$ctr = xtrue) AM_CONDITIONAL(USE_CCM, test x$ccm = xtrue) @@ -1349,6 +1352,7 @@ AC_CONFIG_FILES([ src/libstrongswan/plugins/openssl/Makefile src/libstrongswan/plugins/gcrypt/Makefile src/libstrongswan/plugins/agent/Makefile + src/libstrongswan/plugins/keychain/Makefile src/libstrongswan/plugins/pkcs11/Makefile src/libstrongswan/plugins/ctr/Makefile src/libstrongswan/plugins/ccm/Makefile diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index bde5f710a..82d2159ce 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -423,6 +423,13 @@ if MONOLITHIC endif endif +if USE_KEYCHAIN + SUBDIRS += plugins/keychain +if MONOLITHIC + libstrongswan_la_LIBADD += plugins/keychain/libstrongswan-keychain.la +endif +endif + if USE_PKCS11 SUBDIRS += plugins/pkcs11 if MONOLITHIC diff --git a/src/libstrongswan/plugins/keychain/Makefile.am b/src/libstrongswan/plugins/keychain/Makefile.am new file mode 100644 index 000000000..e0d25b686 --- /dev/null +++ b/src/libstrongswan/plugins/keychain/Makefile.am @@ -0,0 +1,16 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-keychain.la +else +plugin_LTLIBRARIES = libstrongswan-keychain.la +endif + +libstrongswan_keychain_la_SOURCES = \ + keychain_plugin.h keychain_plugin.c \ + keychain_creds.h keychain_creds.c + +libstrongswan_keychain_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/keychain/keychain_creds.c b/src/libstrongswan/plugins/keychain/keychain_creds.c new file mode 100644 index 000000000..d3331fa40 --- /dev/null +++ b/src/libstrongswan/plugins/keychain/keychain_creds.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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 "keychain_creds.h" + +#include + +typedef struct private_keychain_creds_t private_keychain_creds_t; + +/** + * Private data of an keychain_creds_t object. + */ +struct private_keychain_creds_t { + + /** + * Public keychain_creds_t interface. + */ + keychain_creds_t public; +}; + +METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, + private_keychain_creds_t *this, certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted) +{ + return enumerator_create_empty(); +} + +METHOD(keychain_creds_t, destroy, void, + private_keychain_creds_t *this) +{ + free(this); +} + +/** + * See header + */ +keychain_creds_t *keychain_creds_create() +{ + private_keychain_creds_t *this; + + INIT(this, + .public = { + .set = { + .create_shared_enumerator = (void*)enumerator_create_empty, + .create_private_enumerator = (void*)enumerator_create_empty, + .create_cert_enumerator = _create_cert_enumerator, + .create_cdp_enumerator = (void*)enumerator_create_empty, + .cache_cert = (void*)nop, + }, + .destroy = _destroy, + }, + ); + + return &this->public; +} diff --git a/src/libstrongswan/plugins/keychain/keychain_creds.h b/src/libstrongswan/plugins/keychain/keychain_creds.h new file mode 100644 index 000000000..f2ca5d75c --- /dev/null +++ b/src/libstrongswan/plugins/keychain/keychain_creds.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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 keychain_creds keychain_creds + * @{ @ingroup keychain + */ + +#ifndef KEYCHAIN_CREDS_H_ +#define KEYCHAIN_CREDS_H_ + +typedef struct keychain_creds_t keychain_creds_t; + +#include + +/** + * Credential set using OS X Keychain Services. + */ +struct keychain_creds_t { + + /** + * Implements credential_set_t. + */ + credential_set_t set; + + /** + * Destroy a keychain_creds_t. + */ + void (*destroy)(keychain_creds_t *this); +}; + +/** + * Create a keychain_creds instance. + */ +keychain_creds_t *keychain_creds_create(); + +#endif /** KEYCHAIN_CREDS_H_ @}*/ diff --git a/src/libstrongswan/plugins/keychain/keychain_plugin.c b/src/libstrongswan/plugins/keychain/keychain_plugin.c new file mode 100644 index 000000000..5ce7b16fb --- /dev/null +++ b/src/libstrongswan/plugins/keychain/keychain_plugin.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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 "keychain_plugin.h" +#include "keychain_creds.h" + +#include + +typedef struct private_keychain_plugin_t private_keychain_plugin_t; + +/** + * private data of keychain_plugin + */ +struct private_keychain_plugin_t { + + /** + * public functions + */ + keychain_plugin_t public; + + /** + * System level Keychain Services credential set + */ + keychain_creds_t *creds; +}; + +METHOD(plugin_t, get_name, char*, + private_keychain_plugin_t *this) +{ + return "keychain"; +} + +METHOD(plugin_t, destroy, void, + private_keychain_plugin_t *this) +{ + lib->credmgr->remove_set(lib->credmgr, &this->creds->set); + this->creds->destroy(this->creds); + free(this); +} + +/* + * see header file + */ +plugin_t *keychain_plugin_create() +{ + private_keychain_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .destroy = _destroy, + }, + }, + .creds = keychain_creds_create(), + ); + + lib->credmgr->add_set(lib->credmgr, &this->creds->set); + + return &this->public.plugin; +} diff --git a/src/libstrongswan/plugins/keychain/keychain_plugin.h b/src/libstrongswan/plugins/keychain/keychain_plugin.h new file mode 100644 index 000000000..482f173c3 --- /dev/null +++ b/src/libstrongswan/plugins/keychain/keychain_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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 keychain keychain + * @ingroup plugins + * + * @defgroup keychain_plugin keychain_plugin + * @{ @ingroup keychain + */ + +#ifndef KEYCHAIN_PLUGIN_H_ +#define KEYCHAIN_PLUGIN_H_ + +#include + +typedef struct keychain_plugin_t keychain_plugin_t; + +/** + * Plugin providing OS X Keychain Services support. + */ +struct keychain_plugin_t { + + /** + * Implements plugin interface, + */ + plugin_t plugin; +}; + +#endif /** KEYCHAIN_PLUGIN_H_ @}*/ From 6f00ddb90c2fa1c37b0bceda630292fa16a7cdf9 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 30 Apr 2013 11:59:01 +0200 Subject: [PATCH 08/39] keychain: support on-the-fly enumeration of trusted/untrusted certificates --- .../plugins/keychain/Makefile.am | 3 +- .../plugins/keychain/keychain_creds.c | 116 ++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/src/libstrongswan/plugins/keychain/Makefile.am b/src/libstrongswan/plugins/keychain/Makefile.am index e0d25b686..508a4b024 100644 --- a/src/libstrongswan/plugins/keychain/Makefile.am +++ b/src/libstrongswan/plugins/keychain/Makefile.am @@ -13,4 +13,5 @@ libstrongswan_keychain_la_SOURCES = \ keychain_plugin.h keychain_plugin.c \ keychain_creds.h keychain_creds.c -libstrongswan_keychain_la_LDFLAGS = -module -avoid-version +libstrongswan_keychain_la_LDFLAGS = -module -avoid-version \ + -framework Security -framework CoreFoundation diff --git a/src/libstrongswan/plugins/keychain/keychain_creds.c b/src/libstrongswan/plugins/keychain/keychain_creds.c index d3331fa40..08ef82614 100644 --- a/src/libstrongswan/plugins/keychain/keychain_creds.c +++ b/src/libstrongswan/plugins/keychain/keychain_creds.c @@ -17,6 +17,8 @@ #include +#include + typedef struct private_keychain_creds_t private_keychain_creds_t; /** @@ -30,10 +32,124 @@ struct private_keychain_creds_t { keychain_creds_t public; }; +/** + * Enumerator for certificates + */ +typedef struct { + /* implements enumerator_t */ + enumerator_t public; + /* currently enumerating certificate */ + certificate_t *current; + /* id to filter for */ + identification_t *id; + /* certificate public key type we are looking for */ + key_type_t type; + /* array of binary certificates to enumerate */ + CFArrayRef certs; + /* current position in array */ + int i; +} cert_enumerator_t; + +METHOD(enumerator_t, enumerate_certs, bool, + cert_enumerator_t *this, certificate_t **out) +{ + DESTROY_IF(this->current); + this->current = NULL; + + while (this->i < CFArrayGetCount(this->certs)) + { + certificate_t *cert; + public_key_t *key; + CFDataRef data; + chunk_t chunk; + + data = CFArrayGetValueAtIndex(this->certs, this->i++); + if (data) + { + chunk = chunk_create((char*)CFDataGetBytePtr(data), + CFDataGetLength(data)); + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, chunk, BUILD_END); + if (cert) + { + if (!this->id || cert->has_subject(cert, this->id)) + { + key = cert->get_public_key(cert); + if (key) + { + if (this->type == KEY_ANY || + this->type == key->get_type(key)) + { + key->destroy(key); + this->current = cert; + *out = cert; + return TRUE; + } + key->destroy(key); + } + } + cert->destroy(cert); + } + } + } + return FALSE; +} + +METHOD(enumerator_t, destroy_certs, void, + cert_enumerator_t *this) +{ + DESTROY_IF(this->current); + CFRelease(this->certs); + free(this); +} + METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, private_keychain_creds_t *this, certificate_type_t cert, key_type_t key, identification_t *id, bool trusted) { + cert_enumerator_t *enumerator; + OSStatus status; + CFDictionaryRef query; + CFArrayRef result; + const void* keys[] = { + kSecReturnData, + kSecMatchLimit, + kSecClass, + kSecAttrCanVerify, + kSecMatchTrustedOnly, + }; + const void* values[] = { + kCFBooleanTrue, + kSecMatchLimitAll, + kSecClassCertificate, + kCFBooleanTrue, + trusted ? kCFBooleanTrue : kCFBooleanFalse, + }; + + if (cert == CERT_ANY || cert == CERT_X509) + { + query = CFDictionaryCreate(NULL, keys, values, countof(keys), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (query) + { + status = SecItemCopyMatching(query, (CFTypeRef*)&result); + CFRelease(query); + if (status == errSecSuccess) + { + INIT(enumerator, + .public = { + .enumerate = (void*)_enumerate_certs, + .destroy = _destroy_certs, + }, + .certs = result, + .id = id, + .type = key, + ); + return &enumerator->public; + } + } + } return enumerator_create_empty(); } From bc6c7bf39ea04a12dba2f892d47bc00ffd94706f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 30 Apr 2013 14:50:48 +0200 Subject: [PATCH 09/39] keychain: load certificates only once during startup, improving performance --- .../plugins/keychain/keychain_creds.c | 149 ++++++------------ .../plugins/keychain/keychain_creds.h | 5 - .../plugins/keychain/keychain_plugin.c | 35 +++- 3 files changed, 78 insertions(+), 111 deletions(-) diff --git a/src/libstrongswan/plugins/keychain/keychain_creds.c b/src/libstrongswan/plugins/keychain/keychain_creds.c index 08ef82614..76a1110fa 100644 --- a/src/libstrongswan/plugins/keychain/keychain_creds.c +++ b/src/libstrongswan/plugins/keychain/keychain_creds.c @@ -16,6 +16,7 @@ #include "keychain_creds.h" #include +#include #include @@ -30,87 +31,22 @@ struct private_keychain_creds_t { * Public keychain_creds_t interface. */ keychain_creds_t public; + + /** + * Active in-memory credential set + */ + mem_cred_t *set; }; /** - * Enumerator for certificates + * Create a credential set loaded with certificates */ -typedef struct { - /* implements enumerator_t */ - enumerator_t public; - /* currently enumerating certificate */ - certificate_t *current; - /* id to filter for */ - identification_t *id; - /* certificate public key type we are looking for */ - key_type_t type; - /* array of binary certificates to enumerate */ - CFArrayRef certs; - /* current position in array */ - int i; -} cert_enumerator_t; - -METHOD(enumerator_t, enumerate_certs, bool, - cert_enumerator_t *this, certificate_t **out) +static mem_cred_t* load_creds(private_keychain_creds_t *this) { - DESTROY_IF(this->current); - this->current = NULL; - - while (this->i < CFArrayGetCount(this->certs)) - { - certificate_t *cert; - public_key_t *key; - CFDataRef data; - chunk_t chunk; - - data = CFArrayGetValueAtIndex(this->certs, this->i++); - if (data) - { - chunk = chunk_create((char*)CFDataGetBytePtr(data), - CFDataGetLength(data)); - cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, chunk, BUILD_END); - if (cert) - { - if (!this->id || cert->has_subject(cert, this->id)) - { - key = cert->get_public_key(cert); - if (key) - { - if (this->type == KEY_ANY || - this->type == key->get_type(key)) - { - key->destroy(key); - this->current = cert; - *out = cert; - return TRUE; - } - key->destroy(key); - } - } - cert->destroy(cert); - } - } - } - return FALSE; -} - -METHOD(enumerator_t, destroy_certs, void, - cert_enumerator_t *this) -{ - DESTROY_IF(this->current); - CFRelease(this->certs); - free(this); -} - -METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, - private_keychain_creds_t *this, certificate_type_t cert, key_type_t key, - identification_t *id, bool trusted) -{ - cert_enumerator_t *enumerator; + mem_cred_t *set; OSStatus status; CFDictionaryRef query; - CFArrayRef result; + CFArrayRef certs; const void* keys[] = { kSecReturnData, kSecMatchLimit, @@ -123,39 +59,54 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, kSecMatchLimitAll, kSecClassCertificate, kCFBooleanTrue, - trusted ? kCFBooleanTrue : kCFBooleanFalse, + kCFBooleanTrue, }; + int i; - if (cert == CERT_ANY || cert == CERT_X509) + set = mem_cred_create(); + + DBG1(DBG_CFG, "loading System certificates:"); + query = CFDictionaryCreate(NULL, keys, values, countof(keys), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (query) { - query = CFDictionaryCreate(NULL, keys, values, countof(keys), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (query) + status = SecItemCopyMatching(query, (CFTypeRef*)&certs); + CFRelease(query); + if (status == errSecSuccess) { - status = SecItemCopyMatching(query, (CFTypeRef*)&result); - CFRelease(query); - if (status == errSecSuccess) + for (i = 0; i < CFArrayGetCount(certs); i++) { - INIT(enumerator, - .public = { - .enumerate = (void*)_enumerate_certs, - .destroy = _destroy_certs, - }, - .certs = result, - .id = id, - .type = key, - ); - return &enumerator->public; + certificate_t *cert; + CFDataRef data; + chunk_t chunk; + + data = CFArrayGetValueAtIndex(certs, i); + if (data) + { + chunk = chunk_create((char*)CFDataGetBytePtr(data), + CFDataGetLength(data)); + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, chunk, BUILD_END); + if (cert) + { + DBG1(DBG_CFG, " loaded '%Y'", cert->get_subject(cert)); + set->add_cert(set, TRUE, cert); + } + } } + CFRelease(certs); } } - return enumerator_create_empty(); + return set; } METHOD(keychain_creds_t, destroy, void, private_keychain_creds_t *this) { + lib->credmgr->remove_set(lib->credmgr, &this->set->set); + this->set->destroy(this->set); free(this); } @@ -168,16 +119,12 @@ keychain_creds_t *keychain_creds_create() INIT(this, .public = { - .set = { - .create_shared_enumerator = (void*)enumerator_create_empty, - .create_private_enumerator = (void*)enumerator_create_empty, - .create_cert_enumerator = _create_cert_enumerator, - .create_cdp_enumerator = (void*)enumerator_create_empty, - .cache_cert = (void*)nop, - }, .destroy = _destroy, }, ); + this->set = load_creds(this); + lib->credmgr->add_set(lib->credmgr, &this->set->set); + return &this->public; } diff --git a/src/libstrongswan/plugins/keychain/keychain_creds.h b/src/libstrongswan/plugins/keychain/keychain_creds.h index f2ca5d75c..64a2ededd 100644 --- a/src/libstrongswan/plugins/keychain/keychain_creds.h +++ b/src/libstrongswan/plugins/keychain/keychain_creds.h @@ -30,11 +30,6 @@ typedef struct keychain_creds_t keychain_creds_t; */ struct keychain_creds_t { - /** - * Implements credential_set_t. - */ - credential_set_t set; - /** * Destroy a keychain_creds_t. */ diff --git a/src/libstrongswan/plugins/keychain/keychain_plugin.c b/src/libstrongswan/plugins/keychain/keychain_plugin.c index 5ce7b16fb..6112afaa8 100644 --- a/src/libstrongswan/plugins/keychain/keychain_plugin.c +++ b/src/libstrongswan/plugins/keychain/keychain_plugin.c @@ -42,11 +42,38 @@ METHOD(plugin_t, get_name, char*, return "keychain"; } +/** + * Load/unload certificates from Keychain. + */ +static bool load_creds(private_keychain_plugin_t *this, + plugin_feature_t *feature, bool reg, void *data) +{ + if (reg) + { + this->creds = keychain_creds_create(); + } + else + { + this->creds->destroy(this->creds); + } + return TRUE; +} + +METHOD(plugin_t, get_features, int, + private_keychain_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK((plugin_feature_callback_t)load_creds, NULL), + PLUGIN_PROVIDE(CUSTOM, "keychain"), + PLUGIN_DEPENDS(CERT_DECODE, CERT_X509), + }; + *features = f; + return countof(f); +} + METHOD(plugin_t, destroy, void, private_keychain_plugin_t *this) { - lib->credmgr->remove_set(lib->credmgr, &this->creds->set); - this->creds->destroy(this->creds); free(this); } @@ -61,13 +88,11 @@ plugin_t *keychain_plugin_create() .public = { .plugin = { .get_name = _get_name, + .get_features = _get_features, .destroy = _destroy, }, }, - .creds = keychain_creds_create(), ); - lib->credmgr->add_set(lib->credmgr, &this->creds->set); - return &this->public.plugin; } From 0bdd453392d87dc96decd2e8ab80412b1a523f6d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 30 Apr 2013 15:33:42 +0200 Subject: [PATCH 10/39] keychain: load certificates from System Roots Keychain --- .../plugins/keychain/keychain_creds.c | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/libstrongswan/plugins/keychain/keychain_creds.c b/src/libstrongswan/plugins/keychain/keychain_creds.c index 76a1110fa..c667983b9 100644 --- a/src/libstrongswan/plugins/keychain/keychain_creds.c +++ b/src/libstrongswan/plugins/keychain/keychain_creds.c @@ -20,6 +20,11 @@ #include +/** + * System Root certificates keychain + */ +#define SYSTEM_ROOTS "/System/Library/Keychains/SystemRootCertificates.keychain" + typedef struct private_keychain_creds_t private_keychain_creds_t; /** @@ -36,8 +41,63 @@ struct private_keychain_creds_t { * Active in-memory credential set */ mem_cred_t *set; + + /** + * System roots credential set + */ + mem_cred_t *roots; }; +/** + * Load a credential set with System Root certificates + */ +static mem_cred_t* load_roots(private_keychain_creds_t *this) +{ + SecKeychainRef keychain; + SecKeychainSearchRef search; + SecKeychainItemRef item; + mem_cred_t *set; + OSStatus status; + + set = mem_cred_create(); + + DBG1(DBG_CFG, "loading System Roots certificates:"); + status = SecKeychainOpen(SYSTEM_ROOTS, &keychain); + if (status == errSecSuccess) + { + status = SecKeychainSearchCreateFromAttributes(keychain, + kSecCertificateItemClass, NULL, &search); + if (status == errSecSuccess) + { + while (SecKeychainSearchCopyNext(search, &item) == errSecSuccess) + { + certificate_t *cert; + UInt32 len; + void *data; + + if (SecKeychainItemCopyAttributesAndData(item, NULL, NULL, NULL, + &len, &data) == errSecSuccess) + { + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, chunk_create(data, len), + BUILD_END); + if (cert) + { + DBG1(DBG_CFG, " loaded '%Y'", cert->get_subject(cert)); + set->add_cert(set, TRUE, cert); + } + SecKeychainItemFreeAttributesAndData(NULL, data); + } + CFRelease(item); + } + CFRelease(search); + } + CFRelease(keychain); + } + return set; +} + /** * Create a credential set loaded with certificates */ @@ -106,7 +166,9 @@ METHOD(keychain_creds_t, destroy, void, private_keychain_creds_t *this) { lib->credmgr->remove_set(lib->credmgr, &this->set->set); + lib->credmgr->remove_set(lib->credmgr, &this->roots->set); this->set->destroy(this->set); + this->roots->destroy(this->roots); free(this); } @@ -123,7 +185,10 @@ keychain_creds_t *keychain_creds_create() }, ); + this->roots = load_roots(this); this->set = load_creds(this); + + lib->credmgr->add_set(lib->credmgr, &this->roots->set); lib->credmgr->add_set(lib->credmgr, &this->set->set); return &this->public; From dcd8bdde4f19646da0ca9a51a58eb140ade2f697 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 1 May 2013 10:37:49 +0200 Subject: [PATCH 11/39] keychain: use SearchCopyNext keychain enumeration for System certs as well SecItemCopyMatching seems to be problematic regarding memory management. And as there does not seem to be a good alternative to enumerate the System Roots keychain using the SecItemCopyMatching API, we stick to the deprecated enumeration functions for now. --- .../plugins/keychain/keychain_creds.c | 83 +++---------------- 1 file changed, 12 insertions(+), 71 deletions(-) diff --git a/src/libstrongswan/plugins/keychain/keychain_creds.c b/src/libstrongswan/plugins/keychain/keychain_creds.c index c667983b9..9182d2af0 100644 --- a/src/libstrongswan/plugins/keychain/keychain_creds.c +++ b/src/libstrongswan/plugins/keychain/keychain_creds.c @@ -21,10 +21,15 @@ #include /** - * System Root certificates keychain + * System Roots keychain */ #define SYSTEM_ROOTS "/System/Library/Keychains/SystemRootCertificates.keychain" +/** + * System keychain + */ +#define SYSTEM "/Library/Keychains/System.keychain" + typedef struct private_keychain_creds_t private_keychain_creds_t; /** @@ -49,9 +54,9 @@ struct private_keychain_creds_t { }; /** - * Load a credential set with System Root certificates + * Load a credential sets with certificates from a keychain path */ -static mem_cred_t* load_roots(private_keychain_creds_t *this) +static mem_cred_t* load_certs(private_keychain_creds_t *this, char *path) { SecKeychainRef keychain; SecKeychainSearchRef search; @@ -61,8 +66,8 @@ static mem_cred_t* load_roots(private_keychain_creds_t *this) set = mem_cred_create(); - DBG1(DBG_CFG, "loading System Roots certificates:"); - status = SecKeychainOpen(SYSTEM_ROOTS, &keychain); + DBG1(DBG_CFG, "loading certificates from %s:", path); + status = SecKeychainOpen(path, &keychain); if (status == errSecSuccess) { status = SecKeychainSearchCreateFromAttributes(keychain, @@ -98,70 +103,6 @@ static mem_cred_t* load_roots(private_keychain_creds_t *this) return set; } -/** - * Create a credential set loaded with certificates - */ -static mem_cred_t* load_creds(private_keychain_creds_t *this) -{ - mem_cred_t *set; - OSStatus status; - CFDictionaryRef query; - CFArrayRef certs; - const void* keys[] = { - kSecReturnData, - kSecMatchLimit, - kSecClass, - kSecAttrCanVerify, - kSecMatchTrustedOnly, - }; - const void* values[] = { - kCFBooleanTrue, - kSecMatchLimitAll, - kSecClassCertificate, - kCFBooleanTrue, - kCFBooleanTrue, - }; - int i; - - set = mem_cred_create(); - - DBG1(DBG_CFG, "loading System certificates:"); - query = CFDictionaryCreate(NULL, keys, values, countof(keys), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (query) - { - status = SecItemCopyMatching(query, (CFTypeRef*)&certs); - CFRelease(query); - if (status == errSecSuccess) - { - for (i = 0; i < CFArrayGetCount(certs); i++) - { - certificate_t *cert; - CFDataRef data; - chunk_t chunk; - - data = CFArrayGetValueAtIndex(certs, i); - if (data) - { - chunk = chunk_create((char*)CFDataGetBytePtr(data), - CFDataGetLength(data)); - cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, chunk, BUILD_END); - if (cert) - { - DBG1(DBG_CFG, " loaded '%Y'", cert->get_subject(cert)); - set->add_cert(set, TRUE, cert); - } - } - } - CFRelease(certs); - } - } - return set; -} - METHOD(keychain_creds_t, destroy, void, private_keychain_creds_t *this) { @@ -185,8 +126,8 @@ keychain_creds_t *keychain_creds_create() }, ); - this->roots = load_roots(this); - this->set = load_creds(this); + this->roots = load_certs(this, SYSTEM_ROOTS); + this->set = load_certs(this, SYSTEM); lib->credmgr->add_set(lib->credmgr, &this->roots->set); lib->credmgr->add_set(lib->credmgr, &this->set->set); From 57dce77ba618d86e715b177220067196720ad565 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 1 May 2013 10:38:46 +0200 Subject: [PATCH 12/39] keychain: monitor changes in the system keychain, reload when necessary --- .../plugins/keychain/keychain_creds.c | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/libstrongswan/plugins/keychain/keychain_creds.c b/src/libstrongswan/plugins/keychain/keychain_creds.c index 9182d2af0..546d3efe1 100644 --- a/src/libstrongswan/plugins/keychain/keychain_creds.c +++ b/src/libstrongswan/plugins/keychain/keychain_creds.c @@ -17,6 +17,7 @@ #include #include +#include #include @@ -51,6 +52,11 @@ struct private_keychain_creds_t { * System roots credential set */ mem_cred_t *roots; + + /** + * Run loop of event monitoring thread + */ + CFRunLoopRef loop; }; /** @@ -103,6 +109,61 @@ static mem_cred_t* load_certs(private_keychain_creds_t *this, char *path) return set; } +/** + * Callback function reloading keychain on changes + */ +static OSStatus keychain_cb(SecKeychainEvent keychainEvent, + SecKeychainCallbackInfo *info, + private_keychain_creds_t *this) +{ + mem_cred_t *new; + + DBG1(DBG_CFG, "received keychain event, reloading credentials"); + + /* register new before removing old */ + new = load_certs(this, SYSTEM); + lib->credmgr->add_set(lib->credmgr, &new->set); + lib->credmgr->remove_set(lib->credmgr, &this->set->set); + + this->set->destroy(this->set); + this->set = new; + + return errSecSuccess; +} + +/** + * Wait for changes in the keychain and handle them + */ +static job_requeue_t monitor_changes(private_keychain_creds_t *this) +{ + if (SecKeychainAddCallback((SecKeychainCallback)keychain_cb, + kSecAddEventMask | kSecDeleteEventMask | + kSecUpdateEventMask | kSecTrustSettingsChangedEventMask, + this) == errSecSuccess) + { + this->loop = CFRunLoopGetCurrent(); + + /* does not return until cancelled */ + CFRunLoopRun(); + + this->loop = NULL; + SecKeychainRemoveCallback((SecKeychainCallback)keychain_cb); + } + return JOB_REQUEUE_NONE; +} + +/** + * Cancel the monitoring thread in its RunLoop + */ +static bool cancel_monitor(private_keychain_creds_t *this) +{ + if (this->loop) + { + CFRunLoopStop(this->loop); + } + return TRUE; +} + METHOD(keychain_creds_t, destroy, void, private_keychain_creds_t *this) { @@ -132,5 +193,9 @@ keychain_creds_t *keychain_creds_create() lib->credmgr->add_set(lib->credmgr, &this->roots->set); lib->credmgr->add_set(lib->credmgr, &this->set->set); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((void*)monitor_changes, + this, NULL, (void*)cancel_monitor, JOB_PRIO_CRITICAL)); + return &this->public; } From 55dacbfac223c9a081ee0ac047bb83ac0c5d9c9b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 1 May 2013 11:14:16 +0200 Subject: [PATCH 13/39] keychain: flush certificate cache after reloading System keychain --- src/libstrongswan/plugins/keychain/keychain_creds.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstrongswan/plugins/keychain/keychain_creds.c b/src/libstrongswan/plugins/keychain/keychain_creds.c index 546d3efe1..ddcc7a461 100644 --- a/src/libstrongswan/plugins/keychain/keychain_creds.c +++ b/src/libstrongswan/plugins/keychain/keychain_creds.c @@ -125,6 +125,8 @@ static OSStatus keychain_cb(SecKeychainEvent keychainEvent, lib->credmgr->add_set(lib->credmgr, &new->set); lib->credmgr->remove_set(lib->credmgr, &this->set->set); + lib->credmgr->flush_cache(lib->credmgr, CERT_X509); + this->set->destroy(this->set); this->set = new; From 61177388bd12c1c7294b4a6c5b8607da37941d1d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 15 May 2013 10:36:08 +0200 Subject: [PATCH 14/39] syslog: setlogmask() to include LOG_INFO LOG_INFO seems to be excluded by default on some systems (OS X). --- src/libcharon/bus/listeners/sys_logger.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcharon/bus/listeners/sys_logger.c b/src/libcharon/bus/listeners/sys_logger.c index 82e2c8e4c..4aeb1c048 100644 --- a/src/libcharon/bus/listeners/sys_logger.c +++ b/src/libcharon/bus/listeners/sys_logger.c @@ -173,6 +173,7 @@ sys_logger_t *sys_logger_create(int facility) ); set_level(this, DBG_ANY, LEVEL_SILENT); + setlogmask(LOG_UPTO(LOG_INFO)); return &this->public; } From 6f8c626b8153afcaf66c5d0e0470931a14f5bb31 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 24 Apr 2013 10:38:19 +0200 Subject: [PATCH 15/39] xpc: add Xcode project for a charon controlled through XPC --- src/frontends/osx/.gitignore | 2 + src/frontends/osx/README.md | 40 +++ .../osx/charon-xpc/charon-xpc-Info.plist | 18 + .../osx/charon-xpc/charon-xpc-Launchd.plist | 13 + src/frontends/osx/charon-xpc/charon-xpc.c | 203 ++++++++++++ .../osx/strongSwan.xcodeproj/project.pbxproj | 308 ++++++++++++++++++ 6 files changed, 584 insertions(+) create mode 100644 src/frontends/osx/.gitignore create mode 100644 src/frontends/osx/README.md create mode 100644 src/frontends/osx/charon-xpc/charon-xpc-Info.plist create mode 100644 src/frontends/osx/charon-xpc/charon-xpc-Launchd.plist create mode 100644 src/frontends/osx/charon-xpc/charon-xpc.c create mode 100644 src/frontends/osx/strongSwan.xcodeproj/project.pbxproj diff --git a/src/frontends/osx/.gitignore b/src/frontends/osx/.gitignore new file mode 100644 index 000000000..f4be87183 --- /dev/null +++ b/src/frontends/osx/.gitignore @@ -0,0 +1,2 @@ +xcuserdata +*.xcworkspace diff --git a/src/frontends/osx/README.md b/src/frontends/osx/README.md new file mode 100644 index 000000000..69ee460a1 --- /dev/null +++ b/src/frontends/osx/README.md @@ -0,0 +1,40 @@ +# strongSwan OS X App # + +## Introduction ## + +The strongSwan OS X App consists of two components: + +* A frontend to configure and control connections +* A privileged helper daemon, controlled using XPC, called charon-xpc + +The privileged helper daemon gets installed automatically using SMJobBless +functionality on its first use, and gets started automatically by Launchd when +needed. + +charon-xpc is a special build linking statically against strongSwan components. + +## Building strongSwan ## + +strongSwan on OS X requires the libvstr library. The simplest way to install +it is using MacPorts. It gets statically linked to charon-xpc, hence it is not +needed to run the built App. + +Before building the Xcode project, the strongSwan base tree must be built using +a monolithic and static build. This can be achieved on OS X by using: + +LDFLAGS="-all_load" \ +CFLAGS="-I/usr/include -DOPENSSL_NO_CMS -O2 -Wall -Wno-format -Wno-pointer-sign" \ +./configure --prefix=/opt/local --disable-defaults --enable-openssl \ + --enable-kernel-pfkey --enable-kernel-pfroute --enable-eap-mschapv2 \ + --enable-eap-identity --enable-monolithic --enable-nonce --enable-random \ + --enable-pkcs1 --enable-pem --enable-socket-default --enable-xauth-generic \ + --enable-ikev1 --enable-ikev2 --enable-charon --disable-shared --enable-static + +followed by calling make (no need to make install). + +Building charon-xpc using the Xcode project yields a single binary without +any non OS X dependencies. + +Both charon-xpc and the App must be code-signed to allow the installation of +the privileged helper. git-grep for "Joe Developer" to change the signing +identity. \ No newline at end of file diff --git a/src/frontends/osx/charon-xpc/charon-xpc-Info.plist b/src/frontends/osx/charon-xpc/charon-xpc-Info.plist new file mode 100644 index 000000000..e8ddd24b0 --- /dev/null +++ b/src/frontends/osx/charon-xpc/charon-xpc-Info.plist @@ -0,0 +1,18 @@ + + + + + CFBundleIdentifier + org.strongswan.charon-xpc + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + charon-xpc + CFBundleVersion + 1.0 + SMAuthorizedClients + + identifier org.strongswan.osx and certificate leaf[subject.CN] = "Joe Developer" + + + diff --git a/src/frontends/osx/charon-xpc/charon-xpc-Launchd.plist b/src/frontends/osx/charon-xpc/charon-xpc-Launchd.plist new file mode 100644 index 000000000..703fab912 --- /dev/null +++ b/src/frontends/osx/charon-xpc/charon-xpc-Launchd.plist @@ -0,0 +1,13 @@ + + + + + Label + org.strongswan.charon-xpc + MachServices + + org.strongswan.charon-xpc + + + + diff --git a/src/frontends/osx/charon-xpc/charon-xpc.c b/src/frontends/osx/charon-xpc/charon-xpc.c new file mode 100644 index 000000000..19142d894 --- /dev/null +++ b/src/frontends/osx/charon-xpc/charon-xpc.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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 +#include +#include +#include +#include + +#include +#include +#include + +/** + * Loglevel configuration + */ +static level_t levels[DBG_MAX]; + +/** + * hook in library for debugging messages + */ +extern void (*dbg) (debug_t group, level_t level, char *fmt, ...); + +/** + * Logging hook for library logs, using stderr output + */ +static void dbg_stderr(debug_t group, level_t level, char *fmt, ...) +{ + va_list args; + + if (level <= 1) + { + va_start(args, fmt); + fprintf(stderr, "00[%N] ", debug_names, group); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); + } +} + +/** + * Return version of this helper + */ +xpc_object_t get_version(xpc_object_t request, xpc_connection_t client) +{ + xpc_object_t reply; + + reply = xpc_dictionary_create_reply(request); + xpc_dictionary_set_string(reply, "version", PACKAGE_VERSION); + + return reply; +} + +/** + * XPC command dispatch table + */ +struct { + char *name; + xpc_object_t (*handler)(xpc_object_t request, xpc_connection_t client); +} commands[] = { + { "get_version", get_version }, +}; + +/** + * Handle a received XPC request message + */ +static void handle(xpc_object_t request) +{ + xpc_connection_t client; + xpc_object_t reply; + const char *command; + int i; + + client = xpc_dictionary_get_remote_connection(request); + command = xpc_dictionary_get_string(request, "command"); + if (command) + { + for (i = 0; i < countof(commands); i++) + { + if (streq(commands[i].name, command)) + { + reply = commands[i].handler(request, client); + if (reply) + { + xpc_connection_send_message(client, reply); + xpc_release(reply); + } + break; + } + } + } +} + +/** + * Dispatch XPC commands + */ +static int dispatch() +{ + xpc_connection_t service; + + service = xpc_connection_create_mach_service("org.strongswan.charon-xpc", + NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER); + if (!service) + { + return EXIT_FAILURE; + } + + xpc_connection_set_event_handler(service, ^(xpc_object_t conn) { + + xpc_connection_set_event_handler(conn, ^(xpc_object_t event) { + + if (xpc_get_type(event) == XPC_TYPE_ERROR) + { + if (event == XPC_ERROR_CONNECTION_INVALID || + event == XPC_ERROR_TERMINATION_IMMINENT) + { + xpc_connection_cancel(conn); + } + } + else + { + handle(event); + } + }); + xpc_connection_resume(conn); + }); + + xpc_connection_resume(service); + + dispatch_main(); + + xpc_release(service); +} + +/** + * Main function, starts the daemon. + */ +int main(int argc, char *argv[]) +{ + struct utsname utsname; + int group; + + dbg = dbg_stderr; + atexit(library_deinit); + if (!library_init(NULL)) + { + exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); + } + if (lib->integrity) + { + if (!lib->integrity->check_file(lib->integrity, "charon-xpc", argv[0])) + { + exit(SS_RC_DAEMON_INTEGRITY); + } + } + atexit(libhydra_deinit); + if (!libhydra_init("charon-xpc")) + { + exit(SS_RC_INITIALIZATION_FAILED); + } + atexit(libcharon_deinit); + if (!libcharon_init("charon-xpc")) + { + exit(SS_RC_INITIALIZATION_FAILED); + } + for (group = 0; group < DBG_MAX; group++) + { + levels[group] = LEVEL_CTRL; + } + charon->load_loggers(charon, levels, TRUE); + + lib->settings->set_default_str(lib->settings, "charon-cmd.port", "0"); + lib->settings->set_default_str(lib->settings, "charon-cmd.port_nat_t", "0"); + if (!charon->initialize(charon, + lib->settings->get_str(lib->settings, "charon-xpc.load", + "random nonce pem pkcs1 openssl kernel-pfkey kernel-pfroute " + "socket-default eap-identity eap-mschapv2"))) + { + exit(SS_RC_INITIALIZATION_FAILED); + } + + if (uname(&utsname) != 0) + { + memset(&utsname, 0, sizeof(utsname)); + } + DBG1(DBG_DMN, "Starting charon-xpc IKE daemon (strongSwan %s, %s %s, %s)", + VERSION, utsname.sysname, utsname.release, utsname.machine); + + charon->start(charon); + return dispatch(); +} diff --git a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj new file mode 100644 index 000000000..eedc804e5 --- /dev/null +++ b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj @@ -0,0 +1,308 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5BD1CCD71726DB4000587077 /* charon-xpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 5BD1CCD61726DB4000587077 /* charon-xpc.c */; }; + 5BF60F31173405A000E5D608 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */; }; + 5BF60F33173405AC00E5D608 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCF21727DE3E00587077 /* Security.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5BD1CCD11726DB4000587077 /* org.strongswan.charon-xpc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.objfile"; includeInIndex = 0; path = "org.strongswan.charon-xpc"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 5BD1CCD61726DB4000587077 /* charon-xpc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "charon-xpc.c"; sourceTree = ""; }; + 5BD1CCE01726DCD000587077 /* charon-xpc-Launchd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "charon-xpc-Launchd.plist"; sourceTree = ""; }; + 5BD1CCE11726DD9900587077 /* charon-xpc-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "charon-xpc-Info.plist"; sourceTree = ""; }; + 5BD1CCEA1727CCA400587077 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = ""; }; + 5BD1CCEC1727D7AF00587077 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; }; + 5BD1CCF21727DE3E00587077 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5BD1CCCE1726DB4000587077 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5BF60F31173405A000E5D608 /* CoreFoundation.framework in Frameworks */, + 5BF60F33173405AC00E5D608 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5BD1CCA11726DB0100587077 = { + isa = PBXGroup; + children = ( + 5BD1CCEA1727CCA400587077 /* README.md */, + 5BD1CCD51726DB4000587077 /* charon-xpc */, + 5BD1CCAF1726DB0100587077 /* Frameworks */, + 5BD1CCAD1726DB0100587077 /* Products */, + ); + sourceTree = ""; + }; + 5BD1CCAD1726DB0100587077 /* Products */ = { + isa = PBXGroup; + children = ( + 5BD1CCD11726DB4000587077 /* org.strongswan.charon-xpc */, + ); + name = Products; + sourceTree = ""; + }; + 5BD1CCAF1726DB0100587077 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5BD1CCF21727DE3E00587077 /* Security.framework */, + 5BD1CCEC1727D7AF00587077 /* ServiceManagement.framework */, + 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 5BD1CCD51726DB4000587077 /* charon-xpc */ = { + isa = PBXGroup; + children = ( + 5BD1CCD61726DB4000587077 /* charon-xpc.c */, + 5BD1CCE01726DCD000587077 /* charon-xpc-Launchd.plist */, + 5BD1CCE11726DD9900587077 /* charon-xpc-Info.plist */, + ); + path = "charon-xpc"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5BD1CCD01726DB4000587077 /* charon-xpc */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5BD1CCDA1726DB4000587077 /* Build configuration list for PBXNativeTarget "charon-xpc" */; + buildPhases = ( + 5BD1CCCD1726DB4000587077 /* Sources */, + 5BD1CCCE1726DB4000587077 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "charon-xpc"; + productName = "charon-xpc"; + productReference = 5BD1CCD11726DB4000587077 /* org.strongswan.charon-xpc */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5BD1CCA31726DB0100587077 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0450; + ORGANIZATIONNAME = "revosec AG"; + }; + buildConfigurationList = 5BD1CCA61726DB0100587077 /* Build configuration list for PBXProject "strongSwan" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 5BD1CCA11726DB0100587077; + productRefGroup = 5BD1CCAD1726DB0100587077 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5BD1CCD01726DB4000587077 /* charon-xpc */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 5BD1CCCD1726DB4000587077 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5BD1CCD71726DB4000587077 /* charon-xpc.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5BD1CCC81726DB0200587077 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.8; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 5BD1CCC91726DB0200587077 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.8; + SDKROOT = macosx; + }; + name = Release; + }; + 5BD1CCDB1726DB4000587077 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Joe Developer"; + GCC_WARN_64_TO_32_BIT_CONVERSION = NO; + HEADER_SEARCH_PATHS = ( + /usr/include, + ../../libstrongswan, + ../../libcharon, + ../../libhydra, + /opt/local/include, + ); + INFOPLIST_FILE = "charon-xpc/charon-xpc-Info.plist"; + INSTALL_PATH = /; + LIBRARY_SEARCH_PATHS = ( + /usr/lib, + ../../libstrongswan/.libs, + ../../libcharon/.libs, + ../../libhydra/.libs, + /opt/local/lib, + ); + OTHER_CFLAGS = ( + "-include", + ../../../config.h, + ); + OTHER_LDFLAGS = ( + "-lcrypto", + /opt/local/lib/libvstr.a, + "-force_load", + ../../libstrongswan/.libs/libstrongswan.a, + "-force_load", + ../../libhydra/.libs/libhydra.a, + "-force_load", + ../../libcharon/.libs/libcharon.a, + "-sectcreate", + __TEXT, + __info_plist, + "charon-xpc/charon-xpc-Info.plist", + "-sectcreate", + __TEXT, + __launchd_plist, + "charon-xpc/charon-xpc-Launchd.plist", + ); + PRODUCT_NAME = "org.strongswan.charon-xpc"; + PROVISIONING_PROFILE = ""; + STRIP_STYLE = "non-global"; + }; + name = Debug; + }; + 5BD1CCDC1726DB4000587077 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Joe Developer"; + COPY_PHASE_STRIP = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = NO; + HEADER_SEARCH_PATHS = ( + /usr/include, + ../../libstrongswan, + ../../libcharon, + ../../libhydra, + /opt/local/include, + ); + INFOPLIST_FILE = "charon-xpc/charon-xpc-Info.plist"; + INSTALL_PATH = /; + LIBRARY_SEARCH_PATHS = ( + /usr/lib, + ../../libstrongswan/.libs, + ../../libcharon/.libs, + ../../libhydra/.libs, + /opt/local/lib, + ); + OTHER_CFLAGS = ( + "-include", + ../../../config.h, + ); + OTHER_LDFLAGS = ( + "-lcrypto", + /opt/local/lib/libvstr.a, + "-force_load", + ../../libstrongswan/.libs/libstrongswan.a, + "-force_load", + ../../libhydra/.libs/libhydra.a, + "-force_load", + ../../libcharon/.libs/libcharon.a, + "-sectcreate", + __TEXT, + __info_plist, + "charon-xpc/charon-xpc-Info.plist", + "-sectcreate", + __TEXT, + __launchd_plist, + "charon-xpc/charon-xpc-Launchd.plist", + ); + PRODUCT_NAME = "org.strongswan.charon-xpc"; + PROVISIONING_PROFILE = ""; + STRIP_STYLE = "non-global"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5BD1CCA61726DB0100587077 /* Build configuration list for PBXProject "strongSwan" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5BD1CCC81726DB0200587077 /* Debug */, + 5BD1CCC91726DB0200587077 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5BD1CCDA1726DB4000587077 /* Build configuration list for PBXNativeTarget "charon-xpc" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5BD1CCDB1726DB4000587077 /* Debug */, + 5BD1CCDC1726DB4000587077 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5BD1CCA31726DB0100587077 /* Project object */; +} From 4204d1d71a9495f57acc37aeeb913fdd5828408f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 26 Apr 2013 14:32:32 +0200 Subject: [PATCH 16/39] xpc: use non-inlining variant of vstr, compiler does not like it --- src/frontends/osx/strongSwan.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj index eedc804e5..88ee1fb49 100644 --- a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj +++ b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj @@ -206,6 +206,7 @@ OTHER_CFLAGS = ( "-include", ../../../config.h, + "-DVSTR_COMPILE_INLINE=0", ); OTHER_LDFLAGS = ( "-lcrypto", @@ -256,6 +257,7 @@ OTHER_CFLAGS = ( "-include", ../../../config.h, + "-DVSTR_COMPILE_INLINE=0", ); OTHER_LDFLAGS = ( "-lcrypto", From 3dcc9d7aa72d391dc73d79d48ef1279c7228a85c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 3 May 2013 16:24:05 +0200 Subject: [PATCH 17/39] xpc: move dispatching to dedicated class, using dedicated thread --- src/frontends/osx/charon-xpc/charon-xpc.c | 172 +++++++++--------- src/frontends/osx/charon-xpc/xpc_dispatch.c | 168 +++++++++++++++++ src/frontends/osx/charon-xpc/xpc_dispatch.h | 42 +++++ .../osx/strongSwan.xcodeproj/project.pbxproj | 6 + 4 files changed, 303 insertions(+), 85 deletions(-) create mode 100644 src/frontends/osx/charon-xpc/xpc_dispatch.c create mode 100644 src/frontends/osx/charon-xpc/xpc_dispatch.h diff --git a/src/frontends/osx/charon-xpc/charon-xpc.c b/src/frontends/osx/charon-xpc/charon-xpc.c index 19142d894..477e1e0c4 100644 --- a/src/frontends/osx/charon-xpc/charon-xpc.c +++ b/src/frontends/osx/charon-xpc/charon-xpc.c @@ -17,11 +17,29 @@ #include #include #include -#include +#include +#include #include #include #include +#include +#include + +#include "xpc_dispatch.h" + +/** + * XPC dispatcher class + */ +static xpc_dispatch_t *dispatcher; + +/** + * atexit() cleanup for dispatcher + */ +void dispatcher_cleanup() +{ + DESTROY_IF(dispatcher); +} /** * Loglevel configuration @@ -51,97 +69,57 @@ static void dbg_stderr(debug_t group, level_t level, char *fmt, ...) } /** - * Return version of this helper + * Run the daemon and handle unix signals */ -xpc_object_t get_version(xpc_object_t request, xpc_connection_t client) +static int run() { - xpc_object_t reply; + sigset_t set; - reply = xpc_dictionary_create_reply(request); - xpc_dictionary_set_string(reply, "version", PACKAGE_VERSION); + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + sigprocmask(SIG_BLOCK, &set, NULL); - return reply; + while (TRUE) + { + int sig; + + if (sigwait(&set, &sig)) + { + DBG1(DBG_DMN, "error while waiting for a signal"); + return 1; + } + switch (sig) + { + case SIGINT: + DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down"); + charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); + return 0; + case SIGTERM: + DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down"); + charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); + return 0; + default: + DBG1(DBG_DMN, "unknown signal %d received. Ignored", sig); + break; + } + } } /** - * XPC command dispatch table + * Handle SIGSEGV/SIGILL signals raised by threads */ -struct { - char *name; - xpc_object_t (*handler)(xpc_object_t request, xpc_connection_t client); -} commands[] = { - { "get_version", get_version }, -}; - -/** - * Handle a received XPC request message - */ -static void handle(xpc_object_t request) +static void segv_handler(int signal) { - xpc_connection_t client; - xpc_object_t reply; - const char *command; - int i; + backtrace_t *backtrace; - client = xpc_dictionary_get_remote_connection(request); - command = xpc_dictionary_get_string(request, "command"); - if (command) - { - for (i = 0; i < countof(commands); i++) - { - if (streq(commands[i].name, command)) - { - reply = commands[i].handler(request, client); - if (reply) - { - xpc_connection_send_message(client, reply); - xpc_release(reply); - } - break; - } - } - } -} + DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal); + backtrace = backtrace_create(2); + backtrace->log(backtrace, NULL, TRUE); + backtrace->destroy(backtrace); -/** - * Dispatch XPC commands - */ -static int dispatch() -{ - xpc_connection_t service; - - service = xpc_connection_create_mach_service("org.strongswan.charon-xpc", - NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER); - if (!service) - { - return EXIT_FAILURE; - } - - xpc_connection_set_event_handler(service, ^(xpc_object_t conn) { - - xpc_connection_set_event_handler(conn, ^(xpc_object_t event) { - - if (xpc_get_type(event) == XPC_TYPE_ERROR) - { - if (event == XPC_ERROR_CONNECTION_INVALID || - event == XPC_ERROR_TERMINATION_IMMINENT) - { - xpc_connection_cancel(conn); - } - } - else - { - handle(event); - } - }); - xpc_connection_resume(conn); - }); - - xpc_connection_resume(service); - - dispatch_main(); - - xpc_release(service); + DBG1(DBG_DMN, "killing ourself, received critical signal"); + abort(); } /** @@ -149,6 +127,7 @@ static int dispatch() */ int main(int argc, char *argv[]) { + struct sigaction action; struct utsname utsname; int group; @@ -184,9 +163,9 @@ int main(int argc, char *argv[]) lib->settings->set_default_str(lib->settings, "charon-cmd.port", "0"); lib->settings->set_default_str(lib->settings, "charon-cmd.port_nat_t", "0"); if (!charon->initialize(charon, - lib->settings->get_str(lib->settings, "charon-xpc.load", - "random nonce pem pkcs1 openssl kernel-pfkey kernel-pfroute " - "socket-default eap-identity eap-mschapv2"))) + lib->settings->get_str(lib->settings, "charon-xpc.load", + "random nonce pem pkcs1 openssl kernel-pfkey kernel-pfroute " + "socket-default eap-identity eap-mschapv2"))) { exit(SS_RC_INITIALIZATION_FAILED); } @@ -198,6 +177,29 @@ int main(int argc, char *argv[]) DBG1(DBG_DMN, "Starting charon-xpc IKE daemon (strongSwan %s, %s %s, %s)", VERSION, utsname.sysname, utsname.release, utsname.machine); + /* add handler for SEGV and ILL, + * INT, TERM and HUP are handled by sigwait() in run() */ + action.sa_handler = segv_handler; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaddset(&action.sa_mask, SIGINT); + sigaddset(&action.sa_mask, SIGTERM); + sigaddset(&action.sa_mask, SIGHUP); + sigaction(SIGSEGV, &action, NULL); + sigaction(SIGILL, &action, NULL); + sigaction(SIGBUS, &action, NULL); + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); + + pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL); + + dispatcher = xpc_dispatch_create(); + if (!dispatcher) + { + exit(SS_RC_INITIALIZATION_FAILED); + } + atexit(dispatcher_cleanup); + charon->start(charon); - return dispatch(); + return run(); } diff --git a/src/frontends/osx/charon-xpc/xpc_dispatch.c b/src/frontends/osx/charon-xpc/xpc_dispatch.c new file mode 100644 index 000000000..3ade31060 --- /dev/null +++ b/src/frontends/osx/charon-xpc/xpc_dispatch.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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 "xpc_dispatch.h" + +#include + +#include +#include + +typedef struct private_xpc_dispatch_t private_xpc_dispatch_t; + +/** + * Private data of an xpc_dispatch_t object. + */ +struct private_xpc_dispatch_t { + + /** + * Public xpc_dispatch_t interface. + */ + xpc_dispatch_t public; + + /** + * XPC service we offer + */ + xpc_connection_t service; + + /** + * GCD queue for XPC events + */ + dispatch_queue_t queue; +}; + +/** + * Return version of this helper + */ +static xpc_object_t get_version(private_xpc_dispatch_t *this, + xpc_object_t request, xpc_connection_t client) +{ + xpc_object_t reply; + + reply = xpc_dictionary_create_reply(request); + xpc_dictionary_set_string(reply, "version", PACKAGE_VERSION); + + return reply; +} + +/** + * XPC command dispatch table + */ +static struct { + char *name; + xpc_object_t (*handler)(private_xpc_dispatch_t *this, + xpc_object_t request, xpc_connection_t client); +} commands[] = { + { "get_version", get_version }, +}; + +/** + * Handle a received XPC request message + */ +static void handle(private_xpc_dispatch_t *this, xpc_object_t request) +{ + xpc_connection_t client; + xpc_object_t reply; + const char *command; + int i; + + client = xpc_dictionary_get_remote_connection(request); + command = xpc_dictionary_get_string(request, "command"); + if (command) + { + for (i = 0; i < countof(commands); i++) + { + if (streq(commands[i].name, command)) + { + reply = commands[i].handler(this, request, client); + if (reply) + { + xpc_connection_send_message(client, reply); + xpc_release(reply); + } + break; + } + } + } +} + +/** + * Set up GCD handler for XPC events + */ +static void set_handler(private_xpc_dispatch_t *this) +{ + xpc_connection_set_event_handler(this->service, ^(xpc_object_t conn) { + + xpc_connection_set_event_handler(conn, ^(xpc_object_t event) { + + if (xpc_get_type(event) == XPC_TYPE_ERROR) + { + if (event == XPC_ERROR_CONNECTION_INVALID || + event == XPC_ERROR_TERMINATION_IMMINENT) + { + xpc_connection_cancel(conn); + } + } + else + { + handle(this, event); + } + }); + + xpc_connection_resume(conn); + }); + + xpc_connection_resume(this->service); +} + +METHOD(xpc_dispatch_t, destroy, void, + private_xpc_dispatch_t *this) +{ + if (this->service) + { + xpc_connection_suspend(this->service); + xpc_connection_cancel(this->service); + } + free(this); +} + +/** + * See header + */ +xpc_dispatch_t *xpc_dispatch_create() +{ + private_xpc_dispatch_t *this; + + INIT(this, + .public = { + .destroy = _destroy, + }, + .queue = dispatch_queue_create("org.strongswan.charon-xpc.q", + DISPATCH_QUEUE_CONCURRENT), + ); + + this->service = xpc_connection_create_mach_service( + "org.strongswan.charon-xpc", this->queue, + XPC_CONNECTION_MACH_SERVICE_LISTENER); + if (!this->service) + { + destroy(this); + return NULL; + } + + set_handler(this); + + return &this->public; +} diff --git a/src/frontends/osx/charon-xpc/xpc_dispatch.h b/src/frontends/osx/charon-xpc/xpc_dispatch.h new file mode 100644 index 000000000..9f40e6027 --- /dev/null +++ b/src/frontends/osx/charon-xpc/xpc_dispatch.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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 xpc_dispatch xpc_dispatch + * @{ @ingroup xpc + */ + +#ifndef XPC_DISPATCH_H_ +#define XPC_DISPATCH_H_ + +typedef struct xpc_dispatch_t xpc_dispatch_t; + +/** + * XPC dispatcher to control the daemon. + */ +struct xpc_dispatch_t { + + /** + * Destroy a xpc_dispatch_t. + */ + void (*destroy)(xpc_dispatch_t *this); +}; + +/** + * Create a xpc_dispatch instance. + */ +xpc_dispatch_t *xpc_dispatch_create(); + +#endif /** XPC_DISPATCH_H_ @}*/ diff --git a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj index 88ee1fb49..8cf467a1e 100644 --- a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj +++ b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj @@ -10,9 +10,12 @@ 5BD1CCD71726DB4000587077 /* charon-xpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 5BD1CCD61726DB4000587077 /* charon-xpc.c */; }; 5BF60F31173405A000E5D608 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */; }; 5BF60F33173405AC00E5D608 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCF21727DE3E00587077 /* Security.framework */; }; + 5BF60F38173405F100E5D608 /* xpc_dispatch.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B74984C172AA3550041971E /* xpc_dispatch.c */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 5B74984C172AA3550041971E /* xpc_dispatch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpc_dispatch.c; sourceTree = ""; }; + 5B74984E172AA3670041971E /* xpc_dispatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_dispatch.h; sourceTree = ""; }; 5BD1CCD11726DB4000587077 /* org.strongswan.charon-xpc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.objfile"; includeInIndex = 0; path = "org.strongswan.charon-xpc"; sourceTree = BUILT_PRODUCTS_DIR; }; 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 5BD1CCD61726DB4000587077 /* charon-xpc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "charon-xpc.c"; sourceTree = ""; }; @@ -70,6 +73,8 @@ 5BD1CCD61726DB4000587077 /* charon-xpc.c */, 5BD1CCE01726DCD000587077 /* charon-xpc-Launchd.plist */, 5BD1CCE11726DD9900587077 /* charon-xpc-Info.plist */, + 5B74984C172AA3550041971E /* xpc_dispatch.c */, + 5B74984E172AA3670041971E /* xpc_dispatch.h */, ); path = "charon-xpc"; sourceTree = ""; @@ -125,6 +130,7 @@ buildActionMask = 2147483647; files = ( 5BD1CCD71726DB4000587077 /* charon-xpc.c in Sources */, + 5BF60F38173405F100E5D608 /* xpc_dispatch.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From e73a653451efb25ec172af95c8db69ac641d2f6c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 26 Apr 2013 15:17:36 +0200 Subject: [PATCH 18/39] xpc: add support for initiate simple IKEv2 EAP connections --- src/frontends/osx/charon-xpc/xpc_dispatch.c | 126 ++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/src/frontends/osx/charon-xpc/xpc_dispatch.c b/src/frontends/osx/charon-xpc/xpc_dispatch.c index 3ade31060..f9f488118 100644 --- a/src/frontends/osx/charon-xpc/xpc_dispatch.c +++ b/src/frontends/osx/charon-xpc/xpc_dispatch.c @@ -57,6 +57,131 @@ static xpc_object_t get_version(private_xpc_dispatch_t *this, return reply; } +/** + * Create peer config with associated ike config + */ +static peer_cfg_t* create_peer_cfg(char *name, char *host) +{ + ike_cfg_t *ike_cfg; + peer_cfg_t *peer_cfg; + u_int16_t local_port, remote_port = IKEV2_UDP_PORT; + + local_port = charon->socket->get_port(charon->socket, FALSE); + if (local_port != IKEV2_UDP_PORT) + { + remote_port = IKEV2_NATT_PORT; + } + ike_cfg = ike_cfg_create(IKEV2, TRUE, FALSE, "0.0.0.0", FALSE, local_port, + host, FALSE, remote_port, FRAGMENTATION_NO, 0); + ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); + peer_cfg = peer_cfg_create(name, ike_cfg, + CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ + 36000, 0, /* rekey 10h, reauth none */ + 600, 600, /* jitter, over 10min */ + TRUE, FALSE, /* mobike, aggressive */ + 30, 0, /* DPD delay, timeout */ + FALSE, NULL, NULL); /* mediation */ + peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); + + return peer_cfg; +} + +/** + * Add a single auth cfg of given class to peer cfg + */ +static void add_auth_cfg(peer_cfg_t *peer_cfg, bool local, + char *id, auth_class_t class) +{ + auth_cfg_t *auth; + + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, class); + auth->add(auth, AUTH_RULE_IDENTITY, identification_create_from_string(id)); + peer_cfg->add_auth_cfg(peer_cfg, auth, local); +} + +/** + * Attach child config to peer config + */ +static child_cfg_t* create_child_cfg(char *name) +{ + child_cfg_t *child_cfg; + traffic_selector_t *ts; + lifetime_cfg_t lifetime = { + .time = { + .life = 10800 /* 3h */, + .rekey = 10200 /* 2h50min */, + .jitter = 300 /* 5min */ + } + }; + + child_cfg = child_cfg_create(name, &lifetime, + NULL, FALSE, MODE_TUNNEL, /* updown, hostaccess */ + ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE, + 0, 0, NULL, NULL, 0); + child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + ts = traffic_selector_create_dynamic(0, 0, 65535); + child_cfg->add_traffic_selector(child_cfg, TRUE, ts); + ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, + "0.0.0.0", 0, "255.255.255.255", 65535); + child_cfg->add_traffic_selector(child_cfg, FALSE, ts); + + return child_cfg; +} + +/** + * Controller initiate callback + */ +static bool initiate_cb(u_int32_t *sa, debug_t group, level_t level, + ike_sa_t *ike_sa, const char *message) +{ + if (ike_sa) + { + *sa = ike_sa->get_unique_id(ike_sa); + return FALSE; + } + return TRUE; +} + +/** + * Start initiating an IKE connection + */ +xpc_object_t start_connection(private_xpc_dispatch_t *this, + xpc_object_t request, xpc_connection_t client) +{ + xpc_object_t reply; + peer_cfg_t *peer_cfg; + child_cfg_t *child_cfg; + char *name, *id, *host; + u_int32_t sa = 0; + + name = (char*)xpc_dictionary_get_string(request, "name"); + host = (char*)xpc_dictionary_get_string(request, "host"); + id = (char*)xpc_dictionary_get_string(request, "id"); + reply = xpc_dictionary_create_reply(request); + + if (name && id && host) + { + peer_cfg = create_peer_cfg(name, host); + + add_auth_cfg(peer_cfg, TRUE, id, AUTH_CLASS_EAP); + add_auth_cfg(peer_cfg, FALSE, host, AUTH_CLASS_ANY); + + child_cfg = create_child_cfg(name); + peer_cfg->add_child_cfg(peer_cfg, child_cfg->get_ref(child_cfg)); + + if (charon->controller->initiate(charon->controller, peer_cfg, child_cfg, + (controller_cb_t)initiate_cb, &sa, 0) != SUCCESS) + { + sa = 0; + } + } + + xpc_dictionary_set_uint64(reply, "connection", sa); + + return reply; +} + /** * XPC command dispatch table */ @@ -66,6 +191,7 @@ static struct { xpc_object_t request, xpc_connection_t client); } commands[] = { { "get_version", get_version }, + { "start_connection", start_connection }, }; /** From 501637039088ccc005153b3074b42b98461573bd Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 3 May 2013 16:51:29 +0200 Subject: [PATCH 19/39] xpc: build with support for the keychain plugin --- src/frontends/osx/README.md | 3 ++- src/frontends/osx/charon-xpc/charon-xpc.c | 2 +- src/frontends/osx/strongSwan.xcodeproj/project.pbxproj | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/frontends/osx/README.md b/src/frontends/osx/README.md index 69ee460a1..62a0b2e0d 100644 --- a/src/frontends/osx/README.md +++ b/src/frontends/osx/README.md @@ -28,7 +28,8 @@ CFLAGS="-I/usr/include -DOPENSSL_NO_CMS -O2 -Wall -Wno-format -Wno-pointer-sign" --enable-kernel-pfkey --enable-kernel-pfroute --enable-eap-mschapv2 \ --enable-eap-identity --enable-monolithic --enable-nonce --enable-random \ --enable-pkcs1 --enable-pem --enable-socket-default --enable-xauth-generic \ - --enable-ikev1 --enable-ikev2 --enable-charon --disable-shared --enable-static + --enable-keychain --enable-ikev1 --enable-ikev2 --enable-charon \ + --disable-shared --enable-static followed by calling make (no need to make install). diff --git a/src/frontends/osx/charon-xpc/charon-xpc.c b/src/frontends/osx/charon-xpc/charon-xpc.c index 477e1e0c4..b4a3d58e1 100644 --- a/src/frontends/osx/charon-xpc/charon-xpc.c +++ b/src/frontends/osx/charon-xpc/charon-xpc.c @@ -165,7 +165,7 @@ int main(int argc, char *argv[]) if (!charon->initialize(charon, lib->settings->get_str(lib->settings, "charon-xpc.load", "random nonce pem pkcs1 openssl kernel-pfkey kernel-pfroute " - "socket-default eap-identity eap-mschapv2"))) + "keychain socket-default eap-identity eap-mschapv2"))) { exit(SS_RC_INITIALIZATION_FAILED); } diff --git a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj index 8cf467a1e..05e38d362 100644 --- a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj +++ b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 5B74984D172AA3550041971E /* xpc_dispatch.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B74984C172AA3550041971E /* xpc_dispatch.c */; }; 5BD1CCD71726DB4000587077 /* charon-xpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 5BD1CCD61726DB4000587077 /* charon-xpc.c */; }; 5BF60F31173405A000E5D608 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */; }; 5BF60F33173405AC00E5D608 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCF21727DE3E00587077 /* Security.framework */; }; From bc74e182230b3177079fb33ebfde5da26a57494e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 1 May 2013 11:06:11 +0200 Subject: [PATCH 20/39] xpc: don't send certificate requests, there are too many when using keychain --- src/frontends/osx/charon-xpc/xpc_dispatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontends/osx/charon-xpc/xpc_dispatch.c b/src/frontends/osx/charon-xpc/xpc_dispatch.c index f9f488118..a6e6c9b73 100644 --- a/src/frontends/osx/charon-xpc/xpc_dispatch.c +++ b/src/frontends/osx/charon-xpc/xpc_dispatch.c @@ -71,7 +71,7 @@ static peer_cfg_t* create_peer_cfg(char *name, char *host) { remote_port = IKEV2_NATT_PORT; } - ike_cfg = ike_cfg_create(IKEV2, TRUE, FALSE, "0.0.0.0", FALSE, local_port, + ike_cfg = ike_cfg_create(IKEV2, FALSE, FALSE, "0.0.0.0", FALSE, local_port, host, FALSE, remote_port, FRAGMENTATION_NO, 0); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); peer_cfg = peer_cfg_create(name, ike_cfg, From 8279ce99c422337b9ac68f0c72f0f09a319afaef Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 3 May 2013 16:53:29 +0200 Subject: [PATCH 21/39] xpc: use IKE_SA specific XPC return channels for further communication --- src/frontends/osx/charon-xpc/xpc_channels.c | 228 ++++++++++++++++++ src/frontends/osx/charon-xpc/xpc_channels.h | 59 +++++ src/frontends/osx/charon-xpc/xpc_dispatch.c | 34 ++- .../osx/strongSwan.xcodeproj/project.pbxproj | 11 +- 4 files changed, 320 insertions(+), 12 deletions(-) create mode 100644 src/frontends/osx/charon-xpc/xpc_channels.c create mode 100644 src/frontends/osx/charon-xpc/xpc_channels.h diff --git a/src/frontends/osx/charon-xpc/xpc_channels.c b/src/frontends/osx/charon-xpc/xpc_channels.c new file mode 100644 index 000000000..e8eb22551 --- /dev/null +++ b/src/frontends/osx/charon-xpc/xpc_channels.c @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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 "xpc_channels.h" + +#include +#include +#include + +typedef struct private_xpc_channels_t private_xpc_channels_t; + +/** + * Private data of an xpc_channels_t object. + */ +struct private_xpc_channels_t { + + /** + * Public xpc_channels_t interface. + */ + xpc_channels_t public; + + /** + * Registered channels, IKE_SA unique ID => entry_t + */ + hashtable_t *channels; + + /** + * Lock for channels list + */ + rwlock_t *lock; +}; + +/** + * Channel entry + */ +typedef struct { + /* XPC channel to App */ + xpc_connection_t conn; + /* associated IKE_SA unique identifier */ + uintptr_t sa; +} entry_t; + +/** + * Clean up an entry, cancelling connection + */ +static void destroy_entry(entry_t *entry) +{ + xpc_connection_suspend(entry->conn); + xpc_connection_cancel(entry->conn); + xpc_release(entry->conn); + free(entry); +} + +/** + * Remove an entry for a given XPC connection + */ +static void remove_conn(private_xpc_channels_t *this, xpc_connection_t conn) +{ + enumerator_t *enumerator; + entry_t *entry; + + this->lock->write_lock(this->lock); + enumerator = this->channels->create_enumerator(this->channels); + while (enumerator->enumerate(enumerator, NULL, &entry)) + { + if (xpc_equal(entry->conn, conn)) + { + this->channels->remove(this->channels, enumerator); + destroy_entry(entry); + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); +} + +/** + * Handle a request message from App + */ +static void handle(private_xpc_channels_t *this, xpc_object_t request) +{ + /* TODO: */ +} + +METHOD(xpc_channels_t, add, void, + private_xpc_channels_t *this, xpc_connection_t conn, u_int32_t ike_sa) +{ + entry_t *entry; + + INIT(entry, + .conn = conn, + .sa = ike_sa, + ); + + xpc_connection_set_event_handler(entry->conn, ^(xpc_object_t event) { + + if (event == XPC_ERROR_CONNECTION_INVALID || + event == XPC_ERROR_CONNECTION_INTERRUPTED) + { + remove_conn(this, entry->conn); + } + else + { + handle(this, event); + } + }); + + this->lock->write_lock(this->lock); + this->channels->put(this->channels, (void*)entry->sa, entry); + this->lock->unlock(this->lock); + + xpc_connection_resume(conn); +} + +METHOD(listener_t, ike_rekey, bool, + private_xpc_channels_t *this, ike_sa_t *old, ike_sa_t *new) +{ + entry_t *entry; + uintptr_t sa; + + sa = old->get_unique_id(old); + this->lock->write_lock(this->lock); + entry = this->channels->remove(this->channels, (void*)sa); + if (entry) + { + entry->sa = new->get_unique_id(new); + this->channels->put(this->channels, (void*)entry->sa, entry); + } + this->lock->unlock(this->lock); + + return TRUE; +} + +METHOD(listener_t, ike_updown, bool, + private_xpc_channels_t *this, ike_sa_t *ike_sa, bool up) +{ + xpc_object_t msg; + entry_t *entry; + uintptr_t sa; + + sa = ike_sa->get_unique_id(ike_sa); + if (up) + { + this->lock->read_lock(this->lock); + entry = this->channels->get(this->channels, (void*)sa); + if (entry) + { + msg = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_string(msg, "type", "event"); + xpc_dictionary_set_string(msg, "event", "up"); + xpc_connection_send_message(entry->conn, msg); + xpc_release(msg); + } + this->lock->unlock(this->lock); + } + else + { + this->lock->write_lock(this->lock); + entry = this->channels->remove(this->channels, (void*)sa); + this->lock->unlock(this->lock); + if (entry) + { + msg = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_string(msg, "type", "event"); + xpc_dictionary_set_string(msg, "event", "down"); + xpc_connection_send_message(entry->conn, msg); + xpc_release(msg); + xpc_connection_send_barrier(entry->conn, ^() { + destroy_entry(entry); + }); + } + } + return TRUE; +} + +METHOD(xpc_channels_t, destroy, void, + private_xpc_channels_t *this) +{ + enumerator_t *enumerator; + entry_t *entry; + + enumerator = this->channels->create_enumerator(this->channels); + while (enumerator->enumerate(enumerator, NULL, &entry)) + { + destroy_entry(entry); + } + enumerator->destroy(enumerator); + + this->channels->destroy(this->channels); + this->lock->destroy(this->lock); + free(this); +} + +/** + * See header + */ +xpc_channels_t *xpc_channels_create() +{ + private_xpc_channels_t *this; + + INIT(this, + .public = { + .listener = { + .ike_updown = _ike_updown, + .ike_rekey = _ike_rekey, + }, + .add = _add, + .destroy = _destroy, + }, + .channels = hashtable_create(hashtable_hash_ptr, + hashtable_equals_ptr, 4), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + return &this->public; +} diff --git a/src/frontends/osx/charon-xpc/xpc_channels.h b/src/frontends/osx/charon-xpc/xpc_channels.h new file mode 100644 index 000000000..125a81f1d --- /dev/null +++ b/src/frontends/osx/charon-xpc/xpc_channels.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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 xpc_channels xpc_channels + * @{ @ingroup xpc + */ + +#ifndef XPC_CHANNELS_H_ +#define XPC_CHANNELS_H_ + +#include + +#include + +typedef struct xpc_channels_t xpc_channels_t; + +/** + * XPC to App channel management. + */ +struct xpc_channels_t { + + /** + * Implements listener_t. + */ + listener_t listener; + + /** + * Associate an IKE_SA unique identifier to an XPC connection. + * + * @param conn XPC connection to channel + * @param ike_sa IKE_SA unique identifier to associate to connection + */ + void (*add)(xpc_channels_t *this, xpc_connection_t conn, u_int32_t ike_sa); + + /** + * Destroy a xpc_channels_t. + */ + void (*destroy)(xpc_channels_t *this); +}; + +/** + * Create a xpc_channels instance. + */ +xpc_channels_t *xpc_channels_create(); + +#endif /** XPC_CHANNELS_H_ @}*/ diff --git a/src/frontends/osx/charon-xpc/xpc_dispatch.c b/src/frontends/osx/charon-xpc/xpc_dispatch.c index a6e6c9b73..56d7850f6 100644 --- a/src/frontends/osx/charon-xpc/xpc_dispatch.c +++ b/src/frontends/osx/charon-xpc/xpc_dispatch.c @@ -14,6 +14,7 @@ */ #include "xpc_dispatch.h" +#include "xpc_channels.h" #include @@ -37,10 +38,15 @@ struct private_xpc_dispatch_t { */ xpc_connection_t service; - /** - * GCD queue for XPC events - */ - dispatch_queue_t queue; + /** + * XPC IKE_SA specific channels to App + */ + xpc_channels_t *channels; + + /** + * GCD queue for XPC events + */ + dispatch_queue_t queue; }; /** @@ -153,14 +159,19 @@ xpc_object_t start_connection(private_xpc_dispatch_t *this, peer_cfg_t *peer_cfg; child_cfg_t *child_cfg; char *name, *id, *host; - u_int32_t sa = 0; + bool success = FALSE; + xpc_endpoint_t endpoint; + xpc_connection_t channel; + u_int32_t ike_sa; name = (char*)xpc_dictionary_get_string(request, "name"); host = (char*)xpc_dictionary_get_string(request, "host"); id = (char*)xpc_dictionary_get_string(request, "id"); + endpoint = xpc_dictionary_get_value(request, "channel"); + channel = xpc_connection_create_from_endpoint(endpoint); reply = xpc_dictionary_create_reply(request); - if (name && id && host) + if (name && id && host && channel) { peer_cfg = create_peer_cfg(name, host); @@ -171,13 +182,14 @@ xpc_object_t start_connection(private_xpc_dispatch_t *this, peer_cfg->add_child_cfg(peer_cfg, child_cfg->get_ref(child_cfg)); if (charon->controller->initiate(charon->controller, peer_cfg, child_cfg, - (controller_cb_t)initiate_cb, &sa, 0) != SUCCESS) + (controller_cb_t)initiate_cb, &ike_sa, 0) == NEED_MORE) { - sa = 0; + this->channels->add(this->channels, channel, ike_sa); + success = TRUE; } } - xpc_dictionary_set_uint64(reply, "connection", sa); + xpc_dictionary_set_bool(reply, "success", success); return reply; } @@ -256,6 +268,8 @@ static void set_handler(private_xpc_dispatch_t *this) METHOD(xpc_dispatch_t, destroy, void, private_xpc_dispatch_t *this) { + charon->bus->remove_listener(charon->bus, &this->channels->listener); + this->channels->destroy(this->channels); if (this->service) { xpc_connection_suspend(this->service); @@ -275,9 +289,11 @@ xpc_dispatch_t *xpc_dispatch_create() .public = { .destroy = _destroy, }, + .channels = xpc_channels_create(), .queue = dispatch_queue_create("org.strongswan.charon-xpc.q", DISPATCH_QUEUE_CONCURRENT), ); + charon->bus->add_listener(charon->bus, &this->channels->listener); this->service = xpc_connection_create_mach_service( "org.strongswan.charon-xpc", this->queue, diff --git a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj index 05e38d362..7fa304b2b 100644 --- a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj +++ b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj @@ -7,16 +7,18 @@ objects = { /* Begin PBXBuildFile section */ - 5B74984D172AA3550041971E /* xpc_dispatch.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B74984C172AA3550041971E /* xpc_dispatch.c */; }; + 5B74989217311B200041971E /* xpc_channels.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B74989117311B200041971E /* xpc_channels.c */; }; 5BD1CCD71726DB4000587077 /* charon-xpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 5BD1CCD61726DB4000587077 /* charon-xpc.c */; }; 5BF60F31173405A000E5D608 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */; }; 5BF60F33173405AC00E5D608 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCF21727DE3E00587077 /* Security.framework */; }; - 5BF60F38173405F100E5D608 /* xpc_dispatch.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B74984C172AA3550041971E /* xpc_dispatch.c */; }; + 5BF60F3E1734070A00E5D608 /* xpc_dispatch.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B74984C172AA3550041971E /* xpc_dispatch.c */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 5B74984C172AA3550041971E /* xpc_dispatch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpc_dispatch.c; sourceTree = ""; }; 5B74984E172AA3670041971E /* xpc_dispatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_dispatch.h; sourceTree = ""; }; + 5B74989017311AFC0041971E /* xpc_channels.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_channels.h; sourceTree = ""; }; + 5B74989117311B200041971E /* xpc_channels.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpc_channels.c; sourceTree = ""; }; 5BD1CCD11726DB4000587077 /* org.strongswan.charon-xpc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.objfile"; includeInIndex = 0; path = "org.strongswan.charon-xpc"; sourceTree = BUILT_PRODUCTS_DIR; }; 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 5BD1CCD61726DB4000587077 /* charon-xpc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "charon-xpc.c"; sourceTree = ""; }; @@ -76,6 +78,8 @@ 5BD1CCE11726DD9900587077 /* charon-xpc-Info.plist */, 5B74984C172AA3550041971E /* xpc_dispatch.c */, 5B74984E172AA3670041971E /* xpc_dispatch.h */, + 5B74989017311AFC0041971E /* xpc_channels.h */, + 5B74989117311B200041971E /* xpc_channels.c */, ); path = "charon-xpc"; sourceTree = ""; @@ -131,7 +135,8 @@ buildActionMask = 2147483647; files = ( 5BD1CCD71726DB4000587077 /* charon-xpc.c in Sources */, - 5BF60F38173405F100E5D608 /* xpc_dispatch.c in Sources */, + 5B74989217311B200041971E /* xpc_channels.c in Sources */, + 5BF60F3E1734070A00E5D608 /* xpc_dispatch.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 39d15dde67fbc2f4c637e352a83d6e774c04154b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 2 May 2013 10:36:37 +0200 Subject: [PATCH 22/39] xpc: ask App for passwords using connection specific channel --- src/frontends/osx/charon-xpc/xpc_channels.c | 90 +++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/src/frontends/osx/charon-xpc/xpc_channels.c b/src/frontends/osx/charon-xpc/xpc_channels.c index e8eb22551..fc03ab333 100644 --- a/src/frontends/osx/charon-xpc/xpc_channels.c +++ b/src/frontends/osx/charon-xpc/xpc_channels.c @@ -15,6 +15,7 @@ #include "xpc_channels.h" +#include #include #include #include @@ -40,6 +41,11 @@ struct private_xpc_channels_t { * Lock for channels list */ rwlock_t *lock; + + /** + * Callback credential set for passwords + */ + callback_cred_t *creds; }; /** @@ -50,6 +56,8 @@ typedef struct { xpc_connection_t conn; /* associated IKE_SA unique identifier */ uintptr_t sa; + /* did we already ask for a password? */ + bool passworded; } entry_t; /** @@ -185,12 +193,90 @@ METHOD(listener_t, ike_updown, bool, return TRUE; } +/** + * Query password from App using XPC channel + */ +static shared_key_t *query_password(xpc_connection_t conn, identification_t *id) +{ + char buf[128], *password; + xpc_object_t request, response; + shared_key_t *shared = NULL; + + request = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_string(request, "type", "rpc"); + xpc_dictionary_set_string(request, "rpc", "get_password"); + snprintf(buf, sizeof(buf), "%Y", id); + xpc_dictionary_set_string(request, "username", buf); + + response = xpc_connection_send_message_with_reply_sync(conn, request); + xpc_release(request); + if (xpc_get_type(response) == XPC_TYPE_DICTIONARY) + { + password = (char*)xpc_dictionary_get_string(response, "password"); + shared = shared_key_create(SHARED_EAP, + chunk_clone(chunk_from_str(password))); + } + xpc_release(response); + return shared; +} + +/** + * Password query callback + */ +static shared_key_t* password_cb(private_xpc_channels_t *this, + shared_key_type_t type, + identification_t *me, identification_t *other, + id_match_t *match_me, id_match_t *match_other) +{ + shared_key_t *shared = NULL; + ike_sa_t *ike_sa; + entry_t *entry; + u_int32_t sa; + + switch (type) + { + case SHARED_EAP: + break; + default: + return NULL; + } + ike_sa = charon->bus->get_sa(charon->bus); + if (ike_sa) + { + sa = ike_sa->get_unique_id(ike_sa); + this->lock->read_lock(this->lock); + entry = this->channels->get(this->channels, (void*)sa); + if (entry && !entry->passworded) + { + entry->passworded = TRUE; + + shared = query_password(entry->conn, me); + if (shared) + { + if (match_me) + { + *match_me = ID_MATCH_PERFECT; + } + if (match_other) + { + *match_other = ID_MATCH_PERFECT; + } + } + } + this->lock->unlock(this->lock); + } + return shared; +} + METHOD(xpc_channels_t, destroy, void, private_xpc_channels_t *this) { enumerator_t *enumerator; entry_t *entry; + lib->credmgr->remove_set(lib->credmgr, &this->creds->set); + this->creds->destroy(this->creds); + enumerator = this->channels->create_enumerator(this->channels); while (enumerator->enumerate(enumerator, NULL, &entry)) { @@ -224,5 +310,9 @@ xpc_channels_t *xpc_channels_create() .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), ); + this->creds = callback_cred_create_shared( + (callback_cred_shared_cb_t)password_cb, this); + lib->credmgr->add_set(lib->credmgr, &this->creds->set); + return &this->public; } From d5966e71e9915191b93b27bbc5f320e9305f05b2 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 2 May 2013 10:54:55 +0200 Subject: [PATCH 23/39] xpc: use the same XPC message "type" mechanism on Mach service as on channels --- src/frontends/osx/charon-xpc/xpc_dispatch.c | 43 +++++++++++++++------ 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/src/frontends/osx/charon-xpc/xpc_dispatch.c b/src/frontends/osx/charon-xpc/xpc_dispatch.c index 56d7850f6..f99ad6775 100644 --- a/src/frontends/osx/charon-xpc/xpc_dispatch.c +++ b/src/frontends/osx/charon-xpc/xpc_dispatch.c @@ -195,7 +195,7 @@ xpc_object_t start_connection(private_xpc_dispatch_t *this, } /** - * XPC command dispatch table + * XPC RPC command dispatch table */ static struct { char *name; @@ -213,26 +213,47 @@ static void handle(private_xpc_dispatch_t *this, xpc_object_t request) { xpc_connection_t client; xpc_object_t reply; - const char *command; + const char *type, *rpc; + bool found = FALSE; int i; client = xpc_dictionary_get_remote_connection(request); - command = xpc_dictionary_get_string(request, "command"); - if (command) + type = xpc_dictionary_get_string(request, "type"); + if (type) { - for (i = 0; i < countof(commands); i++) + if (streq(type, "rpc")) { - if (streq(commands[i].name, command)) + rpc = xpc_dictionary_get_string(request, "rpc"); + if (rpc) { - reply = commands[i].handler(this, request, client); - if (reply) + for (i = 0; i < countof(commands); i++) { - xpc_connection_send_message(client, reply); - xpc_release(reply); + if (streq(commands[i].name, rpc)) + { + found = TRUE; + reply = commands[i].handler(this, request, client); + if (reply) + { + xpc_connection_send_message(client, reply); + xpc_release(reply); + } + break; + } } - break; + } + if (!found) + { + DBG1(DBG_CFG, "received unknown XPC rpc command: %s", rpc); } } + else + { + DBG1(DBG_CFG, "received unknown XPC message type: %s", type); + } + } + else + { + DBG1(DBG_CFG, "received XPC message without a type"); } } From dcf8a3c78b8b1851acf68b359e24a346ca4ed17d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 2 May 2013 11:22:51 +0200 Subject: [PATCH 24/39] xpc: add a description of the basic XPC protocol to README --- src/frontends/osx/README.md | 49 ++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/frontends/osx/README.md b/src/frontends/osx/README.md index 62a0b2e0d..39b5c7349 100644 --- a/src/frontends/osx/README.md +++ b/src/frontends/osx/README.md @@ -38,4 +38,51 @@ any non OS X dependencies. Both charon-xpc and the App must be code-signed to allow the installation of the privileged helper. git-grep for "Joe Developer" to change the signing -identity. \ No newline at end of file +identity. + +## XPC application protocol ## + +charon-xpc provides a Mach service under the name _org.strongswan.charon-xpc_. +Clients can connect to this service to control the daemon. All messages +on all connections use the following string dictionary keys/values: + +* _type_: XPC message type, currently either + * _rpc_ for a remote procedure call, expects a response + * _event_ for application specific event messages +* _rpc_: defines the name of the RPC function to call (for _type_ = _rpc_) +* _event_: defines a name for the event (for _type_ = _event_) + +Additional arguments and return values are specified by the call and can have +any type. Keys are directly attached to the message dictionary. + +On the Mach service connection, the following RPC messages are currently +defined: + +* string version = get_version() + * _version_: strongSwan version of charon-xpc +* bool success = start_connection(string name, string host, string id, + endpoint channel) + * _success_: TRUE if initiation started successfully + * _name_: connection name to initiate + * _host_: server hostname (and identity) + * _id_: client identity to use + * _channel_: XPC endpoint for this connection + +The start_connection() RPC returns just after the initation of the call and +does not wait for the connection to establish. Nonetheless does it have a +return value to indicate if connection initiation could be triggered. + +The App passes an (anonymous) XPC endpoint to start_connection(). If the call +succeeds, charon-xpc connects to this endpoint to establish a channel used for +this specific IKE connection. + +On this channel, the following RPC calls are currently defined from charon-xpc +to the App: + +* string password = get_password(string username) + * _password_: user password returned + * _username_: username to query a password for + +The following events are currently defined from charon-xpc to the App: +* _up_: connection has been established +* _down_: connection has been closed or failed to establish From fbc89786b530050a222ecc21863c132582e95218 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 2 May 2013 11:58:43 +0200 Subject: [PATCH 25/39] xpc: don't warn about pointer signedness mismatch (-Wno-pointer-sign) --- src/frontends/osx/strongSwan.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj index 7fa304b2b..29140b75f 100644 --- a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj +++ b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj @@ -199,6 +199,7 @@ buildSettings = { CODE_SIGN_IDENTITY = "Joe Developer"; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; + GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO; HEADER_SEARCH_PATHS = ( /usr/include, ../../libstrongswan, @@ -250,6 +251,7 @@ CODE_SIGN_IDENTITY = "Joe Developer"; COPY_PHASE_STRIP = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; + GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO; HEADER_SEARCH_PATHS = ( /usr/include, ../../libstrongswan, From 1a3f71d97a55415073eacbea090fba466f3f2c76 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 3 May 2013 16:55:22 +0200 Subject: [PATCH 26/39] xpc: add support for logging over XPC channels --- src/frontends/osx/charon-xpc/xpc_channels.c | 12 ++- src/frontends/osx/charon-xpc/xpc_logger.c | 96 +++++++++++++++++++ src/frontends/osx/charon-xpc/xpc_logger.h | 61 ++++++++++++ .../osx/strongSwan.xcodeproj/project.pbxproj | 6 ++ 4 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 src/frontends/osx/charon-xpc/xpc_logger.c create mode 100644 src/frontends/osx/charon-xpc/xpc_logger.h diff --git a/src/frontends/osx/charon-xpc/xpc_channels.c b/src/frontends/osx/charon-xpc/xpc_channels.c index fc03ab333..494ce0b49 100644 --- a/src/frontends/osx/charon-xpc/xpc_channels.c +++ b/src/frontends/osx/charon-xpc/xpc_channels.c @@ -14,6 +14,7 @@ */ #include "xpc_channels.h" +#include "xpc_logger.h" #include #include @@ -58,6 +59,8 @@ typedef struct { uintptr_t sa; /* did we already ask for a password? */ bool passworded; + /* channel specific logger */ + xpc_logger_t *logger; } entry_t; /** @@ -65,6 +68,8 @@ typedef struct { */ static void destroy_entry(entry_t *entry) { + charon->bus->remove_logger(charon->bus, &entry->logger->logger); + entry->logger->destroy(entry->logger); xpc_connection_suspend(entry->conn); xpc_connection_cancel(entry->conn); xpc_release(entry->conn); @@ -110,6 +115,7 @@ METHOD(xpc_channels_t, add, void, INIT(entry, .conn = conn, .sa = ike_sa, + .logger = xpc_logger_create(conn), ); xpc_connection_set_event_handler(entry->conn, ^(xpc_object_t event) { @@ -117,7 +123,7 @@ METHOD(xpc_channels_t, add, void, if (event == XPC_ERROR_CONNECTION_INVALID || event == XPC_ERROR_CONNECTION_INTERRUPTED) { - remove_conn(this, entry->conn); + remove_conn(this, conn); } else { @@ -125,6 +131,9 @@ METHOD(xpc_channels_t, add, void, } }); + entry->logger->set_ike_sa(entry->logger, entry->sa); + charon->bus->add_logger(charon->bus, &entry->logger->logger); + this->lock->write_lock(this->lock); this->channels->put(this->channels, (void*)entry->sa, entry); this->lock->unlock(this->lock); @@ -144,6 +153,7 @@ METHOD(listener_t, ike_rekey, bool, if (entry) { entry->sa = new->get_unique_id(new); + entry->logger->set_ike_sa(entry->logger, entry->sa); this->channels->put(this->channels, (void*)entry->sa, entry); } this->lock->unlock(this->lock); diff --git a/src/frontends/osx/charon-xpc/xpc_logger.c b/src/frontends/osx/charon-xpc/xpc_logger.c new file mode 100644 index 000000000..38c34e460 --- /dev/null +++ b/src/frontends/osx/charon-xpc/xpc_logger.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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 "xpc_logger.h" + +typedef struct private_xpc_logger_t private_xpc_logger_t; + +/** + * Private data of an xpc_logger_t object. + */ +struct private_xpc_logger_t { + + /** + * Public xpc_logger_t interface. + */ + xpc_logger_t public; + + /** + * XPC channel to send logging messages to + */ + xpc_connection_t conn; + + /** + * IKE_SA we log for + */ + u_int32_t ike_sa; +}; + +METHOD(logger_t, log_, void, + private_xpc_logger_t *this, debug_t group, level_t level, int thread, + ike_sa_t* ike_sa, const char *message) +{ + if (ike_sa && ike_sa->get_unique_id(ike_sa) == this->ike_sa) + { + xpc_object_t msg; + + msg = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_string(msg, "type", "event"); + xpc_dictionary_set_string(msg, "event", "log"); + xpc_dictionary_set_string(msg, "message", message); + xpc_connection_send_message(this->conn, msg); + xpc_release(msg); + } +} + +METHOD(logger_t, get_level, level_t, + private_xpc_logger_t *this, debug_t group) +{ + return LEVEL_CTRL; +} + +METHOD(xpc_logger_t, set_ike_sa, void, + private_xpc_logger_t *this, u_int32_t ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(xpc_logger_t, destroy, void, + private_xpc_logger_t *this) +{ + free(this); +} + +/** + * See header + */ +xpc_logger_t *xpc_logger_create(xpc_connection_t conn) +{ + private_xpc_logger_t *this; + + INIT(this, + .public = { + .logger = { + .log = _log_, + .get_level = _get_level, + }, + .set_ike_sa = _set_ike_sa, + .destroy = _destroy, + }, + .conn = conn, + ); + + return &this->public; +} diff --git a/src/frontends/osx/charon-xpc/xpc_logger.h b/src/frontends/osx/charon-xpc/xpc_logger.h new file mode 100644 index 000000000..fd5ad37a2 --- /dev/null +++ b/src/frontends/osx/charon-xpc/xpc_logger.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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 xpc_logger xpc_logger + * @{ @ingroup xpc + */ + +#ifndef XPC_LOGGER_H_ +#define XPC_LOGGER_H_ + +#include + +#include + +typedef struct xpc_logger_t xpc_logger_t; + +/** + * Connection specific logger over XPC. + */ +struct xpc_logger_t { + + /** + * Implements logger_t. + */ + logger_t logger; + + /** + * Set the IKE_SA unique identifier this logger logs for. + * + * @param ike_sa IKE_SA unique identifier + */ + void (*set_ike_sa)(xpc_logger_t *this, u_int32_t ike_sa); + + /** + * Destroy a xpc_logger_t. + */ + void (*destroy)(xpc_logger_t *this); +}; + +/** + * Create a xpc_logger instance. + * + * @param conn XPC connection to send logging events to + * @return XPC logger + */ +xpc_logger_t *xpc_logger_create(xpc_connection_t conn); + +#endif /** XPC_LOGGER_H_ @}*/ diff --git a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj index 29140b75f..00781e947 100644 --- a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj +++ b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 5B74989217311B200041971E /* xpc_channels.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B74989117311B200041971E /* xpc_channels.c */; }; + 5B7498B8173275D10041971E /* xpc_logger.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B7498B7173275D10041971E /* xpc_logger.c */; }; 5BD1CCD71726DB4000587077 /* charon-xpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 5BD1CCD61726DB4000587077 /* charon-xpc.c */; }; 5BF60F31173405A000E5D608 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */; }; 5BF60F33173405AC00E5D608 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCF21727DE3E00587077 /* Security.framework */; }; @@ -21,6 +22,8 @@ 5B74989117311B200041971E /* xpc_channels.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpc_channels.c; sourceTree = ""; }; 5BD1CCD11726DB4000587077 /* org.strongswan.charon-xpc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.objfile"; includeInIndex = 0; path = "org.strongswan.charon-xpc"; sourceTree = BUILT_PRODUCTS_DIR; }; 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 5B7498B7173275D10041971E /* xpc_logger.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpc_logger.c; sourceTree = ""; }; + 5B7498B9173275DD0041971E /* xpc_logger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_logger.h; sourceTree = ""; }; 5BD1CCD61726DB4000587077 /* charon-xpc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "charon-xpc.c"; sourceTree = ""; }; 5BD1CCE01726DCD000587077 /* charon-xpc-Launchd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "charon-xpc-Launchd.plist"; sourceTree = ""; }; 5BD1CCE11726DD9900587077 /* charon-xpc-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "charon-xpc-Info.plist"; sourceTree = ""; }; @@ -80,6 +83,8 @@ 5B74984E172AA3670041971E /* xpc_dispatch.h */, 5B74989017311AFC0041971E /* xpc_channels.h */, 5B74989117311B200041971E /* xpc_channels.c */, + 5B7498B7173275D10041971E /* xpc_logger.c */, + 5B7498B9173275DD0041971E /* xpc_logger.h */, ); path = "charon-xpc"; sourceTree = ""; @@ -137,6 +142,7 @@ 5BD1CCD71726DB4000587077 /* charon-xpc.c in Sources */, 5B74989217311B200041971E /* xpc_channels.c in Sources */, 5BF60F3E1734070A00E5D608 /* xpc_dispatch.c in Sources */, + 5B7498B8173275D10041971E /* xpc_logger.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 22bffc647dc87a3a3d0c4c2588dc5092607b2892 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 2 May 2013 13:58:22 +0200 Subject: [PATCH 27/39] xpc: no need to clear channel table, they are bound to IKE_SA lifetime --- src/frontends/osx/charon-xpc/xpc_channels.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/frontends/osx/charon-xpc/xpc_channels.c b/src/frontends/osx/charon-xpc/xpc_channels.c index 494ce0b49..3eceaa88f 100644 --- a/src/frontends/osx/charon-xpc/xpc_channels.c +++ b/src/frontends/osx/charon-xpc/xpc_channels.c @@ -286,14 +286,6 @@ METHOD(xpc_channels_t, destroy, void, lib->credmgr->remove_set(lib->credmgr, &this->creds->set); this->creds->destroy(this->creds); - - enumerator = this->channels->create_enumerator(this->channels); - while (enumerator->enumerate(enumerator, NULL, &entry)) - { - destroy_entry(entry); - } - enumerator->destroy(enumerator); - this->channels->destroy(this->channels); this->lock->destroy(this->lock); free(this); From 6aae6268d7b3ff57cea3e453756080b99c176702 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 2 May 2013 14:28:19 +0200 Subject: [PATCH 28/39] xpc: fix some refcounting issues related to XPC connections --- src/frontends/osx/charon-xpc/xpc_channels.c | 19 +++++++++--------- src/frontends/osx/charon-xpc/xpc_dispatch.c | 22 ++++++--------------- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/frontends/osx/charon-xpc/xpc_channels.c b/src/frontends/osx/charon-xpc/xpc_channels.c index 3eceaa88f..0d82d7032 100644 --- a/src/frontends/osx/charon-xpc/xpc_channels.c +++ b/src/frontends/osx/charon-xpc/xpc_channels.c @@ -71,7 +71,6 @@ static void destroy_entry(entry_t *entry) charon->bus->remove_logger(charon->bus, &entry->logger->logger); entry->logger->destroy(entry->logger); xpc_connection_suspend(entry->conn); - xpc_connection_cancel(entry->conn); xpc_release(entry->conn); free(entry); } @@ -88,7 +87,7 @@ static void remove_conn(private_xpc_channels_t *this, xpc_connection_t conn) enumerator = this->channels->create_enumerator(this->channels); while (enumerator->enumerate(enumerator, NULL, &entry)) { - if (xpc_equal(entry->conn, conn)) + if (entry->conn == conn) { this->channels->remove(this->channels, enumerator); destroy_entry(entry); @@ -118,14 +117,14 @@ METHOD(xpc_channels_t, add, void, .logger = xpc_logger_create(conn), ); - xpc_connection_set_event_handler(entry->conn, ^(xpc_object_t event) { - + xpc_connection_set_event_handler(entry->conn, ^(xpc_object_t event) + { if (event == XPC_ERROR_CONNECTION_INVALID || event == XPC_ERROR_CONNECTION_INTERRUPTED) { remove_conn(this, conn); } - else + else if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) { handle(this, event); } @@ -223,8 +222,11 @@ static shared_key_t *query_password(xpc_connection_t conn, identification_t *id) if (xpc_get_type(response) == XPC_TYPE_DICTIONARY) { password = (char*)xpc_dictionary_get_string(response, "password"); - shared = shared_key_create(SHARED_EAP, - chunk_clone(chunk_from_str(password))); + if (password) + { + shared = shared_key_create(SHARED_EAP, + chunk_clone(chunk_from_str(password))); + } } xpc_release(response); return shared; @@ -281,9 +283,6 @@ static shared_key_t* password_cb(private_xpc_channels_t *this, METHOD(xpc_channels_t, destroy, void, private_xpc_channels_t *this) { - enumerator_t *enumerator; - entry_t *entry; - lib->credmgr->remove_set(lib->credmgr, &this->creds->set); this->creds->destroy(this->creds); this->channels->destroy(this->channels); diff --git a/src/frontends/osx/charon-xpc/xpc_dispatch.c b/src/frontends/osx/charon-xpc/xpc_dispatch.c index f99ad6775..1f636bc43 100644 --- a/src/frontends/osx/charon-xpc/xpc_dispatch.c +++ b/src/frontends/osx/charon-xpc/xpc_dispatch.c @@ -262,27 +262,17 @@ static void handle(private_xpc_dispatch_t *this, xpc_object_t request) */ static void set_handler(private_xpc_dispatch_t *this) { - xpc_connection_set_event_handler(this->service, ^(xpc_object_t conn) { - - xpc_connection_set_event_handler(conn, ^(xpc_object_t event) { - - if (xpc_get_type(event) == XPC_TYPE_ERROR) - { - if (event == XPC_ERROR_CONNECTION_INVALID || - event == XPC_ERROR_TERMINATION_IMMINENT) - { - xpc_connection_cancel(conn); - } - } - else + xpc_connection_set_event_handler(this->service, ^(xpc_object_t conn) + { + xpc_connection_set_event_handler(conn, ^(xpc_object_t event) + { + if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) { handle(this, event); } }); - xpc_connection_resume(conn); }); - xpc_connection_resume(this->service); } @@ -294,7 +284,7 @@ METHOD(xpc_dispatch_t, destroy, void, if (this->service) { xpc_connection_suspend(this->service); - xpc_connection_cancel(this->service); + xpc_release(this->service); } free(this); } From a0c125eacb612ecb0e30b1f8335dc6ab3e378c0c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 2 May 2013 14:40:23 +0200 Subject: [PATCH 29/39] xpc: terminate daemon when last XPC connection to App gone --- src/frontends/osx/charon-xpc/xpc_dispatch.c | 28 +++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/frontends/osx/charon-xpc/xpc_dispatch.c b/src/frontends/osx/charon-xpc/xpc_dispatch.c index 1f636bc43..1ef77bfa1 100644 --- a/src/frontends/osx/charon-xpc/xpc_dispatch.c +++ b/src/frontends/osx/charon-xpc/xpc_dispatch.c @@ -17,6 +17,8 @@ #include "xpc_channels.h" #include +#include +#include #include #include @@ -47,6 +49,16 @@ struct private_xpc_dispatch_t { * GCD queue for XPC events */ dispatch_queue_t queue; + + /** + * Number of active App connections + */ + refcount_t refcount; + + /** + * PID of main thread + */ + pid_t pid; }; /** @@ -257,6 +269,18 @@ static void handle(private_xpc_dispatch_t *this, xpc_object_t request) } } +/** + * Finalizer for client connections + */ +static void cleanup_connection(private_xpc_dispatch_t *this) +{ + if (ref_put(&this->refcount)) + { + DBG1(DBG_CFG, "no XPC connections, raising SIGTERM"); + kill(this->pid, SIGTERM); + } +} + /** * Set up GCD handler for XPC events */ @@ -271,6 +295,9 @@ static void set_handler(private_xpc_dispatch_t *this) handle(this, event); } }); + ref_get(&this->refcount); + xpc_connection_set_context(conn, this); + xpc_connection_set_finalizer_f(conn, (void*)cleanup_connection); xpc_connection_resume(conn); }); xpc_connection_resume(this->service); @@ -303,6 +330,7 @@ xpc_dispatch_t *xpc_dispatch_create() .channels = xpc_channels_create(), .queue = dispatch_queue_create("org.strongswan.charon-xpc.q", DISPATCH_QUEUE_CONCURRENT), + .pid = getpid(), ); charon->bus->add_listener(charon->bus, &this->channels->listener); From 790ad9e6778b659086c827bae08c269b431b16e8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 2 May 2013 16:43:44 +0200 Subject: [PATCH 30/39] xpc: move XPC RPC reply creation to command dispatching --- src/frontends/osx/charon-xpc/xpc_dispatch.c | 40 +++++++++------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/src/frontends/osx/charon-xpc/xpc_dispatch.c b/src/frontends/osx/charon-xpc/xpc_dispatch.c index 1ef77bfa1..f60bcbfe0 100644 --- a/src/frontends/osx/charon-xpc/xpc_dispatch.c +++ b/src/frontends/osx/charon-xpc/xpc_dispatch.c @@ -64,15 +64,10 @@ struct private_xpc_dispatch_t { /** * Return version of this helper */ -static xpc_object_t get_version(private_xpc_dispatch_t *this, - xpc_object_t request, xpc_connection_t client) +static void get_version(private_xpc_dispatch_t *this, + xpc_object_t request, xpc_object_t reply) { - xpc_object_t reply; - - reply = xpc_dictionary_create_reply(request); xpc_dictionary_set_string(reply, "version", PACKAGE_VERSION); - - return reply; } /** @@ -164,10 +159,9 @@ static bool initiate_cb(u_int32_t *sa, debug_t group, level_t level, /** * Start initiating an IKE connection */ -xpc_object_t start_connection(private_xpc_dispatch_t *this, - xpc_object_t request, xpc_connection_t client) +void start_connection(private_xpc_dispatch_t *this, + xpc_object_t request, xpc_object_t reply) { - xpc_object_t reply; peer_cfg_t *peer_cfg; child_cfg_t *child_cfg; char *name, *id, *host; @@ -181,7 +175,6 @@ xpc_object_t start_connection(private_xpc_dispatch_t *this, id = (char*)xpc_dictionary_get_string(request, "id"); endpoint = xpc_dictionary_get_value(request, "channel"); channel = xpc_connection_create_from_endpoint(endpoint); - reply = xpc_dictionary_create_reply(request); if (name && id && host && channel) { @@ -202,8 +195,6 @@ xpc_object_t start_connection(private_xpc_dispatch_t *this, } xpc_dictionary_set_bool(reply, "success", success); - - return reply; } /** @@ -211,8 +202,8 @@ xpc_object_t start_connection(private_xpc_dispatch_t *this, */ static struct { char *name; - xpc_object_t (*handler)(private_xpc_dispatch_t *this, - xpc_object_t request, xpc_connection_t client); + void (*handler)(private_xpc_dispatch_t *this, + xpc_object_t request, xpc_object_t reply); } commands[] = { { "get_version", get_version }, { "start_connection", start_connection }, @@ -229,33 +220,34 @@ static void handle(private_xpc_dispatch_t *this, xpc_object_t request) bool found = FALSE; int i; - client = xpc_dictionary_get_remote_connection(request); type = xpc_dictionary_get_string(request, "type"); if (type) { if (streq(type, "rpc")) { + reply = xpc_dictionary_create_reply(request); rpc = xpc_dictionary_get_string(request, "rpc"); - if (rpc) + if (reply && rpc) { for (i = 0; i < countof(commands); i++) { if (streq(commands[i].name, rpc)) { found = TRUE; - reply = commands[i].handler(this, request, client); - if (reply) - { - xpc_connection_send_message(client, reply); - xpc_release(reply); - } + commands[i].handler(this, request, reply); break; } } } if (!found) { - DBG1(DBG_CFG, "received unknown XPC rpc command: %s", rpc); + DBG1(DBG_CFG, "received invalid XPC rpc command: %s", rpc); + } + if (reply) + { + client = xpc_dictionary_get_remote_connection(request); + xpc_connection_send_message(client, reply); + xpc_release(reply); } } else From d60c8d2c740d6cb02776974fa3cd1c0a3f8613cf Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 2 May 2013 17:45:58 +0200 Subject: [PATCH 31/39] xpc: support termination of IKE_SAs using XPC RPC on connection channel --- src/frontends/osx/charon-xpc/xpc_channels.c | 110 ++++++++++++++++++-- 1 file changed, 102 insertions(+), 8 deletions(-) diff --git a/src/frontends/osx/charon-xpc/xpc_channels.c b/src/frontends/osx/charon-xpc/xpc_channels.c index 0d82d7032..ce2c83bfb 100644 --- a/src/frontends/osx/charon-xpc/xpc_channels.c +++ b/src/frontends/osx/charon-xpc/xpc_channels.c @@ -76,34 +76,128 @@ static void destroy_entry(entry_t *entry) } /** - * Remove an entry for a given XPC connection + * Find an IKE_SA unique identifier by a given XPC channel */ -static void remove_conn(private_xpc_channels_t *this, xpc_connection_t conn) +static u_int32_t find_ike_sa_by_conn(private_xpc_channels_t *this, + xpc_connection_t conn) { enumerator_t *enumerator; entry_t *entry; + u_int32_t ike_sa = 0; - this->lock->write_lock(this->lock); + this->lock->read_lock(this->lock); enumerator = this->channels->create_enumerator(this->channels); while (enumerator->enumerate(enumerator, NULL, &entry)) { if (entry->conn == conn) { - this->channels->remove(this->channels, enumerator); - destroy_entry(entry); + ike_sa = entry->sa; break; } } enumerator->destroy(enumerator); this->lock->unlock(this->lock); + + return ike_sa; } +/** + * Remove an entry for a given XPC connection + */ +static void remove_conn(private_xpc_channels_t *this, xpc_connection_t conn) +{ + uintptr_t ike_sa; + entry_t *entry; + + ike_sa = find_ike_sa_by_conn(this, conn); + if (ike_sa) + { + this->lock->write_lock(this->lock); + entry = this->channels->remove(this->channels, (void*)ike_sa); + this->lock->unlock(this->lock); + + if (entry) + { + destroy_entry(entry); + } + } +} + +/** + * Trigger termination of a connection + */ +static void stop_connection(private_xpc_channels_t *this, u_int32_t ike_sa, + xpc_object_t request, xpc_object_t reply) +{ + status_t status; + + status = charon->controller->terminate_ike(charon->controller, ike_sa, + NULL, NULL, 0); + xpc_dictionary_set_bool(reply, "success", status != NOT_FOUND); +} + +/** + * XPC RPC command dispatch table + */ +static struct { + char *name; + void (*handler)(private_xpc_channels_t *this, u_int32_t ike_sa, + xpc_object_t request, xpc_object_t reply); +} commands[] = { + { "stop_connection", stop_connection }, +}; + /** * Handle a request message from App */ -static void handle(private_xpc_channels_t *this, xpc_object_t request) +static void handle(private_xpc_channels_t *this, xpc_connection_t conn, + xpc_object_t request) { - /* TODO: */ + xpc_object_t reply; + const char *type, *rpc; + bool found = FALSE; + u_int32_t ike_sa; + int i; + + type = xpc_dictionary_get_string(request, "type"); + if (type) + { + if (streq(type, "rpc")) + { + reply = xpc_dictionary_create_reply(request); + rpc = xpc_dictionary_get_string(request, "rpc"); + ike_sa = find_ike_sa_by_conn(this, conn); + if (reply && rpc && ike_sa) + { + for (i = 0; i < countof(commands); i++) + { + if (streq(commands[i].name, rpc)) + { + found = TRUE; + commands[i].handler(this, ike_sa, request, reply); + break; + } + } + } + if (!found) + { + DBG1(DBG_CFG, "received invalid XPC rpc command: %s", rpc); + } + if (reply) + { + xpc_connection_send_message(conn, reply); + xpc_release(reply); + } + } + else + { + DBG1(DBG_CFG, "received unknown XPC message type: %s", type); + } + } + else + { + DBG1(DBG_CFG, "received XPC message without a type"); + } } METHOD(xpc_channels_t, add, void, @@ -126,7 +220,7 @@ METHOD(xpc_channels_t, add, void, } else if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) { - handle(this, event); + handle(this, conn, event); } }); From 4edcc8614901b65c58844787362047fe2d33f0fb Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 2 May 2013 18:11:47 +0200 Subject: [PATCH 32/39] xpc: send child_updown events over XPC channel --- src/frontends/osx/charon-xpc/xpc_channels.c | 43 +++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/frontends/osx/charon-xpc/xpc_channels.c b/src/frontends/osx/charon-xpc/xpc_channels.c index ce2c83bfb..1310b37f6 100644 --- a/src/frontends/osx/charon-xpc/xpc_channels.c +++ b/src/frontends/osx/charon-xpc/xpc_channels.c @@ -254,6 +254,48 @@ METHOD(listener_t, ike_rekey, bool, return TRUE; } +METHOD(listener_t, child_updown, bool, + private_xpc_channels_t *this, ike_sa_t *ike_sa, + child_sa_t *child_sa, bool up) +{ + entry_t *entry; + uintptr_t sa; + + sa = ike_sa->get_unique_id(ike_sa); + this->lock->read_lock(this->lock); + entry = this->channels->get(this->channels, (void*)sa); + if (entry) + { + xpc_object_t msg; + linked_list_t *list; + char buf[256]; + + msg = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_string(msg, "type", "event"); + if (up) + { + xpc_dictionary_set_string(msg, "event", "child_up"); + } + else + { + xpc_dictionary_set_string(msg, "event", "child_down"); + } + + list = child_sa->get_traffic_selectors(child_sa, TRUE); + snprintf(buf, sizeof(buf), "%#R", list); + xpc_dictionary_set_string(msg, "ts_local", buf); + + list = child_sa->get_traffic_selectors(child_sa, FALSE); + snprintf(buf, sizeof(buf), "%#R", list); + xpc_dictionary_set_string(msg, "ts_remote", buf); + + xpc_connection_send_message(entry->conn, msg); + xpc_release(msg); + } + this->lock->unlock(this->lock); + return TRUE; +} + METHOD(listener_t, ike_updown, bool, private_xpc_channels_t *this, ike_sa_t *ike_sa, bool up) { @@ -396,6 +438,7 @@ xpc_channels_t *xpc_channels_create() .listener = { .ike_updown = _ike_updown, .ike_rekey = _ike_rekey, + .child_updown = _child_updown, }, .add = _add, .destroy = _destroy, From c7ac7f92e9d8417be0e154648b9fb50a9846a5b8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 3 May 2013 18:35:11 +0200 Subject: [PATCH 33/39] xpc: update README with new events, markdown style fixes --- src/frontends/osx/README.md | 52 ++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/src/frontends/osx/README.md b/src/frontends/osx/README.md index 39b5c7349..ccb46ab9d 100644 --- a/src/frontends/osx/README.md +++ b/src/frontends/osx/README.md @@ -22,14 +22,15 @@ needed to run the built App. Before building the Xcode project, the strongSwan base tree must be built using a monolithic and static build. This can be achieved on OS X by using: -LDFLAGS="-all_load" \ -CFLAGS="-I/usr/include -DOPENSSL_NO_CMS -O2 -Wall -Wno-format -Wno-pointer-sign" \ -./configure --prefix=/opt/local --disable-defaults --enable-openssl \ - --enable-kernel-pfkey --enable-kernel-pfroute --enable-eap-mschapv2 \ - --enable-eap-identity --enable-monolithic --enable-nonce --enable-random \ - --enable-pkcs1 --enable-pem --enable-socket-default --enable-xauth-generic \ - --enable-keychain --enable-ikev1 --enable-ikev2 --enable-charon \ - --disable-shared --enable-static + LDFLAGS="-all_load" \ + CFLAGS="-I/usr/include -DOPENSSL_NO_CMS -O2 -Wall -Wno-format -Wno-pointer-sign" \ + ./configure --prefix=/opt/local --enable-monolithic \ + --disable-shared --enable-static --disable-defaults \ + --enable-openssl --enable-kernel-pfkey --enable-kernel-pfroute \ + --enable-eap-mschapv2 --enable-eap-identity --enable-nonce \ + --enable-random --enable-pkcs1 --enable-pem --enable-socket-default \ + --enable-xauth-generic --enable-keychain --enable-charon \ + --enable-ikev1 --enable-ikev2 followed by calling make (no need to make install). @@ -47,8 +48,8 @@ Clients can connect to this service to control the daemon. All messages on all connections use the following string dictionary keys/values: * _type_: XPC message type, currently either - * _rpc_ for a remote procedure call, expects a response - * _event_ for application specific event messages + * _rpc_ for a remote procedure call, expects a response + * _event_ for application specific event messages * _rpc_: defines the name of the RPC function to call (for _type_ = _rpc_) * _event_: defines a name for the event (for _type_ = _event_) @@ -59,14 +60,14 @@ On the Mach service connection, the following RPC messages are currently defined: * string version = get_version() - * _version_: strongSwan version of charon-xpc + * _version_: strongSwan version of charon-xpc * bool success = start_connection(string name, string host, string id, - endpoint channel) - * _success_: TRUE if initiation started successfully - * _name_: connection name to initiate - * _host_: server hostname (and identity) - * _id_: client identity to use - * _channel_: XPC endpoint for this connection + endpoint channel) + * _success_: TRUE if initiation started successfully + * _name_: connection name to initiate + * _host_: server hostname (and identity) + * _id_: client identity to use + * _channel_: XPC endpoint for this connection The start_connection() RPC returns just after the initation of the call and does not wait for the connection to establish. Nonetheless does it have a @@ -80,9 +81,18 @@ On this channel, the following RPC calls are currently defined from charon-xpc to the App: * string password = get_password(string username) - * _password_: user password returned - * _username_: username to query a password for + * _password_: user password returned + * _username_: username to query a password for + +And the following from the App to charon-xpc: + +* bool success = stop_connection() + * _success_: TRUE if termination of connection initiated The following events are currently defined from charon-xpc to the App: -* _up_: connection has been established -* _down_: connection has been closed or failed to establish + +* up(): IKE_SA has been established +* down(): IKE_SA has been closed or failed to establish +* child_up(string local_ts, string remote_ts): CHILD_SA has been established +* child_down(string local_ts, string remote_ts): CHILD_SA has been closed +* log(string message): debug log message for this connection From 3ffa310c44e0627cdfa918e44901e537043920f4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 15 May 2013 16:04:43 +0200 Subject: [PATCH 34/39] xpc: use osx-attr plugin to install configuration attributes --- src/frontends/osx/charon-xpc/charon-xpc.c | 2 +- src/frontends/osx/strongSwan.xcodeproj/project.pbxproj | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/frontends/osx/charon-xpc/charon-xpc.c b/src/frontends/osx/charon-xpc/charon-xpc.c index b4a3d58e1..5a5ac9a6b 100644 --- a/src/frontends/osx/charon-xpc/charon-xpc.c +++ b/src/frontends/osx/charon-xpc/charon-xpc.c @@ -165,7 +165,7 @@ int main(int argc, char *argv[]) if (!charon->initialize(charon, lib->settings->get_str(lib->settings, "charon-xpc.load", "random nonce pem pkcs1 openssl kernel-pfkey kernel-pfroute " - "keychain socket-default eap-identity eap-mschapv2"))) + "keychain socket-default eap-identity eap-mschapv2 osx-attr"))) { exit(SS_RC_INITIALIZATION_FAILED); } diff --git a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj index 00781e947..2eb88b77a 100644 --- a/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj +++ b/src/frontends/osx/strongSwan.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 5BF60F31173405A000E5D608 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */; }; 5BF60F33173405AC00E5D608 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD1CCF21727DE3E00587077 /* Security.framework */; }; 5BF60F3E1734070A00E5D608 /* xpc_dispatch.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B74984C172AA3550041971E /* xpc_dispatch.c */; }; + 5BF60F631743C57500E5D608 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BF60F621743C57500E5D608 /* SystemConfiguration.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -20,16 +21,16 @@ 5B74984E172AA3670041971E /* xpc_dispatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_dispatch.h; sourceTree = ""; }; 5B74989017311AFC0041971E /* xpc_channels.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_channels.h; sourceTree = ""; }; 5B74989117311B200041971E /* xpc_channels.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpc_channels.c; sourceTree = ""; }; - 5BD1CCD11726DB4000587077 /* org.strongswan.charon-xpc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.objfile"; includeInIndex = 0; path = "org.strongswan.charon-xpc"; sourceTree = BUILT_PRODUCTS_DIR; }; - 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 5B7498B7173275D10041971E /* xpc_logger.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xpc_logger.c; sourceTree = ""; }; 5B7498B9173275DD0041971E /* xpc_logger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_logger.h; sourceTree = ""; }; + 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 5BD1CCD61726DB4000587077 /* charon-xpc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "charon-xpc.c"; sourceTree = ""; }; 5BD1CCE01726DCD000587077 /* charon-xpc-Launchd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "charon-xpc-Launchd.plist"; sourceTree = ""; }; 5BD1CCE11726DD9900587077 /* charon-xpc-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "charon-xpc-Info.plist"; sourceTree = ""; }; 5BD1CCEA1727CCA400587077 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = ""; }; 5BD1CCEC1727D7AF00587077 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; }; 5BD1CCF21727DE3E00587077 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 5BF60F621743C57500E5D608 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -37,6 +38,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 5BF60F631743C57500E5D608 /* SystemConfiguration.framework in Frameworks */, 5BF60F31173405A000E5D608 /* CoreFoundation.framework in Frameworks */, 5BF60F33173405AC00E5D608 /* Security.framework in Frameworks */, ); @@ -66,6 +68,7 @@ 5BD1CCAF1726DB0100587077 /* Frameworks */ = { isa = PBXGroup; children = ( + 5BF60F621743C57500E5D608 /* SystemConfiguration.framework */, 5BD1CCF21727DE3E00587077 /* Security.framework */, 5BD1CCEC1727D7AF00587077 /* ServiceManagement.framework */, 5BD1CCD31726DB4000587077 /* CoreFoundation.framework */, From e37c5d46d3fb5ea5c441b809a12c4538ee818ef5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 22 May 2013 17:22:47 +0200 Subject: [PATCH 35/39] xpc: send a "connecting" event when establishing a connection starts --- src/frontends/osx/charon-xpc/xpc_channels.c | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/frontends/osx/charon-xpc/xpc_channels.c b/src/frontends/osx/charon-xpc/xpc_channels.c index 1310b37f6..92a1049fa 100644 --- a/src/frontends/osx/charon-xpc/xpc_channels.c +++ b/src/frontends/osx/charon-xpc/xpc_channels.c @@ -254,6 +254,32 @@ METHOD(listener_t, ike_rekey, bool, return TRUE; } +METHOD(listener_t, ike_state_change, bool, + private_xpc_channels_t *this, ike_sa_t *ike_sa, ike_sa_state_t state) +{ + if (state == IKE_CONNECTING) + { + entry_t *entry; + uintptr_t sa; + + sa = ike_sa->get_unique_id(ike_sa); + this->lock->read_lock(this->lock); + entry = this->channels->get(this->channels, (void*)sa); + if (entry) + { + xpc_object_t msg; + + msg = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_string(msg, "type", "event"); + xpc_dictionary_set_string(msg, "event", "connecting"); + xpc_connection_send_message(entry->conn, msg); + xpc_release(msg); + } + this->lock->unlock(this->lock); + } + return TRUE; +} + METHOD(listener_t, child_updown, bool, private_xpc_channels_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, bool up) @@ -438,6 +464,7 @@ xpc_channels_t *xpc_channels_create() .listener = { .ike_updown = _ike_updown, .ike_rekey = _ike_rekey, + .ike_state_change = _ike_state_change, .child_updown = _child_updown, }, .add = _add, From e7ee45ef38e55c39cd635c33125e2e926d6ff3b0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 27 May 2013 14:08:39 +0200 Subject: [PATCH 36/39] xpc: enable close_ike_on_child_failure --- src/frontends/osx/charon-xpc/charon-xpc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/frontends/osx/charon-xpc/charon-xpc.c b/src/frontends/osx/charon-xpc/charon-xpc.c index 5a5ac9a6b..a1f64112a 100644 --- a/src/frontends/osx/charon-xpc/charon-xpc.c +++ b/src/frontends/osx/charon-xpc/charon-xpc.c @@ -162,6 +162,8 @@ int main(int argc, char *argv[]) lib->settings->set_default_str(lib->settings, "charon-cmd.port", "0"); lib->settings->set_default_str(lib->settings, "charon-cmd.port_nat_t", "0"); + lib->settings->set_default_str(lib->settings, + "charon-cmd.close_ike_on_child_failure", "yes"); if (!charon->initialize(charon, lib->settings->get_str(lib->settings, "charon-xpc.load", "random nonce pem pkcs1 openssl kernel-pfkey kernel-pfroute " From 06e8712cb359635e99b3a792afad441b649ac5f5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 27 May 2013 14:47:27 +0200 Subject: [PATCH 37/39] xpc: forward some risen alerts over XPC to App --- src/frontends/osx/charon-xpc/xpc_channels.c | 57 +++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/frontends/osx/charon-xpc/xpc_channels.c b/src/frontends/osx/charon-xpc/xpc_channels.c index 92a1049fa..9b5260047 100644 --- a/src/frontends/osx/charon-xpc/xpc_channels.c +++ b/src/frontends/osx/charon-xpc/xpc_channels.c @@ -234,6 +234,62 @@ METHOD(xpc_channels_t, add, void, xpc_connection_resume(conn); } +METHOD(listener_t, alert, bool, + private_xpc_channels_t *this, ike_sa_t *ike_sa, alert_t alert, va_list args) +{ + const char *desc; + + switch (alert) + { + case ALERT_LOCAL_AUTH_FAILED: + desc = "local-auth"; + break; + case ALERT_PEER_AUTH_FAILED: + desc = "remote-auth"; + break; + case ALERT_PEER_ADDR_FAILED: + desc = "dns"; + break; + case ALERT_PEER_INIT_UNREACHABLE: + desc = "unreachable"; + break; + case ALERT_RETRANSMIT_SEND_TIMEOUT: + desc = "timeout"; + break; + case ALERT_PROPOSAL_MISMATCH_IKE: + case ALERT_PROPOSAL_MISMATCH_CHILD: + desc = "proposal-mismatch"; + break; + case ALERT_TS_MISMATCH: + desc = "ts-mismatch"; + break; + default: + return TRUE; + } + if (ike_sa) + { + entry_t *entry; + uintptr_t sa; + + sa = ike_sa->get_unique_id(ike_sa); + this->lock->read_lock(this->lock); + entry = this->channels->get(this->channels, (void*)sa); + if (entry) + { + xpc_object_t msg; + + msg = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_string(msg, "type", "event"); + xpc_dictionary_set_string(msg, "event", "alert"); + xpc_dictionary_set_string(msg, "alert", desc); + xpc_connection_send_message(entry->conn, msg); + xpc_release(msg); + } + this->lock->unlock(this->lock); + } + return TRUE; +} + METHOD(listener_t, ike_rekey, bool, private_xpc_channels_t *this, ike_sa_t *old, ike_sa_t *new) { @@ -462,6 +518,7 @@ xpc_channels_t *xpc_channels_create() INIT(this, .public = { .listener = { + .alert = _alert, .ike_updown = _ike_updown, .ike_rekey = _ike_rekey, .ike_state_change = _ike_state_change, From 7f1adbe94e84d2e76430cf354084af0e296dbeb5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 29 May 2013 14:50:47 +0200 Subject: [PATCH 38/39] xpc: use -idirafter to build against openssl headers from /usr/include --- src/frontends/osx/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/frontends/osx/README.md b/src/frontends/osx/README.md index ccb46ab9d..98cd7221b 100644 --- a/src/frontends/osx/README.md +++ b/src/frontends/osx/README.md @@ -22,10 +22,10 @@ needed to run the built App. Before building the Xcode project, the strongSwan base tree must be built using a monolithic and static build. This can be achieved on OS X by using: - LDFLAGS="-all_load" \ - CFLAGS="-I/usr/include -DOPENSSL_NO_CMS -O2 -Wall -Wno-format -Wno-pointer-sign" \ - ./configure --prefix=/opt/local --enable-monolithic \ - --disable-shared --enable-static --disable-defaults \ + LDFLAGS="-all_load -L/opt/local/lib" \ + CFLAGS="-idirafter /opt/local/include -O2 -Wall -Wno-format -Wno-pointer-sign" + ./configure --enable-monolithic --disable-shared --enable-static \ + --disable-defaults \ --enable-openssl --enable-kernel-pfkey --enable-kernel-pfroute \ --enable-eap-mschapv2 --enable-eap-identity --enable-nonce \ --enable-random --enable-pkcs1 --enable-pem --enable-socket-default \ From b9c47eae0668ea0c736bdbd1564631d82ab76763 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 26 Jun 2013 10:37:19 +0200 Subject: [PATCH 39/39] xpc: allow easy copy & pase of ./configure instructions --- src/frontends/osx/README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/frontends/osx/README.md b/src/frontends/osx/README.md index 98cd7221b..bd24cce1b 100644 --- a/src/frontends/osx/README.md +++ b/src/frontends/osx/README.md @@ -22,15 +22,15 @@ needed to run the built App. Before building the Xcode project, the strongSwan base tree must be built using a monolithic and static build. This can be achieved on OS X by using: - LDFLAGS="-all_load -L/opt/local/lib" \ - CFLAGS="-idirafter /opt/local/include -O2 -Wall -Wno-format -Wno-pointer-sign" - ./configure --enable-monolithic --disable-shared --enable-static \ - --disable-defaults \ - --enable-openssl --enable-kernel-pfkey --enable-kernel-pfroute \ - --enable-eap-mschapv2 --enable-eap-identity --enable-nonce \ - --enable-random --enable-pkcs1 --enable-pem --enable-socket-default \ - --enable-xauth-generic --enable-keychain --enable-charon \ - --enable-ikev1 --enable-ikev2 + LDFLAGS="-all_load -L/opt/local/lib" \ + CFLAGS="-idirafter /opt/local/include -O2 -Wall -Wno-format -Wno-pointer-sign" \ + ./configure --enable-monolithic --disable-shared --enable-static \ + --disable-defaults \ + --enable-openssl --enable-kernel-pfkey --enable-kernel-pfroute \ + --enable-eap-mschapv2 --enable-eap-identity --enable-nonce \ + --enable-random --enable-pkcs1 --enable-pem --enable-socket-default \ + --enable-xauth-generic --enable-keychain --enable-charon \ + --enable-ikev1 --enable-ikev2 followed by calling make (no need to make install).