From: Michael Tremer Date: Sun, 11 Jul 2021 17:06:58 +0000 (+0000) Subject: archive: Write signatures to archives X-Git-Tag: 0.9.28~1048 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=95c4b89c62a26611ef99f35f41567a4c66f951cb;p=pakfire.git archive: Write signatures to archives Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/archive.c b/src/libpakfire/archive.c index 78473993b..e5b61468c 100644 --- a/src/libpakfire/archive.c +++ b/src/libpakfire/archive.c @@ -1433,8 +1433,10 @@ static int pakfire_archive_create_signature(struct pakfire_archive* archive, // Read chksums int r = open_archive_and_read(archive, "chksums", &buffer, &length); - if (r) + if (r) { + ERROR(archive->pakfire, "Could not read chksums file: %m\n"); goto ERROR; + } // Use the key to sign the buffer r = pakfire_key_sign(key, buffer, length, signature, signature_length, timestamp); @@ -1448,6 +1450,127 @@ ERROR: return r; } +/* + This function appends a single file to the archive + + Unfortunately libarchive cannot do this, so we have to manually find the end of the + archive and write another entry... +*/ +static int pakfire_archive_append_file(struct pakfire_archive* archive, + struct archive_entry* entry, const char* buffer, const size_t length) { + off_t offset = 0; + + // Find the end of the archive (exclusing the tar trailer) + int r = pakfire_archive_find_end(archive, &offset); + if (r) + return r; + + // Create a new archive writer + struct archive* a = archive_write_new(); + if (!a) { + ERROR(archive->pakfire, "Could not create an archive writer: %m\n"); + return 1; + } + + // Use the PAX format + r = archive_write_set_format_pax(a); + if (r) { + ERROR(archive->pakfire, "Could not set format to PAX: %s\n", archive_error_string(a)); + goto ERROR; + } + + // Seek to the end of the archive + r = fseek(archive->f, offset, SEEK_SET); + if (r) { + ERROR(archive->pakfire, "Could not seek to position %jd in archive: %m\n", offset); + return r; + } + + // Write archive to f + r = archive_write_open_FILE(a, archive->f); + if (r) { + ERROR(archive->pakfire, "archive_write_open_FILE() failed: %s\n", + archive_error_string(a)); + goto ERROR; + } + + // Write the header + r = archive_write_header(a, entry); + if (r) { + ERROR(archive->pakfire, "Error writing file header: %s\n", + archive_error_string(a)); + goto ERROR; + } + + // Write the payload + ssize_t bytes_written = archive_write_data(a, buffer, length); + if (bytes_written < 0) { + ERROR(archive->pakfire, "Error writing data: %s\n", + archive_error_string(a)); + goto ERROR; + } + + // Finish writing + r = archive_write_finish_entry(a); + if (r) { + ERROR(archive->pakfire, "Could not finish entry: %s\n", + archive_error_string(a)); + goto ERROR; + } + + // Success + r = 0; + +ERROR: + archive_write_free(a); + + return r; +} + +static int pakfire_archive_append_signature(struct pakfire_archive* archive, + struct pakfire_key* key, const char* signature, size_t length, time_t timestamp) { + char path[PATH_MAX]; + int r; + + // Make filename + r = pakfire_string_format(path, "signatures/%s", pakfire_key_get_fingerprint(key)); + if (r < 0) + return 1; + + // Create a new file entry + struct archive_entry* entry = archive_entry_new(); + if (!entry) + return 1; + + // Set filename + archive_entry_set_pathname(entry, path); + + // This is a regular file + archive_entry_set_filetype(entry, AE_IFREG); + archive_entry_set_perm(entry, 0444); + + // Set size + archive_entry_set_size(entry, length); + + // Set ownership + archive_entry_set_uname(entry, "root"); + archive_entry_set_uid(entry, 0); + archive_entry_set_gname(entry, "root"); + archive_entry_set_gid(entry, 0); + + // Set times + archive_entry_set_birthtime(entry, timestamp, 0); + archive_entry_set_ctime(entry, timestamp, 0); + archive_entry_set_mtime(entry, timestamp, 0); + archive_entry_set_atime(entry, timestamp, 0); + + // Write entry + r = pakfire_archive_append_file(archive, entry, signature, length); + archive_entry_free(entry); + + return r; +} + PAKFIRE_EXPORT int pakfire_archive_sign(struct pakfire_archive* archive, struct pakfire_key* key) { int r; @@ -1463,7 +1586,11 @@ PAKFIRE_EXPORT int pakfire_archive_sign(struct pakfire_archive* archive, struct if (r) return r; - // XXX write signature to archive + // Append signature to archive + r = pakfire_archive_append_signature(archive, key, + signature, signature_length, timestamp); + if (r) + return r; return 0; }