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

Generated on Mon Nov 29 2010 05:18:43 for rpm by  doxygen 1.7.2