fix: with unspecified epochs, skip dependency epoch compare.
[platform/upstream/rpm.git] / lib / signature.c
1 /* signature.c - RPM signature functions */
2
3 /* NOTES
4  *
5  * Things have been cleaned up wrt PGP.  We can now handle
6  * signatures of any length (which means you can use any
7  * size key you like).  We also honor PGPPATH finally.
8  */
9
10 #include "system.h"
11
12 #if HAVE_ASM_BYTEORDER_H
13 #include <asm/byteorder.h>
14 #endif
15
16 #include <rpmlib.h>
17 #include <rpmmacro.h>   /* XXX for rpmGetPath */
18
19 #include "md5.h"
20 #include "misc.h"
21 #include "rpmlead.h"
22 #include "signature.h"
23
24 typedef int (*md5func)(const char * fn, unsigned char * digest);
25
26 int rpmLookupSignatureType(int action)
27 {
28     static int disabled = 0;
29     int rc = 0;
30
31     switch (action) {
32     case RPMLOOKUPSIG_DISABLE:
33         disabled = -2;
34         break;
35     case RPMLOOKUPSIG_ENABLE:
36         disabled = 0;
37         /* fall through */
38     case RPMLOOKUPSIG_QUERY:
39         if (disabled)
40             break;      /* Disabled */
41       { const char *name = rpmExpand("%{_signature}", NULL);
42         if (!(name && *name != '%'))
43             rc = 0;
44         else if (!strcasecmp(name, "none"))
45             rc = 0;
46         else if (!strcasecmp(name, "pgp"))
47             rc = RPMSIGTAG_PGP;
48         else if (!strcasecmp(name, "pgp5"))     /* XXX legacy */
49             rc = RPMSIGTAG_PGP;
50         else if (!strcasecmp(name, "gpg"))
51             rc = RPMSIGTAG_GPG;
52         else
53             rc = -1;    /* Invalid %_signature spec in macro file */
54         xfree(name);
55       } break;
56     }
57     return rc;
58 }
59
60 /* rpmDetectPGPVersion() returns the absolute path to the "pgp"  */
61 /* executable of the requested version, or NULL when none found. */
62
63 const char * rpmDetectPGPVersion(pgpVersion *pgpVer)
64 {
65     /* Actually this should support having more then one pgp version. */ 
66     /* At the moment only one version is possible since we only       */
67     /* have one %_pgpbin and one %_pgp_path.                          */
68
69     static pgpVersion saved_pgp_version = PGP_UNKNOWN;
70     const char *pgpbin = rpmGetPath("%{_pgpbin}", NULL);
71
72     if (saved_pgp_version == PGP_UNKNOWN) {
73         char *pgpvbin;
74         struct stat statbuf;
75         
76         if (!pgpbin || ! (pgpvbin = (char *)alloca(strlen(pgpbin) + 2))) {
77           saved_pgp_version = -1;
78           return NULL;
79         }
80         sprintf(pgpvbin, "%sv", pgpbin);
81
82         if (stat(pgpvbin, &statbuf) == 0)
83           saved_pgp_version = PGP_5;
84         else if (stat(pgpbin, &statbuf) == 0)
85           saved_pgp_version = PGP_2;
86         else
87           saved_pgp_version = PGP_NOTDETECTED;
88     }
89
90     if (pgpbin && pgpVer)
91         *pgpVer = saved_pgp_version;
92     return pgpbin;
93 }
94
95 static int checkSize(FD_t fd, int size, int sigsize)
96 {
97     int headerArchiveSize;
98     struct stat statbuf;
99
100     fstat(fdFileno(fd), &statbuf);
101
102     if (S_ISREG(statbuf.st_mode)) {
103         headerArchiveSize = statbuf.st_size - sizeof(struct rpmlead) - sigsize;
104
105         rpmMessage(RPMMESS_DEBUG, _("sigsize         : %d\n"), sigsize);
106         rpmMessage(RPMMESS_DEBUG, _("Header + Archive: %d\n"), headerArchiveSize);
107         rpmMessage(RPMMESS_DEBUG, _("expected size   : %d\n"), size);
108
109         return size - headerArchiveSize;
110     } else {
111         rpmMessage(RPMMESS_DEBUG, _("file is not regular -- skipping size check\n"));
112         return 0;
113     }
114 }
115
116 /* rpmReadSignature() emulates the new style signatures if it finds an */
117 /* old-style one.  It also immediately verifies the header+archive  */
118 /* size and returns an error if it doesn't match.                   */
119
120 int rpmReadSignature(FD_t fd, Header *headerp, short sig_type)
121 {
122     unsigned char buf[2048];
123     int sigSize, pad;
124     int_32 type, count;
125     int_32 *archSize;
126     Header h;
127
128     if (headerp)
129         *headerp = NULL;
130     
131     switch (sig_type) {
132       case RPMSIG_NONE:
133         rpmMessage(RPMMESS_DEBUG, _("No signature\n"));
134         break;
135       case RPMSIG_PGP262_1024:
136         rpmMessage(RPMMESS_DEBUG, _("Old PGP signature\n"));
137         /* These are always 256 bytes */
138         if (timedRead(fd, buf, 256) != 256)
139             return 1;
140         if (headerp) {
141             *headerp = headerNew();
142             headerAddEntry(*headerp, RPMSIGTAG_PGP, RPM_BIN_TYPE, buf, 152);
143         }
144         break;
145       case RPMSIG_MD5:
146       case RPMSIG_MD5_PGP:
147         rpmError(RPMERR_BADSIGTYPE,
148               _("Old (internal-only) signature!  How did you get that!?"));
149         return 1;
150         break;
151       case RPMSIG_HEADERSIG:
152         rpmMessage(RPMMESS_DEBUG, _("New Header signature\n"));
153         /* This is a new style signature */
154         h = headerRead(fd, HEADER_MAGIC_YES);
155         if (h == NULL)
156             return 1;
157         sigSize = headerSizeof(h, HEADER_MAGIC_YES);
158         pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
159         rpmMessage(RPMMESS_DEBUG, _("Signature size: %d\n"), sigSize);
160         rpmMessage(RPMMESS_DEBUG, _("Signature pad : %d\n"), pad);
161         if (! headerGetEntry(h, RPMSIGTAG_SIZE, &type, (void **)&archSize, &count)) {
162             headerFree(h);
163             return 1;
164         }
165         if (checkSize(fd, *archSize, sigSize + pad)) {
166             headerFree(h);
167             return 1;
168         }
169         if (pad) {
170             if (timedRead(fd, buf, pad) != pad) {
171                 headerFree(h);
172                 return 1;
173             }
174         }
175         if (headerp) {
176             *headerp = h;
177         } else {
178             headerFree(h);
179         }
180         break;
181       default:
182         return 1;
183     }
184
185     return 0;
186 }
187
188 int rpmWriteSignature(FD_t fd, Header header)
189 {
190     int sigSize, pad;
191     unsigned char buf[8];
192     int rc = 0;
193     
194     rc = headerWrite(fd, header, HEADER_MAGIC_YES);
195     if (rc)
196         return rc;
197
198     sigSize = headerSizeof(header, HEADER_MAGIC_YES);
199     pad = (8 - (sigSize % 8)) % 8;
200     if (pad) {
201         rpmMessage(RPMMESS_DEBUG, _("Signature size: %d\n"), sigSize);
202         rpmMessage(RPMMESS_DEBUG, _("Signature pad : %d\n"), pad);
203         memset(buf, 0, pad);
204         if (fdWrite(fd, buf, pad) != pad)
205             rc = 1;
206     }
207     return rc;
208 }
209
210 Header rpmNewSignature(void)
211 {
212     return headerNew();
213 }
214
215 void rpmFreeSignature(Header h)
216 {
217     headerFree(h);
218 }
219
220 static int makePGPSignature(const char *file, void **sig, int_32 *size,
221                             const char *passPhrase)
222 {
223     char sigfile[1024];
224     int pid, status;
225     int inpipe[2];
226     struct stat statbuf;
227
228     sprintf(sigfile, "%s.sig", file);
229
230     pipe(inpipe);
231     
232     if (!(pid = fork())) {
233         const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
234         const char *name = rpmExpand("+myname=\"%{_pgp_name}\"", NULL);
235         const char *path;
236         pgpVersion pgpVer;
237
238         close(STDIN_FILENO);
239         dup2(inpipe[0], 3);
240         close(inpipe[1]);
241
242         dosetenv("PGPPASSFD", "3", 1);
243         if (pgp_path && *pgp_path != '%')
244             dosetenv("PGPPATH", pgp_path, 1);
245
246         /* dosetenv("PGPPASS", passPhrase, 1); */
247
248         if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
249             switch(pgpVer) {
250             case PGP_2:
251                 execlp(path, "pgp", "+batchmode=on", "+verbose=0", "+armor=off",
252                     name, "-sb", file, sigfile, NULL);
253                 break;
254             case PGP_5:
255                 execlp(path,"pgps", "+batchmode=on", "+verbose=0", "+armor=off",
256                     name, "-b", file, "-o", sigfile, NULL);
257                 break;
258             case PGP_UNKNOWN:
259             case PGP_NOTDETECTED:
260                 break;
261             }
262         }
263         rpmError(RPMERR_EXEC, _("Couldn't exec pgp (%s)"), path);
264         _exit(RPMERR_EXEC);
265     }
266
267     close(inpipe[0]);
268     write(inpipe[1], passPhrase, strlen(passPhrase));
269     write(inpipe[1], "\n", 1);
270     close(inpipe[1]);
271
272     (void)waitpid(pid, &status, 0);
273     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
274         rpmError(RPMERR_SIGGEN, _("pgp failed"));
275         return 1;
276     }
277
278     if (stat(sigfile, &statbuf)) {
279         /* PGP failed to write signature */
280         unlink(sigfile);  /* Just in case */
281         rpmError(RPMERR_SIGGEN, _("pgp failed to write signature"));
282         return 1;
283     }
284
285     *size = statbuf.st_size;
286     rpmMessage(RPMMESS_DEBUG, _("PGP sig size: %d\n"), *size);
287     *sig = malloc(*size);
288     
289     {   FD_t fd;
290         int rc;
291         fd = fdOpen(sigfile, O_RDONLY, 0);
292         rc = timedRead(fd, *sig, *size);
293         unlink(sigfile);
294         fdClose(fd);
295         if (rc != *size) {
296             free(*sig);
297             rpmError(RPMERR_SIGGEN, _("unable to read the signature"));
298             return 1;
299         }
300     }
301
302     rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of PGP sig\n"), *size);
303     
304     return 0;
305 }
306
307 /* This is an adaptation of the makePGPSignature function to use GPG instead
308  * of PGP to create signatures.  I think I've made all the changes necessary,
309  * but this could be a good place to start looking if errors in GPG signature
310  * creation crop up.
311  */
312 static int makeGPGSignature(const char *file, void **sig, int_32 *size,
313                             const char *passPhrase)
314 {
315     char sigfile[1024];
316     int pid, status;
317     int inpipe[2];
318     FILE *fpipe;
319     struct stat statbuf;
320
321     sprintf(sigfile, "%s.sig", file);
322
323     pipe(inpipe);
324     
325     if (!(pid = fork())) {
326         const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
327         const char *name = rpmExpand("%{_gpg_name}", NULL);
328
329         close(STDIN_FILENO);
330         dup2(inpipe[0], 3);
331         close(inpipe[1]);
332
333         if (gpg_path && *gpg_path != '%')
334             dosetenv("GNUPGHOME", gpg_path, 1);
335         execlp("gpg", "gpg",
336                "--batch", "--no-verbose", "--no-armor", "--passphrase-fd", "3",
337                "-u", name, "-sbo", sigfile, file,
338                NULL);
339         rpmError(RPMERR_EXEC, _("Couldn't exec gpg"));
340         _exit(RPMERR_EXEC);
341     }
342
343     fpipe = fdopen(inpipe[1], "w");
344     close(inpipe[0]);
345     fprintf(fpipe, "%s\n", passPhrase);
346     fclose(fpipe);
347
348     (void)waitpid(pid, &status, 0);
349     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
350         rpmError(RPMERR_SIGGEN, _("gpg failed"));
351         return 1;
352     }
353
354     if (stat(sigfile, &statbuf)) {
355         /* GPG failed to write signature */
356         unlink(sigfile);  /* Just in case */
357         rpmError(RPMERR_SIGGEN, _("gpg failed to write signature"));
358         return 1;
359     }
360
361     *size = statbuf.st_size;
362     rpmMessage(RPMMESS_DEBUG, _("GPG sig size: %d\n"), *size);
363     *sig = malloc(*size);
364     
365     {   FD_t fd;
366         int rc;
367         fd = fdOpen(sigfile, O_RDONLY, 0);
368         rc = timedRead(fd, *sig, *size);
369         unlink(sigfile);
370         fdClose(fd);
371         if (rc != *size) {
372             free(*sig);
373             rpmError(RPMERR_SIGGEN, _("unable to read the signature"));
374             return 1;
375         }
376     }
377
378     rpmMessage(RPMMESS_DEBUG, _("Got %d bytes of GPG sig\n"), *size);
379     
380     return 0;
381 }
382
383 int rpmAddSignature(Header header, const char *file, int_32 sigTag, const char *passPhrase)
384 {
385     struct stat statbuf;
386     int_32 size;
387     unsigned char buf[16];
388     void *sig;
389     int ret = -1;
390     
391     switch (sigTag) {
392     case RPMSIGTAG_SIZE:
393         stat(file, &statbuf);
394         size = statbuf.st_size;
395         ret = 0;
396         headerAddEntry(header, RPMSIGTAG_SIZE, RPM_INT32_TYPE, &size, 1);
397         break;
398     case RPMSIGTAG_MD5:
399         ret = mdbinfile(file, buf);
400         if (ret == 0)
401             headerAddEntry(header, sigTag, RPM_BIN_TYPE, buf, 16);
402         break;
403     case RPMSIGTAG_PGP5:        /* XXX legacy */
404     case RPMSIGTAG_PGP:
405         rpmMessage(RPMMESS_VERBOSE, _("Generating signature using PGP.\n"));
406         ret = makePGPSignature(file, &sig, &size, passPhrase);
407         if (ret == 0)
408             headerAddEntry(header, sigTag, RPM_BIN_TYPE, sig, size);
409         break;
410     case RPMSIGTAG_GPG:
411         rpmMessage(RPMMESS_VERBOSE, _("Generating signature using GPG.\n"));
412         ret = makeGPGSignature(file, &sig, &size, passPhrase);
413         if (ret == 0)
414             headerAddEntry(header, sigTag, RPM_BIN_TYPE, sig, size);
415         break;
416     }
417
418     return ret;
419 }
420
421 static int verifySizeSignature(const char *datafile, int_32 size, char *result)
422 {
423     struct stat statbuf;
424
425     stat(datafile, &statbuf);
426     if (size != statbuf.st_size) {
427         sprintf(result, "Header+Archive size mismatch.\n"
428                 "Expected %d, saw %d.\n",
429                 size, (int)statbuf.st_size);
430         return 1;
431     }
432
433     sprintf(result, "Header+Archive size OK: %d bytes\n", size);
434     return 0;
435 }
436
437 static int verifyMD5Signature(const char *datafile, unsigned char *sig, 
438                               char *result, md5func fn)
439 {
440     unsigned char md5sum[16];
441
442     fn(datafile, md5sum);
443     if (memcmp(md5sum, sig, 16)) {
444         sprintf(result, "MD5 sum mismatch\n"
445                 "Expected: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
446                 "%02x%02x%02x%02x%02x\n"
447                 "Saw     : %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
448                 "%02x%02x%02x%02x%02x\n",
449                 sig[0],  sig[1],  sig[2],  sig[3],
450                 sig[4],  sig[5],  sig[6],  sig[7],
451                 sig[8],  sig[9],  sig[10], sig[11],
452                 sig[12], sig[13], sig[14], sig[15],
453                 md5sum[0],  md5sum[1],  md5sum[2],  md5sum[3],
454                 md5sum[4],  md5sum[5],  md5sum[6],  md5sum[7],
455                 md5sum[8],  md5sum[9],  md5sum[10], md5sum[11],
456                 md5sum[12], md5sum[13], md5sum[14], md5sum[15]);
457         return 1;
458     }
459
460     sprintf(result, "MD5 sum OK: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
461                     "%02x%02x%02x%02x%02x\n",
462             md5sum[0],  md5sum[1],  md5sum[2],  md5sum[3],
463             md5sum[4],  md5sum[5],  md5sum[6],  md5sum[7],
464             md5sum[8],  md5sum[9],  md5sum[10], md5sum[11],
465             md5sum[12], md5sum[13], md5sum[14], md5sum[15]);
466
467     return 0;
468 }
469
470 static int verifyPGPSignature(const char *datafile, void *sig,
471                               int count, char *result)
472 {
473     int pid, status, outpipe[2];
474     FD_t sfd;
475     char *sigfile;
476     unsigned char buf[8192];
477     FILE *file;
478     int res = RPMSIG_OK;
479     const char *path;
480     pgpVersion pgpVer;
481
482     /* What version do we have? */
483     if ((path = rpmDetectPGPVersion(&pgpVer)) == NULL) {
484         errno = ENOENT;
485         rpmError(RPMERR_EXEC, 
486                  _("Could not run pgp.  Use --nopgp to skip PGP checks."));
487         _exit(RPMERR_EXEC);
488     }
489
490     /*
491      * Sad but true: pgp-5.0 returns exit value of 0 on bad signature.
492      * Instead we have to use the text output to detect a bad signature.
493      */
494     if (pgpVer == PGP_5)
495         res = RPMSIG_BAD;
496
497     /* Write out the signature */
498   { const char *tmppath = rpmGetPath("%{_tmppath}", NULL);
499     sigfile = tempnam(tmppath, "rpmsig");
500     xfree(tmppath);
501   }
502     sfd = fdOpen(sigfile, O_WRONLY|O_CREAT|O_TRUNC, 0644);
503     (void)fdWrite(sfd, sig, count);
504     fdClose(sfd);
505
506     /* Now run PGP */
507     pipe(outpipe);
508
509     if (!(pid = fork())) {
510         const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
511
512         close(outpipe[0]);
513         close(STDOUT_FILENO);   /* XXX unnecessary */
514         dup2(outpipe[1], STDOUT_FILENO);
515
516         if (pgp_path && *pgp_path != '%')
517             dosetenv("PGPPATH", pgp_path, 1);
518
519         switch (pgpVer) {
520         case PGP_5:
521             /* Some output (in particular "This signature applies to */
522             /* another message") is _always_ written to stderr; we   */
523             /* want to catch that output, so dup stdout to stderr:   */
524         {   int save_stderr = dup(2);
525             dup2(1, 2);
526             execlp(path, "pgpv", "+batchmode=on", "+verbose=0",
527                    /* Write "Good signature..." to stdout: */
528                    "+OutputInformationFD=1",
529                    /* Write "WARNING: ... is not trusted to... to stdout: */
530                    "+OutputWarningFD=1",
531                    sigfile, "-o", datafile, NULL);
532             /* Restore stderr so we can print the error message below. */
533             dup2(save_stderr, 2);
534             close(save_stderr);
535         }   break;
536         case PGP_2:
537             execlp(path, "pgp", "+batchmode=on", "+verbose=0",
538                    sigfile, datafile, NULL);
539             break;
540         case PGP_UNKNOWN:
541         case PGP_NOTDETECTED:
542             break;
543         }
544
545         fprintf(stderr, _("exec failed!\n"));
546         rpmError(RPMERR_EXEC, 
547                  _("Could not run pgp.  Use --nopgp to skip PGP checks."));
548         _exit(RPMERR_EXEC);
549     }
550
551     close(outpipe[1]);
552     file = fdopen(outpipe[0], "r");
553     result[0] = '\0';
554     while (fgets(buf, 1024, file)) {
555         if (strncmp("File '", buf, 6) &&
556             strncmp("Text is assu", buf, 12) &&
557             strncmp("This signature applies to another message", buf, 41) &&
558             buf[0] != '\n') {
559             strcat(result, buf);
560         }
561         if (!strncmp("WARNING: Can't find the right public key", buf, 40))
562             res = RPMSIG_NOKEY;
563         else if (!strncmp("Signature by unknown keyid:", buf, 27))
564             res = RPMSIG_NOKEY;
565         else if (!strncmp("WARNING: The signing key is not trusted", buf, 39))
566             res = RPMSIG_NOTTRUSTED;
567         else if (!strncmp("Good signature", buf, 14))
568             res = RPMSIG_OK;
569     }
570     fclose(file);
571
572     (void)waitpid(pid, &status, 0);
573     unlink(sigfile);
574     if (!res && (!WIFEXITED(status) || WEXITSTATUS(status))) {
575         res = RPMSIG_BAD;
576     }
577     
578     return res;
579 }
580
581 static int verifyGPGSignature(const char *datafile, void *sig,
582                               int count, char *result)
583 {
584     int pid, status, outpipe[2];
585     FD_t sfd;
586     char *sigfile;
587     unsigned char buf[8192];
588     FILE *file;
589     int res = RPMSIG_OK;
590   
591     /* Write out the signature */
592   { const char *tmppath = rpmGetPath("%{_tmppath}", NULL);
593     sigfile = tempnam(tmppath, "rpmsig");
594     xfree(tmppath);
595   }
596     sfd = fdOpen(sigfile, O_WRONLY|O_CREAT|O_TRUNC, 0644);
597     (void)fdWrite(sfd, sig, count);
598     fdClose(sfd);
599
600     /* Now run GPG */
601     pipe(outpipe);
602
603     if (!(pid = fork())) {
604         const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
605
606         close(outpipe[0]);
607         /* gpg version 0.9 sends its output to stderr. */
608         dup2(outpipe[1], STDERR_FILENO);
609
610         if (gpg_path && *gpg_path != '%')
611             dosetenv("GNUPGHOME", gpg_path, 1);
612
613         execlp("gpg", "gpg",
614                "--batch", "--no-verbose", 
615                "--verify", sigfile, datafile,
616                NULL);
617         fprintf(stderr, _("exec failed!\n"));
618         rpmError(RPMERR_EXEC, 
619                  _("Could not run gpg.  Use --nogpg to skip GPG checks."));
620         _exit(RPMERR_EXEC);
621     }
622
623     close(outpipe[1]);
624     file = fdopen(outpipe[0], "r");
625     result[0] = '\0';
626     while (fgets(buf, 1024, file)) {
627         strcat(result, buf);
628         if (!strncmp("gpg: Can't check signature: Public key not found", buf, 48)) {
629             res = RPMSIG_NOKEY;
630         }
631     }
632     fclose(file);
633   
634     (void)waitpid(pid, &status, 0);
635     unlink(sigfile);
636     if (!res && (!WIFEXITED(status) || WEXITSTATUS(status))) {
637         res = RPMSIG_BAD;
638     }
639     
640     return res;
641 }
642
643 static int checkPassPhrase(const char *passPhrase, const int sigTag)
644 {
645     int passPhrasePipe[2];
646     int pid, status;
647     int fd;
648
649     pipe(passPhrasePipe);
650     if (!(pid = fork())) {
651         close(STDIN_FILENO);
652         close(STDOUT_FILENO);
653         close(passPhrasePipe[1]);
654         if (! rpmIsVerbose()) {
655             close(STDERR_FILENO);
656         }
657         if ((fd = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
658             dup2(fd, STDIN_FILENO);
659             close(fd);
660         }
661         if ((fd = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
662             dup2(fd, STDOUT_FILENO);
663             close(fd);
664         }
665         dup2(passPhrasePipe[0], 3);
666
667         switch (sigTag) {
668         case RPMSIGTAG_GPG:
669         {   const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
670             const char *name = rpmExpand("%{_gpg_name}", NULL);
671             if (gpg_path && *gpg_path != '%')
672                 dosetenv("GNUPGHOME", gpg_path, 1);
673             execlp("gpg", "gpg",
674                    "--batch", "--no-verbose", "--passphrase-fd", "3",
675                    "-u", name, "-so", "-",
676                    NULL);
677             rpmError(RPMERR_EXEC, _("Couldn't exec gpg"));
678             _exit(RPMERR_EXEC);
679         }   break;
680         case RPMSIGTAG_PGP5:    /* XXX legacy */
681         case RPMSIGTAG_PGP:
682         {   const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
683             const char *name = rpmExpand("+myname=\"%{_pgp_name}\"", NULL);
684             const char *path;
685             pgpVersion pgpVer;
686
687             dosetenv("PGPPASSFD", "3", 1);
688             if (pgp_path && *pgp_path != '%')
689                 dosetenv("PGPPATH", pgp_path, 1);
690
691             if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
692                 switch(pgpVer) {
693                 case PGP_2:
694                     execlp(path, "pgp", "+batchmode=on", "+verbose=0",
695                         name, "-sf", NULL);
696                     break;
697                 case PGP_5:     /* XXX legacy */
698                     execlp(path,"pgps", "+batchmode=on", "+verbose=0",
699                         name, "-f", NULL);
700                     break;
701                 case PGP_UNKNOWN:
702                 case PGP_NOTDETECTED:
703                     break;
704                 }
705             }
706             rpmError(RPMERR_EXEC, _("Couldn't exec pgp"));
707             _exit(RPMERR_EXEC);
708         }   break;
709         default: /* This case should have been screened out long ago. */
710             rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file"));
711             _exit(RPMERR_SIGGEN);
712             break;
713         }
714     }
715
716     close(passPhrasePipe[0]);
717     write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
718     write(passPhrasePipe[1], "\n", 1);
719     close(passPhrasePipe[1]);
720
721     (void)waitpid(pid, &status, 0);
722     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
723         return 1;
724     }
725
726     /* passPhrase is good */
727     return 0;
728 }
729
730 char *rpmGetPassPhrase(const char *prompt, const int sigTag)
731 {
732     char *pass;
733     int aok;
734
735     switch (sigTag) {
736     case RPMSIGTAG_GPG:
737       { const char *name = rpmExpand("%{_gpg_name}", NULL);
738         aok = (name && *name != '%');
739         xfree(name);
740       }
741         if (!aok) {
742             rpmError(RPMERR_SIGGEN,
743                 _("You must set \"%%_gpg_name\" in your macro file"));
744             return NULL;
745         }
746         break;
747     case RPMSIGTAG_PGP5:        /* XXX legacy */
748     case RPMSIGTAG_PGP: 
749       { const char *name = rpmExpand("%{_pgp_name}", NULL);
750         aok = (name && *name != '%');
751         xfree(name);
752       }
753         if (!aok) {
754             rpmError(RPMERR_SIGGEN,
755                 _("You must set \"%%_pgp_name\" in your macro file"));
756             return NULL;
757         }
758         break;
759     default:
760         /* Currently the calling function (rpm.c:main) is checking this and
761          * doing a better job.  This section should never be accessed.
762          */
763         rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file"));
764         return NULL;
765         break;
766     }
767
768     if (prompt) {
769         pass = getpass(prompt);
770     } else {
771         pass = getpass("");
772     }
773
774     if (checkPassPhrase(pass, sigTag)) {
775         return NULL;
776     }
777
778     return pass;
779 }
780
781 int rpmVerifySignature(const char *file, int_32 sigTag, void *sig, int count,
782                     char *result)
783 {
784     switch (sigTag) {
785     case RPMSIGTAG_SIZE:
786         if (verifySizeSignature(file, *(int_32 *)sig, result)) {
787             return RPMSIG_BAD;
788         }
789         break;
790     case RPMSIGTAG_MD5:
791         if (verifyMD5Signature(file, sig, result, mdbinfile)) {
792             return 1;
793         }
794         break;
795     case RPMSIGTAG_LEMD5_1:
796     case RPMSIGTAG_LEMD5_2:
797         if (verifyMD5Signature(file, sig, result, mdbinfileBroken)) {
798             return 1;
799         }
800         break;
801     case RPMSIGTAG_PGP5:        /* XXX legacy */
802     case RPMSIGTAG_PGP:
803         return verifyPGPSignature(file, sig, count, result);
804         break;
805     case RPMSIGTAG_GPG:
806         return verifyGPGSignature(file, sig, count, result);
807         break;
808     default:
809         sprintf(result, "Do not know how to verify sig type %d\n", sigTag);
810         return RPMSIG_UNKNOWN;
811     }
812
813     return RPMSIG_OK;
814 }