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>
24 #include "btrfs-util.h"
25 #include "capability.h"
27 #include "dirent-util.h"
31 #include "path-util.h"
32 #include "process-util.h"
33 #include "pull-common.h"
36 #include "signal-util.h"
37 #include "siphash24.h"
38 #include "string-util.h"
42 #define FILENAME_ESCAPE "/.#\"\'"
43 #define HASH_URL_THRESHOLD_LENGTH (_POSIX_PATH_MAX - 16)
45 int pull_find_old_etags(
47 const char *image_root
,
53 _cleanup_free_
char *escaped_url
= NULL
;
54 _cleanup_closedir_
DIR *d
= NULL
;
55 _cleanup_strv_free_
char **l
= NULL
;
63 image_root
= "/var/lib/machines";
65 escaped_url
= xescape(url
, FILENAME_ESCAPE
);
69 d
= opendir(image_root
);
71 if (errno
== ENOENT
) {
79 FOREACH_DIRENT_ALL(de
, d
, return -errno
) {
83 if (de
->d_type
!= DT_UNKNOWN
&&
88 a
= startswith(de
->d_name
, prefix
);
94 a
= startswith(a
, escaped_url
);
98 a
= startswith(a
, ".");
103 b
= endswith(de
->d_name
, suffix
);
107 b
= strchr(de
->d_name
, 0);
112 r
= cunescape_length(a
, b
- a
, 0, &u
);
116 if (!http_etag_is_valid(u
)) {
121 r
= strv_consume(&l
, u
);
132 int pull_make_local_copy(const char *final
, const char *image_root
, const char *local
, bool force_local
) {
140 image_root
= "/var/lib/machines";
142 p
= strjoina(image_root
, "/", local
);
145 (void) rm_rf(p
, REMOVE_ROOT
|REMOVE_PHYSICAL
|REMOVE_SUBVOLUME
);
147 r
= btrfs_subvol_snapshot(final
, p
, BTRFS_SNAPSHOT_QUOTA
);
149 r
= copy_tree(final
, p
, false);
151 return log_error_errno(r
, "Failed to copy image: %m");
153 return log_error_errno(r
, "Failed to create local image: %m");
155 log_info("Created new local image '%s'.", local
);
160 static int hash_url(const char *url
, char **ret
) {
162 static const sd_id128_t k
= SD_ID128_ARRAY(df
,89,16,87,01,cc
,42,30,98,ab
,4a
,19,a6
,a5
,63,4f
);
166 siphash24((uint8_t *) &h
, url
, strlen(url
), k
.bytes
);
167 if (asprintf(ret
, "%"PRIx64
, h
) < 0)
173 int pull_make_path(const char *url
, const char *etag
, const char *image_root
, const char *prefix
, const char *suffix
, char **ret
) {
174 _cleanup_free_
char *escaped_url
= NULL
, *escaped_etag
= NULL
;
181 image_root
= "/var/lib/machines";
183 escaped_url
= xescape(url
, FILENAME_ESCAPE
);
188 escaped_etag
= xescape(etag
, FILENAME_ESCAPE
);
193 path
= strjoin(image_root
, "/", strempty(prefix
), escaped_url
, escaped_etag
? "." : "",
194 strempty(escaped_etag
), strempty(suffix
), NULL
);
198 /* URLs might make the path longer than the maximum allowed length for a file name.
199 * When that happens, a URL hash is used instead. Paths returned by this function
200 * can be later used with tempfn_random() which adds 16 bytes to the resulting name. */
201 if (strlen(path
) >= HASH_URL_THRESHOLD_LENGTH
) {
202 _cleanup_free_
char *hash
= NULL
;
207 r
= hash_url(url
, &hash
);
211 path
= strjoin(image_root
, "/", strempty(prefix
), hash
, escaped_etag
? "." : "",
212 strempty(escaped_etag
), strempty(suffix
), NULL
);
221 int pull_make_settings_job(
225 PullJobFinished on_finished
,
228 _cleanup_free_
char *last_component
= NULL
, *ll
= NULL
, *settings_url
= NULL
;
229 _cleanup_(pull_job_unrefp
) PullJob
*job
= NULL
;
237 r
= import_url_last_component(url
, &last_component
);
241 r
= tar_strip_suffixes(last_component
, &ll
);
245 q
= strjoina(ll
, ".nspawn");
247 r
= import_url_change_last_component(url
, q
, &settings_url
);
251 r
= pull_job_new(&job
, settings_url
, glue
, userdata
);
255 job
->on_finished
= on_finished
;
256 job
->compressed_max
= job
->uncompressed_max
= 1ULL * 1024ULL * 1024ULL;
264 int pull_make_verification_jobs(
265 PullJob
**ret_checksum_job
,
266 PullJob
**ret_signature_job
,
270 PullJobFinished on_finished
,
273 _cleanup_(pull_job_unrefp
) PullJob
*checksum_job
= NULL
, *signature_job
= NULL
;
276 assert(ret_checksum_job
);
277 assert(ret_signature_job
);
279 assert(verify
< _IMPORT_VERIFY_MAX
);
283 if (verify
!= IMPORT_VERIFY_NO
) {
284 _cleanup_free_
char *checksum_url
= NULL
;
286 /* Queue job for the SHA256SUMS file for the image */
287 r
= import_url_change_last_component(url
, "SHA256SUMS", &checksum_url
);
291 r
= pull_job_new(&checksum_job
, checksum_url
, glue
, userdata
);
295 checksum_job
->on_finished
= on_finished
;
296 checksum_job
->uncompressed_max
= checksum_job
->compressed_max
= 1ULL * 1024ULL * 1024ULL;
299 if (verify
== IMPORT_VERIFY_SIGNATURE
) {
300 _cleanup_free_
char *signature_url
= NULL
;
302 /* Queue job for the SHA256SUMS.gpg file for the image. */
303 r
= import_url_change_last_component(url
, "SHA256SUMS.gpg", &signature_url
);
307 r
= pull_job_new(&signature_job
, signature_url
, glue
, userdata
);
311 signature_job
->on_finished
= on_finished
;
312 signature_job
->uncompressed_max
= signature_job
->compressed_max
= 1ULL * 1024ULL * 1024ULL;
315 *ret_checksum_job
= checksum_job
;
316 *ret_signature_job
= signature_job
;
318 checksum_job
= signature_job
= NULL
;
323 int pull_verify(PullJob
*main_job
,
324 PullJob
*settings_job
,
325 PullJob
*checksum_job
,
326 PullJob
*signature_job
) {
328 _cleanup_close_pair_
int gpg_pipe
[2] = { -1, -1 };
329 _cleanup_free_
char *fn
= NULL
;
330 _cleanup_close_
int sig_file
= -1;
331 const char *p
, *line
;
332 char sig_file_path
[] = "/tmp/sigXXXXXX", gpg_home
[] = "/tmp/gpghomeXXXXXX";
333 _cleanup_sigkill_wait_ pid_t pid
= 0;
334 bool gpg_home_created
= false;
338 assert(main_job
->state
== PULL_JOB_DONE
);
343 assert(main_job
->calc_checksum
);
344 assert(main_job
->checksum
);
345 assert(checksum_job
->state
== PULL_JOB_DONE
);
347 if (!checksum_job
->payload
|| checksum_job
->payload_size
<= 0) {
348 log_error("Checksum is empty, cannot verify.");
352 r
= import_url_last_component(main_job
->url
, &fn
);
356 if (!filename_is_valid(fn
)) {
357 log_error("Cannot verify checksum, could not determine valid server-side file name.");
361 line
= strjoina(main_job
->checksum
, " *", fn
, "\n");
363 p
= memmem(checksum_job
->payload
,
364 checksum_job
->payload_size
,
368 if (!p
|| (p
!= (char*) checksum_job
->payload
&& p
[-1] != '\n')) {
369 log_error("DOWNLOAD INVALID: Checksum did not check out, payload has been tampered with.");
373 log_info("SHA256 checksum of %s is valid.", main_job
->url
);
375 assert(!settings_job
|| IN_SET(settings_job
->state
, PULL_JOB_DONE
, PULL_JOB_FAILED
));
378 settings_job
->state
== PULL_JOB_DONE
&&
379 settings_job
->error
== 0 &&
380 !settings_job
->etag_exists
) {
382 _cleanup_free_
char *settings_fn
= NULL
;
384 assert(settings_job
->calc_checksum
);
385 assert(settings_job
->checksum
);
387 r
= import_url_last_component(settings_job
->url
, &settings_fn
);
391 if (!filename_is_valid(settings_fn
)) {
392 log_error("Cannot verify checksum, could not determine server-side settings file name.");
396 line
= strjoina(settings_job
->checksum
, " *", settings_fn
, "\n");
398 p
= memmem(checksum_job
->payload
,
399 checksum_job
->payload_size
,
403 if (!p
|| (p
!= (char*) checksum_job
->payload
&& p
[-1] != '\n')) {
404 log_error("DOWNLOAD INVALID: Checksum of settings file did not checkout, settings file has been tampered with.");
408 log_info("SHA256 checksum of %s is valid.", settings_job
->url
);
414 assert(signature_job
->state
== PULL_JOB_DONE
);
416 if (!signature_job
->payload
|| signature_job
->payload_size
<= 0) {
417 log_error("Signature is empty, cannot verify.");
421 r
= pipe2(gpg_pipe
, O_CLOEXEC
);
423 return log_error_errno(errno
, "Failed to create pipe for gpg: %m");
425 sig_file
= mkostemp(sig_file_path
, O_RDWR
);
427 return log_error_errno(errno
, "Failed to create temporary file: %m");
429 r
= loop_write(sig_file
, signature_job
->payload
, signature_job
->payload_size
, false);
431 log_error_errno(r
, "Failed to write to temporary file: %m");
435 if (!mkdtemp(gpg_home
)) {
436 r
= log_error_errno(errno
, "Failed to create tempory home for gpg: %m");
440 gpg_home_created
= true;
444 return log_error_errno(errno
, "Failed to fork off gpg: %m");
446 const char *cmd
[] = {
449 "--no-default-keyring",
450 "--no-auto-key-locate",
451 "--no-auto-check-trustdb",
453 "--trust-model=always",
454 NULL
, /* --homedir= */
455 NULL
, /* --keyring= */
457 NULL
, /* signature file */
459 NULL
/* trailing NULL */
461 unsigned k
= ELEMENTSOF(cmd
) - 6;
466 (void) reset_all_signal_handlers();
467 (void) reset_signal_mask();
468 assert_se(prctl(PR_SET_PDEATHSIG
, SIGTERM
) == 0);
470 gpg_pipe
[1] = safe_close(gpg_pipe
[1]);
472 if (dup2(gpg_pipe
[0], STDIN_FILENO
) != STDIN_FILENO
) {
473 log_error_errno(errno
, "Failed to dup2() fd: %m");
477 if (gpg_pipe
[0] != STDIN_FILENO
)
478 gpg_pipe
[0] = safe_close(gpg_pipe
[0]);
480 null_fd
= open("/dev/null", O_WRONLY
|O_NOCTTY
);
482 log_error_errno(errno
, "Failed to open /dev/null: %m");
486 if (dup2(null_fd
, STDOUT_FILENO
) != STDOUT_FILENO
) {
487 log_error_errno(errno
, "Failed to dup2() fd: %m");
491 if (null_fd
!= STDOUT_FILENO
)
492 null_fd
= safe_close(null_fd
);
494 cmd
[k
++] = strjoina("--homedir=", gpg_home
);
496 /* We add the user keyring only to the command line
497 * arguments, if it's around since gpg fails
499 if (access(USER_KEYRING_PATH
, F_OK
) >= 0)
500 cmd
[k
++] = "--keyring=" USER_KEYRING_PATH
;
502 cmd
[k
++] = "--keyring=" VENDOR_KEYRING_PATH
;
504 cmd
[k
++] = "--verify";
505 cmd
[k
++] = sig_file_path
;
509 fd_cloexec(STDIN_FILENO
, false);
510 fd_cloexec(STDOUT_FILENO
, false);
511 fd_cloexec(STDERR_FILENO
, false);
513 execvp("gpg2", (char * const *) cmd
);
514 execvp("gpg", (char * const *) cmd
);
515 log_error_errno(errno
, "Failed to execute gpg: %m");
519 gpg_pipe
[0] = safe_close(gpg_pipe
[0]);
521 r
= loop_write(gpg_pipe
[1], checksum_job
->payload
, checksum_job
->payload_size
, false);
523 log_error_errno(r
, "Failed to write to pipe: %m");
527 gpg_pipe
[1] = safe_close(gpg_pipe
[1]);
529 r
= wait_for_terminate_and_warn("gpg", pid
, true);
534 log_error("DOWNLOAD INVALID: Signature verification failed.");
537 log_info("Signature verification succeeded.");
543 (void) unlink(sig_file_path
);
545 if (gpg_home_created
)
546 (void) rm_rf(gpg_home
, REMOVE_ROOT
|REMOVE_PHYSICAL
);