[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [ksecrets] /: Backend setup now works
From: Valentin Rusu <kde () rusu ! info>
Date: 2015-08-13 8:41:35
Message-ID: E1ZPo4t-0002gq-QH () scm ! kde ! org
[Download RAW message or body]
Git commit fff18872cc08cb8bb9f8e1a0db61c70ca4b1d29b by Valentin Rusu.
Committed on 13/08/2015 at 08:34.
Pushed by vrusu into branch 'master'.
Backend setup now works
M +1 -3 autotests/api/CMakeLists.txt
M +4 -1 autotests/ksecrets_store/CMakeLists.txt
M +18 -7 autotests/ksecrets_store/ksecrets_store_test.cpp
M +6 -2 src/runtime/ksecrets_store/ksecrets_credentials.cpp
M +43 -39 src/runtime/ksecrets_store/ksecrets_store.cpp
M +31 -22 src/runtime/ksecrets_store/ksecrets_store.h
M +6 -4 src/runtime/ksecrets_store/ksecrets_store_p.h
http://commits.kde.org/ksecrets/fff18872cc08cb8bb9f8e1a0db61c70ca4b1d29b
diff --git a/autotests/api/CMakeLists.txt b/autotests/api/CMakeLists.txt
index 6dc2343..9cc791c 100644
--- a/autotests/api/CMakeLists.txt
+++ b/autotests/api/CMakeLists.txt
@@ -4,8 +4,6 @@ include(ECMAddTests)
find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Test)
-find_package(LibGcrypt 1.6.0 REQUIRED)
-
include_directories(
${CMAKE_SOURCE_DIR}/src/runtime/ksecrets_store
${CMAKE_BINARY_DIR}/src/runtime/ksecrets_store
@@ -20,6 +18,6 @@ find_package(KF5 REQUIRED CoreAddons)
ecm_add_test(
ksecretsservice-test.cpp
- LINK_LIBRARIES KF5::Secrets Qt5::Test KF5::Secrets KF5::CoreAddons \
ksecrets_store ${LIBGCRYPT_LIBRARIES} keyutils + LINK_LIBRARIES \
Qt5::Test KF5::Secrets KF5::CoreAddons ksecrets_store keyutils )
diff --git a/autotests/ksecrets_store/CMakeLists.txt \
b/autotests/ksecrets_store/CMakeLists.txt index facb282..b0f916b 100644
--- a/autotests/ksecrets_store/CMakeLists.txt
+++ b/autotests/ksecrets_store/CMakeLists.txt
@@ -11,8 +11,11 @@ if(NOT Qt5Test_FOUND)
return()
endif()
+find_package(KF5CoreAddons ${KF5_DEP_VERSION} REQUIRED)
+find_package(KF5Config ${KF5_DEP_VERSION} REQUIRED)
+
ecm_add_test(
ksecrets_store_test.cpp
- LINK_LIBRARIES Qt5::Test ksecrets_store
+ LINK_LIBRARIES Qt5::Test KF5::CoreAddons KF5::ConfigCore \
ksecrets_store )
diff --git a/autotests/ksecrets_store/ksecrets_store_test.cpp \
b/autotests/ksecrets_store/ksecrets_store_test.cpp index 353f10a..9465e63 \
100644
--- a/autotests/ksecrets_store/ksecrets_store_test.cpp
+++ b/autotests/ksecrets_store/ksecrets_store_test.cpp
@@ -24,10 +24,13 @@
#include <ksecrets_store.h>
#include <QtTest/QtTest>
#include <QtCore/QDir>
+#include <ksharedconfig.h>
+#include <kconfiggroup.h>
QTEST_GUILESS_MAIN(KSecretServiceStoreTest);
-const char* test_file_path = "~/.qttest/ksecretsbackend-test.dat";
+KSharedConfig::Ptr sharedConfig;
+QString secretsFilePath;
KSecretServiceStoreTest::KSecretServiceStoreTest(QObject* parent)
: QObject(parent)
@@ -36,21 +39,29 @@ KSecretServiceStoreTest::KSecretServiceStoreTest(QObject* \
parent)
void KSecretServiceStoreTest::initTestCase()
{
+ QStandardPaths::setTestModeEnabled(true);
+ sharedConfig = KSharedConfig::openConfig(QLatin1String("ksecretsrc"));
+
+ secretsFilePath = \
QStandardPaths::writableLocation(QStandardPaths::DataLocation); + \
QVERIFY(QDir::home().mkpath(secretsFilePath)); + secretsFilePath += \
QLatin1Literal("/ksecrets-test.data"); + qDebug() << "secrets store \
path: " << secretsFilePath; // create a test file here and performe the \
real open test below KSecretsStore backend;
- auto setupfut = backend.setup(test_file_path, "test");
+ auto setupfut = \
backend.setup(secretsFilePath.toLocal8Bit().constData(), false); + \
QVERIFY(setupfut.get()); + auto credfut = backend.setCredentials("test", \
"ksecrets-test:crypt", "ksecrets-test:mac"); + QVERIFY(credfut.get());
}
void KSecretServiceStoreTest::cleanupTestCase()
{
- QDir::home().remove(QLatin1Literal(test_file_path));
+ QDir::home().remove(secretsFilePath);
}
void KSecretServiceStoreTest::testOpen()
{
KSecretsStore backend;
- auto setupfut = backend.setup(test_file_path, "test");
- auto openfut = backend.open(true);
- auto openres = openfut.get();
- QVERIFY(openres.status_ == KSecretsStore::StoreStatus::Good);
+ auto setupfut = \
backend.setup(secretsFilePath.toLocal8Bit().constData()); + \
QVERIFY(setupfut.get()); }
diff --git a/src/runtime/ksecrets_store/ksecrets_credentials.cpp \
b/src/runtime/ksecrets_store/ksecrets_credentials.cpp index \
96e4107..b59352e 100644
--- a/src/runtime/ksecrets_store/ksecrets_credentials.cpp
+++ b/src/runtime/ksecrets_store/ksecrets_credentials.cpp
@@ -142,9 +142,13 @@ int KSECRETS_STORE_EXPORT kss_set_credentials(const \
char* user_name, const char* return TRUE;
KSecretsStore secretsStore;
- auto setupres = secretsStore.setup(path, password);
+ auto setupres = secretsStore.setup(path);
+ if (!setupres.get()) {
+ return FALSE;
+ }
- return setupres.get() ? 1 : 0;
+ auto credres = secretsStore.setCredentials(password);
+ return credres.get() ? TRUE: FALSE;
}
extern "C"
diff --git a/src/runtime/ksecrets_store/ksecrets_store.cpp \
b/src/runtime/ksecrets_store/ksecrets_store.cpp index df43001..8da20a4 \
100644
--- a/src/runtime/ksecrets_store/ksecrets_store.cpp
+++ b/src/runtime/ksecrets_store/ksecrets_store.cpp
@@ -52,6 +52,7 @@ KSecretsStorePrivate::KSecretsStorePrivate(KSecretsStore* \
b) : b_(b)
{
status_ = KSecretsStore::StoreStatus::JustCreated;
+ memset(&fileHead_, 0, sizeof(fileHead_));
}
KSecretsStore::KSecretsStore()
@@ -61,11 +62,11 @@ KSecretsStore::KSecretsStore()
KSecretsStore::~KSecretsStore() = default;
-std::future<KSecretsStore::SetupResult> KSecretsStore::setup(const char* \
path, const char* password, const char* keyNameEcrypting, const char* \
keyNameMac) +std::future<KSecretsStore::SetupResult> \
KSecretsStore::setup(const char* path, bool readOnly /* = true */) {
// sanity checks
if (d->status_ != StoreStatus::JustCreated) {
- return std::async(std::launch::deferred, []() { return \
SetupResult{ StoreStatus::IncorrectState, -1 }; }); + return \
std::async(std::launch::deferred, []() { return SetupResult({ \
StoreStatus::IncorrectState, -1 }); }); }
if (path == nullptr || strlen(path) == 0) {
return std::async(std::launch::deferred, []() { return \
SetupResult{ StoreStatus::NoPathGiven, 0 }; }); @@ -75,7 +76,8 @@ \
std::future<KSecretsStore::SetupResult> KSecretsStore::setup(const char* \
path, c struct stat buf;
if (stat(path, &buf) != 0) {
auto err = errno;
- if (ENOENT == err) {
+ // when asking read only access, creating file is not possible
+ if (ENOENT == err && !readOnly) {
shouldCreateFile = true;
}
else {
@@ -89,16 +91,12 @@ std::future<KSecretsStore::SetupResult> \
KSecretsStore::setup(const char* path, c }
}
- ::keyNameEncrypting = keyNameEcrypting;
- ::keyNameMac = keyNameMac;
-
auto localThis = this;
std::string filePath = path;
- std::string pwd = password;
- return std::async(std::launch::async, [localThis, filePath, \
shouldCreateFile, pwd]() { return localThis->d->setup(filePath, \
shouldCreateFile, pwd); }); + return std::async(std::launch::async, \
[localThis, filePath, shouldCreateFile, readOnly]() { return \
localThis->d->setup(filePath, shouldCreateFile, readOnly); }); }
-KSecretsStore::SetupResult KSecretsStorePrivate::setup(const std::string& \
path, bool shouldCreateFile, const std::string& password) \
+KSecretsStore::SetupResult KSecretsStorePrivate::setup(const std::string& \
path, bool shouldCreateFile, bool readOnly) {
if (shouldCreateFile) {
auto createres = createFile(path);
@@ -106,21 +104,38 @@ KSecretsStore::SetupResult \
KSecretsStorePrivate::setup(const std::string& path,
return setStoreStatus(KSecretsStore::SetupResult({ \
KSecretsStore::StoreStatus::SystemError, createres })); }
}
+ secretsFile_.filePath_ = path;
+ secretsFile_.readOnly_ = readOnly;
+ return open(!readOnly);
+}
+
+std::future<KSecretsStore::CredentialsResult> \
KSecretsStore::setCredentials(const char* password, const char* \
keyNameEncrypting, const char* keyNameMac) +{
+ ::keyNameEncrypting = keyNameEncrypting;
+ ::keyNameMac = keyNameMac;
+
+ std::string pwd = password;
+ auto localThis = this;
+ return std::async(std::launch::async, [localThis, pwd]() { return \
localThis->d->setCredentials(pwd); }); +}
+
+KSecretsStore::CredentialsResult \
KSecretsStorePrivate::setCredentials(const std::string& password) +{
+ using Result = KSecretsStore::CredentialsResult;
if (!kss_init_gcry()) {
- return setStoreStatus(KSecretsStore::SetupResult({ \
KSecretsStore::StoreStatus::CannotInitGcrypt, -1 })); + return \
setStoreStatus(Result({ KSecretsStore::StoreStatus::CannotInitGcrypt, -1 \
})); }
// FIXME this should be adjusted on platforms where kernel keyring is \
not available and store the keys elsewhere char \
encryption_key[KSECRETS_KEYSIZE]; char mac_key[KSECRETS_KEYSIZE];
if (!kss_derive_keys(salt(), password.c_str(), encryption_key, \
mac_key, KSECRETS_KEYSIZE)) {
- return setStoreStatus(KSecretsStore::SetupResult({ \
KSecretsStore::StoreStatus::CannotDeriveKeys, -1 })); + return \
setStoreStatus(Result({ KSecretsStore::StoreStatus::CannotDeriveKeys, -1 \
})); }
if (!kss_store_keys(encryption_key, mac_key, KSECRETS_KEYSIZE)) {
- return setStoreStatus(KSecretsStore::SetupResult({ \
KSecretsStore::StoreStatus::CannotStoreKeys, -1 })); + return \
setStoreStatus(Result({ KSecretsStore::StoreStatus::CannotStoreKeys, errno \
})); }
- secretsFile_.filePath_ = path;
- return setStoreStatus(KSecretsStore::SetupResult({ \
KSecretsStore::StoreStatus::SetupDone, 0 })); + return \
setStoreStatus(Result({ KSecretsStore::StoreStatus::CredentialsSet, 0 })); \
}
char fileMagic[] = { 'k', 's', 'e', 'c', 'r', 'e', 't', 's' };
@@ -139,47 +154,35 @@ int KSecretsStorePrivate::createFile(const \
std::string& path) gcry_randomize(emptyFileData.iv, IV_SIZE, \
GCRY_STRONG_RANDOM);
int res = 0;
- if (fwrite(&emptyFileData, sizeof(emptyFileData), 1, f) != \
sizeof(emptyFileData)) {
- res = -1; // FIXME is errno available here?
+ if (fwrite(&emptyFileData, 1, sizeof(emptyFileData), f) != \
sizeof(emptyFileData)) { + res = ferror(f);
}
fclose(f);
return res;
}
-std::future<KSecretsStore::OpenResult> KSecretsStore::open(bool readonly \
/* =true */) noexcept +bool KSecretsStore::isGood() const noexcept { return \
d->status_ == StoreStatus::Good; } +
+const char* KSecretsStore::salt() const
{
- // check the state first
- if (d->status_ == StoreStatus::JustCreated) {
- return std::async(std::launch::deferred, []() { return OpenResult{ \
StoreStatus::SetupShouldBeCalledFirst, -1 }; });
- }
- if (d->status_ != StoreStatus::SetupDone) {
- // open could not be called two times or perhaps the setup call \
left this store in an invalid state because of some error
- return std::async(std::launch::deferred, []() { return OpenResult{ \
StoreStatus::IncorrectState, -1 }; });
- }
- // now we can proceed
- auto localThis = this;
- if (!readonly) {
- return std::async([localThis]() { return localThis->d->open(true); \
});
- }
- else {
- return std::async([localThis]() { return \
localThis->d->open(false); });
- }
+ if (isGood())
+ return d->salt();
+ else
+ return nullptr;
}
-const char* KSecretsStore::salt() const { return d->salt(); }
-
const char* KSecretsStorePrivate::salt() const { return fileHead_.salt; }
-KSecretsStore::OpenResult KSecretsStorePrivate::open(bool lockFile)
+KSecretsStore::SetupResult KSecretsStorePrivate::open(bool lockFile)
{
- using OpenResult = KSecretsStore::OpenResult;
+ using OpenResult = KSecretsStore::SetupResult;
secretsFile_.file_ = ::open(secretsFile_.filePath_.c_str(), O_DSYNC | \
O_NOATIME | O_NOFOLLOW); if (secretsFile_.file_ == -1) {
return setStoreStatus(OpenResult({ \
KSecretsStore::StoreStatus::CannotOpenFile, errno })); }
if (lockFile) {
if (flock(secretsFile_.file_, LOCK_EX) == -1) {
- return KSecretsStore::OpenResult{ \
KSecretsStore::StoreStatus::CannotLockFile, errno }; + return \
setStoreStatus(OpenResult({ KSecretsStore::StoreStatus::CannotLockFile, \
errno })); }
secretsFile_.locked_ = true;
}
@@ -194,7 +197,8 @@ KSecretsStore::OpenResult \
KSecretsStorePrivate::open(bool lockFile)
return setStoreStatus(OpenResult({ KSecretsStore::StoreStatus::Good, 0 \
})); }
-KSecretsStorePrivate::SecretsFile::~SecretsFile(){
+KSecretsStorePrivate::SecretsFile::~SecretsFile()
+{
if (file_ != -1) {
auto r = close(file_);
if (r == -1) {
diff --git a/src/runtime/ksecrets_store/ksecrets_store.h \
b/src/runtime/ksecrets_store/ksecrets_store.h index bb4f394..4d3e5b2 100644
--- a/src/runtime/ksecrets_store/ksecrets_store.h
+++ b/src/runtime/ksecrets_store/ksecrets_store.h
@@ -190,11 +190,11 @@ public:
Good,
JustCreated,
SetupShouldBeCalledFirst,
+ CredentialsSet,
IncorrectState,
CannotInitGcrypt,
CannotDeriveKeys,
CannotStoreKeys,
- SetupDone,
SetupError,
NoPathGiven,
InvalidFile, // the file format was not recognized. Is this a \
ksecrets file? @@ -204,38 +204,47 @@ public:
SystemError
};
- struct SetupResult {
+ template <StoreStatus G>
+ struct OpResult {
StoreStatus status_;
int errno_;
- operator bool() const { return status_ == StoreStatus::SetupDone; \
} + operator bool() const { return status_ == G; }
};
+ using SetupResult = OpResult<StoreStatus::Good>;
+ // struct SetupResult {
+ // StoreStatus status_;
+ // int errno_;
+ // operator bool() const { return status_ == StoreStatus::Good; }
+ // };
+
/*
- * Before opening, the store must be setup, that is, it must know the
- * file path and the user's password. This method is typically called
- * from the pam module but it can also be called from another program
- * after prompting user for the password, for example.
- *
- * This call creates the file if it's not found.
+ * Before usage, the store must be setup, that is, it must know its \
file path. + * This call creates the file if it's not found and the \
readOnly flag is set to false. + * The file is not created when the \
readOnly flag is set to false in order to prevent + * unintended side \
effects. If the file don't exists, the SetupResult.statu_ is set + * to \
StoreStatus::SystemError and errno should be 2
*
* @return SetupResult whose operator bool could be used to check the \
error condition
*/
- std::future<SetupResult> setup(const char* path, const char* password, \
const char* keyNameEcrypting = "ksecrets:encrypting", const char* \
keyNameMac = "ksecrets:mac");
-
- struct OpenResult {
- StoreStatus status_;
- int errno_;
- operator bool() const { return status_ == StoreStatus::Good; }
- };
-
+ std::future<SetupResult> setup(const char* path, bool readOnly =true);
+
+ using CredentialsResult = OpResult<StoreStatus::CredentialsSet>;
+ // struct CredentialsResult {
+ // StoreStatus status_;
+ // int errno_;
+ // operator bool() const { return status_ == StoreStatus::Good; }
+ // };
/**
- * @parameter path full path to the store file to handle
- * @parameter readOnly set it to true if you only intend reading to \
speed
- * things-up and avoid placing a lock on the file
+ * Set the system-wide credentials for the secrets store
*
- * @return OpenResult whose operator bool could be used to check the \
error condition + * This method is typically called from the pam module \
but it can also be + * called from another program after prompting user \
for the password, for example. + * Client applications only need to \
call this once per user session.
*/
- std::future<OpenResult> open(bool readOnly = true) noexcept;
+ std::future<CredentialsResult> setCredentials(const char* password = \
nullptr, const char* keyNameEcrypting = "ksecrets:encrypting", const char* \
keyNameMac = "ksecrets:mac"); +
+ bool isGood() const noexcept;
constexpr static auto SALT_SIZE = 56;
/**
diff --git a/src/runtime/ksecrets_store/ksecrets_store_p.h \
b/src/runtime/ksecrets_store/ksecrets_store_p.h index 4ec75c8..270763d \
100644
--- a/src/runtime/ksecrets_store/ksecrets_store_p.h
+++ b/src/runtime/ksecrets_store/ksecrets_store_p.h
@@ -58,9 +58,9 @@ public:
KSecretsStorePrivate() = delete;
explicit KSecretsStorePrivate(KSecretsStore*);
- KSecretsStore::SetupResult setup(const std::string& path, bool, const \
std::string&);
- KSecretsStore::OpenResult open(bool lock);
- using open_action = std::function<KSecretsStore::OpenResult(const \
std::string&)>; + KSecretsStore::SetupResult setup(const std::string& \
path, bool, bool); + KSecretsStore::CredentialsResult \
setCredentials(const std::string&); + KSecretsStore::SetupResult \
open(bool); int createFile(const std::string&);
const char* salt() const;
@@ -80,11 +80,13 @@ public:
struct SecretsFile {
SecretsFile()
- : file_(-1), locked_(false) {};
+ : file_(-1)
+ , locked_(false){};
~SecretsFile();
std::string filePath_;
int file_;
bool locked_;
+ bool readOnly_;
};
KSecretsStore* b_;
SecretsFile secretsFile_;
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic