aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/httprpc.cpp19
-rw-r--r--src/init.cpp1
-rw-r--r--src/rpc/request.cpp21
-rw-r--r--src/rpc/request.h3
-rw-r--r--src/util/fs_helpers.cpp40
-rw-r--r--src/util/fs_helpers.h14
6 files changed, 89 insertions, 9 deletions
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 128597157d..af809eaf38 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -11,6 +11,8 @@
#include <netaddress.h>
#include <rpc/protocol.h>
#include <rpc/server.h>
+#include <util/fs.h>
+#include <util/fs_helpers.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <walletinitinterface.h>
@@ -19,6 +21,7 @@
#include <iterator>
#include <map>
#include <memory>
+#include <optional>
#include <set>
#include <string>
#include <vector>
@@ -291,8 +294,20 @@ static bool InitRPCAuthentication()
{
if (gArgs.GetArg("-rpcpassword", "") == "")
{
- LogPrintf("Using random cookie authentication.\n");
- if (!GenerateAuthCookie(&strRPCUserColonPass)) {
+ LogInfo("Using random cookie authentication.\n");
+
+ std::optional<fs::perms> cookie_perms{std::nullopt};
+ auto cookie_perms_arg{gArgs.GetArg("-rpccookieperms")};
+ if (cookie_perms_arg) {
+ auto perm_opt = InterpretPermString(*cookie_perms_arg);
+ if (!perm_opt) {
+ LogInfo("Invalid -rpccookieperms=%s; must be one of 'owner', 'group', or 'all'.\n", *cookie_perms_arg);
+ return false;
+ }
+ cookie_perms = *perm_opt;
+ }
+
+ if (!GenerateAuthCookie(&strRPCUserColonPass, cookie_perms)) {
return false;
}
} else {
diff --git a/src/init.cpp b/src/init.cpp
index c6ef62372e..c9405153b4 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -659,6 +659,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-rpcbind=<addr>[:port]", "Bind to given address to listen for JSON-RPC connections. Do not expose the RPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
argsman.AddArg("-rpcdoccheck", strprintf("Throw a non-fatal error at runtime if the documentation for an RPC is incorrect (default: %u)", DEFAULT_RPC_DOC_CHECK), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
argsman.AddArg("-rpccookiefile=<loc>", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
+ argsman.AddArg("-rpccookieperms=<readable-by>", strprintf("Set permissions on the RPC auth cookie file so that it is readable by [owner|group|all] (default: owner [via umask 0077])"), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
argsman.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
argsman.AddArg("-rpcport=<port>", strprintf("Listen for JSON-RPC connections on <port> (default: %u, testnet: %u, signet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), signetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
argsman.AddArg("-rpcservertimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp
index 87b9f18b33..083d1be44f 100644
--- a/src/rpc/request.cpp
+++ b/src/rpc/request.cpp
@@ -5,12 +5,11 @@
#include <rpc/request.h>
-#include <util/fs.h>
-
#include <common/args.h>
#include <logging.h>
#include <random.h>
#include <rpc/protocol.h>
+#include <util/fs.h>
#include <util/fs_helpers.h>
#include <util/strencodings.h>
@@ -95,7 +94,7 @@ static fs::path GetAuthCookieFile(bool temp=false)
static bool g_generated_cookie = false;
-bool GenerateAuthCookie(std::string *cookie_out)
+bool GenerateAuthCookie(std::string* cookie_out, std::optional<fs::perms> cookie_perms)
{
const size_t COOKIE_SIZE = 32;
unsigned char rand_pwd[COOKIE_SIZE];
@@ -109,7 +108,7 @@ bool GenerateAuthCookie(std::string *cookie_out)
fs::path filepath_tmp = GetAuthCookieFile(true);
file.open(filepath_tmp);
if (!file.is_open()) {
- LogPrintf("Unable to open cookie authentication file %s for writing\n", fs::PathToString(filepath_tmp));
+ LogInfo("Unable to open cookie authentication file %s for writing\n", fs::PathToString(filepath_tmp));
return false;
}
file << cookie;
@@ -117,11 +116,21 @@ bool GenerateAuthCookie(std::string *cookie_out)
fs::path filepath = GetAuthCookieFile(false);
if (!RenameOver(filepath_tmp, filepath)) {
- LogPrintf("Unable to rename cookie authentication file %s to %s\n", fs::PathToString(filepath_tmp), fs::PathToString(filepath));
+ LogInfo("Unable to rename cookie authentication file %s to %s\n", fs::PathToString(filepath_tmp), fs::PathToString(filepath));
return false;
}
+ if (cookie_perms) {
+ std::error_code code;
+ fs::permissions(filepath, cookie_perms.value(), fs::perm_options::replace, code);
+ if (code) {
+ LogInfo("Unable to set permissions on cookie authentication file %s\n", fs::PathToString(filepath_tmp));
+ return false;
+ }
+ }
+
g_generated_cookie = true;
- LogPrintf("Generated RPC authentication cookie %s\n", fs::PathToString(filepath));
+ LogInfo("Generated RPC authentication cookie %s\n", fs::PathToString(filepath));
+ LogInfo("Permissions used for cookie: %s\n", PermsToSymbolicString(fs::status(filepath).permissions()));
if (cookie_out)
*cookie_out = cookie;
diff --git a/src/rpc/request.h b/src/rpc/request.h
index 9968426636..24887e8691 100644
--- a/src/rpc/request.h
+++ b/src/rpc/request.h
@@ -11,6 +11,7 @@
#include <string>
#include <univalue.h>
+#include <util/fs.h>
enum class JSONRPCVersion {
V1_LEGACY,
@@ -23,7 +24,7 @@ UniValue JSONRPCReplyObj(UniValue result, UniValue error, std::optional<UniValue
UniValue JSONRPCError(int code, const std::string& message);
/** Generate a new RPC authentication cookie and write it to disk */
-bool GenerateAuthCookie(std::string *cookie_out);
+bool GenerateAuthCookie(std::string* cookie_out, std::optional<fs::perms> cookie_perms=std::nullopt);
/** Read the RPC authentication cookie from disk */
bool GetAuthCookie(std::string *cookie_out);
/** Delete RPC authentication cookie from disk */
diff --git a/src/util/fs_helpers.cpp b/src/util/fs_helpers.cpp
index 8952f20f79..41c8fe3b8f 100644
--- a/src/util/fs_helpers.cpp
+++ b/src/util/fs_helpers.cpp
@@ -16,6 +16,7 @@
#include <fstream>
#include <map>
#include <memory>
+#include <optional>
#include <string>
#include <system_error>
#include <utility>
@@ -269,3 +270,42 @@ bool TryCreateDirectories(const fs::path& p)
// create_directories didn't create the directory, it had to have existed already
return false;
}
+
+std::string PermsToSymbolicString(fs::perms p)
+{
+ std::string perm_str(9, '-');
+
+ auto set_perm = [&](size_t pos, fs::perms required_perm, char letter) {
+ if ((p & required_perm) != fs::perms::none) {
+ perm_str[pos] = letter;
+ }
+ };
+
+ set_perm(0, fs::perms::owner_read, 'r');
+ set_perm(1, fs::perms::owner_write, 'w');
+ set_perm(2, fs::perms::owner_exec, 'x');
+ set_perm(3, fs::perms::group_read, 'r');
+ set_perm(4, fs::perms::group_write, 'w');
+ set_perm(5, fs::perms::group_exec, 'x');
+ set_perm(6, fs::perms::others_read, 'r');
+ set_perm(7, fs::perms::others_write, 'w');
+ set_perm(8, fs::perms::others_exec, 'x');
+
+ return perm_str;
+}
+
+std::optional<fs::perms> InterpretPermString(const std::string& s)
+{
+ if (s == "owner") {
+ return fs::perms::owner_read | fs::perms::owner_write;
+ } else if (s == "group") {
+ return fs::perms::owner_read | fs::perms::owner_write |
+ fs::perms::group_read;
+ } else if (s == "all") {
+ return fs::perms::owner_read | fs::perms::owner_write |
+ fs::perms::group_read |
+ fs::perms::others_read;
+ } else {
+ return std::nullopt;
+ }
+}
diff --git a/src/util/fs_helpers.h b/src/util/fs_helpers.h
index ea3778eac3..28dd6d979d 100644
--- a/src/util/fs_helpers.h
+++ b/src/util/fs_helpers.h
@@ -12,6 +12,7 @@
#include <cstdio>
#include <iosfwd>
#include <limits>
+#include <optional>
/**
* Ensure file contents are fully committed to disk, using a platform-specific
@@ -62,6 +63,19 @@ void ReleaseDirectoryLocks();
bool TryCreateDirectories(const fs::path& p);
fs::path GetDefaultDataDir();
+/** Convert fs::perms to symbolic string of the form 'rwxrwxrwx'
+ *
+ * @param[in] p the perms to be converted
+ * @return Symbolic permissions string
+ */
+std::string PermsToSymbolicString(fs::perms p);
+/** Interpret a custom permissions level string as fs::perms
+ *
+ * @param[in] s Permission level string
+ * @return Permissions as fs::perms
+ */
+std::optional<fs::perms> InterpretPermString(const std::string& s);
+
#ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif