Add a pmpgpsig_t struct to the database entry struct and functions for
the lazy loading of database signatures. Add a function for checking
database signatures, reusing (and generalizing) the code currently used
for checking package signatures.
TODO: The code for reading in signature files from the filesystem is
duplicated for local packages and database and needs refactored.
Signed-off-by: Allan McRae <allan(a)archlinux.org>
---
lib/libalpm/alpm.h | 1 +
lib/libalpm/db.c | 56 +++++++++++++++++++++++++++++++++++++++++++++
lib/libalpm/db.h | 7 +++++-
lib/libalpm/package.h | 11 +--------
lib/libalpm/signing.c | 61 ++++++++++++++++++++++++++++++------------------
lib/libalpm/signing.h | 12 +++++++++-
6 files changed, 113 insertions(+), 35 deletions(-)
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 9dd222d..74598ef 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -253,6 +253,7 @@ alpm_list_t *alpm_pkg_unused_deltas(pmpkg_t *pkg);
*/
int alpm_pkg_check_pgp_signature(pmpkg_t *pkg);
+int alpm_db_check_pgp_signature(pmdb_t *db);
/* GPG signature verification option */
typedef enum _pgp_verify_t {
diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c
index 9fd918a..a7718d5 100644
--- a/lib/libalpm/db.c
+++ b/lib/libalpm/db.c
@@ -409,6 +409,62 @@ pmdb_t *_alpm_db_new(const char *treename, int is_local)
return(db);
}
+static int load_pgpsig(pmdb_t *db) {
+ size_t len;
+ const char *dbfile;
+ char *sigfile;
+
+ dbfile = _alpm_db_path(db);
+ len = strlen(dbfile) + 5;
+ MALLOC(sigfile, len, RET_ERR(PM_ERR_MEMORY, -1));
+ sprintf(sigfile, "%s.sig", dbfile);
+
+ if(access(sigfile, R_OK) == 0) {
+ FILE *f;
+ long bytes;
+ size_t bytes_read;
+ f = fopen(sigfile, "rb");
+ fseek(f, 0L, SEEK_END);
+ bytes = ftell(f);
+ fseek(f, 0L, SEEK_SET);
+ CALLOC(db->pgpsig.rawdata, bytes, sizeof(char),
+ goto error);
+ bytes_read = fread(db->pgpsig.rawdata, sizeof(char), bytes, f);
+ if(bytes_read == bytes) {
+ db->pgpsig.rawlen = bytes;
+ _alpm_log(PM_LOG_DEBUG,
+ "loaded database .sig file, location %s\n", sigfile);
+ } else {
+ _alpm_log(PM_LOG_WARNING, _("Failed reading PGP signature file for %s"),
+ dbfile);
+ }
+ fclose(f);
+ } else {
+ _alpm_log(PM_LOG_DEBUG, "no database signature file found\n");
+ }
+
+ return(0);
+
+error:
+ FREE(db->pgpsig.rawdata);
+ db->pgpsig.rawlen = 0;
+ return(1);
+}
+
+const pmpgpsig_t *_alpm_db_pgpsig(pmdb_t *db)
+{
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(db != NULL, return(NULL));
+
+ if(db->pgpsig.rawdata == NULL) {
+ load_pgpsig(db);
+ }
+
+ return &(db->pgpsig);
+}
+
void _alpm_db_free(pmdb_t *db)
{
ALPM_LOG_FUNC;
diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h
index ab896b9..1372b0d 100644
--- a/lib/libalpm/db.h
+++ b/lib/libalpm/db.h
@@ -22,7 +22,6 @@
#ifndef _ALPM_DB_H
#define _ALPM_DB_H
-#include "alpm.h"
#include <limits.h>
#include <time.h>
@@ -30,6 +29,9 @@
#include <archive.h>
#include <archive_entry.h>
+#include "alpm.h"
+#include "signing.h"
+
/* Database entries */
typedef enum _pmdbinfrq_t {
INFRQ_BASE = 1,
@@ -58,6 +60,8 @@ struct __pmdb_t {
alpm_list_t *pkgcache;
alpm_list_t *grpcache;
alpm_list_t *servers;
+ /* do not access directly, use _alpm_db_pgpsig(db) for lazy access */
+ pmpgpsig_t pgpsig;
pgp_verify_t pgp_verify;
struct db_operations *ops;
@@ -73,6 +77,7 @@ pmdb_t *_alpm_db_register_local(void);
pmdb_t *_alpm_db_register_sync(const char *treename);
void _alpm_db_unregister(pmdb_t *db);
pmdb_t *_alpm_db_new(const char *treename, int is_local);
+const pmpgpsig_t *_alpm_db_pgpsig(pmdb_t *db);
/* be_*.c, backend specific calls */
int _alpm_local_db_populate(pmdb_t *db);
diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h
index be5ce32..7c11e38 100644
--- a/lib/libalpm/package.h
+++ b/lib/libalpm/package.h
@@ -29,6 +29,7 @@
#include "alpm.h"
#include "db.h"
+#include "signing.h"
typedef enum _pmpkgfrom_t {
PKG_FROM_FILE = 1,
@@ -90,16 +91,6 @@ struct pkg_operations {
*/
extern struct pkg_operations default_pkg_ops;
-struct __pmpgpsig_t {
- /* we will either store the encoded data or the raw data-
- * this way we can decode on an as-needed basis since most
- * operations won't require the overhead of base64 decodes
- * on all packages in a sync repository. */
- char *encdata;
- size_t rawlen;
- unsigned char *rawdata;
-};
-
struct __pmpkg_t {
char *filename;
char *name;
diff --git a/lib/libalpm/signing.c b/lib/libalpm/signing.c
index 2b15528..826c34b 100644
--- a/lib/libalpm/signing.c
+++ b/lib/libalpm/signing.c
@@ -92,28 +92,28 @@ error:
}
/**
- * Check the PGP package signature for the given package file.
- * @param pkgpath the full path to a package file
+ * Check the PGP package signature for the given file.
+ * @param path the full path to a file
* @param sig PGP signature data in raw form (already decoded)
* @return a int value : 0 (valid), 1 (invalid), -1 (an error occured)
*/
-int _alpm_gpgme_checksig(const char *pkgpath, const pmpgpsig_t *sig)
+int _alpm_gpgme_checksig(const char *path, const pmpgpsig_t *sig)
{
int ret = 0;
gpgme_error_t err;
gpgme_ctx_t ctx;
- gpgme_data_t pkgdata, sigdata;
+ gpgme_data_t filedata, sigdata;
gpgme_verify_result_t result;
gpgme_signature_t gpgsig;
- FILE *pkgfile = NULL, *sigfile = NULL;
+ FILE *file = NULL, *sigfile = NULL;
ALPM_LOG_FUNC;
if(!sig || !sig->rawdata) {
RET_ERR(PM_ERR_SIG_UNKNOWN, -1);
}
- if(!pkgpath || access(pkgpath, R_OK) != 0) {
- RET_ERR(PM_ERR_PKG_NOT_FOUND, -1);
+ if(!path || access(path, R_OK) != 0) {
+ RET_ERR(PM_ERR_NOT_A_FILE, -1);
}
if(gpgme_init()) {
/* pm_errno was set in gpgme_init() */
@@ -124,13 +124,13 @@ int _alpm_gpgme_checksig(const char *pkgpath, const pmpgpsig_t *sig)
/* create our necessary data objects to verify the signature */
/* first the package itself */
- pkgfile = fopen(pkgpath, "rb");
- if(pkgfile == NULL) {
- pm_errno = PM_ERR_PKG_OPEN;
+ file = fopen(path, "rb");
+ if(file == NULL) {
+ pm_errno = PM_ERR_NOT_A_FILE;
ret = -1;
goto error;
}
- err = gpgme_data_new_from_stream(&pkgdata, pkgfile);
+ err = gpgme_data_new_from_stream(&filedata, file);
CHECK_ERR();
/* next create data object for the signature */
@@ -138,7 +138,7 @@ int _alpm_gpgme_checksig(const char *pkgpath, const pmpgpsig_t *sig)
CHECK_ERR();
/* here's where the magic happens */
- err = gpgme_op_verify(ctx, sigdata, pkgdata, NULL);
+ err = gpgme_op_verify(ctx, sigdata, filedata, NULL);
CHECK_ERR();
result = gpgme_op_verify_result(ctx);
gpgsig = result->signatures;
@@ -161,34 +161,34 @@ int _alpm_gpgme_checksig(const char *pkgpath, const pmpgpsig_t *sig)
if(gpgsig->summary & GPGME_SIGSUM_VALID) {
/* good signature, continue */
- _alpm_log(PM_LOG_DEBUG, _("Package %s has a valid signature.\n"),
- pkgpath);
+ _alpm_log(PM_LOG_DEBUG, _("File %s has a valid signature.\n"),
+ path);
} else if(gpgsig->summary & GPGME_SIGSUM_GREEN) {
/* 'green' signature, not sure what to do here */
- _alpm_log(PM_LOG_WARNING, _("Package %s has a green signature.\n"),
- pkgpath);
+ _alpm_log(PM_LOG_WARNING, _("File %s has a green signature.\n"),
+ path);
} else if(gpgsig->summary & GPGME_SIGSUM_KEY_MISSING) {
pm_errno = PM_ERR_SIG_UNKNOWN;
- _alpm_log(PM_LOG_WARNING, _("Package %s has a signature from an unknown key.\n"),
- pkgpath);
+ _alpm_log(PM_LOG_WARNING, _("File %s has a signature from an unknown key.\n"),
+ path);
ret = -1;
} else {
/* we'll capture everything else here */
pm_errno = PM_ERR_SIG_INVALID;
- _alpm_log(PM_LOG_ERROR, _("Package %s has an invalid signature.\n"),
- pkgpath);
+ _alpm_log(PM_LOG_ERROR, _("File %s has an invalid signature.\n"),
+ path);
ret = 1;
}
error:
gpgme_data_release(sigdata);
- gpgme_data_release(pkgdata);
+ gpgme_data_release(filedata);
gpgme_release(ctx);
if(sigfile) {
fclose(sigfile);
}
- if(pkgfile) {
- fclose(pkgfile);
+ if(file) {
+ fclose(file);
}
if(err != GPG_ERR_NO_ERROR) {
_alpm_log(PM_LOG_ERROR, _("GPGME error: %s\n"), gpgme_strerror(err));
@@ -211,4 +211,19 @@ int SYMEXPORT alpm_pkg_check_pgp_signature(pmpkg_t *pkg)
alpm_pkg_get_pgpsig(pkg)));
}
+/**
+ * Check the PGP package signature for the given database.
+ * @param db the database to check
+ * @return a int value : 0 (valid), 1 (invalid), -1 (an error occured)
+ */
+int SYMEXPORT alpm_db_check_pgp_signature(pmdb_t *db)
+{
+ ALPM_LOG_FUNC;
+ ASSERT(db != NULL, return(0));
+
+ return(_alpm_gpgme_checksig(_alpm_db_path(db),
+ _alpm_db_pgpsig(db)));
+}
+
+
/* vim: set ts=2 sw=2 noet: */
diff --git a/lib/libalpm/signing.h b/lib/libalpm/signing.h
index c004697..8fbb25d 100644
--- a/lib/libalpm/signing.h
+++ b/lib/libalpm/signing.h
@@ -21,7 +21,17 @@
#include "alpm.h"
-int _alpm_gpgme_checksig(const char *pkgpath, const pmpgpsig_t *sig);
+struct __pmpgpsig_t {
+ /* we will either store the encoded data or the raw data-
+ * this way we can decode on an as-needed basis since most
+ * operations won't require the overhead of base64 decodes
+ * on all packages in a sync repository. */
+ char *encdata;
+ size_t rawlen;
+ unsigned char *rawdata;
+};
+
+int _alpm_gpgme_checksig(const char *path, const pmpgpsig_t *sig);
#endif /* _ALPM_SIGNING_H */
--
1.7.3.2