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

Generated on Wed Jan 28 12:45:24 2009 for rpm by  doxygen 1.4.7