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