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

Generated on Sun Oct 26 13:02:01 2003 for rpm by doxygen1.2.18