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

Generated at Thu Apr 19 15:29:44 2001 for rpm by doxygen1.2.6-20010408 written by Dimitri van Heesch, © 1997-2001