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

Generated at Fri Feb 15 10:35:59 2002 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001