From fa6727f564debe32bc91cf1b18cabd19d489caef Mon Sep 17 00:00:00 2001
From: Arie Peterson <arie@greenhost.nl>
Date: Wed, 21 Jun 2017 14:36:12 +0200
Subject: [PATCH] Resolve discussions of !3

---
 src/api/encryption_add.c   | 40 ++++++++++++++++++++++++++++++-----
 src/auxiliary.c            |  8 +++++--
 src/encryption_functions.c | 43 ++++++++++++++++++++------------------
 3 files changed, 64 insertions(+), 27 deletions(-)

diff --git a/src/api/encryption_add.c b/src/api/encryption_add.c
index 57132fb..554300d 100644
--- a/src/api/encryption_add.c
+++ b/src/api/encryption_add.c
@@ -1,5 +1,17 @@
 /**
  * Callback function for encrypting an unencrypted device.
+ * It proceeds as follows:
+ * 1. check if the device isn't already encrypted;
+ * 2. mount the unencrypted device;
+ * 3. determine the total size of the files on the device, and guess if they
+ *    will fit into memory;
+ * 4. rsync all files from the unencrypted device to memory;
+ * 5. unmount the unencrypted device;
+ * 6. initialise a new encrypted container on the same device, replacing the
+      unencrypted contents, and unlock it for use;
+ * 7. create a new filesystem inside the new container, and mount it;
+ * 8. rsync all files back from memory to this newly encrypted device;
+ * 9. unmount the new filesystem, and lock the encrypted container.
  * @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
@@ -20,25 +32,32 @@ int callback_encryption_add(const struct _u_request * request,
     }
  
     // Check if the device isn't already encrypted.
-    bool device_encrypted = is_encrypted_device(CONTAINER_DEVICE);
-    if (device_encrypted)
+    if (is_encrypted_device(CONTAINER_DEVICE))
     {
         // The device is already encrypted; we don't want to encrypt it again.
         return send_simple_response(response, 500, "error",
            "already encrypted");
     }
 
-    // Create temporary mountpoint.
+    // Mount the filesystem on the unencrypted device.
     r = temporary_mount(CONTAINER_DEVICE, UNENCRYPTED_MOUNTPOINT,
         FILESYSTEM_TYPE);
     if (r != 0)
     {
+        printf("mounting root disk failed: return code %d", r);
         return send_simple_response(response, 500, "error",
            "mounting root disk failed");
     }
 
     // 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", size);
+        return send_simple_response(response, 500, "error",
+           "determining filesystem usage failed");
+    }
     printf("root disk usage: %lu bytes\n", size);
 
     // Determine the available memory.
@@ -60,8 +79,10 @@ int callback_encryption_add(const struct _u_request * request,
     r = system(command);
     if(r != 0)
     {
+        printf("copying rootdisk contents into memory failed: return code %d",
+            r);
         return send_simple_response(response, 500, "error",
-           "copying rootdisk contents into memory failed");
+            "copying rootdisk contents into memory failed");
     }
 
     // Unmount unencrypted device.
@@ -69,15 +90,17 @@ int callback_encryption_add(const struct _u_request * request,
     r = umount(UNENCRYPTED_MOUNTPOINT);
     if (r != 0)
     {
+        printf("unmounting encrypted device failed: return code %d", r);
         return send_simple_response(response, 500, "error",
            "unmounting unencrypted disk failed");
     }
 
     // Initialise encrypted container, overwriting existing device.
-    printf("creating encrypted device at %s\n", CONTAINER_DEVICE);
+    printf("creating encrypted container at %s\n", CONTAINER_DEVICE);
     r = create_encrypted_device(CONTAINER_DEVICE, password);
     if(r != 0)
     {
+        printf("creating encrypted container failed: return code %d", r);
         return send_simple_response(response, 500, "error",
            "creating encryption container failed");
     }
@@ -87,6 +110,7 @@ int callback_encryption_add(const struct _u_request * request,
     r = encryption_unlock(CONTAINER_DEVICE, MAPPED_DEVICE_NAME, password);
     if(r != 0)
     {
+        printf("unlocking encrypted container failed: return code %d", r);
         return send_simple_response(response, 500, "error",
            "unlocking new encryption container failed");
     }
@@ -98,6 +122,7 @@ int callback_encryption_add(const struct _u_request * request,
     r = system(command);
     if(r != 0)
     {
+        printf("creating filesystem failed: return code %d", r);
         return send_simple_response(response, 500, "error",
            "creating filesystem inside encrypted container failed");
     }
@@ -108,6 +133,7 @@ int callback_encryption_add(const struct _u_request * request,
         FILESYSTEM_TYPE);
     if (r != 0)
     {
+        printf("mounting encrypted disk failed: return code %d", r);
         return send_simple_response(response, 500, "error",
            "mounting encrypted root disk failed");
     }
@@ -119,6 +145,8 @@ int callback_encryption_add(const struct _u_request * request,
     r = system(command);
     if(r != 0)
     {
+        printf("copying from memory to encrypted disk failed: return code %d",
+            r);
         return send_simple_response(response, 500, "error",
            "copying rootdisk contents from memory failed");
     }
@@ -128,6 +156,7 @@ int callback_encryption_add(const struct _u_request * request,
     r = umount(ENCRYPTED_MOUNTPOINT);
     if (r != 0)
     {
+        printf("unmounting encrypted disk failed: return code %d", r);
         return send_simple_response(response, 500, "error",
            "unmounting encrypted disk failed");
     }
@@ -137,6 +166,7 @@ int callback_encryption_add(const struct _u_request * request,
     r = encryption_lock(MAPPED_DEVICE_NAME);
     if(r != 0)
     {
+        printf("locking encrypted container failed: return code %d", r);
         return send_simple_response(response, 500, "error",
            "locking container failed");
     }
diff --git a/src/auxiliary.c b/src/auxiliary.c
index 722b358..fcbcde6 100644
--- a/src/auxiliary.c
+++ b/src/auxiliary.c
@@ -98,12 +98,16 @@ unsigned long available_memory()
 /**
  * Determine the usage of the given filesystem.
  * @param  path Path of the mounted filesystem.
- * @return      Number of bytes used.
+ * @return      Number of bytes used, or -1 in case of failure.
  */
 unsigned long filesystem_usage(const char * path)
 {
     struct statvfs s;
-    statvfs(path, &s);
+    int r = statvfs(path, &s);
+    if (r != 0)
+    {
+        return -1;
+    }
     return (s.f_blocks - s.f_bfree) * s.f_bsize;
 }
 
diff --git a/src/encryption_functions.c b/src/encryption_functions.c
index 313b65c..7f1f842 100644
--- a/src/encryption_functions.c
+++ b/src/encryption_functions.c
@@ -4,16 +4,21 @@
  * seems usable.
  * @param crypt_device struct to store crypt device context
  * @param crypt_device 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)
+static int container_initialise(struct crypt_device ** cd, const char * path,
+     const bool debug)
 {
     // Let LUKS initialise the encrypted device.
     int r = crypt_init(cd, path);
     if (r < 0)
     {
-        printf("crypt_init() failed for %s.\n", path);
-        printf("status: %d.\n", r);
+        if (debug)
+        {
+            printf("crypt_init() failed for %s.\n", path);
+            printf("status: %d.\n", r);
+        }
         return r;
     }
 
@@ -21,8 +26,11 @@ static int container_initialise(struct crypt_device **cd, const char *path)
     r = crypt_load(*cd, CRYPT_LUKS1, NULL);
     if (r < 0)
     {
-        printf("crypt_load() failed on device %s.\n",
-            crypt_get_device_name(*cd));
+        if (debug)
+        {
+            printf("crypt_load() failed on device %s.\n",
+                crypt_get_device_name(*cd));
+        }
     }
 
     return r;
@@ -32,18 +40,13 @@ static int container_initialise(struct crypt_device **cd, const char *path)
  * Check if the given device is actually an encrypted container.
  * @param path path to the encrypted container
  */
-static bool is_encrypted_device (const char *path)
+static bool is_encrypted_device(const char * path)
 {
     // Let LUKS initialise the encrypted device.
-    struct crypt_device *cd;
-    int r = container_initialise(&cd, path);
+    struct crypt_device * cd;
+    int r = container_initialise(&cd, path, false);
     crypt_free(cd);
-    if (r < 0)
-    {
-        return false;
-    }
-
-    return true;
+    return (r >= 0);
 }
 
 /**
@@ -54,12 +57,12 @@ static bool is_encrypted_device (const char *path)
  * @param password    encryption password of the container
  * @return            status code
  */
-static int encryption_unlock(const char *path, const char *device_name,
-    const char *password)
+static int encryption_unlock(const char * path, const char * device_name,
+    const char * password)
 {
     // Let LUKS initialise the encrypted device.
-    struct crypt_device *cd;
-    int r = container_initialise(&cd, path);
+    struct crypt_device * cd;
+    int r = container_initialise(&cd, path, true);
     if (r < 0)
     {
         printf("crypt_load() failed on device %s.\n",
@@ -92,9 +95,9 @@ static int encryption_unlock(const char *path, const char *device_name,
  * @param device_name name of the mapping
  * @return            status code
  */
-static int encryption_lock(const char *device_name)
+static int encryption_lock(const char * device_name)
 {
-    struct crypt_device *cd;
+    struct crypt_device * cd;
     int r;
 
     r = crypt_init_by_name(&cd, device_name);
-- 
GitLab