1
0

AdminClient.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include "client/AdminClient.h"
  16. #include "benc/serialization/standard/BencMessageReader.h"
  17. #include "benc/serialization/standard/BencMessageWriter.h"
  18. #include "benc/serialization/cloner/Cloner.h"
  19. #include "exception/Except.h"
  20. #include "util/Bits.h"
  21. #include "util/Endian.h"
  22. #include "util/Hex.h"
  23. #include "util/events/Timeout.h"
  24. #include "util/Identity.h"
  25. #include "wire/Message.h"
  26. #include "wire/Error.h"
  27. #include <sodium/crypto_hash_sha256.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. struct Request;
  31. typedef void (* AdminClient_RespHandler)(struct Request* req);
  32. struct Request
  33. {
  34. struct AdminClient_Result res;
  35. struct AdminClient_Promise* promise;
  36. AdminClient_RespHandler callback;
  37. struct Context* ctx;
  38. struct Allocator* alloc;
  39. /** Need a special allocator for the timeout so it can be axed before the request is complete */
  40. struct Allocator* timeoutAlloc;
  41. struct Timeout* timeout;
  42. Dict* requestMessage;
  43. /** the handle in the ctx->outstandingRequests map */
  44. uint32_t handle;
  45. Identity
  46. };
  47. #define Map_NAME OfRequestByHandle
  48. #define Map_ENABLE_HANDLES
  49. #define Map_VALUE_TYPE struct Request*
  50. #include "util/Map.h"
  51. struct Context
  52. {
  53. struct AdminClient pub;
  54. struct EventBase* eventBase;
  55. struct Iface addrIface;
  56. struct Sockaddr* targetAddr;
  57. struct Log* logger;
  58. String* password;
  59. struct Map_OfRequestByHandle outstandingRequests;
  60. struct Allocator* alloc;
  61. Identity
  62. };
  63. static int calculateAuth(Dict* message,
  64. String* password,
  65. String* cookieStr,
  66. struct Allocator* alloc)
  67. {
  68. // Calculate the hash of the password.
  69. String* hashHex = String_newBinary(NULL, 64, alloc);
  70. uint8_t passAndCookie[64];
  71. uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0;
  72. snprintf((char*) passAndCookie, 64, "%s%u", password->bytes, cookie);
  73. uint8_t hash[32];
  74. crypto_hash_sha256(hash, passAndCookie, CString_strlen((char*) passAndCookie));
  75. Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32);
  76. Dict_putString(message, String_new("hash", alloc), hashHex, alloc);
  77. Dict_putString(message, String_new("cookie", alloc), cookieStr, alloc);
  78. // serialize the message with the password hash
  79. struct Message* msg = Message_new(0, AdminClient_MAX_MESSAGE_SIZE, alloc);
  80. Er_assert(BencMessageWriter_write(message, msg));
  81. // calculate the hash of the message with the password hash
  82. crypto_hash_sha256(hash, msg->msgbytes, Message_getLength(msg));
  83. // swap the hash of the message with the password hash into the location
  84. // where the password hash was.
  85. Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32);
  86. return 0;
  87. }
  88. static void done(struct Request* req, enum AdminClient_Error err)
  89. {
  90. req->res.err = err;
  91. Allocator_t* ra = req->timeoutAlloc;
  92. req->callback(req);
  93. if (ra == req->timeoutAlloc) { Allocator_free(req->timeoutAlloc); }
  94. }
  95. static void timeout(void* vreq)
  96. {
  97. done((struct Request*) vreq, AdminClient_Error_TIMEOUT);
  98. }
  99. static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* addrIface)
  100. {
  101. struct Context* ctx = Identity_containerOf(addrIface, struct Context, addrIface);
  102. struct Sockaddr_storage source;
  103. Er_assert(Message_epop(msg, &source, ctx->targetAddr->addrLen));
  104. if (Bits_memcmp(&source, ctx->targetAddr, ctx->targetAddr->addrLen)) {
  105. Log_info(ctx->logger, "Got spurious message from [%s], expecting messages from [%s]",
  106. Sockaddr_print(&source.addr, Message_getAlloc(msg)),
  107. Sockaddr_print(ctx->targetAddr, Message_getAlloc(msg)));
  108. // The UDP interface can't make use of an error but we'll inform anyway
  109. return Error(msg, "INVALID source addr");
  110. }
  111. // we don't yet know with which message this data belongs,
  112. // the message alloc lives the length of the message reception.
  113. struct Allocator* alloc = Allocator_child(Message_getAlloc(msg));
  114. int origLen = Message_getLength(msg);
  115. Dict* d = NULL;
  116. const char* err = BencMessageReader_readNoExcept(msg, alloc, &d);
  117. if (err) { return Error(msg, "Error decoding benc: %s", err); }
  118. Er_assert(Message_eshift(msg, origLen));
  119. String* txid = Dict_getStringC(d, "txid");
  120. if (!txid || txid->len != 8) { return Error(msg, "INVALID missing or wrong size txid"); }
  121. // look up the result
  122. uint32_t handle = ~0u;
  123. Hex_decode((uint8_t*)&handle, 4, txid->bytes, 8);
  124. int idx = Map_OfRequestByHandle_indexForHandle(handle, &ctx->outstandingRequests);
  125. if (idx < 0) { return Error(msg, "INVALID no such handle"); }
  126. struct Request* req = ctx->outstandingRequests.values[idx];
  127. // now this data will outlive the life of the message.
  128. Allocator_adopt(req->promise->alloc, alloc);
  129. req->res.responseDict = d;
  130. int len = (Message_getLength(msg) > AdminClient_MAX_MESSAGE_SIZE)
  131. ? AdminClient_MAX_MESSAGE_SIZE
  132. : Message_getLength(msg);
  133. Bits_memset(req->res.messageBytes, 0, AdminClient_MAX_MESSAGE_SIZE);
  134. Bits_memcpy(req->res.messageBytes, msg->msgbytes, len);
  135. done(req, AdminClient_Error_NONE);
  136. return NULL;
  137. }
  138. static int requestOnFree(struct Allocator_OnFreeJob* job)
  139. {
  140. struct Request* req = Identity_check((struct Request*) job->userData);
  141. int idx = Map_OfRequestByHandle_indexForHandle(req->handle, &req->ctx->outstandingRequests);
  142. if (idx > -1) {
  143. Map_OfRequestByHandle_remove(idx, &req->ctx->outstandingRequests);
  144. }
  145. return 0;
  146. }
  147. static struct Request* sendRaw(Dict* messageDict,
  148. struct AdminClient_Promise* promise,
  149. struct Context* ctx,
  150. String* cookie,
  151. AdminClient_RespHandler callback)
  152. {
  153. struct Allocator* reqAlloc = Allocator_child(promise->alloc);
  154. struct Request* req = Allocator_clone(reqAlloc, (&(struct Request) {
  155. .alloc = reqAlloc,
  156. .ctx = ctx,
  157. .promise = promise
  158. }));
  159. Identity_set(req);
  160. int idx = Map_OfRequestByHandle_put(&req, &ctx->outstandingRequests);
  161. req->handle = ctx->outstandingRequests.handles[idx];
  162. String* id = String_newBinary(NULL, 8, req->alloc);
  163. Hex_encode(id->bytes, 8, (int8_t*) &req->handle, 4);
  164. Dict_putStringC(messageDict, "txid", id, req->alloc);
  165. if (cookie) {
  166. Assert_true(!calculateAuth(messageDict, ctx->password, cookie, req->alloc));
  167. }
  168. struct Allocator* child = Allocator_child(req->alloc);
  169. struct Message* msg = Message_new(0, AdminClient_MAX_MESSAGE_SIZE + 256, child);
  170. Er_assert(BencMessageWriter_write(messageDict, msg));
  171. req->timeoutAlloc = Allocator_child(req->alloc);
  172. req->timeout = Timeout_setTimeout(timeout,
  173. req,
  174. ctx->pub.millisecondsToWait,
  175. ctx->eventBase,
  176. req->timeoutAlloc);
  177. Allocator_onFree(req->timeoutAlloc, requestOnFree, req);
  178. req->callback = callback;
  179. Er_assert(Message_epush(msg, ctx->targetAddr, ctx->targetAddr->addrLen));
  180. Iface_send(&ctx->addrIface, msg);
  181. Allocator_free(child);
  182. return req;
  183. }
  184. static void requestCallback(struct Request* req)
  185. {
  186. if (req->promise->callback) {
  187. req->promise->callback(req->promise, &req->res);
  188. }
  189. Allocator_free(req->promise->alloc);
  190. }
  191. static void cookieCallback(struct Request* req)
  192. {
  193. if (req->res.err) {
  194. requestCallback(req);
  195. return;
  196. }
  197. String* cookie = Dict_getStringC(req->res.responseDict, "cookie");
  198. if (!cookie) {
  199. req->res.err = AdminClient_Error_NO_COOKIE;
  200. requestCallback(req);
  201. return;
  202. }
  203. Dict* message = req->requestMessage;
  204. sendRaw(message, req->promise, req->ctx, cookie, requestCallback);
  205. Allocator_free(req->alloc);
  206. }
  207. static struct AdminClient_Promise* doCall(Dict* message,
  208. struct Context* ctx,
  209. struct Allocator* alloc)
  210. {
  211. struct Allocator* promiseAlloc = Allocator_child(alloc);
  212. struct AdminClient_Promise* promise =
  213. Allocator_calloc(promiseAlloc, sizeof(struct AdminClient_Promise), 1);
  214. promise->alloc = promiseAlloc;
  215. Dict gc = Dict_CONST(String_CONST("q"), String_OBJ(String_CONST("cookie")), NULL);
  216. struct Request* req = sendRaw(&gc, promise, ctx, NULL, cookieCallback);
  217. req->requestMessage = Cloner_cloneDict(message, promiseAlloc);
  218. return promise;
  219. }
  220. struct AdminClient_Promise* AdminClient_rpcCall(String* function,
  221. Dict* args,
  222. struct AdminClient* client,
  223. struct Allocator* alloc)
  224. {
  225. struct Context* ctx = Identity_check((struct Context*) client);
  226. Dict a = (args) ? *args : NULL;
  227. Dict message = Dict_CONST(
  228. String_CONST("q"), String_OBJ(String_CONST("auth")), Dict_CONST(
  229. String_CONST("aq"), String_OBJ(function), Dict_CONST(
  230. String_CONST("args"), Dict_OBJ(&a), NULL
  231. )));
  232. return doCall(&message, ctx, alloc);
  233. }
  234. char* AdminClient_errorString(enum AdminClient_Error err)
  235. {
  236. switch (err) {
  237. case AdminClient_Error_NONE:
  238. return "Success";
  239. case AdminClient_Error_OVERLONG_RESPONSE:
  240. return "Overlong resonse message";
  241. case AdminClient_Error_ERROR_READING_FROM_SOCKET:
  242. return "Error reading from socket, check errno.";
  243. case AdminClient_Error_SOCKET_NOT_READY:
  244. return "Socket not ready for reading";
  245. case AdminClient_Error_DESERIALIZATION_FAILED:
  246. return "Failed to deserialize response";
  247. case AdminClient_Error_SERIALIZATION_FAILED:
  248. return "Failed to serialize request";
  249. case AdminClient_Error_TIMEOUT:
  250. return "Timed out waiting for a response";
  251. case AdminClient_Error_NO_COOKIE:
  252. return "Cookie request returned with no cookie";
  253. default:
  254. return "Internal error";
  255. };
  256. }
  257. struct AdminClient* AdminClient_new(AddrIface_t* ai,
  258. struct Sockaddr* connectToAddress,
  259. String* adminPassword,
  260. struct EventBase* eventBase,
  261. struct Log* logger,
  262. struct Allocator* alloc)
  263. {
  264. struct Context* context = Allocator_clone(alloc, (&(struct Context) {
  265. .eventBase = eventBase,
  266. .logger = logger,
  267. .password = adminPassword,
  268. .pub = {
  269. .millisecondsToWait = 5000,
  270. },
  271. .outstandingRequests = {
  272. .allocator = alloc
  273. },
  274. .alloc = alloc
  275. }));
  276. context->addrIface.send = receiveMessage;
  277. Identity_set(context);
  278. context->targetAddr = Sockaddr_clone(connectToAddress, alloc);
  279. if (Sockaddr_getFamily(context->targetAddr) == Sockaddr_AF_INET) {
  280. uint8_t* addrBytes;
  281. int len = Sockaddr_getAddress(context->targetAddr, &addrBytes);
  282. if (Bits_isZero(addrBytes, len)) {
  283. // 127.0.0.1
  284. uint32_t loopback = Endian_hostToBigEndian32(0x7f000001);
  285. Bits_memcpy(addrBytes, &loopback, 4);
  286. }
  287. }
  288. Log_debug(logger, "Connecting to [%s]", Sockaddr_print(context->targetAddr, alloc));
  289. Iface_plumb(ai->iface, &context->addrIface);
  290. return &context->pub;
  291. }