Skip to content

Commit f467aed

Browse files
committed
init: add option for rpccookie permissions
Add a bitcoind launch option `-rpccookieperms` to configure the file permissions of the cookie on Unix systems.
1 parent 7df03f1 commit f467aed

File tree

4 files changed

+36
-9
lines changed

4 files changed

+36
-9
lines changed

src/httprpc.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include <netaddress.h>
1212
#include <rpc/protocol.h>
1313
#include <rpc/server.h>
14+
#include <util/fs.h>
15+
#include <util/fs_helpers.h>
1416
#include <util/strencodings.h>
1517
#include <util/string.h>
1618
#include <walletinitinterface.h>
@@ -19,6 +21,7 @@
1921
#include <iterator>
2022
#include <map>
2123
#include <memory>
24+
#include <optional>
2225
#include <set>
2326
#include <string>
2427
#include <vector>
@@ -244,8 +247,20 @@ static bool InitRPCAuthentication()
244247
{
245248
if (gArgs.GetArg("-rpcpassword", "") == "")
246249
{
247-
LogPrintf("Using random cookie authentication.\n");
248-
if (!GenerateAuthCookie(&strRPCUserColonPass)) {
250+
LogInfo("Using random cookie authentication.\n");
251+
252+
std::optional<fs::perms> cookie_perms{std::nullopt};
253+
auto cookie_perms_arg{gArgs.GetArg("-rpccookieperms")};
254+
if (cookie_perms_arg) {
255+
auto perm_opt = InterpretPermString(*cookie_perms_arg);
256+
if (!perm_opt) {
257+
LogInfo("Invalid -rpccookieperms=%s; must be one of 'owner', 'group', or 'all'.\n", *cookie_perms_arg);
258+
return false;
259+
}
260+
cookie_perms = *perm_opt;
261+
}
262+
263+
if (!GenerateAuthCookie(&strRPCUserColonPass, cookie_perms)) {
249264
return false;
250265
}
251266
} else {

src/init.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,7 @@ void SetupServerArgs(ArgsManager& argsman)
650650
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);
651651
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);
652652
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);
653+
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);
653654
argsman.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
654655
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);
655656
argsman.AddArg("-rpcservertimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);

src/rpc/request.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55

66
#include <rpc/request.h>
77

8-
#include <util/fs.h>
9-
108
#include <common/args.h>
119
#include <logging.h>
1210
#include <random.h>
1311
#include <rpc/protocol.h>
12+
#include <util/fs.h>
1413
#include <util/fs_helpers.h>
1514
#include <util/strencodings.h>
1615

@@ -82,7 +81,7 @@ static fs::path GetAuthCookieFile(bool temp=false)
8281

8382
static bool g_generated_cookie = false;
8483

85-
bool GenerateAuthCookie(std::string *cookie_out)
84+
bool GenerateAuthCookie(std::string* cookie_out, std::optional<fs::perms> cookie_perms)
8685
{
8786
const size_t COOKIE_SIZE = 32;
8887
unsigned char rand_pwd[COOKIE_SIZE];
@@ -96,19 +95,29 @@ bool GenerateAuthCookie(std::string *cookie_out)
9695
fs::path filepath_tmp = GetAuthCookieFile(true);
9796
file.open(filepath_tmp);
9897
if (!file.is_open()) {
99-
LogPrintf("Unable to open cookie authentication file %s for writing\n", fs::PathToString(filepath_tmp));
98+
LogInfo("Unable to open cookie authentication file %s for writing\n", fs::PathToString(filepath_tmp));
10099
return false;
101100
}
102101
file << cookie;
103102
file.close();
104103

105104
fs::path filepath = GetAuthCookieFile(false);
106105
if (!RenameOver(filepath_tmp, filepath)) {
107-
LogPrintf("Unable to rename cookie authentication file %s to %s\n", fs::PathToString(filepath_tmp), fs::PathToString(filepath));
106+
LogInfo("Unable to rename cookie authentication file %s to %s\n", fs::PathToString(filepath_tmp), fs::PathToString(filepath));
108107
return false;
109108
}
109+
if (cookie_perms) {
110+
std::error_code code;
111+
fs::permissions(filepath, cookie_perms.value(), fs::perm_options::replace, code);
112+
if (code) {
113+
LogInfo("Unable to set permissions on cookie authentication file %s\n", fs::PathToString(filepath_tmp));
114+
return false;
115+
}
116+
}
117+
110118
g_generated_cookie = true;
111-
LogPrintf("Generated RPC authentication cookie %s\n", fs::PathToString(filepath));
119+
LogInfo("Generated RPC authentication cookie %s\n", fs::PathToString(filepath));
120+
LogInfo("Permissions used for cookie: %s\n", PermsToSymbolicString(fs::status(filepath).permissions()));
112121

113122
if (cookie_out)
114123
*cookie_out = cookie;

src/rpc/request.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,19 @@
77
#define BITCOIN_RPC_REQUEST_H
88

99
#include <any>
10+
#include <optional>
1011
#include <string>
1112

1213
#include <univalue.h>
14+
#include <util/fs.h>
1315

1416
UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id);
1517
UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id);
1618
std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
1719
UniValue JSONRPCError(int code, const std::string& message);
1820

1921
/** Generate a new RPC authentication cookie and write it to disk */
20-
bool GenerateAuthCookie(std::string *cookie_out);
22+
bool GenerateAuthCookie(std::string* cookie_out, std::optional<fs::perms> cookie_perms=std::nullopt);
2123
/** Read the RPC authentication cookie from disk */
2224
bool GetAuthCookie(std::string *cookie_out);
2325
/** Delete RPC authentication cookie from disk */

0 commit comments

Comments
 (0)