lib/rpmchecksig.c

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

Generated on Fri Oct 12 08:44:53 2007 for rpm by  doxygen 1.5.2