Main Page   Modules   Compound List   File List   Compound Members   File Members   Related Pages  

lib/verify.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include <rpmlib.h>
00008 #include <rpmbuild.h>
00009 #include <rpmurl.h>
00010 
00011 #include "depends.h"
00012 #include "install.h"
00013 #include "md5.h"
00014 #include "misc.h"
00015 #include "debug.h"
00016 
00017 static int _ie = 0x44332211;
00018 static union _vendian { int i; char b[4]; } *_endian = (union _vendian *)&_ie;
00019 #define IS_BIG_ENDIAN()         (_endian->b[0] == '\x44')
00020 #define IS_LITTLE_ENDIAN()      (_endian->b[0] == '\x11')
00021 
00022 #define S_ISDEV(m) (S_ISBLK((m)) || S_ISCHR((m)))
00023 
00024 #define POPT_NODEPS     1000
00025 #define POPT_NOFILES    1001
00026 #define POPT_NOMD5      1002
00027 #define POPT_NOSCRIPTS  1003
00028 
00029 /* ========== Verify specific popt args */
00030 static void verifyArgCallback(/*@unused@*/poptContext con,
00031         /*@unused@*/enum poptCallbackReason reason,
00032         const struct poptOption * opt, /*@unused@*/const char * arg,
00033         const void * data)
00034 {
00035     QVA_t *qva = &rpmQVArgs;
00036     switch (opt->val) {
00037     case POPT_NODEPS: qva->qva_flags |= VERIFY_DEPS; break;
00038     case POPT_NOFILES: qva->qva_flags |= VERIFY_FILES; break;
00039     case POPT_NOMD5: qva->qva_flags |= VERIFY_MD5; break;
00040     case POPT_NOSCRIPTS: qva->qva_flags |= VERIFY_SCRIPT; break;
00041     }
00042 }
00043 
00044 static int noDeps = 0;
00045 static int noFiles = 0;
00046 static int noMd5 = 0;
00047 static int noScripts = 0;
00048 
00050 struct poptOption rpmVerifyPoptTable[] = {
00051  { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA, 
00052         verifyArgCallback, 0, NULL, NULL },
00053  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmQVSourcePoptTable, 0,
00054         NULL, NULL },
00055  { "nodeps", '\0', 0, &noDeps, POPT_NODEPS,
00056         N_("do not verify package dependencies"),
00057         NULL },
00058  { "nofiles", '\0', 0, &noFiles, POPT_NOFILES,
00059         N_("don't verify files in package"),
00060         NULL},
00061  { "nomd5", '\0', 0, &noMd5, POPT_NOMD5,
00062         N_("do not verify file md5 checksums"),
00063         NULL },
00064  { "noscripts", '\0', 0, &noScripts, POPT_NOSCRIPTS,
00065         N_("do not execute %verifyscript (if any)"),
00066         NULL },
00067     POPT_TABLEEND
00068 };
00069 
00070 /* ======================================================================== */
00071 int rpmVerifyFile(const char * prefix, Header h, int filenum,
00072                 int * result, int omitMask)
00073 {
00074     char ** baseNames, ** md5List, ** linktoList, ** dirNames;
00075     int_32 * verifyFlags;
00076     rpmVerifyAttrs flags;
00077     int_32 * sizeList, * mtimeList, * dirIndexes;
00078     unsigned short * modeList, * rdevList;
00079     char * fileStatesList;
00080     char * filespec;
00081     char * name;
00082     gid_t gid;
00083     int type, count, rc;
00084     struct stat sb;
00085     unsigned char md5sum[40];
00086     int_32 * uidList, * gidList;
00087     char linkto[1024];
00088     int size;
00089     char ** unameList, ** gnameList;
00090     int_32 useBrokenMd5;
00091 
00092   if (IS_BIG_ENDIAN()) {        /* XXX was ifdef WORDS_BIGENDIAN */
00093     int_32 * brokenPtr;
00094     if (!headerGetEntry(h, RPMTAG_BROKENMD5, NULL, (void **) &brokenPtr, NULL)) {
00095         char * rpmVersion;
00096 
00097         if (headerGetEntry(h, RPMTAG_RPMVERSION, NULL, (void **) &rpmVersion, 
00098                                 NULL)) {
00099             useBrokenMd5 = ((rpmvercmp(rpmVersion, "2.3.3") >= 0) &&
00100                             (rpmvercmp(rpmVersion, "2.3.8") <= 0));
00101         } else {
00102             useBrokenMd5 = 1;
00103         }
00104         headerAddEntry(h, RPMTAG_BROKENMD5, RPM_INT32_TYPE, &useBrokenMd5, 1);
00105     } else {
00106         useBrokenMd5 = *brokenPtr;
00107     }
00108   } else {
00109     useBrokenMd5 = 0;
00110   }
00111 
00112     headerGetEntry(h, RPMTAG_FILEMODES, &type, (void **) &modeList, &count);
00113 
00114     if (headerGetEntry(h, RPMTAG_FILEVERIFYFLAGS, &type, (void **) &verifyFlags, 
00115                  &count)) {
00116         flags = verifyFlags[filenum];
00117     } else {
00118         flags = RPMVERIFY_ALL;
00119     }
00120 
00121     headerGetEntry(h, RPMTAG_BASENAMES, &type, (void **) &baseNames, 
00122                    &count);
00123     headerGetEntry(h, RPMTAG_DIRINDEXES, &type, (void **) &dirIndexes, 
00124                    NULL);
00125     headerGetEntry(h, RPMTAG_DIRNAMES, &type, (void **) &dirNames, NULL);
00126 
00127     filespec = alloca(strlen(dirNames[dirIndexes[filenum]]) + 
00128                       strlen(baseNames[filenum]) + strlen(prefix) + 5);
00129     sprintf(filespec, "%s/%s%s", prefix, dirNames[dirIndexes[filenum]],
00130                 baseNames[filenum]);
00131     free(baseNames);
00132     free(dirNames);
00133     
00134     *result = 0;
00135 
00136     /* Check to see if the file was installed - if not pretend all is OK */
00137     if (headerGetEntry(h, RPMTAG_FILESTATES, &type, 
00138                  (void **) &fileStatesList, &count) && fileStatesList) {
00139         if (fileStatesList[filenum] == RPMFILE_STATE_NOTINSTALLED)
00140             return 0;
00141     }
00142 
00143     if (lstat(filespec, &sb)) {
00144         *result |= RPMVERIFY_LSTATFAIL;
00145         return 1;
00146     }
00147 
00148     if (S_ISDIR(sb.st_mode))
00149         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00150                         RPMVERIFY_LINKTO);
00151     else if (S_ISLNK(sb.st_mode)) {
00152         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
00153                 RPMVERIFY_MODE);
00154 #       if CHOWN_FOLLOWS_SYMLINK
00155             flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP);
00156 #       endif
00157     }
00158     else if (S_ISFIFO(sb.st_mode))
00159         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00160                         RPMVERIFY_LINKTO);
00161     else if (S_ISCHR(sb.st_mode))
00162         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00163                         RPMVERIFY_LINKTO);
00164     else if (S_ISBLK(sb.st_mode))
00165         flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME | 
00166                         RPMVERIFY_LINKTO);
00167     else 
00168         flags &= ~(RPMVERIFY_LINKTO);
00169 
00170     /* Don't verify any features in omitMask */
00171     flags &= ~(omitMask | RPMVERIFY_LSTATFAIL|RPMVERIFY_READFAIL|RPMVERIFY_READLINKFAIL);
00172 
00173     if (flags & RPMVERIFY_MD5) {
00174         headerGetEntry(h, RPMTAG_FILEMD5S, &type, (void **) &md5List, &count);
00175         if (useBrokenMd5) {
00176             rc = mdfileBroken(filespec, md5sum);
00177         } else {
00178             rc = mdfile(filespec, md5sum);
00179         }
00180 
00181         if (rc)
00182             *result |= (RPMVERIFY_READFAIL|RPMVERIFY_MD5);
00183         else if (strcmp(md5sum, md5List[filenum]))
00184             *result |= RPMVERIFY_MD5;
00185         free(md5List);
00186     } 
00187     if (flags & RPMVERIFY_LINKTO) {
00188         headerGetEntry(h, RPMTAG_FILELINKTOS, &type, (void **) &linktoList, &count);
00189         size = readlink(filespec, linkto, sizeof(linkto)-1);
00190         if (size == -1)
00191             *result |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
00192         else  {
00193             linkto[size] = '\0';
00194             if (strcmp(linkto, linktoList[filenum]))
00195                 *result |= RPMVERIFY_LINKTO;
00196         }
00197         free(linktoList);
00198     } 
00199 
00200     if (flags & RPMVERIFY_FILESIZE) {
00201         headerGetEntry(h, RPMTAG_FILESIZES, &type, (void **) &sizeList, &count);
00202         if (sizeList[filenum] != sb.st_size)
00203             *result |= RPMVERIFY_FILESIZE;
00204     } 
00205 
00206     if (flags & RPMVERIFY_MODE) {
00207         if (modeList[filenum] != sb.st_mode)
00208             *result |= RPMVERIFY_MODE;
00209     }
00210 
00211     if (flags & RPMVERIFY_RDEV) {
00212         if (S_ISCHR(modeList[filenum]) != S_ISCHR(sb.st_mode) ||
00213             S_ISBLK(modeList[filenum]) != S_ISBLK(sb.st_mode)) {
00214             *result |= RPMVERIFY_RDEV;
00215         } else if (S_ISDEV(modeList[filenum]) && S_ISDEV(sb.st_mode)) {
00216             headerGetEntry(h, RPMTAG_FILERDEVS, NULL, (void **) &rdevList, 
00217                            NULL);
00218             if (rdevList[filenum] != sb.st_rdev)
00219                 *result |= RPMVERIFY_RDEV;
00220         } 
00221     }
00222 
00223     if (flags & RPMVERIFY_MTIME) {
00224         headerGetEntry(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtimeList, NULL);
00225         if (mtimeList[filenum] != sb.st_mtime)
00226             *result |= RPMVERIFY_MTIME;
00227     }
00228 
00229     if (flags & RPMVERIFY_USER) {
00230         if (headerGetEntry(h, RPMTAG_FILEUSERNAME, NULL, (void **) &unameList, 
00231                            NULL)) {
00232             name = uidToUname(sb.st_uid);
00233             if (!name || strcmp(unameList[filenum], name))
00234                 *result |= RPMVERIFY_USER;
00235             free(unameList);
00236         } else if (headerGetEntry(h, RPMTAG_FILEUIDS, NULL, (void **) &uidList, 
00237                                   &count)) {
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         if (headerGetEntry(h, RPMTAG_FILEGROUPNAME, NULL, (void **) &gnameList, 
00249                         NULL)) {
00250             rc =  gnameToGid(gnameList[filenum],&gid);
00251             if (rc || (gid != sb.st_gid))
00252                 *result |= RPMVERIFY_GROUP;
00253             free(gnameList);
00254         } else if (headerGetEntry(h, RPMTAG_FILEGIDS, NULL, (void **) &gidList, 
00255                                   &count)) {
00256             if (gidList[filenum] != sb.st_gid)
00257                 *result |= RPMVERIFY_GROUP;
00258         } else {
00259             rpmError(RPMERR_INTERNAL, _("package lacks both group name and id "
00260                      "lists (this should never happen)\n"));
00261             *result |= RPMVERIFY_GROUP;
00262         }
00263     }
00264 
00265     return 0;
00266 }
00267 
00276 int rpmVerifyScript(const char * rootDir, Header h, FD_t scriptFd)
00277 {
00278     rpmdb rpmdb = NULL;
00279     rpmTransactionSet ts = rpmtransCreateSet(rpmdb, rootDir);
00280     int rc;
00281 
00282     if (scriptFd)
00283         ts->scriptFd = fdLink(scriptFd, "rpmVerifyScript");
00284     rc = runInstScript(ts, h, RPMTAG_VERIFYSCRIPT, RPMTAG_VERIFYSCRIPTPROG,
00285                      0, 0);
00286     rpmtransFree(ts);
00287     return rc;
00288 }
00289 
00290 /* ======================================================================== */
00291 static int verifyHeader(QVA_t *qva, Header h)
00292 {
00293     char buf[BUFSIZ];
00294     char * t, * te;
00295 
00296     const char ** fileNames = NULL;
00297     int count;
00298     int_32 * fileFlagsList = NULL;
00299     rpmVerifyAttrs verifyResult = 0;
00300     rpmVerifyAttrs omitMask = !(qva->qva_flags & VERIFY_MD5)
00301                         ? RPMVERIFY_MD5 : RPMVERIFY_NONE;
00302     int ec = 0;
00303     int i;
00304 
00305     te = t = buf;
00306     *te = '\0';
00307 
00308     if (!headerGetEntry(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlagsList, NULL))
00309         goto exit;
00310 
00311     if (!headerIsEntry(h, RPMTAG_BASENAMES))
00312         goto exit;
00313 
00314     rpmBuildFileList(h, &fileNames, &count);
00315 
00316     for (i = 0; i < count; i++) {
00317         int rc;
00318 
00319         rc = rpmVerifyFile(qva->qva_prefix, h, i, &verifyResult, omitMask);
00320         if (rc) {
00321             sprintf(te, _("missing    %s"), fileNames[i]);
00322             te += strlen(te);
00323             ec = rc;
00324         } else if (verifyResult) {
00325             const char * size, * md5, * link, * mtime, * mode;
00326             const char * group, * user, * rdev;
00327             /*@observer@*/ static const char *const aok = ".";
00328             /*@observer@*/ static const char *const unknown = "?";
00329 
00330             ec = 1;
00331 
00332 #define _verify(_RPMVERIFY_F, _C)       \
00333         ((verifyResult & _RPMVERIFY_F) ? _C : aok)
00334 #define _verifylink(_RPMVERIFY_F, _C)   \
00335         ((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \
00336          (verifyResult & _RPMVERIFY_F) ? _C : aok)
00337 #define _verifyfile(_RPMVERIFY_F, _C)   \
00338         ((verifyResult & RPMVERIFY_READFAIL) ? unknown : \
00339          (verifyResult & _RPMVERIFY_F) ? _C : aok)
00340         
00341             md5 = _verifyfile(RPMVERIFY_MD5, "5");
00342             size = _verify(RPMVERIFY_FILESIZE, "S");
00343             link = _verifylink(RPMVERIFY_LINKTO, "L");
00344             mtime = _verify(RPMVERIFY_MTIME, "T");
00345             rdev = _verify(RPMVERIFY_RDEV, "D");
00346             user = _verify(RPMVERIFY_USER, "U");
00347             group = _verify(RPMVERIFY_GROUP, "G");
00348             mode = _verify(RPMVERIFY_MODE, "M");
00349 
00350 #undef _verify
00351 #undef _verifylink
00352 #undef _verifyfile
00353 
00354             sprintf(te, "%s%s%s%s%s%s%s%s %c %s",
00355                        size, mode, md5, rdev, link, user, group, mtime, 
00356                        fileFlagsList[i] & RPMFILE_CONFIG ? 'c' : ' ', 
00357                        fileNames[i]);
00358             te += strlen(te);
00359         }
00360 
00361         if (te > t) {
00362             *te++ = '\n';
00363             *te = '\0';
00364             rpmMessage(RPMMESS_NORMAL, "%s", t);
00365             te = t = buf;
00366             *t = '\0';
00367         }
00368     }
00369         
00370 exit:
00371     if (fileNames) free(fileNames);
00372     return ec;
00373 }
00374 
00375 static int verifyDependencies(rpmdb rpmdb, Header h)
00376 {
00377     rpmTransactionSet rpmdep;
00378     struct rpmDependencyConflict * conflicts;
00379     int numConflicts;
00380     int rc = 0;
00381     int i;
00382 
00383     rpmdep = rpmtransCreateSet(rpmdb, NULL);
00384     rpmtransAddPackage(rpmdep, h, NULL, NULL, 0, NULL);
00385 
00386     rpmdepCheck(rpmdep, &conflicts, &numConflicts);
00387     rpmtransFree(rpmdep);
00388 
00389     if (numConflicts) {
00390         const char * name, * version, * release;
00391         char * t, * te;
00392         int nb = 512;
00393         headerNVR(h, &name, &version, &release);
00394 
00395         for (i = 0; i < numConflicts; i++) {
00396             nb += strlen(conflicts[i].needsName) + sizeof(", ") - 1;
00397             if (conflicts[i].needsFlags)
00398                 nb += strlen(conflicts[i].needsVersion) + 5;
00399         }
00400         te = t = alloca(nb);
00401         *te = '\0';
00402         sprintf(te, _("Unsatisfied dependencies for %s-%s-%s: "),
00403                 name, version, release);
00404         te += strlen(te);
00405         for (i = 0; i < numConflicts; i++) {
00406             if (i) te = stpcpy(te, ", ");
00407             te = stpcpy(te, conflicts[i].needsName);
00408             if (conflicts[i].needsFlags) {
00409                 int flags = conflicts[i].needsFlags;
00410                 *te++ = ' ';
00411                 if (flags & RPMSENSE_LESS)      *te++ = '<';
00412                 if (flags & RPMSENSE_GREATER)   *te++ = '>';
00413                 if (flags & RPMSENSE_EQUAL)     *te++ = '=';
00414                 *te++ = ' ';
00415                 te = stpcpy(te, conflicts[i].needsVersion);
00416             }
00417         }
00418         rpmdepFreeConflicts(conflicts, numConflicts);
00419         if (te > t) {
00420             *te++ = '\n';
00421             *te = '\0';
00422             rpmMessage(RPMMESS_NORMAL, "%s", t);
00423             te = t;
00424             *t = '\0';
00425         }
00426         rc = 1;
00427     }
00428     return rc;
00429 }
00430 
00431 int showVerifyPackage(QVA_t *qva, rpmdb rpmdb, Header h)
00432 {
00433     FD_t fdo;
00434     int ec = 0;
00435     int rc;
00436 
00437     if ((qva->qva_flags & VERIFY_DEPS) &&
00438         (rc = verifyDependencies(rpmdb, h)) != 0)
00439             ec = rc;
00440     if ((qva->qva_flags & VERIFY_FILES) &&
00441         (rc = verifyHeader(qva, h)) != 0)
00442             ec = rc;;
00443     fdo = fdDup(STDOUT_FILENO);
00444     if ((qva->qva_flags & VERIFY_SCRIPT) &&
00445         (rc = rpmVerifyScript(qva->qva_prefix, h, fdo)) != 0)
00446             ec = rc;
00447     Fclose(fdo);
00448     return ec;
00449 }
00450 
00451 int rpmVerify(QVA_t *qva, rpmQVSources source, const char *arg)
00452 {
00453     rpmdb rpmdb = NULL;
00454     int rc;
00455 
00456     switch (source) {
00457     case RPMQV_RPM:
00458         if (!(qva->qva_flags & VERIFY_DEPS))
00459             break;
00460         /*@fallthrough@*/
00461     default:
00462         if (rpmdbOpen(qva->qva_prefix, &rpmdb, O_RDONLY, 0644))
00463             return 1;
00464         break;
00465     }
00466 
00467     rc = rpmQueryVerify(qva, source, arg, rpmdb, showVerifyPackage);
00468 
00469     if (rpmdb)
00470         rpmdbClose(rpmdb);
00471 
00472     return rc;
00473 }

Generated at Sun Apr 8 18:43:01 2001 for rpm by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000