static int calculateAuth(Dict* message, String* password, String* cookieStr, struct Allocator* alloc) { // Calculate the hash of the password. String* hashHex = String_newBinary(NULL, 64, alloc); uint8_t passAndCookie[64]; uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0; snprintf((char*) passAndCookie, 64, "%s%u", password->bytes, cookie); uint8_t hash[32]; crypto_hash_sha256(hash, passAndCookie, strlen((char*) passAndCookie)); Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32); Dict_putString(message, String_new("hash", alloc), hashHex, alloc); Dict_putString(message, String_new("cookie", alloc), cookieStr, alloc); // serialize the message with the password hash uint8_t buffer[AdminClient_MAX_MESSAGE_SIZE]; struct Writer* writer = ArrayWriter_new(buffer, AdminClient_MAX_MESSAGE_SIZE, alloc); if (StandardBencSerializer_get()->serializeDictionary(writer, message)) { return -1; } int length = writer->bytesWritten; // calculate the hash of the message with the password hash crypto_hash_sha256(hash, buffer, length); // swap the hash of the message with the password hash into the location // where the password hash was. Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32); return 0; }
String* VersionList_stringify(struct VersionList* list, struct Allocator* alloc) { uint8_t numberSize = 1; uint32_t max = 0xff; for (int i = 0; i < (int)list->length; i++) { while (list->versions[i] >= max) { numberSize++; max = max << 8 | 0xff; } } String* out = String_newBinary(NULL, (numberSize * list->length + 1), alloc); struct Writer* w = ArrayWriter_new(out->bytes, out->len, alloc); Writer_write(w, &numberSize, 1); for (int i = 0; i < (int)list->length; i++) { uint32_t ver = list->versions[i] << ((4-numberSize) * 8); ver = Endian_hostToBigEndian32(ver); Writer_write(w, (uint8_t*) &ver, numberSize); } Writer_write(w, &numberSize, 1); return out; }
static void sendConfToCore(struct Interface* toCoreInterface, struct Allocator* tempAlloc, Dict* config, struct Except* eh, struct Log* logger) { #define CONFIG_BUFF_SIZE 1024 uint8_t buff[CONFIG_BUFF_SIZE + 32] = {0}; uint8_t* start = buff + 32; struct Writer* writer = ArrayWriter_new(start, CONFIG_BUFF_SIZE - 33, tempAlloc); if (StandardBencSerializer_get()->serializeDictionary(writer, config)) { Except_raise(eh, -1, "Failed to serialize pre-configuration for core."); } struct Message* m = &(struct Message) { .bytes = start, .length = writer->bytesWritten, .padding = 32 }; m = Message_clone(m, tempAlloc); Log_keys(logger, "Sent [%d] bytes to core [%s].", m->length, m->bytes); toCoreInterface->sendMessage(m, toCoreInterface); } static void setUser(char* user, struct Log* logger, struct Except* eh) { struct Jmp jmp; Jmp_try(jmp) { Security_setUser(user, logger, &jmp.handler); } Jmp_catch { if (jmp.code == Security_setUser_PERMISSION) { return; } Except_raise(eh, jmp.code, "%s", jmp.message); } } static struct Pipe* getClientPipe(int argc, char** argv, struct EventBase* base, struct Except* eh, struct Allocator* alloc) { int inFromClientNo; int outToClientNo; if (argc < 4 || (inFromClientNo = atoi(argv[2])) == 0) { inFromClientNo = STDIN_FILENO; } if (argc < 4 || (outToClientNo = atoi(argv[3])) == 0) { outToClientNo = STDOUT_FILENO; } // named pipe. if (argc > 2 && inFromClientNo == STDIN_FILENO) { return Pipe_named(argv[2], base, eh, alloc); } return Pipe_forFiles(inFromClientNo, outToClientNo, base, eh, alloc); }
int main() { char buffer[512]; char out[512]; struct Allocator* alloc = BufferAllocator_new(buffer, 512); struct Writer* writer = ArrayWriter_new(out, 512, alloc); struct Reader* reader = ArrayReader_new(out, 512, alloc); return testSerialize(writer, reader); }
int main() { char out[512]; struct Allocator* alloc = CanaryAllocator_new(MallocAllocator_new(1<<20), NULL); struct Writer* writer = ArrayWriter_new(out, 512, alloc); struct Reader* reader = ArrayReader_new(out, 512, alloc); testSerialize(writer, reader); testParse(writer, reader, alloc); Allocator_free(alloc); }
static int parseEmptyList() { char* test = "d" "2:hi" "le" "e"; struct Allocator* alloc = MallocAllocator_new(1<<20); struct Reader* reader = ArrayReader_new(test, CString_strlen(test), alloc); Dict d; int ret = StandardBencSerializer_get()->parseDictionary(reader, alloc, &d); char out[256]; struct Writer* w = ArrayWriter_new(out, 256, alloc); ret |= StandardBencSerializer_get()->serializeDictionary(w, &d); ret |= Bits_memcmp(test, out, CString_strlen(test)); Allocator_free(alloc); return ret; }
int parseEmptyList() { char* test = "d" "2:hi" "le" "e"; char buffer[512]; struct Allocator* alloc = BufferAllocator_new(buffer, 512); struct Reader* reader = ArrayReader_new(test, strlen(test), alloc); Dict d; int ret = StandardBencSerializer_get()->parseDictionary(reader, alloc, &d); if (ret) { return ret; } char out[256]; struct Writer* w = ArrayWriter_new(out, 256, alloc); ret = StandardBencSerializer_get()->serializeDictionary(w, &d); if (ret) { return ret; } return Bits_memcmp(test, out, strlen(test)); }
void Admin_sendMessage(Dict* message, String* txid, struct Admin* admin) { if (!admin) { return; } uint8_t buff[MAX_API_REQUEST_SIZE]; uint8_t allocBuff[256]; struct Allocator* allocator = BufferAllocator_new(allocBuff, 256); int skip = (txid) ? 8 : 0; struct Writer* w = ArrayWriter_new(buff + skip, MAX_API_REQUEST_SIZE - skip, allocator); StandardBencSerializer_get()->serializeDictionary(w, message); size_t written = w->bytesWritten(w) + skip; if (txid) { memcpy(buff, "4567", 4); memcpy(buff + 4, txid->bytes, 4); } write(admin->outFd, buff, written); }
static int testSerialization() { char* context = "Hello World"; struct DHTModule module = { .name = "TestModule", .context = context, .serialize = serialize }; char buffer[256]; struct Allocator* allocator = BufferAllocator_new(buffer, 256); char writeBuffer[64]; memset(writeBuffer, 0, 64); struct Writer* writer = ArrayWriter_new(writeBuffer, 64, allocator); struct DHTModuleRegistry* reg = DHTModules_new(allocator); DHTModules_register(&module, reg); DHTModules_serialize(reg, writer); /* This is ok because the output is null padded at the end. */ printf("The content is: %s\nand the length is: %d\n", writeBuffer, (int) writer->bytesWritten(writer)); if (writer->bytesWritten(writer) != strlen(control)) { printf("Length mismatch! expected: %d", (int) strlen(control)); } return memcmp(writeBuffer, control, writer->bytesWritten(writer)); } static void deserialize(const Dict* serialData, void* vcontext) { char* context = (char*) vcontext; String* out = Dict_getString(serialData, &hi); memcpy(context, out->bytes, out->len); }
int main(int argc, char** argv) { #ifdef Log_KEYS fprintf(stderr, "Log_LEVEL = KEYS, EXPECT TO SEE PRIVATE KEYS IN YOUR LOGS!\n"); #endif if (isatty(STDIN_FILENO) || argc < 2) { // Fall through. } else if (!strcmp("angel", argv[1])) { return AngelInit_main(argc, argv); } else if (!strcmp("core", argv[1])) { return Core_main(argc, argv); } Assert_true(argc > 0); struct Except* eh = NULL; // Allow it to allocate 4MB struct Allocator* allocator = MallocAllocator_new(1<<22); struct Random* rand = Random_new(allocator, NULL, eh); struct EventBase* eventBase = EventBase_new(allocator); if (argc == 2) { // one argument if ((strcmp(argv[1], "--help") == 0) || (strcmp(argv[1], "-h") == 0)) { return usage(argv[0]); } else if (strcmp(argv[1], "--genconf") == 0) { return genconf(rand); } else if (strcmp(argv[1], "--pidfile") == 0) { // deprecated fprintf(stderr, "'--pidfile' option is deprecated.\n"); return 0; } else if (strcmp(argv[1], "--reconf") == 0) { // Performed after reading the configuration } else if (strcmp(argv[1], "--bench") == 0) { return benchmark(); } else if ((strcmp(argv[1], "--version") == 0) || (strcmp(argv[1], "-v") == 0)) { printf("Cjdns Git Version ID: %s\n", Version_gitVersion()); return 0; } else if (strcmp(argv[1], "--cleanconf") == 0) { // Performed after reading configuration } else { fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[1]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); return -1; } } else if (argc > 2) { // more than one argument? fprintf(stderr, "%s: too many arguments\n", argv[0]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); // because of '--pidfile $filename'? if (strcmp(argv[1], "--pidfile") == 0) { fprintf(stderr, "\n'--pidfile' option is deprecated.\n"); } return -1; } if (isatty(STDIN_FILENO)) { // We were started from a terminal // The chances an user wants to type in a configuration // bij hand are pretty slim so we show him the usage return usage(argv[0]); } else { // We assume stdin is a configuration file and that we should // start routing } struct Reader* stdinReader = FileReader_new(stdin, allocator); Dict config; if (JsonBencSerializer_get()->parseDictionary(stdinReader, allocator, &config)) { fprintf(stderr, "Failed to parse configuration.\n"); return -1; } if (argc == 2 && strcmp(argv[1], "--cleanconf") == 0) { struct Writer* stdoutWriter = FileWriter_new(stdout, allocator); JsonBencSerializer_get()->serializeDictionary(stdoutWriter, &config); printf("\n"); return 0; } struct Writer* logWriter = FileWriter_new(stdout, allocator); struct Log* logger = WriterLog_new(logWriter, allocator); // --------------------- Get Admin --------------------- // Dict* configAdmin = Dict_getDict(&config, String_CONST("admin")); String* adminPass = Dict_getString(configAdmin, String_CONST("password")); String* adminBind = Dict_getString(configAdmin, String_CONST("bind")); if (!adminPass) { adminPass = String_newBinary(NULL, 32, allocator); Random_base32(rand, (uint8_t*) adminPass->bytes, 32); adminPass->len = strlen(adminPass->bytes); } if (!adminBind) { Except_raise(eh, -1, "You must specify admin.bind in the cjdroute.conf file."); } // --------------------- Check for running instance --------------------- // Log_info(logger, "Checking for running instance..."); checkRunningInstance(allocator, eventBase, adminBind, adminPass, logger, eh); // --------------------- Setup Pipes to Angel --------------------- // char angelPipeName[64] = "client-angel-"; Random_base32(rand, (uint8_t*)angelPipeName+13, 31); Assert_true(EventBase_eventCount(eventBase) == 0); struct Pipe* angelPipe = Pipe_named(angelPipeName, eventBase, eh, allocator); Assert_true(EventBase_eventCount(eventBase) == 2); angelPipe->logger = logger; char* args[] = { "angel", angelPipeName, NULL }; // --------------------- Spawn Angel --------------------- // String* privateKey = Dict_getString(&config, String_CONST("privateKey")); char* corePath = Process_getPath(allocator); if (!corePath) { Except_raise(eh, -1, "Can't find a usable cjdns core executable, " "make sure it is in the same directory as cjdroute"); } if (!privateKey) { Except_raise(eh, -1, "Need to specify privateKey."); } Log_info(logger, "Forking angel to background."); Process_spawn(corePath, args, eventBase, allocator); // --------------------- Get user for angel to setuid() ---------------------- // String* securityUser = NULL; List* securityConf = Dict_getList(&config, String_CONST("security")); for (int i = 0; i < List_size(securityConf); i++) { securityUser = Dict_getString(List_getDict(securityConf, i), String_CONST("setuser")); if (securityUser) { int64_t* ea = Dict_getInt(List_getDict(securityConf, i), String_CONST("exemptAngel")); if (ea && *ea) { securityUser = NULL; } break; } } // --------------------- Pre-Configure Angel ------------------------- // Dict* preConf = Dict_new(allocator); Dict* adminPreConf = Dict_new(allocator); Dict_putDict(preConf, String_CONST("admin"), adminPreConf, allocator); Dict_putString(adminPreConf, String_CONST("core"), String_new(corePath, allocator), allocator); Dict_putString(preConf, String_CONST("privateKey"), privateKey, allocator); Dict_putString(adminPreConf, String_CONST("bind"), adminBind, allocator); Dict_putString(adminPreConf, String_CONST("pass"), adminPass, allocator); if (securityUser) { Dict_putString(adminPreConf, String_CONST("user"), securityUser, allocator); } Dict* logging = Dict_getDict(&config, String_CONST("logging")); if (logging) { Dict_putDict(preConf, String_CONST("logging"), logging, allocator); } #define CONFIG_BUFF_SIZE 1024 uint8_t buff[CONFIG_BUFF_SIZE] = {0}; struct Writer* toAngelWriter = ArrayWriter_new(buff, CONFIG_BUFF_SIZE - 1, allocator); if (StandardBencSerializer_get()->serializeDictionary(toAngelWriter, preConf)) { Except_raise(eh, -1, "Failed to serialize pre-configuration"); } struct Message* toAngelMsg = &(struct Message) { .bytes = buff, .length = toAngelWriter->bytesWritten }; toAngelMsg = Message_clone(toAngelMsg, allocator); Interface_sendMessage(&angelPipe->iface, toAngelMsg); Log_keys(logger, "Sent [%s] to angel process.", buff); // --------------------- Get Response from Angel --------------------- // struct Message* fromAngelMsg = InterfaceWaiter_waitForData(&angelPipe->iface, eventBase, allocator, eh); Dict responseFromAngel; struct Reader* responseFromAngelReader = ArrayReader_new(fromAngelMsg->bytes, fromAngelMsg->length, allocator); if (StandardBencSerializer_get()->parseDictionary(responseFromAngelReader, allocator, &responseFromAngel)) { Except_raise(eh, -1, "Failed to parse pre-configuration response [%s]", buff); } // --------------------- Get Admin Addr/Port/Passwd --------------------- // Dict* responseFromAngelAdmin = Dict_getDict(&responseFromAngel, String_CONST("admin")); adminBind = Dict_getString(responseFromAngelAdmin, String_CONST("bind")); if (!adminBind) { Except_raise(eh, -1, "didn't get address and port back from angel"); } struct Sockaddr_storage adminAddr; if (Sockaddr_parse(adminBind->bytes, &adminAddr)) { Except_raise(eh, -1, "Unable to parse [%s] as an ip address port, eg: 127.0.0.1:11234", adminBind->bytes); } // sanity check, Pipe_named() creates 2 events, see above. Assert_true(EventBase_eventCount(eventBase) == 2); // --------------------- Configuration ------------------------- // Configurator_config(&config, &adminAddr.addr, adminPass, eventBase, logger, allocator); // --------------------- noBackground ------------------------ // int64_t* noBackground = Dict_getInt(&config, String_CONST("noBackground")); if (noBackground && *noBackground) { EventBase_beginLoop(eventBase); } //Allocator_free(allocator); return 0; }
int main(int argc, char** argv) { #ifdef Log_KEYS fprintf(stderr, "Log_LEVEL = KEYS, EXPECT TO SEE PRIVATE KEYS IN YOUR LOGS!\n"); #endif Assert_true(argc > 0); struct Except* eh = NULL; // Allow it to allocate 4MB struct Allocator* allocator = MallocAllocator_new(1<<22); struct Random* rand = Random_new(allocator, NULL, eh); struct EventBase* eventBase = EventBase_new(allocator); if (argc == 2) { // one argument if (strcmp(argv[1], "--help") == 0) { return usage(argv[0]); } else if (strcmp(argv[1], "--genconf") == 0) { return genconf(rand); } else if (strcmp(argv[1], "--pidfile") == 0) { // Performed after reading the configuration } else if (strcmp(argv[1], "--reconf") == 0) { // Performed after reading the configuration } else if (strcmp(argv[1], "--bench") == 0) { return benchmark(); } else if (strcmp(argv[1], "--version") == 0) { //printf("Version ID: %s\n", RouterModule_gitVersion()); return 0; } else { fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[1]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); return -1; } } else if (argc > 2) { // more than one argument? fprintf(stderr, "%s: too many arguments\n", argv[0]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); return -1; } if (isatty(STDIN_FILENO)) { // We were started from a terminal // The chances an user wants to type in a configuration // bij hand are pretty slim so we show him the usage return usage(argv[0]); } else { // We assume stdin is a configuration file and that we should // start routing } struct Reader* stdinReader = FileReader_new(stdin, allocator); Dict config; if (JsonBencSerializer_get()->parseDictionary(stdinReader, allocator, &config)) { fprintf(stderr, "Failed to parse configuration.\n"); return -1; } struct Writer* logWriter = FileWriter_new(stdout, allocator); struct Log* logger = WriterLog_new(logWriter, allocator); // --------------------- Setup Pipes to Angel --------------------- // int pipeToAngel[2]; int pipeFromAngel[2]; if (Pipe_createUniPipe(pipeToAngel) || Pipe_createUniPipe(pipeFromAngel)) { Except_raise(eh, -1, "Failed to create pipes to angel [%s]", Errno_getString()); } char pipeToAngelStr[8]; snprintf(pipeToAngelStr, 8, "%d", pipeToAngel[0]); char pipeFromAngelStr[8]; snprintf(pipeFromAngelStr, 8, "%d", pipeFromAngel[1]); char* args[] = { "angel", pipeToAngelStr, pipeFromAngelStr, NULL }; // --------------------- Spawn Angel --------------------- // String* privateKey = Dict_getString(&config, String_CONST("privateKey")); String* corePath = getCorePath(allocator); if (!corePath) { Except_raise(eh, -1, "Can't find a usable cjdns core executable, " "make sure it is in the same directory as cjdroute"); } if (!privateKey) { Except_raise(eh, -1, "Need to specify privateKey."); } Log_info(logger, "Forking angel to background."); Process_spawn(corePath->bytes, args); // --------------------- Get Admin --------------------- // Dict* configAdmin = Dict_getDict(&config, String_CONST("admin")); String* adminPass = Dict_getString(configAdmin, String_CONST("password")); String* adminBind = Dict_getString(configAdmin, String_CONST("bind")); if (!adminPass) { adminPass = String_newBinary(NULL, 32, allocator); Random_base32(rand, (uint8_t*) adminPass->bytes, 32); adminPass->len = strlen(adminPass->bytes); } if (!adminBind) { adminBind = String_new("127.0.0.1:0", allocator); } // --------------------- Get user for angel to setuid() ---------------------- // String* securityUser = NULL; List* securityConf = Dict_getList(&config, String_CONST("security")); for (int i = 0; i < List_size(securityConf); i++) { securityUser = Dict_getString(List_getDict(securityConf, i), String_CONST("setuser")); if (securityUser) { int64_t* ea = Dict_getInt(List_getDict(securityConf, i), String_CONST("exemptAngel")); if (ea && *ea) { securityUser = NULL; } break; } } // --------------------- Pre-Configure Angel ------------------------- // Dict* preConf = Dict_new(allocator); Dict* adminPreConf = Dict_new(allocator); Dict_putDict(preConf, String_CONST("admin"), adminPreConf, allocator); Dict_putString(adminPreConf, String_CONST("core"), corePath, allocator); Dict_putString(preConf, String_CONST("privateKey"), privateKey, allocator); Dict_putString(adminPreConf, String_CONST("bind"), adminBind, allocator); Dict_putString(adminPreConf, String_CONST("pass"), adminPass, allocator); if (securityUser) { Dict_putString(adminPreConf, String_CONST("user"), securityUser, allocator); } #define CONFIG_BUFF_SIZE 1024 uint8_t buff[CONFIG_BUFF_SIZE] = {0}; struct Writer* toAngelWriter = ArrayWriter_new(buff, CONFIG_BUFF_SIZE - 1, allocator); if (StandardBencSerializer_get()->serializeDictionary(toAngelWriter, preConf)) { Except_raise(eh, -1, "Failed to serialize pre-configuration"); } write(pipeToAngel[1], buff, toAngelWriter->bytesWritten(toAngelWriter)); Log_keys(logger, "Sent [%s] to angel process.", buff); // --------------------- Get Response from Angel --------------------- // uint32_t amount = Waiter_getData(buff, CONFIG_BUFF_SIZE, pipeFromAngel[0], eventBase, eh); Dict responseFromAngel; struct Reader* responseFromAngelReader = ArrayReader_new(buff, amount, allocator); if (StandardBencSerializer_get()->parseDictionary(responseFromAngelReader, allocator, &responseFromAngel)) { Except_raise(eh, -1, "Failed to parse pre-configuration response [%s]", buff); } // --------------------- Get Admin Addr/Port/Passwd --------------------- // Dict* responseFromAngelAdmin = Dict_getDict(&responseFromAngel, String_CONST("admin")); adminBind = Dict_getString(responseFromAngelAdmin, String_CONST("bind")); if (!adminBind) { Except_raise(eh, -1, "didn't get address and port back from angel"); } struct Sockaddr_storage adminAddr; if (Sockaddr_parse(adminBind->bytes, &adminAddr)) { Except_raise(eh, -1, "Unable to parse [%s] as an ip address port, eg: 127.0.0.1:11234", adminBind->bytes); } // sanity check Assert_true(EventBase_eventCount(eventBase) == 0); // --------------------- Configuration ------------------------- // Configurator_config(&config, &adminAddr.addr, adminPass, eventBase, logger, allocator); return 0; }
/** @return a string representing the address and port to connect to. */ static String* initAngel(int fromAngel, int toAngel, int corePipes[2][2], struct PipeInterface** piOut, struct EventBase* eventBase, struct Log* logger, struct Allocator* alloc, struct Random* rand) { #define TO_CORE (corePipes[0][1]) #define FROM_CORE (corePipes[1][0]) #define TO_ANGEL_AS_CORE (corePipes[1][1]) #define FROM_ANGEL_AS_CORE (corePipes[0][0]) Dict core = Dict_CONST( String_CONST("fromCore"), Int_OBJ(FROM_CORE), Dict_CONST( String_CONST("toCore"), Int_OBJ(TO_CORE), NULL )); Dict admin = Dict_CONST( String_CONST("bind"), String_OBJ(String_CONST("127.0.0.1")), Dict_CONST( String_CONST("core"), Dict_OBJ(&core), Dict_CONST( String_CONST("pass"), String_OBJ(String_CONST("abcd")), NULL ))); Dict message = Dict_CONST( String_CONST("admin"), Dict_OBJ(&admin), NULL ); struct Allocator* tempAlloc; BufferAllocator_STACK(tempAlloc, 1024); #define BUFFER_SZ 1023 uint8_t buff[BUFFER_SZ + 1] = {0}; struct Writer* w = ArrayWriter_new(buff, BUFFER_SZ, tempAlloc); StandardBencSerializer_get()->serializeDictionary(w, &message); Log_info(logger, "Writing intial configuration to angel on [%d] config: [%s]", toAngel, buff); write(toAngel, buff, w->bytesWritten(w)); // This is angel->core data, we can throw this away. //Waiter_getData(buff, BUFFER_SZ, fromAngel, eventBase, NULL); //Log_info(logger, "Init message from angel to core: [%s]", buff); Bits_memset(buff, 0, BUFFER_SZ); struct PipeInterface* pi = PipeInterface_new(FROM_ANGEL_AS_CORE, TO_ANGEL_AS_CORE, eventBase, logger, alloc, rand); *piOut = pi; Log_info(logger, "PipeInterface [%p] is now ready.", (void*)pi); // Make sure the angel sends data to the core. InterfaceWaiter_waitForData(&pi->generic, eventBase, alloc, NULL); // Send response on behalf of core. char coreToAngelResponse[128] = " PADDING " "\xff\xff\xff\xff" "d" "5:error" "4:none" "e"; char* start = strchr(coreToAngelResponse, '\xff'); struct Message m = { .bytes = (uint8_t*) start, .length = strlen(start), .padding = start - coreToAngelResponse }; pi->generic.sendMessage(&m, &pi->generic); // This is angel->client data, it will tell us which port was bound. Waiter_getData(buff, BUFFER_SZ, fromAngel, eventBase, NULL); printf("Response from angel to client: [%s]\n", buff); struct Reader* reader = ArrayReader_new(buff, BUFFER_SZ, tempAlloc); Dict configStore; Dict* config = &configStore; Assert_true(!StandardBencSerializer_get()->parseDictionary(reader, tempAlloc, config)); Dict* responseAdmin = Dict_getDict(config, String_CONST("admin")); String* bind = Dict_getString(responseAdmin, String_CONST("bind")); Assert_true(bind); return String_clone(bind, alloc); } /** * This spawns itself as the Angel process which spawns itself again as the core process. * The "core process" pipes all of its inputs back to the originating process */ struct AdminTestFramework* AdminTestFramework_setUp(int argc, char** argv) { if (argc > 1 && !strcmp("angel", argv[1])) { exit(AngelInit_main(argc, argv)); } struct Allocator* alloc = CanaryAllocator_new(MallocAllocator_new(1<<20), NULL); struct Writer* logwriter = FileWriter_new(stdout, alloc); Assert_always(logwriter); struct Log* logger = WriterLog_new(logwriter, alloc); struct EventBase* eventBase = EventBase_new(alloc); struct Random* rand = Random_new(alloc, NULL); int fromAngel; int toAngel; int corePipes[2][2]; if (Pipe_createUniPipe(corePipes[0]) || Pipe_createUniPipe(corePipes[1])) { Except_raise(NULL, -1, "Failed to create pipes [%s]", Errno_getString()); } spawnAngel(&fromAngel, &toAngel); struct PipeInterface* pi; String* addrStr = initAngel(fromAngel, toAngel, corePipes, &pi, eventBase, logger, alloc, rand); Log_info(logger, "Angel initialized."); String* password = String_new("abcd", alloc); struct Admin* admin = Admin_new(&pi->generic, alloc, logger, eventBase, password); // Now setup the client. struct sockaddr_storage addr; int addrLen = sizeof(struct sockaddr_storage); Bits_memset(&addr, 0, sizeof(struct sockaddr_storage)); Assert_true(!evutil_parse_sockaddr_port(addrStr->bytes, (struct sockaddr*) &addr, &addrLen)); struct AdminClient* client = AdminClient_new((uint8_t*) &addr, addrLen, password, eventBase, logger, alloc); Assert_always(client); return alloc->clone(sizeof(struct AdminTestFramework), alloc, &(struct AdminTestFramework) { .admin = admin, .client = client, .alloc = alloc, .eventBase = eventBase, .logger = logger, .addr = alloc->clone(addrLen, alloc, &addr), .addrLen = addrLen, .angelInterface = &pi->generic }); }
static void sendConfToCore(struct Interface* toCoreInterface, struct Allocator* alloc, Dict* config, struct Except* eh, struct Log* logger) { #define CONFIG_BUFF_SIZE 1024 uint8_t buff[CONFIG_BUFF_SIZE + 32] = {0}; uint8_t* start = buff + 32; struct Writer* writer = ArrayWriter_new(start, CONFIG_BUFF_SIZE - 33, alloc); if (StandardBencSerializer_get()->serializeDictionary(writer, config)) { Except_raise(eh, -1, "Failed to serialize pre-configuration for core."); } struct Message m = { .bytes = start, .length = writer->bytesWritten(writer), .padding = 32 }; Log_keys(logger, "Sent [%d] bytes to core [%s].", m.length, m.bytes); toCoreInterface->sendMessage(&m, toCoreInterface); } static void setUser(char* user, struct Log* logger, struct Except* eh) { struct Jmp jmp; Jmp_try(jmp) { Security_setUser(user, logger, &jmp.handler); } Jmp_catch { if (jmp.code == Security_setUser_PERMISSION) { return; } Except_raise(eh, jmp.code, "%s", jmp.message); } } /** * Input: * { * "admin": { * "core": "/path/to/core/binary", * "bind": "127.0.0.1:12345", * "pass": "******", * "user": "******" * } * } * for example: * d5:admind4:core30:./build/admin/angel/cjdns-core4:bind15:127.0.0.1:123454:pass4:abcdee * * Pre-existing core mode: * { * "admin": { * "core": { * "fromCore": 12, * "toCore": 14 * }, * "bind": "127.0.0.1:12345", * "pass": "******", * "user": "******" * } * } * * If "core" is a dictionary, the angel will behave as though the core is already spawned and * it will read from the core on the file descriptor given by "fromCore" and write to the file * given by "toCore". * * "user" is optional, if set the angel will setuid() that user's uid. */ int AngelInit_main(int argc, char** argv) { struct Except* eh = NULL; int inFromClientNo; int outToClientNo; if (argc < 3 || (inFromClientNo = atoi(argv[2])) == 0) { inFromClientNo = STDIN_FILENO; } if (argc < 4 || (outToClientNo = atoi(argv[3])) == 0) { outToClientNo = STDOUT_FILENO; } struct Allocator* alloc = MallocAllocator_new(1<<21); struct Writer* logWriter = FileWriter_new(stdout, alloc); struct Log* logger = WriterLog_new(logWriter, alloc); struct Random* rand = Random_new(alloc, logger, eh); alloc = CanaryAllocator_new(alloc, rand); struct Allocator* tempAlloc = Allocator_child(alloc); struct EventBase* eventBase = EventBase_new(alloc); Log_debug(logger, "Initializing angel with input [%d] and output [%d]", inFromClientNo, outToClientNo); Log_debug(logger, "Getting pre-configuration from client"); #define CONFIG_BUFF_SIZE 1024 uint8_t buff[CONFIG_BUFF_SIZE] = {0}; Waiter_getData(buff, CONFIG_BUFF_SIZE, inFromClientNo, eventBase, eh); Log_debug(logger, "Finished getting pre-configuration from client"); struct Reader* reader = ArrayReader_new(buff, CONFIG_BUFF_SIZE, tempAlloc); Dict config; if (StandardBencSerializer_get()->parseDictionary(reader, tempAlloc, &config)) { Except_raise(eh, -1, "Failed to parse configuration."); } Dict* admin = Dict_getDict(&config, String_CONST("admin")); String* core = Dict_getString(admin, String_CONST("core")); String* bind = Dict_getString(admin, String_CONST("bind")); String* pass = Dict_getString(admin, String_CONST("pass")); String* user = Dict_getString(admin, String_CONST("user")); int toCore = -1; int fromCore = -1; if (!core) { Dict* coreDict = Dict_getDict(admin, String_CONST("core")); int64_t* toCorePtr = Dict_getInt(coreDict, String_CONST("toCore")); int64_t* fromCorePtr = Dict_getInt(coreDict, String_CONST("fromCore")); toCore = (toCorePtr) ? *toCorePtr : -1; fromCore = (fromCorePtr) ? *fromCorePtr : -1; } if (!bind || !pass || (!core && (toCore == -1 || fromCore == -1))) { Except_raise(eh, -1, "missing configuration params in preconfig. [%s]", buff); } if (core) { Log_info(logger, "Initializing core [%s]", core->bytes); initCore(core->bytes, &toCore, &fromCore, eh); } Log_debug(logger, "Sending pre-configuration to core."); struct PipeInterface* pif = PipeInterface_new(fromCore, toCore, eventBase, logger, alloc, rand); struct Interface* coreIface = &pif->generic; PipeInterface_waitUntilReady(pif); sendConfToCore(coreIface, tempAlloc, &config, eh, logger); struct Message* coreResponse = InterfaceWaiter_waitForData(coreIface, eventBase, tempAlloc, eh); if (write(outToClientNo, coreResponse->bytes, coreResponse->length)) { // Ignore the result of write() without the compiler complaining. } #ifdef Log_KEYS uint8_t lastChar = coreResponse->bytes[coreResponse->length-1]; coreResponse->bytes[coreResponse->length-1] = 0; Log_keys(logger, "Sent [%s%c] to client.", coreResponse->bytes, lastChar); coreResponse->bytes[coreResponse->length-1] = lastChar; #endif if (user) { setUser(user->bytes, logger, eh); } Allocator_free(tempAlloc); Angel_start(coreIface, eventBase, logger, alloc); return 0; }
/** * send a message */ static void adminChannelSendData(struct Admin* admin, uint32_t channelNum, const void *data, uint32_t length) { /* if this changes, we need to fragment the messages * into MAX_MESSAGE_SIZE chunks */ Assert_compileTime(MAX_API_REQUEST_SIZE == MAX_MESSAGE_SIZE); Assert_true(length <= MAX_MESSAGE_SIZE); struct Admin_MessageHeader header = { .magic = admin->pipeMagic, .length = length, .channelNum = channelNum }; const uint8_t* buf = (const uint8_t*) data; // TODO: check result, buffer writes write(admin->outFd, &header, Admin_MessageHeader_SIZE); if (length > 0) { write(admin->outFd, buf, length); } } /** * public function to send responses */ void Admin_sendMessage(Dict* message, String* txid, struct Admin* admin) { if (!admin) { return; } Assert_true(txid); uint32_t channelNum; struct Admin_Channel* channel = adminChannelFindByTxid(admin, txid, &channelNum); if (!channel) { // txid too short, invalid channel number, closed channel or not matching serial Log_debug(admin->logger, "Dropped response because channel isn't open anymore."); return; } uint8_t buff[MAX_API_REQUEST_SIZE]; uint8_t allocBuff[256]; struct Allocator* allocator = BufferAllocator_new(allocBuff, 256); // Bounce back the user-supplied txid. String userTxid = { .bytes = txid->bytes + Admin_TxidPrefix_SIZE, .len = txid->len - Admin_TxidPrefix_SIZE }; if (txid->len > Admin_TxidPrefix_SIZE) { Dict_putString(message, TXID, &userTxid, allocator); } struct Writer* w = ArrayWriter_new(buff, sizeof(buff), allocator); StandardBencSerializer_get()->serializeDictionary(w, message); adminChannelSendData(admin, channelNum, buff, w->bytesWritten(w)); } /** * close a channel (for example if an error happened or we received non-empty * messages on a invalid channel number) * also used to cleanup if we receive a close message */ static void adminChannelClose(struct Admin* admin, uint32_t channelNum) { struct Admin_Channel* channel = adminChannelFindById(admin, channelNum); if (channel) { switch (channel->state) { case Admin_ChannelState_OPEN: break; case Admin_ChannelState_CLOSED: case Admin_ChannelState_WAIT_FOR_CLOSE: return; // already sent close, nothing to do } channel->state = Admin_ChannelState_WAIT_FOR_CLOSE; // clean up bufers channel->bufferLen = 0; channel->buffer = NULL; if (channel->allocator) { channel->allocator->free(channel->allocator); channel->allocator = NULL; } } adminChannelSendData(admin, channelNum, NULL, 0); } /** * handle a received channel close (the received header is in admin->messageHeader) * as invalid channels are never OPEN we never have to ACK a close on them */ static void adminChannelHandleClose(struct Admin* admin) { uint32_t channelNum = admin->messageHeader.channelNum; struct Admin_Channel* channel = adminChannelFindById(admin, channelNum); if (channel) { switch (channel->state) { case Admin_ChannelState_OPEN: // close active channel adminChannelClose(admin, channelNum); // now the state is WAIT_FOR_CLOSE, set it to CLOSED channel->state = Admin_ChannelState_CLOSED; break; case Admin_ChannelState_WAIT_FOR_CLOSE: channel->state = Admin_ChannelState_CLOSED; channel->serial++; break; case Admin_ChannelState_CLOSED: // nothing to do break; } } } static inline bool authValid(Dict* message, uint8_t* buffer, uint32_t length, struct Admin* admin) { String* cookieStr = Dict_getString(message, String_CONST("cookie")); uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0; if (!cookie) { int64_t* cookieInt = Dict_getInt(message, String_CONST("cookie")); cookie = (cookieInt) ? *cookieInt : 0; } uint64_t nowSecs = Time_currentTimeSeconds(admin->eventBase); String* submittedHash = Dict_getString(message, String_CONST("hash")); if (cookie > nowSecs || cookie < nowSecs - 20 || !submittedHash || submittedHash->len != 64) { return false; } uint8_t* hashPtr = (uint8_t*) strstr((char*) buffer, submittedHash->bytes); if (!hashPtr || !admin->password) { return false; } uint8_t passAndCookie[64]; snprintf((char*) passAndCookie, 64, "%s%u", admin->password->bytes, cookie); uint8_t hash[32]; crypto_hash_sha256(hash, passAndCookie, strlen((char*) passAndCookie)); Hex_encode(hashPtr, 64, hash, 32); crypto_hash_sha256(hash, buffer, length); Hex_encode(hashPtr, 64, hash, 32); return memcmp(hashPtr, submittedHash->bytes, 64) == 0; }
/** @return a string representing the address and port to connect to. */ static void initAngel(struct Pipe* asClientPipe, struct Interface* asCoreIface, char* asCorePipeName, struct EventBase* eventBase, struct Log* logger, struct Allocator* alloc, struct Random* rand) { Dict admin = Dict_CONST( String_CONST("bind"), String_OBJ(String_CONST("127.0.0.1")), Dict_CONST( String_CONST("corePipeName"), String_OBJ(String_CONST(asCorePipeName)), Dict_CONST( String_CONST("pass"), String_OBJ(String_CONST("abcd")), NULL ))); Dict message = Dict_CONST( String_CONST("admin"), Dict_OBJ(&admin), NULL ); struct Allocator* tempAlloc = Allocator_child(alloc); #define BUFFER_SZ 1023 uint8_t buff[BUFFER_SZ + 1] = {0}; struct Writer* w = ArrayWriter_new(buff, BUFFER_SZ, tempAlloc); StandardBencSerializer_get()->serializeDictionary(w, &message); struct Message* toAngel = Allocator_malloc(tempAlloc, sizeof(struct Message) + w->bytesWritten); toAngel->bytes = (uint8_t*) (&toAngel[1]); toAngel->length = toAngel->capacity = w->bytesWritten; toAngel->padding = 0; toAngel->alloc = tempAlloc; Bits_memcpy(toAngel->bytes, buff, toAngel->length); Log_info(logger, "Writing intial configuration to angel on [%s] config: [%s]", asClientPipe->name, buff); Interface_sendMessage(&asClientPipe->iface, toAngel); // This is client->angel->core data, we can throw this away. //struct Message* angelToCore = InterfaceWaiter_waitForData(asCoreIface, eventBase, tempAlloc, NULL); // unterminated string //Log_info(logger, "Init message from angel to core: [%s]", angelToCore->bytes); // Send response on behalf of core. char* coreToAngelResponse = " PADDING " "d" "5:error" "4:none" "e"; struct Message* m = &(struct Message) { .bytes = (uint8_t*) coreToAngelResponse, .length = strlen(coreToAngelResponse), .padding = 0, .capacity = strlen(coreToAngelResponse) }; Message_shift(m, -24, NULL); m = Message_clone(m, tempAlloc); Interface_sendMessage(asCoreIface, m); // This is angel->client data, it will tell us which port was bound. struct Message* angelToClient = InterfaceWaiter_waitForData(&asClientPipe->iface, eventBase, tempAlloc, NULL); printf("Response from angel to client: [%s]\n", angelToClient->bytes); Allocator_free(tempAlloc); return; }
void Admin_sendMessage(Dict* message, String* txid, struct Admin* admin) { if (!admin) { return; } Assert_true(txid); uint8_t buff[MAX_API_REQUEST_SIZE + TXID_LEN]; // Write the inter-process txid. Bits_memcpyConst(buff, txid->bytes, TXID_LEN); uint8_t allocBuff[256]; struct Allocator* allocator = BufferAllocator_new(allocBuff, 256); // Bounce back the user-supplied txid. String userTxid = { .bytes = txid->bytes + TXID_LEN, .len = txid->len - TXID_LEN }; if (txid->len > TXID_LEN) { Dict_putString(message, TXID, &userTxid, allocator); } struct Writer* w = ArrayWriter_new(buff + TXID_LEN, MAX_API_REQUEST_SIZE, allocator); StandardBencSerializer_get()->serializeDictionary(w, message); write(admin->outFd, buff, w->bytesWritten(w) + TXID_LEN); } struct Admin* Admin_new(struct sockaddr_storage* addr, int addrLen, String* password, char* user, struct event_base* eventBase, struct ExceptionHandler* eh, struct Log* logger, struct Allocator* allocator) { errno = 0; int pipes[2][2]; if (pipe(pipes[0]) || pipe(pipes[1])) { eh->exception(__FILE__ " Failed to create pipes.", errno, eh); } int pgid = getpid(); int pid = fork(); if (pid < 0) { eh->exception(__FILE__ " Failed to fork()", errno, eh); } bool isChild = (pid == 0); int inFd = pipes[isChild][0]; close(pipes[!isChild][0]); int outFd = pipes[!isChild][1]; close(pipes[isChild][1]); if (isChild) { // Set the process group so that children will not // become orphaned if the parent gets signal 11 err um 9. setpgid(0, pgid); if (user) { Security_setUser(user, NULL, AbortHandler_INSTANCE); } struct ChildContext context; memset(&context, 0, sizeof(struct ChildContext)); context.inFd = inFd; context.outFd = outFd; context.allocator = allocator; event_reinit(eventBase); context.eventBase = eventBase; child(addr, addrLen, user, &context); fprintf(stderr, "Admin process exiting."); exit(0); } setpgid(pid, pgid); struct Admin* admin = allocator->calloc(sizeof(struct Admin), 1, allocator); admin->inFd = inFd; admin->outFd = outFd; admin->allocator = allocator; admin->logger = logger; admin->functionCount = 0; admin->eventBase = eventBase; admin->password = password; Bits_memcpyConst(&admin->address, addr, sizeof(struct sockaddr_storage)); admin->addressLength = addrLen; admin->pipeEv = event_new(eventBase, inFd, EV_READ | EV_PERSIST, inFromChild, admin); event_add(admin->pipeEv, NULL); event_base_dispatch(eventBase); return admin; }
.onResponseContext = onResponseContext, .hermes = hermes })); Identity_set(req); int index = Map_RequestSet_put(&req, &hermes->requestSet); Allocator_onFree(reqAlloc, removeReqFromSet, req); uint32_t handle = hermes->requestSet.handles[index]; req->handle = handle; uint8_t handleHex[9]; Hex_encode(handleHex, 9, (uint8_t*)&handle, 4); Dict_putString(message, String_CONST("txid"), String_CONST((char*)handleHex), reqAlloc); struct Writer* writer = ArrayWriter_new(buff.message, BUFF_SIZE, reqAlloc); if (StandardBencSerializer_get()->serializeDictionary(writer, message)) { Except_raise(eh, Hermes_callAngel_ESERIALIZE, "Failed to serialize message"); } // Remove the txid string so there is not a dangling pointer in the message. Dict_remove(message, String_CONST("txid")); // This is done in a strange way but it is to prevent "possible buffer overflow" errors struct Message* m = &(struct Message) { .bytes = (uint8_t*) &buff, .length = writer->bytesWritten + PADDING, .padding = 0 }; m->capacity = m->length; Message_shift(m, -PADDING);