aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/util.cpp76
-rw-r--r--src/common/util.h26
2 files changed, 79 insertions, 23 deletions
diff --git a/src/common/util.cpp b/src/common/util.cpp
index 046961b06..74a6babf1 100644
--- a/src/common/util.cpp
+++ b/src/common/util.cpp
@@ -39,11 +39,13 @@ using namespace epee;
#include "net/http_client.h" // epee::net_utils::...
#ifdef WIN32
-#include <windows.h>
-#include <shlobj.h>
-#include <strsafe.h>
+ #include <windows.h>
+ #include <shlobj.h>
+ #include <strsafe.h>
#else
-#include <sys/utsname.h>
+ #include <sys/file.h>
+ #include <sys/utsname.h>
+ #include <sys/stat.h>
#endif
#include <boost/filesystem.hpp>
#include <boost/asio.hpp>
@@ -53,7 +55,12 @@ namespace tools
{
std::function<void(int)> signal_handler::m_handler;
- std::unique_ptr<std::FILE, tools::close_file> create_private_file(const std::string& name)
+ private_file::private_file() noexcept : m_handle(), m_filename() {}
+
+ private_file::private_file(std::FILE* handle, std::string&& filename) noexcept
+ : m_handle(handle), m_filename(std::move(filename)) {}
+
+ private_file private_file::create(std::string name)
{
#ifdef WIN32
struct close_handle
@@ -70,17 +77,17 @@ namespace tools
const bool fail = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, std::addressof(temp)) == 0;
process.reset(temp);
if (fail)
- return nullptr;
+ return {};
}
DWORD sid_size = 0;
GetTokenInformation(process.get(), TokenOwner, nullptr, 0, std::addressof(sid_size));
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- return nullptr;
+ return {};
std::unique_ptr<char[]> sid{new char[sid_size]};
if (!GetTokenInformation(process.get(), TokenOwner, sid.get(), sid_size, std::addressof(sid_size)))
- return nullptr;
+ return {};
const PSID psid = reinterpret_cast<const PTOKEN_OWNER>(sid.get())->Owner;
const DWORD daclSize =
@@ -88,17 +95,17 @@ namespace tools
const std::unique_ptr<char[]> dacl{new char[daclSize]};
if (!InitializeAcl(reinterpret_cast<PACL>(dacl.get()), daclSize, ACL_REVISION))
- return nullptr;
+ return {};
if (!AddAccessAllowedAce(reinterpret_cast<PACL>(dacl.get()), ACL_REVISION, (READ_CONTROL | FILE_GENERIC_READ | DELETE), psid))
- return nullptr;
+ return {};
SECURITY_DESCRIPTOR descriptor{};
if (!InitializeSecurityDescriptor(std::addressof(descriptor), SECURITY_DESCRIPTOR_REVISION))
- return nullptr;
+ return {};
if (!SetSecurityDescriptorDacl(std::addressof(descriptor), true, reinterpret_cast<PACL>(dacl.get()), false))
- return nullptr;
+ return {};
SECURITY_ATTRIBUTES attributes{sizeof(SECURITY_ATTRIBUTES), std::addressof(descriptor), false};
std::unique_ptr<void, close_handle> file{
@@ -106,7 +113,7 @@ namespace tools
name.c_str(),
GENERIC_WRITE, FILE_SHARE_READ,
std::addressof(attributes),
- CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY,
+ CREATE_NEW, (FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE),
nullptr
)
};
@@ -121,22 +128,49 @@ namespace tools
{
_close(fd);
}
- return {real_file, tools::close_file{}};
+ return {real_file, std::move(name)};
}
}
#else
- const int fd = open(name.c_str(), (O_RDWR | O_EXCL | O_CREAT), S_IRUSR);
- if (0 <= fd)
+ const int fdr = open(name.c_str(), (O_RDONLY | O_CREAT), S_IRUSR);
+ if (0 <= fdr)
{
- std::FILE* file = fdopen(fd, "w");
- if (!file)
+ struct stat rstats = {};
+ if (fstat(fdr, std::addressof(rstats)) != 0)
{
- close(fd);
+ close(fdr);
+ return {};
+ }
+ fchmod(fdr, (S_IRUSR | S_IWUSR));
+ const int fdw = open(name.c_str(), O_RDWR);
+ fchmod(fdr, rstats.st_mode);
+ close(fdr);
+
+ if (0 <= fdw)
+ {
+ struct stat wstats = {};
+ if (fstat(fdw, std::addressof(wstats)) == 0 &&
+ rstats.st_dev == wstats.st_dev && rstats.st_ino == wstats.st_ino &&
+ flock(fdw, (LOCK_EX | LOCK_NB)) == 0 && ftruncate(fdw, 0) == 0)
+ {
+ std::FILE* file = fdopen(fdw, "w");
+ if (file) return {file, std::move(name)};
+ }
+ close(fdw);
}
- return {file, tools::close_file{}};
}
#endif
- return nullptr;
+ return {};
+ }
+
+ private_file::~private_file() noexcept
+ {
+ try
+ {
+ boost::system::error_code ec{};
+ boost::filesystem::remove(filename(), ec);
+ }
+ catch (...) {}
}
#ifdef WIN32
diff --git a/src/common/util.h b/src/common/util.h
index 2452bc9d5..48bdbbc28 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -60,8 +60,30 @@ namespace tools
}
};
- //! \return File only readable by owner. nullptr if `filename` exists.
- std::unique_ptr<std::FILE, close_file> create_private_file(const std::string& filename);
+ //! A file restricted to process owner AND process. Deletes file on destruction.
+ class private_file {
+ std::unique_ptr<std::FILE, close_file> m_handle;
+ std::string m_filename;
+
+ private_file(std::FILE* handle, std::string&& filename) noexcept;
+ public:
+
+ //! `handle() == nullptr && filename.empty()`.
+ private_file() noexcept;
+
+ /*! \return File only readable by owner and only used by this process
+ OR `private_file{}` on error. */
+ static private_file create(std::string filename);
+
+ private_file(private_file&&) = default;
+ private_file& operator=(private_file&&) = default;
+
+ //! Deletes `filename()` and closes `handle()`.
+ ~private_file() noexcept;
+
+ std::FILE* handle() const noexcept { return m_handle.get(); }
+ const std::string& filename() const noexcept { return m_filename; }
+ };
/*! \brief Returns the default data directory.
*