summaryrefslogtreecommitdiff
path: root/lib/package.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/package.c')
-rw-r--r--lib/package.c807
1 files changed, 807 insertions, 0 deletions
diff --git a/lib/package.c b/lib/package.c
new file mode 100644
index 0000000..e1795dd
--- /dev/null
+++ b/lib/package.c
@@ -0,0 +1,807 @@
+/** \ingroup header
+ * \file lib/package.c
+ */
+
+#include "system.h"
+
+#include <netinet/in.h>
+
+#include <rpm/rpmlib.h> /* XXX RPMSIGTAG, other sig stuff */
+#include <rpm/rpmts.h>
+#include <rpm/rpmlog.h>
+#include <rpm/rpmstring.h>
+#include <rpm/rpmkeyring.h>
+
+#include "lib/rpmlead.h"
+#include "lib/signature.h"
+#include "rpmio/digest.h"
+#include "rpmio/rpmio_internal.h" /* fd digest bits */
+#include "lib/header_internal.h" /* XXX headerCheck */
+
+#include "debug.h"
+
+static int _print_pkts = 0;
+
+static const unsigned int nkeyids_max = 256;
+static unsigned int nkeyids = 0;
+static unsigned int nextkeyid = 0;
+static unsigned int * keyids;
+
+void headerMergeLegacySigs(Header h, const Header sigh)
+{
+ HeaderIterator hi;
+ struct rpmtd_s td;
+
+ hi = headerInitIterator(sigh);
+ for (; headerNext(hi, &td); rpmtdFreeData(&td))
+ {
+ switch (td.tag) {
+ /* XXX Translate legacy signature tag values. */
+ case RPMSIGTAG_SIZE:
+ td.tag = RPMTAG_SIGSIZE;
+ break;
+ case RPMSIGTAG_PGP:
+ td.tag = RPMTAG_SIGPGP;
+ break;
+ case RPMSIGTAG_MD5:
+ td.tag = RPMTAG_SIGMD5;
+ break;
+ case RPMSIGTAG_GPG:
+ td.tag = RPMTAG_SIGGPG;
+ break;
+ case RPMSIGTAG_PGP5:
+ td.tag = RPMTAG_SIGPGP5;
+ break;
+ case RPMSIGTAG_PAYLOADSIZE:
+ td.tag = RPMTAG_ARCHIVESIZE;
+ break;
+ case RPMSIGTAG_SHA1:
+ case RPMSIGTAG_DSA:
+ case RPMSIGTAG_RSA:
+ default:
+ if (!(td.tag >= HEADER_SIGBASE && td.tag < HEADER_TAGBASE))
+ continue;
+ break;
+ }
+ if (td.data == NULL) continue; /* XXX can't happen */
+ if (!headerIsEntry(h, td.tag)) {
+ if (hdrchkType(td.type))
+ continue;
+ if (td.count < 0 || hdrchkData(td.count))
+ continue;
+ switch(td.type) {
+ case RPM_NULL_TYPE:
+ continue;
+ break;
+ case RPM_CHAR_TYPE:
+ case RPM_INT8_TYPE:
+ case RPM_INT16_TYPE:
+ case RPM_INT32_TYPE:
+ case RPM_INT64_TYPE:
+ if (td.count != 1)
+ continue;
+ break;
+ case RPM_STRING_TYPE:
+ case RPM_BIN_TYPE:
+ if (td.count >= 16*1024)
+ continue;
+ break;
+ case RPM_STRING_ARRAY_TYPE:
+ case RPM_I18NSTRING_TYPE:
+ continue;
+ break;
+ }
+ (void) headerPut(h, &td, HEADERPUT_DEFAULT);
+ }
+ }
+ hi = headerFreeIterator(hi);
+}
+
+Header headerRegenSigHeader(const Header h, int noArchiveSize)
+{
+ Header sigh = rpmNewSignature();
+ HeaderIterator hi;
+ struct rpmtd_s td;
+
+ for (hi = headerInitIterator(h); headerNext(hi, &td); rpmtdFreeData(&td)) {
+ switch (td.tag) {
+ /* XXX Translate legacy signature tag values. */
+ case RPMTAG_SIGSIZE:
+ td.tag = RPMSIGTAG_SIZE;
+ break;
+ case RPMTAG_SIGPGP:
+ td.tag = RPMSIGTAG_PGP;
+ break;
+ case RPMTAG_SIGMD5:
+ td.tag = RPMSIGTAG_MD5;
+ break;
+ case RPMTAG_SIGGPG:
+ td.tag = RPMSIGTAG_GPG;
+ break;
+ case RPMTAG_SIGPGP5:
+ td.tag = RPMSIGTAG_PGP5;
+ break;
+ case RPMTAG_ARCHIVESIZE:
+ /* XXX rpm-4.1 and later has archive size in signature header. */
+ if (noArchiveSize)
+ continue;
+ td.tag = RPMSIGTAG_PAYLOADSIZE;
+ break;
+ case RPMTAG_SHA1HEADER:
+ case RPMTAG_DSAHEADER:
+ case RPMTAG_RSAHEADER:
+ default:
+ if (!(td.tag >= HEADER_SIGBASE && td.tag < HEADER_TAGBASE))
+ continue;
+ break;
+ }
+ if (td.data == NULL) continue; /* XXX can't happen */
+ if (!headerIsEntry(sigh, td.tag))
+ (void) headerPut(sigh, &td, HEADERPUT_DEFAULT);
+ }
+ hi = headerFreeIterator(hi);
+ return sigh;
+}
+
+/**
+ * Remember current key id.
+ * @param dig OpenPGP packet containter
+ * @return 0 if new keyid, otherwise 1
+ */
+static int stashKeyid(pgpDig dig)
+{
+ pgpDigParams sigp = dig ? &dig->signature : NULL;
+ unsigned int keyid;
+ int i;
+
+ if (dig == NULL || sigp == NULL)
+ return 0;
+
+ keyid = pgpGrab(sigp->signid+4, 4);
+ if (keyid == 0)
+ return 0;
+
+ if (keyids != NULL)
+ for (i = 0; i < nkeyids; i++) {
+ if (keyid == keyids[i])
+ return 1;
+ }
+
+ if (nkeyids < nkeyids_max) {
+ nkeyids++;
+ keyids = xrealloc(keyids, nkeyids * sizeof(*keyids));
+ }
+ if (keyids) /* XXX can't happen */
+ keyids[nextkeyid] = keyid;
+ nextkeyid++;
+ nextkeyid %= nkeyids_max;
+
+ return 0;
+}
+
+/* Parse the parameters from the OpenPGP packets that will be needed. */
+static rpmRC parsePGP(rpmtd sigtd, const char *type, pgpDig dig)
+{
+ rpmRC rc = RPMRC_FAIL;
+ int debug = (_print_pkts & rpmIsDebug());
+ if ((pgpPrtPkts(sigtd->data, sigtd->count, dig, debug) == 0) &&
+ (dig->signature.version == 3 || dig->signature.version == 4)) {
+ rc = RPMRC_OK;
+ } else {
+ rpmlog(RPMLOG_ERR,
+ _("skipping %s with unverifiable V%u signature\n"), type,
+ dig->signature.version);
+ }
+ return rc;
+}
+
+static rpmRC headerVerify(rpmKeyring keyring, rpmVSFlags vsflags,
+ const void * uh, size_t uc, char ** msg)
+{
+ pgpDig dig = NULL;
+ char *buf = NULL;
+ int32_t * ei = (int32_t *) uh;
+ int32_t il = ntohl(ei[0]);
+ int32_t dl = ntohl(ei[1]);
+ entryInfo pe = (entryInfo) &ei[2];
+ int32_t ildl[2];
+ int32_t pvlen = sizeof(ildl) + (il * sizeof(*pe)) + dl;
+ unsigned char * dataStart = (unsigned char *) (pe + il);
+ struct indexEntry_s entry;
+ struct entryInfo_s info;
+ unsigned const char * b;
+ size_t siglen = 0;
+ size_t blen;
+ size_t nb;
+ int32_t ril = 0;
+ unsigned char * regionEnd = NULL;
+ rpmRC rc = RPMRC_FAIL; /* assume failure */
+ int xx;
+ int i;
+ struct rpmtd_s sigtd;
+ DIGEST_CTX ctx = NULL;
+
+ /* Is the blob the right size? */
+ if (uc > 0 && pvlen != uc) {
+ rasprintf(&buf, _("blob size(%d): BAD, 8 + 16 * il(%d) + dl(%d)\n"),
+ (int)uc, (int)il, (int)dl);
+ goto exit;
+ }
+
+ memset(&entry, 0, sizeof(entry));
+ memset(&info, 0, sizeof(info));
+
+ /* Check (and convert) the 1st tag element. */
+ xx = headerVerifyInfo(1, dl, pe, &entry.info, 0);
+ if (xx != -1) {
+ rasprintf(&buf, _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
+ 0, entry.info.tag, entry.info.type,
+ entry.info.offset, entry.info.count);
+ goto exit;
+ }
+
+ /* Is there an immutable header region tag? */
+ if (!(entry.info.tag == RPMTAG_HEADERIMMUTABLE
+ && entry.info.type == RPM_BIN_TYPE
+ && entry.info.count == REGION_TAG_COUNT))
+ {
+ rc = RPMRC_NOTFOUND;
+ goto exit;
+ }
+
+ /* Is the offset within the data area? */
+ if (entry.info.offset >= dl) {
+ rasprintf(&buf,
+ _("region offset: BAD, tag %d type %d offset %d count %d\n"),
+ entry.info.tag, entry.info.type,
+ entry.info.offset, entry.info.count);
+ goto exit;
+ }
+
+ /* Is there an immutable header region tag trailer? */
+ regionEnd = dataStart + entry.info.offset;
+ (void) memcpy(&info, regionEnd, REGION_TAG_COUNT);
+ regionEnd += REGION_TAG_COUNT;
+
+ xx = headerVerifyInfo(1, dl, &info, &entry.info, 1);
+ if (xx != -1 ||
+ !(entry.info.tag == RPMTAG_HEADERIMMUTABLE
+ && entry.info.type == RPM_BIN_TYPE
+ && entry.info.count == REGION_TAG_COUNT))
+ {
+ rasprintf(&buf,
+ _("region trailer: BAD, tag %d type %d offset %d count %d\n"),
+ entry.info.tag, entry.info.type,
+ entry.info.offset, entry.info.count);
+ goto exit;
+ }
+ memset(&info, 0, sizeof(info));
+
+ /* Is the no. of tags in the region less than the total no. of tags? */
+ ril = entry.info.offset/sizeof(*pe);
+ if ((entry.info.offset % sizeof(*pe)) || ril > il) {
+ rasprintf(&buf, _("region size: BAD, ril(%d) > il(%d)\n"), ril, il);
+ goto exit;
+ }
+
+ /* Find a header-only digest/signature tag. */
+ for (i = ril; i < il; i++) {
+ xx = headerVerifyInfo(1, dl, pe+i, &entry.info, 0);
+ if (xx != -1) {
+ rasprintf(&buf,
+ _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
+ i, entry.info.tag, entry.info.type,
+ entry.info.offset, entry.info.count);
+ goto exit;
+ }
+
+ switch (entry.info.tag) {
+ case RPMTAG_SHA1HEADER:
+ if (vsflags & RPMVSF_NOSHA1HEADER)
+ break;
+ blen = 0;
+ for (b = dataStart + entry.info.offset; *b != '\0'; b++) {
+ if (strchr("0123456789abcdefABCDEF", *b) == NULL)
+ break;
+ blen++;
+ }
+ if (entry.info.type != RPM_STRING_TYPE || *b != '\0' || blen != 40)
+ {
+ rasprintf(&buf, _("hdr SHA1: BAD, not hex\n"));
+ goto exit;
+ }
+ if (info.tag == 0) {
+ info = entry.info; /* structure assignment */
+ siglen = blen + 1;
+ }
+ break;
+ case RPMTAG_RSAHEADER:
+ if (vsflags & RPMVSF_NORSAHEADER)
+ break;
+ if (entry.info.type != RPM_BIN_TYPE) {
+ rasprintf(&buf, _("hdr RSA: BAD, not binary\n"));
+ goto exit;
+ }
+ info = entry.info; /* structure assignment */
+ siglen = info.count;
+ break;
+ case RPMTAG_DSAHEADER:
+ if (vsflags & RPMVSF_NODSAHEADER)
+ break;
+ if (entry.info.type != RPM_BIN_TYPE) {
+ rasprintf(&buf, _("hdr DSA: BAD, not binary\n"));
+ goto exit;
+ }
+ info = entry.info; /* structure assignment */
+ siglen = info.count;
+ break;
+ default:
+ break;
+ }
+ }
+ rc = RPMRC_NOTFOUND;
+
+exit:
+ /* Return determined RPMRC_OK/RPMRC_FAIL conditions. */
+ if (rc != RPMRC_NOTFOUND) {
+ if (msg)
+ *msg = buf;
+ else
+ free(buf);
+ return rc;
+ }
+
+ /* If no header-only digest/signature, then do simple sanity check. */
+ if (info.tag == 0) {
+verifyinfo_exit:
+ xx = headerVerifyInfo(ril-1, dl, pe+1, &entry.info, 0);
+ if (xx != -1) {
+ rasprintf(&buf,
+ _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
+ xx+1, entry.info.tag, entry.info.type,
+ entry.info.offset, entry.info.count);
+ rc = RPMRC_FAIL;
+ } else {
+ rasprintf(&buf, "Header sanity check: OK\n");
+ rc = RPMRC_OK;
+ }
+ if (msg)
+ *msg = buf;
+ else
+ free(buf);
+ return rc;
+ }
+
+ /* Verify header-only digest/signature. */
+ dig = pgpNewDig();
+ if (dig == NULL)
+ goto verifyinfo_exit;
+
+ sigtd.tag = info.tag;
+ sigtd.type = info.type;
+ sigtd.count = info.count;
+ sigtd.data = memcpy(xmalloc(siglen), dataStart + info.offset, siglen);
+ sigtd.flags = RPMTD_ALLOCED;
+
+ switch (info.tag) {
+ case RPMTAG_RSAHEADER:
+ case RPMTAG_DSAHEADER:
+ if ((rc = parsePGP(&sigtd, "header", dig)) != RPMRC_OK) {
+ pgpFreeDig(dig);
+ goto exit;
+ }
+ /* fallthrough */
+ case RPMTAG_SHA1HEADER: {
+ int hashalgo = (info.tag == RPMTAG_SHA1HEADER) ?
+ PGPHASHALGO_SHA1 : dig->signature.hash_algo;
+ ildl[0] = htonl(ril);
+ ildl[1] = (regionEnd - dataStart);
+ ildl[1] = htonl(ildl[1]);
+
+ ctx = rpmDigestInit(hashalgo, RPMDIGEST_NONE);
+
+ b = (unsigned char *) rpm_header_magic;
+ nb = sizeof(rpm_header_magic);
+ (void) rpmDigestUpdate(ctx, b, nb);
+
+ b = (unsigned char *) ildl;
+ nb = sizeof(ildl);
+ (void) rpmDigestUpdate(ctx, b, nb);
+
+ b = (unsigned char *) pe;
+ nb = (htonl(ildl[0]) * sizeof(*pe));
+ (void) rpmDigestUpdate(ctx, b, nb);
+
+ b = (unsigned char *) dataStart;
+ nb = htonl(ildl[1]);
+ (void) rpmDigestUpdate(ctx, b, nb);
+ } break;
+ default:
+ sigtd.data = _free(sigtd.data); /* Hmm...? */
+ break;
+ }
+
+ rc = rpmVerifySignature(keyring, &sigtd, dig, ctx, &buf);
+
+ if (msg)
+ *msg = buf;
+ else
+ free(buf);
+
+ rpmtdFreeData(&sigtd);
+ pgpFreeDig(dig);
+ rpmDigestFinal(ctx, NULL, NULL, 0);
+ return rc;
+}
+
+rpmRC headerCheck(rpmts ts, const void * uh, size_t uc, char ** msg)
+{
+ rpmRC rc;
+ rpmVSFlags vsflags = rpmtsVSFlags(ts);
+ rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
+
+ rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
+ rc = headerVerify(keyring, vsflags, uh, uc, msg);
+ rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), uc);
+ rpmKeyringFree(keyring);
+
+ return rc;
+}
+
+static rpmRC rpmpkgReadHeader(rpmKeyring keyring, rpmVSFlags vsflags,
+ FD_t fd, Header *hdrp, char ** msg)
+{
+ char *buf = NULL;
+ int32_t block[4];
+ int32_t il;
+ int32_t dl;
+ int32_t * ei = NULL;
+ size_t uc;
+ size_t nb;
+ Header h = NULL;
+ rpmRC rc = RPMRC_FAIL; /* assume failure */
+ int xx;
+
+ if (hdrp)
+ *hdrp = NULL;
+ if (msg)
+ *msg = NULL;
+
+ memset(block, 0, sizeof(block));
+ if ((xx = timedRead(fd, (char *)block, sizeof(block))) != sizeof(block)) {
+ rasprintf(&buf,
+ _("hdr size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx);
+ goto exit;
+ }
+ if (memcmp(block, rpm_header_magic, sizeof(rpm_header_magic))) {
+ rasprintf(&buf, _("hdr magic: BAD\n"));
+ goto exit;
+ }
+ il = ntohl(block[2]);
+ if (hdrchkTags(il)) {
+ rasprintf(&buf, _("hdr tags: BAD, no. of tags(%d) out of range\n"), il);
+ goto exit;
+ }
+ dl = ntohl(block[3]);
+ if (hdrchkData(dl)) {
+ rasprintf(&buf,
+ _("hdr data: BAD, no. of bytes(%d) out of range\n"), dl);
+ goto exit;
+ }
+
+ nb = (il * sizeof(struct entryInfo_s)) + dl;
+ uc = sizeof(il) + sizeof(dl) + nb;
+ ei = xmalloc(uc);
+ ei[0] = block[2];
+ ei[1] = block[3];
+ if ((xx = timedRead(fd, (char *)&ei[2], nb)) != nb) {
+ rasprintf(&buf, _("hdr blob(%zd): BAD, read returned %d\n"), nb, xx);
+ goto exit;
+ }
+
+ /* Sanity check header tags */
+ rc = headerVerify(keyring, vsflags, ei, uc, msg);
+ if (rc != RPMRC_OK)
+ goto exit;
+
+ /* OK, blob looks sane, load the header. */
+ h = headerLoad(ei);
+ if (h == NULL) {
+ rasprintf(&buf, _("hdr load: BAD\n"));
+ rc = RPMRC_FAIL;
+ goto exit;
+ }
+ ei = NULL; /* XXX will be freed with header */
+
+exit:
+ if (hdrp && h && rc == RPMRC_OK)
+ *hdrp = headerLink(h);
+ ei = _free(ei);
+ h = headerFree(h);
+
+ if (msg != NULL && *msg == NULL && buf != NULL) {
+ *msg = buf;
+ } else {
+ free(buf);
+ }
+
+ return rc;
+}
+
+rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, char ** msg)
+{
+ rpmRC rc;
+ rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
+ rpmVSFlags vsflags = rpmtsVSFlags(ts);
+
+ rc = rpmpkgReadHeader(keyring, vsflags, fd, hdrp, msg);
+
+ rpmKeyringFree(keyring);
+ return rc;
+}
+
+static rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags vsflags,
+ FD_t fd, const char * fn, Header * hdrp)
+{
+ pgpDig dig = NULL;
+ char buf[8*BUFSIZ];
+ ssize_t count;
+ rpmlead l = NULL;
+ Header sigh = NULL;
+ rpmTagVal sigtag;
+ struct rpmtd_s sigtd;
+ Header h = NULL;
+ char * msg;
+ rpmRC rc = RPMRC_FAIL; /* assume failure */
+ int leadtype = -1;
+ headerGetFlags hgeflags = HEADERGET_DEFAULT;
+ DIGEST_CTX ctx = NULL;
+
+ if (hdrp) *hdrp = NULL;
+
+ rpmtdReset(&sigtd);
+ l = rpmLeadNew();
+
+ if ((rc = rpmLeadRead(fd, l)) == RPMRC_OK) {
+ const char * err = NULL;
+ if ((rc = rpmLeadCheck(l, &err)) == RPMRC_FAIL) {
+ rpmlog(RPMLOG_ERR, "%s: %s\n", fn, err);
+ }
+ leadtype = rpmLeadType(l);
+ }
+ l = rpmLeadFree(l);
+
+ if (rc != RPMRC_OK)
+ goto exit;
+
+ /* Read the signature header. */
+ msg = NULL;
+ rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg);
+ switch (rc) {
+ default:
+ rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), fn,
+ (msg && *msg ? msg : "\n"));
+ msg = _free(msg);
+ goto exit;
+ break;
+ case RPMRC_OK:
+ if (sigh == NULL) {
+ rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
+ rc = RPMRC_FAIL;
+ goto exit;
+ }
+ break;
+ }
+ msg = _free(msg);
+
+#define _chk(_mask, _tag) \
+ (sigtag == 0 && !(vsflags & (_mask)) && headerIsEntry(sigh, (_tag)))
+
+ /*
+ * Figger the most effective available signature.
+ * Prefer signatures over digests, then header-only over header+payload.
+ * DSA will be preferred over RSA if both exist because tested first.
+ * Note that NEEDPAYLOAD prevents header+payload signatures and digests.
+ */
+ sigtag = 0;
+ if (_chk(RPMVSF_NODSAHEADER, RPMSIGTAG_DSA)) {
+ sigtag = RPMSIGTAG_DSA;
+ } else if (_chk(RPMVSF_NORSAHEADER, RPMSIGTAG_RSA)) {
+ sigtag = RPMSIGTAG_RSA;
+ } else if (_chk(RPMVSF_NODSA|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_GPG)) {
+ sigtag = RPMSIGTAG_GPG;
+ fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
+ } else if (_chk(RPMVSF_NORSA|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_PGP)) {
+ sigtag = RPMSIGTAG_PGP;
+ fdInitDigest(fd, PGPHASHALGO_MD5, 0);
+ } else if (_chk(RPMVSF_NOSHA1HEADER, RPMSIGTAG_SHA1)) {
+ sigtag = RPMSIGTAG_SHA1;
+ } else if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD, RPMSIGTAG_MD5)) {
+ sigtag = RPMSIGTAG_MD5;
+ fdInitDigest(fd, PGPHASHALGO_MD5, 0);
+ }
+
+ /* Read the metadata, computing digest(s) on the fly. */
+ h = NULL;
+ msg = NULL;
+
+ rc = rpmpkgReadHeader(keyring, vsflags, fd, &h, &msg);
+
+ if (rc != RPMRC_OK || h == NULL) {
+ rpmlog(RPMLOG_ERR, _("%s: headerRead failed: %s"), fn,
+ (msg && *msg ? msg : "\n"));
+ msg = _free(msg);
+ goto exit;
+ }
+ msg = _free(msg);
+
+ /* Any digests or signatures to check? */
+ if (sigtag == 0) {
+ rc = RPMRC_OK;
+ goto exit;
+ }
+
+ dig = pgpNewDig();
+ if (dig == NULL) {
+ rc = RPMRC_FAIL;
+ goto exit;
+ }
+
+ /* Retrieve the tag parameters from the signature header. */
+ if (!headerGet(sigh, sigtag, &sigtd, hgeflags)) {
+ rc = RPMRC_FAIL;
+ goto exit;
+ }
+
+ switch (sigtag) {
+ case RPMSIGTAG_RSA:
+ case RPMSIGTAG_DSA:
+ if ((rc = parsePGP(&sigtd, "package", dig)) != RPMRC_OK) {
+ goto exit;
+ }
+ /* fallthrough */
+ case RPMSIGTAG_SHA1:
+ { struct rpmtd_s utd;
+ int hashalgo = (sigtag == RPMSIGTAG_SHA1) ?
+ PGPHASHALGO_SHA1 : dig->signature.hash_algo;
+
+ if (!headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, hgeflags))
+ break;
+ ctx = rpmDigestInit(hashalgo, RPMDIGEST_NONE);
+ (void) rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
+ (void) rpmDigestUpdate(ctx, utd.data, utd.count);
+ rpmtdFreeData(&utd);
+ } break;
+ case RPMSIGTAG_GPG:
+ case RPMSIGTAG_PGP5: /* XXX legacy */
+ case RPMSIGTAG_PGP:
+ if ((rc = parsePGP(&sigtd, "package", dig)) != RPMRC_OK) {
+ goto exit;
+ }
+ /* fallthrough */
+ case RPMSIGTAG_MD5:
+ /* Legacy signatures need the compressed payload in the digest too. */
+ while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) {}
+ if (count < 0) {
+ rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"),
+ fn, Fstrerror(fd));
+ rc = RPMRC_FAIL;
+ goto exit;
+ }
+
+ ctx = rpmDigestBundleDupCtx(fdGetBundle(fd), (sigtag == RPMSIGTAG_MD5) ?
+ PGPHASHALGO_MD5 : dig->signature.hash_algo);
+ break;
+ default:
+ break;
+ }
+
+ /** @todo Implement disable/enable/warn/error/anal policy. */
+ rc = rpmVerifySignature(keyring, &sigtd, dig, ctx, &msg);
+
+ switch (rc) {
+ case RPMRC_OK: /* Signature is OK. */
+ rpmlog(RPMLOG_DEBUG, "%s: %s", fn, msg);
+ break;
+ case RPMRC_NOTTRUSTED: /* Signature is OK, but key is not trusted. */
+ case RPMRC_NOKEY: /* Public key is unavailable. */
+ /* XXX Print NOKEY/NOTTRUSTED warning only once. */
+ { int lvl = (stashKeyid(dig) ? RPMLOG_DEBUG : RPMLOG_WARNING);
+ rpmlog(lvl, "%s: %s", fn, msg);
+ } break;
+ case RPMRC_NOTFOUND: /* Signature is unknown type. */
+ rpmlog(RPMLOG_WARNING, "%s: %s", fn, msg);
+ break;
+ default:
+ case RPMRC_FAIL: /* Signature does not verify. */
+ rpmlog(RPMLOG_ERR, "%s: %s", fn, msg);
+ break;
+ }
+ free(msg);
+
+exit:
+ if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) {
+ /* Retrofit RPMTAG_SOURCEPACKAGE to srpms for compatibility */
+ if (leadtype == RPMLEAD_SOURCE && headerIsSource(h)) {
+ if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE)) {
+ uint32_t one = 1;
+ headerPutUint32(h, RPMTAG_SOURCEPACKAGE, &one, 1);
+ }
+ }
+ /*
+ * Try to make sure binary rpms have RPMTAG_SOURCERPM set as that's
+ * what we use for differentiating binary vs source elsewhere.
+ */
+ if (!headerIsEntry(h, RPMTAG_SOURCEPACKAGE) && headerIsSource(h)) {
+ headerPutString(h, RPMTAG_SOURCERPM, "(none)");
+ }
+ /*
+ * Convert legacy headers on the fly. Not having "new" style compressed
+ * filenames is close enough estimate for legacy indication...
+ */
+ if (!headerIsEntry(h, RPMTAG_DIRNAMES)) {
+ headerConvert(h, HEADERCONV_RETROFIT_V3);
+ }
+
+ /* Append (and remap) signature tags to the metadata. */
+ headerMergeLegacySigs(h, sigh);
+
+ /* Bump reference count for return. */
+ *hdrp = headerLink(h);
+ }
+ rpmtdFreeData(&sigtd);
+ rpmDigestFinal(ctx, NULL, NULL, 0);
+ h = headerFree(h);
+ pgpFreeDig(dig);
+ sigh = rpmFreeSignature(sigh);
+ return rc;
+}
+
+rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp)
+{
+ rpmRC rc;
+ rpmVSFlags vsflags = rpmtsVSFlags(ts);
+ rpmKeyring keyring = 0;
+
+ if ((vsflags & _RPMVSF_NOSIGNATURES) != _RPMVSF_NOSIGNATURES)
+ keyring = rpmtsGetKeyring(ts, 1);
+
+ rc = rpmpkgRead(keyring, vsflags, fd, fn, hdrp);
+
+ if (keyring)
+ rpmKeyringFree(keyring);
+ return rc;
+}
+
+/**
+ * Check for supported payload format in header.
+ * @param h header to check
+ * @return RPMRC_OK if supported, RPMRC_FAIL otherwise
+ */
+rpmRC headerCheckPayloadFormat(Header h) {
+ rpmRC rc = RPMRC_OK;
+ const char *payloadfmt = headerGetString(h, RPMTAG_PAYLOADFORMAT);
+ /*
+ * XXX Ugh, rpm 3.x packages don't have payload format tag. Instead
+ * of blinly allowing, should check somehow (HDRID existence or... ?)
+ */
+ if (!payloadfmt) return rc;
+
+ if (!rstreq(payloadfmt, "cpio")) {
+ char *nevra = headerGetAsString(h, RPMTAG_NEVRA);
+ if (payloadfmt && rstreq(payloadfmt, "drpm")) {
+ rpmlog(RPMLOG_ERR,
+ _("%s is a Delta RPM and cannot be directly installed\n"),
+ nevra);
+ } else {
+ rpmlog(RPMLOG_ERR,
+ _("Unsupported payload (%s) in package %s\n"),
+ payloadfmt ? payloadfmt : "none", nevra);
+ }
+ nevra = _free(nevra);
+ rc = RPMRC_FAIL;
+ }
+ return rc;
+}
+
+