~ubuntu-branches/ubuntu/edgy/rpm/edgy

« back to all changes in this revision

Viewing changes to lib/signature.c

  • Committer: Bazaar Package Importer
  • Author(s): Joey Hess
  • Date: 2002-01-22 20:56:57 UTC
  • Revision ID: james.westby@ubuntu.com-20020122205657-l74j50mr9z8ofcl5
Tags: upstream-4.0.3
ImportĀ upstreamĀ versionĀ 4.0.3

Show diffs side-by-side

added added

removed removed

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