rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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@*/