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

Generated at Thu Apr 19 15:29:44 2001 for rpm by doxygen1.2.6-20010408 written by Dimitri van Heesch, © 1997-2001