Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

lib/signature.c

Go to the documentation of this file.
00001 
00005 /* signature.c - RPM signature functions */
00006 
00007 /* NOTES
00008  *
00009  * Things have been cleaned up wrt PGP.  We can now handle
00010  * signatures of any length (which means you can use any
00011  * size key you like).  We also honor PGPPATH finally.
00012  */
00013 
00014 #include "system.h"
00015 
00016 #if HAVE_ASM_BYTEORDER_H
00017 #include <asm/byteorder.h>
00018 #endif
00019 
00020 #include <rpmlib.h>
00021 #include <rpmmacro.h>   /* XXX for rpmGetPath() */
00022 
00023 #include "md5.h"
00024 #include "misc.h"       /* XXX for dosetenv() and makeTempFile() */
00025 #include "rpmlead.h"
00026 #include "signature.h"
00027 #include "debug.h"
00028 
00029 /*@access Header@*/             /* XXX compared with NULL */
00030 /*@access FD_t@*/               /* XXX compared with NULL */
00031 
00032 typedef unsigned char byte;
00033 
00034 typedef int (*md5func)(const char * fn, /*@out@*/ byte * digest);
00035 
00036 int rpmLookupSignatureType(int action)
00037 {
00038     static int disabled = 0;
00039     int rc = 0;
00040 
00041     switch (action) {
00042     case RPMLOOKUPSIG_DISABLE:
00043         disabled = -2;
00044         break;
00045     case RPMLOOKUPSIG_ENABLE:
00046         disabled = 0;
00047         /*@fallthrough@*/
00048     case RPMLOOKUPSIG_QUERY:
00049         if (disabled)
00050             break;      /* Disabled */
00051       { const char *name = rpmExpand("%{_signature}", NULL);
00052         if (!(name && *name != '%'))
00053             rc = 0;
00054         else if (!xstrcasecmp(name, "none"))
00055             rc = 0;
00056         else if (!xstrcasecmp(name, "pgp"))
00057             rc = RPMSIGTAG_PGP;
00058         else if (!xstrcasecmp(name, "pgp5"))    /* XXX legacy */
00059             rc = RPMSIGTAG_PGP;
00060         else if (!xstrcasecmp(name, "gpg"))
00061             rc = RPMSIGTAG_GPG;
00062         else
00063             rc = -1;    /* Invalid %_signature spec in macro file */
00064         name = _free(name);
00065       } break;
00066     }
00067     return rc;
00068 }
00069 
00070 /* rpmDetectPGPVersion() returns the absolute path to the "pgp"  */
00071 /* executable of the requested version, or NULL when none found. */
00072 
00073 const char * rpmDetectPGPVersion(pgpVersion * pgpVer)
00074 {
00075     /* Actually this should support having more then one pgp version. */ 
00076     /* At the moment only one version is possible since we only       */
00077     /* have one %_pgpbin and one %_pgp_path.                          */
00078 
00079     static pgpVersion saved_pgp_version = PGP_UNKNOWN;
00080     const char *pgpbin = rpmGetPath("%{_pgpbin}", NULL);
00081 
00082     if (saved_pgp_version == PGP_UNKNOWN) {
00083         char *pgpvbin;
00084         struct stat st;
00085         
00086         if (!(pgpbin && pgpbin[0] != '%')) {
00087           pgpbin = _free(pgpbin);
00088           saved_pgp_version = -1;
00089           return NULL;
00090         }
00091         pgpvbin = (char *)alloca(strlen(pgpbin) + sizeof("v"));
00092         (void)stpcpy(stpcpy(pgpvbin, pgpbin), "v");
00093 
00094         if (stat(pgpvbin, &st) == 0)
00095           saved_pgp_version = PGP_5;
00096         else if (stat(pgpbin, &st) == 0)
00097           saved_pgp_version = PGP_2;
00098         else
00099           saved_pgp_version = PGP_NOTDETECTED;
00100     }
00101 
00102     if (pgpVer && pgpbin)
00103         *pgpVer = saved_pgp_version;
00104     return pgpbin;
00105 }
00106 
00116 static inline rpmRC checkSize(FD_t fd, int siglen, int pad, int datalen)
00117         /*@modifies fileSystem @*/
00118 {
00119     struct stat st;
00120     rpmRC rc;
00121 
00122     if (fstat(Fileno(fd), &st))
00123         return RPMRC_FAIL;
00124 
00125     if (!S_ISREG(st.st_mode)) {
00126         rpmMessage(RPMMESS_DEBUG,
00127             _("file is not regular -- skipping size check\n"));
00128         return RPMRC_OK;
00129     }
00130 
00131     rc = (((sizeof(struct rpmlead) + siglen + pad + datalen) - st.st_size)
00132         ? RPMRC_BADSIZE : RPMRC_OK);
00133 
00134     rpmMessage((rc == RPMRC_OK ? RPMMESS_DEBUG : RPMMESS_WARNING),
00135         _("Expected size: %12d = lead(%d)+sigs(%d)+pad(%d)+data(%d)\n"),
00136                 (int)sizeof(struct rpmlead)+siglen+pad+datalen,
00137                 (int)sizeof(struct rpmlead), siglen, pad, datalen);
00138     rpmMessage((rc == RPMRC_OK ? RPMMESS_DEBUG : RPMMESS_WARNING),
00139         _("  Actual size: %12d\n"), (int)st.st_size);
00140 
00141     return rc;
00142 }
00143 
00144 rpmRC rpmReadSignature(FD_t fd, Header * headerp, sigType sig_type)
00145 {
00146     byte buf[2048];
00147     int sigSize, pad;
00148     int_32 type, count;
00149     int_32 *archSize;
00150     Header h = NULL;
00151     rpmRC rc = RPMRC_FAIL;              /* assume failure */
00152 
00153     if (headerp)
00154         *headerp = NULL;
00155 
00156     switch (sig_type) {
00157     case RPMSIGTYPE_NONE:
00158         rpmMessage(RPMMESS_DEBUG, _("No signature\n"));
00159         rc = RPMRC_OK;
00160         break;
00161     case RPMSIGTYPE_PGP262_1024:
00162         rpmMessage(RPMMESS_DEBUG, _("Old PGP signature\n"));
00163         /* These are always 256 bytes */
00164         if (timedRead(fd, buf, 256) != 256)
00165             break;
00166         h = headerNew();
00167         (void) headerAddEntry(h, RPMSIGTAG_PGP, RPM_BIN_TYPE, buf, 152);
00168         rc = RPMRC_OK;
00169         break;
00170     case RPMSIGTYPE_MD5:
00171     case RPMSIGTYPE_MD5_PGP:
00172         rpmError(RPMERR_BADSIGTYPE,
00173               _("Old (internal-only) signature!  How did you get that!?\n"));
00174         break;
00175     case RPMSIGTYPE_HEADERSIG:
00176     case RPMSIGTYPE_DISABLE:
00177         /* This is a new style signature */
00178         h = headerRead(fd, HEADER_MAGIC_YES);
00179         if (h == NULL)
00180             break;
00181 
00182         rc = RPMRC_OK;
00183         sigSize = headerSizeof(h, HEADER_MAGIC_YES);
00184 
00185         /* XXX Legacy headers have a HEADER_IMAGE tag added. */
00186         if (headerIsEntry(h, RPMTAG_HEADERIMAGE))
00187             sigSize -= (16 + 16);
00188 
00189         pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
00190         if (sig_type == RPMSIGTYPE_HEADERSIG) {
00191             if (! headerGetEntry(h, RPMSIGTAG_SIZE, &type,
00192                                 (void **)&archSize, &count))
00193                 break;
00194             rc = checkSize(fd, sigSize, pad, *archSize);
00195         }
00196         if (pad && timedRead(fd, buf, pad) != pad)
00197             rc = RPMRC_SHORTREAD;
00198         break;
00199     default:
00200         break;
00201     }
00202 
00203     if (rc == 0 && headerp)
00204         /*@-nullderef@*/
00205         *headerp = h;
00206         /*@=nullderef@*/
00207     else if (h)
00208         h = headerFree(h);
00209 
00210     return rc;
00211 }
00212 
00213 int rpmWriteSignature(FD_t fd, Header h)
00214 {
00215     static byte buf[8] = "\000\000\000\000\000\000\000\000";
00216     int sigSize, pad;
00217     int rc;
00218     
00219     rc = headerWrite(fd, h, HEADER_MAGIC_YES);
00220     if (rc)
00221         return rc;
00222 
00223     sigSize = headerSizeof(h, HEADER_MAGIC_YES);
00224     pad = (8 - (sigSize % 8)) % 8;
00225     if (pad) {
00226         if (Fwrite(buf, sizeof(buf[0]), pad, fd) != pad)
00227             rc = 1;
00228     }
00229     rpmMessage(RPMMESS_DEBUG, _("Signature: size(%d)+pad(%d)\n"), sigSize, pad);
00230     return rc;
00231 }
00232 
00233 Header rpmNewSignature(void)
00234 {
00235     Header h = headerNew();
00236     return h;
00237 }
00238 
00239 Header rpmFreeSignature(Header h)
00240 {
00241     return headerFree(h);
00242 }
00243 
00244 static int makePGPSignature(const char * file, /*@out@*/ void ** sig,
00245                 /*@out@*/ int_32 * size, /*@null@*/ const char * passPhrase)
00246         /*@modifies *sig, *size, fileSystem @*/
00247 {
00248     char * sigfile = alloca(1024);
00249     int pid, status;
00250     int inpipe[2];
00251     struct stat st;
00252 
00253     (void) stpcpy( stpcpy(sigfile, file), ".sig");
00254 
00255     inpipe[0] = inpipe[1] = 0;
00256     (void) pipe(inpipe);
00257     
00258     if (!(pid = fork())) {
00259         const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
00260         const char *name = rpmExpand("+myname=\"%{_pgp_name}\"", NULL);
00261         const char *path;
00262         pgpVersion pgpVer;
00263 
00264         (void) close(STDIN_FILENO);
00265         (void) dup2(inpipe[0], 3);
00266         (void) close(inpipe[1]);
00267 
00268         (void) dosetenv("PGPPASSFD", "3", 1);
00269         if (pgp_path && *pgp_path != '%')
00270             (void) dosetenv("PGPPATH", pgp_path, 1);
00271 
00272         /* dosetenv("PGPPASS", passPhrase, 1); */
00273 
00274         if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
00275             switch(pgpVer) {
00276             case PGP_2:
00277                 (void) execlp(path, "pgp", "+batchmode=on", "+verbose=0", "+armor=off",
00278                     name, "-sb", file, sigfile, NULL);
00279                 break;
00280             case PGP_5:
00281                 (void) execlp(path,"pgps", "+batchmode=on", "+verbose=0", "+armor=off",
00282                     name, "-b", file, "-o", sigfile, NULL);
00283                 break;
00284             case PGP_UNKNOWN:
00285             case PGP_NOTDETECTED:
00286                 break;
00287             }
00288         }
00289         rpmError(RPMERR_EXEC, _("Couldn't exec pgp (%s)\n"),
00290                         (path ? path : NULL));
00291         _exit(RPMERR_EXEC);
00292     }
00293 
00294     (void) close(inpipe[0]);
00295     if (passPhrase)
00296         (void) write(inpipe[1], passPhrase, strlen(passPhrase));
00297     (void) write(inpipe[1], "\n", 1);
00298     (void) close(inpipe[1]);
00299 
00300     (void)waitpid(pid, &status, 0);
00301     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00302         rpmError(RPMERR_SIGGEN, _("pgp failed\n"));
00303         return 1;
00304     }
00305 
00306     if (stat(sigfile, &st)) {
00307         /* PGP failed to write signature */
00308         if (sigfile) (void) unlink(sigfile);  /* Just in case */
00309         rpmError(RPMERR_SIGGEN, _("pgp failed to write signature\n"));
00310         return 1;
00311     }
00312 
00313     *size = st.st_size;
00314     rpmMessage(RPMMESS_DEBUG, _("PGP sig size: %d\n"), *size);
00315     *sig = xmalloc(*size);
00316     
00317     {   FD_t fd;
00318         int rc = 0;
00319         fd = Fopen(sigfile, "r.fdio");
00320         if (fd != NULL && !Ferror(fd)) {
00321             rc = timedRead(fd, *sig, *size);
00322             if (sigfile) (void) unlink(sigfile);
00323             (void) Fclose(fd);
00324         }
00325         if (rc != *size) {
00326             *sig = _free(*sig);
00327             rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
00328             return 1;
00329         }
00330     }
00331 
00332     rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of PGP sig\n"), *size);
00333     
00334     return 0;
00335 }
00336 
00337 /* This is an adaptation of the makePGPSignature function to use GPG instead
00338  * of PGP to create signatures.  I think I've made all the changes necessary,
00339  * but this could be a good place to start looking if errors in GPG signature
00340  * creation crop up.
00341  */
00342 static int makeGPGSignature(const char * file, /*@out@*/ void ** sig,
00343                 /*@out@*/ int_32 * size, /*@null@*/ const char * passPhrase)
00344         /*@modifies *sig, *size, fileSystem @*/
00345 {
00346     char * sigfile = alloca(1024);
00347     int pid, status;
00348     int inpipe[2];
00349     FILE * fpipe;
00350     struct stat st;
00351 
00352     (void) stpcpy( stpcpy(sigfile, file), ".sig");
00353 
00354     inpipe[0] = inpipe[1] = 0;
00355     (void) pipe(inpipe);
00356     
00357     if (!(pid = fork())) {
00358         const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
00359         const char *name = rpmExpand("%{_gpg_name}", NULL);
00360 
00361         (void) close(STDIN_FILENO);
00362         (void) dup2(inpipe[0], 3);
00363         (void) close(inpipe[1]);
00364 
00365         if (gpg_path && *gpg_path != '%')
00366             (void) dosetenv("GNUPGHOME", gpg_path, 1);
00367         (void) execlp("gpg", "gpg",
00368                "--batch", "--no-verbose", "--no-armor", "--passphrase-fd", "3",
00369                "-u", name, "-sbo", sigfile, file,
00370                NULL);
00371         rpmError(RPMERR_EXEC, _("Couldn't exec gpg\n"));
00372         _exit(RPMERR_EXEC);
00373     }
00374 
00375     fpipe = fdopen(inpipe[1], "w");
00376     (void) close(inpipe[0]);
00377     if (fpipe) {
00378         fprintf(fpipe, "%s\n", (passPhrase ? passPhrase : ""));
00379         (void) fclose(fpipe);
00380     }
00381 
00382     (void)waitpid(pid, &status, 0);
00383     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00384         rpmError(RPMERR_SIGGEN, _("gpg failed\n"));
00385         return 1;
00386     }
00387 
00388     if (stat(sigfile, &st)) {
00389         /* GPG failed to write signature */
00390         if (sigfile) (void) unlink(sigfile);  /* Just in case */
00391         rpmError(RPMERR_SIGGEN, _("gpg failed to write signature\n"));
00392         return 1;
00393     }
00394 
00395     *size = st.st_size;
00396     rpmMessage(RPMMESS_DEBUG, _("GPG sig size: %d\n"), *size);
00397     *sig = xmalloc(*size);
00398     
00399     {   FD_t fd;
00400         int rc = 0;
00401         fd = Fopen(sigfile, "r.fdio");
00402         if (fd != NULL && !Ferror(fd)) {
00403             rc = timedRead(fd, *sig, *size);
00404             if (sigfile) (void) unlink(sigfile);
00405             (void) Fclose(fd);
00406         }
00407         if (rc != *size) {
00408             *sig = _free(*sig);
00409             rpmError(RPMERR_SIGGEN, _("unable to read the signature\n"));
00410             return 1;
00411         }
00412     }
00413 
00414     rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of GPG sig\n"), *size);
00415     
00416     return 0;
00417 }
00418 
00419 int rpmAddSignature(Header h, const char * file, int_32 sigTag,
00420                 const char *passPhrase)
00421 {
00422     struct stat st;
00423     int_32 size;
00424     byte buf[16];
00425     void *sig;
00426     int ret = -1;
00427     
00428     switch (sigTag) {
00429     case RPMSIGTAG_SIZE:
00430         (void) stat(file, &st);
00431         size = st.st_size;
00432         ret = 0;
00433         (void) headerAddEntry(h, RPMSIGTAG_SIZE, RPM_INT32_TYPE, &size, 1);
00434         break;
00435     case RPMSIGTAG_MD5:
00436         ret = mdbinfile(file, buf);
00437         if (ret == 0)
00438             (void) headerAddEntry(h, sigTag, RPM_BIN_TYPE, buf, 16);
00439         break;
00440     case RPMSIGTAG_PGP5:        /* XXX legacy */
00441     case RPMSIGTAG_PGP:
00442         rpmMessage(RPMMESS_VERBOSE, _("Generating signature using PGP.\n"));
00443         ret = makePGPSignature(file, &sig, &size, passPhrase);
00444         if (ret == 0)
00445             (void) headerAddEntry(h, sigTag, RPM_BIN_TYPE, sig, size);
00446         break;
00447     case RPMSIGTAG_GPG:
00448         rpmMessage(RPMMESS_VERBOSE, _("Generating signature using GPG.\n"));
00449         ret = makeGPGSignature(file, &sig, &size, passPhrase);
00450         if (ret == 0)
00451             (void) headerAddEntry(h, sigTag, RPM_BIN_TYPE, sig, size);
00452         break;
00453     }
00454 
00455     return ret;
00456 }
00457 
00458 static rpmVerifySignatureReturn
00459 verifySizeSignature(const char * datafile, int_32 size, char * result)
00460         /*@modifies *result, fileSystem @*/
00461 {
00462     struct stat st;
00463 
00464     (void) stat(datafile, &st);
00465     if (size != st.st_size) {
00466         sprintf(result, "Header+Archive size mismatch.\n"
00467                 "Expected %d, saw %d.\n",
00468                 size, (int)st.st_size);
00469         return RPMSIG_BAD;
00470     }
00471 
00472     sprintf(result, "Header+Archive size OK: %d bytes\n", size);
00473     return RPMSIG_OK;
00474 }
00475 
00476 #define X(_x)   (unsigned)((_x) & 0xff)
00477 
00478 static rpmVerifySignatureReturn
00479 verifyMD5Signature(const char * datafile, const byte * sig, 
00480                               char * result, md5func fn)
00481         /*@modifies *result, fileSystem @*/
00482 {
00483     byte md5sum[16];
00484 
00485     (void) fn(datafile, md5sum);
00486     if (memcmp(md5sum, sig, 16)) {
00487         sprintf(result, "MD5 sum mismatch\n"
00488                 "Expected: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
00489                 "%02x%02x%02x%02x%02x\n"
00490                 "Saw     : %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
00491                 "%02x%02x%02x%02x%02x\n",
00492                 X(sig[0]),  X(sig[1]),  X(sig[2]),  X(sig[3]),
00493                 X(sig[4]),  X(sig[5]),  X(sig[6]),  X(sig[7]),
00494                 X(sig[8]),  X(sig[9]),  X(sig[10]), X(sig[11]),
00495                 X(sig[12]), X(sig[13]), X(sig[14]), X(sig[15]),
00496                 X(md5sum[0]),  X(md5sum[1]),  X(md5sum[2]),  X(md5sum[3]),
00497                 X(md5sum[4]),  X(md5sum[5]),  X(md5sum[6]),  X(md5sum[7]),
00498                 X(md5sum[8]),  X(md5sum[9]),  X(md5sum[10]), X(md5sum[11]),
00499                 X(md5sum[12]), X(md5sum[13]), X(md5sum[14]), X(md5sum[15]) );
00500         return RPMSIG_BAD;
00501     }
00502 
00503     sprintf(result, "MD5 sum OK: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
00504                     "%02x%02x%02x%02x%02x\n",
00505             X(md5sum[0]),  X(md5sum[1]),  X(md5sum[2]),  X(md5sum[3]),
00506             X(md5sum[4]),  X(md5sum[5]),  X(md5sum[6]),  X(md5sum[7]),
00507             X(md5sum[8]),  X(md5sum[9]),  X(md5sum[10]), X(md5sum[11]),
00508             X(md5sum[12]), X(md5sum[13]), X(md5sum[14]), X(md5sum[15]) );
00509 
00510     return RPMSIG_OK;
00511 }
00512 
00513 static rpmVerifySignatureReturn
00514 verifyPGPSignature(const char * datafile, const void * sig, int count,
00515                 char * result)
00516         /*@modifies *result, fileSystem @*/
00517 {
00518     int pid, status, outpipe[2];
00519 /*@only@*/ /*@null@*/ const char * sigfile = NULL;
00520     byte buf[BUFSIZ];
00521     FILE *file;
00522     int res = RPMSIG_OK;
00523     const char *path;
00524     pgpVersion pgpVer;
00525 
00526     /* What version do we have? */
00527     if ((path = rpmDetectPGPVersion(&pgpVer)) == NULL) {
00528         errno = ENOENT;
00529         rpmError(RPMERR_EXEC, 
00530                  _("Could not run pgp.  Use --nopgp to skip PGP checks.\n"));
00531         _exit(RPMERR_EXEC);
00532     }
00533 
00534     /*
00535      * Sad but true: pgp-5.0 returns exit value of 0 on bad signature.
00536      * Instead we have to use the text output to detect a bad signature.
00537      */
00538     if (pgpVer == PGP_5)
00539         res = RPMSIG_BAD;
00540 
00541     /* Write out the signature */
00542 #ifdef  DYING
00543   { const char *tmppath = rpmGetPath("%{_tmppath}", NULL);
00544     sigfile = tempnam(tmppath, "rpmsig");
00545     tmppath = _free(tmppath);
00546   }
00547     sfd = Fopen(sigfile, "w.fdio");
00548     if (sfd != NULL && !Ferror(sfd)) {
00549         (void) Fwrite(sig, sizeof(char), count, sfd);
00550         (void) Fclose(sfd);
00551     }
00552 #else
00553     {   FD_t sfd;
00554         if (!makeTempFile(NULL, &sigfile, &sfd)) {
00555             (void) Fwrite(sig, sizeof(char), count, sfd);
00556             (void) Fclose(sfd);
00557             sfd = NULL;
00558         }
00559     }
00560 #endif
00561     if (sigfile == NULL)
00562         return RPMSIG_BAD;
00563 
00564     /* Now run PGP */
00565     outpipe[0] = outpipe[1] = 0;
00566     (void) pipe(outpipe);
00567 
00568     if (!(pid = fork())) {
00569         const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
00570 
00571         (void) close(outpipe[0]);
00572         (void) close(STDOUT_FILENO);    /* XXX unnecessary */
00573         (void) dup2(outpipe[1], STDOUT_FILENO);
00574 
00575         if (pgp_path && *pgp_path != '%')
00576             (void) dosetenv("PGPPATH", pgp_path, 1);
00577 
00578         switch (pgpVer) {
00579         case PGP_5:
00580             /* Some output (in particular "This signature applies to */
00581             /* another message") is _always_ written to stderr; we   */
00582             /* want to catch that output, so dup stdout to stderr:   */
00583         {   int save_stderr = dup(2);
00584             (void) dup2(1, 2);
00585             (void) execlp(path, "pgpv", "+batchmode=on", "+verbose=0",
00586                    /* Write "Good signature..." to stdout: */
00587                    "+OutputInformationFD=1",
00588                    /* Write "WARNING: ... is not trusted to... to stdout: */
00589                    "+OutputWarningFD=1",
00590                    sigfile, "-o", datafile, NULL);
00591             /* Restore stderr so we can print the error message below. */
00592             (void) dup2(save_stderr, 2);
00593             (void) close(save_stderr);
00594         }   break;
00595         case PGP_2:
00596             (void) execlp(path, "pgp", "+batchmode=on", "+verbose=0",
00597                    sigfile, datafile, NULL);
00598             break;
00599         case PGP_UNKNOWN:
00600         case PGP_NOTDETECTED:
00601             break;
00602         }
00603 
00604         rpmError(RPMERR_EXEC, 
00605                  _("Could not run pgp.  Use --nopgp to skip PGP checks.\n"));
00606         _exit(RPMERR_EXEC);
00607     }
00608 
00609     (void) close(outpipe[1]);
00610     file = fdopen(outpipe[0], "r");
00611     result[0] = '\0';
00612     if (file) {
00613         while (fgets(buf, 1024, file)) {
00614             if (strncmp("File '", buf, 6) &&
00615                 strncmp("Text is assu", buf, 12) &&
00616                 strncmp("This signature applies to another message", buf, 41) &&
00617                 buf[0] != '\n') {
00618                 strcat(result, buf);
00619             }
00620             if (!strncmp("WARNING: Can't find the right public key", buf, 40))
00621                 res = RPMSIG_NOKEY;
00622             else if (!strncmp("Signature by unknown keyid:", buf, 27))
00623                 res = RPMSIG_NOKEY;
00624             else if (!strncmp("WARNING: The signing key is not trusted", buf, 39))
00625                 res = RPMSIG_NOTTRUSTED;
00626             else if (!strncmp("Good signature", buf, 14))
00627                 res = RPMSIG_OK;
00628         }
00629         (void) fclose(file);
00630     }
00631 
00632     (void) waitpid(pid, &status, 0);
00633     if (sigfile) (void) unlink(sigfile);
00634     sigfile = _free(sigfile);
00635     if (!res && (!WIFEXITED(status) || WEXITSTATUS(status))) {
00636         res = RPMSIG_BAD;
00637     }
00638     
00639     return res;
00640 }
00641 
00642 static rpmVerifySignatureReturn
00643 verifyGPGSignature(const char * datafile, const void * sig, int count,
00644                 char * result)
00645         /*@modifies *result, fileSystem @*/
00646 {
00647     int pid, status, outpipe[2];
00648 /*@only@*/ /*@null@*/ const char * sigfile = NULL;
00649     byte buf[BUFSIZ];
00650     FILE *file;
00651     int res = RPMSIG_OK;
00652   
00653     /* Write out the signature */
00654 #ifdef  DYING
00655   { const char *tmppath = rpmGetPath("%{_tmppath}", NULL);
00656     sigfile = tempnam(tmppath, "rpmsig");
00657     tmppath = _free(tmppath);
00658   }
00659     sfd = Fopen(sigfile, "w.fdio");
00660     if (sfd != NULL && !Ferror(sfd)) {
00661         (void) Fwrite(sig, sizeof(char), count, sfd);
00662         (void) Fclose(sfd);
00663     }
00664 #else
00665     {   FD_t sfd;
00666         if (!makeTempFile(NULL, &sigfile, &sfd)) {
00667             (void) Fwrite(sig, sizeof(char), count, sfd);
00668             (void) Fclose(sfd);
00669             sfd = NULL;
00670         }
00671     }
00672 #endif
00673     if (sigfile == NULL)
00674         return RPMSIG_BAD;
00675 
00676     /* Now run GPG */
00677     outpipe[0] = outpipe[1] = 0;
00678     (void) pipe(outpipe);
00679 
00680     if (!(pid = fork())) {
00681         const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
00682 
00683         (void) close(outpipe[0]);
00684         /* gpg version 0.9 sends its output to stderr. */
00685         (void) dup2(outpipe[1], STDERR_FILENO);
00686 
00687         if (gpg_path && *gpg_path != '%')
00688             (void) dosetenv("GNUPGHOME", gpg_path, 1);
00689 
00690         (void) execlp("gpg", "gpg",
00691                "--batch", "--no-verbose", 
00692                "--verify", sigfile, datafile,
00693                NULL);
00694         rpmError(RPMERR_EXEC, 
00695                  _("Could not run gpg.  Use --nogpg to skip GPG checks.\n"));
00696         _exit(RPMERR_EXEC);
00697     }
00698 
00699     (void) close(outpipe[1]);
00700     file = fdopen(outpipe[0], "r");
00701     result[0] = '\0';
00702     if (file) {
00703         while (fgets(buf, 1024, file)) {
00704             strcat(result, buf);
00705             if (!xstrncasecmp("gpg: Can't check signature: Public key not found", buf, 48)) {
00706                 res = RPMSIG_NOKEY;
00707             }
00708         }
00709         (void) fclose(file);
00710     }
00711   
00712     (void) waitpid(pid, &status, 0);
00713     if (sigfile) (void) unlink(sigfile);
00714     sigfile = _free(sigfile);
00715     if (!res && (!WIFEXITED(status) || WEXITSTATUS(status))) {
00716         res = RPMSIG_BAD;
00717     }
00718     
00719     return res;
00720 }
00721 
00722 static int checkPassPhrase(const char * passPhrase, const int sigTag)
00723         /*@modifies fileSystem @*/
00724 {
00725     int passPhrasePipe[2];
00726     int pid, status;
00727     int fd;
00728 
00729     passPhrasePipe[0] = passPhrasePipe[1] = 0;
00730     (void) pipe(passPhrasePipe);
00731     if (!(pid = fork())) {
00732         (void) close(STDIN_FILENO);
00733         (void) close(STDOUT_FILENO);
00734         (void) close(passPhrasePipe[1]);
00735         if (! rpmIsVerbose()) {
00736             (void) close(STDERR_FILENO);
00737         }
00738         if ((fd = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
00739             (void) dup2(fd, STDIN_FILENO);
00740             (void) close(fd);
00741         }
00742         if ((fd = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
00743             (void) dup2(fd, STDOUT_FILENO);
00744             (void) close(fd);
00745         }
00746         (void) dup2(passPhrasePipe[0], 3);
00747 
00748         switch (sigTag) {
00749         case RPMSIGTAG_GPG:
00750         {   const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
00751             const char *name = rpmExpand("%{_gpg_name}", NULL);
00752             if (gpg_path && *gpg_path != '%')
00753                 (void) dosetenv("GNUPGHOME", gpg_path, 1);
00754             (void) execlp("gpg", "gpg",
00755                    "--batch", "--no-verbose", "--passphrase-fd", "3",
00756                    "-u", name, "-so", "-",
00757                    NULL);
00758             rpmError(RPMERR_EXEC, _("Couldn't exec gpg\n"));
00759             _exit(RPMERR_EXEC);
00760         }   /*@notreached@*/ break;
00761         case RPMSIGTAG_PGP5:    /* XXX legacy */
00762         case RPMSIGTAG_PGP:
00763         {   const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
00764             const char *name = rpmExpand("+myname=\"%{_pgp_name}\"", NULL);
00765             const char *path;
00766             pgpVersion pgpVer;
00767 
00768             (void) dosetenv("PGPPASSFD", "3", 1);
00769             if (pgp_path && *pgp_path != '%')
00770                 (void) dosetenv("PGPPATH", pgp_path, 1);
00771 
00772             if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
00773                 switch(pgpVer) {
00774                 case PGP_2:
00775                     (void) execlp(path, "pgp", "+batchmode=on", "+verbose=0",
00776                         name, "-sf", NULL);
00777                     break;
00778                 case PGP_5:     /* XXX legacy */
00779                     (void) execlp(path,"pgps", "+batchmode=on", "+verbose=0",
00780                         name, "-f", NULL);
00781                     break;
00782                 case PGP_UNKNOWN:
00783                 case PGP_NOTDETECTED:
00784                     break;
00785                 }
00786             }
00787             rpmError(RPMERR_EXEC, _("Couldn't exec pgp\n"));
00788             _exit(RPMERR_EXEC);
00789         }   /*@notreached@*/ break;
00790         default: /* This case should have been screened out long ago. */
00791             rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
00792             _exit(RPMERR_SIGGEN);
00793             /*@notreached@*/ break;
00794         }
00795     }
00796 
00797     (void) close(passPhrasePipe[0]);
00798     (void) write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
00799     (void) write(passPhrasePipe[1], "\n", 1);
00800     (void) close(passPhrasePipe[1]);
00801 
00802     (void)waitpid(pid, &status, 0);
00803     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00804         return 1;
00805     }
00806 
00807     /* passPhrase is good */
00808     return 0;
00809 }
00810 
00811 char * rpmGetPassPhrase(const char * prompt, const int sigTag)
00812 {
00813     char *pass;
00814     int aok;
00815 
00816     switch (sigTag) {
00817     case RPMSIGTAG_GPG:
00818       { const char *name = rpmExpand("%{_gpg_name}", NULL);
00819         aok = (name && *name != '%');
00820         name = _free(name);
00821       }
00822         if (!aok) {
00823             rpmError(RPMERR_SIGGEN,
00824                 _("You must set \"%%_gpg_name\" in your macro file\n"));
00825             return NULL;
00826         }
00827         break;
00828     case RPMSIGTAG_PGP5:        /* XXX legacy */
00829     case RPMSIGTAG_PGP: 
00830       { const char *name = rpmExpand("%{_pgp_name}", NULL);
00831         aok = (name && *name != '%');
00832         name = _free(name);
00833       }
00834         if (!aok) {
00835             rpmError(RPMERR_SIGGEN,
00836                 _("You must set \"%%_pgp_name\" in your macro file\n"));
00837             return NULL;
00838         }
00839         break;
00840     default:
00841         /* Currently the calling function (rpm.c:main) is checking this and
00842          * doing a better job.  This section should never be accessed.
00843          */
00844         rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
00845         return NULL;
00846         /*@notreached@*/ break;
00847     }
00848 
00849     pass = /*@-unrecog@*/ getpass( (prompt ? prompt : "") ) /*@=unrecog@*/ ;
00850 
00851     if (checkPassPhrase(pass, sigTag))
00852         return NULL;
00853 
00854     return pass;
00855 }
00856 
00857 rpmVerifySignatureReturn
00858 rpmVerifySignature(const char * file, int_32 sigTag, const void * sig,
00859                 int count, char * result)
00860 {
00861     switch (sigTag) {
00862     case RPMSIGTAG_SIZE:
00863         return verifySizeSignature(file, *(int_32 *)sig, result);
00864         /*@notreached@*/ break;
00865     case RPMSIGTAG_MD5:
00866         return verifyMD5Signature(file, sig, result, mdbinfile);
00867         /*@notreached@*/ break;
00868     case RPMSIGTAG_LEMD5_1:
00869     case RPMSIGTAG_LEMD5_2:
00870         return verifyMD5Signature(file, sig, result, mdbinfileBroken);
00871         /*@notreached@*/ break;
00872     case RPMSIGTAG_PGP5:        /* XXX legacy */
00873     case RPMSIGTAG_PGP:
00874         return verifyPGPSignature(file, sig, count, result);
00875         /*@notreached@*/ break;
00876     case RPMSIGTAG_GPG:
00877         return verifyGPGSignature(file, sig, count, result);
00878         /*@notreached@*/ break;
00879     default:
00880         sprintf(result, "Do not know how to verify sig type %d\n", sigTag);
00881         return RPMSIG_UNKNOWN;
00882     }
00883     /*@notreached@*/
00884     return RPMSIG_OK;
00885 }

Generated at Mon Sep 24 10:37:22 2001 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001