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

Generated on Sun Oct 17 02:12:49 2004 for rpm by doxygen 1.3.6