The old API didn't make any sense for the most common case when both the user name and password need to be stored, as it required providing the user name as input, which couldn't work (but somehow this went unnoticed for more than a year...). Fix this by returning the username, and not only the password, from Load() instead of taking it as parameter and removing this parameter from Delete() as well. Also improve the documentation, notably include a simple example of using this class. Notice that this is a backwards-incompatible change, but the old API was really badly broken and didn't appear in 3.1.0 yet, so the breakage is both unavoidable and, hopefully, shouldn't affect much code. Nevertheless, a special wxHAS_SECRETSTORE_LOAD_USERNAME symbol is added to allow testing for it if necessary.
159 lines
5.0 KiB
C++
159 lines
5.0 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/msw/secretstore.cpp
|
|
// Purpose: wxSecretStore implementation for MSW.
|
|
// Author: Vadim Zeitlin
|
|
// Created: 2016-05-27
|
|
// Copyright: (c) 2016 Vadim Zeitlin <vadim@wxwidgets.org>
|
|
// Licence: wxWindows licence
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ============================================================================
|
|
// declarations
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// for compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#if wxUSE_SECRETSTORE
|
|
|
|
#include "wx/secretstore.h"
|
|
#include "wx/private/secretstore.h"
|
|
|
|
#include "wx/log.h" // wxSysErrorMsgStr()
|
|
|
|
// Somewhat surprisingly, wincred.h is not self-contained and relies on some
|
|
// standard Windows macros being defined without including the headers defining
|
|
// them on its own, so we must include <windows.h> (from our private header)
|
|
// before including it.
|
|
#include "wx/msw/private.h"
|
|
#include <wincred.h>
|
|
|
|
namespace
|
|
{
|
|
|
|
// ============================================================================
|
|
// wxSecretStoreImpl for MSW
|
|
// ============================================================================
|
|
|
|
// Helper class to ensure that a CREDENTIAL pointer is always freed.
|
|
class CredentialPtr
|
|
{
|
|
public:
|
|
explicit CredentialPtr(CREDENTIAL* cred) : m_cred(cred) { }
|
|
~CredentialPtr() { ::CredFree(m_cred); }
|
|
|
|
private:
|
|
CREDENTIAL* const m_cred;
|
|
|
|
wxDECLARE_NO_COPY_CLASS(CredentialPtr);
|
|
};
|
|
|
|
class wxSecretStoreMSWImpl : public wxSecretStoreImpl
|
|
{
|
|
public:
|
|
virtual bool Save(const wxString& service,
|
|
const wxString& user,
|
|
const wxSecretValueImpl& secret,
|
|
wxString& errmsg) wxOVERRIDE
|
|
{
|
|
CREDENTIAL cred;
|
|
wxZeroMemory(cred);
|
|
cred.Type = CRED_TYPE_GENERIC;
|
|
cred.TargetName = const_cast<TCHAR*>(static_cast<const TCHAR*>(service.t_str()));
|
|
cred.UserName = const_cast<TCHAR*>(static_cast<const TCHAR*>(user.t_str()));
|
|
cred.CredentialBlobSize = secret.GetSize();
|
|
cred.CredentialBlob = static_cast<BYTE *>(const_cast<void*>(secret.GetData()));
|
|
|
|
// We could also use CRED_PERSIST_ENTERPRISE here to store the password
|
|
// in the roaming section of the profile and this could arguably be
|
|
// more useful. However it might also be unexpected if the user really
|
|
// only wants to store the password on the local machine, so choose
|
|
// security over convenience here. Maybe in the future we should have
|
|
// an option for the password persistence scope.
|
|
cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
|
|
|
|
if ( !::CredWrite(&cred, 0) )
|
|
{
|
|
errmsg = wxSysErrorMsgStr();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
virtual bool Load(const wxString& service,
|
|
wxString* user,
|
|
wxSecretValueImpl** secret,
|
|
wxString& errmsg) const wxOVERRIDE
|
|
{
|
|
CREDENTIAL* pcred = NULL;
|
|
if ( !::CredRead(service.t_str(), CRED_TYPE_GENERIC, 0, &pcred) || !pcred )
|
|
{
|
|
// Not having the password for this service/user combination is not
|
|
// an error, but anything else is.
|
|
if ( ::GetLastError() != ERROR_NOT_FOUND )
|
|
errmsg = wxSysErrorMsgStr();
|
|
|
|
return false;
|
|
}
|
|
|
|
CredentialPtr ensureFree(pcred);
|
|
|
|
*user = pcred->UserName;
|
|
*secret = new wxSecretValueGenericImpl(pcred->CredentialBlobSize,
|
|
pcred->CredentialBlob);
|
|
|
|
return true;
|
|
}
|
|
|
|
virtual bool Delete(const wxString& service,
|
|
wxString& errmsg) wxOVERRIDE
|
|
{
|
|
if ( !::CredDelete(service.t_str(), CRED_TYPE_GENERIC, 0) )
|
|
{
|
|
// Same logic as in Load() above.
|
|
if ( ::GetLastError() != ERROR_NOT_FOUND )
|
|
errmsg = wxSysErrorMsgStr();
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
// ============================================================================
|
|
// MSW-specific implementation of common methods
|
|
// ============================================================================
|
|
|
|
/* static */
|
|
wxSecretValueImpl* wxSecretValue::NewImpl(size_t size, const void *data)
|
|
{
|
|
return new wxSecretValueGenericImpl(size, data);
|
|
}
|
|
|
|
/* static */
|
|
void wxSecretValue::Wipe(size_t size, void *data)
|
|
{
|
|
::SecureZeroMemory(data, size);
|
|
}
|
|
|
|
/* static */
|
|
wxSecretStore wxSecretStore::GetDefault()
|
|
{
|
|
// There is only a single store under Windows anyhow.
|
|
return wxSecretStore(new wxSecretStoreMSWImpl());
|
|
}
|
|
|
|
#endif // wxUSE_SECRETSTORE
|