Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

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

Generated on Tue Sep 17 15:59:53 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002