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