# 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_SHA1HEADER, &hdt, (void **) &hdigest, NULL)
    00318     &&  !hge(h, RPMTAG_SHA1RHN, &hdt, (void **) &hdigest, NULL))
    00319     {
    00320         if (hge(h, RPMTAG_BADSHA1HEADER, &hdt, (void **) &hdigest, NULL))
    00321             return 0;
    00322     }
    00323
    00324     /* Regenerate original header. */
    00325     if (!hge(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc))
    00326         return 0;
    00327
    00328     if (hdigest == NULL || uh == NULL)
    00329         return 0;
    00330
    00331     /* Compute header digest. */
    00332     {   DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
    00333         const char * digest;
    00334         size_t digestlen;
    00335
    00336         (void) rpmDigestUpdate(ctx, uh, uhc);
    00337         (void) rpmDigestFinal(ctx, (void **)&digest, &digestlen, 1);
    00338
    00339         /* XXX can't happen: report NULL malloc return as a digest failure. */
    00340         ec = (digest == NULL || strcmp(hdigest, digest)) ? 1 : 0;
    00341         digest = _free(digest);
    00342     }
    00343
    00344     uh = hfd(uh, uht);
    00345     hdigest = hfd(hdigest, hdt);
    00346
    00347     return ec;
    00348 }
    00349
    00355 static int verifyHeader(QVA_t qva, Header h)
    00356         /*@modifies h @*/
    00357 {
    00358     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    00359     char buf[BUFSIZ];
    00360     char * t, * te;
    00361     const char * prefix = (qva->qva_prefix ? qva->qva_prefix : "");
    00362     const char ** fileNames = NULL;
    00363     int count;
    00364     int_32 * fileFlags = NULL;
    00365     rpmVerifyAttrs verifyResult = 0;
    00366     rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS);
    00367     int ec = 0;         /* assume no problems */
    00368     int i;
    00369
    00370     te = t = buf;
    00371     *te = '\0';
    00372
    00373     if (!hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlags, NULL))
    00374         goto exit;
    00375
    00376     if (!headerIsEntry(h, RPMTAG_BASENAMES))
    00377         goto exit;
    00378
    00379     rpmBuildFileList(h, &fileNames, &count);
    00380
    00381     for (i = 0; i < count; i++) {
    00382         rpmfileAttrs fileAttrs;
    00383         int rc;
    00384
    00385         fileAttrs = fileFlags[i];
    00386
    00387         /* If not verifying %ghost, skip ghost files. */
    00388         if (!(qva->qva_fflags & RPMFILE_GHOST)
    00389         && (fileAttrs & RPMFILE_GHOST))
    00390             continue;
    00391
    00392         rc = rpmVerifyFile(prefix, h, i, &verifyResult, omitMask);
    00393         if (rc) {
    00394             /*@-internalglobs@*/ /* FIX: shrug */
    00395             if (!(fileAttrs & RPMFILE_MISSINGOK) || rpmIsVerbose()) {
    00396                 sprintf(te, _("missing    %s"), fileNames[i]);
    00397                 te += strlen(te);
    00398                 ec = rc;
    00399             }
    00400             /*@=internalglobs@*/
    00401         } else if (verifyResult) {
    00402             const char * size, * md5, * link, * mtime, * mode;
    00403             const char * group, * user, * rdev;
    00404             /*@observer@*/ static const char *const aok = ".";
    00405             /*@observer@*/ static const char *const unknown = "?";
    00406
    00407             ec = 1;
    00408
    00409 #define _verify(_RPMVERIFY_F, _C)       \
    00410         ((verifyResult & _RPMVERIFY_F) ? _C : aok)
    00411 #define _verifylink(_RPMVERIFY_F, _C)   \
    00412         ((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \
    00413          (verifyResult & _RPMVERIFY_F) ? _C : aok)
    00414 #define _verifyfile(_RPMVERIFY_F, _C)   \
    00415         ((verifyResult & RPMVERIFY_READFAIL) ? unknown : \
    00416          (verifyResult & _RPMVERIFY_F) ? _C : aok)
    00417
    00418             md5 = _verifyfile(RPMVERIFY_MD5, "5");
    00419             size = _verify(RPMVERIFY_FILESIZE, "S");
    00420             link = _verifylink(RPMVERIFY_LINKTO, "L");
    00421             mtime = _verify(RPMVERIFY_MTIME, "T");
    00422             rdev = _verify(RPMVERIFY_RDEV, "D");
    00423             user = _verify(RPMVERIFY_USER, "U");
    00424             group = _verify(RPMVERIFY_GROUP, "G");
    00425             mode = _verify(RPMVERIFY_MODE, "M");
    00426
    00427 #undef _verify
    00428 #undef _verifylink
    00429 #undef _verifyfile
    00430
    00431             sprintf(te, "%s%s%s%s%s%s%s%s %c %s",
    00432                         size, mode, md5, rdev, link, user, group, mtime,
    00433                         ((fileAttrs & RPMFILE_CONFIG)   ? 'c' :
    00434                          (fileAttrs & RPMFILE_DOC)      ? 'd' :
    00435                          (fileAttrs & RPMFILE_GHOST)    ? 'g' :
    00436                          (fileAttrs & RPMFILE_LICENSE)  ? 'l' :
    00437                          (fileAttrs & RPMFILE_README)   ? 'r' : ' '),
    00438                         fileNames[i]);
    00439             te += strlen(te);
    00440         }
    00441
    00442         if (te > t) {
    00443             *te++ = '\n';
    00444             *te = '\0';
    00445             rpmMessage(RPMMESS_NORMAL, "%s", t);
    00446             te = t = buf;
    00447             *t = '\0';
    00448         }
    00449     }
    00450
    00451 exit:
    00452     fileNames = _free(fileNames);
    00453     return ec;
    00454 }
    00455
    00462 static int verifyDependencies(rpmdb rpmdb, Header h)
    00463         /*@modifies h @*/
    00464 {
    00465     rpmTransactionSet ts;
    00466     rpmDependencyConflict conflicts;
    00467     int numConflicts;
    00468     int rc = 0;         /* assume no problems */
    00469     int i;
    00470
    00471     ts = rpmtransCreateSet(rpmdb, NULL);
    00472     (void) rpmtransAddPackage(ts, h, NULL, NULL, 0, NULL);
    00473
    00474     (void) rpmdepCheck(ts, &conflicts, &numConflicts);
    00475     ts = rpmtransFree(ts);
    00476
    00477     /*@-branchstate@*/
    00478     if (numConflicts) {
    00479         const char *n, *v, *r;
    00480         char * t, * te;
    00481         int nb = 512;
    00482         (void) headerNVR(h, &n, &v, &r);
    00483
    00484         for (i = 0; i < numConflicts; i++) {
    00485             nb += strlen(conflicts[i].needsName) + sizeof(", ") - 1;
    00486             if (conflicts[i].needsFlags)
    00487                 nb += strlen(conflicts[i].needsVersion) + 5;
    00488         }
    00489         te = t = alloca(nb);
    00490         *te = '\0';
    00491         sprintf(te, _("Unsatisfied dependencies for %s-%s-%s: "), n, v, r);
    00492         te += strlen(te);
    00493         for (i = 0; i < numConflicts; i++) {
    00494             if (i) te = stpcpy(te, ", ");
    00495             te = stpcpy(te, conflicts[i].needsName);
    00496             if (conflicts[i].needsFlags) {
    00497                 int flags = conflicts[i].needsFlags;
    00498                 *te++ = ' ';
    00499                 if (flags & RPMSENSE_LESS)      *te++ = '<';
    00500                 if (flags & RPMSENSE_GREATER)   *te++ = '>';
    00501                 if (flags & RPMSENSE_EQUAL)     *te++ = '=';
    00502                 *te++ = ' ';
    00503                 te = stpcpy(te, conflicts[i].needsVersion);
    00504             }
    00505         }
    00506         conflicts = rpmdepFreeConflicts(conflicts, numConflicts);
    00507         if (te > t) {
    00508             *te++ = '\n';
    00509             *te = '\0';
    00510             rpmMessage(RPMMESS_NORMAL, "%s", t);
    00511             te = t;
    00512             *t = '\0';
    00513         }
    00514         rc = 1;
    00515     }
    00516     /*@=branchstate@*/
    00517     return rc;
    00518 }
    00519
    00520 int showVerifyPackage(QVA_t qva, rpmdb rpmdb, Header h)
    00521 {
    00522     const char * prefix = (qva->qva_prefix ? qva->qva_prefix : "");
    00523     int ec = 0;
    00524     int rc;
    00525
    00526     if (qva->qva_flags & VERIFY_DIGEST) {
    00527         if ((rc = rpmVerifyDigest(h)) != 0) {
    00528             const char *n, *v, *r;
    00529             (void) headerNVR(h, &n, &v, &r);
    00530             rpmMessage(RPMMESS_NORMAL,
    00531                    _("%s-%s-%s: immutable header region digest check failed\n"),
    00532                         n, v, r);
    00533             ec = rc;
    00534         }
    00535     }
    00536     if (qva->qva_flags & VERIFY_DEPS) {
    00537         if ((rc = verifyDependencies(rpmdb, h)) != 0)
    00538             ec = rc;
    00539     }
    00540     if (qva->qva_flags & VERIFY_FILES) {
    00541         if ((rc = verifyHeader(qva, h)) != 0)
    00542             ec = rc;
    00543     }
    00544     if (qva->qva_flags & VERIFY_SCRIPT) {
    00545         FD_t fdo = fdDup(STDOUT_FILENO);
    00546         if ((rc = rpmVerifyScript(prefix, h, fdo)) != 0)
    00547             ec = rc;
    00548         if (fdo)
    00549             rc = Fclose(fdo);
    00550     }
    00551     return ec;
    00552 }
    00553
    00554 int rpmVerify(QVA_t qva, rpmQVSources source, const char * arg)
    00555 {
    00556     rpmdb rpmdb = NULL;
    00557     int rc;
    00558
    00559     switch (source) {
    00560     case RPMQV_RPM:
    00561         if (!(qva->qva_flags & VERIFY_DEPS))
    00562             break;
    00563         /*@fallthrough@*/
    00564     default:
    00565         if ((rc = rpmdbOpen(qva->qva_prefix, &rpmdb, O_RDONLY, 0644)) != 0)
    00566             return 1;
    00567         break;
    00568     }
    00569
    00570     rc = rpmQueryVerify(qva, source, arg, rpmdb, showVerifyPackage);
    00571
    00572     if (rpmdb != NULL)
    00573         (void) rpmdbClose(rpmdb);
    00574
    00575     return rc;
    00576 }