rpm 5.2.1

lib/rpmchecksig.c

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