Perform package verification at package load time
Both md5sum verification and PGP verification can and should be done at package load time. This allows verification to happen as early as possible for packages provided by filename and loaded in the frontend, and moves more stuff out of sync_commit that doesn't really belong there. This should also set the stage for simplified parallel loading of packages later down the road. Signed-off-by: Dan McGee <dan@archlinux.org>
This commit is contained in:
parent
1cf79eb8c8
commit
4d63ebe2fb
8 changed files with 54 additions and 42 deletions
|
@ -383,10 +383,13 @@ int alpm_db_set_pkgreason(pmdb_t *db, const char *name, pmpkgreason_t reason);
|
||||||
* @param filename location of the package tarball
|
* @param filename location of the package tarball
|
||||||
* @param full whether to stop the load after metadata is read or continue
|
* @param full whether to stop the load after metadata is read or continue
|
||||||
* through the full archive
|
* through the full archive
|
||||||
|
* @param check_sig 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
|
* @param pkg address of the package pointer
|
||||||
* @return 0 on success, -1 on error (pm_errno is set accordingly)
|
* @return 0 on success, -1 on error (pm_errno is set accordingly)
|
||||||
*/
|
*/
|
||||||
int alpm_pkg_load(const char *filename, int full, pmpkg_t **pkg);
|
int alpm_pkg_load(const char *filename, int full, pgp_verify_t check_sig,
|
||||||
|
pmpkg_t **pkg);
|
||||||
|
|
||||||
/** Free a package.
|
/** Free a package.
|
||||||
* @param pkg package pointer to free
|
* @param pkg package pointer to free
|
||||||
|
|
|
@ -226,9 +226,10 @@ static int parse_descfile(struct archive *a, pmpkg_t *newpkg)
|
||||||
* through the full archive
|
* through the full archive
|
||||||
* @return An information filled pmpkg_t struct
|
* @return An information filled pmpkg_t struct
|
||||||
*/
|
*/
|
||||||
static pmpkg_t *pkg_load(const char *pkgfile, int full)
|
pmpkg_t *_alpm_pkg_load_internal(const char *pkgfile, int full,
|
||||||
|
const char *md5sum, const char *base64_sig, pgp_verify_t check_sig)
|
||||||
{
|
{
|
||||||
int ret = ARCHIVE_OK;
|
int ret;
|
||||||
int config = 0;
|
int config = 0;
|
||||||
struct archive *archive;
|
struct archive *archive;
|
||||||
struct archive_entry *entry;
|
struct archive_entry *entry;
|
||||||
|
@ -254,6 +255,27 @@ static pmpkg_t *pkg_load(const char *pkgfile, int full)
|
||||||
RET_ERR(PM_ERR_PKG_OPEN, NULL);
|
RET_ERR(PM_ERR_PKG_OPEN, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* first steps- validate the package file */
|
||||||
|
_alpm_log(PM_LOG_DEBUG, "md5sum: %s\n", md5sum);
|
||||||
|
if(md5sum) {
|
||||||
|
_alpm_log(PM_LOG_DEBUG, "checking md5sum for %s\n", pkgfile);
|
||||||
|
if(_alpm_test_md5sum(pkgfile, md5sum) != 0) {
|
||||||
|
alpm_pkg_free(newpkg);
|
||||||
|
RET_ERR(PM_ERR_PKG_INVALID, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_alpm_log(PM_LOG_DEBUG, "base64_sig: %s\n", base64_sig);
|
||||||
|
if(check_sig != PM_PGP_VERIFY_NEVER) {
|
||||||
|
_alpm_log(PM_LOG_DEBUG, "checking signature for %s\n", pkgfile);
|
||||||
|
ret = _alpm_gpgme_checksig(pkgfile, base64_sig);
|
||||||
|
if((check_sig == PM_PGP_VERIFY_ALWAYS && ret != 0) ||
|
||||||
|
(check_sig == PM_PGP_VERIFY_OPTIONAL && ret == 1)) {
|
||||||
|
RET_ERR(PM_ERR_SIG_INVALID, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* next- try to create an archive object to read in the package */
|
||||||
if((archive = archive_read_new()) == NULL) {
|
if((archive = archive_read_new()) == NULL) {
|
||||||
alpm_pkg_free(newpkg);
|
alpm_pkg_free(newpkg);
|
||||||
RET_ERR(PM_ERR_LIBARCHIVE, NULL);
|
RET_ERR(PM_ERR_LIBARCHIVE, NULL);
|
||||||
|
@ -332,7 +354,6 @@ static pmpkg_t *pkg_load(const char *pkgfile, int full)
|
||||||
|
|
||||||
/* internal fields for package struct */
|
/* internal fields for package struct */
|
||||||
newpkg->origin = PKG_FROM_FILE;
|
newpkg->origin = PKG_FROM_FILE;
|
||||||
/* TODO eventually kill/move this? */
|
|
||||||
newpkg->origin_data.file = strdup(pkgfile);
|
newpkg->origin_data.file = strdup(pkgfile);
|
||||||
newpkg->ops = get_file_pkg_ops();
|
newpkg->ops = get_file_pkg_ops();
|
||||||
|
|
||||||
|
@ -359,16 +380,15 @@ error:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SYMEXPORT alpm_pkg_load(const char *filename, int full, pmpkg_t **pkg)
|
int SYMEXPORT alpm_pkg_load(const char *filename, int full,
|
||||||
|
pgp_verify_t check_sig, pmpkg_t **pkg)
|
||||||
{
|
{
|
||||||
ALPM_LOG_FUNC;
|
ALPM_LOG_FUNC;
|
||||||
|
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
ASSERT(filename != NULL && strlen(filename) != 0,
|
|
||||||
RET_ERR(PM_ERR_WRONG_ARGS, -1));
|
|
||||||
ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
|
ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
|
||||||
|
|
||||||
*pkg = pkg_load(filename, full);
|
*pkg = _alpm_pkg_load_internal(filename, full, NULL, NULL, check_sig);
|
||||||
if(*pkg == NULL) {
|
if(*pkg == NULL) {
|
||||||
/* pm_errno is set by pkg_load */
|
/* pm_errno is set by pkg_load */
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -139,6 +139,10 @@ pmpkg_t* _alpm_pkg_new(void);
|
||||||
pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg);
|
pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg);
|
||||||
void _alpm_pkg_free(pmpkg_t *pkg);
|
void _alpm_pkg_free(pmpkg_t *pkg);
|
||||||
void _alpm_pkg_free_trans(pmpkg_t *pkg);
|
void _alpm_pkg_free_trans(pmpkg_t *pkg);
|
||||||
|
|
||||||
|
pmpkg_t *_alpm_pkg_load_internal(const char *filename, int full,
|
||||||
|
const char *md5sum, const char *base64_sig, pgp_verify_t check_sig);
|
||||||
|
|
||||||
int _alpm_pkg_cmp(const void *p1, const void *p2);
|
int _alpm_pkg_cmp(const void *p1, const void *p2);
|
||||||
int _alpm_pkg_compare_versions(pmpkg_t *local_pkg, pmpkg_t *pkg);
|
int _alpm_pkg_compare_versions(pmpkg_t *local_pkg, pmpkg_t *pkg);
|
||||||
pmpkg_t *_alpm_pkg_find(alpm_list_t *haystack, const char *needle);
|
pmpkg_t *_alpm_pkg_find(alpm_list_t *haystack, const char *needle);
|
||||||
|
|
|
@ -862,45 +862,27 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data)
|
||||||
for(i = trans->add; i; i = i->next, current++) {
|
for(i = trans->add; i; i = i->next, current++) {
|
||||||
pmpkg_t *spkg = i->data;
|
pmpkg_t *spkg = i->data;
|
||||||
int percent = (current * 100) / numtargs;
|
int percent = (current * 100) / numtargs;
|
||||||
|
const char *filename;
|
||||||
|
char *filepath;
|
||||||
|
pgp_verify_t check_sig;
|
||||||
|
|
||||||
|
PROGRESS(trans, PM_TRANS_PROGRESS_INTEGRITY_START, "", percent,
|
||||||
|
numtargs, current);
|
||||||
if(spkg->origin == PKG_FROM_FILE) {
|
if(spkg->origin == PKG_FROM_FILE) {
|
||||||
continue; /* pkg_load() has been already called, this package is valid */
|
continue; /* pkg_load() has been already called, this package is valid */
|
||||||
}
|
}
|
||||||
PROGRESS(trans, PM_TRANS_PROGRESS_INTEGRITY_START, "", percent,
|
|
||||||
numtargs, current);
|
|
||||||
|
|
||||||
const char *filename = alpm_pkg_get_filename(spkg);
|
filename = alpm_pkg_get_filename(spkg);
|
||||||
char *filepath = _alpm_filecache_find(filename);
|
filepath = _alpm_filecache_find(filename);
|
||||||
const char *md5sum = alpm_pkg_get_md5sum(spkg);
|
|
||||||
pgp_verify_t check_sig;
|
|
||||||
|
|
||||||
/* check md5sum first */
|
|
||||||
if(test_md5sum(trans, filepath, md5sum) != 0) {
|
|
||||||
errors++;
|
|
||||||
*data = alpm_list_add(*data, strdup(filename));
|
|
||||||
FREE(filepath);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* check PGP signature next */
|
|
||||||
pmdb_t *sdb = alpm_pkg_get_db(spkg);
|
pmdb_t *sdb = alpm_pkg_get_db(spkg);
|
||||||
|
|
||||||
check_sig = _alpm_db_get_sigverify_level(sdb);
|
check_sig = _alpm_db_get_sigverify_level(sdb);
|
||||||
|
|
||||||
if(check_sig != PM_PGP_VERIFY_NEVER) {
|
|
||||||
int ret = _alpm_gpgme_checksig(filepath, spkg->base64_sig);
|
|
||||||
if((check_sig == PM_PGP_VERIFY_ALWAYS && ret != 0) ||
|
|
||||||
(check_sig == PM_PGP_VERIFY_OPTIONAL && ret == 1)) {
|
|
||||||
errors++;
|
|
||||||
*data = alpm_list_add(*data, strdup(filename));
|
|
||||||
FREE(filepath);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* load the package file and replace pkgcache entry with it in the target list */
|
/* 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 */
|
/* TODO: alpm_pkg_get_db() will not work on this target anymore */
|
||||||
_alpm_log(PM_LOG_DEBUG, "replacing pkgcache entry with package file for target %s\n", spkg->name);
|
_alpm_log(PM_LOG_DEBUG, "replacing pkgcache entry with package file for target %s\n", spkg->name);
|
||||||
pmpkg_t *pkgfile;
|
pmpkg_t *pkgfile =_alpm_pkg_load_internal(filepath, 1, spkg->md5sum,
|
||||||
if(alpm_pkg_load(filepath, 1, &pkgfile) != 0) {
|
spkg->base64_sig, check_sig);
|
||||||
_alpm_pkg_free(pkgfile);
|
if(!pkgfile) {
|
||||||
errors++;
|
errors++;
|
||||||
*data = alpm_list_add(*data, strdup(filename));
|
*data = alpm_list_add(*data, strdup(filename));
|
||||||
FREE(filepath);
|
FREE(filepath);
|
||||||
|
|
|
@ -547,7 +547,7 @@ int pacman_query(alpm_list_t *targets)
|
||||||
char *strname = alpm_list_getdata(i);
|
char *strname = alpm_list_getdata(i);
|
||||||
|
|
||||||
if(config->op_q_isfile) {
|
if(config->op_q_isfile) {
|
||||||
alpm_pkg_load(strname, 1, &pkg);
|
alpm_pkg_load(strname, 1, PM_PGP_VERIFY_OPTIONAL, &pkg);
|
||||||
} else {
|
} else {
|
||||||
pkg = alpm_db_get_pkg(db_local, strname);
|
pkg = alpm_db_get_pkg(db_local, strname);
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,7 +211,8 @@ static int sync_cleancache(int level)
|
||||||
/* attempt to load the package, prompt removal on failures as we may have
|
/* 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
|
* files here that aren't valid packages. we also don't need a full
|
||||||
* load of the package, just the metadata. */
|
* load of the package, just the metadata. */
|
||||||
if(alpm_pkg_load(path, 0, &localpkg) != 0 || localpkg == NULL) {
|
if(alpm_pkg_load(path, 0, PM_PGP_VERIFY_NEVER, &localpkg) != 0
|
||||||
|
|| localpkg == NULL) {
|
||||||
if(yesno(_("File %s does not seem to be a valid package, remove it?"), path)) {
|
if(yesno(_("File %s does not seem to be a valid package, remove it?"), path)) {
|
||||||
if(localpkg) {
|
if(localpkg) {
|
||||||
alpm_pkg_free(localpkg);
|
alpm_pkg_free(localpkg);
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
int pacman_upgrade(alpm_list_t *targets)
|
int pacman_upgrade(alpm_list_t *targets)
|
||||||
{
|
{
|
||||||
alpm_list_t *i, *data = NULL;
|
alpm_list_t *i, *data = NULL;
|
||||||
|
pgp_verify_t check_sig = alpm_option_get_default_sigverify();
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
if(targets == NULL) {
|
if(targets == NULL) {
|
||||||
|
@ -75,7 +76,7 @@ int pacman_upgrade(alpm_list_t *targets)
|
||||||
char *targ = alpm_list_getdata(i);
|
char *targ = alpm_list_getdata(i);
|
||||||
pmpkg_t *pkg;
|
pmpkg_t *pkg;
|
||||||
|
|
||||||
if(alpm_pkg_load(targ, 1, &pkg) != 0) {
|
if(alpm_pkg_load(targ, 1, check_sig, &pkg) != 0) {
|
||||||
pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n",
|
pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n",
|
||||||
targ, alpm_strerrorlast());
|
targ, alpm_strerrorlast());
|
||||||
trans_release();
|
trans_release();
|
||||||
|
|
|
@ -55,7 +55,8 @@ int main(int argc, char *argv[])
|
||||||
/* let us get log messages from libalpm */
|
/* let us get log messages from libalpm */
|
||||||
alpm_option_set_logcb(output_cb);
|
alpm_option_set_logcb(output_cb);
|
||||||
|
|
||||||
if(alpm_pkg_load(argv[1], 1, &pkg) == -1 || pkg == NULL) {
|
if(alpm_pkg_load(argv[1], 1, PM_PGP_VERIFY_OPTIONAL, &pkg) == -1
|
||||||
|
|| pkg == NULL) {
|
||||||
switch(pm_errno) {
|
switch(pm_errno) {
|
||||||
case PM_ERR_PKG_OPEN:
|
case PM_ERR_PKG_OPEN:
|
||||||
printf("Cannot open the given file.\n");
|
printf("Cannot open the given file.\n");
|
||||||
|
|
Loading…
Add table
Reference in a new issue