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 }