rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

rpmchecksig.c
Go to the documentation of this file.
1
6 #include "system.h"
7
8 #include <rpmio_internal.h>
9 #include <poptIO.h>
10 #include <rpmbc.h> /* XXX beecrypt base64 */
11 #include <rpmtag.h>
12 #include <rpmtypes.h>
13 #define _RPMEVR_INTERNAL /* XXX RPMSENSE_KEYRING */
14 #include <rpmevr.h>
15 #include <rpmdb.h>
16 #include <rpmxar.h>
17 #include <pkgio.h>
18 #include "signature.h"
19
20 #include <rpmts.h>
21
22 #include "rpmgi.h"
23
24 #include <rpmversion.h>
25 #include <rpmcli.h>
26
27 #include "debug.h"
28
29 /*@access FD_t @*/ /* XXX stealing digests */
30 /*@access Header @*/ /* XXX void * arg */
31 /*@access pgpDig @*/
32 /*@access pgpDigParams @*/
33
34 /*@unchecked@*/
35 int _print_pkts = 0;
36
39 static int manageFile(/*@out@*/ FD_t *fdp,
40 /*@null@*/ /*@out@*/ const char **fnp,
41 int flags, /*@unused@*/ int rc)
42 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
43 /*@modifies *fdp, *fnp, rpmGlobalMacroContext,
44 fileSystem, internalState @*/
45 {
46 const char *fn;
47 FD_t fd;
48
49 if (fdp == NULL) /* programmer error */
50 return 1;
51
52 /* close and reset *fdp to NULL */
53 if (*fdp && (fnp == NULL || *fnp == NULL)) {
54 (void) Fclose(*fdp);
55 *fdp = NULL;
56 return 0;
57 }
58
59 /* open a file and set *fdp */
60 if (*fdp == NULL && fnp != NULL && *fnp != NULL) {
61 fd = Fopen(*fnp, ((flags & O_WRONLY) ? "w.fdio" : "r.fdio"));
62 if (fd == NULL || Ferror(fd)) {
63 rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"), *fnp,
64 Fstrerror(fd));
65 return 1;
66 }
67 *fdp = fd;
68 return 0;
69 }
70
71 /* open a temp file */
72 if (*fdp == NULL && (fnp == NULL || *fnp == NULL)) {
73 fn = NULL;
74 if (rpmTempFile(NULL, (fnp ? &fn : NULL), &fd)) {
75 rpmlog(RPMLOG_ERR, _("rpmTempFile failed\n"));
76 return 1;
77 }
78 if (fnp != NULL)
79 *fnp = fn;
80 /*@-refcounttrans@*/ /* FIX: XfdLink/XfdFree annotation */
81 *fdp = fdLink(fd, "manageFile return");
82 fd = fdFree(fd, "manageFile return");
83 /*@=refcounttrans@*/
84 return 0;
85 }
86
87 /* no operation */
88 if (*fdp != NULL && fnp != NULL && *fnp != NULL)
89 return 0;
90
91 /* XXX never reached */
92 return 1;
93 }
94
98 static int copyFile(FD_t *sfdp, const char **sfnp,
99 FD_t *tfdp, const char **tfnp)
100 /*@globals rpmGlobalMacroContext, h_errno,
101 fileSystem, internalState @*/
102 /*@modifies *sfdp, *sfnp, *tfdp, *tfnp, rpmGlobalMacroContext,
103 fileSystem, internalState @*/
104 {
105 unsigned char buf[BUFSIZ];
106 ssize_t count;
107 int rc = 1;
108
109 if (manageFile(sfdp, sfnp, O_RDONLY, 0))
110 goto exit;
111 if (manageFile(tfdp, tfnp, O_WRONLY|O_CREAT|O_TRUNC, 0))
112 goto exit;
113
114 while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), *sfdp)) > 0)
115 {
116 if (Fwrite(buf, sizeof(buf[0]), count, *tfdp) != (size_t)count) {
117 rpmlog(RPMLOG_ERR, _("%s: Fwrite failed: %s\n"), *tfnp,
118 Fstrerror(*tfdp));
119 goto exit;
120 }
121 }
122 if (count < 0) {
123 rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), *sfnp, Fstrerror(*sfdp));
124 goto exit;
125 }
126 if (Fflush(*tfdp) != 0) {
127 rpmlog(RPMLOG_ERR, _("%s: Fflush failed: %s\n"), *tfnp,
128 Fstrerror(*tfdp));
129 goto exit;
130 }
131
132 rc = 0;
133
134 exit:
135 if (*sfdp) (void) manageFile(sfdp, NULL, 0, rc);
136 if (*tfdp) (void) manageFile(tfdp, NULL, 0, rc);
137 return rc;
138 }
139
147 static int getSignid(Header sigh, rpmSigTag sigtag, unsigned char * signid)
148 /*@globals fileSystem, internalState @*/
149 /*@modifies *signid, fileSystem, internalState @*/
150 {
151 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
152 int rc = 1;
153 int xx;
154
155 he->tag = (rpmTag) sigtag;
156 xx = headerGet(sigh, he, 0);
157 if (xx && he->p.ptr != NULL) {
158 pgpDig dig = pgpDigNew(0);
159
160 if (!pgpPrtPkts(he->p.ptr, he->c, dig, 0)) {
161 memcpy(signid, dig->signature.signid, sizeof(dig->signature.signid));
162 rc = 0;
163 }
164
165 he->p.ptr = _free(he->p.ptr);
166 dig = pgpDigFree(dig, "getSignid");
167 }
168 return rc;
169 }
170
178 static int rpmReSign(/*@unused@*/ rpmts ts,
179 QVA_t qva, const char ** argv)
180 /*@globals rpmGlobalMacroContext, h_errno,
181 fileSystem, internalState @*/
182 /*@modifies ts, rpmGlobalMacroContext,
183 fileSystem, internalState @*/
184 {
185 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
186 rpmgi gi = NULL;
187 FD_t fd = NULL;
188 FD_t ofd = NULL;
189 struct rpmlead *lead = NULL;
190 rpmSigTag sigtag;
191 const char *sigtarget = NULL;
192 char tmprpm[1024+1];
193 Header sigh = NULL;
194 const char * msg = NULL;
195 int res = EXIT_FAILURE;
196 int deleting = (qva->qva_mode == RPMSIGN_DEL_SIGNATURE);
197 rpmRC rc;
198 int xx;
199 int i;
200
201 tmprpm[0] = '\0';
202
203 if (argv)
204 { /* start-of-arg-iteration */
205 rpmuint32_t tag = (qva->qva_source == RPMQV_FTSWALK)
206 ? RPMDBI_FTSWALK : RPMDBI_ARGLIST;
207 rpmgiFlags _giFlags = RPMGI_NONE;
208
209 gi = rpmgiNew(ts, tag, NULL, 0);
210 /*@-mods@*/
211 if (rpmioFtsOpts == 0)
212 rpmioFtsOpts = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
213 /*@=mods@*/
214 rc = rpmgiSetArgs(gi, argv, rpmioFtsOpts, (_giFlags|RPMGI_NOHEADER));
215
216 while (rpmgiNext(gi) == RPMRC_OK) {
217 const char * fn = rpmgiHdrPath(gi);
218 const char * tfn;
219
220 fprintf(stdout, "%s:\n", fn);
221
222 /*@-modobserver@*/ /* XXX rpmgiHdrPath should not be observer */
223 if (manageFile(&fd, &fn, O_RDONLY, 0))
224 goto exit;
225 /*@=modobserver@*/
226
227 { const char item[] = "Lead";
228 msg = NULL;
229 rc = rpmpkgRead(item, fd, &lead, &msg);
230 if (rc != RPMRC_OK) {
231 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
232 msg = _free(msg);
233 goto exit;
234 }
235 msg = _free(msg);
236 }
237
238 { const char item[] = "Signature";
239 msg = NULL;
240 rc = rpmpkgRead(item, fd, &sigh, &msg);
241 switch (rc) {
242 default:
243 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item,
244 (msg && *msg ? msg : ""));
245 msg = _free(msg);
246 goto exit;
247 /*@notreached@*/ /*@switchbreak@*/ break;
248 case RPMRC_OK:
249 if (sigh == NULL) {
250 rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
251 goto exit;
252 }
253 /*@switchbreak@*/ break;
254 }
255 msg = _free(msg);
256 }
257
258 /* Write the header and archive to a temp file */
259 /* ASSERT: ofd == NULL && sigtarget == NULL */
260 /*@-modobserver@*/ /* XXX rpmgiHdrPath should not be observer */
261 if (copyFile(&fd, &fn, &ofd, &sigtarget))
262 goto exit;
263 /*@=modobserver@*/
264 /* Both fd and ofd are now closed. sigtarget contains tempfile name. */
265 /* ASSERT: fd == NULL && ofd == NULL */
266
267 /* Lose the immutable region (if present). */
268 he->tag = RPMTAG_HEADERSIGNATURES;
269 xx = headerGet(sigh, he, 0);
270 if (xx) {
271 HE_t ohe = memset(alloca(sizeof(*ohe)), 0, sizeof(*ohe));
272 HeaderIterator hi;
273 Header oh;
274 Header nh;
275
276 nh = headerNew();
277 if (nh == NULL) {
278 he->p.ptr = _free(he->p.ptr);
279 goto exit;
280 }
281
282 oh = headerCopyLoad(he->p.ptr);
283 for (hi = headerInit(oh);
284 headerNext(hi, ohe, 0);
285 ohe->p.ptr = _free(ohe->p.ptr))
286 {
287 if (ohe->p.ptr) {
288 xx = headerPut(nh, ohe, 0);
289 }
290 }
291 hi = headerFini(hi);
292 (void)headerFree(oh);
293 oh = NULL;
294
295 (void)headerFree(sigh);
296 sigh = NULL;
297 sigh = headerLink(nh);
298 (void)headerFree(nh);
299 nh = NULL;
300 }
301
302 if (sigh != NULL) {
303 /* Eliminate broken digest values. */
304 he->tag = (rpmTag)RPMSIGTAG_LEMD5_1;
305 xx = headerDel(sigh, he, 0);
306 he->tag = (rpmTag)RPMSIGTAG_LEMD5_2;
307 xx = headerDel(sigh, he, 0);
308 he->tag = (rpmTag)RPMSIGTAG_BADSHA1_1;
309 xx = headerDel(sigh, he, 0);
310 he->tag = (rpmTag)RPMSIGTAG_BADSHA1_2;
311 xx = headerDel(sigh, he, 0);
312
313 /* Toss and recalculate header+payload size and digests. */
314 { static const rpmuint32_t sigs[] =
315 { RPMSIGTAG_SIZE, RPMSIGTAG_MD5, RPMSIGTAG_SHA1 };
316 size_t nsigs = sizeof(sigs) / sizeof(sigs[0]);
317 for (i = 0; i < (int)nsigs; i++) {
318 he->tag = (rpmTag)sigs[i];
319 xx = headerDel(sigh, he, 0);
320 xx = rpmAddSignature(sigh, sigtarget, (rpmSigTag) he->tag, qva->passPhrase);
321 if (xx)
322 goto exit;
323 }
324 }
325
326 if (deleting) {
327 /* Nuke all the signature tags. */
328 static const rpmuint32_t sigs[] =
329 { RPMSIGTAG_GPG, RPMSIGTAG_PGP5, RPMSIGTAG_PGP,
330 RPMSIGTAG_DSA, RPMSIGTAG_RSA };
331 size_t nsigs = sizeof(sigs) / sizeof(sigs[0]);
332 for (i = 0; i < (int)nsigs; i++) {
333 he->tag = (rpmTag)sigs[i];
334 xx = headerDel(sigh, he, 0);
335 }
336 } else { /* If gpg/pgp is configured, replace the signature. */
337 int addsig = 0;
338 sigtag = RPMSIGTAG_GPG;
339 addsig = 1;
340
341 if (addsig) {
342 unsigned char oldsignid[8], newsignid[8];
343
344 /* Grab the old signature fingerprint (if any) */
345 memset(oldsignid, 0, sizeof(oldsignid));
346 xx = getSignid(sigh, sigtag, oldsignid);
347
348 switch (sigtag) {
349 default:
350 /*@switchbreak@*/ break;
351 case RPMSIGTAG_DSA:
352 he->tag = (rpmTag)RPMSIGTAG_GPG;
353 xx = headerDel(sigh, he, 0);
354 /*@switchbreak@*/ break;
355 case RPMSIGTAG_RSA:
356 he->tag = (rpmTag)RPMSIGTAG_PGP;
357 xx = headerDel(sigh, he, 0);
358 /*@switchbreak@*/ break;
359 case RPMSIGTAG_GPG:
360 he->tag = (rpmTag)RPMSIGTAG_PGP;
361 xx = headerDel(sigh, he, 0);
362 he->tag = (rpmTag)RPMSIGTAG_DSA;
363 xx = headerDel(sigh, he, 0);
364 /*@fallthrough@*/
365 case RPMSIGTAG_PGP5:
366 case RPMSIGTAG_PGP:
367 he->tag = (rpmTag)RPMSIGTAG_RSA;
368 xx = headerDel(sigh, he, 0);
369 /*@switchbreak@*/ break;
370 }
371
372 he->tag = (rpmTag)sigtag;
373 xx = headerDel(sigh, he, 0);
374 xx = rpmAddSignature(sigh, sigtarget, sigtag, qva->passPhrase);
375 if (xx)
376 goto exit;
377
378 /* If package was previously signed, check for same signer. */
379 memset(newsignid, 0, sizeof(newsignid));
380 if (memcmp(oldsignid, newsignid, sizeof(oldsignid))) {
381
382 /* Grab the new signature fingerprint */
383 xx = getSignid(sigh, sigtag, newsignid);
384
385 /* If same signer, skip resigning the package. */
386 if (!memcmp(oldsignid, newsignid, sizeof(oldsignid))) {
387
388 rpmlog(RPMLOG_WARNING,
389 _("%s: was already signed by key ID %s, skipping\n"),
390 fn, pgpHexStr(newsignid+4, sizeof(newsignid)-4));
391
392 /* Clean up intermediate target */
393 xx = Unlink(sigtarget);
394 sigtarget = _free(sigtarget);
395 continue;
396 }
397 }
398 }
399 }
400
401 /* Reallocate the signature into one contiguous region. */
402 sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES);
403 if (sigh == NULL) /* XXX can't happen */
404 goto exit;
405 }
406
407 /* Write the lead/signature of the output rpm */
408 (void) stpcpy( stpcpy(tmprpm, fn), ".XXXXXX");
409
410 #if defined(HAVE_MKSTEMP)
411 (void) close(mkstemp(tmprpm));
412 #else
413 (void) mktemp(tmprpm);
414 #endif
415 tfn = tmprpm;
416
417 if (manageFile(&ofd, &tfn, O_WRONLY|O_CREAT|O_TRUNC, 0))
418 goto exit;
419
420 { const char item[] = "Lead";
421 rc = rpmpkgWrite(item, ofd, lead, NULL);
422 if (rc != RPMRC_OK) {
423 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", tfn, item, Fstrerror(ofd));
424 goto exit;
425 }
426 }
427
428 { const char item[] = "Signature";
429 rc = rpmpkgWrite(item, ofd, sigh, NULL);
430 if (rc != RPMRC_OK) {
431 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", tfn, item, Fstrerror(ofd));
432 goto exit;
433 }
434 }
435
436 /* Append the header and archive from the temp file */
437 /* ASSERT: fd == NULL && ofd != NULL */
438 if (copyFile(&fd, &sigtarget, &ofd, &tfn))
439 goto exit;
440 /* Both fd and ofd are now closed. */
441 /* ASSERT: fd == NULL && ofd == NULL */
442
443 /* Move final target into place. */
444 xx = Unlink(fn);
445 xx = Rename(tfn, fn);
446 tmprpm[0] = '\0';
447
448 /* Clean up intermediate target */
449 xx = Unlink(sigtarget);
450 sigtarget = _free(sigtarget);
451 }
452
453 } /* end-of-arg-iteration */
454
455 res = 0;
456
457 exit:
458 if (fd) (void) manageFile(&fd, NULL, 0, res);
459 if (ofd) (void) manageFile(&ofd, NULL, 0, res);
460
461 lead = _free(lead);
462 (void)headerFree(sigh);
463 sigh = NULL;
464
465 gi = rpmgiFree(gi);
466
467 if (sigtarget) {
468 xx = Unlink(sigtarget);
469 sigtarget = _free(sigtarget);
470 }
471 if (tmprpm[0] != '\0') {
472 xx = Unlink(tmprpm);
473 tmprpm[0] = '\0';
474 }
475
476 return res;
477 }
478
479 rpmRC rpmcliImportPubkey(const rpmts ts, const unsigned char * pkt, ssize_t pktlen)
480 {
481 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
482 static unsigned char zeros[] =
483 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
484 const char * afmt = "%{pubkeys:armor}";
485 const char * group = "Public Keys";
486 const char * license = "pubkey";
487 const char * buildhost = "localhost";
488 rpmuint32_t pflags = (RPMSENSE_KEYRING|RPMSENSE_EQUAL);
489 rpmuint32_t zero = 0;
490 pgpDig dig = NULL;
491 pgpDigParams pubp = NULL;
492 const char * d = NULL;
493 const char * enc = NULL;
494 const char * n = NULL;
495 const char * u = NULL;
496 const char * v = NULL;
497 const char * r = NULL;
498 const char * evr = NULL;
499 Header h = NULL;
500 rpmRC rc = RPMRC_FAIL; /* assume failure */
501 char * t;
502 int xx;
503
504 if (pkt == NULL || pktlen <= 0)
505 return RPMRC_FAIL;
506 if (rpmtsOpenDB(ts, (O_RDWR|O_CREAT)))
507 return RPMRC_FAIL;
508
509 /*@-moduncon@*/
510 if ((enc = b64encode(pkt, pktlen)) == NULL)
511 goto exit;
512 /*@=moduncon@*/
513
514 dig = pgpDigNew(0);
515
516 /* Build header elements. */
517 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
518 pubp = pgpGetPubkey(dig);
519
520 if (!memcmp(pubp->signid, zeros, sizeof(pubp->signid))
521 || !memcmp(pubp->time, zeros, sizeof(pubp->time))
522 || pubp->userid == NULL)
523 goto exit;
524
525 v = t = xmalloc(16+1);
526 t = stpcpy(t, pgpHexStr(pubp->signid, sizeof(pubp->signid)));
527
528 r = t = xmalloc(8+1);
529 t = stpcpy(t, pgpHexStr(pubp->time, sizeof(pubp->time)));
530
531 n = t = xmalloc(sizeof("gpg()")+8);
532 t = stpcpy( stpcpy( stpcpy(t, "gpg("), v+8), ")");
533
534 /*@-nullpass@*/ /* FIX: pubp->userid may be NULL */
535 u = t = xmalloc(sizeof("gpg()")+strlen(pubp->userid));
536 t = stpcpy( stpcpy( stpcpy(t, "gpg("), pubp->userid), ")");
537 /*@=nullpass@*/
538
539 evr = t = xmalloc(sizeof("4X:-")+strlen(v)+strlen(r));
540 t = stpcpy(t, (pubp->version == 4 ? "4:" : "3:"));
541 t = stpcpy( stpcpy( stpcpy(t, v), "-"), r);
542
543 /* Check for pre-existing header. */
544
545 /* Build pubkey header. */
546 h = headerNew();
547
548 he->append = 1;
549
550 he->tag = RPMTAG_PUBKEYS;
551 he->t = RPM_STRING_ARRAY_TYPE;
552 he->p.argv = &enc;
553 he->c = 1;
554 xx = headerPut(h, he, 0);
555
556 he->append = 0;
557
558 d = headerSprintf(h, afmt, NULL, rpmHeaderFormats, NULL);
559 if (d == NULL)
560 goto exit;
561
562 he->t = RPM_STRING_TYPE;
563 he->c = 1;
564 he->tag = RPMTAG_NAME;
565 he->p.str = xstrdup("gpg-pubkey");
566 xx = headerPut(h, he, 0);
567 he->p.ptr = _free(he->p.ptr);
568 he->tag = RPMTAG_VERSION;
569 he->p.str = v+8;
570 xx = headerPut(h, he, 0);
571 he->tag = RPMTAG_RELEASE;
572 he->p.str = xstrdup(r);
573 xx = headerPut(h, he, 0);
574 he->p.ptr = _free(he->p.ptr);
575
576 /* Add Summary/Description/Group. */
577 he->tag = RPMTAG_DESCRIPTION;
578 he->p.str = xstrdup(d);
579 #if defined(SUPPORT_IMPLICIT_TAG_DATA_TYPES)
580 xx = headerAddI18NString(h, he->tag, he->p.ptr, "C");
581 #else
582 xx = headerPut(h, he, 0);
583 #endif
584 he->p.ptr = _free(he->p.ptr);
585
586 he->tag = RPMTAG_GROUP;
587 he->p.str = xstrdup(group);
588 #if defined(SUPPORT_IMPLICIT_TAG_DATA_TYPES)
589 xx = headerAddI18NString(h, he->tag, he->p.ptr, "C");
590 #else
591 xx = headerPut(h, he, 0);
592 #endif
593 he->p.ptr = _free(he->p.ptr);
594
595 he->tag = RPMTAG_SUMMARY;
596 he->p.str = xstrdup(u);
597 #if defined(SUPPORT_IMPLICIT_TAG_DATA_TYPES)
598 xx = headerAddI18NString(h, he->tag, he->p.ptr, "C");
599 #else
600 xx = headerPut(h, he, 0);
601 #endif
602 he->p.ptr = _free(he->p.ptr);
603
604 #ifdef NOTYET /* XXX can't erase pubkeys with "pubkey" arch. */
605 /* Add a "pubkey" arch/os to avoid missing value NULL ptrs. */
606 he->tag = RPMTAG_ARCH;
607 he->p.str = "pubkey";
608 xx = headerPut(h, he, 0);
609 he->tag = RPMTAG_OS;
610 he->p.str = "pubkey";
611 xx = headerPut(h, he, 0);
612 #endif
613
614 he->tag = RPMTAG_LICENSE;
615 he->p.str = xstrdup(license);
616 xx = headerPut(h, he, 0);
617 he->p.ptr = _free(he->p.ptr);
618
619 he->tag = RPMTAG_SIZE;
620 he->t = RPM_UINT32_TYPE;
621 he->p.ui32p = &zero;
622 he->c = 1;
623 xx = headerPut(h, he, 0);
624
625 he->append = 1;
626
627 /* Provides: gpg(IDENTITY) = PUBKEYVERSIONTYPE:PUBKEYID-CREATION */
628 he->tag = RPMTAG_PROVIDENAME;
629 he->t = RPM_STRING_ARRAY_TYPE;
630 he->p.argv = &u;
631 he->c = 1;
632 xx = headerPut(h, he, 0);
633 he->tag = RPMTAG_PROVIDEVERSION;
634 he->t = RPM_STRING_ARRAY_TYPE;
635 he->p.argv = &evr;
636 he->c = 1;
637 xx = headerPut(h, he, 0);
638 he->tag = RPMTAG_PROVIDEFLAGS;
639 he->t = RPM_UINT32_TYPE;
640 he->p.ui32p = &pflags;
641 he->c = 1;
642 xx = headerPut(h, he, 0);
643
644 /* Provides: gpg(PUBKEYID) = PUBKEYVERSION:PUBKEYID-CREATION */
645 he->tag = RPMTAG_PROVIDENAME;
646 he->t = RPM_STRING_ARRAY_TYPE;
647 he->p.argv = &n;
648 he->c = 1;
649 xx = headerPut(h, he, 0);
650 he->tag = RPMTAG_PROVIDEVERSION;
651 he->t = RPM_STRING_ARRAY_TYPE;
652 he->p.argv = &evr;
653 he->c = 1;
654 xx = headerPut(h, he, 0);
655 he->tag = RPMTAG_PROVIDEFLAGS;
656 he->t = RPM_UINT32_TYPE;
657 he->p.ui32p = &pflags;
658 he->c = 1;
659 xx = headerPut(h, he, 0);
660
661 he->append = 0;
662
663 he->tag = RPMTAG_RPMVERSION;
664 he->t = RPM_STRING_TYPE;
665 he->p.str = xstrdup(RPMVERSION);
666 he->c = 1;
667 xx = headerPut(h, he, 0);
668 he->p.ptr = _free(he->p.ptr);
669
670 /* XXX W2DO: tag value inherited from parent? */
671 he->tag = RPMTAG_BUILDHOST;
672 he->t = RPM_STRING_TYPE;
673 he->p.str = xstrdup(buildhost);
674 he->c = 1;
675 xx = headerPut(h, he, 0);
676 he->p.ptr = _free(he->p.ptr);
677
678 { rpmuint32_t tid = rpmtsGetTid(ts);
679 he->tag = RPMTAG_INSTALLTIME;
680 he->t = RPM_UINT32_TYPE;
681 he->p.ui32p = &tid;
682 he->c = 1;
683 xx = headerPut(h, he, 0);
684 /* XXX W2DO: tag value inherited from parent? */
685 he->tag = RPMTAG_BUILDTIME;
686 he->t = RPM_UINT32_TYPE;
687 he->p.ui32p = &tid;
688 he->c = 1;
689 xx = headerPut(h, he, 0);
690 }
691
692 #ifdef NOTYET
693 /* XXX W2DO: tag value inherited from parent? */
694 he->tag = RPMTAG_SOURCERPM;
695 he->t = RPM_STRING_TYPE;
696 he->p.str = fn;
697 he->c = 1;
698 xx = headerPut(h, he, 0);
699 #endif
700
701 /* Add header to database. */
702 xx = rpmdbAdd(rpmtsGetRdb(ts), rpmtsGetTid(ts), h, NULL);
703 if (xx != 0)
704 goto exit;
705 rc = RPMRC_OK;
706
707 exit:
708 /* Clean up. */
709 (void)headerFree(h);
710 h = NULL;
711 dig = pgpDigFree(dig, "rpmcliImportPubkey");
712 n = _free(n);
713 u = _free(u);
714 v = _free(v);
715 r = _free(r);
716 evr = _free(evr);
717 enc = _free(enc);
718 d = _free(d);
719
720 return rc;
721 }
722
731 static int rpmcliImportPubkeys(const rpmts ts,
732 /*@unused@*/ QVA_t qva,
733 /*@null@*/ const char ** argv)
734 /*@globals rpmGlobalMacroContext, h_errno,
735 fileSystem, internalState @*/
736 /*@modifies ts, rpmGlobalMacroContext,
737 fileSystem, internalState @*/
738 {
739 const char * fn;
740 rpmuint8_t * pkt = NULL;
741 size_t pktlen = 0;
742 char * t = NULL;
743 int res = 0;
744 rpmRC rpmrc;
745 int rc;
746
747 if (argv == NULL) return res;
748
749 while ((fn = *argv++) != NULL) {
750
751 rpmtsClean(ts);
752 pkt = _free(pkt);
753 t = _free(t);
754
755 /* If arg looks like a keyid, then attempt keyserver retrieve. */
756 if (fn[0] == '0' && fn[1] == 'x') {
757 const char * s;
758 int i;
759 for (i = 0, s = fn+2; *s && isxdigit(*s); s++, i++)
760 {};
761 if (i == 8 || i == 16) {
762 t = rpmExpand("%{_hkp_keyserver_query}", fn+2, NULL);
763 if (t && *t != '%')
764 fn = t;
765 }
766 }
767
768 /* Read pgp packet. */
769 if ((rc = pgpReadPkts(fn, &pkt, &pktlen)) <= 0) {
770 rpmlog(RPMLOG_ERR, _("%s: import read failed(%d).\n"), fn, rc);
771 res++;
772 continue;
773 }
774 if (rc != PGPARMOR_PUBKEY) {
775 rpmlog(RPMLOG_ERR, _("%s: not an armored public key.\n"), fn);
776 res++;
777 continue;
778 }
779
780 /* Import pubkey packet(s). */
781 if ((rpmrc = rpmcliImportPubkey(ts, pkt, pktlen)) != RPMRC_OK) {
782 rpmlog(RPMLOG_ERR, _("%s: import failed.\n"), fn);
783 res++;
784 continue;
785 }
786
787 }
788
789 rpmtsClean(ts);
790 pkt = _free(pkt);
791 t = _free(t);
792 return res;
793 }
794
798 static rpmRC readFile(FD_t fd, const char * fn)
799 /*@globals fileSystem, internalState @*/
800 /*@modifies fd, fileSystem, internalState @*/
801 {
802 rpmxar xar = fdGetXAR(fd);
803 pgpDig dig = fdGetDig(fd);
804 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
805 unsigned char buf[4*BUFSIZ];
806 ssize_t count;
807 rpmRC rc;
808 int xx;
809
810 dig->nbytes = 0;
811
812 /* Read the header from the package. */
813 { Header h = NULL;
814 const char item[] = "Header";
815 const char * msg = NULL;
816 rc = rpmpkgRead(item, fd, &h, &msg);
817 if (rc != RPMRC_OK) {
818 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
819 msg = _free(msg);
820 goto exit;
821 }
822 msg = _free(msg);
823
824 dig->nbytes += headerSizeof(h);
825
826 if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
827 unsigned char * hmagic = NULL;
828 size_t nmagic = 0;
829
830 he->tag = RPMTAG_HEADERIMMUTABLE;
831 xx = headerGet(h, he, 0);
832 if (!xx || he->p.ptr == NULL) {
833 (void)headerFree(h);
834 h = NULL;
835 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, _("headerGet failed"),
836 _("failed to retrieve original header\n"));
837 rc = RPMRC_FAIL;
838 goto exit;
839 }
840 (void) headerGetMagic(NULL, &hmagic, &nmagic);
841 dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
842 if (hmagic && nmagic > 0)
843 (void) rpmDigestUpdate(dig->hdrsha1ctx, hmagic, nmagic);
844 (void) rpmDigestUpdate(dig->hdrsha1ctx, he->p.ptr, he->c);
845 dig->hdrctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
846 if (hmagic && nmagic > 0)
847 (void) rpmDigestUpdate(dig->hdrctx, hmagic, nmagic);
848 (void) rpmDigestUpdate(dig->hdrctx, he->p.ptr, he->c);
849 he->p.ptr = _free(he->p.ptr);
850 }
851 (void)headerFree(h);
852 h = NULL;
853 }
854
855 if (xar != NULL) {
856 const char item[] = "Payload";
857 if ((xx = rpmxarNext(xar)) != 0 || (xx = rpmxarPull(xar, item)) != 0) {
858 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item,
859 _("XAR file not found (or no XAR support)"));
860 rc = RPMRC_NOTFOUND;
861 goto exit;
862 }
863 }
864
865 /* Read the payload from the package. */
866 while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
867 dig->nbytes += count;
868 if (count < 0 || Ferror(fd)) {
869 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, _("Fread failed"), Fstrerror(fd));
870 rc = RPMRC_FAIL;
871 goto exit;
872 }
873
874 /* XXX Steal the digest-in-progress from the file handle. */
875 fdStealDigest(fd, dig);
876
877 rc = RPMRC_OK; /* XXX unnecessary */
878
879 exit:
880 return rc;
881 }
882
883 int rpmVerifySignatures(QVA_t qva, rpmts ts, void * _fd, const char * fn)
884 {
885 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
886 HE_t she = memset(alloca(sizeof(*she)), 0, sizeof(*she));
887 /*@-castexpose@*/
888 FD_t fd = (FD_t)_fd;
889 /*@=castexpose@*/
890 char result[1024];
891 char buf[8192], * b;
892 char missingKeys[7164], * m;
893 char untrustedKeys[7164], * u;
894 pgpDig dig;
895 pgpDigParams sigp;
896 Header sigh = NULL;
897 HeaderIterator hi = NULL;
898 const char * msg = NULL;
899 int res = 0;
900 int xx;
901 rpmRC rc, sigres;
902 int failed;
903 int nodigests = !(qva->qva_flags & VERIFY_DIGEST);
904 int nosignatures = !(qva->qva_flags & VERIFY_SIGNATURE);
905
906 {
907 { const char item[] = "Lead";
908 msg = NULL;
909 /*@-mods@*/ /* LCL: avoid void * _fd annotation for now. */
910 rc = rpmpkgRead(item, fd, NULL, &msg);
911 /*@=mods@*/
912 if (rc != RPMRC_OK) {
913 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
914 msg = _free(msg);
915 res++;
916 goto exit;
917 }
918 msg = _free(msg);
919 }
920
921 { const char item[] = "Signature";
922 msg = NULL;
923 /*@-mods@*/ /* LCL: avoid void * _fd annotation for now. */
924 rc = rpmpkgRead(item, fd, &sigh, &msg);
925 /*@=mods@*/
926 switch (rc) {
927 default:
928 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item,
929 (msg && *msg ? msg : ""));
930 msg = _free(msg);
931 res++;
932 goto exit;
933 /*@notreached@*/ /*@switchbreak@*/ break;
934 case RPMRC_OK:
935 if (sigh == NULL) {
936 rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
937 res++;
938 goto exit;
939 }
940 /*@switchbreak@*/ break;
941 }
942 msg = _free(msg);
943 }
944
945 /* Grab a hint of what needs doing to avoid duplication. */
946 she->tag = 0;
947 if (she->tag == 0 && !nosignatures) {
948 if (headerIsEntry(sigh, (rpmTag) RPMSIGTAG_DSA))
949 she->tag = (rpmTag) RPMSIGTAG_DSA;
950 else if (headerIsEntry(sigh, (rpmTag) RPMSIGTAG_RSA))
951 she->tag = (rpmTag) RPMSIGTAG_RSA;
952 }
953 if (she->tag == 0 && !nodigests) {
954 if (headerIsEntry(sigh, (rpmTag) RPMSIGTAG_MD5))
955 she->tag = (rpmTag) RPMSIGTAG_MD5;
956 else if (headerIsEntry(sigh, (rpmTag) RPMSIGTAG_SHA1))
957 she->tag = (rpmTag) RPMSIGTAG_SHA1; /* XXX never happens */
958 }
959
960 dig = rpmtsDig(ts);
961 /*@-mods@*/ /* LCL: avoid void * _fd annotation for now. */
962 (void) fdSetDig(fd, dig);
963 /*@=mods@*/
964 sigp = pgpGetSignature(dig);
965
966 /* XXX RSA needs the hash_algo, so decode early. */
967 if ((rpmSigTag) she->tag == RPMSIGTAG_RSA) {
968 he->tag = she->tag;
969 xx = headerGet(sigh, he, 0);
970 xx = pgpPrtPkts(he->p.ptr, he->c, dig, 0);
971 he->p.ptr = _free(he->p.ptr);
972 }
973
974 /*@-mods@*/ /* LCL: avoid void * _fd annotation for now. */
975 if (headerIsEntry(sigh, (rpmTag)RPMSIGTAG_MD5))
976 fdInitDigest(fd, PGPHASHALGO_MD5, 0);
977 /*@=mods@*/
978
979 /* Read the file, generating digest(s) on the fly. */
980 /*@-mods@*/ /* LCL: avoid void * _fd annotation for now. */
981 if (dig == NULL || sigp == NULL
982 || readFile(fd, fn) != RPMRC_OK)
983 {
984 res++;
985 goto exit;
986 }
987 /*@=mods@*/
988
989 failed = 0;
990 b = buf; *b = '\0';
991 m = missingKeys; *m = '\0';
992 u = untrustedKeys; *u = '\0';
993 sprintf(b, "%s:%c", fn, (rpmIsVerbose() ? '\n' : ' ') );
994 b += strlen(b);
995
996 if (sigh != NULL)
997 for (hi = headerInit(sigh);
998 headerNext(hi, she, 0) != 0;
999 she->p.ptr = _free(she->p.ptr))
1000 {
1001
1002 assert(she->p.ptr != NULL);
1003
1004 /* Clean up parameters from previous she->tag. */
1005 pgpDigClean(dig);
1006
1007 /*@-ownedtrans -noeffect@*/
1008 xx = pgpSetSig(dig, she->tag, she->t, she->p.ptr, she->c);
1009 /*@=ownedtrans =noeffect@*/
1010
1011 switch ((rpmSigTag)she->tag) {
1012 case RPMSIGTAG_RSA:
1013 case RPMSIGTAG_DSA:
1014 if (nosignatures)
1015 continue;
1016 xx = pgpPrtPkts(she->p.ptr, she->c, dig,
1017 (_print_pkts & rpmIsDebug()));
1018
1019 if (sigp->version != 3 && sigp->version != 4) {
1020 rpmlog(RPMLOG_ERR,
1021 _("skipping package %s with unverifiable V%u signature\n"),
1022 fn, sigp->version);
1023 res++;
1024 goto exit;
1025 }
1026 /*@switchbreak@*/ break;
1027 case RPMSIGTAG_SHA1:
1028 if (nodigests)
1029 continue;
1030 /* XXX Don't bother with header sha1 if header dsa. */
1031 if (!nosignatures && (rpmSigTag)she->tag == RPMSIGTAG_DSA)
1032 continue;
1033 /*@switchbreak@*/ break;
1034 case RPMSIGTAG_MD5:
1035 if (nodigests)
1036 continue;
1037 /*@switchbreak@*/ break;
1038 default:
1039 continue;
1040 /*@notreached@*/ /*@switchbreak@*/ break;
1041 }
1042
1043 sigres = rpmVerifySignature(dig, result);
1044
1045 if (sigres) {
1046 failed = 1;
1047 if (rpmIsVerbose())
1048 b = stpcpy( stpcpy( stpcpy(b, " "), result), "\n");
1049 else
1050 switch ((rpmSigTag)she->tag) {
1051 case RPMSIGTAG_SIZE:
1052 b = stpcpy(b, "SIZE ");
1053 /*@switchbreak@*/ break;
1054 case RPMSIGTAG_SHA1:
1055 b = stpcpy(b, "SHA1 ");
1056 /*@switchbreak@*/ break;
1057 case RPMSIGTAG_MD5:
1058 b = stpcpy(b, "MD5 ");
1059 /*@switchbreak@*/ break;
1060 case RPMSIGTAG_RSA:
1061 b = stpcpy(b, "RSA ");
1062 /*@switchbreak@*/ break;
1063 case RPMSIGTAG_DSA:
1064 b = stpcpy(b, "(SHA1) DSA ");
1065 /*@switchbreak@*/ break;
1066 default:
1067 b = stpcpy(b, "?UnknownSignatureType? ");
1068 /*@switchbreak@*/ break;
1069 }
1070 } else {
1071 if (rpmIsVerbose())
1072 b = stpcpy( stpcpy( stpcpy(b, " "), result), "\n");
1073 else
1074 switch ((rpmSigTag)she->tag) {
1075 case RPMSIGTAG_SIZE:
1076 b = stpcpy(b, "size ");
1077 /*@switchbreak@*/ break;
1078 case RPMSIGTAG_SHA1:
1079 b = stpcpy(b, "sha1 ");
1080 /*@switchbreak@*/ break;
1081 case RPMSIGTAG_MD5:
1082 b = stpcpy(b, "md5 ");
1083 /*@switchbreak@*/ break;
1084 case RPMSIGTAG_RSA:
1085 b = stpcpy(b, "rsa ");
1086 /*@switchbreak@*/ break;
1087 case RPMSIGTAG_DSA:
1088 b = stpcpy(b, "(sha1) dsa ");
1089 /*@switchbreak@*/ break;
1090 default:
1091 b = stpcpy(b, "??? ");
1092 /*@switchbreak@*/ break;
1093 }
1094 }
1095 }
1096 hi = headerFini(hi);
1097 /* XXX clear the already free'd signature data. */
1098 /*@-noeffect@*/
1099 xx = pgpSetSig(dig, 0, 0, NULL, 0);
1100 /*@=noeffect@*/
1101
1102 res += failed;
1103
1104 if (failed) {
1105 if (rpmIsVerbose()) {
1106 rpmlog(RPMLOG_NOTICE, "%s", buf);
1107 } else {
1108 rpmlog(RPMLOG_NOTICE, "%s%s%s%s%s%s%s%s\n", buf,
1109 _("NOT_OK"),
1110 (missingKeys[0] != '\0') ? _(" (MISSING KEYS:") : "",
1111 missingKeys,
1112 (missingKeys[0] != '\0') ? _(") ") : "",
1113 (untrustedKeys[0] != '\0') ? _(" (UNTRUSTED KEYS:") : "",
1114 untrustedKeys,
1115 (untrustedKeys[0] != '\0') ? _(")") : "");
1116
1117 }
1118 } else {
1119 if (rpmIsVerbose()) {
1120 rpmlog(RPMLOG_NOTICE, "%s", buf);
1121 } else {
1122 rpmlog(RPMLOG_NOTICE, "%s%s%s%s%s%s%s%s\n", buf,
1123 _("OK"),
1124 (missingKeys[0] != '\0') ? _(" (MISSING KEYS:") : "",
1125 missingKeys,
1126 (missingKeys[0] != '\0') ? _(") ") : "",
1127 (untrustedKeys[0] != '\0') ? _(" (UNTRUSTED KEYS:") : "",
1128 untrustedKeys,
1129 (untrustedKeys[0] != '\0') ? _(")") : "");
1130 }
1131 }
1132
1133 }
1134
1135 exit:
1136 rpmtsCleanDig(ts);
1137 (void)headerFree(sigh);
1138 sigh = NULL;
1139 return res;
1140 }
1141
1142 int rpmcliSign(rpmts ts, QVA_t qva, const char ** argv)
1143 /*@globals rpmioFtsOpts @*/
1144 /*@modifies rpmioFtsOpts @*/
1145 {
1146 int res = 0;
1147
1148 if (argv == NULL) return res;
1149
1150 switch (qva->qva_mode) {
1151 case RPMSIGN_CHK_SIGNATURE:
1152 break;
1153 case RPMSIGN_IMPORT_PUBKEY:
1154 return rpmcliImportPubkeys(ts, qva, argv);
1155 /*@notreached@*/ break;
1156 case RPMSIGN_NEW_SIGNATURE:
1157 case RPMSIGN_ADD_SIGNATURE:
1158 case RPMSIGN_DEL_SIGNATURE:
1159 return rpmReSign(ts, qva, argv);
1160 /*@notreached@*/ break;
1161 case RPMSIGN_NONE:
1162 default:
1163 return -1;
1164 /*@notreached@*/ break;
1165 }
1166
1167 { /* start-of-arg-iteration */
1168
1169 int tag = (qva->qva_source == RPMQV_FTSWALK)
1170 ? RPMDBI_FTSWALK : RPMDBI_ARGLIST;
1171 rpmgi gi = rpmgiNew(ts, tag, NULL, 0);
1172 rpmgiFlags _giFlags = RPMGI_NONE;
1173 rpmRC rc;
1174
1175 if (rpmioFtsOpts == 0)
1176 rpmioFtsOpts = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
1177 rc = rpmgiSetArgs(gi, argv, rpmioFtsOpts, (_giFlags|RPMGI_NOHEADER));
1178 while (rpmgiNext(gi) == RPMRC_OK) {
1179 const char * fn = rpmgiHdrPath(gi);
1180 FD_t fd;
1181 int xx;
1182
1183 fd = Fopen(fn, "r.fdio");
1184 if (fd == NULL || Ferror(fd)) {
1185 rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"),
1186 fn, Fstrerror(fd));
1187 res++;
1188 } else if (rpmVerifySignatures(qva, ts, fd, fn)) {
1189 res++;
1190 }
1191
1192 if (fd != NULL) {
1193 xx = Fclose(fd);
1194 }
1195 }
1196
1197 gi = rpmgiFree(gi);
1198
1199 } /* end-of-arg-iteration */
1200
1201 return res;
1202 }