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_ERROR,
00546                 _("skipping header with unverifiable V%u signature\n"),
00547                 dig->signature.version);
00548             rpmtsCleanDig(ts);
00549             rc = RPMRC_FAIL;
00550             goto exit;
00551         }
00552 
00553         ildl[0] = htonl(ril);
00554         ildl[1] = (regionEnd - dataStart);
00555         ildl[1] = htonl(ildl[1]);
00556 
00557         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00558         dig->hdrmd5ctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
00559 
00560         b = (unsigned char *) header_magic;
00561         nb = sizeof(header_magic);
00562         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00563         dig->nbytes += nb;
00564 
00565         b = (unsigned char *) ildl;
00566         nb = sizeof(ildl);
00567         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00568         dig->nbytes += nb;
00569 
00570         b = (unsigned char *) pe;
00571         nb = (htonl(ildl[0]) * sizeof(*pe));
00572         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00573         dig->nbytes += nb;
00574 
00575         b = (unsigned char *) dataStart;
00576         nb = htonl(ildl[1]);
00577         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00578         dig->nbytes += nb;
00579         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00580 
00581         break;
00582     case RPMTAG_DSAHEADER:
00583         /* Parse the parameters from the OpenPGP packets that will be needed. */
00584         xx = pgpPrtPkts(sig, info->count, dig, (_print_pkts & rpmIsDebug()));
00585         if (dig->signature.version != 3 && dig->signature.version != 4) {
00586             rpmMessage(RPMMESS_ERROR,
00587                 _("skipping header with unverifiable V%u signature\n"),
00588                 dig->signature.version);
00589             rpmtsCleanDig(ts);
00590             rc = RPMRC_FAIL;
00591             goto exit;
00592         }
00593         /*@fallthrough@*/
00594     case RPMTAG_SHA1HEADER:
00595 /*@-boundswrite@*/
00596         ildl[0] = htonl(ril);
00597         ildl[1] = (regionEnd - dataStart);
00598         ildl[1] = htonl(ildl[1]);
00599 /*@=boundswrite@*/
00600 
00601         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00602         dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00603 
00604         b = (unsigned char *) header_magic;
00605         nb = sizeof(header_magic);
00606         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00607         dig->nbytes += nb;
00608 
00609         b = (unsigned char *) ildl;
00610         nb = sizeof(ildl);
00611         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00612         dig->nbytes += nb;
00613 
00614         b = (unsigned char *) pe;
00615         nb = (htonl(ildl[0]) * sizeof(*pe));
00616         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00617         dig->nbytes += nb;
00618 
00619         b = (unsigned char *) dataStart;
00620         nb = htonl(ildl[1]);
00621         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00622         dig->nbytes += nb;
00623         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00624 
00625         break;
00626     default:
00627         sig = _free(sig);
00628         break;
00629     }
00630 
00631 /*@-boundswrite@*/
00632     buf[0] = '\0';
00633 /*@=boundswrite@*/
00634     rc = rpmVerifySignature(ts, buf);
00635 
00636 /*@-boundswrite@*/
00637     buf[sizeof(buf)-1] = '\0';
00638     if (msg) *msg = xstrdup(buf);
00639 /*@=boundswrite@*/
00640 
00641     /* XXX headerCheck can recurse, free info only at top level. */
00642     if (hclvl == 1)
00643         rpmtsCleanDig(ts);
00644     if (info->tag == RPMTAG_SHA1HEADER)
00645         sig = _free(sig);
00646     hclvl--;
00647     return rc;
00648 }
00649 
00650 rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, const char ** msg)
00651 {
00652     char buf[BUFSIZ];
00653     int_32 block[4];
00654     int_32 il;
00655     int_32 dl;
00656     int_32 * ei = NULL;
00657     size_t uc;
00658     int_32 nb;
00659     Header h = 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 exit:
00730 /*@-boundswrite@*/
00731     if (hdrp && h && rc == RPMRC_OK)
00732         *hdrp = headerLink(h);
00733 /*@=boundswrite@*/
00734     ei = _free(ei);
00735     h = headerFree(h);
00736 
00737 /*@-boundswrite@*/
00738     if (msg != NULL && *msg == NULL && buf[0] != '\0') {
00739         buf[sizeof(buf)-1] = '\0';
00740         *msg = xstrdup(buf);
00741     }
00742 /*@=boundswrite@*/
00743 
00744     return rc;
00745 }
00746 
00747 /*@-bounds@*/   /* LCL: segfault */
00748 rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp)
00749 {
00750     pgpDig dig;
00751     byte buf[8*BUFSIZ];
00752     ssize_t count;
00753     struct rpmlead * l = alloca(sizeof(*l));
00754     Header sigh = NULL;
00755     int_32 sigtag;
00756     int_32 sigtype;
00757     const void * sig;
00758     int_32 siglen;
00759     rpmtsOpX opx;
00760     size_t nb;
00761     Header h = NULL;
00762     const char * msg;
00763     rpmVSFlags vsflags;
00764     rpmRC rc = RPMRC_FAIL;      /* assume failure */
00765     int xx;
00766     int i;
00767 
00768     if (hdrp) *hdrp = NULL;
00769 
00770 #ifdef  DYING
00771     {   struct stat st;
00772 /*@-boundswrite@*/
00773         memset(&st, 0, sizeof(st));
00774 /*@=boundswrite@*/
00775         (void) fstat(Fileno(fd), &st);
00776         /* if fd points to a socket, pipe, etc, st.st_size is *always* zero */
00777         if (S_ISREG(st.st_mode) && st.st_size < sizeof(*l)) {
00778             rc = RPMRC_NOTFOUND;
00779             goto exit;
00780         }
00781     }
00782 #endif
00783 
00784     memset(l, 0, sizeof(*l));
00785     rc = readLead(fd, l);
00786     if (rc != RPMRC_OK)
00787         goto exit;
00788 
00789     switch (l->major) {
00790     case 1:
00791         rpmError(RPMERR_NEWPACKAGE,
00792             _("packaging version 1 is not supported by this version of RPM\n"));
00793         rc = RPMRC_NOTFOUND;
00794         goto exit;
00795         /*@notreached@*/ break;
00796     case 2:
00797     case 3:
00798     case 4:
00799         break;
00800     default:
00801         rpmError(RPMERR_NEWPACKAGE, _("only packaging with major numbers <= 4 "
00802                 "is supported by this version of RPM\n"));
00803         rc = RPMRC_NOTFOUND;
00804         goto exit;
00805         /*@notreached@*/ break;
00806     }
00807 
00808     /* Read the signature header. */
00809     msg = NULL;
00810     rc = rpmReadSignature(fd, &sigh, l->signature_type, &msg);
00811     switch (rc) {
00812     default:
00813         rpmError(RPMERR_SIGGEN, _("%s: rpmReadSignature failed: %s"), fn,
00814                 (msg && *msg ? msg : "\n"));
00815         msg = _free(msg);
00816         goto exit;
00817         /*@notreached@*/ break;
00818     case RPMRC_OK:
00819         if (sigh == NULL) {
00820             rpmError(RPMERR_SIGGEN, _("%s: No signature available\n"), fn);
00821             rc = RPMRC_FAIL;
00822             goto exit;
00823         }
00824         break;
00825     }
00826     msg = _free(msg);
00827 
00828 #define _chk(_mask)     (sigtag == 0 && !(vsflags & (_mask)))
00829 
00830     /*
00831      * Figger the most effective available signature.
00832      * Prefer signatures over digests, then header-only over header+payload.
00833      * DSA will be preferred over RSA if both exist because tested first.
00834      * Note that NEEDPAYLOAD prevents header+payload signatures and digests.
00835      */
00836     sigtag = 0;
00837     opx = 0;
00838     vsflags = rpmtsVSFlags(ts);
00839     if (_chk(RPMVSF_NODSAHEADER) && headerIsEntry(sigh, RPMSIGTAG_DSA)) {
00840         sigtag = RPMSIGTAG_DSA;
00841     } else
00842     if (_chk(RPMVSF_NORSAHEADER) && headerIsEntry(sigh, RPMSIGTAG_RSA)) {
00843         sigtag = RPMSIGTAG_RSA;
00844     } else
00845     if (_chk(RPMVSF_NODSA|RPMVSF_NEEDPAYLOAD) &&
00846         headerIsEntry(sigh, RPMSIGTAG_GPG))
00847     {
00848         sigtag = RPMSIGTAG_GPG;
00849         fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
00850         opx = RPMTS_OP_SIGNATURE;
00851     } else
00852     if (_chk(RPMVSF_NORSA|RPMVSF_NEEDPAYLOAD) &&
00853         headerIsEntry(sigh, RPMSIGTAG_PGP))
00854     {
00855         sigtag = RPMSIGTAG_PGP;
00856         fdInitDigest(fd, PGPHASHALGO_MD5, 0);
00857         opx = RPMTS_OP_SIGNATURE;
00858     } else
00859     if (_chk(RPMVSF_NOSHA1HEADER) && headerIsEntry(sigh, RPMSIGTAG_SHA1)) {
00860         sigtag = RPMSIGTAG_SHA1;
00861     } else
00862     if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD) &&
00863         headerIsEntry(sigh, RPMSIGTAG_MD5))
00864     {
00865         sigtag = RPMSIGTAG_MD5;
00866         fdInitDigest(fd, PGPHASHALGO_MD5, 0);
00867         opx = RPMTS_OP_DIGEST;
00868     }
00869 
00870     /* Read the metadata, computing digest(s) on the fly. */
00871     h = NULL;
00872     msg = NULL;
00873 
00874     /* XXX stats will include header i/o and setup overhead. */
00875     /* XXX repackaged packages have appended tags, legacy dig/sig check fails */
00876     if (opx > 0)
00877         (void) rpmswEnter(rpmtsOp(ts, opx), 0);
00878 /*@-type@*/     /* XXX arrow access of non-pointer (FDSTAT_t) */
00879     nb = -fd->stats->ops[FDSTAT_READ].bytes;
00880     rc = rpmReadHeader(ts, fd, &h, &msg);
00881     nb += fd->stats->ops[FDSTAT_READ].bytes;
00882 /*@=type@*/
00883     if (opx > 0)
00884         (void) rpmswExit(rpmtsOp(ts, opx), nb);
00885 
00886     if (rc != RPMRC_OK || h == NULL) {
00887         rpmError(RPMERR_FREAD, _("%s: headerRead failed: %s"), fn,
00888                 (msg && *msg ? msg : "\n"));
00889         msg = _free(msg);
00890         goto exit;
00891     }
00892     msg = _free(msg);
00893 
00894     /* Any digests or signatures to check? */
00895     if (sigtag == 0) {
00896         rc = RPMRC_OK;
00897         goto exit;
00898     }
00899 
00900     dig = rpmtsDig(ts);
00901     if (dig == NULL) {
00902         rc = RPMRC_FAIL;
00903         goto exit;
00904     }
00905     dig->nbytes = 0;
00906 
00907     /* Retrieve the tag parameters from the signature header. */
00908     sig = NULL;
00909     xx = headerGetEntry(sigh, sigtag, &sigtype, (void **) &sig, &siglen);
00910     if (sig == NULL) {
00911         rc = RPMRC_FAIL;
00912         goto exit;
00913     }
00914     (void) rpmtsSetSig(ts, sigtag, sigtype, sig, siglen);
00915 
00916     switch (sigtag) {
00917     case RPMSIGTAG_RSA:
00918         /* Parse the parameters from the OpenPGP packets that will be needed. */
00919         xx = pgpPrtPkts(sig, siglen, dig, (_print_pkts & rpmIsDebug()));
00920         if (dig->signature.version != 3 && dig->signature.version != 4) {
00921             rpmMessage(RPMMESS_ERROR,
00922                 _("skipping package %s with unverifiable V%u signature\n"),
00923                 fn, dig->signature.version);
00924             rc = RPMRC_FAIL;
00925             goto exit;
00926         }
00927     {   void * uh = NULL;
00928         int_32 uht;
00929         int_32 uhc;
00930 
00931         if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc))
00932             break;
00933         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00934         dig->hdrmd5ctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
00935         (void) rpmDigestUpdate(dig->hdrmd5ctx, header_magic, sizeof(header_magic));
00936         dig->nbytes += sizeof(header_magic);
00937         (void) rpmDigestUpdate(dig->hdrmd5ctx, uh, uhc);
00938         dig->nbytes += uhc;
00939         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00940         rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;  /* XXX one too many */
00941         uh = headerFreeData(uh, uht);
00942     }   break;
00943     case RPMSIGTAG_DSA:
00944         /* Parse the parameters from the OpenPGP packets that will be needed. */
00945         xx = pgpPrtPkts(sig, siglen, dig, (_print_pkts & rpmIsDebug()));
00946         if (dig->signature.version != 3 && dig->signature.version != 4) {
00947             rpmMessage(RPMMESS_ERROR,
00948                 _("skipping package %s with unverifiable V%u signature\n"), 
00949                 fn, dig->signature.version);
00950             rc = RPMRC_FAIL;
00951             goto exit;
00952         }
00953         /*@fallthrough@*/
00954     case RPMSIGTAG_SHA1:
00955     {   void * uh = NULL;
00956         int_32 uht;
00957         int_32 uhc;
00958 
00959         if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc))
00960             break;
00961         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00962         dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00963         (void) rpmDigestUpdate(dig->hdrsha1ctx, header_magic, sizeof(header_magic));
00964         dig->nbytes += sizeof(header_magic);
00965         (void) rpmDigestUpdate(dig->hdrsha1ctx, uh, uhc);
00966         dig->nbytes += uhc;
00967         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00968         if (sigtag == RPMSIGTAG_SHA1)
00969             rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;      /* XXX one too many */
00970         uh = headerFreeData(uh, uht);
00971     }   break;
00972     case RPMSIGTAG_GPG:
00973     case RPMSIGTAG_PGP5:        /* XXX legacy */
00974     case RPMSIGTAG_PGP:
00975         /* Parse the parameters from the OpenPGP packets that will be needed. */
00976         xx = pgpPrtPkts(sig, siglen, dig, (_print_pkts & rpmIsDebug()));
00977 
00978         if (dig->signature.version != 3 && dig->signature.version != 4) {
00979             rpmMessage(RPMMESS_ERROR,
00980                 _("skipping package %s with unverifiable V%u signature\n"),
00981                 fn, dig->signature.version);
00982             rc = RPMRC_FAIL;
00983             goto exit;
00984         }
00985         /*@fallthrough@*/
00986     case RPMSIGTAG_MD5:
00987         /* Legacy signatures need the compressed payload in the digest too. */
00988         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00989         while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
00990             dig->nbytes += count;
00991         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00992         rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;  /* XXX one too many */
00993         dig->nbytes += nb;      /* XXX include size of header blob. */
00994         if (count < 0) {
00995             rpmError(RPMERR_FREAD, _("%s: Fread failed: %s\n"),
00996                                         fn, Fstrerror(fd));
00997             rc = RPMRC_FAIL;
00998             goto exit;
00999         }
01000 
01001         /* XXX Steal the digest-in-progress from the file handle. */
01002         for (i = fd->ndigests - 1; i >= 0; i--) {
01003             FDDIGEST_t fddig = fd->digests + i;
01004             if (fddig->hashctx != NULL)
01005             switch (fddig->hashalgo) {
01006             case PGPHASHALGO_MD5:
01007                 dig->md5ctx = fddig->hashctx;
01008                 fddig->hashctx = NULL;
01009                 /*@switchbreak@*/ break;
01010             case PGPHASHALGO_SHA1:
01011 #if HAVE_BEECRYPT_API_H
01012             case PGPHASHALGO_SHA256:
01013             case PGPHASHALGO_SHA384:
01014             case PGPHASHALGO_SHA512:
01015 #endif
01016                 dig->sha1ctx = fddig->hashctx;
01017                 fddig->hashctx = NULL;
01018                 /*@switchbreak@*/ break;
01019             default:
01020                 /*@switchbreak@*/ break;
01021             }
01022         }
01023         break;
01024     }
01025 
01028 /*@-boundswrite@*/
01029     buf[0] = '\0';
01030 /*@=boundswrite@*/
01031     rc = rpmVerifySignature(ts, buf);
01032     switch (rc) {
01033     case RPMRC_OK:              /* Signature is OK. */
01034         rpmMessage(RPMMESS_DEBUG, "%s: %s", fn, buf);
01035         break;
01036     case RPMRC_NOTTRUSTED:      /* Signature is OK, but key is not trusted. */
01037     case RPMRC_NOKEY:           /* Public key is unavailable. */
01038         /* XXX Print NOKEY/NOTTRUSTED warning only once. */
01039     {   int lvl = (rpmtsStashKeyid(ts) ? RPMMESS_DEBUG : RPMMESS_WARNING);
01040         rpmMessage(lvl, "%s: %s", fn, buf);
01041     }   break;
01042     case RPMRC_NOTFOUND:        /* Signature is unknown type. */
01043         rpmMessage(RPMMESS_WARNING, "%s: %s", fn, buf);
01044         break;
01045     default:
01046     case RPMRC_FAIL:            /* Signature does not verify. */
01047         rpmMessage(RPMMESS_ERROR, "%s: %s", fn, buf);
01048         break;
01049     }
01050 
01051 exit:
01052     if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) {
01053         /* Convert legacy headers on the fly ... */
01054         legacyRetrofit(h, l);
01055         
01056         /* Append (and remap) signature tags to the metadata. */
01057         headerMergeLegacySigs(h, sigh);
01058 
01059         /* Bump reference count for return. */
01060 /*@-boundswrite@*/
01061         *hdrp = headerLink(h);
01062 /*@=boundswrite@*/
01063     }
01064     h = headerFree(h);
01065     rpmtsCleanDig(ts);
01066     sigh = rpmFreeSignature(sigh);
01067     return rc;
01068 }
01069 
01075 rpmRC headerCheckPayloadFormat(Header h) {
01076     rpmRC rc = RPMRC_FAIL;
01077     int xx;
01078     const char *payloadfmt = NULL;
01079 
01080     xx = headerGetEntry(h, RPMTAG_PAYLOADFORMAT, NULL, 
01081                         (void **)&payloadfmt, NULL);
01082     /* 
01083      * XXX Ugh, rpm 3.x packages don't have payload format tag. Instead
01084      * of blinly allowing, should check somehow (HDRID existence or... ?)
01085      */
01086     if (!payloadfmt)
01087         return RPMRC_OK;
01088 
01089     if (payloadfmt && strncmp(payloadfmt, "cpio", strlen("cpio")) == 0) {
01090         rc = RPMRC_OK;
01091     } else {
01092         const char *nevra = hGetNEVRA(h, NULL);
01093         if (payloadfmt && strncmp(payloadfmt, "drpm", strlen("drpm")) == 0) {
01094             rpmMessage(RPMMESS_ERROR,
01095                      _("%s is a Delta RPM and cannot be directly installed\n"),
01096                      nevra);
01097         } else {
01098             rpmMessage(RPMMESS_ERROR, 
01099                      _("Unsupported payload (%s) in package %s\n"),
01100                      payloadfmt ? payloadfmt : "none", nevra);
01101         } 
01102         nevra = _free(nevra);
01103     }
01104     return rc;
01105 }
01106 
01107 
01108 /*@=bounds@*/

Generated on Fri Oct 12 08:44:53 2007 for rpm by  doxygen 1.5.2