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