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 (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     if (!(entry->info.tag == RPMTAG_HEADERIMMUTABLE)) {
00380         rc = RPMRC_NOTFOUND;
00381         goto exit;
00382     }
00383 
00384     /* Is the region tag sane? */
00385     if (!(entry->info.type == REGION_TAG_TYPE &&
00386           entry->info.count == REGION_TAG_COUNT)) {
00387         (void) snprintf(buf, sizeof(buf),
00388                 _("region tag: BAD, tag %d type %d offset %d count %d\n"),
00389                 entry->info.tag, entry->info.type,
00390                 entry->info.offset, entry->info.count);
00391         goto exit;
00392     }
00393 
00394     /* Is the trailer within the data area? */
00395     if (entry->info.offset + REGION_TAG_COUNT > dl) {
00396         (void) snprintf(buf, sizeof(buf),
00397                 _("region offset: BAD, tag %d type %d offset %d count %d\n"),
00398                 entry->info.tag, entry->info.type,
00399                 entry->info.offset, entry->info.count);
00400         goto exit;
00401     }
00402 
00403     /* Is there an immutable header region tag trailer? */
00404     regionEnd = dataStart + entry->info.offset;
00405 /*@-sizeoftype@*/
00406 /*@-bounds@*/
00407     (void) memcpy(info, regionEnd, REGION_TAG_COUNT);
00408 /*@=bounds@*/
00409     regionEnd += REGION_TAG_COUNT;
00410 
00411     xx = headerVerifyInfo(1, il * sizeof(*pe), info, &entry->info, 1);
00412     if (xx != -1 ||
00413         !(entry->info.tag == RPMTAG_HEADERIMMUTABLE
00414        && entry->info.type == REGION_TAG_TYPE
00415        && entry->info.count == REGION_TAG_COUNT))
00416     {
00417         (void) snprintf(buf, sizeof(buf),
00418                 _("region trailer: BAD, tag %d type %d offset %d count %d\n"),
00419                 entry->info.tag, entry->info.type,
00420                 entry->info.offset, entry->info.count);
00421         goto exit;
00422     }
00423 /*@=sizeoftype@*/
00424 /*@-boundswrite@*/
00425     memset(info, 0, sizeof(*info));
00426 /*@=boundswrite@*/
00427 
00428     /* Is the no. of tags in the region less than the total no. of tags? */
00429     ril = entry->info.offset/sizeof(*pe);
00430     if ((entry->info.offset % sizeof(*pe)) || ril > il) {
00431         (void) snprintf(buf, sizeof(buf),
00432                 _("region size: BAD, ril(%d) > il(%d)\n"), ril, il);
00433         goto exit;
00434     }
00435 
00436     /* Find a header-only digest/signature tag. */
00437     for (i = ril; i < il; i++) {
00438         xx = headerVerifyInfo(1, dl, pe+i, &entry->info, 0);
00439         if (xx != -1) {
00440             (void) snprintf(buf, sizeof(buf),
00441                 _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
00442                 i, entry->info.tag, entry->info.type,
00443                 entry->info.offset, entry->info.count);
00444             goto exit;
00445         }
00446 
00447         switch (entry->info.tag) {
00448         case RPMTAG_SHA1HEADER:
00449             if (vsflags & RPMVSF_NOSHA1HEADER)
00450                 /*@switchbreak@*/ break;
00451             blen = 0;
00452 /*@-boundsread@*/
00453             for (b = dataStart + entry->info.offset; *b != '\0'; b++) {
00454                 if (strchr("0123456789abcdefABCDEF", *b) == NULL)
00455                     /*@innerbreak@*/ break;
00456                 blen++;
00457             }
00458             if (entry->info.type != RPM_STRING_TYPE || *b != '\0' || blen != 40)
00459             {
00460                 (void) snprintf(buf, sizeof(buf), _("hdr SHA1: BAD, not hex\n"));
00461                 goto exit;
00462             }
00463 /*@=boundsread@*/
00464             if (info->tag == 0) {
00465 /*@-boundswrite@*/
00466                 *info = entry->info;    /* structure assignment */
00467 /*@=boundswrite@*/
00468                 siglen = blen + 1;
00469             }
00470             /*@switchbreak@*/ break;
00471         case RPMTAG_RSAHEADER:
00472             if (vsflags & RPMVSF_NORSAHEADER)
00473                 /*@switchbreak@*/ break;
00474             if (entry->info.type != RPM_BIN_TYPE) {
00475                 (void) snprintf(buf, sizeof(buf), _("hdr RSA: BAD, not binary\n"));
00476                 goto exit;
00477             }
00478 /*@-boundswrite@*/
00479             *info = entry->info;        /* structure assignment */
00480 /*@=boundswrite@*/
00481             siglen = info->count;
00482             /*@switchbreak@*/ break;
00483         case RPMTAG_DSAHEADER:
00484             if (vsflags & RPMVSF_NODSAHEADER)
00485                 /*@switchbreak@*/ break;
00486             if (entry->info.type != RPM_BIN_TYPE) {
00487                 (void) snprintf(buf, sizeof(buf), _("hdr DSA: BAD, not binary\n"));
00488                 goto exit;
00489             }
00490 /*@-boundswrite@*/
00491             *info = entry->info;        /* structure assignment */
00492 /*@=boundswrite@*/
00493             siglen = info->count;
00494             /*@switchbreak@*/ break;
00495         default:
00496             /*@switchbreak@*/ break;
00497         }
00498     }
00499     rc = RPMRC_NOTFOUND;
00500 
00501 exit:
00502     /* Return determined RPMRC_OK/RPMRC_FAIL conditions. */
00503     if (rc != RPMRC_NOTFOUND) {
00504 /*@-boundswrite@*/
00505         buf[sizeof(buf)-1] = '\0';
00506         if (msg) *msg = xstrdup(buf);
00507 /*@=boundswrite@*/
00508         hclvl--;
00509         return rc;
00510     }
00511 
00512     /* If no header-only digest/signature, then do simple sanity check. */
00513     if (info->tag == 0) {
00514 verifyinfo_exit:
00515         xx = headerVerifyInfo(ril-1, dl, pe+1, &entry->info, 0);
00516         if (xx != -1) {
00517             (void) snprintf(buf, sizeof(buf),
00518                 _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
00519                 xx+1, entry->info.tag, entry->info.type,
00520                 entry->info.offset, entry->info.count);
00521             rc = RPMRC_FAIL;
00522         } else {
00523             (void) snprintf(buf, sizeof(buf), "Header sanity check: OK\n");
00524             rc = RPMRC_OK;
00525         }
00526 /*@-boundswrite@*/
00527         buf[sizeof(buf)-1] = '\0';
00528         if (msg) *msg = xstrdup(buf);
00529 /*@=boundswrite@*/
00530         hclvl--;
00531         return rc;
00532     }
00533 
00534     /* Verify header-only digest/signature. */
00535     dig = rpmtsDig(ts);
00536     if (dig == NULL)
00537         goto verifyinfo_exit;
00538     dig->nbytes = 0;
00539 
00540 /*@-boundsread@*/
00541     sig = memcpy(xmalloc(siglen), dataStart + info->offset, siglen);
00542 /*@=boundsread@*/
00543     (void) rpmtsSetSig(ts, info->tag, info->type, sig, info->count);
00544 
00545     switch (info->tag) {
00546     case RPMTAG_RSAHEADER:
00547         /* Parse the parameters from the OpenPGP packets that will be needed. */
00548         xx = pgpPrtPkts(sig, info->count, dig, (_print_pkts & rpmIsDebug()));
00549         if (dig->signature.version != 3 && dig->signature.version != 4) {
00550             rpmMessage(RPMMESS_ERROR,
00551                 _("skipping header with unverifiable V%u signature\n"),
00552                 dig->signature.version);
00553             rpmtsCleanDig(ts);
00554             rc = RPMRC_FAIL;
00555             goto exit;
00556         }
00557 
00558         ildl[0] = htonl(ril);
00559         ildl[1] = (regionEnd - dataStart);
00560         ildl[1] = htonl(ildl[1]);
00561 
00562         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00563         dig->hdrmd5ctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
00564 
00565         b = (unsigned char *) header_magic;
00566         nb = sizeof(header_magic);
00567         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00568         dig->nbytes += nb;
00569 
00570         b = (unsigned char *) ildl;
00571         nb = sizeof(ildl);
00572         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00573         dig->nbytes += nb;
00574 
00575         b = (unsigned char *) pe;
00576         nb = (htonl(ildl[0]) * sizeof(*pe));
00577         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00578         dig->nbytes += nb;
00579 
00580         b = (unsigned char *) dataStart;
00581         nb = htonl(ildl[1]);
00582         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00583         dig->nbytes += nb;
00584         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00585 
00586         break;
00587     case RPMTAG_DSAHEADER:
00588         /* Parse the parameters from the OpenPGP packets that will be needed. */
00589         xx = pgpPrtPkts(sig, info->count, dig, (_print_pkts & rpmIsDebug()));
00590         if (dig->signature.version != 3 && dig->signature.version != 4) {
00591             rpmMessage(RPMMESS_ERROR,
00592                 _("skipping header with unverifiable V%u signature\n"),
00593                 dig->signature.version);
00594             rpmtsCleanDig(ts);
00595             rc = RPMRC_FAIL;
00596             goto exit;
00597         }
00598         /*@fallthrough@*/
00599     case RPMTAG_SHA1HEADER:
00600 /*@-boundswrite@*/
00601         ildl[0] = htonl(ril);
00602         ildl[1] = (regionEnd - dataStart);
00603         ildl[1] = htonl(ildl[1]);
00604 /*@=boundswrite@*/
00605 
00606         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00607         dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00608 
00609         b = (unsigned char *) header_magic;
00610         nb = sizeof(header_magic);
00611         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00612         dig->nbytes += nb;
00613 
00614         b = (unsigned char *) ildl;
00615         nb = sizeof(ildl);
00616         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00617         dig->nbytes += nb;
00618 
00619         b = (unsigned char *) pe;
00620         nb = (htonl(ildl[0]) * sizeof(*pe));
00621         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00622         dig->nbytes += nb;
00623 
00624         b = (unsigned char *) dataStart;
00625         nb = htonl(ildl[1]);
00626         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00627         dig->nbytes += nb;
00628         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00629 
00630         break;
00631     default:
00632         sig = _free(sig);
00633         break;
00634     }
00635 
00636 /*@-boundswrite@*/
00637     buf[0] = '\0';
00638 /*@=boundswrite@*/
00639     rc = rpmVerifySignature(ts, buf);
00640 
00641 /*@-boundswrite@*/
00642     buf[sizeof(buf)-1] = '\0';
00643     if (msg) *msg = xstrdup(buf);
00644 /*@=boundswrite@*/
00645 
00646     /* XXX headerCheck can recurse, free info only at top level. */
00647     if (hclvl == 1)
00648         rpmtsCleanDig(ts);
00649     if (info->tag == RPMTAG_SHA1HEADER)
00650         sig = _free(sig);
00651     hclvl--;
00652     return rc;
00653 }
00654 
00655 rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, const char ** msg)
00656 {
00657     char buf[BUFSIZ];
00658     int_32 block[4];
00659     int_32 il;
00660     int_32 dl;
00661     int_32 * ei = NULL;
00662     size_t uc;
00663     int_32 nb;
00664     Header h = NULL;
00665     rpmRC rc = RPMRC_FAIL;              /* assume failure */
00666     int xx;
00667 
00668 /*@-boundswrite@*/
00669     buf[0] = '\0';
00670 
00671     if (hdrp)
00672         *hdrp = NULL;
00673     if (msg)
00674         *msg = NULL;
00675 /*@=boundswrite@*/
00676 
00677     memset(block, 0, sizeof(block));
00678     if ((xx = timedRead(fd, (char *)block, sizeof(block))) != sizeof(block)) {
00679         (void) snprintf(buf, sizeof(buf),
00680                 _("hdr size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx);
00681         goto exit;
00682     }
00683     if (memcmp(block, header_magic, sizeof(header_magic))) {
00684         (void) snprintf(buf, sizeof(buf), _("hdr magic: BAD\n"));
00685         goto exit;
00686     }
00687 /*@-boundsread@*/
00688     il = ntohl(block[2]);
00689 /*@=boundsread@*/
00690     if (hdrchkTags(il)) {
00691         (void) snprintf(buf, sizeof(buf),
00692                 _("hdr tags: BAD, no. of tags(%d) out of range\n"), il);
00693 
00694         goto exit;
00695     }
00696 /*@-boundsread@*/
00697     dl = ntohl(block[3]);
00698 /*@=boundsread@*/
00699     if (hdrchkData(dl)) {
00700         (void) snprintf(buf, sizeof(buf),
00701                 _("hdr data: BAD, no. of bytes(%d) out of range\n"), dl);
00702         goto exit;
00703     }
00704 
00705 /*@-sizeoftype@*/
00706     nb = (il * sizeof(struct entryInfo_s)) + dl;
00707 /*@=sizeoftype@*/
00708     uc = sizeof(il) + sizeof(dl) + nb;
00709     ei = xmalloc(uc);
00710 /*@-bounds@*/
00711     ei[0] = block[2];
00712     ei[1] = block[3];
00713     if ((xx = timedRead(fd, (char *)&ei[2], nb)) != nb) {
00714         (void) snprintf(buf, sizeof(buf),
00715                 _("hdr blob(%d): BAD, read returned %d\n"), nb, xx);
00716         goto exit;
00717     }
00718 /*@=bounds@*/
00719 
00720     /* Sanity check header tags */
00721     rc = headerCheck(ts, ei, uc, msg);
00722     if (rc != RPMRC_OK)
00723         goto exit;
00724 
00725     /* OK, blob looks sane, load the header. */
00726     h = headerLoad(ei);
00727     if (h == NULL) {
00728         (void) snprintf(buf, sizeof(buf), _("hdr load: BAD\n"));
00729         goto exit;
00730     }
00731     h->flags |= HEADERFLAG_ALLOCATED;
00732     ei = NULL;  /* XXX will be freed with header */
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     int xx;
00771     int i;
00772 
00773     if (hdrp) *hdrp = NULL;
00774 
00775 #ifdef  DYING
00776     {   struct stat st;
00777 /*@-boundswrite@*/
00778         memset(&st, 0, sizeof(st));
00779 /*@=boundswrite@*/
00780         (void) fstat(Fileno(fd), &st);
00781         /* if fd points to a socket, pipe, etc, st.st_size is *always* zero */
00782         if (S_ISREG(st.st_mode) && st.st_size < sizeof(*l)) {
00783             rc = RPMRC_NOTFOUND;
00784             goto exit;
00785         }
00786     }
00787 #endif
00788 
00789     memset(l, 0, sizeof(*l));
00790     rc = readLead(fd, l);
00791     if (rc != RPMRC_OK)
00792         goto exit;
00793 
00794     switch (l->major) {
00795     case 1:
00796         rpmError(RPMERR_NEWPACKAGE,
00797             _("packaging version 1 is not supported by this version of RPM\n"));
00798         rc = RPMRC_NOTFOUND;
00799         goto exit;
00800         /*@notreached@*/ break;
00801     case 2:
00802     case 3:
00803     case 4:
00804         break;
00805     default:
00806         rpmError(RPMERR_NEWPACKAGE, _("only packaging with major numbers <= 4 "
00807                 "is supported by this version of RPM\n"));
00808         rc = RPMRC_NOTFOUND;
00809         goto exit;
00810         /*@notreached@*/ break;
00811     }
00812 
00813     /* Read the signature header. */
00814     msg = NULL;
00815     rc = rpmReadSignature(fd, &sigh, l->signature_type, &msg);
00816     switch (rc) {
00817     default:
00818         rpmError(RPMERR_SIGGEN, _("%s: rpmReadSignature failed: %s"), fn,
00819                 (msg && *msg ? msg : "\n"));
00820         msg = _free(msg);
00821         goto exit;
00822         /*@notreached@*/ break;
00823     case RPMRC_OK:
00824         if (sigh == NULL) {
00825             rpmError(RPMERR_SIGGEN, _("%s: No signature available\n"), fn);
00826             rc = RPMRC_FAIL;
00827             goto exit;
00828         }
00829         break;
00830     }
00831     msg = _free(msg);
00832 
00833 #define _chk(_mask)     (sigtag == 0 && !(vsflags & (_mask)))
00834 
00835     /*
00836      * Figger the most effective available signature.
00837      * Prefer signatures over digests, then header-only over header+payload.
00838      * DSA will be preferred over RSA if both exist because tested first.
00839      * Note that NEEDPAYLOAD prevents header+payload signatures and digests.
00840      */
00841     sigtag = 0;
00842     opx = 0;
00843     vsflags = rpmtsVSFlags(ts);
00844     if (_chk(RPMVSF_NODSAHEADER) && headerIsEntry(sigh, RPMSIGTAG_DSA)) {
00845         sigtag = RPMSIGTAG_DSA;
00846     } else
00847     if (_chk(RPMVSF_NORSAHEADER) && headerIsEntry(sigh, RPMSIGTAG_RSA)) {
00848         sigtag = RPMSIGTAG_RSA;
00849     } else
00850     if (_chk(RPMVSF_NODSA|RPMVSF_NEEDPAYLOAD) &&
00851         headerIsEntry(sigh, RPMSIGTAG_GPG))
00852     {
00853         sigtag = RPMSIGTAG_GPG;
00854         fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
00855         opx = RPMTS_OP_SIGNATURE;
00856     } else
00857     if (_chk(RPMVSF_NORSA|RPMVSF_NEEDPAYLOAD) &&
00858         headerIsEntry(sigh, RPMSIGTAG_PGP))
00859     {
00860         sigtag = RPMSIGTAG_PGP;
00861         fdInitDigest(fd, PGPHASHALGO_MD5, 0);
00862         opx = RPMTS_OP_SIGNATURE;
00863     } else
00864     if (_chk(RPMVSF_NOSHA1HEADER) && headerIsEntry(sigh, RPMSIGTAG_SHA1)) {
00865         sigtag = RPMSIGTAG_SHA1;
00866     } else
00867     if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD) &&
00868         headerIsEntry(sigh, RPMSIGTAG_MD5))
00869     {
00870         sigtag = RPMSIGTAG_MD5;
00871         fdInitDigest(fd, PGPHASHALGO_MD5, 0);
00872         opx = RPMTS_OP_DIGEST;
00873     }
00874 
00875     /* Read the metadata, computing digest(s) on the fly. */
00876     h = NULL;
00877     msg = NULL;
00878 
00879     /* XXX stats will include header i/o and setup overhead. */
00880     /* XXX repackaged packages have appended tags, legacy dig/sig check fails */
00881     if (opx > 0)
00882         (void) rpmswEnter(rpmtsOp(ts, opx), 0);
00883 /*@-type@*/     /* XXX arrow access of non-pointer (FDSTAT_t) */
00884     nb = -fd->stats->ops[FDSTAT_READ].bytes;
00885     rc = rpmReadHeader(ts, fd, &h, &msg);
00886     nb += fd->stats->ops[FDSTAT_READ].bytes;
00887 /*@=type@*/
00888     if (opx > 0)
00889         (void) rpmswExit(rpmtsOp(ts, opx), nb);
00890 
00891     if (rc != RPMRC_OK || h == NULL) {
00892         rpmError(RPMERR_FREAD, _("%s: headerRead failed: %s"), fn,
00893                 (msg && *msg ? msg : "\n"));
00894         msg = _free(msg);
00895         goto exit;
00896     }
00897     msg = _free(msg);
00898 
00899     /* Any digests or signatures to check? */
00900     if (sigtag == 0) {
00901         rc = RPMRC_OK;
00902         goto exit;
00903     }
00904 
00905     dig = rpmtsDig(ts);
00906     if (dig == NULL) {
00907         rc = RPMRC_FAIL;
00908         goto exit;
00909     }
00910     dig->nbytes = 0;
00911 
00912     /* Retrieve the tag parameters from the signature header. */
00913     sig = NULL;
00914     xx = headerGetEntry(sigh, sigtag, &sigtype, (void **) &sig, &siglen);
00915     if (sig == NULL) {
00916         rc = RPMRC_FAIL;
00917         goto exit;
00918     }
00919     (void) rpmtsSetSig(ts, sigtag, sigtype, sig, siglen);
00920 
00921     switch (sigtag) {
00922     case RPMSIGTAG_RSA:
00923         /* Parse the parameters from the OpenPGP packets that will be needed. */
00924         xx = pgpPrtPkts(sig, siglen, dig, (_print_pkts & rpmIsDebug()));
00925         if (dig->signature.version != 3 && dig->signature.version != 4) {
00926             rpmMessage(RPMMESS_ERROR,
00927                 _("skipping package %s with unverifiable V%u signature\n"),
00928                 fn, dig->signature.version);
00929             rc = RPMRC_FAIL;
00930             goto exit;
00931         }
00932     {   void * uh = NULL;
00933         int_32 uht;
00934         int_32 uhc;
00935 
00936         if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc))
00937             break;
00938         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00939         dig->hdrmd5ctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
00940         (void) rpmDigestUpdate(dig->hdrmd5ctx, header_magic, sizeof(header_magic));
00941         dig->nbytes += sizeof(header_magic);
00942         (void) rpmDigestUpdate(dig->hdrmd5ctx, uh, uhc);
00943         dig->nbytes += uhc;
00944         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00945         rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;  /* XXX one too many */
00946         uh = headerFreeData(uh, uht);
00947     }   break;
00948     case RPMSIGTAG_DSA:
00949         /* Parse the parameters from the OpenPGP packets that will be needed. */
00950         xx = pgpPrtPkts(sig, siglen, dig, (_print_pkts & rpmIsDebug()));
00951         if (dig->signature.version != 3 && dig->signature.version != 4) {
00952             rpmMessage(RPMMESS_ERROR,
00953                 _("skipping package %s with unverifiable V%u signature\n"), 
00954                 fn, dig->signature.version);
00955             rc = RPMRC_FAIL;
00956             goto exit;
00957         }
00958         /*@fallthrough@*/
00959     case RPMSIGTAG_SHA1:
00960     {   void * uh = NULL;
00961         int_32 uht;
00962         int_32 uhc;
00963 
00964         if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc))
00965             break;
00966         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00967         dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00968         (void) rpmDigestUpdate(dig->hdrsha1ctx, header_magic, sizeof(header_magic));
00969         dig->nbytes += sizeof(header_magic);
00970         (void) rpmDigestUpdate(dig->hdrsha1ctx, uh, uhc);
00971         dig->nbytes += uhc;
00972         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00973         if (sigtag == RPMSIGTAG_SHA1)
00974             rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;      /* XXX one too many */
00975         uh = headerFreeData(uh, uht);
00976     }   break;
00977     case RPMSIGTAG_GPG:
00978     case RPMSIGTAG_PGP5:        /* XXX legacy */
00979     case RPMSIGTAG_PGP:
00980         /* Parse the parameters from the OpenPGP packets that will be needed. */
00981         xx = pgpPrtPkts(sig, siglen, dig, (_print_pkts & rpmIsDebug()));
00982 
00983         if (dig->signature.version != 3 && dig->signature.version != 4) {
00984             rpmMessage(RPMMESS_ERROR,
00985                 _("skipping package %s with unverifiable V%u signature\n"),
00986                 fn, dig->signature.version);
00987             rc = RPMRC_FAIL;
00988             goto exit;
00989         }
00990         /*@fallthrough@*/
00991     case RPMSIGTAG_MD5:
00992         /* Legacy signatures need the compressed payload in the digest too. */
00993         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00994         while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
00995             dig->nbytes += count;
00996         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00997         rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;  /* XXX one too many */
00998         dig->nbytes += nb;      /* XXX include size of header blob. */
00999         if (count < 0) {
01000             rpmError(RPMERR_FREAD, _("%s: Fread failed: %s\n"),
01001                                         fn, Fstrerror(fd));
01002             rc = RPMRC_FAIL;
01003             goto exit;
01004         }
01005 
01006         /* XXX Steal the digest-in-progress from the file handle. */
01007         for (i = fd->ndigests - 1; i >= 0; i--) {
01008             FDDIGEST_t fddig = fd->digests + i;
01009             if (fddig->hashctx != NULL)
01010             switch (fddig->hashalgo) {
01011             case PGPHASHALGO_MD5:
01012                 dig->md5ctx = fddig->hashctx;
01013                 fddig->hashctx = NULL;
01014                 /*@switchbreak@*/ break;
01015             case PGPHASHALGO_SHA1:
01016             case PGPHASHALGO_SHA256:
01017             case PGPHASHALGO_SHA384:
01018             case PGPHASHALGO_SHA512:
01019                 dig->sha1ctx = fddig->hashctx;
01020                 fddig->hashctx = NULL;
01021                 /*@switchbreak@*/ break;
01022             default:
01023                 /*@switchbreak@*/ break;
01024             }
01025         }
01026         break;
01027     }
01028 
01031 /*@-boundswrite@*/
01032     buf[0] = '\0';
01033 /*@=boundswrite@*/
01034     rc = rpmVerifySignature(ts, buf);
01035     switch (rc) {
01036     case RPMRC_OK:              /* Signature is OK. */
01037         rpmMessage(RPMMESS_DEBUG, "%s: %s", fn, buf);
01038         break;
01039     case RPMRC_NOTTRUSTED:      /* Signature is OK, but key is not trusted. */
01040     case RPMRC_NOKEY:           /* Public key is unavailable. */
01041         /* XXX Print NOKEY/NOTTRUSTED warning only once. */
01042     {   int lvl = (rpmtsStashKeyid(ts) ? RPMMESS_DEBUG : RPMMESS_WARNING);
01043         rpmMessage(lvl, "%s: %s", fn, buf);
01044     }   break;
01045     case RPMRC_NOTFOUND:        /* Signature is unknown type. */
01046         rpmMessage(RPMMESS_WARNING, "%s: %s", fn, buf);
01047         break;
01048     default:
01049     case RPMRC_FAIL:            /* Signature does not verify. */
01050         rpmMessage(RPMMESS_ERROR, "%s: %s", fn, buf);
01051         break;
01052     }
01053 
01054 exit:
01055     if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) {
01056         /* Convert legacy headers on the fly ... */
01057         legacyRetrofit(h, l);
01058         
01059         /* Append (and remap) signature tags to the metadata. */
01060         headerMergeLegacySigs(h, sigh);
01061 
01062         /* Bump reference count for return. */
01063 /*@-boundswrite@*/
01064         *hdrp = headerLink(h);
01065 /*@=boundswrite@*/
01066     }
01067     h = headerFree(h);
01068     rpmtsCleanDig(ts);
01069     sigh = rpmFreeSignature(sigh);
01070     return rc;
01071 }
01072 
01078 rpmRC headerCheckPayloadFormat(Header h) {
01079     rpmRC rc = RPMRC_FAIL;
01080     int xx;
01081     const char *payloadfmt = NULL;
01082 
01083     xx = headerGetEntry(h, RPMTAG_PAYLOADFORMAT, NULL, 
01084                         (void **)&payloadfmt, NULL);
01085     /* 
01086      * XXX Ugh, rpm 3.x packages don't have payload format tag. Instead
01087      * of blinly allowing, should check somehow (HDRID existence or... ?)
01088      */
01089     if (!payloadfmt)
01090         return RPMRC_OK;
01091 
01092     if (payloadfmt && strncmp(payloadfmt, "cpio", strlen("cpio")) == 0) {
01093         rc = RPMRC_OK;
01094     } else {
01095         const char *nevra = hGetNEVRA(h, NULL);
01096         if (payloadfmt && strncmp(payloadfmt, "drpm", strlen("drpm")) == 0) {
01097             rpmMessage(RPMMESS_ERROR,
01098                      _("%s is a Delta RPM and cannot be directly installed\n"),
01099                      nevra);
01100         } else {
01101             rpmMessage(RPMMESS_ERROR, 
01102                      _("Unsupported payload (%s) in package %s\n"),
01103                      payloadfmt ? payloadfmt : "none", nevra);
01104         } 
01105         nevra = _free(nevra);
01106     }
01107     return rc;
01108 }
01109 
01110 
01111 /*@=bounds@*/

Generated on Mon Feb 25 17:14:22 2013 for rpm by  doxygen 1.4.7