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

Generated on Fri Oct 12 08:44:54 2007 for rpm by  doxygen 1.5.2