diff options
author | jbj <devnull@localhost> | 2002-03-03 23:09:49 +0000 |
---|---|---|
committer | jbj <devnull@localhost> | 2002-03-03 23:09:49 +0000 |
commit | 2e2d1cad39b9bf8af73ec7b2c584236aabcdad14 (patch) | |
tree | 29804eebc51fc8e0143e62a7743f1c635b25820e | |
parent | 48b19eaedae1d80691073730628c3ef806d6322d (diff) | |
download | librpm-tizen-2e2d1cad39b9bf8af73ec7b2c584236aabcdad14.tar.gz librpm-tizen-2e2d1cad39b9bf8af73ec7b2c584236aabcdad14.tar.bz2 librpm-tizen-2e2d1cad39b9bf8af73ec7b2c584236aabcdad14.zip |
- add payload uncompressed size to signature to avoid rewriting header.
- drill header sha1 into signature parallel to header+payload md5.
- mandatory "most effective" signature check on query/verify/install.
- don't bother adding empty filemd's to index.
- add Pubkey index, using signer id as binary key.
- display pubkeys in hex when debugging db access.
- retrieve pubkey(s) from rpmdb, not from detached signature file.
- reapply Berkeley DB patch #4491.
CVS patchset: 5341
CVS date: 2002/03/03 23:09:49
-rw-r--r-- | CHANGES | 8 | ||||
-rw-r--r-- | build/pack.c | 15 | ||||
-rw-r--r-- | db/hash/hash_dup.c | 265 | ||||
-rw-r--r-- | db/hash/hash_page.c | 523 | ||||
-rw-r--r-- | lib/package.c | 151 | ||||
-rw-r--r-- | lib/query.c | 2 | ||||
-rw-r--r-- | lib/rpmchecksig.c | 44 | ||||
-rw-r--r-- | lib/rpmlib.h | 13 | ||||
-rw-r--r-- | lib/signature.c | 328 | ||||
-rw-r--r-- | lib/verify.c | 2 | ||||
-rw-r--r-- | rpm.spec | 12 | ||||
-rw-r--r-- | rpm.spec.in | 8 | ||||
-rw-r--r-- | rpmdb/rpmdb.c | 157 | ||||
-rw-r--r-- | rpmdb/rpmdb.h | 1 | ||||
-rw-r--r-- | rpmio/rpmio_internal.h | 10 |
15 files changed, 1123 insertions, 416 deletions
@@ -81,6 +81,13 @@ - splint fiddles. - make peace with gcc-3.1, remove compiler cruft. - make peace with automake et al in 8.0, ugh. + - add payload uncompressed size to signature to avoid rewriting header. + - drill header sha1 into signature parallel to header+payload md5. + - mandatory "most effective" signature check on query/verify/install. + - don't bother adding empty filemd's to index. + - add Pubkey index, using signer id as binary key. + - display pubkeys in hex when debugging db access. + - retrieve pubkey(s) from rpmdb, not from detached signature file. 4.0.3 -> 4.0.4: - solaris: translate i86pc to i386 (#57182). @@ -127,6 +134,7 @@ - query/verify by install transaction id. - rpm-4.0.4 release candidate. - add cpanflute2, another perl.req fiddle. + - reapply Berkeley DB patch #4491. 4.0.2 -> 4.0.3: - update per-interpreter dependency scripts, add sql/tcl (#20295). diff --git a/build/pack.c b/build/pack.c index 1f0e98221..33b81e9a8 100644 --- a/build/pack.c +++ b/build/pack.c @@ -410,12 +410,14 @@ int writeRPM(Header *hdrp, const char *fileName, int type, h = headerLink(*hdrp, "writeRPM xfer"); *hdrp = headerFree(*hdrp, "writeRPM xfer"); +#ifdef DYING if (Fileno(csa->cpioFdIn) < 0) { csa->cpioArchiveSize = 0; /* Add a bogus archive size to the Header */ (void) headerAddEntry(h, RPMTAG_ARCHIVESIZE, RPM_INT32_TYPE, &csa->cpioArchiveSize, 1); } +#endif /* Binary packages now have explicit Provides: name = version-release. */ if (type == RPMLEAD_BINARY) @@ -480,10 +482,12 @@ int writeRPM(Header *hdrp, const char *fileName, int type, goto exit; } + fdInitDigest(fd, PGPHASHALGO_SHA1, 0); if (headerWrite(fd, h, HEADER_MAGIC_YES)) { rc = RPMERR_NOSPACE; rpmError(RPMERR_NOSPACE, _("Unable to write temp header\n")); } else { /* Write the archive and get the size */ + fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&sha1, NULL, 1); if (csa->cpioList != NULL) { rc = cpio_doio(fd, h, csa, rpmio_flags); } else if (Fileno(csa->cpioFdIn) >= 0) { @@ -498,6 +502,7 @@ int writeRPM(Header *hdrp, const char *fileName, int type, if (rc) goto exit; +#ifdef DYING /* * Set the actual archive size, and rewrite the header. * This used to be done using headerModifyEntry(), but now that headers @@ -529,6 +534,7 @@ int writeRPM(Header *hdrp, const char *fileName, int type, } (void) Fflush(fd); fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&sha1, NULL, 1); +#endif (void) Fclose(fd); fd = NULL; @@ -542,16 +548,22 @@ int writeRPM(Header *hdrp, const char *fileName, int type, sig = rpmNewSignature(); (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_SIZE, passPhrase); (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_MD5, passPhrase); + if ((sigtype = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) > 0) { rpmMessage(RPMMESS_NORMAL, _("Generating signature: %d\n"), sigtype); (void) rpmAddSignature(sig, sigtarget, sigtype, passPhrase); } if (sha1) { - (void) headerAddEntry(sig, RPMTAG_SHA1HEADER, RPM_STRING_TYPE, sha1, 1); + (void) headerAddEntry(sig, RPMSIGTAG_SHA1, RPM_STRING_TYPE, sha1, 1); sha1 = _free(sha1); } + { int_32 payloadSize = csa->cpioArchiveSize; + (void) headerAddEntry(sig, RPMSIGTAG_PAYLOADSIZE, RPM_INT32_TYPE, + &payloadSize, 1); + } + /* Reallocate the signature into one contiguous region. */ sig = headerReload(sig, RPMTAG_HEADERSIGNATURES); if (sig == NULL) { /* XXX can't happen */ @@ -621,6 +633,7 @@ int writeRPM(Header *hdrp, const char *fileName, int type, } /* Add signatures to header, and write header into the package. */ + /* XXX header+payload digests/signatures might be checked again here. */ { Header nh = headerRead(ifd, HEADER_MAGIC_YES); if (nh == NULL) { diff --git a/db/hash/hash_dup.c b/db/hash/hash_dup.c index f5fbf4f47..ad06c522c 100644 --- a/db/hash/hash_dup.c +++ b/db/hash/hash_dup.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Copyright (c) 1996-2001 * Sleepycat Software. All rights reserved. */ /* @@ -38,7 +38,7 @@ #include "db_config.h" #ifndef lint -static const char revid[] = "$Id: hash_dup.c,v 11.49 2000/12/21 21:54:35 margo Exp $"; +static const char revid[] = "Id: hash_dup.c,v 11.65 2001/08/13 19:11:37 bostic Exp "; #endif /* not lint */ /* @@ -66,8 +66,11 @@ static const char revid[] = "$Id: hash_dup.c,v 11.49 2000/12/21 21:54:35 margo E #include "btree.h" #include "txn.h" +static int __ham_c_chgpg __P((DBC *, + db_pgno_t, u_int32_t, db_pgno_t, u_int32_t)); static int __ham_check_move __P((DBC *, u_int32_t)); static int __ham_dcursor __P((DBC *, db_pgno_t, u_int32_t)); +static int __ham_move_offpage __P((DBC *, PAGE *, u_int32_t, db_pgno_t)); /* * Called from hash_access to add a duplicate key. nval is the new @@ -92,13 +95,15 @@ __ham_add_dup(dbc, nval, flags, pgnop) db_pgno_t *pgnop; { DB *dbp; - HASH_CURSOR *hcp; DBT pval, tmp_val; + DB_MPOOLFILE *mpf; + HASH_CURSOR *hcp; u_int32_t add_bytes, new_size; int cmp, ret; u_int8_t *hk; dbp = dbc->dbp; + mpf = dbp->mpf; hcp = (HASH_CURSOR *)dbc->internal; DB_ASSERT(flags != DB_CURRENT); @@ -148,8 +153,8 @@ __ham_add_dup(dbc, nval, flags, pgnop) pval.size = LEN_HDATA(hcp->page, dbp->pgsize, hcp->indx); if ((ret = __ham_make_dup(dbp->dbenv, - &pval, &tmp_val, &dbc->rdata.data, - &dbc->rdata.ulen)) != 0 || (ret = + &pval, &tmp_val, &dbc->my_rdata.data, + &dbc->my_rdata.ulen)) != 0 || (ret = __ham_replpair(dbc, &tmp_val, 1)) != 0) return (ret); hk = H_PAIRDATA(hcp->page, hcp->indx); @@ -167,7 +172,7 @@ __ham_add_dup(dbc, nval, flags, pgnop) /* Now make the new entry a duplicate. */ if ((ret = __ham_make_dup(dbp->dbenv, nval, - &tmp_val, &dbc->rdata.data, &dbc->rdata.ulen)) != 0) + &tmp_val, &dbc->my_rdata.data, &dbc->my_rdata.ulen)) != 0) return (ret); tmp_val.dlen = 0; @@ -176,7 +181,8 @@ __ham_add_dup(dbc, nval, flags, pgnop) case DB_KEYLAST: case DB_NODUPDATA: if (dbp->dup_compare != NULL) { - __ham_dsearch(dbc, nval, &tmp_val.doff, &cmp); + __ham_dsearch(dbc, + nval, &tmp_val.doff, &cmp, flags); /* dup dups are not supported w/ sorted dups */ if (cmp == 0) @@ -203,8 +209,7 @@ __ham_add_dup(dbc, nval, flags, pgnop) /* Add the duplicate. */ ret = __ham_replpair(dbc, &tmp_val, 0); if (ret == 0) - ret = memp_fset(dbp->mpf, hcp->page, DB_MPOOL_DIRTY); - + ret = mpf->set(mpf, hcp->page, DB_MPOOL_DIRTY); if (ret != 0) return (ret); @@ -245,19 +250,21 @@ int __ham_dup_convert(dbc) DBC *dbc; { + BOVERFLOW bo; DB *dbp; DBC **hcs; + DBT dbt; DB_LSN lsn; - PAGE *dp; + DB_MPOOLFILE *mpf; HASH_CURSOR *hcp; - BOVERFLOW bo; - DBT dbt; HOFFPAGE ho; + PAGE *dp; db_indx_t i, len, off; int c, ret, t_ret; u_int8_t *p, *pend; dbp = dbc->dbp; + mpf = dbp->mpf; hcp = (HASH_CURSOR *)dbc->internal; /* @@ -274,7 +281,7 @@ __ham_dup_convert(dbc) */ if ((ret = __ham_get_clist(dbp, PGNO(hcp->page), (u_int32_t)hcp->indx, &hcs)) != 0) - return (ret); + goto err; /* * Now put the duplicates onto the new page. @@ -301,12 +308,11 @@ __ham_dup_convert(dbc) dbt.data = &bo; ret = __db_pitem(dbc, dp, 0, dbt.size, &dbt, NULL); - finish: if (ret == 0) { - memp_fset(dbp->mpf, dp, DB_MPOOL_DIRTY); - /* - * Update any other cursors - */ + if ((ret = mpf->set(mpf, dp, DB_MPOOL_DIRTY)) != 0) + break; + + /* Update any other cursors. */ if (hcs != NULL && DB_LOGGING(dbc) && IS_SUBTRANSACTION(dbc->txn)) { if ((ret = __ham_chgpg_log(dbp->dbenv, @@ -319,10 +325,8 @@ finish: if (ret == 0) { if ((ret = __ham_dcursor(hcs[c], PGNO(dp), 0)) != 0) break; - } break; - case H_DUPLICATE: p = HKEYDATA_DATA(H_PAIRDATA(hcp->page, hcp->indx)); pend = p + @@ -344,39 +348,49 @@ finish: if (ret == 0) { if ((ret = __db_pitem(dbc, dp, i, BKEYDATA_SIZE(dbt.size), NULL, &dbt)) != 0) break; - /* - * Update any other cursors - */ + + /* Update any other cursors */ + if (hcs != NULL && DB_LOGGING(dbc) + && IS_SUBTRANSACTION(dbc->txn)) { + if ((ret = __ham_chgpg_log(dbp->dbenv, + dbc->txn, &lsn, 0, dbp->log_fileid, + DB_HAM_DUP, PGNO(hcp->page), + PGNO(dp), hcp->indx, i)) != 0) + break; + } for (c = 0; hcs != NULL && hcs[c] != NULL; c++) if (((HASH_CURSOR *)(hcs[c]->internal))->dup_off == off && (ret = __ham_dcursor(hcs[c], PGNO(dp), i)) != 0) - goto out; + goto err; off += len + 2 * sizeof(db_indx_t); } -out: break; - + break; default: - ret = __db_pgfmt(dbp, (u_long)hcp->pgno); + ret = __db_pgfmt(dbp->dbenv, (u_long)hcp->pgno); break; } - if (ret == 0) { - /* - * Now attach this to the source page in place of - * the old duplicate item. - */ - __ham_move_offpage(dbc, hcp->page, + + /* + * Now attach this to the source page in place of the old duplicate + * item. + */ + if (ret == 0) + ret = __ham_move_offpage(dbc, hcp->page, (u_int32_t)H_DATAINDEX(hcp->indx), PGNO(dp)); - ret = memp_fset(dbp->mpf, hcp->page, DB_MPOOL_DIRTY); - if ((t_ret = memp_fput(dbp->mpf, dp, DB_MPOOL_DIRTY)) != 0) - ret = t_ret; +err: if (ret == 0) + ret = mpf->set(mpf, hcp->page, DB_MPOOL_DIRTY); + + if ((t_ret = + mpf->put(mpf, dp, ret == 0 ? DB_MPOOL_DIRTY : 0)) != 0 && ret == 0) + ret = t_ret; + + if (ret == 0) hcp->dup_tlen = hcp->dup_off = hcp->dup_len = 0; - } else - (void)__db_free(dbc, dp); if (hcs != NULL) - __os_free(hcs, 0); + __os_free(dbp->dbenv, hcs, 0); return (ret); } @@ -444,9 +458,10 @@ __ham_check_move(dbc, add_len) u_int32_t add_len; { DB *dbp; - HASH_CURSOR *hcp; DBT k, d; DB_LSN new_lsn; + DB_MPOOLFILE *mpf; + HASH_CURSOR *hcp; PAGE *next_pagep; db_pgno_t next_pgno; u_int32_t new_datalen, old_len, rectype; @@ -454,6 +469,7 @@ __ham_check_move(dbc, add_len) int ret; dbp = dbc->dbp; + mpf = dbp->mpf; hcp = (HASH_CURSOR *)dbc->internal; hk = H_PAIRDATA(hcp->page, hcp->indx); @@ -500,10 +516,10 @@ __ham_check_move(dbc, add_len) for (next_pgno = NEXT_PGNO(hcp->page); next_pgno != PGNO_INVALID; next_pgno = NEXT_PGNO(next_pagep)) { if (next_pagep != NULL && - (ret = memp_fput(dbp->mpf, next_pagep, 0)) != 0) + (ret = mpf->put(mpf, next_pagep, 0)) != 0) return (ret); - if ((ret = memp_fget(dbp->mpf, + if ((ret = mpf->get(mpf, &next_pgno, DB_MPOOL_CREATE, &next_pagep)) != 0) return (ret); @@ -519,7 +535,7 @@ __ham_check_move(dbc, add_len) /* Add new page at the end of the chain. */ if (P_FREESPACE(next_pagep) < new_datalen && (ret = __ham_add_ovflpage(dbc, next_pagep, 1, &next_pagep)) != 0) { - (void)memp_fput(dbp->mpf, next_pagep, 0); + (void)mpf->put(mpf, next_pagep, 0); return (ret); } @@ -557,13 +573,14 @@ __ham_check_move(dbc, add_len) dbp->log_fileid, PGNO(next_pagep), (u_int32_t)NUM_ENT(next_pagep), &LSN(next_pagep), &k, &d)) != 0) { - (void)memp_fput(dbp->mpf, next_pagep, 0); + (void)mpf->put(mpf, next_pagep, 0); return (ret); } + } else + LSN_NOT_LOGGED(new_lsn); - /* Move lsn onto page. */ - LSN(next_pagep) = new_lsn; /* Structure assignment. */ - } + /* Move lsn onto page. */ + LSN(next_pagep) = new_lsn; /* Structure assignment. */ __ham_copy_item(dbp->pgsize, hcp->page, H_KEYINDEX(hcp->indx), next_pagep); @@ -581,7 +598,7 @@ __ham_check_move(dbc, add_len) * Note that __ham_del_pair should dirty the page we're moving * the items from, so we need only dirty the new page ourselves. */ - if ((ret = memp_fset(dbp->mpf, next_pagep, DB_MPOOL_DIRTY)) != 0) + if ((ret = mpf->set(mpf, next_pagep, DB_MPOOL_DIRTY)) != 0) goto out; /* Update all cursors that used to point to this item. */ @@ -596,12 +613,17 @@ __ham_check_move(dbc, add_len) * __ham_del_pair decremented nelem. This is incorrect; we * manually copied the element elsewhere, so the total number * of elements hasn't changed. Increment it again. + * + * !!! + * Note that we still have the metadata page pinned, and + * __ham_del_pair dirtied it, so we don't need to set the dirty + * flag again. */ if (!STD_LOCKING(dbc)) hcp->hdr->nelem++; out: - (void)memp_fput(dbp->mpf, hcp->page, DB_MPOOL_DIRTY); + (void)mpf->put(mpf, hcp->page, DB_MPOOL_DIRTY); hcp->page = next_pagep; hcp->pgno = PGNO(hcp->page); hcp->indx = NUM_ENT(hcp->page) - 2; @@ -620,9 +642,8 @@ out: * This is really just a special case of __onpage_replace; we should * probably combine them. * - * PUBLIC: void __ham_move_offpage __P((DBC *, PAGE *, u_int32_t, db_pgno_t)); */ -void +static int __ham_move_offpage(dbc, pagep, ndx, pgno) DBC *dbc; PAGE *pagep; @@ -630,32 +651,34 @@ __ham_move_offpage(dbc, pagep, ndx, pgno) db_pgno_t pgno; { DB *dbp; - HASH_CURSOR *hcp; DBT new_dbt; DBT old_dbt; HOFFDUP od; db_indx_t i; int32_t shrink; u_int8_t *src; + int ret; dbp = dbc->dbp; - hcp = (HASH_CURSOR *)dbc->internal; od.type = H_OFFDUP; UMRW_SET(od.unused[0]); UMRW_SET(od.unused[1]); UMRW_SET(od.unused[2]); od.pgno = pgno; + ret = 0; if (DB_LOGGING(dbc)) { new_dbt.data = &od; new_dbt.size = HOFFDUP_SIZE; old_dbt.data = P_ENTRY(pagep, ndx); old_dbt.size = LEN_HITEM(pagep, dbp->pgsize, ndx); - (void)__ham_replace_log(dbp->dbenv, + if ((ret = __ham_replace_log(dbp->dbenv, dbc->txn, &LSN(pagep), 0, dbp->log_fileid, PGNO(pagep), (u_int32_t)ndx, &LSN(pagep), -1, - &old_dbt, &new_dbt, 0); - } + &old_dbt, &new_dbt, 0)) != 0) + return (ret); + } else + LSN_NOT_LOGGED(LSN(pagep)); shrink = LEN_HITEM(pagep, dbp->pgsize, ndx) - HOFFDUP_SIZE; @@ -672,6 +695,7 @@ __ham_move_offpage(dbc, pagep, ndx, pgno) /* Now copy the offdup entry onto the page. */ memcpy(P_ENTRY(pagep, ndx), &od, HOFFDUP_SIZE); + return (ret); } /* @@ -679,13 +703,14 @@ __ham_move_offpage(dbc, pagep, ndx, pgno) * Locate a particular duplicate in a duplicate set. Make sure that * we exit with the cursor set appropriately. * - * PUBLIC: void __ham_dsearch __P((DBC *, DBT *, u_int32_t *, int *)); + * PUBLIC: void __ham_dsearch + * PUBLIC: __P((DBC *, DBT *, u_int32_t *, int *, u_int32_t)); */ void -__ham_dsearch(dbc, dbt, offp, cmpp) +__ham_dsearch(dbc, dbt, offp, cmpp, flags) DBC *dbc; DBT *dbt; - u_int32_t *offp; + u_int32_t *offp, flags; int *cmpp; { DB *dbp; @@ -697,10 +722,7 @@ __ham_dsearch(dbc, dbt, offp, cmpp) dbp = dbc->dbp; hcp = (HASH_CURSOR *)dbc->internal; - if (dbp->dup_compare == NULL) - func = __bam_defcmp; - else - func = dbp->dup_compare; + func = dbp->dup_compare == NULL ? __bam_defcmp : dbp->dup_compare; i = F_ISSET(hcp, H_CONTINUE) ? hcp->dup_off: 0; data = HKEYDATA_DATA(H_PAIRDATA(hcp->page, hcp->indx)) + i; @@ -710,12 +732,26 @@ __ham_dsearch(dbc, dbt, offp, cmpp) data += sizeof(db_indx_t); cur.data = data; cur.size = (u_int32_t)len; + + /* + * If we find an exact match, we're done. If in a sorted + * duplicate set and the item is larger than our test item, + * we're done. In the latter case, if permitting partial + * matches, it's not a failure. + */ *cmpp = func(dbp, dbt, &cur); - if (*cmpp == 0 || (*cmpp < 0 && dbp->dup_compare != NULL)) + if (*cmpp == 0) break; + if (*cmpp < 0 && dbp->dup_compare != NULL) { + if (flags == DB_GET_BOTH_RANGE) + *cmpp = 0; + break; + } + i += len + 2 * sizeof(db_indx_t); data += len + sizeof(db_indx_t); } + *offp = i; hcp->dup_off = i; hcp->dup_len = len; @@ -727,29 +763,22 @@ __ham_dsearch(dbc, dbt, offp, cmpp) * __ham_cprint -- * Display the current cursor list. * - * PUBLIC: int __ham_cprint __P((DB *)); + * PUBLIC: void __ham_cprint __P((DBC *)); */ -int -__ham_cprint(dbp) - DB *dbp; +void +__ham_cprint(dbc) + DBC *dbc; { HASH_CURSOR *cp; - DBC *dbc; - MUTEX_THREAD_LOCK(dbp->dbenv, dbp->mutexp); - for (dbc = TAILQ_FIRST(&dbp->active_queue); - dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) { - cp = (HASH_CURSOR *)dbc->internal; - fprintf(stderr, "%#0lx->%#0lx: page: %lu index: %lu", - P_TO_ULONG(dbc), P_TO_ULONG(cp), (u_long)cp->pgno, - (u_long)cp->indx); - if (F_ISSET(cp, H_DELETED)) - fprintf(stderr, " (deleted)"); - fprintf(stderr, "\n"); - } - MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp); + cp = (HASH_CURSOR *)dbc->internal; - return (0); + fprintf(stderr, "%#0lx->%#0lx: page: %lu index: %lu", + P_TO_ULONG(dbc), P_TO_ULONG(cp), (u_long)cp->pgno, + (u_long)cp->indx); + if (F_ISSET(cp, H_DELETED)) + fprintf(stderr, " (deleted)"); + fprintf(stderr, "\n"); } #endif /* DEBUG */ @@ -803,3 +832,75 @@ __ham_dcursor(dbc, pgno, indx) return (0); } + +/* + * __ham_c_chgpg -- + * Adjust the cursors after moving an item to a new page. We only + * move cursors that are pointing at this one item and are not + * deleted; since we only touch non-deleted cursors, and since + * (by definition) no item existed at the pgno/indx we're moving the + * item to, we're guaranteed that all the cursors we affect here or + * on abort really do refer to this one item. + */ +static int +__ham_c_chgpg(dbc, old_pgno, old_index, new_pgno, new_index) + DBC *dbc; + db_pgno_t old_pgno, new_pgno; + u_int32_t old_index, new_index; +{ + DB *dbp, *ldbp; + DB_ENV *dbenv; + DB_LSN lsn; + DB_TXN *my_txn; + DBC *cp; + HASH_CURSOR *hcp; + int found, ret; + + dbp = dbc->dbp; + dbenv = dbp->dbenv; + + my_txn = IS_SUBTRANSACTION(dbc->txn) ? dbc->txn : NULL; + found = 0; + + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL; + cp = TAILQ_NEXT(cp, links)) { + if (cp == dbc || cp->dbtype != DB_HASH) + continue; + + hcp = (HASH_CURSOR *)cp->internal; + + /* + * If a cursor is deleted, it doesn't refer to this + * item--it just happens to have the same indx, but + * it points to a former neighbor. Don't move it. + */ + if (F_ISSET(hcp, H_DELETED)) + continue; + + if (hcp->pgno == old_pgno) { + if (hcp->indx == old_index) { + hcp->pgno = new_pgno; + hcp->indx = new_index; + } else + continue; + if (my_txn != NULL && cp->txn != my_txn) + found = 1; + } + } + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + + if (found != 0 && DB_LOGGING(dbc)) { + if ((ret = __ham_chgpg_log(dbenv, + my_txn, &lsn, 0, dbp->log_fileid, DB_HAM_CHGPG, + old_pgno, new_pgno, old_index, new_index)) != 0) + return (ret); + } + return (0); +} diff --git a/db/hash/hash_page.c b/db/hash/hash_page.c index 64f388532..a7bc1cd1b 100644 --- a/db/hash/hash_page.c +++ b/db/hash/hash_page.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996, 1997, 1998, 1999, 2000 + * Copyright (c) 1996-2001 * Sleepycat Software. All rights reserved. */ /* @@ -43,7 +43,7 @@ #include "db_config.h" #ifndef lint -static const char revid[] = "$Id: hash_page.c,v 11.46 2001/01/11 18:19:51 bostic Exp $"; +static const char revid[] = "Id: hash_page.c,v 11.74 2001/10/20 20:10:01 bostic Exp "; #endif /* not lint */ /* @@ -75,6 +75,9 @@ static const char revid[] = "$Id: hash_page.c,v 11.46 2001/01/11 18:19:51 bostic #include "lock.h" #include "txn.h" +static int __ham_c_delpg + __P((DBC *, db_pgno_t, db_pgno_t, u_int32_t, db_ham_mode, u_int32_t *)); + /* * PUBLIC: int __ham_item __P((DBC *, db_lockmode_t, db_pgno_t *)); */ @@ -153,15 +156,18 @@ int __ham_item_reset(dbc) DBC *dbc; { - HASH_CURSOR *hcp; DB *dbp; + DB_MPOOLFILE *mpf; + HASH_CURSOR *hcp; int ret; - ret = 0; dbp = dbc->dbp; + mpf = dbp->mpf; hcp = (HASH_CURSOR *)dbc->internal; + + ret = 0; if (hcp->page != NULL) - ret = memp_fput(dbp->mpf, hcp->page, 0); + ret = mpf->put(mpf, hcp->page, 0); __ham_item_init(dbc); return (ret); @@ -181,8 +187,7 @@ __ham_item_init(dbc) * If this cursor still holds any locks, we must * release them if we are not running with transactions. */ - if (hcp->lock.off != LOCK_INVALID && dbc->txn == NULL) - (void)lock_put(dbc->dbp->dbenv, &hcp->lock); + (void)__TLPUT(dbc, hcp->lock); /* * The following fields must *not* be initialized here @@ -191,7 +196,7 @@ __ham_item_init(dbc) */ hcp->bucket = BUCKET_INVALID; hcp->lbucket = BUCKET_INVALID; - hcp->lock.off = LOCK_INVALID; + LOCK_INIT(hcp->lock); hcp->lock_mode = DB_LOCK_NG; hcp->dup_off = 0; hcp->dup_len = 0; @@ -264,13 +269,12 @@ __ham_item_prev(dbc, mode, pgnop) db_lockmode_t mode; db_pgno_t *pgnop; { - DB *dbp; HASH_CURSOR *hcp; db_pgno_t next_pgno; int ret; - dbp = dbc->dbp; hcp = (HASH_CURSOR *)dbc->internal; + /* * There are 5 cases for backing up in a hash file. * Case 1: In the middle of a page, no duplicates, just dec the index. @@ -537,25 +541,27 @@ __ham_del_pair(dbc, reclaim_page) int reclaim_page; { DB *dbp; - HASH_CURSOR *hcp; DBT data_dbt, key_dbt; DB_ENV *dbenv; DB_LSN new_lsn, *n_lsn, tmp_lsn; + DB_MPOOLFILE *mpf; + HASH_CURSOR *hcp; PAGE *n_pagep, *nn_pagep, *p, *p_pagep; + db_ham_mode op; db_indx_t ndx; db_pgno_t chg_pgno, pgno, tmp_pgno; int ret, t_ret; + u_int32_t order; dbp = dbc->dbp; - hcp = (HASH_CURSOR *)dbc->internal; - dbenv = dbp->dbenv; - ndx = hcp->indx; - + mpf = dbp->mpf; + hcp = (HASH_CURSOR *)dbc->internal; n_pagep = p_pagep = nn_pagep = NULL; + ndx = hcp->indx; - if (hcp->page == NULL && (ret = memp_fget(dbp->mpf, - &hcp->pgno, DB_MPOOL_CREATE, &hcp->page)) != 0) + if (hcp->page == NULL && + (ret = mpf->get(mpf, &hcp->pgno, DB_MPOOL_CREATE, &hcp->page)) != 0) return (ret); p = hcp->page; @@ -607,10 +613,11 @@ __ham_del_pair(dbc, reclaim_page) dbp->log_fileid, PGNO(p), (u_int32_t)ndx, &LSN(p), &key_dbt, &data_dbt)) != 0) return (ret); + } else + LSN_NOT_LOGGED(new_lsn); - /* Move lsn onto page. */ - LSN(p) = new_lsn; - } + /* Move lsn onto page. */ + LSN(p) = new_lsn; /* Do the delete. */ __ham_dpair(dbp, p, ndx); @@ -636,8 +643,11 @@ __ham_del_pair(dbc, reclaim_page) * XXX * Perhaps we can retain incremental numbers and apply them later. */ - if (!STD_LOCKING(dbc)) + if (!STD_LOCKING(dbc)) { --hcp->hdr->nelem; + if ((ret = __ham_dirty_meta(dbc)) != 0) + return (ret); + } /* * If we need to reclaim the page, then check if the page is empty. @@ -650,20 +660,18 @@ __ham_del_pair(dbc, reclaim_page) if (!reclaim_page || NUM_ENT(p) != 0 || (PREV_PGNO(p) == PGNO_INVALID && NEXT_PGNO(p) == PGNO_INVALID)) - return (memp_fset(dbp->mpf, p, DB_MPOOL_DIRTY)); + return (mpf->set(mpf, p, DB_MPOOL_DIRTY)); if (PREV_PGNO(p) == PGNO_INVALID) { /* * First page in chain is empty and we know that there * are more pages in the chain. */ - if ((ret = - memp_fget(dbp->mpf, &NEXT_PGNO(p), 0, &n_pagep)) != 0) + if ((ret = mpf->get(mpf, &NEXT_PGNO(p), 0, &n_pagep)) != 0) return (ret); - if (NEXT_PGNO(n_pagep) != PGNO_INVALID && - (ret = memp_fget(dbp->mpf, &NEXT_PGNO(n_pagep), 0, - &nn_pagep)) != 0) + if (NEXT_PGNO(n_pagep) != PGNO_INVALID && (ret = + mpf->get(mpf, &NEXT_PGNO(n_pagep), 0, &nn_pagep)) != 0) goto err; if (DB_LOGGING(dbc)) { @@ -676,17 +684,19 @@ __ham_del_pair(dbc, reclaim_page) nn_pagep == NULL ? NULL : &LSN(nn_pagep), &key_dbt)) != 0) goto err; + } else + LSN_NOT_LOGGED(new_lsn); + + /* Move lsn onto page. */ + LSN(p) = new_lsn; /* Structure assignment. */ + LSN(n_pagep) = new_lsn; + if (NEXT_PGNO(n_pagep) != PGNO_INVALID) + LSN(nn_pagep) = new_lsn; - /* Move lsn onto page. */ - LSN(p) = new_lsn; /* Structure assignment. */ - LSN(n_pagep) = new_lsn; - if (NEXT_PGNO(n_pagep) != PGNO_INVALID) - LSN(nn_pagep) = new_lsn; - } if (nn_pagep != NULL) { PREV_PGNO(nn_pagep) = PGNO(p); - if ((ret = memp_fput(dbp->mpf, - nn_pagep, DB_MPOOL_DIRTY)) != 0) { + if ((ret = + mpf->put(mpf, nn_pagep, DB_MPOOL_DIRTY)) != 0) { nn_pagep = NULL; goto err; } @@ -703,26 +713,30 @@ __ham_del_pair(dbc, reclaim_page) * Update cursors to reflect the fact that records * on the second page have moved to the first page. */ - if ((ret = __ham_c_chgpg(dbc, - PGNO(n_pagep), NDX_INVALID, PGNO(p), NDX_INVALID)) != 0) - return (ret); + if ((ret = __ham_c_delpg(dbc, PGNO(n_pagep), + PGNO(p), 0, DB_HAM_DELFIRSTPG, &order)) != 0) + goto err; /* * Update the cursor to reflect its new position. */ hcp->indx = 0; hcp->pgno = PGNO(p); - if ((ret = memp_fset(dbp->mpf, p, DB_MPOOL_DIRTY)) != 0 || - (ret = __db_free(dbc, n_pagep)) != 0) - return (ret); + hcp->order += order; + + if ((ret = mpf->set(mpf, p, DB_MPOOL_DIRTY)) != 0) + goto err; + if ((ret = __db_free(dbc, n_pagep)) != 0) { + n_pagep = NULL; + goto err; + } } else { - if ((ret = - memp_fget(dbp->mpf, &PREV_PGNO(p), 0, &p_pagep)) != 0) + if ((ret = mpf->get(mpf, &PREV_PGNO(p), 0, &p_pagep)) != 0) goto err; if (NEXT_PGNO(p) != PGNO_INVALID) { - if ((ret = memp_fget(dbp->mpf, - &NEXT_PGNO(p), 0, &n_pagep)) != 0) + if ((ret = + mpf->get(mpf, &NEXT_PGNO(p), 0, &n_pagep)) != 0) goto err; n_lsn = &LSN(n_pagep); } else { @@ -740,26 +754,35 @@ __ham_del_pair(dbc, reclaim_page) dbp->log_fileid, PREV_PGNO(p), &LSN(p_pagep), PGNO(p), &LSN(p), NEXT_PGNO(p), n_lsn)) != 0) goto err; + } else + LSN_NOT_LOGGED(new_lsn); + + /* Move lsn onto page. */ + LSN(p_pagep) = new_lsn; /* Structure assignment. */ + if (n_pagep) + LSN(n_pagep) = new_lsn; + LSN(p) = new_lsn; - /* Move lsn onto page. */ - LSN(p_pagep) = new_lsn; /* Structure assignment. */ - if (n_pagep) - LSN(n_pagep) = new_lsn; - LSN(p) = new_lsn; - } if (NEXT_PGNO(p) == PGNO_INVALID) { /* * There is no next page; put the cursor on the * previous page as if we'd deleted the last item - * on that page; index greater than number of - * valid entries and H_DELETED set. + * on that page, with index after the last valid + * entry. + * + * The deleted flag was set up above. */ hcp->pgno = PGNO(p_pagep); hcp->indx = NUM_ENT(p_pagep); - F_SET(hcp, H_DELETED); + op = DB_HAM_DELLASTPG; } else { + /* + * There is a next page, so put the cursor at + * the beginning of it. + */ hcp->pgno = NEXT_PGNO(p); hcp->indx = 0; + op = DB_HAM_DELMIDPG; } /* @@ -770,26 +793,28 @@ __ham_del_pair(dbc, reclaim_page) hcp->page = NULL; chg_pgno = PGNO(p); ret = __db_free(dbc, p); - if ((t_ret = memp_fput(dbp->mpf, p_pagep, DB_MPOOL_DIRTY)) != 0 - && ret == 0) + if ((t_ret = + mpf->put(mpf, p_pagep, DB_MPOOL_DIRTY)) != 0 && ret == 0) ret = t_ret; - if (n_pagep != NULL && (t_ret = memp_fput(dbp->mpf, - n_pagep, DB_MPOOL_DIRTY)) != 0 && ret == 0) + if (n_pagep != NULL && (t_ret = + mpf->put(mpf, n_pagep, DB_MPOOL_DIRTY)) != 0 && ret == 0) ret = t_ret; if (ret != 0) return (ret); - ret = __ham_c_chgpg(dbc, - chg_pgno, 0, hcp->pgno, hcp->indx); + if ((ret = __ham_c_delpg(dbc, + chg_pgno, hcp->pgno, hcp->indx, op, &order)) != 0) + return (ret); + hcp->order += order; } return (ret); err: /* Clean up any pages. */ if (n_pagep != NULL) - (void)memp_fput(dbp->mpf, n_pagep, 0); + (void)mpf->put(mpf, n_pagep, 0); if (nn_pagep != NULL) - (void)memp_fput(dbp->mpf, nn_pagep, 0); + (void)mpf->put(mpf, nn_pagep, 0); if (p_pagep != NULL) - (void)memp_fput(dbp->mpf, p_pagep, 0); + (void)mpf->put(mpf, p_pagep, 0); return (ret); } @@ -811,8 +836,8 @@ __ham_replpair(dbc, dbt, make_dup) DBT old_dbt, tdata, tmp; DB_LSN new_lsn; int32_t change; /* XXX: Possible overflow. */ - u_int32_t dup, len, memsize; - int is_big, ret, type; + u_int32_t dup_flag, len, memsize; + int beyond_eor, is_big, ret, type; u_int8_t *beg, *dest, *end, *hk, *src; void *memp; @@ -850,10 +875,11 @@ __ham_replpair(dbc, dbt, make_dup) len = LEN_HKEYDATA(hcp->page, dbp->pgsize, H_DATAINDEX(hcp->indx)); - if (dbt->doff + dbt->dlen > len) + beyond_eor = dbt->doff + dbt->dlen > len; + if (beyond_eor) change += dbt->doff + dbt->dlen - len; - if (change > (int32_t)P_FREESPACE(hcp->page) || is_big) { + if (change > (int32_t)P_FREESPACE(hcp->page) || beyond_eor || is_big) { /* * Case 3 -- two subcases. * A. This is not really a partial operation, but an overwrite. @@ -868,16 +894,16 @@ __ham_replpair(dbc, dbt, make_dup) memset(&tmp, 0, sizeof(tmp)); if ((ret = __db_ret(dbp, hcp->page, H_KEYINDEX(hcp->indx), - &tmp, &dbc->rkey.data, &dbc->rkey.ulen)) != 0) + &tmp, &dbc->rkey->data, &dbc->rkey->ulen)) != 0) return (ret); /* Preserve duplicate info. */ - dup = F_ISSET(hcp, H_ISDUP); + dup_flag = F_ISSET(hcp, H_ISDUP); if (dbt->doff == 0 && dbt->dlen == len) { ret = __ham_del_pair(dbc, 0); if (ret == 0) ret = __ham_add_el(dbc, - &tmp, dbt, dup ? H_DUPLICATE : H_KEYDATA); + &tmp, dbt, dup_flag ? H_DUPLICATE : H_KEYDATA); } else { /* Case B */ type = HPAGE_PTYPE(hk) != H_OFFPAGE ? HPAGE_PTYPE(hk) : H_KEYDATA; @@ -891,15 +917,14 @@ __ham_replpair(dbc, dbt, make_dup) /* Now we can delete the item. */ if ((ret = __ham_del_pair(dbc, 0)) != 0) { - __os_free(memp, memsize); + __os_free(dbp->dbenv, memp, memsize); goto err; } /* Now shift old data around to make room for new. */ if (change > 0) { if ((ret = __os_realloc(dbp->dbenv, - tdata.size + change, - NULL, &tdata.data)) != 0) + tdata.size + change, &tdata.data)) != 0) return (ret); memp = tdata.data; memsize = tdata.size + change; @@ -920,9 +945,9 @@ __ham_replpair(dbc, dbt, make_dup) /* Now add the pair. */ ret = __ham_add_el(dbc, &tmp, &tdata, type); - __os_free(memp, memsize); + __os_free(dbp->dbenv, memp, memsize); } - F_SET(hcp, dup); + F_SET(hcp, dup_flag); err: return (ret); } @@ -947,8 +972,10 @@ err: return (ret); (u_int32_t)dbt->doff, &old_dbt, dbt, make_dup)) != 0) return (ret); - LSN(hcp->page) = new_lsn; /* Structure assignment. */ - } + } else + LSN_NOT_LOGGED(new_lsn); + + LSN(hcp->page) = new_lsn; /* Structure assignment. */ __ham_onpage_replace(hcp->page, dbp->pgsize, (u_int32_t)H_DATAINDEX(hcp->indx), (int32_t)dbt->doff, change, dbt); @@ -1022,10 +1049,12 @@ __ham_split_page(dbc, obucket, nbucket) { DB *dbp; DBC **carray; - HASH_CURSOR *hcp, *cp; DBT key, page_dbt; DB_ENV *dbenv; + DB_LOCK block; DB_LSN new_lsn; + DB_MPOOLFILE *mpf; + HASH_CURSOR *hcp, *cp; PAGE **pp, *old_pagep, *temp_pagep, *new_pagep; db_indx_t n; db_pgno_t bucket_pgno, npgno, next_pgno; @@ -1034,22 +1063,24 @@ __ham_split_page(dbc, obucket, nbucket) void *big_buf; dbp = dbc->dbp; - hcp = (HASH_CURSOR *)dbc->internal; dbenv = dbp->dbenv; + mpf = dbp->mpf; + hcp = (HASH_CURSOR *)dbc->internal; temp_pagep = old_pagep = new_pagep = NULL; - - if ((ret = __ham_get_clist(dbp, obucket, NDX_INVALID, &carray)) != 0) - return (ret); + carray = NULL; + LOCK_INIT(block); bucket_pgno = BUCKET_TO_PAGE(hcp, obucket); - if ((ret = memp_fget(dbp->mpf, + if ((ret = __db_lget(dbc, + 0, bucket_pgno, DB_LOCK_WRITE, 0, &block)) != 0) + goto err; + if ((ret = mpf->get(mpf, &bucket_pgno, DB_MPOOL_CREATE, &old_pagep)) != 0) goto err; /* Properly initialize the new bucket page. */ npgno = BUCKET_TO_PAGE(hcp, nbucket); - if ((ret = memp_fget(dbp->mpf, - &npgno, DB_MPOOL_CREATE, &new_pagep)) != 0) + if ((ret = mpf->get(mpf, &npgno, DB_MPOOL_CREATE, &new_pagep)) != 0) goto err; P_INIT(new_pagep, dbp->pgsize, npgno, PGNO_INVALID, PGNO_INVALID, 0, P_HASH); @@ -1064,26 +1095,28 @@ __ham_split_page(dbc, obucket, nbucket) dbc->txn, &new_lsn, 0, dbp->log_fileid, SPLITOLD, PGNO(old_pagep), &page_dbt, &LSN(old_pagep))) != 0) goto err; - } + } else + LSN_NOT_LOGGED(new_lsn); + + LSN(old_pagep) = new_lsn; /* Structure assignment. */ P_INIT(old_pagep, dbp->pgsize, PGNO(old_pagep), PGNO_INVALID, PGNO_INVALID, 0, P_HASH); - if (DB_LOGGING(dbc)) - LSN(old_pagep) = new_lsn; /* Structure assignment. */ - big_len = 0; big_buf = NULL; key.flags = 0; while (temp_pagep != NULL) { + if ((ret = __ham_get_clist(dbp, + PGNO(temp_pagep), NDX_INVALID, &carray)) != 0) + goto err; + for (n = 0; n < (db_indx_t)NUM_ENT(temp_pagep); n += 2) { - if ((ret = - __db_ret(dbp, temp_pagep, H_KEYINDEX(n), - &key, &big_buf, &big_len)) != 0) + if ((ret = __db_ret(dbp, temp_pagep, + H_KEYINDEX(n), &key, &big_buf, &big_len)) != 0) goto err; - if (__ham_call_hash(dbc, key.data, key.size) - == obucket) + if (__ham_call_hash(dbc, key.data, key.size) == obucket) pp = &old_pagep; else pp = &new_pagep; @@ -1092,7 +1125,6 @@ __ham_split_page(dbc, obucket, nbucket) * Figure out how many bytes we need on the new * page to store the key/data pair. */ - len = LEN_HITEM(temp_pagep, dbp->pgsize, H_DATAINDEX(n)) + LEN_HITEM(temp_pagep, dbp->pgsize, @@ -1109,8 +1141,9 @@ __ham_split_page(dbc, obucket, nbucket) SPLITNEW, PGNO(*pp), &page_dbt, &LSN(*pp))) != 0) goto err; - LSN(*pp) = new_lsn; - } + } else + LSN_NOT_LOGGED(new_lsn); + LSN(*pp) = new_lsn; if ((ret = __ham_add_ovflpage(dbc, *pp, 1, pp)) != 0) goto err; @@ -1156,23 +1189,30 @@ __ham_split_page(dbc, obucket, nbucket) if (next_pgno == PGNO_INVALID) temp_pagep = NULL; - else if ((ret = memp_fget(dbp->mpf, - &next_pgno, DB_MPOOL_CREATE, &temp_pagep)) != 0) + else if ((ret = mpf->get( + mpf, &next_pgno, DB_MPOOL_CREATE, &temp_pagep)) != 0) goto err; - if (temp_pagep != NULL && DB_LOGGING(dbc)) { - page_dbt.size = dbp->pgsize; - page_dbt.data = temp_pagep; - if ((ret = __ham_splitdata_log(dbenv, - dbc->txn, &new_lsn, 0, dbp->log_fileid, - SPLITOLD, PGNO(temp_pagep), - &page_dbt, &LSN(temp_pagep))) != 0) - goto err; + if (temp_pagep != NULL) { + if (DB_LOGGING(dbc)) { + page_dbt.size = dbp->pgsize; + page_dbt.data = temp_pagep; + if ((ret = __ham_splitdata_log(dbenv, + dbc->txn, &new_lsn, 0, dbp->log_fileid, + SPLITOLD, PGNO(temp_pagep), + &page_dbt, &LSN(temp_pagep))) != 0) + goto err; + } else + LSN_NOT_LOGGED(new_lsn); LSN(temp_pagep) = new_lsn; } + + if (carray != NULL) /* We never knew its size. */ + __os_free(dbp->dbenv, carray, 0); + carray = NULL; } if (big_buf != NULL) - __os_free(big_buf, big_len); + __os_free(dbenv, big_buf, big_len); /* * If the original bucket spanned multiple pages, then we've got @@ -1203,22 +1243,28 @@ __ham_split_page(dbc, obucket, nbucket) &LSN(new_pagep))) != 0) goto err; LSN(new_pagep) = new_lsn; + } else { + LSN_NOT_LOGGED(LSN(old_pagep)); + LSN_NOT_LOGGED(LSN(new_pagep)); } - ret = memp_fput(dbp->mpf, old_pagep, DB_MPOOL_DIRTY); - if ((t_ret = memp_fput(dbp->mpf, new_pagep, DB_MPOOL_DIRTY)) != 0 - && ret == 0) + + ret = mpf->put(mpf, old_pagep, DB_MPOOL_DIRTY); + if ((t_ret = + mpf->put(mpf, new_pagep, DB_MPOOL_DIRTY)) != 0 && ret == 0) ret = t_ret; if (0) { err: if (old_pagep != NULL) - (void)memp_fput(dbp->mpf, old_pagep, DB_MPOOL_DIRTY); + (void)mpf->put(mpf, old_pagep, DB_MPOOL_DIRTY); if (new_pagep != NULL) - (void)memp_fput(dbp->mpf, new_pagep, DB_MPOOL_DIRTY); + (void)mpf->put(mpf, new_pagep, DB_MPOOL_DIRTY); if (temp_pagep != NULL && PGNO(temp_pagep) != bucket_pgno) - (void)memp_fput(dbp->mpf, temp_pagep, DB_MPOOL_DIRTY); + (void)mpf->put(mpf, temp_pagep, DB_MPOOL_DIRTY); } + if (LOCK_ISSET(block)) + __TLPUT(dbc, block); if (carray != NULL) /* We never knew its size. */ - __os_free(carray, 0); + __os_free(dbp->dbenv, carray, 0); return (ret); } @@ -1237,11 +1283,12 @@ __ham_add_el(dbc, key, val, type) const DBT *key, *val; int type; { - DB *dbp; - HASH_CURSOR *hcp; const DBT *pkey, *pdata; + DB *dbp; DBT key_dbt, data_dbt; DB_LSN new_lsn; + DB_MPOOLFILE *mpf; + HASH_CURSOR *hcp; HOFFPAGE doff, koff; db_pgno_t next_pgno, pgno; u_int32_t data_size, key_size, pairsize, rectype; @@ -1249,13 +1296,14 @@ __ham_add_el(dbc, key, val, type) int key_type, data_type; dbp = dbc->dbp; + mpf = dbp->mpf; hcp = (HASH_CURSOR *)dbc->internal; do_expand = 0; - pgno = hcp->seek_found_page != PGNO_INVALID ? hcp->seek_found_page : - hcp->pgno; - if (hcp->page == NULL && (ret = memp_fget(dbp->mpf, &pgno, - DB_MPOOL_CREATE, &hcp->page)) != 0) + pgno = hcp->seek_found_page != PGNO_INVALID ? + hcp->seek_found_page : hcp->pgno; + if (hcp->page == NULL && + (ret = mpf->get(mpf, &pgno, DB_MPOOL_CREATE, &hcp->page)) != 0) return (ret); key_size = HKEYDATA_PSIZE(key->size); @@ -1279,8 +1327,7 @@ __ham_add_el(dbc, key, val, type) if (P_FREESPACE(hcp->page) >= pairsize) break; next_pgno = NEXT_PGNO(hcp->page); - if ((ret = - __ham_next_cpage(dbc, next_pgno, 0)) != 0) + if ((ret = __ham_next_cpage(dbc, next_pgno, 0)) != 0) return (ret); } @@ -1290,7 +1337,7 @@ __ham_add_el(dbc, key, val, type) if (P_FREESPACE(hcp->page) < pairsize) { do_expand = 1; if ((ret = __ham_add_ovflpage(dbc, - (PAGE *)hcp->page, 1, (PAGE **)&hcp->page)) != 0) + (PAGE *)hcp->page, 1, (PAGE **)&hcp->page)) != 0) return (ret); hcp->pgno = PGNO(hcp->page); } @@ -1348,10 +1395,11 @@ __ham_add_el(dbc, key, val, type) (u_int32_t)NUM_ENT(hcp->page), &LSN(hcp->page), pkey, pdata)) != 0) return (ret); + } else + LSN_NOT_LOGGED(new_lsn); - /* Move lsn onto page. */ - LSN(hcp->page) = new_lsn; /* Structure assignment. */ - } + /* Move lsn onto page. */ + LSN(hcp->page) = new_lsn; /* Structure assignment. */ __ham_putitem(hcp->page, pkey, key_type); __ham_putitem(hcp->page, pdata, data_type); @@ -1369,8 +1417,11 @@ __ham_add_el(dbc, key, val, type) * XXX * Maybe keep incremental numbers here. */ - if (!STD_LOCKING(dbc)) + if (!STD_LOCKING(dbc)) { hcp->hdr->nelem++; + if ((ret = __ham_dirty_meta(dbc)) != 0) + return (ret); + } if (do_expand || (hcp->hdr->ffactor != 0 && (u_int32_t)H_NUMPAIRS(hcp->page) > hcp->hdr->ffactor)) @@ -1427,13 +1478,13 @@ __ham_add_ovflpage(dbc, pagep, release, pp) PAGE **pp; { DB *dbp; - HASH_CURSOR *hcp; DB_LSN new_lsn; + DB_MPOOLFILE *mpf; PAGE *new_pagep; int ret; dbp = dbc->dbp; - hcp = (HASH_CURSOR *)dbc->internal; + mpf = dbp->mpf; if ((ret = __db_new(dbc, P_HASH, &new_pagep)) != 0) return (ret); @@ -1443,15 +1494,17 @@ __ham_add_ovflpage(dbc, pagep, release, pp) PUTOVFL, dbp->log_fileid, PGNO(pagep), &LSN(pagep), PGNO(new_pagep), &LSN(new_pagep), PGNO_INVALID, NULL)) != 0) return (ret); + } else + LSN_NOT_LOGGED(new_lsn); - /* Move lsn onto page. */ - LSN(pagep) = LSN(new_pagep) = new_lsn; - } + /* Move lsn onto page. */ + LSN(pagep) = LSN(new_pagep) = new_lsn; NEXT_PGNO(pagep) = PGNO(new_pagep); + PREV_PGNO(new_pagep) = PGNO(pagep); if (release) - ret = memp_fput(dbp->mpf, pagep, DB_MPOOL_DIRTY); + ret = mpf->put(mpf, pagep, DB_MPOOL_DIRTY); *pp = new_pagep; return (ret); @@ -1467,10 +1520,12 @@ __ham_get_cpage(dbc, mode) { DB *dbp; DB_LOCK tmp_lock; + DB_MPOOLFILE *mpf; HASH_CURSOR *hcp; int ret; dbp = dbc->dbp; + mpf = dbp->mpf; hcp = (HASH_CURSOR *)dbc->internal; ret = 0; @@ -1485,25 +1540,22 @@ __ham_get_cpage(dbc, mode) * 4. If there is a lock, but it's for a different bucket, then we need * to release the existing lock and get a new lock. */ - tmp_lock.off = LOCK_INVALID; + LOCK_INIT(tmp_lock); if (STD_LOCKING(dbc)) { - if (hcp->lock.off != LOCK_INVALID && - hcp->lbucket != hcp->bucket) { /* Case 4 */ - if (dbc->txn == NULL && - (ret = lock_put(dbp->dbenv, &hcp->lock)) != 0) - return (ret); - hcp->lock.off = LOCK_INVALID; - } - if ((hcp->lock.off != LOCK_INVALID && + if (hcp->lbucket != hcp->bucket && /* Case 4 */ + (ret = __TLPUT(dbc, hcp->lock)) != 0) + return (ret); + + if ((LOCK_ISSET(hcp->lock) && (hcp->lock_mode == DB_LOCK_READ && mode == DB_LOCK_WRITE))) { /* Case 3. */ tmp_lock = hcp->lock; - hcp->lock.off = LOCK_INVALID; + LOCK_INIT(hcp->lock); } /* Acquire the lock. */ - if (hcp->lock.off == LOCK_INVALID) + if (!LOCK_ISSET(hcp->lock)) /* Cases 1, 3, and 4. */ if ((ret = __ham_lock_bucket(dbc, mode)) != 0) return (ret); @@ -1511,17 +1563,18 @@ __ham_get_cpage(dbc, mode) if (ret == 0) { hcp->lock_mode = mode; hcp->lbucket = hcp->bucket; - if (tmp_lock.off != LOCK_INVALID) + if (LOCK_ISSET(tmp_lock)) /* Case 3: release the original lock. */ - ret = lock_put(dbp->dbenv, &tmp_lock); - } else if (tmp_lock.off != LOCK_INVALID) + ret = + dbp->dbenv->lock_put(dbp->dbenv, &tmp_lock); + } else if (LOCK_ISSET(tmp_lock)) hcp->lock = tmp_lock; } if (ret == 0 && hcp->page == NULL) { if (hcp->pgno == PGNO_INVALID) hcp->pgno = BUCKET_TO_PAGE(hcp, hcp->bucket); - if ((ret = memp_fget(dbp->mpf, + if ((ret = mpf->get(mpf, &hcp->pgno, DB_MPOOL_CREATE, &hcp->page)) != 0) return (ret); } @@ -1543,18 +1596,21 @@ __ham_next_cpage(dbc, pgno, dirty) int dirty; { DB *dbp; + DB_MPOOLFILE *mpf; HASH_CURSOR *hcp; PAGE *p; int ret; dbp = dbc->dbp; + mpf = dbp->mpf; hcp = (HASH_CURSOR *)dbc->internal; - if (hcp->page != NULL && (ret = memp_fput(dbp->mpf, - hcp->page, dirty ? DB_MPOOL_DIRTY : 0)) != 0) + if (hcp->page != NULL && + (ret = mpf->put(mpf, hcp->page, dirty ? DB_MPOOL_DIRTY : 0)) != 0) return (ret); + hcp->page = NULL; - if ((ret = memp_fget(dbp->mpf, &pgno, DB_MPOOL_CREATE, &p)) != 0) + if ((ret = mpf->get(mpf, &pgno, DB_MPOOL_CREATE, &p)) != 0) return (ret); hcp->page = p; @@ -1576,7 +1632,7 @@ __ham_lock_bucket(dbc, mode) db_lockmode_t mode; { HASH_CURSOR *hcp; - u_int32_t flags; + db_pgno_t pgno; int gotmeta, ret; hcp = (HASH_CURSOR *)dbc->internal; @@ -1584,17 +1640,12 @@ __ham_lock_bucket(dbc, mode) if (gotmeta) if ((ret = __ham_get_meta(dbc)) != 0) return (ret); - dbc->lock.pgno = BUCKET_TO_PAGE(hcp, hcp->bucket); + pgno = BUCKET_TO_PAGE(hcp, hcp->bucket); if (gotmeta) if ((ret = __ham_release_meta(dbc)) != 0) return (ret); - flags = 0; - if (DB_NONBLOCK(dbc)) - LF_SET(DB_LOCK_NOWAIT); - - ret = lock_get(dbc->dbp->dbenv, - dbc->locker, flags, &dbc->lock_dbt, mode, &hcp->lock); + ret = __db_lget(dbc, 0, pgno, mode, 0, &hcp->lock); hcp->lock_mode = mode; return (ret); @@ -1606,6 +1657,9 @@ __ham_lock_bucket(dbc, mode) * represents. The caller is responsible for freeing up duplicates * or offpage entries that might be referenced by this pair. * + * Recovery assumes that this may be called without the metadata + * page pinned. + * * PUBLIC: void __ham_dpair __P((DB *, PAGE *, u_int32_t)); */ void @@ -1653,3 +1707,152 @@ __ham_dpair(dbp, p, indx) p->inp[n] = p->inp[n + 2] + delta; } + +/* + * __ham_c_delpg -- + * + * Adjust the cursors after we've emptied a page in a bucket, taking + * care that when we move cursors pointing to deleted items, their + * orders don't collide with the orders of cursors on the page we move + * them to (since after this function is called, cursors with the same + * index on the two pages will be otherwise indistinguishable--they'll + * all have pgno new_pgno). There are three cases: + * + * 1) The emptied page is the first page in the bucket. In this + * case, we've copied all the items from the second page into the + * first page, so the first page is new_pgno and the second page is + * old_pgno. new_pgno is empty, but can have deleted cursors + * pointing at indx 0, so we need to be careful of the orders + * there. This is DB_HAM_DELFIRSTPG. + * + * 2) The page is somewhere in the middle of a bucket. Our caller + * can just delete such a page, so it's old_pgno. old_pgno is + * empty, but may have deleted cursors pointing at indx 0, so we + * need to be careful of indx 0 when we move those cursors to + * new_pgno. This is DB_HAM_DELMIDPG. + * + * 3) The page is the last in a bucket. Again the empty page is + * old_pgno, and again it should only have cursors that are deleted + * and at indx == 0. This time, though, there's no next page to + * move them to, so we set them to indx == num_ent on the previous + * page--and indx == num_ent is the index whose cursors we need to + * be careful of. This is DB_HAM_DELLASTPG. + */ +static int +__ham_c_delpg(dbc, old_pgno, new_pgno, num_ent, op, orderp) + DBC *dbc; + db_pgno_t old_pgno, new_pgno; + u_int32_t num_ent; + db_ham_mode op; + u_int32_t *orderp; +{ + DB *dbp, *ldbp; + DB_ENV *dbenv; + DB_LSN lsn; + DB_TXN *my_txn; + DBC *cp; + HASH_CURSOR *hcp; + int found, ret; + db_indx_t indx; + u_int32_t order; + + /* Which is the worrisome index? */ + indx = (op == DB_HAM_DELLASTPG) ? num_ent : 0; + + dbp = dbc->dbp; + dbenv = dbp->dbenv; + + my_txn = IS_SUBTRANSACTION(dbc->txn) ? dbc->txn : NULL; + found = 0; + + MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp); + /* + * Find the highest order of any cursor our movement + * may collide with. + */ + order = 1; + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL; + cp = TAILQ_NEXT(cp, links)) { + if (cp == dbc || cp->dbtype != DB_HASH) + continue; + hcp = (HASH_CURSOR *)cp->internal; + if (hcp->pgno == new_pgno) { + if (hcp->indx == indx && + F_ISSET(hcp, H_DELETED) && + hcp->order >= order) + order = hcp->order + 1; + DB_ASSERT(op != DB_HAM_DELFIRSTPG || + hcp->indx == NDX_INVALID || + (hcp->indx == 0 && + F_ISSET(hcp, H_DELETED))); + } + } + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + + for (ldbp = __dblist_get(dbenv, dbp->adj_fileid); + ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid; + ldbp = LIST_NEXT(ldbp, dblistlinks)) { + MUTEX_THREAD_LOCK(dbenv, dbp->mutexp); + for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL; + cp = TAILQ_NEXT(cp, links)) { + if (cp == dbc || cp->dbtype != DB_HASH) + continue; + + hcp = (HASH_CURSOR *)cp->internal; + + if (hcp->pgno == old_pgno) { + switch (op) { + case DB_HAM_DELFIRSTPG: + /* + * We're moving all items, + * regardless of index. + */ + hcp->pgno = new_pgno; + + /* + * But we have to be careful of + * the order values. + */ + if (hcp->indx == indx) + hcp->order += order; + break; + case DB_HAM_DELMIDPG: + hcp->pgno = new_pgno; + DB_ASSERT(hcp->indx == 0 && + F_ISSET(hcp, H_DELETED)); + hcp->order += order; + break; + case DB_HAM_DELLASTPG: + hcp->pgno = new_pgno; + DB_ASSERT(hcp->indx == 0 && + F_ISSET(hcp, H_DELETED)); + hcp->indx = indx; + hcp->order += order; + break; + default: + DB_ASSERT(0); + return (__db_panic(dbp->dbenv, EINVAL)); + } + if (my_txn != NULL && cp->txn != my_txn) + found = 1; + } + } + MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp); + } + MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp); + + if (found != 0 && DB_LOGGING(dbc)) { + if ((ret = __ham_chgpg_log(dbenv, + my_txn, &lsn, 0, dbp->log_fileid, op, + old_pgno, new_pgno, indx, order)) != 0) + return (ret); + } + *orderp = order; + return (0); +} + diff --git a/lib/package.c b/lib/package.c index 712289b0c..3d79c2b9a 100644 --- a/lib/package.c +++ b/lib/package.c @@ -39,6 +39,7 @@ void headerMergeLegacySigs(Header h, const Header sig) ptr = hfd(ptr, type)) { switch (tag) { + /* XXX Translate legacy signature tag values. */ case RPMSIGTAG_SIZE: tag = RPMTAG_SIGSIZE; /*@switchbreak@*/ break; @@ -60,6 +61,11 @@ void headerMergeLegacySigs(Header h, const Header sig) case RPMSIGTAG_PGP5: tag = RPMTAG_SIGPGP5; /*@switchbreak@*/ break; + case RPMSIGTAG_PAYLOADSIZE: + tag = RPMTAG_ARCHIVESIZE; + /*@switchbreak@*/ break; + case RPMSIGTAG_SHA1: + case RPMSIGTAG_DSA: default: if (!(tag >= HEADER_SIGBASE && tag < HEADER_TAGBASE)) continue; @@ -88,6 +94,7 @@ Header headerRegenSigHeader(const Header h) ptr = hfd(ptr, type)) { switch (tag) { + /* XXX Translate legacy signature tag values. */ case RPMTAG_SIGSIZE: stag = RPMSIGTAG_SIZE; /*@switchbreak@*/ break; @@ -109,6 +116,11 @@ Header headerRegenSigHeader(const Header h) case RPMTAG_SIGPGP5: stag = RPMSIGTAG_PGP5; /*@switchbreak@*/ break; + case RPMTAG_ARCHIVESIZE: + stag = RPMSIGTAG_PAYLOADSIZE; + /*@switchbreak@*/ break; + case RPMTAG_SHA1HEADER: + case RPMTAG_DSAHEADER: default: if (!(tag >= HEADER_SIGBASE && tag < HEADER_TAGBASE)) continue; @@ -249,6 +261,7 @@ int rpmReadPackageFile(rpmTransactionSet ts, FD_t fd, /*@notreached@*/ break; } + /* Read the signature header. */ rc = rpmReadSignature(fd, &sig, l->signature_type); if (!(rc == RPMRC_OK || rc == RPMRC_BADSIZE)) { rpmError(RPMERR_SIGGEN, _("%s: rpmReadSignature failed\n"), fn); @@ -260,24 +273,26 @@ int rpmReadPackageFile(rpmTransactionSet ts, FD_t fd, goto exit; } - if (!ts->verify_legacy) /* leave fd ready to install payload */ - ts->sigtag = 0; - else if (headerIsEntry(sig, RPMSIGTAG_GPG)) + /* Figger the most effective available signature. */ + if (headerIsEntry(sig, RPMSIGTAG_DSA)) + ts->sigtag = RPMSIGTAG_DSA; + else if (!ts->verify_legacy) /* leave fd ready to install payload */ + ts->sigtag = (headerIsEntry(sig, RPMSIGTAG_SHA1)) ? RPMSIGTAG_SHA1 : 0; + else if (headerIsEntry(sig, RPMSIGTAG_GPG)) { ts->sigtag = RPMSIGTAG_GPG; - else if (headerIsEntry(sig, RPMSIGTAG_PGP)) + fdInitDigest(fd, PGPHASHALGO_SHA1, 0); + } else if (headerIsEntry(sig, RPMSIGTAG_PGP)) { ts->sigtag = RPMSIGTAG_PGP; - else if (headerIsEntry(sig, RPMSIGTAG_MD5)) + fdInitDigest(fd, PGPHASHALGO_MD5, 0); + } else if (headerIsEntry(sig, RPMSIGTAG_SHA1)) { + ts->sigtag = RPMSIGTAG_SHA1; /* XXX never happens */ + } else if (headerIsEntry(sig, RPMSIGTAG_MD5)) { ts->sigtag = RPMSIGTAG_MD5; - else - ts->sigtag = 0; - - /*@-type@*/ /* FIX: cast? */ - if (ts->sigtag == RPMSIGTAG_GPG) - fdInitDigest(fd, PGPHASHALGO_SHA1, 0); - else if (ts->sigtag == RPMSIGTAG_PGP || ts->sigtag == RPMSIGTAG_MD5) fdInitDigest(fd, PGPHASHALGO_MD5, 0); - /*@=type@*/ + } else + ts->sigtag = 0; /* XXX never happens */ + /* Read the metadata, computing digest(s) on the fly. */ hmagic = ((l->major >= 3) ? HEADER_MAGIC_YES : HEADER_MAGIC_NO); h = headerRead(fd, hmagic); if (h == NULL) { @@ -293,56 +308,94 @@ int rpmReadPackageFile(rpmTransactionSet ts, FD_t fd, } ts->dig = pgpNewDig(); - ts->dig->nbytes = headerSizeof(h, hmagic); - - /* Read the compressed payload. */ - while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) - ts->dig->nbytes += count; - - if (count < 0) { - rpmError(RPMERR_FREAD, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd)); - rc = RPMRC_FAIL; + if (ts->dig == NULL) { + rc = RPMRC_OK; /* XXX WRONG */ goto exit; } - ts->dig->nbytes += count; + ts->dig->nbytes = 0; + /* Retrieve the tag parameters from the signature header. */ + ts->sig = NULL; xx = headerGetEntry(sig, ts->sigtag, &ts->sigtype, (void **) &ts->sig, &ts->siglen); + if (ts->sig == NULL) { + rc = RPMRC_OK; /* XXX WRONG */ + goto exit; + } - xx = pgpPrtPkts(ts->sig, ts->siglen, ts->dig, rpmIsDebug()); - - /*@-type@*/ /* FIX: cast? */ - for (i = fd->ndigests - 1; i >= 0; i--) { - FDDIGEST_t fddig = fd->digests + i; - if (fddig->hashctx == NULL) - continue; - if (fddig->hashalgo == PGPHASHALGO_MD5) { - /*@-branchstate@*/ - if (ts->dig->md5ctx != NULL) - (void) rpmDigestFinal(ts->dig->md5ctx, NULL, NULL, 0); - /*@=branchstate@*/ - ts->dig->md5ctx = fddig->hashctx; - fddig->hashctx = NULL; - continue; + switch (ts->sigtag) { + case RPMSIGTAG_DSA: + /* Parse the parameters from the OpenPGP packets that will be needed. */ + xx = pgpPrtPkts(ts->sig, ts->siglen, ts->dig, rpmIsDebug()); + /*@fallthrough@*/ + case RPMSIGTAG_SHA1: + { void * uh = NULL; + int_32 uht; + int_32 uhc; + + /*@-branchstate@*/ + if (headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)) { + ts->dig->sha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE); + (void) rpmDigestUpdate(ts->dig->sha1ctx, uh, uhc); + ts->dig->nbytes += uhc; + uh = headerFreeData(uh, uht); } - if (fddig->hashalgo == PGPHASHALGO_SHA1) { - /*@-branchstate@*/ - if (ts->dig->sha1ctx != NULL) - (void) rpmDigestFinal(ts->dig->sha1ctx, NULL, NULL, 0); - /*@=branchstate@*/ - ts->dig->sha1ctx = fddig->hashctx; - fddig->hashctx = NULL; - continue; + /*@=branchstate@*/ + } break; + case RPMSIGTAG_GPG: + case RPMSIGTAG_PGP5: /* XXX legacy */ + case RPMSIGTAG_PGP: + /* Parse the parameters from the OpenPGP packets that will be needed. */ + xx = pgpPrtPkts(ts->sig, ts->siglen, ts->dig, rpmIsDebug()); + /*@fallthrough@*/ + case RPMSIGTAG_MD5: + /* Legacy signatures need the compressed payload in the digest too. */ + ts->dig->nbytes += headerSizeof(h, hmagic); + while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0) + ts->dig->nbytes += count; + if (count < 0) { + rpmError(RPMERR_FREAD, _("%s: Fread failed: %s\n"), + fn, Fstrerror(fd)); + rc = RPMRC_FAIL; + goto exit; + } + ts->dig->nbytes += count; + + /* XXX Steal the digest-in-progress from the file handle. */ + /*@-type@*/ /* FIX: cast? */ + for (i = fd->ndigests - 1; i >= 0; i--) { + FDDIGEST_t fddig = fd->digests + i; + if (fddig->hashctx == NULL) + continue; + if (fddig->hashalgo == PGPHASHALGO_MD5) { + /*@-branchstate@*/ + if (ts->dig->md5ctx != NULL) + (void) rpmDigestFinal(ts->dig->md5ctx, NULL, NULL, 0); + /*@=branchstate@*/ + ts->dig->md5ctx = fddig->hashctx; + fddig->hashctx = NULL; + continue; + } + if (fddig->hashalgo == PGPHASHALGO_SHA1) { + /*@-branchstate@*/ + if (ts->dig->sha1ctx != NULL) + (void) rpmDigestFinal(ts->dig->sha1ctx, NULL, NULL, 0); + /*@=branchstate@*/ + ts->dig->sha1ctx = fddig->hashctx; + fddig->hashctx = NULL; + continue; + } } + /*@=type@*/ + break; } - /*@=type@*/ /** @todo Implement disable/enable/warn/error/anal policy. */ buf[0] = '\0'; switch (rpmVerifySignature(ts, buf)) { case RPMSIG_OK: /* Signature is OK. */ - rpmMessage(RPMMESS_VERBOSE, "%s: %s", fn, buf); + rpmMessage(RPMMESS_DEBUG, "%s: %s", fn, buf); rc = RPMRC_OK; break; case RPMSIG_UNKNOWN: /* Signature is unknown. */ @@ -363,7 +416,7 @@ exit: /* Convert legacy headers on the fly ... */ legacyRetrofit(h, l); - /* Append (and remap) signature tags. */ + /* Append (and remap) signature tags to the metadata. */ headerMergeLegacySigs(h, sig); /* Bump reference count for return. */ diff --git a/lib/query.c b/lib/query.c index d08b02ad5..09f0875e9 100644 --- a/lib/query.c +++ b/lib/query.c @@ -974,7 +974,9 @@ int rpmcliQuery(rpmTransactionSet ts, QVA_t qva, const char ** argv) qva->qva_showPackage = showQueryPackage; switch (qva->qva_source) { +#ifdef DYING case RPMQV_RPM: +#endif case RPMQV_SPECFILE: break; default: diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c index 671b3a49a..6bc10328d 100644 --- a/lib/rpmchecksig.c +++ b/lib/rpmchecksig.c @@ -21,6 +21,8 @@ /*@access FD_t @*/ /*@access pgpDig @*/ +/** + */ static int manageFile(FD_t *fdp, const char **fnp, int flags, /*@unused@*/ int rc) /*@globals rpmGlobalMacroContext, @@ -78,6 +80,7 @@ static int manageFile(FD_t *fdp, const char **fnp, int flags, } /** + * Copy header+payload, calculating digest(s) on the fly. */ static int copyFile(FD_t *sfdp, const char **sfnp, FD_t *tfdp, const char **tfnp) @@ -158,11 +161,11 @@ static int rpmReSign(/*@unused@*/ rpmTransactionSet ts, } switch (l->major) { case 1: - rpmError(RPMERR_BADSIGTYPE, _("%s: Can't sign v1.0 RPM\n"), rpm); + rpmError(RPMERR_BADSIGTYPE, _("%s: Can't sign v1 packaging\n"), rpm); goto exit; /*@notreached@*/ /*@switchbreak@*/ break; case 2: - rpmError(RPMERR_BADSIGTYPE, _("%s: Can't re-sign v2.0 RPM\n"), rpm); + rpmError(RPMERR_BADSIGTYPE, _("%s: Can't re-sign v2 packaging\n"), rpm); goto exit; /*@notreached@*/ /*@switchbreak@*/ break; default: @@ -202,18 +205,25 @@ static int rpmReSign(/*@unused@*/ rpmTransactionSet ts, } (void) headerRemoveEntry(sig, RPMSIGTAG_SIZE); - (void) headerRemoveEntry(sig, RPMSIGTAG_MD5); + (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_SIZE, qva->passPhrase); (void) headerRemoveEntry(sig, RPMSIGTAG_LEMD5_1); (void) headerRemoveEntry(sig, RPMSIGTAG_LEMD5_2); + (void) headerRemoveEntry(sig, RPMSIGTAG_MD5); + (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_MD5, qva->passPhrase); +#ifdef NOTNOW + (void) headerRemoveEntry(sig, RPMSIGTAG_SHA1); + (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_SHA1, qva->passPhrase); + (void) headerRemoveEntry(sig, RPMSIGTAG_PGP5); (void) headerRemoveEntry(sig, RPMSIGTAG_PGP); (void) headerRemoveEntry(sig, RPMSIGTAG_GPG); - (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_SIZE, qva->passPhrase); - (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_MD5, qva->passPhrase); +#endif } - if ((sigtype = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) > 0) + if ((sigtype = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) > 0) { + (void) headerRemoveEntry(sig, sigtype); (void) rpmAddSignature(sig, sigtarget, sigtype, qva->passPhrase); + } /* Write the lead/signature of the output rpm */ strcpy(tmprpm, rpm); @@ -466,7 +476,6 @@ static int readFile(FD_t fd, int_32 sigtag, const char * fn, pgpDig dig) rpmError(RPMERR_FREAD, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd)); goto exit; } - dig->nbytes += count; /*@-type@*/ /* FIX: cast? */ for (i = fd->ndigests - 1; i >= 0; i--) { @@ -546,14 +555,20 @@ int rpmVerifySignatures(QVA_t qva, rpmTransactionSet ts, FD_t fd, } /* Grab a hint of what needs doing to avoid duplication. */ - if (headerIsEntry(sig, RPMSIGTAG_GPG)) + if (headerIsEntry(sig, RPMSIGTAG_DSA)) + sigtag = RPMSIGTAG_DSA; + else if (headerIsEntry(sig, RPMSIGTAG_GPG)) sigtag = RPMSIGTAG_GPG; else if (headerIsEntry(sig, RPMSIGTAG_PGP)) sigtag = RPMSIGTAG_PGP; else if (headerIsEntry(sig, RPMSIGTAG_MD5)) sigtag = RPMSIGTAG_MD5; +#ifdef NOTYET + else if (headerIsEntry(sig, RPMSIGTAG_SHA1)) + sigtag = RPMSIGTAG_SHA1; /* XXX never happens */ +#endif else - sigtag = 0; /* XXX never happens */ + sigtag = 0; /* XXX never happens */ ts->dig = pgpNewDig(); @@ -589,6 +604,7 @@ if (rpmIsDebug()) fprintf(stderr, "========================= Package RSA Signature\n"); xx = pgpPrtPkts(ts->sig, ts->siglen, ts->dig, rpmIsDebug()); /*@switchbreak@*/ break; + case RPMSIGTAG_DSA: case RPMSIGTAG_GPG: if (!(qva->qva_flags & VERIFY_SIGNATURE)) continue; @@ -603,11 +619,17 @@ fprintf(stderr, "========================= Package DSA Signature\n"); continue; /* * Don't bother with md5 if pgp, as RSA/MD5 is more reliable - * than the legacy -- now unsupported -- legacy md5 breakage. + * than the -- now unsupported -- legacy md5 breakage. */ if (sigtag == RPMSIGTAG_PGP) continue; /*@switchbreak@*/ break; + case RPMSIGTAG_SHA1: +#ifdef NOTYET + if (!(qva->qva_flags & VERIFY_DIGEST)) + continue; + /*@switchbreak@*/ break; +#endif default: continue; /*@notreached@*/ /*@switchbreak@*/ break; @@ -662,6 +684,7 @@ fprintf(stderr, "========================= Package DSA Signature\n"); /*@innerbreak@*/ break; } /*@switchbreak@*/ break; + case RPMSIGTAG_DSA: case RPMSIGTAG_GPG: /* Do not consider this a failure */ switch (res3) { @@ -703,6 +726,7 @@ fprintf(stderr, "========================= Package DSA Signature\n"); case RPMSIGTAG_PGP: b = stpcpy(b, "pgp "); /*@switchbreak@*/ break; + case RPMSIGTAG_DSA: case RPMSIGTAG_GPG: b = stpcpy(b, "gpg "); /*@switchbreak@*/ break; diff --git a/lib/rpmlib.h b/lib/rpmlib.h index 4b34fbbe7..1f7310969 100644 --- a/lib/rpmlib.h +++ b/lib/rpmlib.h @@ -228,6 +228,7 @@ typedef enum rpmTag_e { /*@=enummemuse@*/ RPMTAG_SHA1HEADER = RPMTAG_SIG_BASE+9, RPMTAG_PUBKEYS = RPMTAG_SIG_BASE+10, + RPMTAG_DSAHEADER = RPMTAG_SIG_BASE+11, RPMTAG_NAME = 1000, RPMTAG_VERSION = 1001, @@ -773,9 +774,9 @@ typedef /*@abstract@*/ struct _rpmdbMatchIterator * rpmdbMatchIterator; /*@modifies mi, fileSystem @*/; /** \ingroup rpmdb - * Return join key for current position of rpm database iterator. + * Return header join key for current position of rpm database iterator. * @param mi rpm database iterator - * @return current join key + * @return current header join key */ unsigned int rpmdbGetIteratorOffset(/*@null@*/ rpmdbMatchIterator mi) /*@*/; @@ -1780,12 +1781,16 @@ typedef enum rpmEraseInterfaceFlags_e { enum rpmtagSignature { RPMSIGTAG_SIZE = 1000, /*!< Header+Payload size in bytes. */ /* the md5 sum was broken *twice* on big endian machines */ - RPMSIGTAG_LEMD5_1 = 1001, /*!< Broken MD5, take 1 */ + RPMSIGTAG_LEMD5_1 = 1001, /*!< Broken MD5, take 1 @deprecated legacy. */ RPMSIGTAG_PGP = 1002, /*!< PGP 2.6.3 signature. */ - RPMSIGTAG_LEMD5_2 = 1003, /*!< Broken MD5, take 2 */ + RPMSIGTAG_LEMD5_2 = 1003, /*!< Broken MD5, take 2 @deprecated legacy. */ RPMSIGTAG_MD5 = 1004, /*!< MD5 signature. */ RPMSIGTAG_GPG = 1005, /*!< GnuPG signature. */ RPMSIGTAG_PGP5 = 1006, /*!< PGP5 signature @deprecated legacy. */ + RPMSIGTAG_PAYLOADSIZE = 1007, + /*!< uncompressed payload size in bytes. */ + RPMSIGTAG_SHA1 = RPMTAG_SHA1HEADER, /*!< sha1 header digest. */ + RPMSIGTAG_DSA = RPMTAG_DSAHEADER, /*!< DSA header signature. */ }; /** diff --git a/lib/signature.c b/lib/signature.c index 40ed66cc1..f9a81b2e0 100644 --- a/lib/signature.c +++ b/lib/signature.c @@ -7,6 +7,7 @@ #include "rpmio_internal.h" #include <rpmlib.h> #include <rpmmacro.h> /* XXX for rpmGetPath() */ +#include "rpmdb.h" #include "depends.h" #include "misc.h" /* XXX for dosetenv() and makeTempFile() */ @@ -483,6 +484,10 @@ int rpmAddSignature(Header h, const char * file, int_32 sigTag, if (ret == 0) (void) headerAddEntry(h, sigTag, RPM_BIN_TYPE, sig, size); break; + case RPMSIGTAG_DSA: /* XXX UNIMPLEMENTED */ + break; + case RPMSIGTAG_SHA1: /* XXX UNIMPLEMENTED */ + break; } return ret; @@ -523,6 +528,7 @@ static int checkPassPhrase(const char * passPhrase, const int sigTag) (void) dup2(passPhrasePipe[0], 3); switch (sigTag) { + case RPMSIGTAG_DSA: case RPMSIGTAG_GPG: { const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL); @@ -597,6 +603,7 @@ char * rpmGetPassPhrase(const char * prompt, const int sigTag) int aok; switch (sigTag) { + case RPMSIGTAG_DSA: case RPMSIGTAG_GPG: { const char *name = rpmExpand("%{?_gpg_name}", NULL); aok = (name && *name != '\0'); @@ -662,21 +669,31 @@ verifySizeSignature(const rpmTransactionSet ts, /*@out@*/ char * t) *t = '\0'; t = stpcpy(t, _("Header+Payload size: ")); -/*@-nullpass -nullderef@*/ /* FIX: ts->{sig,dig} can be NULL */ + if (ts->sig == NULL || ts->dig == NULL) { + res = RPMSIG_NOKEY; + t = stpcpy(t, rpmSigString(res)); + goto exit; + } + +/*@=nullpass =nullderef@*/ /* FIX: ts->{sig,dig} can be NULL */ memcpy(&size, ts->sig, sizeof(size)); /*@-type@*/ /*@-nullderef@*/ /* FIX: ts->dig can be NULL */ if (size != ts->dig->nbytes) { res = RPMSIG_BAD; - sprintf(t, "BAD Expected(%d) != (%d)\n", size, ts->dig->nbytes); + t = stpcpy(t, rpmSigString(res)); + sprintf(t, " Expected(%d) != (%d)\n", size, ts->dig->nbytes); } else { res = RPMSIG_OK; - sprintf(t, "OK (%d)\n", ts->dig->nbytes); + t = stpcpy(t, rpmSigString(res)); + sprintf(t, " (%d)", ts->dig->nbytes); } /*@=type@*/ /*@=nullpass =nullderef@*/ +exit: + t = stpcpy(t, "\n"); return res; } @@ -691,7 +708,13 @@ verifyMD5Signature(const rpmTransactionSet ts, /*@out@*/ char * t) *t = '\0'; t = stpcpy(t, _("MD5 digest: ")); -/*@-nullpass -nullderef@*/ /* FIX: ts->{sig,dig} can be NULL */ + if (ts->sig == NULL || ts->dig == NULL) { + res = RPMSIG_NOKEY; + t = stpcpy(t, rpmSigString(res)); + goto exit; + } + +/*@=nullpass =nullderef@*/ /* FIX: ts->{sig,dig} can be NULL */ /*@-type@*/ (void) rpmDigestFinal(rpmDigestDup(ts->dig->md5ctx), (void **)&md5sum, &md5len, 0); @@ -699,21 +722,172 @@ verifyMD5Signature(const rpmTransactionSet ts, /*@out@*/ char * t) if (md5len != ts->siglen || memcmp(md5sum, ts->sig, md5len)) { res = RPMSIG_BAD; - t = stpcpy(t, "BAD Expected("); + t = stpcpy(t, rpmSigString(res)); + t = stpcpy(t, " Expected("); (void) pgpHexCvt(t, ts->sig, ts->siglen); t += strlen(t); t = stpcpy(t, ") != ("); } else { res = RPMSIG_OK; - t = stpcpy(t, "OK ("); + t = stpcpy(t, rpmSigString(res)); + t = stpcpy(t, " ("); } /*@=nullpass =nullderef@*/ (void) pgpHexCvt(t, md5sum, md5len); t += strlen(t); - t = stpcpy(t, ")\n"); + t = stpcpy(t, ")"); +exit: md5sum = _free(md5sum); + t = stpcpy(t, "\n"); + return res; +} + +static rpmVerifySignatureReturn +verifySHA1Signature(const rpmTransactionSet ts, /*@out@*/ char * t) + /*@modifies *t @*/ +{ + rpmVerifySignatureReturn res; + const char * sha1 = NULL; + + *t = '\0'; + t = stpcpy(t, _("SHA1 header digest: ")); + + if (ts->sig == NULL || ts->dig == NULL) { + res = RPMSIG_NOKEY; + t = stpcpy(t, rpmSigString(res)); + goto exit; + } + + /*@-type@*/ + (void) rpmDigestFinal(rpmDigestDup(ts->dig->sha1ctx), + (void **)&sha1, NULL, 1); + /*@=type@*/ + + if (sha1 == NULL || strlen(sha1) != strlen(ts->sig)) { + res = RPMSIG_BAD; + t = stpcpy(t, rpmSigString(res)); + t = stpcpy(t, " Expected("); + t = stpcpy(t, ts->sig); + t = stpcpy(t, ") != ("); + } else { + res = RPMSIG_OK; + t = stpcpy(t, rpmSigString(res)); + t = stpcpy(t, " ("); + } + if (sha1) + t = stpcpy(t, sha1); + t = stpcpy(t, ")"); + +exit: + sha1 = _free(sha1); + t = stpcpy(t, "\n"); + return res; +} + +/** + * Retrieve pubkey from rpm database. + * @param ts rpm transaction + * @return RPMSIG_OK on success, RPMSIG_NOKEY if not found + */ +static rpmVerifySignatureReturn +rpmtsFindPubkey(rpmTransactionSet ts) + /*@modifies ts */ +{ + struct pgpDigParams_s * sigp = NULL; + rpmVerifySignatureReturn res; + /*@unchecked@*/ /*@only@*/ static const byte * pkpkt = NULL; + /*@unchecked@*/ static size_t pkpktlen = 0; + /*@unchecked@*/ static byte pksignid[8]; + int xx; + + if (ts->sig == NULL || ts->dig == NULL) { + res = RPMSIG_NOKEY; + goto exit; + } + sigp = &ts->dig->signature; + + /*@-globs -internalglobs -mods -modfilesys@*/ + if (pkpkt == NULL || memcmp(sigp->signid, pksignid, sizeof(pksignid))) { + int ix = -1; + rpmdbMatchIterator mi; + Header h; + + pkpkt = _free(pkpkt); + pkpktlen = 0; + memset(pksignid, 0, sizeof(pksignid)); + + (void) rpmtsOpenDB(ts, ts->dbmode); + + mi = rpmtsInitIterator(ts, RPMTAG_PUBKEYS, sigp->signid, sizeof(sigp->signid)); + while ((h = rpmdbNextIterator(mi)) != NULL) { + const char ** pubkeys; + int_32 pt, pc; + + if (!headerGetEntry(h, RPMTAG_PUBKEYS, &pt, (void **)&pubkeys, &pc)) + continue; + ix = rpmdbGetIteratorFileNum(mi); + if (ix >= pc + || b64decode(pubkeys[ix], (void **) &pkpkt, &pkpktlen)) + ix = -1; + pubkeys = headerFreeData(pubkeys, pt); + break; + } + mi = rpmdbFreeIterator(mi); + + if (ix < 0 || pkpkt == NULL) { + res = RPMSIG_NOKEY; + goto exit; + } + + /* Make sure the pkt can be parsed, print info if debugging. */ + if (pgpPrtPkts(pkpkt, pkpktlen, NULL, 0)) { + res = RPMSIG_NOKEY; + goto exit; + } + + /* XXX Verify the pubkey signature. */ + + /* Packet looks good, save the signer id. */ + memcpy(pksignid, sigp->signid, sizeof(pksignid)); + } + +#ifdef NOTNOW + { + if (pkpkt == NULL) { + const char * pkfn = rpmExpand("%{_gpg_pubkey}", NULL); + if (pgpReadPkts(pkfn, &pkpkt, &pkpktlen) != PGPARMOR_PUBKEY) { + pkfn = _free(pkfn); + res = RPMSIG_NOKEY; + goto exit; + } + pkfn = _free(pkfn); + } + } +#endif + + rpmMessage(RPMMESS_DEBUG, "========== %s pubkey id %s\n", + (sigp->pubkey_algo == PGPPUBKEYALGO_DSA ? "DSA" : + (sigp->pubkey_algo == PGPPUBKEYALGO_RSA ? "RSA" : "???")), + pgpHexStr(sigp->signid, sizeof(sigp->signid))); + + /* Retrieve parameters from pubkey packet(s). */ + xx = pgpPrtPkts(pkpkt, pkpktlen, ts->dig, 0); + /*@=globs =internalglobs =mods =modfilesys@*/ + + /* Make sure we have the correct public key. */ + if (ts->dig->signature.pubkey_algo == ts->dig->pubkey.pubkey_algo +#ifdef NOTYET + && ts->dig->signature.hash_algo == ts->dig->pubkey.hash_algo +#endif + && !memcmp(ts->dig->signature.signid, ts->dig->pubkey.signid, 8)) + res = RPMSIG_OK; + else + res = RPMSIG_NOKEY; + + /* XXX Verify the signature signature. */ +exit: return res; } @@ -721,22 +895,33 @@ static rpmVerifySignatureReturn verifyPGPSignature(rpmTransactionSet ts, /*@out@*/ char * t) /*@modifies ts, *t */ { -/*@-nullpass -nullderef@*/ /* FIX: ts->{sig,dig} can be NULL */ + struct pgpDigParams_s * sigp = NULL; rpmVerifySignatureReturn res; - struct pgpDigParams_s * digp = &ts->dig->signature; - /*@unchecked@*/ static const byte * pgppk = NULL; - /*@unchecked@*/ static size_t pgppklen = 0; int xx; *t = '\0'; t = stpcpy(t, _("V3 RSA/MD5 signature: ")); + if (ts->sig == NULL || ts->dig == NULL) { + res = RPMSIG_NOKEY; + goto exit; + } + sigp = &ts->dig->signature; + /* XXX sanity check on ts->sigtag and signature agreement. */ + if (!(ts->sigtag == RPMSIGTAG_PGP + && sigp->pubkey_algo == PGPPUBKEYALGO_RSA + && sigp->hash_algo == PGPHASHALGO_MD5)) + { + res = RPMSIG_NOKEY; + goto exit; + } /*@-type@*/ /* FIX: cast? */ { DIGEST_CTX ctx = rpmDigestDup(ts->dig->md5ctx); - xx = rpmDigestUpdate(ctx, digp->hash, digp->hashlen); + if (sigp->hash != NULL) + xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen); xx = rpmDigestFinal(ctx, (void **)&ts->dig->md5, &ts->dig->md5len, 1); /* XXX compare leading 16 bits of digest for quick check. */ @@ -763,46 +948,25 @@ verifyPGPSignature(rpmTransactionSet ts, /*@out@*/ char * t) hexstr = _free(hexstr); } - /* XXX retrieve by keyid from signature. */ - - /*@-globs -internalglobs -mods -modfilesys@*/ - if (pgppk == NULL) { - const char * pkfn = rpmExpand("%{_pgp_pubkey}", NULL); - if (pgpReadPkts(pkfn, &pgppk, &pgppklen) != PGPARMOR_PUBKEY) { - pkfn = _free(pkfn); - res = RPMSIG_NOKEY; - goto exit; - } - rpmMessage(RPMMESS_DEBUG, - "========== PGP RSA/MD5 pubkey %s\n", pkfn); - xx = pgpPrtPkts(pgppk, pgppklen, NULL, rpmIsDebug()); - pkfn = _free(pkfn); - } - - /* Retrieve parameters from pubkey packet(s). */ - xx = pgpPrtPkts(pgppk, pgppklen, ts->dig, 0); - /*@=globs =internalglobs =mods =modfilesys@*/ - - /* Make sure we have the correct public key. */ - if (ts->dig->signature.pubkey_algo != ts->dig->pubkey.pubkey_algo - || memcmp(ts->dig->signature.signid, ts->dig->pubkey.signid, 8)) - { - res = RPMSIG_NOKEY; + /* Retrieve the matching public key. */ + res = rpmtsFindPubkey(ts); + if (res != RPMSIG_OK) goto exit; - } /*@-type@*/ - if (!rsavrfy(&ts->dig->rsa_pk, &ts->dig->rsahm, &ts->dig->c)) - res = RPMSIG_BAD; - else + if (rsavrfy(&ts->dig->rsa_pk, &ts->dig->rsahm, &ts->dig->c)) res = RPMSIG_OK; + else + res = RPMSIG_BAD; /*@=type@*/ -/*@=nullpass =nullderef@*/ exit: - t = stpcpy( stpcpy(t, rpmSigString(res)), ", key ID "); - (void) pgpHexCvt(t, digp->signid+4, sizeof(digp->signid)-4); - t += strlen(t); + t = stpcpy(t, rpmSigString(res)); + if (sigp != NULL) { + t = stpcpy(t, ", key ID "); + (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4); + t += strlen(t); + } t = stpcpy(t, "\n"); return res; } @@ -811,71 +975,61 @@ static rpmVerifySignatureReturn verifyGPGSignature(rpmTransactionSet ts, /*@out@*/ char * t) /*@modifies ts, *t @*/ { -/*@-nullpass -nullderef@*/ /* FIX: ts->{sig,dig} can be NULL */ + struct pgpDigParams_s * sigp = NULL; rpmVerifySignatureReturn res; - struct pgpDigParams_s * digp = &ts->dig->signature; - /*@unchecked@*/ static const byte * gpgpk = NULL; - /*@unchecked@*/ static size_t gpgpklen = 0; int xx; *t = '\0'; t = stpcpy(t, _("V3 DSA signature: ")); + if (ts->sig == NULL || ts->dig == NULL) { + res = RPMSIG_NOKEY; + goto exit; + } + sigp = &ts->dig->signature; + /* XXX sanity check on ts->sigtag and signature agreement. */ + if (!((ts->sigtag == RPMSIGTAG_GPG || ts->sigtag == RPMSIGTAG_DSA) + && sigp->pubkey_algo == PGPPUBKEYALGO_DSA + && sigp->hash_algo == PGPHASHALGO_SHA1)) + { + res = RPMSIG_NOKEY; + goto exit; + } /*@-type@*/ /* FIX: cast? */ { DIGEST_CTX ctx = rpmDigestDup(ts->dig->sha1ctx); - xx = rpmDigestUpdate(ctx, digp->hash, digp->hashlen); + if (sigp->hash != NULL) + xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen); xx = rpmDigestFinal(ctx, (void **)&ts->dig->sha1, &ts->dig->sha1len, 1); + /* XXX compare leading 16 bits of digest for quick check. */ + mp32nzero(&ts->dig->hm); mp32nsethex(&ts->dig->hm, ts->dig->sha1); } /*@=type@*/ - /* XXX retrieve by keyid from signature. */ - - /*@-globs -internalglobs -mods -modfilesys@*/ - if (gpgpk == NULL) { - const char * pkfn = rpmExpand("%{_gpg_pubkey}", NULL); - int printing = 0; /* XXX was rpmIsDebug() */ - - if (pgpReadPkts(pkfn, &gpgpk, &gpgpklen) != PGPARMOR_PUBKEY) { - pkfn = _free(pkfn); - res = RPMSIG_NOKEY; - goto exit; - } - rpmMessage(RPMMESS_DEBUG, - "========== GPG DSA pubkey %s\n", pkfn); - xx = pgpPrtPkts(gpgpk, gpgpklen, NULL, printing); - pkfn = _free(pkfn); - } - - /* Retrieve parameters from pubkey packet(s). */ - xx = pgpPrtPkts(gpgpk, gpgpklen, ts->dig, 0); - /*@=globs =internalglobs =mods =modfilesys@*/ - - /* Make sure we have the correct public key. */ - if (ts->dig->signature.pubkey_algo != ts->dig->pubkey.pubkey_algo - || memcmp(ts->dig->signature.signid, ts->dig->pubkey.signid, 8)) - { - res = RPMSIG_NOKEY; + /* Retrieve the matching public key. */ + res = rpmtsFindPubkey(ts); + if (res != RPMSIG_OK) goto exit; - } /*@-type@*/ - if (!dsavrfy(&ts->dig->p, &ts->dig->q, &ts->dig->g, + if (dsavrfy(&ts->dig->p, &ts->dig->q, &ts->dig->g, &ts->dig->hm, &ts->dig->y, &ts->dig->r, &ts->dig->s)) - res = RPMSIG_BAD; - else res = RPMSIG_OK; + else + res = RPMSIG_BAD; /*@=type@*/ -/*@=nullpass =nullderef@*/ exit: - t = stpcpy( stpcpy(t, rpmSigString(res)), ", key ID "); - (void) pgpHexCvt(t, digp->signid+4, sizeof(digp->signid)-4); - t += strlen(t); + t = stpcpy(t, rpmSigString(res)); + if (sigp != NULL) { + t = stpcpy(t, ", key ID "); + (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4); + t += strlen(t); + } t = stpcpy(t, "\n"); return res; } @@ -897,10 +1051,14 @@ rpmVerifySignature(const rpmTransactionSet ts, char * result) case RPMSIGTAG_MD5: res = verifyMD5Signature(ts, result); break; + case RPMSIGTAG_SHA1: + res = verifySHA1Signature(ts, result); + break; case RPMSIGTAG_PGP5: /* XXX legacy */ case RPMSIGTAG_PGP: res = verifyPGPSignature(ts, result); break; + case RPMSIGTAG_DSA: case RPMSIGTAG_GPG: res = verifyGPGSignature(ts, result); break; diff --git a/lib/verify.c b/lib/verify.c index 13a30e3ee..c3f544bf1 100644 --- a/lib/verify.c +++ b/lib/verify.c @@ -572,10 +572,12 @@ int rpmcliVerify(rpmTransactionSet ts, QVA_t qva, const char ** argv) qva->qva_showPackage = showVerifyPackage; switch (qva->qva_source) { +#ifdef DYING case RPMQV_RPM: if (!(qva->qva_flags & VERIFY_DEPS)) break; /*@fallthrough@*/ +#endif default: if (rpmtsOpenDB(ts, O_RDONLY)) return 1; /* XXX W2DO? */ @@ -2,7 +2,7 @@ %define with_python_version 2.2%{nil} %define with_perl_subpackage 1 %define with_bzip2 1%{nil} -%define with_apidocs 1%{nil} +%define with_apidocs 0%{nil} %define with_internal_db 1%{nil} %define strip_binaries 1 @@ -479,7 +479,7 @@ fi %files devel %defattr(-,root,root) %if %{with_apidocs} -%doc apidocs +%doc %endif %{__prefix}/include/rpm %{__prefix}/lib/librpm.a @@ -647,3 +647,11 @@ fi - add cpanflute2, another perl.req fiddle. - make peace with gcc-3.1, remove compiler cruft. - make peace with automake et al in 8.0, ugh. +- add payload uncompressed size to signature to avoid rewriting header. +- drill header sha1 into signature parallel to header+payload md5. +- mandatory "most effective" signature check on query/verify/install. +- don't bother adding empty filemd's to index. +- add Pubkey index, using signer id as binary key. +- display pubkeys in hex when debugging db access. +- retrieve pubkey(s) from rpmdb, not from detached signature file. +- reapply Berkeley DB patch #4491. diff --git a/rpm.spec.in b/rpm.spec.in index b1898f2dc..f89f7ab82 100644 --- a/rpm.spec.in +++ b/rpm.spec.in @@ -647,3 +647,11 @@ fi - add cpanflute2, another perl.req fiddle. - make peace with gcc-3.1, remove compiler cruft. - make peace with automake et al in 8.0, ugh. +- add payload uncompressed size to signature to avoid rewriting header. +- drill header sha1 into signature parallel to header+payload md5. +- mandatory "most effective" signature check on query/verify/install. +- don't bother adding empty filemd's to index. +- add Pubkey index, using signer id as binary key. +- display pubkeys in hex when debugging db access. +- retrieve pubkey(s) from rpmdb, not from detached signature file. +- reapply Berkeley DB patch #4491. diff --git a/rpmdb/rpmdb.c b/rpmdb/rpmdb.c index 339804bc3..b879142aa 100644 --- a/rpmdb/rpmdb.c +++ b/rpmdb/rpmdb.c @@ -33,6 +33,7 @@ extern void regfree (/*@only@*/ regex_t *preg) #endif #include <rpmcli.h> +#include <rpmpgp.h> #include "rpmdb.h" #include "fprint.h" @@ -63,6 +64,38 @@ static int _db_filter_dups = 0; int dbiTagsMax = 0; /** + * Convert hex to binary nibble. + * @param c hex character + * @return binary nibble + */ +static inline unsigned char nibble(char c) + /*@*/ +{ + if (c >= '0' && c <= '9') + return (c - '0'); + if (c >= 'A' && c <= 'F') + return (c - 'A') + 10; + if (c >= 'a' && c <= 'f') + return (c - 'a') + 10; + return 0; +} + +/** + * Check key for printable characters. + * @param ptr key value pointer + * @param len key value length + * @return 1 if only ASCII, 0 otherwise. + */ +static int printable(const void * ptr, size_t len) /*@*/ +{ + const char * s = ptr; + int i; + for (i = 0; i < len; i++, s++) + if (!(*s >= ' ' && *s <= '~')) return 0; + return 1; +} + +/** * Return dbi index used for rpm tag. * @param rpmtag rpm header tag * @return dbi index, -1 on error @@ -209,15 +242,6 @@ fprintf(stderr, "--- RMW %s\n", tagName(dbi->dbi_rpmtag)); return (*dbi->dbi_vec->cclose) (dbi, dbcursor, flags); } -static int printable(const void * ptr, size_t len) /*@*/ -{ - const char * s = ptr; - int i; - for (i = 0; i < len; i++, s++) - if (!(*s >= ' ' && *s <= '~')) return 0; - return 1; -} - INLINE int dbiDel(dbiIndex dbi, DBC * dbcursor, const void * keyp, size_t keylen, unsigned int flags) { @@ -257,13 +281,24 @@ if (_debug < 0 || dbi->dbi_debug) { char keyval[64]; keyval[0] = '\0'; if (keypp && *keypp && keylenp) { - if (*keylenp <= sizeof(int) && !printable(*keypp, *keylenp)) { + if (printable(*keypp, *keylenp)) { + kvp = *keypp; + } else if (*keylenp <= sizeof(int)) { int keyint = 0; memcpy(&keyint, *keypp, sizeof(keyint)); sprintf(keyval, "#%d", keyint); kvp = keyval; } else { - kvp = *keypp; + static const char hex[] = "0123456789abcdef"; + const byte * s = *keypp; + char * t = keyval; + int i; + for (i = 0; i < *keylenp && t < (keyval+sizeof(keyval)-2); i++) { + *t++ = hex[ (unsigned)((*s >> 4) & 0x0f) ]; + *t++ = hex[ (unsigned)((*s++ ) & 0x0f) ]; + } + *t = '\0'; + kvp = keyval; } } else kvp = keyval; @@ -298,13 +333,24 @@ if (_debug < 0 || dbi->dbi_debug) { char keyval[64]; keyval[0] = '\0'; if (keyp) { - if (keylen == sizeof(int) && !printable(keyp, keylen)) { + if (printable(keyp, keylen)) { + kvp = keyp; + } else if (keylen <= sizeof(int)) { int keyint = 0; memcpy(&keyint, keyp, sizeof(keyint)); sprintf(keyval, "#%d", keyint); kvp = keyval; } else { - kvp = keyp; + static const char hex[] = "0123456789abcdef"; + const byte * s = keyp; + char * t = keyval; + int i; + for (i = 0; i < keylen && t < (keyval+sizeof(keyval)-2); i++) { + *t++ = hex[ (unsigned)((*s >> 4) & 0x0f) ]; + *t++ = hex[ (unsigned)((*s++ ) & 0x0f) ]; + } + *t = '\0'; + kvp = keyval; } } else kvp = keyval; @@ -2457,7 +2503,7 @@ int rpmdbRemove(rpmdb db, /*@unused@*/ int rid, unsigned int hdrNum) int rpmcnt = 0; int rpmtag; int xx; - int i; + int i, j; dbi = NULL; rpmtag = dbiTags[dbix]; @@ -2506,6 +2552,17 @@ int rpmdbRemove(rpmdb db, /*@unused@*/ int rid, unsigned int hdrNum) const void * valp; size_t vallen; int stringvalued; + byte bin[32]; + + switch (dbi->dbi_rpmtag) { + case RPMTAG_FILEMD5S: + /* Filter out empty MD5 strings. */ + if (!(rpmvals[i] && *rpmvals[i] != '\0')) + /*@innercontinue@*/ continue; + /*@switchbreak@*/ break; + default: + /*@switchbreak@*/ break; + } /* Identify value pointer and length. */ stringvalued = 0; @@ -2533,6 +2590,36 @@ int rpmdbRemove(rpmdb db, /*@unused@*/ int rid, unsigned int hdrNum) rpmcnt = 1; /* XXX break out of loop. */ /*@fallthrough@*/ case RPM_STRING_ARRAY_TYPE: + /* Convert from hex to binary. */ + if (dbi->dbi_rpmtag == RPMTAG_FILEMD5S) { + const char * s; + byte * t; + + s = rpmvals[i]; + t = bin; + for (j = 0; j < 16; j++, t++, s += 2) + *t = (nibble(s[0]) << 4) | nibble(s[1]); + valp = bin; + vallen = 16; + /*@switchbreak@*/ break; + } + /* Extract the pubkey id from the base64 blob. */ + if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) { + pgpDig dig = pgpNewDig(); + const byte * pkt; + ssize_t pktlen; + + if (b64decode(rpmvals[i], (void **)&pkt, &pktlen)) + continue; + (void) pgpPrtPkts(pkt, pktlen, dig, 0); + memcpy(bin, dig->pubkey.signid, 8); + pkt = _free(pkt); + dig = _free(dig); + valp = bin; + vallen = 8; + /*@switchbreak@*/ break; + } + /*@fallthrough@*/ default: vallen = strlen(rpmvals[i]); valp = rpmvals[i]; @@ -2812,17 +2899,25 @@ int rpmdbAdd(rpmdb db, int iid, Header h) const void * valp; size_t vallen; int stringvalued; + byte bin[32]; /* * Include the tagNum in all indices. rpm-3.0.4 and earlier * included the tagNum only for files. */ + rec->tagNum = i; switch (dbi->dbi_rpmtag) { + case RPMTAG_PUBKEYS: + /*@switchbreak@*/ break; + case RPMTAG_FILEMD5S: + /* Filter out empty MD5 strings. */ + if (!(rpmvals[i] && *rpmvals[i] != '\0')) + /*@innercontinue@*/ continue; + /*@switchbreak@*/ break; case RPMTAG_REQUIRENAME: /* Filter out install prerequisites. */ if (requireFlags && isInstallPreReq(requireFlags[i])) /*@innercontinue@*/ continue; - rec->tagNum = i; /*@switchbreak@*/ break; case RPMTAG_TRIGGERNAME: if (i) { /* don't add duplicates */ @@ -2833,10 +2928,8 @@ int rpmdbAdd(rpmdb db, int iid, Header h) if (j < i) /*@innercontinue@*/ continue; } - rec->tagNum = i; /*@switchbreak@*/ break; default: - rec->tagNum = i; /*@switchbreak@*/ break; } @@ -2866,6 +2959,36 @@ int rpmdbAdd(rpmdb db, int iid, Header h) rpmcnt = 1; /* XXX break out of loop. */ /*@fallthrough@*/ case RPM_STRING_ARRAY_TYPE: + /* Convert from hex to binary. */ + if (dbi->dbi_rpmtag == RPMTAG_FILEMD5S) { + const char * s; + byte * t; + + s = rpmvals[i]; + t = bin; + for (j = 0; j < 16; j++, t++, s += 2) + *t = (nibble(s[0]) << 4) | nibble(s[1]); + valp = bin; + vallen = 16; + /*@switchbreak@*/ break; + } + /* Extract the pubkey id from the base64 blob. */ + if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) { + pgpDig dig = pgpNewDig(); + const byte * pkt; + ssize_t pktlen; + + if (b64decode(rpmvals[i], (void **)&pkt, &pktlen)) + continue; + (void) pgpPrtPkts(pkt, pktlen, dig, 0); + memcpy(bin, dig->pubkey.signid, 8); + pkt = _free(pkt); + dig = _free(dig); + valp = bin; + vallen = 8; + /*@switchbreak@*/ break; + } + /*@fallthrough@*/ default: valp = rpmvals[i]; vallen = strlen(rpmvals[i]); diff --git a/rpmdb/rpmdb.h b/rpmdb/rpmdb.h index 4dc515010..c0fd4dd79 100644 --- a/rpmdb/rpmdb.h +++ b/rpmdb/rpmdb.h @@ -519,7 +519,6 @@ char * db1basename(int rpmtag) /** \ingroup rpmdb */ -/*@unused@*/ unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi) /*@*/; diff --git a/rpmio/rpmio_internal.h b/rpmio/rpmio_internal.h index 8c645ca14..28eb4036f 100644 --- a/rpmio/rpmio_internal.h +++ b/rpmio/rpmio_internal.h @@ -507,11 +507,11 @@ void fdFiniDigest(FD_t fd, pgpHashAlgo hashalgo, if (i < 0) { if (datap) *datap = NULL; if (lenp) *lenp = 0; - return; - } else if (i == imax) - fd->ndigests = imax - 1; - else - fd->ndigests = imax; + } + + fd->ndigests = imax; + if (i < imax) + fd->ndigests++; /* convert index to count */ } /*@-shadow@*/ |