char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX";
_cleanup_(sigkill_waitp) pid_t pid = 0;
bool gpg_home_created = false;
+ VerificationStyle style;
int r;
assert(main_job);
if (!signature_job)
return 0;
- if (checksum_job->style == VERIFICATION_PER_FILE)
+ r = verification_style_from_url(checksum_job->url, &style);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine verification style from URL '%s': %m", checksum_job->url);
+
+ if (style == VERIFICATION_PER_FILE) /* if this is per-file verification, then the signature is in the
+ * checksum job, let's thus ignore the signature job from now on,
+ * and use the checksum job as signature job. */
signature_job = checksum_job;
assert(signature_job->state == PULL_JOB_DONE);
cmd[k++] = "--keyring=" VENDOR_KEYRING_PATH;
cmd[k++] = "--verify";
- if (checksum_job->style == VERIFICATION_PER_DIRECTORY) {
+ if (style == VERIFICATION_PER_DIRECTORY) {
cmd[k++] = sig_file_path;
cmd[k++] = "-";
cmd[k++] = NULL;
return r;
}
+
+int verification_style_from_url(const char *url, VerificationStyle *ret) {
+ _cleanup_free_ char *last = NULL;
+ int r;
+
+ assert(url);
+ assert(ret);
+
+ /* Determines which kind of verification style is appropriate for this url */
+
+ r = import_url_last_component(url, &last);
+ if (r < 0)
+ return r;
+
+ if (streq(last, "SHA256SUMS")) {
+ *ret = VERIFICATION_PER_DIRECTORY;
+ return 0;
+ }
+
+ if (endswith(last, ".sha256")) {
+ *ret = VERIFICATION_PER_FILE;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+int pull_job_restart_with_sha256sum(PullJob *j, char **ret) {
+ VerificationStyle style;
+ int r;
+
+ assert(j);
+
+ /* Generic implementation of a PullJobNotFound handler, that restarts the job requesting SHA256SUMS */
+
+ r = verification_style_from_url(j->url, &style);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine verification style of URL '%s': %m", j->url);
+
+ if (style == VERIFICATION_PER_DIRECTORY) /* Nothing to do anymore */
+ return 0;
+
+ assert(style == VERIFICATION_PER_FILE); /* This must have been .sha256 style URL before */
+
+ log_debug("Got 404 for %s, now trying to get SHA256SUMS instead.", j->url);
+
+ r = import_url_change_last_component(j->url, "SHA256SUMS", ret);
+ if (r < 0)
+ return log_error_errno(r, "Failed to replace SHA256SUMS suffix: %m");
+
+ return 1;
+}
int pull_make_verification_jobs(PullJob **ret_checksum_job, PullJob **ret_signature_job, ImportVerify verify, const char *url, CurlGlue *glue, PullJobFinished on_finished, void *userdata);
int pull_verify(PullJob *main_job, PullJob *roothash_job, PullJob *settings_job, PullJob *checksum_job, PullJob *signature_job);
+
+typedef enum VerificationStyle {
+ VERIFICATION_PER_FILE, /* SuSE-style ".sha256" files with inline gpg signature */
+ VERIFICATION_PER_DIRECTORY, /* Ubuntu-style SHA256SUM files with detached SHA256SUM.gpg signatures */
+ _VERIFICATION_STYLE_MAX,
+ _VERIFICATION_STYLE_INVALID = -1,
+} VerificationStyle;
+
+int verification_style_from_url(const char *url, VerificationStyle *style);
+
+int pull_job_restart_with_sha256sum(PullJob *job, char **ret);
j->on_finished(j);
}
-static int pull_job_restart(PullJob *j) {
+static int pull_job_restart(PullJob *j, const char *new_url) {
int r;
- char *chksum_url = NULL;
- r = import_url_change_last_component(j->url, "SHA256SUMS", &chksum_url);
+ assert(j);
+ assert(new_url);
+
+ r = free_and_strdup(&j->url, new_url);
if (r < 0)
return r;
- free(j->url);
- j->url = chksum_url;
j->state = PULL_JOB_INIT;
j->payload = mfree(j->payload);
j->payload_size = 0;
r = 0;
goto finish;
} else if (status >= 300) {
- if (status == 404 && j->style == VERIFICATION_PER_FILE) {
- /* retry pull job with SHA256SUMS file */
- r = pull_job_restart(j);
+ if (status == 404 && j->on_not_found) {
+ _cleanup_free_ char *new_url = NULL;
+
+ /* This resource wasn't found, but the implementor wants to maybe let us know a new URL, query for it. */
+ r = j->on_not_found(j, &new_url);
if (r < 0)
goto finish;
- code = curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status);
- if (code != CURLE_OK) {
- log_error("Failed to retrieve response code: %s", curl_easy_strerror(code));
- r = -EIO;
- goto finish;
- }
+ if (r > 0) { /* A new url to use */
+ assert(new_url);
+
+ r = pull_job_restart(j, new_url);
+ if (r < 0)
+ goto finish;
+
+ code = curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status);
+ if (code != CURLE_OK) {
+ log_error("Failed to retrieve response code: %s", curl_easy_strerror(code));
+ r = -EIO;
+ goto finish;
+ }
- if (status == 0) {
- j->style = VERIFICATION_PER_DIRECTORY;
- return;
+ if (status == 0)
+ return;
}
}
.start_usec = now(CLOCK_MONOTONIC),
.compressed_max = 64LLU * 1024LLU * 1024LLU * 1024LLU, /* 64GB safety limit */
.uncompressed_max = 64LLU * 1024LLU * 1024LLU * 1024LLU, /* 64GB safety limit */
- .style = VERIFICATION_STYLE_UNSET,
.url = TAKE_PTR(u),
};
typedef int (*PullJobOpenDisk)(PullJob *job);
typedef int (*PullJobHeader)(PullJob *job, const char *header, size_t sz);
typedef void (*PullJobProgress)(PullJob *job);
+typedef int (*PullJobNotFound)(PullJob *job, char **ret_new_url);
typedef enum PullJobState {
PULL_JOB_INIT,
_PULL_JOB_STATE_INVALID = -1,
} PullJobState;
-typedef enum VerificationStyle {
- VERIFICATION_STYLE_UNSET,
- VERIFICATION_PER_FILE, /* SuSE-style ".sha256" files with inline signature */
- VERIFICATION_PER_DIRECTORY, /* Ubuntu-style SHA256SUM files with detach SHA256SUM.gpg signatures */
-} VerificationStyle;
-
#define PULL_JOB_IS_COMPLETE(j) (IN_SET((j)->state, PULL_JOB_DONE, PULL_JOB_FAILED))
struct PullJob {
PullJobOpenDisk on_open_disk;
PullJobHeader on_header;
PullJobProgress on_progress;
+ PullJobNotFound on_not_found;
CurlGlue *glue;
CURL *curl;
gcry_md_hd_t checksum_context;
char *checksum;
-
- VerificationStyle style;
};
int pull_job_new(PullJob **job, const char *url, CurlGlue *glue, void *userdata);
if (!raw_pull_is_done(i))
return;
- if (i->signature_job && i->checksum_job->style == VERIFICATION_PER_DIRECTORY && i->signature_job->error != 0) {
- log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
+ if (i->signature_job && i->signature_job->error != 0) {
+ VerificationStyle style;
- r = i->signature_job->error;
- goto finish;
+ r = verification_style_from_url(i->checksum_job->url, &style);
+ if (r < 0) {
+ log_error_errno(r, "Failed to determine verification style from checksum URL: %m");
+ goto finish;
+ }
+
+ if (style == VERIFICATION_PER_DIRECTORY) { /* A failed signature file download only matters
+ * in per-directory verification mode, since only
+ * then the signature is detached, and thus a file
+ * of its own. */
+ log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
+ r = i->signature_job->error;
+ goto finish;
+ }
}
if (i->roothash_job)
if (i->checksum_job) {
i->checksum_job->on_progress = raw_pull_job_on_progress;
- i->checksum_job->style = VERIFICATION_PER_FILE;
+ i->checksum_job->on_not_found = pull_job_restart_with_sha256sum;
r = pull_job_begin(i->checksum_job);
if (r < 0)
if (!tar_pull_is_done(i))
return;
- if (i->signature_job && i->checksum_job->style == VERIFICATION_PER_DIRECTORY && i->signature_job->error != 0) {
- log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
+ if (i->signature_job && i->signature_job->error != 0) {
+ VerificationStyle style;
- r = i->signature_job->error;
- goto finish;
+ r = verification_style_from_url(i->checksum_job->url, &style);
+ if (r < 0) {
+ log_error_errno(r, "Failed to determine verification style from checksum URL: %m");
+ goto finish;
+ }
+
+ if (style == VERIFICATION_PER_DIRECTORY) { /* A failed signature file download only matters
+ * in per-directory verification mode, since only
+ * then the signature is detached, and thus a file
+ * of its own. */
+ log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
+ r = i->signature_job->error;
+ goto finish;
+ }
}
i->tar_job->disk_fd = safe_close(i->tar_job->disk_fd);
if (i->checksum_job) {
i->checksum_job->on_progress = tar_pull_job_on_progress;
- i->checksum_job->style = VERIFICATION_PER_FILE;
+ i->checksum_job->on_not_found = pull_job_restart_with_sha256sum;
r = pull_job_begin(i->checksum_job);
if (r < 0)