Skip to content

Commit e49a727

Browse files
vasildlaanwj
authored andcommitted
rpc: Avoid join-split roundtrip for user:pass for auth credentials
1 parent 98ff38a commit e49a727

File tree

3 files changed

+42
-27
lines changed

3 files changed

+42
-27
lines changed

src/httprpc.cpp

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ static bool HTTPReq_JSONRPC(const std::any& context, HTTPRequest* req)
278278

279279
static bool InitRPCAuthentication()
280280
{
281-
std::string user_colon_pass;
281+
std::string user;
282+
std::string pass;
282283

283284
if (gArgs.GetArg("-rpcpassword", "") == "")
284285
{
@@ -293,30 +294,25 @@ static bool InitRPCAuthentication()
293294
cookie_perms = *perm_opt;
294295
}
295296

296-
if (!GenerateAuthCookie(&user_colon_pass, cookie_perms)) {
297+
switch (GenerateAuthCookie(cookie_perms, user, pass)) {
298+
case GenerateAuthCookieResult::ERR:
297299
return false;
298-
}
299-
if (user_colon_pass.empty()) {
300+
case GenerateAuthCookieResult::DISABLED:
300301
LogInfo("RPC authentication cookie file generation is disabled.");
301-
} else {
302+
break;
303+
case GenerateAuthCookieResult::OK:
302304
LogInfo("Using random cookie authentication.");
305+
break;
303306
}
304307
} else {
305308
LogInfo("Using rpcuser/rpcpassword authentication.");
306309
LogWarning("The use of rpcuser/rpcpassword is less secure, because credentials are configured in plain text. It is recommended that locally-run instances switch to cookie-based auth, or otherwise to use hashed rpcauth credentials. See share/rpcauth in the source directory for more information.");
307-
user_colon_pass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", "");
310+
user = gArgs.GetArg("-rpcuser", "");
311+
pass = gArgs.GetArg("-rpcpassword", "");
308312
}
309313

310314
// If there is a plaintext credential, hash it with a random salt before storage.
311-
if (!user_colon_pass.empty()) {
312-
std::vector<std::string> fields{SplitString(user_colon_pass, ':')};
313-
if (fields.size() != 2) {
314-
LogError("Unable to parse RPC credentials. The configured rpcuser or rpcpassword cannot contain a \":\".");
315-
return false;
316-
}
317-
const std::string& user = fields[0];
318-
const std::string& pass = fields[1];
319-
315+
if (!user.empty() || !pass.empty()) {
320316
// Generate a random 16 byte hex salt.
321317
std::array<unsigned char, 16> raw_salt;
322318
GetStrongRandBytes(raw_salt);

src/rpc/request.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,50 +97,52 @@ static fs::path GetAuthCookieFile(bool temp=false)
9797

9898
static bool g_generated_cookie = false;
9999

100-
bool GenerateAuthCookie(std::string* cookie_out, std::optional<fs::perms> cookie_perms)
100+
GenerateAuthCookieResult GenerateAuthCookie(const std::optional<fs::perms>& cookie_perms,
101+
std::string& user,
102+
std::string& pass)
101103
{
102104
const size_t COOKIE_SIZE = 32;
103105
unsigned char rand_pwd[COOKIE_SIZE];
104106
GetRandBytes(rand_pwd);
105-
std::string cookie = COOKIEAUTH_USER + ":" + HexStr(rand_pwd);
107+
const std::string rand_pwd_hex{HexStr(rand_pwd)};
106108

107109
/** the umask determines what permissions are used to create this file -
108110
* these are set to 0077 in common/system.cpp.
109111
*/
110112
std::ofstream file;
111113
fs::path filepath_tmp = GetAuthCookieFile(true);
112114
if (filepath_tmp.empty()) {
113-
return true; // -norpccookiefile
115+
return GenerateAuthCookieResult::DISABLED; // -norpccookiefile
114116
}
115117
file.open(filepath_tmp);
116118
if (!file.is_open()) {
117119
LogWarning("Unable to open cookie authentication file %s for writing", fs::PathToString(filepath_tmp));
118-
return false;
120+
return GenerateAuthCookieResult::ERR;
119121
}
120-
file << cookie;
122+
file << COOKIEAUTH_USER << ":" << rand_pwd_hex;
121123
file.close();
122124

123125
fs::path filepath = GetAuthCookieFile(false);
124126
if (!RenameOver(filepath_tmp, filepath)) {
125127
LogWarning("Unable to rename cookie authentication file %s to %s", fs::PathToString(filepath_tmp), fs::PathToString(filepath));
126-
return false;
128+
return GenerateAuthCookieResult::ERR;
127129
}
128130
if (cookie_perms) {
129131
std::error_code code;
130132
fs::permissions(filepath, cookie_perms.value(), fs::perm_options::replace, code);
131133
if (code) {
132134
LogWarning("Unable to set permissions on cookie authentication file %s", fs::PathToString(filepath));
133-
return false;
135+
return GenerateAuthCookieResult::ERR;
134136
}
135137
}
136138

137139
g_generated_cookie = true;
138140
LogInfo("Generated RPC authentication cookie %s\n", fs::PathToString(filepath));
139141
LogInfo("Permissions used for cookie: %s\n", PermsToSymbolicString(fs::status(filepath).permissions()));
140142

141-
if (cookie_out)
142-
*cookie_out = cookie;
143-
return true;
143+
user = COOKIEAUTH_USER;
144+
pass = rand_pwd_hex;
145+
return GenerateAuthCookieResult::OK;
144146
}
145147

146148
bool GetAuthCookie(std::string *cookie_out)

src/rpc/request.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,25 @@ UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params,
2323
UniValue JSONRPCReplyObj(UniValue result, UniValue error, std::optional<UniValue> id, JSONRPCVersion jsonrpc_version);
2424
UniValue JSONRPCError(int code, const std::string& message);
2525

26-
/** Generate a new RPC authentication cookie and write it to disk */
27-
bool GenerateAuthCookie(std::string* cookie_out, std::optional<fs::perms> cookie_perms=std::nullopt);
26+
enum class GenerateAuthCookieResult : uint8_t {
27+
DISABLED, // -norpccookiefile
28+
ERR,
29+
OK,
30+
};
31+
32+
/**
33+
* Generate a new RPC authentication cookie and write it to disk
34+
* @param[in] cookie_perms Filesystem permissions to use for the cookie file.
35+
* @param[out] user Generated username, only set if `OK` is returned.
36+
* @param[out] pass Generated password, only set if `OK` is returned.
37+
* @retval GenerateAuthCookieResult::DISABLED Authentication via cookie is disabled.
38+
* @retval GenerateAuthCookieResult::ERROR Error occurred, auth data could not be saved to disk.
39+
* @retval GenerateAuthCookieResult::OK Auth data was generated, saved to disk and in `user` and `pass`.
40+
*/
41+
GenerateAuthCookieResult GenerateAuthCookie(const std::optional<fs::perms>& cookie_perms,
42+
std::string& user,
43+
std::string& pass);
44+
2845
/** Read the RPC authentication cookie from disk */
2946
bool GetAuthCookie(std::string *cookie_out);
3047
/** Delete RPC authentication cookie from disk */

0 commit comments

Comments
 (0)