Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| /* | |
| 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 <rpm/rpmts.h> | |
| #include <rpm/rpmcli.h> | |
| #include <rpm/rpmdb.h> | |
| #include <rpm/rpmpgp.h> | |
| #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; | |
| /* | |
| * <npajkovs> hello, what's the difference between epoch '0' and '(none)'? | |
| * <Panu> 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); | |
| } |