rpm/lib/package.c

380 lines
9.8 KiB
C

/** \ingroup header
* \file lib/package.c
*/
#include "system.h"
#include <netinet/in.h>
#include <rpmio_internal.h>
#include <rpmlib.h>
#include "depends.h"
#include "misc.h" /* XXX stripTrailingChar() */
#include "legacy.h" /* XXX providePackageNVR() and compressFileList() */
#include "rpmlead.h"
#include "signature.h"
#include "debug.h"
#define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s))
/*@access rpmTransactionSet@*/
/*@access Header@*/ /* XXX compared with NULL */
void headerMergeLegacySigs(Header h, const Header sig)
{
HFD_t hfd = (HFD_t) headerFreeData;
HAE_t hae = (HAE_t) headerAddEntry;
HeaderIterator hi;
int_32 tag, type, count;
const void * ptr;
int xx;
/*@-mods@*/ /* FIX: undocumented modification of sig */
for (hi = headerInitIterator(sig);
/*@=mods@*/
headerNextIterator(hi, &tag, &type, &ptr, &count);
ptr = hfd(ptr, type))
{
switch (tag) {
case RPMSIGTAG_SIZE:
tag = RPMTAG_SIGSIZE;
/*@switchbreak@*/ break;
case RPMSIGTAG_LEMD5_1:
tag = RPMTAG_SIGLEMD5_1;
/*@switchbreak@*/ break;
case RPMSIGTAG_PGP:
tag = RPMTAG_SIGPGP;
/*@switchbreak@*/ break;
case RPMSIGTAG_LEMD5_2:
tag = RPMTAG_SIGLEMD5_2;
/*@switchbreak@*/ break;
case RPMSIGTAG_MD5:
tag = RPMTAG_SIGMD5;
/*@switchbreak@*/ break;
case RPMSIGTAG_GPG:
tag = RPMTAG_SIGGPG;
/*@switchbreak@*/ break;
case RPMSIGTAG_PGP5:
tag = RPMTAG_SIGPGP5;
/*@switchbreak@*/ break;
default:
if (!(tag >= HEADER_SIGBASE && tag < HEADER_TAGBASE))
continue;
/*@switchbreak@*/ break;
}
if (ptr == NULL) continue; /* XXX can't happen */
if (!headerIsEntry(h, tag))
xx = hae(h, tag, type, ptr, count);
}
hi = headerFreeIterator(hi);
}
Header headerRegenSigHeader(const Header h)
{
HFD_t hfd = (HFD_t) headerFreeData;
Header sig = rpmNewSignature();
HeaderIterator hi;
int_32 tag, stag, type, count;
const void * ptr;
int xx;
/*@-mods@*/ /* FIX: undocumented modification of h */
for (hi = headerInitIterator(h);
/*@=mods@*/
headerNextIterator(hi, &tag, &type, &ptr, &count);
ptr = hfd(ptr, type))
{
switch (tag) {
case RPMTAG_SIGSIZE:
stag = RPMSIGTAG_SIZE;
/*@switchbreak@*/ break;
case RPMTAG_SIGLEMD5_1:
stag = RPMSIGTAG_LEMD5_1;
/*@switchbreak@*/ break;
case RPMTAG_SIGPGP:
stag = RPMSIGTAG_PGP;
/*@switchbreak@*/ break;
case RPMTAG_SIGLEMD5_2:
stag = RPMSIGTAG_LEMD5_2;
/*@switchbreak@*/ break;
case RPMTAG_SIGMD5:
stag = RPMSIGTAG_MD5;
/*@switchbreak@*/ break;
case RPMTAG_SIGGPG:
stag = RPMSIGTAG_GPG;
/*@switchbreak@*/ break;
case RPMTAG_SIGPGP5:
stag = RPMSIGTAG_PGP5;
/*@switchbreak@*/ break;
default:
if (!(tag >= HEADER_SIGBASE && tag < HEADER_TAGBASE))
continue;
stag = tag;
/*@switchbreak@*/ break;
}
if (ptr == NULL) continue; /* XXX can't happen */
if (!headerIsEntry(sig, stag))
xx = headerAddEntry(sig, stag, type, ptr, count);
}
hi = headerFreeIterator(hi);
return sig;
}
#ifdef DYING
/**
* Retrieve package components from file handle.
* @param fd file handle
* @param leadPtr address of lead (or NULL)
* @param sigs address of signatures (or NULL)
* @param hdrPtr address of header (or NULL)
* @return rpmRC return code
*/
static rpmRC readPackageHeaders(FD_t fd,
/*@null@*/ /*@out@*/ struct rpmlead * leadPtr,
/*@null@*/ /*@out@*/ Header * sigs,
/*@null@*/ /*@out@*/ Header * hdrPtr)
/*@globals fileSystem@*/
/*@modifies fd, *leadPtr, *sigs, *hdrPtr, fileSystem @*/
{
Header hdrBlock;
struct rpmlead leadBlock;
Header * hdr = NULL;
struct rpmlead * lead;
struct stat sb;
rpmRC rc;
hdr = hdrPtr ? hdrPtr : &hdrBlock;
lead = leadPtr ? leadPtr : &leadBlock;
memset(&sb, 0, sizeof(sb));
(void) fstat(Fileno(fd), &sb);
/* if fd points to a socket, pipe, etc, sb.st_size is *always* zero */
if (S_ISREG(sb.st_mode) && sb.st_size < sizeof(*lead)) return 1;
if (readLead(fd, lead))
return RPMRC_FAIL;
if (lead->magic[0] != RPMLEAD_MAGIC0 || lead->magic[1] != RPMLEAD_MAGIC1 ||
lead->magic[2] != RPMLEAD_MAGIC2 || lead->magic[3] != RPMLEAD_MAGIC3)
return RPMRC_BADMAGIC;
switch (lead->major) {
case 1:
rpmError(RPMERR_NEWPACKAGE,
_("packaging version 1 is not supported by this version of RPM\n"));
return RPMRC_FAIL;
/*@notreached@*/ break;
case 2:
case 3:
case 4:
rc = rpmReadSignature(fd, sigs, lead->signature_type);
if (rc == RPMRC_FAIL)
return rc;
*hdr = headerRead(fd, (lead->major >= 3)
? HEADER_MAGIC_YES : HEADER_MAGIC_NO);
if (*hdr == NULL) {
if (sigs != NULL)
*sigs = rpmFreeSignature(*sigs);
return RPMRC_FAIL;
}
/* Convert legacy headers on the fly ... */
legacyRetrofit(*hdr, lead);
break;
default:
rpmError(RPMERR_NEWPACKAGE, _("only packaging with major numbers <= 4 "
"is supported by this version of RPM\n"));
return RPMRC_FAIL;
/*@notreached@*/ break;
}
if (hdrPtr == NULL)
*hdr = headerFree(*hdr);
return RPMRC_OK;
}
#endif
int rpmReadPackageFile(rpmTransactionSet ts, FD_t fd,
const char * fn, Header * hdrp)
{
byte buf[8*BUFSIZ];
ssize_t count;
struct rpmlead * l = alloca(sizeof(*l));
Header sig;
Header h = NULL;
int hmagic;
rpmRC rc = RPMRC_FAIL; /* assume failure */
int xx;
int i;
{ struct stat st;
memset(&st, 0, sizeof(st));
(void) fstat(Fileno(fd), &st);
/* if fd points to a socket, pipe, etc, st.st_size is *always* zero */
if (S_ISREG(st.st_mode) && st.st_size < sizeof(*l))
goto exit;
}
memset(l, 0, sizeof(*l));
if (readLead(fd, l)) {
rpmError(RPMERR_READLEAD, _("%s: readLead failed\n"), fn);
goto exit;
}
if (l->magic[0] != RPMLEAD_MAGIC0 || l->magic[1] != RPMLEAD_MAGIC1
|| l->magic[2] != RPMLEAD_MAGIC2 || l->magic[3] != RPMLEAD_MAGIC3) {
rpmError(RPMERR_READLEAD, _("%s: bad magic\n"), fn);
rc = RPMRC_BADMAGIC;
goto exit;
}
switch (l->major) {
case 1:
rpmError(RPMERR_NEWPACKAGE,
_("packaging version 1 is not supported by this version of RPM\n"));
goto exit;
/*@notreached@*/ break;
case 2:
case 3:
case 4:
break;
default:
rpmError(RPMERR_NEWPACKAGE, _("only packaging with major numbers <= 4 "
"is supported by this version of RPM\n"));
goto exit;
/*@notreached@*/ break;
}
rc = rpmReadSignature(fd, &sig, l->signature_type);
if (!(rc == RPMRC_OK || rc == RPMRC_BADSIZE)) {
rpmError(RPMERR_SIGGEN, _("%s: rpmReadSignature failed\n"), fn);
goto exit;
}
if (sig == NULL) {
rpmError(RPMERR_SIGGEN, _("%s: No signature available\n"), fn);
rc = RPMRC_FAIL;
goto exit;
}
if (!ts->verify_legacy) /* leave fd ready to install payload */
ts->sigtag = 0;
else if (headerIsEntry(sig, RPMSIGTAG_GPG))
ts->sigtag = RPMSIGTAG_GPG;
else if (headerIsEntry(sig, RPMSIGTAG_PGP))
ts->sigtag = RPMSIGTAG_PGP;
else if (headerIsEntry(sig, RPMSIGTAG_MD5))
ts->sigtag = RPMSIGTAG_MD5;
else
ts->sigtag = 0;
/*@-type@*/ /* FIX: cast? */
if (ts->sigtag == RPMSIGTAG_GPG)
fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
else if (ts->sigtag == RPMSIGTAG_PGP || ts->sigtag == RPMSIGTAG_MD5)
fdInitDigest(fd, PGPHASHALGO_MD5, 0);
/*@=type@*/
hmagic = ((l->major >= 3) ? HEADER_MAGIC_YES : HEADER_MAGIC_NO);
h = headerRead(fd, hmagic);
if (h == NULL) {
rpmError(RPMERR_FREAD, _("%s: headerRead failed\n"), fn);
rc = RPMRC_FAIL;
goto exit;
}
/* Any signatures to check? */
if (ts->sigtag == 0) {
rc = RPMRC_OK;
goto exit;
}
ts->dig = pgpNewDig();
ts->dig->nbytes = headerSizeof(h, hmagic);
/* Read the compressed payload. */
while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
ts->dig->nbytes += count;
if (count < 0) {
rpmError(RPMERR_FREAD, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd));
rc = RPMRC_FAIL;
goto exit;
}
ts->dig->nbytes += count;
xx = headerGetEntry(sig, ts->sigtag, &ts->sigtype,
(void **) &ts->sig, &ts->siglen);
xx = pgpPrtPkts(ts->sig, ts->siglen, ts->dig, rpmIsDebug());
/*@-type@*/ /* FIX: cast? */
for (i = fd->ndigests - 1; i >= 0; i--) {
FDDIGEST_t fddig = fd->digests + i;
if (fddig->hashctx == NULL)
continue;
if (fddig->hashalgo == PGPHASHALGO_MD5) {
/*@-branchstate@*/
if (ts->dig->md5ctx != NULL)
(void) rpmDigestFinal(ts->dig->md5ctx, NULL, NULL, 0);
/*@=branchstate@*/
ts->dig->md5ctx = fddig->hashctx;
fddig->hashctx = NULL;
continue;
}
if (fddig->hashalgo == PGPHASHALGO_SHA1) {
/*@-branchstate@*/
if (ts->dig->sha1ctx != NULL)
(void) rpmDigestFinal(ts->dig->sha1ctx, NULL, NULL, 0);
/*@=branchstate@*/
ts->dig->sha1ctx = fddig->hashctx;
fddig->hashctx = NULL;
continue;
}
}
/*@=type@*/
/** @todo Implement disable/enable/warn/error/anal policy. */
buf[0] = '\0';
switch (rpmVerifySignature(ts, buf)) {
case RPMSIG_OK: /*!< Signature is OK. */
rpmMessage(RPMMESS_VERBOSE, "%s: %s", fn, buf);
rc = RPMRC_OK;
break;
case RPMSIG_UNKNOWN: /*!< Signature is unknown. */
case RPMSIG_NOKEY: /*!< Key is unavailable. */
case RPMSIG_NOTTRUSTED: /*!< Signature is OK, but key is not trusted. */
rpmMessage(RPMMESS_WARNING, "%s: %s", fn, buf);
rc = RPMRC_OK;
break;
default:
case RPMSIG_BAD: /*!< Signature does not verify. */
rpmMessage(RPMMESS_ERROR, "%s: %s", fn, buf);
rc = RPMRC_OK;
break;
}
exit:
if (rc == 0 && hdrp != NULL) {
/* Convert legacy headers on the fly ... */
legacyRetrofit(h, l);
/* Append (and remap) signature tags. */
headerMergeLegacySigs(h, sig);
/* Bump reference count for return. */
*hdrp = headerLink(h);
}
h = headerFree(h);
if (ts->sig != NULL)
ts->sig = headerFreeData(ts->sig, ts->sigtype);
if (ts->dig != NULL)
ts->dig = pgpFreeDig(ts->dig);
sig = rpmFreeSignature(sig);
return rc;
}