Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

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

Generated on Sun Oct 26 13:02:00 2003 for rpm by doxygen1.2.18