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 "capability.h"
30 #include "pull-common.h"
32 #define FILENAME_ESCAPE "/.#\"\'"
34 int pull_find_old_etags(const char *url, const char *image_root, int dt, const char *prefix, const char *suffix, char ***etags) {
35 _cleanup_free_ char *escaped_url = NULL;
36 _cleanup_closedir_ DIR *d = NULL;
37 _cleanup_strv_free_ char **l = NULL;
45 image_root = "/var/lib/machines";
47 escaped_url = xescape(url, FILENAME_ESCAPE);
51 d = opendir(image_root);
53 if (errno == ENOENT) {
61 FOREACH_DIRENT_ALL(de, d, return -errno) {
65 if (de->d_type != DT_UNKNOWN &&
70 a = startswith(de->d_name, prefix);
76 a = startswith(a, escaped_url);
80 a = startswith(a, ".");
85 b = endswith(de->d_name, suffix);
89 b = strchr(de->d_name, 0);
94 u = cunescape_length(a, b - a);
98 if (!http_etag_is_valid(u)) {
103 r = strv_consume(&l, u);
114 int pull_make_local_copy(const char *final, const char *image_root, const char *local, bool force_local) {
122 image_root = "/var/lib/machines";
124 p = strjoina(image_root, "/", local);
127 (void) btrfs_subvol_remove(p);
128 (void) rm_rf_dangerous(p, false, true, false);
131 r = btrfs_subvol_snapshot(final, p, false, false);
133 r = copy_tree(final, p, false);
135 return log_error_errno(r, "Failed to copy image: %m");
137 return log_error_errno(r, "Failed to create local image: %m");
139 log_info("Created new local image '%s'.", local);
144 int pull_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret) {
145 _cleanup_free_ char *escaped_url = NULL;
152 image_root = "/var/lib/machines";
154 escaped_url = xescape(url, FILENAME_ESCAPE);
159 _cleanup_free_ char *escaped_etag = NULL;
161 escaped_etag = xescape(etag, FILENAME_ESCAPE);
165 path = strjoin(image_root, "/", strempty(prefix), escaped_url, ".", escaped_etag, strempty(suffix), NULL);
167 path = strjoin(image_root, "/", strempty(prefix), escaped_url, strempty(suffix), NULL);
175 int pull_make_verification_jobs(
176 PullJob **ret_checksum_job,
177 PullJob **ret_signature_job,
181 PullJobFinished on_finished,
184 _cleanup_(pull_job_unrefp) PullJob *checksum_job = NULL, *signature_job = NULL;
187 assert(ret_checksum_job);
188 assert(ret_signature_job);
190 assert(verify < _IMPORT_VERIFY_MAX);
194 if (verify != IMPORT_VERIFY_NO) {
195 _cleanup_free_ char *checksum_url = NULL;
197 /* Queue job for the SHA256SUMS file for the image */
198 r = import_url_change_last_component(url, "SHA256SUMS", &checksum_url);
202 r = pull_job_new(&checksum_job, checksum_url, glue, userdata);
206 checksum_job->on_finished = on_finished;
207 checksum_job->uncompressed_max = checksum_job->compressed_max = 1ULL * 1024ULL * 1024ULL;
210 if (verify == IMPORT_VERIFY_SIGNATURE) {
211 _cleanup_free_ char *signature_url = NULL;
213 /* Queue job for the SHA256SUMS.gpg file for the image. */
214 r = import_url_change_last_component(url, "SHA256SUMS.gpg", &signature_url);
218 r = pull_job_new(&signature_job, signature_url, glue, userdata);
222 signature_job->on_finished = on_finished;
223 signature_job->uncompressed_max = signature_job->compressed_max = 1ULL * 1024ULL * 1024ULL;
226 *ret_checksum_job = checksum_job;
227 *ret_signature_job = signature_job;
229 checksum_job = signature_job = NULL;
236 PullJob *checksum_job,
237 PullJob *signature_job) {
239 _cleanup_close_pair_ int gpg_pipe[2] = { -1, -1 };
240 _cleanup_free_ char *fn = NULL;
241 _cleanup_close_ int sig_file = -1;
242 const char *p, *line;
243 char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX";
244 _cleanup_sigkill_wait_ pid_t pid = 0;
245 bool gpg_home_created = false;
249 assert(main_job->state == PULL_JOB_DONE);
254 assert(main_job->calc_checksum);
255 assert(main_job->checksum);
256 assert(checksum_job->state == PULL_JOB_DONE);
258 if (!checksum_job->payload || checksum_job->payload_size <= 0) {
259 log_error("Checksum is empty, cannot verify.");
263 r = import_url_last_component(main_job->url, &fn);
267 if (!filename_is_valid(fn)) {
268 log_error("Cannot verify checksum, could not determine valid server-side file name.");
272 line = strjoina(main_job->checksum, " *", fn, "\n");
274 p = memmem(checksum_job->payload,
275 checksum_job->payload_size,
279 if (!p || (p != (char*) checksum_job->payload && p[-1] != '\n')) {
280 log_error("Checksum did not check out, payload has been tempered with.");
284 log_info("SHA256 checksum of %s is valid.", main_job->url);
289 assert(signature_job->state == PULL_JOB_DONE);
291 if (!signature_job->payload || signature_job->payload_size <= 0) {
292 log_error("Signature is empty, cannot verify.");
296 r = pipe2(gpg_pipe, O_CLOEXEC);
298 return log_error_errno(errno, "Failed to create pipe for gpg: %m");
300 sig_file = mkostemp(sig_file_path, O_RDWR);
302 return log_error_errno(errno, "Failed to create temporary file: %m");
304 r = loop_write(sig_file, signature_job->payload, signature_job->payload_size, false);
306 log_error_errno(r, "Failed to write to temporary file: %m");
310 if (!mkdtemp(gpg_home)) {
311 r = log_error_errno(errno, "Failed to create tempory home for gpg: %m");
315 gpg_home_created = true;
319 return log_error_errno(errno, "Failed to fork off gpg: %m");
321 const char *cmd[] = {
324 "--no-default-keyring",
325 "--no-auto-key-locate",
326 "--no-auto-check-trustdb",
328 "--trust-model=always",
329 NULL, /* --homedir= */
330 NULL, /* --keyring= */
332 NULL, /* signature file */
334 NULL /* trailing NULL */
336 unsigned k = ELEMENTSOF(cmd) - 6;
341 reset_all_signal_handlers();
343 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
345 gpg_pipe[1] = safe_close(gpg_pipe[1]);
347 if (dup2(gpg_pipe[0], STDIN_FILENO) != STDIN_FILENO) {
348 log_error_errno(errno, "Failed to dup2() fd: %m");
352 if (gpg_pipe[0] != STDIN_FILENO)
353 gpg_pipe[0] = safe_close(gpg_pipe[0]);
355 null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
357 log_error_errno(errno, "Failed to open /dev/null: %m");
361 if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
362 log_error_errno(errno, "Failed to dup2() fd: %m");
366 if (null_fd != STDOUT_FILENO)
367 null_fd = safe_close(null_fd);
369 cmd[k++] = strjoina("--homedir=", gpg_home);
371 /* We add the user keyring only to the command line
372 * arguments, if it's around since gpg fails
374 if (access(USER_KEYRING_PATH, F_OK) >= 0)
375 cmd[k++] = "--keyring=" USER_KEYRING_PATH;
377 cmd[k++] = "--keyring=" VENDOR_KEYRING_PATH;
379 cmd[k++] = "--verify";
380 cmd[k++] = sig_file_path;
384 fd_cloexec(STDIN_FILENO, false);
385 fd_cloexec(STDOUT_FILENO, false);
386 fd_cloexec(STDERR_FILENO, false);
388 execvp("gpg2", (char * const *) cmd);
389 execvp("gpg", (char * const *) cmd);
390 log_error_errno(errno, "Failed to execute gpg: %m");
394 gpg_pipe[0] = safe_close(gpg_pipe[0]);
396 r = loop_write(gpg_pipe[1], checksum_job->payload, checksum_job->payload_size, false);
398 log_error_errno(r, "Failed to write to pipe: %m");
402 gpg_pipe[1] = safe_close(gpg_pipe[1]);
404 r = wait_for_terminate_and_warn("gpg", pid, true);
409 log_error("Signature verification failed.");
412 log_info("Signature verification succeeded.");
418 unlink(sig_file_path);
420 if (gpg_home_created)
421 rm_rf_dangerous(gpg_home, false, true, false);