Admin.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  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 "admin/Admin.h"
  16. #include "benc/String.h"
  17. #include "benc/Int.h"
  18. #include "benc/Dict.h"
  19. #include "benc/serialization/standard/BencMessageWriter.h"
  20. #include "benc/serialization/standard/BencMessageReader.h"
  21. #include "exception/Err.h"
  22. #include "memory/Allocator.h"
  23. #include "rust/cjdns_sys/RTypes.h"
  24. #include "rust/cjdns_sys/Rffi.h"
  25. #include "util/Assert.h"
  26. #include "util/Bits.h"
  27. #include "util/Hex.h"
  28. #include "util/log/Log.h"
  29. #include "util/events/Time.h"
  30. #include "util/events/Timeout.h"
  31. #include "util/Identity.h"
  32. #include "util/platform/Sockaddr.h"
  33. #include "util/Defined.h"
  34. #include <sodium/crypto_verify_32.h>
  35. #include <stdlib.h>
  36. #include <stdio.h>
  37. static String* TYPE = String_CONST_SO("type");
  38. static String* REQUIRED = String_CONST_SO("required");
  39. static String* STRING = String_CONST_SO("String");
  40. static String* INTEGER = String_CONST_SO("Int");
  41. static String* DICT = String_CONST_SO("Dict");
  42. static String* LIST = String_CONST_SO("List");
  43. static String* TXID = String_CONST_SO("txid");
  44. /** Number of milliseconds before a session times out and outgoing messages are failed. */
  45. #define TIMEOUT_MILLISECONDS 30000
  46. /** map values for tracking time of last message by source address */
  47. struct MapValue
  48. {
  49. /** time when the last incoming message was received. */
  50. uint64_t timeOfLastMessage;
  51. /** used to allocate the memory for the key (Sockaddr) and value (this). */
  52. struct Allocator* allocator;
  53. };
  54. //////// generate time-of-last-message-by-address map
  55. #define Map_USE_HASH
  56. #define Map_USE_COMPARATOR
  57. #define Map_NAME LastMessageTimeByAddr
  58. #define Map_KEY_TYPE struct Sockaddr*
  59. #define Map_VALUE_TYPE struct MapValue*
  60. #include "util/Map.h"
  61. static inline uint32_t Map_LastMessageTimeByAddr_hash(struct Sockaddr** key)
  62. {
  63. return Sockaddr_hash(*key);
  64. }
  65. static inline int Map_LastMessageTimeByAddr_compare(struct Sockaddr** keyA, struct Sockaddr** keyB)
  66. {
  67. return Sockaddr_compare(*keyA, *keyB);
  68. }
  69. /////// end map
  70. struct Function
  71. {
  72. String* name;
  73. Admin_Function call;
  74. void* context;
  75. bool needsAuth;
  76. Dict* args;
  77. };
  78. struct Admin_pvt
  79. {
  80. struct Admin pub;
  81. struct Iface iface;
  82. EventBase_t* eventBase;
  83. struct Function* functions;
  84. int functionCount;
  85. struct Allocator* allocator;
  86. String* password;
  87. struct Log* logger;
  88. struct Map_LastMessageTimeByAddr map;
  89. /** non-null if we are currently in an admin request. */
  90. Message_t* currentRequest;
  91. /** non-zero if this session able to receive asynchronous messages. */
  92. int asyncEnabled;
  93. Message_t* tempSendMsg;
  94. Identity
  95. };
  96. static Err_DEFUN sendMessage(
  97. Message_t* message, struct Sockaddr* dest, struct Admin_pvt* admin)
  98. {
  99. // stack overflow when used with admin logger.
  100. //Log_keys(admin->logger, "sending message to angel [%s]", message->bytes);
  101. Err(Message_epush(message, dest, dest->addrLen));
  102. return Iface_send(&admin->iface, message);
  103. }
  104. static Err_DEFUN sendBenc(Dict* message,
  105. struct Sockaddr* dest,
  106. struct Allocator* alloc,
  107. struct Admin_pvt* admin,
  108. int fd)
  109. {
  110. Message_reset(admin->tempSendMsg);
  111. Err(BencMessageWriter_write(message, admin->tempSendMsg));
  112. Message_t* msg = Message_new(0, Message_getLength(admin->tempSendMsg) + 32, alloc);
  113. Err(Message_epush(msg, Message_bytes(admin->tempSendMsg), Message_getLength(admin->tempSendMsg)));
  114. Message_setAssociatedFd(msg, fd);
  115. return sendMessage(msg, dest, admin);
  116. }
  117. /**
  118. * If no incoming data has been sent by this address in TIMEOUT_MILLISECONDS
  119. * then Admin_sendMessage() should fail so that it doesn't endlessly send
  120. * udp packets into outer space after a logging client disconnects.
  121. */
  122. static int checkAddress(struct Admin_pvt* admin, int index, uint64_t now)
  123. {
  124. uint64_t diff = now - admin->map.values[index]->timeOfLastMessage;
  125. // check for backwards time
  126. if (diff > TIMEOUT_MILLISECONDS && diff < ((uint64_t)INT64_MAX)) {
  127. Allocator_free(admin->map.values[index]->allocator);
  128. Map_LastMessageTimeByAddr_remove(index, &admin->map);
  129. return -1;
  130. }
  131. return 0;
  132. }
  133. static void clearExpiredAddresses(void* vAdmin)
  134. {
  135. struct Admin_pvt* admin = Identity_check((struct Admin_pvt*) vAdmin);
  136. uint64_t now = Time_currentTimeMilliseconds();
  137. int count = 0;
  138. for (int i = admin->map.count - 1; i >= 0; i--) {
  139. if (checkAddress(admin, i, now)) {
  140. count++;
  141. }
  142. }
  143. Log_debug(admin->logger, "Cleared [%d] expired sessions", count);
  144. }
  145. static int sendMessage0(Dict* message, String* txid, struct Admin* adminPub, int fd)
  146. {
  147. struct Admin_pvt* admin = Identity_check((struct Admin_pvt*) adminPub);
  148. if (!admin) {
  149. return 0;
  150. }
  151. Assert_true(txid && txid->len >= sizeof(struct Sockaddr));
  152. uint16_t addrLen = 0;
  153. Bits_memcpy(&addrLen, txid->bytes, 2);
  154. Assert_true(txid->len >= addrLen);
  155. struct Allocator* alloc = NULL;
  156. if (admin->currentRequest) {
  157. alloc = Message_getAlloc(admin->currentRequest);
  158. } else {
  159. alloc = Allocator_child(admin->allocator);
  160. }
  161. struct Sockaddr* addr = Sockaddr_clone((struct Sockaddr*) txid->bytes, alloc);
  162. // if this is an async call, check if we've got any input from that client.
  163. // if the client is nresponsive then fail the call so logs don't get sent
  164. // out forever after a disconnection.
  165. if (!admin->currentRequest) {
  166. int index = Map_LastMessageTimeByAddr_indexForKey(&addr, &admin->map);
  167. uint64_t now = Time_currentTimeMilliseconds();
  168. if (index < 0 || checkAddress(admin, index, now)) {
  169. Allocator_free(alloc);
  170. return Admin_sendMessage_CHANNEL_CLOSED;
  171. }
  172. }
  173. // Bounce back the user-supplied txid.
  174. if (txid->len > addr->addrLen) {
  175. String* userTxid =
  176. String_newBinary(&txid->bytes[addr->addrLen], txid->len - addr->addrLen, alloc);
  177. Dict_putString(message, TXID, userTxid, alloc);
  178. }
  179. RTypes_Error_t* err = sendBenc(message, addr, alloc, admin, fd);
  180. if (err) {
  181. Log_warn(admin->logger, "Error sending benc: %s", Rffi_printError(err, alloc));
  182. }
  183. Dict_remove(message, TXID);
  184. if (!admin->currentRequest) {
  185. Allocator_free(alloc);
  186. }
  187. return 0;
  188. }
  189. int Admin_sendMessage(Dict* message, String* txid, struct Admin* adminPub)
  190. {
  191. return sendMessage0(message, txid, adminPub, -1);
  192. }
  193. static inline bool authValid(Dict* message, Message_t* messageBytes, struct Admin_pvt* admin)
  194. {
  195. String* cookieStr = Dict_getStringC(message, "cookie");
  196. uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0;
  197. if (!cookie) {
  198. int64_t* cookieInt = Dict_getIntC(message, "cookie");
  199. cookie = (cookieInt) ? *cookieInt : 0;
  200. }
  201. uint64_t nowSecs = Time_currentTimeSeconds();
  202. String* submittedHash = Dict_getStringC(message, "hash");
  203. if (cookie > nowSecs || cookie < nowSecs - 20 || !submittedHash || submittedHash->len != 64) {
  204. return false;
  205. }
  206. uint8_t* hashPtr = CString_strstr(Message_bytes(messageBytes), submittedHash->bytes);
  207. if (!hashPtr || !admin->password) {
  208. return false;
  209. }
  210. uint8_t passAndCookie[64];
  211. snprintf((char*) passAndCookie, 64, "%s%u", admin->password->bytes, cookie);
  212. uint8_t hash[32];
  213. Rffi_crypto_hash_sha256(hash, passAndCookie, CString_strlen((char*) passAndCookie));
  214. Hex_encode(hashPtr, 64, hash, 32);
  215. Rffi_crypto_hash_sha256(hash, Message_bytes(messageBytes), Message_getLength(messageBytes));
  216. Hex_encode(hashPtr, 64, hash, 32);
  217. int res = crypto_verify_32(hashPtr, submittedHash->bytes);
  218. res |= crypto_verify_32(hashPtr + 32, submittedHash->bytes + 32);
  219. return res == 0;
  220. }
  221. static bool checkArgs(Dict* args,
  222. struct Function* func,
  223. String* txid,
  224. struct Allocator* requestAlloc,
  225. struct Admin_pvt* admin)
  226. {
  227. struct Dict_Entry* entry = *func->args;
  228. String* error = NULL;
  229. while (entry != NULL) {
  230. String* key = (String*) entry->key;
  231. Assert_ifParanoid(entry->val->type == Object_DICT);
  232. Dict* value = entry->val->as.dictionary;
  233. entry = entry->next;
  234. if (*Dict_getIntC(value, "required") == 0) {
  235. continue;
  236. }
  237. String* type = Dict_getStringC(value, "type");
  238. if ((type == STRING && !Dict_getString(args, key))
  239. || (type == DICT && !Dict_getDict(args, key))
  240. || (type == INTEGER && !Dict_getInt(args, key))
  241. || (type == LIST && !Dict_getList(args, key)))
  242. {
  243. error = String_printf(requestAlloc,
  244. "Entry [%s] is required and must be of type [%s]",
  245. key->bytes,
  246. type->bytes);
  247. break;
  248. }
  249. }
  250. if (error) {
  251. Dict d = Dict_CONST(String_CONST("error"), String_OBJ(error), NULL);
  252. Admin_sendMessage(&d, txid, &admin->pub);
  253. }
  254. return !error;
  255. }
  256. static void asyncEnabled(Dict* args, void* vAdmin, String* txid, struct Allocator* requestAlloc)
  257. {
  258. struct Admin_pvt* admin = Identity_check((struct Admin_pvt*) vAdmin);
  259. int64_t enabled = admin->asyncEnabled;
  260. Dict d = Dict_CONST(String_CONST("asyncEnabled"), Int_OBJ(enabled), NULL);
  261. Admin_sendMessage(&d, txid, &admin->pub);
  262. }
  263. #define ENTRIES_PER_PAGE 8
  264. static void availableFunctions(Dict* args, void* vAdmin, String* txid, struct Allocator* tempAlloc)
  265. {
  266. struct Admin_pvt* admin = Identity_check((struct Admin_pvt*) vAdmin);
  267. int64_t* page = Dict_getIntC(args, "page");
  268. uint32_t i = (page) ? *page * ENTRIES_PER_PAGE : 0;
  269. Dict* d = Dict_new(tempAlloc);
  270. Dict* functions = Dict_new(tempAlloc);
  271. int count = 0;
  272. for (; i < (uint32_t)admin->functionCount && count++ < ENTRIES_PER_PAGE; i++) {
  273. Dict_putDict(functions, admin->functions[i].name, admin->functions[i].args, tempAlloc);
  274. }
  275. if (count >= ENTRIES_PER_PAGE) {
  276. Dict_putIntC(d, "more", 1, tempAlloc);
  277. }
  278. Dict_putDictC(d, "availableFunctions", functions, tempAlloc);
  279. Admin_sendMessage(d, txid, &admin->pub);
  280. }
  281. static Err_DEFUN handleRequest(Dict* messageDict,
  282. Message_t* message,
  283. struct Sockaddr* src,
  284. struct Allocator* allocator,
  285. struct Admin_pvt* admin)
  286. {
  287. String* query = Dict_getStringC(messageDict, "q");
  288. if (!query) {
  289. Log_info(admin->logger, "Got a non-query from admin interface");
  290. return NULL;
  291. }
  292. // txid becomes the user supplied txid combined with the channel num.
  293. String* userTxid = Dict_getString(messageDict, TXID);
  294. uint32_t txidlen = ((userTxid) ? userTxid->len : 0) + src->addrLen;
  295. String* txid = String_newBinary(NULL, txidlen, allocator);
  296. Bits_memcpy(txid->bytes, src, src->addrLen);
  297. if (userTxid) {
  298. Bits_memcpy(txid->bytes + src->addrLen, userTxid->bytes, userTxid->len);
  299. }
  300. // If they're asking for a cookie then lets give them one.
  301. String* cookie = String_CONST("cookie");
  302. if (String_equals(query, cookie)) {
  303. //Log_debug(admin->logger, "Got a request for a cookie");
  304. Dict* d = Dict_new(allocator);
  305. char bytes[32];
  306. snprintf(bytes, 32, "%u", (uint32_t) Time_currentTimeSeconds());
  307. String* theCookie = &(String) { .len = CString_strlen(bytes), .bytes = bytes };
  308. Dict_putString(d, cookie, theCookie, allocator);
  309. Admin_sendMessage(d, txid, &admin->pub);
  310. return NULL;
  311. }
  312. // If this is a permitted query, make sure the cookie is right.
  313. String* auth = String_CONST("auth");
  314. bool authed = false;
  315. if (String_equals(query, auth)) {
  316. if (!authValid(messageDict, message, admin)) {
  317. Dict* d = Dict_new(allocator);
  318. Dict_putStringCC(d, "error", "Auth failed.", allocator);
  319. Admin_sendMessage(d, txid, &admin->pub);
  320. return NULL;
  321. }
  322. query = Dict_getStringC(messageDict, "aq");
  323. authed = true;
  324. }
  325. if (String_equals(admin->password, String_CONST("NONE"))) {
  326. // If there's no password then we'll consider everything to be authed
  327. authed = true;
  328. }
  329. // Then sent a valid authed query, lets track their address so they can receive
  330. // asynchronous messages.
  331. int index = Map_LastMessageTimeByAddr_indexForKey(&src, &admin->map);
  332. uint64_t now = Time_currentTimeMilliseconds();
  333. admin->asyncEnabled = 1;
  334. if (index >= 0) {
  335. admin->map.values[index]->timeOfLastMessage = now;
  336. } else if (authed) {
  337. struct Allocator* entryAlloc = Allocator_child(admin->allocator);
  338. struct MapValue* mv = Allocator_calloc(entryAlloc, sizeof(struct MapValue), 1);
  339. mv->timeOfLastMessage = now;
  340. mv->allocator = entryAlloc;
  341. struct Sockaddr* storedAddr = Sockaddr_clone(src, entryAlloc);
  342. Map_LastMessageTimeByAddr_put(&storedAddr, &mv, &admin->map);
  343. } else {
  344. admin->asyncEnabled = 0;
  345. }
  346. Dict* args = Dict_getDictC(messageDict, "args");
  347. bool noFunctionsCalled = true;
  348. for (int i = 0; i < admin->functionCount; i++) {
  349. if (String_equals(query, admin->functions[i].name)
  350. && (authed || !admin->functions[i].needsAuth))
  351. {
  352. if (checkArgs(args, &admin->functions[i], txid, Message_getAlloc(message), admin)) {
  353. admin->functions[i].call(args, admin->functions[i].context, txid, Message_getAlloc(message));
  354. }
  355. noFunctionsCalled = false;
  356. }
  357. }
  358. if (noFunctionsCalled) {
  359. Dict d = Dict_CONST(
  360. String_CONST("error"),
  361. String_OBJ(String_CONST("No functions matched your request, "
  362. "try Admin_availableFunctions()")),
  363. NULL
  364. );
  365. Admin_sendMessage(&d, txid, &admin->pub);
  366. }
  367. return NULL;
  368. }
  369. static Err_DEFUN handleMessage(Message_t* message,
  370. struct Sockaddr* src,
  371. struct Allocator* alloc,
  372. struct Admin_pvt* admin)
  373. {
  374. if (Defined(Log_KEYS)) {
  375. uint8_t lastChar = Message_bytes(message)[Message_getLength(message) - 1];
  376. Message_bytes(message)[Message_getLength(message) - 1] = '\0';
  377. Log_keys(admin->logger, "Got message from [%s] [%s]",
  378. Sockaddr_print(src, alloc), Message_bytes(message));
  379. Message_bytes(message)[Message_getLength(message) - 1] = lastChar;
  380. }
  381. // handle non empty message data
  382. if (Message_getLength(message) > Admin_MAX_REQUEST_SIZE) {
  383. #define TOO_BIG "d5:error16:Request too big.e"
  384. #define TOO_BIG_STRLEN (sizeof(TOO_BIG) - 1)
  385. Bits_memcpy(Message_bytes(message), TOO_BIG, TOO_BIG_STRLEN);
  386. Err(Message_truncate(message, TOO_BIG_STRLEN));
  387. return sendMessage(message, src, admin);
  388. }
  389. int origMessageLen = Message_getLength(message);
  390. Dict* messageDict = NULL;
  391. const char* err = BencMessageReader_readNoExcept(message, alloc, &messageDict);
  392. if (err) {
  393. Log_warn(admin->logger,
  394. "Unparsable data from [%s] content: [%s] error: [%s]",
  395. Sockaddr_print(src, alloc),
  396. Hex_print(Message_bytes(message), Message_getLength(message), alloc),
  397. err);
  398. return NULL;
  399. }
  400. if (Message_getLength(message)) {
  401. Log_warn(admin->logger,
  402. "Message from [%s] contained garbage after byte [%d] content: [%s]",
  403. Sockaddr_print(src, alloc), Message_getLength(message), Message_bytes(message));
  404. return NULL;
  405. }
  406. // put the data back in the front of the message because it is used by the auth checker.
  407. Err(Message_eshift(message, origMessageLen));
  408. return handleRequest(messageDict, message, src, alloc, admin);
  409. }
  410. static Iface_DEFUN receiveMessage(Message_t* message, struct Iface* iface)
  411. {
  412. struct Admin_pvt* admin = Identity_containerOf(iface, struct Admin_pvt, iface);
  413. struct Allocator* alloc = Allocator_child(admin->allocator);
  414. struct Sockaddr_storage addrStore;
  415. Err(AddrIface_popAddr(&addrStore, message));
  416. admin->currentRequest = message;
  417. RTypes_Error_t* err = handleMessage(message, Sockaddr_clone(&addrStore.addr, alloc), alloc, admin);
  418. admin->currentRequest = NULL;
  419. Allocator_free(alloc);
  420. return err;
  421. }
  422. void Admin_registerFunctionWithArgCount(char* name,
  423. Admin_Function callback,
  424. void* callbackContext,
  425. bool needsAuth,
  426. struct Admin_FunctionArg* arguments,
  427. int argCount,
  428. struct Admin* adminPub)
  429. {
  430. struct Admin_pvt* admin = Identity_check((struct Admin_pvt*) adminPub);
  431. String* str = String_new(name, admin->allocator);
  432. admin->functions =
  433. Allocator_realloc(admin->allocator,
  434. admin->functions,
  435. sizeof(struct Function) * (admin->functionCount + 1));
  436. struct Function* fu = &admin->functions[admin->functionCount];
  437. admin->functionCount++;
  438. fu->name = str;
  439. fu->call = callback;
  440. fu->context = callbackContext;
  441. fu->needsAuth = needsAuth;
  442. fu->args = Dict_new(admin->allocator);
  443. for (int i = 0; arguments && i < argCount; i++) {
  444. // "type" must be one of: [ "String", "Int", "Dict", "List" ]
  445. String* type = NULL;
  446. if (!CString_strcmp(arguments[i].type, STRING->bytes)) {
  447. type = STRING;
  448. } else if (!CString_strcmp(arguments[i].type, INTEGER->bytes)) {
  449. type = INTEGER;
  450. } else if (!CString_strcmp(arguments[i].type, DICT->bytes)) {
  451. type = DICT;
  452. } else if (!CString_strcmp(arguments[i].type, LIST->bytes)) {
  453. type = LIST;
  454. } else {
  455. abort();
  456. }
  457. Dict* arg = Dict_new(admin->allocator);
  458. Dict_putString(arg, TYPE, type, admin->allocator);
  459. Dict_putInt(arg, REQUIRED, arguments[i].required, admin->allocator);
  460. String* name = String_new(arguments[i].name, admin->allocator);
  461. Dict_putDict(fu->args, name, arg, admin->allocator);
  462. }
  463. }
  464. static void importFd(Dict* args, void* vAdmin, String* txid, struct Allocator* requestAlloc)
  465. {
  466. struct Admin_pvt* admin = Identity_check((struct Admin_pvt*) vAdmin);
  467. int fd = Message_getAssociatedFd(admin->currentRequest);
  468. Dict* res = Dict_new(requestAlloc);
  469. char* error = "none";
  470. if (fd < 0) {
  471. if (Defined(win32)) {
  472. error = "Admin_importFd() does not support win32";
  473. } else {
  474. error = "file descriptor was not attached to message";
  475. }
  476. } else {
  477. Dict_putIntC(res, "fd", fd, requestAlloc);
  478. }
  479. Dict_putStringCC(res, "error", error, requestAlloc);
  480. Admin_sendMessage(res, txid, &admin->pub);
  481. }
  482. static void exportFd(Dict* args, void* vAdmin, String* txid, struct Allocator* requestAlloc)
  483. {
  484. struct Admin_pvt* admin = Identity_check((struct Admin_pvt*) vAdmin);
  485. int64_t* fd_p = Dict_getIntC(args, "fd");
  486. if (!fd_p || *fd_p < 0) {
  487. Dict* res = Dict_new(requestAlloc);
  488. Dict_putStringCC(res, "error", "invalid fd", requestAlloc);
  489. Admin_sendMessage(res, txid, &admin->pub);
  490. return;
  491. }
  492. int fd = *fd_p;
  493. Dict* res = Dict_new(requestAlloc);
  494. char* error = "none";
  495. if (fd < 0) {
  496. if (Defined(win32)) {
  497. error = "Admin_exportFd() does not support win32";
  498. } else {
  499. error = "file descriptor was not attached to message";
  500. }
  501. }
  502. Dict_putStringCC(res, "error", error, requestAlloc);
  503. sendMessage0(res, txid, &admin->pub, fd);
  504. }
  505. struct Admin* Admin_new(AddrIface_t* ai,
  506. struct Log* logger,
  507. EventBase_t* eventBase,
  508. String* password)
  509. {
  510. struct Allocator* alloc = ai->alloc;
  511. struct Admin_pvt* admin = Allocator_calloc(alloc, sizeof(struct Admin_pvt), 1);
  512. Identity_set(admin);
  513. admin->allocator = alloc;
  514. admin->logger = logger;
  515. admin->eventBase = eventBase;
  516. admin->map.allocator = alloc;
  517. admin->iface.send = receiveMessage;
  518. Iface_plumb(&admin->iface, ai->iface);
  519. admin->tempSendMsg = Message_new(0, Admin_MAX_RESPONSE_SIZE, alloc);
  520. admin->password = String_clone(password, alloc);
  521. Timeout_setInterval(clearExpiredAddresses, admin, TIMEOUT_MILLISECONDS * 3, eventBase, alloc);
  522. Admin_registerFunction("Admin_asyncEnabled", asyncEnabled, admin, false, NULL, &admin->pub);
  523. Admin_registerFunction("Admin_availableFunctions", availableFunctions, admin, false,
  524. ((struct Admin_FunctionArg[]) {
  525. { .name = "page", .required = 0, .type = "Int" }
  526. }), &admin->pub);
  527. Admin_registerFunction("Admin_importFd", importFd, admin, true, NULL, &admin->pub);
  528. Admin_registerFunction("Admin_exportFd", exportFd, admin, true,
  529. ((struct Admin_FunctionArg[]) {
  530. { .name = "fd", .required = 1, .type = "Int" }
  531. }), &admin->pub);
  532. return &admin->pub;
  533. }