Пример #1
0
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;
}
Пример #2
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;
}
Пример #3
0
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);
}
Пример #5
0
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);
}
Пример #6
0
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;
}
Пример #7
0
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));
}
Пример #8
0
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);
}
Пример #10
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

    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;
}
Пример #11
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;
}
Пример #12
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
    });
}
Пример #13
0
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;
}
Пример #14
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;
}
Пример #15
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;
}
Пример #16
0
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;
}
Пример #17
0
        .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);