• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

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 }

Generated on Mon Nov 29 2010 05:18:45 for rpm by  doxygen 1.7.2