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

Generated at Tue Dec 23 04:54:12 2003 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001