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