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

Generated at Sun Apr 8 18:43:01 2001 for rpm by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000