Dash Core  0.12.2.1
P2P Digital Currency
httprpc.cpp
Go to the documentation of this file.
1 #include "httprpc.h"
2 
3 #include "base58.h"
4 #include "chainparams.h"
5 #include "httpserver.h"
6 #include "rpc/protocol.h"
7 #include "rpc/server.h"
8 #include "random.h"
9 #include "sync.h"
10 #include "util.h"
11 #include "utilstrencodings.h"
12 #include "ui_interface.h"
13 #include "crypto/hmac_sha256.h"
14 #include <stdio.h>
15 #include "utilstrencodings.h"
16 
17 #include <boost/algorithm/string.hpp> // boost::trim
18 #include <boost/foreach.hpp> //BOOST_FOREACH
19 
21 static const char* WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\"";
22 
26 class HTTPRPCTimer : public RPCTimerBase
27 {
28 public:
29  HTTPRPCTimer(struct event_base* eventBase, boost::function<void(void)>& func, int64_t millis) :
30  ev(eventBase, false, func)
31  {
32  struct timeval tv;
33  tv.tv_sec = millis/1000;
34  tv.tv_usec = (millis%1000)*1000;
35  ev.trigger(&tv);
36  }
37 private:
39 };
40 
42 {
43 public:
44  HTTPRPCTimerInterface(struct event_base* base) : base(base)
45  {
46  }
47  const char* Name()
48  {
49  return "HTTP";
50  }
51  RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis)
52  {
53  return new HTTPRPCTimer(base, func, millis);
54  }
55 private:
56  struct event_base* base;
57 };
58 
59 
60 /* Pre-base64-encoded authentication token */
61 static std::string strRPCUserColonPass;
62 /* Stored RPC timer interface (for unregistration) */
64 
65 static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id)
66 {
67  // Send error reply from json-rpc error object
68  int nStatus = HTTP_INTERNAL_SERVER_ERROR;
69  int code = find_value(objError, "code").get_int();
70 
71  if (code == RPC_INVALID_REQUEST)
72  nStatus = HTTP_BAD_REQUEST;
73  else if (code == RPC_METHOD_NOT_FOUND)
74  nStatus = HTTP_NOT_FOUND;
75 
76  std::string strReply = JSONRPCReply(NullUniValue, objError, id);
77 
78  req->WriteHeader("Content-Type", "application/json");
79  req->WriteReply(nStatus, strReply);
80 }
81 
82 //This function checks username and password against -rpcauth
83 //entries from config file.
84 static bool multiUserAuthorized(std::string strUserPass)
85 {
86  if (strUserPass.find(":") == std::string::npos) {
87  return false;
88  }
89  std::string strUser = strUserPass.substr(0, strUserPass.find(":"));
90  std::string strPass = strUserPass.substr(strUserPass.find(":") + 1);
91 
92  if (mapMultiArgs.count("-rpcauth") > 0) {
93  //Search for multi-user login/pass "rpcauth" from config
94  BOOST_FOREACH(std::string strRPCAuth, mapMultiArgs["-rpcauth"])
95  {
96  std::vector<std::string> vFields;
97  boost::split(vFields, strRPCAuth, boost::is_any_of(":$"));
98  if (vFields.size() != 3) {
99  //Incorrect formatting in config file
100  continue;
101  }
102 
103  std::string strName = vFields[0];
104  if (!TimingResistantEqual(strName, strUser)) {
105  continue;
106  }
107 
108  std::string strSalt = vFields[1];
109  std::string strHash = vFields[2];
110 
111  unsigned int KEY_SIZE = 32;
112  unsigned char *out = new unsigned char[KEY_SIZE];
113 
114  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);
115  std::vector<unsigned char> hexvec(out, out+KEY_SIZE);
116  std::string strHashFromPass = HexStr(hexvec);
117 
118  if (TimingResistantEqual(strHashFromPass, strHash)) {
119  return true;
120  }
121  }
122  }
123  return false;
124 }
125 
126 static bool RPCAuthorized(const std::string& strAuth)
127 {
128  if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called
129  return false;
130  if (strAuth.substr(0, 6) != "Basic ")
131  return false;
132  std::string strUserPass64 = strAuth.substr(6);
133  boost::trim(strUserPass64);
134  std::string strUserPass = DecodeBase64(strUserPass64);
135 
136  //Check if authorized under single-user field
137  if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
138  return true;
139  }
140  return multiUserAuthorized(strUserPass);
141 }
142 
143 static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
144 {
145  // JSONRPC handles only POST
146  if (req->GetRequestMethod() != HTTPRequest::POST) {
147  req->WriteReply(HTTP_BAD_METHOD, "JSONRPC server handles only POST requests");
148  return false;
149  }
150  // Check authorization
151  std::pair<bool, std::string> authHeader = req->GetHeader("authorization");
152  if (!authHeader.first) {
153  req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
155  return false;
156  }
157 
158  if (!RPCAuthorized(authHeader.second)) {
159  LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", req->GetPeer().ToString());
160 
161  /* Deter brute-forcing
162  If this results in a DoS the user really
163  shouldn't have their RPC port exposed. */
164  MilliSleep(250);
165 
166  req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
168  return false;
169  }
170 
171  JSONRequest jreq;
172  try {
173  // Parse request
174  UniValue valRequest;
175  if (!valRequest.read(req->ReadBody()))
176  throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
177 
178  std::string strReply;
179  // singleton request
180  if (valRequest.isObject()) {
181  jreq.parse(valRequest);
182 
184 
185  // Send reply
186  strReply = JSONRPCReply(result, NullUniValue, jreq.id);
187 
188  // array of requests
189  } else if (valRequest.isArray())
190  strReply = JSONRPCExecBatch(valRequest.get_array());
191  else
192  throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
193 
194  req->WriteHeader("Content-Type", "application/json");
195  req->WriteReply(HTTP_OK, strReply);
196  } catch (const UniValue& objError) {
197  JSONErrorReply(req, objError, jreq.id);
198  return false;
199  } catch (const std::exception& e) {
200  JSONErrorReply(req, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
201  return false;
202  }
203  return true;
204 }
205 
207 {
208  if (mapArgs["-rpcpassword"] == "")
209  {
210  LogPrintf("No rpcpassword set - using random cookie authentication\n");
213  _("Error: A fatal internal error occurred, see debug.log for details"), // Same message as AbortNode
215  return false;
216  }
217  } else {
218  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");
219  strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
220  }
221  return true;
222 }
223 
225 {
226  LogPrint("rpc", "Starting HTTP RPC server\n");
227  if (!InitRPCAuthentication())
228  return false;
229 
231 
232  assert(EventBase());
235  return true;
236 }
237 
239 {
240  LogPrint("rpc", "Interrupting HTTP RPC server\n");
241 }
242 
244 {
245  LogPrint("rpc", "Stopping HTTP RPC server\n");
246  UnregisterHTTPHandler("/", true);
247  if (httpRPCTimerInterface) {
249  delete httpRPCTimerInterface;
251  }
252 }
void MilliSleep(int64_t n)
Definition: utiltime.cpp:63
static const char * WWW_AUTH_HEADER_DATA
Definition: httprpc.cpp:21
static std::string strRPCUserColonPass
Definition: httprpc.cpp:61
std::string JSONRPCExecBatch(const UniValue &vReq)
Definition: server.cpp:532
UniValue id
Definition: server.h:38
static bool InitRPCAuthentication()
Definition: httprpc.cpp:206
bool StartHTTPRPC()
Definition: httprpc.cpp:224
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
static void JSONErrorReply(HTTPRequest *req, const UniValue &objError, const UniValue &id)
Definition: httprpc.cpp:65
std::string ReadBody()
Definition: httpserver.cpp:579
HTTPEvent ev
Definition: httprpc.cpp:38
HTTPRPCTimer(struct event_base *eventBase, boost::function< void(void)> &func, int64_t millis)
Definition: httprpc.cpp:29
std::string ToString(bool fUseGetnameinfo=true) const
Definition: netaddress.cpp:568
void InterruptHTTPRPC()
Definition: httprpc.cpp:238
void trigger(struct timeval *tv)
Definition: httpserver.cpp:547
static bool HTTPReq_JSONRPC(HTTPRequest *req, const std::string &)
Definition: httprpc.cpp:143
boost::signals2::signal< bool(const std::string &message, const std::string &caption, unsigned int style), boost::signals2::last_value< bool > > ThreadSafeMessageBox
Definition: ui_interface.h:77
HTTPRPCTimerInterface(struct event_base *base)
Definition: httprpc.cpp:44
const UniValue & find_value(const UniValue &obj, const std::string &name)
Definition: univalue.cpp:280
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Definition: httpserver.cpp:665
bool TimingResistantEqual(const T &a, const T &b)
const char * Name()
Definition: httprpc.cpp:47
const CRPCTable tableRPC
Definition: server.cpp:614
static bool multiUserAuthorized(std::string strUserPass)
Definition: httprpc.cpp:84
#define LogPrintf(...)
Definition: util.h:98
static int LogPrint(const char *category, const char *format)
Definition: util.h:126
vector< unsigned char > DecodeBase64(const char *p, bool *pfInvalid)
void WriteReply(int nStatus, const std::string &strReply="")
Definition: httpserver.cpp:611
static bool RPCAuthorized(const std::string &strAuth)
Definition: httprpc.cpp:126
CClientUIInterface uiInterface
Definition: init.cpp:130
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
Definition: httpserver.cpp:671
bool isArray() const
Definition: univalue.h:83
struct event_base * EventBase()
Definition: httpserver.cpp:523
std::pair< bool, std::string > GetHeader(const std::string &hdr)
Definition: httpserver.cpp:568
struct event_base * base
Definition: httprpc.cpp:56
void StopHTTPRPC()
Definition: httprpc.cpp:243
CService GetPeer()
Definition: httpserver.cpp:625
void RPCRegisterTimerInterface(RPCTimerInterface *iface)
Definition: server.cpp:592
bool GenerateAuthCookie(std::string *cookie_out)
Definition: protocol.cpp:79
static HTTPRPCTimerInterface * httpRPCTimerInterface
Definition: httprpc.cpp:63
RequestMethod GetRequestMethod()
Definition: httpserver.cpp:644
RPCTimerBase * NewTimer(boost::function< void(void)> &func, int64_t millis)
Definition: httprpc.cpp:51
const UniValue NullUniValue
Definition: univalue.cpp:78
int get_int() const
Definition: univalue.cpp:317
void WriteHeader(const std::string &hdr, const std::string &value)
Definition: httpserver.cpp:599
void parse(const UniValue &valRequest)
Definition: server.cpp:478
Standard JSON-RPC 2.0 errors.
Definition: protocol.h:34
string JSONRPCReply(const UniValue &result, const UniValue &error, const UniValue &id)
Definition: protocol.cpp:51
bool isObject() const
Definition: univalue.h:84
UniValue params
Definition: server.h:40
UniValue execute(const std::string &method, const UniValue &params) const
Definition: server.cpp:541
bool read(const char *raw)
map< string, vector< string > > mapMultiArgs
Definition: util.cpp:123
std::string strMethod
Definition: server.h:39
UniValue JSONRPCError(int code, const string &message)
Definition: protocol.cpp:57
const UniValue & get_array() const
Definition: univalue.cpp:354
std::string _(const char *psz)
Definition: util.h:84
map< string, string > mapArgs
Definition: util.cpp:122
result
Definition: rpcuser.py:37
static struct event_base * eventBase
libevent event loop
Definition: httpserver.cpp:183
void RPCUnregisterTimerInterface(RPCTimerInterface *iface)
Definition: server.cpp:597