From: Martin Willi Date: Wed, 1 May 2013 08:38:46 +0000 (+0200) Subject: keychain: monitor changes in the system keychain, reload when necessary X-Git-Tag: 5.1.0rc1~25^2~27 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=57dce77ba618d86e715b177220067196720ad565;p=thirdparty%2Fstrongswan.git keychain: monitor changes in the system keychain, reload when necessary --- diff --git a/src/libstrongswan/plugins/keychain/keychain_creds.c b/src/libstrongswan/plugins/keychain/keychain_creds.c index 9182d2af0a..546d3efe12 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; }