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