diff --git a/CHANGES b/CHANGES index 4e559b15d..0026860cd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,6 @@ 2.92 -> 2.93 - eliminate old rpmrc configuration syntax. + - pgp5 support (Carlo Wood ) 2.91 -> 2.92 - update with libtool-2.4f. diff --git a/checksig.c b/checksig.c index 5456ab06c..008ac6233 100644 --- a/checksig.c +++ b/checksig.c @@ -152,6 +152,7 @@ int doCheckSig(int flags, const char **argv) const char * sigtarget; unsigned char buffer[8192]; unsigned char missingKeys[7164]; + unsigned char untrustedKeys[7164]; char *tempKey; Header sig; HeaderIterator sigIter; @@ -212,13 +213,15 @@ int doCheckSig(int flags, const char **argv) sigIter = headerInitIterator(sig); res2 = 0; missingKeys[0] = '\0'; + untrustedKeys[0] = '\0'; if (rpmIsVerbose()) { sprintf(buffer, "%s:\n", rpm); } else { sprintf(buffer, "%s: ", rpm); } while (headerNextIterator(sigIter, &tag, &type, &ptr, &count)) { - if ((tag == RPMSIGTAG_PGP) && !(flags & CHECKSIG_PGP)) + if ((tag == RPMSIGTAG_PGP || tag == RPMSIGTAG_PGP5) + && !(flags & CHECKSIG_PGP)) continue; if ((tag == RPMSIGTAG_GPG) && !(flags & CHECKSIG_GPG)) continue; @@ -246,12 +249,24 @@ int doCheckSig(int flags, const char **argv) res2 = 1; break; case RPMSIGTAG_PGP: - if (res3 == RPMSIG_NOKEY) { - /* Do not consider this a failure */ + case RPMSIGTAG_PGP5: + if (res3 == RPMSIG_NOKEY || res3 == RPMSIG_NOTTRUSTED) { + /* Do not consider these a failure */ + int offset = 7; strcat(buffer, "(PGP) "); - strcat(missingKeys, " PGP#"); tempKey = strstr(result, "Key ID"); - strncat(missingKeys, tempKey+7, 8); + if (!tempKey) + { + tempKey = strstr(result, "keyid:"); + offset = 9; + } + if (res3 == RPMSIG_NOKEY) { + strcat(missingKeys, " PGP#"); + strncat(missingKeys, tempKey + offset, 8); + } else { + strcat(untrustedKeys, " PGP#"); + strncat(untrustedKeys, tempKey + offset, 8); + } } else { strcat(buffer, "PGP "); res2 = 1; @@ -288,6 +303,7 @@ int doCheckSig(int flags, const char **argv) strcat(buffer, "md5 "); break; case RPMSIGTAG_PGP: + case RPMSIGTAG_PGP5: strcat(buffer, "pgp "); break; case RPMSIGTAG_GPG: @@ -308,20 +324,28 @@ int doCheckSig(int flags, const char **argv) if (rpmIsVerbose()) { fprintf(stderr, "%s", (char *)buffer); } else { - fprintf(stderr, "%s%s%s%s%s\n", (char *)buffer, _("NOT OK"), + fprintf(stderr, "%s%s%s%s%s%s%s%s\n", (char *)buffer, + _("NOT OK"), (missingKeys[0] != '\0') ? _(" (MISSING KEYS:") : "", (char *)missingKeys, - (missingKeys[0] != '\0') ? _(")") : ""); + (missingKeys[0] != '\0') ? _(") ") : "", + (untrustedKeys[0] != '\0') ? _(" (UNTRUSTED KEYS:") : "", + (char *)untrustedKeys, + (untrustedKeys[0] != '\0') ? _(")") : ""); } } else { if (rpmIsVerbose()) { fprintf(stdout, "%s", (char *)buffer); } else { - fprintf(stdout, "%s%s%s%s%s\n", (char *)buffer, _("OK"), + fprintf(stdout, "%s%s%s%s%s%s%s%s\n", (char *)buffer, + _("OK"), (missingKeys[0] != '\0') ? _(" (MISSING KEYS:") : "", (char *)missingKeys, - (missingKeys[0] != '\0') ? _(")") : ""); + (missingKeys[0] != '\0') ? _(") ") : "", + (untrustedKeys[0] != '\0') ? _(" (UNTRUSTED KEYS:") : "", + (char *)untrustedKeys, + (untrustedKeys[0] != '\0') ? _(")") : ""); } } } diff --git a/configure.in b/configure.in index 56504a8a4..c509ba367 100644 --- a/configure.in +++ b/configure.in @@ -199,6 +199,25 @@ if test "$cross_compiling" != "yes"; then AC_MSG_RESULT($BZIP2BIN) fi + AC_MSG_CHECKING(for pgp location) + if test -z "$PGPBIN"; then + oldifs="$IFS" + IFS=: + for n in $MYPATH; do + if test -f $n/pgp; then + PGPBIN="$n/pgp"; + break + fi + done + IFS="$oldifs" + fi + + if test -z "$PGPBIN"; then + PGPBIN="/usr/bin/pgp" + else + AC_MSG_RESULT($PGPBIN) + fi + AC_MSG_CHECKING(old version of patch) PATCHVERSION=`patch --version 2>&1` @@ -636,6 +655,7 @@ AC_SUBST(LIBS) AC_SUBST(RPM) AC_SUBST(GZIPBIN) AC_SUBST(BZIP2BIN) +AC_SUBST(PGPBIN) AC_SUBST(FIXPERMS) AC_SUBST(LIBMISC) AC_SUBST(MKDIR_P) diff --git a/lib/rpmlib.h b/lib/rpmlib.h index 2e1869a9d..3467cc2c8 100644 --- a/lib/rpmlib.h +++ b/lib/rpmlib.h @@ -563,6 +563,7 @@ rpmErrorCallBackType rpmErrorSetCallback(rpmErrorCallBackType); #define RPMSIGTAG_LEMD5_2 1003 #define RPMSIGTAG_MD5 1004 #define RPMSIGTAG_GPG 1005 +#define RPMSIGTAG_PGP5 1006 /**************************************************/ /* */ @@ -571,10 +572,11 @@ rpmErrorCallBackType rpmErrorSetCallback(rpmErrorCallBackType); /**************************************************/ /* verifySignature() results */ -#define RPMSIG_OK 0 -#define RPMSIG_UNKNOWN 1 -#define RPMSIG_BAD 2 -#define RPMSIG_NOKEY 3 /* Do not have the key to check this signature */ +#define RPMSIG_OK 0 +#define RPMSIG_UNKNOWN 1 +#define RPMSIG_BAD 2 +#define RPMSIG_NOKEY 3 /* Do not have the key to check this signature */ +#define RPMSIG_NOTTRUSTED 4 /* We have the key but it is not trusted */ void rpmFreeSignature(Header h); diff --git a/lib/signature.c b/lib/signature.c index 1a244f8f8..ccddc8a5a 100644 --- a/lib/signature.c +++ b/lib/signature.c @@ -23,7 +23,7 @@ typedef int (*md5func)(const char * fn, unsigned char * digest); static int makePGPSignature(const char *file, void **sig, int_32 *size, - const char *passPhrase); + const char *passPhrase, int sigTag); static int makeGPGSignature(const char *file, void **sig, int_32 *size, const char *passPhrase); static int checkSize(FD_t fd, int size, int sigsize); @@ -31,7 +31,7 @@ static int verifySizeSignature(const char *datafile, int_32 size, char *result); static int verifyMD5Signature(const char *datafile, unsigned char *sig, char *result, md5func fn); static int verifyPGPSignature(const char *datafile, void *sig, - int count, char *result); + int count, char *result, int sigTag); static int verifyGPGSignature(const char *datafile, void *sig, int count, char *result); static int checkPassPhrase(const char *passPhrase, const int sigType); @@ -47,6 +47,8 @@ int rpmLookupSignatureType(void) rc = 0; else if (!strcasecmp(name, "pgp")) rc = RPMSIGTAG_PGP; + else if (!strcasecmp(name, "pgp5")) + rc = RPMSIGTAG_PGP5; else if (!strcasecmp(name, "gpg")) rc = RPMSIGTAG_GPG; else @@ -56,6 +58,56 @@ int rpmLookupSignatureType(void) return rc; } +/* rpmDetectPGPVersion() returns the absolute path to the "pgp" */ +/* executable of the requested version, or NULL when none found. */ + +const char * rpmDetectPGPVersion(int sigType) +{ + /* Actually this should support having more then one pgp version. */ + /* At the moment only one version is possible since we only */ + /* have one %__pgp and one pgp_path. */ + + static int pgp_version; + const char *pgpbin = rpmGetPath("%{_pgpbin}", NULL); + + if (!pgp_version) + { + char *pgpvbin; + struct stat statbuf; + + if (!pgpbin || ! (pgpvbin = (char *)malloc(strlen(pgpbin) + 2))) + { + pgp_version = -1; + return NULL; + } + sprintf(pgpvbin, "%sv", pgpbin); + + if (stat(pgpvbin, &statbuf) == 0) + pgp_version = 50; + else if (stat(pgpbin, &statbuf) == 0) + pgp_version = 26; + else + pgp_version = -1; + + free(pgpvbin); + } + + switch (sigType) + { + case RPMSIGTAG_PGP: + if (pgp_version == 26) + return pgpbin; + break; + case RPMSIGTAG_PGP5: + if (pgp_version == 50) + return pgpbin; + break; + default: + break; + } + return NULL; +} + /* rpmReadSignature() emulates the new style signatures if it finds an */ /* old-style one. It also immediately verifies the header+archive */ /* size and returns an error if it doesn't match. */ @@ -176,7 +228,8 @@ int rpmAddSignature(Header header, const char *file, int_32 sigTag, const char * headerAddEntry(header, sigTag, RPM_BIN_TYPE, buf, 16); break; case RPMSIGTAG_PGP: - makePGPSignature(file, &sig, &size, passPhrase); + case RPMSIGTAG_PGP5: + makePGPSignature(file, &sig, &size, passPhrase, sigTag); headerAddEntry(header, sigTag, RPM_BIN_TYPE, sig, size); break; case RPMSIGTAG_GPG: @@ -189,12 +242,11 @@ int rpmAddSignature(Header header, const char *file, int_32 sigTag, const char * } static int makePGPSignature(const char *file, void **sig, int_32 *size, - const char *passPhrase) + const char *passPhrase, int sigTag) { char sigfile[1024]; int pid, status; int inpipe[2]; - FILE *fpipe; struct stat statbuf; sprintf(sigfile, "%s.sig", file); @@ -204,6 +256,7 @@ static int makePGPSignature(const char *file, void **sig, int_32 *size, if (!(pid = fork())) { const char *pgp_path = rpmExpand("%{_pgp_path}", NULL); const char *name = rpmExpand("+myname=\"%{_pgp_name}\"", NULL); + const char *path; close(STDIN_FILENO); dup2(inpipe[0], 3); @@ -214,18 +267,27 @@ static int makePGPSignature(const char *file, void **sig, int_32 *size, dosetenv("PGPPATH", pgp_path, 1); /* dosetenv("PGPPASS", passPhrase, 1); */ - execlp("pgp", "pgp", - "+batchmode=on", "+verbose=0", "+armor=off", - name, "-sb", file, sigfile, - NULL); + + if ((path = rpmDetectPGPVersion(sigTag)) != NULL { + switch(sigTag) { + case RPMSIGTAG_PGP: + execlp(path, "pgp", "+batchmode=on", "+verbose=0", "+armor=off", + name, "-sb", file, sigfile, NULL); + break; + case RPMSIGTAG_PGP5: + execlp(path,"pgps", "+batchmode=on", "+verbose=0", "+armor=off", + name, "-b", file, "-o", sigfile, NULL); + break; + } + } rpmError(RPMERR_EXEC, _("Couldn't exec pgp")); _exit(RPMERR_EXEC); } - fpipe = fdopen(inpipe[1], "w"); close(inpipe[0]); - fprintf(fpipe, "%s\n", passPhrase); - fclose(fpipe); + write(inpipe[1], passPhrase, strlen(passPhrase)); + write(inpipe[1], "\n", 1); + close(inpipe[1]); (void)waitpid(pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status)) { @@ -380,7 +442,8 @@ int rpmVerifySignature(const char *file, int_32 sigTag, void *sig, int count, } break; case RPMSIGTAG_PGP: - return verifyPGPSignature(file, sig, count, result); + case RPMSIGTAG_PGP%: + return verifyPGPSignature(file, sig, count, result, sigTag); break; case RPMSIGTAG_GPG: return verifyGPGSignature(file, sig, count, result); @@ -443,7 +506,7 @@ static int verifyMD5Signature(const char *datafile, unsigned char *sig, } static int verifyPGPSignature(const char *datafile, void *sig, - int count, char *result) + int count, char *result, int sigTag) { int pid, status, outpipe[2]; FD_t sfd; @@ -451,7 +514,29 @@ static int verifyPGPSignature(const char *datafile, void *sig, unsigned char buf[8192]; FILE *file; int res = RPMSIG_OK; + int usingPGP5 = 0; + const char *path; + /* What version do we have? */ + if ((path = rpmDetectPGPVersion(RPMSIGTAG_PGP5))/* Use pgp5 if we have it */ + || sigTag == RPMSIGTAG_PGP5) /* ... or request it. */ + { + usingPGP5 = 1; + /* Its sad but true: pgp-5.0 returns also an exit value of 0 */ + /* when it finds a BAD signature. So instead we have to use */ + /* the text output. */ + res = RPMSIG_BAD; + } + else if (! (path = rpmDetectPGPVersion(RPMSIGTAG_PGP)) + || sigTag != RPMSIGTAG_PGP) + path = NULL; /* Fail */ + if (path == NULL) + { + errno = ENOENT; + rpmError(RPMERR_EXEC, + _("Could not run pgp. Use --nopgp to skip PGP checks.")); + _exit(RPMERR_EXEC); + } /* Write out the signature */ { const char *tmppath = rpmGetPath("%{_tmppath}", NULL); sigfile = tempnam(tmppath, "rpmsig"); @@ -473,10 +558,27 @@ static int verifyPGPSignature(const char *datafile, void *sig, if (pgp_path && *pgp_path != '%') dosetenv("PGPPATH", pgp_path, 1); - execlp("pgp", "pgp", - "+batchmode=on", "+verbose=0", - sigfile, datafile, - NULL); + + if (usingPGP5) { + /* Some output (in particular "This signature applies to */ + /* another message") is _always_ written to stderr; we */ + /* want to catch that output, so dup stdout to stderr: */ + int save_stderr = dup(2); + dup2(1, 2); + execlp(path, "pgpv", "+batchmode=on", "+verbose=0", + /* Write "Good signature..." to stdout: */ + "+OutputInformationFD=1", + /* Write "WARNING: ... is not trusted to... to stdout: */ + "+OutputWarningFD=1", + sigfile, "-o", datafile, NULL); + /* Restore stderr so we can print the error message below. */ + dup2(save_stderr, 2); + close(save_stderr); + } else { + execlp(path, "pgp", "+batchmode=on", "+verbose=0", + sigfile, datafile, NULL); + } + fprintf(stderr, _("exec failed!\n")); rpmError(RPMERR_EXEC, _("Could not run pgp. Use --nopgp to skip PGP checks.")); @@ -489,12 +591,18 @@ static int verifyPGPSignature(const char *datafile, void *sig, while (fgets(buf, 1024, file)) { if (strncmp("File '", buf, 6) && strncmp("Text is assu", buf, 12) && + strncmp("This signature applies to another message", buf, 41) && buf[0] != '\n') { strcat(result, buf); } - if (!strncmp("WARNING: Can't find the right public key", buf, 40)) { + if (!strncmp("WARNING: Can't find the right public key", buf, 40)) res = RPMSIG_NOKEY; - } + else if (!strncmp("Signature by unknown keyid:", buf, 27)) + res = RPMSIG_NOKEY; + else if (!strncmp("WARNING: The signing key is not trusted", buf, 39)) + res = RPMSIG_NOTTRUSTED; + else if (!strncmp("Good signature", buf, 14)) + res = RPMSIG_OK; } fclose(file); @@ -534,7 +642,6 @@ static int verifyGPGSignature(const char *datafile, void *sig, close(outpipe[0]); /* gpg version 0.9 sends its output to stderr. */ - close(STDERR_FILENO); /* XXX unnecessary */ dup2(outpipe[1], STDERR_FILENO); if (gpg_path && *gpg_path != '%') @@ -554,7 +661,7 @@ static int verifyGPGSignature(const char *datafile, void *sig, file = fdopen(outpipe[0], "r"); result[0] = '\0'; while (fgets(buf, 1024, file)) { - strcat(result, buf); + strcat(result, buf); if (!strncmp("gpg: Can't check signature: Public key not found", buf, 48)) { res = RPMSIG_NOKEY; } @@ -581,36 +688,36 @@ char *rpmGetPassPhrase(const char *prompt, const int sigTag) aok = (name && *name != '%'); xfree(name); } - if (!aok) { - rpmError(RPMERR_SIGGEN, - _("You must set \"%%_gpg_name\" in your macro file")); - return NULL; - } - break; + if (!aok) { + rpmError(RPMERR_SIGGEN, + _("You must set \"%%_gpg_name\" in your macro file")); + return NULL; + } + break; case RPMSIGTAG_PGP: + case RPMSIGTAG_PGP5: { const char *name = rpmExpand("%{_pgp_name}", NULL); aok = (name && *name != '%'); xfree(name); } - if (!aok) { - rpmError(RPMERR_SIGGEN, - _("You must set \"%%_pgp_name\" in your macro file")); + if (!aok) { + rpmError(RPMERR_SIGGEN, + _("You must set \"%%_pgp_name\" in your macro file")); return NULL; - } - break; + } + break; default: - /* Currently the calling function (rpm.c:main) is checking this and - * doing a better job. This section should never be accessed. - */ - rpmError(RPMERR_SIGGEN, - _("Invalid signature spec in rc file")); - return NULL; + /* Currently the calling function (rpm.c:main) is checking this and + * doing a better job. This section should never be accessed. + */ + rpmError(RPMERR_SIGGEN, _("Invalid signature spec in rc file")); + return NULL; } if (prompt) { - pass = getpass(prompt); + pass = getpass(prompt); } else { - pass = getpass(""); + pass = getpass(""); } if (checkPassPhrase(pass, sigTag)) { @@ -623,7 +730,6 @@ char *rpmGetPassPhrase(const char *prompt, const int sigTag) static int checkPassPhrase(const char *passPhrase, const int sigType) { int passPhrasePipe[2]; - FILE *fpipe; int pid, status; int fd; @@ -631,14 +737,17 @@ static int checkPassPhrase(const char *passPhrase, const int sigType) if (!(pid = fork())) { close(STDIN_FILENO); close(STDOUT_FILENO); + close(passPhrasePipe[1]); if (! rpmIsVerbose()) { close(STDERR_FILENO); } if ((fd = open("/dev/null", O_RDONLY)) != STDIN_FILENO) { dup2(fd, STDIN_FILENO); + close(fd); } if ((fd = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) { dup2(fd, STDOUT_FILENO); + close(fd); } dup2(passPhrasePipe[0], 3); @@ -656,15 +765,27 @@ static int checkPassPhrase(const char *passPhrase, const int sigType) _exit(RPMERR_EXEC); } break; case RPMSIGTAG_PGP: + case RPMSIGTAG_PGP5: { const char *pgp_path = rpmExpand("%{_pgp_path}", NULL); const char *name = rpmExpand("+myname=\"%{_pgp_name}\"", NULL); + const char *path; + dosetenv("PGPPASSFD", "3", 1); if (pgp_path && *pgp_path != '%') dosetenv("PGPPATH", pgp_path, 1); - execlp("pgp", "pgp", - "+batchmode=on", "+verbose=0", - name, "-sf", - NULL); + + if ((path = rpmDetectPGPVersion(sigTag)) != NULL { + switch(sigTag) { + case RPMSIGTAG_PGP: + execlp(path, "pgp", "+batchmode=on", "+verbose=0", + name, "-sf", NULL); + break; + case RPMSIGTAG_PGP5: + execlp(path,"pgps", "+batchmode=on", "+verbose=0", + name, "-f", file, NULL); + break; + } + } rpmError(RPMERR_EXEC, _("Couldn't exec pgp")); _exit(RPMERR_EXEC); } break; @@ -675,10 +796,10 @@ static int checkPassPhrase(const char *passPhrase, const int sigType) } } - fpipe = fdopen(passPhrasePipe[1], "w"); close(passPhrasePipe[0]); - fprintf(fpipe, "%s\n", passPhrase); - fclose(fpipe); + write(passPhrasePipe[1], passPhrase, strlen(passPhrase)); + write(passPhrasePipe[1], "\n", 1); + close(passPhrasePipe[1]); (void)waitpid(pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status)) { diff --git a/lib/signature.h b/lib/signature.h index 66bc12708..f7ac50aba 100644 --- a/lib/signature.h +++ b/lib/signature.h @@ -49,4 +49,7 @@ int rpmLookupSignatureType(void); /* Utility to read a pass phrase from the user */ char *rpmGetPassPhrase(const char *prompt, const int sigTag); +/* Return path to pgp executable of given type, or NULL when not found */ +const char *rpmDetectPGPVersion(int sigType); + #endif /* H_SIGNATURE */ diff --git a/macros.in b/macros.in index b46cadbe1..3fb91d87b 100644 --- a/macros.in +++ b/macros.in @@ -1,4 +1,4 @@ -# $Id: macros.in,v 1.16 1999/03/20 21:09:50 jbj Exp $ +# $Id: macros.in,v 1.17 1999/03/21 18:43:26 jbj Exp $ #============================================================================== # Macro naming conventions (preliminary): # @@ -54,6 +54,7 @@ # %_gzipbin @GZIPBIN@ %_instchangelog 5 +%_pgpbin @PGPBIN@ %_rpmdir %{_topdir}/RPMS # # XXX Note escaped %% for use in headerSprintf diff --git a/rpm.c b/rpm.c index 3880dda78..a9dcbd727 100755 --- a/rpm.c +++ b/rpm.c @@ -1101,21 +1101,43 @@ int main(int argc, char ** argv) { if (poptPeekArg(optCon)) { switch (sigTag = rpmLookupSignatureType()) { - case RPMSIGTAG_GPG: /* Fall Through */ + case 0: + break; + case RPMSIGTAG_GPG: case RPMSIGTAG_PGP: - if (!(passPhrase = + case RPMSIGTAG_PGP5: + if (sigTag == RPMSIGTAG_PGP + && !rpmDetectPGPVersion(RPMSIGTAG_PGP)) { + fprintf(stderr, _("pgp not found: ")); + if (rpmDetectPGPVersion(RPMSIGTAG_PGP5)) { + fprintf(stderr, + _("Use `signature: pgp5' instead of `signature: pgp' in spec file.\n")); + exit(EXIT_FAILURE); + } + /* Fall through to default: */ + } + else if (sigTag == RPMSIGTAG_PGP5 + && !rpmDetectPGPVersion(RPMSIGTAG_PGP5)) { + fprintf(stderr, _("pgp version 5 not found: ")); + if (rpmDetectPGPVersion(RPMSIGTAG_PGP)) { + fprintf(stderr, + _("Use `signature: pgp' instead of `signature: pgp5' in spec file.\n")); + exit(EXIT_FAILURE); + } + /* Fall through to default: */ + } + else if (!(passPhrase = rpmGetPassPhrase("Enter pass phrase: ", sigTag))) { fprintf(stderr, _("Pass phrase check failed\n")); exit(EXIT_FAILURE); } else { fprintf(stderr, _("Pass phrase is good.\n")); passPhrase = strdup(passPhrase); + break; } - break; - case 0: - break; + /* Fall through */ default: - fprintf(stderr, "Invalid signature spec in rc file\n"); + fprintf(stderr, _("Invalid signature spec in rc file.\n")); exit(EXIT_FAILURE); } }