- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

# 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 }