char * rpmVerifyString(uint32_t verifyResult, const char *pad) { char *fmt = NULL; rasprintf(&fmt, "%s%s%s%s%s%s%s%s%s", _verify(RPMVERIFY_FILESIZE, "S", pad), _verify(RPMVERIFY_MODE, "M", pad), _verifyfile(RPMVERIFY_FILEDIGEST, "5", pad), _verify(RPMVERIFY_RDEV, "D", pad), _verifylink(RPMVERIFY_LINKTO, "L", pad), _verify(RPMVERIFY_USER, "U", pad), _verify(RPMVERIFY_GROUP, "G", pad), _verify(RPMVERIFY_MTIME, "T", pad), _verify(RPMVERIFY_CAPS, "P", pad)); return fmt; }
/** \ingroup rpmcli * Verify file attributes (including file digest). * @param vf file data to verify * #param spew should verify results be printed? * @return 0 on success (or not installed), 1 on error */ static int rpmvfVerify(rpmvf vf, int spew) /*@globals h_errno, fileSystem, internalState @*/ /*@modifies vf, fileSystem, internalState @*/ { rpmVerifyAttrs res = RPMVERIFY_NONE; struct stat sb; int ec = 0; /* Check to see if the file was installed - if not pretend all is OK. */ switch (vf->fstate) { default: case RPMFILE_STATE_NETSHARED: case RPMFILE_STATE_REPLACED: case RPMFILE_STATE_NOTINSTALLED: case RPMFILE_STATE_WRONGCOLOR: goto exit; /*@notreached@*/ break; case RPMFILE_STATE_NORMAL: break; } assert(vf->fn != NULL); if (vf->fn == NULL || Lstat(vf->fn, &sb) != 0) { res |= RPMVERIFY_LSTATFAIL; ec = 1; goto exit; } /* Not all attributes of non-regular files can be verified. */ if (S_ISDIR(sb.st_mode)) vf->vflags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_LINKTO | RPMVERIFY_HMAC); else if (S_ISLNK(sb.st_mode)) { vf->vflags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_MODE | RPMVERIFY_HMAC); #if CHOWN_FOLLOWS_SYMLINK vf->vflags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP); #endif } else if (S_ISFIFO(sb.st_mode)) vf->vflags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_LINKTO | RPMVERIFY_HMAC); else if (S_ISCHR(sb.st_mode)) vf->vflags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_LINKTO | RPMVERIFY_HMAC); else if (S_ISBLK(sb.st_mode)) vf->vflags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | RPMVERIFY_LINKTO | RPMVERIFY_HMAC); else vf->vflags &= ~(RPMVERIFY_LINKTO); if (vf->vflags & (RPMVERIFY_FDIGEST | RPMVERIFY_HMAC)) { if (vf->digest == NULL || vf->dlen == 0) res |= RPMVERIFY_FDIGEST; else { /* XXX If --nofdigest, then prelinked library sizes fail to verify. */ unsigned char * fdigest = memset(alloca(vf->dlen), 0, vf->dlen); size_t fsize = 0; #define _mask (RPMVERIFY_FDIGEST|RPMVERIFY_HMAC) unsigned dflags = (vf->vflags & _mask) == RPMVERIFY_HMAC ? 0x2 : 0x0; #undef _mask int rc = dodigest(vf->dalgo, vf->fn, fdigest, dflags, &fsize); sb.st_size = fsize; if (rc) res |= (RPMVERIFY_READFAIL|RPMVERIFY_FDIGEST); else if (memcmp(fdigest, vf->digest, vf->dlen)) res |= RPMVERIFY_FDIGEST; } } if (vf->vflags & RPMVERIFY_LINKTO) { char linkto[1024+1]; int size = 0; if ((size = Readlink(vf->fn, linkto, sizeof(linkto)-1)) == -1) res |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO); else { linkto[size] = '\0'; if (vf->flink == NULL || strcmp(linkto, vf->flink)) res |= RPMVERIFY_LINKTO; } } if (vf->vflags & RPMVERIFY_FILESIZE) { if (sb.st_size != vf->sb.st_size) res |= RPMVERIFY_FILESIZE; } if (vf->vflags & RPMVERIFY_MODE) { /* XXX AIX has sizeof(mode_t) > sizeof(unsigned short) */ unsigned short metamode = (unsigned short)vf->sb.st_mode; unsigned short filemode = (unsigned short)sb.st_mode; /* Comparing type of %ghost files is meaningless, but perms are OK. */ if (vf->fflags & RPMFILE_GHOST) { metamode &= ~0xf000; filemode &= ~0xf000; } if (metamode != filemode) res |= RPMVERIFY_MODE; } if (vf->vflags & RPMVERIFY_RDEV) { if (S_ISCHR(vf->sb.st_mode) != S_ISCHR(sb.st_mode) || S_ISBLK(vf->sb.st_mode) != S_ISBLK(sb.st_mode)) res |= RPMVERIFY_RDEV; else if (S_ISDEV(vf->sb.st_mode) && S_ISDEV(sb.st_mode)) { rpmuint16_t st_rdev = (rpmuint16_t)(sb.st_rdev & 0xffff); rpmuint16_t frdev = (rpmuint16_t)(vf->sb.st_rdev & 0xffff); if (st_rdev != frdev) res |= RPMVERIFY_RDEV; } } if (vf->vflags & RPMVERIFY_MTIME) { if (sb.st_mtime != vf->sb.st_mtime) res |= RPMVERIFY_MTIME; } if (vf->vflags & RPMVERIFY_USER) { const char * fuser = uidToUname(sb.st_uid); if (fuser == NULL || vf->fuser == NULL || strcmp(fuser, vf->fuser)) res |= RPMVERIFY_USER; } if (vf->vflags & RPMVERIFY_GROUP) { const char * fgroup = gidToGname(sb.st_gid); if (fgroup == NULL || vf->fgroup == NULL || strcmp(fgroup, vf->fgroup)) res |= RPMVERIFY_GROUP; } exit: if (spew) { /* XXX no output w verify(...) probe. */ char buf[BUFSIZ]; char * t = buf; char * te = t; *te = '\0'; if (ec) { if (!(vf->fflags & (RPMFILE_MISSINGOK|RPMFILE_GHOST)) || rpmIsVerbose()) { sprintf(te, _("missing %c %s"), ((vf->fflags & RPMFILE_CONFIG) ? 'c' : (vf->fflags & RPMFILE_DOC) ? 'd' : (vf->fflags & RPMFILE_GHOST) ? 'g' : (vf->fflags & RPMFILE_LICENSE) ? 'l' : (vf->fflags & RPMFILE_PUBKEY) ? 'P' : (vf->fflags & RPMFILE_README) ? 'r' : ' '), vf->fn); if ((res & RPMVERIFY_LSTATFAIL) != 0 && errno != ENOENT) { te += strlen(te); sprintf(te, " (%s)", strerror(errno)); } } } else if (res || rpmIsVerbose()) { /*@observer@*/ static const char aok[] = "."; /*@observer@*/ static const char unknown[] = "?"; #define _verify(_RPMVERIFY_F, _C) \ ((res & _RPMVERIFY_F) ? _C : aok) #define _verifylink(_RPMVERIFY_F, _C) \ ((res & RPMVERIFY_READLINKFAIL) ? unknown : \ (res & _RPMVERIFY_F) ? _C : aok) #define _verifyfile(_RPMVERIFY_F, _C) \ ((res & RPMVERIFY_READFAIL) ? unknown : \ (res & _RPMVERIFY_F) ? _C : aok) const char * digest = _verifyfile(RPMVERIFY_FDIGEST, "5"); const char * size = _verify(RPMVERIFY_FILESIZE, "S"); const char * link = _verifylink(RPMVERIFY_LINKTO, "L"); const char * mtime = _verify(RPMVERIFY_MTIME, "T"); const char * rdev = _verify(RPMVERIFY_RDEV, "D"); const char * user = _verify(RPMVERIFY_USER, "U"); const char * group = _verify(RPMVERIFY_GROUP, "G"); const char * mode = _verify(RPMVERIFY_MODE, "M"); #undef _verifyfile #undef _verifylink #undef _verify sprintf(te, "%s%s%s%s%s%s%s%s %c %s", size, mode, digest, rdev, link, user, group, mtime, ((vf->fflags & RPMFILE_CONFIG) ? 'c' : (vf->fflags & RPMFILE_DOC) ? 'd' : (vf->fflags & RPMFILE_GHOST) ? 'g' : (vf->fflags & RPMFILE_LICENSE) ? 'l' : (vf->fflags & RPMFILE_PUBKEY) ? 'P' : (vf->fflags & RPMFILE_README) ? 'r' : ' '), vf->fn); } if (t && *t) rpmlog(RPMLOG_NOTICE, "%s\n", t); } return (res != 0); }
/** * Check file info from header against what's actually installed. * @param qva parsed query/verify options * @param ts transaction set * @param h header to verify * @return 0 no problems, 1 problems found */ static int verifyHeader(QVA_t qva, const rpmts ts, Header h) { rpmVerifyAttrs verifyResult = 0; /* FIX: union? */ rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS); int ec = 0; /* assume no problems */ char *buf = NULL; int i; rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_FLAGS_VERIFY); rpmfiInit(fi, 0); while ((i = rpmfiNext(fi)) >= 0) { rpmfileAttrs fileAttrs; int rc; fileAttrs = rpmfiFFlags(fi); /* If not verifying %ghost, skip ghost files. */ if (!(qva->qva_fflags & RPMFILE_GHOST) && (fileAttrs & RPMFILE_GHOST)) continue; rc = rpmVerifyFile(ts, fi, &verifyResult, omitMask); if (rc) { if (!(fileAttrs & (RPMFILE_MISSINGOK|RPMFILE_GHOST)) || rpmIsVerbose()) { rasprintf(&buf, _("missing %c %s"), ((fileAttrs & RPMFILE_CONFIG) ? 'c' : (fileAttrs & RPMFILE_DOC) ? 'd' : (fileAttrs & RPMFILE_GHOST) ? 'g' : (fileAttrs & RPMFILE_LICENSE) ? 'l' : (fileAttrs & RPMFILE_PUBKEY) ? 'P' : (fileAttrs & RPMFILE_README) ? 'r' : ' '), rpmfiFN(fi)); if ((verifyResult & RPMVERIFY_LSTATFAIL) != 0 && errno != ENOENT) { char *app; rasprintf(&app, " (%s)", strerror(errno)); rstrcat(&buf, app); free(app); } ec = rc; } } else if (verifyResult || rpmIsVerbose()) { const char * size, * MD5, * link, * mtime, * mode; const char * group, * user, * rdev, *caps; static const char *const aok = "."; static const char *const unknown = "?"; ec = 1; #define _verify(_RPMVERIFY_F, _C) \ ((verifyResult & _RPMVERIFY_F) ? _C : aok) #define _verifylink(_RPMVERIFY_F, _C) \ ((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \ (verifyResult & _RPMVERIFY_F) ? _C : aok) #define _verifyfile(_RPMVERIFY_F, _C) \ ((verifyResult & RPMVERIFY_READFAIL) ? unknown : \ (verifyResult & _RPMVERIFY_F) ? _C : aok) MD5 = _verifyfile(RPMVERIFY_MD5, "5"); size = _verify(RPMVERIFY_FILESIZE, "S"); link = _verifylink(RPMVERIFY_LINKTO, "L"); mtime = _verify(RPMVERIFY_MTIME, "T"); rdev = _verify(RPMVERIFY_RDEV, "D"); user = _verify(RPMVERIFY_USER, "U"); group = _verify(RPMVERIFY_GROUP, "G"); mode = _verify(RPMVERIFY_MODE, "M"); caps = _verify(RPMVERIFY_CAPS, "P"); #undef _verifyfile #undef _verifylink #undef _verify rasprintf(&buf, "%s%s%s%s%s%s%s%s%s %c %s", size, mode, MD5, rdev, link, user, group, mtime, caps, ((fileAttrs & RPMFILE_CONFIG) ? 'c' : (fileAttrs & RPMFILE_DOC) ? 'd' : (fileAttrs & RPMFILE_GHOST) ? 'g' : (fileAttrs & RPMFILE_LICENSE) ? 'l' : (fileAttrs & RPMFILE_PUBKEY) ? 'P' : (fileAttrs & RPMFILE_README) ? 'r' : ' '), rpmfiFN(fi)); } if (buf) { rpmlog(RPMLOG_NOTICE, "%s\n", buf); buf = _free(buf); } } rpmfiFree(fi); return ec; }