int rpmtsCloseDB(rpmts ts) { int rc = 0; if (ts->rdb != NULL) { (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET), rpmdbOp(ts->rdb, RPMDB_OP_DBGET)); (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT), rpmdbOp(ts->rdb, RPMDB_OP_DBPUT)); (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL), rpmdbOp(ts->rdb, RPMDB_OP_DBDEL)); rc = rpmdbClose(ts->rdb); ts->rdb = NULL; } return rc; }
static rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage) { const rpmts ts = psm->ts; rpmfi fi = psm->fi; rpmRC rc = RPMRC_OK; switch (stage) { case PSM_UNKNOWN: break; case PSM_INIT: rpmlog(RPMLOG_DEBUG, "%s: %s has %d files\n", psm->goalName, rpmteNEVR(psm->te), rpmfiFC(fi)); /* * When we run scripts, we pass an argument which is the number of * versions of this package that will be installed when we are * finished. */ psm->npkgs_installed = rpmdbCountPackages(rpmtsGetRdb(ts), rpmteN(psm->te)); if (psm->npkgs_installed < 0) { rc = RPMRC_FAIL; break; } if (psm->goal == PKG_INSTALL) { Header h = rpmteHeader(psm->te); psm->scriptArg = psm->npkgs_installed + 1; psm->amount = 0; psm->total = headerGetNumber(h, RPMTAG_LONGARCHIVESIZE); /* fake up something for packages with no files */ if (psm->total == 0) psm->total = 100; /* HACK: reinstall abuses te instance to remove old header */ if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG) markReplacedInstance(ts, psm->te); if (rpmfiFC(fi) > 0) { struct rpmtd_s filenames; rpmTag ftag = RPMTAG_FILENAMES; if (headerIsEntry(h, RPMTAG_ORIGBASENAMES)) { ftag = RPMTAG_ORIGFILENAMES; } headerGet(h, ftag, &filenames, HEADERGET_EXT); fi->apath = filenames.data; /* Ick.. */ } headerFree(h); } if (psm->goal == PKG_ERASE) { psm->scriptArg = psm->npkgs_installed - 1; psm->amount = 0; psm->total = rpmfiFC(fi) ? rpmfiFC(fi) : 100; } break; case PSM_PRE: if (psm->goal == PKG_INSTALL) { psm->scriptTag = RPMTAG_PREIN; psm->sense = RPMSENSE_TRIGGERPREIN; psm->countCorrection = 0; /* XXX is this correct?!? */ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPREIN)) { /* Run triggers in other package(s) this package sets off. */ rc = rpmpsmNext(psm, PSM_TRIGGERS); if (rc) break; /* Run triggers in this package other package(s) set off. */ rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS); if (rc) break; } if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRE)) { rc = rpmpsmNext(psm, PSM_SCRIPT); if (rc) break; } } if (psm->goal == PKG_ERASE) { psm->scriptTag = RPMTAG_PREUN; psm->sense = RPMSENSE_TRIGGERUN; psm->countCorrection = -1; if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERUN)) { /* Run triggers in this package other package(s) set off. */ rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS); if (rc) break; /* Run triggers in other package(s) this package sets off. */ rc = rpmpsmNext(psm, PSM_TRIGGERS); if (rc) break; } if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPREUN)) rc = rpmpsmNext(psm, PSM_SCRIPT); } break; case PSM_PROCESS: if (psm->goal == PKG_INSTALL) { int fsmrc = 0; rpmpsmNotify(psm, RPMCALLBACK_INST_START, 0); /* make sure first progress call gets made */ rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, 0); if (rpmfiFC(fi) > 0 && !(rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)) { FD_t payload = rpmtePayload(psm->te); if (payload == NULL) { rc = RPMRC_FAIL; break; } fsmrc = rpmPackageFilesInstall(psm->ts, psm->te, psm->fi, payload, psm, &psm->failedFile); rpmswAdd(rpmtsOp(psm->ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ)); rpmswAdd(rpmtsOp(psm->ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST)); Fclose(payload); } /* XXX make sure progress reaches 100% */ rpmpsmNotify(psm, 0, psm->total); rpmpsmNotify(psm, RPMCALLBACK_INST_STOP, psm->total); if (fsmrc) { char *emsg = rpmcpioStrerror(fsmrc); rpmlog(RPMLOG_ERR, _("unpacking of archive failed%s%s: %s\n"), (psm->failedFile != NULL ? _(" on file ") : ""), (psm->failedFile != NULL ? psm->failedFile : ""), emsg); free(emsg); rc = RPMRC_FAIL; /* XXX notify callback on error. */ rpmtsNotify(ts, psm->te, RPMCALLBACK_UNPACK_ERROR, 0, 0); break; } } if (psm->goal == PKG_ERASE) { if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB) break; rpmpsmNotify(psm, RPMCALLBACK_UNINST_START, 0); /* make sure first progress call gets made */ rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, 0); /* XXX should't we log errors from here? */ if (rpmfiFC(fi) > 0 && !(rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)) { rc = rpmPackageFilesRemove(psm->ts, psm->te, psm->fi, psm, &psm->failedFile); } /* XXX make sure progress reaches 100% */ rpmpsmNotify(psm, 0, psm->total); rpmpsmNotify(psm, RPMCALLBACK_UNINST_STOP, psm->total); } break; case PSM_POST: if (psm->goal == PKG_INSTALL) { rpm_time_t installTime = (rpm_time_t) time(NULL); rpmfs fs = rpmteGetFileStates(psm->te); rpm_count_t fc = rpmfsFC(fs); rpm_fstate_t * fileStates = rpmfsGetStates(fs); Header h = rpmteHeader(psm->te); rpm_color_t tscolor = rpmtsColor(ts); if (fileStates != NULL && fc > 0) { headerPutChar(h, RPMTAG_FILESTATES, fileStates, fc); } headerPutUint32(h, RPMTAG_INSTALLTIME, &installTime, 1); headerPutUint32(h, RPMTAG_INSTALLCOLOR, &tscolor, 1); headerFree(h); /* * If this package has already been installed, remove it from * the database before adding the new one. */ if (rpmteDBInstance(psm->te)) { rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE); if (rc) break; } rc = rpmpsmNext(psm, PSM_RPMDB_ADD); if (rc) break; psm->scriptTag = RPMTAG_POSTIN; psm->sense = RPMSENSE_TRIGGERIN; psm->countCorrection = 0; if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOST)) { rc = rpmpsmNext(psm, PSM_SCRIPT); if (rc) break; } if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERIN)) { /* Run triggers in other package(s) this package sets off. */ rc = rpmpsmNext(psm, PSM_TRIGGERS); if (rc) break; /* Run triggers in this package other package(s) set off. */ rc = rpmpsmNext(psm, PSM_IMMED_TRIGGERS); if (rc) break; } rc = markReplacedFiles(psm); } if (psm->goal == PKG_ERASE) { psm->scriptTag = RPMTAG_POSTUN; psm->sense = RPMSENSE_TRIGGERPOSTUN; psm->countCorrection = -1; if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTUN)) { rc = rpmpsmNext(psm, PSM_SCRIPT); if (rc) break; } if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPOSTUN)) { /* Run triggers in other package(s) this package sets off. */ rc = rpmpsmNext(psm, PSM_TRIGGERS); if (rc) break; } rc = rpmpsmNext(psm, PSM_RPMDB_REMOVE); } break; case PSM_UNDO: break; case PSM_FINI: if (rc) { char *emsg = rpmcpioStrerror(rc); if (psm->failedFile) rpmlog(RPMLOG_ERR, _("%s failed on file %s: %s\n"), psm->goalName, psm->failedFile, emsg); else rpmlog(RPMLOG_ERR, _("%s failed: %s\n"), psm->goalName, emsg); free(emsg); /* XXX notify callback on error. */ rpmtsNotify(ts, psm->te, RPMCALLBACK_CPIO_ERROR, 0, 0); } psm->failedFile = _free(psm->failedFile); fi->apath = _free(fi->apath); break; case PSM_CREATE: break; case PSM_DESTROY: break; case PSM_SCRIPT: /* Run current package scriptlets. */ rc = runInstScript(psm); break; case PSM_TRIGGERS: /* Run triggers in other package(s) this package sets off. */ rc = runTriggers(psm); break; case PSM_IMMED_TRIGGERS: /* Run triggers in this package other package(s) set off. */ rc = runImmedTriggers(psm); break; case PSM_RPMDB_ADD: { Header h = rpmteHeader(psm->te); if (!headerIsEntry(h, RPMTAG_INSTALLTID)) { rpm_tid_t tid = rpmtsGetTid(ts); if (tid != 0 && tid != (rpm_tid_t)-1) headerPutUint32(h, RPMTAG_INSTALLTID, &tid, 1); } (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBADD), 0); rc = (rpmdbAdd(rpmtsGetRdb(ts), h) == 0) ? RPMRC_OK : RPMRC_FAIL; (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBADD), 0); if (rc == RPMRC_OK) rpmteSetDBInstance(psm->te, headerGetInstance(h)); headerFree(h); } break; case PSM_RPMDB_REMOVE: (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0); rc = (rpmdbRemove(rpmtsGetRdb(ts), rpmteDBInstance(psm->te)) == 0) ? RPMRC_OK : RPMRC_FAIL; (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBREMOVE), 0); if (rc == RPMRC_OK) rpmteSetDBInstance(psm->te, 0); break; default: break; } return rc; }
/*@-mods@*/ rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp) { HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he)); HE_t she = (HE_t) memset(alloca(sizeof(*she)), 0, sizeof(*she)); pgpDig dig = rpmtsDig(ts); char buf[8*BUFSIZ]; ssize_t count; Header sigh = NULL; rpmtsOpX opx; rpmop op = NULL; size_t nb; unsigned ix; Header h = NULL; const char * msg = NULL; rpmVSFlags vsflags; rpmRC rc = RPMRC_FAIL; /* assume failure */ rpmop opsave = (rpmop) memset(alloca(sizeof(*opsave)), 0, sizeof(*opsave)); int xx; pgpPkt pp = (pgpPkt) alloca(sizeof(*pp)); if (hdrp) *hdrp = NULL; assert(dig != NULL); (void) fdSetDig(fd, dig); /* Snapshot current I/O counters (cached persistent I/O reuses counters) */ (void) rpmswAdd(opsave, fdstat_op(fd, FDSTAT_READ)); { const char item[] = "Lead"; msg = NULL; rc = rpmpkgRead(item, fd, NULL, &msg); switch (rc) { default: rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg); /*@fallthrough@*/ case RPMRC_NOTFOUND: msg = _free(msg); goto exit; /*@notreached@*/ break; case RPMRC_OK: break; } msg = _free(msg); } { const char item[] = "Signature"; msg = NULL; rc = rpmpkgRead(item, fd, &sigh, &msg); switch (rc) { default: rpmlog(RPMLOG_ERR, "%s: %s: %s", fn, item, (msg && *msg ? msg : _("read failed\n"))); msg = _free(msg); goto exit; /*@notreached@*/ break; case RPMRC_OK: if (sigh == NULL) { rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn); rc = RPMRC_FAIL; goto exit; } break; } msg = _free(msg); } #define _chk(_mask) (she->tag == 0 && !(vsflags & (_mask))) /* * Figger the most effective available signature. * Prefer signatures over digests, then header-only over header+payload. * DSA will be preferred over RSA if both exist because tested first. * Note that NEEDPAYLOAD prevents header+payload signatures and digests. */ she->tag = (rpmTag)0; opx = (rpmtsOpX)0; vsflags = pgpDigVSFlags; if (_chk(RPMVSF_NOECDSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_ECDSA)) { she->tag = (rpmTag)RPMSIGTAG_ECDSA; } else if (_chk(RPMVSF_NODSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_DSA)) { she->tag = (rpmTag)RPMSIGTAG_DSA; } else if (_chk(RPMVSF_NORSAHEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_RSA)) { she->tag = (rpmTag)RPMSIGTAG_RSA; } else if (_chk(RPMVSF_NOSHA1HEADER) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_SHA1)) { she->tag = (rpmTag)RPMSIGTAG_SHA1; } else if (_chk(RPMVSF_NOMD5|RPMVSF_NEEDPAYLOAD) && headerIsEntry(sigh, (rpmTag)RPMSIGTAG_MD5)) { she->tag = (rpmTag)RPMSIGTAG_MD5; fdInitDigest(fd, PGPHASHALGO_MD5, 0); opx = RPMTS_OP_DIGEST; } /* Read the metadata, computing digest(s) on the fly. */ h = NULL; msg = NULL; /* XXX stats will include header i/o and setup overhead. */ /* XXX repackaged packages have appended tags, legacy dig/sig check fails */ if (opx > 0) { op = (rpmop) pgpStatsAccumulator(dig, opx); (void) rpmswEnter(op, 0); } /*@-type@*/ /* XXX arrow access of non-pointer (FDSTAT_t) */ nb = fd->stats->ops[FDSTAT_READ].bytes; { const char item[] = "Header"; msg = NULL; rc = rpmpkgRead(item, fd, &h, &msg); if (rc != RPMRC_OK) { rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg); msg = _free(msg); goto exit; } msg = _free(msg); } nb = fd->stats->ops[FDSTAT_READ].bytes - nb; /*@=type@*/ if (opx > 0 && op != NULL) { (void) rpmswExit(op, nb); op = NULL; } /* Any digests or signatures to check? */ if (she->tag == 0) { rc = RPMRC_OK; goto exit; } dig->nbytes = 0; /* Fish out the autosign pubkey (if present). */ he->tag = RPMTAG_PUBKEYS; xx = headerGet(h, he, 0); if (xx && he->p.argv != NULL && he->c > 0) switch (he->t) { default: break; case RPM_STRING_ARRAY_TYPE: ix = he->c - 1; /* XXX FIXME: assumes last pubkey */ dig->pub = _free(dig->pub); dig->publen = 0; { rpmiob iob = rpmiobNew(0); iob = rpmiobAppend(iob, he->p.argv[ix], 0); xx = pgpArmorUnwrap(iob, (rpmuint8_t **)&dig->pub, &dig->publen); iob = rpmiobFree(iob); } if (xx != PGPARMOR_PUBKEY) { dig->pub = _free(dig->pub); dig->publen = 0; } break; } he->p.ptr = _free(he->p.ptr); /* Retrieve the tag parameters from the signature header. */ xx = headerGet(sigh, she, 0); if (she->p.ptr == NULL) { rc = RPMRC_FAIL; goto exit; } /*@-ownedtrans -noeffect@*/ xx = pgpSetSig(dig, she->tag, she->t, she->p.ptr, she->c); /*@=ownedtrans =noeffect@*/ switch ((rpmSigTag)she->tag) { default: /* XXX keep gcc quiet. */ assert(0); /*@notreached@*/ break; case RPMSIGTAG_RSA: /* Parse the parameters from the OpenPGP packets that will be needed. */ xx = pgpPktLen(she->p.ui8p, she->c, pp); xx = rpmhkpLoadSignature(NULL, dig, pp); if (dig->signature.version != 3 && dig->signature.version != 4) { rpmlog(RPMLOG_ERR, _("skipping package %s with unverifiable V%u signature\n"), fn, dig->signature.version); rc = RPMRC_FAIL; goto exit; } xx = hBlobDigest(h, dig, dig->signature.hash_algo, &dig->hrsa); break; case RPMSIGTAG_DSA: /* Parse the parameters from the OpenPGP packets that will be needed. */ xx = pgpPktLen(she->p.ui8p, she->c, pp); xx = rpmhkpLoadSignature(NULL, dig, pp); if (dig->signature.version != 3 && dig->signature.version != 4) { rpmlog(RPMLOG_ERR, _("skipping package %s with unverifiable V%u signature\n"), fn, dig->signature.version); rc = RPMRC_FAIL; goto exit; } xx = hBlobDigest(h, dig, dig->signature.hash_algo, &dig->hdsa); break; case RPMSIGTAG_ECDSA: /* Parse the parameters from the OpenPGP packets that will be needed. */ xx = pgpPktLen(she->p.ui8p, she->c, pp); xx = rpmhkpLoadSignature(NULL, dig, pp); if (dig->signature.version != 3 && dig->signature.version != 4) { rpmlog(RPMLOG_ERR, _("skipping package %s with unverifiable V%u signature\n"), fn, dig->signature.version); rc = RPMRC_FAIL; goto exit; } xx = hBlobDigest(h, dig, dig->signature.hash_algo, &dig->hecdsa); break; case RPMSIGTAG_SHA1: /* XXX dig->hsha? */ xx = hBlobDigest(h, dig, PGPHASHALGO_SHA1, &dig->hdsa); break; case RPMSIGTAG_MD5: /* Legacy signatures need the compressed payload in the digest too. */ op = (rpmop) pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */ (void) rpmswEnter(op, 0); while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) dig->nbytes += count; (void) rpmswExit(op, dig->nbytes); op->count--; /* XXX one too many */ dig->nbytes += nb; /* XXX include size of header blob. */ if (count < 0) { rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd)); rc = RPMRC_FAIL; goto exit; } /* XXX Steal the digest-in-progress from the file handle. */ fdStealDigest(fd, dig); break; } /** @todo Implement disable/enable/warn/error/anal policy. */ buf[0] = '\0'; rc = rpmVerifySignature(dig, buf); switch (rc) { case RPMRC_OK: /* Signature is OK. */ rpmlog(RPMLOG_DEBUG, "%s: %s\n", fn, buf); break; case RPMRC_NOTTRUSTED: /* Signature is OK, but key is not trusted. */ case RPMRC_NOKEY: /* Public key is unavailable. */ #ifndef DYING /* XXX Print NOKEY/NOTTRUSTED warning only once. */ { int lvl = (pgpStashKeyid(dig) ? RPMLOG_DEBUG : RPMLOG_WARNING); rpmlog(lvl, "%s: %s\n", fn, buf); } break; case RPMRC_NOTFOUND: /* Signature is unknown type. */ rpmlog(RPMLOG_WARNING, "%s: %s\n", fn, buf); break; #else case RPMRC_NOTFOUND: /* Signature is unknown type. */ case RPMRC_NOSIG: /* Signature is unavailable. */ #endif default: case RPMRC_FAIL: /* Signature does not verify. */ rpmlog(RPMLOG_ERR, "%s: %s\n", fn, buf); break; } exit: if (rc != RPMRC_FAIL && h != NULL && hdrp != NULL) { /* Append (and remap) signature tags to the metadata. */ headerMergeLegacySigs(h, sigh); /* Bump reference count for return. */ *hdrp = headerLink(h); } (void)headerFree(h); h = NULL; /* Accumulate time reading package header. */ (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_READHDR), fdstat_op(fd, FDSTAT_READ)); (void) rpmswSub(rpmtsOp(ts, RPMTS_OP_READHDR), opsave); #ifdef NOTYET /* Return RPMRC_NOSIG for MANDATORY signature verification. */ { rpmSigTag sigtag = pgpGetSigtag(dig); switch (sigtag) { default: rc = RPMRC_NOSIG; /*@fallthrough@*/ case RPMSIGTAG_RSA: case RPMSIGTAG_DSA: case RPMSIGTAG_ECDSA: break; } } #endif rpmtsCleanDig(ts); (void)headerFree(sigh); sigh = NULL; return rc; }