diff --git a/src/api/encryption_keys_put.c b/src/api/encryption_keys_put.c new file mode 100644 index 0000000000000000000000000000000000000000..023b639c75c33f7d028d95a61b01862ca758fc3f --- /dev/null +++ b/src/api/encryption_keys_put.c @@ -0,0 +1,85 @@ +/** + * Callback function to change a luks encryption password. + * @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_encryption_keys_put(const struct _u_request * request, + struct _u_response * response, void * user_data) +{ + int r; + + // Read in json request body. + json_t * json_input = ulfius_get_json_body_request(request, NULL); + + // Read (current) password from request. + const char * password; + password = json_string_value(json_object_get(json_input, "password")); + if (password == NULL) + { + return send_simple_response(response, 400, "error", "missing password"); + } + + // Read new password from request. + const char * new_password; + new_password = json_string_value(json_object_get(json_input, + "new-password")); + if (new_password == NULL) + { + return send_simple_response(response, 400, "error", + "missing new password"); + } + + // Read keyslot from request URI. + const char * keyslot_string = u_map_get(request->map_url, "slot"); + if (keyslot_string == NULL) + { + return send_simple_response(response, 500, "error", + "missing url parameter `slot`"); + } + int keyslot; + r = parse_int(keyslot_string, &keyslot); + if (r != 0) + { + printf("invalid url parameter `slot`: %s\n", keyslot_string); + return send_simple_response(response, 500, "error", + "invalid url parameter `slot`"); + } + + // Initialise encrypted container. + struct crypt_device * cd = NULL; + r = container_initialise(&cd, DATA_PARTITION_DEVICE, true); + if (r < 0) + { + crypt_free(cd); + } + if (r != 0) + { + printf("container_initialise failed with status %d\n", r); + return send_simple_response(response, 500, "error", + "initialising encrypted container failed"); + } + + // Add encryption password. + r = crypt_keyslot_change_by_passphrase(cd, keyslot, keyslot, + password, strlen(password), new_password, strlen(new_password)); + + if (r == -1) + { + // Experience learns that -1 is returned when the password is wrong. + return send_simple_response(response, 403, "error", + "incorrect password"); + } + + if (r < 0) + { + // Something else went wrong. + printf("crypt_keyslot_add_by_passphrase failed with status %d\n", r); + return send_simple_response(response, 500, "error", + "error changing password"); + } + + // If we reach this point, apparently everything went well. + return send_simple_response(response, 200, "status", "ok"); +} diff --git a/src/auxiliary.c b/src/auxiliary.c index 6226e2a62e7e782c4c5c97c30be2d4c2d35635f6..797839db2a39488633f758a290907354d1e09241 100644 --- a/src/auxiliary.c +++ b/src/auxiliary.c @@ -149,3 +149,25 @@ void reboot_initrd() // Parent (init) waits. while (1); } + +/** + * Parse an integer written in decimal. + * @param[in] input String to parse. + * @param[out] result Resulting integer, or NULL on failure. + * @return Return code: 0 on success, nonzero on failure. + */ +int parse_int(const char * input, int * result) +{ + if (input[0] == '\0' || isspace((unsigned char) input[0])) + { + return -1; + } + char * end; + long l = strtol(input, &end, 10); + if (*end != '\0') + { + return -1; + } + *result = l; + return 0; +} diff --git a/src/cryptops-api.c b/src/cryptops-api.c index 5c348cf93b2dd418301e9a885fc0276ea2facd67..5d80f1a08928a9dfcc65cb535dbc7e60743ac29b 100644 --- a/src/cryptops-api.c +++ b/src/cryptops-api.c @@ -8,6 +8,7 @@ #include <api/default.c> #include <api/encryption_add.c> #include <api/encryption_unlock.c> +#include <api/encryption_keys_put.c> #include <api/ssh_keys_get.c> int main(int argc, char ** argv) @@ -36,11 +37,17 @@ int main(int argc, char ** argv) // Add api endpoints. bool reboot = false; - ulfius_add_endpoint_by_val(&instance, "POST", PREFIX, "/encryption/add", + ulfius_add_endpoint_by_val(&instance, "POST", PREFIX, + "/encryption/add", 0, &callback_encryption_add, &reboot); - ulfius_add_endpoint_by_val(&instance, "POST", PREFIX, "/encryption/unlock", + ulfius_add_endpoint_by_val(&instance, "POST", PREFIX, + "/encryption/unlock", 0, &callback_encryption_unlock, NULL); - ulfius_add_endpoint_by_val(&instance, "GET" , PREFIX, "/ssh/keys", + ulfius_add_endpoint_by_val(&instance, "PUT" , PREFIX, + "/encryption/keys/:slot", + 0, &callback_encryption_keys_put, NULL); + ulfius_add_endpoint_by_val(&instance, "GET" , PREFIX, + "/ssh/keys", 0, &callback_ssh_keys_get, NULL); // Add default endpoint. diff --git a/src/encryption_functions.c b/src/encryption_functions.c index 2a47b409af7e6f9903f6b6d546ed27fcc1fc5895..1bc128a48732056facee36e187adabbf7ba156cb 100644 --- a/src/encryption_functions.c +++ b/src/encryption_functions.c @@ -3,12 +3,12 @@ * It will not be opened (decrypted) yet, but it does check if the container * seems usable. * @param crypt_device struct to store crypt device context - * @param crypt_device path to the encrypted container + * @param path path to the encrypted container * @param debug whether to print debug messages * @return status code */ static int container_initialise(struct crypt_device ** cd, const char * path, - const bool debug) + const bool debug) { // Check if the device exists. struct stat st = {0}; diff --git a/src/includes/common-includes.h b/src/includes/common-includes.h index aa3f9d62dd4c3d8254f218741125c37320e9bfad..a350af7b16cb20cc8c50b008dfa01073d074e3ef 100644 --- a/src/includes/common-includes.h +++ b/src/includes/common-includes.h @@ -1,5 +1,6 @@ #include <string.h> #include <stdbool.h> +#include <ctype.h> #include <sys/stat.h> #include <sys/sysinfo.h> #include <sys/ioctl.h>