📄 pgprngpriv.c
字号:
}
}
/* Skip to next object */
if( IsPGPError( err =
pgpVirtMaskOR (pool, &objmask, &remmask) ) )
goto error;
objp = &robj->g.next;
}
pgpVirtMaskCleanup (pool, omask);
*omask = remmask;
error:
pgpVirtMaskCleanup (pool, &tmpmask);
pgpVirtMaskCleanup (pool, &objmask);
return err;
}
/*
* Reclaim all unused bits and delete any unreferenced memory objects.
* Return TRUE if did some reclamation.
*/
PGPBoolean
ringGarbageCollect(RingPool *pool)
{
PGPVirtMask mask;
PGPError err;
/* Build sig lists so we know which keys act as signers.
These should be left as dummy keys rather than freed. */
ringPoolListSigsBy (pool);
if (IsPGPError( err = pgpVirtMaskInit (pool, &mask) ) )
return FALSE;
if (IsPGPError (err = ringAllocMask(pool, (RingSet const *)NULL, &mask)))
return FALSE;
if (!pgpVirtMaskIsEqual (&mask, &pool->allocmask)) {
pgpVirtMaskCopy (pool, &mask, &pool->allocmask);
if (IsPGPError( err = ringClearMask(pool, &pool->keys, &mask,
NULL, &mask)))
return FALSE;
pgpVirtMaskAND(pool, &pool->memringmask, &mask);
if (pgpVirtMaskIsEmpty(&mask)) {
memPoolEmpty(&pool->files[MEMRINGBIT]->strings);
memPoolEmpty(&pool->files[MEMRINGBIT]->fpos);
pool->files[MEMRINGBIT]->freepos = NULL;
pgpVirtMaskCleanup (pool, &mask);
return TRUE; /* Something freed */
}
}
pgpVirtMaskCleanup (pool, &mask);
return FALSE; /* Nothing freed */
}
/* Remove a single key from its hash chain */
static void
ringGarbageHackKey(RingPool *pool, RingKey *key)
{
RingKey **keyp;
keyp = &pool->hashtable[key->keyID[0]];
while (*keyp != key) {
pgpAssert(*keyp);
keyp = &(*keyp)->util;
}
*keyp = key->util;
}
/* Remove a single signature from its sigsby list */
static void
ringGarbageHackSig(RingSig *sig)
{
RingKey *key;
RingSig **sigp;
key = &sig->by->k;
pgpAssert(KEYISKEY(key));
/*
* This could be one loop but for type rules, sigh...
* The problem doesn't happen often, fortunately.
* (The single loop can be expressed in C using the
* cheat sigp = (RingSig **)&key->sigsby; but
* while that's portable in practice, we eschew it
* for the sake of ANSI C purity.)
*/
if (&key->sigsby->s == sig) {
key->sigsby = (union RingObject *)sig->nextby;
} else {
sigp = &key->sigsby->s.nextby;
while (*sigp != sig)
sigp = &(*sigp)->nextby;
*sigp = sig->nextby;
}
}
/*
* Delete a single object from the global pool if it is an unreferenced
* memory object.
*/
void
ringGarbageCollectObject(RingPool *pool, union RingObject *robj)
{
union RingObject **objp;
if (pgpVirtMaskIsEqual (&robj->g.mask, &pool->memringmask)) {
pgpAssert(!robj->g.down);
objp = OBJISTOP(robj) ? &pool->keys : &robj->g.up->g.down;
while (*objp != robj) {
pgpAssert(*objp);
objp = &(*objp)->g.next;
}
*objp = robj->g.next;
if (OBJISKEY(robj))
ringGarbageHackKey(pool, &robj->k);
else if (OBJISSIG(robj))
ringGarbageHackSig(&robj->s);
ringFreeObject(pool, robj);
}
}
/* Find and allocate a new, unused mask bit. Search through all bits
* until we find one unused.
*/
PGPError
ringBitAlloc(RingPool *pool, PGPUInt32 *newbit)
{
PGPVirtMask mask;
#if VIRTMASK
PGPUInt32 maskbit;
PGPError err;
maskbit = MEMRINGBIT + 1;
if( IsPGPError( err = pgpVirtMaskInit (pool, &mask) ) )
return err;
for ( ; ; ) {
if( IsPGPError( err =
pgpVirtMaskSetBit (pool, &mask, maskbit) ) )
return err;
if (!pgpVirtMaskIsOverlapping (&mask, &pool->allocmask)) {
/* Occasionally reclaim unused bits */
if (maskbit % 32 == 0) {
ringGarbageCollect(pool);
}
*newbit = maskbit;
err = pgpVirtMaskCleanup (pool, &mask);
return err;
}
pgpVirtMaskClearBit (pool, &mask, maskbit);
++maskbit;
}
/* NOTREACHED */
#else
/* Allocate a new bit */
pgpVirtMaskInit (pool, &mask);
pgpVirtMaskCopy (pool, &pool->allocmask, &mask);
#if MULTIMASK
pgpVirtMaskNOT (pool, &mask, 32*MULTIMASK);
#else
pgpVirtMaskNOT (pool, &mask, 32);
#endif
if (pgpVirtMaskIsEmpty(&mask)) {
/* Wups, out of bits - try something before dying */
ringGarbageCollect(pool);
pgpVirtMaskCopy (pool, &pool->allocmask, &mask);
#if MULTIMASK
pgpVirtMaskNOT (pool, &mask, 32*MULTIMASK);
#else
pgpVirtMaskNOT (pool, &mask, 32);
#endif
if (pgpVirtMaskIsEmpty(&mask)) {
ringSimpleErr(pool, kPGPError_OutOfRings);
return kPGPError_OutOfRings;
}
}
*newbit = pgpVirtMaskLSBit(&mask);
return kPGPError_NoErr;
#endif
}
/*
* Allocate and deallocate useful structures.
* Note the interesting shenanigans used to allocate
* a structure the alignment of an enclosing union, ensuring
* that even on a maximally-perverse ANSI C implementation,
* it is safe to cast the returned structure pointer to a union
* pointer.
*/
union RingObject *
ringNewObject(RingPool *pool, int objtype)
{
union RingObject *robj;
/* How to initialize each object to empty */
static RingKey const nullkey = NULLRINGKEY;
static RingSec const nullsec = NULLRINGSEC;
static RingName const nullname = NULLRINGNAME;
static RingSig const nullsig = NULLRINGSIG;
static RingCRL const nullcrl = NULLRINGCRL;
static RingUnk const nullunk = NULLRINGUNK;
static void const *nullobjs[RINGTYPE_MAX] = {
&nullkey, &nullsec, &nullname, &nullsig, &nullcrl, &nullunk
};
size_t const sizes[RINGTYPE_MAX] = {
sizeof(RingKey), sizeof(RingSec),
sizeof(RingName), sizeof(RingSig),
sizeof(RingCRL), sizeof(RingUnk)
};
/* Object types are 1-based */
pgpAssert(objtype > 0);
pgpAssert(objtype <= RINGTYPE_MAX);
robj = pool->freeobjs[objtype-1];
if (robj) {
pool->freeobjs[objtype-1] = robj->g.next;
} else {
robj = (union RingObject *)
memPoolAlloc(&pool->structs, sizes[objtype-1],
alignof(union RingObject));
if (!robj) {
ringAllocErr(pool);
return NULL;
}
}
memcpy(robj, nullobjs[objtype-1], sizes[objtype-1]);
pgpAssert(ringObjectType(robj) == objtype);
return robj;
}
/*
* Free an object. This does not do any cleanup with any pointers in the
* object, except the regexp which belongs to sig objects.
*/
void
ringFreeObject(RingPool *pool, union RingObject *obj)
{
int type = ringObjectType(obj);
pgpAssert(type > 0);
pgpAssert(type <= RINGTYPE_MAX);
if (OBJISSIG(obj)) {
if (obj->s.regexp) {
pgpContextMemFree( pool->context, obj->s.regexp );
obj->s.regexp = NULL;
}
}
pgpVirtMaskCleanup (pool, &obj->g.mask);
obj->g.next = pool->freeobjs[type-1];
pool->freeobjs[type-1] = obj;
}
/*
* Remove an object from its parent and free it. This does not do
* anything with the object's FilePos list.
*/
void
ringRemObject(RingPool *pool, union RingObject *obj)
{
union RingObject **objp;
pgpAssert(!OBJISTOP(obj));
objp = &obj->g.up->g.down;
/* Unlink the object from its parent */
while (*objp != obj) {
pgpAssert(*objp);
objp = &(*objp)->g.next;
}
*objp = obj->g.next;
ringFreeObject(pool, obj);
}
/*
* Rebuild the pool's hash table from scratch,
* inserting all keys and subkeys.
*/
void
ringPoolHash(RingPool *pool)
{
union RingObject *key, *subkey;
int i;
for (i = 0; i < 256; i++)
pool->hashtable[i] = NULL;
for (key = pool->keys; key; key = key->g.next) {
pgpAssert(OBJISKEY(key));
RINGPOOLHASHKEY(pool, key);
for (subkey = key->g.down; subkey; subkey = subkey->g.next) {
if (OBJISKEY(subkey))
RINGPOOLHASHKEY(pool, subkey);
}
}
}
/*
* Find a key given a keyID.
*
* ViaCrypt added pkalgs 2 and 3 which are limited RSA, but doesn't
* completely distinguish beterrn them, so this doesn't either. Sigh.
*/
union RingObject *
ringPoolFindKey(RingPool const *pool, PGPByte pkalg, PGPByte const keyID[8])
{
RingKey *key;
if ((pkalg | 1) == 3)
pkalg = 1;
for (key = pool->hashtable[keyID[0]]; key; key = key->util) {
if (memcmp(keyID, key->keyID, 8) == 0) {
if (pkalg == key->pkalg)
break;
/* Cope with ViaCrypt's things */
if (pkalg == 1 && (key->pkalg | 1) == 3)
break;
}
}
return (union RingObject *)key;
}
/*
* Find a key given a "20n" fingerprint (SHA-1 hash over numeric data)
* Note that this does disk accesses and may change RingFile pointers.
*/
RingObject *
ringPoolFindKey20n(RingPool *pool, PGPByte const *fp20n)
{
RingObject *key;
RingSet *allset;
PGPByte hashbuf[20];
allset = ringSetCreateUniversal (pool);
for (key = pool->keys; key; key = key->g.next) {
/* Look for non-dummy key which matches fingerprint */
if (pgpIsRingSetMember( allset, key ) &&
key->k.fp20n == fp20n[0]) {
ringKeyFingerprint20n (allset, key, hashbuf);
pgpAssert (hashbuf[0] == key->k.fp20n);
if (memcmp (fp20n, hashbuf, sizeof(hashbuf)) == 0)
break;
}
}
ringSetDestroy (allset);
return (union RingObject *)key;
}
/*
* Ensure that each key's list of the signatures by it is
* valid. This also establishes the extra invariant (used in
* pgpRngMnt.c) that all signatures by one key on another object
* are adjacent on that key's sigsby list.
*/
void
ringPoolListSigsBy(RingPool *pool)
{
union RingObject *key, *n, *s;
/* Initialize sigsby lists to null */
for (key = pool->keys; key; key = key->g.next) {
pgpAssert(OBJISTOPKEY(key));
key->k.sigsby = NULL;
}
/* Install every sig on a sigsby list */
for (key = pool->keys; key; key = key->g.next) {
for (n = key->k.down; n; n = n->g.next) {
if (OBJISSIG(n)) {
n->s.nextby = (RingSig *) n->s.by->k.sigsby;
n->s.by->k.sigsby = n;
} else for (s = n->g.down; s; s = s->g.next) {
if (OBJISSIG(s)) {
s->s.nextby = (RingSig *) s->s.by->k.sigsby;
s->s.by->k.sigsby = s;
}
}
}
}
}
/*
* Return the mask of RingFiles that are "better" (higher priority
* for fetching) than *any* home of the specified object.
*/
PGPError
ringObjBetters(union RingObject const *obj, RingPool const *pool,
PGPVirtMask *omask)
{
PGPVirtMask better;
PGPVirtMask mask;
PGPInt32 bit;
pgpVirtMaskCleanup (pool, omask);
pgpVirtMaskInit (pool, &better);
pgpVirtMaskInit (pool, &mask);
pgpVirtMaskCopy (pool, &obj->g.mask, &mask);
pgpVirtMaskAND (pool, &pool->filemask, &mask);
pgpVirtMaskCopy (pool, &pool->filemask, &better);
pgpAssert(!pgpVirtMaskIsEmpty(&mask));
while (!pgpVirtMaskIsEmpty(&mask)) {
bit = pgpVirtMaskLSBit(&mask);
pgpVirtMaskAND (pool, &pool->files[bit]->higherpri, &better);
pgpVirtMaskClearBit(pool, &mask, bit);
}
pgpVirtMaskCleanup (pool, &mask);
*omask = better;
return kPGPError_NoErr;
}
/*
* Return TRUE if the specified subkey has a valid sig from the main key.
* Assumes subkey sigs are always tried, which should happen when they are
* created or added to the keyring. The only time this isn't true is when
* we are considering adding a key. We will give the sig the benefit of
* the doubt in that case as we aren't using it yet.
*/
int
ringSubkeyValid(RingSet const *set, union RingObject *subkey,
PGPBoolean unExpired)
{
union RingObject *sig;
union RingObject *key;
PGPUInt32 curtime;
PGPUInt32 exptime;
pgpAssert(OBJISSUBKEY(subkey));
pgpAssert(pgpIsRingSetMember(set, subkey));
key = subkey->g.up;
pgpAssert(OBJISTOPKEY(key));
if (subkey->k.trust & PGP_KEYTRUSTF_REVOKED)
return 0;
if (unExpired) {
/* Don't use key if has expired or creation time is > 24 hours
in future */
if (subkey->k.trust & PGP_KEYTRUSTF_EXPIRED)
return 0;
curtime = (PGPUInt32) PGPGetTime();
exptime = (PGPUInt32) ringKeyExpiration(set, subkey);
if ((exptime != 0 && curtime > exptime) ||
curtime < ringKeyCreation(set, subkey) - 24*60*60)
return 0;
}
/* Check legality of subkey */
for (sig = subkey->g.down; sig; sig = sig->g.next) {
if (OBJISSIG(sig) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -