Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

httprpc.cpp
Go to the documentation of this file.
1 // Copyright (c) 2015 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <httprpc.h>
6 
7 #include <base58.h>
8 #include <chainparams.h>
9 #include <httpserver.h>
10 #include <rpc/protocol.h>
11 #include <rpc/server.h>
12 #include <random.h>
13 #include <sync.h>
14 #include <util.h>
15 #include <utilstrencodings.h>
16 #include <ui_interface.h>
17 #include <crypto/hmac_sha256.h>
18 #include <stdio.h>
19 
20 #include <memory>
21 
22 #include <boost/algorithm/string.hpp> // boost::trim
23 
25 static const char* WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\"";
26 
30 class HTTPRPCTimer : public RPCTimerBase
31 {
32 public:
33  HTTPRPCTimer(struct event_base* eventBase, std::function<void(void)>& func, int64_t millis) :
34  ev(eventBase, false, func)
35  {
36  struct timeval tv;
37  tv.tv_sec = millis/1000;
38  tv.tv_usec = (millis%1000)*1000;
39  ev.trigger(&tv);
40  }
41 private:
43 };
44 
46 {
47 public:
48  explicit HTTPRPCTimerInterface(struct event_base* _base) : base(_base)
49  {
50  }
51  const char* Name() override
52  {
53  return "HTTP";
54  }
55  RPCTimerBase* NewTimer(std::function<void(void)>& func, int64_t millis) override
56  {
57  return new HTTPRPCTimer(base, func, millis);
58  }
59 private:
60  struct event_base* base;
61 };
62 
63 
64 /* Pre-base64-encoded authentication token */
65 static std::string strRPCUserColonPass;
66 /* Stored RPC timer interface (for unregistration) */
67 static std::unique_ptr<HTTPRPCTimerInterface> httpRPCTimerInterface;
68 
69 static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id)
70 {
71  // Send error reply from json-rpc error object
72  int nStatus = HTTP_INTERNAL_SERVER_ERROR;
73  int code = find_value(objError, "code").get_int();
74 
75  if (code == RPC_INVALID_REQUEST)
76  nStatus = HTTP_BAD_REQUEST;
77  else if (code == RPC_METHOD_NOT_FOUND)
78  nStatus = HTTP_NOT_FOUND;
79 
80  std::string strReply = JSONRPCReply(NullUniValue, objError, id);
81 
82  req->WriteHeader("Content-Type", "application/json");
83  req->WriteReply(nStatus, strReply);
84 }
85 
86 //This function checks username and password against -rpcauth
87 //entries from config file.
88 static bool multiUserAuthorized(std::string strUserPass)
89 {
90  if (strUserPass.find(':') == std::string::npos) {
91  return false;
92  }
93  std::string strUser = strUserPass.substr(0, strUserPass.find(':'));
94  std::string strPass = strUserPass.substr(strUserPass.find(':') + 1);
95 
96  for (const std::string& strRPCAuth : gArgs.GetArgs("-rpcauth")) {
97  //Search for multi-user login/pass "rpcauth" from config
98  std::vector<std::string> vFields;
99  boost::split(vFields, strRPCAuth, boost::is_any_of(":$"));
100  if (vFields.size() != 3) {
101  //Incorrect formatting in config file
102  continue;
103  }
104 
105  std::string strName = vFields[0];
106  if (!TimingResistantEqual(strName, strUser)) {
107  continue;
108  }
109 
110  std::string strSalt = vFields[1];
111  std::string strHash = vFields[2];
112 
113  static const unsigned int KEY_SIZE = 32;
114  unsigned char out[KEY_SIZE];
115 
116  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);
117  std::vector<unsigned char> hexvec(out, out+KEY_SIZE);
118  std::string strHashFromPass = HexStr(hexvec);
119 
120  if (TimingResistantEqual(strHashFromPass, strHash)) {
121  return true;
122  }
123  }
124  return false;
125 }
126 
127 static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUsernameOut)
128 {
129  if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called
130  return false;
131  if (strAuth.substr(0, 6) != "Basic ")
132  return false;
133  std::string strUserPass64 = strAuth.substr(6);
134  boost::trim(strUserPass64);
135  std::string strUserPass = DecodeBase64(strUserPass64);
136 
137  if (strUserPass.find(':') != std::string::npos)
138  strAuthUsernameOut = strUserPass.substr(0, strUserPass.find(':'));
139 
140  //Check if authorized under single-user field
141  if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
142  return true;
143  }
144  return multiUserAuthorized(strUserPass);
145 }
146 
147 static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
148 {
149  // JSONRPC handles only POST
150  if (req->GetRequestMethod() != HTTPRequest::POST) {
151  req->WriteReply(HTTP_BAD_METHOD, "JSONRPC server handles only POST requests");
152  return false;
153  }
154  // Check authorization
155  std::pair<bool, std::string> authHeader = req->GetHeader("authorization");
156  if (!authHeader.first) {
157  req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
159  return false;
160  }
161 
162  JSONRPCRequest jreq;
163  if (!RPCAuthorized(authHeader.second, jreq.authUser)) {
164  LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", req->GetPeer().ToString());
165 
166  /* Deter brute-forcing
167  If this results in a DoS the user really
168  shouldn't have their RPC port exposed. */
169  MilliSleep(250);
170 
171  req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
173  return false;
174  }
175 
176  try {
177  // Parse request
178  UniValue valRequest;
179  if (!valRequest.read(req->ReadBody()))
180  throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
181 
182  // Set the URI
183  jreq.URI = req->GetURI();
184 
185  std::string strReply;
186  // singleton request
187  if (valRequest.isObject()) {
188  jreq.parse(valRequest);
189 
190  UniValue result = tableRPC.execute(jreq);
191 
192  // Send reply
193  strReply = JSONRPCReply(result, NullUniValue, jreq.id);
194 
195  // array of requests
196  } else if (valRequest.isArray())
197  strReply = JSONRPCExecBatch(jreq, valRequest.get_array());
198  else
199  throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
200 
201  req->WriteHeader("Content-Type", "application/json");
202  req->WriteReply(HTTP_OK, strReply);
203  } catch (const UniValue& objError) {
204  JSONErrorReply(req, objError, jreq.id);
205  return false;
206  } catch (const std::exception& e) {
207  JSONErrorReply(req, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
208  return false;
209  }
210  return true;
211 }
212 
214 {
215  if (gArgs.GetArg("-rpcpassword", "") == "")
216  {
217  LogPrintf("No rpcpassword set - using random cookie authentication\n");
220  _("Error: A fatal internal error occurred, see debug.log for details"), // Same message as AbortNode
222  return false;
223  }
224  } else {
225  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");
226  strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", "");
227  }
228  return true;
229 }
230 
232 {
233  LogPrint(BCLog::RPC, "Starting HTTP RPC server\n");
234  if (!InitRPCAuthentication())
235  return false;
236 
238 #ifdef ENABLE_WALLET
239  // ifdef can be removed once we switch to better endpoint support and API versioning
240  RegisterHTTPHandler("/wallet/", false, HTTPReq_JSONRPC);
241 #endif
242  assert(EventBase());
243  httpRPCTimerInterface = MakeUnique<HTTPRPCTimerInterface>(EventBase());
245  return true;
246 }
247 
249 {
250  LogPrint(BCLog::RPC, "Interrupting HTTP RPC server\n");
251 }
252 
254 {
255  LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n");
256  UnregisterHTTPHandler("/", true);
257  if (httpRPCTimerInterface) {
259  httpRPCTimerInterface.reset();
260  }
261 }
bool isObject() const
Definition: univalue.h:85
RPC timer "driver".
Definition: server.h:98
HTTPRPCTimer(struct event_base *eventBase, std::function< void(void)> &func, int64_t millis)
Definition: httprpc.cpp:33
std::string ToString(bool fUseGetnameinfo=true) const
Definition: netaddress.cpp:581
std::vector< unsigned char > DecodeBase64(const char *p, bool *pfInvalid)
HTTPRPCTimerInterface(struct event_base *_base)
Definition: httprpc.cpp:48
void MilliSleep(int64_t n)
Definition: utiltime.cpp:75
const char * Name() override
Implementation name.
Definition: httprpc.cpp:51
static const char * WWW_AUTH_HEADER_DATA
WWW-Authenticate to present with 401 Unauthorized response.
Definition: httprpc.cpp:25
bool read(const char *raw, size_t len)
static std::string strRPCUserColonPass
Definition: httprpc.cpp:65
HTTPEvent ev
Definition: httprpc.cpp:42
std::pair< bool, std::string > GetHeader(const std::string &hdr)
Get the request header specified by hdr, or an empty string.
Definition: httpserver.cpp:532
Event class.
Definition: httpserver.h:130
static bool InitRPCAuthentication()
Definition: httprpc.cpp:213
bool StartHTTPRPC()
Start HTTP RPC subsystem.
Definition: httprpc.cpp:231
std::string GetURI()
Get requested URI.
Definition: httpserver.cpp:619
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
struct event_base * base
Definition: httprpc.cpp:60
static void JSONErrorReply(HTTPRequest *req, const UniValue &objError, const UniValue &id)
Definition: httprpc.cpp:69
A hasher class for HMAC-SHA-256.
Definition: hmac_sha256.h:14
const UniValue & get_array() const
void InterruptHTTPRPC()
Interrupt HTTP RPC subsystem.
Definition: httprpc.cpp:248
std::string JSONRPCReply(const UniValue &result, const UniValue &error, const UniValue &id)
Definition: protocol.cpp:48
RequestMethod GetRequestMethod()
Get request method.
Definition: httpserver.cpp:624
static bool HTTPReq_JSONRPC(HTTPRequest *req, const std::string &)
Definition: httprpc.cpp:147
void RPCUnsetTimerInterface(RPCTimerInterface *iface)
Unset factory function for timers.
Definition: server.cpp:601
const UniValue & find_value(const UniValue &obj, const std::string &name)
Definition: univalue.cpp:236
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Register handler for prefix.
Definition: httpserver.cpp:645
UniValue execute(const JSONRPCRequest &request) const
Execute a method.
Definition: server.cpp:536
bool TimingResistantEqual(const T &a, const T &b)
Timing-attack-resistant comparison.
false
Definition: bls_dkg.cpp:168
static std::unique_ptr< HTTPRPCTimerInterface > httpRPCTimerInterface
Definition: httprpc.cpp:67
static bool RPCAuthorized(const std::string &strAuth, std::string &strAuthUsernameOut)
Definition: httprpc.cpp:127
CRPCTable tableRPC
Definition: server.cpp:616
static bool multiUserAuthorized(std::string strUserPass)
Definition: httprpc.cpp:88
#define LogPrintf(...)
Definition: util.h:203
void WriteReply(int nStatus, const std::string &strReply="")
Write HTTP reply.
Definition: httpserver.cpp:575
Simple one-shot callback timer to be used by the RPC mechanism to e.g.
Definition: httprpc.cpp:30
std::string JSONRPCExecBatch(const JSONRPCRequest &jreq, const UniValue &vReq)
Definition: server.cpp:477
UniValue id
Definition: server.h:40
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
Unregister handler for prefix.
Definition: httpserver.cpp:651
int get_int() const
CService GetPeer()
Get CService (address:ip) for the origin of the http request.
Definition: httpserver.cpp:605
struct event_base * EventBase()
Return evhttp event base.
Definition: httpserver.cpp:487
void StopHTTPRPC()
Stop HTTP RPC subsystem.
Definition: httprpc.cpp:253
#define LogPrint(category,...)
Definition: util.h:214
void parse(const UniValue &valRequest)
Definition: server.cpp:416
ArgsManager gArgs
Definition: util.cpp:108
bool GenerateAuthCookie(std::string *cookie_out)
Generate a new RPC authentication cookie and write it to disk.
Definition: protocol.cpp:79
void WriteHeader(const std::string &hdr, const std::string &value)
Write output header.
Definition: httpserver.cpp:563
void trigger(struct timeval *tv)
Trigger the event.
Definition: httpserver.cpp:511
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: util.cpp:808
std::string URI
Definition: server.h:44
std::string authUser
Definition: server.h:45
void RPCSetTimerInterface(RPCTimerInterface *iface)
Set the factory function for timers.
Definition: server.cpp:596
Opaque base class for timers returned by NewTimerFunc.
Definition: server.h:89
const UniValue NullUniValue
Definition: univalue.cpp:15
boost::signals2::signal< bool(const std::string &message, const std::string &caption, unsigned int style), boost::signals2::last_value< bool > > ThreadSafeMessageBox
Show message box.
Definition: ui_interface.h:76
std::string ReadBody()
Read request body.
Definition: httpserver.cpp:543
Standard JSON-RPC 2.0 errors.
Definition: protocol.h:37
UniValue JSONRPCError(int code, const std::string &message)
Definition: protocol.cpp:54
In-flight HTTP request.
Definition: httpserver.h:57
CClientUIInterface uiInterface
Definition: ui_interface.cpp:8
std::vector< std::string > GetArgs(const std::string &strArg) const
Return a vector of strings of the given argument.
Definition: util.cpp:765
bool isArray() const
Definition: univalue.h:84
RPCTimerBase * NewTimer(std::function< void(void)> &func, int64_t millis) override
Factory function for timers.
Definition: httprpc.cpp:55
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a boost::optional result...
Definition: util.h:92
static struct event_base * eventBase
HTTP module state.
Definition: httpserver.cpp:144
Released under the MIT license