[pacman-dev] [PATCH 1/4] signing: move to new signing verification and return scheme
This gives us more granularity than the former Never/Optional/Always trifecta. The frontend still uses these values temporarily but that will be changed in a future patch. * Use 'siglevel' consistenly in method names, 'level' as variable name * The level becomes an enum bitmask value for flexibility * Signature check methods now return a array of status codes rather than a simple integer success/failure value. This allows callers to determine whether things such as an unknown signature are valid. * Specific signature error codes mostly disappear in favor of the above returned status code; pm_errno is now set only to PKG_INVALID_SIG or DB_INVALID_SIG as appropriate. Signed-off-by: Dan McGee <dan@archlinux.org> --- lib/libalpm/alpm.h | 64 ++++++++++++------ lib/libalpm/be_package.c | 20 +++--- lib/libalpm/be_sync.c | 30 ++++----- lib/libalpm/db.c | 16 ++-- lib/libalpm/db.h | 4 +- lib/libalpm/dload.c | 5 +- lib/libalpm/error.c | 12 ++-- lib/libalpm/handle.c | 15 ++-- lib/libalpm/handle.h | 2 +- lib/libalpm/package.h | 2 +- lib/libalpm/signing.c | 167 ++++++++++++++++++++++++++++++++++++---------- lib/libalpm/signing.h | 5 +- lib/libalpm/sync.c | 6 +- src/pacman/conf.c | 38 ++++++----- src/pacman/conf.h | 2 +- src/pacman/query.c | 2 +- src/pacman/sync.c | 2 +- src/pacman/upgrade.c | 4 +- src/util/cleanupdelta.c | 3 +- src/util/pactree.c | 3 +- src/util/testdb.c | 3 +- src/util/testpkg.c | 3 +- 22 files changed, 266 insertions(+), 142 deletions(-) diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index e733eb2..db8e8ef 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -87,14 +87,28 @@ typedef enum _alpm_fileconflicttype_t { } alpm_fileconflicttype_t; /** - * GPG signature verification options + * PGP signature verification options */ -typedef enum _pgp_verify_t { - PM_PGP_VERIFY_UNKNOWN, - PM_PGP_VERIFY_NEVER, - PM_PGP_VERIFY_OPTIONAL, - PM_PGP_VERIFY_ALWAYS -} pgp_verify_t; +typedef enum _alpm_siglevel_t { + ALPM_SIG_PACKAGE = (1 << 0), + ALPM_SIG_PACKAGE_OPTIONAL = (1 << 1), + ALPM_SIG_DATABASE = (1 << 2), + ALPM_SIG_DATABASE_OPTIONAL = (1 << 3), + ALPM_SIG_UNKNOWN_OK = (1 << 4), + ALPM_SIG_MARGINAL_OK = (1 << 5), + + ALPM_SIG_USE_DEFAULT = (1 << 31), +} alpm_siglevel_t; + +/** + * PGP signature verification return codes + */ +typedef enum _alpm_sigstatus_t { + ALPM_SIGSTATUS_VALID = 0, + ALPM_SIGSTATUS_MARGINAL, + ALPM_SIGSTATUS_UNKNOWN, + ALPM_SIGSTATUS_BAD +} alpm_sigstatus_t; /* * Structures @@ -173,6 +187,15 @@ typedef struct _alpm_backup_t { char *hash; } alpm_backup_t; +/** Signature result. Contains the number of signatures found and pointers to + * arrays containing key and status info. All contained arrays have size + * #count.*/ +typedef struct _alpm_sigresult_t { + int count; + alpm_sigstatus_t *status; + char **uid; +} alpm_sigresult_t; + /* * Logging facilities */ @@ -335,8 +358,8 @@ int alpm_option_set_usedelta(alpm_handle_t *handle, int usedelta); int alpm_option_get_checkspace(alpm_handle_t *handle); int alpm_option_set_checkspace(alpm_handle_t *handle, int checkspace); -pgp_verify_t alpm_option_get_default_sigverify(alpm_handle_t *handle); -int alpm_option_set_default_sigverify(alpm_handle_t *handle, pgp_verify_t level); +alpm_siglevel_t alpm_option_get_default_siglevel(alpm_handle_t *handle); +int alpm_option_set_default_siglevel(alpm_handle_t *handle, alpm_siglevel_t level); /** @} */ @@ -364,12 +387,12 @@ alpm_list_t *alpm_option_get_syncdbs(alpm_handle_t *handle); /** Register a sync database of packages. * @param handle the context handle * @param treename the name of the sync repository - * @param check_sig what level of signature checking to perform on the + * @param level what level of signature checking to perform on the * database; note that this must be a '.sig' file type verification - * @return a alpm_db_t* on success (the value), NULL on error + * @return an alpm_db_t* on success (the value), NULL on error */ alpm_db_t *alpm_db_register_sync(alpm_handle_t *handle, const char *treename, - pgp_verify_t check_sig); + alpm_siglevel_t level); /** Unregister a package database. * @param db pointer to the package database to unregister @@ -391,11 +414,11 @@ const char *alpm_db_get_name(const alpm_db_t *db); /** Get the signature verification level for a database. * Will return the default verification level if this database is set up - * with PM_PGP_VERIFY_UNKNOWN. + * with ALPM_SIG_USE_DEFAULT. * @param db pointer to the package database * @return the signature verification level */ -pgp_verify_t alpm_db_get_sigverify_level(alpm_db_t *db); +alpm_siglevel_t alpm_db_get_siglevel(alpm_db_t *db); /** Check the validity of a database. * This is most useful for sync databases and verifying signature status. @@ -473,13 +496,13 @@ int alpm_db_set_pkgreason(alpm_db_t *db, const char *name, alpm_pkgreason_t reas * @param filename location of the package tarball * @param full whether to stop the load after metadata is read or continue * through the full archive - * @param check_sig what level of package signature checking to perform on the + * @param level what level of package signature checking to perform on the * package; note that this must be a '.sig' file type verification * @param pkg address of the package pointer * @return 0 on success, -1 on error (pm_errno is set accordingly) */ int alpm_pkg_load(alpm_handle_t *handle, const char *filename, int full, - pgp_verify_t check_sig, alpm_pkg_t **pkg); + alpm_siglevel_t, alpm_pkg_t **pkg); /** Free a package. * @param pkg package pointer to free @@ -715,9 +738,9 @@ alpm_list_t *alpm_pkg_unused_deltas(alpm_pkg_t *pkg); * Signatures */ -int alpm_pkg_check_pgp_signature(alpm_pkg_t *pkg); +int alpm_pkg_check_pgp_signature(alpm_pkg_t *pkg, alpm_sigresult_t *result); -int alpm_db_check_pgp_signature(alpm_db_t *db); +int alpm_db_check_pgp_signature(alpm_db_t *db, alpm_sigresult_t *result); /* * Groups @@ -1025,6 +1048,7 @@ enum _alpm_errno_t { ALPM_ERR_DB_NOT_NULL, ALPM_ERR_DB_NOT_FOUND, ALPM_ERR_DB_INVALID, + ALPM_ERR_DB_INVALID_SIG, ALPM_ERR_DB_VERSION, ALPM_ERR_DB_WRITE, ALPM_ERR_DB_REMOVE, @@ -1044,15 +1068,15 @@ enum _alpm_errno_t { ALPM_ERR_PKG_NOT_FOUND, ALPM_ERR_PKG_IGNORED, ALPM_ERR_PKG_INVALID, + ALPM_ERR_PKG_INVALID_SIG, ALPM_ERR_PKG_OPEN, ALPM_ERR_PKG_CANT_REMOVE, ALPM_ERR_PKG_INVALID_NAME, ALPM_ERR_PKG_INVALID_ARCH, ALPM_ERR_PKG_REPO_NOT_FOUND, /* Signatures */ - ALPM_ERR_SIG_MISSINGDIR, + ALPM_ERR_SIG_MISSING, ALPM_ERR_SIG_INVALID, - ALPM_ERR_SIG_UNKNOWN, /* Deltas */ ALPM_ERR_DLT_INVALID, ALPM_ERR_DLT_PATCHFAILED, diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c index af21324..2f83610 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -233,7 +233,7 @@ static int parse_descfile(alpm_handle_t *handle, struct archive *a, alpm_pkg_t * */ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle, const char *pkgfile, int full, const char *md5sum, const char *base64_sig, - pgp_verify_t check_sig) + alpm_siglevel_t level) { int ret; int config = 0; @@ -271,14 +271,12 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle, const char *pkgfile, } _alpm_log(handle, ALPM_LOG_DEBUG, "base64_sig: %s\n", base64_sig); - if(check_sig != PM_PGP_VERIFY_NEVER) { - _alpm_log(handle, ALPM_LOG_DEBUG, "checking signature for %s\n", pkgfile); - ret = _alpm_gpgme_checksig(handle, pkgfile, base64_sig); - if((check_sig == PM_PGP_VERIFY_ALWAYS && ret != 0) || - (check_sig == PM_PGP_VERIFY_OPTIONAL && ret == 1)) { - alpm_pkg_free(newpkg); - RET_ERR(handle, ALPM_ERR_SIG_INVALID, NULL); - } + if(level & ALPM_SIG_PACKAGE && + _alpm_check_pgp_helper(handle, pkgfile, base64_sig, + level & ALPM_SIG_PACKAGE_OPTIONAL, level & ALPM_SIG_MARGINAL_OK, + level & ALPM_SIG_UNKNOWN_OK, ALPM_ERR_PKG_INVALID_SIG)) { + _alpm_pkg_free(newpkg); + return NULL; } /* next- try to create an archive object to read in the package */ @@ -396,12 +394,12 @@ error: } int SYMEXPORT alpm_pkg_load(alpm_handle_t *handle, const char *filename, int full, - pgp_verify_t check_sig, alpm_pkg_t **pkg) + alpm_siglevel_t level, alpm_pkg_t **pkg) { CHECK_HANDLE(handle, return -1); ASSERT(pkg != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1)); - *pkg = _alpm_pkg_load_internal(handle, filename, full, NULL, NULL, check_sig); + *pkg = _alpm_pkg_load_internal(handle, filename, full, NULL, NULL, level); if(*pkg == NULL) { /* pm_errno is set by pkg_load */ return -1; diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index 368acce..2a6cb1b 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -69,7 +69,7 @@ static char *get_sync_dir(alpm_handle_t *handle) static int sync_db_validate(alpm_db_t *db) { - pgp_verify_t check_sig; + alpm_siglevel_t level; if(db->status & DB_STATUS_VALID) { return 0; @@ -77,10 +77,9 @@ static int sync_db_validate(alpm_db_t *db) /* this takes into account the default verification level if UNKNOWN * was assigned to this db */ - check_sig = alpm_db_get_sigverify_level(db); + level = alpm_db_get_siglevel(db); - if(check_sig != PM_PGP_VERIFY_NEVER) { - int ret; + if(level & ALPM_SIG_DATABASE) { const char *dbpath = _alpm_db_path(db); if(!dbpath) { /* pm_errno set in _alpm_db_path() */ @@ -93,12 +92,10 @@ static int sync_db_validate(alpm_db_t *db) return 0; } - _alpm_log(db->handle, ALPM_LOG_DEBUG, "checking signature for %s\n", - db->treename); - ret = _alpm_gpgme_checksig(db->handle, dbpath, NULL); - if((check_sig == PM_PGP_VERIFY_ALWAYS && ret != 0) || - (check_sig == PM_PGP_VERIFY_OPTIONAL && ret == 1)) { - RET_ERR(db->handle, ALPM_ERR_SIG_INVALID, -1); + if(_alpm_check_pgp_helper(db->handle, dbpath, NULL, + level & ALPM_SIG_DATABASE_OPTIONAL, level & ALPM_SIG_MARGINAL_OK, + level & ALPM_SIG_UNKNOWN_OK, ALPM_ERR_DB_INVALID_SIG)) { + return 1; } } @@ -149,7 +146,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) int ret = -1; mode_t oldmask; alpm_handle_t *handle; - pgp_verify_t check_sig; + alpm_siglevel_t level; /* Sanity checks */ ASSERT(db != NULL, return -1); @@ -166,7 +163,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) /* make sure we have a sane umask */ oldmask = umask(0022); - check_sig = alpm_db_get_sigverify_level(db); + level = alpm_db_get_siglevel(db); /* attempt to grab a lock */ if(_alpm_handle_lock(handle)) { @@ -186,8 +183,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) ret = _alpm_download(handle, fileurl, syncpath, force, 0, 0); - if(ret == 0 && (check_sig == PM_PGP_VERIFY_ALWAYS || - check_sig == PM_PGP_VERIFY_OPTIONAL)) { + if(ret == 0 && (level & ALPM_SIG_DATABASE)) { /* an existing sig file is no good at this point */ char *sigpath = _alpm_db_sig_path(db); if(!sigpath) { @@ -197,7 +193,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) unlink(sigpath); free(sigpath); - int errors_ok = (check_sig == PM_PGP_VERIFY_OPTIONAL); + int errors_ok = (level & ALPM_SIG_DATABASE_OPTIONAL); /* if we downloaded a DB, we want the .sig from the same server */ snprintf(fileurl, len, "%s/%s.db.sig", server, db->treename); @@ -586,7 +582,7 @@ struct db_operations sync_db_ops = { }; alpm_db_t *_alpm_db_register_sync(alpm_handle_t *handle, const char *treename, - pgp_verify_t level) + alpm_siglevel_t level) { alpm_db_t *db; @@ -598,7 +594,7 @@ alpm_db_t *_alpm_db_register_sync(alpm_handle_t *handle, const char *treename, } db->ops = &sync_db_ops; db->handle = handle; - db->pgp_verify = level; + db->siglevel = level; if(sync_db_validate(db)) { _alpm_db_free(db); diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c index 17f26e9..af27047 100644 --- a/lib/libalpm/db.c +++ b/lib/libalpm/db.c @@ -45,8 +45,8 @@ */ /** Register a sync database of packages. */ -alpm_db_t SYMEXPORT *alpm_db_register_sync(alpm_handle_t *handle, const char *treename, - pgp_verify_t check_sig) +alpm_db_t SYMEXPORT *alpm_db_register_sync(alpm_handle_t *handle, + const char *treename, alpm_siglevel_t level) { /* Sanity checks */ CHECK_HANDLE(handle, return NULL); @@ -55,7 +55,7 @@ alpm_db_t SYMEXPORT *alpm_db_register_sync(alpm_handle_t *handle, const char *tr /* Do not register a database if a transaction is on-going */ ASSERT(handle->trans == NULL, RET_ERR(handle, ALPM_ERR_TRANS_NOT_NULL, NULL)); - return _alpm_db_register_sync(handle, treename, check_sig); + return _alpm_db_register_sync(handle, treename, level); } /* Helper function for alpm_db_unregister{_all} */ @@ -220,13 +220,13 @@ const char SYMEXPORT *alpm_db_get_name(const alpm_db_t *db) } /** Get the signature verification level for a database. */ -pgp_verify_t SYMEXPORT alpm_db_get_sigverify_level(alpm_db_t *db) +alpm_siglevel_t SYMEXPORT alpm_db_get_siglevel(alpm_db_t *db) { ASSERT(db != NULL, return -1); - if(db->pgp_verify == PM_PGP_VERIFY_UNKNOWN) { - return alpm_option_get_default_sigverify(db->handle); + if(db->siglevel & ALPM_SIG_USE_DEFAULT) { + return alpm_option_get_default_siglevel(db->handle); } else { - return db->pgp_verify; + return db->siglevel; } } @@ -323,7 +323,7 @@ alpm_db_t *_alpm_db_new(const char *treename, int is_local) CALLOC(db, 1, sizeof(alpm_db_t), return NULL); STRDUP(db->treename, treename, return NULL); db->is_local = is_local; - db->pgp_verify = PM_PGP_VERIFY_UNKNOWN; + db->siglevel = 0; return db; } diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h index 0f00f68..a950130 100644 --- a/lib/libalpm/db.h +++ b/lib/libalpm/db.h @@ -69,7 +69,7 @@ struct __alpm_db_t { alpm_pkghash_t *pkgcache; alpm_list_t *grpcache; alpm_list_t *servers; - pgp_verify_t pgp_verify; + alpm_siglevel_t siglevel; struct db_operations *ops; }; @@ -84,7 +84,7 @@ int _alpm_db_cmp(const void *d1, const void *d2); alpm_list_t *_alpm_db_search(alpm_db_t *db, const alpm_list_t *needles); alpm_db_t *_alpm_db_register_local(alpm_handle_t *handle); alpm_db_t *_alpm_db_register_sync(alpm_handle_t *handle, const char *treename, - pgp_verify_t level); + alpm_siglevel_t level); void _alpm_db_unregister(alpm_db_t *db); /* be_*.c, backend specific calls */ diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index c7a1c2b..4b4d8df 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -363,11 +363,10 @@ char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url) _alpm_log(handle, ALPM_LOG_DEBUG, "successfully downloaded %s\n", url); /* attempt to download the signature */ - if(ret == 0 && (handle->sigverify == PM_PGP_VERIFY_ALWAYS || - handle->sigverify == PM_PGP_VERIFY_OPTIONAL)) { + if(ret == 0 && (handle->siglevel & ALPM_SIG_PACKAGE)) { char *sig_url; size_t len; - int errors_ok = (handle->sigverify == PM_PGP_VERIFY_OPTIONAL); + int errors_ok = (handle->siglevel & ALPM_SIG_PACKAGE_OPTIONAL); len = strlen(url) + 5; CALLOC(sig_url, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c index 8716109..7e0e5c8 100644 --- a/lib/libalpm/error.c +++ b/lib/libalpm/error.c @@ -72,6 +72,8 @@ const char SYMEXPORT *alpm_strerror(enum _alpm_errno_t err) return _("could not find database"); case ALPM_ERR_DB_INVALID: return _("invalid or corrupted database"); + case ALPM_ERR_DB_INVALID_SIG: + return _("invalid or corrupted database (PGP signature)"); case ALPM_ERR_DB_VERSION: return _("database is incorrect version"); case ALPM_ERR_DB_WRITE: @@ -106,7 +108,9 @@ const char SYMEXPORT *alpm_strerror(enum _alpm_errno_t err) case ALPM_ERR_PKG_IGNORED: return _("operation cancelled due to ignorepkg"); case ALPM_ERR_PKG_INVALID: - return _("invalid or corrupted package"); + return _("invalid or corrupted package (checksum)"); + case ALPM_ERR_PKG_INVALID_SIG: + return _("invalid or corrupted package (PGP signature)"); case ALPM_ERR_PKG_OPEN: return _("cannot open package file"); case ALPM_ERR_PKG_CANT_REMOVE: @@ -118,12 +122,10 @@ const char SYMEXPORT *alpm_strerror(enum _alpm_errno_t err) case ALPM_ERR_PKG_REPO_NOT_FOUND: return _("could not find repository for target"); /* Signatures */ - case ALPM_ERR_SIG_MISSINGDIR: - return _("signature directory not configured correctly"); + case ALPM_ERR_SIG_MISSING: + return _("missing PGP signature"); case ALPM_ERR_SIG_INVALID: return _("invalid PGP signature"); - case ALPM_ERR_SIG_UNKNOWN: - return _("unknown PGP signature"); /* Deltas */ case ALPM_ERR_DLT_INVALID: return _("invalid or corrupted delta"); diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index 22f3fc8..ddd76a2 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -45,7 +45,8 @@ alpm_handle_t *_alpm_handle_new() CALLOC(handle, 1, sizeof(alpm_handle_t), return NULL); - handle->sigverify = PM_PGP_VERIFY_OPTIONAL; + handle->siglevel = ALPM_SIG_PACKAGE | ALPM_SIG_PACKAGE_OPTIONAL | + ALPM_SIG_DATABASE | ALPM_SIG_DATABASE_OPTIONAL; return handle; } @@ -574,18 +575,18 @@ int SYMEXPORT alpm_option_set_checkspace(alpm_handle_t *handle, int checkspace) return 0; } -int SYMEXPORT alpm_option_set_default_sigverify(alpm_handle_t *handle, pgp_verify_t level) +int SYMEXPORT alpm_option_set_default_siglevel(alpm_handle_t *handle, + alpm_siglevel_t level) { CHECK_HANDLE(handle, return -1); - ASSERT(level != PM_PGP_VERIFY_UNKNOWN, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1)); - handle->sigverify = level; + handle->siglevel = level; return 0; } -pgp_verify_t SYMEXPORT alpm_option_get_default_sigverify(alpm_handle_t *handle) +alpm_siglevel_t SYMEXPORT alpm_option_get_default_siglevel(alpm_handle_t *handle) { - CHECK_HANDLE(handle, return PM_PGP_VERIFY_UNKNOWN); - return handle->sigverify; + CHECK_HANDLE(handle, return -1); + return handle->siglevel; } /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h index ae8c7c8..9e03858 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -69,7 +69,7 @@ struct __alpm_handle_t { char *arch; /* Architecture of packages we should allow */ int usedelta; /* Download deltas if possible */ int checkspace; /* Check disk space before installing */ - pgp_verify_t sigverify; /* Default signature verification level */ + alpm_siglevel_t siglevel; /* Default signature verification level */ /* error code */ enum _alpm_errno_t pm_errno; diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h index b602193..f76812b 100644 --- a/lib/libalpm/package.h +++ b/lib/libalpm/package.h @@ -151,7 +151,7 @@ void _alpm_pkg_free_trans(alpm_pkg_t *pkg); alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle, const char *pkgfile, int full, const char *md5sum, const char *base64_sig, - pgp_verify_t check_sig); + alpm_siglevel_t level); int _alpm_pkg_cmp(const void *p1, const void *p2); int _alpm_pkg_compare_versions(alpm_pkg_t *local_pkg, alpm_pkg_t *pkg); diff --git a/lib/libalpm/signing.c b/lib/libalpm/signing.c index 1ac9963..0dc15ad 100644 --- a/lib/libalpm/signing.c +++ b/lib/libalpm/signing.c @@ -117,9 +117,6 @@ static int init_gpgme(alpm_handle_t *handle) } sigdir = alpm_option_get_gpgdir(handle); - if(!sigdir) { - RET_ERR(handle, ALPM_ERR_SIG_MISSINGDIR, 1); - } /* calling gpgme_check_version() returns the current version and runs * some internal library setup code */ @@ -196,23 +193,27 @@ error: * Check the PGP signature for the given file path. * If base64_sig is provided, it will be used as the signature data after * decoding. If base64_sig is NULL, expect a signature file next to path - * (e.g. "%s.sig"). The return value will be 0 if all checked signatures are - * valid, 1 if there was some sort of problem (but not necessarily rejection), - * and -1 if an error occurred while checking signatures. If 1 is returned, - * pm_errno should be checked to see why the signatures did not pass muster. + * (e.g. "%s.sig"). + * + * The return value will be 0 if nothing abnormal happened during the signature + * check, and -1 if an error occurred while checking signatures or if a + * signature could not be found; pm_errno will be set. Note that "abnormal" + * does not include a failed signature; the value in #result should be checked + * to determine if the signature(s) are good. * @param handle the context handle * @param path the full path to a file * @param base64_sig optional PGP signature data in base64 encoding - * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred) + * @result + * @return 0 in normal cases, -1 if the something failed in the check process */ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, - const char *base64_sig) + const char *base64_sig, alpm_sigresult_t *result) { - int ret = 0; + int ret = -1, sigcount; gpgme_error_t err; gpgme_ctx_t ctx; gpgme_data_t filedata, sigdata; - gpgme_verify_result_t result; + gpgme_verify_result_t verify_result; gpgme_signature_t gpgsig; char *sigpath = NULL; unsigned char *decoded_sigdata = NULL; @@ -222,14 +223,18 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, RET_ERR(handle, ALPM_ERR_NOT_A_FILE, -1); } + if(!result) { + RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1); + } + result->count = 0; + if(!base64_sig) { size_t len = strlen(path) + 5; CALLOC(sigpath, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); snprintf(sigpath, len, "%s.sig", path); if(!access(sigpath, R_OK) == 0) { - FREE(sigpath); - RET_ERR(handle, ALPM_ERR_SIG_UNKNOWN, -1); + /* sigcount is 0 */ } } @@ -251,7 +256,6 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, file = fopen(path, "rb"); if(file == NULL) { handle->pm_errno = ALPM_ERR_NOT_A_FILE; - ret = -1; goto error; } err = gpgme_data_new_from_stream(&filedata, file); @@ -264,7 +268,7 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, int decode_ret = decode_signature(base64_sig, &decoded_sigdata, &data_len); if(decode_ret) { - ret = -1; + handle->pm_errno = ALPM_ERR_SIG_INVALID; goto error; } err = gpgme_data_new_from_mem(&sigdata, @@ -273,8 +277,7 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, /* file-based, it is on disk */ sigfile = fopen(sigpath, "rb"); if(sigfile == NULL) { - handle->pm_errno = ALPM_ERR_NOT_A_FILE; - ret = -1; + handle->pm_errno = ALPM_ERR_SIG_MISSING; goto error; } err = gpgme_data_new_from_stream(&sigdata, sigfile); @@ -284,16 +287,28 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, /* here's where the magic happens */ err = gpgme_op_verify(ctx, sigdata, filedata, NULL); CHECK_ERR(); - result = gpgme_op_verify_result(ctx); - gpgsig = result->signatures; - if(!gpgsig) { + verify_result = gpgme_op_verify_result(ctx); + if(!verify_result->signatures) { _alpm_log(handle, ALPM_LOG_DEBUG, "no signatures returned\n"); - ret = -1; + handle->pm_errno = ALPM_ERR_SIG_MISSING; goto error; } + for(gpgsig = verify_result->signatures, sigcount = 0; + gpgsig; gpgsig = gpgsig->next, sigcount++); + _alpm_log(handle, ALPM_LOG_DEBUG, "%d signatures returned\n", sigcount); + + result->status = calloc(sigcount, sizeof(alpm_sigstatus_t)); + result->uid = calloc(sigcount, sizeof(char*)); + if(!result->status || !result->uid) { + handle->pm_errno = ALPM_ERR_MEMORY; + goto error; + } + result->count = sigcount; - while(gpgsig) { + for(gpgsig = verify_result->signatures, sigcount = 0; gpgsig; + gpgsig = gpgsig->next, sigcount++) { alpm_list_t *summary_list, *summary; + alpm_sigstatus_t status; _alpm_log(handle, ALPM_LOG_DEBUG, "fingerprint: %s\n", gpgsig->fpr); summary_list = list_sigsum(gpgsig->summary); @@ -308,34 +323,53 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, string_validity(gpgsig->validity), gpgme_strerror(gpgsig->validity_reason)); - /* Note: this is structured so any bad signature will set the return code - * to a bad one, but good ones just leave the default value in place; e.g. - * worst case wins out. */ + err = gpgme_get_key(ctx, gpgsig->fpr, &key, 0); + if(gpg_err_code(err) == GPG_ERR_EOF) { + _alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed, unknown key\n"); + err = GPG_ERR_NO_ERROR; + } else { + CHECK_ERR(); + if(key->uids) { + const char *uid = key->uids->uid; + STRDUP(result->uid[sigcount], uid, + handle->pm_errno = ALPM_ERR_MEMORY; goto error); + _alpm_log(handle, ALPM_LOG_DEBUG, "key user: %s\n", uid); + } + gpgme_key_unref(key); + } + if(gpgsig->summary & GPGME_SIGSUM_VALID) { /* definite good signature */ _alpm_log(handle, ALPM_LOG_DEBUG, "result: valid signature\n"); + status = ALPM_SIGSTATUS_VALID; } else if(gpgsig->summary & GPGME_SIGSUM_GREEN) { /* good signature */ _alpm_log(handle, ALPM_LOG_DEBUG, "result: green signature\n"); + status = ALPM_SIGSTATUS_VALID; } else if(gpgsig->summary & GPGME_SIGSUM_RED) { /* definite bad signature, error */ _alpm_log(handle, ALPM_LOG_DEBUG, "result: red signature\n"); - handle->pm_errno = ALPM_ERR_SIG_INVALID; - ret = 1; + status = ALPM_SIGSTATUS_BAD; } else if(gpgsig->summary & GPGME_SIGSUM_KEY_MISSING) { _alpm_log(handle, ALPM_LOG_DEBUG, "result: signature from unknown key\n"); - handle->pm_errno = ALPM_ERR_SIG_UNKNOWN; - ret = 1; + status = ALPM_SIGSTATUS_UNKNOWN; + } else if(gpgsig->summary & GPGME_SIGSUM_KEY_EXPIRED) { + _alpm_log(handle, ALPM_LOG_DEBUG, "result: key expired\n"); + status = ALPM_SIGSTATUS_BAD; + } else if(gpgsig->summary & GPGME_SIGSUM_SIG_EXPIRED) { + _alpm_log(handle, ALPM_LOG_DEBUG, "result: signature expired\n"); + status = ALPM_SIGSTATUS_BAD; } else { /* we'll capture everything else here */ _alpm_log(handle, ALPM_LOG_DEBUG, "result: invalid signature\n"); - handle->pm_errno = ALPM_ERR_SIG_INVALID; - ret = 1; + status = ALPM_SIGSTATUS_BAD; } - gpgsig = gpgsig->next; + result->status[sigcount] = status; } + ret = 0; + error: gpgme_data_release(sigdata); gpgme_data_release(filedata); @@ -362,18 +396,77 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, } #endif +int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path, + const char *base64_sig, int optional, int marginal, int unknown, + enum _alpm_errno_t invalid_err) +{ + alpm_sigresult_t result; + int ret; + + memset(&result, 0, sizeof(result)); + + _alpm_log(handle, ALPM_LOG_DEBUG, "checking signatures for %s\n", path); + ret = _alpm_gpgme_checksig(handle, path, base64_sig, &result); + if(ret && handle->pm_errno == ALPM_ERR_SIG_MISSING) { + if(optional) { + _alpm_log(handle, ALPM_LOG_DEBUG, "missing optional signature\n"); + handle->pm_errno = 0; + ret = 0; + } else { + _alpm_log(handle, ALPM_LOG_DEBUG, "missing required signature\n"); + /* ret will already be -1 */ + } + } else if(ret) { + _alpm_log(handle, ALPM_LOG_DEBUG, "signature check failed\n"); + /* ret will already be -1 */ + } else { + int num; + for(num = result.count; num < result.count; num++) { + /* fallthrough in this case block is on purpose. if one allows unknown + * signatures, then a marginal signature should be allowed as well, and + * if neither of these are allowed we fall all the way through to bad. */ + switch(result.status[num]) { + case ALPM_SIGSTATUS_VALID: + _alpm_log(handle, ALPM_LOG_DEBUG, "signature is valid\n"); + break; + case ALPM_SIGSTATUS_MARGINAL: + if(marginal) { + _alpm_log(handle, ALPM_LOG_DEBUG, "allowing marginal signature\n"); + break; + } + case ALPM_SIGSTATUS_UNKNOWN: + if(unknown) { + _alpm_log(handle, ALPM_LOG_DEBUG, "allowing unknown signature\n"); + break; + } + case ALPM_SIGSTATUS_BAD: + default: + _alpm_log(handle, ALPM_LOG_DEBUG, "signature is invalid\n"); + handle->pm_errno = invalid_err; + ret = -1; + } + } + } + + free(result.status); + free(result.uid); + return ret; +} + /** * Check the PGP signature for the given package file. * @param pkg the package to check * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred) */ -int SYMEXPORT alpm_pkg_check_pgp_signature(alpm_pkg_t *pkg) +int SYMEXPORT alpm_pkg_check_pgp_signature(alpm_pkg_t *pkg, + alpm_sigresult_t *result) { ASSERT(pkg != NULL, return -1); + ASSERT(result != NULL, RET_ERR(pkg->handle, ALPM_ERR_WRONG_ARGS, -1)); pkg->handle->pm_errno = 0; return _alpm_gpgme_checksig(pkg->handle, alpm_pkg_get_filename(pkg), - pkg->base64_sig); + pkg->base64_sig, result); } /** @@ -381,12 +474,14 @@ int SYMEXPORT alpm_pkg_check_pgp_signature(alpm_pkg_t *pkg) * @param db the database to check * @return a int value : 0 (valid), 1 (invalid), -1 (an error occurred) */ -int SYMEXPORT alpm_db_check_pgp_signature(alpm_db_t *db) +int SYMEXPORT alpm_db_check_pgp_signature(alpm_db_t *db, + alpm_sigresult_t *result) { ASSERT(db != NULL, return -1); + ASSERT(result != NULL, RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, -1)); db->handle->pm_errno = 0; - return _alpm_gpgme_checksig(db->handle, _alpm_db_path(db), NULL); + return _alpm_gpgme_checksig(db->handle, _alpm_db_path(db), NULL, result); } /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/signing.h b/lib/libalpm/signing.h index b1b90d7..22f6357 100644 --- a/lib/libalpm/signing.h +++ b/lib/libalpm/signing.h @@ -22,7 +22,10 @@ #include "alpm.h" int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, - const char *base64_sig); + const char *base64_sig, alpm_sigresult_t *result); +int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path, + const char *base64_sig, int optional, int marginal, int unknown, + enum _alpm_errno_t invalid_err); #endif /* _ALPM_SIGNING_H */ diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index d6b54ba..783c728 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -863,7 +863,7 @@ int _alpm_sync_commit(alpm_handle_t *handle, alpm_list_t **data) int percent = (current * 100) / numtargs; const char *filename; char *filepath; - pgp_verify_t check_sig; + alpm_siglevel_t level; PROGRESS(trans, ALPM_TRANS_PROGRESS_INTEGRITY_START, "", percent, numtargs, current); @@ -874,7 +874,7 @@ int _alpm_sync_commit(alpm_handle_t *handle, alpm_list_t **data) filename = alpm_pkg_get_filename(spkg); filepath = _alpm_filecache_find(handle, filename); alpm_db_t *sdb = alpm_pkg_get_db(spkg); - check_sig = alpm_db_get_sigverify_level(sdb); + level = alpm_db_get_siglevel(sdb); /* load the package file and replace pkgcache entry with it in the target list */ /* TODO: alpm_pkg_get_db() will not work on this target anymore */ @@ -882,7 +882,7 @@ int _alpm_sync_commit(alpm_handle_t *handle, alpm_list_t **data) "replacing pkgcache entry with package file for target %s\n", spkg->name); alpm_pkg_t *pkgfile =_alpm_pkg_load_internal(handle, filepath, 1, spkg->md5sum, - spkg->base64_sig, check_sig); + spkg->base64_sig, level); if(!pkgfile) { errors++; *data = alpm_list_add(*data, strdup(filename)); diff --git a/src/pacman/conf.c b/src/pacman/conf.c index f2df260..3af3fa5 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -52,7 +52,7 @@ config_t *config_new(void) newconfig->op = PM_OP_MAIN; newconfig->logmask = ALPM_LOG_ERROR | ALPM_LOG_WARNING; newconfig->configfile = strdup(CONFFILE); - newconfig->sigverify = PM_PGP_VERIFY_UNKNOWN; + newconfig->siglevel = ALPM_SIG_USE_DEFAULT; return newconfig; } @@ -222,17 +222,18 @@ int config_set_arch(const char *arch) return 0; } -static pgp_verify_t option_verifysig(const char *value) +static alpm_siglevel_t option_verifysig(const char *value) { - pgp_verify_t level; + alpm_siglevel_t level; if(strcmp(value, "Always") == 0) { - level = PM_PGP_VERIFY_ALWAYS; + level = ALPM_SIG_PACKAGE | ALPM_SIG_DATABASE; } else if(strcmp(value, "Optional") == 0) { - level = PM_PGP_VERIFY_OPTIONAL; + level = ALPM_SIG_PACKAGE | ALPM_SIG_PACKAGE_OPTIONAL | + ALPM_SIG_DATABASE | ALPM_SIG_DATABASE_OPTIONAL; } else if(strcmp(value, "Never") == 0) { - level = PM_PGP_VERIFY_NEVER; + level = 0; } else { - level = PM_PGP_VERIFY_UNKNOWN; + return -1; } pm_printf(ALPM_LOG_DEBUG, "config: VerifySig = %s (%d)\n", value, level); return level; @@ -359,9 +360,9 @@ static int _parse_options(const char *key, char *value, } FREELIST(methods); } else if(strcmp(key, "VerifySig") == 0) { - pgp_verify_t level = option_verifysig(value); - if(level != PM_PGP_VERIFY_UNKNOWN) { - config->sigverify = level; + alpm_siglevel_t level = option_verifysig(value); + if(level != -1) { + config->siglevel = level; } else { pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: directive '%s' has invalid value '%s'\n"), @@ -484,8 +485,8 @@ static int setup_libalpm(void) alpm_option_set_cachedirs(handle, config->cachedirs); } - if(config->sigverify != PM_PGP_VERIFY_UNKNOWN) { - alpm_option_set_default_sigverify(handle, config->sigverify); + if(config->siglevel != ALPM_SIG_USE_DEFAULT) { + alpm_option_set_default_siglevel(handle, config->siglevel); } if(config->xfercommand) { @@ -518,7 +519,7 @@ struct section_t { char *name; int is_options; /* db section option gathering */ - pgp_verify_t sigverify; + alpm_siglevel_t siglevel; alpm_list_t *servers; }; @@ -545,7 +546,7 @@ static int finish_section(struct section_t *section, int parse_options) } /* if we are not looking at options sections only, register a db */ - db = alpm_db_register_sync(config->handle, section->name, section->sigverify); + db = alpm_db_register_sync(config->handle, section->name, section->siglevel); if(db == NULL) { pm_printf(ALPM_LOG_ERROR, _("could not register '%s' database (%s)\n"), section->name, alpm_strerror(alpm_errno(config->handle))); @@ -568,7 +569,7 @@ static int finish_section(struct section_t *section, int parse_options) cleanup: alpm_list_free(section->servers); section->servers = NULL; - section->sigverify = 0; + section->siglevel = ALPM_SIG_USE_DEFAULT; free(section->name); section->name = NULL; return ret; @@ -726,9 +727,9 @@ static int _parseconfig(const char *file, struct section_t *section, } section->servers = alpm_list_add(section->servers, strdup(value)); } else if(strcmp(key, "VerifySig") == 0) { - pgp_verify_t level = option_verifysig(value); - if(level != PM_PGP_VERIFY_UNKNOWN) { - section->sigverify = level; + alpm_siglevel_t level = option_verifysig(value); + if(level != -1) { + section->siglevel = level; } else { pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: directive '%s' has invalid value '%s'\n"), @@ -763,6 +764,7 @@ int parseconfig(const char *file) int ret; struct section_t section; memset(§ion, 0, sizeof(struct section_t)); + section.siglevel = ALPM_SIG_USE_DEFAULT; /* the config parse is a two-pass affair. We first parse the entire thing for * the [options] section so we can get all default and path options set. * Next, we go back and parse everything but [options]. */ diff --git a/src/pacman/conf.h b/src/pacman/conf.h index 64b911a..bce42ab 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -71,7 +71,7 @@ typedef struct __config_t { unsigned short noask; unsigned int ask; alpm_transflag_t flags; - pgp_verify_t sigverify; + alpm_siglevel_t siglevel; /* conf file options */ /* I Love Candy! */ diff --git a/src/pacman/query.c b/src/pacman/query.c index 045dc7f..5dff03f 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -551,7 +551,7 @@ int pacman_query(alpm_list_t *targets) char *strname = alpm_list_getdata(i); if(config->op_q_isfile) { - alpm_pkg_load(config->handle, strname, 1, PM_PGP_VERIFY_OPTIONAL, &pkg); + alpm_pkg_load(config->handle, strname, 1, 0, &pkg); } else { pkg = alpm_db_get_pkg(db_local, strname); } diff --git a/src/pacman/sync.c b/src/pacman/sync.c index ad6d5e5..5f67236 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -220,7 +220,7 @@ static int sync_cleancache(int level) /* attempt to load the package, prompt removal on failures as we may have * files here that aren't valid packages. we also don't need a full * load of the package, just the metadata. */ - if(alpm_pkg_load(config->handle, path, 0, PM_PGP_VERIFY_NEVER, &localpkg) != 0 + if(alpm_pkg_load(config->handle, path, 0, 0, &localpkg) != 0 || localpkg == NULL) { if(yesno(_("File %s does not seem to be a valid package, remove it?"), path)) { diff --git a/src/pacman/upgrade.c b/src/pacman/upgrade.c index 95b17cc..11d00e7 100644 --- a/src/pacman/upgrade.c +++ b/src/pacman/upgrade.c @@ -42,7 +42,7 @@ int pacman_upgrade(alpm_list_t *targets) { alpm_list_t *i, *data = NULL; - pgp_verify_t check_sig = alpm_option_get_default_sigverify(config->handle); + alpm_siglevel_t level = alpm_option_get_default_siglevel(config->handle); int retval = 0; if(targets == NULL) { @@ -76,7 +76,7 @@ int pacman_upgrade(alpm_list_t *targets) char *targ = alpm_list_getdata(i); alpm_pkg_t *pkg; - if(alpm_pkg_load(config->handle, targ, 1, check_sig, &pkg) != 0) { + if(alpm_pkg_load(config->handle, targ, 1, level, &pkg) != 0) { pm_fprintf(stderr, ALPM_LOG_ERROR, "'%s': %s\n", targ, alpm_strerror(alpm_errno(config->handle))); trans_release(); diff --git a/src/util/cleanupdelta.c b/src/util/cleanupdelta.c index 08d8a55..a45efdc 100644 --- a/src/util/cleanupdelta.c +++ b/src/util/cleanupdelta.c @@ -71,11 +71,12 @@ static void checkdbs(const char *dbpath, alpm_list_t *dbnames) { char syncdbpath[PATH_MAX]; alpm_db_t *db = NULL; alpm_list_t *i; + const alpm_siglevel_t level = ALPM_SIG_DATABASE | ALPM_SIG_DATABASE_OPTIONAL; for(i = dbnames; i; i = alpm_list_next(i)) { char *dbname = alpm_list_getdata(i); snprintf(syncdbpath, PATH_MAX, "%s/sync/%s", dbpath, dbname); - db = alpm_db_register_sync(handle, dbname, PM_PGP_VERIFY_OPTIONAL); + db = alpm_db_register_sync(handle, dbname, level); if(db == NULL) { fprintf(stderr, "error: could not register sync database (%s)\n", alpm_strerror(alpm_errno(handle))); diff --git a/src/util/pactree.c b/src/util/pactree.c index 7b87ac1..9b67863 100644 --- a/src/util/pactree.c +++ b/src/util/pactree.c @@ -124,6 +124,7 @@ static int register_syncs(void) { FILE *fp; char *ptr, *section = NULL; char line[LINE_MAX]; + const alpm_siglevel_t level = ALPM_SIG_DATABASE | ALPM_SIG_DATABASE_OPTIONAL; fp = fopen(CONFFILE, "r"); if(!fp) { @@ -147,7 +148,7 @@ static int register_syncs(void) { section = strndup(&line[1], strlen(line) - 2); if(section && strcmp(section, "options") != 0) { - alpm_db_register_sync(handle, section, PM_PGP_VERIFY_OPTIONAL); + alpm_db_register_sync(handle, section, level); } } } diff --git a/src/util/testdb.c b/src/util/testdb.c index 642890b..ee169df 100644 --- a/src/util/testdb.c +++ b/src/util/testdb.c @@ -148,10 +148,11 @@ static int check_syncdbs(alpm_list_t *dbnames) { int ret = 0; alpm_db_t *db = NULL; alpm_list_t *i, *pkglist, *syncpkglist = NULL; + const alpm_siglevel_t level = ALPM_SIG_DATABASE | ALPM_SIG_DATABASE_OPTIONAL; for(i = dbnames; i; i = alpm_list_next(i)) { char *dbname = alpm_list_getdata(i); - db = alpm_db_register_sync(handle, dbname, PM_PGP_VERIFY_OPTIONAL); + db = alpm_db_register_sync(handle, dbname, level); if(db == NULL) { fprintf(stderr, "error: could not register sync database (%s)\n", alpm_strerror(alpm_errno(handle))); diff --git a/src/util/testpkg.c b/src/util/testpkg.c index 03234ed..ac2dde2 100644 --- a/src/util/testpkg.c +++ b/src/util/testpkg.c @@ -43,6 +43,7 @@ int main(int argc, char *argv[]) alpm_handle_t *handle; enum _alpm_errno_t err; alpm_pkg_t *pkg = NULL; + const alpm_siglevel_t level = ALPM_SIG_PACKAGE | ALPM_SIG_PACKAGE_OPTIONAL; if(argc != 2) { fprintf(stderr, "usage: %s <package file>\n", BASENAME); @@ -58,7 +59,7 @@ int main(int argc, char *argv[]) /* let us get log messages from libalpm */ alpm_option_set_logcb(handle, output_cb); - if(alpm_pkg_load(handle, argv[1], 1, PM_PGP_VERIFY_OPTIONAL, &pkg) == -1 + if(alpm_pkg_load(handle, argv[1], 1, level, &pkg) == -1 || pkg == NULL) { err = alpm_errno(handle); switch(err) { -- 1.7.6
The error code is in fact a bitmask value of an error code and an error source, so use the proper function to get only the relevant bits. For the no error case, this shouldn't ever matter, but it bit me when I was trying to compare the error code to other values and wondered why it wasn't working, so set a good example. Signed-off-by: Dan McGee <dan@archlinux.org> --- lib/libalpm/signing.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/libalpm/signing.c b/lib/libalpm/signing.c index 0dc15ad..9c5d8cb 100644 --- a/lib/libalpm/signing.c +++ b/lib/libalpm/signing.c @@ -39,7 +39,7 @@ #if HAVE_LIBGPGME #define CHECK_ERR(void) do { \ - if(err != GPG_ERR_NO_ERROR) { goto error; } \ + if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { goto error; } \ } while(0) static const char *string_validity(gpgme_validity_t validity) @@ -382,7 +382,7 @@ error: } FREE(sigpath); FREE(decoded_sigdata); - if(err != GPG_ERR_NO_ERROR) { + if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { _alpm_log(handle, ALPM_LOG_ERROR, _("GPGME error: %s\n"), gpgme_strerror(err)); RET_ERR(handle, ALPM_ERR_GPGME, -1); } -- 1.7.6
Show output in -Qip for each package signature, which includes the UID string from the key ("Joe User <joe@example.com>") and the validity of said key. Example output: Signatures : Valid signature from "Dan McGee <dpmcgee@gmail.com>" Unknown signature from "<Key Unknown>" Invalid signature from "Dan McGee <dpmcgee@gmail.com>" Also add a backend alpm_sigresult_cleanup() function since memory allocation took place on this object, and we need some way of freeing it. Signed-off-by: Dan McGee <dan@archlinux.org> --- lib/libalpm/alpm.h | 2 ++ lib/libalpm/signing.c | 22 ++++++++++++++++++++-- src/pacman/package.c | 11 +++++++++++ src/pacman/util.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- src/pacman/util.h | 1 + 5 files changed, 81 insertions(+), 3 deletions(-) diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index db8e8ef..e3304df 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -742,6 +742,8 @@ int alpm_pkg_check_pgp_signature(alpm_pkg_t *pkg, alpm_sigresult_t *result); int alpm_db_check_pgp_signature(alpm_db_t *db, alpm_sigresult_t *result); +int alpm_sigresult_cleanup(alpm_sigresult_t *result); + /* * Groups */ diff --git a/lib/libalpm/signing.c b/lib/libalpm/signing.c index 9c5d8cb..7b048f6 100644 --- a/lib/libalpm/signing.c +++ b/lib/libalpm/signing.c @@ -309,6 +309,7 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, gpgsig = gpgsig->next, sigcount++) { alpm_list_t *summary_list, *summary; alpm_sigstatus_t status; + gpgme_key_t key; _alpm_log(handle, ALPM_LOG_DEBUG, "fingerprint: %s\n", gpgsig->fpr); summary_list = list_sigsum(gpgsig->summary); @@ -448,8 +449,7 @@ int _alpm_check_pgp_helper(alpm_handle_t *handle, const char *path, } } - free(result.status); - free(result.uid); + alpm_sigresult_cleanup(&result); return ret; } @@ -484,4 +484,22 @@ int SYMEXPORT alpm_db_check_pgp_signature(alpm_db_t *db, return _alpm_gpgme_checksig(db->handle, _alpm_db_path(db), NULL, result); } +int SYMEXPORT alpm_sigresult_cleanup(alpm_sigresult_t *result) +{ + ASSERT(result != NULL, return -1); + /* Because it is likely result is on the stack, uid and status may have bogus + * values in the struct. Only look at them if count is greater than 0. */ + if(result->count > 0) { + free(result->status); + if(result->uid) { + int i; + for(i = 0; i < result->count; i++) { + free(result->uid[i]); + } + free(result->uid); + } + } + return 0; +} + /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/package.c b/src/pacman/package.c index 5514f00..72b71dd 100644 --- a/src/pacman/package.c +++ b/src/pacman/package.c @@ -136,6 +136,17 @@ void dump_pkg_full(alpm_pkg_t *pkg, enum pkg_from from, int extra) if(from == PKG_FROM_SYNCDB) { string_display(_("MD5 Sum :"), alpm_pkg_get_md5sum(pkg)); } + if(from == PKG_FROM_FILE) { + alpm_sigresult_t result; + int err = alpm_pkg_check_pgp_signature(pkg, &result); + if(err) { + string_display(_("Signatures :"), + _("Error checking package signatures")); + } else { + signature_display(_("Signatures :"), &result); + } + alpm_sigresult_cleanup(&result); + } string_display(_("Description :"), alpm_pkg_get_desc(pkg)); /* Print additional package info if info flag passed more than once */ diff --git a/src/pacman/util.c b/src/pacman/util.c index 9ced7aa..28beaca 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -613,7 +613,6 @@ void list_display(const char *title, const alpm_list_t *list) void list_display_linebreak(const char *title, const alpm_list_t *list) { - const alpm_list_t *i; int len = 0; if(title) { @@ -624,6 +623,7 @@ void list_display_linebreak(const char *title, const alpm_list_t *list) if(!list) { printf("%s\n", _("None")); } else { + const alpm_list_t *i; /* Print the first element */ indentprint((const char *) alpm_list_getdata(list), len); printf("\n"); @@ -639,6 +639,52 @@ void list_display_linebreak(const char *title, const alpm_list_t *list) } } +void signature_display(const char *title, alpm_sigresult_t *result) +{ + int len = 0; + + if(title) { + len = string_length(title) + 1; + printf("%s ", title); + } + if(result->count == 0) { + printf(_("None")); + } else { + int i; + for(i = 0; i < result->count; i++) { + char sigline[PATH_MAX]; + const char *validity, *name; + /* Don't re-indent the first result */ + if(i != 0) { + int j; + for(j = 1; j <= len; j++) { + printf(" "); + } + } + switch(result->status[i]) { + case ALPM_SIGSTATUS_VALID: + validity = _("Valid signature"); + break; + case ALPM_SIGSTATUS_MARGINAL: + validity = _("Marginal signature"); + break; + case ALPM_SIGSTATUS_UNKNOWN: + validity = _("Unknown signature"); + break; + case ALPM_SIGSTATUS_BAD: + validity = _("Invalid signature"); + break; + default: + validity = _("Signature error"); + } + name = result->uid[i] ? result->uid[i] : _("<Key Unknown>"); + snprintf(sigline, PATH_MAX, _("%s from \"%s\""), validity, name); + indentprint(sigline, len); + printf("\n"); + } + } +} + /* creates a header row for use with table_display */ static alpm_list_t *create_verbose_header(int install) { diff --git a/src/pacman/util.h b/src/pacman/util.h index 5d86dfd..a914d0c 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -56,6 +56,7 @@ double humanize_size(off_t bytes, const char target_unit, int long_labels, const int table_display(const char *title, const alpm_list_t *header, const alpm_list_t *rows); void list_display(const char *title, const alpm_list_t *list); void list_display_linebreak(const char *title, const alpm_list_t *list); +void signature_display(const char *title, alpm_sigresult_t *result); void display_targets(const alpm_list_t *pkgs, int install); int str_cmp(const void *s1, const void *s2); void display_new_optdepends(alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg); -- 1.7.6
They are placeholders, but important for things like trying to re-sync a database missing a signature. By using the alpm_db_validity() method at the right time, a client can take the appropriate action with these invalid databases as necessary. In pacman's case, we disallow just about anything that involves looking at a sync database outside of an '-Sy' operation (although we do check the validity immediately after). A few operations are still permitted- '-Q' ops that don't touch sync databases as well as '-R'. Signed-off-by: Dan McGee <dan@archlinux.org> --- lib/libalpm/be_sync.c | 6 +----- lib/libalpm/sync.c | 8 ++++++++ lib/libalpm/trans.c | 8 -------- src/pacman/database.c | 2 +- src/pacman/query.c | 7 ++----- src/pacman/remove.c | 2 +- src/pacman/sync.c | 15 +++++++++------ src/pacman/upgrade.c | 2 +- src/pacman/util.c | 30 +++++++++++++++++++++++++++++- src/pacman/util.h | 3 ++- 10 files changed, 54 insertions(+), 29 deletions(-) diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index 2a6cb1b..5c71343 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -596,14 +596,10 @@ alpm_db_t *_alpm_db_register_sync(alpm_handle_t *handle, const char *treename, db->handle = handle; db->siglevel = level; - if(sync_db_validate(db)) { - _alpm_db_free(db); - return NULL; - } + sync_db_validate(db); handle->dbs_sync = alpm_list_add(handle->dbs_sync, db); return db; } - /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index 783c728..1d71279 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -315,6 +315,14 @@ int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data) *data = NULL; } + /* ensure all sync database are valid since we will be using them */ + for(i = handle->dbs_sync; i; i = i->next) { + const alpm_db_t *db = i->data; + if(!(db->status & DB_STATUS_VALID)) { + RET_ERR(handle, ALPM_ERR_DB_INVALID, -1); + } + } + if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) { alpm_list_t *resolved = NULL; /* target list after resolvedeps */ diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c index 2698949..6cea9b7 100644 --- a/lib/libalpm/trans.c +++ b/lib/libalpm/trans.c @@ -53,19 +53,11 @@ int SYMEXPORT alpm_trans_init(alpm_handle_t *handle, alpm_transflag_t flags, alpm_trans_cb_progress progress) { alpm_trans_t *trans; - alpm_list_t *i; /* Sanity checks */ CHECK_HANDLE(handle, return -1); ASSERT(handle->trans == NULL, RET_ERR(handle, ALPM_ERR_TRANS_NOT_NULL, -1)); - for(i = handle->dbs_sync; i; i = i->next) { - const alpm_db_t *db = i->data; - if(!(db->status & DB_STATUS_VALID)) { - RET_ERR(handle, ALPM_ERR_DB_INVALID, -1); - } - } - /* lock db */ if(!(flags & ALPM_TRANS_FLAG_NOLOCK)) { if(_alpm_handle_lock(handle)) { diff --git a/src/pacman/database.c b/src/pacman/database.c index 5a1aa52..41efdd3 100644 --- a/src/pacman/database.c +++ b/src/pacman/database.c @@ -59,7 +59,7 @@ int pacman_database(alpm_list_t *targets) } /* Lock database */ - if(trans_init(0) == -1) { + if(trans_init(0, 0) == -1) { return 1; } diff --git a/src/pacman/query.c b/src/pacman/query.c index 5dff03f..90329b3 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -501,11 +501,8 @@ int pacman_query(alpm_list_t *targets) return ret; } - if(config->op_q_foreign) { - /* ensure we have at least one valid sync db set up */ - alpm_list_t *sync_dbs = alpm_option_get_syncdbs(config->handle); - if(sync_dbs == NULL) { - pm_printf(ALPM_LOG_ERROR, _("no usable package repositories configured.\n")); + if(config->op_q_foreign || config->op_q_upgrade) { + if(check_syncdbs(1, 1)) { return 1; } } diff --git a/src/pacman/remove.c b/src/pacman/remove.c index 3cedb89..f0ac04e 100644 --- a/src/pacman/remove.c +++ b/src/pacman/remove.c @@ -81,7 +81,7 @@ int pacman_remove(alpm_list_t *targets) } /* Step 0: create a new transaction */ - if(trans_init(config->flags) == -1) { + if(trans_init(config->flags, 0) == -1) { return 1; } diff --git a/src/pacman/sync.c b/src/pacman/sync.c index 5f67236..26c9ccc 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -738,7 +738,7 @@ static int sync_trans(alpm_list_t *targets) alpm_list_t *i; /* Step 1: create a new transaction... */ - if(trans_init(config->flags) == -1) { + if(trans_init(config->flags, 1) == -1) { return 1; } @@ -885,7 +885,7 @@ int pacman_sync(alpm_list_t *targets) if(config->op_s_clean) { int ret = 0; - if(trans_init(0) == -1) { + if(trans_init(0, 0) == -1) { return 1; } @@ -900,13 +900,12 @@ int pacman_sync(alpm_list_t *targets) return ret; } - /* ensure we have at least one valid sync db set up */ - sync_dbs = alpm_option_get_syncdbs(config->handle); - if(sync_dbs == NULL) { - pm_printf(ALPM_LOG_ERROR, _("no usable package repositories configured.\n")); + if(check_syncdbs(1, 0)) { return 1; } + sync_dbs = alpm_option_get_syncdbs(config->handle); + if(config->op_s_sync) { /* grab a fresh package list */ printf(_(":: Synchronizing package databases...\n")); @@ -916,6 +915,10 @@ int pacman_sync(alpm_list_t *targets) } } + if(check_syncdbs(1, 1)) { + return 1; + } + /* search for a package */ if(config->op_s_search) { return sync_search(sync_dbs, targets); diff --git a/src/pacman/upgrade.c b/src/pacman/upgrade.c index 11d00e7..a99b137 100644 --- a/src/pacman/upgrade.c +++ b/src/pacman/upgrade.c @@ -67,7 +67,7 @@ int pacman_upgrade(alpm_list_t *targets) } /* Step 1: create a new transaction */ - if(trans_init(config->flags) == -1) { + if(trans_init(config->flags, 1) == -1) { return 1; } diff --git a/src/pacman/util.c b/src/pacman/util.c index 28beaca..c367d36 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -49,9 +49,12 @@ #include "callback.h" -int trans_init(alpm_transflag_t flags) +int trans_init(alpm_transflag_t flags, int check_valid) { int ret; + + check_syncdbs(0, check_valid); + if(config->print) { ret = alpm_trans_init(config->handle, flags, NULL, NULL, NULL); } else { @@ -101,6 +104,31 @@ int needs_root(void) } } +int check_syncdbs(size_t need_repos, int check_valid) +{ + int ret = 0; + alpm_list_t *i; + alpm_list_t *sync_dbs = alpm_option_get_syncdbs(config->handle); + + if(need_repos && sync_dbs == NULL) { + pm_printf(ALPM_LOG_ERROR, _("no usable package repositories configured.\n")); + return 1; + } + + if(check_valid) { + /* ensure all known dbs are valid */ + for(i = sync_dbs; i; i = alpm_list_next(i)) { + alpm_db_t *db = i->data; + if(alpm_db_get_valid(db)) { + pm_printf(ALPM_LOG_ERROR, _("database '%s' is not valid (%s)\n"), + alpm_db_get_name(db), alpm_strerror(alpm_errno(config->handle))); + ret = 1; + } + } + } + return ret; +} + /* discard unhandled input on the terminal's input buffer */ static int flush_term_input(void) { #ifdef HAVE_TCFLUSH diff --git a/src/pacman/util.h b/src/pacman/util.h index a914d0c..ee3dbd1 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -39,9 +39,10 @@ /* update speed for the fill_progress based functions */ #define UPDATE_SPEED_SEC 0.2f -int trans_init(alpm_transflag_t flags); +int trans_init(alpm_transflag_t flags, int check_valid); int trans_release(void); int needs_root(void); +int check_syncdbs(size_t need_repos, int check_valid); int getcols(void); int rmrf(const char *path); const char *mbasename(const char *path); -- 1.7.6
participants (1)
-
Dan McGee