rpm  5.2.1
package.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #include <netinet/in.h>
8 
9 #include <rpmio_internal.h>
10 #include <rpmcb.h> /* XXX fnpyKey */
11 
12 #include <rpmtag.h>
13 #include <rpmtypes.h>
14 #include <pkgio.h>
15 #include "signature.h" /* XXX rpmVerifySignature */
16 
17 #include "rpmts.h"
18 
19 #include "debug.h"
20 
21 #define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s))
22 
23 /*@access pgpDig @*/
24 /*@access pgpDigParams @*/
25 /*@access Header @*/ /* XXX compared with NULL */
26 /*@access FD_t @*/ /* XXX void * */
27 
28 /*@unchecked@*/
29 static int _print_pkts = 0;
30 
31 /*@unchecked@*/
32 static unsigned int nkeyids_max = 256;
33 /*@unchecked@*/
34 static unsigned int nkeyids = 0;
35 /*@unchecked@*/
36 static unsigned int nextkeyid = 0;
37 /*@unchecked@*/ /*@only@*/ /*@null@*/
38 unsigned int * keyids = NULL;
39 
45 static int pgpStashKeyid(pgpDig dig)
46  /*@globals nextkeyid, nkeyids, keyids @*/
47  /*@modifies nextkeyid, nkeyids, keyids @*/
48 {
49  pgpDigParams sigp = pgpGetSignature(dig);
50  const void * sig = pgpGetSig(dig);
51  unsigned int keyid;
52  unsigned int i;
53 
54  if (sig == NULL || dig == NULL || sigp == NULL)
55  return 0;
56 
57  keyid = pgpGrab(sigp->signid+4, 4);
58  if (keyid == 0)
59  return 0;
60 
61  if (keyids != NULL)
62  for (i = 0; i < nkeyids; i++) {
63  if (keyid == keyids[i])
64  return 1;
65  }
66 
67  if (nkeyids < nkeyids_max) {
68  nkeyids++;
69  keyids = xrealloc(keyids, nkeyids * sizeof(*keyids));
70  }
71  if (keyids) /* XXX can't happen */
72  keyids[nextkeyid] = keyid;
73  nextkeyid++;
75 
76  return 0;
77 }
78 
79 /*@-mods@*/
80 rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp)
81 {
82  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
83  HE_t she = memset(alloca(sizeof(*she)), 0, sizeof(*she));
84  pgpDig dig = rpmtsDig(ts);
85  char buf[8*BUFSIZ];
86  ssize_t count;
87  Header sigh = NULL;
88  rpmtsOpX opx;
89  rpmop op = NULL;
90  size_t nb;
91  Header h = NULL;
92  const char * msg = NULL;
94  rpmRC rc = RPMRC_FAIL; /* assume failure */
95  rpmop opsave = memset(alloca(sizeof(*opsave)), 0, sizeof(*opsave));
96  int xx;
97 
98  if (hdrp) *hdrp = NULL;
99 
100 assert(dig != NULL);
101  (void) fdSetDig(fd, dig);
102 
103  /* Snapshot current I/O counters (cached persistent I/O reuses counters) */
104  (void) rpmswAdd(opsave, fdstat_op(fd, FDSTAT_READ));
105 
106  { const char item[] = "Lead";
107  msg = NULL;
108  rc = rpmpkgRead(item, fd, NULL, &msg);
109  switch (rc) {
110  default:
111  rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
112  /*@fallthrough@*/
113  case RPMRC_NOTFOUND:
114  msg = _free(msg);
115  goto exit;
116  /*@notreached@*/ break;
117  case RPMRC_OK:
118  break;
119  }
120  msg = _free(msg);
121  }
122 
123  { const char item[] = "Signature";
124  msg = NULL;
125  rc = rpmpkgRead(item, fd, &sigh, &msg);
126  switch (rc) {
127  default:
128  rpmlog(RPMLOG_ERR, "%s: %s: %s", fn, item,
129  (msg && *msg ? msg : _("read failed\n")));
130  msg = _free(msg);
131  goto exit;
132  /*@notreached@*/ break;
133  case RPMRC_OK:
134  if (sigh == NULL) {
135  rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
136  rc = RPMRC_FAIL;
137  goto exit;
138  }
139  break;
140  }
141  msg = _free(msg);
142  }
143 
144 #define _chk(_mask) (she->tag == 0 && !(vsflags & (_mask)))
145 
146  /*
147  * Figger the most effective available signature.
148  * Prefer signatures over digests, then header-only over header+payload.
149  * DSA will be preferred over RSA if both exist because tested first.
150  * Note that NEEDPAYLOAD prevents header+payload signatures and digests.
151  */
152  she->tag = 0;
153  opx = 0;
154  vsflags = pgpDigVSFlags;
156  she->tag = (rpmTag)RPMSIGTAG_DSA;
157  } else
159  she->tag = (rpmTag)RPMSIGTAG_RSA;
160  } else
162  she->tag = (rpmTag)RPMSIGTAG_SHA1;
163  } else
166  {
167  she->tag = (rpmTag)RPMSIGTAG_MD5;
169  opx = RPMTS_OP_DIGEST;
170  }
171 
172  /* Read the metadata, computing digest(s) on the fly. */
173  h = NULL;
174  msg = NULL;
175 
176  /* XXX stats will include header i/o and setup overhead. */
177  /* XXX repackaged packages have appended tags, legacy dig/sig check fails */
178  if (opx > 0) {
179  op = pgpStatsAccumulator(dig, opx);
180  (void) rpmswEnter(op, 0);
181  }
182 /*@-type@*/ /* XXX arrow access of non-pointer (FDSTAT_t) */
183  nb = fd->stats->ops[FDSTAT_READ].bytes;
184  { const char item[] = "Header";
185  msg = NULL;
186  rc = rpmpkgRead(item, fd, &h, &msg);
187  if (rc != RPMRC_OK) {
188  rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
189  msg = _free(msg);
190  goto exit;
191  }
192  msg = _free(msg);
193  }
194  nb = fd->stats->ops[FDSTAT_READ].bytes - nb;
195 /*@=type@*/
196  if (opx > 0 && op != NULL) {
197  (void) rpmswExit(op, nb);
198  op = NULL;
199  }
200 
201  /* Any digests or signatures to check? */
202  if (she->tag == 0) {
203  rc = RPMRC_OK;
204  goto exit;
205  }
206 
207  dig->nbytes = 0;
208 
209  /* Retrieve the tag parameters from the signature header. */
210  xx = headerGet(sigh, she, 0);
211  if (she->p.ptr == NULL) {
212  rc = RPMRC_FAIL;
213  goto exit;
214  }
215 /*@-ownedtrans -noeffect@*/
216  xx = pgpSetSig(dig, she->tag, she->t, she->p.ptr, she->c);
217 /*@=ownedtrans =noeffect@*/
218 
219  switch ((rpmSigTag)she->tag) {
220  default: /* XXX keep gcc quiet. */
221 assert(0);
222  /*@notreached@*/ break;
223  case RPMSIGTAG_RSA:
224  /* Parse the parameters from the OpenPGP packets that will be needed. */
225  xx = pgpPrtPkts(she->p.ptr, she->c, dig, (_print_pkts & rpmIsDebug()));
226  if (dig->signature.version != 3 && dig->signature.version != 4) {
228  _("skipping package %s with unverifiable V%u signature\n"),
229  fn, dig->signature.version);
230  rc = RPMRC_FAIL;
231  goto exit;
232  }
233  { void * uh = NULL;
234  rpmTagType uht;
235  rpmTagCount uhc;
236  unsigned char * hmagic = NULL;
237  size_t nmagic = 0;
238 
240  xx = headerGet(h, he, 0);
241  uht = he->t;
242  uh = he->p.ptr;
243  uhc = he->c;
244  if (!xx)
245  break;
246  (void) headerGetMagic(NULL, &hmagic, &nmagic);
247  op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
248  (void) rpmswEnter(op, 0);
249  dig->hdrctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
250  if (hmagic && nmagic > 0) {
251  (void) rpmDigestUpdate(dig->hdrctx, hmagic, nmagic);
252  dig->nbytes += nmagic;
253  }
254  (void) rpmDigestUpdate(dig->hdrctx, uh, uhc);
255  dig->nbytes += uhc;
256  (void) rpmswExit(op, dig->nbytes);
257  op->count--; /* XXX one too many */
258  uh = _free(uh);
259  } break;
260  case RPMSIGTAG_DSA:
261  /* Parse the parameters from the OpenPGP packets that will be needed. */
262  xx = pgpPrtPkts(she->p.ptr, she->c, dig, (_print_pkts & rpmIsDebug()));
263  if (dig->signature.version != 3 && dig->signature.version != 4) {
265  _("skipping package %s with unverifiable V%u signature\n"),
266  fn, dig->signature.version);
267  rc = RPMRC_FAIL;
268  goto exit;
269  }
270  /*@fallthrough@*/
271  case RPMSIGTAG_SHA1:
272  { void * uh = NULL;
273  rpmTagType uht;
274  rpmTagCount uhc;
275  unsigned char * hmagic = NULL;
276  size_t nmagic = 0;
277 
279  xx = headerGet(h, he, 0);
280  uht = he->t;
281  uh = he->p.ptr;
282  uhc = he->c;
283  if (!xx)
284  break;
285  (void) headerGetMagic(NULL, &hmagic, &nmagic);
286  op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
287  (void) rpmswEnter(op, 0);
288  dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
289  if (hmagic && nmagic > 0) {
290  (void) rpmDigestUpdate(dig->hdrsha1ctx, hmagic, nmagic);
291  dig->nbytes += nmagic;
292  }
293  (void) rpmDigestUpdate(dig->hdrsha1ctx, uh, uhc);
294  dig->nbytes += uhc;
295  (void) rpmswExit(op, dig->nbytes);
296  if ((rpmSigTag)she->tag == RPMSIGTAG_SHA1)
297  op->count--; /* XXX one too many */
298  uh = _free(uh);
299  } break;
300  case RPMSIGTAG_MD5:
301  /* Legacy signatures need the compressed payload in the digest too. */
302  op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
303  (void) rpmswEnter(op, 0);
304  while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
305  dig->nbytes += count;
306  (void) rpmswExit(op, dig->nbytes);
307  op->count--; /* XXX one too many */
308  dig->nbytes += nb; /* XXX include size of header blob. */
309  if (count < 0) {
310  rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"),
311  fn, Fstrerror(fd));
312  rc = RPMRC_FAIL;
313  goto exit;
314  }
315 
316  /* XXX Steal the digest-in-progress from the file handle. */
317  fdStealDigest(fd, dig);
318  break;
319  }
320 
323  buf[0] = '\0';
324  rc = rpmVerifySignature(dig, buf);
325  switch (rc) {
326  case RPMRC_OK: /* Signature is OK. */
327  rpmlog(RPMLOG_DEBUG, "%s: %s\n", fn, buf);
328  break;
329  case RPMRC_NOTTRUSTED: /* Signature is OK, but key is not trusted. */
330  case RPMRC_NOKEY: /* Public key is unavailable. */
331  /* XXX Print NOKEY/NOTTRUSTED warning only once. */
332  { int lvl = (pgpStashKeyid(dig) ? RPMLOG_DEBUG : RPMLOG_WARNING);
333  rpmlog(lvl, "%s: %s\n", fn, buf);
334  } break;
335  case RPMRC_NOTFOUND: /* Signature is unknown type. */
336  rpmlog(RPMLOG_WARNING, "%s: %s\n", fn, buf);
337  break;
338  default:
339  case RPMRC_FAIL: /* Signature does not verify. */
340  rpmlog(RPMLOG_ERR, "%s: %s\n", fn, buf);
341  break;
342  }
343 
344 exit:
345  if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) {
346 
347  /* Append (and remap) signature tags to the metadata. */
348  headerMergeLegacySigs(h, sigh);
349 
350  /* Bump reference count for return. */
351  *hdrp = headerLink(h);
352  }
353  (void)headerFree(h);
354  h = NULL;
355 
356  /* Accumulate time reading package header. */
357  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_READHDR),
358  fdstat_op(fd, FDSTAT_READ));
359  (void) rpmswSub(rpmtsOp(ts, RPMTS_OP_READHDR),
360  opsave);
361 
362  rpmtsCleanDig(ts);
363  (void)headerFree(sigh);
364  sigh = NULL;
365  return rc;
366 }
367 /*@=mods@*/