rpm 5.2.1

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 <rpmcb.h>              /* XXX fnpyKey */
00011 
00012 #include <rpmtag.h>
00013 #include <rpmtypes.h>
00014 #include <pkgio.h>
00015 #include "signature.h"          /* XXX rpmVerifySignature */
00016 
00017 #include "rpmts.h"
00018 
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 FD_t @*/              /* XXX void * */
00027 
00028 /*@unchecked@*/
00029 static int _print_pkts = 0;
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     Header h = NULL;
00092     const char * msg = NULL;
00093     rpmVSFlags vsflags;
00094     rpmRC rc = RPMRC_FAIL;      /* assume failure */
00095     rpmop opsave = memset(alloca(sizeof(*opsave)), 0, sizeof(*opsave));
00096     int xx;
00097 
00098     if (hdrp) *hdrp = NULL;
00099 
00100 assert(dig != NULL);
00101     (void) fdSetDig(fd, dig);
00102 
00103     /* Snapshot current I/O counters (cached persistent I/O reuses counters) */
00104     (void) rpmswAdd(opsave, fdstat_op(fd, FDSTAT_READ));
00105 
00106    {    const char item[] = "Lead";
00107         msg = NULL;
00108         rc = rpmpkgRead(item, fd, NULL, &msg);
00109         switch (rc) {
00110         default:
00111            rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
00112            /*@fallthrough@*/
00113         case RPMRC_NOTFOUND:
00114            msg = _free(msg);
00115            goto exit;
00116            /*@notreached@*/ break;
00117         case RPMRC_OK:
00118            break;
00119         }
00120         msg = _free(msg);
00121     }
00122 
00123     {   const char item[] = "Signature";
00124         msg = NULL;
00125         rc = rpmpkgRead(item, fd, &sigh, &msg);
00126         switch (rc) {
00127         default:
00128             rpmlog(RPMLOG_ERR, "%s: %s: %s", fn, item,
00129                 (msg && *msg ? msg : _("read failed\n")));
00130             msg = _free(msg);
00131             goto exit;
00132             /*@notreached@*/ break;
00133         case RPMRC_OK:
00134             if (sigh == NULL) {
00135                 rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
00136                 rc = RPMRC_FAIL;
00137                 goto exit;
00138             }
00139             break;
00140         }
00141         msg = _free(msg);
00142     }
00143 
00144 #define _chk(_mask)     (she->tag == 0 && !(vsflags & (_mask)))
00145 
00146     /*
00147      * Figger the most effective available signature.
00148      * Prefer signatures over digests, then header-only over header+payload.
00149      * DSA will be preferred over RSA if both exist because tested first.
00150      * Note that NEEDPAYLOAD prevents header+payload signatures and digests.
00151      */
00152     she->tag = 0;
00153     opx = 0;
00154     vsflags = pgpDigVSFlags;
00155     if (_chk(RPMVSF_NODSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_DSA)) {
00156         she->tag = (rpmTag)RPMSIGTAG_DSA;
00157     } else
00158     if (_chk(RPMVSF_NORSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_RSA)) {
00159         she->tag = (rpmTag)RPMSIGTAG_RSA;
00160     } else
00161     if (_chk(RPMVSF_NOSHA1HEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_SHA1)) {
00162         she->tag = (rpmTag)RPMSIGTAG_SHA1;
00163     } else
00164     if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD) &&
00165         headerIsEntry(sigh, (rpmTag)RPMSIGTAG_MD5))
00166     {
00167         she->tag = (rpmTag)RPMSIGTAG_MD5;
00168         fdInitDigest(fd, PGPHASHALGO_MD5, 0);
00169         opx = RPMTS_OP_DIGEST;
00170     }
00171 
00172     /* Read the metadata, computing digest(s) on the fly. */
00173     h = NULL;
00174     msg = NULL;
00175 
00176     /* XXX stats will include header i/o and setup overhead. */
00177     /* XXX repackaged packages have appended tags, legacy dig/sig check fails */
00178     if (opx > 0) {
00179         op = pgpStatsAccumulator(dig, opx);
00180         (void) rpmswEnter(op, 0);
00181     }
00182 /*@-type@*/     /* XXX arrow access of non-pointer (FDSTAT_t) */
00183     nb = fd->stats->ops[FDSTAT_READ].bytes;
00184     {   const char item[] = "Header";
00185         msg = NULL;
00186         rc = rpmpkgRead(item, fd, &h, &msg);
00187         if (rc != RPMRC_OK) {
00188             rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
00189             msg = _free(msg);
00190             goto exit;
00191         }
00192         msg = _free(msg);
00193     }
00194     nb = fd->stats->ops[FDSTAT_READ].bytes - nb;
00195 /*@=type@*/
00196     if (opx > 0 && op != NULL) {
00197         (void) rpmswExit(op, nb);
00198         op = NULL;
00199     }
00200 
00201     /* Any digests or signatures to check? */
00202     if (she->tag == 0) {
00203         rc = RPMRC_OK;
00204         goto exit;
00205     }
00206 
00207     dig->nbytes = 0;
00208 
00209     /* Retrieve the tag parameters from the signature header. */
00210     xx = headerGet(sigh, she, 0);
00211     if (she->p.ptr == NULL) {
00212         rc = RPMRC_FAIL;
00213         goto exit;
00214     }
00215 /*@-ownedtrans -noeffect@*/
00216     xx = pgpSetSig(dig, she->tag, she->t, she->p.ptr, she->c);
00217 /*@=ownedtrans =noeffect@*/
00218 
00219     switch ((rpmSigTag)she->tag) {
00220     default:    /* XXX keep gcc quiet. */
00221 assert(0);
00222         /*@notreached@*/ break;
00223     case RPMSIGTAG_RSA:
00224         /* Parse the parameters from the OpenPGP packets that will be needed. */
00225         xx = pgpPrtPkts(she->p.ptr, she->c, dig, (_print_pkts & rpmIsDebug()));
00226         if (dig->signature.version != 3 && dig->signature.version != 4) {
00227             rpmlog(RPMLOG_ERR,
00228                 _("skipping package %s with unverifiable V%u signature\n"),
00229                 fn, dig->signature.version);
00230             rc = RPMRC_FAIL;
00231             goto exit;
00232         }
00233     {   void * uh = NULL;
00234         rpmTagType uht;
00235         rpmTagCount uhc;
00236         unsigned char * hmagic = NULL;
00237         size_t nmagic = 0;
00238 
00239         he->tag = RPMTAG_HEADERIMMUTABLE;
00240         xx = headerGet(h, he, 0);
00241         uht = he->t;
00242         uh = he->p.ptr;
00243         uhc = he->c;
00244         if (!xx)
00245             break;
00246         (void) headerGetMagic(NULL, &hmagic, &nmagic);
00247         op = pgpStatsAccumulator(dig, 10);      /* RPMTS_OP_DIGEST */
00248         (void) rpmswEnter(op, 0);
00249         dig->hdrctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
00250         if (hmagic && nmagic > 0) {
00251             (void) rpmDigestUpdate(dig->hdrctx, hmagic, nmagic);
00252             dig->nbytes += nmagic;
00253         }
00254         (void) rpmDigestUpdate(dig->hdrctx, uh, uhc);
00255         dig->nbytes += uhc;
00256         (void) rpmswExit(op, dig->nbytes);
00257         op->count--;    /* XXX one too many */
00258         uh = _free(uh);
00259     }   break;
00260     case RPMSIGTAG_DSA:
00261         /* Parse the parameters from the OpenPGP packets that will be needed. */
00262         xx = pgpPrtPkts(she->p.ptr, she->c, dig, (_print_pkts & rpmIsDebug()));
00263         if (dig->signature.version != 3 && dig->signature.version != 4) {
00264             rpmlog(RPMLOG_ERR,
00265                 _("skipping package %s with unverifiable V%u signature\n"), 
00266                 fn, dig->signature.version);
00267             rc = RPMRC_FAIL;
00268             goto exit;
00269         }
00270         /*@fallthrough@*/
00271     case RPMSIGTAG_SHA1:
00272     {   void * uh = NULL;
00273         rpmTagType uht;
00274         rpmTagCount uhc;
00275         unsigned char * hmagic = NULL;
00276         size_t nmagic = 0;
00277 
00278         he->tag = RPMTAG_HEADERIMMUTABLE;
00279         xx = headerGet(h, he, 0);
00280         uht = he->t;
00281         uh = he->p.ptr;
00282         uhc = he->c;
00283         if (!xx)
00284             break;
00285         (void) headerGetMagic(NULL, &hmagic, &nmagic);
00286         op = pgpStatsAccumulator(dig, 10);      /* RPMTS_OP_DIGEST */
00287         (void) rpmswEnter(op, 0);
00288         dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00289         if (hmagic && nmagic > 0) {
00290             (void) rpmDigestUpdate(dig->hdrsha1ctx, hmagic, nmagic);
00291             dig->nbytes += nmagic;
00292         }
00293         (void) rpmDigestUpdate(dig->hdrsha1ctx, uh, uhc);
00294         dig->nbytes += uhc;
00295         (void) rpmswExit(op, dig->nbytes);
00296         if ((rpmSigTag)she->tag == RPMSIGTAG_SHA1)
00297             op->count--;        /* XXX one too many */
00298         uh = _free(uh);
00299     }   break;
00300     case RPMSIGTAG_MD5:
00301         /* Legacy signatures need the compressed payload in the digest too. */
00302         op = pgpStatsAccumulator(dig, 10);      /* RPMTS_OP_DIGEST */
00303         (void) rpmswEnter(op, 0);
00304         while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
00305             dig->nbytes += count;
00306         (void) rpmswExit(op, dig->nbytes);
00307         op->count--;    /* XXX one too many */
00308         dig->nbytes += nb;      /* XXX include size of header blob. */
00309         if (count < 0) {
00310             rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"),
00311                                         fn, Fstrerror(fd));
00312             rc = RPMRC_FAIL;
00313             goto exit;
00314         }
00315 
00316         /* XXX Steal the digest-in-progress from the file handle. */
00317         fdStealDigest(fd, dig);
00318         break;
00319     }
00320 
00323     buf[0] = '\0';
00324     rc = rpmVerifySignature(dig, buf);
00325     switch (rc) {
00326     case RPMRC_OK:              /* Signature is OK. */
00327         rpmlog(RPMLOG_DEBUG, "%s: %s\n", fn, buf);
00328         break;
00329     case RPMRC_NOTTRUSTED:      /* Signature is OK, but key is not trusted. */
00330     case RPMRC_NOKEY:           /* Public key is unavailable. */
00331         /* XXX Print NOKEY/NOTTRUSTED warning only once. */
00332     {   int lvl = (pgpStashKeyid(dig) ? RPMLOG_DEBUG : RPMLOG_WARNING);
00333         rpmlog(lvl, "%s: %s\n", fn, buf);
00334     }   break;
00335     case RPMRC_NOTFOUND:        /* Signature is unknown type. */
00336         rpmlog(RPMLOG_WARNING, "%s: %s\n", fn, buf);
00337         break;
00338     default:
00339     case RPMRC_FAIL:            /* Signature does not verify. */
00340         rpmlog(RPMLOG_ERR, "%s: %s\n", fn, buf);
00341         break;
00342     }
00343 
00344 exit:
00345     if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) {
00346 
00347         /* Append (and remap) signature tags to the metadata. */
00348         headerMergeLegacySigs(h, sigh);
00349 
00350         /* Bump reference count for return. */
00351         *hdrp = headerLink(h);
00352     }
00353     (void)headerFree(h);
00354     h = NULL;
00355 
00356     /* Accumulate time reading package header. */
00357     (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_READHDR),
00358                 fdstat_op(fd, FDSTAT_READ));
00359     (void) rpmswSub(rpmtsOp(ts, RPMTS_OP_READHDR),
00360                 opsave);
00361 
00362     rpmtsCleanDig(ts);
00363     (void)headerFree(sigh);
00364     sigh = NULL;
00365     return rc;
00366 }
00367 /*@=mods@*/