aboutsummaryrefslogtreecommitdiff
path: root/src/httprpc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/httprpc.cpp')
-rw-r--r--src/httprpc.cpp49
1 files changed, 32 insertions, 17 deletions
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 2920aa26f..daac7a0f1 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -1,10 +1,14 @@
+// Copyright (c) 2015-2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
#include "httprpc.h"
#include "base58.h"
#include "chainparams.h"
#include "httpserver.h"
-#include "rpcprotocol.h"
-#include "rpcserver.h"
+#include "rpc/protocol.h"
+#include "rpc/server.h"
#include "random.h"
#include "sync.h"
#include "util.h"
@@ -17,8 +21,11 @@
#include <boost/algorithm/string.hpp> // boost::trim
#include <boost/foreach.hpp> //BOOST_FOREACH
+/** WWW-Authenticate to present with 401 Unauthorized response */
+static const char* WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\"";
+
/** Simple one-shot callback timer to be used by the RPC mechanism to e.g.
- * re-lock the wellet.
+ * re-lock the wallet.
*/
class HTTPRPCTimer : public RPCTimerBase
{
@@ -38,7 +45,7 @@ private:
class HTTPRPCTimerInterface : public RPCTimerInterface
{
public:
- HTTPRPCTimerInterface(struct event_base* base) : base(base)
+ HTTPRPCTimerInterface(struct event_base* _base) : base(_base)
{
}
const char* Name()
@@ -88,7 +95,7 @@ static bool multiUserAuthorized(std::string strUserPass)
if (mapMultiArgs.count("-rpcauth") > 0) {
//Search for multi-user login/pass "rpcauth" from config
- BOOST_FOREACH(std::string strRPCAuth, mapMultiArgs["-rpcauth"])
+ BOOST_FOREACH(std::string strRPCAuth, mapMultiArgs.at("-rpcauth"))
{
std::vector<std::string> vFields;
boost::split(vFields, strRPCAuth, boost::is_any_of(":$"));
@@ -106,8 +113,8 @@ static bool multiUserAuthorized(std::string strUserPass)
std::string strHash = vFields[2];
unsigned int KEY_SIZE = 32;
- unsigned char *out = new unsigned char[KEY_SIZE];
-
+ unsigned char out[KEY_SIZE];
+
CHMAC_SHA256(reinterpret_cast<const unsigned char*>(strSalt.c_str()), strSalt.size()).Write(reinterpret_cast<const unsigned char*>(strPass.c_str()), strPass.size()).Finalize(out);
std::vector<unsigned char> hexvec(out, out+KEY_SIZE);
std::string strHashFromPass = HexStr(hexvec);
@@ -120,7 +127,7 @@ static bool multiUserAuthorized(std::string strUserPass)
return false;
}
-static bool RPCAuthorized(const std::string& strAuth)
+static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUsernameOut)
{
if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called
return false;
@@ -129,7 +136,10 @@ static bool RPCAuthorized(const std::string& strAuth)
std::string strUserPass64 = strAuth.substr(6);
boost::trim(strUserPass64);
std::string strUserPass = DecodeBase64(strUserPass64);
-
+
+ if (strUserPass.find(":") != std::string::npos)
+ strAuthUsernameOut = strUserPass.substr(0, strUserPass.find(":"));
+
//Check if authorized under single-user field
if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
return true;
@@ -147,11 +157,13 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
// Check authorization
std::pair<bool, std::string> authHeader = req->GetHeader("authorization");
if (!authHeader.first) {
+ req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
req->WriteReply(HTTP_UNAUTHORIZED);
return false;
}
- if (!RPCAuthorized(authHeader.second)) {
+ JSONRPCRequest jreq;
+ if (!RPCAuthorized(authHeader.second, jreq.authUser)) {
LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", req->GetPeer().ToString());
/* Deter brute-forcing
@@ -159,23 +171,26 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
shouldn't have their RPC port exposed. */
MilliSleep(250);
+ req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
req->WriteReply(HTTP_UNAUTHORIZED);
return false;
}
- JSONRequest jreq;
try {
// Parse request
UniValue valRequest;
if (!valRequest.read(req->ReadBody()))
throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
+ // Set the URI
+ jreq.URI = req->GetURI();
+
std::string strReply;
// singleton request
if (valRequest.isObject()) {
jreq.parse(valRequest);
- UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);
+ UniValue result = tableRPC.execute(jreq);
// Send reply
strReply = JSONRPCReply(result, NullUniValue, jreq.id);
@@ -200,7 +215,7 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
static bool InitRPCAuthentication()
{
- if (mapArgs["-rpcpassword"] == "")
+ if (GetArg("-rpcpassword", "") == "")
{
LogPrintf("No rpcpassword set - using random cookie authentication\n");
if (!GenerateAuthCookie(&strRPCUserColonPass)) {
@@ -210,8 +225,8 @@ static bool InitRPCAuthentication()
return false;
}
} else {
- LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcuser for rpcauth auth generation.");
- strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
+ LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcuser for rpcauth auth generation.\n");
+ strRPCUserColonPass = GetArg("-rpcuser", "") + ":" + GetArg("-rpcpassword", "");
}
return true;
}
@@ -226,7 +241,7 @@ bool StartHTTPRPC()
assert(EventBase());
httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase());
- RPCRegisterTimerInterface(httpRPCTimerInterface);
+ RPCSetTimerInterface(httpRPCTimerInterface);
return true;
}
@@ -240,7 +255,7 @@ void StopHTTPRPC()
LogPrint("rpc", "Stopping HTTP RPC server\n");
UnregisterHTTPHandler("/", true);
if (httpRPCTimerInterface) {
- RPCUnregisterTimerInterface(httpRPCTimerInterface);
+ RPCUnsetTimerInterface(httpRPCTimerInterface);
delete httpRPCTimerInterface;
httpRPCTimerInterface = 0;
}