rpm 5.3.12
rpmdb/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 <rpmcb.h>              /* XXX fnpyKey */
00011 
00012 #define _RPMHKP_INTERNAL        /* XXX internal prototypes. */
00013 #include <rpmhkp.h>
00014 
00015 #include <rpmtag.h>
00016 #include <rpmtypes.h>
00017 #include <pkgio.h>
00018 #include "signature.h"          /* XXX rpmVerifySignature */
00019 
00020 #include "rpmts.h"
00021 
00022 #include "debug.h"
00023 
00024 #define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
00025 
00026 /*@access pgpDig @*/
00027 /*@access pgpDigParams @*/
00028 /*@access Header @*/            /* XXX compared with NULL */
00029 /*@access FD_t @*/              /* XXX void * */
00030 
00031 /*@unchecked@*/
00032 static unsigned int nkeyids_max = 256;
00033 /*@unchecked@*/
00034 static unsigned int nkeyids = 0;
00035 /*@unchecked@*/
00036 static unsigned int nextkeyid  = 0;
00037 /*@unchecked@*/ /*@only@*/ /*@null@*/
00038 unsigned int * keyids = NULL;
00039 
00045 static int pgpStashKeyid(pgpDig dig)
00046         /*@globals nextkeyid, nkeyids, keyids @*/
00047         /*@modifies nextkeyid, nkeyids, keyids @*/
00048 {
00049     pgpDigParams sigp = pgpGetSignature(dig);
00050     const void * sig = pgpGetSig(dig);
00051     unsigned int keyid;
00052     unsigned int i;
00053 
00054     if (sig == NULL || dig == NULL || sigp == NULL)
00055         return 0;
00056 
00057     keyid = pgpGrab(sigp->signid+4, 4);
00058     if (keyid == 0)
00059         return 0;
00060 
00061     if (keyids != NULL)
00062     for (i = 0; i < nkeyids; i++) {
00063         if (keyid == keyids[i])
00064             return 1;
00065     }
00066 
00067     if (nkeyids < nkeyids_max) {
00068         nkeyids++;
00069         keyids = xrealloc(keyids, nkeyids * sizeof(*keyids));
00070     }
00071     if (keyids)         /* XXX can't happen */
00072         keyids[nextkeyid] = keyid;
00073     nextkeyid++;
00074     nextkeyid %= nkeyids_max;
00075 
00076     return 0;
00077 }
00078 
00079 /*@-mods@*/
00080 rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp)
00081 {
00082     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00083     HE_t she = memset(alloca(sizeof(*she)), 0, sizeof(*she));
00084     pgpDig dig = rpmtsDig(ts);
00085     char buf[8*BUFSIZ];
00086     ssize_t count;
00087     Header sigh = NULL;
00088     rpmtsOpX opx;
00089     rpmop op = NULL;
00090     size_t nb;
00091     unsigned ix;
00092     Header h = NULL;
00093     const char * msg = NULL;
00094     rpmVSFlags vsflags;
00095     rpmRC rc = RPMRC_FAIL;      /* assume failure */
00096     rpmop opsave = memset(alloca(sizeof(*opsave)), 0, sizeof(*opsave));
00097     int xx;
00098 pgpPkt pp = alloca(sizeof(*pp));
00099 
00100     if (hdrp) *hdrp = NULL;
00101 
00102 assert(dig != NULL);
00103     (void) fdSetDig(fd, dig);
00104 
00105     /* Snapshot current I/O counters (cached persistent I/O reuses counters) */
00106     (void) rpmswAdd(opsave, fdstat_op(fd, FDSTAT_READ));
00107 
00108    {    const char item[] = "Lead";
00109         msg = NULL;
00110         rc = rpmpkgRead(item, fd, NULL, &msg);
00111         switch (rc) {
00112         default:
00113            rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
00114            /*@fallthrough@*/
00115         case RPMRC_NOTFOUND:
00116            msg = _free(msg);
00117            goto exit;
00118            /*@notreached@*/ break;
00119         case RPMRC_OK:
00120            break;
00121         }
00122         msg = _free(msg);
00123     }
00124 
00125     {   const char item[] = "Signature";
00126         msg = NULL;
00127         rc = rpmpkgRead(item, fd, &sigh, &msg);
00128         switch (rc) {
00129         default:
00130             rpmlog(RPMLOG_ERR, "%s: %s: %s", fn, item,
00131                 (msg && *msg ? msg : _("read failed\n")));
00132             msg = _free(msg);
00133             goto exit;
00134             /*@notreached@*/ break;
00135         case RPMRC_OK:
00136             if (sigh == NULL) {
00137                 rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
00138                 rc = RPMRC_FAIL;
00139                 goto exit;
00140             }
00141             break;
00142         }
00143         msg = _free(msg);
00144     }
00145 
00146 #define _chk(_mask)     (she->tag == 0 && !(vsflags & (_mask)))
00147 
00148     /*
00149      * Figger the most effective available signature.
00150      * Prefer signatures over digests, then header-only over header+payload.
00151      * DSA will be preferred over RSA if both exist because tested first.
00152      * Note that NEEDPAYLOAD prevents header+payload signatures and digests.
00153      */
00154     she->tag = 0;
00155     opx = 0;
00156     vsflags = pgpDigVSFlags;
00157     if (_chk(RPMVSF_NODSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_DSA)) {
00158         she->tag = (rpmTag)RPMSIGTAG_DSA;
00159     } else
00160     if (_chk(RPMVSF_NORSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_RSA)) {
00161         she->tag = (rpmTag)RPMSIGTAG_RSA;
00162     } else
00163     if (_chk(RPMVSF_NOSHA1HEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_SHA1)) {
00164         she->tag = (rpmTag)RPMSIGTAG_SHA1;
00165     } else
00166     if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD) &&
00167         headerIsEntry(sigh, (rpmTag)RPMSIGTAG_MD5))
00168     {
00169         she->tag = (rpmTag)RPMSIGTAG_MD5;
00170         fdInitDigest(fd, PGPHASHALGO_MD5, 0);
00171         opx = RPMTS_OP_DIGEST;
00172     }
00173 
00174     /* Read the metadata, computing digest(s) on the fly. */
00175     h = NULL;
00176     msg = NULL;
00177 
00178     /* XXX stats will include header i/o and setup overhead. */
00179     /* XXX repackaged packages have appended tags, legacy dig/sig check fails */
00180     if (opx > 0) {
00181         op = pgpStatsAccumulator(dig, opx);
00182         (void) rpmswEnter(op, 0);
00183     }
00184 /*@-type@*/     /* XXX arrow access of non-pointer (FDSTAT_t) */
00185     nb = fd->stats->ops[FDSTAT_READ].bytes;
00186     {   const char item[] = "Header";
00187         msg = NULL;
00188         rc = rpmpkgRead(item, fd, &h, &msg);
00189         if (rc != RPMRC_OK) {
00190             rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
00191             msg = _free(msg);
00192             goto exit;
00193         }
00194         msg = _free(msg);
00195     }
00196     nb = fd->stats->ops[FDSTAT_READ].bytes - nb;
00197 /*@=type@*/
00198     if (opx > 0 && op != NULL) {
00199         (void) rpmswExit(op, nb);
00200         op = NULL;
00201     }
00202 
00203     /* Any digests or signatures to check? */
00204     if (she->tag == 0) {
00205         rc = RPMRC_OK;
00206         goto exit;
00207     }
00208 
00209     dig->nbytes = 0;
00210 
00211     /* Fish out the autosign pubkey (if present). */
00212     he->tag = RPMTAG_PUBKEYS;
00213     xx = headerGet(h, he, 0);
00214     if (xx && he->p.argv != NULL && he->c > 0)
00215     switch (he->t) {
00216     default:
00217         break;
00218     case RPM_STRING_ARRAY_TYPE:
00219         ix = he->c - 1; /* XXX FIXME: assumes last pubkey */
00220         dig->pub = _free(dig->pub);
00221         dig->publen = 0;
00222         {   rpmiob iob = rpmiobNew(0);
00223             iob = rpmiobAppend(iob, he->p.argv[ix], 0);
00224             xx = pgpArmorUnwrap(iob, (void *)&dig->pub, &dig->publen);
00225             iob = rpmiobFree(iob);
00226         }
00227         if (xx != PGPARMOR_PUBKEY) {
00228             dig->pub = _free(dig->pub);
00229             dig->publen = 0;
00230         }
00231         break;
00232     }
00233     he->p.ptr = _free(he->p.ptr);
00234 
00235     /* Retrieve the tag parameters from the signature header. */
00236     xx = headerGet(sigh, she, 0);
00237     if (she->p.ptr == NULL) {
00238         rc = RPMRC_FAIL;
00239         goto exit;
00240     }
00241 /*@-ownedtrans -noeffect@*/
00242     xx = pgpSetSig(dig, she->tag, she->t, she->p.ptr, she->c);
00243 /*@=ownedtrans =noeffect@*/
00244 
00245     switch ((rpmSigTag)she->tag) {
00246     default:    /* XXX keep gcc quiet. */
00247 assert(0);
00248         /*@notreached@*/ break;
00249     case RPMSIGTAG_RSA:
00250         /* Parse the parameters from the OpenPGP packets that will be needed. */
00251         xx = pgpPktLen(she->p.ptr, she->c, pp);
00252         xx = rpmhkpLoadSignature(NULL, dig, pp);
00253         if (dig->signature.version != 3 && dig->signature.version != 4) {
00254             rpmlog(RPMLOG_ERR,
00255                 _("skipping package %s with unverifiable V%u signature\n"),
00256                 fn, dig->signature.version);
00257             rc = RPMRC_FAIL;
00258             goto exit;
00259         }
00260     {   void * uh = NULL;
00261         rpmTagType uht;
00262         rpmTagCount uhc;
00263         unsigned char * hmagic = NULL;
00264         size_t nmagic = 0;
00265 
00266         he->tag = RPMTAG_HEADERIMMUTABLE;
00267         xx = headerGet(h, he, 0);
00268         uht = he->t;
00269         uh = he->p.ptr;
00270         uhc = he->c;
00271         if (!xx)
00272             break;
00273         (void) headerGetMagic(NULL, &hmagic, &nmagic);
00274         op = pgpStatsAccumulator(dig, 10);      /* RPMTS_OP_DIGEST */
00275         (void) rpmswEnter(op, 0);
00276         dig->hdrctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
00277         if (hmagic && nmagic > 0) {
00278             (void) rpmDigestUpdate(dig->hdrctx, hmagic, nmagic);
00279             dig->nbytes += nmagic;
00280         }
00281         (void) rpmDigestUpdate(dig->hdrctx, uh, uhc);
00282         dig->nbytes += uhc;
00283         (void) rpmswExit(op, dig->nbytes);
00284         op->count--;    /* XXX one too many */
00285         uh = _free(uh);
00286     }   break;
00287     case RPMSIGTAG_DSA:
00288         /* Parse the parameters from the OpenPGP packets that will be needed. */
00289         xx = pgpPktLen(she->p.ptr, she->c, pp);
00290         xx = rpmhkpLoadSignature(NULL, dig, pp);
00291         if (dig->signature.version != 3 && dig->signature.version != 4) {
00292             rpmlog(RPMLOG_ERR,
00293                 _("skipping package %s with unverifiable V%u signature\n"), 
00294                 fn, dig->signature.version);
00295             rc = RPMRC_FAIL;
00296             goto exit;
00297         }
00298         /*@fallthrough@*/
00299     case RPMSIGTAG_SHA1:
00300     {   void * uh = NULL;
00301         rpmTagType uht;
00302         rpmTagCount uhc;
00303         unsigned char * hmagic = NULL;
00304         size_t nmagic = 0;
00305 
00306         he->tag = RPMTAG_HEADERIMMUTABLE;
00307         xx = headerGet(h, he, 0);
00308         uht = he->t;
00309         uh = he->p.ptr;
00310         uhc = he->c;
00311         if (!xx)
00312             break;
00313         (void) headerGetMagic(NULL, &hmagic, &nmagic);
00314         op = pgpStatsAccumulator(dig, 10);      /* RPMTS_OP_DIGEST */
00315         (void) rpmswEnter(op, 0);
00316         dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00317         if (hmagic && nmagic > 0) {
00318             (void) rpmDigestUpdate(dig->hdrsha1ctx, hmagic, nmagic);
00319             dig->nbytes += nmagic;
00320         }
00321         (void) rpmDigestUpdate(dig->hdrsha1ctx, uh, uhc);
00322         dig->nbytes += uhc;
00323         (void) rpmswExit(op, dig->nbytes);
00324         if ((rpmSigTag)she->tag == RPMSIGTAG_SHA1)
00325             op->count--;        /* XXX one too many */
00326         uh = _free(uh);
00327     }   break;
00328     case RPMSIGTAG_MD5:
00329         /* Legacy signatures need the compressed payload in the digest too. */
00330         op = pgpStatsAccumulator(dig, 10);      /* RPMTS_OP_DIGEST */
00331         (void) rpmswEnter(op, 0);
00332         while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
00333             dig->nbytes += count;
00334         (void) rpmswExit(op, dig->nbytes);
00335         op->count--;    /* XXX one too many */
00336         dig->nbytes += nb;      /* XXX include size of header blob. */
00337         if (count < 0) {
00338             rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"),
00339                                         fn, Fstrerror(fd));
00340             rc = RPMRC_FAIL;
00341             goto exit;
00342         }
00343 
00344         /* XXX Steal the digest-in-progress from the file handle. */
00345         fdStealDigest(fd, dig);
00346         break;
00347     }
00348 
00351     buf[0] = '\0';
00352     rc = rpmVerifySignature(dig, buf);
00353     switch (rc) {
00354     case RPMRC_OK:              /* Signature is OK. */
00355         rpmlog(RPMLOG_DEBUG, "%s: %s\n", fn, buf);
00356         break;
00357     case RPMRC_NOTTRUSTED:      /* Signature is OK, but key is not trusted. */
00358     case RPMRC_NOKEY:           /* Public key is unavailable. */
00359         /* XXX Print NOKEY/NOTTRUSTED warning only once. */
00360     {   int lvl = (pgpStashKeyid(dig) ? RPMLOG_DEBUG : RPMLOG_WARNING);
00361         rpmlog(lvl, "%s: %s\n", fn, buf);
00362     }   break;
00363     case RPMRC_NOTFOUND:        /* Signature is unknown type. */
00364         rpmlog(RPMLOG_WARNING, "%s: %s\n", fn, buf);
00365         break;
00366     default:
00367     case RPMRC_FAIL:            /* Signature does not verify. */
00368         rpmlog(RPMLOG_ERR, "%s: %s\n", fn, buf);
00369         break;
00370     }
00371 
00372 exit:
00373     if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) {
00374 
00375         /* Append (and remap) signature tags to the metadata. */
00376         headerMergeLegacySigs(h, sigh);
00377 
00378         /* Bump reference count for return. */
00379         *hdrp = headerLink(h);
00380     }
00381     (void)headerFree(h);
00382     h = NULL;
00383 
00384     /* Accumulate time reading package header. */
00385     (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_READHDR),
00386                 fdstat_op(fd, FDSTAT_READ));
00387     (void) rpmswSub(rpmtsOp(ts, RPMTS_OP_READHDR),
00388                 opsave);
00389 
00390     rpmtsCleanDig(ts);
00391     (void)headerFree(sigh);
00392     sigh = NULL;
00393     return rc;
00394 }
00395 /*@=mods@*/