/
githubmirror
/
rpm
Обзор
Документация
Войти
/
githubmirror
/
rpm
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
lib/package.cc
372 строки
10 KB
Panu Matilainen
Fix transaction verification output as well
13 янв 2026, 10:25
13 янв 2026, 10:25
294b68b
Код
Авторство
О чём код?
/** \ingroup header * \file lib/package.c */ #include "system.h" #include <string> #include <mutex> #include <set> #include <netinet/in.h> #include <rpm/rpmlib.h> /* XXX RPMSIGTAG, other sig stuff */ #include <rpm/rpmts.h> #include <rpm/rpmlog.h> #include <rpm/rpmstring.h> #include <rpm/rpmkeyring.h> #include "rpmlead.hh" #include "rpmio_internal.hh" /* fd digest bits */ #include "rpmlog_internal.hh" /* rpmlogOnce */ #include "header_internal.hh" /* XXX headerCheck */ #include "rpmvs.hh" #include "debug.h" typedef struct pkgdata_s *pkgdatap; typedef void (*hdrvsmsg)(struct rpmsinfo_s *sinfo, pkgdatap pkgdata, const char *msg); struct pkgdata_s { const char *fn; char *msg; uint64_t logDomain; rpmRC rc; }; static struct taglate_s { rpmTagVal stag; rpmTagVal xtag; rpm_count_t count; int quirk; } const xlateTags[] = { { RPMSIGTAG_SIZE, RPMTAG_SIGSIZE, 1, 0 }, { RPMSIGTAG_PGP, RPMTAG_SIGPGP, 0, 0 }, { RPMSIGTAG_MD5, RPMTAG_SIGMD5, 16, 0 }, { RPMSIGTAG_GPG, RPMTAG_SIGGPG, 0, 0 }, /* { RPMSIGTAG_PGP5, RPMTAG_SIGPGP5, 0, 0 }, */ /* long obsolete, dont use */ { RPMSIGTAG_PAYLOADSIZE, RPMTAG_ARCHIVESIZE, 1, 1 }, { RPMSIGTAG_FILESIGNATURES, RPMTAG_FILESIGNATURES, 0, 1 }, { RPMSIGTAG_FILESIGNATURELENGTH, RPMTAG_FILESIGNATURELENGTH, 1, 1 }, { RPMSIGTAG_VERITYSIGNATURES, RPMTAG_VERITYSIGNATURES, 0, 0 }, { RPMSIGTAG_VERITYSIGNATUREALGO, RPMTAG_VERITYSIGNATUREALGO, 1, 0 }, { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 }, { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 }, { RPMSIGTAG_SHA3_256, RPMTAG_SHA3_256HEADER, 1, 0 }, { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 }, { RPMSIGTAG_RSA, RPMTAG_RSAHEADER, 0, 0 }, { RPMSIGTAG_LONGSIZE, RPMTAG_LONGSIGSIZE, 1, 0 }, { RPMSIGTAG_LONGARCHIVESIZE, RPMTAG_LONGARCHIVESIZE, 1, 0 }, { RPMSIGTAG_OPENPGP, RPMTAG_OPENPGP, 0, 0 }, { 0 } }; /** \ingroup header * Translate and merge legacy signature tags into header. * @param h header (dest) * @param sigh signature header (src) * @return failing tag number, 0 on success */ static rpmTagVal headerMergeLegacySigs(Header h, Header sigh, char **msg) { const struct taglate_s *xl; struct rpmtd_s td; int rpmformat = headerGetNumber(h, RPMTAG_RPMFORMAT); for (xl = xlateTags; xl->stag; xl++) { /* There mustn't be one in the main header */ if (headerIsEntry(h, xl->xtag)) { /* In v3/v4 some tags may exist in either header, but never both */ if (rpmformat < 6 && xl->quirk && !headerIsEntry(sigh, xl->stag)) continue; goto exit; } } rpmtdReset(&td); for (xl = xlateTags; xl->stag; xl++) { /* Completely ignore legacy signature tags on v6 packages */ if (rpmformat >= 6 && xl->stag >= HEADER_TAGBASE) continue; if (headerGet(sigh, xl->stag, &td, HEADERGET_RAW|HEADERGET_MINMEM)) { /* Translate legacy tags */ if (xl->stag != xl->xtag) td.tag = xl->xtag; /* Ensure type and tag size match expectations */ if (td.type != rpmTagGetTagType(td.tag)) break; if (td.count < 1 || td.count > 16*1024*1024) break; if (xl->count && td.count != xl->count) break; if (!headerPut(h, &td, HEADERPUT_DEFAULT)) break; rpmtdFreeData(&td); } } rpmtdFreeData(&td); exit: if (xl->stag) { rasprintf(msg, "invalid signature tag %s (%d)", rpmTagGetName(xl->xtag), xl->xtag); } return xl->stag; } static int handleHdrVS(struct rpmsinfo_s *sinfo, void *cbdata) { struct pkgdata_s *pkgdata = (struct pkgdata_s *)cbdata; /* Remember actual return code, but don't override a previous failure */ if (sortRC(sinfo->rc) > sortRC(pkgdata->rc)) pkgdata->rc = sinfo->rc; return 1; } static int appendhdrmsg(struct rpmsinfo_s *sinfo, void *cbdata) { struct pkgdata_s *pkgdata = (struct pkgdata_s *)cbdata; if (sinfo->rc != RPMRC_NOTFOUND) { char *msg = rpmsinfoMsg(sinfo); pkgdata->msg = rstrscat(&pkgdata->msg, "\n", msg, NULL); free(msg); } return 1; } rpmRC headerCheck(rpmts ts, const void * uh, size_t uc, char ** msg) { rpmRC rc = RPMRC_FAIL; rpmVSFlags vsflags = rpmtsVSFlags(ts) | RPMVSF_NEEDPAYLOAD; rpmKeyring keyring = rpmtsGetKeyring(ts, 1); struct hdrblob_s blob; struct pkgdata_s pkgdata = { .fn = NULL, .msg = NULL, .logDomain = (uint64_t) ts, .rc = RPMRC_OK, }; if (hdrblobInit(uh, uc, 0, 0, &blob, msg) == RPMRC_OK) { struct rpmvs_s *vs = rpmvsCreate(0, vsflags, keyring); rpmDigestBundle bundle = rpmDigestBundleNew(); rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0); rpmvsInit(vs, &blob, bundle); rpmvsInitRange(vs, RPMSIG_HEADER); hdrblobDigestUpdate(bundle, &blob); rpmvsFiniRange(vs, RPMSIG_HEADER); rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, handleHdrVS, &pkgdata); rpmvsForeach(vs, appendhdrmsg, &pkgdata); rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), uc); rc = pkgdata.rc; if (rc == RPMRC_OK && pkgdata.msg == NULL) pkgdata.msg = xstrdup("Header sanity check: OK"); if (msg) *msg = pkgdata.msg; else free(pkgdata.msg); rpmDigestBundleFree(bundle); rpmvsFree(vs); } rpmKeyringFree(keyring); return rc; } rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, char ** msg) { char *buf = NULL; struct hdrblob_s blob; Header h = NULL; rpmRC rc = RPMRC_FAIL; /* assume failure */ if (hdrp) *hdrp = NULL; if (msg) *msg = NULL; if (hdrblobRead(fd, 1, 1, RPMTAG_HEADERIMMUTABLE, &blob, &buf) != RPMRC_OK) goto exit; /* OK, blob looks sane, load the header. */ rc = hdrblobImport(&blob, 0, &h, &buf); exit: if (hdrp && h && rc == RPMRC_OK) *hdrp = headerLink(h); headerFree(h); if (msg != NULL && *msg == NULL && buf != NULL) { *msg = buf; } else { free(buf); } return rc; } static void applyRetrofits(Header h) { int v3 = 0; /* * Make sure that either RPMTAG_SOURCERPM or RPMTAG_SOURCEPACKAGE * is set. Use a simple heuristic to find the type if both are unset. */ if (!headerIsEntry(h, RPMTAG_SOURCERPM) && !headerIsEntry(h, RPMTAG_SOURCEPACKAGE)) { /* the heuristic needs the compressed file list */ if (headerIsEntry(h, RPMTAG_OLDFILENAMES)) headerConvert(h, HEADERCONV_COMPRESSFILELIST); if (headerIsSourceHeuristic(h)) { /* Retrofit RPMTAG_SOURCEPACKAGE to srpms for compatibility */ uint32_t one = 1; headerPutUint32(h, RPMTAG_SOURCEPACKAGE, &one, 1); } else { /* * Make sure binary rpms have RPMTAG_SOURCERPM set as that's * what we use for differentiating binary vs source elsewhere. */ headerPutString(h, RPMTAG_SOURCERPM, "(none)"); } } /* * Convert legacy headers on the fly. Not having immutable region * equals a truly ancient package, do full retrofit. OTOH newer * packages might have been built with --nodirtokens, test and handle * the non-compressed filelist case separately. */ if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) { v3 = 1; headerConvert(h, HEADERCONV_RETROFIT_V3); } else if (headerIsEntry(h, RPMTAG_OLDFILENAMES)) { headerConvert(h, HEADERCONV_COMPRESSFILELIST); v3 = 1; } if (v3) { char *s = headerGetAsString(h, RPMTAG_NEVRA); rpmlog(RPMLOG_WARNING, _("RPM v3 packages are deprecated: %s\n"), s); free(s); } } static int loghdrmsg(struct rpmsinfo_s *sinfo, void *cbdata) { const struct pkgdata_s *pkgdata = (const struct pkgdata_s *)cbdata; int lvl = RPMLOG_DEBUG; int once = 0; int log = 1; switch (sinfo->rc) { case RPMRC_NOTFOUND: /* Signature/digest not present. */ log = 0; break; case RPMRC_NOTTRUSTED: /* Signature is OK, but key is not trusted. */ case RPMRC_OK: /* Signature is OK. */ break; case RPMRC_NOKEY: /* Public key is unavailable. */ lvl = RPMLOG_WARNING; once = 1; break; default: case RPMRC_FAIL: /* Signature does not verify. */ lvl = RPMLOG_ERR; break; } if (log) { char *msg = rpmsinfoMsg(sinfo); if (once) { rpmlogOnce(pkgdata->logDomain, sinfo->keyid, lvl, "%s: %s\n", pkgdata->fn, msg); } else { rpmlog(lvl, "%s: %s\n", pkgdata->fn, msg); } free(msg); } return 1; } rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char * fn, Header * hdrp) { char *msg = NULL; Header h = NULL; Header sigh = NULL; hdrblob blob = NULL; hdrblob sigblob = NULL; rpmVSFlags vsflags = rpmtsVSFlags(ts) | RPMVSF_NEEDPAYLOAD; rpmKeyring keyring = rpmtsGetKeyring(ts, 1); struct rpmvs_s *vs = rpmvsCreate(0, vsflags, keyring); struct pkgdata_s pkgdata = { .fn = fn ? fn : Fdescr(fd), .msg = NULL, .logDomain = (uint64_t) ts, .rc = RPMRC_OK, }; /* XXX: lots of 3rd party software relies on the behavior */ if (hdrp) *hdrp = NULL; rpmRC rc = rpmpkgRead(vs, fd, &sigblob, &blob, &msg); if (rc) goto exit; /* Actually all verify discovered signatures and digests */ rc = RPMRC_FAIL; rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, handleHdrVS, &pkgdata); rpmvsForeach(vs, loghdrmsg, &pkgdata); /* Preserve traditional behavior for now: only failure prevents read */ if (pkgdata.rc != RPMRC_FAIL) { /* Finally import the headers and do whatever required retrofits etc */ if (hdrp) { if (hdrblobImport(sigblob, 0, &sigh, &msg)) goto exit; if (hdrblobImport(blob, 0, &h, &msg)) goto exit; /* Append (and remap) signature tags to the metadata. */ if (headerMergeLegacySigs(h, sigh, &msg)) goto exit; applyRetrofits(h); /* Bump reference count for return. */ *hdrp = headerLink(h); } rc = RPMRC_OK; } /* If there was a "substatus" (NOKEY in practise), return that instead */ if (rc == RPMRC_OK && pkgdata.rc) rc = pkgdata.rc; exit: if (rc && msg) rpmlog(RPMLOG_ERR, "%s: %s\n", Fdescr(fd), msg); hdrblobFree(sigblob); hdrblobFree(blob); headerFree(sigh); headerFree(h); rpmKeyringFree(keyring); rpmvsFree(vs); free(msg); return rc; }