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