Skip to content

Commit

Permalink
OrcLib: add Registry class to read values from the registry
Browse files Browse the repository at this point in the history
  • Loading branch information
jgautier-anssi authored and fabienfl-orc committed Jul 31, 2020
1 parent cdcc0ea commit 68eab1e
Show file tree
Hide file tree
Showing 5 changed files with 485 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/OrcLib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,8 @@ set(SRC_UTILITIES_SYSTEM
"Privilege.h"
"ProfileList.cpp"
"ProfileList.h"
"Registry.cpp"
"Registry.h"
"Robustness.cpp"
"Robustness.h"
"SecurityDescriptor.cpp"
Expand Down
312 changes: 312 additions & 0 deletions src/OrcLib/Registry.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
//
// SPDX-License-Identifier: LGPL-2.1-or-later
//
// Copyright © 2011-2019 ANSSI. All Rights Reserved.
//
// Author(s): Jean Gautier (ANSSI)
//

#include "stdafx.h"

#include "Registry.h"


template <>
Orc::Result<ULONG32>
Orc::Registry::Read<ULONG32>(const logger& pLog, HKEY hParentKey, LPWSTR szKeyName, LPWSTR szValueName)
{
HKEY hKey = nullptr;

if (szKeyName)
{
if (auto status = RegOpenKeyExW(hParentKey, szKeyName, REG_OPTION_OPEN_LINK, KEY_QUERY_VALUE, &hKey);
status != ERROR_SUCCESS)
{
log::Error(pLog, HRESULT_FROM_WIN32(status), L"Failed to registry key %s\r\n", szKeyName);
return Orc::Result<ULONG32>(HRESULT_FROM_WIN32(status));
}
}
else
{
hKey = hParentKey;
}

BOOST_SCOPE_EXIT(&hKey, &hParentKey)
{
if (hKey != hParentKey)
RegCloseKey(hKey);
}
BOOST_SCOPE_EXIT_END;

Buffer<ULONG32, 1> valueBuffer;
DWORD cbBytes = sizeof(ULONG32);
valueBuffer.reserve(1);
DWORD dwValueType = 0;

if (auto status = RegQueryValueExW(hKey, szValueName, NULL, &dwValueType, (LPBYTE)valueBuffer.get(), &cbBytes);
status != ERROR_SUCCESS)
{
if (status == ERROR_MORE_DATA)
{
log::Error(pLog, HRESULT_FROM_WIN32(status), L"Unexepected registry value \"%s\" is bigger than expected (ULONG32)\r\n", szValueName);
return Orc::Result<ULONG32>(HRESULT_FROM_WIN32(status));
}
else
{
log::Error(pLog, HRESULT_FROM_WIN32(status), L"Failed to open registry \"%s\" value\r\n", szValueName);
return Orc::Result<ULONG32>(HRESULT_FROM_WIN32(status));
}
}
else
{
valueBuffer.use((cbBytes / sizeof(ULONG32)));
}
if (dwValueType != REG_DWORD || (dwValueType != REG_BINARY && cbBytes!=sizeof(ULONG32)))
{
log::Error(
pLog,
HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH),
L"Unexpected value \"%s\" type (not ULONG32 compatible)\r\n",
szValueName);
return Orc::Result<ULONG32>(HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH));
}

return Result<ULONG32>(valueBuffer[0]);
}

template <>
Orc::Result<ULONG64>
Orc::Registry::Read<ULONG64>(const logger& pLog, HKEY hParentKey, LPWSTR szKeyName, LPWSTR szValueName)
{
HKEY hKey = nullptr;

if (szKeyName)
{
if (auto status = RegOpenKeyExW(hParentKey, szKeyName, REG_OPTION_OPEN_LINK, KEY_QUERY_VALUE, &hKey);
status != ERROR_SUCCESS)
{
log::Error(pLog, HRESULT_FROM_WIN32(status), L"Failed to registry key %s\r\n", szKeyName);
return Orc::Result<ULONG64>(HRESULT_FROM_WIN32(status));
}
}
else
{
hKey = hParentKey;
}

BOOST_SCOPE_EXIT(&hKey, &hParentKey)
{
if (hKey != hParentKey)
RegCloseKey(hKey);
}
BOOST_SCOPE_EXIT_END;

Buffer<ULONG64, 1> valueBuffer;
DWORD cbBytes = sizeof(ULONG64);
valueBuffer.reserve(1);
DWORD dwValueType = 0;

if (auto status = RegQueryValueExW(hKey, szValueName, NULL, &dwValueType, (LPBYTE)valueBuffer.get(), &cbBytes);
status != ERROR_SUCCESS)
{
if (status == ERROR_MORE_DATA)
{
log::Error(
pLog,
HRESULT_FROM_WIN32(status),
L"Unexepected registry value \"%s\" is bigger than expected (ULONG32)\r\n",
szValueName);
return Orc::Result<ULONG64>(HRESULT_FROM_WIN32(status));
}
else
{
log::Error(pLog, HRESULT_FROM_WIN32(status), L"Failed to open registry \"%s\" value\r\n", szValueName);
return Orc::Result<ULONG64>(HRESULT_FROM_WIN32(status));
}
}
else
{
valueBuffer.use((cbBytes / sizeof(ULONG64)));
}
if (dwValueType != REG_QWORD || (dwValueType != REG_BINARY && cbBytes != sizeof(ULONG64)))
{
log::Error(
pLog,
HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH),
L"Unexpected value \"%s\" type (not ULONG32 compatible)\r\n",
szValueName);
return Orc::Result<ULONG64>(HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH));
}

return Result<ULONG64>(valueBuffer[0]);
}

template <>
Orc::Result<Orc::ByteBuffer>
Orc::Registry::Read<Orc::ByteBuffer>(const logger& pLog, HKEY hParentKey, LPWSTR szKeyName, LPWSTR szValueName)
{
HKEY hKey = nullptr;

if (szKeyName)
{
if (auto status = RegOpenKeyExW(hParentKey, szKeyName, REG_OPTION_OPEN_LINK, KEY_QUERY_VALUE, &hKey);
status != ERROR_SUCCESS)
{
log::Error(pLog, HRESULT_FROM_WIN32(status), L"Failed to registry key %s\r\n", szKeyName);
return Orc::Result<ByteBuffer>(HRESULT_FROM_WIN32(status));
}
}
else
{
hKey = hParentKey;
}

BOOST_SCOPE_EXIT(&hKey, &hParentKey)
{
if (hKey != hParentKey)
RegCloseKey(hKey);
}
BOOST_SCOPE_EXIT_END;

ByteBuffer valueBuffer;
DWORD cbBytes = valueBuffer.inner_elts() * sizeof(BYTE);
valueBuffer.reserve(valueBuffer.inner_elts());
DWORD dwValueType = 0;
if (auto status = RegQueryValueExW(hKey, szValueName, NULL, &dwValueType, (LPBYTE)valueBuffer.get(), &cbBytes);
status != ERROR_SUCCESS)
{
if (status == ERROR_MORE_DATA)
{
valueBuffer.resize(cbBytes / sizeof(BYTE));
if (auto status = RegQueryValueExW(hKey, szValueName, NULL, NULL, (LPBYTE)valueBuffer.get(), &cbBytes);
status != ERROR_SUCCESS)
{
log::Error(pLog, HRESULT_FROM_WIN32(status), L"Failed to reg value \"%s:%s\" value\r\n", szKeyName?szKeyName:L"", szValueName);
return Orc::Result<ByteBuffer>(HRESULT_FROM_WIN32(status));
}
}
else
{
log::Error(
pLog, HRESULT_FROM_WIN32(status), L"Failed to reg value \"%s:%s\" value\r\n", szKeyName?szKeyName:L"", szValueName);
return Orc::Result<ByteBuffer>(HRESULT_FROM_WIN32(status));
}
}
else
{
valueBuffer.use((cbBytes / sizeof(BYTE)));
}
return Orc::Result<ByteBuffer>(std::move(valueBuffer));
}

template <>
Orc::Result<std::wstring>
Orc::Registry::Read<std::wstring>(const logger& pLog, HKEY hParentKey, LPWSTR szKeyName, LPWSTR szValueName)
{
HKEY hKey = nullptr;

if (szKeyName)
{
if (auto status = RegOpenKeyExW(hParentKey, szKeyName, REG_OPTION_OPEN_LINK, KEY_QUERY_VALUE, &hKey);
status != ERROR_SUCCESS)
{
log::Error(pLog, HRESULT_FROM_WIN32(status), L"Failed to registry key %s\r\n", szKeyName);
return Orc::Result<std::wstring>(HRESULT_FROM_WIN32(status));
}
}
else
{
hKey = hParentKey;
}

BOOST_SCOPE_EXIT(&hKey, &hParentKey)
{
if (hKey != hParentKey)
RegCloseKey(hKey);
}
BOOST_SCOPE_EXIT_END;

Buffer<WCHAR, MAX_PATH> valueBuffer;
DWORD cbBytes = MAX_PATH * sizeof(WCHAR);
valueBuffer.reserve(MAX_PATH);
DWORD dwValueType = 0;
if (auto status = RegQueryValueExW(hKey, szValueName, NULL, &dwValueType, (LPBYTE)valueBuffer.get(), &cbBytes);
status != ERROR_SUCCESS)
{
if (status == ERROR_MORE_DATA)
{
valueBuffer.resize(cbBytes / sizeof(WCHAR));
if (auto status = RegQueryValueExW(hKey, szValueName, NULL, NULL, (LPBYTE)valueBuffer.get(), &cbBytes);
status != ERROR_SUCCESS)
{
log::Error(pLog, HRESULT_FROM_WIN32(status), L"Failed to reg value \"%s\" value\r\n", szValueName);
return Orc::Result<std::wstring>(HRESULT_FROM_WIN32(status));
}
}
else
{
log::Error(pLog, HRESULT_FROM_WIN32(status), L"Failed to open profile list \"%s\" value\r\n", szValueName);
return Orc::Result<std::wstring>(HRESULT_FROM_WIN32(status));
}
}
else
{
valueBuffer.use((cbBytes / sizeof(WCHAR)));
}

if (dwValueType == REG_SZ)
{
if (valueBuffer.size()
>= 1) // If string is not empty, we need to get rid of the trailing \0 to build a wstring
{
valueBuffer.resize(valueBuffer.size() - 1);
}

return Orc::Result<std::wstring>(std::wstring(valueBuffer.get(), valueBuffer.size()));
}
else if (dwValueType == REG_EXPAND_SZ)
{
Buffer<WCHAR, MAX_PATH> expandBuffer;
expandBuffer.reserve(MAX_PATH);

if (auto cbSize = ExpandEnvironmentStringsW(valueBuffer.get(), expandBuffer.get(), MAX_PATH); cbSize > MAX_PATH)
{
expandBuffer.reserve(cbSize);
if (auto cbSizeReTry = ExpandEnvironmentStringsW(valueBuffer.get(), expandBuffer.get(), cbSize);
cbSizeReTry == cbSize)
{
expandBuffer.use(cbSize);
}
else
{
throw Exception(
ExceptionSeverity::Continue, E_FAIL, L"Unexpected return value for ExpandEnvironmentStringsW\r\n");
}
}
else
{
expandBuffer.use(cbSize);
}
return Orc::Result<std::wstring>(std::wstring(expandBuffer.get(), expandBuffer.size()));
}
else
{
log::Error(
pLog,
HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH),
L"Registry value %s is not of the expected (REG_*SZ) type\r\n",
szValueName);
return Orc::Result<std::wstring>(HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH));
}
}

template <>
Orc::Result<std::filesystem::path>
Orc::Registry::Read<std::filesystem::path>(const logger& pLog, HKEY hParentKey, LPWSTR szKeyName, LPWSTR szValueName)
{
auto string = Read<std::wstring>(pLog, hParentKey, szKeyName, szValueName);
if (string.is_ok())
return string.unwrap();
else
return string.err();
}
64 changes: 64 additions & 0 deletions src/OrcLib/Registry.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//
// SPDX-License-Identifier: LGPL-2.1-or-later
//
// Copyright © 2011-2019 ANSSI. All Rights Reserved.
//
// Author(s): Jean Gautier (ANSSI)
//
#pragma once

#include "OrcLib.h"

#include "OrcResult.h"
#include "Buffer.h"

#include <optional>
#include <filesystem>
#include <Windows.h>
#include "boost/scope_exit.hpp"

#pragma managed(push, off)


namespace Orc {

class LogFileWriter;

class ORCLIB_API Registry
{
public:
template <typename _T>
static Result<_T> Read(const logger& pLog, HKEY hParentKey, LPWSTR szKeyName, LPWSTR szValueName) {
static_assert(false, "Registry read for your type must be a specialised version");
}
};


template <>
Orc::Result<ULONG32>
Orc::Registry::Read<ULONG32>(const logger& pLog, HKEY hParentKey, LPWSTR szKeyName, LPWSTR szValueName);

template <>
Orc::Result<ULONG64>
Orc::Registry::Read<ULONG64>(const logger& pLog, HKEY hParentKey, LPWSTR szKeyName, LPWSTR szValueName);

template <>
Orc::Result<ByteBuffer>
Orc::Registry::Read<ByteBuffer>(const logger& pLog, HKEY hParentKey, LPWSTR szKeyName, LPWSTR szValueName);

template <>
Orc::Result<std::wstring>
Orc::Registry::Read<std::wstring>(const logger& pLog, HKEY hParentKey, LPWSTR szKeyName, LPWSTR szValueName);

template <>
Orc::Result<std::vector<std::wstring>>
Orc::Registry::Read<std::vector<std::wstring>>(const logger& pLog, HKEY hParentKey, LPWSTR szKeyName, LPWSTR szValueName);

template <>
Orc::Result<std::filesystem::path>
Orc::Registry::Read<std::filesystem::path>(const logger& pLog, HKEY hParentKey, LPWSTR szKeyName, LPWSTR szValueName);

} // namespace Orc


#pragma managed(pop)
1 change: 1 addition & 0 deletions tests/OrcLibTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ set(SRC_UTILITIES
"crypto_utilities_test.cpp"
"embedded_resource.cpp"
"libraries_test.cpp"
"registry.cpp"
"temporary.cpp"
"logwriter.cpp"
"system_details.cpp"
Expand Down
Loading

0 comments on commit 68eab1e

Please sign in to comment.