diff options
Diffstat (limited to 'lib/verify.c')
-rw-r--r-- | lib/verify.c | 200 |
1 files changed, 140 insertions, 60 deletions
diff --git a/lib/verify.c b/lib/verify.c index 3dcec10f7..5528ba95e 100644 --- a/lib/verify.c +++ b/lib/verify.c @@ -53,25 +53,22 @@ static int cap_compare(cap_t acap, cap_t bcap) } #endif -int rpmVerifyFile(const rpmts ts, const rpmfi fi, - rpmVerifyAttrs * res, rpmVerifyAttrs omitMask) +rpmVerifyAttrs rpmfilesVerify(rpmfiles fi, int ix, rpmVerifyAttrs omitMask) { - rpm_mode_t fmode = rpmfiFMode(fi); - rpmfileAttrs fileAttrs = rpmfiFFlags(fi); - rpmVerifyAttrs flags = rpmfiVFlags(fi); - const char * fn = rpmfiFN(fi); + rpm_mode_t fmode = rpmfilesFMode(fi, ix); + rpmfileAttrs fileAttrs = rpmfilesFFlags(fi, ix); + rpmVerifyAttrs flags = rpmfilesVFlags(fi, ix); + const char * fn = rpmfilesFN(fi, ix); struct stat sb; - int rc; - - *res = RPMVERIFY_NONE; + rpmVerifyAttrs vfy = RPMVERIFY_NONE; /* * Check to see if the file was installed - if not pretend all is OK. */ - switch (rpmfiFState(fi)) { + switch (rpmfilesFState(fi, ix)) { case RPMFILE_STATE_NETSHARED: case RPMFILE_STATE_NOTINSTALLED: - return 0; + goto exit; break; case RPMFILE_STATE_REPLACED: /* For replaced files we can only verify if it exists at all */ @@ -92,8 +89,23 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi, } if (fn == NULL || lstat(fn, &sb) != 0) { - *res |= RPMVERIFY_LSTATFAIL; - return 1; + vfy |= RPMVERIFY_LSTATFAIL; + goto exit; + } + + /* If we expected a directory but got a symlink to one, follow the link */ + if (S_ISDIR(fmode) && S_ISLNK(sb.st_mode)) { + struct stat dsb; + /* ...if it actually points to a directory */ + if (stat(fn, &dsb) == 0 && S_ISDIR(dsb.st_mode)) { + uid_t fuid; + /* ...and is by a legit user, to match fsmVerify() behavior */ + if (sb.st_uid == 0 || + (rpmugUid(rpmfilesFUser(fi, ix), &fuid) == 0 && + sb.st_uid == fuid)) { + sb = dsb; /* struct assignment */ + } + } } /* Links have no mode, other types have no linkto */ @@ -122,19 +134,19 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi, size_t diglen; /* XXX If --nomd5, then prelinked library sizes are not corrected. */ - if ((digest = rpmfiFDigest(fi, &algo, &diglen))) { + if ((digest = rpmfilesFDigest(fi, ix, &algo, &diglen))) { unsigned char fdigest[diglen]; rpm_loff_t fsize; - rc = rpmDoDigest(algo, fn, 0, fdigest, &fsize); - sb.st_size = fsize; - if (rc) { - *res |= (RPMVERIFY_READFAIL|RPMVERIFY_FILEDIGEST); - } else if (memcmp(fdigest, digest, diglen)) { - *res |= RPMVERIFY_FILEDIGEST; + if (rpmDoDigest(algo, fn, 0, fdigest, &fsize)) { + vfy |= (RPMVERIFY_READFAIL|RPMVERIFY_FILEDIGEST); + } else { + sb.st_size = fsize; + if (memcmp(fdigest, digest, diglen)) + vfy |= RPMVERIFY_FILEDIGEST; } } else { - *res |= RPMVERIFY_FILEDIGEST; + vfy |= RPMVERIFY_FILEDIGEST; } } @@ -143,18 +155,18 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi, int size = 0; if ((size = readlink(fn, linkto, sizeof(linkto)-1)) == -1) - *res |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO); + vfy |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO); else { - const char * flink = rpmfiFLink(fi); + const char * flink = rpmfilesFLink(fi, ix); linkto[size] = '\0'; if (flink == NULL || !rstreq(linkto, flink)) - *res |= RPMVERIFY_LINKTO; + vfy |= RPMVERIFY_LINKTO; } } if (flags & RPMVERIFY_FILESIZE) { - if (sb.st_size != rpmfiFSize(fi)) - *res |= RPMVERIFY_FILESIZE; + if (sb.st_size != rpmfilesFSize(fi, ix)) + vfy |= RPMVERIFY_FILESIZE; } if (flags & RPMVERIFY_MODE) { @@ -176,7 +188,7 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi, } if (metamode != filemode) - *res |= RPMVERIFY_MODE; + vfy |= RPMVERIFY_MODE; #if WITH_ACL /* @@ -186,7 +198,7 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi, acl_t facl = acl_get_file(fn, ACL_TYPE_ACCESS); if (facl) { if (acl_equiv_mode(facl, NULL) == 1) { - *res |= RPMVERIFY_MODE; + vfy |= RPMVERIFY_MODE; } acl_free(facl); } @@ -197,12 +209,12 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi, if (S_ISCHR(fmode) != S_ISCHR(sb.st_mode) || S_ISBLK(fmode) != S_ISBLK(sb.st_mode)) { - *res |= RPMVERIFY_RDEV; + vfy |= RPMVERIFY_RDEV; } else if (S_ISDEV(fmode) && S_ISDEV(sb.st_mode)) { rpm_rdev_t st_rdev = (sb.st_rdev & 0xffff); - rpm_rdev_t frdev = (rpmfiFRdev(fi) & 0xffff); + rpm_rdev_t frdev = (rpmfilesFRdev(fi, ix) & 0xffff); if (st_rdev != frdev) - *res |= RPMVERIFY_RDEV; + vfy |= RPMVERIFY_RDEV; } } @@ -213,7 +225,7 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi, * capabilities at all but suffices for now... */ cap_t cap, fcap; - cap = cap_from_text(rpmfiFCaps(fi)); + cap = cap_from_text(rpmfilesFCaps(fi, ix)); if (!cap) { cap = cap_from_text("="); } @@ -223,32 +235,71 @@ int rpmVerifyFile(const rpmts ts, const rpmfi fi, } if (cap_compare(cap, fcap) != 0) - *res |= RPMVERIFY_CAPS; + vfy |= RPMVERIFY_CAPS; cap_free(fcap); cap_free(cap); } #endif - if ((flags & RPMVERIFY_MTIME) && (sb.st_mtime != rpmfiFMtime(fi))) { - *res |= RPMVERIFY_MTIME; + if ((flags & RPMVERIFY_MTIME) && (sb.st_mtime != rpmfilesFMtime(fi, ix))) { + vfy |= RPMVERIFY_MTIME; } if (flags & RPMVERIFY_USER) { const char * name = rpmugUname(sb.st_uid); - const char * fuser = rpmfiFUser(fi); - if (name == NULL || fuser == NULL || !rstreq(name, fuser)) - *res |= RPMVERIFY_USER; + const char * fuser = rpmfilesFUser(fi, ix); + uid_t uid; + int namematch = 0; + int idmatch = 0; + + if (name && fuser) + namematch = rstreq(name, fuser); + if (fuser && rpmugUid(fuser, &uid) == 0) + idmatch = (uid == sb.st_uid); + + if (namematch != idmatch) { + rpmlog(RPMLOG_WARNING, + _("Duplicate username or UID for user %s\n"), fuser); + } + + if (!(namematch || idmatch)) + vfy |= RPMVERIFY_USER; } if (flags & RPMVERIFY_GROUP) { const char * name = rpmugGname(sb.st_gid); - const char * fgroup = rpmfiFGroup(fi); - if (name == NULL || fgroup == NULL || !rstreq(name, fgroup)) - *res |= RPMVERIFY_GROUP; + const char * fgroup = rpmfilesFGroup(fi, ix); + gid_t gid; + int namematch = 0; + int idmatch = 0; + + if (name && fgroup) + namematch = rstreq(name, fgroup); + if (fgroup && rpmugGid(fgroup, &gid) == 0) + idmatch = (gid == sb.st_gid); + + if (namematch != idmatch) { + rpmlog(RPMLOG_WARNING, + _("Duplicate groupname or GID for group %s\n"), fgroup); + } + + if (!(namematch || idmatch)) + vfy |= RPMVERIFY_GROUP; } - return 0; +exit: + return vfy; +} + +int rpmVerifyFile(const rpmts ts, const rpmfi fi, + rpmVerifyAttrs * res, rpmVerifyAttrs omitMask) +{ + rpmVerifyAttrs vfy = rpmfiVerify(fi, omitMask); + if (res) + *res = vfy; + + return (vfy & RPMVERIFY_LSTATFAIL) ? 1 : 0; } /** @@ -314,7 +365,7 @@ char * rpmVerifyString(uint32_t verifyResult, const char *pad) char * rpmFFlagsString(uint32_t fflags, const char *pad) { char *fmt = NULL; - rasprintf(&fmt, "%s%s%s%s%s%s%s%s", + rasprintf(&fmt, "%s%s%s%s%s%s%s%s%s", (fflags & RPMFILE_DOC) ? "d" : pad, (fflags & RPMFILE_CONFIG) ? "c" : pad, (fflags & RPMFILE_SPECFILE) ? "s" : pad, @@ -322,22 +373,43 @@ char * rpmFFlagsString(uint32_t fflags, const char *pad) (fflags & RPMFILE_NOREPLACE) ? "n" : pad, (fflags & RPMFILE_GHOST) ? "g" : pad, (fflags & RPMFILE_LICENSE) ? "l" : pad, - (fflags & RPMFILE_README) ? "r" : pad); + (fflags & RPMFILE_README) ? "r" : pad, + (fflags & RPMFILE_ARTIFACT) ? "a" : pad); return fmt; } +static const char * stateStr(rpmfileState fstate) +{ + switch (fstate) { + case RPMFILE_STATE_NORMAL: + return NULL; + case RPMFILE_STATE_NOTINSTALLED: + return rpmIsVerbose() ? _("not installed") : NULL; + case RPMFILE_STATE_NETSHARED: + return rpmIsVerbose() ? _("net shared") : NULL; + case RPMFILE_STATE_WRONGCOLOR: + return rpmIsVerbose() ? _("wrong color") : NULL; + case RPMFILE_STATE_REPLACED: + return _("replaced"); + case RPMFILE_STATE_MISSING: + return _("no state"); + } + return _("unknown state"); +} + /** * Check file info from header against what's actually installed. * @param ts transaction set * @param h header to verify * @param omitMask bits to disable verify checks - * @param ghosts should ghosts be verified? + * @param skipAttr skip files with these attrs (eg %ghost) * @return 0 no problems, 1 problems found */ -static int verifyHeader(rpmts ts, Header h, rpmVerifyAttrs omitMask, int ghosts) +static int verifyHeader(rpmts ts, Header h, rpmVerifyAttrs omitMask, + rpmfileAttrs skipAttrs) { rpmVerifyAttrs verifyResult = 0; - int ec = 0; /* assume no problems */ + rpmVerifyAttrs verifyAll = 0; /* assume no problems */ rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_FLAGS_VERIFY); if (fi == NULL) @@ -347,17 +419,17 @@ static int verifyHeader(rpmts ts, Header h, rpmVerifyAttrs omitMask, int ghosts) while (rpmfiNext(fi) >= 0) { rpmfileAttrs fileAttrs = rpmfiFFlags(fi); char *buf = NULL, *attrFormat; + const char *fstate = NULL; char ac; - int rc; - /* If not verifying %ghost, skip ghost files. */ - if ((fileAttrs & RPMFILE_GHOST) && !ghosts) + /* Skip on attributes (eg from --noghost) */ + if (skipAttrs & fileAttrs) continue; - rc = rpmVerifyFile(ts, fi, &verifyResult, omitMask); + verifyResult = rpmfiVerify(fi, omitMask); /* Filter out timestamp differences of shared files */ - if (rc == 0 && (verifyResult & RPMVERIFY_MTIME)) { + if (verifyResult & RPMVERIFY_MTIME) { rpmdbMatchIterator mi; mi = rpmtsInitIterator(ts, RPMDBI_BASENAMES, rpmfiFN(fi), 0); if (rpmdbGetIteratorCount(mi) > 1) @@ -365,9 +437,13 @@ static int verifyHeader(rpmts ts, Header h, rpmVerifyAttrs omitMask, int ghosts) rpmdbFreeIterator(mi); } + /* State is only meaningful for installed packages */ + if (headerGetInstance(h)) + fstate = stateStr(rpmfiFState(fi)); + attrFormat = rpmFFlagsString(fileAttrs, ""); ac = rstreq(attrFormat, "") ? ' ' : attrFormat[0]; - if (rc) { + if (verifyResult & RPMVERIFY_LSTATFAIL) { if (!(fileAttrs & (RPMFILE_MISSINGOK|RPMFILE_GHOST)) || rpmIsVerbose()) { rasprintf(&buf, _("missing %c %s"), ac, rpmfiFN(fi)); if ((verifyResult & RPMVERIFY_LSTATFAIL) != 0 && @@ -377,25 +453,30 @@ static int verifyHeader(rpmts ts, Header h, rpmVerifyAttrs omitMask, int ghosts) rstrcat(&buf, app); free(app); } - ec = rc; } - } else if (verifyResult || rpmIsVerbose()) { + } else if (verifyResult || fstate || rpmIsVerbose()) { char *verifyFormat = rpmVerifyString(verifyResult, "."); rasprintf(&buf, "%s %c %s", verifyFormat, ac, rpmfiFN(fi)); free(verifyFormat); - - if (verifyResult) ec = 1; } free(attrFormat); if (buf) { + if (fstate) + buf = rstrscat(&buf, " (", fstate, ")", NULL); rpmlog(RPMLOG_NOTICE, "%s\n", buf); buf = _free(buf); } + + /* Filter out missing %ghost/%missingok errors from final result */ + if (fileAttrs & (RPMFILE_MISSINGOK|RPMFILE_GHOST)) + verifyResult &= ~RPMVERIFY_LSTATFAIL; + + verifyAll |= verifyResult; } rpmfiFree(fi); - return ec; + return (verifyAll != 0) ? 1 : 0; } /** @@ -440,7 +521,6 @@ static int verifyDependencies(rpmts ts, Header h) int showVerifyPackage(QVA_t qva, rpmts ts, Header h) { rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS); - int ghosts = (qva->qva_fflags & RPMFILE_GHOST); int ec = 0; int rc; @@ -449,7 +529,7 @@ int showVerifyPackage(QVA_t qva, rpmts ts, Header h) ec = rc; } if (qva->qva_flags & VERIFY_FILES) { - if ((rc = verifyHeader(ts, h, omitMask, ghosts)) != 0) + if ((rc = verifyHeader(ts, h, omitMask, qva->qva_fflags)) != 0) ec = rc; } if (qva->qva_flags & VERIFY_SCRIPT) { |