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