2 This file is part of systemd.
4 Copyright 2015 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include <sys/prctl.h>
22 #include "alloc-util.h"
23 #include "btrfs-util.h"
24 #include "capability-util.h"
26 #include "dirent-util.h"
30 #include "path-util.h"
31 #include "process-util.h"
32 #include "pull-common.h"
35 #include "signal-util.h"
36 #include "siphash24.h"
37 #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 h
= siphash24(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
);