Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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     flags |= RPMVERIFY_CONTEXTS;        /* no disable from package. */
00082 
00083     /*
00084      * Not all attributes of non-regular files can be verified.
00085      */
00086     if (S_ISDIR(sb.st_mode))
00087         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00088                         RPMVERIFY_LINKTO);
00089     else if (S_ISLNK(sb.st_mode)) {
00090         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00091                 RPMVERIFY_MODE);
00092 #if CHOWN_FOLLOWS_SYMLINK
00093             flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP);
00094 #endif
00095     }
00096     else if (S_ISFIFO(sb.st_mode))
00097         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00098                         RPMVERIFY_LINKTO);
00099     else if (S_ISCHR(sb.st_mode))
00100         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00101                         RPMVERIFY_LINKTO);
00102     else if (S_ISBLK(sb.st_mode))
00103         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00104                         RPMVERIFY_LINKTO);
00105     else 
00106         flags &= ~(RPMVERIFY_LINKTO);
00107 
00108     /*
00109      * Content checks of %ghost files are meaningless.
00110      */
00111     if (fileAttrs & RPMFILE_GHOST)
00112         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00113                         RPMVERIFY_LINKTO);
00114 
00115     /*
00116      * Don't verify any features in omitMask.
00117      */
00118     flags &= ~(omitMask | RPMVERIFY_FAILURES);
00119 
00120     /*
00121      * Verify file security context.
00122      */
00123 /*@-branchstate@*/
00124     if (selinuxEnabled == 1 && (flags & RPMVERIFY_CONTEXTS)) {
00125         security_context_t con;
00126 
00127         rc = lgetfilecon(fn, &con);
00128         if (rc == -1)
00129             *res |= (RPMVERIFY_LGETFILECONFAIL|RPMVERIFY_CONTEXTS);
00130         else {
00131             rpmsx sx = rpmtsREContext(ts);
00132             const char * fcontext;
00133 
00134             if (sx != NULL) {
00135                 /* Get file security context from patterns. */
00136                 fcontext = rpmsxFContext(sx, fn, fmode);
00137                 sx = rpmsxFree(sx);
00138             } else {
00139                 /* Get file security context from package. */
00140                 fcontext = rpmfiFContext(fi);
00141             }
00142             if (fcontext == NULL || strcmp(fcontext, con))
00143                 *res |= RPMVERIFY_CONTEXTS;
00144             freecon(con);
00145         }
00146     }
00147 /*@=branchstate@*/
00148 
00149     if (flags & RPMVERIFY_MD5) {
00150         unsigned char md5sum[16];
00151         size_t fsize;
00152 
00153         /* XXX If --nomd5, then prelinked library sizes are not corrected. */
00154         rc = domd5(fn, md5sum, 0, &fsize);
00155         sb.st_size = fsize;
00156         if (rc)
00157             *res |= (RPMVERIFY_READFAIL|RPMVERIFY_MD5);
00158         else {
00159             const unsigned char * MD5 = rpmfiMD5(fi);
00160             if (MD5 == NULL || memcmp(md5sum, MD5, sizeof(md5sum)))
00161                 *res |= RPMVERIFY_MD5;
00162         }
00163     } 
00164 
00165     if (flags & RPMVERIFY_LINKTO) {
00166         char linkto[1024+1];
00167         int size = 0;
00168 
00169         if ((size = Readlink(fn, linkto, sizeof(linkto)-1)) == -1)
00170             *res |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
00171         else {
00172             const char * flink = rpmfiFLink(fi);
00173             linkto[size] = '\0';
00174             if (flink == NULL || strcmp(linkto, flink))
00175                 *res |= RPMVERIFY_LINKTO;
00176         }
00177     } 
00178 
00179     if (flags & RPMVERIFY_FILESIZE) {
00180         if (sb.st_size != rpmfiFSize(fi))
00181             *res |= RPMVERIFY_FILESIZE;
00182     } 
00183 
00184     if (flags & RPMVERIFY_MODE) {
00185         unsigned short metamode = fmode;
00186         unsigned short filemode;
00187 
00188         /*
00189          * Platforms (like AIX) where sizeof(unsigned short) != sizeof(mode_t)
00190          * need the (unsigned short) cast here. 
00191          */
00192         filemode = (unsigned short)sb.st_mode;
00193 
00194         /*
00195          * Comparing the type of %ghost files is meaningless, but perms are OK.
00196          */
00197         if (fileAttrs & RPMFILE_GHOST) {
00198             metamode &= ~0xf000;
00199             filemode &= ~0xf000;
00200         }
00201 
00202         if (metamode != filemode)
00203             *res |= RPMVERIFY_MODE;
00204     }
00205 
00206     if (flags & RPMVERIFY_RDEV) {
00207         if (S_ISCHR(fmode) != S_ISCHR(sb.st_mode)
00208          || S_ISBLK(fmode) != S_ISBLK(sb.st_mode))
00209         {
00210             *res |= RPMVERIFY_RDEV;
00211         } else if (S_ISDEV(fmode) && S_ISDEV(sb.st_mode)) {
00212             uint_16 st_rdev = (sb.st_rdev & 0xffff);
00213             uint_16 frdev = (rpmfiFRdev(fi) & 0xffff);
00214             if (st_rdev != frdev)
00215                 *res |= RPMVERIFY_RDEV;
00216         } 
00217     }
00218 
00219     if (flags & RPMVERIFY_MTIME) {
00220         if (sb.st_mtime != rpmfiFMtime(fi))
00221             *res |= RPMVERIFY_MTIME;
00222     }
00223 
00224     if (flags & RPMVERIFY_USER) {
00225         const char * name = uidToUname(sb.st_uid);
00226         const char * fuser = rpmfiFUser(fi);
00227         if (name == NULL || fuser == NULL || strcmp(name, fuser))
00228             *res |= RPMVERIFY_USER;
00229     }
00230 
00231     if (flags & RPMVERIFY_GROUP) {
00232         const char * name = gidToGname(sb.st_gid);
00233         const char * fgroup = rpmfiFGroup(fi);
00234         if (name == NULL || fgroup == NULL || strcmp(name, fgroup))
00235             *res |= RPMVERIFY_GROUP;
00236     }
00237 
00238     return 0;
00239 }
00240 
00250 static int rpmVerifyScript(/*@unused@*/ QVA_t qva, rpmts ts,
00251                 rpmfi fi, /*@null@*/ FD_t scriptFd)
00252         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00253         /*@modifies ts, fi, scriptFd, rpmGlobalMacroContext,
00254                 fileSystem, internalState @*/
00255 {
00256     rpmpsm psm = rpmpsmNew(ts, NULL, fi);
00257     int rc = 0;
00258 
00259     if (psm == NULL)    /* XXX can't happen */
00260         return rc;
00261 
00262     if (scriptFd != NULL)
00263         rpmtsSetScriptFd(psm->ts, scriptFd);
00264 
00265     psm->stepName = "verify";
00266     psm->scriptTag = RPMTAG_VERIFYSCRIPT;
00267     psm->progTag = RPMTAG_VERIFYSCRIPTPROG;
00268     rc = rpmpsmStage(psm, PSM_SCRIPT);
00269 
00270     if (scriptFd != NULL)
00271         rpmtsSetScriptFd(psm->ts, NULL);
00272 
00273     psm = rpmpsmFree(psm);
00274 
00275     return rc;
00276 }
00277 
00285 static int verifyHeader(QVA_t qva, const rpmts ts, rpmfi fi)
00286         /*@globals h_errno, fileSystem, internalState @*/
00287         /*@modifies ts, fi, fileSystem, internalState  @*/
00288 {
00289     int selinuxEnabled = rpmtsSELinuxEnabled(ts);
00290     rpmVerifyAttrs verifyResult = 0;
00291     /*@-type@*/ /* FIX: union? */
00292     rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS);
00293     /*@=type@*/
00294     int ec = 0;         /* assume no problems */
00295     char * t, * te;
00296     char buf[BUFSIZ];
00297     int i;
00298 
00299     te = t = buf;
00300     *te = '\0';
00301 
00302     fi = rpmfiLink(fi, "verifyHeader");
00303     fi = rpmfiInit(fi, 0);
00304     if (fi != NULL)     /* XXX lclint */
00305     while ((i = rpmfiNext(fi)) >= 0) {
00306         rpmfileAttrs fileAttrs;
00307         int rc;
00308 
00309         fileAttrs = rpmfiFFlags(fi);
00310 
00311         /* If not verifying %ghost, skip ghost files. */
00312         if (!(qva->qva_fflags & RPMFILE_GHOST)
00313         && (fileAttrs & RPMFILE_GHOST))
00314             continue;
00315 
00316 /*@-boundswrite@*/
00317         rc = rpmVerifyFile(ts, fi, &verifyResult, omitMask);
00318 /*@=boundswrite@*/
00319         if (rc) {
00320             if (!(fileAttrs & (RPMFILE_MISSINGOK|RPMFILE_GHOST)) || rpmIsVerbose()) {
00321                 sprintf(te, _("missing   %c %s"),
00322                         ((fileAttrs & RPMFILE_CONFIG)   ? 'c' :
00323                          (fileAttrs & RPMFILE_DOC)      ? 'd' :
00324                          (fileAttrs & RPMFILE_GHOST)    ? 'g' :
00325                          (fileAttrs & RPMFILE_LICENSE)  ? 'l' :
00326                          (fileAttrs & RPMFILE_PUBKEY)   ? 'P' :
00327                          (fileAttrs & RPMFILE_README)   ? 'r' : ' '), 
00328                         rpmfiFN(fi));
00329                 te += strlen(te);
00330                 ec = rc;
00331             }
00332         } else if (verifyResult || rpmIsVerbose()) {
00333             const char * size, * MD5, * link, * mtime, * mode;
00334             const char * group, * user, * rdev, *ctxt;
00335             /*@observer@*/ static const char *const aok = ".";
00336             /*@observer@*/ static const char *const unknown = "?";
00337             /*@observer@*/ static const char *const ctxt_ignore = " ";
00338 
00339             ec = 1;
00340 
00341 #define _verify(_RPMVERIFY_F, _C)       \
00342         ((verifyResult & _RPMVERIFY_F) ? _C : aok)
00343 #define _verifylink(_RPMVERIFY_F, _C)   \
00344         ((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \
00345          (verifyResult & _RPMVERIFY_F) ? _C : aok)
00346 #define _verifyfile(_RPMVERIFY_F, _C)   \
00347         ((verifyResult & RPMVERIFY_READFAIL) ? unknown : \
00348          (verifyResult & _RPMVERIFY_F) ? _C : aok)
00349 #define _verifyctxt(_RPMVERIFY_F, _C)   \
00350         ((selinuxEnabled != 1 ? ctxt_ignore : \
00351          (verifyResult & RPMVERIFY_LGETFILECONFAIL) ? unknown : \
00352          (verifyResult & _RPMVERIFY_F) ? _C : aok))
00353         
00354             MD5 = _verifyfile(RPMVERIFY_MD5, "5");
00355             size = _verify(RPMVERIFY_FILESIZE, "S");
00356             link = _verifylink(RPMVERIFY_LINKTO, "L");
00357             mtime = _verify(RPMVERIFY_MTIME, "T");
00358             rdev = _verify(RPMVERIFY_RDEV, "D");
00359             user = _verify(RPMVERIFY_USER, "U");
00360             group = _verify(RPMVERIFY_GROUP, "G");
00361             mode = _verify(RPMVERIFY_MODE, "M");
00362             ctxt = _verifyctxt(RPMVERIFY_CONTEXTS, "C");
00363 
00364 #undef _verifyctxt
00365 #undef _verifyfile
00366 #undef _verifylink
00367 #undef _verify
00368 
00369             sprintf(te, "%s%s%s%s%s%s%s%s%s %c %s",
00370                         size, mode, MD5, rdev, link, user, group, mtime, ctxt,
00371                         ((fileAttrs & RPMFILE_CONFIG)   ? 'c' :
00372                          (fileAttrs & RPMFILE_DOC)      ? 'd' :
00373                          (fileAttrs & RPMFILE_GHOST)    ? 'g' :
00374                          (fileAttrs & RPMFILE_LICENSE)  ? 'l' :
00375                          (fileAttrs & RPMFILE_PUBKEY)   ? 'P' :
00376                          (fileAttrs & RPMFILE_README)   ? 'r' : ' '), 
00377                         rpmfiFN(fi));
00378             te += strlen(te);
00379         }
00380 
00381 /*@-boundswrite@*/
00382         if (te > t) {
00383             *te++ = '\n';
00384             *te = '\0';
00385             rpmMessage(RPMMESS_NORMAL, "%s", t);
00386             te = t = buf;
00387             *t = '\0';
00388         }
00389 /*@=boundswrite@*/
00390     }
00391     fi = rpmfiUnlink(fi, "verifyHeader");
00392         
00393     return ec;
00394 }
00395 
00403 static int verifyDependencies(/*@unused@*/ QVA_t qva, rpmts ts,
00404                 Header h)
00405         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00406         /*@modifies ts, h, rpmGlobalMacroContext, fileSystem, internalState @*/
00407 {
00408     rpmps ps;
00409     int numProblems;
00410     int rc = 0;         /* assume no problems */
00411     int xx;
00412     int i;
00413 
00414     rpmtsEmpty(ts);
00415     (void) rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
00416 
00417     xx = rpmtsCheck(ts);
00418     ps = rpmtsProblems(ts);
00419 
00420     numProblems = rpmpsNumProblems(ps);
00421     /*@-branchstate@*/
00422     if (ps != NULL && numProblems > 0) {
00423         const char * pkgNEVR, * altNEVR;
00424         rpmProblem p;
00425         char * t, * te;
00426         int nb = 512;
00427 
00428         for (i = 0; i < numProblems; i++) {
00429             p = ps->probs + i;
00430             altNEVR = (p->altNEVR ? p->altNEVR : "? ?altNEVR?");
00431             nb += strlen(altNEVR+2) + sizeof(", ") - 1;
00432         }
00433         te = t = alloca(nb);
00434 /*@-boundswrite@*/
00435         *te = '\0';
00436         pkgNEVR = (ps->probs->pkgNEVR ? ps->probs->pkgNEVR : "?pkgNEVR?");
00437         sprintf(te, _("Unsatisfied dependencies for %s: "), pkgNEVR);
00438         te += strlen(te);
00439         for (i = 0; i < numProblems; i++) {
00440             p = ps->probs + i;
00441             altNEVR = (p->altNEVR ? p->altNEVR : "? ?altNEVR?");
00442             if (i) te = stpcpy(te, ", ");
00443             /* XXX FIXME: should probably supply the "[R|C] " type prefix */
00444             te = stpcpy(te, altNEVR+2);
00445         }
00446 
00447         if (te > t) {
00448             *te++ = '\n';
00449             *te = '\0';
00450             rpmMessage(RPMMESS_NORMAL, "%s", t);
00451             te = t;
00452             *t = '\0';
00453         }
00454 /*@=boundswrite@*/
00455         rc = 1;
00456     }
00457     /*@=branchstate@*/
00458 
00459     ps = rpmpsFree(ps);
00460 
00461     rpmtsEmpty(ts);
00462 
00463     return rc;
00464 }
00465 
00466 int showVerifyPackage(QVA_t qva, rpmts ts, Header h)
00467 {
00468     int scareMem = 1;   /* XXX only rpmVerifyScript needs now */
00469     rpmfi fi;
00470     int ec = 0;
00471     int rc;
00472 
00473     fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
00474     if (fi != NULL) {
00475 
00476         if (qva->qva_flags & VERIFY_DEPS) {
00477             int save_noise = _rpmds_unspecified_epoch_noise;
00478 /*@-mods@*/
00479             if (rpmIsVerbose())
00480                 _rpmds_unspecified_epoch_noise = 1;
00481             if ((rc = verifyDependencies(qva, ts, h)) != 0)
00482                 ec = rc;
00483             _rpmds_unspecified_epoch_noise = save_noise;
00484 /*@=mods@*/
00485         }
00486         if (qva->qva_flags & VERIFY_FILES) {
00487             if ((rc = verifyHeader(qva, ts, fi)) != 0)
00488                 ec = rc;
00489         }
00490         if ((qva->qva_flags & VERIFY_SCRIPT)
00491          && headerIsEntry(h, RPMTAG_VERIFYSCRIPT))
00492         {
00493             FD_t fdo = fdDup(STDOUT_FILENO);
00494             if ((rc = rpmVerifyScript(qva, ts, fi, fdo)) != 0)
00495                 ec = rc;
00496             if (fdo != NULL)
00497                 rc = Fclose(fdo);
00498         }
00499 
00500         fi = rpmfiFree(fi);
00501     }
00502 
00503     return ec;
00504 }
00505 
00506 int rpmcliVerify(rpmts ts, QVA_t qva, const char ** argv)
00507 {
00508     const char * arg;
00509     rpmVSFlags vsflags, ovsflags;
00510     int ec = 0;
00511 
00512     if (qva->qva_showPackage == NULL)
00513         qva->qva_showPackage = showVerifyPackage;
00514 
00515     /* XXX verify flags are inverted from query. */
00516     vsflags = rpmExpandNumeric("%{?_vsflags_verify}");
00517     if (!(qva->qva_flags & VERIFY_DIGEST))
00518         vsflags |= _RPMVSF_NODIGESTS;
00519     if (!(qva->qva_flags & VERIFY_SIGNATURE))
00520         vsflags |= _RPMVSF_NOSIGNATURES;
00521     if (!(qva->qva_flags & VERIFY_HDRCHK))
00522         vsflags |= RPMVSF_NOHDRCHK;
00523     vsflags &= ~RPMVSF_NEEDPAYLOAD;
00524 
00525     /* Initialize security context patterns (if not already done). */
00526     if (qva->qva_flags & VERIFY_CONTEXTS) {
00527         rpmsx sx = rpmtsREContext(ts);
00528         if (sx == NULL) {
00529             arg = rpmGetPath("%{?_verify_file_context_path}", NULL);
00530             if (arg != NULL && *arg != '\0') {
00531                 sx = rpmsxNew(arg);
00532                 (void) rpmtsSetREContext(ts, sx);
00533             }
00534             arg = _free(arg);
00535         }
00536         sx = rpmsxFree(sx);
00537     }
00538 
00539     ovsflags = rpmtsSetVSFlags(ts, vsflags);
00540     if (qva->qva_source == RPMQV_ALL) {
00541         /*@-nullpass@*/ /* FIX: argv can be NULL, cast to pass argv array */
00542         ec = rpmQueryVerify(qva, ts, (const char *) argv);
00543         /*@=nullpass@*/
00544     } else {
00545 /*@-boundsread@*/
00546         if (argv != NULL)
00547         while ((arg = *argv++) != NULL) {
00548             ec += rpmQueryVerify(qva, ts, arg);
00549             rpmtsEmpty(ts);
00550         }
00551 /*@=boundsread@*/
00552     }
00553     vsflags = rpmtsSetVSFlags(ts, ovsflags);
00554 
00555     if (qva->qva_showPackage == showVerifyPackage)
00556         qva->qva_showPackage = NULL;
00557 
00558     rpmtsEmpty(ts);
00559 
00560     return ec;
00561 }

Generated on Fri May 22 11:59:47 2009 for rpm by  doxygen 1.3.9.1