lib/package.c

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

Generated on Thu Feb 7 03:43:12 2008 for rpm by  doxygen 1.5.1