Beispiel #1
0
/* Dumb wrapper around headerPut() for signature header */
static int sighdrPut(Header h, rpmTagVal tag, rpmTagType type,
                     rpm_data_t p, rpm_count_t c)
{
    struct rpmtd_s sigtd;
    rpmtdReset(&sigtd);
    sigtd.tag = tag;
    sigtd.type = type;
    sigtd.data = p;
    sigtd.count = c;
    return headerPut(h, &sigtd, HEADERPUT_DEFAULT);
}
Beispiel #2
0
int headerNext(HeaderIterator hi, rpmtd td)
{
    indexEntry entry = nextIndex(hi);
    int rc = 0;

    rpmtdReset(td);
    if (entry) {
	td->tag = entry->info.tag;
	rc = copyTdEntry(entry, td, HEADERGET_DEFAULT);
    }
    return ((rc == 1) ? 1 : 0);
}
Beispiel #3
0
/*
 * Validate generated signature and insert to header if it looks sane.
 * NSS doesn't support everything GPG does. Basic tests to see if the 
 * generated signature is something we can use.
 * Return 0 on success, 1 on failure.
 */
static int putSignature(Header sigh, int ishdr, uint8_t *pkt, size_t pktlen)
{
    pgpDigParams sigp = NULL;
    rpmTagVal sigtag;
    struct rpmtd_s sigtd;
    int rc = 1; /* assume failure */
    unsigned int hash_algo;
    unsigned int pubkey_algo;

    if (pgpPrtParams(pkt, pktlen, PGPTAG_SIGNATURE, &sigp)) {
	rpmlog(RPMLOG_ERR, _("Unsupported PGP signature\n"));
	goto exit;
    }

    hash_algo = pgpDigParamsAlgo(sigp, PGPVAL_HASHALGO);
    if (rpmDigestLength(hash_algo) == 0) {
	rpmlog(RPMLOG_ERR, _("Unsupported PGP hash algorithm %u\n"), hash_algo);
	goto exit;
    }

    pubkey_algo = pgpDigParamsAlgo(sigp, PGPVAL_PUBKEYALGO);
    switch (pubkey_algo) {
    case PGPPUBKEYALGO_DSA:
	sigtag = ishdr ? RPMSIGTAG_DSA : RPMSIGTAG_GPG;
	break;
    case PGPPUBKEYALGO_RSA:
	sigtag = ishdr ? RPMSIGTAG_RSA : RPMSIGTAG_PGP;
	break;
    default:
	rpmlog(RPMLOG_ERR, _("Unsupported PGP pubkey algorithm %u\n"),
		pubkey_algo);
	goto exit;
	break;
    }

    /* Looks sane, insert into header */
    rpmtdReset(&sigtd);
    sigtd.count = pktlen;
    sigtd.data = pkt;
    sigtd.type = RPM_BIN_TYPE;
    sigtd.tag = sigtag;

    /* Argh, reversed return codes */
    rc = (headerPut(sigh, &sigtd, HEADERPUT_DEFAULT) == 0);

exit:
    pgpDigParamsFree(sigp);
    return rc;
}
Beispiel #4
0
static inline int rpmtdSet(rpmtd td, rpmTagVal tag, rpmTagType type, 
			    rpm_constdata_t data, rpm_count_t count)
{
    rpmtdReset(td);
    td->tag = tag;
    td->type = type;
    td->count = count;
    /* 
     * Discards const, but we won't touch the data (even rpmtdFreeData()
     * wont free it as allocation flags aren't set) so it's "ok". 
     * XXX: Should there be a separate RPMTD_FOO flag for "user data"?
     */
    td->data = (void *) data;
    return 1;
}
Beispiel #5
0
void rpmtdFreeData(rpmtd td)
{
    assert(td != NULL);

    if (td->flags & RPMTD_ALLOCED) {
	if (td->flags & RPMTD_PTR_ALLOCED) {
	    assert(td->data != NULL);
	    char **data = td->data;
	    for (int i = 0; i < td->count; i++) {
		free(data[i]);
	    }
	}
	free(td->data);
    }
    rpmtdReset(td);
}
Beispiel #6
0
int headerGet(Header h, rpmTagVal tag, rpmtd td, headerGetFlags flags)
{
    int rc;
    headerTagTagFunction tagfunc = intGetTdEntry;

    if (td == NULL) return 0;

    rpmtdReset(td);
    td->tag = tag;

    if (flags & HEADERGET_EXT) {
	headerTagTagFunction extfunc = rpmHeaderTagFunc(tag);
	if (extfunc) tagfunc = extfunc;
    }
    rc = tagfunc(h, td, flags);

    assert(tag == td->tag);
    return rc;
}
Beispiel #7
0
/*
 * Sanity check data types against tag table before putting. Assume
 * append on all array-types.
 */
static int headerPutType(Header h, rpmTagVal tag, rpmTagType reqtype,
			rpm_constdata_t data, rpm_count_t size)
{
    struct rpmtd_s td;
    rpmTagType type = rpmTagGetTagType(tag);
    rpmTagReturnType retype = rpmTagGetReturnType(tag);
    headerPutFlags flags = HEADERPUT_APPEND; 
    int valid = 1;

    /* Basic sanity checks: type must match and there must be data to put */
    if (type != reqtype 
	|| size < 1 || data == NULL || h == NULL) {
	valid = 0;
    }

    /*
     * Non-array types can't be appended to. Binary types use size
     * for data length, for other non-array types size must be 1.
     */
    if (retype != RPM_ARRAY_RETURN_TYPE) {
	flags = HEADERPUT_DEFAULT;
	if (type != RPM_BIN_TYPE && size != 1) {
	    valid = 0;
	}
    }

    if (valid) {
	rpmtdReset(&td);
	td.tag = tag;
	td.type = type;
	td.data = (void *) data;
	td.count = size;

	valid = headerPut(h, &td, flags);
    }

    return valid;
}
Beispiel #8
0
int rpmTagGetNames(rpmtd tagnames, int fullname)
{
    const char **names;
    const char *name;

    if (_rpmTags.byName == NULL)
	tagLoadIndex(&_rpmTags.byName, &_rpmTags.byNameSize, tagCmpName);
    if (tagnames == NULL ||_rpmTags.byName == NULL)
	return 0;

    rpmtdReset(tagnames);
    tagnames->count = _rpmTags.byNameSize;
    tagnames->data = names = xmalloc(tagnames->count * sizeof(*names));
    tagnames->type = RPM_STRING_ARRAY_TYPE;
    tagnames->flags = RPMTD_ALLOCED | RPMTD_IMMUTABLE;

    for (int i = 0; i < tagnames->count; i++) {
	name = fullname ? _rpmTags.byName[i]->name : 
			  _rpmTags.byName[i]->shortname;
	names[i] = name;
    }
    return tagnames->count;
}
Beispiel #9
0
static rpmRC writeModuleToHeader(ModuleRec mod, Package pkg)
{
    rpmRC rc = RPMRC_FAIL;
    ARGV_t av;
    uint32_t count;
    struct rpmtd_s policies;
    struct rpmtd_s policynames;
    struct rpmtd_s policyflags;
    struct rpmtd_s policytypes;
    struct rpmtd_s policytypesidx;
    rpmtdReset(&policies);
    rpmtdReset(&policynames);
    rpmtdReset(&policyflags);
    rpmtdReset(&policytypes);
    rpmtdReset(&policytypesidx);

    if (!mod || !pkg) {
	goto exit;
    }

    /* check for duplicates */
    if (headerIsEntry(pkg->header, RPMTAG_POLICYNAMES)) {
	int typeCount;
	const char *name;
	char *type;
	int i;
	int idx;

	headerGet(pkg->header, RPMTAG_POLICYNAMES, &policynames, HEADERGET_MINMEM);
	headerGet(pkg->header, RPMTAG_POLICYFLAGS, &policyflags, HEADERGET_ARGV | HEADERGET_MINMEM);
	headerGet(pkg->header, RPMTAG_POLICYTYPES, &policytypes, HEADERGET_ARGV | HEADERGET_MINMEM);
	headerGet(pkg->header, RPMTAG_POLICYTYPESINDEXES, &policytypesidx, HEADERGET_ARGV | HEADERGET_MINMEM);
	typeCount = rpmtdCount(&policytypes);

	while ((name = rpmtdNextString(&policynames))) {
	    int overlappingtypes = 0;

	    idx = rpmtdGetIndex(&policynames);

	    for (i = 0; i < typeCount; i++) {
		if (((int *) policytypesidx.data)[i] != idx) {
		    continue;
		}

		type = ((char **) policytypes.data)[i];

		if (rstreq(type, RPMPOL_TYPE_DEFAULT) ||
		    argvSearch(mod->types, type, NULL) ||
		    argvSearch(mod->types, RPMPOL_TYPE_DEFAULT, NULL)) {
		    overlappingtypes = 1;
		    break;
		}
	    }

	    if (!overlappingtypes) {
		continue;
	    }

	    if (rstreq(mod->name, name)) {
		rpmlog(RPMLOG_ERR, _("Policy module '%s' duplicated with overlapping types\n"), name);
		goto exit;
	    }

	    if ((mod->flags && RPMPOL_FLAG_BASE) &&
		(((int *) policyflags.data)[idx] & RPMPOL_FLAG_BASE)) {
		rpmlog(RPMLOG_ERR, _("Base modules '%s' and '%s' have overlapping types\n"), mod->name, name);
		goto exit;
	    }
	}
    }

    if (headerIsEntry(pkg->header, RPMTAG_POLICIES)) {
	if (!headerGet(pkg->header, RPMTAG_POLICIES, &policies, HEADERGET_MINMEM)) {
	    rpmlog(RPMLOG_ERR, _("Failed to get policies from header\n"));
	    goto exit;
	}
	count = rpmtdCount(&policies);
    } else {
	count = 0;
    }

    /* save everything to the header */
    headerPutString(pkg->header, RPMTAG_POLICIES, mod->data);
    headerPutString(pkg->header, RPMTAG_POLICYNAMES, mod->name);
    headerPutUint32(pkg->header, RPMTAG_POLICYFLAGS, &mod->flags, 1);

    for (av = mod->types; av && *av; av++) {
	headerPutString(pkg->header, RPMTAG_POLICYTYPES, *av);
	headerPutUint32(pkg->header, RPMTAG_POLICYTYPESINDEXES, &count, 1);
    }

    rc = RPMRC_OK;

  exit:

    rpmtdFreeData(&policies);
    rpmtdFreeData(&policynames);
    rpmtdFreeData(&policyflags);
    rpmtdFreeData(&policytypes);
    rpmtdFreeData(&policytypesidx);

    return rc;
}
Beispiel #10
0
/*
 * Argument monster to verify header-only signature/digest if there is
 * one, otherwisereturn RPMRC_NOTFOUND to signal for plain sanity check.
 */
static rpmRC headerSigVerify(rpmKeyring keyring, rpmVSFlags vsflags,
			     int il, int dl, int ril, int rdl,
			     entryInfo pe, unsigned char * dataStart,
			     char **buf)
{
    size_t siglen = 0;
    rpmRC rc = RPMRC_FAIL;
    pgpDigParams sig = NULL;
    struct rpmtd_s sigtd;
    struct entryInfo_s info, einfo;
    unsigned int hashalgo = 0;

    rpmtdReset(&sigtd);
    memset(&info, 0, sizeof(info));
    memset(&einfo, 0, sizeof(einfo));

    /* Find a header-only digest/signature tag. */
    for (int i = ril; i < il; i++) {
	if (headerVerifyInfo(1, dl, pe+i, &einfo, 0) != -1) {
	    rasprintf(buf,
		_("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
		i, einfo.tag, einfo.type,
		einfo.offset, einfo.count);
	    goto exit;
	}

	switch (einfo.tag) {
	case RPMTAG_SHA1HEADER: {
	    size_t blen = 0;
	    unsigned const char * b;
	    if (vsflags & RPMVSF_NOSHA1HEADER)
		break;
	    for (b = dataStart + einfo.offset; *b != '\0'; b++) {
		if (strchr("0123456789abcdefABCDEF", *b) == NULL)
		    break;
		blen++;
	    }
	    if (einfo.type != RPM_STRING_TYPE || *b != '\0' || blen != 40)
	    {
		rasprintf(buf, _("hdr SHA1: BAD, not hex\n"));
		goto exit;
	    }
	    if (info.tag == 0) {
		info = einfo;	/* structure assignment */
		siglen = blen + 1;
	    }
	    } break;
	case RPMTAG_RSAHEADER:
	    if (vsflags & RPMVSF_NORSAHEADER)
		break;
	    if (einfo.type != RPM_BIN_TYPE) {
		rasprintf(buf, _("hdr RSA: BAD, not binary\n"));
		goto exit;
	    }
	    info = einfo;	/* structure assignment */
	    siglen = info.count;
	    break;
	case RPMTAG_DSAHEADER:
	    if (vsflags & RPMVSF_NODSAHEADER)
		break;
	    if (einfo.type != RPM_BIN_TYPE) {
		rasprintf(buf, _("hdr DSA: BAD, not binary\n"));
		goto exit;
	    }
	    info = einfo;	/* structure assignment */
	    siglen = info.count;
	    break;
	default:
	    break;
	}
    }

    /* No header-only digest/signature found, get outta here */
    if (info.tag == 0) {
	rc = RPMRC_NOTFOUND;
	goto 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 (parsePGPSig(&sigtd, "header", NULL, &sig))
	    goto exit;
	hashalgo = pgpDigParamsAlgo(sig, PGPVAL_HASHALGO);
	break;
    case RPMTAG_SHA1HEADER:
	hashalgo = PGPHASHALGO_SHA1;
	break;
    default:
	break;
    }

    if (hashalgo) {
	DIGEST_CTX ctx = rpmDigestInit(hashalgo, RPMDIGEST_NONE);
	int32_t ildl[2] = { htonl(ril), htonl(rdl) };

	rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
	rpmDigestUpdate(ctx, ildl, sizeof(ildl));
	rpmDigestUpdate(ctx, pe, (ril * sizeof(*pe)));
	rpmDigestUpdate(ctx, dataStart, rdl);

	rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, buf);

    	rpmDigestFinal(ctx, NULL, NULL, 0);
    }

exit:
    rpmtdFreeData(&sigtd);
    pgpDigParamsFree(sig);

    return rc;
}
Beispiel #11
0
int headerAddI18NString(Header h, rpmTagVal tag, const char * string,
		const char * lang)
{
    indexEntry table, entry;
    const char ** strArray;
    int length;
    int ghosts;
    rpm_count_t i, langNum;
    char * buf;

    table = findEntry(h, RPMTAG_HEADERI18NTABLE, RPM_STRING_ARRAY_TYPE);
    entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);

    if (!table && entry)
	return 0;		/* this shouldn't ever happen!! */

    if (!table && !entry) {
	const char * charArray[2];
	rpm_count_t count = 0;
	struct rpmtd_s td;
	if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
	    charArray[count++] = "C";
	} else {
	    charArray[count++] = "C";
	    charArray[count++] = lang;
	}
	
	rpmtdReset(&td);
	td.tag = RPMTAG_HEADERI18NTABLE;
	td.type = RPM_STRING_ARRAY_TYPE;
	td.data = (void *) charArray;
	td.count = count;
	if (!headerPut(h, &td, HEADERPUT_DEFAULT))
	    return 0;
	table = findEntry(h, RPMTAG_HEADERI18NTABLE, RPM_STRING_ARRAY_TYPE);
    }

    if (!table)
	return 0;
    if (!lang) lang = "C";

    {	const char * l = table->data;
	for (langNum = 0; langNum < table->info.count; langNum++) {
	    if (rstreq(l, lang)) break;
	    l += strlen(l) + 1;
	}
    }

    if (langNum >= table->info.count) {
	length = strlen(lang) + 1;
	if (ENTRY_IN_REGION(table)) {
	    char * t = xmalloc(table->length + length);
	    memcpy(t, table->data, table->length);
	    table->data = t;
	    table->info.offset = 0;
	} else
	    table->data = xrealloc(table->data, table->length + length);
	memmove(((char *)table->data) + table->length, lang, length);
	table->length += length;
	table->info.count++;
    }

    if (!entry) {
	int rc;
	struct rpmtd_s td;
	strArray = xmalloc(sizeof(*strArray) * (langNum + 1));
	for (i = 0; i < langNum; i++)
	    strArray[i] = "";
	strArray[langNum] = string;

	rpmtdReset(&td);
	td.tag = tag;
	td.type = RPM_I18NSTRING_TYPE;
	td.data = strArray;
	td.count = langNum + 1;
	rc = headerPut(h, &td, HEADERPUT_DEFAULT);
	free(strArray);
	return rc;
    } else if (langNum >= entry->info.count) {
	ghosts = langNum - entry->info.count;
	
	length = strlen(string) + 1 + ghosts;
	if (ENTRY_IN_REGION(entry)) {
	    char * t = xmalloc(entry->length + length);
	    memcpy(t, entry->data, entry->length);
	    entry->data = t;
	    entry->info.offset = 0;
	} else
	    entry->data = xrealloc(entry->data, entry->length + length);

	memset(((char *)entry->data) + entry->length, '\0', ghosts);
	memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);

	entry->length += length;
	entry->info.count = langNum + 1;
    } else {
	char *b, *be, *e, *ee, *t;
	size_t bn, sn, en;

	/* Set beginning/end pointers to previous data */
	b = be = e = ee = entry->data;
	for (i = 0; i < table->info.count; i++) {
	    if (i == langNum)
		be = ee;
	    ee += strlen(ee) + 1;
	    if (i == langNum)
		e  = ee;
	}

	/* Get storage for new buffer */
	bn = (be-b);
	sn = strlen(string) + 1;
	en = (ee-e);
	length = bn + sn + en;
	t = buf = xmalloc(length);

	/* Copy values into new storage */
	memcpy(t, b, bn);
	t += bn;
	memcpy(t, string, sn);
	t += sn;
	memcpy(t, e, en);
	t += en;

	/* Replace i18N string array */
	entry->length -= strlen(be) + 1;
	entry->length += sn;
	
	if (ENTRY_IN_REGION(entry)) {
	    entry->info.offset = 0;
	} else
	    entry->data = _free(entry->data);
	entry->data = buf;
    }

    return 0;
}
Beispiel #12
0
Datei: pack.c Projekt: kaltsi/rpm
static rpmRC writeRPM(Header *hdrp, unsigned char ** pkgidp, const char *fileName,
	     CSA_t csa, char **cookie)
{
    FD_t fd = NULL;
    FD_t ifd = NULL;
    ssize_t count;
    char * sigtarget = NULL;;
    char * rpmio_flags = NULL;
    char * SHA1 = NULL;
    const char *s;
    char *buf = NULL;
    Header h;
    Header sig = NULL;
    int xx;
    rpmRC rc = RPMRC_OK;
    struct rpmtd_s td;
    rpmTagVal sizetag;
    rpmTagVal payloadtag;

    /* Transfer header reference form *hdrp to h. */
    h = headerLink(*hdrp);
    *hdrp = headerFree(*hdrp);

    if (pkgidp)
	*pkgidp = NULL;

    /* Save payload information */
    if (headerIsSource(h))
	rpmio_flags = rpmExpand("%{?_source_payload}", NULL);
    else 
	rpmio_flags = rpmExpand("%{?_binary_payload}", NULL);

    if (!(rpmio_flags && *rpmio_flags)) {
	rpmio_flags = _free(rpmio_flags);
	rpmio_flags = xstrdup("w9.gzdio");
    }
    s = strchr(rpmio_flags, '.');
    if (s) {
	const char *compr = NULL;
	headerPutString(h, RPMTAG_PAYLOADFORMAT, "cpio");

	if (rstreq(s+1, "ufdio")) {
	    compr = NULL;
	} else if (rstreq(s+1, "gzdio")) {
	    compr = "gzip";
#if HAVE_BZLIB_H
	} else if (rstreq(s+1, "bzdio")) {
	    compr = "bzip2";
	    /* Add prereq on rpm version that understands bzip2 payloads */
	    (void) rpmlibNeedsFeature(h, "PayloadIsBzip2", "3.0.5-1");
#endif
#if HAVE_LZMA_H
	} else if (rstreq(s+1, "xzdio")) {
	    compr = "xz";
	    (void) rpmlibNeedsFeature(h, "PayloadIsXz", "5.2-1");
	} else if (rstreq(s+1, "lzdio")) {
	    compr = "lzma";
	    (void) rpmlibNeedsFeature(h, "PayloadIsLzma", "4.4.6-1");
#endif
	} else {
	    rpmlog(RPMLOG_ERR, _("Unknown payload compression: %s\n"),
		   rpmio_flags);
	    rc = RPMRC_FAIL;
	    goto exit;
	}

	if (compr)
	    headerPutString(h, RPMTAG_PAYLOADCOMPRESSOR, compr);
	buf = xstrdup(rpmio_flags);
	buf[s - rpmio_flags] = '\0';
	headerPutString(h, RPMTAG_PAYLOADFLAGS, buf+1);
	free(buf);
    }

    /* Create and add the cookie */
    if (cookie) {
	rasprintf(cookie, "%s %d", buildHost(), (int) (*getBuildTime()));
	headerPutString(h, RPMTAG_COOKIE, *cookie);
    }
    
    /* Reallocate the header into one contiguous region. */
    h = headerReload(h, RPMTAG_HEADERIMMUTABLE);
    if (h == NULL) {	/* XXX can't happen */
	rc = RPMRC_FAIL;
	rpmlog(RPMLOG_ERR, _("Unable to create immutable header region.\n"));
	goto exit;
    }
    /* Re-reference reallocated header. */
    *hdrp = headerLink(h);

    /*
     * Write the header+archive into a temp file so that the size of
     * archive (after compression) can be added to the header.
     */
    fd = rpmMkTempFile(NULL, &sigtarget);
    if (fd == NULL || Ferror(fd)) {
	rc = RPMRC_FAIL;
	rpmlog(RPMLOG_ERR, _("Unable to open temp file.\n"));
	goto exit;
    }

    fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
    if (headerWrite(fd, h, HEADER_MAGIC_YES)) {
	rc = RPMRC_FAIL;
	rpmlog(RPMLOG_ERR, _("Unable to write temp header\n"));
    } else { /* Write the archive and get the size */
	(void) Fflush(fd);
	fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&SHA1, NULL, 1);
	if (csa->cpioList != NULL) {
	    rc = cpio_doio(fd, h, csa, rpmio_flags);
	} else if (Fileno(csa->cpioFdIn) >= 0) {
	    rc = cpio_copy(fd, csa);
	} else {
	    rc = RPMRC_FAIL;
	    rpmlog(RPMLOG_ERR, _("Bad CSA data\n"));
	}
    }

    if (rc != RPMRC_OK)
	goto exit;

    (void) Fclose(fd);
    fd = NULL;
    (void) unlink(fileName);

    /* Generate the signature */
    (void) fflush(stdout);
    sig = rpmNewSignature();

    /*
     * There should be rpmlib() dependency on this, but that doesn't
     * really do much good as these are signature tags that get read
     * way before dependency checking has a chance to figure out anything.
     * On the positive side, not inserting the 32bit tag at all means
     * older rpm will just bail out with error message on attempt to read
     * such a package.
     */
    if (csa->cpioArchiveSize < UINT32_MAX) {
	sizetag = RPMSIGTAG_SIZE;
	payloadtag = RPMSIGTAG_PAYLOADSIZE;
    } else {
	sizetag = RPMSIGTAG_LONGSIZE;
	payloadtag = RPMSIGTAG_LONGARCHIVESIZE;
    }
    (void) rpmGenDigest(sig, sigtarget, sizetag);
    (void) rpmGenDigest(sig, sigtarget, RPMSIGTAG_MD5);

    if (SHA1) {
	/* XXX can't use rpmtdFromFoo() on RPMSIGTAG_* items */
	rpmtdReset(&td);
	td.tag = RPMSIGTAG_SHA1;
	td.type = RPM_STRING_TYPE;
	td.data = SHA1;
	td.count = 1;
	headerPut(sig, &td, HEADERPUT_DEFAULT);
	SHA1 = _free(SHA1);
    }

    {	
	/* XXX can't use headerPutType() on legacy RPMSIGTAG_* items */
	rpmtdReset(&td);
	td.tag = payloadtag;
	td.count = 1;
	if (payloadtag == RPMSIGTAG_PAYLOADSIZE) {
	    rpm_off_t asize = csa->cpioArchiveSize;
	    td.type = RPM_INT32_TYPE;
	    td.data = &asize;
	    headerPut(sig, &td, HEADERPUT_DEFAULT);
	} else {
	    rpm_loff_t asize = csa->cpioArchiveSize;
	    td.type = RPM_INT64_TYPE;
	    td.data = &asize;
	    headerPut(sig, &td, HEADERPUT_DEFAULT);
	}
    }

    /* Reallocate the signature into one contiguous region. */
    sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
    if (sig == NULL) {	/* XXX can't happen */
	rc = RPMRC_FAIL;
	rpmlog(RPMLOG_ERR, _("Unable to reload signature header.\n"));
	goto exit;
    }

    /* Open the output file */
    fd = Fopen(fileName, "w.ufdio");
    if (fd == NULL || Ferror(fd)) {
	rc = RPMRC_FAIL;
	rpmlog(RPMLOG_ERR, _("Could not open %s: %s\n"),
		fileName, Fstrerror(fd));
	goto exit;
    }

    /* Write the lead section into the package. */
    {	
	rpmlead lead = rpmLeadFromHeader(h);
	rc = rpmLeadWrite(fd, lead);
	lead = rpmLeadFree(lead);
	if (rc != RPMRC_OK) {
	    rc = RPMRC_FAIL;
	    rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"),
		 Fstrerror(fd));
	    goto exit;
	}
    }

    /* Write the signature section into the package. */
    if (rpmWriteSignature(fd, sig)) {
	rc = RPMRC_FAIL;
	goto exit;
    }

    /* Append the header and archive */
    ifd = Fopen(sigtarget, "r.ufdio");
    if (ifd == NULL || Ferror(ifd)) {
	rc = RPMRC_FAIL;
	rpmlog(RPMLOG_ERR, _("Unable to open sigtarget %s: %s\n"),
		sigtarget, Fstrerror(ifd));
	goto exit;
    }

    /* Add signatures to header, and write header into the package. */
    /* XXX header+payload digests/signatures might be checked again here. */
    {	Header nh = headerRead(ifd, HEADER_MAGIC_YES);

	if (nh == NULL) {
	    rc = RPMRC_FAIL;
	    rpmlog(RPMLOG_ERR, _("Unable to read header from %s: %s\n"),
			sigtarget, Fstrerror(ifd));
	    goto exit;
	}

#ifdef	NOTYET
	(void) headerMergeLegacySigs(nh, sig);
#endif

	xx = headerWrite(fd, nh, HEADER_MAGIC_YES);
	nh = headerFree(nh);

	if (xx) {
	    rc = RPMRC_FAIL;
	    rpmlog(RPMLOG_ERR, _("Unable to write header to %s: %s\n"),
			fileName, Fstrerror(fd));
	    goto exit;
	}
    }
	
    /* Write the payload into the package. */
    buf = xmalloc(BUFSIZ);
    while ((count = Fread(buf, 1, BUFSIZ, ifd)) > 0) {
	if (count == -1) {
	    free(buf);
	    rc = RPMRC_FAIL;
	    rpmlog(RPMLOG_ERR, _("Unable to read payload from %s: %s\n"),
		     sigtarget, Fstrerror(ifd));
	    goto exit;
	}
	if (Fwrite(buf, sizeof(buf[0]), count, fd) != count) {
	    free(buf);
	    rc = RPMRC_FAIL;
	    rpmlog(RPMLOG_ERR, _("Unable to write payload to %s: %s\n"),
		     fileName, Fstrerror(fd));
	    goto exit;
	}
    }
    free(buf);
    rc = RPMRC_OK;

exit:
    rpmio_flags = _free(rpmio_flags);
    SHA1 = _free(SHA1);
    h = headerFree(h);

    /* XXX Fish the pkgid out of the signature header. */
    if (sig != NULL && pkgidp != NULL) {
	struct rpmtd_s md5tag;
	headerGet(sig, RPMSIGTAG_MD5, &md5tag, HEADERGET_DEFAULT);
	if (rpmtdType(&md5tag) == RPM_BIN_TYPE &&
	    			md5tag.count == 16 && md5tag.data != NULL) {
	    *pkgidp = md5tag.data;
	}
    }

    sig = rpmFreeSignature(sig);
    if (ifd) {
	(void) Fclose(ifd);
	ifd = NULL;
    }
    if (fd) {
	(void) Fclose(fd);
	fd = NULL;
    }
    if (sigtarget) {
	(void) unlink(sigtarget);
	sigtarget = _free(sigtarget);
    }

    if (rc == RPMRC_OK)
	rpmlog(RPMLOG_NOTICE, _("Wrote: %s\n"), fileName);
    else
	(void) unlink(fileName);

    return rc;
}
Beispiel #13
0
/** \ingroup rpmcli
 * Create/modify elements in signature header.
 * @param rpm		path to package
 * @param deleting	adding or deleting signature?
 * @param signfiles	sign files if non-zero
 * @return		0 on success, -1 on error
 */
static int rpmSign(const char *rpm, int deleting, int signfiles)
{
    FD_t fd = NULL;
    FD_t ofd = NULL;
    char *trpm = NULL;
    Header sigh = NULL;
    Header h = NULL;
    char *msg = NULL;
    int res = -1; /* assume failure */
    rpmRC rc;
    struct rpmtd_s utd;
    off_t headerStart;
    off_t sigStart;
    struct sigTarget_s sigt_v3;
    struct sigTarget_s sigt_v4;
    unsigned int origSigSize;
    int insSig = 0;

    fprintf(stdout, "%s:\n", rpm);

    if (manageFile(&fd, rpm, O_RDWR))
	goto exit;

    if ((rc = rpmLeadRead(fd, &msg)) != RPMRC_OK) {
	rpmlog(RPMLOG_ERR, "%s: %s\n", rpm, msg);
	goto exit;
    }

    sigStart = Ftell(fd);
    rc = rpmReadSignature(fd, &sigh, &msg);
    if (rc != RPMRC_OK) {
	rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), rpm,
		    (msg && *msg ? msg : "\n"));
	goto exit;
    }

    headerStart = Ftell(fd);
    if (rpmReadHeader(NULL, fd, &h, &msg) != RPMRC_OK) {
	rpmlog(RPMLOG_ERR, _("%s: headerRead failed: %s\n"), rpm, msg);
	goto exit;
    }

    if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
	rpmlog(RPMLOG_ERR, _("Cannot sign RPM v3 packages\n"));
	goto exit;
    }

    unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES);
    origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES);

    if (signfiles) {
	if (includeFileSignatures(&sigh, &h))
	    goto exit;
    }

    if (deleting) {	/* Nuke all the signature tags. */
	deleteSigs(sigh);
    } else {
	/* Signature target containing header + payload */
	sigt_v3.fd = fd;
	sigt_v3.start = headerStart;
	sigt_v3.fileName = rpm;
	sigt_v3.size = fdSize(fd) - headerStart;

	/* Signature target containing only header */
	sigt_v4 = sigt_v3;
	sigt_v4.size = headerSizeof(h, HEADER_MAGIC_YES);

	res = replaceSignature(sigh, &sigt_v3, &sigt_v4);
	if (res != 0) {
	    if (res == 1) {
		rpmlog(RPMLOG_WARNING,
		   _("%s already contains identical signature, skipping\n"),
		   rpm);
		/* Identical signature is not an error */
		res = 0;
	    }
	    goto exit;
	}
	res = -1;
    }

    /* Try to make new signature smaller to have size of original signature */
    rpmtdReset(&utd);
    if (headerGet(sigh, RPMSIGTAG_RESERVEDSPACE, &utd, HEADERGET_MINMEM)) {
	int diff;
	int count;
	char *reservedSpace = NULL;

	count = utd.count;
	diff = headerSizeof(sigh, HEADER_MAGIC_YES) - origSigSize;

	if (diff < count) {
	    reservedSpace = xcalloc(count - diff, sizeof(char));
	    headerDel(sigh, RPMSIGTAG_RESERVEDSPACE);
	    rpmtdReset(&utd);
	    utd.tag = RPMSIGTAG_RESERVEDSPACE;
	    utd.count = count - diff;
	    utd.type = RPM_BIN_TYPE;
	    utd.data = reservedSpace;
	    headerPut(sigh, &utd, HEADERPUT_DEFAULT);
	    free(reservedSpace);
	    insSig = 1;
	}
    }

    /* Reallocate the signature into one contiguous region. */
    sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES);
    if (sigh == NULL)	/* XXX can't happen */
	goto exit;

    if (insSig) {
	/* Insert new signature into original rpm */
	if (Fseek(fd, sigStart, SEEK_SET) < 0) {
	    rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
		    rpm, Fstrerror(fd));
	    goto exit;
	}

	if (rpmWriteSignature(fd, sigh)) {
	    rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n"), rpm,
		Fstrerror(fd));
	    goto exit;
	}
	res = 0;
    } else {
	/* Replace orignal rpm with new rpm containing new signature */
	rasprintf(&trpm, "%s.XXXXXX", rpm);
	ofd = rpmMkTemp(trpm);
	if (ofd == NULL || Ferror(ofd)) {
	    rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n"));
	    goto exit;
	}

	/* Write the lead/signature of the output rpm */
	rc = rpmLeadWrite(ofd, h);
	if (rc != RPMRC_OK) {
	    rpmlog(RPMLOG_ERR, _("%s: writeLead failed: %s\n"), trpm,
		Fstrerror(ofd));
	    goto exit;
	}

	if (rpmWriteSignature(ofd, sigh)) {
	    rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n"), trpm,
		Fstrerror(ofd));
	    goto exit;
	}

	if (Fseek(fd, headerStart, SEEK_SET) < 0) {
	    rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
		    rpm, Fstrerror(fd));
	    goto exit;
	}
	/* Append the header and archive from the temp file */
	if (copyFile(&fd, rpm, &ofd, trpm) == 0) {
	    struct stat st;

	    /* Move final target into place, restore file permissions. */
	    if (stat(rpm, &st) == 0 && unlink(rpm) == 0 &&
			rename(trpm, rpm) == 0 && chmod(rpm, st.st_mode) == 0) {
		res = 0;
	    } else {
		rpmlog(RPMLOG_ERR, _("replacing %s failed: %s\n"),
		       rpm, strerror(errno));
	    }
	}
    }

exit:
    if (fd)	(void) closeFile(&fd);
    if (ofd)	(void) closeFile(&ofd);

    headerFree(sigh);
    headerFree(h);
    free(msg);

    /* Clean up intermediate target */
    if (trpm) {
	(void) unlink(trpm);
	free(trpm);
    }

    return res;
}
Beispiel #14
0
rpmRC rpmInstallSourcePackage(rpmts ts, FD_t fd,
		char ** specFilePtr, char ** cookie)
{
    rpmfi fi = NULL;
    char * specFile = NULL;
    const char *rootdir = rpmtsRootDir(ts);
    Header h = NULL;
    rpmpsm psm = NULL;
    rpmte te = NULL;
    rpmRC rpmrc;
    int specix = -1;
    struct rpmtd_s filenames;

    rpmtdReset(&filenames);
    rpmrc = rpmReadPackageFile(ts, fd, NULL, &h);
    switch (rpmrc) {
    case RPMRC_NOTTRUSTED:
    case RPMRC_NOKEY:
    case RPMRC_OK:
	break;
    default:
	goto exit;
	break;
    }
    if (h == NULL)
	goto exit;

    rpmrc = RPMRC_FAIL; /* assume failure */

    if (!headerIsSource(h)) {
	rpmlog(RPMLOG_ERR, _("source package expected, binary found\n"));
	goto exit;
    }

    /* src.rpm install can require specific rpmlib features, check them */
    if (!rpmlibDeps(h))
	goto exit;

    if (headerGet(h, RPMTAG_BASENAMES, &filenames, HEADERGET_ALLOC)) {
	struct rpmtd_s td;
	const char *str;
	const char *_cookie = headerGetString(h, RPMTAG_COOKIE);
	if (cookie && _cookie) *cookie = xstrdup(_cookie);
	
	/* Try to find spec by file flags */
	if (_cookie && headerGet(h, RPMTAG_FILEFLAGS, &td, HEADERGET_MINMEM)) {
	    rpmfileAttrs *flags;
	    while (specix < 0 && (flags = rpmtdNextUint32(&td))) {
		if (*flags & RPMFILE_SPECFILE)
		    specix = rpmtdGetIndex(&td);
	    }
	}
	/* Still no spec? Look by filename. */
	while (specix < 0 && (str = rpmtdNextString(&filenames))) {
	    if (rpmFileHasSuffix(str, ".spec")) 
		specix = rpmtdGetIndex(&filenames);
	}
    }

    if (rootdir && rstreq(rootdir, "/"))
	rootdir = NULL;

    /* Macros need to be added before trying to create directories */
    rpmInstallLoadMacros(h);

    if (specix >= 0) {
	const char *bn;

	headerDel(h, RPMTAG_BASENAMES);
	headerDel(h, RPMTAG_DIRNAMES);
	headerDel(h, RPMTAG_DIRINDEXES);

	rpmtdInit(&filenames);
	for (int i = 0; (bn = rpmtdNextString(&filenames)); i++) {
	    int spec = (i == specix);
	    char *fn = rpmGenPath(rpmtsRootDir(ts),
				  spec ? "%{_specdir}" : "%{_sourcedir}", bn);
	    headerPutString(h, RPMTAG_OLDFILENAMES, fn);
	    if (spec) specFile = xstrdup(fn);
	    free(fn);
	}
	headerConvert(h, HEADERCONV_COMPRESSFILELIST);
    } else {
	rpmlog(RPMLOG_ERR, _("source package contains no .spec file\n"));
	goto exit;
    };

    if (rpmtsAddInstallElement(ts, h, NULL, 0, NULL)) {
	goto exit;
    }

    te = rpmtsElement(ts, 0);
    if (te == NULL) {	/* XXX can't happen */
	goto exit;
    }
    rpmteSetFd(te, fd);

    rpmteSetHeader(te, h);
    fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER);
    h = headerFree(h);

    if (fi == NULL) {
	goto exit;
    }
    fi->apath = filenames.data; /* Ick */
    rpmteSetFI(te, fi);
    fi = rpmfiFree(fi);

    if (rpmMkdirs(rpmtsRootDir(ts), "%{_topdir}:%{_sourcedir}:%{_specdir}")) {
	goto exit;
    }

    {
	/* set all files to be installed */
	rpmfs fs = rpmteGetFileStates(te);
	int i;
	unsigned int fc = rpmfiFC(fi);
	for (i=0; i<fc; i++) rpmfsSetAction(fs, i, FA_CREATE);
    }

    psm = rpmpsmNew(ts, te);
    psm->goal = PKG_INSTALL;

   	/* FIX: psm->fi->dnl should be owned. */
    if (rpmpsmStage(psm, PSM_PROCESS) == RPMRC_OK)
	rpmrc = RPMRC_OK;

    (void) rpmpsmStage(psm, PSM_FINI);
    rpmpsmFree(psm);

exit:
    if (specFilePtr && specFile && rpmrc == RPMRC_OK)
	*specFilePtr = specFile;
    else
	free(specFile);

    headerFree(h);
    rpmfiFree(fi);

    /* XXX nuke the added package(s). */
    rpmtsClean(ts);

    return rpmrc;
}
Beispiel #15
0
int parseScript(rpmSpec spec, int parsePart)
{
    /* There are a few options to scripts: */
    /*  <pkg>                              */
    /*  -n <pkg>                           */
    /*  -p <sh>                            */
    /*  -p "<sh> <args>..."                */
    /*  -f <file>                          */

    const char *p;
    const char **progArgv = NULL;
    int progArgc;
    const char *partname = NULL;
    rpmTagVal reqtag = 0;
    rpmTagVal tag = 0;
    rpmsenseFlags tagflags = 0;
    rpmTagVal progtag = 0;
    rpmTagVal flagtag = 0;
    rpmscriptFlags scriptFlags = 0;
    int flag = PART_SUBNAME;
    Package pkg;
    StringBuf sb = NULL;
    int nextPart;
    int index;
    char * reqargs = NULL;

    int res = PART_ERROR; /* assume failure */
    int rc, argc;
    int arg;
    const char **argv = NULL;
    poptContext optCon = NULL;
    const char *name = NULL;
    const char *prog = "/bin/sh";
    const char *file = NULL;
    struct poptOption optionsTable[] = {
	{ NULL, 'p', POPT_ARG_STRING, &prog, 'p',	NULL, NULL},
	{ NULL, 'n', POPT_ARG_STRING, &name, 'n',	NULL, NULL},
	{ NULL, 'f', POPT_ARG_STRING, &file, 'f',	NULL, NULL},
	{ NULL, 'e', POPT_BIT_SET, &scriptFlags, RPMSCRIPT_FLAG_EXPAND,
	  NULL, NULL},
	{ NULL, 'q', POPT_BIT_SET, &scriptFlags, RPMSCRIPT_FLAG_QFORMAT,
	  NULL, NULL},
	{ 0, 0, 0, 0, 0,	NULL, NULL}
    };

    switch (parsePart) {
      case PART_PRE:
	tag = RPMTAG_PREIN;
	tagflags = RPMSENSE_SCRIPT_PRE;
	progtag = RPMTAG_PREINPROG;
	flagtag = RPMTAG_PREINFLAGS;
	partname = "%pre";
	break;
      case PART_POST:
	tag = RPMTAG_POSTIN;
	tagflags = RPMSENSE_SCRIPT_POST;
	progtag = RPMTAG_POSTINPROG;
	flagtag = RPMTAG_POSTINFLAGS;
	partname = "%post";
	break;
      case PART_PREUN:
	tag = RPMTAG_PREUN;
	tagflags = RPMSENSE_SCRIPT_PREUN;
	progtag = RPMTAG_PREUNPROG;
	flagtag = RPMTAG_PREUNFLAGS;
	partname = "%preun";
	break;
      case PART_POSTUN:
	tag = RPMTAG_POSTUN;
	tagflags = RPMSENSE_SCRIPT_POSTUN;
	progtag = RPMTAG_POSTUNPROG;
	flagtag = RPMTAG_POSTUNFLAGS;
	partname = "%postun";
	break;
      case PART_PRETRANS:
	tag = RPMTAG_PRETRANS;
	tagflags = RPMSENSE_PRETRANS;
	progtag = RPMTAG_PRETRANSPROG;
	flagtag = RPMTAG_PRETRANSFLAGS;
	partname = "%pretrans";
	break;
      case PART_POSTTRANS:
	tag = RPMTAG_POSTTRANS;
	tagflags = RPMSENSE_POSTTRANS;
	progtag = RPMTAG_POSTTRANSPROG;
	flagtag = RPMTAG_POSTTRANSFLAGS;
	partname = "%posttrans";
	break;
      case PART_VERIFYSCRIPT:
	tag = RPMTAG_VERIFYSCRIPT;
	tagflags = RPMSENSE_SCRIPT_VERIFY;
	progtag = RPMTAG_VERIFYSCRIPTPROG;
	flagtag = RPMTAG_VERIFYSCRIPTFLAGS;
	partname = "%verifyscript";
	break;
      case PART_TRIGGERPREIN:
	tag = RPMTAG_TRIGGERSCRIPTS;
	tagflags = 0;
	reqtag = RPMTAG_TRIGGERPREIN;
	progtag = RPMTAG_TRIGGERSCRIPTPROG;
	flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
	partname = "%triggerprein";
	break;
      case PART_TRIGGERIN:
	tag = RPMTAG_TRIGGERSCRIPTS;
	tagflags = 0;
	reqtag = RPMTAG_TRIGGERIN;
	progtag = RPMTAG_TRIGGERSCRIPTPROG;
	flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
	partname = "%triggerin";
	break;
      case PART_TRIGGERUN:
	tag = RPMTAG_TRIGGERSCRIPTS;
	tagflags = 0;
	reqtag = RPMTAG_TRIGGERUN;
	progtag = RPMTAG_TRIGGERSCRIPTPROG;
	flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
	partname = "%triggerun";
	break;
      case PART_TRIGGERPOSTUN:
	tag = RPMTAG_TRIGGERSCRIPTS;
	tagflags = 0;
	reqtag = RPMTAG_TRIGGERPOSTUN;
	progtag = RPMTAG_TRIGGERSCRIPTPROG;
	flagtag = RPMTAG_TRIGGERSCRIPTFLAGS;
	partname = "%triggerpostun";
	break;
      case PART_FILETRIGGERIN:
	tag = RPMTAG_FILETRIGGERSCRIPTS;
	tagflags = 0;
	reqtag = RPMTAG_FILETRIGGERIN;
	progtag = RPMTAG_FILETRIGGERSCRIPTPROG;
	flagtag = RPMTAG_FILETRIGGERSCRIPTFLAGS;
	partname = "%filetriggerin";
	break;
      case PART_FILETRIGGERUN:
	tag = RPMTAG_FILETRIGGERSCRIPTS;
	tagflags = 0;
	reqtag = RPMTAG_FILETRIGGERUN;
	progtag = RPMTAG_FILETRIGGERSCRIPTPROG;
	flagtag = RPMTAG_FILETRIGGERSCRIPTFLAGS;
	partname = "%filetriggerun";
	break;
      case PART_FILETRIGGERPOSTUN:
	tag = RPMTAG_FILETRIGGERSCRIPTS;
	tagflags = 0;
	reqtag = RPMTAG_FILETRIGGERPOSTUN;
	progtag = RPMTAG_FILETRIGGERSCRIPTPROG;
	flagtag = RPMTAG_FILETRIGGERSCRIPTFLAGS;
	partname = "%filetriggerpostun";
	break;
      case PART_TRANSFILETRIGGERIN:
	tag = RPMTAG_TRANSFILETRIGGERSCRIPTS;
	tagflags = 0;
	reqtag = RPMTAG_TRANSFILETRIGGERIN;
	progtag = RPMTAG_TRANSFILETRIGGERSCRIPTPROG;
	flagtag = RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS;
	partname = "%transfiletriggerin";
	break;
      case PART_TRANSFILETRIGGERUN:
	tag = RPMTAG_TRANSFILETRIGGERSCRIPTS;
	tagflags = 0;
	reqtag = RPMTAG_TRANSFILETRIGGERUN;
	progtag = RPMTAG_TRANSFILETRIGGERSCRIPTPROG;
	flagtag = RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS;
	partname = "%transfiletriggerun";
	break;
      case PART_TRANSFILETRIGGERPOSTUN:
	tag = RPMTAG_TRANSFILETRIGGERSCRIPTS;
	tagflags = 0;
	reqtag = RPMTAG_TRANSFILETRIGGERPOSTUN;
	progtag = RPMTAG_TRANSFILETRIGGERSCRIPTPROG;
	flagtag = RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS;
	partname = "%transfiletriggerpostun";
	break;
    }

    if (tag == RPMTAG_TRIGGERSCRIPTS || tag == RPMTAG_FILETRIGGERSCRIPTS ||
	tag == RPMTAG_TRANSFILETRIGGERSCRIPTS) {
	/* break line into two */
	char *s = strstr(spec->line, "--");
	if (!s) {
	    rpmlog(RPMLOG_ERR, _("line %d: triggers must have --: %s\n"),
		     spec->lineNum, spec->line);
	    return PART_ERROR;
	}

	*s = '\0';
	reqargs = xstrdup(s + 2);
    }
    
    if ((rc = poptParseArgvString(spec->line, &argc, &argv))) {
	rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"),
		 spec->lineNum, partname, poptStrerror(rc));
	goto exit;
    }
    
    optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
    while ((arg = poptGetNextOpt(optCon)) > 0) {
	switch (arg) {
	case 'p':
	    if (prog[0] == '<') {
		if (prog[strlen(prog)-1] != '>') {
		    rpmlog(RPMLOG_ERR,
			     _("line %d: internal script must end "
			     "with \'>\': %s\n"), spec->lineNum, prog);
		    goto exit;
		}
	    } else if (prog[0] != '/') {
		rpmlog(RPMLOG_ERR,
			 _("line %d: script program must begin "
			 "with \'/\': %s\n"), spec->lineNum, prog);
		goto exit;
	    }
	    break;
	case 'n':
	    flag = PART_NAME;
	    break;
	}
    }
    
    if (arg < -1) {
	rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"),
		 spec->lineNum,
		 poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
		 spec->line);
	goto exit;
    }

    if (poptPeekArg(optCon)) {
	if (name == NULL)
	    name = poptGetArg(optCon);
	if (poptPeekArg(optCon)) {
	    rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"),
		     spec->lineNum,
		     spec->line);
	    goto exit;
	}
    }
    
    if (lookupPackage(spec, name, flag, &pkg)) {
	rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"),
		 spec->lineNum, spec->line);
	goto exit;
    }

    if (tag != RPMTAG_TRIGGERSCRIPTS) {
	if (headerIsEntry(pkg->header, progtag)) {
	    rpmlog(RPMLOG_ERR, _("line %d: Second %s\n"),
		     spec->lineNum, partname);
	    goto exit;
	}
    }

    if ((rc = poptParseArgvString(prog, &progArgc, &progArgv))) {
	rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"),
		 spec->lineNum, partname, poptStrerror(rc));
	goto exit;
    }

    sb = newStringBuf();
    if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
	nextPart = PART_NONE;
    } else if (rc < 0) {
	goto exit;
    } else {
	while (! (nextPart = isPart(spec->line))) {
	    appendStringBuf(sb, spec->line);
	    if ((rc = readLine(spec, STRIP_NOTHING)) > 0) {
		nextPart = PART_NONE;
		break;
	    } else if (rc < 0) {
		goto exit;
	    }
	}
    }
    stripTrailingBlanksStringBuf(sb);
    p = getStringBuf(sb);

#ifdef WITH_LUA
    if (rstreq(progArgv[0], "<lua>")) {
	rpmlua lua = NULL; /* Global state. */
	if (rpmluaCheckScript(lua, p, partname) != RPMRC_OK) {
	    goto exit;
	}
	(void) rpmlibNeedsFeature(pkg, "BuiltinLuaScripts", "4.2.2-1");
    } else
#endif
    if (progArgv[0][0] == '<') {
	rpmlog(RPMLOG_ERR,
		 _("line %d: unsupported internal script: %s\n"),
		 spec->lineNum, progArgv[0]);
	goto exit;
    } else {
        (void) addReqProv(pkg, RPMTAG_REQUIRENAME,
		progArgv[0], NULL, (tagflags | RPMSENSE_INTERP), 0);
    }

    if (scriptFlags) {
	rpmlibNeedsFeature(pkg, "ScriptletExpansion", "4.9.0-1");
    }

    /* Trigger script insertion is always delayed in order to */
    /* get the index right.                                   */
    if (tag == RPMTAG_TRIGGERSCRIPTS || tag == RPMTAG_FILETRIGGERSCRIPTS ||
	tag == RPMTAG_TRANSFILETRIGGERSCRIPTS) {
	if (progArgc > 1) {
	    rpmlog(RPMLOG_ERR,
	      _("line %d: interpreter arguments not allowed in triggers: %s\n"),
	      spec->lineNum, prog);
	    goto exit;
	}
	/* Add file/index/prog triple to the trigger file list */
	index = addTriggerIndex(pkg, file, p, progArgv[0], scriptFlags, tag);

	/* Generate the trigger tags */
	if (parseRCPOT(spec, pkg, reqargs, reqtag, index, tagflags))
	    goto exit;
    } else {
	struct rpmtd_s td;

	/*
 	 * XXX Ancient rpm uses STRING, not STRING_ARRAY type here. Construct
 	 * the td manually and preserve legacy compat for now...
 	 */
	rpmtdReset(&td);
	td.tag = progtag;
	td.count = progArgc;
	if (progArgc == 1) {
	    td.data = (void *) *progArgv;
	    td.type = RPM_STRING_TYPE;
	} else {
	    (void) rpmlibNeedsFeature(pkg,
			"ScriptletInterpreterArgs", "4.0.3-1");
	    td.data = progArgv;
	    td.type = RPM_STRING_ARRAY_TYPE;
	}
	headerPut(pkg->header, &td, HEADERPUT_DEFAULT);

	if (*p != '\0') {
	    headerPutString(pkg->header, tag, p);
	}
	if (scriptFlags) {
	    headerPutUint32(pkg->header, flagtag, &scriptFlags, 1);
	}

	if (file) {
	    switch (parsePart) {
	      case PART_PRE:
		pkg->preInFile = xstrdup(file);
		break;
	      case PART_POST:
		pkg->postInFile = xstrdup(file);
		break;
	      case PART_PREUN:
		pkg->preUnFile = xstrdup(file);
		break;
	      case PART_POSTUN:
		pkg->postUnFile = xstrdup(file);
		break;
	      case PART_PRETRANS:
		pkg->preTransFile = xstrdup(file);
		break;
	      case PART_POSTTRANS:
		pkg->postTransFile = xstrdup(file);
		break;
	      case PART_VERIFYSCRIPT:
		pkg->verifyFile = xstrdup(file);
		break;
	    }
	}
    }
    res = nextPart;
    
exit:
    free(reqargs);
    freeStringBuf(sb);
    free(progArgv);
    free(argv);
    poptFreeContext(optCon);
    
    return res;
}
Beispiel #16
0
static rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags vsflags, 
			FD_t fd,
			Header * hdrp, unsigned int *keyidp, char **msg)
{
    pgpDigParams sig = NULL;
    Header sigh = NULL;
    rpmTagVal sigtag;
    struct rpmtd_s sigtd;
    struct sigtInfo_s sinfo;
    Header h = NULL;
    rpmRC rc = RPMRC_FAIL;	/* assume failure */
    int leadtype = -1;
    headerGetFlags hgeflags = HEADERGET_DEFAULT;

    if (hdrp) *hdrp = NULL;

    rpmtdReset(&sigtd);

    if ((rc = rpmLeadRead(fd, &leadtype, msg)) != RPMRC_OK) {
	/* Avoid message spew on manifests */
	if (rc == RPMRC_NOTFOUND) {
	    *msg = _free(*msg);
	}
	goto exit;
    }

    /* Read the signature header. */
    rc = rpmReadSignature(fd, &sigh, msg);

    if (rc != RPMRC_OK) {
	goto exit;
    }

#define	_chk(_mask, _tag) \
	(sigtag == 0 && !(vsflags & (_mask)) && headerIsEntry(sigh, (_tag)))

    /*
     * Figger the most effective means of verification available, prefer
     * signatures over digests. Legacy header+payload entries are not used.
     * DSA will be preferred over RSA if both exist because tested first.
     */
    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_NOSHA1HEADER, RPMSIGTAG_SHA1)) {
	sigtag = RPMSIGTAG_SHA1;
    }

    /* Read the metadata, computing digest(s) on the fly. */
    h = NULL;

    rc = rpmpkgReadHeader(fd, &h, msg);

    if (rc != RPMRC_OK || h == NULL) {
	goto exit;
    }

    /* Any digests or signatures to check? */
    if (sigtag == 0) {
	rc = RPMRC_OK;
	goto exit;
    }

    /* Free up any previous "ok" message before signature/digest check */
    *msg = _free(*msg);

    /* Retrieve the tag parameters from the signature header. */
    if (!headerGet(sigh, sigtag, &sigtd, hgeflags)) {
	rc = RPMRC_FAIL;
	goto exit;
    }

    if (rpmSigInfoParse(&sigtd, "package", &sinfo, &sig, msg) == RPMRC_OK) {
	struct rpmtd_s utd;
	DIGEST_CTX ctx = rpmDigestInit(sinfo.hashalgo, RPMDIGEST_NONE);

	if (headerGet(h, RPMTAG_HEADERIMMUTABLE, &utd, hgeflags)) {
	    rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
	    rpmDigestUpdate(ctx, utd.data, utd.count);
	    rpmtdFreeData(&utd);
	}
	/** @todo Implement disable/enable/warn/error/anal policy. */
	rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, msg);

	rpmDigestFinal(ctx, NULL, NULL, 0);
    } else {
	rc = RPMRC_FAIL;
    }

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 immutable region
         * equals a truly ancient package, do full retrofit. OTOH newer
         * packages might have been built with --nodirtokens, test and handle
         * the non-compressed filelist case separately.
         */
	if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE))
	    headerConvert(h, HEADERCONV_RETROFIT_V3);
	else if (headerIsEntry(h, RPMTAG_OLDFILENAMES))
	    headerConvert(h, HEADERCONV_COMPRESSFILELIST);
	
	/* Append (and remap) signature tags to the metadata. */
	headerMergeLegacySigs(h, sigh);

	/* Bump reference count for return. */
	*hdrp = headerLink(h);

	if (keyidp)
	    *keyidp = getKeyid(sig);
    }
    rpmtdFreeData(&sigtd);
    h = headerFree(h);
    pgpDigParamsFree(sig);
    sigh = headerFree(sigh);
    return rc;
}
Beispiel #17
0
/*
 * Argument monster to verify header-only signature/digest if there is
 * one, otherwisereturn RPMRC_NOTFOUND to signal for plain sanity check.
 */
static rpmRC headerSigVerify(rpmKeyring keyring, rpmVSFlags vsflags,
			     hdrblob blob, char **buf)
{
    rpmRC rc = RPMRC_FAIL;
    pgpDigParams sig = NULL;
    struct rpmtd_s sigtd;
    struct entryInfo_s einfo;
    struct sigtInfo_s sinfo;

    rpmtdReset(&sigtd);
    memset(&einfo, 0, sizeof(einfo));

    /* Find a header-only digest/signature tag. */
    for (int i = blob->ril; i < blob->il; i++) {
	ei2h(blob->pe+i, &einfo);

	switch (einfo.tag) {
	case RPMTAG_SHA1HEADER:
	    if (vsflags & RPMVSF_NOSHA1HEADER)
		break;
	    if (sigtd.tag == 0)
		ei2td(&einfo, blob->dataStart, 0, &sigtd);
	    break;
	case RPMTAG_RSAHEADER:
	    if (vsflags & RPMVSF_NORSAHEADER)
		break;
	    ei2td(&einfo, blob->dataStart, einfo.count, &sigtd);
	    break;
	case RPMTAG_DSAHEADER:
	    if (vsflags & RPMVSF_NODSAHEADER)
		break;
	    ei2td(&einfo, blob->dataStart, einfo.count, &sigtd);
	    break;
	default:
	    break;
	}
    }

    /* No header-only digest/signature found, get outta here */
    if (sigtd.tag == 0) {
	rc = RPMRC_NOTFOUND;
	goto exit;
    }

    if (rpmSigInfoParse(&sigtd, "header", &sinfo, &sig, buf))
	goto exit;

    if (sinfo.hashalgo) {
	DIGEST_CTX ctx = rpmDigestInit(sinfo.hashalgo, RPMDIGEST_NONE);
	int32_t ildl[2] = { htonl(blob->ril), htonl(blob->rdl) };

	rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
	rpmDigestUpdate(ctx, ildl, sizeof(ildl));
	rpmDigestUpdate(ctx, blob->pe, (blob->ril * sizeof(*blob->pe)));
	rpmDigestUpdate(ctx, blob->dataStart, blob->rdl);

	rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, buf);

    	rpmDigestFinal(ctx, NULL, NULL, 0);
    }

exit:
    rpmtdFreeData(&sigtd);
    pgpDigParamsFree(sig);

    return rc;
}
Beispiel #18
0
static sepol *sepolNew(rpmte te)
{
    sepol *head = NULL;
    sepol *ret = NULL;
    sepolAction action;
    Header h;
    struct rpmtd_s policies, names, types, typesidx, flags;
    int i, j;
    int count;

    rpmtdReset(&policies);
    rpmtdReset(&names);
    rpmtdReset(&types);
    rpmtdReset(&typesidx);
    rpmtdReset(&flags);

    h = rpmteHeader(te);
    if (!h) {
	goto exit;
    }

    if (!headerIsEntry(h, RPMTAG_POLICIES)) {
	goto exit;
    }

    if (!headerGet(h, RPMTAG_POLICIES, &policies, HEADERGET_MINMEM)) {
	goto exit;
    }

    count = rpmtdCount(&policies);
    if (count <= 0) {
	goto exit;
    }

    if (!headerGet(h, RPMTAG_POLICYNAMES, &names, HEADERGET_MINMEM)
	|| rpmtdCount(&names) != count) {
	goto exit;
    }

    if (!headerGet(h, RPMTAG_POLICYFLAGS, &flags, HEADERGET_MINMEM)
	|| rpmtdCount(&flags) != count) {
	goto exit;
    }

    if (!headerGet(h, RPMTAG_POLICYTYPES, &types, HEADERGET_MINMEM)) {
	goto exit;
    }

    if (!headerGet(h, RPMTAG_POLICYTYPESINDEXES, &typesidx, HEADERGET_MINMEM)
	|| rpmtdCount(&types) != rpmtdCount(&typesidx)) {
	goto exit;
    }

    action = (rpmteType(te) == TR_ADDED) ? SEPOL_ACTION_INSTALL : SEPOL_ACTION_REMOVE;

    for (i = 0; i < count; i++) {
	sepol *pol = xcalloc(1, sizeof(*pol));
	pol->next = head;
	head = pol;

	pol->data = xstrdup(rpmtdNextString(&policies));
	pol->name = xstrdup(rpmtdNextString(&names));
	pol->flags = *rpmtdNextUint32(&flags);
	pol->action = action;

	for (j = 0; j < rpmtdCount(&types); j++) {
	    uint32_t index = ((uint32_t *) typesidx.data)[j];
	    if (index < 0 || index >= count) {
		goto exit;
	    }
	    if (index != i) {
		continue;
	    }
	    argvAdd(&pol->types, rpmtdNextString(&types));
	}
	argvSort(pol->types, NULL);
    }

    ret = head;

  exit:
    headerFree(h);

    rpmtdFreeData(&policies);
    rpmtdFreeData(&names);
    rpmtdFreeData(&types);
    rpmtdFreeData(&typesidx);
    rpmtdFreeData(&flags);

    if (!ret) {
	sepolFree(head);
    }

    return ret;
}
Beispiel #19
0
rpmRC rpmGenerateSignature(char *SHA1, uint8_t *MD5, rpm_loff_t size,
				rpm_loff_t payloadSize, FD_t fd)
{
    Header sig = headerNew();
    struct rpmtd_s td;
    rpmRC rc = RPMRC_OK;
    char *reservedSpace;
    int spaceSize = 32; /* always reserve a bit of space */
    int gpgSize = rpmExpandNumeric("%{__gpg_reserved_space}");

    /* Prepare signature */
    rpmtdReset(&td);
    td.tag = RPMSIGTAG_SHA1;
    td.count = 1;
    td.type = RPM_STRING_TYPE;
    td.data = SHA1;
    headerPut(sig, &td, HEADERPUT_DEFAULT);

    rpmtdReset(&td);
    td.tag = RPMSIGTAG_MD5;
    td.count = 16;
    td.type = RPM_BIN_TYPE;
    td.data = MD5;
    headerPut(sig, &td, HEADERPUT_DEFAULT);

    rpmtdReset(&td);
    td.count = 1;
    if (payloadSize < UINT32_MAX) {
	rpm_off_t p = payloadSize;
	rpm_off_t s = size;
	td.type = RPM_INT32_TYPE;

	td.tag = RPMSIGTAG_PAYLOADSIZE;
	td.data = &p;
	headerPut(sig, &td, HEADERPUT_DEFAULT);

	td.tag = RPMSIGTAG_SIZE;
	td.data = &s;
	headerPut(sig, &td, HEADERPUT_DEFAULT);
    } else {
	rpm_loff_t p = payloadSize;
	rpm_loff_t s = size;
	td.type = RPM_INT64_TYPE;

	td.tag = RPMSIGTAG_LONGARCHIVESIZE;
	td.data = &p;
	headerPut(sig, &td, HEADERPUT_DEFAULT);

	td.tag = RPMSIGTAG_LONGSIZE;
	td.data = &s;
	headerPut(sig, &td, HEADERPUT_DEFAULT);

	/* adjust for the size difference between 64- and 32bit tags */
	spaceSize -= 8;
    }

    if (gpgSize > 0)
	spaceSize += gpgSize;

    if(spaceSize > 0) {
	reservedSpace = xcalloc(spaceSize, sizeof(char));
	rpmtdReset(&td);
	td.tag = RPMSIGTAG_RESERVEDSPACE;
	td.count = spaceSize;
	td.type = RPM_BIN_TYPE;
	td.data = reservedSpace;
	headerPut(sig, &td, HEADERPUT_DEFAULT);
	free(reservedSpace);
    }

    /* Reallocate the signature into one contiguous region. */
    sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
    if (sig == NULL) { /* XXX can't happen */
	rpmlog(RPMLOG_ERR, _("Unable to reload signature header.\n"));
	rc = RPMRC_FAIL;
	goto exit;
    }

    /* Write the signature section into the package. */
    if (rpmWriteSignature(fd, sig)) {
	rc = RPMRC_FAIL;
	goto exit;
    }

exit:
    headerFree(sig);
    return rc;
}
Beispiel #20
0
rpmtd rpmtdNew(void)
{
    rpmtd td = xmalloc(sizeof(*td));
    rpmtdReset(td);
    return td;
}
Beispiel #21
0
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;
    rpmSigTag 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;
	pgpHashAlgo 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;
}