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     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         char *t = result;
00656         int nb = 8*BUFSIZ - 1;
00657         while (fgets(buf, 1024, file)) {
00658             if (strncmp("File '", buf, 6) &&
00659                 strncmp("Text is assu", buf, 12) &&
00660                 strncmp("This signature applies to another message", buf, 41) &&
00661                 buf[0] != '\n') {
00662                     nb -= strlen(buf);
00663                     if (nb > 0) t = stpncpy(t, buf, nb);
00664             }
00665             if (!strncmp("WARNING: Can't find the right public key", buf, 40))
00666                 res = RPMSIG_NOKEY;
00667             else if (!strncmp("Signature by unknown keyid:", buf, 27))
00668                 res = RPMSIG_NOKEY;
00669             else if (!strncmp("WARNING: The signing key is not trusted", buf, 39))
00670                 res = RPMSIG_NOTTRUSTED;
00671             else if (!strncmp("Good signature", buf, 14))
00672                 res = RPMSIG_OK;
00673         }
00674         (void) fclose(file);
00675         *t = '\0';
00676     }
00677 
00678     (void) waitpid(pid, &status, 0);
00679     if (sigfile) (void) unlink(sigfile);
00680     sigfile = _free(sigfile);
00681     if (!res && (!WIFEXITED(status) || WEXITSTATUS(status))) {
00682         res = RPMSIG_BAD;
00683     }
00684 
00685     return res;
00686 }
00687 
00688 static rpmVerifySignatureReturn
00689 verifyGPGSignature(const char * datafile, const void * sig, int count,
00690                 /*@out@*/ char * result)
00691         /*@globals rpmGlobalMacroContext, fileSystem @*/
00692         /*@modifies *result, rpmGlobalMacroContext, fileSystem @*/
00693 {
00694     int pid, status, outpipe[2];
00695 /*@only@*/ /*@null@*/ const char * sigfile = NULL;
00696     byte buf[BUFSIZ];
00697     FILE *file;
00698     int res = RPMSIG_OK;
00699     const char * cmd;
00700     char *const *av;
00701     int rc;
00702 
00703     /* Write out the signature */
00704 #ifdef  DYING
00705   { const char *tmppath = rpmGetPath("%{_tmppath}", NULL);
00706     sigfile = tempnam(tmppath, "rpmsig");
00707     tmppath = _free(tmppath);
00708   }
00709     sfd = Fopen(sigfile, "w.fdio");
00710     if (sfd != NULL && !Ferror(sfd)) {
00711         (void) Fwrite(sig, sizeof(char), count, sfd);
00712         (void) Fclose(sfd);
00713     }
00714 #else
00715     {   FD_t sfd;
00716         if (!makeTempFile(NULL, &sigfile, &sfd)) {
00717             (void) Fwrite(sig, sizeof(char), count, sfd);
00718             (void) Fclose(sfd);
00719             sfd = NULL;
00720         }
00721     }
00722 #endif
00723     if (sigfile == NULL)
00724         return RPMSIG_BAD;
00725 
00726     addMacro(NULL, "__plaintext_filename", NULL, datafile, -1);
00727     addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
00728 
00729     /* Now run GPG */
00730     outpipe[0] = outpipe[1] = 0;
00731     (void) pipe(outpipe);
00732 
00733     if (!(pid = fork())) {
00734         const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
00735 
00736         (void) close(outpipe[0]);
00737         /* gpg version 0.9 sends its output to stderr. */
00738         (void) dup2(outpipe[1], STDERR_FILENO);
00739 
00740         if (gpg_path && *gpg_path != '\0')
00741             (void) dosetenv("GNUPGHOME", gpg_path, 1);
00742 
00743         cmd = rpmExpand("%{?__gpg_verify_cmd}", NULL);
00744         rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00745         if (!rc)
00746             rc = execve(av[0], av+1, environ);
00747 
00748         rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg",
00749                         strerror(errno));
00750         _exit(RPMERR_EXEC);
00751     }
00752 
00753     delMacro(NULL, "__plaintext_filename");
00754     delMacro(NULL, "__signature_filename");
00755 
00756     (void) close(outpipe[1]);
00757     file = fdopen(outpipe[0], "r");
00758     result[0] = '\0';
00759     if (file) {
00760         char * t = result;
00761         int nb = 8*BUFSIZ - 1;
00762         while (fgets(buf, 1024, file)) {
00763             nb -= strlen(buf);
00764             if (nb > 0) t = stpncpy(t, buf, nb);
00765             if (!xstrncasecmp("gpg: Can't check signature: Public key not found", buf, 48)) {
00766                 res = RPMSIG_NOKEY;
00767             }
00768         }
00769         (void) fclose(file);
00770         *t = '\0';
00771     }
00772 
00773     (void) waitpid(pid, &status, 0);
00774     if (sigfile) (void) unlink(sigfile);
00775     sigfile = _free(sigfile);
00776     if (!res && (!WIFEXITED(status) || WEXITSTATUS(status))) {
00777         res = RPMSIG_BAD;
00778     }
00779 
00780     return res;
00781 }
00782 
00783 static int checkPassPhrase(const char * passPhrase, const int sigTag)
00784         /*@globals rpmGlobalMacroContext, fileSystem @*/
00785         /*@modifies rpmGlobalMacroContext, fileSystem @*/
00786 {
00787     int passPhrasePipe[2];
00788     int pid, status;
00789     int fd;
00790     const char * cmd;
00791     char *const *av;
00792     int rc;
00793 
00794     passPhrasePipe[0] = passPhrasePipe[1] = 0;
00795     (void) pipe(passPhrasePipe);
00796     if (!(pid = fork())) {
00797         (void) close(STDIN_FILENO);
00798         (void) close(STDOUT_FILENO);
00799         (void) close(passPhrasePipe[1]);
00800         if (! rpmIsVerbose()) {
00801             (void) close(STDERR_FILENO);
00802         }
00803         if ((fd = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
00804             (void) dup2(fd, STDIN_FILENO);
00805             (void) close(fd);
00806         }
00807         if ((fd = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
00808             (void) dup2(fd, STDOUT_FILENO);
00809             (void) close(fd);
00810         }
00811         (void) dup2(passPhrasePipe[0], 3);
00812 
00813         switch (sigTag) {
00814         case RPMSIGTAG_GPG:
00815         {   const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
00816 
00817             if (gpg_path && *gpg_path != '\0')
00818                 (void) dosetenv("GNUPGHOME", gpg_path, 1);
00819 
00820             cmd = rpmExpand("%{?__gpg_check_password_cmd}", NULL);
00821             rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00822             if (!rc)
00823                 rc = execve(av[0], av+1, environ);
00824 
00825             rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg",
00826                         strerror(errno));
00827             _exit(RPMERR_EXEC);
00828         }   /*@notreached@*/ break;
00829         case RPMSIGTAG_PGP5:    /* XXX legacy */
00830         case RPMSIGTAG_PGP:
00831         {   const char *pgp_path = rpmExpand("%{?_pgp_path}", NULL);
00832             const char *path;
00833             pgpVersion pgpVer;
00834 
00835             (void) dosetenv("PGPPASSFD", "3", 1);
00836             if (pgp_path && *pgp_path != '\0')
00837                 (void) dosetenv("PGPPATH", pgp_path, 1);
00838 
00839             if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
00840                 switch(pgpVer) {
00841                 case PGP_2:
00842                     cmd = rpmExpand("%{?__pgp_check_password_cmd}", NULL);
00843                     rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00844                     if (!rc)
00845                         rc = execve(av[0], av+1, environ);
00846                     break;
00847                 case PGP_5:     /* XXX legacy */
00848                     cmd = rpmExpand("%{?__pgp5_check_password_cmd}", NULL);
00849                     rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00850                     if (!rc)
00851                         rc = execve(av[0], av+1, environ);
00852                     break;
00853                 case PGP_UNKNOWN:
00854                 case PGP_NOTDETECTED:
00855                     break;
00856                 }
00857             }
00858             rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "pgp",
00859                         strerror(errno));
00860             _exit(RPMERR_EXEC);
00861         }   /*@notreached@*/ break;
00862         default: /* This case should have been screened out long ago. */
00863             rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
00864             _exit(RPMERR_SIGGEN);
00865             /*@notreached@*/ break;
00866         }
00867     }
00868 
00869     (void) close(passPhrasePipe[0]);
00870     (void) write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
00871     (void) write(passPhrasePipe[1], "\n", 1);
00872     (void) close(passPhrasePipe[1]);
00873 
00874     (void)waitpid(pid, &status, 0);
00875     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00876         return 1;
00877     }
00878 
00879     /* passPhrase is good */
00880     return 0;
00881 }
00882 
00883 char * rpmGetPassPhrase(const char * prompt, const int sigTag)
00884 {
00885     char *pass;
00886     int aok;
00887 
00888     switch (sigTag) {
00889     case RPMSIGTAG_GPG:
00890       { const char *name = rpmExpand("%{?_gpg_name}", NULL);
00891         aok = (name && *name != '\0');
00892         name = _free(name);
00893       }
00894         if (!aok) {
00895             rpmError(RPMERR_SIGGEN,
00896                 _("You must set \"%%_gpg_name\" in your macro file\n"));
00897             return NULL;
00898         }
00899         break;
00900     case RPMSIGTAG_PGP5:        /* XXX legacy */
00901     case RPMSIGTAG_PGP:
00902       { const char *name = rpmExpand("%{?_pgp_name}", NULL);
00903         aok = (name && *name != '\0');
00904         name = _free(name);
00905       }
00906         if (!aok) {
00907             rpmError(RPMERR_SIGGEN,
00908                 _("You must set \"%%_pgp_name\" in your macro file\n"));
00909             return NULL;
00910         }
00911         break;
00912     default:
00913         /* Currently the calling function (rpm.c:main) is checking this and
00914          * doing a better job.  This section should never be accessed.
00915          */
00916         rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n"));
00917         return NULL;
00918         /*@notreached@*/ break;
00919     }
00920 
00921     pass = /*@-unrecog@*/ getpass( (prompt ? prompt : "") ) /*@=unrecog@*/ ;
00922 
00923     if (checkPassPhrase(pass, sigTag))
00924         return NULL;
00925 
00926     return pass;
00927 }
00928 
00929 rpmVerifySignatureReturn
00930 rpmVerifySignature(const char * file, int_32 sigTag, const void * sig,
00931                 int count, char * result)
00932 {
00933      rpmVerifySignatureReturn res;
00934 
00935     switch (sigTag) {
00936     case RPMSIGTAG_SIZE:
00937         res = verifySizeSignature(file, *(int_32 *)sig, result);
00938         break;
00939     case RPMSIGTAG_MD5:
00940         res = verifyMD5Signature(file, sig, result, mdbinfile);
00941         break;
00942     case RPMSIGTAG_PGP5:        /* XXX legacy */
00943     case RPMSIGTAG_PGP:
00944         res = verifyPGPSignature(file, sig, count, result);
00945         break;
00946     case RPMSIGTAG_GPG:
00947         res = verifyGPGSignature(file, sig, count, result);
00948         break;
00949     case RPMSIGTAG_LEMD5_1:
00950     case RPMSIGTAG_LEMD5_2:
00951         sprintf(result, _("Broken MD5 digest: UNSUPPORTED\n"));
00952         res = RPMSIG_UNKNOWN;
00953         break;
00954     default:
00955         sprintf(result, "Do not know how to verify sig type %d\n", sigTag);
00956         res = RPMSIG_UNKNOWN;
00957         break;
00958     }
00959     return res;
00960 }

Generated on Thu Apr 18 17:34:43 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002