From 9fb8ea615d99af30b60871202183f14e03172b40 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Sat, 6 Jul 2013 00:30:43 -0700 Subject: [PATCH] Add a password storage system. --- Sources/Plasma/FeatureLib/CMakeLists.txt | 1 + .../FeatureLib/pfPasswordStore/CMakeLists.txt | 20 ++ .../pfPasswordStore/pfPasswordStore.cpp | 196 ++++++++++++++++++ .../pfPasswordStore/pfPasswordStore.h | 59 ++++++ .../pfPasswordStore/pfPasswordStore_impl.h | 83 ++++++++ 5 files changed, 359 insertions(+) create mode 100644 Sources/Plasma/FeatureLib/pfPasswordStore/CMakeLists.txt create mode 100644 Sources/Plasma/FeatureLib/pfPasswordStore/pfPasswordStore.cpp create mode 100644 Sources/Plasma/FeatureLib/pfPasswordStore/pfPasswordStore.h create mode 100644 Sources/Plasma/FeatureLib/pfPasswordStore/pfPasswordStore_impl.h diff --git a/Sources/Plasma/FeatureLib/CMakeLists.txt b/Sources/Plasma/FeatureLib/CMakeLists.txt index 5faa5ada..39acaf4a 100644 --- a/Sources/Plasma/FeatureLib/CMakeLists.txt +++ b/Sources/Plasma/FeatureLib/CMakeLists.txt @@ -18,6 +18,7 @@ add_subdirectory(pfJournalBook) add_subdirectory(pfLocalizationMgr) add_subdirectory(pfMessage) add_subdirectory(pfMoviePlayer) +add_subdirectory(pfPasswordStore) add_subdirectory(pfPatcher) add_subdirectory(pfPython) add_subdirectory(pfSurface) diff --git a/Sources/Plasma/FeatureLib/pfPasswordStore/CMakeLists.txt b/Sources/Plasma/FeatureLib/pfPasswordStore/CMakeLists.txt new file mode 100644 index 00000000..2ab83c4e --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfPasswordStore/CMakeLists.txt @@ -0,0 +1,20 @@ +include_directories("../../CoreLib") +include_directories("../../NucleusLib") +include_directories("../../NucleusLib/inc") +include_directories("../../PubUtilLib") + +set(pfPasswordStore_HEADERS + pfPasswordStore.h + pfPasswordStore_impl.h +) + +set(pfPasswordStore_SOURCES + pfPasswordStore.cpp +) + +add_library(pfPasswordStore STATIC ${pfPasswordStore_HEADERS} ${pfPasswordStore_SOURCES}) +target_link_libraries(pfPasswordStore CoreLib plFile) + +source_group("Header Files" FILES ${pfPasswordStore_HEADERS}) +source_group("Source Files" FILES ${pfPasswordStore_SOURCES}) + diff --git a/Sources/Plasma/FeatureLib/pfPasswordStore/pfPasswordStore.cpp b/Sources/Plasma/FeatureLib/pfPasswordStore/pfPasswordStore.cpp new file mode 100644 index 00000000..b3faeae4 --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfPasswordStore/pfPasswordStore.cpp @@ -0,0 +1,196 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ + +#include "pfPasswordStore.h" +#include "pfPasswordStore_impl.h" + +#include "plProduct.h" +#include "plFile/plEncryptedStream.h" + +/* Get the pfPasswordStore instance */ +pfPasswordStore* pfPasswordStore::Instance() +{ + static pfPasswordStore* store = nullptr; + + if (store == nullptr) { +#ifdef HS_BUILD_FOR_WIN32 + store = new pfWin32PasswordStore(); +#else + store = new pfFilePasswordStore(); +#endif + } + + return store; +} + + + +/***************************************************************************** + ** pfFilePasswordStore ** + *****************************************************************************/ + +pfFilePasswordStore::pfFilePasswordStore() +{ + // TODO: Cross-platform CryptKey initialization + uint32_t* product = (uint32_t*)plProduct::UUID(); + for (int i = 0; i < 4; i++) { + fCryptKey[i] = product[i]; + } +} + + +const plString pfFilePasswordStore::GetPassword(const plString& username) +{ + plFileName loginDat = plFileName::Join(plFileSystem::GetInitPath(), "login.dat"); + plString password = plString::Null; + +#ifndef PLASMA_EXTERNAL_RELEASE + // internal builds can use the local init directory + plFileName local("init\\login.dat"); + if (plFileInfo(local).Exists()) + loginDat = local; +#endif + + hsStream* stream = plEncryptedStream::OpenEncryptedFile(loginDat, fCryptKey); + if (stream && !stream->AtEnd()) + { + uint32_t savedKey[4]; + stream->Read(sizeof(savedKey), savedKey); + + if (memcmp(fCryptKey, savedKey, sizeof(savedKey)) == 0 && !stream->AtEnd()) + { + plString uname = stream->ReadSafeString(); + if (username.CompareI(uname) == 0) { + password = stream->ReadSafeString(); + } + } + + stream->Close(); + delete stream; + } + + return password; +} + + +bool pfFilePasswordStore::SetPassword(const plString& username, const plString& password) +{ + plFileName loginDat = plFileName::Join(plFileSystem::GetInitPath(), "login.dat"); + +#ifndef PLASMA_EXTERNAL_RELEASE + // internal builds can use the local init directory + plFileName local("init\\login.dat"); + if (plFileInfo(local).Exists()) + loginDat = local; +#endif + + hsStream* stream = plEncryptedStream::OpenEncryptedFileWrite(loginDat, fCryptKey); + if (stream) + { + stream->Write(sizeof(fCryptKey), fCryptKey); + stream->WriteSafeString(username); + stream->WriteSafeString(password); + + stream->Close(); + delete stream; + + return true; + } + + return false; +} + + + +#ifdef HS_BUILD_FOR_WIN32 +#include + +/***************************************************************************** + ** pfWin32PasswordStore ** + *****************************************************************************/ +const plString pfWin32PasswordStore::GetPassword(const plString& username) +{ + PCREDENTIALW credential; + plString target = plString::Format("%s__%s", plProduct::UUID(), username.c_str()); + plString password = plString::Null; + + if (!CredReadW(target.ToUtf16(), CRED_TYPE_GENERIC, 0, &credential)) { + return password; + } + + password = plString::FromUtf16((uint16_t*)credential->CredentialBlob, credential->CredentialBlobSize); + + memset(credential->CredentialBlob, 0, credential->CredentialBlobSize); + CredFree(credential); + + return password; +} + + +bool pfWin32PasswordStore::SetPassword(const plString& username, const plString& password) +{ + CREDENTIALW credential; + plString target = plString::Format("%s__%s", plProduct::UUID(), username.c_str()); + + if (password.IsNull()) { + if (CredDeleteW(target.ToUtf16(), CRED_TYPE_GENERIC, 0)) { + return true; + } + + return false; + } + + memset(&credential, 0, sizeof(CREDENTIALW)); + credential.Type = CRED_TYPE_GENERIC; + credential.TargetName = target.ToUtf16(); + credential.CredentialBlobSize = password.GetSize(); + credential.CredentialBlob = (LPBYTE)password.ToUtf16(); + credential.Persist = CRED_PERSIST_LOCAL_MACHINE; + credential.UserName = username.ToUtf16(); + + if (!CredWriteW(&credential, 0)) { + return false; + } + + return true; +} +#endif diff --git a/Sources/Plasma/FeatureLib/pfPasswordStore/pfPasswordStore.h b/Sources/Plasma/FeatureLib/pfPasswordStore/pfPasswordStore.h new file mode 100644 index 00000000..fd794ba2 --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfPasswordStore/pfPasswordStore.h @@ -0,0 +1,59 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ + +#ifndef pfPasswordStore_inc +#define pfPasswordStore_inc + +#include "HeadSpin.h" +#include "plString.h" + +class pfPasswordStore +{ +public: + static pfPasswordStore* Instance(); + + + virtual const plString GetPassword(const plString& username) = 0; + virtual bool SetPassword(const plString& username, const plString& password) = 0; +}; + +#endif //pfPasswordStore_inc diff --git a/Sources/Plasma/FeatureLib/pfPasswordStore/pfPasswordStore_impl.h b/Sources/Plasma/FeatureLib/pfPasswordStore/pfPasswordStore_impl.h new file mode 100644 index 00000000..ebbe0a08 --- /dev/null +++ b/Sources/Plasma/FeatureLib/pfPasswordStore/pfPasswordStore_impl.h @@ -0,0 +1,83 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ + +#ifndef pfPasswordStore_impl_inc +#define pfPasswordStore_impl_inc + +#include "pfPasswordStore.h" + +/** + * An encrypted file-based password storage mechanism. + */ +class pfFilePasswordStore : public pfPasswordStore +{ +private: + uint32_t fCryptKey[4]; + +public: + pfFilePasswordStore(); + + virtual const plString GetPassword(const plString& username); + virtual bool SetPassword(const plString& username, const plString& password); +}; + + +#ifdef HS_BUILD_FOR_WIN32 +/** + * A Windows Credential Vault password storage mechanism. + */ +class pfWin32PasswordStore : public pfPasswordStore +{ +public: + pfWin32PasswordStore() { } + + virtual const plString GetPassword(const plString& username); + virtual bool SetPassword(const plString& username, const plString& password); +}; +#endif //HS_BUILD_FOR_WIN32 + + +// TODO: A Linux libsecret-based storage mechanism + +// TODO: An OSX KeyChain-based storage mechanism + +#endif //pfPasswordStore_impl_inc