1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2015 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/prctl.h>
27 #include "btrfs-util.h"
28 #include "import-job.h"
29 #include "import-common.h"
31 #define FILENAME_ESCAPE "/.#\"\'"
33 int import_find_old_etags(const char *url, const char *image_root, int dt, const char *prefix, const char *suffix, char ***etags) {
34 _cleanup_free_ char *escaped_url = NULL;
35 _cleanup_closedir_ DIR *d = NULL;
36 _cleanup_strv_free_ char **l = NULL;
44 image_root = "/var/lib/machines";
46 escaped_url = xescape(url, FILENAME_ESCAPE);
50 d = opendir(image_root);
52 if (errno == ENOENT) {
60 FOREACH_DIRENT_ALL(de, d, return -errno) {
64 if (de->d_type != DT_UNKNOWN &&
69 a = startswith(de->d_name, prefix);
75 a = startswith(a, escaped_url);
79 a = startswith(a, ".");
84 b = endswith(de->d_name, suffix);
88 b = strchr(de->d_name, 0);
93 u = cunescape_length(a, b - a);
97 if (!http_etag_is_valid(u)) {
102 r = strv_consume(&l, u);
113 int import_make_local_copy(const char *final, const char *image_root, const char *local, bool force_local) {
121 image_root = "/var/lib/machines";
123 p = strappenda(image_root, "/", local);
126 (void) btrfs_subvol_remove(p);
127 (void) rm_rf_dangerous(p, false, true, false);
130 r = btrfs_subvol_snapshot(final, p, false, false);
132 r = copy_tree(final, p, false);
134 return log_error_errno(r, "Failed to copy image: %m");
136 return log_error_errno(r, "Failed to create local image: %m");
138 log_info("Created new local image '%s'.", local);
143 int import_make_read_only_fd(int fd) {
148 /* First, let's make this a read-only subvolume if it refers
150 r = btrfs_subvol_set_read_only_fd(fd, true);
151 if (r == -ENOTTY || r == -ENOTDIR || r == -EINVAL) {
154 /* This doesn't refer to a subvolume, or the file
155 * system isn't even btrfs. In that, case fall back to
160 return log_error_errno(errno, "Failed to stat temporary image: %m");
163 if (fchmod(fd, st.st_mode & 07555) < 0)
164 return log_error_errno(errno, "Failed to chmod() final image: %m");
169 return log_error_errno(r, "Failed to make subvolume read-only: %m");
174 int import_make_read_only(const char *path) {
175 _cleanup_close_ int fd = 1;
177 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
179 return log_error_errno(errno, "Failed to open %s: %m", path);
181 return import_make_read_only_fd(fd);
184 int import_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret) {
185 _cleanup_free_ char *escaped_url = NULL;
192 image_root = "/var/lib/machines";
194 escaped_url = xescape(url, FILENAME_ESCAPE);
199 _cleanup_free_ char *escaped_etag = NULL;
201 escaped_etag = xescape(etag, FILENAME_ESCAPE);
205 path = strjoin(image_root, "/", strempty(prefix), escaped_url, ".", escaped_etag, strempty(suffix), NULL);
207 path = strjoin(image_root, "/", strempty(prefix), escaped_url, strempty(suffix), NULL);
215 int import_make_verification_jobs(
216 ImportJob **ret_checksum_job,
217 ImportJob **ret_signature_job,
221 ImportJobFinished on_finished,
224 _cleanup_(import_job_unrefp) ImportJob *checksum_job = NULL, *signature_job = NULL;
227 assert(ret_checksum_job);
228 assert(ret_signature_job);
230 assert(verify < _IMPORT_VERIFY_MAX);
234 if (verify != IMPORT_VERIFY_NO) {
235 _cleanup_free_ char *checksum_url = NULL;
237 /* Queue job for the SHA256SUMS file for the image */
238 r = import_url_change_last_component(url, "SHA256SUMS", &checksum_url);
242 r = import_job_new(&checksum_job, checksum_url, glue, userdata);
246 checksum_job->on_finished = on_finished;
247 checksum_job->uncompressed_max = checksum_job->compressed_max = 1ULL * 1024ULL * 1024ULL;
250 if (verify == IMPORT_VERIFY_SIGNATURE) {
251 _cleanup_free_ char *signature_url = NULL;
253 /* Queue job for the SHA256SUMS.gpg file for the image. */
254 r = import_url_change_last_component(url, "SHA256SUMS.gpg", &signature_url);
258 r = import_job_new(&signature_job, signature_url, glue, userdata);
262 signature_job->on_finished = on_finished;
263 signature_job->uncompressed_max = signature_job->compressed_max = 1ULL * 1024ULL * 1024ULL;
266 *ret_checksum_job = checksum_job;
267 *ret_signature_job = signature_job;
269 checksum_job = signature_job = NULL;
276 ImportJob *checksum_job,
277 ImportJob *signature_job) {
279 _cleanup_close_pair_ int gpg_pipe[2] = { -1, -1 };
280 _cleanup_free_ char *fn = NULL;
281 _cleanup_close_ int sig_file = -1;
282 const char *p, *line;
283 char sig_file_path[] = "/tmp/sigXXXXXX";
284 _cleanup_sigkill_wait_ pid_t pid = 0;
288 assert(main_job->state == IMPORT_JOB_DONE);
293 assert(main_job->calc_checksum);
294 assert(main_job->checksum);
295 assert(checksum_job->state == IMPORT_JOB_DONE);
297 if (!checksum_job->payload || checksum_job->payload_size <= 0) {
298 log_error("Checksum is empty, cannot verify.");
302 r = import_url_last_component(main_job->url, &fn);
306 if (!filename_is_valid(fn)) {
307 log_error("Cannot verify checksum, could not determine valid server-side file name.");
311 line = strappenda(main_job->checksum, " *", fn, "\n");
313 p = memmem(checksum_job->payload,
314 checksum_job->payload_size,
318 if (!p || (p != (char*) checksum_job->payload && p[-1] != '\n')) {
319 log_error("Checksum did not check out, payload has been tempered with.");
323 log_info("SHA256 checksum of %s is valid.", main_job->url);
328 assert(signature_job->state == IMPORT_JOB_DONE);
330 if (!signature_job->payload || signature_job->payload_size <= 0) {
331 log_error("Signature is empty, cannot verify.");
335 r = pipe2(gpg_pipe, O_CLOEXEC);
337 return log_error_errno(errno, "Failed to create pipe for gpg: %m");
339 sig_file = mkostemp(sig_file_path, O_RDWR);
341 return log_error_errno(errno, "Failed to create temporary file: %m");
343 r = loop_write(sig_file, signature_job->payload, signature_job->payload_size, false);
345 log_error_errno(r, "Failed to write to temporary file: %m");
351 return log_error_errno(errno, "Failed to fork off gpg: %m");
353 const char *cmd[] = {
356 "--no-default-keyring",
357 "--no-auto-key-locate",
358 "--no-auto-check-trustdb",
360 "--trust-model=always",
361 "--keyring=" VENDOR_KEYRING_PATH,
362 NULL, /* maybe user keyring */
364 NULL, /* signature file */
366 NULL /* trailing NULL */
368 unsigned k = ELEMENTSOF(cmd) - 5;
373 reset_all_signal_handlers();
375 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
377 gpg_pipe[1] = safe_close(gpg_pipe[1]);
379 if (dup2(gpg_pipe[0], STDIN_FILENO) != STDIN_FILENO) {
380 log_error_errno(errno, "Failed to dup2() fd: %m");
384 if (gpg_pipe[0] != STDIN_FILENO)
385 gpg_pipe[0] = safe_close(gpg_pipe[0]);
387 null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
389 log_error_errno(errno, "Failed to open /dev/null: %m");
393 if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
394 log_error_errno(errno, "Failed to dup2() fd: %m");
398 if (null_fd != STDOUT_FILENO)
399 null_fd = safe_close(null_fd);
401 /* We add the user keyring only to the command line
402 * arguments, if it's around since gpg fails
404 if (access(USER_KEYRING_PATH, F_OK) >= 0)
405 cmd[k++] = "--keyring=" USER_KEYRING_PATH;
407 cmd[k++] = "--verify";
408 cmd[k++] = sig_file_path;
412 fd_cloexec(STDIN_FILENO, false);
413 fd_cloexec(STDOUT_FILENO, false);
414 fd_cloexec(STDERR_FILENO, false);
416 execvp("gpg", (char * const *) cmd);
417 log_error_errno(errno, "Failed to execute gpg: %m");
421 gpg_pipe[0] = safe_close(gpg_pipe[0]);
423 r = loop_write(gpg_pipe[1], checksum_job->payload, checksum_job->payload_size, false);
425 log_error_errno(r, "Failed to write to pipe: %m");
429 gpg_pipe[1] = safe_close(gpg_pipe[1]);
431 r = wait_for_terminate_and_warn("gpg", pid, true);
436 log_error("Signature verification failed.");
439 log_info("Signature verification succeeded.");
445 unlink(sig_file_path);