- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

# lib/rpmchecksig.c

Go to the documentation of this file.

    00001
    00006 #include "system.h"
    00007
    00008 #include <rpmio_internal.h>
    00009 #include <rpmbc.h>              /* XXX beecrypt base64 */
    00010 #include <rpmtag.h>
    00011 #include <rpmcli.h>
    00012 #define _RPMEVR_INTERNAL        /* XXX RPMSENSE_KEYRING */
    00013 #include <rpmevr.h>
    00014
    00015 #include <rpmts.h>
    00016
    00017 #include "rpmdb.h"
    00018 #include "rpmgi.h"
    00019
    00020 #include <rpmxar.h>
    00021 #include <pkgio.h>
    00022
    00023 #include "signature.h"
    00024 #include "debug.h"
    00025
    00026 /*@access FD_t @*/              /* XXX stealing digests */
    00027 /*@access Header @*/            /* XXX void * arg */
    00028 /*@access pgpDig @*/
    00029 /*@access pgpDigParams @*/
    00030
    00031 /*@unchecked@*/
    00032 int _print_pkts = 0;
    00033
    00036 static int manageFile(/*@out@*/ FD_t *fdp,
    00037                 /*@null@*/ /*@out@*/ const char **fnp,
    00038                 int flags, /*@unused@*/ int rc)
    00039         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
    00040         /*@modifies *fdp, *fnp, rpmGlobalMacroContext,
    00041                 fileSystem, internalState @*/
    00042 {
    00043     const char *fn;
    00044     FD_t fd;
    00045
    00046     if (fdp == NULL)    /* programmer error */
    00047         return 1;
    00048
    00049     /* close and reset *fdp to NULL */
    00050     if (*fdp && (fnp == NULL || *fnp == NULL)) {
    00051         (void) Fclose(*fdp);
    00052         *fdp = NULL;
    00053         return 0;
    00054     }
    00055
    00056     /* open a file and set *fdp */
    00057     if (*fdp == NULL && fnp != NULL && *fnp != NULL) {
    00058         fd = Fopen(*fnp, ((flags & O_WRONLY) ? "w.fdio" : "r.fdio"));
    00059         if (fd == NULL || Ferror(fd)) {
    00060             rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"), *fnp,
    00061                 Fstrerror(fd));
    00062             return 1;
    00063         }
    00064         *fdp = fd;
    00065         return 0;
    00066     }
    00067
    00068     /* open a temp file */
    00069     if (*fdp == NULL && (fnp == NULL || *fnp == NULL)) {
    00070         fn = NULL;
    00071         if (rpmTempFile(NULL, (fnp ? &fn : NULL), &fd)) {
    00072             rpmlog(RPMLOG_ERR, _("rpmTempFile failed\n"));
    00073             return 1;
    00074         }
    00075         if (fnp != NULL)
    00076             *fnp = fn;
    00077         *fdp = fdLink(fd, "manageFile return");
    00078         fd = fdFree(fd, "manageFile return");
    00079         return 0;
    00080     }
    00081
    00082     /* no operation */
    00083     if (*fdp != NULL && fnp != NULL && *fnp != NULL)
    00084         return 0;
    00085
    00086     /* XXX never reached */
    00087     return 1;
    00088 }
    00089
    00093 static int copyFile(FD_t *sfdp, const char **sfnp,
    00094                 FD_t *tfdp, const char **tfnp)
    00095         /*@globals rpmGlobalMacroContext, h_errno,
    00096                 fileSystem, internalState @*/
    00097         /*@modifies *sfdp, *sfnp, *tfdp, *tfnp, rpmGlobalMacroContext,
    00098                 fileSystem, internalState @*/
    00099 {
    00100     unsigned char buf[BUFSIZ];
    00101     ssize_t count;
    00102     int rc = 1;
    00103
    00104     if (manageFile(sfdp, sfnp, O_RDONLY, 0))
    00105         goto exit;
    00106     if (manageFile(tfdp, tfnp, O_WRONLY|O_CREAT|O_TRUNC, 0))
    00107         goto exit;
    00108
    00109     while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), *sfdp)) > 0)
    00110     {
    00111         if (Fwrite(buf, sizeof(buf[0]), count, *tfdp) != count) {
    00112             rpmlog(RPMLOG_ERR, _("%s: Fwrite failed: %s\n"), *tfnp,
    00113                 Fstrerror(*tfdp));
    00114             goto exit;
    00115         }
    00116     }
    00117     if (count < 0) {
    00118         rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), *sfnp, Fstrerror(*sfdp));
    00119         goto exit;
    00120     }
    00121     if (Fflush(*tfdp) != 0) {
    00122         rpmlog(RPMLOG_ERR, _("%s: Fflush failed: %s\n"), *tfnp,
    00123             Fstrerror(*tfdp));
    00124         goto exit;
    00125     }
    00126
    00127     rc = 0;
    00128
    00129 exit:
    00130     if (*sfdp)  (void) manageFile(sfdp, NULL, 0, rc);
    00131     if (*tfdp)  (void) manageFile(tfdp, NULL, 0, rc);
    00132     return rc;
    00133 }
    00134
    00142 static int getSignid(Header sigh, int sigtag, unsigned char * signid)
    00143         /*@globals fileSystem, internalState @*/
    00144         /*@modifies *signid, fileSystem, internalState @*/
    00145 {
    00146     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00147     int rc = 1;
    00148     int xx;
    00149
    00150     he->tag = sigtag;
    00151     xx = headerGet(sigh, he, 0);
    00152     if (xx && he->p.ptr != NULL) {
    00153         pgpDig dig = pgpDigNew(0);
    00154
    00155         if (!pgpPrtPkts(he->p.ptr, he->c, dig, 0)) {
    00156             memcpy(signid, dig->signature.signid, sizeof(dig->signature.signid));
    00157             rc = 0;
    00158         }
    00159
    00160         he->p.ptr = _free(he->p.ptr);
    00161         dig = pgpDigFree(dig);
    00162     }
    00163     return rc;
    00164 }
    00165
    00173 static int rpmReSign(/*@unused@*/ rpmts ts,
    00174                 QVA_t qva, const char ** argv)
    00175         /*@globals rpmGlobalMacroContext, h_errno,
    00176                 fileSystem, internalState @*/
    00177         /*@modifies ts, rpmGlobalMacroContext,
    00178                 fileSystem, internalState @*/
    00179 {
    00180     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00181     rpmgi gi = NULL;
    00182     FD_t fd = NULL;
    00183     FD_t ofd = NULL;
    00184     struct rpmlead *lead = NULL;
    00185     rpmSigTag sigtag;
    00186     const char *sigtarget = NULL;
    00187     char tmprpm[1024+1];
    00188     Header sigh = NULL;
    00189     const char * msg = NULL;
    00190     int res = EXIT_FAILURE;
    00191     int deleting = (qva->qva_mode == RPMSIGN_DEL_SIGNATURE);
    00192     rpmRC rc;
    00193     int xx;
    00194
    00195     tmprpm[0] = '\0';
    00196
    00197     if (argv)
    00198  {       /* start-of-arg-iteration */
    00199     uint32_t tag = (qva->qva_source == RPMQV_FTSWALK)
    00200         ? RPMDBI_FTSWALK : RPMDBI_ARGLIST;
    00201     rpmgiFlags _giFlags = RPMGI_NONE;
    00202
    00203     gi = rpmgiNew(ts, tag, NULL, 0);
    00204 /*@-mods@*/
    00205     if (ftsOpts == 0)
    00206         ftsOpts = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
    00207 /*@=mods@*/
    00208     rc = rpmgiSetArgs(gi, argv, ftsOpts, (_giFlags|RPMGI_NOHEADER));
    00209
    00210     while (rpmgiNext(gi) == RPMRC_OK) {
    00211         const char * fn = rpmgiHdrPath(gi);
    00212         const char * tfn;
    00213
    00214         fprintf(stdout, "%s:\n", fn);
    00215
    00216 /*@-modobserver@*/      /* XXX rpmgiHdrPath should not be observer */
    00217         if (manageFile(&fd, &fn, O_RDONLY, 0))
    00218             goto exit;
    00219 /*@=modobserver@*/
    00220
    00221     {   const char item[] = "Lead";
    00222         msg = NULL;
    00223         rc = rpmpkgRead(item, fd, &lead, &msg);
    00224         if (rc != RPMRC_OK) {
    00225             rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
    00226             msg = _free(msg);
    00227             goto exit;
    00228         }
    00229         msg = _free(msg);
    00230     }
    00231
    00232     {   const char item[] = "Signature";
    00233         msg = NULL;
    00234         rc = rpmpkgRead(item, fd, &sigh, &msg);
    00235         switch (rc) {
    00236         default:
    00237             rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item,
    00238                         (msg && *msg ? msg : ""));
    00239             msg = _free(msg);
    00240             goto exit;
    00241             /*@notreached@*/ /*@switchbreak@*/ break;
    00242         case RPMRC_OK:
    00243             if (sigh == NULL) {
    00244                 rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
    00245                 goto exit;
    00246             }
    00247             /*@switchbreak@*/ break;
    00248         }
    00249         msg = _free(msg);
    00250     }
    00251
    00252         /* Write the header and archive to a temp file */
    00253         /* ASSERT: ofd == NULL && sigtarget == NULL */
    00254 /*@-modobserver@*/      /* XXX rpmgiHdrPath should not be observer */
    00255         if (copyFile(&fd, &fn, &ofd, &sigtarget))
    00256             goto exit;
    00257 /*@=modobserver@*/
    00258         /* Both fd and ofd are now closed. sigtarget contains tempfile name. */
    00259         /* ASSERT: fd == NULL && ofd == NULL */
    00260
    00261         /* Lose the immutable region (if present). */
    00262         he->tag = RPMTAG_HEADERSIGNATURES;
    00263         xx = headerGet(sigh, he, 0);
    00264         if (xx) {
    00265             HE_t ohe = memset(alloca(sizeof(*ohe)), 0, sizeof(*ohe));
    00266             HeaderIterator hi;
    00267             Header oh;
    00268             Header nh;
    00269
    00270             nh = headerNew();
    00271             if (nh == NULL) {
    00272                 he->p.ptr = _free(he->p.ptr);
    00273                 goto exit;
    00274             }
    00275
    00276             oh = headerCopyLoad(he->p.ptr);
    00277             for (hi = headerInit(oh);
    00278                 headerNext(hi, ohe, 0);
    00279                 ohe->p.ptr = _free(ohe->p.ptr))
    00280             {
    00281                 if (ohe->p.ptr) {
    00282                     xx = headerPut(nh, ohe, 0);
    00283                 }
    00284             }
    00285             hi = headerFini(hi);
    00286             oh = headerFree(oh);
    00287
    00288             sigh = headerFree(sigh);
    00289             sigh = headerLink(nh);
    00290             nh = headerFree(nh);
    00291         }
    00292
    00293 if (sigh != NULL) {
    00294         /* Eliminate broken digest values. */
    00295         he->tag = (rpmTag)RPMSIGTAG_LEMD5_1;
    00296         xx = headerDel(sigh, he, 0);
    00297         he->tag = (rpmTag)RPMSIGTAG_LEMD5_2;
    00298         xx = headerDel(sigh, he, 0);
    00299         he->tag = (rpmTag)RPMSIGTAG_BADSHA1_1;
    00300         xx = headerDel(sigh, he, 0);
    00301         he->tag = (rpmTag)RPMSIGTAG_BADSHA1_2;
    00302         xx = headerDel(sigh, he, 0);
    00303
    00304         /* Toss and recalculate header+payload size and digests. */
    00305         he->tag = (rpmTag)RPMSIGTAG_SIZE;
    00306         xx = headerDel(sigh, he, 0);
    00307         xx = rpmAddSignature(sigh, sigtarget, RPMSIGTAG_SIZE, qva->passPhrase);
    00308         he->tag = (rpmTag)RPMSIGTAG_MD5;
    00309         xx = headerDel(sigh, he, 0);
    00310         xx = rpmAddSignature(sigh, sigtarget, RPMSIGTAG_MD5, qva->passPhrase);
    00311         he->tag = (rpmTag)RPMSIGTAG_SHA1;
    00312         xx = headerDel(sigh, he, 0);
    00313         xx = rpmAddSignature(sigh, sigtarget, RPMSIGTAG_SHA1, qva->passPhrase);
    00314
    00315         if (deleting) { /* Nuke all the signature tags. */
    00316             he->tag = (rpmTag)RPMSIGTAG_GPG;
    00317             xx = headerDel(sigh, he, 0);
    00318             he->tag = (rpmTag)RPMSIGTAG_PGP5;
    00319             xx = headerDel(sigh, he, 0);
    00320             he->tag = (rpmTag)RPMSIGTAG_PGP;
    00321             xx = headerDel(sigh, he, 0);
    00322             he->tag = (rpmTag)RPMSIGTAG_DSA;
    00323             xx = headerDel(sigh, he, 0);
    00324             he->tag = (rpmTag)RPMSIGTAG_RSA;
    00325             xx = headerDel(sigh, he, 0);
    00326         } else {                /* If gpg/pgp is configured, replace the signature. */
    00327           int addsig = 0;
    00328           sigtag = RPMSIGTAG_GPG;
    00329           addsig = 1;
    00330
    00331           if (addsig) {
    00332             unsigned char oldsignid[8], newsignid[8];
    00333
    00334             /* Grab the old signature fingerprint (if any) */
    00335             memset(oldsignid, 0, sizeof(oldsignid));
    00336             xx = getSignid(sigh, sigtag, oldsignid);
    00337
    00338             switch (sigtag) {
    00339             default:
    00340                 /*@switchbreak@*/ break;
    00341             case RPMSIGTAG_DSA:
    00342                 he->tag = (rpmTag)RPMSIGTAG_GPG;
    00343                 xx = headerDel(sigh, he, 0);
    00344                 /*@switchbreak@*/ break;
    00345             case RPMSIGTAG_RSA:
    00346                 he->tag = (rpmTag)RPMSIGTAG_PGP;
    00347                 xx = headerDel(sigh, he, 0);
    00348                 /*@switchbreak@*/ break;
    00349             case RPMSIGTAG_GPG:
    00350                 he->tag = (rpmTag)RPMSIGTAG_DSA;
    00351                 xx = headerDel(sigh, he, 0);
    00352                 /*@fallthrough@*/
    00353             case RPMSIGTAG_PGP5:
    00354             case RPMSIGTAG_PGP:
    00355                 he->tag = (rpmTag)RPMSIGTAG_RSA;
    00356                 xx = headerDel(sigh, he, 0);
    00357                 /*@switchbreak@*/ break;
    00358             }
    00359
    00360             he->tag = (rpmTag)sigtag;
    00361             xx = headerDel(sigh, he, 0);
    00362             xx = rpmAddSignature(sigh, sigtarget, sigtag, qva->passPhrase);
    00363
    00364             /* If package was previously signed, check for same signer. */
    00365             memset(newsignid, 0, sizeof(newsignid));
    00366             if (memcmp(oldsignid, newsignid, sizeof(oldsignid))) {
    00367
    00368                 /* Grab the new signature fingerprint */
    00369                 xx = getSignid(sigh, sigtag, newsignid);
    00370
    00371                 /* If same signer, skip resigning the package. */
    00372                 if (!memcmp(oldsignid, newsignid, sizeof(oldsignid))) {
    00373
    00374                     rpmlog(RPMLOG_WARNING,
    00375                         _("%s: was already signed by key ID %s, skipping\n"),
    00376                         fn, pgpHexStr(newsignid+4, sizeof(newsignid)-4));
    00377
    00378                     /* Clean up intermediate target */
    00379                     xx = Unlink(sigtarget);
    00380                     sigtarget = _free(sigtarget);
    00381                     continue;
    00382                 }
    00383             }
    00384           }
    00385         }
    00386
    00387         /* Reallocate the signature into one contiguous region. */
    00388         sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES);
    00389         if (sigh == NULL)       /* XXX can't happen */
    00390             goto exit;
    00391 }
    00392
    00393         /* Write the lead/signature of the output rpm */
    00394         (void) stpcpy( stpcpy(tmprpm, fn), ".XXXXXX");
    00395
    00396 #if defined(HAVE_MKSTEMP)
    00397         (void) close(mkstemp(tmprpm));
    00398 #else
    00399         (void) mktemp(tmprpm);
    00400 #endif
    00401         tfn = tmprpm;
    00402
    00403         if (manageFile(&ofd, &tfn, O_WRONLY|O_CREAT|O_TRUNC, 0))
    00404             goto exit;
    00405
    00406         {   const char item[] = "Lead";
    00407             rc = rpmpkgWrite(item, ofd, lead, NULL);
    00408             if (rc != RPMRC_OK) {
    00409                 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", tfn, item, Fstrerror(ofd));
    00410                 goto exit;
    00411             }
    00412         }
    00413
    00414         {   const char item[] = "Signature";
    00415             rc = rpmpkgWrite(item, ofd, sigh, NULL);
    00416             if (rc != RPMRC_OK) {
    00417                 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", tfn, item, Fstrerror(ofd));
    00418                 goto exit;
    00419             }
    00420         }
    00421
    00422         /* Append the header and archive from the temp file */
    00423         /* ASSERT: fd == NULL && ofd != NULL */
    00424         if (copyFile(&fd, &sigtarget, &ofd, &tfn))
    00425             goto exit;
    00426         /* Both fd and ofd are now closed. */
    00427         /* ASSERT: fd == NULL && ofd == NULL */
    00428
    00429         /* Move final target into place. */
    00430         xx = Unlink(fn);
    00431         xx = Rename(tfn, fn);
    00432         tmprpm[0] = '\0';
    00433
    00434         /* Clean up intermediate target */
    00435         xx = Unlink(sigtarget);
    00436         sigtarget = _free(sigtarget);
    00437     }
    00438
    00439  }      /* end-of-arg-iteration */
    00440
    00441     res = 0;
    00442
    00443 exit:
    00444     if (fd)     (void) manageFile(&fd, NULL, 0, res);
    00445     if (ofd)    (void) manageFile(&ofd, NULL, 0, res);
    00446
    00447     lead = _free(lead);
    00448     sigh = headerFree(sigh);
    00449
    00450     gi = rpmgiFree(gi);
    00451
    00452     if (sigtarget) {
    00453         xx = Unlink(sigtarget);
    00454         sigtarget = _free(sigtarget);
    00455     }
    00456     if (tmprpm[0] != '\0') {
    00457         xx = Unlink(tmprpm);
    00458         tmprpm[0] = '\0';
    00459     }
    00460
    00461     return res;
    00462 }
    00463
    00464 rpmRC rpmcliImportPubkey(const rpmts ts, const unsigned char * pkt, ssize_t pktlen)
    00465 {
    00466     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00467     static unsigned char zeros[] =
    00468         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    00469     const char * afmt = "%{pubkeys:armor}";
    00470     const char * group = "Public Keys";
    00471     const char * license = "pubkey";
    00472     const char * buildhost = "localhost";
    00473     uint32_t pflags = (RPMSENSE_KEYRING|RPMSENSE_EQUAL);
    00474     uint32_t zero = 0;
    00475     pgpDig dig = NULL;
    00476     pgpDigParams pubp = NULL;
    00477     const char * d = NULL;
    00478     const char * enc = NULL;
    00479     const char * n = NULL;
    00480     const char * u = NULL;
    00481     const char * v = NULL;
    00482     const char * r = NULL;
    00483     const char * evr = NULL;
    00484     Header h = NULL;
    00485     rpmRC rc = RPMRC_FAIL;              /* assume failure */
    00486     char * t;
    00487     int xx;
    00488
    00489     if (pkt == NULL || pktlen <= 0)
    00490         return RPMRC_FAIL;
    00491     if (rpmtsOpenDB(ts, (O_RDWR|O_CREAT)))
    00492         return RPMRC_FAIL;
    00493
    00494 /*@-moduncon@*/
    00495     if ((enc = b64encode(pkt, pktlen)) == NULL)
    00496         goto exit;
    00497 /*@=moduncon@*/
    00498
    00499     dig = pgpDigNew(0);
    00500
    00501     /* Build header elements. */
    00502     (void) pgpPrtPkts(pkt, pktlen, dig, 0);
    00503     pubp = pgpGetPubkey(dig);
    00504
    00505     if (!memcmp(pubp->signid, zeros, sizeof(pubp->signid))
    00506      || !memcmp(pubp->time, zeros, sizeof(pubp->time))
    00507      || pubp->userid == NULL)
    00508         goto exit;
    00509
    00510     v = t = xmalloc(16+1);
    00511     t = stpcpy(t, pgpHexStr(pubp->signid, sizeof(pubp->signid)));
    00512
    00513     r = t = xmalloc(8+1);
    00514     t = stpcpy(t, pgpHexStr(pubp->time, sizeof(pubp->time)));
    00515
    00516     n = t = xmalloc(sizeof("gpg()")+8);
    00517     t = stpcpy( stpcpy( stpcpy(t, "gpg("), v+8), ")");
    00518
    00519     /*@-nullpass@*/ /* FIX: pubp->userid may be NULL */
    00520     u = t = xmalloc(sizeof("gpg()")+strlen(pubp->userid));
    00521     t = stpcpy( stpcpy( stpcpy(t, "gpg("), pubp->userid), ")");
    00522     /*@=nullpass@*/
    00523
    00524     evr = t = xmalloc(sizeof("4X:-")+strlen(v)+strlen(r));
    00525     t = stpcpy(t, (pubp->version == 4 ? "4:" : "3:"));
    00526     t = stpcpy( stpcpy( stpcpy(t, v), "-"), r);
    00527
    00528     /* Check for pre-existing header. */
    00529
    00530     /* Build pubkey header. */
    00531     h = headerNew();
    00532
    00533     he->append = 1;
    00534
    00535     he->tag = RPMTAG_PUBKEYS;
    00536     he->t = RPM_STRING_ARRAY_TYPE;
    00537     he->p.argv = &enc;
    00538     he->c = 1;
    00539     xx = headerPut(h, he, 0);
    00540
    00541     he->append = 0;
    00542
    00543     d = headerSprintf(h, afmt, NULL, rpmHeaderFormats, NULL);
    00544     if (d == NULL)
    00545         goto exit;
    00546
    00547     he->t = RPM_STRING_TYPE;
    00548     he->c = 1;
    00549     he->tag = RPMTAG_NAME;
    00550     he->p.str = "gpg-pubkey";
    00551     xx = headerPut(h, he, 0);
    00552     he->tag = RPMTAG_VERSION;
    00553     he->p.str = v+8;
    00554     xx = headerPut(h, he, 0);
    00555     he->tag = RPMTAG_RELEASE;
    00556     he->p.str = r;
    00557     xx = headerPut(h, he, 0);
    00558
    00559     /* Add Summary/Description/Group. */
    00560     he->tag = RPMTAG_DESCRIPTION;
    00561     he->p.str = d;
    00562 #if defined(SUPPORT_IMPLICIT_TAG_DATA_TYPES)
    00563     xx = headerAddI18NString(h, he->tag, he->p.ptr, "C");
    00564 #else
    00565     xx = headerPut(h, he, 0);
    00566 #endif
    00567     he->tag = RPMTAG_GROUP;
    00568     he->p.str = group;
    00569 #if defined(SUPPORT_IMPLICIT_TAG_DATA_TYPES)
    00570     xx = headerAddI18NString(h, he->tag, he->p.ptr, "C");
    00571 #else
    00572     xx = headerPut(h, he, 0);
    00573 #endif
    00574     he->tag = RPMTAG_SUMMARY;
    00575     he->p.str = u;
    00576 #if defined(SUPPORT_IMPLICIT_TAG_DATA_TYPES)
    00577     xx = headerAddI18NString(h, he->tag, he->p.ptr, "C");
    00578 #else
    00579     xx = headerPut(h, he, 0);
    00580 #endif
    00581
    00582 #ifdef  NOTYET  /* XXX can't erase pubkeys with "pubkey" arch. */
    00583     /* Add a "pubkey" arch/os to avoid missing value NULL ptrs. */
    00584     he->tag = RPMTAG_ARCH;
    00585     he->p.str = "pubkey";
    00586     xx = headerPut(h, he, 0);
    00587     he->tag = RPMTAG_OS;
    00588     he->p.str = "pubkey";
    00589     xx = headerPut(h, he, 0);
    00590 #endif
    00591
    00592     he->tag = RPMTAG_LICENSE;
    00593     he->p.str = license;
    00594     xx = headerPut(h, he, 0);
    00595
    00596     he->tag = RPMTAG_SIZE;
    00597     he->t = RPM_UINT32_TYPE;
    00598     he->p.ui32p = &zero;
    00599     he->c = 1;
    00600     xx = headerPut(h, he, 0);
    00601
    00602     he->append = 1;
    00603
    00604     he->tag = RPMTAG_PROVIDENAME;
    00605     he->t = RPM_STRING_ARRAY_TYPE;
    00606     he->p.argv = &u;
    00607     he->c = 1;
    00608     xx = headerPut(h, he, 0);
    00609     he->tag = RPMTAG_PROVIDEVERSION;
    00610     he->t = RPM_STRING_ARRAY_TYPE;
    00611     he->p.argv = &evr;
    00612     he->c = 1;
    00613     xx = headerPut(h, he, 0);
    00614     he->tag = RPMTAG_PROVIDEFLAGS;
    00615     he->t = RPM_UINT32_TYPE;
    00616     he->p.ui32p = &pflags;
    00617     he->c = 1;
    00618     xx = headerPut(h, he, 0);
    00619
    00620     he->tag = RPMTAG_PROVIDENAME;
    00621     he->t = RPM_STRING_ARRAY_TYPE;
    00622     he->p.argv = &n;
    00623     he->c = 1;
    00624     xx = headerPut(h, he, 0);
    00625     he->tag = RPMTAG_PROVIDEVERSION;
    00626     he->t = RPM_STRING_ARRAY_TYPE;
    00627     he->p.argv = &evr;
    00628     he->c = 1;
    00629     xx = headerPut(h, he, 0);
    00630     he->tag = RPMTAG_PROVIDEFLAGS;
    00631     he->t = RPM_UINT32_TYPE;
    00632     he->p.ui32p = &pflags;
    00633     he->c = 1;
    00634     xx = headerPut(h, he, 0);
    00635
    00636     he->append = 0;
    00637
    00638     he->tag = RPMTAG_RPMVERSION;
    00639     he->t = RPM_STRING_TYPE;
    00640     he->p.str = RPMVERSION;
    00641     he->c = 1;
    00642     xx = headerPut(h, he, 0);
    00643
    00644     /* XXX W2DO: tag value inheirited from parent? */
    00645     he->tag = RPMTAG_BUILDHOST;
    00646     he->t = RPM_STRING_TYPE;
    00647     he->p.str = buildhost;
    00648     he->c = 1;
    00649     xx = headerPut(h, he, 0);
    00650     {   uint32_t tid = rpmtsGetTid(ts);
    00651         he->tag = RPMTAG_INSTALLTIME;
    00652         he->t = RPM_UINT32_TYPE;
    00653         he->p.ui32p = &tid;
    00654         he->c = 1;
    00655         xx = headerPut(h, he, 0);
    00656         /* XXX W2DO: tag value inheirited from parent? */
    00657         he->tag = RPMTAG_BUILDTIME;
    00658         he->t = RPM_UINT32_TYPE;
    00659         he->p.ui32p = &tid;
    00660         he->c = 1;
    00661         xx = headerPut(h, he, 0);
    00662     }
    00663
    00664 #ifdef  NOTYET
    00665     /* XXX W2DO: tag value inheirited from parent? */
    00666     he->tag = RPMTAG_SOURCERPM;
    00667     he->t = RPM_STRING_TYPE;
    00668     he->p.str = fn;
    00669     he->c = 1;
    00670     xx = headerPut(h, he, 0);
    00671 #endif
    00672
    00673     /* Add header to database. */
    00674     xx = rpmdbAdd(rpmtsGetRdb(ts), rpmtsGetTid(ts), h, NULL);
    00675     if (xx != 0)
    00676         goto exit;
    00677     rc = RPMRC_OK;
    00678
    00679 exit:
    00680     /* Clean up. */
    00681     h = headerFree(h);
    00682     dig = pgpDigFree(dig);
    00683     n = _free(n);
    00684     u = _free(u);
    00685     v = _free(v);
    00686     r = _free(r);
    00687     evr = _free(evr);
    00688     enc = _free(enc);
    00689     d = _free(d);
    00690
    00691     return rc;
    00692 }
    00693
    00702 static int rpmcliImportPubkeys(const rpmts ts,
    00703                 /*@unused@*/ QVA_t qva,
    00704                 /*@null@*/ const char ** argv)
    00705         /*@globals RPMVERSION, rpmGlobalMacroContext, h_errno,
    00706                 fileSystem, internalState @*/
    00707         /*@modifies ts, rpmGlobalMacroContext,
    00708                 fileSystem, internalState @*/
    00709 {
    00710     const char * fn;
    00711     const unsigned char * pkt = NULL;
    00712     size_t pktlen = 0;
    00713     char * t = NULL;
    00714     int res = 0;
    00715     rpmRC rpmrc;
    00716     int rc;
    00717
    00718     if (argv == NULL) return res;
    00719
    00720     while ((fn = *argv++) != NULL) {
    00721
    00722         rpmtsClean(ts);
    00723         pkt = _free(pkt);
    00724         t = _free(t);
    00725
    00726         /* If arg looks like a keyid, then attempt keyserver retrieve. */
    00727         if (fn[0] == '0' && fn[1] == 'x') {
    00728             const char * s;
    00729             int i;
    00730             for (i = 0, s = fn+2; *s && isxdigit(*s); s++, i++)
    00731                 {};
    00732             if (i == 8 || i == 16) {
    00733                 t = rpmExpand("%{_hkp_keyserver_query}", fn+2, NULL);
    00734                 if (t && *t != '%')
    00735                     fn = t;
    00736             }
    00737         }
    00738
    00739         /* Read pgp packet. */
    00740         if ((rc = pgpReadPkts(fn, &pkt, &pktlen)) <= 0) {
    00741             rpmlog(RPMLOG_ERR, _("%s: import read failed(%d).\n"), fn, rc);
    00742             res++;
    00743             continue;
    00744         }
    00745         if (rc != PGPARMOR_PUBKEY) {
    00746             rpmlog(RPMLOG_ERR, _("%s: not an armored public key.\n"), fn);
    00747             res++;
    00748             continue;
    00749         }
    00750
    00751         /* Import pubkey packet(s). */
    00752         if ((rpmrc = rpmcliImportPubkey(ts, pkt, pktlen)) != RPMRC_OK) {
    00753             rpmlog(RPMLOG_ERR, _("%s: import failed.\n"), fn);
    00754             res++;
    00755             continue;
    00756         }
    00757
    00758     }
    00759
    00760 rpmtsClean(ts);
    00761     pkt = _free(pkt);
    00762     t = _free(t);
    00763     return res;
    00764 }
    00765
    00769 static rpmRC readFile(FD_t fd, const char * fn)
    00770         /*@globals fileSystem, internalState @*/
    00771         /*@modifies fd, fileSystem, internalState @*/
    00772 {
    00773 rpmxar xar = fdGetXAR(fd);
    00774 pgpDig dig = fdGetDig(fd);
    00775     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00776     unsigned char buf[4*BUFSIZ];
    00777     ssize_t count;
    00778     rpmRC rc;
    00779     int xx;
    00780
    00781     dig->nbytes = 0;
    00782
    00783     /* Read the header from the package. */
    00784     {   Header h = NULL;
    00785         const char item[] = "Header";
    00786         const char * msg = NULL;
    00787         rc = rpmpkgRead(item, fd, &h, &msg);
    00788         if (rc != RPMRC_OK) {
    00789             rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
    00790             msg = _free(msg);
    00791             goto exit;
    00792         }
    00793         msg = _free(msg);
    00794
    00795         dig->nbytes += headerSizeof(h);
    00796
    00797         if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
    00798             unsigned char * hmagic = NULL;
    00799             size_t nmagic = 0;
    00800
    00801             he->tag = RPMTAG_HEADERIMMUTABLE;
    00802             xx = headerGet(h, he, 0);
    00803             if (!xx || he->p.ptr == NULL) {
    00804                 h = headerFree(h);
    00805                 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, _("headerGet failed"),
    00806                         _("failed to retrieve original header\n"));
    00807                 rc = RPMRC_FAIL;
    00808                 goto exit;
    00809             }
    00810             (void) headerGetMagic(NULL, &hmagic, &nmagic);
    00811             dig->hdrsha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
    00812             if (hmagic && nmagic > 0)
    00813                 (void) rpmDigestUpdate(dig->hdrsha1ctx, hmagic, nmagic);
    00814             (void) rpmDigestUpdate(dig->hdrsha1ctx, he->p.ptr, he->c);
    00815             dig->hdrmd5ctx = rpmDigestInit(dig->signature.hash_algo, RPMDIGEST_NONE);
    00816             if (hmagic && nmagic > 0)
    00817                 (void) rpmDigestUpdate(dig->hdrmd5ctx, hmagic, nmagic);
    00818             (void) rpmDigestUpdate(dig->hdrmd5ctx, he->p.ptr, he->c);
    00819             he->p.ptr = _free(he->p.ptr);
    00820         }
    00821         h = headerFree(h);
    00822     }
    00823
    00824     if (xar != NULL) {
    00825         const char item[] = "Payload";
    00826         if ((xx = rpmxarNext(xar)) != 0 || (xx = rpmxarPull(xar, item)) != 0) {
    00827             rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item,
    00828                 _("XAR file not found (or no XAR support)"));
    00829             rc = RPMRC_NOTFOUND;
    00830             goto exit;
    00831         }
    00832     }
    00833
    00834     /* Read the payload from the package. */
    00835     while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
    00836         dig->nbytes += count;
    00837     if (count < 0 || Ferror(fd)) {
    00838         rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, _("Fread failed"), Fstrerror(fd));
    00839         rc = RPMRC_FAIL;
    00840         goto exit;
    00841     }
    00842
    00843     /* XXX Steal the digest-in-progress from the file handle. */
    00844     fdStealDigest(fd, dig);
    00845
    00846     rc = RPMRC_OK;      /* XXX unnecessary */
    00847
    00848 exit:
    00849     return rc;
    00850 }
    00851
    00852 int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd,
    00853                 const char * fn)
    00854 {
    00855     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00856     HE_t she = memset(alloca(sizeof(*she)), 0, sizeof(*she));
    00857     int res2, res3;
    00858     char result[1024];
    00859     char buf[8192], * b;
    00860     char missingKeys[7164], * m;
    00861     char untrustedKeys[7164], * u;
    00862     pgpDig dig;
    00863     pgpDigParams sigp;
    00864     Header sigh = NULL;
    00865     HeaderIterator hi = NULL;
    00866     const char * msg = NULL;
    00867     int res = 0;
    00868     int xx;
    00869     rpmRC rc;
    00870     int nodigests = !(qva->qva_flags & VERIFY_DIGEST);
    00871     int nosignatures = !(qva->qva_flags & VERIFY_SIGNATURE);
    00872
    00873     if ((rc = rpmtsOpenDB(ts, rpmtsDBMode(ts))) != RPMRC_OK) {
    00874         /* XXX rpmtsOpenDB has reported the error. */
    00875         res++;
    00876         goto exit;
    00877     }
    00878
    00879     {
    00880         {   const char item[] = "Lead";
    00881             msg = NULL;
    00882             rc = rpmpkgRead(item, fd, NULL, &msg);
    00883             if (rc != RPMRC_OK) {
    00884                 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
    00885                 msg = _free(msg);
    00886                 res++;
    00887                 goto exit;
    00888             }
    00889             msg = _free(msg);
    00890         }
    00891
    00892         {   const char item[] = "Signature";
    00893             msg = NULL;
    00894             rc = rpmpkgRead(item, fd, &sigh, &msg);
    00895             switch (rc) {
    00896             default:
    00897                 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item,
    00898                         (msg && *msg ? msg : ""));
    00899                 msg = _free(msg);
    00900                 res++;
    00901                 goto exit;
    00902                 /*@notreached@*/ /*@switchbreak@*/ break;
    00903             case RPMRC_OK:
    00904                 if (sigh == NULL) {
    00905                     rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), fn);
    00906                     res++;
    00907                     goto exit;
    00908                 }
    00909                 /*@switchbreak@*/ break;
    00910             }
    00911             msg = _free(msg);
    00912         }
    00913
    00914         /* Grab a hint of what needs doing to avoid duplication. */
    00915         she->tag = 0;
    00916         if (she->tag == 0 && !nosignatures) {
    00917             if (headerIsEntry(sigh, (rpmTag) RPMSIGTAG_DSA))
    00918                 she->tag = (rpmTag) RPMSIGTAG_DSA;
    00919             else if (headerIsEntry(sigh, (rpmTag) RPMSIGTAG_RSA))
    00920                 she->tag = (rpmTag) RPMSIGTAG_RSA;
    00921         }
    00922         if (she->tag == 0 && !nodigests) {
    00923             if (headerIsEntry(sigh, (rpmTag) RPMSIGTAG_MD5))
    00924                 she->tag = (rpmTag) RPMSIGTAG_MD5;
    00925             else if (headerIsEntry(sigh, (rpmTag) RPMSIGTAG_SHA1))
    00926                 she->tag = (rpmTag) RPMSIGTAG_SHA1;     /* XXX never happens */
    00927         }
    00928
    00929         dig = rpmtsDig(ts);
    00930         (void) fdSetDig(fd, dig);
    00931         sigp = pgpGetSignature(dig);
    00932
    00933         /* XXX RSA needs the hash_algo, so decode early. */
    00934         if ((rpmSigTag) she->tag == RPMSIGTAG_RSA) {
    00935             he->tag = she->tag;
    00936             xx = headerGet(sigh, he, 0);
    00937             xx = pgpPrtPkts(he->p.ptr, he->c, dig, 0);
    00938             he->p.ptr = _free(he->p.ptr);
    00939         }
    00940
    00941         if (headerIsEntry(sigh, (rpmTag)RPMSIGTAG_MD5))
    00942             fdInitDigest(fd, PGPHASHALGO_MD5, 0);
    00943
    00944         /* Read the file, generating digest(s) on the fly. */
    00945         if (dig == NULL || sigp == NULL
    00946          || readFile(fd, fn) != RPMRC_OK)
    00947         {
    00948             res++;
    00949             goto exit;
    00950         }
    00951
    00952         res2 = 0;
    00953         b = buf;                *b = '\0';
    00954         m = missingKeys;        *m = '\0';
    00955         u = untrustedKeys;      *u = '\0';
    00956         sprintf(b, "%s:%c", fn, (rpmIsVerbose() ? '\n' : ' ') );
    00957         b += strlen(b);
    00958
    00959         if (sigh != NULL)
    00960         for (hi = headerInit(sigh);
    00961             headerNext(hi, she, 0) != 0;
    00962             she->p.ptr = _free(she->p.ptr))
    00963         {
    00964
    00965 assert(she->p.ptr != NULL);
    00966
    00967             /* Clean up parameters from previous she->tag. */
    00968             pgpDigClean(dig);
    00969
    00970 /*@-noeffect@*/
    00971             xx = pgpSetSig(dig, she->tag, she->t, she->p.ptr, she->c);
    00972 /*@=noeffect@*/
    00973
    00974             switch ((rpmSigTag)she->tag) {
    00975             case RPMSIGTAG_RSA:
    00976             case RPMSIGTAG_DSA:
    00977                 if (nosignatures)
    00978                      continue;
    00979                 xx = pgpPrtPkts(she->p.ptr, she->c, dig,
    00980                         (_print_pkts & rpmIsDebug()));
    00981
    00982                 if (sigp->version != 3 && sigp->version != 4) {
    00983                     rpmlog(RPMLOG_ERR,
    00984                 _("skipping package %s with unverifiable V%u signature\n"),
    00985                         fn, sigp->version);
    00986                     res++;
    00987                     goto exit;
    00988                 }
    00989                 /*@switchbreak@*/ break;
    00990             case RPMSIGTAG_SHA1:
    00991                 if (nodigests)
    00992                      continue;
    00993                 /* XXX Don't bother with header sha1 if header dsa. */
    00994                 if (!nosignatures && (rpmSigTag)she->tag == RPMSIGTAG_DSA)
    00995                     continue;
    00996                 /*@switchbreak@*/ break;
    00997             case RPMSIGTAG_MD5:
    00998                 if (nodigests)
    00999                      continue;
    01000                 /*@switchbreak@*/ break;
    01001             default:
    01002                 continue;
    01003                 /*@notreached@*/ /*@switchbreak@*/ break;
    01004             }
    01005
    01006             res3 = rpmVerifySignature(dig, result);
    01007
    01008             if (res3) {
    01009                 if (rpmIsVerbose()) {
    01010                     b = stpcpy( stpcpy( stpcpy(b, "    "), result), "\n");
    01011                     res2 = 1;
    01012                 } else {
    01013                     switch ((rpmSigTag)she->tag) {
    01014                     case RPMSIGTAG_SIZE:
    01015                         b = stpcpy(b, "SIZE ");
    01016                         res2 = 1;
    01017                         /*@switchbreak@*/ break;
    01018                     case RPMSIGTAG_SHA1:
    01019                         b = stpcpy(b, "SHA1 ");
    01020                         res2 = 1;
    01021                         /*@switchbreak@*/ break;
    01022                     case RPMSIGTAG_MD5:
    01023                         b = stpcpy(b, "MD5 ");
    01024                         res2 = 1;
    01025                         /*@switchbreak@*/ break;
    01026                     case RPMSIGTAG_RSA:
    01027                         b = stpcpy(b, "RSA ");
    01028                         res2 = 1;
    01029                         /*@switchbreak@*/ break;
    01030                     case RPMSIGTAG_DSA:
    01031                         b = stpcpy(b, "(SHA1) DSA ");
    01032                         res2 = 1;
    01033                         /*@switchbreak@*/ break;
    01034                     default:
    01035                         b = stpcpy(b, "?UnknownSignatureType? ");
    01036                         res2 = 1;
    01037                         /*@switchbreak@*/ break;
    01038                     }
    01039                 }
    01040             } else {
    01041                 if (rpmIsVerbose()) {
    01042                     b = stpcpy( stpcpy( stpcpy(b, "    "), result), "\n");
    01043                 } else {
    01044                     switch ((rpmSigTag)she->tag) {
    01045                     case RPMSIGTAG_SIZE:
    01046                         b = stpcpy(b, "size ");
    01047                         /*@switchbreak@*/ break;
    01048                     case RPMSIGTAG_SHA1:
    01049                         b = stpcpy(b, "sha1 ");
    01050                         /*@switchbreak@*/ break;
    01051                     case RPMSIGTAG_MD5:
    01052                         b = stpcpy(b, "md5 ");
    01053                         /*@switchbreak@*/ break;
    01054                     case RPMSIGTAG_RSA:
    01055                         b = stpcpy(b, "rsa ");
    01056                         /*@switchbreak@*/ break;
    01057                     case RPMSIGTAG_DSA:
    01058                         b = stpcpy(b, "(sha1) dsa ");
    01059                         /*@switchbreak@*/ break;
    01060                     default:
    01061                         b = stpcpy(b, "??? ");
    01062                         /*@switchbreak@*/ break;
    01063                     }
    01064                 }
    01065             }
    01066         }
    01067         hi = headerFini(hi);
    01068         /* XXX clear the already free'd signature data. */
    01069 /*@-noeffect@*/
    01070         xx = pgpSetSig(dig, 0, 0, NULL, 0);
    01071 /*@=noeffect@*/
    01072
    01073         res += res2;
    01074
    01075         if (res2) {
    01076             if (rpmIsVerbose()) {
    01077                 rpmlog(RPMLOG_NOTICE, "%s", buf);
    01078             } else {
    01079                 rpmlog(RPMLOG_NOTICE, "%s%s%s%s%s%s%s%s\n", buf,
    01080                         _("NOT OK"),
    01081                         (missingKeys[0] != '\0') ? _(" (MISSING KEYS:") : "",
    01082                         missingKeys,
    01083                         (missingKeys[0] != '\0') ? _(") ") : "",
    01084                         (untrustedKeys[0] != '\0') ? _(" (UNTRUSTED KEYS:") : "",
    01085                         untrustedKeys,
    01086                         (untrustedKeys[0] != '\0') ? _(")") : "");
    01087
    01088             }
    01089         } else {
    01090             if (rpmIsVerbose()) {
    01091                 rpmlog(RPMLOG_NOTICE, "%s", buf);
    01092             } else {
    01093                 rpmlog(RPMLOG_NOTICE, "%s%s%s%s%s%s%s%s\n", buf,
    01094                         _("OK"),
    01095                         (missingKeys[0] != '\0') ? _(" (MISSING KEYS:") : "",
    01096                         missingKeys,
    01097                         (missingKeys[0] != '\0') ? _(") ") : "",
    01098                         (untrustedKeys[0] != '\0') ? _(" (UNTRUSTED KEYS:") : "",
    01099                         untrustedKeys,
    01100                         (untrustedKeys[0] != '\0') ? _(")") : "");
    01101             }
    01102         }
    01103
    01104     }
    01105
    01106 exit:
    01107     rpmtsCleanDig(ts);
    01108     sigh = headerFree(sigh);
    01109     return res;
    01110 }
    01111
    01112 int rpmcliSign(rpmts ts, QVA_t qva, const char ** argv)
    01113 {
    01114     int res = 0;
    01115
    01116     if (argv == NULL) return res;
    01117
    01118     switch (qva->qva_mode) {
    01119     case RPMSIGN_CHK_SIGNATURE:
    01120         break;
    01121     case RPMSIGN_IMPORT_PUBKEY:
    01122         return rpmcliImportPubkeys(ts, qva, argv);
    01123         /*@notreached@*/ break;
    01124     case RPMSIGN_NEW_SIGNATURE:
    01125     case RPMSIGN_ADD_SIGNATURE:
    01126     case RPMSIGN_DEL_SIGNATURE:
    01127         return rpmReSign(ts, qva, argv);
    01128         /*@notreached@*/ break;
    01129     case RPMSIGN_NONE:
    01130     default:
    01131         return -1;
    01132         /*@notreached@*/ break;
    01133     }
    01134
    01135 {       /* start-of-arg-iteration */
    01136
    01137     int tag = (qva->qva_source == RPMQV_FTSWALK)
    01138         ? RPMDBI_FTSWALK : RPMDBI_ARGLIST;
    01139     rpmgi gi = rpmgiNew(ts, tag, NULL, 0);
    01140     rpmgiFlags _giFlags = RPMGI_NONE;
    01141     rpmRC rc;
    01142
    01143 /*@-mods@*/
    01144     if (ftsOpts == 0)
    01145         ftsOpts = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
    01146 /*@=mods@*/
    01147     rc = rpmgiSetArgs(gi, argv, ftsOpts, (_giFlags|RPMGI_NOHEADER));
    01148     while (rpmgiNext(gi) == RPMRC_OK) {
    01149         const char * fn = rpmgiHdrPath(gi);
    01150         FD_t fd;
    01151         int xx;
    01152
    01153         fd = Fopen(fn, "r.fdio");
    01154         if (fd == NULL || Ferror(fd)) {
    01155             rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"),
    01156                      fn, Fstrerror(fd));
    01157             res++;
    01158         } else if (rpmVerifySignatures(qva, ts, fd, fn)) {
    01159             res++;
    01160         }
    01161
    01162         if (fd != NULL) {
    01163             xx = Fclose(fd);
    01164         }
    01165     }
    01166
    01167     gi = rpmgiFree(gi);
    01168
    01169 }       /* end-of-arg-iteration */
    01170
    01171     return res;
    01172 }