Esempio n. 1
0
File: pack.c Progetto: 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;
}
Esempio n. 2
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;
}
Esempio n. 3
0
int rpmDoDigest(int algo, const char * fn,int asAscii,
                unsigned char * digest, rpm_loff_t * fsizep)
{
    const char * path;
    urltype ut = urlPath(fn, &path);
    unsigned char * dig = NULL;
    size_t diglen;
    unsigned char buf[32*BUFSIZ];
    FD_t fd;
    rpm_loff_t fsize = 0;
    pid_t pid = 0;
    int rc = 0;
    int fdno;

    fdno = open_dso(path, &pid, &fsize);
    if (fdno < 0) {
	rc = 1;
	goto exit;
    }

    switch(ut) {
    case URL_IS_PATH:
    case URL_IS_UNKNOWN:
    case URL_IS_HTTPS:
    case URL_IS_HTTP:
    case URL_IS_FTP:
    case URL_IS_HKP:
    case URL_IS_DASH:
    default:
	/* Either use the pipe to prelink -y or open the URL. */
	fd = (pid != 0) ? fdDup(fdno) : Fopen(fn, "r.ufdio");
	(void) close(fdno);
	if (fd == NULL || Ferror(fd)) {
	    rc = 1;
	    if (fd != NULL)
		(void) Fclose(fd);
	    break;
	}
	
	fdInitDigest(fd, algo, 0);
	fsize = 0;
	while ((rc = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
	    fsize += rc;
	fdFiniDigest(fd, algo, (void **)&dig, &diglen, asAscii);
	if (dig == NULL || Ferror(fd))
	    rc = 1;

	(void) Fclose(fd);
	break;
    }

    /* Reap the prelink -y helper. */
    if (pid) {
	int status;
	(void) waitpid(pid, &status, 0);
	if (!WIFEXITED(status) || WEXITSTATUS(status))
	    rc = 1;
    }

exit:
    if (fsizep)
	*fsizep = fsize;
    if (!rc)
	memcpy(digest, dig, diglen);
    dig = _free(dig);

    return rc;
}
Esempio n. 4
0
/*@-mods@*/
rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp)
{
    HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
    HE_t she = (HE_t) memset(alloca(sizeof(*she)), 0, sizeof(*she));
    pgpDig dig = rpmtsDig(ts);
    char buf[8*BUFSIZ];
    ssize_t count;
    Header sigh = NULL;
    rpmtsOpX opx;
    rpmop op = NULL;
    size_t nb;
    unsigned ix;
    Header h = NULL;
    const char * msg = NULL;
    rpmVSFlags vsflags;
    rpmRC rc = RPMRC_FAIL;	/* assume failure */
    rpmop opsave = (rpmop) memset(alloca(sizeof(*opsave)), 0, sizeof(*opsave));
    int xx;
pgpPkt pp = (pgpPkt) alloca(sizeof(*pp));

    if (hdrp) *hdrp = NULL;

assert(dig != NULL);
    (void) fdSetDig(fd, dig);

    /* Snapshot current I/O counters (cached persistent I/O reuses counters) */
    (void) rpmswAdd(opsave, fdstat_op(fd, FDSTAT_READ));

   {	const char item[] = "Lead";
	msg = NULL;
	rc = rpmpkgRead(item, fd, NULL, &msg);
	switch (rc) {
	default:
	   rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
	   /*@fallthrough@*/
	case RPMRC_NOTFOUND:
	   msg = _free(msg);
	   goto exit;
	   /*@notreached@*/ break;
	case RPMRC_OK:
	   break;
	}
	msg = _free(msg);
    }

    {	const char item[] = "Signature";
	msg = NULL;
	rc = rpmpkgRead(item, fd, &sigh, &msg);
	switch (rc) {
	default:
	    rpmlog(RPMLOG_ERR, "%s: %s: %s", fn, item,
		(msg && *msg ? msg : _("read failed\n")));
	    msg = _free(msg);
	    goto exit;
	    /*@notreached@*/ 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)	(she->tag == 0 && !(vsflags & (_mask)))

    /*
     * 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.
     */
    she->tag = (rpmTag)0;
    opx = (rpmtsOpX)0;
    vsflags = pgpDigVSFlags;
    if (_chk(RPMVSF_NOECDSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_ECDSA)) {
	she->tag = (rpmTag)RPMSIGTAG_ECDSA;
    } else
    if (_chk(RPMVSF_NODSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_DSA)) {
	she->tag = (rpmTag)RPMSIGTAG_DSA;
    } else
    if (_chk(RPMVSF_NORSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_RSA)) {
	she->tag = (rpmTag)RPMSIGTAG_RSA;
    } else
    if (_chk(RPMVSF_NOSHA1HEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_SHA1)) {
	she->tag = (rpmTag)RPMSIGTAG_SHA1;
    } else
    if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD) &&
	headerIsEntry(sigh, (rpmTag)RPMSIGTAG_MD5))
    {
	she->tag = (rpmTag)RPMSIGTAG_MD5;
	fdInitDigest(fd, PGPHASHALGO_MD5, 0);
	opx = RPMTS_OP_DIGEST;
    }

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

    /* XXX stats will include header i/o and setup overhead. */
    /* XXX repackaged packages have appended tags, legacy dig/sig check fails */
    if (opx > 0) {
	op = (rpmop) pgpStatsAccumulator(dig, opx);
	(void) rpmswEnter(op, 0);
    }
/*@-type@*/	/* XXX arrow access of non-pointer (FDSTAT_t) */
    nb = fd->stats->ops[FDSTAT_READ].bytes;
    {	const char item[] = "Header";
	msg = NULL;
	rc = rpmpkgRead(item, fd, &h, &msg);
	if (rc != RPMRC_OK) {
	    rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
	    msg = _free(msg);
	    goto exit;
	}
	msg = _free(msg);
    }
    nb = fd->stats->ops[FDSTAT_READ].bytes - nb;
/*@=type@*/
    if (opx > 0 && op != NULL) {
	(void) rpmswExit(op, nb);
	op = NULL;
    }

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

    dig->nbytes = 0;

    /* Fish out the autosign pubkey (if present). */
    he->tag = RPMTAG_PUBKEYS;
    xx = headerGet(h, he, 0);
    if (xx && he->p.argv != NULL && he->c > 0)
    switch (he->t) {
    default:
 	break;
    case RPM_STRING_ARRAY_TYPE:
 	ix = he->c - 1;	/* XXX FIXME: assumes last pubkey */
 	dig->pub = _free(dig->pub);
 	dig->publen = 0;
 	{   rpmiob iob = rpmiobNew(0);
 	    iob = rpmiobAppend(iob, he->p.argv[ix], 0);
 	    xx = pgpArmorUnwrap(iob, (rpmuint8_t **)&dig->pub, &dig->publen);
 	    iob = rpmiobFree(iob);
 	}
 	if (xx != PGPARMOR_PUBKEY) {
 	    dig->pub = _free(dig->pub);
 	    dig->publen = 0;
 	}
 	break;
    }
    he->p.ptr = _free(he->p.ptr);

    /* Retrieve the tag parameters from the signature header. */
    xx = headerGet(sigh, she, 0);
    if (she->p.ptr == NULL) {
	rc = RPMRC_FAIL;
	goto exit;
    }
/*@-ownedtrans -noeffect@*/
    xx = pgpSetSig(dig, she->tag, she->t, she->p.ptr, she->c);
/*@=ownedtrans =noeffect@*/

    switch ((rpmSigTag)she->tag) {
    default:	/* XXX keep gcc quiet. */
assert(0);
	/*@notreached@*/ break;
    case RPMSIGTAG_RSA:
	/* Parse the parameters from the OpenPGP packets that will be needed. */
	xx = pgpPktLen(she->p.ui8p, she->c, pp);
	xx = rpmhkpLoadSignature(NULL, dig, pp);
	if (dig->signature.version != 3 && dig->signature.version != 4) {
	    rpmlog(RPMLOG_ERR,
		_("skipping package %s with unverifiable V%u signature\n"),
		fn, dig->signature.version);
	    rc = RPMRC_FAIL;
	    goto exit;
	}
	xx = hBlobDigest(h, dig, dig->signature.hash_algo, &dig->hrsa);
	break;
    case RPMSIGTAG_DSA:
	/* Parse the parameters from the OpenPGP packets that will be needed. */
	xx = pgpPktLen(she->p.ui8p, she->c, pp);
	xx = rpmhkpLoadSignature(NULL, dig, pp);
	if (dig->signature.version != 3 && dig->signature.version != 4) {
	    rpmlog(RPMLOG_ERR,
		_("skipping package %s with unverifiable V%u signature\n"), 
		fn, dig->signature.version);
	    rc = RPMRC_FAIL;
	    goto exit;
	}
	xx = hBlobDigest(h, dig, dig->signature.hash_algo, &dig->hdsa);
	break;
    case RPMSIGTAG_ECDSA:
	/* Parse the parameters from the OpenPGP packets that will be needed. */
	xx = pgpPktLen(she->p.ui8p, she->c, pp);
	xx = rpmhkpLoadSignature(NULL, dig, pp);
	if (dig->signature.version != 3 && dig->signature.version != 4) {
	    rpmlog(RPMLOG_ERR,
		_("skipping package %s with unverifiable V%u signature\n"), 
		fn, dig->signature.version);
	    rc = RPMRC_FAIL;
	    goto exit;
	}
	xx = hBlobDigest(h, dig, dig->signature.hash_algo, &dig->hecdsa);
	break;
    case RPMSIGTAG_SHA1:
	/* XXX dig->hsha? */
	xx = hBlobDigest(h, dig, PGPHASHALGO_SHA1, &dig->hdsa);
	break;
    case RPMSIGTAG_MD5:
	/* Legacy signatures need the compressed payload in the digest too. */
	op = (rpmop) pgpStatsAccumulator(dig, 10);	/* RPMTS_OP_DIGEST */
	(void) rpmswEnter(op, 0);
	while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
	    dig->nbytes += count;
	(void) rpmswExit(op, dig->nbytes);
	op->count--;	/* XXX one too many */
	dig->nbytes += nb;	/* XXX include size of header blob. */
	if (count < 0) {
	    rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"),
					fn, Fstrerror(fd));
	    rc = RPMRC_FAIL;
	    goto exit;
	}

	/* XXX Steal the digest-in-progress from the file handle. */
	fdStealDigest(fd, dig);
	break;
    }

/** @todo Implement disable/enable/warn/error/anal policy. */

    buf[0] = '\0';
    rc = rpmVerifySignature(dig, buf);
    switch (rc) {
    case RPMRC_OK:		/* Signature is OK. */
	rpmlog(RPMLOG_DEBUG, "%s: %s\n", fn, buf);
	break;
    case RPMRC_NOTTRUSTED:	/* Signature is OK, but key is not trusted. */
    case RPMRC_NOKEY:		/* Public key is unavailable. */
#ifndef	DYING
	/* XXX Print NOKEY/NOTTRUSTED warning only once. */
    {	int lvl = (pgpStashKeyid(dig) ? RPMLOG_DEBUG : RPMLOG_WARNING);
	rpmlog(lvl, "%s: %s\n", fn, buf);
    }	break;
    case RPMRC_NOTFOUND:	/* Signature is unknown type. */
	rpmlog(RPMLOG_WARNING, "%s: %s\n", fn, buf);
	break;
#else
    case RPMRC_NOTFOUND:	/* Signature is unknown type. */
    case RPMRC_NOSIG:		/* Signature is unavailable. */
#endif
    default:
    case RPMRC_FAIL:		/* Signature does not verify. */
	rpmlog(RPMLOG_ERR, "%s: %s\n", fn, buf);
	break;
    }

exit:
    if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) {

	/* Append (and remap) signature tags to the metadata. */
	headerMergeLegacySigs(h, sigh);

	/* Bump reference count for return. */
	*hdrp = headerLink(h);
    }
    (void)headerFree(h);
    h = NULL;

    /* Accumulate time reading package header. */
    (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_READHDR),
		fdstat_op(fd, FDSTAT_READ));
    (void) rpmswSub(rpmtsOp(ts, RPMTS_OP_READHDR),
		opsave);

#ifdef	NOTYET
    /* Return RPMRC_NOSIG for MANDATORY signature verification. */
    {	rpmSigTag sigtag = pgpGetSigtag(dig);
	switch (sigtag) {
	default:
	    rc = RPMRC_NOSIG;
	    /*@fallthrough@*/
	case RPMSIGTAG_RSA:
	case RPMSIGTAG_DSA:
	case RPMSIGTAG_ECDSA:
	    break;
	}
    }
#endif

    rpmtsCleanDig(ts);
    (void)headerFree(sigh);
    sigh = NULL;

    return rc;
}
Esempio n. 5
0
static rpmRC includeFileSignatures(FD_t fd, const char *rpm,
				   Header *sigp, Header *hdrp,
				   off_t sigStart, off_t headerStart)
{
    FD_t ofd = NULL;
    char *trpm = NULL;
    char *key;
    char *keypass;
    char *SHA1 = NULL;
    uint8_t *MD5 = NULL;
    size_t sha1len;
    size_t md5len;
    off_t sigTargetSize;
    rpmRC rc = RPMRC_OK;
    struct rpmtd_s osigtd;
    char *o_sha1 = NULL;
    uint8_t o_md5[16];

#ifndef WITH_IMAEVM
    rpmlog(RPMLOG_ERR, _("missing libimaevm\n"));
    return RPMRC_FAIL;
#endif
    unloadImmutableRegion(hdrp, RPMTAG_HEADERIMMUTABLE);

    key = rpmExpand("%{?_file_signing_key}", NULL);

    keypass = rpmExpand("%{_file_signing_key_password}", NULL);
    if (rstreq(keypass, "")) {
	free(keypass);
	keypass = NULL;
    }

    rc = rpmSignFiles(*hdrp, key, keypass);
    if (rc != RPMRC_OK) {
	goto exit;
    }

    *hdrp = headerReload(*hdrp, RPMTAG_HEADERIMMUTABLE);
    if (*hdrp == NULL) {
	rc = RPMRC_FAIL;
	rpmlog(RPMLOG_ERR, _("headerReload failed\n"));
	goto exit;
    }

    ofd = rpmMkTempFile(NULL, &trpm);
    if (ofd == NULL || Ferror(ofd)) {
	rc = RPMRC_FAIL;
	rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n"));
	goto exit;
    }

    /* Copy archive to temp file */
    if (copyFile(&fd, rpm, &ofd, trpm)) {
	rc = RPMRC_FAIL;
	rpmlog(RPMLOG_ERR, _("copyFile failed\n"));
	goto exit;
    }

    if (Fseek(fd, headerStart, SEEK_SET) < 0) {
	rc = RPMRC_FAIL;
	rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
		rpm, Fstrerror(fd));
	goto exit;
    }

    /* Start MD5 calculation */
    fdInitDigest(fd, PGPHASHALGO_MD5, 0);

    /* Write header to rpm and recalculate SHA1 */
    fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
    rc = headerWrite(fd, *hdrp, HEADER_MAGIC_YES);
    if (rc != RPMRC_OK) {
	rpmlog(RPMLOG_ERR, _("headerWrite failed\n"));
	goto exit;
    }
    fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&SHA1, &sha1len, 1);

    /* Copy archive from temp file */
    if (Fseek(ofd, 0, SEEK_SET) < 0) {
	rc = RPMRC_FAIL;
	rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
		rpm, Fstrerror(fd));
	goto exit;
    }
    if (copyFile(&ofd, trpm, &fd, rpm)) {
	rc = RPMRC_FAIL;
	rpmlog(RPMLOG_ERR, _("copyFile failed\n"));
	goto exit;
    }
    unlink(trpm);

    sigTargetSize = Ftell(fd) - headerStart;
    fdFiniDigest(fd, PGPHASHALGO_MD5, (void **)&MD5, &md5len, 0);

    if (headerGet(*sigp, RPMSIGTAG_MD5, &osigtd, HEADERGET_DEFAULT)) {
	memcpy(o_md5, osigtd.data, 16);
	rpmtdFreeData(&osigtd);
    }

    if (headerGet(*sigp, RPMSIGTAG_SHA1, &osigtd, HEADERGET_DEFAULT)) {
	o_sha1 = xstrdup(osigtd.data);
	rpmtdFreeData(&osigtd);
    }

    if (memcmp(MD5, o_md5, md5len) == 0 && strcmp(SHA1, o_sha1) == 0)
	rpmlog(RPMLOG_WARNING,
	       _("%s already contains identical file signatures\n"),
	       rpm);
    else
	replaceSigDigests(fd, rpm, sigp, sigStart, sigTargetSize, SHA1, MD5);

exit:
    free(trpm);
    free(MD5);
    free(SHA1);
    free(o_sha1);
    free(keypass);
    free(key);
    if (ofd)
	(void) closeFile(&ofd);
    return rc;
}