rpc: Implement random-cookie based authentication

When no `-rpcpassword` is specified, use a special 'cookie' file for
authentication. This file is generated with random content when the
daemon starts, and deleted when it exits. Read access to this file
controls who can access through RPC. By default this file is stored in
the data directory but it be overriden with `-rpccookiefile`.

This is similar to Tor CookieAuthentication: see
https://www.torproject.org/docs/tor-manual.html.en

Alternative to #6258. Like that pull, this allows running bitcoind
without any manual configuration. However, daemons should ideally never write to
their configuration files, so I prefer this solution.
This commit is contained in:
Wladimir J. van der Laan
2015-07-07 14:53:48 +02:00
parent 3d9362d5ac
commit 71cbeaad9a
4 changed files with 105 additions and 27 deletions

View File

@@ -597,27 +597,18 @@ void StartRPCThreads()
strAllowed += subnet.ToString() + " ";
LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed);
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
if (mapArgs["-rpcpassword"] == "")
{
unsigned char rand_pwd[32];
GetRandBytes(rand_pwd, 32);
uiInterface.ThreadSafeMessageBox(strprintf(
_("To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file:\n"
"%s\n"
"It is recommended you use the following random password:\n"
"rpcuser=bitcoinrpc\n"
"rpcpassword=%s\n"
"(you do not need to remember this password)\n"
"The username and password MUST NOT be the same.\n"
"If the file does not exist, create it with owner-readable-only file permissions.\n"
"It is also recommended to set alertnotify so you are notified of problems;\n"
"for example: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@foo.com\n"),
GetConfigFile().string(),
EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32)),
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::SECURE);
StartShutdown();
return;
LogPrintf("No rpcpassword set - using random cookie authentication\n");
if (!GenerateAuthCookie(&strRPCUserColonPass)) {
uiInterface.ThreadSafeMessageBox(
_("Error: A fatal internal error occured, see debug.log for details"), // Same message as AbortNode
"", CClientUIInterface::MSG_ERROR);
StartShutdown();
return;
}
} else {
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
}
assert(rpc_io_service == NULL);
@@ -768,6 +759,8 @@ void StopRPCThreads()
}
deadlineTimers.clear();
DeleteAuthCookie();
rpc_io_service->stop();
g_rpcSignals.Stopped();
if (rpc_worker_group != NULL)