Make fdFileno() static, use Fileno()/Ferror() analogues throughout.
[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, /*@out@*/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         /*@fallthrough@*/
39     case RPMLOOKUPSIG_QUERY:
40         if (disabled)
41             break;      /* Disabled */
42       { const char *name = rpmExpand("%{_signature}", NULL);
43         if (!(name && *name != '%'))
44             rc = 0;
45         else if (!strcasecmp(name, "none"))
46             rc = 0;
47         else if (!strcasecmp(name, "pgp"))
48             rc = RPMSIGTAG_PGP;
49         else if (!strcasecmp(name, "pgp5"))     /* XXX legacy */
50             rc = RPMSIGTAG_PGP;
51         else if (!strcasecmp(name, "gpg"))
52             rc = RPMSIGTAG_GPG;
53         else
54             rc = -1;    /* Invalid %_signature spec in macro file */
55         xfree(name);
56       } break;
57     }
58     return rc;
59 }
60
61 /* rpmDetectPGPVersion() returns the absolute path to the "pgp"  */
62 /* executable of the requested version, or NULL when none found. */
63
64 const char * rpmDetectPGPVersion(pgpVersion *pgpVer)
65 {
66     /* Actually this should support having more then one pgp version. */ 
67     /* At the moment only one version is possible since we only       */
68     /* have one %_pgpbin and one %_pgp_path.                          */
69
70     static pgpVersion saved_pgp_version = PGP_UNKNOWN;
71     const char *pgpbin = rpmGetPath("%{_pgpbin}", NULL);
72
73     if (saved_pgp_version == PGP_UNKNOWN) {
74         char *pgpvbin;
75         struct stat statbuf;
76         
77         if (!(pgpbin && pgpbin[0] != '%') || ! (pgpvbin = (char *)alloca(strlen(pgpbin) + 2))) {
78           if (pgpbin) xfree(pgpbin);
79           saved_pgp_version = -1;
80           return NULL;
81         }
82         sprintf(pgpvbin, "%sv", pgpbin);
83
84         if (stat(pgpvbin, &statbuf) == 0)
85           saved_pgp_version = PGP_5;
86         else if (stat(pgpbin, &statbuf) == 0)
87           saved_pgp_version = PGP_2;
88         else
89           saved_pgp_version = PGP_NOTDETECTED;
90     }
91
92     if (pgpbin && pgpVer)
93         *pgpVer = saved_pgp_version;
94     return pgpbin;
95 }
96
97 static int checkSize(FD_t fd, int size, int sigsize)
98 {
99     int headerArchiveSize;
100     struct stat statbuf;
101
102     fstat(Fileno(fd), &statbuf);
103
104     if (S_ISREG(statbuf.st_mode)) {
105         headerArchiveSize = statbuf.st_size - sizeof(struct rpmlead) - sigsize;
106
107         rpmMessage(RPMMESS_DEBUG, _("sigsize         : %d\n"), sigsize);
108         rpmMessage(RPMMESS_DEBUG, _("Header + Archive: %d\n"), headerArchiveSize);
109         rpmMessage(RPMMESS_DEBUG, _("expected size   : %d\n"), size);
110
111         return size - headerArchiveSize;
112     } else {
113         rpmMessage(RPMMESS_DEBUG, _("file is not regular -- skipping size check\n"));
114         return 0;
115     }
116 }
117
118 /* rpmReadSignature() emulates the new style signatures if it finds an */
119 /* old-style one.  It also immediately verifies the header+archive  */
120 /* size and returns an error if it doesn't match.                   */
121
122 int rpmReadSignature(FD_t fd, Header *headerp, short sig_type)
123 {
124     unsigned char buf[2048];
125     int sigSize, pad;
126     int_32 type, count;
127     int_32 *archSize;
128     Header h;
129
130     if (headerp)
131         *headerp = NULL;
132     
133     switch (sig_type) {
134       case RPMSIG_NONE:
135         rpmMessage(RPMMESS_DEBUG, _("No signature\n"));
136         break;
137       case RPMSIG_PGP262_1024:
138         rpmMessage(RPMMESS_DEBUG, _("Old PGP signature\n"));
139         /* These are always 256 bytes */
140         if (timedRead(fd, buf, 256) != 256)
141             return 1;
142         if (headerp) {
143             *headerp = headerNew();
144             headerAddEntry(*headerp, RPMSIGTAG_PGP, RPM_BIN_TYPE, buf, 152);
145         }
146         break;
147       case RPMSIG_MD5:
148       case RPMSIG_MD5_PGP:
149         rpmError(RPMERR_BADSIGTYPE,
150               _("Old (internal-only) signature!  How did you get that!?"));
151         return 1;
152         /*@notreached@*/ break;
153       case RPMSIG_HEADERSIG:
154         rpmMessage(RPMMESS_DEBUG, _("New Header signature\n"));
155         /* This is a new style signature */
156         h = headerRead(fd, HEADER_MAGIC_YES);
157         if (h == NULL)
158             return 1;
159         sigSize = headerSizeof(h, HEADER_MAGIC_YES);
160         pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
161         rpmMessage(RPMMESS_DEBUG, _("Signature size: %d\n"), sigSize);
162         rpmMessage(RPMMESS_DEBUG, _("Signature pad : %d\n"), pad);
163         if (! headerGetEntry(h, RPMSIGTAG_SIZE, &type, (void **)&archSize, &count)) {
164             headerFree(h);
165             return 1;
166         }
167         if (checkSize(fd, *archSize, sigSize + pad)) {
168             headerFree(h);
169             return 1;
170         }
171         if (pad) {
172             if (timedRead(fd, buf, pad) != pad) {
173                 headerFree(h);
174                 return 1;
175             }
176         }
177         if (headerp) {
178             *headerp = h;
179         } else {
180             headerFree(h);
181         }
182         break;
183       default:
184         return 1;
185     }
186
187     return 0;
188 }
189
190 int rpmWriteSignature(FD_t fd, Header header)
191 {
192     int sigSize, pad;
193     unsigned char 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, pad, 1, 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 = fdOpen(sigfile, O_RDONLY, 0);
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 = fdOpen(sigfile, O_RDONLY, 0);
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     unsigned char 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 int verifySizeSignature(const char *datafile, int_32 size, char *result)
427 {
428     struct stat statbuf;
429
430     stat(datafile, &statbuf);
431     if (size != statbuf.st_size) {
432         sprintf(result, "Header+Archive size mismatch.\n"
433                 "Expected %d, saw %d.\n",
434                 size, (int)statbuf.st_size);
435         return 1;
436     }
437
438     sprintf(result, "Header+Archive size OK: %d bytes\n", size);
439     return 0;
440 }
441
442 #define X(_x)   (unsigned)((_x) & 0xff)
443
444 static int verifyMD5Signature(const char *datafile, unsigned char *sig, 
445                               char *result, md5func fn)
446 {
447     unsigned char md5sum[16];
448
449     fn(datafile, md5sum);
450     if (memcmp(md5sum, sig, 16)) {
451         sprintf(result, "MD5 sum mismatch\n"
452                 "Expected: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
453                 "%02x%02x%02x%02x%02x\n"
454                 "Saw     : %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
455                 "%02x%02x%02x%02x%02x\n",
456                 X(sig[0]),  X(sig[1]),  X(sig[2]),  X(sig[3]),
457                 X(sig[4]),  X(sig[5]),  X(sig[6]),  X(sig[7]),
458                 X(sig[8]),  X(sig[9]),  X(sig[10]), X(sig[11]),
459                 X(sig[12]), X(sig[13]), X(sig[14]), X(sig[15]),
460                 X(md5sum[0]),  X(md5sum[1]),  X(md5sum[2]),  X(md5sum[3]),
461                 X(md5sum[4]),  X(md5sum[5]),  X(md5sum[6]),  X(md5sum[7]),
462                 X(md5sum[8]),  X(md5sum[9]),  X(md5sum[10]), X(md5sum[11]),
463                 X(md5sum[12]), X(md5sum[13]), X(md5sum[14]), X(md5sum[15]) );
464         return 1;
465     }
466
467     sprintf(result, "MD5 sum OK: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
468                     "%02x%02x%02x%02x%02x\n",
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
474     return 0;
475 }
476
477 static int verifyPGPSignature(const char *datafile, void *sig,
478                               int count, char *result)
479 {
480     int pid, status, outpipe[2];
481     FD_t sfd;
482     char *sigfile;
483     unsigned char buf[8192];
484     FILE *file;
485     int res = RPMSIG_OK;
486     const char *path;
487     pgpVersion pgpVer;
488
489     /* What version do we have? */
490     if ((path = rpmDetectPGPVersion(&pgpVer)) == NULL) {
491         errno = ENOENT;
492         rpmError(RPMERR_EXEC, 
493                  _("Could not run pgp.  Use --nopgp to skip PGP checks."));
494         _exit(RPMERR_EXEC);
495     }
496
497     /*
498      * Sad but true: pgp-5.0 returns exit value of 0 on bad signature.
499      * Instead we have to use the text output to detect a bad signature.
500      */
501     if (pgpVer == PGP_5)
502         res = RPMSIG_BAD;
503
504     /* Write out the signature */
505   { const char *tmppath = rpmGetPath("%{_tmppath}", NULL);
506     sigfile = tempnam(tmppath, "rpmsig");
507     xfree(tmppath);
508   }
509     sfd = fdOpen(sigfile, O_WRONLY|O_CREAT|O_TRUNC, 0644);
510     (void)Fwrite(sig, count, 1, sfd);
511     Fclose(sfd);
512
513     /* Now run PGP */
514     outpipe[0] = outpipe[1] = 0;
515     pipe(outpipe);
516
517     if (!(pid = fork())) {
518         const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
519
520         close(outpipe[0]);
521         close(STDOUT_FILENO);   /* XXX unnecessary */
522         dup2(outpipe[1], STDOUT_FILENO);
523
524         if (pgp_path && *pgp_path != '%')
525             dosetenv("PGPPATH", pgp_path, 1);
526
527         switch (pgpVer) {
528         case PGP_5:
529             /* Some output (in particular "This signature applies to */
530             /* another message") is _always_ written to stderr; we   */
531             /* want to catch that output, so dup stdout to stderr:   */
532         {   int save_stderr = dup(2);
533             dup2(1, 2);
534             execlp(path, "pgpv", "+batchmode=on", "+verbose=0",
535                    /* Write "Good signature..." to stdout: */
536                    "+OutputInformationFD=1",
537                    /* Write "WARNING: ... is not trusted to... to stdout: */
538                    "+OutputWarningFD=1",
539                    sigfile, "-o", datafile, NULL);
540             /* Restore stderr so we can print the error message below. */
541             dup2(save_stderr, 2);
542             close(save_stderr);
543         }   break;
544         case PGP_2:
545             execlp(path, "pgp", "+batchmode=on", "+verbose=0",
546                    sigfile, datafile, NULL);
547             break;
548         case PGP_UNKNOWN:
549         case PGP_NOTDETECTED:
550             break;
551         }
552
553         fprintf(stderr, _("exec failed!\n"));
554         rpmError(RPMERR_EXEC, 
555                  _("Could not run pgp.  Use --nopgp to skip PGP checks."));
556         _exit(RPMERR_EXEC);
557     }
558
559     close(outpipe[1]);
560     file = fdopen(outpipe[0], "r");
561     result[0] = '\0';
562     while (fgets(buf, 1024, file)) {
563         if (strncmp("File '", buf, 6) &&
564             strncmp("Text is assu", buf, 12) &&
565             strncmp("This signature applies to another message", buf, 41) &&
566             buf[0] != '\n') {
567             strcat(result, buf);
568         }
569         if (!strncmp("WARNING: Can't find the right public key", buf, 40))
570             res = RPMSIG_NOKEY;
571         else if (!strncmp("Signature by unknown keyid:", buf, 27))
572             res = RPMSIG_NOKEY;
573         else if (!strncmp("WARNING: The signing key is not trusted", buf, 39))
574             res = RPMSIG_NOTTRUSTED;
575         else if (!strncmp("Good signature", buf, 14))
576             res = RPMSIG_OK;
577     }
578     fclose(file);
579
580     (void)waitpid(pid, &status, 0);
581     unlink(sigfile);
582     if (!res && (!WIFEXITED(status) || WEXITSTATUS(status))) {
583         res = RPMSIG_BAD;
584     }
585     
586     return res;
587 }
588
589 static int verifyGPGSignature(const char *datafile, void *sig,
590                               int count, char *result)
591 {
592     int pid, status, outpipe[2];
593     FD_t sfd;
594     char *sigfile;
595     unsigned char buf[8192];
596     FILE *file;
597     int res = RPMSIG_OK;
598   
599     /* Write out the signature */
600   { const char *tmppath = rpmGetPath("%{_tmppath}", NULL);
601     sigfile = tempnam(tmppath, "rpmsig");
602     xfree(tmppath);
603   }
604     sfd = fdOpen(sigfile, O_WRONLY|O_CREAT|O_TRUNC, 0644);
605     (void)Fwrite(sig, count, 1, sfd);
606     Fclose(sfd);
607
608     /* Now run GPG */
609     outpipe[0] = outpipe[1] = 0;
610     pipe(outpipe);
611
612     if (!(pid = fork())) {
613         const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
614
615         close(outpipe[0]);
616         /* gpg version 0.9 sends its output to stderr. */
617         dup2(outpipe[1], STDERR_FILENO);
618
619         if (gpg_path && *gpg_path != '%')
620             dosetenv("GNUPGHOME", gpg_path, 1);
621
622         execlp("gpg", "gpg",
623                "--batch", "--no-verbose", 
624                "--verify", sigfile, datafile,
625                NULL);
626         fprintf(stderr, _("exec failed!\n"));
627         rpmError(RPMERR_EXEC, 
628                  _("Could not run gpg.  Use --nogpg to skip GPG checks."));
629         _exit(RPMERR_EXEC);
630     }
631
632     close(outpipe[1]);
633     file = fdopen(outpipe[0], "r");
634     result[0] = '\0';
635     while (fgets(buf, 1024, file)) {
636         strcat(result, buf);
637         if (!strncmp("gpg: Can't check signature: Public key not found", buf, 48)) {
638             res = RPMSIG_NOKEY;
639         }
640     }
641     fclose(file);
642   
643     (void)waitpid(pid, &status, 0);
644     unlink(sigfile);
645     if (!res && (!WIFEXITED(status) || WEXITSTATUS(status))) {
646         res = RPMSIG_BAD;
647     }
648     
649     return res;
650 }
651
652 static int checkPassPhrase(const char *passPhrase, const int sigTag)
653 {
654     int passPhrasePipe[2];
655     int pid, status;
656     int fd;
657
658     passPhrasePipe[0] = passPhrasePipe[1] = 0;
659     pipe(passPhrasePipe);
660     if (!(pid = fork())) {
661         close(STDIN_FILENO);
662         close(STDOUT_FILENO);
663         close(passPhrasePipe[1]);
664         if (! rpmIsVerbose()) {
665             close(STDERR_FILENO);
666         }
667         if ((fd = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
668             dup2(fd, STDIN_FILENO);
669             close(fd);
670         }
671         if ((fd = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
672             dup2(fd, STDOUT_FILENO);
673             close(fd);
674         }
675         dup2(passPhrasePipe[0], 3);
676
677         switch (sigTag) {
678         case RPMSIGTAG_GPG:
679         {   const char *gpg_path = rpmExpand("%{_gpg_path}", NULL);
680             const char *name = rpmExpand("%{_gpg_name}", NULL);
681             if (gpg_path && *gpg_path != '%')
682                 dosetenv("GNUPGHOME", gpg_path, 1);
683             execlp("gpg", "gpg",
684                    "--batch", "--no-verbose", "--passphrase-fd", "3",
685                    "-u", name, "-so", "-",
686                    NULL);
687             rpmError(RPMERR_EXEC, _("Couldn't exec gpg"));
688             _exit(RPMERR_EXEC);
689         }   /*@notreached@*/ break;
690         case RPMSIGTAG_PGP5:    /* XXX legacy */
691         case RPMSIGTAG_PGP:
692         {   const char *pgp_path = rpmExpand("%{_pgp_path}", NULL);
693             const char *name = rpmExpand("+myname=\"%{_pgp_name}\"", NULL);
694             const char *path;
695             pgpVersion pgpVer;
696
697             dosetenv("PGPPASSFD", "3", 1);
698             if (pgp_path && *pgp_path != '%')
699                 dosetenv("PGPPATH", pgp_path, 1);
700
701             if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) {
702                 switch(pgpVer) {
703                 case PGP_2:
704                     execlp(path, "pgp", "+batchmode=on", "+verbose=0",
705                         name, "-sf", NULL);
706                     break;
707                 case PGP_5:     /* XXX legacy */
708                     execlp(path,"pgps", "+batchmode=on", "+verbose=0",
709                         name, "-f", NULL);
710                     break;
711                 case PGP_UNKNOWN:
712                 case PGP_NOTDETECTED:
713                     break;
714                 }
715             }
716             rpmError(RPMERR_EXEC, _("Couldn't exec pgp"));
717             _exit(RPMERR_EXEC);
718         }   /*@notreached@*/ break;
719         default: /* This case should have been screened out long ago. */
720             rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file"));
721             _exit(RPMERR_SIGGEN);
722             /*@notreached@*/ break;
723         }
724     }
725
726     close(passPhrasePipe[0]);
727     (void)write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
728     (void)write(passPhrasePipe[1], "\n", 1);
729     close(passPhrasePipe[1]);
730
731     (void)waitpid(pid, &status, 0);
732     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
733         return 1;
734     }
735
736     /* passPhrase is good */
737     return 0;
738 }
739
740 char *rpmGetPassPhrase(const char *prompt, const int sigTag)
741 {
742     char *pass;
743     int aok;
744
745     switch (sigTag) {
746     case RPMSIGTAG_GPG:
747       { const char *name = rpmExpand("%{_gpg_name}", NULL);
748         aok = (name && *name != '%');
749         xfree(name);
750       }
751         if (!aok) {
752             rpmError(RPMERR_SIGGEN,
753                 _("You must set \"%%_gpg_name\" in your macro file"));
754             return NULL;
755         }
756         break;
757     case RPMSIGTAG_PGP5:        /* XXX legacy */
758     case RPMSIGTAG_PGP: 
759       { const char *name = rpmExpand("%{_pgp_name}", NULL);
760         aok = (name && *name != '%');
761         xfree(name);
762       }
763         if (!aok) {
764             rpmError(RPMERR_SIGGEN,
765                 _("You must set \"%%_pgp_name\" in your macro file"));
766             return NULL;
767         }
768         break;
769     default:
770         /* Currently the calling function (rpm.c:main) is checking this and
771          * doing a better job.  This section should never be accessed.
772          */
773         rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file"));
774         return NULL;
775         /*@notreached@*/ break;
776     }
777
778     pass = /*@-unrecog@*/ getpass( (prompt ? prompt : "") ) /*@=unrecog@*/ ;
779
780     if (checkPassPhrase(pass, sigTag))
781         return NULL;
782
783     return pass;
784 }
785
786 int rpmVerifySignature(const char *file, int_32 sigTag, void *sig, int count,
787                     char *result)
788 {
789     switch (sigTag) {
790     case RPMSIGTAG_SIZE:
791         if (verifySizeSignature(file, *(int_32 *)sig, result)) {
792             return RPMSIG_BAD;
793         }
794         break;
795     case RPMSIGTAG_MD5:
796         if (verifyMD5Signature(file, sig, result, mdbinfile)) {
797             return 1;
798         }
799         break;
800     case RPMSIGTAG_LEMD5_1:
801     case RPMSIGTAG_LEMD5_2:
802         if (verifyMD5Signature(file, sig, result, mdbinfileBroken)) {
803             return 1;
804         }
805         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
818     return RPMSIG_OK;
819 }