Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

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 #if defined(RPM_VENDOR_MANDRIVA)
00013 #define _RPMEVR_INTERNAL
00014 #include "rpmevr.h"
00015 #endif
00016 
00017 #include "rpmts.h"
00018 #include "rpmevr.h"
00019 
00020 #include "misc.h"       /* XXX stripTrailingChar() */
00021 #include "rpmlead.h"
00022 
00023 #include "header_internal.h"    /* XXX headerCheck */
00024 #include "signature.h"
00025 #include "debug.h"
00026 
00027 #define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
00028 
00029 /*@access pgpDig @*/
00030 /*@access pgpDigParams @*/
00031 /*@access Header @*/            /* XXX compared with NULL */
00032 /*@access entryInfo @*/         /* XXX headerCheck */
00033 /*@access indexEntry @*/        /* XXX headerCheck */
00034 /*@access FD_t @*/              /* XXX stealing digests */
00035 
00036 /*@unchecked@*/
00037 static int _print_pkts = 0;
00038 
00039 /*@unchecked@*/
00040 static unsigned int nkeyids_max = 256;
00041 /*@unchecked@*/
00042 static unsigned int nkeyids = 0;
00043 /*@unchecked@*/
00044 static unsigned int nextkeyid  = 0;
00045 /*@unchecked@*/ /*@only@*/ /*@null@*/
00046 static unsigned int * keyids;
00047 
00048 /*@unchecked@*/
00049 static unsigned char header_magic[8] = {
00050         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00051 };
00052 
00056 /*@observer@*/ /*@unchecked@*/
00057 static int typeAlign[16] =  {
00058     1,  
00059     1,  
00060     1,  
00061     2,  
00062     4,  
00063     8,  
00064     1,  
00065     1,  
00066     1,  
00067     1,  
00068     0,
00069     0,
00070     0,
00071     0,
00072     0,
00073     0
00074 };
00075 
00080 #define hdrchkTags(_ntags)      ((_ntags) & 0xffff0000)
00081 
00085 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00086 
00091 #define hdrchkData(_nbytes) ((_nbytes) & 0xff000000)
00092 
00096 #define hdrchkAlign(_type, _off)        ((_off) & (typeAlign[_type]-1))
00097 
00101 #define hdrchkRange(_dl, _off)          ((_off) < 0 || (_off) > (_dl))
00102 
00103 #if defined(RPM_VENDOR_MANDRIVA)
00104 /*@-boundsread@*/
00105 static int dncmp(const void * a, const void * b)
00106        /*@*/
00107 {
00108     const char *const * first = a;
00109     const char *const * second = b;
00110     return strcmp(*first, *second);
00111 }
00112 /*@=boundsread@*/
00113 
00114 /*@-bounds@*/
00119 static void compressFilelist(Header h)
00120         /*@modifies h @*/
00121 {
00122     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00123     HAE_t hae = (HAE_t)headerAddEntry;
00124     HRE_t hre = (HRE_t)headerRemoveEntry;
00125     HFD_t hfd = headerFreeData;
00126     char ** fileNames;
00127     const char ** dirNames;
00128     const char ** baseNames;
00129     int_32 * dirIndexes;
00130     rpmTagType fnt;
00131     int count;
00132     int i, xx;
00133     int dirIndex = -1;
00134 
00135     /*
00136      * This assumes the file list is already sorted, and begins with a
00137      * single '/'. That assumption isn't critical, but it makes things go
00138      * a bit faster.
00139      */
00140 
00141     if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
00142         xx = hre(h, RPMTAG_OLDFILENAMES);
00143         return;         /* Already converted. */
00144     }
00145 
00146     if (!hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &fileNames, &count))
00147         return;         /* no file list */
00148     if (fileNames == NULL || count <= 0)
00149         return;
00150 
00151     dirNames = alloca(sizeof(*dirNames) * count);       /* worst case */
00152     baseNames = alloca(sizeof(*dirNames) * count);
00153     dirIndexes = alloca(sizeof(*dirIndexes) * count);
00154 
00155     if (fileNames[0][0] != '/') {
00156         /* HACK. Source RPM, so just do things differently */
00157         dirIndex = 0;
00158         dirNames[dirIndex] = "";
00159         for (i = 0; i < count; i++) {
00160             dirIndexes[i] = dirIndex;
00161             baseNames[i] = fileNames[i];
00162         }
00163         goto exit;
00164     }
00165 
00166     /*@-branchstate@*/
00167     for (i = 0; i < count; i++) {
00168         const char ** needle;
00169         char savechar;
00170         char * baseName;
00171         int len;
00172 
00173         if (fileNames[i] == NULL)       /* XXX can't happen */
00174             continue;
00175         baseName = strrchr(fileNames[i], '/') + 1;
00176         len = baseName - fileNames[i];
00177         needle = dirNames;
00178         savechar = *baseName;
00179         *baseName = '\0';
00180 /*@-compdef@*/
00181         if (dirIndex < 0 ||
00182             (needle = bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
00183             char *s = alloca(len + 1);
00184             memcpy(s, fileNames[i], len + 1);
00185             s[len] = '\0';
00186             dirIndexes[i] = ++dirIndex;
00187             dirNames[dirIndex] = s;
00188         } else
00189             dirIndexes[i] = needle - dirNames;
00190 /*@=compdef@*/
00191 
00192         *baseName = savechar;
00193         baseNames[i] = baseName;
00194     }
00195     /*@=branchstate@*/
00196 
00197 exit:
00198     if (count > 0) {
00199         xx = hae(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dirIndexes, count);
00200         xx = hae(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
00201                         baseNames, count);
00202         xx = hae(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
00203                         dirNames, dirIndex + 1);
00204     }
00205 
00206     fileNames = hfd(fileNames, fnt);
00207 
00208     xx = hre(h, RPMTAG_OLDFILENAMES);
00209 }
00210 /*@=bounds@*/
00211 
00212 
00213 /* copied verbatim from build/pack.c */
00214 static void providePackageNVR(Header h)
00215         /*@modifies h @*/
00216 {
00217     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00218     HFD_t hfd = headerFreeData;
00219     const char *name, *version, *release;
00220     int_32 * epoch;
00221     const char *pEVR;
00222     char *p;
00223     int_32 pFlags = RPMSENSE_EQUAL;
00224     const char ** provides = NULL;
00225     const char ** providesEVR = NULL;
00226     rpmTagType pnt, pvt;
00227     int_32 * provideFlags = NULL;
00228     int providesCount;
00229     int i, xx;
00230     int bingo = 1;
00231 
00232     /* Generate provides for this package name-version-release. */
00233     xx = headerNVR(h, &name, &version, &release);
00234     if (!(name && version && release))
00235         return;
00236     pEVR = p = alloca(21 + strlen(version) + 1 + strlen(release) + 1);
00237     *p = '\0';
00238     if (hge(h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) {
00239         sprintf(p, "%d:", *epoch);
00240         while (*p != '\0')
00241             p++;
00242     }
00243     (void) stpcpy( stpcpy( stpcpy(p, version) , "-") , release);
00244 
00245     /*
00246      * Rpm prior to 3.0.3 does not have versioned provides.
00247      * If no provides at all are available, we can just add.
00248      */
00249     if (!hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides, &providesCount))
00250         goto exit;
00251 
00252     /*
00253      * Otherwise, fill in entries on legacy packages.
00254      */
00255     if (!hge(h, RPMTAG_PROVIDEVERSION, &pvt, (void **) &providesEVR, NULL)) {
00256         for (i = 0; i < providesCount; i++) {
00257             char * vdummy = "";
00258             int_32 fdummy = RPMSENSE_ANY;
00259             xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
00260                         &vdummy, 1);
00261             xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
00262                         &fdummy, 1);
00263         }
00264         goto exit;
00265     }
00266 
00267     xx = hge(h, RPMTAG_PROVIDEFLAGS, NULL, (void **) &provideFlags, NULL);
00268 
00269     /*@-nullderef@*/    /* LCL: providesEVR is not NULL */
00270     if (provides && providesEVR && provideFlags)
00271     for (i = 0; i < providesCount; i++) {
00272         if (!(provides[i] && providesEVR[i]))
00273             continue;
00274         if (!(provideFlags[i] == RPMSENSE_EQUAL &&
00275             !strcmp(name, provides[i]) && !strcmp(pEVR, providesEVR[i])))
00276             continue;
00277         bingo = 0;
00278         break;
00279     }
00280     /*@=nullderef@*/
00281 
00282 exit:
00283     provides = hfd(provides, pnt);
00284     providesEVR = hfd(providesEVR, pvt);
00285 
00286     if (bingo) {
00287         xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME, RPM_STRING_ARRAY_TYPE,
00288                 &name, 1);
00289         xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE,
00290                 &pFlags, 1);
00291         xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE,
00292                 &pEVR, 1);
00293     }
00294 }
00295 
00296 static void add_RPMTAG_SOURCERPM(Header h)
00297 {
00298   if (!headerIsEntry(h, RPMTAG_SOURCERPM) && !headerIsEntry(h, RPMTAG_SOURCEPACKAGE)) {
00299     /* we have no way to know if this is a srpm or an rpm with no SOURCERPM */
00300     /* but since this is an old v3 rpm, we suppose it's not a srpm */
00301     headerAddEntry(h, RPMTAG_SOURCERPM, RPM_STRING_TYPE, "\0", 1);
00302   }
00303 }
00304 
00305 /* rpm v3 compatibility */
00306 static void rpm3to4(Header h) {
00307     char * rpmversion;
00308     rpmTagType rpmversion_type;
00309 
00310     (void) headerGetEntry(h, RPMTAG_RPMVERSION, NULL, (void **) &rpmversion, &rpmversion_type);
00311 
00312     if ((!rpmversion) || rpmversion[0] < '4') {
00313         add_RPMTAG_SOURCERPM(h);
00314         providePackageNVR(h);
00315         compressFilelist(h);
00316     }
00317     headerFreeTag(h, (void *) rpmversion, rpmversion_type);
00318     return;
00319 }
00320 #endif
00321 
00322 /*@-boundsread@*/
00323 static int dncmp(const void * a, const void * b)
00324        /*@*/
00325 {
00326     const char *const * first = a;
00327     const char *const * second = b;
00328     return strcmp(*first, *second);
00329 }
00330 /*@=boundsread@*/
00331 
00332 /*@-bounds@*/
00337 static void compressFilelist(Header h)
00338         /*@modifies h @*/
00339 {
00340     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00341     HAE_t hae = (HAE_t)headerAddEntry;
00342     HRE_t hre = (HRE_t)headerRemoveEntry;
00343     HFD_t hfd = headerFreeData;
00344     char ** fileNames;
00345     const char ** dirNames;
00346     const char ** baseNames;
00347     int_32 * dirIndexes;
00348     rpmTagType fnt;
00349     int count;
00350     int i, xx;
00351     int dirIndex = -1;
00352 
00353     /*
00354      * This assumes the file list is already sorted, and begins with a
00355      * single '/'. That assumption isn't critical, but it makes things go
00356      * a bit faster.
00357      */
00358 
00359     if (headerIsEntry(h, RPMTAG_DIRNAMES)) {
00360         xx = hre(h, RPMTAG_OLDFILENAMES);
00361         return;         /* Already converted. */
00362     }
00363 
00364     if (!hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &fileNames, &count))
00365         return;         /* no file list */
00366     if (fileNames == NULL || count <= 0)
00367         return;
00368 
00369     dirNames = alloca(sizeof(*dirNames) * count);       /* worst case */
00370     baseNames = alloca(sizeof(*dirNames) * count);
00371     dirIndexes = alloca(sizeof(*dirIndexes) * count);
00372 
00373     if (fileNames[0][0] != '/') {
00374         /* HACK. Source RPM, so just do things differently */
00375         dirIndex = 0;
00376         dirNames[dirIndex] = "";
00377         for (i = 0; i < count; i++) {
00378             dirIndexes[i] = dirIndex;
00379             baseNames[i] = fileNames[i];
00380         }
00381         goto exit;
00382     }
00383 
00384     /*@-branchstate@*/
00385     for (i = 0; i < count; i++) {
00386         const char ** needle;
00387         char savechar;
00388         char * baseName;
00389         int len;
00390 
00391         if (fileNames[i] == NULL)       /* XXX can't happen */
00392             continue;
00393         baseName = strrchr(fileNames[i], '/') + 1;
00394         len = baseName - fileNames[i];
00395         needle = dirNames;
00396         savechar = *baseName;
00397         *baseName = '\0';
00398 /*@-compdef@*/
00399         if (dirIndex < 0 ||
00400             (needle = bsearch(&fileNames[i], dirNames, dirIndex + 1, sizeof(dirNames[0]), dncmp)) == NULL) {
00401             char *s = alloca(len + 1);
00402             memcpy(s, fileNames[i], len + 1);
00403             s[len] = '\0';
00404             dirIndexes[i] = ++dirIndex;
00405             dirNames[dirIndex] = s;
00406         } else
00407             dirIndexes[i] = needle - dirNames;
00408 /*@=compdef@*/
00409 
00410         *baseName = savechar;
00411         baseNames[i] = baseName;
00412     }
00413     /*@=branchstate@*/
00414 
00415 exit:
00416     if (count > 0) {
00417         xx = hae(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dirIndexes, count);
00418         xx = hae(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
00419                         baseNames, count);
00420         xx = hae(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
00421                         dirNames, dirIndex + 1);
00422     }
00423 
00424     fileNames = hfd(fileNames, fnt);
00425 
00426     xx = hre(h, RPMTAG_OLDFILENAMES);
00427 }
00428 /*@=bounds@*/
00429 
00430 /* rpm v3 compatibility */
00431 static void rpm3to4(Header h) {
00432     char * rpmversion;
00433     int_32 rpmversion_type;
00434 
00435     (void) headerGetEntry(h, RPMTAG_RPMVERSION, NULL, (void **) &rpmversion, &rpmversion_type);
00436 
00437     if ((!rpmversion) || rpmversion[0] < '4') {
00438         int *epoch;
00439         const char * name, *version, *release;
00440         const char *pEVR;
00441         char *p;
00442         int_32 pFlags = RPMSENSE_EQUAL;
00443 
00444         if (headerNVR(h, &name, &version, &release) == 0) {
00445             pEVR = p = alloca(21 + strlen(version) + 1 + strlen(release) + 1);
00446             *p = '\0';
00447             if (headerGetEntry(h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) {
00448                 sprintf(p, "%d:", *epoch);
00449                 while (*p != '\0')
00450                 p++;
00451             }
00452             (void) stpcpy( stpcpy( stpcpy(p, version) , "-") , release);
00453 
00454             headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME, RPM_STRING_ARRAY_TYPE, &name, 1);
00455             headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS, RPM_INT32_TYPE, &pFlags, 1);
00456             headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION, RPM_STRING_ARRAY_TYPE, &pEVR, 1);
00457         }
00458         compressFilelist(h);
00459     }
00460     headerFreeTag(h, (void *) rpmversion, rpmversion_type);
00461     return;
00462 }
00463 
00464 void headerMergeLegacySigs(Header h, const Header sigh)
00465 {
00466     HFD_t hfd = (HFD_t) headerFreeData;
00467     HAE_t hae = (HAE_t) headerAddEntry;
00468     HeaderIterator hi;
00469     int_32 tag, type, count;
00470     const void * ptr;
00471     int xx;
00472 
00473     for (hi = headerInitIterator(sigh);
00474         headerNextIterator(hi, &tag, &type, &ptr, &count);
00475         ptr = hfd(ptr, type))
00476     {
00477         switch (tag) {
00478         /* XXX Translate legacy signature tag values. */
00479         case RPMSIGTAG_SIZE:
00480             tag = RPMTAG_SIGSIZE;
00481             /*@switchbreak@*/ break;
00482         case RPMSIGTAG_LEMD5_1:
00483             tag = RPMTAG_SIGLEMD5_1;
00484             /*@switchbreak@*/ break;
00485         case RPMSIGTAG_PGP:
00486             tag = RPMTAG_SIGPGP;
00487             /*@switchbreak@*/ break;
00488         case RPMSIGTAG_LEMD5_2:
00489             tag = RPMTAG_SIGLEMD5_2;
00490             /*@switchbreak@*/ break;
00491         case RPMSIGTAG_MD5:
00492             tag = RPMTAG_SIGMD5;
00493             /*@switchbreak@*/ break;
00494         case RPMSIGTAG_GPG:
00495             tag = RPMTAG_SIGGPG;
00496             /*@switchbreak@*/ break;
00497         case RPMSIGTAG_PGP5:
00498             tag = RPMTAG_SIGPGP5;
00499             /*@switchbreak@*/ break;
00500         case RPMSIGTAG_PAYLOADSIZE:
00501             tag = RPMTAG_ARCHIVESIZE;
00502             /*@switchbreak@*/ break;
00503         case RPMSIGTAG_SHA1:
00504         case RPMSIGTAG_DSA:
00505         case RPMSIGTAG_RSA:
00506         default:
00507             if (!(tag >= HEADER_SIGBASE && tag < HEADER_TAGBASE))
00508                 continue;
00509             /*@switchbreak@*/ break;
00510         }
00511         if (ptr == NULL) continue;      /* XXX can't happen */
00512         if (!headerIsEntry(h, tag)) {
00513             if (hdrchkType(type))
00514                 continue;
00515             if (count < 0 || hdrchkData(count))
00516                 continue;
00517             switch(type) {
00518             case RPM_NULL_TYPE:
00519                 continue;
00520                 /*@notreached@*/ /*@switchbreak@*/ break;
00521             case RPM_CHAR_TYPE:
00522             case RPM_INT8_TYPE:
00523             case RPM_INT16_TYPE:
00524             case RPM_INT32_TYPE:
00525                 if (count != 1)
00526                     continue;
00527                 /*@switchbreak@*/ break;
00528             case RPM_STRING_TYPE:
00529             case RPM_BIN_TYPE:
00530                 if (count >= 16*1024)
00531                     continue;
00532                 /*@switchbreak@*/ break;
00533             case RPM_STRING_ARRAY_TYPE:
00534             case RPM_I18NSTRING_TYPE:
00535                 continue;
00536                 /*@notreached@*/ /*@switchbreak@*/ break;
00537             }
00538             xx = hae(h, tag, type, ptr, count);
00539         }
00540     }
00541     hi = headerFreeIterator(hi);
00542 }
00543 
00544 Header headerRegenSigHeader(const Header h, int noArchiveSize)
00545 {
00546     HFD_t hfd = (HFD_t) headerFreeData;
00547     Header sigh = rpmNewSignature();
00548     HeaderIterator hi;
00549     int_32 tag, stag, type, count;
00550     const void * ptr;
00551     int xx;
00552 
00553     for (hi = headerInitIterator(h);
00554         headerNextIterator(hi, &tag, &type, &ptr, &count);
00555         ptr = hfd(ptr, type))
00556     {
00557         switch (tag) {
00558         /* XXX Translate legacy signature tag values. */
00559         case RPMTAG_SIGSIZE:
00560             stag = RPMSIGTAG_SIZE;
00561             /*@switchbreak@*/ break;
00562         case RPMTAG_SIGLEMD5_1:
00563             stag = RPMSIGTAG_LEMD5_1;
00564             /*@switchbreak@*/ break;
00565         case RPMTAG_SIGPGP:
00566             stag = RPMSIGTAG_PGP;
00567             /*@switchbreak@*/ break;
00568         case RPMTAG_SIGLEMD5_2:
00569             stag = RPMSIGTAG_LEMD5_2;
00570             /*@switchbreak@*/ break;
00571         case RPMTAG_SIGMD5:
00572             stag = RPMSIGTAG_MD5;
00573             /*@switchbreak@*/ break;
00574         case RPMTAG_SIGGPG:
00575             stag = RPMSIGTAG_GPG;
00576             /*@switchbreak@*/ break;
00577         case RPMTAG_SIGPGP5:
00578             stag = RPMSIGTAG_PGP5;
00579             /*@switchbreak@*/ break;
00580         case RPMTAG_ARCHIVESIZE:
00581             /* XXX rpm-4.1 and later has archive size in signature header. */
00582             if (noArchiveSize)
00583                 continue;
00584             stag = RPMSIGTAG_PAYLOADSIZE;
00585             /*@switchbreak@*/ break;
00586         case RPMTAG_SHA1HEADER:
00587         case RPMTAG_DSAHEADER:
00588         case RPMTAG_RSAHEADER:
00589         default:
00590             if (!(tag >= HEADER_SIGBASE && tag < HEADER_TAGBASE))
00591                 continue;
00592             stag = tag;
00593             /*@switchbreak@*/ break;
00594         }
00595         if (ptr == NULL) continue;      /* XXX can't happen */
00596         if (!headerIsEntry(sigh, stag))
00597             xx = headerAddEntry(sigh, stag, type, ptr, count);
00598     }
00599     hi = headerFreeIterator(hi);
00600     return sigh;
00601 }
00602 
00608 static int rpmtsStashKeyid(rpmts ts)
00609         /*@globals nextkeyid, nkeyids, keyids @*/
00610         /*@modifies nextkeyid, nkeyids, keyids @*/
00611 {
00612     const void * sig = rpmtsSig(ts);
00613     pgpDig dig = rpmtsDig(ts);
00614     pgpDigParams sigp = rpmtsSignature(ts);
00615     unsigned int keyid;
00616     int i;
00617 
00618     if (sig == NULL || dig == NULL || sigp == NULL)
00619         return 0;
00620 
00621     keyid = pgpGrab(sigp->signid+4, 4);
00622     if (keyid == 0)
00623         return 0;
00624 
00625     if (keyids != NULL)
00626     for (i = 0; i < nkeyids; i++) {
00627 /*@-boundsread@*/
00628         if (keyid == keyids[i])
00629             return 1;
00630 /*@=boundsread@*/
00631     }
00632 
00633     if (nkeyids < nkeyids_max) {
00634         nkeyids++;
00635         keyids = xrealloc(keyids, nkeyids * sizeof(*keyids));
00636     }
00637 /*@-boundswrite@*/
00638     if (keyids)         /* XXX can't happen */
00639         keyids[nextkeyid] = keyid;
00640 /*@=boundswrite@*/
00641     nextkeyid++;
00642     nextkeyid %= nkeyids_max;
00643 
00644     return 0;
00645 }
00646 
00647 int headerVerifyInfo(int il, int dl, const void * pev, void * iv, int negate)
00648 {
00649 /*@-castexpose@*/
00650     entryInfo pe = (entryInfo) pev;
00651 /*@=castexpose@*/
00652     entryInfo info = iv;
00653     int i;
00654 
00655 /*@-boundsread@*/
00656     for (i = 0; i < il; i++) {
00657         info->tag = ntohl(pe[i].tag);
00658         info->type = ntohl(pe[i].type);
00659         info->offset = ntohl(pe[i].offset);
00660         if (negate)
00661             info->offset = -info->offset;
00662         info->count = ntohl(pe[i].count);
00663 
00664         if (hdrchkType(info->type))
00665             return i;
00666         if (hdrchkAlign(info->type, info->offset))
00667             return i;
00668         if (!negate && hdrchkRange(dl, info->offset))
00669             return i;
00670         if (hdrchkData(info->count))
00671             return i;
00672 
00673     }
00674 /*@=boundsread@*/
00675     return -1;
00676 }
00677 
00691 rpmRC headerCheck(rpmts ts, const void * uh, size_t uc, const char ** msg)
00692 {
00693     pgpDig dig;
00694     unsigned char buf[8*BUFSIZ];
00695     int_32 * ei = (int_32 *) uh;
00696 /*@-boundsread@*/
00697     int_32 il = ntohl(ei[0]);
00698     int_32 dl = ntohl(ei[1]);
00699 /*@-castexpose@*/
00700     entryInfo pe = (entryInfo) &ei[2];
00701 /*@=castexpose@*/
00702 /*@=boundsread@*/
00703     int_32 ildl[2];
00704     int_32 pvlen = sizeof(ildl) + (il * sizeof(*pe)) + dl;
00705     unsigned char * dataStart = (unsigned char *) (pe + il);
00706     indexEntry entry = memset(alloca(sizeof(*entry)), 0, sizeof(*entry));
00707     entryInfo info = memset(alloca(sizeof(*info)), 0, sizeof(*info));
00708     const void * sig = NULL;
00709     const char * b;
00710     rpmVSFlags vsflags = rpmtsVSFlags(ts);
00711     int siglen = 0;
00712     int blen;
00713     size_t nb;
00714     int_32 ril = 0;
00715     unsigned char * regionEnd = NULL;
00716     rpmRC rc = RPMRC_FAIL;      /* assume failure */
00717     int xx;
00718     int i;
00719     static int hclvl;
00720 
00721     hclvl++;
00722 /*@-boundswrite@*/
00723     buf[0] = '\0';
00724 /*@=boundswrite@*/
00725 
00726     /* Is the blob the right size? */
00727     if (uc > 0 && pvlen != uc) {
00728         (void) snprintf(buf, sizeof(buf),
00729                 _("blob size(%d): BAD, 8 + 16 * il(%d) + dl(%d)\n"),
00730                 (int)uc, (int)il, (int)dl);
00731         goto exit;
00732     }
00733 
00734     /* Check (and convert) the 1st tag element. */
00735     xx = headerVerifyInfo(1, dl, pe, &entry->info, 0);
00736     if (xx != -1) {
00737         (void) snprintf(buf, sizeof(buf),
00738                 _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
00739                 0, entry->info.tag, entry->info.type,
00740                 entry->info.offset, entry->info.count);
00741         goto exit;
00742     }
00743 
00744     /* Is there an immutable header region tag? */
00745 /*@-sizeoftype@*/
00746     if (!(entry->info.tag == RPMTAG_HEADERIMMUTABLE
00747        && entry->info.type == RPM_BIN_TYPE
00748        && entry->info.count == REGION_TAG_COUNT))
00749     {
00750         rc = RPMRC_NOTFOUND;
00751         goto exit;
00752     }
00753 /*@=sizeoftype@*/
00754 
00755     /* Is the offset within the data area? */
00756     if (entry->info.offset >= dl) {
00757         (void) snprintf(buf, sizeof(buf),
00758                 _("region offset: BAD, tag %d type %d offset %d count %d\n"),
00759                 entry->info.tag, entry->info.type,
00760                 entry->info.offset, entry->info.count);
00761         goto exit;
00762     }
00763 
00764     /* Is there an immutable header region tag trailer? */
00765     regionEnd = dataStart + entry->info.offset;
00766 /*@-sizeoftype@*/
00767 /*@-bounds@*/
00768     (void) memcpy(info, regionEnd, REGION_TAG_COUNT);
00769 /*@=bounds@*/
00770     regionEnd += REGION_TAG_COUNT;
00771 
00772     xx = headerVerifyInfo(1, dl, info, &entry->info, 1);
00773     if (xx != -1 ||
00774         !(entry->info.tag == RPMTAG_HEADERIMMUTABLE
00775        && entry->info.type == RPM_BIN_TYPE
00776        && entry->info.count == REGION_TAG_COUNT))
00777     {
00778         (void) snprintf(buf, sizeof(buf),
00779                 _("region trailer: BAD, tag %d type %d offset %d count %d\n"),
00780                 entry->info.tag, entry->info.type,
00781                 entry->info.offset, entry->info.count);
00782         goto exit;
00783     }
00784 /*@=sizeoftype@*/
00785 /*@-boundswrite@*/
00786     memset(info, 0, sizeof(*info));
00787 /*@=boundswrite@*/
00788 
00789     /* Is the no. of tags in the region less than the total no. of tags? */
00790     ril = entry->info.offset/sizeof(*pe);
00791     if ((entry->info.offset % sizeof(*pe)) || ril > il) {
00792         (void) snprintf(buf, sizeof(buf),
00793                 _("region size: BAD, ril(%d) > il(%d)\n"), ril, il);
00794         goto exit;
00795     }
00796 
00797     /* Find a header-only digest/signature tag. */
00798     for (i = ril; i < il; i++) {
00799         xx = headerVerifyInfo(1, dl, pe+i, &entry->info, 0);
00800         if (xx != -1) {
00801             (void) snprintf(buf, sizeof(buf),
00802                 _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
00803                 i, entry->info.tag, entry->info.type,
00804                 entry->info.offset, entry->info.count);
00805             goto exit;
00806         }
00807 
00808         switch (entry->info.tag) {
00809         case RPMTAG_SHA1HEADER:
00810             if (vsflags & RPMVSF_NOSHA1HEADER)
00811                 /*@switchbreak@*/ break;
00812             blen = 0;
00813 /*@-boundsread@*/
00814             for (b = dataStart + entry->info.offset; *b != '\0'; b++) {
00815                 if (strchr("0123456789abcdefABCDEF", *b) == NULL)
00816                     /*@innerbreak@*/ break;
00817                 blen++;
00818             }
00819             if (entry->info.type != RPM_STRING_TYPE || *b != '\0' || blen != 40)
00820             {
00821                 (void) snprintf(buf, sizeof(buf), _("hdr SHA1: BAD, not hex\n"));
00822                 goto exit;
00823             }
00824 /*@=boundsread@*/
00825             if (info->tag == 0) {
00826 /*@-boundswrite@*/
00827                 *info = entry->info;    /* structure assignment */
00828 /*@=boundswrite@*/
00829                 siglen = blen + 1;
00830             }
00831             /*@switchbreak@*/ break;
00832         case RPMTAG_RSAHEADER:
00833             if (vsflags & RPMVSF_NORSAHEADER)
00834                 /*@switchbreak@*/ break;
00835             if (entry->info.type != RPM_BIN_TYPE) {
00836                 (void) snprintf(buf, sizeof(buf), _("hdr RSA: BAD, not binary\n"));
00837                 goto exit;
00838             }
00839 /*@-boundswrite@*/
00840             *info = entry->info;        /* structure assignment */
00841 /*@=boundswrite@*/
00842             siglen = info->count;
00843             /*@switchbreak@*/ break;
00844         case RPMTAG_DSAHEADER:
00845             if (vsflags & RPMVSF_NODSAHEADER)
00846                 /*@switchbreak@*/ break;
00847             if (entry->info.type != RPM_BIN_TYPE) {
00848                 (void) snprintf(buf, sizeof(buf), _("hdr DSA: BAD, not binary\n"));
00849                 goto exit;
00850             }
00851 /*@-boundswrite@*/
00852             *info = entry->info;        /* structure assignment */
00853 /*@=boundswrite@*/
00854             siglen = info->count;
00855             /*@switchbreak@*/ break;
00856         default:
00857             /*@switchbreak@*/ break;
00858         }
00859     }
00860     rc = RPMRC_NOTFOUND;
00861 
00862 exit:
00863     /* Return determined RPMRC_OK/RPMRC_FAIL conditions. */
00864     if (rc != RPMRC_NOTFOUND) {
00865 /*@-boundswrite@*/
00866         buf[sizeof(buf)-1] = '\0';
00867         if (msg) *msg = xstrdup(buf);
00868 /*@=boundswrite@*/
00869         hclvl--;
00870         return rc;
00871     }
00872 
00873     /* If no header-only digest/signature, then do simple sanity check. */
00874     if (info->tag == 0) {
00875 verifyinfo_exit:
00876         xx = headerVerifyInfo(ril-1, dl, pe+1, &entry->info, 0);
00877         if (xx != -1) {
00878             (void) snprintf(buf, sizeof(buf),
00879                 _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"),
00880                 xx+1, entry->info.tag, entry->info.type,
00881                 entry->info.offset, entry->info.count);
00882             rc = RPMRC_FAIL;
00883         } else {
00884             (void) snprintf(buf, sizeof(buf), "Header sanity check: OK\n");
00885             rc = RPMRC_OK;
00886         }
00887 /*@-boundswrite@*/
00888         buf[sizeof(buf)-1] = '\0';
00889         if (msg) *msg = xstrdup(buf);
00890 /*@=boundswrite@*/
00891         hclvl--;
00892         return rc;
00893     }
00894 
00895     /* Verify header-only digest/signature. */
00896     dig = rpmtsDig(ts);
00897     if (dig == NULL)
00898         goto verifyinfo_exit;
00899     dig->nbytes = 0;
00900 
00901 /*@-boundsread@*/
00902     sig = memcpy(xmalloc(siglen), dataStart + info->offset, siglen);
00903 /*@=boundsread@*/
00904     (void) rpmtsSetSig(ts, info->tag, info->type, sig, info->count);
00905 
00906     switch (info->tag) {
00907     case RPMTAG_RSAHEADER:
00908         /* Parse the parameters from the OpenPGP packets that will be needed. */
00909         xx = pgpPrtPkts(sig, info->count, dig, (_print_pkts & rpmIsDebug()));
00910         if (dig->signature.version != 3 && dig->signature.version != 4) {
00911             rpmMessage(RPMMESS_ERROR,
00912                 _("skipping header with unverifiable V%u signature\n"),
00913                 dig->signature.version);
00914             rpmtsCleanDig(ts);
00915             rc = RPMRC_FAIL;
00916             goto exit;
00917         }
00918 
00919         ildl[0] = htonl(ril);
00920         ildl[1] = (regionEnd - dataStart);
00921         ildl[1] = htonl(ildl[1]);
00922 
00923         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00924         dig->hdrmd5ctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
00925 
00926         b = (unsigned char *) header_magic;
00927         nb = sizeof(header_magic);
00928         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00929         dig->nbytes += nb;
00930 
00931         b = (unsigned char *) ildl;
00932         nb = sizeof(ildl);
00933         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00934         dig->nbytes += nb;
00935 
00936         b = (unsigned char *) pe;
00937         nb = (htonl(ildl[0]) * sizeof(*pe));
00938         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00939         dig->nbytes += nb;
00940 
00941         b = (unsigned char *) dataStart;
00942         nb = htonl(ildl[1]);
00943         (void) rpmDigestUpdate(dig->hdrmd5ctx, b, nb);
00944         dig->nbytes += nb;
00945         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00946 
00947         break;
00948     case RPMTAG_DSAHEADER:
00949         /* Parse the parameters from the OpenPGP packets that will be needed. */
00950         xx = pgpPrtPkts(sig, info->count, dig, (_print_pkts & rpmIsDebug()));
00951         if (dig->signature.version != 3 && dig->signature.version != 4) {
00952             rpmMessage(RPMMESS_ERROR,
00953                 _("skipping header with unverifiable V%u signature\n"),
00954                 dig->signature.version);
00955             rpmtsCleanDig(ts);
00956             rc = RPMRC_FAIL;
00957             goto exit;
00958         }
00959         /*@fallthrough@*/
00960     case RPMTAG_SHA1HEADER:
00961 /*@-boundswrite@*/
00962         ildl[0] = htonl(ril);
00963         ildl[1] = (regionEnd - dataStart);
00964         ildl[1] = htonl(ildl[1]);
00965 /*@=boundswrite@*/
00966 
00967         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
00968         dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00969 
00970         b = (unsigned char *) header_magic;
00971         nb = sizeof(header_magic);
00972         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00973         dig->nbytes += nb;
00974 
00975         b = (unsigned char *) ildl;
00976         nb = sizeof(ildl);
00977         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00978         dig->nbytes += nb;
00979 
00980         b = (unsigned char *) pe;
00981         nb = (htonl(ildl[0]) * sizeof(*pe));
00982         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00983         dig->nbytes += nb;
00984 
00985         b = (unsigned char *) dataStart;
00986         nb = htonl(ildl[1]);
00987         (void) rpmDigestUpdate(dig->hdrsha1ctx, b, nb);
00988         dig->nbytes += nb;
00989         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
00990 
00991         break;
00992     default:
00993         sig = _free(sig);
00994         break;
00995     }
00996 
00997 /*@-boundswrite@*/
00998     buf[0] = '\0';
00999 /*@=boundswrite@*/
01000     rc = rpmVerifySignature(ts, buf);
01001 
01002 /*@-boundswrite@*/
01003     buf[sizeof(buf)-1] = '\0';
01004     if (msg) *msg = xstrdup(buf);
01005 /*@=boundswrite@*/
01006 
01007     /* XXX headerCheck can recurse, free info only at top level. */
01008     if (hclvl == 1)
01009         rpmtsCleanDig(ts);
01010     if (info->tag == RPMTAG_SHA1HEADER)
01011         sig = _free(sig);
01012     hclvl--;
01013     return rc;
01014 }
01015 
01016 rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, const char ** msg)
01017 {
01018     char buf[BUFSIZ];
01019     int_32 block[4];
01020     int_32 il;
01021     int_32 dl;
01022     int_32 * ei = NULL;
01023     size_t uc;
01024     size_t startoff;
01025     int_32 nb;
01026     Header h = NULL;
01027     const char * origin = NULL;
01028     rpmRC rc = RPMRC_FAIL;              /* assume failure */
01029     int xx;
01030 
01031 /*@-boundswrite@*/
01032     buf[0] = '\0';
01033 
01034     if (hdrp)
01035         *hdrp = NULL;
01036     if (msg)
01037         *msg = NULL;
01038 /*@=boundswrite@*/
01039 
01040     startoff = fd->stats->ops[FDSTAT_READ].bytes;
01041     memset(block, 0, sizeof(block));
01042     if ((xx = timedRead(fd, (char *)block, sizeof(block))) != sizeof(block)) {
01043         (void) snprintf(buf, sizeof(buf),
01044                 _("hdr size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx);
01045         goto exit;
01046     }
01047     if (memcmp(block, header_magic, sizeof(header_magic))) {
01048         (void) snprintf(buf, sizeof(buf), _("hdr magic: BAD\n"));
01049         goto exit;
01050     }
01051 /*@-boundsread@*/
01052     il = ntohl(block[2]);
01053 /*@=boundsread@*/
01054     if (hdrchkTags(il)) {
01055         (void) snprintf(buf, sizeof(buf),
01056                 _("hdr tags: BAD, no. of tags(%d) out of range\n"), il);
01057 
01058         goto exit;
01059     }
01060 /*@-boundsread@*/
01061     dl = ntohl(block[3]);
01062 /*@=boundsread@*/
01063     if (hdrchkData(dl)) {
01064         (void) snprintf(buf, sizeof(buf),
01065                 _("hdr data: BAD, no. of bytes(%d) out of range\n"), dl);
01066         goto exit;
01067     }
01068 
01069 /*@-sizeoftype@*/
01070     nb = (il * sizeof(struct entryInfo_s)) + dl;
01071 /*@=sizeoftype@*/
01072     uc = sizeof(il) + sizeof(dl) + nb;
01073     ei = xmalloc(uc);
01074 /*@-bounds@*/
01075     ei[0] = block[2];
01076     ei[1] = block[3];
01077     if ((xx = timedRead(fd, (char *)&ei[2], nb)) != nb) {
01078         (void) snprintf(buf, sizeof(buf),
01079                 _("hdr blob(%d): BAD, read returned %d\n"), nb, xx);
01080         goto exit;
01081     }
01082 /*@=bounds@*/
01083 
01084     /* Sanity check header tags */
01085     rc = headerCheck(ts, ei, uc, msg);
01086     if (rc != RPMRC_OK)
01087         goto exit;
01088 
01089     /* OK, blob looks sane, load the header. */
01090     h = headerLoad(ei);
01091     if (h == NULL) {
01092         (void) snprintf(buf, sizeof(buf), _("hdr load: BAD\n"));
01093         goto exit;
01094     }
01095     h->flags |= HEADERFLAG_ALLOCATED;
01096     ei = NULL;  /* XXX will be freed with header */
01097 
01098     /* Save the opened path as the header origin. */
01099     origin = fdGetOPath(fd);
01100     if (origin != NULL) {
01101         const char * lpath = NULL;
01102         int ut = urlPath(origin, &lpath);
01103         ut = ut;        /* XXX keep gcc quiet. */
01104         if (lpath && *lpath != '/') {
01105             char * rpath = Realpath(origin, NULL);
01106             (void) headerSetOrigin(h, rpath);
01107             rpath = _free(rpath);
01108         } else
01109             (void) headerSetOrigin(h, origin);
01110     }
01111     {   struct stat * st = headerGetStatbuf(h);
01112         int saveno = errno;
01113         (void) fstat(Fileno(fd), st);
01114         errno = saveno;
01115     }
01116     (void) headerSetStartOff(h, startoff);
01117     (void) headerSetEndOff(h, fd->stats->ops[FDSTAT_READ].bytes);
01118     
01119 exit:
01120 /*@-boundswrite@*/
01121     if (hdrp && h && rc == RPMRC_OK)
01122         *hdrp = headerLink(h);
01123 /*@=boundswrite@*/
01124     ei = _free(ei);
01125     h = headerFree(h);
01126 
01127 /*@-boundswrite@*/
01128     if (msg != NULL && *msg == NULL && buf[0] != '\0') {
01129         buf[sizeof(buf)-1] = '\0';
01130         *msg = xstrdup(buf);
01131     }
01132 /*@=boundswrite@*/
01133 
01134     return rc;
01135 }
01136 
01137 /*@-bounds@*/   /* LCL: segfault */
01138 rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp)
01139 {
01140     pgpDig dig;
01141     byte buf[8*BUFSIZ];
01142     ssize_t count;
01143     struct rpmlead * l = alloca(sizeof(*l));
01144     Header sigh = NULL;
01145     int_32 sigtag;
01146     int_32 sigtype;
01147     const void * sig;
01148     int_32 siglen;
01149     rpmtsOpX opx;
01150     size_t nb;
01151     Header h = NULL;
01152     const char * msg;
01153     rpmVSFlags vsflags;
01154     rpmRC rc = RPMRC_FAIL;      /* assume failure */
01155     rpmop opsave = memset(alloca(sizeof(*opsave)), 0, sizeof(*opsave));
01156     int xx;
01157     int i;
01158 
01159     if (hdrp) *hdrp = NULL;
01160 
01161 #ifdef  DYING
01162     {   struct stat st;
01163 /*@-boundswrite@*/
01164         memset(&st, 0, sizeof(st));
01165 /*@=boundswrite@*/
01166         (void) fstat(Fileno(fd), &st);
01167         /* if fd points to a socket, pipe, etc, st.st_size is *always* zero */
01168         if (S_ISREG(st.st_mode) && st.st_size < sizeof(*l)) {
01169             rc = RPMRC_NOTFOUND;
01170             goto exit;
01171         }
01172     }
01173 #endif
01174 
01175     /* Snapshot current I/O counters (cached persistent I/O reuses counters) */
01176     (void) rpmswAdd(opsave, fdstat_op(fd, FDSTAT_READ));
01177 
01178     memset(l, 0, sizeof(*l));
01179     rc = readLead(fd, l);
01180     if (rc != RPMRC_OK)
01181         goto exit;
01182 
01183     switch (l->major) {
01184     case 1:
01185         rpmError(RPMERR_NEWPACKAGE,
01186             _("packaging version 1 is not supported by this version of RPM\n"));
01187         rc = RPMRC_NOTFOUND;
01188         goto exit;
01189         /*@notreached@*/ break;
01190     case 2:
01191     case 3:
01192     case 4:
01193         break;
01194     default:
01195         rpmError(RPMERR_NEWPACKAGE, _("only packaging with major numbers <= 4 "
01196                 "is supported by this version of RPM\n"));
01197         rc = RPMRC_NOTFOUND;
01198         goto exit;
01199         /*@notreached@*/ break;
01200     }
01201 
01202     /* Read the signature header. */
01203     msg = NULL;
01204     rc = rpmReadSignature(fd, &sigh, l->signature_type, &msg);
01205     switch (rc) {
01206     default:
01207         rpmError(RPMERR_SIGGEN, _("%s: rpmReadSignature failed: %s"), fn,
01208                 (msg && *msg ? msg : "\n"));
01209         msg = _free(msg);
01210         goto exit;
01211         /*@notreached@*/ break;
01212     case RPMRC_OK:
01213         if (sigh == NULL) {
01214             rpmError(RPMERR_SIGGEN, _("%s: No signature available\n"), fn);
01215             rc = RPMRC_FAIL;
01216             goto exit;
01217         }
01218         break;
01219     }
01220     msg = _free(msg);
01221 
01222 #define _chk(_mask)     (sigtag == 0 && !(vsflags & (_mask)))
01223 
01224     /*
01225      * Figger the most effective available signature.
01226      * Prefer signatures over digests, then header-only over header+payload.
01227      * DSA will be preferred over RSA if both exist because tested first.
01228      * Note that NEEDPAYLOAD prevents header+payload signatures and digests.
01229      */
01230     sigtag = 0;
01231     opx = 0;
01232     vsflags = rpmtsVSFlags(ts);
01233     if (_chk(RPMVSF_NODSAHEADER) && headerIsEntry(sigh, RPMSIGTAG_DSA)) {
01234         sigtag = RPMSIGTAG_DSA;
01235     } else
01236     if (_chk(RPMVSF_NORSAHEADER) && headerIsEntry(sigh, RPMSIGTAG_RSA)) {
01237         sigtag = RPMSIGTAG_RSA;
01238     } else
01239     if (_chk(RPMVSF_NODSA|RPMVSF_NEEDPAYLOAD) &&
01240         headerIsEntry(sigh, RPMSIGTAG_GPG))
01241     {
01242         sigtag = RPMSIGTAG_GPG;
01243         fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
01244         opx = RPMTS_OP_SIGNATURE;
01245     } else
01246     if (_chk(RPMVSF_NORSA|RPMVSF_NEEDPAYLOAD) &&
01247         headerIsEntry(sigh, RPMSIGTAG_PGP))
01248     {
01249         sigtag = RPMSIGTAG_PGP;
01250         fdInitDigest(fd, PGPHASHALGO_MD5, 0);
01251         opx = RPMTS_OP_SIGNATURE;
01252     } else
01253     if (_chk(RPMVSF_NOSHA1HEADER) && headerIsEntry(sigh, RPMSIGTAG_SHA1)) {
01254         sigtag = RPMSIGTAG_SHA1;
01255     } else
01256     if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD) &&
01257         headerIsEntry(sigh, RPMSIGTAG_MD5))
01258     {
01259         sigtag = RPMSIGTAG_MD5;
01260         fdInitDigest(fd, PGPHASHALGO_MD5, 0);
01261         opx = RPMTS_OP_DIGEST;
01262     }
01263 
01264     /* Read the metadata, computing digest(s) on the fly. */
01265     h = NULL;
01266     msg = NULL;
01267 
01268     /* XXX stats will include header i/o and setup overhead. */
01269     /* XXX repackaged packages have appended tags, legacy dig/sig check fails */
01270     if (opx > 0)
01271         (void) rpmswEnter(rpmtsOp(ts, opx), 0);
01272 /*@-type@*/     /* XXX arrow access of non-pointer (FDSTAT_t) */
01273     nb = -fd->stats->ops[FDSTAT_READ].bytes;
01274     rc = rpmReadHeader(ts, fd, &h, &msg);
01275     nb += fd->stats->ops[FDSTAT_READ].bytes;
01276 /*@=type@*/
01277     if (opx > 0)
01278         (void) rpmswExit(rpmtsOp(ts, opx), nb);
01279 
01280     if (rc != RPMRC_OK || h == NULL) {
01281         rpmError(RPMERR_FREAD, _("%s: headerRead failed: %s"), fn,
01282                 (msg && *msg ? msg : "\n"));
01283         msg = _free(msg);
01284         goto exit;
01285     }
01286     msg = _free(msg);
01287 
01288     /* Any digests or signatures to check? */
01289     if (sigtag == 0) {
01290         rc = RPMRC_OK;
01291         goto exit;
01292     }
01293 
01294     dig = rpmtsDig(ts);
01295     if (dig == NULL) {
01296         rc = RPMRC_FAIL;
01297         goto exit;
01298     }
01299     dig->nbytes = 0;
01300 
01301     /* Retrieve the tag parameters from the signature header. */
01302     sig = NULL;
01303     xx = headerGetEntry(sigh, sigtag, &sigtype, (void **) &sig, &siglen);
01304     if (sig == NULL) {
01305         rc = RPMRC_FAIL;
01306         goto exit;
01307     }
01308     (void) rpmtsSetSig(ts, sigtag, sigtype, sig, siglen);
01309 
01310     switch (sigtag) {
01311     case RPMSIGTAG_RSA:
01312         /* Parse the parameters from the OpenPGP packets that will be needed. */
01313         xx = pgpPrtPkts(sig, siglen, dig, (_print_pkts & rpmIsDebug()));
01314         if (dig->signature.version != 3 && dig->signature.version != 4) {
01315             rpmMessage(RPMMESS_ERROR,
01316                 _("skipping package %s with unverifiable V%u signature\n"),
01317                 fn, dig->signature.version);
01318             rc = RPMRC_FAIL;
01319             goto exit;
01320         }
01321     {   void * uh = NULL;
01322         int_32 uht;
01323         int_32 uhc;
01324 
01325         if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc))
01326             break;
01327         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01328         dig->hdrmd5ctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
01329         (void) rpmDigestUpdate(dig->hdrmd5ctx, header_magic, sizeof(header_magic));
01330         dig->nbytes += sizeof(header_magic);
01331         (void) rpmDigestUpdate(dig->hdrmd5ctx, uh, uhc);
01332         dig->nbytes += uhc;
01333         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
01334         rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;  /* XXX one too many */
01335         uh = headerFreeData(uh, uht);
01336     }   break;
01337     case RPMSIGTAG_DSA:
01338         /* Parse the parameters from the OpenPGP packets that will be needed. */
01339         xx = pgpPrtPkts(sig, siglen, dig, (_print_pkts & rpmIsDebug()));
01340         if (dig->signature.version != 3 && dig->signature.version != 4) {
01341             rpmMessage(RPMMESS_ERROR,
01342                 _("skipping package %s with unverifiable V%u signature\n"), 
01343                 fn, dig->signature.version);
01344             rc = RPMRC_FAIL;
01345             goto exit;
01346         }
01347         /*@fallthrough@*/
01348     case RPMSIGTAG_SHA1:
01349     {   void * uh = NULL;
01350         int_32 uht;
01351         int_32 uhc;
01352 
01353         if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc))
01354             break;
01355         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01356         dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
01357         (void) rpmDigestUpdate(dig->hdrsha1ctx, header_magic, sizeof(header_magic));
01358         dig->nbytes += sizeof(header_magic);
01359         (void) rpmDigestUpdate(dig->hdrsha1ctx, uh, uhc);
01360         dig->nbytes += uhc;
01361         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
01362         if (sigtag == RPMSIGTAG_SHA1)
01363             rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;      /* XXX one too many */
01364         uh = headerFreeData(uh, uht);
01365     }   break;
01366     case RPMSIGTAG_GPG:
01367     case RPMSIGTAG_PGP5:        /* XXX legacy */
01368     case RPMSIGTAG_PGP:
01369         /* Parse the parameters from the OpenPGP packets that will be needed. */
01370         xx = pgpPrtPkts(sig, siglen, dig, (_print_pkts & rpmIsDebug()));
01371 
01372         if (dig->signature.version != 3 && dig->signature.version != 4) {
01373             rpmMessage(RPMMESS_ERROR,
01374                 _("skipping package %s with unverifiable V%u signature\n"),
01375                 fn, dig->signature.version);
01376             rc = RPMRC_FAIL;
01377             goto exit;
01378         }
01379         /*@fallthrough@*/
01380     case RPMSIGTAG_MD5:
01381         /* Legacy signatures need the compressed payload in the digest too. */
01382         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0);
01383         while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
01384             dig->nbytes += count;
01385         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), dig->nbytes);
01386         rpmtsOp(ts, RPMTS_OP_DIGEST)->count--;  /* XXX one too many */
01387         dig->nbytes += nb;      /* XXX include size of header blob. */
01388         if (count < 0) {
01389             rpmError(RPMERR_FREAD, _("%s: Fread failed: %s\n"),
01390                                         fn, Fstrerror(fd));
01391             rc = RPMRC_FAIL;
01392             goto exit;
01393         }
01394 
01395         /* XXX Steal the digest-in-progress from the file handle. */
01396         for (i = fd->ndigests - 1; i >= 0; i--) {
01397             FDDIGEST_t fddig = fd->digests + i;
01398             if (fddig->hashctx != NULL)
01399             switch (fddig->hashalgo) {
01400             case PGPHASHALGO_MD5:
01401                 dig->md5ctx = fddig->hashctx;
01402                 fddig->hashctx = NULL;
01403                 /*@switchbreak@*/ break;
01404             case PGPHASHALGO_SHA1:
01405             case PGPHASHALGO_RIPEMD160:
01406 #if HAVE_BEECRYPT_API_H
01407             case PGPHASHALGO_SHA256:
01408             case PGPHASHALGO_SHA384:
01409             case PGPHASHALGO_SHA512:
01410 #endif
01411                 dig->sha1ctx = fddig->hashctx;
01412                 fddig->hashctx = NULL;
01413                 /*@switchbreak@*/ break;
01414             default:
01415                 /*@switchbreak@*/ break;
01416             }
01417         }
01418         break;
01419     }
01420 
01423 /*@-boundswrite@*/
01424     buf[0] = '\0';
01425 /*@=boundswrite@*/
01426     rc = rpmVerifySignature(ts, buf);
01427     switch (rc) {
01428     case RPMRC_OK:              /* Signature is OK. */
01429         rpmMessage(RPMMESS_DEBUG, "%s: %s", fn, buf);
01430         break;
01431     case RPMRC_NOTTRUSTED:      /* Signature is OK, but key is not trusted. */
01432     case RPMRC_NOKEY:           /* Public key is unavailable. */
01433         /* XXX Print NOKEY/NOTTRUSTED warning only once. */
01434     {   int lvl = (rpmtsStashKeyid(ts) ? RPMMESS_DEBUG : RPMMESS_WARNING);
01435         rpmMessage(lvl, "%s: %s", fn, buf);
01436     }   break;
01437     case RPMRC_NOTFOUND:        /* Signature is unknown type. */
01438         rpmMessage(RPMMESS_WARNING, "%s: %s", fn, buf);
01439         break;
01440     default:
01441     case RPMRC_FAIL:            /* Signature does not verify. */
01442         rpmMessage(RPMMESS_ERROR, "%s: %s", fn, buf);
01443         break;
01444     }
01445 
01446 exit:
01447     if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) {
01448 
01449         /* Append (and remap) signature tags to the metadata. */
01450         headerMergeLegacySigs(h, sigh);
01451 
01452 #if defined(RPM_VENDOR_MANDRIVA)
01453     rpm3to4(h);
01454 #endif
01455 
01456     rpm3to4(h);
01457 
01458         /* Bump reference count for return. */
01459 /*@-boundswrite@*/
01460         *hdrp = headerLink(h);
01461 /*@=boundswrite@*/
01462     }
01463     h = headerFree(h);
01464 
01465     /* Accumulate time reading package header. */
01466     (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_READHDR),
01467                 fdstat_op(fd, FDSTAT_READ));
01468     (void) rpmswSub(rpmtsOp(ts, RPMTS_OP_READHDR),
01469                 opsave);
01470 
01471     rpmtsCleanDig(ts);
01472     sigh = rpmFreeSignature(sigh);
01473     return rc;
01474 }
01475 /*@=bounds@*/

Generated on Sat Oct 1 16:48:17 2011 for rpm by  doxygen 1.4.4