- Main Page
- Related Pages
- Modules
- Data Structures
- Files

# lib/verify.c

Go to the documentation of this file.

    00001
    00006 #include "system.h"
    00007
    00008 #include <rpmio.h>
    00009 #define _RPMFI_INTERNAL
    00010 #define _RPMPS_INTERNAL /* XXX rpmps needs iterator. */
    00011 #include <rpmcli.h>
    00012
    00013 #define _RPMSQ_INTERNAL
    00014 #include "psm.h"
    00015
    00016 #include "legacy.h"     /* XXX dodigest(), uidToUname(), gnameToGid */
    00017 #include "ugid.h"
    00018 #include "debug.h"
    00019
    00020 /*@access rpmfi @*/
    00021 /*@access rpmpsm @*/    /* XXX for %verifyscript through rpmpsmStage() */
    00022 /*@access rpmProblem @*/
    00023
    00024 #define S_ISDEV(m) (S_ISBLK((m)) || S_ISCHR((m)))
    00025
    00026 /*@unchecked@*/
    00027 extern int _rpmds_unspecified_epoch_noise;
    00028
    00029 int rpmVerifyFile(const rpmts ts, const rpmfi fi,
    00030                 rpmVerifyAttrs * res, rpmVerifyAttrs omitMask)
    00031 {
    00032     unsigned short fmode = rpmfiFMode(fi);
    00033     rpmfileAttrs fileAttrs = rpmfiFFlags(fi);
    00034     rpmVerifyAttrs flags = rpmfiVFlags(fi);
    00035     const char * fn = rpmfiFN(fi);
    00036     const char * rootDir = rpmtsRootDir(ts);
    00037     struct stat sb;
    00038     int rc;
    00039
    00040     /* Prepend the path to root (if specified). */
    00041     if (rootDir && *rootDir != '\0'
    00042      && !(rootDir[0] == '/' && rootDir[1] == '\0'))
    00043     {
    00044         int nb = strlen(fn) + strlen(rootDir) + 1;
    00045         char * tb = alloca(nb);
    00046         char * t;
    00047
    00048         t = tb;
    00049         *t = '\0';
    00050         t = stpcpy(t, rootDir);
    00051         while (t > tb && t[-1] == '/') {
    00052             --t;
    00053             *t = '\0';
    00054         }
    00055         t = stpcpy(t, fn);
    00056         fn = tb;
    00057     }
    00058
    00059     *res = RPMVERIFY_NONE;
    00060
    00061     /*
    00062      * Check to see if the file was installed - if not pretend all is OK.
    00063      */
    00064     switch (rpmfiFState(fi)) {
    00065     case RPMFILE_STATE_NETSHARED:
    00066     case RPMFILE_STATE_REPLACED:
    00067     case RPMFILE_STATE_NOTINSTALLED:
    00068     case RPMFILE_STATE_WRONGCOLOR:
    00069         return 0;
    00070         /*@notreached@*/ break;
    00071     case RPMFILE_STATE_NORMAL:
    00072         break;
    00073     }
    00074
    00075     if (fn == NULL || Lstat(fn, &sb) != 0) {
    00076         *res |= RPMVERIFY_LSTATFAIL;
    00077         return 1;
    00078     }
    00079
    00080     /*
    00081      * Not all attributes of non-regular files can be verified.
    00082      */
    00083     if (S_ISDIR(sb.st_mode))
    00084         flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
    00085                         RPMVERIFY_LINKTO);
    00086     else if (S_ISLNK(sb.st_mode)) {
    00087         flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
    00088                 RPMVERIFY_MODE);
    00089 #if CHOWN_FOLLOWS_SYMLINK
    00090             flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP);
    00091 #endif
    00092     }
    00093     else if (S_ISFIFO(sb.st_mode))
    00094         flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
    00095                         RPMVERIFY_LINKTO);
    00096     else if (S_ISCHR(sb.st_mode))
    00097         flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
    00098                         RPMVERIFY_LINKTO);
    00099     else if (S_ISBLK(sb.st_mode))
    00100         flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
    00101                         RPMVERIFY_LINKTO);
    00102     else
    00103         flags &= ~(RPMVERIFY_LINKTO);
    00104
    00105     /*
    00106      * Content checks of %ghost files are meaningless.
    00107      */
    00108     if (fileAttrs & RPMFILE_GHOST)
    00109         flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
    00110                         RPMVERIFY_LINKTO);
    00111
    00112     /*
    00113      * Don't verify any features in omitMask.
    00114      */
    00115     flags &= ~(omitMask | RPMVERIFY_FAILURES);
    00116
    00117
    00118     if (flags & RPMVERIFY_FDIGEST) {
    00119         int dalgo = 0;
    00120         size_t dlen = 0;
    00121         const unsigned char * digest = rpmfiDigest(fi, &dalgo, &dlen);
    00122
    00123         if (digest == NULL)
    00124             *res |= RPMVERIFY_FDIGEST;
    00125         else {
    00126         /* XXX If --nofdigest, then prelinked library sizes fail to verify. */
    00127             unsigned char * fdigest = memset(alloca(dlen), 0, dlen);
    00128             size_t fsize;
    00129             rc = dodigest(dalgo, fn, fdigest, 0, &fsize);
    00130             sb.st_size = fsize;
    00131             if (rc)
    00132                 *res |= (RPMVERIFY_READFAIL|RPMVERIFY_FDIGEST);
    00133             else
    00134             if (memcmp(fdigest, digest, dlen))
    00135                 *res |= RPMVERIFY_FDIGEST;
    00136         }
    00137     }
    00138
    00139     if (flags & RPMVERIFY_LINKTO) {
    00140         char linkto[1024+1];
    00141         int size = 0;
    00142
    00143         if ((size = Readlink(fn, linkto, sizeof(linkto)-1)) == -1)
    00144             *res |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
    00145         else {
    00146             const char * flink = rpmfiFLink(fi);
    00147             linkto[size] = '\0';
    00148             if (flink == NULL || strcmp(linkto, flink))
    00149                 *res |= RPMVERIFY_LINKTO;
    00150         }
    00151     }
    00152
    00153     if (flags & RPMVERIFY_FILESIZE) {
    00154         if (sb.st_size != rpmfiFSize(fi))
    00155             *res |= RPMVERIFY_FILESIZE;
    00156     }
    00157
    00158     if (flags & RPMVERIFY_MODE) {
    00159         unsigned short metamode = fmode;
    00160         unsigned short filemode;
    00161
    00162         /*
    00163          * Platforms (like AIX) where sizeof(unsigned short) != sizeof(mode_t)
    00164          * need the (unsigned short) cast here.
    00165          */
    00166         filemode = (unsigned short)sb.st_mode;
    00167
    00168         /*
    00169          * Comparing the type of %ghost files is meaningless, but perms are OK.
    00170          */
    00171         if (fileAttrs & RPMFILE_GHOST) {
    00172             metamode &= ~0xf000;
    00173             filemode &= ~0xf000;
    00174         }
    00175
    00176         if (metamode != filemode)
    00177             *res |= RPMVERIFY_MODE;
    00178     }
    00179
    00180     if (flags & RPMVERIFY_RDEV) {
    00181         if (S_ISCHR(fmode) != S_ISCHR(sb.st_mode)
    00182          || S_ISBLK(fmode) != S_ISBLK(sb.st_mode))
    00183         {
    00184             *res |= RPMVERIFY_RDEV;
    00185         } else if (S_ISDEV(fmode) && S_ISDEV(sb.st_mode)) {
    00186             uint16_t st_rdev = (sb.st_rdev & 0xffff);
    00187             uint16_t frdev = (rpmfiFRdev(fi) & 0xffff);
    00188             if (st_rdev != frdev)
    00189                 *res |= RPMVERIFY_RDEV;
    00190         }
    00191     }
    00192
    00193     if (flags & RPMVERIFY_MTIME) {
    00194         if (sb.st_mtime != rpmfiFMtime(fi))
    00195             *res |= RPMVERIFY_MTIME;
    00196     }
    00197
    00198     if (flags & RPMVERIFY_USER) {
    00199         const char * name = uidToUname(sb.st_uid);
    00200         const char * fuser = rpmfiFUser(fi);
    00201         if (name == NULL || fuser == NULL || strcmp(name, fuser))
    00202             *res |= RPMVERIFY_USER;
    00203     }
    00204
    00205     if (flags & RPMVERIFY_GROUP) {
    00206         const char * name = gidToGname(sb.st_gid);
    00207         const char * fgroup = rpmfiFGroup(fi);
    00208         if (name == NULL || fgroup == NULL || strcmp(name, fgroup))
    00209             *res |= RPMVERIFY_GROUP;
    00210     }
    00211
    00212     return 0;
    00213 }
    00214
    00224 static int rpmVerifyScript(/*@unused@*/ QVA_t qva, rpmts ts,
    00225                 rpmfi fi, /*@null@*/ FD_t scriptFd)
    00226         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
    00227         /*@modifies ts, fi, scriptFd, rpmGlobalMacroContext,
    00228                 fileSystem, internalState @*/
    00229 {
    00230     rpmpsm psm = rpmpsmNew(ts, NULL, fi);
    00231     int rc = 0;
    00232
    00233     if (psm == NULL)    /* XXX can't happen */
    00234         return rc;
    00235
    00236     if (scriptFd != NULL)
    00237         rpmtsSetScriptFd(psm->ts, scriptFd);
    00238
    00239     psm->stepName = "verify";
    00240     psm->scriptTag = RPMTAG_VERIFYSCRIPT;
    00241     psm->progTag = RPMTAG_VERIFYSCRIPTPROG;
    00242     rc = rpmpsmStage(psm, PSM_SCRIPT);
    00243
    00244     psm->stepName = "sanitycheck";
    00245     psm->scriptTag = RPMTAG_SANITYCHECK;
    00246     psm->progTag = RPMTAG_SANITYCHECKPROG;
    00247     rc = rpmpsmStage(psm, PSM_SCRIPT);
    00248
    00249     if (scriptFd != NULL)
    00250         rpmtsSetScriptFd(psm->ts, NULL);
    00251
    00252     psm = rpmpsmFree(psm);
    00253
    00254     return rc;
    00255 }
    00256
    00264 static int verifyHeader(QVA_t qva, const rpmts ts, rpmfi fi)
    00265         /*@globals h_errno, fileSystem, internalState @*/
    00266         /*@modifies ts, fi, fileSystem, internalState  @*/
    00267 {
    00268     rpmVerifyAttrs verifyResult = 0;
    00269     /*@-type@*/ /* FIX: union? */
    00270     rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS);
    00271     /*@=type@*/
    00272     int ec = 0;         /* assume no problems */
    00273     char * t, * te;
    00274     char buf[BUFSIZ];
    00275     int i;
    00276
    00277     te = t = buf;
    00278     *te = '\0';
    00279
    00280     fi = rpmfiLink(fi, "verifyHeader");
    00281     fi = rpmfiInit(fi, 0);
    00282     if (fi != NULL)     /* XXX lclint */
    00283     while ((i = rpmfiNext(fi)) >= 0) {
    00284         rpmfileAttrs fflags;
    00285         int rc;
    00286
    00287         fflags = rpmfiFFlags(fi);
    00288
    00289         /* If not querying %config, skip config files. */
    00290         if ((qva->qva_fflags & RPMFILE_CONFIG) && (fflags & RPMFILE_CONFIG))
    00291             continue;
    00292
    00293         /* If not querying %doc, skip doc files. */
    00294         if ((qva->qva_fflags & RPMFILE_DOC) && (fflags & RPMFILE_DOC))
    00295             continue;
    00296
    00297         /* If not verifying %ghost, skip ghost files. */
    00298         /* XXX the broken!!! logic disables %ghost queries always. */
    00299         if (!(qva->qva_fflags & RPMFILE_GHOST) && (fflags & RPMFILE_GHOST))
    00300             continue;
    00301
    00302         rc = rpmVerifyFile(ts, fi, &verifyResult, omitMask);
    00303         if (rc) {
    00304             if (!(fflags & (RPMFILE_MISSINGOK|RPMFILE_GHOST)) || rpmIsVerbose()) {
    00305                 sprintf(te, _("missing   %c %s"),
    00306                         ((fflags & RPMFILE_CONFIG)      ? 'c' :
    00307                          (fflags & RPMFILE_DOC)         ? 'd' :
    00308                          (fflags & RPMFILE_GHOST)       ? 'g' :
    00309                          (fflags & RPMFILE_LICENSE)     ? 'l' :
    00310                          (fflags & RPMFILE_PUBKEY)      ? 'P' :
    00311                          (fflags & RPMFILE_README)      ? 'r' : ' '),
    00312                         rpmfiFN(fi));
    00313                 te += strlen(te);
    00314                 if ((verifyResult & RPMVERIFY_LSTATFAIL) != 0 && errno != ENOENT) {
    00315                     sprintf(te, " (%s)", strerror(errno));
    00316                     te += strlen(te);
    00317                 }
    00318                 ec = rc;
    00319             }
    00320         } else if (verifyResult || rpmIsVerbose()) {
    00321             const char * size, * digest, * link, * mtime, * mode;
    00322             const char * group, * user, * rdev;
    00323             /*@observer@*/ static const char *const aok = ".";
    00324             /*@observer@*/ static const char *const unknown = "?";
    00325
    00326             ec = 1;
    00327
    00328 #define _verify(_RPMVERIFY_F, _C)       \
    00329         ((verifyResult & _RPMVERIFY_F) ? _C : aok)
    00330 #define _verifylink(_RPMVERIFY_F, _C)   \
    00331         ((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \
    00332          (verifyResult & _RPMVERIFY_F) ? _C : aok)
    00333 #define _verifyfile(_RPMVERIFY_F, _C)   \
    00334         ((verifyResult & RPMVERIFY_READFAIL) ? unknown : \
    00335          (verifyResult & _RPMVERIFY_F) ? _C : aok)
    00336
    00337             digest = _verifyfile(RPMVERIFY_FDIGEST, "5");
    00338             size = _verify(RPMVERIFY_FILESIZE, "S");
    00339             link = _verifylink(RPMVERIFY_LINKTO, "L");
    00340             mtime = _verify(RPMVERIFY_MTIME, "T");
    00341             rdev = _verify(RPMVERIFY_RDEV, "D");
    00342             user = _verify(RPMVERIFY_USER, "U");
    00343             group = _verify(RPMVERIFY_GROUP, "G");
    00344             mode = _verify(RPMVERIFY_MODE, "M");
    00345
    00346 #undef _verifyfile
    00347 #undef _verifylink
    00348 #undef _verify
    00349
    00350             sprintf(te, "%s%s%s%s%s%s%s%s  %c %s",
    00351                 size, mode, digest, rdev, link, user, group, mtime,
    00352                         ((fflags & RPMFILE_CONFIG)      ? 'c' :
    00353                          (fflags & RPMFILE_DOC) ? 'd' :
    00354                          (fflags & RPMFILE_GHOST)       ? 'g' :
    00355                          (fflags & RPMFILE_LICENSE)     ? 'l' :
    00356                          (fflags & RPMFILE_PUBKEY)      ? 'P' :
    00357                          (fflags & RPMFILE_README)      ? 'r' : ' '),
    00358                         rpmfiFN(fi));
    00359             te += strlen(te);
    00360         }
    00361
    00362         if (te > t) {
    00363             *te++ = '\n';
    00364             *te = '\0';
    00365             rpmlog(RPMLOG_NOTICE, "%s", t);
    00366             te = t = buf;
    00367             *t = '\0';
    00368         }
    00369     }
    00370     fi = rpmfiUnlink(fi, "verifyHeader");
    00371
    00372     return ec;
    00373 }
    00374
    00382 static int verifyDependencies(/*@unused@*/ QVA_t qva, rpmts ts,
    00383                 Header h)
    00384         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
    00385         /*@modifies ts, h, rpmGlobalMacroContext, fileSystem, internalState @*/
    00386 {
    00387 #ifdef  NOTYET
    00388     int instance = headerGetInstance(h);
    00389 #endif
    00390     rpmps ps;
    00391     int rc = 0;         /* assume no problems */
    00392     int xx;
    00393
    00394     rpmtsEmpty(ts);
    00395 #ifdef  NOTYET
    00396     if (instance > 0)
    00397         (void) rpmtsAddEraseElement(ts, h, instance);
    00398     else
    00399 #endif
    00400         (void) rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
    00401
    00402     xx = rpmtsCheck(ts);
    00403     ps = rpmtsProblems(ts);
    00404
    00405     if (rpmpsNumProblems(ps) > 0) {
    00406         const char * altNEVR;
    00407         const char * pkgNEVR = NULL;
    00408         rpmpsi psi;
    00409         rpmProblem p;
    00410         char * t, * te;
    00411         int nb = 512;
    00412
    00413         psi = rpmpsInitIterator(ps);
    00414         while (rpmpsNextIterator(psi) >= 0) {
    00415             p = rpmpsProblem(psi);
    00416             if (pkgNEVR == NULL)
    00417                 pkgNEVR = rpmProblemGetPkgNEVR(p);
    00418
    00419             altNEVR = rpmProblemGetAltNEVR(p);
    00420             if (altNEVR[0] == 'R' && altNEVR[1] == ' ')
    00421                 nb += sizeof("\tRequires: ")-1;
    00422             if (altNEVR[0] == 'C' && altNEVR[1] == ' ')
    00423                 nb += sizeof("\tConflicts: ")-1;
    00424             nb += strlen(altNEVR+2) + sizeof("\n") - 1;
    00425
    00426         }
    00427         psi = rpmpsFreeIterator(psi);
    00428
    00429         te = t = alloca(nb);
    00430         *te = '\0';
    00431         sprintf(te, _("Unsatisfied dependencies for %s:\n"), pkgNEVR);
    00432         te += strlen(te);
    00433
    00434         psi = rpmpsInitIterator(ps);
    00435         while (rpmpsNextIterator(psi) >= 0) {
    00436             p = rpmpsProblem(psi);
    00437
    00438             altNEVR = (p->altNEVR ? p->altNEVR : "? ?altNEVR?");
    00439             if (altNEVR[0] == 'R' && altNEVR[1] == ' ')
    00440                 te = stpcpy(te, "\tRequires: ");
    00441             if (altNEVR[0] == 'C' && altNEVR[1] == ' ')
    00442                 te = stpcpy(te, "\tConflicts: ");
    00443             te = stpcpy( stpcpy(te, altNEVR+2), "\n");
    00444
    00445             rc++;
    00446         }
    00447         psi = rpmpsFreeIterator(psi);
    00448
    00449         if (te > t) {
    00450             *te++ = '\n';
    00451             *te = '\0';
    00452             rpmlog(RPMLOG_NOTICE, "%s", t);
    00453             te = t;
    00454             *t = '\0';
    00455         }
    00456     }
    00457
    00458     ps = rpmpsFree(ps);
    00459
    00460     rpmtsEmpty(ts);
    00461
    00462     return rc;
    00463 }
    00464
    00465 int showVerifyPackage(QVA_t qva, rpmts ts, Header h)
    00466 {
    00467     int scareMem = 0;
    00468     rpmfi fi = NULL;
    00469     int ec = 0;
    00470     int rc;
    00471
    00472     fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
    00473     if (fi != NULL) {
    00474         if (qva->qva_flags & VERIFY_DEPS) {
    00475             int save_noise = _rpmds_unspecified_epoch_noise;
    00476 /*@-mods@*/
    00477             if (rpmIsVerbose())
    00478                 _rpmds_unspecified_epoch_noise = 1;
    00479             if ((rc = verifyDependencies(qva, ts, h)) != 0)
    00480                 ec = rc;
    00481             _rpmds_unspecified_epoch_noise = save_noise;
    00482 /*@=mods@*/
    00483         }
    00484         if (qva->qva_flags & VERIFY_FILES) {
    00485             if ((rc = verifyHeader(qva, ts, fi)) != 0)
    00486                 ec = rc;
    00487         }
    00488         if ((qva->qva_flags & VERIFY_SCRIPT)
    00489          && (headerIsEntry(h, RPMTAG_VERIFYSCRIPT) ||
    00490              headerIsEntry(h, RPMTAG_SANITYCHECK)))
    00491         {
    00492             FD_t fdo = fdDup(STDOUT_FILENO);
    00493
    00494 /* XXX hackery to assert(!scaremem) in rpmfiNew. */
    00495 if (fi->h == NULL) fi->h = headerLink(h);
    00496             if ((rc = rpmVerifyScript(qva, ts, fi, fdo)) != 0)
    00497                 ec = rc;
    00498             if (fdo != NULL)
    00499                 rc = Fclose(fdo);
    00500 fi->h = headerFree(fi->h);
    00501         }
    00502
    00503         fi = rpmfiFree(fi);
    00504     }
    00505
    00506     return ec;
    00507 }
    00508
    00509 int rpmcliVerify(rpmts ts, QVA_t qva, const char ** argv)
    00510 {
    00511     rpmdepFlags depFlags = qva->depFlags, odepFlags;
    00512     rpmtransFlags transFlags = qva->transFlags, otransFlags;
    00513     rpmVSFlags vsflags, ovsflags;
    00514     int ec = 0;
    00515
    00516     if (qva->qva_showPackage == NULL)
    00517         qva->qva_showPackage = showVerifyPackage;
    00518
    00519     /* XXX verify flags are inverted from query. */
    00520     vsflags = rpmExpandNumeric("%{?_vsflags_verify}");
    00521     if (!(qva->qva_flags & VERIFY_DIGEST))
    00522         vsflags |= _RPMVSF_NODIGESTS;
    00523     if (!(qva->qva_flags & VERIFY_SIGNATURE))
    00524         vsflags |= _RPMVSF_NOSIGNATURES;
    00525     if (!(qva->qva_flags & VERIFY_HDRCHK))
    00526         vsflags |= RPMVSF_NOHDRCHK;
    00527     vsflags &= ~RPMVSF_NEEDPAYLOAD;
    00528
    00529     odepFlags = rpmtsSetDFlags(ts, depFlags);
    00530     otransFlags = rpmtsSetFlags(ts, transFlags);
    00531     ovsflags = rpmtsSetVSFlags(ts, vsflags);
    00532     ec = rpmcliArgIter(ts, qva, argv);
    00533     vsflags = rpmtsSetVSFlags(ts, ovsflags);
    00534     transFlags = rpmtsSetFlags(ts, otransFlags);
    00535     depFlags = rpmtsSetDFlags(ts, odepFlags);
    00536
    00537     if (qva->qva_showPackage == showVerifyPackage)
    00538         qva->qva_showPackage = NULL;
    00539
    00540     rpmtsEmpty(ts);
    00541
    00542     return ec;
    00543 }