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