rpm 5.2.1

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

- File List
- Globals

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++;
74 nextkeyid %= nkeyids_max;
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;
93 rpmVSFlags vsflags;
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;
155 if (_chk(RPMVSF_NODSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_DSA)) {
156 she->tag = (rpmTag)RPMSIGTAG_DSA;
157 } else
158 if (_chk(RPMVSF_NORSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_RSA)) {
159 she->tag = (rpmTag)RPMSIGTAG_RSA;
160 } else
161 if (_chk(RPMVSF_NOSHA1HEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_SHA1)) {
162 she->tag = (rpmTag)RPMSIGTAG_SHA1;
163 } else
164 if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD) &&
165 headerIsEntry(sigh, (rpmTag)RPMSIGTAG_MD5))
166 {
167 she->tag = (rpmTag)RPMSIGTAG_MD5;
168 fdInitDigest(fd, PGPHASHALGO_MD5, 0);
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) {
227 rpmlog(RPMLOG_ERR,
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
239 he->tag = RPMTAG_HEADERIMMUTABLE;
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) {
264 rpmlog(RPMLOG_ERR,
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
278 he->tag = RPMTAG_HEADERIMMUTABLE;
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@*/