chiark / gitweb /
import: add support for gpg2 for verifying imported images
[elogind.git] / src / import / import-common.c
index 395f998f16b6bd3ffb2693bae5f249e3e0d1a91a..f10a453eed8693e5e236821b8248e6f00527c49a 100644 (file)
@@ -25,6 +25,7 @@
 #include "strv.h"
 #include "copy.h"
 #include "btrfs-util.h"
+#include "capability.h"
 #include "import-job.h"
 #include "import-common.h"
 
@@ -120,7 +121,7 @@ int import_make_local_copy(const char *final, const char *image_root, const char
         if (!image_root)
                 image_root = "/var/lib/machines";
 
-        p = strappenda(image_root, "/", local);
+        p = strjoina(image_root, "/", local);
 
         if (force_local) {
                 (void) btrfs_subvol_remove(p);
@@ -280,8 +281,9 @@ int import_verify(
         _cleanup_free_ char *fn = NULL;
         _cleanup_close_ int sig_file = -1;
         const char *p, *line;
-        char sig_file_path[] = "/tmp/sigXXXXXX";
+        char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX";
         _cleanup_sigkill_wait_ pid_t pid = 0;
+        bool gpg_home_created = false;
         int r;
 
         assert(main_job);
@@ -308,7 +310,7 @@ int import_verify(
                 return -EBADMSG;
         }
 
-        line = strappenda(main_job->checksum, " *", fn, "\n");
+        line = strjoina(main_job->checksum, " *", fn, "\n");
 
         p = memmem(checksum_job->payload,
                    checksum_job->payload_size,
@@ -346,6 +348,13 @@ int import_verify(
                 goto finish;
         }
 
+        if (!mkdtemp(gpg_home)) {
+                r = log_error_errno(errno, "Failed to create tempory home for gpg: %m");
+                goto finish;
+        }
+
+        gpg_home_created = true;
+
         pid = fork();
         if (pid < 0)
                 return log_error_errno(errno, "Failed to fork off gpg: %m");
@@ -358,14 +367,14 @@ int import_verify(
                         "--no-auto-check-trustdb",
                         "--batch",
                         "--trust-model=always",
-                        "--keyring=" VENDOR_KEYRING_PATH,
-                        NULL, /* maybe user keyring */
+                        NULL, /* --homedir=  */
+                        NULL, /* --keyring= */
                         NULL, /* --verify */
                         NULL, /* signature file */
                         NULL, /* dash */
                         NULL  /* trailing NULL */
                 };
-                unsigned k = ELEMENTSOF(cmd) - 5;
+                unsigned k = ELEMENTSOF(cmd) - 6;
                 int null_fd;
 
                 /* Child */
@@ -398,11 +407,15 @@ int import_verify(
                 if (null_fd != STDOUT_FILENO)
                         null_fd = safe_close(null_fd);
 
+                cmd[k++] = strjoina("--homedir=", gpg_home);
+
                 /* We add the user keyring only to the command line
                  * arguments, if it's around since gpg fails
                  * otherwise. */
                 if (access(USER_KEYRING_PATH, F_OK) >= 0)
                         cmd[k++] = "--keyring=" USER_KEYRING_PATH;
+                else
+                        cmd[k++] = "--keyring=" VENDOR_KEYRING_PATH;
 
                 cmd[k++] = "--verify";
                 cmd[k++] = sig_file_path;
@@ -413,6 +426,7 @@ int import_verify(
                 fd_cloexec(STDOUT_FILENO, false);
                 fd_cloexec(STDERR_FILENO, false);
 
+                execvp("gpg2", (char * const *) cmd);
                 execvp("gpg", (char * const *) cmd);
                 log_error_errno(errno, "Failed to execute gpg: %m");
                 _exit(EXIT_FAILURE);
@@ -444,5 +458,88 @@ finish:
         if (sig_file >= 0)
                 unlink(sig_file_path);
 
+        if (gpg_home_created)
+                rm_rf_dangerous(gpg_home, false, true, false);
+
+        return r;
+}
+
+int import_fork_tar(const char *path, pid_t *ret) {
+        _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
+        pid_t pid;
+        int r;
+
+        assert(path);
+        assert(ret);
+
+        if (pipe2(pipefd, O_CLOEXEC) < 0)
+                return log_error_errno(errno, "Failed to create pipe for tar: %m");
+
+        pid = fork();
+        if (pid < 0)
+                return log_error_errno(errno, "Failed to fork off tar: %m");
+
+        if (pid == 0) {
+                int null_fd;
+                uint64_t retain =
+                        (1ULL << CAP_CHOWN) |
+                        (1ULL << CAP_FOWNER) |
+                        (1ULL << CAP_FSETID) |
+                        (1ULL << CAP_MKNOD) |
+                        (1ULL << CAP_SETFCAP) |
+                        (1ULL << CAP_DAC_OVERRIDE);
+
+                /* Child */
+
+                reset_all_signal_handlers();
+                reset_signal_mask();
+                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
+
+                pipefd[1] = safe_close(pipefd[1]);
+
+                if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
+                        log_error_errno(errno, "Failed to dup2() fd: %m");
+                        _exit(EXIT_FAILURE);
+                }
+
+                if (pipefd[0] != STDIN_FILENO)
+                        pipefd[0] = safe_close(pipefd[0]);
+
+                null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
+                if (null_fd < 0) {
+                        log_error_errno(errno, "Failed to open /dev/null: %m");
+                        _exit(EXIT_FAILURE);
+                }
+
+                if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
+                        log_error_errno(errno, "Failed to dup2() fd: %m");
+                        _exit(EXIT_FAILURE);
+                }
+
+                if (null_fd != STDOUT_FILENO)
+                        null_fd = safe_close(null_fd);
+
+                fd_cloexec(STDIN_FILENO, false);
+                fd_cloexec(STDOUT_FILENO, false);
+                fd_cloexec(STDERR_FILENO, false);
+
+                if (unshare(CLONE_NEWNET) < 0)
+                        log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
+
+                r = capability_bounding_set_drop(~retain, true);
+                if (r < 0)
+                        log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
+
+                execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", NULL);
+                log_error_errno(errno, "Failed to execute tar: %m");
+                _exit(EXIT_FAILURE);
+        }
+
+        pipefd[0] = safe_close(pipefd[0]);
+        r = pipefd[1];
+        pipefd[1] = -1;
+
+        *ret = pid;
+
         return r;
 }