diff --git a/src/api/encryption_get.c b/src/api/encryption_get.c new file mode 100644 index 0000000000000000000000000000000000000000..cc64e6c214514d323a2befa0d0ac33e37da1ee42 --- /dev/null +++ b/src/api/encryption_get.c @@ -0,0 +1,65 @@ +/** + * Callback function that shows the current encryption status (encrypted or + * unencrypted). + * + * Example output: + * {"encryption-status":"encrypted"} + * + * @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_get(const struct _u_request * request, + struct _u_response * response, void * user_data) +{ + bool encrypted; + bool * can_encrypt_nullable = NULL; + bool can_encrypt = true; + json_t * messages = json_array(); + + if (path_exists(DATA_PARTITION_DEVICE) && + is_encrypted_device(DATA_PARTITION_DEVICE)) + { + encrypted = true; + } + else + { + encrypted = false; + can_encrypt_nullable = &can_encrypt; + + // Mount the filesystem on the unencrypted device. + int r = temporary_mount(ROOT_DEVICE, UNENCRYPTED_MOUNTPOINT, + FILESYSTEM_TYPE); + if (r != 0) + { + printf("mounting root device failed: return code %d\n", r); + return send_simple_response(response, 500, "error", + "mounting root device failed"); + } + bool fits = filesystem_fits_in_memory(UNENCRYPTED_MOUNTPOINT, + MEMORY_USAGE); + umount(UNENCRYPTED_MOUNTPOINT); + if (! fits) + { + can_encrypt = false; + json_array_append_new(messages, json_string( + "existing files do not fit in memory")); + } + } + + json_t * json_body = NULL; + json_body = json_object(); + + json_object_set_new(json_body, "encrypted", + encrypted ? json_true() : json_false()); + + json_object_set_new(json_body, "can-encrypt", + can_encrypt_nullable == NULL ? json_null() : + (can_encrypt ? json_true() : json_false())); + json_object_set_new(json_body, "messages", messages); + + ulfius_set_json_body_response(response, 200, json_body); + json_decref(json_body); + return U_CALLBACK_CONTINUE; +} diff --git a/src/api/encryption_init.c b/src/api/encryption_init_post.c similarity index 93% rename from src/api/encryption_init.c rename to src/api/encryption_init_post.c index 17b1a0b4211f831c0d9351ba3ac63cd4a2c83d28..14d6742dc34a04fdc104cd80352ef30b09840bd8 100644 --- a/src/api/encryption_init.c +++ b/src/api/encryption_init_post.c @@ -27,7 +27,7 @@ * @param[in] user_data extra data to pass between handler and main thread * @return internal status code */ -int callback_encryption_init(const struct _u_request * request, +int callback_encryption_init_post(const struct _u_request * request, struct _u_response * response, void * user_data) { bool * reboot = (bool *)user_data; @@ -43,7 +43,9 @@ int callback_encryption_init(const struct _u_request * request, } // Check if the device isn't already encrypted. - if (is_encrypted_device(ROOT_DEVICE)) + // Actually we check if the device has any partitions; if so, we're not in + // the expected situation of an unpartitioned unencrypted root device. + if (path_exists(INFO_PARTITION_DEVICE)) { // The device is already encrypted; we don't want to encrypt it again. return send_simple_response(response, 500, "error", @@ -61,22 +63,9 @@ int callback_encryption_init(const struct _u_request * request, } // Determine the filesystem usage of the device to be encrypted. - unsigned long size = filesystem_usage(UNENCRYPTED_MOUNTPOINT); - if (size < 0) - { - // Something went wrong in determining the filesystem usage. - printf("determining filesystem usage failed: return code %lu\n", size); - return send_simple_response(response, 500, "error", - "determining filesystem usage failed"); - } - printf("root device usage: %lu bytes\n", size); - - // Determine the available memory. - unsigned long memory = available_memory(); - - double projected_usage = (double)size / (double)memory; - printf("projected memory usage: %.3f\n", projected_usage); - if (projected_usage > MEMORY_USAGE) + bool fits = filesystem_fits_in_memory(UNENCRYPTED_MOUNTPOINT, + MEMORY_USAGE); + if (! fits) { // Projected memory usage is really high, so abort. return send_simple_response(response, 500, "error", diff --git a/src/api/encryption_unlock.c b/src/api/encryption_unlock_post.c similarity index 95% rename from src/api/encryption_unlock.c rename to src/api/encryption_unlock_post.c index fd20287806e66b2579528fae256760feaf02681d..83340837691ef09686d9929c74e996571247b5b9 100644 --- a/src/api/encryption_unlock.c +++ b/src/api/encryption_unlock_post.c @@ -6,7 +6,7 @@ * @param[in] user_data extra data to pass between main thread and callbacks * @return internal status code */ -int callback_encryption_unlock(const struct _u_request * request, +int callback_encryption_unlock_post(const struct _u_request * request, struct _u_response * response, void * user_data) { json_t * json_input = ulfius_get_json_body_request(request, NULL); diff --git a/src/auxiliary.c b/src/auxiliary.c index 127133206459b98ee9bf0ac3fe6693c727917df1..f85f56583720f20d4082a66b9a626bbba8419e40 100644 --- a/src/auxiliary.c +++ b/src/auxiliary.c @@ -131,6 +131,34 @@ unsigned long filesystem_usage(const char * path) return (s.f_blocks - s.f_bfree) * s.f_bsize; } +/** + * Check if the files on the given filesystem would fit into memory. + * @param path Path of the mounted filesystem. + * @param safety_margin Fraction (between zero and one) of free memory to + deem available for containing the files. + * @return Whether the filesystem seems to fit into memory. + */ +bool filesystem_fits_in_memory(const char * path, double safety_margin) +{ + // Determine the filesystem usage of the device to be encrypted. + unsigned long size = filesystem_usage(path); + if (size < 0) + { + // Something went wrong in determining the filesystem usage. + // Return false as a precaution. + printf("Determining file system usage failed (size: %lu)\n", size); + return false; + } + printf("file system usage: %lu bytes\n", size); + + // Determine the available memory. + unsigned long memory = available_memory(); + + double projected_usage = (double)size / (double)memory; + printf("projected memory usage: %.3f\n", projected_usage); + return (projected_usage <= safety_margin); +} + /** * Mount a filesystem; create the mount target if it doesn't exist. * @param device_path Path to the device to mount. @@ -206,3 +234,14 @@ int add_ssh_command(char ** ssh_key_with_command, const char * 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. + */ +bool path_exists(const char * path) +{ + struct stat st = {0}; + return (stat(path, &st) == 0); +} diff --git a/src/cryptops-api.c b/src/cryptops-api.c index faaf253e4f8d3df0db6f20b0a6eaba4e17726663..0c6ed52aaa90e2a2d6684b92d8080b98ef401478 100644 --- a/src/cryptops-api.c +++ b/src/cryptops-api.c @@ -6,8 +6,9 @@ #include <auxiliary.c> #include <encryption_functions.c> #include <api/default.c> -#include <api/encryption_init.c> -#include <api/encryption_unlock.c> +#include <api/encryption_get.c> +#include <api/encryption_init_post.c> +#include <api/encryption_unlock_post.c> #include <api/encryption_keys_put.c> #include <api/ssh_keys_get.c> #include <api/ssh_keys_post.c> @@ -38,12 +39,15 @@ int main(int argc, char ** argv) // Add api endpoints. bool reboot = false; + ulfius_add_endpoint_by_val(&instance, "GET" , PREFIX, + "/encryption", + 0, &callback_encryption_get, NULL); ulfius_add_endpoint_by_val(&instance, "POST", PREFIX, "/encryption/init", - 0, &callback_encryption_init, &reboot); + 0, &callback_encryption_init_post, &reboot); ulfius_add_endpoint_by_val(&instance, "POST", PREFIX, "/encryption/unlock", - 0, &callback_encryption_unlock, NULL); + 0, &callback_encryption_unlock_post, NULL); ulfius_add_endpoint_by_val(&instance, "PUT" , PREFIX, "/encryption/keys/:slot", 0, &callback_encryption_keys_put, NULL); diff --git a/src/encryption_functions.c b/src/encryption_functions.c index 1bc128a48732056facee36e187adabbf7ba156cb..9bbceecd4fa95ce917855f20a35eecadf50ed392 100644 --- a/src/encryption_functions.c +++ b/src/encryption_functions.c @@ -11,8 +11,7 @@ static int container_initialise(struct crypt_device ** cd, const char * path, const bool debug) { // Check if the device exists. - struct stat st = {0}; - if (stat(path, &st) == -1) + if (! path_exists(path)) { printf("device does not exist: %s.\n", path); return 1;