Git commit 19576a02138dd21beaf943b4d4a400b188ebc9c4 by Valentin Rusu. Committed on 12/08/2015 at 15:29. Pushed by vrusu into branch 'master'. Working on api tests M +7 -1 autotests/api/ksecretsservice-test.cpp M +1 -1 src/runtime/ksecrets_store/CMakeLists.txt R +43 -30 src/runtime/ksecrets_store/ksecrets_credentials.cpp [from: s= rc/runtime/ksecrets_store/ksecrets_credentials.c - 078% similarity] M +1 -1 src/runtime/ksecrets_store/ksecrets_credentials.h M +136 -95 src/runtime/pam-ksecrets/pam_ksecrets.c http://commits.kde.org/ksecrets/19576a02138dd21beaf943b4d4a400b188ebc9c4 diff --git a/autotests/api/ksecretsservice-test.cpp b/autotests/api/ksecret= sservice-test.cpp index c16c424..27d967f 100644 --- a/autotests/api/ksecretsservice-test.cpp +++ b/autotests/api/ksecretsservice-test.cpp @@ -48,6 +48,7 @@ KSecretServiceTest::KSecretServiceTest(QObject* parent) = KSecrets::CollectionPtr collection; KSharedConfig::Ptr sharedConfig; +QString secretsFilePath; = void KSecretServiceTest::initTestCase() { @@ -58,6 +59,11 @@ void KSecretServiceTest::initTestCase() QStandardPaths::setTestModeEnabled(true); sharedConfig =3D KSharedConfig::openConfig(QLatin1String("ksecretsrc")= ); = + secretsFilePath =3D QStandardPaths::writableLocation(QStandardPaths::D= ataLocation); + QVERIFY(QDir::home().mkpath(secretsFilePath)); + secretsFilePath +=3D QLatin1Literal("/ksecrets-test.data"); + qDebug() << "secrets store path: " << secretsFilePath; + setupKeyring(); = collection =3D KSecrets::Service::findCollection( @@ -170,7 +176,7 @@ void KSecretServiceTest::setupKeyring() QVERIFY(-1 =3D=3D key); = /* now go setup user's keyring */ - QVERIFY(kss_set_credentials(testUser.constData(), testPass.constData()= )); + QVERIFY(kss_set_credentials(testUser.constData(), testPass.constData()= , secretsFilePath.toLocal8Bit().constData())); = // the right keys should be present into the kernel keyring key =3D request_key("user", KEYNAME_ENCRYPTING, 0, KEY_SPEC_SESSION_KE= YRING); diff --git a/src/runtime/ksecrets_store/CMakeLists.txt b/src/runtime/ksecre= ts_store/CMakeLists.txt index 82b5ad1..36fd30d 100644 --- a/src/runtime/ksecrets_store/CMakeLists.txt +++ b/src/runtime/ksecrets_store/CMakeLists.txt @@ -9,7 +9,7 @@ ecm_setup_version(${KF5_VERSION} VARIABLE_PREFIX KSECRETS_B= ACKEND PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5Sec= retsStoreConfigVersion.cmake") = set(ksecrets_store_SRC - ksecrets_credentials.c + ksecrets_credentials.cpp ksecrets_store.cpp) = add_library(ksecrets_store SHARED ${ksecrets_store_SRC}) diff --git a/src/runtime/ksecrets_store/ksecrets_credentials.c b/src/runtim= e/ksecrets_store/ksecrets_credentials.cpp similarity index 78% rename from src/runtime/ksecrets_store/ksecrets_credentials.c rename to src/runtime/ksecrets_store/ksecrets_credentials.cpp index 155796a..96e4107 100644 --- a/src/runtime/ksecrets_store/ksecrets_credentials.c +++ b/src/runtime/ksecrets_store/ksecrets_credentials.cpp @@ -18,6 +18,7 @@ * Boston, MA 02110-1301, USA. */ #include "ksecrets_credentials.h" +#include "ksecrets_store.h" = #include #include @@ -28,7 +29,9 @@ #include #include #include +extern "C" { #include +} = #define GCRPYT_NO_DEPRECATED #include @@ -42,14 +45,16 @@ #define KSECRETS_ITERATIONS 50000 = /* these functions are implemented in config.cpp next to this file */ -extern const char* prepare_secret_file_location(const char*); -extern const char* get_keyname_encrypting(); -extern const char* get_keyname_mac(); +extern "C" const char* prepare_secret_file_location(const char*); +extern "C" const char* get_keyname_encrypting(); +extern "C" const char* get_keyname_mac(); = -#define false 0 -#define true 1 +#define FALSE 0 +#define TRUE 1 +#define UNUSED(x) (void)(x) = -int kss_init_gcry() +extern "C" +int KSECRETS_STORE_EXPORT kss_init_gcry() { syslog(KSS_LOG_DEBUG, "ksecrets: setting-up grypt library"); if (!gcry_check_version(GCRYPT_REQUIRED_VERSION)) { @@ -69,14 +74,15 @@ int kss_init_gcry() return 1; } = -int kss_derive_keys(const char* salt, const char* password, char* encrypti= on_key, char* mac_key, size_t keySize) +extern "C" +int KSECRETS_STORE_EXPORT kss_derive_keys(const char* salt, const char* pa= ssword, char* encryption_key, char* mac_key, size_t keySize) { gpg_error_t gcryerr; = syslog(KSS_LOG_INFO, "kss_set_credentials: attempting keys generation"= ); if (0 =3D=3D password) { syslog(KSS_LOG_INFO, "NULL password given. ksecrets will not be av= ailable."); - return false; + return FALSE; } = /* generate both encryption and MAC key in one go */ @@ -84,24 +90,25 @@ int kss_derive_keys(const char* salt, const char* passw= ord, char* encryption_key gcryerr =3D gcry_kdf_derive(password, strlen(password), GCRY_KDF_ITERS= ALTED_S2K, GCRY_MD_SHA512, salt, 8, KSECRETS_ITERATIONS, 2 * keySize, keys); if (gcryerr) { syslog(KSS_LOG_ERR, "key derivation failed: code 0x%0x: %s/%s", gc= ryerr, gcry_strsource(gcryerr), gcry_strerror(gcryerr)); - return false; + return FALSE; } = memcpy(encryption_key, keys, keySize); memcpy(mac_key, keys + keySize, keySize); syslog(KSS_LOG_INFO, "successuflly generated ksecrets keys from user p= assword."); = - return true; + return TRUE; } = -int kss_store_keys(const char* encryption_key, const char* mac_key, size_t= keySize) +extern "C" +int KSECRETS_STORE_EXPORT kss_store_keys(const char* encryption_key, const= char* mac_key, size_t keySize) { key_serial_t ks; const char* key_name =3D get_keyname_encrypting(); ks =3D add_key("user", key_name, encryption_key, keySize, KEY_SPEC_SES= SION_KEYRING); if (-1 =3D=3D ks) { syslog(KSS_LOG_ERR, "ksecrets: cannot store encryption key in kern= el keyring: errno=3D%d (%m)", errno); - return false; + return FALSE; } syslog(KSS_LOG_DEBUG, "ksecrets: encrpyting key now in kernel keyring = with id %d and desc %s", ks, key_name); = @@ -109,10 +116,10 @@ int kss_store_keys(const char* encryption_key, const = char* mac_key, size_t keySi ks =3D add_key("user", key_name, mac_key, keySize, KEY_SPEC_SESSION_KE= YRING); if (-1 =3D=3D ks) { syslog(KSS_LOG_ERR, "ksecrets: cannot store mac key in kernel keyr= ing: errno=3D%d (%m)", errno); - return false; + return FALSE; } syslog(KSS_LOG_DEBUG, "ksecrets: mac key now in kernel keyring with id= %d and desc %s", ks, key_name); - return true; + return TRUE; } = int kss_keys_already_there() @@ -121,61 +128,67 @@ int kss_keys_already_there() key =3D request_key("user", get_keyname_encrypting(), 0, KEY_SPEC_SESS= ION_KEYRING); if (-1 =3D=3D key) { syslog(KSS_LOG_DEBUG, "request_key failed with errno %d (%m), so a= ssuming ksecrets not yet loaded", errno); - return false; + return FALSE; } syslog(KSS_LOG_DEBUG, "ksecrets: keys already in keyring"); - return true; + return TRUE; } = -int kss_set_credentials(const char* user_name, const char* password) +extern "C" +int KSECRETS_STORE_EXPORT kss_set_credentials(const char* user_name, const= char* password, const char* path) { - syslog(KSS_LOG_DEBUG, "kss_set_credentials for %s", user_name); + UNUSED(user_name); if (kss_keys_already_there()) - return true; + return TRUE; = + KSecretsStore secretsStore; + auto setupres =3D secretsStore.setup(path, password); = - return true; + return setupres.get() ? 1 : 0; } = -int kss_delete_credentials() +extern "C" +int KSECRETS_STORE_EXPORT kss_delete_credentials() { syslog(KSS_LOG_INFO, "kss_delete_credentials"); key_serial_t key; key =3D request_key("user", get_keyname_encrypting(), 0, KEY_SPEC_SESS= ION_KEYRING); if (-1 =3D=3D key) { syslog(KSS_LOG_DEBUG, "request_key failed with errno %d (%m), cann= ot purge encrypting key", errno); - return false; + return FALSE; } long res =3D keyctl(KEYCTL_REVOKE, key); if (-1 =3D=3D res) { syslog(KSS_LOG_DEBUG, "removing key failed with errno %d (%m), can= not purge encrypting key", errno); - return false; + return FALSE; } = key =3D request_key("user", get_keyname_mac(), 0, KEY_SPEC_SESSION_KEY= RING); if (-1 =3D=3D key) { syslog(KSS_LOG_DEBUG, "request_key failed with errno %d (%m), cann= ot purge mac key", errno); - return false; + return FALSE; } res =3D keyctl(KEYCTL_REVOKE, key); if (-1 =3D=3D res) { syslog(KSS_LOG_DEBUG, "removing key failed with errno %d (%m), can= not purge mac key", errno); - return false; + return FALSE; } - return true; + return TRUE; } = -int kss_can_change_password() +extern "C" +int KSECRETS_STORE_EXPORT kss_can_change_password() { /* nothing to do for the moment */ syslog(KSS_LOG_INFO, "kss_can_change_password"); - return true; + return TRUE; } = -int kss_change_password(const char* new_password) +extern "C" +int KSECRETS_STORE_EXPORT kss_change_password(const char* new_password) { syslog(LOG_INFO, "kss_change_password"); - return true; + return TRUE; } /* vim: tw=3D220 ts=3D4 */ diff --git a/src/runtime/ksecrets_store/ksecrets_credentials.h b/src/runtim= e/ksecrets_store/ksecrets_credentials.h index 0242a24..2b979b5 100644 --- a/src/runtime/ksecrets_store/ksecrets_credentials.h +++ b/src/runtime/ksecrets_store/ksecrets_credentials.h @@ -27,7 +27,7 @@ extern "C" { #endif = -int kss_set_credentials(const char* user_name, const char* password); +int kss_set_credentials(const char* user_name, const char* password, const= char* path); = int kss_delete_credentials(); = diff --git a/src/runtime/pam-ksecrets/pam_ksecrets.c b/src/runtime/pam-ksec= rets/pam_ksecrets.c index eaf8f21..bb97632 100644 --- a/src/runtime/pam-ksecrets/pam_ksecrets.c +++ b/src/runtime/pam-ksecrets/pam_ksecrets.c @@ -9,133 +9,174 @@ #include #include #include +#include +#include +#include +#include +#include = #define UNUSED(x) (void)(x) = const char* password; = -/* these extern functions are implemented in ksecrets_store_bridge.cpp */ -extern int kss_set_credentials(const char*, const char*); -extern int kss_delete_credentials(); -extern int kss_can_change_password(); -extern int kss_change_password(const char*); - PAM_EXTERN int pam_sm_authenticate( pam_handle_t* pamh, int flags, int argc, const char** argv) { - pam_syslog(pamh, LOG_INFO, "pam_sm_authenticate flags=3D%X", flags); - UNUSED(flags); - UNUSED(argc); - UNUSED(argv); - - password =3D 0; - int result =3D pam_get_item(pamh, PAM_AUTHTOK, (const void**)&password); - if (result !=3D PAM_SUCCESS) { - pam_syslog(pamh, LOG_ERR, "Couldn't get password %s", - pam_strerror(pamh, result)); - } - - /* this module does not participate to the user authentication process */ - return PAM_IGNORE; + pam_syslog(pamh, LOG_INFO, "pam_sm_authenticate flags=3D%X", flags); + UNUSED(flags); + UNUSED(argc); + UNUSED(argv); + + password =3D 0; + int result =3D pam_get_item(pamh, PAM_AUTHTOK, (const void**)&password= ); + if (result !=3D PAM_SUCCESS) { + pam_syslog(pamh, LOG_ERR, "Couldn't get password %s", + pam_strerror(pamh, result)); + } + + /* this module does not participate to the user authentication process= */ + return PAM_IGNORE; } = +/** + * The module PAM module configuration should specify the location of the + * secrets file. The location should contain only the part of the path + * relative to the user's $HOME directory. So, if you'd like to have secre= ts + * managed in, say, $HOME/owncloud/ksecrets.data then the pam configuration + * file should contain something like this: + * + * auth required pam_ksecrets.so owncloud/ksecrets.data + * + * As you may have guessed, the configuration will be the same for all the + * users, and that cannot be changed from one user to another, at least no= t in + * this version of pam_ksecrets. + * + * If nothing is specified, then the default path will be + * $HOME/.local/share/ksecrets/ksecrets.data + * + * The location should point to an actual file. If it's a symlink, then the + * store handling routine will fail. + */ PAM_EXTERN int pam_sm_setcred( pam_handle_t* pamh, int flags, int argc, const char** argv) { - UNUSED(argc); - UNUSED(argv); - pam_syslog(pamh, LOG_INFO, "pam_sm_setcred flags=3D%X", flags); - if (flags & PAM_ESTABLISH_CRED) { - if (0 =3D=3D password) - return PAM_CRED_UNAVAIL; - - const char* user_name; - user_name =3D 0; - int result =3D pam_get_item(pamh, PAM_USER, (const void**)&user_name); - if (result !=3D PAM_SUCCESS) { - pam_syslog(pamh, LOG_ERR, "Couldn't get password %s", - pam_strerror(pamh, result)); + UNUSED(argc); + UNUSED(argv); + pam_syslog(pamh, LOG_INFO, "pam_sm_setcred flags=3D%X", flags); + if (flags & PAM_ESTABLISH_CRED) { + if (0 =3D=3D password) + return PAM_CRED_UNAVAIL; + + const char* user_name; + user_name =3D 0; + int result =3D pam_get_item(pamh, PAM_USER, (const void**)&user_na= me); + if (result !=3D PAM_SUCCESS) { + pam_syslog(pamh, LOG_ERR, "Couldn't get password %s", + pam_strerror(pamh, result)); + return PAM_CRED_UNAVAIL; + } + + struct passwd *pwd; + pwd =3D getpwnam(user_name); + if (pwd =3D=3D 0) { + pam_syslog(pamh, LOG_ERR, "Couldn't get user passwd info %d (%= m)", errno); + return PAM_CRED_ERR; + } + + char secrets_path[PATH_MAX]; + memset(secrets_path, 0, sizeof(secrets_path)/sizeof(secrets_path[0= ])); + strncpy(secrets_path, pwd->pw_dir, PATH_MAX); + static const char *defaultPath =3D ".local/share/ksecrets/ksecrets= .data"; + if (argc =3D=3D 1 && argv[0] !=3D 0) { + strncat(secrets_path, argv[0], PATH_MAX - strlen(secrets_path)= -1); + } else { + strncat(secrets_path, defaultPath, PATH_MAX - strlen(secrets_p= ath) -1); + } + pam_syslog(pamh, LOG_INFO, "ksecrets: setting secrets path to %s",= secrets_path); + + if (!kss_set_credentials(user_name, password, secrets_path)) { + pam_syslog( + pamh, LOG_ERR, "ksecrets credentials could not be set."); + return PAM_CRED_ERR; + } + return PAM_SUCCESS; } - if (!kss_set_credentials(user_name, password)) { - pam_syslog(pamh, LOG_ERR, "ksecrets credentials could not be set."); - return PAM_CRED_ERR; + if (flags & PAM_DELETE_CRED) { + kss_delete_credentials(); } - return PAM_SUCCESS; - } - if (flags & PAM_DELETE_CRED) { - kss_delete_credentials(); - } - return PAM_IGNORE; + return PAM_IGNORE; } = PAM_EXTERN int pam_sm_open_session( pam_handle_t* pamh, int flags, int argc, const char** argv) { - UNUSED(pamh); - UNUSED(flags); - UNUSED(argc); - UNUSED(argv); - /* not used */ - return PAM_IGNORE; + UNUSED(pamh); + UNUSED(flags); + UNUSED(argc); + UNUSED(argv); + /* not used */ + return PAM_IGNORE; } = PAM_EXTERN int pam_sm_close_session( pam_handle_t* pamh, int flags, int argc, const char** argv) { - UNUSED(pamh); - UNUSED(flags); - UNUSED(argc); - UNUSED(argv); - /* not used */ - return PAM_SUCCESS; + UNUSED(pamh); + UNUSED(flags); + UNUSED(argc); + UNUSED(argv); + /* not used */ + return PAM_SUCCESS; } = PAM_EXTERN int pam_sm_chauthtok( pam_handle_t* pamh, int flags, int argc, const char** argv) { - UNUSED(argc); - UNUSED(argv); - pam_syslog(pamh, LOG_INFO, "pam_sm_chauthtok flags=3D%X", flags); - - if (flags & PAM_PRELIM_CHECK) { - pam_syslog(pamh, LOG_INFO, "pam_sm_chauthtok preliminary check"); - if (kss_can_change_password()) { - return PAM_SUCCESS; - } - else { - pam_syslog(pamh, LOG_ERR, "pam_sm_chauthtok prelimnary check failed " - "because ksecrets cannot be locked"); - return PAM_AUTHTOK_LOCK_BUSY; - } - } - - if (flags & PAM_UPDATE_AUTHTOK) { - pam_syslog(pamh, LOG_INFO, - "pam_sm_chauthtok attempt updating ksecret service key"); - - const char* password; - password =3D 0; - int result =3D pam_get_item(pamh, PAM_AUTHTOK, (const void**)&password= ); - if (result !=3D PAM_SUCCESS) { - pam_syslog(pamh, LOG_ERR, "Couldn't get password %s", - pam_strerror(pamh, result)); - return PAM_IGNORE; - } - - if (0 =3D=3D password) { - pam_syslog( - pamh, LOG_WARNING, "pam_sm_authenticate got NULL password! "); - return PAM_AUTHTOK_ERR; + UNUSED(argc); + UNUSED(argv); + pam_syslog(pamh, LOG_INFO, "pam_sm_chauthtok flags=3D%X", flags); + + if (flags & PAM_PRELIM_CHECK) { + pam_syslog(pamh, LOG_INFO, "pam_sm_chauthtok preliminary check"); + if (kss_can_change_password()) { + return PAM_SUCCESS; + } + else { + pam_syslog(pamh, LOG_ERR, + "pam_sm_chauthtok prelimnary check failed " + "because ksecrets cannot be locked"); + return PAM_AUTHTOK_LOCK_BUSY; + } } = - if (kss_change_password(password)) - return PAM_SUCCESS; - else { - pam_syslog(pamh, LOG_ERR, "ksecrets service failed to update the key= s. " - "Aborting password change."); - return PAM_AUTHTOK_ERR; + if (flags & PAM_UPDATE_AUTHTOK) { + pam_syslog(pamh, LOG_INFO, + "pam_sm_chauthtok attempt updating ksecret service key"); + + const char* password; + password =3D 0; + int result =3D pam_get_item(pamh, PAM_AUTHTOK, (const void**)&pass= word); + if (result !=3D PAM_SUCCESS) { + pam_syslog(pamh, LOG_ERR, "Couldn't get password %s", + pam_strerror(pamh, result)); + return PAM_IGNORE; + } + + if (0 =3D=3D password) { + pam_syslog( + pamh, LOG_WARNING, "pam_sm_authenticate got NULL password!= "); + return PAM_AUTHTOK_ERR; + } + + if (kss_change_password(password)) + return PAM_SUCCESS; + else { + pam_syslog(pamh, LOG_ERR, + "ksecrets service failed to update the keys. " + "Aborting password change."); + return PAM_AUTHTOK_ERR; + } } - } = - return PAM_IGNORE; + return PAM_IGNORE; }