lib/verify.c

Go to the documentation of this file.
00001 
00006 #include "system.h"
00007 
00008 #define _RPMPS_INTERNAL /* XXX rpmps needs iterator. */
00009 #include <rpmcli.h>
00010 
00011 #include "psm.h"
00012 #include "rpmfi.h"
00013 
00014 #include "rpmts.h"
00015 
00016 #include "legacy.h"     /* XXX dodigest(), uidToUname(), gnameToGid */
00017 #include "ugid.h"
00018 #include "debug.h"
00019 
00020 /*@access rpmps @*/
00021 /*@access rpmProblem @*/
00022 /*@access rpmpsm @*/    /* XXX for %verifyscript through rpmpsmStage() */
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     case RPMFILE_STATE_WRONGCOLOR:
00071         return 0;
00072         /*@notreached@*/ break;
00073     case RPMFILE_STATE_NORMAL:
00074         break;
00075     }
00076 
00077     if (fn == NULL || Lstat(fn, &sb) != 0) {
00078         *res |= RPMVERIFY_LSTATFAIL;
00079         return 1;
00080     }
00081 
00082     /*
00083      * Not all attributes of non-regular files can be verified.
00084      */
00085     if (S_ISDIR(sb.st_mode))
00086         flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00087                         RPMVERIFY_LINKTO);
00088     else if (S_ISLNK(sb.st_mode)) {
00089         flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00090                 RPMVERIFY_MODE);
00091 #if CHOWN_FOLLOWS_SYMLINK
00092             flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP);
00093 #endif
00094     }
00095     else if (S_ISFIFO(sb.st_mode))
00096         flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00097                         RPMVERIFY_LINKTO);
00098     else if (S_ISCHR(sb.st_mode))
00099         flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00100                         RPMVERIFY_LINKTO);
00101     else if (S_ISBLK(sb.st_mode))
00102         flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00103                         RPMVERIFY_LINKTO);
00104     else
00105         flags &= ~(RPMVERIFY_LINKTO);
00106 
00107     /*
00108      * Content checks of %ghost files are meaningless.
00109      */
00110     if (fileAttrs & RPMFILE_GHOST)
00111         flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00112                         RPMVERIFY_LINKTO);
00113 
00114     /*
00115      * Don't verify any features in omitMask.
00116      */
00117     flags &= ~(omitMask | RPMVERIFY_FAILURES);
00118 
00119 /*@=branchstate@*/
00120 
00121     if (flags & RPMVERIFY_FDIGEST) {
00122         int dalgo = 0;
00123         size_t dlen = 0;
00124         const unsigned char * digest = rpmfiDigest(fi, &dalgo, &dlen);
00125 
00126         if (digest == NULL)
00127             *res |= RPMVERIFY_FDIGEST;
00128         else {
00129         /* XXX If --nofdigest, then prelinked library sizes fail to verify. */
00130             unsigned char * fdigest = memset(alloca(dlen), 0, dlen);
00131             size_t fsize;
00132             rc = dodigest(dalgo, fn, fdigest, 0, &fsize);
00133             sb.st_size = fsize;
00134             if (rc)
00135                 *res |= (RPMVERIFY_READFAIL|RPMVERIFY_FDIGEST);
00136             else
00137             if (memcmp(fdigest, digest, dlen))
00138                 *res |= RPMVERIFY_FDIGEST;
00139         }
00140     }
00141 
00142     if (flags & RPMVERIFY_LINKTO) {
00143         char linkto[1024+1];
00144         int size = 0;
00145 
00146         if ((size = Readlink(fn, linkto, sizeof(linkto)-1)) == -1)
00147             *res |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
00148         else {
00149             const char * flink = rpmfiFLink(fi);
00150             linkto[size] = '\0';
00151             if (flink == NULL || strcmp(linkto, flink))
00152                 *res |= RPMVERIFY_LINKTO;
00153         }
00154     }
00155 
00156     if (flags & RPMVERIFY_FILESIZE) {
00157         if (sb.st_size != rpmfiFSize(fi))
00158             *res |= RPMVERIFY_FILESIZE;
00159     }
00160 
00161     if (flags & RPMVERIFY_MODE) {
00162         unsigned short metamode = fmode;
00163         unsigned short filemode;
00164 
00165         /*
00166          * Platforms (like AIX) where sizeof(unsigned short) != sizeof(mode_t)
00167          * need the (unsigned short) cast here.
00168          */
00169         filemode = (unsigned short)sb.st_mode;
00170 
00171         /*
00172          * Comparing the type of %ghost files is meaningless, but perms are OK.
00173          */
00174         if (fileAttrs & RPMFILE_GHOST) {
00175             metamode &= ~0xf000;
00176             filemode &= ~0xf000;
00177         }
00178 
00179         if (metamode != filemode)
00180             *res |= RPMVERIFY_MODE;
00181     }
00182 
00183     if (flags & RPMVERIFY_RDEV) {
00184         if (S_ISCHR(fmode) != S_ISCHR(sb.st_mode)
00185          || S_ISBLK(fmode) != S_ISBLK(sb.st_mode))
00186         {
00187             *res |= RPMVERIFY_RDEV;
00188         } else if (S_ISDEV(fmode) && S_ISDEV(sb.st_mode)) {
00189             uint_16 st_rdev = (sb.st_rdev & 0xffff);
00190             uint_16 frdev = (rpmfiFRdev(fi) & 0xffff);
00191             if (st_rdev != frdev)
00192                 *res |= RPMVERIFY_RDEV;
00193         }
00194     }
00195 
00196     if (flags & RPMVERIFY_MTIME) {
00197         if (sb.st_mtime != rpmfiFMtime(fi))
00198             *res |= RPMVERIFY_MTIME;
00199     }
00200 
00201     if (flags & RPMVERIFY_USER) {
00202         const char * name = uidToUname(sb.st_uid);
00203         const char * fuser = rpmfiFUser(fi);
00204         if (name == NULL || fuser == NULL || strcmp(name, fuser))
00205             *res |= RPMVERIFY_USER;
00206     }
00207 
00208     if (flags & RPMVERIFY_GROUP) {
00209         const char * name = gidToGname(sb.st_gid);
00210         const char * fgroup = rpmfiFGroup(fi);
00211         if (name == NULL || fgroup == NULL || strcmp(name, fgroup))
00212             *res |= RPMVERIFY_GROUP;
00213     }
00214 
00215     return 0;
00216 }
00217 
00227 static int rpmVerifyScript(/*@unused@*/ QVA_t qva, rpmts ts,
00228                 rpmfi fi, /*@null@*/ FD_t scriptFd)
00229         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00230         /*@modifies ts, fi, scriptFd, rpmGlobalMacroContext,
00231                 fileSystem, internalState @*/
00232 {
00233     rpmpsm psm = rpmpsmNew(ts, NULL, fi);
00234     int rc = 0;
00235 
00236     if (psm == NULL)    /* XXX can't happen */
00237         return rc;
00238 
00239     if (scriptFd != NULL)
00240         rpmtsSetScriptFd(psm->ts, scriptFd);
00241 
00242     psm->stepName = "verify";
00243     psm->scriptTag = RPMTAG_VERIFYSCRIPT;
00244     psm->progTag = RPMTAG_VERIFYSCRIPTPROG;
00245     rc = rpmpsmStage(psm, PSM_SCRIPT);
00246 
00247     if (scriptFd != NULL)
00248         rpmtsSetScriptFd(psm->ts, NULL);
00249 
00250     psm = rpmpsmFree(psm);
00251 
00252     return rc;
00253 }
00254 
00262 static int verifyHeader(QVA_t qva, const rpmts ts, rpmfi fi)
00263         /*@globals h_errno, fileSystem, internalState @*/
00264         /*@modifies ts, fi, fileSystem, internalState  @*/
00265 {
00266     rpmVerifyAttrs verifyResult = 0;
00267     /*@-type@*/ /* FIX: union? */
00268     rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS);
00269     /*@=type@*/
00270     int ec = 0;         /* assume no problems */
00271     char * t, * te;
00272     char buf[BUFSIZ];
00273     int i;
00274 
00275     te = t = buf;
00276     *te = '\0';
00277 
00278     fi = rpmfiLink(fi, "verifyHeader");
00279     fi = rpmfiInit(fi, 0);
00280     if (fi != NULL)     /* XXX lclint */
00281     while ((i = rpmfiNext(fi)) >= 0) {
00282         rpmfileAttrs fflags;
00283         int rc;
00284 
00285         fflags = rpmfiFFlags(fi);
00286 
00287         /* If not querying %config, skip config files. */
00288         if ((qva->qva_fflags & RPMFILE_CONFIG) && (fflags & RPMFILE_CONFIG))
00289             continue;
00290 
00291         /* If not querying %doc, skip doc files. */
00292         if ((qva->qva_fflags & RPMFILE_DOC) && (fflags & RPMFILE_DOC))
00293             continue;
00294 
00295         /* If not verifying %ghost, skip ghost files. */
00296         /* XXX the broken!!! logic disables %ghost queries always. */
00297         if (!(qva->qva_fflags & RPMFILE_GHOST) && (fflags & RPMFILE_GHOST))
00298             continue;
00299 
00300 /*@-boundswrite@*/
00301         rc = rpmVerifyFile(ts, fi, &verifyResult, omitMask);
00302 /*@=boundswrite@*/
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                 ec = rc;
00315             }
00316         } else if (verifyResult || rpmIsVerbose()) {
00317             const char * size, * digest, * link, * mtime, * mode;
00318             const char * group, * user, * rdev;
00319             /*@observer@*/ static const char *const aok = ".";
00320             /*@observer@*/ static const char *const unknown = "?";
00321 
00322             ec = 1;
00323 
00324 #define _verify(_RPMVERIFY_F, _C)       \
00325         ((verifyResult & _RPMVERIFY_F) ? _C : aok)
00326 #define _verifylink(_RPMVERIFY_F, _C)   \
00327         ((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \
00328          (verifyResult & _RPMVERIFY_F) ? _C : aok)
00329 #define _verifyfile(_RPMVERIFY_F, _C)   \
00330         ((verifyResult & RPMVERIFY_READFAIL) ? unknown : \
00331          (verifyResult & _RPMVERIFY_F) ? _C : aok)
00332         
00333             digest = _verifyfile(RPMVERIFY_FDIGEST, "5");
00334             size = _verify(RPMVERIFY_FILESIZE, "S");
00335             link = _verifylink(RPMVERIFY_LINKTO, "L");
00336             mtime = _verify(RPMVERIFY_MTIME, "T");
00337             rdev = _verify(RPMVERIFY_RDEV, "D");
00338             user = _verify(RPMVERIFY_USER, "U");
00339             group = _verify(RPMVERIFY_GROUP, "G");
00340             mode = _verify(RPMVERIFY_MODE, "M");
00341 
00342 #undef _verifyfile
00343 #undef _verifylink
00344 #undef _verify
00345 
00346             sprintf(te, "%s%s%s%s%s%s%s%s %c %s",
00347                 size, mode, digest, rdev, link, user, group, mtime,
00348                         ((fflags & RPMFILE_CONFIG)      ? 'c' :
00349                          (fflags & RPMFILE_DOC) ? 'd' :
00350                          (fflags & RPMFILE_GHOST)       ? 'g' :
00351                          (fflags & RPMFILE_LICENSE)     ? 'l' :
00352                          (fflags & RPMFILE_PUBKEY)      ? 'P' :
00353                          (fflags & RPMFILE_README)      ? 'r' : ' '),
00354                         rpmfiFN(fi));
00355             te += strlen(te);
00356         }
00357 
00358 /*@-boundswrite@*/
00359         if (te > t) {
00360             *te++ = '\n';
00361             *te = '\0';
00362             rpmMessage(RPMMESS_NORMAL, "%s", t);
00363             te = t = buf;
00364             *t = '\0';
00365         }
00366 /*@=boundswrite@*/
00367     }
00368     fi = rpmfiUnlink(fi, "verifyHeader");
00369         
00370     return ec;
00371 }
00372 
00380 static int verifyDependencies(/*@unused@*/ QVA_t qva, rpmts ts,
00381                 Header h)
00382         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00383         /*@modifies ts, h, rpmGlobalMacroContext, fileSystem, internalState @*/
00384 {
00385     int instance = headerGetInstance(h);
00386     rpmps ps;
00387     int numProblems;
00388     int rc = 0;         /* assume no problems */
00389     int xx;
00390     int i;
00391 
00392     rpmtsEmpty(ts);
00393 #ifdef  NOTYET
00394     if (instance > 0)
00395         (void) rpmtsAddEraseElement(ts, h, instance);
00396     else
00397 #endif
00398         (void) rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
00399 
00400     xx = rpmtsCheck(ts);
00401     ps = rpmtsProblems(ts);
00402 
00403     numProblems = rpmpsNumProblems(ps);
00404     /*@-branchstate@*/
00405     if (ps != NULL && numProblems > 0) {
00406         const char * pkgNEVR, * altNEVR;
00407         rpmProblem p;
00408         char * t, * te;
00409         int nb = 512;
00410 
00411         for (i = 0; i < numProblems; i++) {
00412             p = ps->probs + i;
00413             altNEVR = (p->altNEVR ? p->altNEVR : "? ?altNEVR?");
00414             if (altNEVR[0] == 'R' && altNEVR[1] == ' ')
00415                 nb += sizeof("\tRequires: ")-1;
00416             if (altNEVR[0] == 'C' && altNEVR[1] == ' ')
00417                 nb += sizeof("\tConflicts: ")-1;
00418             nb += strlen(altNEVR+2) + sizeof("\n") - 1;
00419         }
00420         te = t = alloca(nb);
00421 /*@-boundswrite@*/
00422         *te = '\0';
00423         pkgNEVR = (ps->probs->pkgNEVR ? ps->probs->pkgNEVR : "?pkgNEVR?");
00424         sprintf(te, _("Unsatisfied dependencies for %s:\n"), pkgNEVR);
00425         te += strlen(te);
00426         for (i = 0; i < numProblems; i++) {
00427             p = ps->probs + i;
00428             altNEVR = (p->altNEVR ? p->altNEVR : "? ?altNEVR?");
00429             if (altNEVR[0] == 'R' && altNEVR[1] == ' ')
00430                 te = stpcpy(te, "\tRequires: ");
00431             if (altNEVR[0] == 'C' && altNEVR[1] == ' ')
00432                 te = stpcpy(te, "\tConflicts: ");
00433             te = stpcpy( stpcpy(te, altNEVR+2), "\n");
00434         }
00435 
00436         if (te > t) {
00437             *te++ = '\n';
00438             *te = '\0';
00439             rpmMessage(RPMMESS_NORMAL, "%s", t);
00440             te = t;
00441             *t = '\0';
00442         }
00443 /*@=boundswrite@*/
00444         rc = 1;
00445     }
00446     /*@=branchstate@*/
00447 
00448     ps = rpmpsFree(ps);
00449 
00450     rpmtsEmpty(ts);
00451 
00452     return rc;
00453 }
00454 
00455 int showVerifyPackage(QVA_t qva, rpmts ts, Header h)
00456 {
00457 /*
00458  * XXX Sick hackery to work around qva being clobbered on CentOS3
00459  * XXX using gcc-3.2.3-49.x86_64.
00460  */
00461 #if defined(__x86_64__)
00462 static QVA_t Qva;
00463 #endif
00464     int scareMem = 1;   /* XXX rpmpsmStage needs fi->h */
00465     rpmfi fi = NULL;
00466     int ec = 0;
00467     int rc;
00468 
00469 #if defined(__x86_64__)
00470 fi = rpmfiFree(fi);     /* XXX do something to confuse the optimizer. */
00471 Qva = qva;
00472 #endif
00473     fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
00474     if (fi != NULL) {
00475 
00476 #if defined(__x86_64__)
00477 qva = Qva;
00478 #endif
00479         if (qva->qva_flags & VERIFY_DEPS) {
00480             int save_noise = _rpmds_unspecified_epoch_noise;
00481 /*@-mods@*/
00482             if (rpmIsVerbose())
00483                 _rpmds_unspecified_epoch_noise = 1;
00484             if ((rc = verifyDependencies(qva, ts, h)) != 0)
00485                 ec = rc;
00486             _rpmds_unspecified_epoch_noise = save_noise;
00487 /*@=mods@*/
00488         }
00489         if (qva->qva_flags & VERIFY_FILES) {
00490             if ((rc = verifyHeader(qva, ts, fi)) != 0)
00491                 ec = rc;
00492         }
00493         if ((qva->qva_flags & VERIFY_SCRIPT)
00494          && headerIsEntry(h, RPMTAG_VERIFYSCRIPT))
00495         {
00496             FD_t fdo = fdDup(STDOUT_FILENO);
00497             if ((rc = rpmVerifyScript(qva, ts, fi, fdo)) != 0)
00498                 ec = rc;
00499             if (fdo != NULL)
00500                 rc = Fclose(fdo);
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 Aug 3 15:18:59 2009 for rpm by  doxygen 1.5.1