Do database signature checking at load time

This is the ideal place to do it as all clients should be checking the
return value and ensuring there are no errors. This is similar to
pkg_load().

We also add an additional step of validation after we download a new
database; a subsequent '-y' operation can potentially invalidate the
original check at registration time.

Note that this implementation is still a bit naive; if a signature is
invalid it is currently impossible to refresh and re-download the file
without manually deleting it first. Similarly, if one downloads a
database and the check fails, the database object is still there and can
be used. These shortcomings will be addressed in a future commit.

Signed-off-by: Dan McGee <dan@archlinux.org>
This commit is contained in:
Dan McGee 2011-06-07 17:29:55 -05:00
parent 94d22f9309
commit db3b86e7f3
8 changed files with 71 additions and 22 deletions

View File

@ -357,9 +357,12 @@ alpm_list_t *alpm_option_get_syncdbs(pmhandle_t *handle);
/** Register a sync database of packages. /** Register a sync database of packages.
* @param handle the context handle * @param handle the context handle
* @param treename the name of the sync repository * @param treename the name of the sync repository
* @param check_sig what level of signature checking to perform on the
* database; note that this must be a '.sig' file type verification
* @return a pmdb_t* on success (the value), NULL on error * @return a pmdb_t* on success (the value), NULL on error
*/ */
pmdb_t *alpm_db_register_sync(pmhandle_t *handle, const char *treename); pmdb_t *alpm_db_register_sync(pmhandle_t *handle, const char *treename,
pgp_verify_t check_sig);
/** Unregister a package database. /** Unregister a package database.
* @param db pointer to the package database to unregister * @param db pointer to the package database to unregister

View File

@ -20,7 +20,9 @@
#include "config.h" #include "config.h"
#include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h>
/* libarchive */ /* libarchive */
#include <archive.h> #include <archive.h>
@ -65,6 +67,37 @@ static char *get_sync_dir(pmhandle_t *handle)
return syncpath; return syncpath;
} }
static int sync_db_validate(pmdb_t *db)
{
/* this takes into account the default verification level if UNKNOWN
* was assigned to this db */
pgp_verify_t check_sig = _alpm_db_get_sigverify_level(db);
if(check_sig != PM_PGP_VERIFY_NEVER) {
int ret;
const char *dbpath = _alpm_db_path(db);
if(!dbpath) {
/* pm_errno set in _alpm_db_path() */
return -1;
}
/* we can skip any validation if the database doesn't exist */
if(access(dbpath, R_OK) != 0 && errno == ENOENT) {
return 0;
}
_alpm_log(db->handle, PM_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, PM_ERR_SIG_INVALID, -1);
}
}
return 0;
}
/** Update a package database /** Update a package database
* *
* An update of the package database \a db will be attempted. Unless * An update of the package database \a db will be attempted. Unless
@ -144,6 +177,15 @@ int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
if(ret == 0 && (check_sig == PM_PGP_VERIFY_ALWAYS || if(ret == 0 && (check_sig == PM_PGP_VERIFY_ALWAYS ||
check_sig == PM_PGP_VERIFY_OPTIONAL)) { check_sig == PM_PGP_VERIFY_OPTIONAL)) {
/* an existing sig file is no good at this point */
char *sigpath = _alpm_db_sig_path(db);
if(!sigpath) {
ret = -1;
break;
}
unlink(sigpath);
free(sigpath);
int errors_ok = (check_sig == PM_PGP_VERIFY_OPTIONAL); int errors_ok = (check_sig == PM_PGP_VERIFY_OPTIONAL);
/* if we downloaded a DB, we want the .sig from the same server */ /* if we downloaded a DB, we want the .sig from the same server */
snprintf(fileurl, len, "%s/%s.db.sig", server, db->treename); snprintf(fileurl, len, "%s/%s.db.sig", server, db->treename);
@ -173,6 +215,11 @@ int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
/* Cache needs to be rebuilt */ /* Cache needs to be rebuilt */
_alpm_db_free_pkgcache(db); _alpm_db_free_pkgcache(db);
if(sync_db_validate(db)) {
/* pm_errno should be set */
ret = -1;
}
cleanup: cleanup:
free(syncpath); free(syncpath);
@ -523,7 +570,8 @@ struct db_operations sync_db_ops = {
.version = sync_db_version, .version = sync_db_version,
}; };
pmdb_t *_alpm_db_register_sync(pmhandle_t *handle, const char *treename) pmdb_t *_alpm_db_register_sync(pmhandle_t *handle, const char *treename,
pgp_verify_t level)
{ {
pmdb_t *db; pmdb_t *db;
@ -535,6 +583,12 @@ pmdb_t *_alpm_db_register_sync(pmhandle_t *handle, const char *treename)
} }
db->ops = &sync_db_ops; db->ops = &sync_db_ops;
db->handle = handle; db->handle = handle;
db->pgp_verify = level;
if(sync_db_validate(db)) {
_alpm_db_free(db);
return NULL;
}
handle->dbs_sync = alpm_list_add(handle->dbs_sync, db); handle->dbs_sync = alpm_list_add(handle->dbs_sync, db);
return db; return db;

View File

@ -45,7 +45,8 @@
*/ */
/** Register a sync database of packages. */ /** Register a sync database of packages. */
pmdb_t SYMEXPORT *alpm_db_register_sync(pmhandle_t *handle, const char *treename) pmdb_t SYMEXPORT *alpm_db_register_sync(pmhandle_t *handle, const char *treename,
pgp_verify_t check_sig)
{ {
/* Sanity checks */ /* Sanity checks */
CHECK_HANDLE(handle, return NULL); CHECK_HANDLE(handle, return NULL);
@ -54,7 +55,7 @@ pmdb_t SYMEXPORT *alpm_db_register_sync(pmhandle_t *handle, const char *treename
/* Do not register a database if a transaction is on-going */ /* Do not register a database if a transaction is on-going */
ASSERT(handle->trans == NULL, RET_ERR(handle, PM_ERR_TRANS_NOT_NULL, NULL)); ASSERT(handle->trans == NULL, RET_ERR(handle, PM_ERR_TRANS_NOT_NULL, NULL));
return _alpm_db_register_sync(handle, treename); return _alpm_db_register_sync(handle, treename, check_sig);
} }
/* Helper function for alpm_db_unregister{_all} */ /* Helper function for alpm_db_unregister{_all} */

View File

@ -77,7 +77,8 @@ int _alpm_db_version(pmdb_t *db);
int _alpm_db_cmp(const void *d1, const void *d2); int _alpm_db_cmp(const void *d1, const void *d2);
alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles); alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles);
pmdb_t *_alpm_db_register_local(pmhandle_t *handle); pmdb_t *_alpm_db_register_local(pmhandle_t *handle);
pmdb_t *_alpm_db_register_sync(pmhandle_t *handle, const char *treename); pmdb_t *_alpm_db_register_sync(pmhandle_t *handle, const char *treename,
pgp_verify_t level);
void _alpm_db_unregister(pmdb_t *db); void _alpm_db_unregister(pmdb_t *db);
/* be_*.c, backend specific calls */ /* be_*.c, backend specific calls */

View File

@ -460,7 +460,7 @@ static int setup_libalpm(void)
ret = alpm_option_set_logfile(handle, config->logfile); ret = alpm_option_set_logfile(handle, config->logfile);
if(ret != 0) { if(ret != 0) {
pm_printf(PM_LOG_ERROR, _("problem setting logfile '%s' (%s)\n"), pm_printf(PM_LOG_ERROR, _("problem setting logfile '%s' (%s)\n"),
config->logfile, alpm_strerror(alpm_errno(config->handle))); config->logfile, alpm_strerror(alpm_errno(handle)));
return ret; return ret;
} }
@ -470,7 +470,7 @@ static int setup_libalpm(void)
ret = alpm_option_set_gpgdir(handle, config->gpgdir); ret = alpm_option_set_gpgdir(handle, config->gpgdir);
if(ret != 0) { if(ret != 0) {
pm_printf(PM_LOG_ERROR, _("problem setting gpgdir '%s' (%s)\n"), pm_printf(PM_LOG_ERROR, _("problem setting gpgdir '%s' (%s)\n"),
config->gpgdir, alpm_strerror(alpm_errno(config->handle))); config->gpgdir, alpm_strerror(alpm_errno(handle)));
return ret; return ret;
} }
@ -542,7 +542,7 @@ static int finish_section(struct section_t *section, int parse_options)
} }
/* if we are not looking at options sections only, register a db */ /* if we are not looking at options sections only, register a db */
db = alpm_db_register_sync(config->handle, section->name); db = alpm_db_register_sync(config->handle, section->name, section->sigverify);
if(db == NULL) { if(db == NULL) {
pm_printf(PM_LOG_ERROR, _("could not register '%s' database (%s)\n"), pm_printf(PM_LOG_ERROR, _("could not register '%s' database (%s)\n"),
section->name, alpm_strerror(alpm_errno(config->handle))); section->name, alpm_strerror(alpm_errno(config->handle)));
@ -550,16 +550,6 @@ static int finish_section(struct section_t *section, int parse_options)
goto cleanup; goto cleanup;
} }
if(section->sigverify) {
if(alpm_db_set_pgp_verify(db, section->sigverify)) {
pm_printf(PM_LOG_ERROR,
_("could not set verify option for database '%s' (%s)\n"),
section->name, alpm_strerror(alpm_errno(config->handle)));
ret = 1;
goto cleanup;
}
}
for(i = section->servers; i; i = alpm_list_next(i)) { for(i = section->servers; i; i = alpm_list_next(i)) {
char *value = alpm_list_getdata(i); char *value = alpm_list_getdata(i);
if(_add_mirror(db, value) != 0) { if(_add_mirror(db, value) != 0) {

View File

@ -75,7 +75,7 @@ static void checkdbs(const char *dbpath, alpm_list_t *dbnames) {
for(i = dbnames; i; i = alpm_list_next(i)) { for(i = dbnames; i; i = alpm_list_next(i)) {
char *dbname = alpm_list_getdata(i); char *dbname = alpm_list_getdata(i);
snprintf(syncdbpath, PATH_MAX, "%s/sync/%s", dbpath, dbname); snprintf(syncdbpath, PATH_MAX, "%s/sync/%s", dbpath, dbname);
db = alpm_db_register_sync(handle, dbname); db = alpm_db_register_sync(handle, dbname, PM_PGP_VERIFY_OPTIONAL);
if(db == NULL) { if(db == NULL) {
fprintf(stderr, "error: could not register sync database (%s)\n", fprintf(stderr, "error: could not register sync database (%s)\n",
alpm_strerror(alpm_errno(handle))); alpm_strerror(alpm_errno(handle)));

View File

@ -151,7 +151,7 @@ static int check_syncdbs(alpm_list_t *dbnames) {
for(i = dbnames; i; i = alpm_list_next(i)) { for(i = dbnames; i; i = alpm_list_next(i)) {
char *dbname = alpm_list_getdata(i); char *dbname = alpm_list_getdata(i);
db = alpm_db_register_sync(handle, dbname); db = alpm_db_register_sync(handle, dbname, PM_PGP_VERIFY_OPTIONAL);
if(db == NULL) { if(db == NULL) {
fprintf(stderr, "error: could not register sync database (%s)\n", fprintf(stderr, "error: could not register sync database (%s)\n",
alpm_strerror(alpm_errno(handle))); alpm_strerror(alpm_errno(handle)));

View File

@ -1,8 +1,8 @@
self.description = "Add a signature to a package DB" self.description = "Add a bogus signature to a package DB"
sp = pmpkg("pkg1") sp = pmpkg("pkg1")
sp.pgpsig = "asdfasdfsdfasdfsdafasdfsdfasd" sp.pgpsig = "asdfasdfsdfasdfsdafasdfsdfasd"
self.addpkg2db("sync+Always", sp) self.addpkg2db("sync+Optional", sp)
self.args = "-Ss" self.args = "-Ss"