Merge pull request #2379
9c83f806
Do not create file when RPC user/pass is given and use file locking (Lee Clagett)
This commit is contained in:
commit
216395d43e
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -37,7 +37,6 @@ using namespace epee;
|
|||
#include "wallet/wallet_args.h"
|
||||
#include "common/command_line.h"
|
||||
#include "common/i18n.h"
|
||||
#include "common/util.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_basic/account.h"
|
||||
#include "wallet_rpc_server_commands_defs.h"
|
||||
|
@ -70,18 +69,12 @@ namespace tools
|
|||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
wallet_rpc_server::wallet_rpc_server():m_wallet(NULL), rpc_login_filename(), m_stop(false), m_trusted_daemon(false)
|
||||
wallet_rpc_server::wallet_rpc_server():m_wallet(NULL), rpc_login_file(), m_stop(false), m_trusted_daemon(false)
|
||||
{
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
wallet_rpc_server::~wallet_rpc_server()
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::system::error_code ec{};
|
||||
boost::filesystem::remove(rpc_login_filename, ec);
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
void wallet_rpc_server::set_wallet(wallet2 *cr)
|
||||
|
@ -182,34 +175,32 @@ namespace tools
|
|||
default_rpc_username,
|
||||
string_encoding::base64_encode(rand_128bit.data(), rand_128bit.size())
|
||||
);
|
||||
|
||||
std::string temp = "monero-wallet-rpc." + bind_port + ".login";
|
||||
rpc_login_file = tools::private_file::create(temp);
|
||||
if (!rpc_login_file.handle())
|
||||
{
|
||||
LOG_ERROR(tr("Failed to create file ") << temp << tr(". Check permissions or remove file"));
|
||||
return false;
|
||||
}
|
||||
std::fputs(http_login->username.c_str(), rpc_login_file.handle());
|
||||
std::fputc(':', rpc_login_file.handle());
|
||||
std::fputs(http_login->password.c_str(), rpc_login_file.handle());
|
||||
std::fflush(rpc_login_file.handle());
|
||||
if (std::ferror(rpc_login_file.handle()))
|
||||
{
|
||||
LOG_ERROR(tr("Error writing to file ") << temp);
|
||||
return false;
|
||||
}
|
||||
LOG_PRINT_L0(tr("RPC username/password is stored in file ") << temp);
|
||||
}
|
||||
else
|
||||
else // chosen user/pass
|
||||
{
|
||||
http_login.emplace(
|
||||
std::move(rpc_config->login->username), std::move(rpc_config->login->password).password()
|
||||
);
|
||||
}
|
||||
assert(bool(http_login));
|
||||
|
||||
std::string temp = "monero-wallet-rpc." + bind_port + ".login";
|
||||
const auto cookie = tools::create_private_file(temp);
|
||||
if (!cookie)
|
||||
{
|
||||
LOG_ERROR(tr("Failed to create file ") << temp << tr(". Check permissions or remove file"));
|
||||
return false;
|
||||
}
|
||||
rpc_login_filename.swap(temp); // nothrow guarantee destructor cleanup
|
||||
temp = rpc_login_filename;
|
||||
std::fputs(http_login->username.c_str(), cookie.get());
|
||||
std::fputc(':', cookie.get());
|
||||
std::fputs(http_login->password.c_str(), cookie.get());
|
||||
std::fflush(cookie.get());
|
||||
if (std::ferror(cookie.get()))
|
||||
{
|
||||
LOG_ERROR(tr("Error writing to file ") << temp);
|
||||
return false;
|
||||
}
|
||||
LOG_PRINT_L0(tr("RPC username/password is stored in file ") << temp);
|
||||
} // end auth enabled
|
||||
|
||||
m_http_client.set_server(walvars->get_daemon_address(), walvars->get_daemon_login());
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
#include <string>
|
||||
#include "common/util.h"
|
||||
#include "net/http_server_impl_base.h"
|
||||
#include "wallet_rpc_server_commands_defs.h"
|
||||
#include "wallet2.h"
|
||||
|
@ -154,7 +155,7 @@ namespace tools
|
|||
|
||||
wallet2 *m_wallet;
|
||||
std::string m_wallet_dir;
|
||||
std::string rpc_login_filename;
|
||||
tools::private_file rpc_login_file;
|
||||
std::atomic<bool> m_stop;
|
||||
bool m_trusted_daemon;
|
||||
epee::net_utils::http::http_simple_client m_http_client;
|
||||
|
|
Loading…
Reference in New Issue