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