Blame src/daemon/rpm.c

Packit Service 8a8a03
/*
Packit Service 8a8a03
    Copyright (C) 2010  ABRT team
Packit Service 8a8a03
    Copyright (C) 2010  RedHat Inc
Packit Service 8a8a03
Packit Service 8a8a03
    This program is free software; you can redistribute it and/or modify
Packit Service 8a8a03
    it under the terms of the GNU General Public License as published by
Packit Service 8a8a03
    the Free Software Foundation; either version 2 of the License, or
Packit Service 8a8a03
    (at your option) any later version.
Packit Service 8a8a03
Packit Service 8a8a03
    This program is distributed in the hope that it will be useful,
Packit Service 8a8a03
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 8a8a03
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 8a8a03
    GNU General Public License for more details.
Packit Service 8a8a03
Packit Service 8a8a03
    You should have received a copy of the GNU General Public License along
Packit Service 8a8a03
    with this program; if not, write to the Free Software Foundation, Inc.,
Packit Service 8a8a03
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit Service 8a8a03
*/
Packit Service 8a8a03
#include "libabrt.h"
Packit Service 8a8a03
#include "rpm.h"
Packit Service 8a8a03
Packit Service 8a8a03
#ifdef HAVE_LIBRPM
Packit Service 8a8a03
#include <rpm/rpmts.h>
Packit Service 8a8a03
#include <rpm/rpmcli.h>
Packit Service 8a8a03
#include <rpm/rpmdb.h>
Packit Service 8a8a03
#include <rpm/rpmpgp.h>
Packit Service 8a8a03
#endif
Packit Service 8a8a03
Packit Service 8a8a03
/**
Packit Service 8a8a03
* A set, which contains finger prints.
Packit Service 8a8a03
*/
Packit Service 8a8a03
Packit Service 8a8a03
static GList *list_fingerprints = NULL;
Packit Service 8a8a03
Packit Service 8a8a03
/* cuts the name from the NVR format: foo-1.2.3-1.el6
Packit Service 8a8a03
   returns a newly allocated string
Packit Service 8a8a03
*/
Packit Service 8a8a03
char* get_package_name_from_NVR_or_NULL(const char* packageNVR)
Packit Service 8a8a03
{
Packit Service 8a8a03
    char* package_name = NULL;
Packit Service 8a8a03
    if (packageNVR != NULL)
Packit Service 8a8a03
    {
Packit Service 8a8a03
        log_notice("packageNVR %s", packageNVR);
Packit Service 8a8a03
        package_name = xstrdup(packageNVR);
Packit Service 8a8a03
        char *pos = strrchr(package_name, '-');
Packit Service 8a8a03
        if (pos != NULL)
Packit Service 8a8a03
        {
Packit Service 8a8a03
            *pos = '\0';
Packit Service 8a8a03
            pos = strrchr(package_name, '-');
Packit Service 8a8a03
            if (pos != NULL)
Packit Service 8a8a03
            {
Packit Service 8a8a03
                *pos = '\0';
Packit Service 8a8a03
            }
Packit Service 8a8a03
        }
Packit Service 8a8a03
    }
Packit Service 8a8a03
    return package_name;
Packit Service 8a8a03
}
Packit Service 8a8a03
Packit Service 8a8a03
void rpm_init()
Packit Service 8a8a03
{
Packit Service 8a8a03
#ifdef HAVE_LIBRPM
Packit Service 8a8a03
    if (rpmReadConfigFiles(NULL, NULL) != 0)
Packit Service 8a8a03
        error_msg("Can't read RPM rc files");
Packit Service 8a8a03
#endif
Packit Service 8a8a03
Packit Service 8a8a03
    list_free_with_free(list_fingerprints); /* paranoia */
Packit Service 8a8a03
    /* Huh? Why do we start the list with an element with NULL string? */
Packit Service 8a8a03
    list_fingerprints = g_list_alloc();
Packit Service 8a8a03
}
Packit Service 8a8a03
Packit Service 8a8a03
void rpm_destroy()
Packit Service 8a8a03
{
Packit Service 8a8a03
#ifdef HAVE_LIBRPM
Packit Service 8a8a03
    /* Mirroring the order of deinit calls in rpm-4.11.1/lib/poptALL.c::rpmcliFini() */
Packit Service 8a8a03
    rpmFreeCrypto();
Packit Service 8a8a03
    rpmFreeMacros(NULL);
Packit Service 8a8a03
    rpmFreeRpmrc();
Packit Service 8a8a03
Packit Service 8a8a03
/* rpm >= 4.14 handles this automatically on exit */
Packit Service 8a8a03
#if 0
Packit Service 8a8a03
    /* RPM doc says "clean up any open iterators and databases".
Packit Service 8a8a03
     * Observed to eliminate these Berkeley DB warnings:
Packit Service 8a8a03
     * "BDB2053 Freeing read locks for locker 0x1e0: 28718/139661746636736"
Packit Service 8a8a03
     */
Packit Service 8a8a03
    rpmdbCheckTerminate(1);
Packit Service 8a8a03
#endif
Packit Service 8a8a03
#endif
Packit Service 8a8a03
Packit Service 8a8a03
    list_free_with_free(list_fingerprints);
Packit Service 8a8a03
    list_fingerprints = NULL;
Packit Service 8a8a03
}
Packit Service 8a8a03
Packit Service 8a8a03
void rpm_load_gpgkey(const char* filename)
Packit Service 8a8a03
{
Packit Service 8a8a03
#ifdef HAVE_LIBRPM
Packit Service 8a8a03
    uint8_t *pkt = NULL;
Packit Service 8a8a03
    size_t pklen;
Packit Service 8a8a03
    if (pgpReadPkts(filename, &pkt, &pklen) != PGPARMOR_PUBKEY)
Packit Service 8a8a03
    {
Packit Service 8a8a03
        free(pkt);
Packit Service 8a8a03
        error_msg("Can't load public GPG key %s", filename);
Packit Service 8a8a03
        return;
Packit Service 8a8a03
    }
Packit Service 8a8a03
Packit Service 8a8a03
    uint8_t keyID[8];
Packit Service 8a8a03
#if 0
Packit Service 8a8a03
    if (pgpPubkeyFingerprint(pkt, pklen, keyID) == 0)
Packit Service 8a8a03
#else
Packit Service 8a8a03
    if (pgpPubkeyKeyID(pkt, pklen, keyID) == 0)
Packit Service 8a8a03
#endif
Packit Service 8a8a03
    {
Packit Service 8a8a03
        char *fingerprint = pgpHexStr(keyID, sizeof(keyID));
Packit Service 8a8a03
        if (fingerprint != NULL)
Packit Service 8a8a03
            list_fingerprints = g_list_append(list_fingerprints, fingerprint);
Packit Service 8a8a03
    }
Packit Service 8a8a03
    free(pkt);
Packit Service 8a8a03
#else
Packit Service 8a8a03
    return;
Packit Service 8a8a03
#endif
Packit Service 8a8a03
}
Packit Service 8a8a03
Packit Service 8a8a03
int rpm_chk_fingerprint(const char* pkg)
Packit Service 8a8a03
{
Packit Service 8a8a03
    char *fingerprint = rpm_get_fingerprint(pkg);
Packit Service 8a8a03
    int res = 0;
Packit Service 8a8a03
    if (fingerprint)
Packit Service 8a8a03
        res = rpm_fingerprint_is_imported(fingerprint);
Packit Service 8a8a03
    free(fingerprint);
Packit Service 8a8a03
    return res;
Packit Service 8a8a03
}
Packit Service 8a8a03
Packit Service 8a8a03
int rpm_fingerprint_is_imported(const char* fingerprint)
Packit Service 8a8a03
{
Packit Service 8a8a03
    return !!g_list_find_custom(list_fingerprints, fingerprint, (GCompareFunc)g_strcmp0);
Packit Service 8a8a03
}
Packit Service 8a8a03
Packit Service 8a8a03
char *rpm_get_fingerprint(const char *pkg)
Packit Service 8a8a03
{
Packit Service 8a8a03
#ifdef HAVE_LIBRPM
Packit Service 8a8a03
    char *fingerprint = NULL;
Packit Service 8a8a03
    char *pgpsig = NULL;
Packit Service 8a8a03
    const char *errmsg = NULL;
Packit Service 8a8a03
Packit Service 8a8a03
    rpmts ts = rpmtsCreate();
Packit Service 8a8a03
    rpmdbMatchIterator iter = rpmtsInitIterator(ts, RPMTAG_NAME, pkg, 0);
Packit Service 8a8a03
    Header header = rpmdbNextIterator(iter);
Packit Service 8a8a03
Packit Service 8a8a03
    if (!header)
Packit Service 8a8a03
        goto error;
Packit Service 8a8a03
Packit Service 8a8a03
    pgpsig = headerFormat(header, "%|SIGGPG?{%{SIGGPG:pgpsig}}:{%{SIGPGP:pgpsig}}|", &errmsg);
Packit Service 8a8a03
    if (!pgpsig && errmsg)
Packit Service 8a8a03
    {
Packit Service 8a8a03
        log_notice("cannot get siggpg:pgpsig. reason: %s", errmsg);
Packit Service 8a8a03
        goto error;
Packit Service 8a8a03
    }
Packit Service 8a8a03
Packit Service 8a8a03
    char *pgpsig_tmp = strstr(pgpsig, " Key ID ");
Packit Service 8a8a03
    if (pgpsig_tmp)
Packit Service 8a8a03
        fingerprint = xstrdup(pgpsig_tmp + sizeof(" Key ID ") - 1);
Packit Service 8a8a03
Packit Service 8a8a03
error:
Packit Service 8a8a03
    free(pgpsig);
Packit Service 8a8a03
    rpmdbFreeIterator(iter);
Packit Service 8a8a03
    rpmtsFree(ts);
Packit Service 8a8a03
    return fingerprint;
Packit Service 8a8a03
#else
Packit Service 8a8a03
    return NULL;
Packit Service 8a8a03
#endif
Packit Service 8a8a03
}
Packit Service 8a8a03
Packit Service 8a8a03
/*
Packit Service 8a8a03
  Checking the MD5 sum requires to run prelink to "un-prelink" the
Packit Service 8a8a03
  binaries - this is considered potential security risk so we don't
Packit Service 8a8a03
  use it, until we find some non-intrusive way
Packit Service 8a8a03
*/
Packit Service 8a8a03
Packit Service 8a8a03
/*
Packit Service 8a8a03
 * Not woking, need to be rewriten
Packit Service 8a8a03
 *
Packit Service 8a8a03
bool CheckHash(const char* pPackage, const char* pPath)
Packit Service 8a8a03
{
Packit Service 8a8a03
    bool ret = true;
Packit Service 8a8a03
    rpmts ts = rpmtsCreate();
Packit Service 8a8a03
    rpmdbMatchIterator iter = rpmtsInitIterator(ts, RPMTAG_NAME, pPackage, 0);
Packit Service 8a8a03
    Header header = rpmdbNextIterator(iter);
Packit Service 8a8a03
    if (header == NULL)
Packit Service 8a8a03
        goto error;
Packit Service 8a8a03
Packit Service 8a8a03
    rpmfi fi = rpmfiNew(ts, header, RPMTAG_BASENAMES, RPMFI_NOHEADER);
Packit Service 8a8a03
    std::string headerHash;
Packit Service 8a8a03
    char computedHash[1024] = "";
Packit Service 8a8a03
Packit Service 8a8a03
    while (rpmfiNext(fi) != -1)
Packit Service 8a8a03
    {
Packit Service 8a8a03
        if (strcmp(pPath, rpmfiFN(fi)) == 0)
Packit Service 8a8a03
        {
Packit Service 8a8a03
            headerHash = rpmfiFDigestHex(fi, NULL);
Packit Service 8a8a03
            rpmDoDigest(rpmfiDigestAlgo(fi), pPath, 1, (unsigned char*) computedHash, NULL);
Packit Service 8a8a03
            ret = (headerHash != "" && headerHash == computedHash);
Packit Service 8a8a03
            break;
Packit Service 8a8a03
        }
Packit Service 8a8a03
    }
Packit Service 8a8a03
    rpmfiFree(fi);
Packit Service 8a8a03
error:
Packit Service 8a8a03
    rpmdbFreeIterator(iter);
Packit Service 8a8a03
    rpmtsFree(ts);
Packit Service 8a8a03
    return ret;
Packit Service 8a8a03
}
Packit Service 8a8a03
*/
Packit Service 8a8a03
Packit Service 8a8a03
#ifdef HAVE_LIBRPM
Packit Service 8a8a03
static int rpm_query_file(rpmts *ts, rpmdbMatchIterator *iter, Header *header,
Packit Service 8a8a03
        const char *filename, const char *rootdir_or_NULL)
Packit Service 8a8a03
{
Packit Service 8a8a03
    const char *queryname = filename;
Packit Service 8a8a03
Packit Service 8a8a03
    *ts = rpmtsCreate();
Packit Service 8a8a03
    if (rootdir_or_NULL)
Packit Service 8a8a03
    {
Packit Service 8a8a03
        if (rpmtsSetRootDir(*ts, rootdir_or_NULL) != 0)
Packit Service 8a8a03
        {
Packit Service 8a8a03
            rpmtsFree(*ts);
Packit Service 8a8a03
            return -1;
Packit Service 8a8a03
        }
Packit Service 8a8a03
Packit Service 8a8a03
        unsigned len = strlen(rootdir_or_NULL);
Packit Service 8a8a03
        /* remove 'chroot' prefix */
Packit Service 8a8a03
        if (strncmp(filename, rootdir_or_NULL, len) == 0 && filename[len] == '/')
Packit Service 8a8a03
            queryname += len;
Packit Service 8a8a03
    }
Packit Service 8a8a03
Packit Service 8a8a03
    *iter = rpmtsInitIterator(*ts, RPMTAG_BASENAMES, queryname, 0);
Packit Service 8a8a03
    *header = rpmdbNextIterator(*iter);
Packit Service 8a8a03
Packit Service 8a8a03
    if (!(*header) && rootdir_or_NULL)
Packit Service 8a8a03
    {
Packit Service 8a8a03
        rpmdbFreeIterator(*iter);
Packit Service 8a8a03
        rpmtsFree(*ts);
Packit Service 8a8a03
Packit Service 8a8a03
        return rpm_query_file(ts, iter, header, filename, NULL);
Packit Service 8a8a03
    }
Packit Service 8a8a03
Packit Service 8a8a03
    return 0;
Packit Service 8a8a03
}
Packit Service 8a8a03
#endif
Packit Service 8a8a03
Packit Service 8a8a03
char* rpm_get_component(const char *filename, const char *rootdir_or_NULL)
Packit Service 8a8a03
{
Packit Service 8a8a03
#ifdef HAVE_LIBRPM
Packit Service 8a8a03
    char *ret = NULL;
Packit Service 8a8a03
    char *srpm = NULL;
Packit Service 8a8a03
    rpmts ts;
Packit Service 8a8a03
    rpmdbMatchIterator iter;
Packit Service 8a8a03
    Header header;
Packit Service 8a8a03
Packit Service 8a8a03
    if (rpm_query_file(&ts, &iter, &header, filename, rootdir_or_NULL) < 0)
Packit Service 8a8a03
        return NULL;
Packit Service 8a8a03
Packit Service 8a8a03
    if (!header)
Packit Service 8a8a03
        goto error;
Packit Service 8a8a03
Packit Service 8a8a03
    const char *errmsg = NULL;
Packit Service 8a8a03
    srpm = headerFormat(header, "%{SOURCERPM}", &errmsg);
Packit Service 8a8a03
    if (!srpm && errmsg)
Packit Service 8a8a03
    {
Packit Service 8a8a03
        error_msg("cannot get srpm. reason: %s", errmsg);
Packit Service 8a8a03
        goto error;
Packit Service 8a8a03
    }
Packit Service 8a8a03
Packit Service 8a8a03
    ret = get_package_name_from_NVR_or_NULL(srpm);
Packit Service 8a8a03
    free(srpm);
Packit Service 8a8a03
Packit Service 8a8a03
 error:
Packit Service 8a8a03
    rpmdbFreeIterator(iter);
Packit Service 8a8a03
    rpmtsFree(ts);
Packit Service 8a8a03
    return ret;
Packit Service 8a8a03
#else
Packit Service 8a8a03
    return NULL;
Packit Service 8a8a03
#endif
Packit Service 8a8a03
}
Packit Service 8a8a03
Packit Service 8a8a03
#ifdef HAVE_LIBRPM
Packit Service 8a8a03
#define pkg_add_id(name)                                                \
Packit Service 8a8a03
    static inline int pkg_add_##name(Header header, struct pkg_envra *p) \
Packit Service 8a8a03
    {                                                                   \
Packit Service 8a8a03
        const char *errmsg = NULL;                                      \
Packit Service 8a8a03
        p->p_##name = headerFormat(header, "%{"#name"}", &errmsg);      \
Packit Service 8a8a03
        if (p->p_##name || !errmsg)                                     \
Packit Service 8a8a03
            return 0;                                                   \
Packit Service 8a8a03
                                                                        \
Packit Service 8a8a03
        error_msg("cannot get "#name": %s", errmsg);                    \
Packit Service 8a8a03
                                                                        \
Packit Service 8a8a03
        return -1;                                                      \
Packit Service 8a8a03
    }                                                                   \
Packit Service 8a8a03
Packit Service 8a8a03
pkg_add_id(epoch);
Packit Service 8a8a03
pkg_add_id(name);
Packit Service 8a8a03
pkg_add_id(version);
Packit Service 8a8a03
pkg_add_id(release);
Packit Service 8a8a03
pkg_add_id(arch);
Packit Service 8a8a03
pkg_add_id(vendor);
Packit Service 8a8a03
#endif
Packit Service 8a8a03
Packit Service 8a8a03
// caller is responsible to free returned value
Packit Service 8a8a03
struct pkg_envra *rpm_get_package_nvr(const char *filename, const char *rootdir_or_NULL)
Packit Service 8a8a03
{
Packit Service 8a8a03
#ifdef HAVE_LIBRPM
Packit Service 8a8a03
    rpmts ts;
Packit Service 8a8a03
    rpmdbMatchIterator iter;
Packit Service 8a8a03
    Header header;
Packit Service 8a8a03
Packit Service 8a8a03
    struct pkg_envra *p = NULL;
Packit Service 8a8a03
Packit Service 8a8a03
    if (rpm_query_file(&ts, &iter, &header, filename, rootdir_or_NULL) < 0)
Packit Service 8a8a03
        return NULL;
Packit Service 8a8a03
Packit Service 8a8a03
    if (!header)
Packit Service 8a8a03
        goto error;
Packit Service 8a8a03
Packit Service 8a8a03
    p = xzalloc(sizeof(*p));
Packit Service 8a8a03
    int r;
Packit Service 8a8a03
    r = pkg_add_epoch(header, p);
Packit Service 8a8a03
    if (r)
Packit Service 8a8a03
        goto error;
Packit Service 8a8a03
   /*
Packit Service 8a8a03
    * <npajkovs> hello, what's the difference between epoch '0' and  '(none)'?
Packit Service 8a8a03
    * <Panu> nothing really, a missing epoch is considered equal to zero epoch
Packit Service 8a8a03
    */
Packit Service 8a8a03
    if (!strncmp(p->p_epoch, "(none)", strlen("(none)")))
Packit Service 8a8a03
    {
Packit Service 8a8a03
        free(p->p_epoch);
Packit Service 8a8a03
        p->p_epoch = xstrdup("0");
Packit Service 8a8a03
    }
Packit Service 8a8a03
Packit Service 8a8a03
    r = pkg_add_name(header, p);
Packit Service 8a8a03
    if (r)
Packit Service 8a8a03
        goto error;
Packit Service 8a8a03
Packit Service 8a8a03
    r = pkg_add_version(header, p);
Packit Service 8a8a03
    if (r)
Packit Service 8a8a03
        goto error;
Packit Service 8a8a03
Packit Service 8a8a03
    r = pkg_add_release(header, p);
Packit Service 8a8a03
    if (r)
Packit Service 8a8a03
        goto error;
Packit Service 8a8a03
Packit Service 8a8a03
    r = pkg_add_arch(header, p);
Packit Service 8a8a03
    if (r)
Packit Service 8a8a03
        goto error;
Packit Service 8a8a03
Packit Service 8a8a03
    r = pkg_add_vendor(header, p);
Packit Service 8a8a03
    if (r)
Packit Service 8a8a03
        goto error;
Packit Service 8a8a03
Packit Service 8a8a03
    if (strcmp(p->p_epoch, "0") == 0)
Packit Service 8a8a03
        p->p_nvr = xasprintf("%s-%s-%s", p->p_name, p->p_version, p->p_release);
Packit Service 8a8a03
    else
Packit Service 8a8a03
        p->p_nvr = xasprintf("%s:%s-%s-%s", p->p_epoch, p->p_name, p->p_version, p->p_release);
Packit Service 8a8a03
Packit Service 8a8a03
    rpmdbFreeIterator(iter);
Packit Service 8a8a03
    rpmtsFree(ts);
Packit Service 8a8a03
    return p;
Packit Service 8a8a03
Packit Service 8a8a03
 error:
Packit Service 8a8a03
    free_pkg_envra(p);
Packit Service 8a8a03
Packit Service 8a8a03
    rpmdbFreeIterator(iter);
Packit Service 8a8a03
    rpmtsFree(ts);
Packit Service 8a8a03
    return NULL;
Packit Service 8a8a03
#else
Packit Service 8a8a03
    return NULL;
Packit Service 8a8a03
#endif
Packit Service 8a8a03
}
Packit Service 8a8a03
Packit Service 8a8a03
void free_pkg_envra(struct pkg_envra *p)
Packit Service 8a8a03
{
Packit Service 8a8a03
    if (!p)
Packit Service 8a8a03
        return;
Packit Service 8a8a03
Packit Service 8a8a03
    free(p->p_vendor);
Packit Service 8a8a03
    free(p->p_epoch);
Packit Service 8a8a03
    free(p->p_name);
Packit Service 8a8a03
    free(p->p_version);
Packit Service 8a8a03
    free(p->p_release);
Packit Service 8a8a03
    free(p->p_arch);
Packit Service 8a8a03
    free(p->p_nvr);
Packit Service 8a8a03
    free(p);
Packit Service 8a8a03
}