rpc: Write authcookie atomically

Use POSIX rename atomicity at the `bitcoind` side to create a working
cookie atomically:

- Write `.cookie.tmp`, close file
- Rename `.cookie.tmp` to `.cookie`

This avoids clients reading invalid/partial cookies as in #11129.

(cherry picked from commit bitcoin/bitcoin@82dd7195e1)
This commit is contained in:
Wladimir J. van der Laan 2017-08-25 12:39:30 +02:00 committed by Jack Grigg
parent db29ea9e05
commit 43e97615ab
2 changed files with 16 additions and 7 deletions

View File

@ -69,9 +69,14 @@ static const std::string COOKIEAUTH_USER = "__cookie__";
/** Default name for auth cookie file */
static const std::string COOKIEAUTH_FILE = ".cookie";
fs::path GetAuthCookieFile()
/** Get name of RPC authentication cookie file */
static fs::path GetAuthCookieFile(bool temp=false)
{
fs::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE));
std::string arg = GetArg("-rpccookiefile", COOKIEAUTH_FILE);
if (temp) {
arg += ".tmp";
}
fs::path path(arg);
if (!path.is_complete()) path = GetDataDir() / path;
return path;
}
@ -86,14 +91,20 @@ bool GenerateAuthCookie(std::string *cookie_out)
* these are set to 077 in init.cpp unless overridden with -sysperms.
*/
std::ofstream file;
fs::path filepath = GetAuthCookieFile();
file.open(filepath.string().c_str());
fs::path filepath_tmp = GetAuthCookieFile(true);
file.open(filepath_tmp.string().c_str());
if (!file.is_open()) {
LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string());
LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath_tmp.string());
return false;
}
file << cookie;
file.close();
fs::path filepath = GetAuthCookieFile(false);
if (!RenameOver(filepath_tmp, filepath)) {
LogPrintf("Unable to rename cookie authentication file %s to %s\n", filepath_tmp.string(), filepath.string());
return false;
}
LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());
if (cookie_out)

View File

@ -84,8 +84,6 @@ UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const Un
std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
UniValue JSONRPCError(int code, const std::string& message);
/** Get name of RPC authentication cookie file */
fs::path GetAuthCookieFile();
/** Generate a new RPC authentication cookie and write it to disk */
bool GenerateAuthCookie(std::string *cookie_out);
/** Read the RPC authentication cookie from disk */