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

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