]> git.ipfire.org Git - pakfire.git/commitdiff
archive: Write signatures to archives
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 11 Jul 2021 17:06:58 +0000 (17:06 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 11 Jul 2021 17:06:58 +0000 (17:06 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/archive.c

index 78473993bf6e3d5eb2e77b191d3307f4d584eb1c..e5b61468c764b7ee6f2aa49067543d63a6c89c80 100644 (file)
@@ -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;
 }