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 "alloc-util.h"
25 #include "btrfs-util.h"
26 #include "capability-util.h"
28 #include "dirent-util.h"
32 #include "path-util.h"
33 #include "process-util.h"
34 #include "pull-common.h"
37 #include "signal-util.h"
38 #include "siphash24.h"
39 #include "string-util.h"
44 #define FILENAME_ESCAPE "/.#\"\'"
45 #define HASH_URL_THRESHOLD_LENGTH (_POSIX_PATH_MAX - 16)
47 int pull_find_old_etags(
49 const char *image_root
,
55 _cleanup_free_
char *escaped_url
= NULL
;
56 _cleanup_closedir_
DIR *d
= NULL
;
57 _cleanup_strv_free_
char **l
= NULL
;
65 image_root
= "/var/lib/machines";
67 escaped_url
= xescape(url
, FILENAME_ESCAPE
);
71 d
= opendir(image_root
);
73 if (errno
== ENOENT
) {
81 FOREACH_DIRENT_ALL(de
, d
, return -errno
) {
85 if (de
->d_type
!= DT_UNKNOWN
&&
90 a
= startswith(de
->d_name
, prefix
);
96 a
= startswith(a
, escaped_url
);
100 a
= startswith(a
, ".");
105 b
= endswith(de
->d_name
, suffix
);
109 b
= strchr(de
->d_name
, 0);
114 r
= cunescape_length(a
, b
- a
, 0, &u
);
118 if (!http_etag_is_valid(u
)) {
123 r
= strv_consume(&l
, u
);
134 int pull_make_local_copy(const char *final
, const char *image_root
, const char *local
, bool force_local
) {
142 image_root
= "/var/lib/machines";
144 p
= strjoina(image_root
, "/", local
);
147 (void) rm_rf(p
, REMOVE_ROOT
|REMOVE_PHYSICAL
|REMOVE_SUBVOLUME
);
149 r
= btrfs_subvol_snapshot(final
, p
, BTRFS_SNAPSHOT_QUOTA
);
151 r
= copy_tree(final
, p
, false);
153 return log_error_errno(r
, "Failed to copy image: %m");
155 return log_error_errno(r
, "Failed to create local image: %m");
157 log_info("Created new local image '%s'.", local
);
162 static int hash_url(const char *url
, char **ret
) {
164 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
);
168 h
= siphash24(url
, strlen(url
), k
.bytes
);
169 if (asprintf(ret
, "%"PRIx64
, h
) < 0)
175 int pull_make_path(const char *url
, const char *etag
, const char *image_root
, const char *prefix
, const char *suffix
, char **ret
) {
176 _cleanup_free_
char *escaped_url
= NULL
, *escaped_etag
= NULL
;
183 image_root
= "/var/lib/machines";
185 escaped_url
= xescape(url
, FILENAME_ESCAPE
);
190 escaped_etag
= xescape(etag
, FILENAME_ESCAPE
);
195 path
= strjoin(image_root
, "/", strempty(prefix
), escaped_url
, escaped_etag
? "." : "",
196 strempty(escaped_etag
), strempty(suffix
), NULL
);
200 /* URLs might make the path longer than the maximum allowed length for a file name.
201 * When that happens, a URL hash is used instead. Paths returned by this function
202 * can be later used with tempfn_random() which adds 16 bytes to the resulting name. */
203 if (strlen(path
) >= HASH_URL_THRESHOLD_LENGTH
) {
204 _cleanup_free_
char *hash
= NULL
;
209 r
= hash_url(url
, &hash
);
213 path
= strjoin(image_root
, "/", strempty(prefix
), hash
, escaped_etag
? "." : "",
214 strempty(escaped_etag
), strempty(suffix
), NULL
);
223 int pull_make_settings_job(
227 PullJobFinished on_finished
,
230 _cleanup_free_
char *last_component
= NULL
, *ll
= NULL
, *settings_url
= NULL
;
231 _cleanup_(pull_job_unrefp
) PullJob
*job
= NULL
;
239 r
= import_url_last_component(url
, &last_component
);
243 r
= tar_strip_suffixes(last_component
, &ll
);
247 q
= strjoina(ll
, ".nspawn");
249 r
= import_url_change_last_component(url
, q
, &settings_url
);
253 r
= pull_job_new(&job
, settings_url
, glue
, userdata
);
257 job
->on_finished
= on_finished
;
258 job
->compressed_max
= job
->uncompressed_max
= 1ULL * 1024ULL * 1024ULL;
266 int pull_make_verification_jobs(
267 PullJob
**ret_checksum_job
,
268 PullJob
**ret_signature_job
,
272 PullJobFinished on_finished
,
275 _cleanup_(pull_job_unrefp
) PullJob
*checksum_job
= NULL
, *signature_job
= NULL
;
278 assert(ret_checksum_job
);
279 assert(ret_signature_job
);
281 assert(verify
< _IMPORT_VERIFY_MAX
);
285 if (verify
!= IMPORT_VERIFY_NO
) {
286 _cleanup_free_
char *checksum_url
= NULL
;
288 /* Queue job for the SHA256SUMS file for the image */
289 r
= import_url_change_last_component(url
, "SHA256SUMS", &checksum_url
);
293 r
= pull_job_new(&checksum_job
, checksum_url
, glue
, userdata
);
297 checksum_job
->on_finished
= on_finished
;
298 checksum_job
->uncompressed_max
= checksum_job
->compressed_max
= 1ULL * 1024ULL * 1024ULL;
301 if (verify
== IMPORT_VERIFY_SIGNATURE
) {
302 _cleanup_free_
char *signature_url
= NULL
;
304 /* Queue job for the SHA256SUMS.gpg file for the image. */
305 r
= import_url_change_last_component(url
, "SHA256SUMS.gpg", &signature_url
);
309 r
= pull_job_new(&signature_job
, signature_url
, glue
, userdata
);
313 signature_job
->on_finished
= on_finished
;
314 signature_job
->uncompressed_max
= signature_job
->compressed_max
= 1ULL * 1024ULL * 1024ULL;
317 *ret_checksum_job
= checksum_job
;
318 *ret_signature_job
= signature_job
;
320 checksum_job
= signature_job
= NULL
;
325 int pull_verify(PullJob
*main_job
,
326 PullJob
*settings_job
,
327 PullJob
*checksum_job
,
328 PullJob
*signature_job
) {
330 _cleanup_close_pair_
int gpg_pipe
[2] = { -1, -1 };
331 _cleanup_free_
char *fn
= NULL
;
332 _cleanup_close_
int sig_file
= -1;
333 const char *p
, *line
;
334 char sig_file_path
[] = "/tmp/sigXXXXXX", gpg_home
[] = "/tmp/gpghomeXXXXXX";
335 _cleanup_sigkill_wait_ pid_t pid
= 0;
336 bool gpg_home_created
= false;
340 assert(main_job
->state
== PULL_JOB_DONE
);
345 assert(main_job
->calc_checksum
);
346 assert(main_job
->checksum
);
347 assert(checksum_job
->state
== PULL_JOB_DONE
);
349 if (!checksum_job
->payload
|| checksum_job
->payload_size
<= 0) {
350 log_error("Checksum is empty, cannot verify.");
354 r
= import_url_last_component(main_job
->url
, &fn
);
358 if (!filename_is_valid(fn
)) {
359 log_error("Cannot verify checksum, could not determine valid server-side file name.");
363 line
= strjoina(main_job
->checksum
, " *", fn
, "\n");
365 p
= memmem(checksum_job
->payload
,
366 checksum_job
->payload_size
,
370 if (!p
|| (p
!= (char*) checksum_job
->payload
&& p
[-1] != '\n')) {
371 log_error("DOWNLOAD INVALID: Checksum did not check out, payload has been tampered with.");
375 log_info("SHA256 checksum of %s is valid.", main_job
->url
);
377 assert(!settings_job
|| IN_SET(settings_job
->state
, PULL_JOB_DONE
, PULL_JOB_FAILED
));
380 settings_job
->state
== PULL_JOB_DONE
&&
381 settings_job
->error
== 0 &&
382 !settings_job
->etag_exists
) {
384 _cleanup_free_
char *settings_fn
= NULL
;
386 assert(settings_job
->calc_checksum
);
387 assert(settings_job
->checksum
);
389 r
= import_url_last_component(settings_job
->url
, &settings_fn
);
393 if (!filename_is_valid(settings_fn
)) {
394 log_error("Cannot verify checksum, could not determine server-side settings file name.");
398 line
= strjoina(settings_job
->checksum
, " *", settings_fn
, "\n");
400 p
= memmem(checksum_job
->payload
,
401 checksum_job
->payload_size
,
405 if (!p
|| (p
!= (char*) checksum_job
->payload
&& p
[-1] != '\n')) {
406 log_error("DOWNLOAD INVALID: Checksum of settings file did not checkout, settings file has been tampered with.");
410 log_info("SHA256 checksum of %s is valid.", settings_job
->url
);
416 assert(signature_job
->state
== PULL_JOB_DONE
);
418 if (!signature_job
->payload
|| signature_job
->payload_size
<= 0) {
419 log_error("Signature is empty, cannot verify.");
423 r
= pipe2(gpg_pipe
, O_CLOEXEC
);
425 return log_error_errno(errno
, "Failed to create pipe for gpg: %m");
427 sig_file
= mkostemp(sig_file_path
, O_RDWR
);
429 return log_error_errno(errno
, "Failed to create temporary file: %m");
431 r
= loop_write(sig_file
, signature_job
->payload
, signature_job
->payload_size
, false);
433 log_error_errno(r
, "Failed to write to temporary file: %m");
437 if (!mkdtemp(gpg_home
)) {
438 r
= log_error_errno(errno
, "Failed to create tempory home for gpg: %m");
442 gpg_home_created
= true;
446 return log_error_errno(errno
, "Failed to fork off gpg: %m");
448 const char *cmd
[] = {
451 "--no-default-keyring",
452 "--no-auto-key-locate",
453 "--no-auto-check-trustdb",
455 "--trust-model=always",
456 NULL
, /* --homedir= */
457 NULL
, /* --keyring= */
459 NULL
, /* signature file */
461 NULL
/* trailing NULL */
463 unsigned k
= ELEMENTSOF(cmd
) - 6;
468 (void) reset_all_signal_handlers();
469 (void) reset_signal_mask();
470 assert_se(prctl(PR_SET_PDEATHSIG
, SIGTERM
) == 0);
472 gpg_pipe
[1] = safe_close(gpg_pipe
[1]);
474 if (dup2(gpg_pipe
[0], STDIN_FILENO
) != STDIN_FILENO
) {
475 log_error_errno(errno
, "Failed to dup2() fd: %m");
479 if (gpg_pipe
[0] != STDIN_FILENO
)
480 gpg_pipe
[0] = safe_close(gpg_pipe
[0]);
482 null_fd
= open("/dev/null", O_WRONLY
|O_NOCTTY
);
484 log_error_errno(errno
, "Failed to open /dev/null: %m");
488 if (dup2(null_fd
, STDOUT_FILENO
) != STDOUT_FILENO
) {
489 log_error_errno(errno
, "Failed to dup2() fd: %m");
493 if (null_fd
!= STDOUT_FILENO
)
494 null_fd
= safe_close(null_fd
);
496 cmd
[k
++] = strjoina("--homedir=", gpg_home
);
498 /* We add the user keyring only to the command line
499 * arguments, if it's around since gpg fails
501 if (access(USER_KEYRING_PATH
, F_OK
) >= 0)
502 cmd
[k
++] = "--keyring=" USER_KEYRING_PATH
;
504 cmd
[k
++] = "--keyring=" VENDOR_KEYRING_PATH
;
506 cmd
[k
++] = "--verify";
507 cmd
[k
++] = sig_file_path
;
511 fd_cloexec(STDIN_FILENO
, false);
512 fd_cloexec(STDOUT_FILENO
, false);
513 fd_cloexec(STDERR_FILENO
, false);
515 execvp("gpg2", (char * const *) cmd
);
516 execvp("gpg", (char * const *) cmd
);
517 log_error_errno(errno
, "Failed to execute gpg: %m");
521 gpg_pipe
[0] = safe_close(gpg_pipe
[0]);
523 r
= loop_write(gpg_pipe
[1], checksum_job
->payload
, checksum_job
->payload_size
, false);
525 log_error_errno(r
, "Failed to write to pipe: %m");
529 gpg_pipe
[1] = safe_close(gpg_pipe
[1]);
531 r
= wait_for_terminate_and_warn("gpg", pid
, true);
536 log_error("DOWNLOAD INVALID: Signature verification failed.");
539 log_info("Signature verification succeeded.");
545 (void) unlink(sig_file_path
);
547 if (gpg_home_created
)
548 (void) rm_rf(gpg_home
, REMOVE_ROOT
|REMOVE_PHYSICAL
);