splint fiddles, no warnings.
[platform/upstream/rpm.git] / lib / package.c
1 /** \ingroup header
2  * \file lib/package.c
3  */
4
5 #include "system.h"
6
7 #include <netinet/in.h>
8
9 #include <rpmio_internal.h>
10 #include <rpmlib.h>
11
12 #include "rpmts.h"
13
14 #include "misc.h"       /* XXX stripTrailingChar() */
15 #include "legacy.h"     /* XXX legacyRetrofit() */
16 #include "rpmlead.h"
17
18 #include "header_internal.h"    /* XXX headerCheck */
19 #include "signature.h"
20 #include "debug.h"
21
22 #define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
23
24 /*@access pgpDig @*/
25 /*@access pgpDigParams @*/
26 /*@access Header @*/            /* XXX compared with NULL */
27 /*@access entryInfo @*/         /* XXX headerCheck */
28 /*@access indexEntry @*/        /* XXX headerCheck */
29 /*@access FD_t @*/              /* XXX stealing digests */
30
31 /*@unchecked@*/
32 static int _print_pkts = 0;
33
34 /*@unchecked@*/
35 static unsigned int nkeyids_max = 256;
36 /*@unchecked@*/
37 static unsigned int nkeyids = 0;
38 /*@unchecked@*/
39 static unsigned int nextkeyid  = 0;
40 /*@unchecked@*/ /*@only@*/ /*@null@*/
41 static unsigned int * keyids;
42
43 /*@unchecked@*/
44 static unsigned char header_magic[8] = {
45         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
46 };
47
48 /**
49  * Alignment needs (and sizeof scalars types) for internal rpm data types.
50  */
51 /*@observer@*/ /*@unchecked@*/
52 static int typeAlign[16] =  {
53     1,  /*!< RPM_NULL_TYPE */
54     1,  /*!< RPM_CHAR_TYPE */
55     1,  /*!< RPM_INT8_TYPE */
56     2,  /*!< RPM_INT16_TYPE */
57     4,  /*!< RPM_INT32_TYPE */
58     8,  /*!< RPM_INT64_TYPE */
59     1,  /*!< RPM_STRING_TYPE */
60     1,  /*!< RPM_BIN_TYPE */
61     1,  /*!< RPM_STRING_ARRAY_TYPE */
62     1,  /*!< RPM_I18NSTRING_TYPE */
63     0,
64     0,
65     0,
66     0,
67     0,
68     0
69 };
70
71 /**
72  * Sanity check on no. of tags.
73  * This check imposes a limit of 65K tags, more than enough.
74  */
75 #define hdrchkTags(_ntags)      ((_ntags) & 0xffff0000)
76
77 /**
78  * Sanity check on type values.
79  */
80 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
81
82 /**
83  * Sanity check on data size and/or offset and/or count.
84  * This check imposes a limit of 16 MB, more than enough.
85  */
86 #define hdrchkData(_nbytes) ((_nbytes) & 0xff000000)
87
88 /**
89  * Sanity check on data alignment for data type.
90  */
91 #define hdrchkAlign(_type, _off)        ((_off) & (typeAlign[_type]-1))
92
93 /**
94  * Sanity check on range of data offset.
95  */
96 #define hdrchkRange(_dl, _off)          ((_off) < 0 || (_off) > (_dl))
97
98 void headerMergeLegacySigs(Header h, const Header sigh)
99 {
100     HFD_t hfd = (HFD_t) headerFreeData;
101     HAE_t hae = (HAE_t) headerAddEntry;
102     HeaderIterator hi;
103     int_32 tag, type, count;
104     const void * ptr;
105     int xx;
106
107     for (hi = headerInitIterator(sigh);
108         headerNextIterator(hi, &tag, &type, &ptr, &count);
109         ptr = hfd(ptr, type))
110     {
111         switch (tag) {
112         /* XXX Translate legacy signature tag values. */
113         case RPMSIGTAG_SIZE:
114             tag = RPMTAG_SIGSIZE;
115             /*@switchbreak@*/ break;
116         case RPMSIGTAG_LEMD5_1:
117             tag = RPMTAG_SIGLEMD5_1;
118             /*@switchbreak@*/ break;
119         case RPMSIGTAG_PGP:
120             tag = RPMTAG_SIGPGP;
121             /*@switchbreak@*/ break;
122         case RPMSIGTAG_LEMD5_2:
123             tag = RPMTAG_SIGLEMD5_2;
124             /*@switchbreak@*/ break;
125         case RPMSIGTAG_MD5:
126             tag = RPMTAG_SIGMD5;
127             /*@switchbreak@*/ break;
128         case RPMSIGTAG_GPG:
129             tag = RPMTAG_SIGGPG;
130             /*@switchbreak@*/ break;
131         case RPMSIGTAG_PGP5:
132             tag = RPMTAG_SIGPGP5;
133             /*@switchbreak@*/ break;
134         case RPMSIGTAG_PAYLOADSIZE:
135             tag = RPMTAG_ARCHIVESIZE;
136             /*@switchbreak@*/ break;
137         case RPMSIGTAG_SHA1:
138         case RPMSIGTAG_DSA:
139         case RPMSIGTAG_RSA:
140         default:
141             if (!(tag >= HEADER_SIGBASE && tag < HEADER_TAGBASE))
142                 continue;
143             /*@switchbreak@*/ break;
144         }
145         if (ptr == NULL) continue;      /* XXX can't happen */
146         if (!headerIsEntry(h, tag)) {
147             if (hdrchkType(type))
148                 continue;
149             if (count < 0 || hdrchkData(count))
150                 continue;
151             switch(type) {
152             case RPM_NULL_TYPE:
153                 continue;
154                 /*@notreached@*/ /*@switchbreak@*/ break;
155             case RPM_CHAR_TYPE:
156             case RPM_INT8_TYPE:
157             case RPM_INT16_TYPE:
158             case RPM_INT32_TYPE:
159                 if (count != 1)
160                     continue;
161                 /*@switchbreak@*/ break;
162             case RPM_STRING_TYPE:
163             case RPM_BIN_TYPE:
164                 if (count >= 16*1024)
165                     continue;
166                 /*@switchbreak@*/ break;
167             case RPM_STRING_ARRAY_TYPE:
168             case RPM_I18NSTRING_TYPE:
169                 continue;
170                 /*@notreached@*/ /*@switchbreak@*/ break;
171             }
172             xx = hae(h, tag, type, ptr, count);
173         }
174     }
175     hi = headerFreeIterator(hi);
176 }
177
178 Header headerRegenSigHeader(const Header h, int noArchiveSize)
179 {
180     HFD_t hfd = (HFD_t) headerFreeData;
181     Header sigh = rpmNewSignature();
182     HeaderIterator hi;
183     int_32 tag, stag, type, count;
184     const void * ptr;
185     int xx;
186
187     for (hi = headerInitIterator(h);
188         headerNextIterator(hi, &tag, &type, &ptr, &count);
189         ptr = hfd(ptr, type))
190     {
191         switch (tag) {
192         /* XXX Translate legacy signature tag values. */
193         case RPMTAG_SIGSIZE:
194             stag = RPMSIGTAG_SIZE;
195             /*@switchbreak@*/ break;
196         case RPMTAG_SIGLEMD5_1:
197             stag = RPMSIGTAG_LEMD5_1;
198             /*@switchbreak@*/ break;
199         case RPMTAG_SIGPGP:
200             stag = RPMSIGTAG_PGP;
201             /*@switchbreak@*/ break;
202         case RPMTAG_SIGLEMD5_2:
203             stag = RPMSIGTAG_LEMD5_2;
204             /*@switchbreak@*/ break;
205         case RPMTAG_SIGMD5:
206             stag = RPMSIGTAG_MD5;
207             /*@switchbreak@*/ break;
208         case RPMTAG_SIGGPG:
209             stag = RPMSIGTAG_GPG;
210             /*@switchbreak@*/ break;
211         case RPMTAG_SIGPGP5:
212             stag = RPMSIGTAG_PGP5;
213             /*@switchbreak@*/ break;
214         case RPMTAG_ARCHIVESIZE:
215             /* XXX rpm-4.1 and later has archive size in signature header. */
216             if (noArchiveSize)
217                 continue;
218             stag = RPMSIGTAG_PAYLOADSIZE;
219             /*@switchbreak@*/ break;
220         case RPMTAG_SHA1HEADER:
221         case RPMTAG_DSAHEADER:
222         case RPMTAG_RSAHEADER:
223         default:
224             if (!(tag >= HEADER_SIGBASE && tag < HEADER_TAGBASE))
225                 continue;
226             stag = tag;
227             /*@switchbreak@*/ break;
228         }
229         if (ptr == NULL) continue;      /* XXX can't happen */
230         if (!headerIsEntry(sigh, stag))
231             xx = headerAddEntry(sigh, stag, type, ptr, count);
232     }
233     hi = headerFreeIterator(hi);
234     return sigh;
235 }
236
237 /**
238  * Remember current key id.
239  * @param ts            transaction set
240  * @return              0 if new keyid, otherwise 1
241  */
242 static int rpmtsStashKeyid(rpmts ts)
243         /*@globals nextkeyid, nkeyids, keyids @*/
244         /*@modifies nextkeyid, nkeyids, keyids @*/
245 {
246     const void * sig = rpmtsSig(ts);
247     pgpDig dig = rpmtsDig(ts);
248     pgpDigParams sigp = rpmtsSignature(ts);
249     unsigned int keyid;
250     int i;
251
252     if (sig == NULL || dig == NULL || sigp == NULL)
253         return 0;
254
255     keyid = pgpGrab(sigp->signid+4, 4);
256     if (keyid == 0)
257         return 0;
258
259     if (keyids != NULL)
260     for (i = 0; i < nkeyids; i++) {
261 /*@-boundsread@*/
262         if (keyid == keyids[i])
263             return 1;
264 /*@=boundsread@*/
265     }
266
267     if (nkeyids < nkeyids_max) {
268         nkeyids++;
269         keyids = xrealloc(keyids, nkeyids * sizeof(*keyids));
270     }
271 /*@-boundswrite@*/
272     if (keyids)         /* XXX can't happen */
273         keyids[nextkeyid] = keyid;
274 /*@=boundswrite@*/
275     nextkeyid++;
276     nextkeyid %= nkeyids_max;
277
278     return 0;
279 }
280
281 int headerVerifyInfo(int il, int dl, const void * pev, void * iv, int negate)
282 {
283 /*@-castexpose@*/
284     entryInfo pe = (entryInfo) pev;
285 /*@=castexpose@*/
286     entryInfo info = iv;
287     int i;
288
289 /*@-boundsread@*/
290     for (i = 0; i < il; i++) {
291         info->tag = ntohl(pe[i].tag);
292         info->type = ntohl(pe[i].type);
293         info->offset = ntohl(pe[i].offset);
294         if (negate)
295             info->offset = -info->offset;
296         info->count = ntohl(pe[i].count);
297
298         if (hdrchkType(info->type))
299             return i;
300         if (hdrchkAlign(info->type, info->offset))
301             return i;
302         if (!negate && hdrchkRange(dl, info->offset))
303             return i;
304         if (hdrchkData(info->count))
305             return i;
306
307     }
308 /*@=boundsread@*/
309     return -1;
310 }
311
312 /**
313  * Check header consistency, performing headerGetEntry() the hard way.
314  *
315  * Sanity checks on the header are performed while looking for a
316  * header-only digest or signature to verify the blob. If found,
317  * the digest or signature is verified.
318  *
319  * @param ts            transaction set
320  * @param uh            unloaded header blob
321  * @param uc            no. of bytes in blob (or 0 to disable)
322  * @retval *msg         signature verification msg
323  * @return              RPMRC_OK/RPMRC_NOTFOUND/RPMRC_FAIL
324  */
325 rpmRC headerCheck(rpmts ts, const void * uh, size_t uc, const char ** msg)
326 {
327     pgpDig dig;
328     unsigned char buf[8*BUFSIZ];
329     int_32 * ei = (int_32 *) uh;
330 /*@-boundsread@*/
331     int_32 il = ntohl(ei[0]);
332     int_32 dl = ntohl(ei[1]);
333 /*@-castexpose@*/
334     entryInfo pe = (entryInfo) &ei[2];
335 /*@=castexpose@*/
336 /*@=boundsread@*/
337     int_32 ildl[2];
338     int_32 pvlen = sizeof(ildl) + (il * sizeof(*pe)) + dl;
339     unsigned char * dataStart = (unsigned char *) (pe + il);
340     indexEntry entry = memset(alloca(sizeof(*entry)), 0, sizeof(*entry));
341     entryInfo info = memset(alloca(sizeof(*info)), 0, sizeof(*info));
342     const void * sig = NULL;
343     const char * b;
344     rpmVSFlags vsflags = rpmtsVSFlags(ts);
345     int siglen = 0;
346     int blen;
347     size_t nb;
348     int_32 ril = 0;
349     unsigned char * regionEnd = NULL;
350     rpmRC rc = RPMRC_FAIL;      /* assume failure */
351     int xx;
352     int i;
353
354 /*@-boundswrite@*/
355     buf[0] = '\0';
356 /*@=boundswrite@*/
357
358     /* Is the blob the right size? */
359     if (uc > 0 && pvlen != uc) {
360         (void) snprintf(buf, sizeof(buf),
361                 _("blob size(%d): BAD, 8 + 16 * il(%d) + dl(%d)\n"),
362                 (int)uc, (int)il, (int)dl);
363         goto exit;
364     }
365
366     /* Check (and convert) the 1st tag element. */
367     xx = headerVerifyInfo(1, dl, pe, &entry->info, 0);
368     if (xx != -1) {
369         (void) snprintf(buf, sizeof(buf),
370                 _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
371                 0, entry->info.tag, entry->info.type,
372                 entry->info.offset, entry->info.count);
373         goto exit;
374     }
375
376     /* Is there an immutable header region tag? */
377 /*@-sizeoftype@*/
378     if (!(entry->info.tag == RPMTAG_HEADERIMMUTABLE
379        && entry->info.type == RPM_BIN_TYPE
380        && entry->info.count == REGION_TAG_COUNT))
381     {
382         rc = RPMRC_NOTFOUND;
383         goto exit;
384     }
385 /*@=sizeoftype@*/
386
387     /* Is the offset within the data area? */
388     if (entry->info.offset >= dl) {
389         (void) snprintf(buf, sizeof(buf),
390                 _("region offset: BAD, tag %d type %d offset %d count %d\n"),
391                 entry->info.tag, entry->info.type,
392                 entry->info.offset, entry->info.count);
393         goto exit;
394     }
395
396     /* Is there an immutable header region tag trailer? */
397     regionEnd = dataStart + entry->info.offset;
398 /*@-sizeoftype@*/
399 /*@-bounds@*/
400     (void) memcpy(info, regionEnd, REGION_TAG_COUNT);
401 /*@=bounds@*/
402     regionEnd += REGION_TAG_COUNT;
403
404     xx = headerVerifyInfo(1, dl, info, &entry->info, 1);
405     if (xx != -1 ||
406         !(entry->info.tag == RPMTAG_HEADERIMMUTABLE
407        && entry->info.type == RPM_BIN_TYPE
408        && entry->info.count == REGION_TAG_COUNT))
409     {
410         (void) snprintf(buf, sizeof(buf),
411                 _("region trailer: BAD, tag %d type %d offset %d count %d\n"),
412                 entry->info.tag, entry->info.type,
413                 entry->info.offset, entry->info.count);
414         goto exit;
415     }
416 /*@=sizeoftype@*/
417 /*@-boundswrite@*/
418     memset(info, 0, sizeof(*info));
419 /*@=boundswrite@*/
420
421     /* Is the no. of tags in the region less than the total no. of tags? */
422     ril = entry->info.offset/sizeof(*pe);
423     if ((entry->info.offset % sizeof(*pe)) || ril > il) {
424         (void) snprintf(buf, sizeof(buf),
425                 _("region size: BAD, ril(%d) > il(%d)\n"), ril, il);
426         goto exit;
427     }
428
429     /* Find a header-only digest/signature tag. */
430     for (i = ril; i < il; i++) {
431         xx = headerVerifyInfo(1, dl, pe+i, &entry->info, 0);
432         if (xx != -1) {
433             (void) snprintf(buf, sizeof(buf),
434                 _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
435                 i, entry->info.tag, entry->info.type,
436                 entry->info.offset, entry->info.count);
437             goto exit;
438         }
439
440         switch (entry->info.tag) {
441         case RPMTAG_SHA1HEADER:
442             if (vsflags & RPMVSF_NOSHA1HEADER)
443                 /*@switchbreak@*/ break;
444             blen = 0;
445 /*@-boundsread@*/
446             for (b = dataStart + entry->info.offset; *b != '\0'; b++) {
447                 if (strchr("0123456789abcdefABCDEF", *b) == NULL)
448                     /*@innerbreak@*/ break;
449                 blen++;
450             }
451             if (entry->info.type != RPM_STRING_TYPE || *b != '\0' || blen != 40)
452             {
453                 (void) snprintf(buf, sizeof(buf), _("hdr SHA1: BAD, not hex\n"));
454                 goto exit;
455             }
456 /*@=boundsread@*/
457             if (info->tag == 0) {
458 /*@-boundswrite@*/
459                 *info = entry->info;    /* structure assignment */
460 /*@=boundswrite@*/
461                 siglen = blen + 1;
462             }
463             /*@switchbreak@*/ break;
464 #ifdef  NOTYET
465         case RPMTAG_RSAHEADER:
466 #endif
467         case RPMTAG_DSAHEADER:
468             if (vsflags & RPMVSF_NODSAHEADER)
469                 /*@switchbreak@*/ break;
470             if (entry->info.type != RPM_BIN_TYPE) {
471                 (void) snprintf(buf, sizeof(buf), _("hdr DSA: BAD, not binary\n"));
472                 goto exit;
473             }
474 /*@-boundswrite@*/
475             *info = entry->info;        /* structure assignment */
476 /*@=boundswrite@*/
477             siglen = info->count;
478             /*@switchbreak@*/ break;
479         default:
480             /*@switchbreak@*/ break;
481         }
482     }
483     rc = RPMRC_NOTFOUND;
484
485 exit:
486     /* Return determined RPMRC_OK/RPMRC_FAIL conditions. */
487     if (rc != RPMRC_NOTFOUND) {
488 /*@-boundswrite@*/
489         buf[sizeof(buf)-1] = '\0';
490         if (msg) *msg = xstrdup(buf);
491 /*@=boundswrite@*/
492         return rc;
493     }
494
495     /* If no header-only digest/signature, then do simple sanity check. */
496     if (info->tag == 0) {
497 verifyinfo_exit:
498         xx = headerVerifyInfo(ril-1, dl, pe+1, &entry->info, 0);
499         if (xx != -1) {
500             (void) snprintf(buf, sizeof(buf),
501                 _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
502                 xx+1, entry->info.tag, entry->info.type,
503                 entry->info.offset, entry->info.count);
504             rc = RPMRC_FAIL;
505         } else {
506             (void) snprintf(buf, sizeof(buf), "Header sanity check: OK\n");
507             rc = RPMRC_OK;
508         }
509 /*@-boundswrite@*/
510         buf[sizeof(buf)-1] = '\0';
511         if (msg) *msg = xstrdup(buf);
512 /*@=boundswrite@*/
513         return rc;
514     }
515
516     /* Verify header-only digest/signature. */
517     dig = rpmtsDig(ts);
518     if (dig == NULL)
519         goto verifyinfo_exit;
520     dig->nbytes = 0;
521
522 /*@-boundsread@*/
523     sig = memcpy(xmalloc(siglen), dataStart + info->offset, siglen);
524 /*@=boundsread@*/
525     (void) rpmtsSetSig(ts, info->tag, info->type, sig, info->count);
526
527     switch (info->tag) {
528 #ifdef  NOTYET
529     case RPMTAG_RSAHEADER:
530         /* Parse the parameters from the OpenPGP packets that will be needed. */
531         xx = pgpPrtPkts(sig, info->count, dig, (_print_pkts & rpmIsDebug()));
532         /* XXX only V3 signatures for now. */
533         if (dig->signature.version != 3) {
534             rpmMessage(RPMMESS_WARNING,
535                 _("only V3 signatures can be verified, skipping V%u signature\n"),
536                 dig->signature.version);
537             rpmtsCleanDig(ts);
538             goto verifyinfo_exit;
539         }
540
541         ildl[0] = htonl(ril);
542         ildl[1] = (regionEnd - dataStart);
543         ildl[1] = htonl(ildl[1]);
544
545         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
546         dig->hdrmd5ctx = rpmDigestInit(PGPHASHALGO_MD5, RPMDIGEST_NONE);
547
548         b = (unsigned char *) header_magic;
549         nb = sizeof(header_magic);
550         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
551         dig->nbytes += nb;
552
553         b = (unsigned char *) ildl;
554         nb = sizeof(ildl);
555         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
556         dig->nbytes += nb;
557
558         b = (unsigned char *) pe;
559         nb = (htonl(ildl[0]) * sizeof(*pe));
560         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
561         dig->nbytes += nb;
562
563         b = (unsigned char *) dataStart;
564         nb = htonl(ildl[1]);
565         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
566         dig->nbytes += nb;
567         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
568
569         break;
570 #endif
571     case RPMTAG_DSAHEADER:
572         /* Parse the parameters from the OpenPGP packets that will be needed. */
573         xx = pgpPrtPkts(sig, info->count, dig, (_print_pkts & rpmIsDebug()));
574         /* XXX only V3 signatures for now. */
575         if (dig->signature.version != 3) {
576             rpmMessage(RPMMESS_WARNING,
577                 _("only V3 signatures can be verified, skipping V%u signature\n"),
578                 dig->signature.version);
579             rpmtsCleanDig(ts);
580             goto verifyinfo_exit;
581         }
582         /*@fallthrough@*/
583     case RPMTAG_SHA1HEADER:
584 /*@-boundswrite@*/
585         ildl[0] = htonl(ril);
586         ildl[1] = (regionEnd - dataStart);
587         ildl[1] = htonl(ildl[1]);
588 /*@=boundswrite@*/
589
590         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
591         dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
592
593         b = (unsigned char *) header_magic;
594         nb = sizeof(header_magic);
595         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
596         dig->nbytes += nb;
597
598         b = (unsigned char *) ildl;
599         nb = sizeof(ildl);
600         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
601         dig->nbytes += nb;
602
603         b = (unsigned char *) pe;
604         nb = (htonl(ildl[0]) * sizeof(*pe));
605         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
606         dig->nbytes += nb;
607
608         b = (unsigned char *) dataStart;
609         nb = htonl(ildl[1]);
610         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
611         dig->nbytes += nb;
612         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
613
614         break;
615     default:
616         sig = _free(sig);
617         break;
618     }
619
620 /*@-boundswrite@*/
621     buf[0] = '\0';
622 /*@=boundswrite@*/
623     rc = rpmVerifySignature(ts, buf);
624
625 /*@-boundswrite@*/
626     buf[sizeof(buf)-1] = '\0';
627     if (msg) *msg = xstrdup(buf);
628 /*@=boundswrite@*/
629
630     rpmtsCleanDig(ts);
631     if (info->tag == RPMTAG_SHA1HEADER)
632         sig = _free(sig);
633     return rc;
634 }
635
636 rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, const char ** msg)
637 {
638     char buf[BUFSIZ];
639     int_32 block[4];
640     int_32 il;
641     int_32 dl;
642     int_32 * ei = NULL;
643     size_t uc;
644     int_32 nb;
645     Header h = NULL;
646     rpmRC rc = RPMRC_FAIL;              /* assume failure */
647     int xx;
648
649 /*@-boundswrite@*/
650     buf[0] = '\0';
651
652     if (hdrp)
653         *hdrp = NULL;
654     if (msg)
655         *msg = NULL;
656 /*@=boundswrite@*/
657
658     memset(block, 0, sizeof(block));
659     if ((xx = timedRead(fd, (char *)block, sizeof(block))) != sizeof(block)) {
660         (void) snprintf(buf, sizeof(buf),
661                 _("hdr size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx);
662         goto exit;
663     }
664     if (memcmp(block, header_magic, sizeof(header_magic))) {
665         (void) snprintf(buf, sizeof(buf), _("hdr magic: BAD\n"));
666         goto exit;
667     }
668 /*@-boundsread@*/
669     il = ntohl(block[2]);
670 /*@=boundsread@*/
671     if (hdrchkTags(il)) {
672         (void) snprintf(buf, sizeof(buf),
673                 _("hdr tags: BAD, no. of tags(%d) out of range\n"), il);
674
675         goto exit;
676     }
677 /*@-boundsread@*/
678     dl = ntohl(block[3]);
679 /*@=boundsread@*/
680     if (hdrchkData(dl)) {
681         (void) snprintf(buf, sizeof(buf),
682                 _("hdr data: BAD, no. of bytes(%d) out of range\n"), dl);
683         goto exit;
684     }
685
686 /*@-sizeoftype@*/
687     nb = (il * sizeof(struct entryInfo_s)) + dl;
688 /*@=sizeoftype@*/
689     uc = sizeof(il) + sizeof(dl) + nb;
690     ei = xmalloc(uc);
691 /*@-bounds@*/
692     ei[0] = block[2];
693     ei[1] = block[3];
694     if ((xx = timedRead(fd, (char *)&ei[2], nb)) != nb) {
695         (void) snprintf(buf, sizeof(buf),
696                 _("hdr blob(%d): BAD, read returned %d\n"), nb, xx);
697         goto exit;
698     }
699 /*@=bounds@*/
700
701     /* Sanity check header tags */
702     rc = headerCheck(ts, ei, uc, msg);
703     if (rc != RPMRC_OK)
704         goto exit;
705
706     /* OK, blob looks sane, load the header. */
707     h = headerLoad(ei);
708     if (h == NULL) {
709         (void) snprintf(buf, sizeof(buf), _("hdr load: BAD\n"));
710         goto exit;
711     }
712     h->flags |= HEADERFLAG_ALLOCATED;
713     ei = NULL;  /* XXX will be freed with header */
714     
715 exit:
716 /*@-boundswrite@*/
717     if (hdrp && h && rc == RPMRC_OK)
718         *hdrp = headerLink(h);
719 /*@=boundswrite@*/
720     ei = _free(ei);
721     h = headerFree(h);
722
723 /*@-boundswrite@*/
724     if (msg != NULL && *msg == NULL && buf[0] != '\0') {
725         buf[sizeof(buf)-1] = '\0';
726         *msg = xstrdup(buf);
727     }
728 /*@=boundswrite@*/
729
730     return rc;
731 }
732
733 /*@-bounds@*/   /* LCL: segfault */
734 rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp)
735 {
736     pgpDig dig;
737     byte buf[8*BUFSIZ];
738     ssize_t count;
739     struct rpmlead * l = alloca(sizeof(*l));
740     Header sigh = NULL;
741     int_32 sigtag;
742     int_32 sigtype;
743     const void * sig;
744     int_32 siglen;
745     Header h = NULL;
746     const char * msg;
747     int hmagic;
748     rpmVSFlags vsflags;
749     rpmRC rc = RPMRC_FAIL;      /* assume failure */
750     int xx;
751     int i;
752
753     if (hdrp) *hdrp = NULL;
754
755 #ifdef  DYING
756     {   struct stat st;
757 /*@-boundswrite@*/
758         memset(&st, 0, sizeof(st));
759 /*@=boundswrite@*/
760         (void) fstat(Fileno(fd), &st);
761         /* if fd points to a socket, pipe, etc, st.st_size is *always* zero */
762         if (S_ISREG(st.st_mode) && st.st_size < sizeof(*l)) {
763             rc = RPMRC_NOTFOUND;
764             goto exit;
765         }
766     }
767 #endif
768
769     memset(l, 0, sizeof(*l));
770     rc = readLead(fd, l);
771     if (rc != RPMRC_OK)
772         goto exit;
773
774     switch (l->major) {
775     case 1:
776         rpmError(RPMERR_NEWPACKAGE,
777             _("packaging version 1 is not supported by this version of RPM\n"));
778         rc = RPMRC_NOTFOUND;
779         goto exit;
780         /*@notreached@*/ break;
781     case 2:
782     case 3:
783     case 4:
784         break;
785     default:
786         rpmError(RPMERR_NEWPACKAGE, _("only packaging with major numbers <= 4 "
787                 "is supported by this version of RPM\n"));
788         rc = RPMRC_NOTFOUND;
789         goto exit;
790         /*@notreached@*/ break;
791     }
792
793     /* Read the signature header. */
794     msg = NULL;
795     rc = rpmReadSignature(fd, &sigh, l->signature_type, &msg);
796     switch (rc) {
797     default:
798         rpmError(RPMERR_SIGGEN, _("%s: rpmReadSignature failed: %s"), fn,
799                 (msg && *msg ? msg : "\n"));
800         msg = _free(msg);
801         goto exit;
802         /*@notreached@*/ break;
803     case RPMRC_OK:
804         if (sigh == NULL) {
805             rpmError(RPMERR_SIGGEN, _("%s: No signature available\n"), fn);
806             rc = RPMRC_FAIL;
807             goto exit;
808         }
809         break;
810     }
811     msg = _free(msg);
812
813 #define _chk(_mask)     (sigtag == 0 && !(vsflags & (_mask)))
814
815     /* Figger the most effective available signature. */
816     sigtag = 0;
817     vsflags = rpmtsVSFlags(ts);
818 #ifdef  DYING
819     if (_chk(RPMVSF_NODSAHEADER) && headerIsEntry(sigh, RPMSIGTAG_DSA))
820         sigtag = RPMSIGTAG_DSA;
821     if (_chk(RPMVSF_NORSAHEADER) && headerIsEntry(sigh, RPMSIGTAG_RSA))
822         sigtag = RPMSIGTAG_RSA;
823 #endif
824     if (_chk(RPMVSF_NODSA|RPMVSF_NEEDPAYLOAD) &&
825         headerIsEntry(sigh, RPMSIGTAG_GPG))
826     {
827         sigtag = RPMSIGTAG_GPG;
828         fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
829     }
830     if (_chk(RPMVSF_NORSA|RPMVSF_NEEDPAYLOAD) &&
831         headerIsEntry(sigh, RPMSIGTAG_PGP))
832     {
833         sigtag = RPMSIGTAG_PGP;
834         fdInitDigest(fd, PGPHASHALGO_MD5, 0);
835     }
836 #ifdef  DYING
837     if (_chk(RPMVSF_NOSHA1HEADER) && headerIsEntry(sigh, RPMSIGTAG_SHA1))
838         sigtag = RPMSIGTAG_SHA1;
839 #endif
840     if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD) &&
841         headerIsEntry(sigh, RPMSIGTAG_MD5))
842     {
843         sigtag = RPMSIGTAG_MD5;
844         fdInitDigest(fd, PGPHASHALGO_MD5, 0);
845     }
846
847     /* Read the metadata, computing digest(s) on the fly. */
848     h = NULL;
849     msg = NULL;
850     rc = rpmReadHeader(ts, fd, &h, &msg);
851     if (rc != RPMRC_OK || h == NULL) {
852         rpmError(RPMERR_FREAD, _("%s: headerRead failed: %s"), fn,
853                 (msg && *msg ? msg : "\n"));
854         msg = _free(msg);
855         goto exit;
856     }
857     msg = _free(msg);
858
859     /* Any signatures to check? */
860     if (sigtag == 0) {
861         rc = RPMRC_OK;
862         goto exit;
863     }
864
865     dig = rpmtsDig(ts);
866     if (dig == NULL) {
867         rc = RPMRC_FAIL;
868         goto exit;
869     }
870     dig->nbytes = 0;
871
872     /* Retrieve the tag parameters from the signature header. */
873     sig = NULL;
874     xx = headerGetEntry(sigh, sigtag, &sigtype, (void **) &sig, &siglen);
875     if (sig == NULL) {
876         rc = RPMRC_FAIL;
877         goto exit;
878     }
879     (void) rpmtsSetSig(ts, sigtag, sigtype, sig, siglen);
880
881     switch (sigtag) {
882     case RPMSIGTAG_RSA:
883         /* Parse the parameters from the OpenPGP packets that will be needed. */
884         xx = pgpPrtPkts(sig, siglen, dig, (_print_pkts & rpmIsDebug()));
885         /* XXX only V3 signatures for now. */
886         if (dig->signature.version != 3) {
887             rpmMessage(RPMMESS_WARNING,
888                 _("only V3 signatures can be verified, skipping V%u signature\n"),
889                 dig->signature.version);
890             rc = RPMRC_OK;
891             goto exit;
892         }
893     {   void * uh = NULL;
894         int_32 uht;
895         int_32 uhc;
896
897         if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc))
898             break;
899         dig->md5ctx = rpmDigestInit(PGPHASHALGO_MD5, RPMDIGEST_NONE);
900         (void) rpmDigestUpdate(dig->md5ctx, header_magic, sizeof(header_magic));
901         dig->nbytes += sizeof(header_magic);
902         (void) rpmDigestUpdate(dig->md5ctx, uh, uhc);
903         dig->nbytes += uhc;
904         uh = headerFreeData(uh, uht);
905     }   break;
906     case RPMSIGTAG_DSA:
907         /* Parse the parameters from the OpenPGP packets that will be needed. */
908         xx = pgpPrtPkts(sig, siglen, dig, (_print_pkts & rpmIsDebug()));
909         /* XXX only V3 signatures for now. */
910         if (dig->signature.version != 3) {
911             rpmMessage(RPMMESS_WARNING,
912                 _("only V3 signatures can be verified, skipping V%u signature\n"),
913                 dig->signature.version);
914             rc = RPMRC_OK;
915             goto exit;
916         }
917         /*@fallthrough@*/
918     case RPMSIGTAG_SHA1:
919     {   void * uh = NULL;
920         int_32 uht;
921         int_32 uhc;
922
923         if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc))
924             break;
925         dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
926         (void) rpmDigestUpdate(dig->hdrsha1ctx, header_magic, sizeof(header_magic));
927         dig->nbytes += sizeof(header_magic);
928         (void) rpmDigestUpdate(dig->hdrsha1ctx, uh, uhc);
929         dig->nbytes += uhc;
930         uh = headerFreeData(uh, uht);
931     }   break;
932     case RPMSIGTAG_GPG:
933     case RPMSIGTAG_PGP5:        /* XXX legacy */
934     case RPMSIGTAG_PGP:
935         /* Parse the parameters from the OpenPGP packets that will be needed. */
936         xx = pgpPrtPkts(sig, siglen, dig,
937                         (_print_pkts & rpmIsDebug()));
938
939         /* XXX only V3 signatures for now. */
940         if (dig->signature.version != 3) {
941             rpmMessage(RPMMESS_WARNING,
942                 _("only V3 signatures can be verified, skipping V%u signature\n"),
943                 dig->signature.version);
944             rc = RPMRC_OK;
945             goto exit;
946         }
947         /*@fallthrough@*/
948     case RPMSIGTAG_MD5:
949         /* Legacy signatures need the compressed payload in the digest too. */
950         hmagic = ((l->major >= 3) ? HEADER_MAGIC_YES : HEADER_MAGIC_NO);
951         dig->nbytes += headerSizeof(h, hmagic);
952         while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
953             dig->nbytes += count;
954         if (count < 0) {
955             rpmError(RPMERR_FREAD, _("%s: Fread failed: %s\n"),
956                                         fn, Fstrerror(fd));
957             rc = RPMRC_FAIL;
958             goto exit;
959         }
960         dig->nbytes += count;
961
962         /* XXX Steal the digest-in-progress from the file handle. */
963         for (i = fd->ndigests - 1; i >= 0; i--) {
964             FDDIGEST_t fddig = fd->digests + i;
965             if (fddig->hashctx == NULL)
966                 continue;
967             if (fddig->hashalgo == PGPHASHALGO_MD5) {
968                 dig->md5ctx = fddig->hashctx;
969                 fddig->hashctx = NULL;
970                 continue;
971             }
972             if (fddig->hashalgo == PGPHASHALGO_SHA1) {
973                 dig->sha1ctx = fddig->hashctx;
974                 fddig->hashctx = NULL;
975                 continue;
976             }
977         }
978         break;
979     }
980
981 /** @todo Implement disable/enable/warn/error/anal policy. */
982
983 /*@-boundswrite@*/
984     buf[0] = '\0';
985 /*@=boundswrite@*/
986     rc = rpmVerifySignature(ts, buf);
987     switch (rc) {
988     case RPMRC_OK:              /* Signature is OK. */
989         rpmMessage(RPMMESS_DEBUG, "%s: %s", fn, buf);
990         break;
991     case RPMRC_NOTTRUSTED:      /* Signature is OK, but key is not trusted. */
992     case RPMRC_NOKEY:           /* Public key is unavailable. */
993         /* XXX Print NOKEY/NOTTRUSTED warning only once. */
994     {   int lvl = (rpmtsStashKeyid(ts) ? RPMMESS_DEBUG : RPMMESS_WARNING);
995         rpmMessage(lvl, "%s: %s", fn, buf);
996     }   break;
997     case RPMRC_NOTFOUND:        /* Signature is unknown type. */
998         rpmMessage(RPMMESS_WARNING, "%s: %s", fn, buf);
999         break;
1000     default:
1001     case RPMRC_FAIL:            /* Signature does not verify. */
1002         rpmMessage(RPMMESS_ERROR, "%s: %s", fn, buf);
1003         break;
1004     }
1005
1006 exit:
1007     if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) {
1008         /* Convert legacy headers on the fly ... */
1009         legacyRetrofit(h, l);
1010         
1011         /* Append (and remap) signature tags to the metadata. */
1012         headerMergeLegacySigs(h, sigh);
1013
1014         /* Bump reference count for return. */
1015 /*@-boundswrite@*/
1016         *hdrp = headerLink(h);
1017 /*@=boundswrite@*/
1018     }
1019     h = headerFree(h);
1020     rpmtsCleanDig(ts);
1021     sigh = rpmFreeSignature(sigh);
1022     return rc;
1023 }
1024 /*@=bounds@*/