lib/verify.c

Go to the documentation of this file.
00001 
00006 #include "system.h"
00007 
00008 #include <rpmcli.h>
00009 
00010 #include "psm.h"
00011 #include "rpmfi.h"
00012 #include "rpmts.h"
00013 
00014 #include "legacy.h"     /* XXX domd5(), uidToUname(), gnameToGid */
00015 #include "ugid.h"
00016 #include "debug.h"
00017 
00018 /*@access rpmps @*/
00019 /*@access rpmProblem @*/
00020 /*@access rpmpsm @*/    /* XXX for %verifyscript through rpmpsmStage() */
00021 
00022 #define S_ISDEV(m) (S_ISBLK((m)) || S_ISCHR((m)))
00023 
00024 /*@unchecked@*/
00025 extern int _rpmds_unspecified_epoch_noise;
00026 extern int _cacheDependsRC;
00027 
00028 int rpmVerifyFile(const rpmts ts, const rpmfi fi,
00029                 rpmVerifyAttrs * res, rpmVerifyAttrs omitMask)
00030 {
00031     unsigned short fmode = rpmfiFMode(fi);
00032     rpmfileAttrs fileAttrs = rpmfiFFlags(fi);
00033     rpmVerifyAttrs flags = rpmfiVFlags(fi);
00034     const char * fn = rpmfiFN(fi);
00035     int selinuxEnabled = rpmtsSELinuxEnabled(ts);
00036     struct stat sb;
00037     int rc;
00038 
00039     *res = RPMVERIFY_NONE;
00040 
00041     /*
00042      * Check to see if the file was installed - if not pretend all is OK.
00043      */
00044     switch (rpmfiFState(fi)) {
00045     case RPMFILE_STATE_NETSHARED:
00046     case RPMFILE_STATE_REPLACED:
00047     case RPMFILE_STATE_NOTINSTALLED:
00048     case RPMFILE_STATE_WRONGCOLOR:
00049         return 0;
00050         /*@notreached@*/ break;
00051     case RPMFILE_STATE_NORMAL:
00052         break;
00053     }
00054 
00055     if (fn == NULL || Lstat(fn, &sb) != 0) {
00056         *res |= RPMVERIFY_LSTATFAIL;
00057         return 1;
00058     }
00059 
00060     /*
00061      * Not all attributes of non-regular files can be verified.
00062      */
00063     if (S_ISDIR(sb.st_mode))
00064         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00065                         RPMVERIFY_LINKTO);
00066     else if (S_ISLNK(sb.st_mode)) {
00067         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00068                 RPMVERIFY_MODE);
00069 #if CHOWN_FOLLOWS_SYMLINK
00070             flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP);
00071 #endif
00072     }
00073     else if (S_ISFIFO(sb.st_mode))
00074         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00075                         RPMVERIFY_LINKTO);
00076     else if (S_ISCHR(sb.st_mode))
00077         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00078                         RPMVERIFY_LINKTO);
00079     else if (S_ISBLK(sb.st_mode))
00080         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00081                         RPMVERIFY_LINKTO);
00082     else 
00083         flags &= ~(RPMVERIFY_LINKTO);
00084 
00085     /*
00086      * Content checks of %ghost files are meaningless.
00087      */
00088     if (fileAttrs & RPMFILE_GHOST)
00089         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00090                         RPMVERIFY_LINKTO);
00091 
00092     /*
00093      * Don't verify any features in omitMask.
00094      */
00095     flags &= ~(omitMask | RPMVERIFY_FAILURES);
00096 
00097 /*@=branchstate@*/
00098 
00099     if (flags & RPMVERIFY_MD5) {
00100         unsigned char md5sum[16];
00101         size_t fsize;
00102 
00103         /* XXX If --nomd5, then prelinked library sizes are not corrected. */
00104         rc = domd5(fn, md5sum, 0, &fsize);
00105         sb.st_size = fsize;
00106         if (rc)
00107             *res |= (RPMVERIFY_READFAIL|RPMVERIFY_MD5);
00108         else {
00109             const unsigned char * MD5 = rpmfiMD5(fi);
00110             if (MD5 == NULL || memcmp(md5sum, MD5, sizeof(md5sum)))
00111                 *res |= RPMVERIFY_MD5;
00112         }
00113     } 
00114 
00115     if (flags & RPMVERIFY_LINKTO) {
00116         char linkto[1024+1];
00117         int size = 0;
00118 
00119         if ((size = Readlink(fn, linkto, sizeof(linkto)-1)) == -1)
00120             *res |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
00121         else {
00122             const char * flink = rpmfiFLink(fi);
00123             linkto[size] = '\0';
00124             if (flink == NULL || strcmp(linkto, flink))
00125                 *res |= RPMVERIFY_LINKTO;
00126         }
00127     } 
00128 
00129     if (flags & RPMVERIFY_FILESIZE) {
00130         if (sb.st_size != rpmfiFSize(fi))
00131             *res |= RPMVERIFY_FILESIZE;
00132     } 
00133 
00134     if (flags & RPMVERIFY_MODE) {
00135         unsigned short metamode = fmode;
00136         unsigned short filemode;
00137 
00138         /*
00139          * Platforms (like AIX) where sizeof(unsigned short) != sizeof(mode_t)
00140          * need the (unsigned short) cast here. 
00141          */
00142         filemode = (unsigned short)sb.st_mode;
00143 
00144         /*
00145          * Comparing the type of %ghost files is meaningless, but perms are OK.
00146          */
00147         if (fileAttrs & RPMFILE_GHOST) {
00148             metamode &= ~0xf000;
00149             filemode &= ~0xf000;
00150         }
00151 
00152         if (metamode != filemode)
00153             *res |= RPMVERIFY_MODE;
00154     }
00155 
00156     if (flags & RPMVERIFY_RDEV) {
00157         if (S_ISCHR(fmode) != S_ISCHR(sb.st_mode)
00158          || S_ISBLK(fmode) != S_ISBLK(sb.st_mode))
00159         {
00160             *res |= RPMVERIFY_RDEV;
00161         } else if (S_ISDEV(fmode) && S_ISDEV(sb.st_mode)) {
00162             uint_16 st_rdev = (sb.st_rdev & 0xffff);
00163             uint_16 frdev = (rpmfiFRdev(fi) & 0xffff);
00164             if (st_rdev != frdev)
00165                 *res |= RPMVERIFY_RDEV;
00166         } 
00167     }
00168 
00169     if ((flags & RPMVERIFY_MTIME) && (sb.st_mtime != rpmfiFMtime(fi))) {
00170         /* Filter out timestamp differences of shared files */
00171         rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, fn, 0);
00172         if (rpmdbGetIteratorCount(mi) < 2) 
00173             *res |= RPMVERIFY_MTIME;
00174         rpmdbFreeIterator(mi);
00175     }
00176 
00177     if (flags & RPMVERIFY_USER) {
00178         const char * name = uidToUname(sb.st_uid);
00179         const char * fuser = rpmfiFUser(fi);
00180         if (name == NULL || fuser == NULL || strcmp(name, fuser))
00181             *res |= RPMVERIFY_USER;
00182     }
00183 
00184     if (flags & RPMVERIFY_GROUP) {
00185         const char * name = gidToGname(sb.st_gid);
00186         const char * fgroup = rpmfiFGroup(fi);
00187         if (name == NULL || fgroup == NULL || strcmp(name, fgroup))
00188             *res |= RPMVERIFY_GROUP;
00189     }
00190 
00191     return 0;
00192 }
00193 
00203 static int rpmVerifyScript(/*@unused@*/ QVA_t qva, rpmts ts,
00204                 rpmfi fi, /*@null@*/ FD_t scriptFd)
00205         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00206         /*@modifies ts, fi, scriptFd, rpmGlobalMacroContext,
00207                 fileSystem, internalState @*/
00208 {
00209     rpmpsm psm = rpmpsmNew(ts, NULL, fi);
00210     int rc = 0;
00211 
00212     if (psm == NULL)    /* XXX can't happen */
00213         return rc;
00214 
00215     if (scriptFd != NULL)
00216         rpmtsSetScriptFd(psm->ts, scriptFd);
00217 
00218     psm->stepName = "verify";
00219     psm->scriptTag = RPMTAG_VERIFYSCRIPT;
00220     psm->progTag = RPMTAG_VERIFYSCRIPTPROG;
00221     rc = rpmpsmStage(psm, PSM_SCRIPT);
00222 
00223     if (scriptFd != NULL)
00224         rpmtsSetScriptFd(psm->ts, NULL);
00225 
00226     psm = rpmpsmFree(psm);
00227 
00228     return rc;
00229 }
00230 
00238 static int verifyHeader(QVA_t qva, const rpmts ts, rpmfi fi)
00239         /*@globals h_errno, fileSystem, internalState @*/
00240         /*@modifies ts, fi, fileSystem, internalState  @*/
00241 {
00242     int selinuxEnabled = rpmtsSELinuxEnabled(ts);
00243     rpmVerifyAttrs verifyResult = 0;
00244     /*@-type@*/ /* FIX: union? */
00245     rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS);
00246     /*@=type@*/
00247     int ec = 0;         /* assume no problems */
00248     char * t, * te;
00249     char buf[BUFSIZ];
00250     int i;
00251 
00252     te = t = buf;
00253     *te = '\0';
00254 
00255     fi = rpmfiLink(fi, "verifyHeader");
00256     fi = rpmfiInit(fi, 0);
00257     if (fi != NULL)     /* XXX lclint */
00258     while ((i = rpmfiNext(fi)) >= 0) {
00259         rpmfileAttrs fileAttrs;
00260         int rc;
00261 
00262         fileAttrs = rpmfiFFlags(fi);
00263 
00264         /* If not verifying %ghost, skip ghost files. */
00265         if (!(qva->qva_fflags & RPMFILE_GHOST)
00266         && (fileAttrs & RPMFILE_GHOST))
00267             continue;
00268 
00269 /*@-boundswrite@*/
00270         rc = rpmVerifyFile(ts, fi, &verifyResult, omitMask);
00271 /*@=boundswrite@*/
00272         if (rc) {
00273             if (!(fileAttrs & (RPMFILE_MISSINGOK|RPMFILE_GHOST)) || rpmIsVerbose()) {
00274                 sprintf(te, _("missing   %c %s"),
00275                         ((fileAttrs & RPMFILE_CONFIG)   ? 'c' :
00276                          (fileAttrs & RPMFILE_DOC)      ? 'd' :
00277                          (fileAttrs & RPMFILE_GHOST)    ? 'g' :
00278                          (fileAttrs & RPMFILE_LICENSE)  ? 'l' :
00279                          (fileAttrs & RPMFILE_PUBKEY)   ? 'P' :
00280                          (fileAttrs & RPMFILE_README)   ? 'r' : ' '), 
00281                         rpmfiFN(fi));
00282                 te += strlen(te);
00283                 if ((verifyResult & RPMVERIFY_LSTATFAIL) != 0 &&
00284                     errno != ENOENT) {
00285                     sprintf(te, " (%s)", strerror(errno));
00286                     te += strlen(te);
00287                 }
00288                 ec = rc;
00289             }
00290         } else if (verifyResult || rpmIsVerbose()) {
00291             const char * size, * MD5, * link, * mtime, * mode;
00292             const char * group, * user, * rdev;
00293             /*@observer@*/ static const char *const aok = ".";
00294             /*@observer@*/ static const char *const unknown = "?";
00295 
00296             ec = 1;
00297 
00298 #define _verify(_RPMVERIFY_F, _C)       \
00299         ((verifyResult & _RPMVERIFY_F) ? _C : aok)
00300 #define _verifylink(_RPMVERIFY_F, _C)   \
00301         ((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \
00302          (verifyResult & _RPMVERIFY_F) ? _C : aok)
00303 #define _verifyfile(_RPMVERIFY_F, _C)   \
00304         ((verifyResult & RPMVERIFY_READFAIL) ? unknown : \
00305          (verifyResult & _RPMVERIFY_F) ? _C : aok)
00306         
00307             MD5 = _verifyfile(RPMVERIFY_MD5, "5");
00308             size = _verify(RPMVERIFY_FILESIZE, "S");
00309             link = _verifylink(RPMVERIFY_LINKTO, "L");
00310             mtime = _verify(RPMVERIFY_MTIME, "T");
00311             rdev = _verify(RPMVERIFY_RDEV, "D");
00312             user = _verify(RPMVERIFY_USER, "U");
00313             group = _verify(RPMVERIFY_GROUP, "G");
00314             mode = _verify(RPMVERIFY_MODE, "M");
00315 
00316 #undef _verifyfile
00317 #undef _verifylink
00318 #undef _verify
00319 
00320             sprintf(te, "%s%s%s%s%s%s%s%s  %c %s",
00321                         size, mode, MD5, rdev, link, user, group, mtime,
00322                         ((fileAttrs & RPMFILE_CONFIG)   ? 'c' :
00323                          (fileAttrs & RPMFILE_DOC)      ? 'd' :
00324                          (fileAttrs & RPMFILE_GHOST)    ? 'g' :
00325                          (fileAttrs & RPMFILE_LICENSE)  ? 'l' :
00326                          (fileAttrs & RPMFILE_PUBKEY)   ? 'P' :
00327                          (fileAttrs & RPMFILE_README)   ? 'r' : ' '), 
00328                         rpmfiFN(fi));
00329             te += strlen(te);
00330         }
00331 
00332 /*@-boundswrite@*/
00333         if (te > t) {
00334             *te++ = '\n';
00335             *te = '\0';
00336             rpmMessage(RPMMESS_NORMAL, "%s", t);
00337             te = t = buf;
00338             *t = '\0';
00339         }
00340 /*@=boundswrite@*/
00341     }
00342     fi = rpmfiUnlink(fi, "verifyHeader");
00343         
00344     return ec;
00345 }
00346 
00354 static int verifyDependencies(/*@unused@*/ QVA_t qva, rpmts ts,
00355                 Header h)
00356         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00357         /*@modifies ts, h, rpmGlobalMacroContext, fileSystem, internalState @*/
00358 {
00359     rpmps ps;
00360     int numProblems;
00361     int rc = 0;         /* assume no problems */
00362     int xx;
00363     int i;
00364 
00365     rpmtsEmpty(ts);
00366     (void) rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
00367 
00368     xx = rpmtsCheck(ts);
00369     ps = rpmtsProblems(ts);
00370 
00371     numProblems = rpmpsNumProblems(ps);
00372     /*@-branchstate@*/
00373     if (ps != NULL && numProblems > 0) {
00374         const char * pkgNEVR, * altNEVR;
00375         rpmProblem p;
00376         char * t, * te;
00377         int nb = 512;
00378 
00379         for (i = 0; i < numProblems; i++) {
00380             p = ps->probs + i;
00381             altNEVR = (p->altNEVR ? p->altNEVR : "? ?altNEVR?");
00382             nb += strlen(altNEVR+2) + sizeof(", ") - 1;
00383         }
00384         te = t = alloca(nb);
00385 /*@-boundswrite@*/
00386         *te = '\0';
00387         pkgNEVR = (ps->probs->pkgNEVR ? ps->probs->pkgNEVR : "?pkgNEVR?");
00388         sprintf(te, _("Unsatisfied dependencies for %s: "), pkgNEVR);
00389         te += strlen(te);
00390         for (i = 0; i < numProblems; i++) {
00391             p = ps->probs + i;
00392             altNEVR = (p->altNEVR ? p->altNEVR : "? ?altNEVR?");
00393             if (i) te = stpcpy(te, ", ");
00394             /* XXX FIXME: should probably supply the "[R|C] " type prefix */
00395             te = stpcpy(te, altNEVR+2);
00396         }
00397 
00398         if (te > t) {
00399             *te++ = '\n';
00400             *te = '\0';
00401             rpmMessage(RPMMESS_NORMAL, "%s", t);
00402             te = t;
00403             *t = '\0';
00404         }
00405 /*@=boundswrite@*/
00406         rc = 1;
00407     }
00408     /*@=branchstate@*/
00409 
00410     ps = rpmpsFree(ps);
00411 
00412     rpmtsEmpty(ts);
00413 
00414     return rc;
00415 }
00416 
00417 int showVerifyPackage(QVA_t qva, rpmts ts, Header h)
00418 {
00419     int scareMem = 1;   /* XXX only rpmVerifyScript needs now */
00420     rpmfi fi;
00421     int ec = 0;
00422     int rc;
00423 
00424     fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
00425     if (fi != NULL) {
00426 
00427         if (qva->qva_flags & VERIFY_DEPS) {
00428             int save_noise = _rpmds_unspecified_epoch_noise;
00429 /*@-mods@*/
00430             if (rpmIsVerbose())
00431                 _rpmds_unspecified_epoch_noise = 1;
00432             if ((rc = verifyDependencies(qva, ts, h)) != 0)
00433                 ec = rc;
00434             _rpmds_unspecified_epoch_noise = save_noise;
00435 /*@=mods@*/
00436         }
00437         if (qva->qva_flags & VERIFY_FILES) {
00438             if ((rc = verifyHeader(qva, ts, fi)) != 0)
00439                 ec = rc;
00440         }
00441         if ((qva->qva_flags & VERIFY_SCRIPT)
00442          && headerIsEntry(h, RPMTAG_VERIFYSCRIPT))
00443         {
00444             FD_t fdo = fdDup(STDOUT_FILENO);
00445             if ((rc = rpmVerifyScript(qva, ts, fi, fdo)) != 0)
00446                 ec = rc;
00447             if (fdo != NULL)
00448                 rc = Fclose(fdo);
00449         }
00450 
00451         fi = rpmfiFree(fi);
00452     }
00453 
00454     return ec;
00455 }
00456 
00457 int rpmcliVerify(rpmts ts, QVA_t qva, const char ** argv)
00458 {
00459     const char * arg;
00460     rpmVSFlags vsflags, ovsflags;
00461     int ec = 0, xx;
00462     const char * rootDir = rpmtsRootDir(ts);
00463     int cachingDeps = _cacheDependsRC;
00464 
00465     /* 
00466      * Open the DB + indices explicitly before possible chroot,
00467      * otherwises BDB is going to be unhappy...
00468      */
00469     rpmtsOpenDB(ts, O_RDONLY);
00470     rpmdbOpenAll(rpmtsGetRdb(ts));
00471     if (rootDir && strcmp(rootDir, "/") != 0) {
00472         if (chroot(rootDir) == -1) {
00473             rpmlog(RPMLOG_ERR, _("Unable to change root directory: %m\n"));
00474             ec = 1;
00475             goto exit;
00476         } else {
00477             rpmtsSetChrootDone(ts, 1);
00478             /* XXX temporary db path is wrong when chrooted, disable caching */
00479             _cacheDependsRC = 0;
00480         }
00481     }
00482 
00483     if (qva->qva_showPackage == NULL)
00484         qva->qva_showPackage = showVerifyPackage;
00485 
00486     /* XXX verify flags are inverted from query. */
00487     vsflags = rpmExpandNumeric("%{?_vsflags_verify}");
00488     if (!(qva->qva_flags & VERIFY_DIGEST))
00489         vsflags |= _RPMVSF_NODIGESTS;
00490     if (!(qva->qva_flags & VERIFY_SIGNATURE))
00491         vsflags |= _RPMVSF_NOSIGNATURES;
00492     if (!(qva->qva_flags & VERIFY_HDRCHK))
00493         vsflags |= RPMVSF_NOHDRCHK;
00494     vsflags &= ~RPMVSF_NEEDPAYLOAD;
00495 
00496     ovsflags = rpmtsSetVSFlags(ts, vsflags);
00497     ec = rpmcliArgIter(ts, qva, argv);
00498     vsflags = rpmtsSetVSFlags(ts, ovsflags);
00499 
00500     if (qva->qva_showPackage == showVerifyPackage)
00501         qva->qva_showPackage = NULL;
00502 
00503     rpmtsEmpty(ts);
00504 
00505     if (rpmtsChrootDone(ts)) {
00506         /* only done if previous chroot succeeded, assume success */
00507         xx = chroot(".");
00508         rpmtsSetChrootDone(ts, 0);
00509     }
00510 exit:
00511     _cacheDependsRC = cachingDeps;
00512 
00513     return ec;
00514 }

Generated on Tue Jan 15 14:32:09 2013 for rpm by  doxygen 1.4.7