rpm  5.2.1
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)
207  rpmgiFlags _giFlags = RPMGI_NONE;
208 
209  gi = rpmgiNew(ts, tag, NULL, 0);
210 /*@-mods@*/
211  if (rpmioFtsOpts == 0)
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). */
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. */
305  xx = headerDel(sigh, he, 0);
307  xx = headerDel(sigh, he, 0);
309  xx = headerDel(sigh, he, 0);
311  xx = headerDel(sigh, he, 0);
312 
313  /* Toss and recalculate header+payload size and digests. */
314  { static const rpmuint32_t sigs[] =
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[] =
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 
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. */
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);
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);
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 
827  unsigned char * hmagic = NULL;
828  size_t nmagic = 0;
829 
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))
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) {
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)
1171  rpmgi gi = rpmgiNew(ts, tag, NULL, 0);
1172  rpmgiFlags _giFlags = RPMGI_NONE;
1173  rpmRC rc;
1174 
1175  if (rpmioFtsOpts == 0)
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 }