From e84daa3c86fd0d54a47ec72517fbcf79b355c958 Mon Sep 17 00:00:00 2001
From: Maarten de Waard <maarten@greenhost.nl>
Date: Wed, 12 Jul 2017 18:06:33 +0200
Subject: [PATCH] initial untested work on ssh_keys_post function

---
 share/restrict_command.sed |  3 ++
 src/api/ssh_keys_post.c    | 68 ++++++++++++++++++++++++++++++++++++++
 src/auxiliary.c            | 45 ++++++++++++++-----------
 src/cryptops-api.c         | 10 ++++--
 src/includes/settings.h    |  5 ++-
 5 files changed, 108 insertions(+), 23 deletions(-)
 create mode 100644 share/restrict_command.sed
 create mode 100644 src/api/ssh_keys_post.c

diff --git a/share/restrict_command.sed b/share/restrict_command.sed
new file mode 100644
index 0000000..9b8500c
--- /dev/null
+++ b/share/restrict_command.sed
@@ -0,0 +1,3 @@
+# Usage: echo "blablabla bia" | sed -rf etc/restrictCommand.sed
+/^#/d
+s@^(agent-forwarding|cert-authority|command="[^"]*"|environment="[^"]*"|from="[^"]*"|no-agent-forwarding|no-port-forwarding|no-pty|no-user-rc|no-X11-forwarding|permitopen="[^"]*"|port-forwarding|principals="[^"]*"|pty|restrict|tunnel="[^"]*"|user-rc|X11-forwarding|,)* *@command="cd / \&\& /usr/bin/cryptops-client" @
diff --git a/src/api/ssh_keys_post.c b/src/api/ssh_keys_post.c
new file mode 100644
index 0000000..f579496
--- /dev/null
+++ b/src/api/ssh_keys_post.c
@@ -0,0 +1,68 @@
+/**
+ * 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 reading 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");
+    }
+
+    // Call cat to append the command correctly:
+    char * command = NULL;
+    asprintf(&command, "echo %s | sed -rf %s", ssh_key, RESTRICT_COMMAND_PATH);
+    FILE *sed_output = popen(command, "r");
+
+    if (!sed_output)
+    {
+        return send_simple_response(response, 500, "error", "Internal error while handling ssh-key");
+    }
+
+    // Get the output from sed
+    ssh_key = read_from_file(sed_output);
+
+    if(!ssh_key)
+    {
+        return send_simple_response(response, 500, "error", "Internal error while converting ssh-key");
+    }
+
+    // Write SSH key to file
+    fprintf(authorized_keys, ssh_key);
+    fclose(authorized_keys);
+
+    return send_simple_response(response, 200, "status", "ok");
+}
+
diff --git a/src/auxiliary.c b/src/auxiliary.c
index 797839d..1a0b9b6 100644
--- a/src/auxiliary.c
+++ b/src/auxiliary.c
@@ -18,30 +18,37 @@ void stop_server()
  */
 char * read_file(const char * filename)
 {
-    char * buffer = NULL;
-    long length;
-    FILE * file = fopen(filename, "rb");
     if (filename != NULL)
     {
-        if (file)
-        {
-            fseek(file, 0, SEEK_END);
-            length = ftell(file);
-            fseek(file, 0, SEEK_SET);
-            buffer = o_malloc(length + 1);
-            if (buffer)
-            {
-                fread(buffer, 1, length, file);
-            }
-            buffer[length] = '\0';
-            fclose (file);
-        }
-        return buffer;
+        FILE * file = fopen(filename, "rb");
+        return read_from_file(file);
     }
-    else
+    return NULL;
+}
+
+/**
+ * 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_from_file(const FILE file)
+{
+    long length;
+    char * buffer = NULL;
+    if (file)
     {
-        return NULL;
+        fseek(file, 0, SEEK_END);
+        length = ftell(file);
+        fseek(file, 0, SEEK_SET);
+        buffer = o_malloc(length + 1);
+        if (buffer)
+        {
+            fread(buffer, 1, length, file);
+        }
+        buffer[length] = '\0';
+        fclose (file);
     }
+    return buffer;
 }
 
 /**
diff --git a/src/cryptops-api.c b/src/cryptops-api.c
index 5b1e102..faaf253 100644
--- a/src/cryptops-api.c
+++ b/src/cryptops-api.c
@@ -10,6 +10,7 @@
 #include <api/encryption_unlock.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)
 {
@@ -49,6 +50,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);
@@ -76,7 +80,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");
@@ -93,9 +97,9 @@ int main(int argc, char ** argv)
         y_log_message(Y_LOG_LEVEL_DEBUG, "Error starting framework");
     }
     y_log_message(Y_LOG_LEVEL_DEBUG, "End framework");
-    
+
     y_close_logs();
-    
+
     ulfius_stop_framework(&instance);
     ulfius_clean_instance(&instance);
 
diff --git a/src/includes/settings.h b/src/includes/settings.h
index 8352c51..d9e98d5 100644
--- a/src/includes/settings.h
+++ b/src/includes/settings.h
@@ -14,4 +14,7 @@
 #define TMP_LOCATION "/tmp/" MAPPED_DEVICE_NAME
 #define AUTHORIZED_KEYS_DIR "/root/.ssh"
 #define AUTHORIZED_KEYS_PATH AUTHORIZED_KEYS_DIR "/authorized_keys"
-#define SSH_HOST_KEY_DIR "/dropbear"
\ No newline at end of file
+#define SSH_HOST_KEY_DIR "/dropbear"
+// FIXME: This means that we need to add copying this script to the initrd to
+// the deploy script
+#define RESTRICT_COMMAND_PATH "/etc/cryptops-api/restrict_command.sed"
-- 
GitLab