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 "psm.h"
00009 #include "rpmcli.h"
00010 
00011 #include "ugid.h"
00012 #include "misc.h"       /* XXX for uidToUname() and gnameToGid() */
00013 #include "debug.h"
00014 
00015 /*@access TFI_t*/
00016 /*@access PSM_t*/
00017 /*@access FD_t*/        /* XXX compared with NULL */
00018 /*@access rpmdb*/       /* XXX compared with NULL */
00019 
00020 #define S_ISDEV(m) (S_ISBLK((m)) || S_ISCHR((m)))
00021 
00022 int rpmVerifyFile(const char * root, Header h, int filenum,
00023                 rpmVerifyAttrs * result, rpmVerifyAttrs omitMask)
00024 {
00025     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00026     HFD_t hfd = headerFreeData;
00027     int_32 * fileFlags;
00028     rpmfileAttrs fileAttrs = RPMFILE_NONE;
00029     int_32 * verifyFlags;
00030     rpmVerifyAttrs flags = RPMVERIFY_ALL;
00031     unsigned short * modeList;
00032     const char * fileStatesList;
00033     const char * filespec = NULL;
00034     int count;
00035     int rc;
00036     struct stat sb;
00037 
00038     rc = hge(h, RPMTAG_FILEMODES, NULL, (void **) &modeList, &count);
00039     if (hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlags, NULL))
00040         fileAttrs = fileFlags[filenum];
00041 
00042     if (hge(h, RPMTAG_FILEVERIFYFLAGS, NULL, (void **) &verifyFlags, NULL))
00043         flags = verifyFlags[filenum];
00044 
00045     {
00046         const char ** baseNames;
00047         const char ** dirNames;
00048         int_32 * dirIndexes;
00049         rpmTagType bnt, dnt;
00050 
00051         if (hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, NULL)
00052         &&  hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL)
00053         &&  hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL))
00054         {
00055             int nb = (strlen(dirNames[dirIndexes[filenum]]) + 
00056                       strlen(baseNames[filenum]) + strlen(root) + 5);
00057             char * t = alloca(nb);
00058             filespec = t;
00059             *t = '\0';
00060             if (root && !(root[0] == '/' && root[1] == '\0')) {
00061                 t = stpcpy(t, root);
00062                 while (t > filespec && t[-1] == '/') {
00063                     --t;
00064                     *t = '\0';
00065                 }
00066             }
00067             t = stpcpy(t, dirNames[dirIndexes[filenum]]);
00068             t = stpcpy(t, baseNames[filenum]);
00069         }
00070         baseNames = hfd(baseNames, bnt);
00071         dirNames = hfd(dirNames, dnt);
00072     }
00073 
00074     *result = RPMVERIFY_NONE;
00075 
00076     /*
00077      * Check to see if the file was installed - if not pretend all is OK.
00078      */
00079     if (hge(h, RPMTAG_FILESTATES, NULL, (void **) &fileStatesList, NULL) &&
00080         fileStatesList != NULL)
00081     {
00082         rpmfileState fstate = fileStatesList[filenum];
00083         switch (fstate) {
00084         case RPMFILE_STATE_NETSHARED:
00085         case RPMFILE_STATE_REPLACED:
00086         case RPMFILE_STATE_NOTINSTALLED:
00087             return 0;
00088             /*@notreached@*/ break;
00089         case RPMFILE_STATE_NORMAL:
00090             break;
00091         }
00092     }
00093 
00094     if (filespec == NULL) {
00095         *result |= RPMVERIFY_LSTATFAIL;
00096         return 1;
00097     }
00098 
00099     if (Lstat(filespec, &sb) != 0) {
00100         *result |= RPMVERIFY_LSTATFAIL;
00101         return 1;
00102     }
00103 
00104     /*
00105      * Not all attributes of non-regular files can be verified.
00106      */
00107     if (S_ISDIR(sb.st_mode))
00108         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00109                         RPMVERIFY_LINKTO);
00110     else if (S_ISLNK(sb.st_mode)) {
00111         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00112                 RPMVERIFY_MODE);
00113 #if CHOWN_FOLLOWS_SYMLINK
00114             flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP);
00115 #endif
00116     }
00117     else if (S_ISFIFO(sb.st_mode))
00118         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00119                         RPMVERIFY_LINKTO);
00120     else if (S_ISCHR(sb.st_mode))
00121         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00122                         RPMVERIFY_LINKTO);
00123     else if (S_ISBLK(sb.st_mode))
00124         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00125                         RPMVERIFY_LINKTO);
00126     else 
00127         flags &= ~(RPMVERIFY_LINKTO);
00128 
00129     /*
00130      * Content checks of %ghost files are meaningless.
00131      */
00132     if (fileAttrs & RPMFILE_GHOST)
00133         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00134                         RPMVERIFY_LINKTO);
00135 
00136     /*
00137      * Don't verify any features in omitMask.
00138      */
00139     flags &= ~(omitMask | RPMVERIFY_LSTATFAIL|RPMVERIFY_READFAIL|RPMVERIFY_READLINKFAIL);
00140 
00141     if (flags & RPMVERIFY_MD5) {
00142         unsigned char md5sum[40];
00143         const char ** md5List;
00144         rpmTagType mdt;
00145 
00146         if (!hge(h, RPMTAG_FILEMD5S, &mdt, (void **) &md5List, NULL))
00147             *result |= RPMVERIFY_MD5;
00148         else {
00149             rc = domd5(filespec, md5sum, 1);
00150             if (rc)
00151                 *result |= (RPMVERIFY_READFAIL|RPMVERIFY_MD5);
00152             else if (strcmp(md5sum, md5List[filenum]))
00153                 *result |= RPMVERIFY_MD5;
00154         }
00155         md5List = hfd(md5List, mdt);
00156     } 
00157 
00158     if (flags & RPMVERIFY_LINKTO) {
00159         char linkto[1024];
00160         int size = 0;
00161         const char ** linktoList;
00162         rpmTagType ltt;
00163 
00164         if (!hge(h, RPMTAG_FILELINKTOS, &ltt, (void **) &linktoList, NULL)
00165         || (size = Readlink(filespec, linkto, sizeof(linkto)-1)) == -1)
00166             *result |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
00167         else {
00168             linkto[size] = '\0';
00169             if (strcmp(linkto, linktoList[filenum]))
00170                 *result |= RPMVERIFY_LINKTO;
00171         }
00172         linktoList = hfd(linktoList, ltt);
00173     } 
00174 
00175     if (flags & RPMVERIFY_FILESIZE) {
00176         int_32 * sizeList;
00177 
00178         if (!hge(h, RPMTAG_FILESIZES, NULL, (void **) &sizeList, NULL)
00179         || sizeList[filenum] != sb.st_size)
00180             *result |= RPMVERIFY_FILESIZE;
00181     } 
00182 
00183     if (flags & RPMVERIFY_MODE) {
00184         unsigned short metamode = modeList[filenum];
00185         unsigned short filemode;
00186 
00187         /*
00188          * Platforms (like AIX) where sizeof(unsigned short) != sizeof(mode_t)
00189          * need the (unsigned short) cast here. 
00190          */
00191         filemode = (unsigned short)sb.st_mode;
00192 
00193         /*
00194          * Comparing the type of %ghost files is meaningless, but perms are OK.
00195          */
00196         if (fileAttrs & RPMFILE_GHOST) {
00197             metamode &= ~0xf000;
00198             filemode &= ~0xf000;
00199         }
00200 
00201         if (metamode != filemode)
00202             *result |= RPMVERIFY_MODE;
00203     }
00204 
00205     if (flags & RPMVERIFY_RDEV) {
00206         if (S_ISCHR(modeList[filenum]) != S_ISCHR(sb.st_mode) ||
00207             S_ISBLK(modeList[filenum]) != S_ISBLK(sb.st_mode))
00208         {
00209             *result |= RPMVERIFY_RDEV;
00210         } else if (S_ISDEV(modeList[filenum]) && S_ISDEV(sb.st_mode)) {
00211             unsigned short * rdevList;
00212             if (!hge(h, RPMTAG_FILERDEVS, NULL, (void **) &rdevList, NULL)
00213             || rdevList[filenum] != sb.st_rdev)
00214                 *result |= RPMVERIFY_RDEV;
00215         } 
00216     }
00217 
00218     if (flags & RPMVERIFY_MTIME) {
00219         int_32 * mtimeList;
00220 
00221         if (!hge(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtimeList, NULL)
00222         ||  mtimeList[filenum] != sb.st_mtime)
00223             *result |= RPMVERIFY_MTIME;
00224     }
00225 
00226     if (flags & RPMVERIFY_USER) {
00227         const char * name;
00228         const char ** unameList;
00229         int_32 * uidList;
00230         rpmTagType unt;
00231 
00232         if (hge(h, RPMTAG_FILEUSERNAME, &unt, (void **) &unameList, NULL)) {
00233             name = uidToUname(sb.st_uid);
00234             if (!name || strcmp(unameList[filenum], name))
00235                 *result |= RPMVERIFY_USER;
00236             unameList = hfd(unameList, unt);
00237         } else if (hge(h, RPMTAG_FILEUIDS, NULL, (void **) &uidList, NULL)) {
00238             if (uidList[filenum] != sb.st_uid)
00239                 *result |= RPMVERIFY_GROUP;
00240         } else {
00241             rpmError(RPMERR_INTERNAL, _("package lacks both user name and id "
00242                   "lists (this should never happen)\n"));
00243             *result |= RPMVERIFY_GROUP;
00244         }
00245     }
00246 
00247     if (flags & RPMVERIFY_GROUP) {
00248         const char ** gnameList;
00249         int_32 * gidList;
00250         rpmTagType gnt;
00251         gid_t gid;
00252 
00253         if (hge(h, RPMTAG_FILEGROUPNAME, &gnt, (void **) &gnameList, NULL)) {
00254             rc = gnameToGid(gnameList[filenum], &gid);
00255             if (rc || (gid != sb.st_gid))
00256                 *result |= RPMVERIFY_GROUP;
00257             gnameList = hfd(gnameList, gnt);
00258         } else if (hge(h, RPMTAG_FILEGIDS, NULL, (void **) &gidList, NULL)) {
00259             if (gidList[filenum] != sb.st_gid)
00260                 *result |= RPMVERIFY_GROUP;
00261         } else {
00262             rpmError(RPMERR_INTERNAL, _("package lacks both group name and id "
00263                      "lists (this should never happen)\n"));
00264             *result |= RPMVERIFY_GROUP;
00265         }
00266     }
00267 
00268     return 0;
00269 }
00270 
00279 int rpmVerifyScript(const char * rootDir, Header h, /*@null@*/ FD_t scriptFd)
00280 {
00281     rpmdb rpmdb = NULL;
00282     rpmTransactionSet ts = rpmtransCreateSet(rpmdb, rootDir);
00283     TFI_t fi = xcalloc(1, sizeof(*fi));
00284     struct psm_s psmbuf;
00285     PSM_t psm = &psmbuf;
00286     int rc;
00287 
00288     if (scriptFd != NULL)
00289         ts->scriptFd = fdLink(scriptFd, "rpmVerifyScript");
00290     fi->magic = TFIMAGIC;
00291     loadFi(h, fi);
00292     memset(psm, 0, sizeof(*psm));
00293     psm->ts = ts;
00294     psm->fi = fi;
00295     psm->stepName = "verify";
00296     psm->scriptTag = RPMTAG_VERIFYSCRIPT;
00297     psm->progTag = RPMTAG_VERIFYSCRIPTPROG;
00298     rc = psmStage(psm, PSM_SCRIPT);
00299     freeFi(fi);
00300     fi = _free(fi);
00301     ts = rpmtransFree(ts);
00302     return rc;
00303 }
00304 
00305 int rpmVerifyDigest(Header h)
00306 {
00307     HGE_t hge = (HGE_t)headerGetEntry;  /* XXX headerGetEntryMinMemory? */
00308     HFD_t hfd = headerFreeData;
00309     void * uh = NULL;
00310     rpmTagType uht;
00311     int_32 uhc;
00312     const char * hdigest;
00313     rpmTagType hdt;
00314     int ec = 0;         /* assume no problems */
00315 
00316     /* Retrieve header digest. */
00317     if (!hge(h, RPMTAG_SHA1RHN, &hdt, (void **) &hdigest, NULL))
00318             return 0;
00319 
00320     /* Regenerate original header. */
00321     if (!hge(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc))
00322         return 0;
00323 
00324     if (hdigest == NULL || uh == NULL)
00325         return 0;
00326 
00327     /* Compute header digest. */
00328     {   DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00329         const char * digest;
00330         size_t digestlen;
00331 
00332         (void) rpmDigestUpdate(ctx, uh, uhc);
00333         (void) rpmDigestFinal(ctx, (void **)&digest, &digestlen, 1);
00334 
00335         /* XXX can't happen: report NULL malloc return as a digest failure. */
00336         ec = (digest == NULL || strcmp(hdigest, digest)) ? 1 : 0;
00337         digest = _free(digest);
00338     }
00339 
00340     uh = hfd(uh, uht);
00341     hdigest = hfd(hdigest, hdt);
00342 
00343     return ec;
00344 }
00345 
00352 static int verifyHeader(QVA_t qva, Header h)
00353         /*@modifies h @*/
00354 {
00355     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00356     char buf[BUFSIZ];
00357     char * t, * te;
00358     const char * prefix = (qva->qva_prefix ? qva->qva_prefix : "");
00359     const char ** fileNames = NULL;
00360     int count;
00361     int_32 * fileFlags = NULL;
00362     rpmVerifyAttrs verifyResult = 0;
00363     rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS);
00364     int ec = 0;         /* assume no problems */
00365     int i;
00366 
00367     te = t = buf;
00368     *te = '\0';
00369 
00370     if (!hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlags, NULL))
00371         goto exit;
00372 
00373     if (!headerIsEntry(h, RPMTAG_BASENAMES))
00374         goto exit;
00375 
00376     rpmBuildFileList(h, &fileNames, &count);
00377 
00378     for (i = 0; i < count; i++) {
00379         rpmfileAttrs fileAttrs;
00380         int rc;
00381 
00382         fileAttrs = fileFlags[i];
00383 
00384         /* If not verifying %ghost, skip ghost files. */
00385         if (!(qva->qva_fflags & RPMFILE_GHOST)
00386         && (fileAttrs & RPMFILE_GHOST))
00387             continue;
00388 
00389         rc = rpmVerifyFile(prefix, h, i, &verifyResult, omitMask);
00390         if (rc) {
00391             /*@-internalglobs@*/ /* FIX: shrug */
00392             if (!(fileAttrs & RPMFILE_MISSINGOK) || rpmIsVerbose()) {
00393                 sprintf(te, _("missing    %s"), fileNames[i]);
00394                 te += strlen(te);
00395                 ec = rc;
00396             }
00397             /*@=internalglobs@*/
00398         } else if (verifyResult) {
00399             const char * size, * md5, * link, * mtime, * mode;
00400             const char * group, * user, * rdev;
00401             /*@observer@*/ static const char *const aok = ".";
00402             /*@observer@*/ static const char *const unknown = "?";
00403 
00404             ec = 1;
00405 
00406 #define _verify(_RPMVERIFY_F, _C)       \
00407         ((verifyResult & _RPMVERIFY_F) ? _C : aok)
00408 #define _verifylink(_RPMVERIFY_F, _C)   \
00409         ((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \
00410          (verifyResult & _RPMVERIFY_F) ? _C : aok)
00411 #define _verifyfile(_RPMVERIFY_F, _C)   \
00412         ((verifyResult & RPMVERIFY_READFAIL) ? unknown : \
00413          (verifyResult & _RPMVERIFY_F) ? _C : aok)
00414         
00415             md5 = _verifyfile(RPMVERIFY_MD5, "5");
00416             size = _verify(RPMVERIFY_FILESIZE, "S");
00417             link = _verifylink(RPMVERIFY_LINKTO, "L");
00418             mtime = _verify(RPMVERIFY_MTIME, "T");
00419             rdev = _verify(RPMVERIFY_RDEV, "D");
00420             user = _verify(RPMVERIFY_USER, "U");
00421             group = _verify(RPMVERIFY_GROUP, "G");
00422             mode = _verify(RPMVERIFY_MODE, "M");
00423 
00424 #undef _verify
00425 #undef _verifylink
00426 #undef _verifyfile
00427 
00428             sprintf(te, "%s%s%s%s%s%s%s%s %c %s",
00429                         size, mode, md5, rdev, link, user, group, mtime, 
00430                         ((fileAttrs & RPMFILE_CONFIG)   ? 'c' :
00431                          (fileAttrs & RPMFILE_DOC)      ? 'd' :
00432                          (fileAttrs & RPMFILE_GHOST)    ? 'g' :
00433                          (fileAttrs & RPMFILE_LICENSE)  ? 'l' :
00434                          (fileAttrs & RPMFILE_README)   ? 'r' : ' '), 
00435                         fileNames[i]);
00436             te += strlen(te);
00437         }
00438 
00439         if (te > t) {
00440             *te++ = '\n';
00441             *te = '\0';
00442             rpmMessage(RPMMESS_NORMAL, "%s", t);
00443             te = t = buf;
00444             *t = '\0';
00445         }
00446     }
00447         
00448 exit:
00449     fileNames = _free(fileNames);
00450     return ec;
00451 }
00452 
00459 static int verifyDependencies(rpmdb rpmdb, Header h)
00460         /*@modifies h @*/
00461 {
00462     rpmTransactionSet ts;
00463     rpmDependencyConflict conflicts;
00464     int numConflicts;
00465     int rc = 0;         /* assume no problems */
00466     int i;
00467 
00468     ts = rpmtransCreateSet(rpmdb, NULL);
00469     (void) rpmtransAddPackage(ts, h, NULL, NULL, 0, NULL);
00470 
00471     (void) rpmdepCheck(ts, &conflicts, &numConflicts);
00472     ts = rpmtransFree(ts);
00473 
00474     /*@-branchstate@*/
00475     if (numConflicts) {
00476         const char *n, *v, *r;
00477         char * t, * te;
00478         int nb = 512;
00479         (void) headerNVR(h, &n, &v, &r);
00480 
00481         for (i = 0; i < numConflicts; i++) {
00482             nb += strlen(conflicts[i].needsName) + sizeof(", ") - 1;
00483             if (conflicts[i].needsFlags)
00484                 nb += strlen(conflicts[i].needsVersion) + 5;
00485         }
00486         te = t = alloca(nb);
00487         *te = '\0';
00488         sprintf(te, _("Unsatisfied dependencies for %s-%s-%s: "), n, v, r);
00489         te += strlen(te);
00490         for (i = 0; i < numConflicts; i++) {
00491             if (i) te = stpcpy(te, ", ");
00492             te = stpcpy(te, conflicts[i].needsName);
00493             if (conflicts[i].needsFlags) {
00494                 int flags = conflicts[i].needsFlags;
00495                 *te++ = ' ';
00496                 if (flags & RPMSENSE_LESS)      *te++ = '<';
00497                 if (flags & RPMSENSE_GREATER)   *te++ = '>';
00498                 if (flags & RPMSENSE_EQUAL)     *te++ = '=';
00499                 *te++ = ' ';
00500                 te = stpcpy(te, conflicts[i].needsVersion);
00501             }
00502         }
00503         conflicts = rpmdepFreeConflicts(conflicts, numConflicts);
00504         if (te > t) {
00505             *te++ = '\n';
00506             *te = '\0';
00507             rpmMessage(RPMMESS_NORMAL, "%s", t);
00508             te = t;
00509             *t = '\0';
00510         }
00511         rc = 1;
00512     }
00513     /*@=branchstate@*/
00514     return rc;
00515 }
00516 
00517 int showVerifyPackage(QVA_t qva, rpmdb rpmdb, Header h)
00518 {
00519     const char * prefix = (qva->qva_prefix ? qva->qva_prefix : "");
00520     int ec = 0;
00521     int rc;
00522 
00523     if (qva->qva_flags & VERIFY_DIGEST) {
00524         if ((rc = rpmVerifyDigest(h)) != 0) {
00525             const char *n, *v, *r;
00526             (void) headerNVR(h, &n, &v, &r);
00527             rpmMessage(RPMMESS_NORMAL,
00528                    _("%s-%s-%s: immutable header region digest check failed\n"),
00529                         n, v, r);
00530             ec = rc;
00531         }
00532     }
00533     if (qva->qva_flags & VERIFY_DEPS) {
00534         if ((rc = verifyDependencies(rpmdb, h)) != 0)
00535             ec = rc;
00536     }
00537     if (qva->qva_flags & VERIFY_FILES) {
00538         if ((rc = verifyHeader(qva, h)) != 0)
00539             ec = rc;
00540     }
00541     if (qva->qva_flags & VERIFY_SCRIPT) {
00542         FD_t fdo = fdDup(STDOUT_FILENO);
00543         if ((rc = rpmVerifyScript(prefix, h, fdo)) != 0)
00544             ec = rc;
00545         if (fdo)
00546             rc = Fclose(fdo);
00547     }
00548     return ec;
00549 }
00550 
00551 int rpmVerify(QVA_t qva, rpmQVSources source, const char * arg)
00552 {
00553     rpmdb rpmdb = NULL;
00554     int rc;
00555 
00556     switch (source) {
00557     case RPMQV_RPM:
00558         if (!(qva->qva_flags & VERIFY_DEPS))
00559             break;
00560         /*@fallthrough@*/
00561     default:
00562         if ((rc = rpmdbOpen(qva->qva_prefix, &rpmdb, O_RDONLY, 0644)) != 0)
00563             return 1;
00564         break;
00565     }
00566 
00567     rc = rpmQueryVerify(qva, source, arg, rpmdb, showVerifyPackage);
00568 
00569     if (rpmdb != NULL)
00570         (void) rpmdbClose(rpmdb);
00571 
00572     return rc;
00573 }

Generated on Sun Feb 2 23:32:03 2003 for rpm by doxygen1.2.18