diff --git a/keychain.cpp b/keychain.cpp index ffcf1ef..ded13da 100644 --- a/keychain.cpp +++ b/keychain.cpp @@ -32,28 +32,37 @@ QString Keychain::errorString() const { return d->errorString; } -void Keychain::writePassword( const QString& account, const QString& password, OverwriteMode om ) { +void Keychain::writePassword( const QString &key, const QString &password, OverwriteMode om ) { + writeEntry( key, password.toUtf8(), om ); +} + +void Keychain::writeEntry( const QString& key, const QByteArray& ba, OverwriteMode om ) { QString err; - const Error ret = d->writePasswordImpl( account, password, om, &err ); + const Error ret = d->writeEntryImpl( key, ba, om, &err ); d->error = ret; d->errorString = err; } -QString Keychain::readPassword( const QString& account ) { +QString Keychain::readPassword( const QString& key ) { + const QByteArray ba = readEntry( key ); + return QString::fromUtf8( ba.constData(), ba.size() ); +} + +QByteArray Keychain::readEntry( const QString& key ) { QString err; - QString pw; - const Error ret = d->readPasswordImpl( &pw, account, &err ); + QByteArray pw; + const Error ret = d->readEntryImpl( &pw, key, &err ); d->error = ret; d->errorString = err; if ( ret != NoError ) - return QString(); + return QByteArray(); else return pw; } -void Keychain::deletePassword( const QString& account ) { +void Keychain::deleteEntry( const QString& key ) { QString err; - const Error ret = d->deletePasswordImpl( account, &err ); + const Error ret = d->deleteEntryImpl( key, &err ); d->error = ret; d->errorString = err; } diff --git a/keychain.h b/keychain.h index 751746e..342de2a 100644 --- a/keychain.h +++ b/keychain.h @@ -13,7 +13,14 @@ namespace QKeychain { /** + * Provides access to platform-specific key stores for secure persistence of + * passwords and other sensitive user data. * + * On Windows, TODO + * On Mac OS X, the OS X keychain is used. + * On other Unixes, TODO + * + * TODO we don't guarantee anything */ class Keychain { public: @@ -35,11 +42,11 @@ public: */ enum Error { NoError=0, /*< No error occurred, operation was successful */ - PasswordNotFound, /*< For the given account no password was found */ - CouldNotDeletePassword, /*< Could not delete existing password */ + EntryNotFound, /*< For the given key no data was found */ + CouldNotDeleteEntry, /*< Could not delete existing secret data */ AccessDeniedByUser, /*< User denied access to keychain */ AccessDenied, /*< Access denied for other reasons */ - EntryAlreadyExists, /*< There is already a password for the given account and overwriting was not enforced */ + EntryAlreadyExists, /*< There is already an entry for the given key and overwriting was not enforced */ OtherError /*< Something else went wrong (errorString() might provide details) */ }; @@ -48,7 +55,7 @@ public: */ enum OverwriteMode { DoNotOverwrite, /*< Do not overwrite existing entries */ - ForceOverwrite /*< Replace old passowrd by new one */ + ForceOverwrite /*< Replace old data by new one */ }; /** @@ -67,32 +74,52 @@ public: QString errorString() const; /** - * Stores a @p password in the keychain, for a given @p account. + * Stores a @p password in the keychain, for a given @p key. * error() and errorString() hold the result of the write operation. * - * @param account the account to store a password for - * @param the password to store + * @param key the key to store a password for + * @param password the password to store * @param om Whether to overwrite existing passwords */ - void writePassword( const QString& account, + void writePassword( const QString& key, const QString& password, OverwriteMode om=DoNotOverwrite ); /** - * Reads the @p password for an @p account from the keychain. - * error() and errorString() hold the result of the read operation. + * Stores @p data in the keychain, for a given @p key. + * error() and errorString() hold the result of the write operation. * - * @param account the account ot read the password for + * @param key the key to store a password for + * @param data the data to store + * @param om Whether to overwrite existing passwords */ - QString readPassword( const QString& account ); + void writeEntry( const QString& key, + const QByteArray& data, + OverwriteMode om=DoNotOverwrite ); /** - * Deletes the @p password for an @p account from the keychain. + * Reads the password for a given @p key from the keychain. * error() and errorString() hold the result of the read operation. * - * @param account The account to delete the password for + * @param key the key ot read the password for */ - void deletePassword( const QString& account ); + QString readPassword( const QString& key ); + + /** + * Reads data for a given @p key from the keychain. + * error() and errorString() hold the result of the read operation. + * + * @param key the key ot read the password for + */ + QByteArray readEntry( const QString& key ); + + /** + * Deletes the data for a @p key from the keychain. + * error() and errorString() hold the result of the delete operation. + * + * @param key The key to delete the data for + */ + void deleteEntry( const QString& key ); private: class Private; diff --git a/keychain_mac.cpp b/keychain_mac.cpp index 66dbaed..f81e066 100644 --- a/keychain_mac.cpp +++ b/keychain_mac.cpp @@ -32,7 +32,7 @@ static QString strForStatus( OSStatus os ) { return QString::fromUtf8( buf, strlen( buf ) ); } -static OSStatus readPw( QString* pw, +static OSStatus readPw( QByteArray* pw, const QString& service, const QString& account, SecKeychainItemRef* ref ) { @@ -53,7 +53,7 @@ static OSStatus readPw( QString* pw, &data, ref ); if ( ret == noErr ) { - *pw = QString::fromUtf8( reinterpret_cast( data ), len ); + *pw = QByteArray( reinterpret_cast( data ), len ); const OSStatus ret2 = SecKeychainItemFreeContent ( 0, data ); if ( ret2 != noErr ) qWarning() << "Could not free item content: " << strForStatus( ret2 ); @@ -61,9 +61,9 @@ static OSStatus readPw( QString* pw, return ret; } -Keychain::Error Keychain::Private::readPasswordImpl( QString* pw, - const QString& account, - QString* err ) { +Keychain::Error Keychain::Private::readEntryImpl( QByteArray* pw, + const QString& account, + QString* err ) { Q_ASSERT( pw ); Q_ASSERT( err ); err->clear(); @@ -73,29 +73,28 @@ Keychain::Error Keychain::Private::readPasswordImpl( QString* pw, return NoError; case errSecItemNotFound: *err = tr("Password not found"); - return PasswordNotFound; + return EntryNotFound; default: *err = strForStatus( ret ); return OtherError; } } -Keychain::Error Keychain::Private::writePasswordImpl( const QString& account, - const QString& password, - Keychain::OverwriteMode ov, - QString* err ) { +Keychain::Error Keychain::Private::writeEntryImpl( const QString& account, + const QByteArray& data, + Keychain::OverwriteMode ov, + QString* err ) { Q_ASSERT( err ); err->clear(); const QByteArray serviceData = service.toUtf8(); const QByteArray accountData = account.toUtf8(); - const QByteArray passwordData = password.toUtf8(); const OSStatus ret = SecKeychainAddGenericPassword( NULL, //default keychain serviceData.size(), serviceData.constData(), accountData.size(), accountData.constData(), - passwordData.size(), - passwordData.constData(), + data.size(), + data.constData(), NULL //item reference ); if ( ret != noErr ) { @@ -106,11 +105,11 @@ Keychain::Error Keychain::Private::writePasswordImpl( const QString& account, *err = tr("Entry already exists"); return EntryAlreadyExists; } - Error derr = deletePasswordImpl( account, err ); + Error derr = deleteEntryImpl( account, err ); if ( derr != NoError ) - return CouldNotDeletePassword; + return CouldNotDeleteEntry; else - return writePasswordImpl( account, password, ov, err ); + return writeEntryImpl( account, data, ov, err ); } default: *err = strForStatus( ret ); @@ -121,10 +120,10 @@ Keychain::Error Keychain::Private::writePasswordImpl( const QString& account, return NoError; } -Keychain::Error Keychain::Private::deletePasswordImpl( const QString& account, - QString* err ) { +Keychain::Error Keychain::Private::deleteEntryImpl( const QString& account, + QString* err ) { SecKeychainItemRef ref; - QString pw; + QByteArray pw; const OSStatus ret1 = readPw( &pw, service, account, &ref ); if ( ret1 == errSecItemNotFound ) return NoError; // No item stored, we're done @@ -141,6 +140,6 @@ Keychain::Error Keychain::Private::deletePasswordImpl( const QString& account, return NoError; //TODO map error code *err = strForStatus( ret2 ); - return CouldNotDeletePassword; + return CouldNotDeleteEntry; } diff --git a/keychain_p.h b/keychain_p.h index 4b90235..2e84931 100644 --- a/keychain_p.h +++ b/keychain_p.h @@ -19,15 +19,15 @@ class Keychain::Private { public: explicit Private( const QString& s ) : service( s ) {} - Keychain::Error writePasswordImpl( const QString& account, - const QString& password, - Keychain::OverwriteMode, - QString* errorString ); - Keychain::Error deletePasswordImpl( const QString& account, - QString* errorString ); - Keychain::Error readPasswordImpl( QString* password, - const QString& account, - QString* errorString ); + Keychain::Error writeEntryImpl( const QString& account, + const QByteArray& data, + Keychain::OverwriteMode, + QString* errorString ); + Keychain::Error deleteEntryImpl( const QString& account, + QString* errorString ); + Keychain::Error readEntryImpl( QByteArray* password, + const QString& account, + QString* errorString ); const QString service; Keychain::Error error; diff --git a/testclient.cpp b/testclient.cpp index e0fc9e8..2e5873e 100644 --- a/testclient.cpp +++ b/testclient.cpp @@ -66,7 +66,7 @@ int main( int argc, char** argv ) { if ( ++it != args.constEnd() ) return printUsage(); Keychain k( QLatin1String("qtkeychain-testclient") ); - k.deletePassword( acc ); + k.deleteEntry( acc ); if ( k.error() ) { std::cerr << "Deleting password failed: " << qPrintable(k.errorString()) << std::endl; return 1;