diff --git a/src/api/encryption_init_post.c b/src/api/encryption_init_post.c index aeef25d1a835ff05c8e3cda53527521707ff8073..0b95fafc30f25e889a41a58f263bd334909ace32 100644 --- a/src/api/encryption_init_post.c +++ b/src/api/encryption_init_post.c @@ -78,7 +78,7 @@ int callback_encryption_init_post(const struct _u_request * request, asprintf(&command, "rsync -a %s/ %s", UNENCRYPTED_TMP_MOUNTPOINT, TMP_LOCATION); r = system(command); - if(r != 0) + if (r != 0) { printf("copying root device contents into memory failed" ": return code %d\n", r); diff --git a/src/api/ssh_keys_post.c b/src/api/ssh_keys_post.c new file mode 100644 index 0000000000000000000000000000000000000000..08fd28f2628463ca8530e238beb4f3f434974e24 --- /dev/null +++ b/src/api/ssh_keys_post.c @@ -0,0 +1,55 @@ +/** + * Callback function that appends an SSH key tot the list of keys authorised for + * access to the initrd. + * + * Example output: + * {"ssh-keys":{"1":"ssh-rsa AAAAB3... example@example.com", + * "2":"ssh-rsa AAAAB3...","5":"command=\"/usr/bin/cryptops-client\" ssh-rsa + * AAAAB3... cryptops-test@greenhost"}} + * + * The indices correspond to line numbers of the authorized_keys file. + * Missing indices (like 3 and 4 in the example) arise from empty lines in the + * file; those are creted when keys are deleted. + * + * @param[in] request incoming HTTP request + * @param[out] response HTTP response to the request + * @param[in] user_data extra data to pass between main thread and callbacks + * @return internal status code + */ +int callback_ssh_keys_post(const struct _u_request * request, + struct _u_response * response, void * user_data) +{ + // Open file with append mode + FILE * authorized_keys = fopen(AUTHORIZED_KEYS_PATH, "a"); + + // Check if that succeeded. + if (authorized_keys == NULL) + { + printf("Could not open authorized_keys file for writing\n"); + return send_simple_response(response, 500, "error", + "error opening authorized_keys"); + } + + // Read in json request body. + json_t * json_input = ulfius_get_json_body_request(request, NULL); + + // Read SSH key from request. + const char * ssh_key; + ssh_key = json_string_value(json_object_get(json_input, "ssh-key")); + if (ssh_key == NULL) + { + return send_simple_response(response, 400, "error", "missing ssh-key"); + } + + char * ssh_key_with_command; + + add_ssh_command(&ssh_key_with_command, ssh_key); + + asprintf(&ssh_key_with_command, "%s\n", ssh_key_with_command); + + // Write SSH key to file + fprintf(authorized_keys, ssh_key_with_command); + fclose(authorized_keys); + + return send_simple_response(response, 200, "status", "ok"); +} diff --git a/src/auxiliary.c b/src/auxiliary.c index afa4ff6001f7ebc62e28161883fd667af7cdd0c0..db1f7af3102e10c382acff61258b17dc3a222ad8 100644 --- a/src/auxiliary.c +++ b/src/auxiliary.c @@ -12,36 +12,56 @@ void stop_server() } /** - * Read a file completely into a string. - * @param filename Path to the file to read. - * @return Contents of the file. + * Read the contents of an already opened file into a string + * @param file The file as opened by fopen with "rb" + * @return Contents of the file */ -char * read_file(const char * filename) +char * read_from_file(FILE * file) { - char * buffer = NULL; - long length; - FILE * file = fopen(filename, "rb"); - if (filename != NULL) + char buf[100]; + char * str = NULL; + char * temp = NULL; + // start with size of 1 to make room for null terminator + unsigned int size = 1; + unsigned int strlength; + if (file) { - if (file) + while (fgets(buf, sizeof(buf), file) != NULL) { - fseek(file, 0, SEEK_END); - length = ftell(file); - fseek(file, 0, SEEK_SET); - buffer = o_malloc(length + 1); - if (buffer) + strlength = strlen(buf); + // allocate room for the buf that gets appended + temp = realloc(str, size + strlength); + if (temp == NULL) + { + printf("Could not allocate memory for file reading\n"); + return NULL; + } + else { - fread(buffer, 1, length, file); + str = temp; } - buffer[length] = '\0'; - fclose (file); + // append buffer to str + strcpy(str + size - 1, buf); + size += strlength; } - return buffer; + pclose(file); } - else + return str; +} + +/** + * Read a file completely into a string. + * @param filename Path to the file to read. + * @return Contents of the file. + */ +char * read_file(const char * filename) +{ + if (filename != NULL) { - return NULL; + FILE * file = fopen(filename, "rb"); + return read_from_file(file); } + return NULL; } /** @@ -201,6 +221,21 @@ int parse_int(const char * input, int * result) } /** + * Add the SSH_COMMAND string in front of ssh_key unless it's already there + * because people have seen it being used in ssh_keys_list. + * @param[out] ssh_key_with_command the ssh_key with the command prepended + * if needed + * @param[in] ssh_key a valid ssh key string + */ +int add_ssh_command(char ** ssh_key_with_command, const char * ssh_key) +{ + if (strncmp(SSH_COMMAND, ssh_key, strlen(SSH_COMMAND)) != 0) + return asprintf(ssh_key_with_command, "%s %s", SSH_COMMAND, ssh_key); + else + return asprintf(ssh_key_with_command, "%s", ssh_key); +} + +/* * Check if the given path already exists (as a (special) file or directory). * @param path Path to test. * @return `true` if path exists, `false` otherwise. diff --git a/src/cryptops-api.c b/src/cryptops-api.c index 114850423a3f74cb710a1a3edb661e0f6160b9d7..ffbc915b82a7fb604da6d7c1c47c87a2187ce497 100644 --- a/src/cryptops-api.c +++ b/src/cryptops-api.c @@ -12,6 +12,7 @@ #include <api/encryption_unlock_post.c> #include <api/encryption_keys_put.c> #include <api/ssh_keys_get.c> +#include <api/ssh_keys_post.c> int main(int argc, char ** argv) { @@ -57,6 +58,9 @@ int main(int argc, char ** argv) ulfius_add_endpoint_by_val(&instance, "GET" , PREFIX, "/ssh/keys", 0, &callback_ssh_keys_get, NULL); + ulfius_add_endpoint_by_val(&instance, "POST" , PREFIX, + "/ssh/keys", + 0, &callback_ssh_keys_post, NULL); // Add default endpoint. ulfius_set_default_endpoint(&instance, &callback_default, NULL); @@ -84,7 +88,7 @@ int main(int argc, char ** argv) y_log_message(Y_LOG_LEVEL_DEBUG, "Start %sframework on port %d", ((argc == 4 && strcmp("-secure", argv[1]) == 0) ? "secure " : ""), instance.port); - + // Wait for signal from fifo to quit. y_init_logs("cryptops-api", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "Waiting for fifo signal to quit"); @@ -107,7 +111,7 @@ int main(int argc, char ** argv) sleep(1); y_close_logs(); - + ulfius_stop_framework(&instance); ulfius_clean_instance(&instance); diff --git a/src/includes/settings.h b/src/includes/settings.h index 8035b1024dfa8b91d5fb4c76c4f878f682ad9266..83ae0fab0d5650a1ad746db0d0288b18ae4a6407 100644 --- a/src/includes/settings.h +++ b/src/includes/settings.h @@ -29,3 +29,7 @@ #define AUTHORIZED_KEYS_DIR "/root/.ssh" #define AUTHORIZED_KEYS_PATH AUTHORIZED_KEYS_DIR "/authorized_keys" #define SSH_HOST_KEY_DIR "/dropbear" + +// Ssh authorized_keys settings. +// This string is prepended to new and converted authorized_keys. +#define SSH_COMMAND "command=\"cd / && /usr/bin/cryptops-client\""