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

Generated on Wed Mar 13 15:34:49 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002