rpm-build/lib/rpmchecksig.c

533 lines
13 KiB
C

/** \ingroup rpmcli
* \file lib/rpmchecksig.c
* Verify the signature of a package.
*/
#include "system.h"
#include "rpmcli.h"
#include "rpmlead.h"
#include "signature.h"
#include "misc.h" /* XXX for makeTempFile() */
#include "debug.h"
/*@access Header@*/ /* XXX compared with NULL */
/*@access FD_t@*/ /* XXX compared with NULL */
static int manageFile(FD_t *fdp, const char **fnp, int flags,
/*@unused@*/ int rc)
/*@globals rpmGlobalMacroContext, fileSystem @*/
/*@modifies *fdp, *fnp, rpmGlobalMacroContext, fileSystem @*/
{
const char *fn;
FD_t fd;
if (fdp == NULL) { /* programmer error */
return 1;
}
/* close and reset *fdp to NULL */
if (*fdp && (fnp == NULL || *fnp == NULL)) {
(void) Fclose(*fdp);
*fdp = NULL;
return 0;
}
/* open a file and set *fdp */
if (*fdp == NULL && fnp && *fnp) {
fd = Fopen(*fnp, ((flags & O_WRONLY) ? "w.ufdio" : "r.ufdio"));
if (fd == NULL || Ferror(fd)) {
rpmError(RPMERR_OPEN, _("%s: open failed: %s\n"), *fnp,
Fstrerror(fd));
return 1;
}
*fdp = fd;
return 0;
}
/* open a temp file */
if (*fdp == NULL && (fnp == NULL || *fnp == NULL)) {
fn = NULL;
if (makeTempFile(NULL, (fnp ? &fn : NULL), &fd)) {
rpmError(RPMERR_MAKETEMP, _("makeTempFile failed\n"));
return 1;
}
if (fnp)
*fnp = fn;
*fdp = fdLink(fd, "manageFile return");
(void) fdFree(fd, "manageFile return");
return 0;
}
/* no operation */
if (*fdp && fnp && *fnp) {
return 0;
}
/* XXX never reached */
return 1;
}
static int copyFile(FD_t *sfdp, const char **sfnp,
FD_t *tfdp, const char **tfnp)
/*@modifies *sfdp, *sfnp, *tfdp, *tfnp, fileSystem @*/
{
unsigned char buffer[BUFSIZ];
ssize_t count;
int rc = 1;
if (manageFile(sfdp, sfnp, O_RDONLY, 0))
goto exit;
if (manageFile(tfdp, tfnp, O_WRONLY|O_CREAT|O_TRUNC, 0))
goto exit;
while ((count = Fread(buffer, sizeof(buffer[0]), sizeof(buffer), *sfdp)) > 0) {
if (Fwrite(buffer, sizeof(buffer[0]), count, *tfdp) != count) {
rpmError(RPMERR_FWRITE, _("%s: Fwrite failed: %s\n"), *tfnp,
Fstrerror(*tfdp));
goto exit;
}
}
if (count < 0) {
rpmError(RPMERR_FREAD, _("%s: Fread failed: %s\n"), *sfnp, Fstrerror(*sfdp));
goto exit;
}
rc = 0;
exit:
if (*sfdp) (void) manageFile(sfdp, NULL, 0, rc);
if (*tfdp) (void) manageFile(tfdp, NULL, 0, rc);
return rc;
}
int rpmReSign(rpmResignFlags flags, char * passPhrase, const char ** argv)
{
FD_t fd = NULL;
FD_t ofd = NULL;
struct rpmlead lead, *l = &lead;
int_32 sigtag;
const char *rpm, *trpm;
const char *sigtarget = NULL;
char tmprpm[1024+1];
Header sig = NULL;
void * uh = NULL;
int_32 uht, uhc;
int res = EXIT_FAILURE;
rpmRC rc;
int xx;
tmprpm[0] = '\0';
if (argv)
while ((rpm = *argv++) != NULL) {
fprintf(stdout, "%s:\n", rpm);
if (manageFile(&fd, &rpm, O_RDONLY, 0))
goto exit;
memset(l, 0, sizeof(*l));
if (readLead(fd, l)) {
rpmError(RPMERR_READLEAD, _("%s: readLead failed\n"), rpm);
goto exit;
}
switch (l->major) {
case 1:
rpmError(RPMERR_BADSIGTYPE, _("%s: Can't sign v1.0 RPM\n"), rpm);
goto exit;
/*@notreached@*/ break;
case 2:
rpmError(RPMERR_BADSIGTYPE, _("%s: Can't re-sign v2.0 RPM\n"), rpm);
goto exit;
/*@notreached@*/ break;
default:
break;
}
rc = rpmReadSignature(fd, &sig, l->signature_type);
if (!(rc == RPMRC_OK || rc == RPMRC_BADSIZE)) {
rpmError(RPMERR_SIGGEN, _("%s: rpmReadSignature failed\n"), rpm);
goto exit;
}
if (sig == NULL) {
rpmError(RPMERR_SIGGEN, _("%s: No signature available\n"), rpm);
goto exit;
}
/* Write the header and archive to a temp file */
/* ASSERT: ofd == NULL && sigtarget == NULL */
if (copyFile(&fd, &rpm, &ofd, &sigtarget))
goto exit;
/* Both fd and ofd are now closed. sigtarget contains tempfile name. */
/* ASSERT: fd == NULL && ofd == NULL */
/* Dump the immutable region (if present). */
if (headerGetEntry(sig, RPMTAG_HEADERSIGNATURES, &uht, &uh, &uhc)) {
HeaderIterator hi;
int_32 tag, type, count;
hPTR_t ptr;
Header oh;
Header nh;
nh = headerNew();
if (nh == NULL) {
uh = headerFreeData(uh, uht);
goto exit;
}
oh = headerCopyLoad(uh);
for (hi = headerInitIterator(oh);
headerNextIterator(hi, &tag, &type, &ptr, &count);
ptr = headerFreeData(ptr, type))
{
if (ptr)
xx = headerAddEntry(nh, tag, type, ptr, count);
}
hi = headerFreeIterator(hi);
oh = headerFree(oh);
sig = headerFree(sig);
sig = headerLink(nh);
nh = headerFree(nh);
}
/* Eliminate broken digest values. */
xx = headerRemoveEntry(sig, RPMSIGTAG_LEMD5_1);
xx = headerRemoveEntry(sig, RPMSIGTAG_LEMD5_2);
xx = headerRemoveEntry(sig, RPMSIGTAG_BADSHA1_1);
xx = headerRemoveEntry(sig, RPMSIGTAG_BADSHA1_2);
/* Toss and recalculate header+payload size and digests. */
xx = headerRemoveEntry(sig, RPMSIGTAG_SIZE);
xx = rpmAddSignature(sig, sigtarget, RPMSIGTAG_SIZE, passPhrase);
xx = headerRemoveEntry(sig, RPMSIGTAG_MD5);
xx = rpmAddSignature(sig, sigtarget, RPMSIGTAG_MD5, passPhrase);
#ifdef NOTYET /* XXX leave new-fangled header-only digest in place. */
xx = headerRemoveEntry(sig, RPMSIGTAG_SHA1);
xx = rpmAddSignature(sig, sigtarget, RPMSIGTAG_SHA1, passPhrase);
#endif
if ((sigtag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) > 0) {
#ifdef NOTYET /* XXX leave new-fangled header-only signatures in place. */
case RPMSIGTAG_GPG:
xx = headerRemoveEntry(sig, RPMSIGTAG_DSA);
/*@fallthrough@*/
case RPMSIGTAG_PGP5:
case RPMSIGTAG_PGP:
xx = headerRemoveEntry(sig, RPMSIGTAG_RSA);
/*@switchbreak@*/ break;
}
#endif
xx = headerRemoveEntry(sig, sigtag);
xx = rpmAddSignature(sig, sigtarget, sigtag, passPhrase);
}
/* Reallocate the signature into one contiguous region. */
sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
if (sig == NULL) /* XXX can't happen */
goto exit;
/* Write the lead/signature of the output rpm */
strcpy(tmprpm, rpm);
strcat(tmprpm, ".XXXXXX");
(void) /*@-unrecog@*/ mktemp(tmprpm) /*@=unrecog@*/;
trpm = tmprpm;
if (manageFile(&ofd, &trpm, O_WRONLY|O_CREAT|O_TRUNC, 0))
goto exit;
l->signature_type = RPMSIGTYPE_HEADERSIG;
if (writeLead(ofd, l)) {
rpmError(RPMERR_WRITELEAD, _("%s: writeLead failed: %s\n"), trpm,
Fstrerror(ofd));
goto exit;
}
if (rpmWriteSignature(ofd, sig)) {
rpmError(RPMERR_SIGGEN, _("%s: rpmWriteSignature failed: %s\n"), trpm,
Fstrerror(ofd));
goto exit;
}
/* Append the header and archive from the temp file */
/* ASSERT: fd == NULL && ofd != NULL */
if (copyFile(&fd, &sigtarget, &ofd, &trpm))
goto exit;
/* Both fd and ofd are now closed. */
/* ASSERT: fd == NULL && ofd == NULL */
/* Clean up intermediate target */
(void) unlink(sigtarget);
sigtarget = _free(sigtarget);
/* Move final target into place. */
(void) unlink(rpm);
(void) rename(trpm, rpm);
tmprpm[0] = '\0';
}
res = 0;
exit:
if (fd) (void) manageFile(&fd, NULL, 0, res);
if (ofd) (void) manageFile(&ofd, NULL, 0, res);
sig = rpmFreeSignature(sig);
if (sigtarget) {
(void) unlink(sigtarget);
sigtarget = _free(sigtarget);
}
if (tmprpm[0] != '\0') {
(void) unlink(tmprpm);
tmprpm[0] = '\0';
}
return res;
}
int rpmCheckSig(rpmCheckSigFlags flags, const char ** argv)
{
FD_t fd = NULL;
FD_t ofd = NULL;
int res2, res3;
struct rpmlead lead, *l = &lead;
const char *rpm = NULL;
char result[8*BUFSIZ];
const char * sigtarget = NULL;
unsigned char buffer[8192];
unsigned char missingKeys[7164];
unsigned char untrustedKeys[7164];
Header sig;
HeaderIterator hi;
int_32 tag, type, count;
const void * ptr;
int res = 0;
rpmRC rc;
if (argv)
while ((rpm = *argv++) != NULL) {
if (manageFile(&fd, &rpm, O_RDONLY, 0)) {
res++;
goto bottom;
}
memset(l, 0, sizeof(*l));
if (readLead(fd, l)) {
rpmError(RPMERR_READLEAD, _("%s: readLead failed\n"), rpm);
res++;
goto bottom;
}
switch (l->major) {
case 1:
rpmError(RPMERR_BADSIGTYPE, _("%s: No signature available (v1.0 RPM)\n"), rpm);
res++;
goto bottom;
/*@notreached@*/ break;
default:
break;
}
rc = rpmReadSignature(fd, &sig, l->signature_type);
if (!(rc == RPMRC_OK || rc == RPMRC_BADSIZE)) {
rpmError(RPMERR_SIGGEN, _("%s: rpmReadSignature failed\n"), rpm);
res++;
goto bottom;
}
if (sig == NULL) {
rpmError(RPMERR_SIGGEN, _("%s: No signature available\n"), rpm);
res++;
goto bottom;
}
/* Write the header and archive to a temp file */
/* ASSERT: ofd == NULL && sigtarget == NULL */
if (copyFile(&fd, &rpm, &ofd, &sigtarget)) {
res++;
goto bottom;
}
/* Both fd and ofd are now closed. sigtarget contains tempfile name. */
/* ASSERT: fd == NULL && ofd == NULL */
res2 = 0;
missingKeys[0] = '\0';
untrustedKeys[0] = '\0';
sprintf(buffer, "%s:%c", rpm, (rpmIsVerbose() ? '\n' : ' ') );
for (hi = headerInitIterator(sig);
headerNextIterator(hi, &tag, &type, &ptr, &count);
ptr = headerFreeData(ptr, type))
{
switch (tag) {
case RPMSIGTAG_PGP5: /* XXX legacy */
case RPMSIGTAG_PGP:
if (!(flags & CHECKSIG_PGP))
continue;
break;
case RPMSIGTAG_GPG:
if (!(flags & CHECKSIG_GPG))
continue;
break;
case RPMSIGTAG_LEMD5_2:
case RPMSIGTAG_LEMD5_1:
case RPMSIGTAG_MD5:
if (!(flags & CHECKSIG_MD5))
continue;
break;
default:
continue;
/*@notreached@*/ break;
}
if (ptr == NULL) continue; /* XXX can't happen */
if ((res3 = rpmVerifySignature(sigtarget, tag, ptr, count,
result))) {
if (rpmIsVerbose()) {
strcat(buffer, result);
res2 = 1;
} else {
char *tempKey;
switch (tag) {
case RPMSIGTAG_SIZE:
strcat(buffer, "SIZE ");
res2 = 1;
break;
case RPMSIGTAG_LEMD5_2:
case RPMSIGTAG_LEMD5_1:
case RPMSIGTAG_MD5:
strcat(buffer, "MD5 ");
res2 = 1;
break;
case RPMSIGTAG_PGP5: /* XXX legacy */
case RPMSIGTAG_PGP:
switch (res3) {
case RPMSIG_NOKEY:
res2 = 1;
/*@fallthrough@*/
case RPMSIG_NOTTRUSTED:
{ int offset = 7;
strcat(buffer, "(PGP) ");
tempKey = strstr(result, "Key ID");
if (tempKey == NULL) {
tempKey = strstr(result, "keyid:");
offset = 9;
}
if (tempKey) {
if (res3 == RPMSIG_NOKEY) {
strcat(missingKeys, " PGP#");
/*@-compdef@*/
strncat(missingKeys, tempKey + offset, 8);
/*@=compdef@*/
} else {
strcat(untrustedKeys, " PGP#");
/*@-compdef@*/
strncat(untrustedKeys, tempKey + offset, 8);
/*@=compdef@*/
}
}
} break;
default:
strcat(buffer, "PGP ");
res2 = 1;
break;
}
break;
case RPMSIGTAG_GPG:
/* Do not consider this a failure */
switch (res3) {
case RPMSIG_NOKEY:
strcat(buffer, "(GPG) ");
strcat(missingKeys, " GPG#");
tempKey = strstr(result, "key ID");
if (tempKey)
/*@-compdef@*/
strncat(missingKeys, tempKey+7, 8);
/*@=compdef@*/
res2 = 1;
break;
default:
strcat(buffer, "GPG ");
res2 = 1;
break;
}
break;
default:
strcat(buffer, "?UnknownSignatureType? ");
res2 = 1;
break;
}
}
} else {
if (rpmIsVerbose()) {
strcat(buffer, result);
} else {
switch (tag) {
case RPMSIGTAG_SIZE:
strcat(buffer, "size ");
break;
case RPMSIGTAG_LEMD5_2:
case RPMSIGTAG_LEMD5_1:
case RPMSIGTAG_MD5:
strcat(buffer, "md5 ");
break;
case RPMSIGTAG_PGP5: /* XXX legacy */
case RPMSIGTAG_PGP:
strcat(buffer, "pgp ");
break;
case RPMSIGTAG_GPG:
strcat(buffer, "gpg ");
break;
default:
strcat(buffer, "??? ");
break;
}
}
}
}
hi = headerFreeIterator(hi);
res += res2;
(void) unlink(sigtarget);
sigtarget = _free(sigtarget);
if (res2) {
if (rpmIsVerbose()) {
rpmError(RPMERR_SIGVFY, "%s", (char *)buffer);
} else {
rpmError(RPMERR_SIGVFY, "%s%s%s%s%s%s%s%s\n", (char *)buffer,
_("NOT OK"),
(missingKeys[0] != '\0') ? _(" (MISSING KEYS:") : "",
(char *)missingKeys,
(missingKeys[0] != '\0') ? _(") ") : "",
(untrustedKeys[0] != '\0') ? _(" (UNTRUSTED KEYS:") : "",
(char *)untrustedKeys,
(untrustedKeys[0] != '\0') ? _(")") : "");
}
} else {
if (rpmIsVerbose()) {
rpmError(RPMERR_SIGVFY, "%s", (char *)buffer);
} else {
rpmError(RPMERR_SIGVFY, "%s%s%s%s%s%s%s%s\n", (char *)buffer,
_("OK"),
(missingKeys[0] != '\0') ? _(" (MISSING KEYS:") : "",
(char *)missingKeys,
(missingKeys[0] != '\0') ? _(") ") : "",
(untrustedKeys[0] != '\0') ? _(" (UNTRUSTED KEYS:") : "",
(char *)untrustedKeys,
(untrustedKeys[0] != '\0') ? _(")") : "");
}
}
bottom:
if (fd) (void) manageFile(&fd, NULL, 0, 0);
if (ofd) (void) manageFile(&ofd, NULL, 0, 0);
if (sigtarget) {
(void) unlink(sigtarget);
sigtarget = _free(sigtarget);
}
}
return res;
}