lib/package.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include <netinet/in.h>
00008 
00009 #include <rpmio_internal.h>
00010 #include <rpmlib.h>
00011 
00012 #include "rpmts.h"
00013 
00014 #include "misc.h"       /* XXX stripTrailingChar() */
00015 #include "rpmlead.h"
00016 
00017 #include "header_internal.h"    /* XXX headerCheck */
00018 #include "signature.h"
00019 #include "debug.h"
00020 
00021 #define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
00022 
00023 /*@access pgpDig @*/
00024 /*@access pgpDigParams @*/
00025 /*@access Header @*/            /* XXX compared with NULL */
00026 /*@access entryInfo @*/         /* XXX headerCheck */
00027 /*@access indexEntry @*/        /* XXX headerCheck */
00028 /*@access FD_t @*/              /* XXX stealing digests */
00029 
00030 /*@unchecked@*/
00031 static int _print_pkts = 0;
00032 
00033 /*@unchecked@*/
00034 static unsigned int nkeyids_max = 256;
00035 /*@unchecked@*/
00036 static unsigned int nkeyids = 0;
00037 /*@unchecked@*/
00038 static unsigned int nextkeyid  = 0;
00039 /*@unchecked@*/ /*@only@*/ /*@null@*/
00040 static unsigned int * keyids;
00041 
00042 /*@unchecked@*/
00043 static unsigned char header_magic[8] = {
00044         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00045 };
00046 
00050 /*@observer@*/ /*@unchecked@*/
00051 static int typeAlign[16] =  {
00052     1,  
00053     1,  
00054     1,  
00055     2,  
00056     4,  
00057     8,  
00058     1,  
00059     1,  
00060     1,  
00061     1,  
00062     0,
00063     0,
00064     0,
00065     0,
00066     0,
00067     0
00068 };
00069 
00074 #define hdrchkTags(_ntags)      ((_ntags) & 0xffff0000)
00075 
00079 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00080 
00085 #define hdrchkData(_nbytes) ((_nbytes) & 0xff000000)
00086 
00090 #define hdrchkAlign(_type, _off)        ((_off) & (typeAlign[_type]-1))
00091 
00095 #define hdrchkRange(_dl, _off)          ((_off) < 0 || (_off) > (_dl))
00096 
00097 void headerMergeLegacySigs(Header h, const Header sigh)
00098 {
00099     HFD_t hfd = (HFD_t) headerFreeData;
00100     HAE_t hae = (HAE_t) headerAddEntry;
00101     HeaderIterator hi;
00102     int_32 tag, type, count;
00103     const void * ptr;
00104     int xx;
00105 
00106     for (hi = headerInitIterator(sigh);
00107         headerNextIterator(hi, &tag, &type, &ptr, &count);
00108         ptr = hfd(ptr, type))
00109     {
00110         switch (tag) {
00111         /* XXX Translate legacy signature tag values. */
00112         case RPMSIGTAG_SIZE:
00113             tag = RPMTAG_SIGSIZE;
00114             /*@switchbreak@*/ break;
00115         case RPMSIGTAG_LEMD5_1:
00116             tag = RPMTAG_SIGLEMD5_1;
00117             /*@switchbreak@*/ break;
00118         case RPMSIGTAG_PGP:
00119             tag = RPMTAG_SIGPGP;
00120             /*@switchbreak@*/ break;
00121         case RPMSIGTAG_LEMD5_2:
00122             tag = RPMTAG_SIGLEMD5_2;
00123             /*@switchbreak@*/ break;
00124         case RPMSIGTAG_MD5:
00125             tag = RPMTAG_SIGMD5;
00126             /*@switchbreak@*/ break;
00127         case RPMSIGTAG_GPG:
00128             tag = RPMTAG_SIGGPG;
00129             /*@switchbreak@*/ break;
00130         case RPMSIGTAG_PGP5:
00131             tag = RPMTAG_SIGPGP5;
00132             /*@switchbreak@*/ break;
00133         case RPMSIGTAG_PAYLOADSIZE:
00134             tag = RPMTAG_ARCHIVESIZE;
00135             /*@switchbreak@*/ break;
00136         case RPMSIGTAG_SHA1:
00137         case RPMSIGTAG_DSA:
00138         case RPMSIGTAG_RSA:
00139         default:
00140             if (!(tag >= HEADER_SIGBASE && tag < HEADER_TAGBASE))
00141                 continue;
00142             /*@switchbreak@*/ break;
00143         }
00144         if (ptr == NULL) continue;      /* XXX can't happen */
00145         if (!headerIsEntry(h, tag)) {
00146             if (hdrchkType(type))
00147                 continue;
00148             if (count < 0 || hdrchkData(count))
00149                 continue;
00150             switch(type) {
00151             case RPM_NULL_TYPE:
00152                 continue;
00153                 /*@notreached@*/ /*@switchbreak@*/ break;
00154             case RPM_CHAR_TYPE:
00155             case RPM_INT8_TYPE:
00156             case RPM_INT16_TYPE:
00157             case RPM_INT32_TYPE:
00158                 if (count != 1)
00159                     continue;
00160                 /*@switchbreak@*/ break;
00161             case RPM_STRING_TYPE:
00162             case RPM_BIN_TYPE:
00163                 if (count >= 16*1024)
00164                     continue;
00165                 /*@switchbreak@*/ break;
00166             case RPM_STRING_ARRAY_TYPE:
00167             case RPM_I18NSTRING_TYPE:
00168                 continue;
00169                 /*@notreached@*/ /*@switchbreak@*/ break;
00170             }
00171             xx = hae(h, tag, type, ptr, count);
00172         }
00173     }
00174     hi = headerFreeIterator(hi);
00175 }
00176 
00177 Header headerRegenSigHeader(const Header h, int noArchiveSize)
00178 {
00179     HFD_t hfd = (HFD_t) headerFreeData;
00180     Header sigh = rpmNewSignature();
00181     HeaderIterator hi;
00182     int_32 tag, stag, type, count;
00183     const void * ptr;
00184     int xx;
00185 
00186     for (hi = headerInitIterator(h);
00187         headerNextIterator(hi, &tag, &type, &ptr, &count);
00188         ptr = hfd(ptr, type))
00189     {
00190         switch (tag) {
00191         /* XXX Translate legacy signature tag values. */
00192         case RPMTAG_SIGSIZE:
00193             stag = RPMSIGTAG_SIZE;
00194             /*@switchbreak@*/ break;
00195         case RPMTAG_SIGLEMD5_1:
00196             stag = RPMSIGTAG_LEMD5_1;
00197             /*@switchbreak@*/ break;
00198         case RPMTAG_SIGPGP:
00199             stag = RPMSIGTAG_PGP;
00200             /*@switchbreak@*/ break;
00201         case RPMTAG_SIGLEMD5_2:
00202             stag = RPMSIGTAG_LEMD5_2;
00203             /*@switchbreak@*/ break;
00204         case RPMTAG_SIGMD5:
00205             stag = RPMSIGTAG_MD5;
00206             /*@switchbreak@*/ break;
00207         case RPMTAG_SIGGPG:
00208             stag = RPMSIGTAG_GPG;
00209             /*@switchbreak@*/ break;
00210         case RPMTAG_SIGPGP5:
00211             stag = RPMSIGTAG_PGP5;
00212             /*@switchbreak@*/ break;
00213         case RPMTAG_ARCHIVESIZE:
00214             /* XXX rpm-4.1 and later has archive size in signature header. */
00215             if (noArchiveSize)
00216                 continue;
00217             stag = RPMSIGTAG_PAYLOADSIZE;
00218             /*@switchbreak@*/ break;
00219         case RPMTAG_SHA1HEADER:
00220         case RPMTAG_DSAHEADER:
00221         case RPMTAG_RSAHEADER:
00222         default:
00223             if (!(tag >= HEADER_SIGBASE && tag < HEADER_TAGBASE))
00224                 continue;
00225             stag = tag;
00226             /*@switchbreak@*/ break;
00227         }
00228         if (ptr == NULL) continue;      /* XXX can't happen */
00229         if (!headerIsEntry(sigh, stag))
00230             xx = headerAddEntry(sigh, stag, type, ptr, count);
00231     }
00232     hi = headerFreeIterator(hi);
00233     return sigh;
00234 }
00235 
00241 static int rpmtsStashKeyid(rpmts ts)
00242         /*@globals nextkeyid, nkeyids, keyids @*/
00243         /*@modifies nextkeyid, nkeyids, keyids @*/
00244 {
00245     const void * sig = rpmtsSig(ts);
00246     pgpDig dig = rpmtsDig(ts);
00247     pgpDigParams sigp = rpmtsSignature(ts);
00248     unsigned int keyid;
00249     int i;
00250 
00251     if (sig == NULL || dig == NULL || sigp == NULL)
00252         return 0;
00253 
00254     keyid = pgpGrab(sigp->signid+4, 4);
00255     if (keyid == 0)
00256         return 0;
00257 
00258     if (keyids != NULL)
00259     for (i = 0; i < nkeyids; i++) {
00260 /*@-boundsread@*/
00261         if (keyid == keyids[i])
00262             return 1;
00263 /*@=boundsread@*/
00264     }
00265 
00266     if (nkeyids < nkeyids_max) {
00267         nkeyids++;
00268         keyids = xrealloc(keyids, nkeyids * sizeof(*keyids));
00269     }
00270 /*@-boundswrite@*/
00271     if (keyids)         /* XXX can't happen */
00272         keyids[nextkeyid] = keyid;
00273 /*@=boundswrite@*/
00274     nextkeyid++;
00275     nextkeyid %= nkeyids_max;
00276 
00277     return 0;
00278 }
00279 
00280 int headerVerifyInfo(int il, int dl, const void * pev, void * iv, int negate)
00281 {
00282 /*@-castexpose@*/
00283     entryInfo pe = (entryInfo) pev;
00284 /*@=castexpose@*/
00285     entryInfo info = iv;
00286     int i;
00287 
00288 /*@-boundsread@*/
00289     for (i = 0; i < il; i++) {
00290         info->tag = ntohl(pe[i].tag);
00291         info->type = ntohl(pe[i].type);
00292         info->offset = ntohl(pe[i].offset);
00293         if (negate)
00294             info->offset = -info->offset;
00295         info->count = ntohl(pe[i].count);
00296 
00297         if (hdrchkType(info->type))
00298             return i;
00299         if (hdrchkAlign(info->type, info->offset))
00300             return i;
00301         if (!negate && hdrchkRange(dl, info->offset))
00302             return i;
00303         if (hdrchkData(info->count))
00304             return i;
00305 
00306     }
00307 /*@=boundsread@*/
00308     return -1;
00309 }
00310 
00324 rpmRC headerCheck(rpmts ts, const void * uh, size_t uc, const char ** msg)
00325 {
00326     pgpDig dig;
00327     unsigned char buf[8*BUFSIZ];
00328     int_32 * ei = (int_32 *) uh;
00329 /*@-boundsread@*/
00330     int_32 il = ntohl(ei[0]);
00331     int_32 dl = ntohl(ei[1]);
00332 /*@-castexpose@*/
00333     entryInfo pe = (entryInfo) &ei[2];
00334 /*@=castexpose@*/
00335 /*@=boundsread@*/
00336     int_32 ildl[2];
00337     int_32 pvlen = sizeof(ildl) + (il * sizeof(*pe)) + dl;
00338     unsigned char * dataStart = (unsigned char *) (pe + il);
00339     indexEntry entry = memset(alloca(sizeof(*entry)), 0, sizeof(*entry));
00340     entryInfo info = memset(alloca(sizeof(*info)), 0, sizeof(*info));
00341     const void * sig = NULL;
00342     const char * b;
00343     rpmVSFlags vsflags = rpmtsVSFlags(ts);
00344     int siglen = 0;
00345     int blen;
00346     size_t nb;
00347     int_32 ril = 0;
00348     unsigned char * regionEnd = NULL;
00349     rpmRC rc = RPMRC_FAIL;      /* assume failure */
00350     int xx;
00351     int i;
00352     static int hclvl;
00353 
00354     hclvl++;
00355 /*@-boundswrite@*/
00356     buf[0] = '\0';
00357 /*@=boundswrite@*/
00358 
00359     /* Is the blob the right size? */
00360     if (uc > 0 && pvlen != uc) {
00361         (void) snprintf(buf, sizeof(buf),
00362                 _("blob size(%d): BAD, 8 + 16 * il(%d) + dl(%d)\n"),
00363                 (int)uc, (int)il, (int)dl);
00364         goto exit;
00365     }
00366 
00367     /* Check (and convert) the 1st tag element. */
00368     xx = headerVerifyInfo(1, dl, pe, &entry->info, 0);
00369     if (xx != -1) {
00370         (void) snprintf(buf, sizeof(buf),
00371                 _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
00372                 0, entry->info.tag, entry->info.type,
00373                 entry->info.offset, entry->info.count);
00374         goto exit;
00375     }
00376 
00377     /* Is there an immutable header region tag? */
00378 /*@-sizeoftype@*/
00379     if (!(entry->info.tag == RPMTAG_HEADERIMMUTABLE
00380        && entry->info.type == RPM_BIN_TYPE
00381        && entry->info.count == REGION_TAG_COUNT))
00382     {
00383         rc = RPMRC_NOTFOUND;
00384         goto exit;
00385     }
00386 /*@=sizeoftype@*/
00387 
00388     /* Is the offset within the data area? */
00389     if (entry->info.offset >= dl) {
00390         (void) snprintf(buf, sizeof(buf),
00391                 _("region offset: BAD, tag %d type %d offset %d count %d\n"),
00392                 entry->info.tag, entry->info.type,
00393                 entry->info.offset, entry->info.count);
00394         goto exit;
00395     }
00396 
00397     /* Is there an immutable header region tag trailer? */
00398     regionEnd = dataStart + entry->info.offset;
00399 /*@-sizeoftype@*/
00400 /*@-bounds@*/
00401     (void) memcpy(info, regionEnd, REGION_TAG_COUNT);
00402 /*@=bounds@*/
00403     regionEnd += REGION_TAG_COUNT;
00404 
00405     xx = headerVerifyInfo(1, dl, info, &entry->info, 1);
00406     if (xx != -1 ||
00407         !(entry->info.tag == RPMTAG_HEADERIMMUTABLE
00408        && entry->info.type == RPM_BIN_TYPE
00409        && entry->info.count == REGION_TAG_COUNT))
00410     {
00411         (void) snprintf(buf, sizeof(buf),
00412                 _("region trailer: BAD, tag %d type %d offset %d count %d\n"),
00413                 entry->info.tag, entry->info.type,
00414                 entry->info.offset, entry->info.count);
00415         goto exit;
00416     }
00417 /*@=sizeoftype@*/
00418 /*@-boundswrite@*/
00419     memset(info, 0, sizeof(*info));
00420 /*@=boundswrite@*/
00421 
00422     /* Is the no. of tags in the region less than the total no. of tags? */
00423     ril = entry->info.offset/sizeof(*pe);
00424     if ((entry->info.offset % sizeof(*pe)) || ril > il) {
00425         (void) snprintf(buf, sizeof(buf),
00426                 _("region size: BAD, ril(%d) > il(%d)\n"), ril, il);
00427         goto exit;
00428     }
00429 
00430     /* Find a header-only digest/signature tag. */
00431     for (i = ril; i < il; i++) {
00432         xx = headerVerifyInfo(1, dl, pe+i, &entry->info, 0);
00433         if (xx != -1) {
00434             (void) snprintf(buf, sizeof(buf),
00435                 _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
00436                 i, entry->info.tag, entry->info.type,
00437                 entry->info.offset, entry->info.count);
00438             goto exit;
00439         }
00440 
00441         switch (entry->info.tag) {
00442         case RPMTAG_SHA1HEADER:
00443             if (vsflags & RPMVSF_NOSHA1HEADER)
00444                 /*@switchbreak@*/ break;
00445             blen = 0;
00446 /*@-boundsread@*/
00447             for (b = dataStart + entry->info.offset; *b != '\0'; b++) {
00448                 if (strchr("0123456789abcdefABCDEF", *b) == NULL)
00449                     /*@innerbreak@*/ break;
00450                 blen++;
00451             }
00452             if (entry->info.type != RPM_STRING_TYPE || *b != '\0' || blen != 40)
00453             {
00454                 (void) snprintf(buf, sizeof(buf), _("hdr SHA1: BAD, not hex\n"));
00455                 goto exit;
00456             }
00457 /*@=boundsread@*/
00458             if (info->tag == 0) {
00459 /*@-boundswrite@*/
00460                 *info = entry->info;    /* structure assignment */
00461 /*@=boundswrite@*/
00462                 siglen = blen + 1;
00463             }
00464             /*@switchbreak@*/ break;
00465         case RPMTAG_RSAHEADER:
00466             if (vsflags & RPMVSF_NORSAHEADER)
00467                 /*@switchbreak@*/ break;
00468             if (entry->info.type != RPM_BIN_TYPE) {
00469                 (void) snprintf(buf, sizeof(buf), _("hdr RSA: BAD, not binary\n"));
00470                 goto exit;
00471             }
00472 /*@-boundswrite@*/
00473             *info = entry->info;        /* structure assignment */
00474 /*@=boundswrite@*/
00475             siglen = info->count;
00476             /*@switchbreak@*/ break;
00477         case RPMTAG_DSAHEADER:
00478             if (vsflags & RPMVSF_NODSAHEADER)
00479                 /*@switchbreak@*/ break;
00480             if (entry->info.type != RPM_BIN_TYPE) {
00481                 (void) snprintf(buf, sizeof(buf), _("hdr DSA: BAD, not binary\n"));
00482                 goto exit;
00483             }
00484 /*@-boundswrite@*/
00485             *info = entry->info;        /* structure assignment */
00486 /*@=boundswrite@*/
00487             siglen = info->count;
00488             /*@switchbreak@*/ break;
00489         default:
00490             /*@switchbreak@*/ break;
00491         }
00492     }
00493     rc = RPMRC_NOTFOUND;
00494 
00495 exit:
00496     /* Return determined RPMRC_OK/RPMRC_FAIL conditions. */
00497     if (rc != RPMRC_NOTFOUND) {
00498 /*@-boundswrite@*/
00499         buf[sizeof(buf)-1] = '\0';
00500         if (msg) *msg = xstrdup(buf);
00501 /*@=boundswrite@*/
00502         hclvl--;
00503         return rc;
00504     }
00505 
00506     /* If no header-only digest/signature, then do simple sanity check. */
00507     if (info->tag == 0) {
00508 verifyinfo_exit:
00509         xx = headerVerifyInfo(ril-1, dl, pe+1, &entry->info, 0);
00510         if (xx != -1) {
00511             (void) snprintf(buf, sizeof(buf),
00512                 _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
00513                 xx+1, entry->info.tag, entry->info.type,
00514                 entry->info.offset, entry->info.count);
00515             rc = RPMRC_FAIL;
00516         } else {
00517             (void) snprintf(buf, sizeof(buf), "Header sanity check: OK\n");
00518             rc = RPMRC_OK;
00519         }
00520 /*@-boundswrite@*/
00521         buf[sizeof(buf)-1] = '\0';
00522         if (msg) *msg = xstrdup(buf);
00523 /*@=boundswrite@*/
00524         hclvl--;
00525         return rc;
00526     }
00527 
00528     /* Verify header-only digest/signature. */
00529     dig = rpmtsDig(ts);
00530     if (dig == NULL)
00531         goto verifyinfo_exit;
00532     dig->nbytes = 0;
00533 
00534 /*@-boundsread@*/
00535     sig = memcpy(xmalloc(siglen), dataStart + info->offset, siglen);
00536 /*@=boundsread@*/
00537     (void) rpmtsSetSig(ts, info->tag, info->type, sig, info->count);
00538 
00539     switch (info->tag) {
00540     case RPMTAG_RSAHEADER:
00541         /* Parse the parameters from the OpenPGP packets that will be needed. */
00542         xx = pgpPrtPkts(sig, info->count, dig, (_print_pkts & rpmIsDebug()));
00543         if (dig->signature.version != 3 && dig->signature.version != 4) {
00544             rpmMessage(RPMMESS_ERROR,
00545                 _("skipping header with unverifiable V%u signature\n"),
00546                 dig->signature.version);
00547             rpmtsCleanDig(ts);
00548             rc = RPMRC_FAIL;
00549             goto exit;
00550         }
00551 
00552         ildl[0] = htonl(ril);
00553         ildl[1] = (regionEnd - dataStart);
00554         ildl[1] = htonl(ildl[1]);
00555 
00556         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00557         dig->hdrmd5ctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
00558 
00559         b = (unsigned char *) header_magic;
00560         nb = sizeof(header_magic);
00561         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00562         dig->nbytes += nb;
00563 
00564         b = (unsigned char *) ildl;
00565         nb = sizeof(ildl);
00566         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00567         dig->nbytes += nb;
00568 
00569         b = (unsigned char *) pe;
00570         nb = (htonl(ildl[0]) * sizeof(*pe));
00571         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00572         dig->nbytes += nb;
00573 
00574         b = (unsigned char *) dataStart;
00575         nb = htonl(ildl[1]);
00576         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00577         dig->nbytes += nb;
00578         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00579 
00580         break;
00581     case RPMTAG_DSAHEADER:
00582         /* Parse the parameters from the OpenPGP packets that will be needed. */
00583         xx = pgpPrtPkts(sig, info->count, dig, (_print_pkts & rpmIsDebug()));
00584         if (dig->signature.version != 3 && dig->signature.version != 4) {
00585             rpmMessage(RPMMESS_ERROR,
00586                 _("skipping header with unverifiable V%u signature\n"),
00587                 dig->signature.version);
00588             rpmtsCleanDig(ts);
00589             rc = RPMRC_FAIL;
00590             goto exit;
00591         }
00592         /*@fallthrough@*/
00593     case RPMTAG_SHA1HEADER:
00594 /*@-boundswrite@*/
00595         ildl[0] = htonl(ril);
00596         ildl[1] = (regionEnd - dataStart);
00597         ildl[1] = htonl(ildl[1]);
00598 /*@=boundswrite@*/
00599 
00600         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00601         dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00602 
00603         b = (unsigned char *) header_magic;
00604         nb = sizeof(header_magic);
00605         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00606         dig->nbytes += nb;
00607 
00608         b = (unsigned char *) ildl;
00609         nb = sizeof(ildl);
00610         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00611         dig->nbytes += nb;
00612 
00613         b = (unsigned char *) pe;
00614         nb = (htonl(ildl[0]) * sizeof(*pe));
00615         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00616         dig->nbytes += nb;
00617 
00618         b = (unsigned char *) dataStart;
00619         nb = htonl(ildl[1]);
00620         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00621         dig->nbytes += nb;
00622         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00623 
00624         break;
00625     default:
00626         sig = _free(sig);
00627         break;
00628     }
00629 
00630 /*@-boundswrite@*/
00631     buf[0] = '\0';
00632 /*@=boundswrite@*/
00633     rc = rpmVerifySignature(ts, buf);
00634 
00635 /*@-boundswrite@*/
00636     buf[sizeof(buf)-1] = '\0';
00637     if (msg) *msg = xstrdup(buf);
00638 /*@=boundswrite@*/
00639 
00640     /* XXX headerCheck can recurse, free info only at top level. */
00641     if (hclvl == 1)
00642         rpmtsCleanDig(ts);
00643     if (info->tag == RPMTAG_SHA1HEADER)
00644         sig = _free(sig);
00645     hclvl--;
00646     return rc;
00647 }
00648 
00649 rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, const char ** msg)
00650 {
00651     char buf[BUFSIZ];
00652     int_32 block[4];
00653     int_32 il;
00654     int_32 dl;
00655     int_32 * ei = NULL;
00656     size_t uc;
00657     int_32 nb;
00658     Header h = NULL;
00659     const char * origin = NULL;
00660     rpmRC rc = RPMRC_FAIL;              /* assume failure */
00661     int xx;
00662 
00663 /*@-boundswrite@*/
00664     buf[0] = '\0';
00665 
00666     if (hdrp)
00667         *hdrp = NULL;
00668     if (msg)
00669         *msg = NULL;
00670 /*@=boundswrite@*/
00671 
00672     memset(block, 0, sizeof(block));
00673     if ((xx = timedRead(fd, (char *)block, sizeof(block))) != sizeof(block)) {
00674         (void) snprintf(buf, sizeof(buf),
00675                 _("hdr size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx);
00676         goto exit;
00677     }
00678     if (memcmp(block, header_magic, sizeof(header_magic))) {
00679         (void) snprintf(buf, sizeof(buf), _("hdr magic: BAD\n"));
00680         goto exit;
00681     }
00682 /*@-boundsread@*/
00683     il = ntohl(block[2]);
00684 /*@=boundsread@*/
00685     if (hdrchkTags(il)) {
00686         (void) snprintf(buf, sizeof(buf),
00687                 _("hdr tags: BAD, no. of tags(%d) out of range\n"), il);
00688 
00689         goto exit;
00690     }
00691 /*@-boundsread@*/
00692     dl = ntohl(block[3]);
00693 /*@=boundsread@*/
00694     if (hdrchkData(dl)) {
00695         (void) snprintf(buf, sizeof(buf),
00696                 _("hdr data: BAD, no. of bytes(%d) out of range\n"), dl);
00697         goto exit;
00698     }
00699 
00700 /*@-sizeoftype@*/
00701     nb = (il * sizeof(struct entryInfo_s)) + dl;
00702 /*@=sizeoftype@*/
00703     uc = sizeof(il) + sizeof(dl) + nb;
00704     ei = xmalloc(uc);
00705 /*@-bounds@*/
00706     ei[0] = block[2];
00707     ei[1] = block[3];
00708     if ((xx = timedRead(fd, (char *)&ei[2], nb)) != nb) {
00709         (void) snprintf(buf, sizeof(buf),
00710                 _("hdr blob(%d): BAD, read returned %d\n"), nb, xx);
00711         goto exit;
00712     }
00713 /*@=bounds@*/
00714 
00715     /* Sanity check header tags */
00716     rc = headerCheck(ts, ei, uc, msg);
00717     if (rc != RPMRC_OK)
00718         goto exit;
00719 
00720     /* OK, blob looks sane, load the header. */
00721     h = headerLoad(ei);
00722     if (h == NULL) {
00723         (void) snprintf(buf, sizeof(buf), _("hdr load: BAD\n"));
00724         goto exit;
00725     }
00726     h->flags |= HEADERFLAG_ALLOCATED;
00727     ei = NULL;  /* XXX will be freed with header */
00728 
00729     /* Save the opened path as the header origin. */
00730     origin = fdGetOPath(fd);
00731     if (origin != NULL)
00732         (void) headerSetOrigin(h, origin);
00733     
00734 exit:
00735 /*@-boundswrite@*/
00736     if (hdrp && h && rc == RPMRC_OK)
00737         *hdrp = headerLink(h);
00738 /*@=boundswrite@*/
00739     ei = _free(ei);
00740     h = headerFree(h);
00741 
00742 /*@-boundswrite@*/
00743     if (msg != NULL && *msg == NULL && buf[0] != '\0') {
00744         buf[sizeof(buf)-1] = '\0';
00745         *msg = xstrdup(buf);
00746     }
00747 /*@=boundswrite@*/
00748 
00749     return rc;
00750 }
00751 
00752 /*@-bounds@*/   /* LCL: segfault */
00753 rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp)
00754 {
00755     pgpDig dig;
00756     byte buf[8*BUFSIZ];
00757     ssize_t count;
00758     struct rpmlead * l = alloca(sizeof(*l));
00759     Header sigh = NULL;
00760     int_32 sigtag;
00761     int_32 sigtype;
00762     const void * sig;
00763     int_32 siglen;
00764     rpmtsOpX opx;
00765     size_t nb;
00766     Header h = NULL;
00767     const char * msg;
00768     rpmVSFlags vsflags;
00769     rpmRC rc = RPMRC_FAIL;      /* assume failure */
00770     rpmop opsave = memset(alloca(sizeof(*opsave)), 0, sizeof(*opsave));
00771     int xx;
00772     int i;
00773 
00774     if (hdrp) *hdrp = NULL;
00775 
00776 #ifdef  DYING
00777     {   struct stat st;
00778 /*@-boundswrite@*/
00779         memset(&st, 0, sizeof(st));
00780 /*@=boundswrite@*/
00781         (void) fstat(Fileno(fd), &st);
00782         /* if fd points to a socket, pipe, etc, st.st_size is *always* zero */
00783         if (S_ISREG(st.st_mode) && st.st_size < sizeof(*l)) {
00784             rc = RPMRC_NOTFOUND;
00785             goto exit;
00786         }
00787     }
00788 #endif
00789 
00790     /* Snapshot current I/O counters (cached persistent I/O reuses counters) */
00791     (void) rpmswAdd(opsave, fdstat_op(fd, FDSTAT_READ));
00792 
00793     memset(l, 0, sizeof(*l));
00794     rc = readLead(fd, l);
00795     if (rc != RPMRC_OK)
00796         goto exit;
00797 
00798     switch (l->major) {
00799     case 1:
00800         rpmError(RPMERR_NEWPACKAGE,
00801             _("packaging version 1 is not supported by this version of RPM\n"));
00802         rc = RPMRC_NOTFOUND;
00803         goto exit;
00804         /*@notreached@*/ break;
00805     case 2:
00806     case 3:
00807     case 4:
00808         break;
00809     default:
00810         rpmError(RPMERR_NEWPACKAGE, _("only packaging with major numbers <= 4 "
00811                 "is supported by this version of RPM\n"));
00812         rc = RPMRC_NOTFOUND;
00813         goto exit;
00814         /*@notreached@*/ break;
00815     }
00816 
00817     /* Read the signature header. */
00818     msg = NULL;
00819     rc = rpmReadSignature(fd, &sigh, l->signature_type, &msg);
00820     switch (rc) {
00821     default:
00822         rpmError(RPMERR_SIGGEN, _("%s: rpmReadSignature failed: %s"), fn,
00823                 (msg && *msg ? msg : "\n"));
00824         msg = _free(msg);
00825         goto exit;
00826         /*@notreached@*/ break;
00827     case RPMRC_OK:
00828         if (sigh == NULL) {
00829             rpmError(RPMERR_SIGGEN, _("%s: No signature available\n"), fn);
00830             rc = RPMRC_FAIL;
00831             goto exit;
00832         }
00833         break;
00834     }
00835     msg = _free(msg);
00836 
00837 #define _chk(_mask)     (sigtag == 0 && !(vsflags & (_mask)))
00838 
00839     /*
00840      * Figger the most effective available signature.
00841      * Prefer signatures over digests, then header-only over header+payload.
00842      * DSA will be preferred over RSA if both exist because tested first.
00843      * Note that NEEDPAYLOAD prevents header+payload signatures and digests.
00844      */
00845     sigtag = 0;
00846     opx = 0;
00847     vsflags = rpmtsVSFlags(ts);
00848     if (_chk(RPMVSF_NODSAHEADER) && headerIsEntry(sigh, RPMSIGTAG_DSA)) {
00849         sigtag = RPMSIGTAG_DSA;
00850     } else
00851     if (_chk(RPMVSF_NORSAHEADER) && headerIsEntry(sigh, RPMSIGTAG_RSA)) {
00852         sigtag = RPMSIGTAG_RSA;
00853     } else
00854     if (_chk(RPMVSF_NODSA|RPMVSF_NEEDPAYLOAD) &&
00855         headerIsEntry(sigh, RPMSIGTAG_GPG))
00856     {
00857         sigtag = RPMSIGTAG_GPG;
00858         fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
00859         opx = RPMTS_OP_SIGNATURE;
00860     } else
00861     if (_chk(RPMVSF_NORSA|RPMVSF_NEEDPAYLOAD) &&
00862         headerIsEntry(sigh, RPMSIGTAG_PGP))
00863     {
00864         sigtag = RPMSIGTAG_PGP;
00865         fdInitDigest(fd, PGPHASHALGO_MD5, 0);
00866         opx = RPMTS_OP_SIGNATURE;
00867     } else
00868     if (_chk(RPMVSF_NOSHA1HEADER) && headerIsEntry(sigh, RPMSIGTAG_SHA1)) {
00869         sigtag = RPMSIGTAG_SHA1;
00870     } else
00871     if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD) &&
00872         headerIsEntry(sigh, RPMSIGTAG_MD5))
00873     {
00874         sigtag = RPMSIGTAG_MD5;
00875         fdInitDigest(fd, PGPHASHALGO_MD5, 0);
00876         opx = RPMTS_OP_DIGEST;
00877     }
00878 
00879     /* Read the metadata, computing digest(s) on the fly. */
00880     h = NULL;
00881     msg = NULL;
00882 
00883     /* XXX stats will include header i/o and setup overhead. */
00884     /* XXX repackaged packages have appended tags, legacy dig/sig check fails */
00885     if (opx > 0)
00886         (void) rpmswEnter(rpmtsOp(ts, opx), 0);
00887 /*@-type@*/     /* XXX arrow access of non-pointer (FDSTAT_t) */
00888     nb = -fd->stats->ops[FDSTAT_READ].bytes;
00889     rc = rpmReadHeader(ts, fd, &h, &msg);
00890     nb += fd->stats->ops[FDSTAT_READ].bytes;
00891 /*@=type@*/
00892     if (opx > 0)
00893         (void) rpmswExit(rpmtsOp(ts, opx), nb);
00894 
00895     if (rc != RPMRC_OK || h == NULL) {
00896         rpmError(RPMERR_FREAD, _("%s: headerRead failed: %s"), fn,
00897                 (msg && *msg ? msg : "\n"));
00898         msg = _free(msg);
00899         goto exit;
00900     }
00901     msg = _free(msg);
00902 
00903     /* Any digests or signatures to check? */
00904     if (sigtag == 0) {
00905         rc = RPMRC_OK;
00906         goto exit;
00907     }
00908 
00909     dig = rpmtsDig(ts);
00910     if (dig == NULL) {
00911         rc = RPMRC_FAIL;
00912         goto exit;
00913     }
00914     dig->nbytes = 0;
00915 
00916     /* Retrieve the tag parameters from the signature header. */
00917     sig = NULL;
00918     xx = headerGetEntry(sigh, sigtag, &sigtype, (void **) &sig, &siglen);
00919     if (sig == NULL) {
00920         rc = RPMRC_FAIL;
00921         goto exit;
00922     }
00923     (void) rpmtsSetSig(ts, sigtag, sigtype, sig, siglen);
00924 
00925     switch (sigtag) {
00926     case RPMSIGTAG_RSA:
00927         /* Parse the parameters from the OpenPGP packets that will be needed. */
00928         xx = pgpPrtPkts(sig, siglen, dig, (_print_pkts & rpmIsDebug()));
00929         if (dig->signature.version != 3 && dig->signature.version != 4) {
00930             rpmMessage(RPMMESS_ERROR,
00931                 _("skipping package %s with unverifiable V%u signature\n"),
00932                 fn, dig->signature.version);
00933             rc = RPMRC_FAIL;
00934             goto exit;
00935         }
00936     {   void * uh = NULL;
00937         int_32 uht;
00938         int_32 uhc;
00939 
00940         if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc))
00941             break;
00942         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00943         dig->hdrmd5ctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
00944         (void) rpmDigestUpdate(dig->hdrmd5ctx, header_magic, sizeof(header_magic));
00945         dig->nbytes += sizeof(header_magic);
00946         (void) rpmDigestUpdate(dig->hdrmd5ctx, uh, uhc);
00947         dig->nbytes += uhc;
00948         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00949         rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;  /* XXX one too many */
00950         uh = headerFreeData(uh, uht);
00951     }   break;
00952     case RPMSIGTAG_DSA:
00953         /* Parse the parameters from the OpenPGP packets that will be needed. */
00954         xx = pgpPrtPkts(sig, siglen, dig, (_print_pkts & rpmIsDebug()));
00955         if (dig->signature.version != 3 && dig->signature.version != 4) {
00956             rpmMessage(RPMMESS_ERROR,
00957                 _("skipping package %s with unverifiable V%u signature\n"), 
00958                 fn, dig->signature.version);
00959             rc = RPMRC_FAIL;
00960             goto exit;
00961         }
00962         /*@fallthrough@*/
00963     case RPMSIGTAG_SHA1:
00964     {   void * uh = NULL;
00965         int_32 uht;
00966         int_32 uhc;
00967 
00968         if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc))
00969             break;
00970         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00971         dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00972         (void) rpmDigestUpdate(dig->hdrsha1ctx, header_magic, sizeof(header_magic));
00973         dig->nbytes += sizeof(header_magic);
00974         (void) rpmDigestUpdate(dig->hdrsha1ctx, uh, uhc);
00975         dig->nbytes += uhc;
00976         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00977         if (sigtag == RPMSIGTAG_SHA1)
00978             rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;      /* XXX one too many */
00979         uh = headerFreeData(uh, uht);
00980     }   break;
00981     case RPMSIGTAG_GPG:
00982     case RPMSIGTAG_PGP5:        /* XXX legacy */
00983     case RPMSIGTAG_PGP:
00984         /* Parse the parameters from the OpenPGP packets that will be needed. */
00985         xx = pgpPrtPkts(sig, siglen, dig, (_print_pkts & rpmIsDebug()));
00986 
00987         if (dig->signature.version != 3 && dig->signature.version != 4) {
00988             rpmMessage(RPMMESS_ERROR,
00989                 _("skipping package %s with unverifiable V%u signature\n"),
00990                 fn, dig->signature.version);
00991             rc = RPMRC_FAIL;
00992             goto exit;
00993         }
00994         /*@fallthrough@*/
00995     case RPMSIGTAG_MD5:
00996         /* Legacy signatures need the compressed payload in the digest too. */
00997         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00998         while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
00999             dig->nbytes += count;
01000         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
01001         rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;  /* XXX one too many */
01002         dig->nbytes += nb;      /* XXX include size of header blob. */
01003         if (count < 0) {
01004             rpmError(RPMERR_FREAD, _("%s: Fread failed: %s\n"),
01005                                         fn, Fstrerror(fd));
01006             rc = RPMRC_FAIL;
01007             goto exit;
01008         }
01009 
01010         /* XXX Steal the digest-in-progress from the file handle. */
01011         for (i = fd->ndigests - 1; i >= 0; i--) {
01012             FDDIGEST_t fddig = fd->digests + i;
01013             if (fddig->hashctx != NULL)
01014             switch (fddig->hashalgo) {
01015             case PGPHASHALGO_MD5:
01016                 dig->md5ctx = fddig->hashctx;
01017                 fddig->hashctx = NULL;
01018                 /*@switchbreak@*/ break;
01019             case PGPHASHALGO_SHA1:
01020             case PGPHASHALGO_RIPEMD160:
01021 #if HAVE_BEECRYPT_API_H
01022             case PGPHASHALGO_SHA256:
01023             case PGPHASHALGO_SHA384:
01024             case PGPHASHALGO_SHA512:
01025 #endif
01026                 dig->sha1ctx = fddig->hashctx;
01027                 fddig->hashctx = NULL;
01028                 /*@switchbreak@*/ break;
01029             default:
01030                 /*@switchbreak@*/ break;
01031             }
01032         }
01033         break;
01034     }
01035 
01038 /*@-boundswrite@*/
01039     buf[0] = '\0';
01040 /*@=boundswrite@*/
01041     rc = rpmVerifySignature(ts, buf);
01042     switch (rc) {
01043     case RPMRC_OK:              /* Signature is OK. */
01044         rpmMessage(RPMMESS_DEBUG, "%s: %s", fn, buf);
01045         break;
01046     case RPMRC_NOTTRUSTED:      /* Signature is OK, but key is not trusted. */
01047     case RPMRC_NOKEY:           /* Public key is unavailable. */
01048         /* XXX Print NOKEY/NOTTRUSTED warning only once. */
01049     {   int lvl = (rpmtsStashKeyid(ts) ? RPMMESS_DEBUG : RPMMESS_WARNING);
01050         rpmMessage(lvl, "%s: %s", fn, buf);
01051     }   break;
01052     case RPMRC_NOTFOUND:        /* Signature is unknown type. */
01053         rpmMessage(RPMMESS_WARNING, "%s: %s", fn, buf);
01054         break;
01055     default:
01056     case RPMRC_FAIL:            /* Signature does not verify. */
01057         rpmMessage(RPMMESS_ERROR, "%s: %s", fn, buf);
01058         break;
01059     }
01060 
01061 exit:
01062     if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) {
01063 
01064         /* Append (and remap) signature tags to the metadata. */
01065         headerMergeLegacySigs(h, sigh);
01066 
01067         /* Bump reference count for return. */
01068 /*@-boundswrite@*/
01069         *hdrp = headerLink(h);
01070 /*@=boundswrite@*/
01071     }
01072     h = headerFree(h);
01073 
01074     /* Accumulate time reading package header. */
01075     (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_READHDR),
01076                 fdstat_op(fd, FDSTAT_READ));
01077     (void) rpmswSub(rpmtsOp(ts, RPMTS_OP_READHDR),
01078                 opsave);
01079 
01080     rpmtsCleanDig(ts);
01081     sigh = rpmFreeSignature(sigh);
01082     return rc;
01083 }
01084 /*@=bounds@*/

Generated on Fri Aug 31 10:38:31 2007 for rpm by  doxygen 1.5.1