AdminClient.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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 <http://www.gnu.org/licenses/>.
  14. */
  15. #include "admin/AdminClient.h"
  16. #include "benc/serialization/BencSerializer.h"
  17. #include "benc/serialization/standard/StandardBencSerializer.h"
  18. #include "interface/addressable/AddrInterface.h"
  19. #include "interface/addressable/UDPAddrInterface.h"
  20. #include "exception/Except.h"
  21. #include "io/ArrayReader.h"
  22. #include "io/ArrayWriter.h"
  23. #include "io/Reader.h"
  24. #include "io/Writer.h"
  25. #include "util/Bits.h"
  26. #include "util/platform/libc/strlen.h"
  27. #include "util/Endian.h"
  28. #include "util/Hex.h"
  29. #include "util/events/Timeout.h"
  30. #include "util/Identity.h"
  31. #include "wire/Message.h"
  32. #include <crypto_hash_sha256.h>
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. struct Result
  36. {
  37. struct AdminClient_Result pub;
  38. struct Context* ctx;
  39. struct Allocator* alloc;
  40. };
  41. struct Context
  42. {
  43. struct AdminClient pub;
  44. struct EventBase* eventBase;
  45. struct Sockaddr* targetAddr;
  46. struct Result* result;
  47. struct AddrInterface* addrIface;
  48. struct Log* logger;
  49. String* password;
  50. Identity
  51. };
  52. static int calculateAuth(Dict* message,
  53. String* password,
  54. String* cookieStr,
  55. struct Allocator* alloc)
  56. {
  57. // Calculate the hash of the password.
  58. String* hashHex = String_newBinary(NULL, 64, alloc);
  59. uint8_t passAndCookie[64];
  60. uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0;
  61. snprintf((char*) passAndCookie, 64, "%s%u", password->bytes, cookie);
  62. uint8_t hash[32];
  63. crypto_hash_sha256(hash, passAndCookie, strlen((char*) passAndCookie));
  64. Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32);
  65. Dict_putString(message, String_new("hash", alloc), hashHex, alloc);
  66. Dict_putString(message, String_new("cookie", alloc), cookieStr, alloc);
  67. // serialize the message with the password hash
  68. uint8_t buffer[AdminClient_MAX_MESSAGE_SIZE];
  69. struct Writer* writer = ArrayWriter_new(buffer, AdminClient_MAX_MESSAGE_SIZE, alloc);
  70. if (StandardBencSerializer_get()->serializeDictionary(writer, message)) {
  71. return -1;
  72. }
  73. int length = writer->bytesWritten;
  74. // calculate the hash of the message with the password hash
  75. crypto_hash_sha256(hash, buffer, length);
  76. // swap the hash of the message with the password hash into the location
  77. // where the password hash was.
  78. Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32);
  79. return 0;
  80. }
  81. static void done(struct Context* ctx, enum AdminClient_Error err)
  82. {
  83. ctx->result->pub.err = err;
  84. EventBase_endLoop(ctx->eventBase);
  85. }
  86. static void timeout(void* vcontext)
  87. {
  88. done((struct Context*) vcontext, AdminClient_Error_TIMEOUT);
  89. }
  90. static void doCall(Dict* message, struct Result* res, bool getCookie)
  91. {
  92. String* cookie = NULL;
  93. if (!getCookie) {
  94. Dict gc = Dict_CONST(String_CONST("q"), String_OBJ(String_CONST("cookie")), NULL);
  95. doCall(&gc, res, true);
  96. if (res->pub.err != AdminClient_Error_NONE) {
  97. return;
  98. }
  99. cookie = Dict_getString(res->pub.responseDict, String_CONST("cookie"));
  100. if (!cookie) {
  101. res->pub.err = AdminClient_Error_NO_COOKIE;
  102. }
  103. }
  104. struct Writer* writer =
  105. ArrayWriter_new(res->pub.messageBytes, AdminClient_MAX_MESSAGE_SIZE, res->alloc);
  106. if (StandardBencSerializer_get()->serializeDictionary(writer, message)) {
  107. res->pub.err = AdminClient_Error_SERIALIZATION_FAILED;
  108. return;
  109. }
  110. if (!getCookie) {
  111. calculateAuth(message, res->ctx->password, cookie, res->alloc);
  112. writer = ArrayWriter_new(res->pub.messageBytes,
  113. AdminClient_MAX_MESSAGE_SIZE,
  114. res->alloc);
  115. if (StandardBencSerializer_get()->serializeDictionary(writer, message)) {
  116. res->pub.err = AdminClient_Error_SERIALIZATION_FAILED;
  117. return;
  118. }
  119. }
  120. struct Timeout* to = Timeout_setTimeout(timeout,
  121. res->ctx,
  122. res->ctx->pub.millisecondsToWait,
  123. res->ctx->eventBase,
  124. res->alloc);
  125. struct Message m = {
  126. .bytes = res->pub.messageBytes,
  127. .padding = AdminClient_Result_PADDING_SIZE,
  128. .length = writer->bytesWritten
  129. };
  130. Message_push(&m, res->ctx->targetAddr, res->ctx->targetAddr->addrLen);
  131. struct Allocator* child = Allocator_child(res->alloc);
  132. struct Message* msg = Message_clone(&m, child);
  133. Interface_sendMessage(&res->ctx->addrIface->generic, msg);
  134. Allocator_free(child);
  135. EventBase_beginLoop(res->ctx->eventBase);
  136. Timeout_clearTimeout(to);
  137. }
  138. static uint8_t receiveMessage(struct Message* msg, struct Interface* iface)
  139. {
  140. struct Context* ctx = Identity_cast((struct Context*) iface->receiverContext);
  141. // Since this is a blocking api, one result per context.
  142. struct Result* res = ctx->result;
  143. struct Sockaddr_storage source;
  144. Message_pop(msg, &source, ctx->targetAddr->addrLen);
  145. if (Bits_memcmp(&source, ctx->targetAddr, ctx->targetAddr->addrLen)) {
  146. Log_info(ctx->logger, "Got spurious message from [%s], expecting messages from [%s]",
  147. Sockaddr_print(&source.addr, res->alloc),
  148. Sockaddr_print(ctx->targetAddr, res->alloc));
  149. return 0;
  150. }
  151. struct Reader* reader = ArrayReader_new(msg->bytes, msg->length, res->alloc);
  152. Dict* d = Dict_new(res->alloc);
  153. if (StandardBencSerializer_get()->parseDictionary(reader, res->alloc, d)) {
  154. done(ctx, AdminClient_Error_DESERIALIZATION_FAILED);
  155. return 0;
  156. }
  157. res->pub.responseDict = d;
  158. int len =
  159. (msg->length > AdminClient_MAX_MESSAGE_SIZE) ? AdminClient_MAX_MESSAGE_SIZE : msg->length;
  160. Bits_memset(res->pub.messageBytes, 0, AdminClient_MAX_MESSAGE_SIZE);
  161. Bits_memcpy(res->pub.messageBytes, msg->bytes, len);
  162. done(ctx, AdminClient_Error_NONE);
  163. return 0;
  164. }
  165. struct AdminClient_Result* AdminClient_rpcCall(String* function,
  166. Dict* args,
  167. struct AdminClient* client,
  168. struct Allocator* alloc)
  169. {
  170. struct Context* ctx = Identity_cast((struct Context*) client);
  171. Dict a = (args) ? *args : NULL;
  172. Dict message = Dict_CONST(
  173. String_CONST("q"), String_OBJ(String_CONST("auth")), Dict_CONST(
  174. String_CONST("aq"), String_OBJ(function), Dict_CONST(
  175. String_CONST("args"), Dict_OBJ(&a), NULL
  176. )));
  177. struct Result* res = Allocator_clone(alloc, (&(struct Result) {
  178. .pub = {
  179. .err = AdminClient_Error_NONE
  180. },
  181. .ctx = ctx,
  182. .alloc = alloc
  183. }));
  184. ctx->result = res;
  185. doCall(&message, res, false);
  186. return &res->pub;
  187. }
  188. char* AdminClient_errorString(enum AdminClient_Error err)
  189. {
  190. switch (err) {
  191. case AdminClient_Error_NONE:
  192. return "Success";
  193. case AdminClient_Error_OVERLONG_RESPONSE:
  194. return "Overlong resonse message";
  195. case AdminClient_Error_ERROR_READING_FROM_SOCKET:
  196. return "Error reading from socket, check errno.";
  197. case AdminClient_Error_SOCKET_NOT_READY:
  198. return "Socket not ready for reading";
  199. case AdminClient_Error_DESERIALIZATION_FAILED:
  200. return "Failed to deserialize response";
  201. case AdminClient_Error_SERIALIZATION_FAILED:
  202. return "Failed to serialize request";
  203. case AdminClient_Error_TIMEOUT:
  204. return "Timed out waiting for a response";
  205. case AdminClient_Error_NO_COOKIE:
  206. return "Cookie request returned with no cookie";
  207. default:
  208. return "Internal error";
  209. };
  210. }
  211. struct AdminClient* AdminClient_new(struct Sockaddr* connectToAddress,
  212. String* adminPassword,
  213. struct EventBase* eventBase,
  214. struct Log* logger,
  215. struct Allocator* alloc)
  216. {
  217. struct Context* context = Allocator_clone(alloc, (&(struct Context) {
  218. .eventBase = eventBase,
  219. .logger = logger,
  220. .password = adminPassword,
  221. .pub = {
  222. .millisecondsToWait = 5000,
  223. }
  224. }));
  225. Identity_set(context);
  226. context->targetAddr = Sockaddr_clone(connectToAddress, alloc);
  227. if (Sockaddr_getFamily(context->targetAddr) == Sockaddr_AF_INET) {
  228. uint8_t* addrBytes;
  229. int len = Sockaddr_getAddress(context->targetAddr, &addrBytes);
  230. if (Bits_isZero(addrBytes, len)) {
  231. // 127.0.0.1
  232. uint32_t loopback = Endian_hostToBigEndian32(0x7f000001);
  233. Bits_memcpyConst(addrBytes, &loopback, 4);
  234. }
  235. }
  236. Log_debug(logger, "Connecting to [%s]", Sockaddr_print(context->targetAddr, alloc));
  237. context->addrIface = UDPAddrInterface_new(eventBase, NULL, alloc, NULL, logger);
  238. context->addrIface->generic.receiveMessage = receiveMessage;
  239. context->addrIface->generic.receiverContext = context;
  240. return &context->pub;
  241. }