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