📄 pgprngread.c
字号:
pgpAssert (OBJISBOT(obj) || IsNull(obj->g.down));
ringRemObject (pool, obj);
}
}
}
/*** Closing a Ringfile ***/
/*
* Set the destruction function for a RingFile.
*/
void
ringFileSetDestructor(RingFile *file,
void (*destructor)(RingFile *, PGPFile *, void *),
void *arg)
{
file->destructor = destructor;
file->arg = arg;
}
/*
* Helper function for ringFileDoClose.
*
* Delete the given file's FilePos entries from the objects in
* the given list, and delete the objects if they are no longer
* needed (mask has gone to 0). Recurse as necessary.
*
* Note that this is not used on the main keys list, because
* there we need to preserve dummy keys which this does not
* understand.
*
* This also removes any cached names from objects.
*/
static void
ringFileCloseList(union RingObject **objp, RingFile *file,
PGPVirtMask *allocmask)
{
union RingObject *obj;
PGPVirtMask mask;
RingPool *pool = file->set.pool;
pgpVirtMaskInit (pool, &mask);
while ((obj = *objp) != NULL) {
/*
* Delete low-level objects with mask==0 as well as objects on
* the ringfile which is going away. We create those objects, e.g.
* when importing a non-exportable sig, and then they prevent the
* parent objects from being deleted properly, later leading to
* an assertion in keysdiffer.
*/
if (pgpIsRingSetMember(&file->set, obj) ||
pgpVirtMaskIsEmpty (&obj->g.mask)) {
if (!OBJISBOT(obj))
ringFileCloseList(&obj->g.down, file, allocmask);
ringRemFilePos(obj, file);
/*
* Delete objects which have no homes other than MEMRING.
* But:
* Do not delete objects which have children, because they may
* have a child obj in the MEMRING which didn't get deleted
* because it was not in this RingFile.
* Do not delete objects whose only home is in the MEMRING
* but which are currently in use in active RingSets. They
* may be newly created objects which will soon be given homes
* in some other RingFile.
*/
pgpVirtMaskCopy (pool, &pool->filemask, &mask);
pgpVirtMaskANDNOT (pool, &pool->memringmask, &mask);
if (!pgpVirtMaskIsOverlapping (&mask, &obj->g.mask)
&& (OBJISBOT(obj) || !obj->g.down)
&& !pgpVirtMaskIsOverlapping (allocmask, &obj->g.mask)) {
*objp = obj->g.next;
ringFreeObject(file->set.pool, obj);
} else {
/*
* If a name is cached from the file which is closing,
* purge it since the file's strings table holds the cached
* names and it's going away.
*/
if (OBJISNAME(obj))
ringPurgeCachedName(file->set.pool, &obj->n,
&file->set.mask);
objp = &obj->g.next;
}
} else
objp = &obj->g.next;
}
pgpVirtMaskCleanup (pool, &mask);
}
/*
* Close the given Ringfile. Returns an error if it can't due to
* conflicts, in which case the file is NOT closed.
*
* This performs four passes over the pool.
* 1. The first does the bulk of the deletion, removing the
* FilePos from the objects and deleting all things
* at levels greater than 1.
* 2. The second rebuilds the sigs-by lists which were broken by
* deleting objects in the middle of them.
* 3. The third finds all keys that are not referenced and do not
* make any signatures, and deletes those keys.
* 4. The fourth rebuilds the hash index of the remaining keys.
*
* Note that the second and third passes delete any allocated-but-not
* linked keys, which are left by ringFileOpen if it runs out of memory
* in mid-operation.
*/
static void
ringFileDoClose(RingFile *file)
{
union RingObject *obj, **objp;
RingPool *pool = file->set.pool;
int i;
PGPVirtMask allocmask;
PGPVirtMask mask;
PGPUInt32 filebit;
pgpVirtMaskInit (pool, &allocmask);
pgpVirtMaskInit (pool, &mask);
ringAllocMask (pool, &file->set, &allocmask);
/* Free some memory right away */
ringFilePurgeTrouble(file);
/* 1: Remove everything in the keyring, but don't delete the keys */
for (obj = pool->keys; obj; obj = obj->g.next) {
if (pgpIsRingSetMember (&file->set, obj)) {
if (!OBJISBOT(obj))
ringFileCloseList(&obj->g.down, file, &allocmask);
ringRemFilePos(obj, file);
}
}
/* 2: Recreate the shattered sigs-by lists */
ringPoolListSigsBy(pool);
/* 3: Now purge the unneeded keys */
objp = &pool->keys;
while ((obj = *objp) != NULL) {
pgpAssert(OBJISTOPKEY(obj));
pgpVirtMaskCopy (pool, &obj->g.mask, &mask);
pgpVirtMaskANDNOT (pool, &pool->memringmask, &mask);
if (pgpVirtMaskIsOverlapping (&mask, &pool->filemask) || obj->g.down) {
objp = &obj->g.next;
} else if (obj->k.sigsby) {
/* Retain key as a dummy key */
pgpAssert(!pgpVirtMaskIsOverlapping (&mask, &allocmask));
pgpAssert(!obj->g.down);
pgpVirtMaskCleanup (pool, &obj->g.mask);
objp = &obj->g.next;
} else {
/* Delete the key */
pgpAssert(!pgpVirtMaskIsOverlapping (&mask, &allocmask));
pgpAssert(!obj->g.down);
*objp = obj->g.next;
ringFreeObject(pool, obj);
}
}
/* 4: Re-initialize the hash chains */
ringPoolHash(pool);
/* Clean up the file's memory pools */
memPoolEmpty(&file->strings);
file->freepos = NULL;
memPoolEmpty(&file->fpos);
pgpAssert(!file->set.next);
/*
* If there's nothing in the structs MemPool that's
* allocated, purge all the memory.
*/
if (!pool->keys && !pool->sets) {
for (i = 0; i < RINGTYPE_MAX; i++)
pool->freeobjs[i] = NULL;
pool->freesets = NULL;
pool->freeiter = NULL;
memPoolEmpty(&pool->structs);
}
/* Cal the file's destructor function, if any */
if (file->destructor) {
file->destructor(file, file->f, file->arg);
file->destructor = NULL;
}
/* Final deallocation of the file */
file->flags = 0;
pgpVirtMaskANDNOT (pool, &file->set.mask, &pool->filemask);
filebit = pgpVirtMaskLSBit (&file->set.mask);
pgpVirtMaskCleanup (pool, &file->set.mask);
pgpVirtMaskCleanup (pool, &file->higherpri);
pgpAssert (pool->files[filebit] == file);
pgpContextMemFree (pool->context, file);
pool->files[filebit] = NULL;
pgpVirtMaskCleanup (pool, &mask);
pgpVirtMaskCleanup (pool, &allocmask);
}
/*
* Check to see if an object anywhere on the list (including children,
* recursively) is included in "allocmask" but not in "filemask."
* Such an object is orphaned, an undesirable state of affairs.
* We have to check the entire keyring, recursively, because a
* given key or name might be duplicated in another keyring, but
* a signature lower down might not be.
*/
static int
ringFileCheckList(union RingObject const *obj, PGPVirtMask *filemask,
PGPVirtMask *allocmask)
{
while (obj) {
if (pgpVirtMaskIsOverlapping (&obj->g.mask, allocmask)) {
/* Would closing orphan this object? */
if (!pgpVirtMaskIsOverlapping (&obj->g.mask, filemask))
return 1;
/* Would closing orphan its children? */
if (!OBJISBOT(obj) && ringFileCheckList(obj->g.down,
filemask,
allocmask))
return 1;
}
obj = obj->g.next;
}
return 0;
}
/* Is it safe to close the given file? */
int
ringFileCheckClose(RingFile const *file)
{
RingPool const *pool = file->set.pool;
int rtrn;
PGPVirtMask allocmask;
PGPVirtMask mask;
if (!file)
return 0;
pgpVirtMaskInit (pool, &allocmask);
pgpVirtMaskInit (pool, &mask);
ringAllocMask (pool, &file->set, &allocmask);
pgpVirtMaskCopy (pool, &pool->filemask, &mask);
pgpVirtMaskANDNOT (pool, &file->set.mask, &mask);
rtrn = ringFileCheckList(pool->keys, &mask, &allocmask);
pgpVirtMaskCleanup (pool, &allocmask);
pgpVirtMaskCleanup (pool, &mask);
return rtrn;
}
/*
* Close the given Ringfile. Returns an error if it can't due to
* conflicts, in which case the file is NOT closed.
*/
PGPError
ringFileClose(RingFile *file)
{
if (!file)
return kPGPError_NoErr; /* close(NULL) is defines as harmless */
if (ringFileCheckClose(file))
return kPGPError_LazyProgrammer;
/* Okay, nothing can fail now */
ringFileDoClose(file);
return kPGPError_NoErr;
}
/*** Routines for fetching things from the keyring ***/
/* Make sure the pool's packet buffer is large enough */
char *
ringReserve(RingPool *pool, size_t len)
{
PGPError err = kPGPError_NoErr;
if (pool->pktbufalloc >= len)
return pool->pktbuf;
if( IsNull( pool->pktbuf ) ) {
pool->pktbuf = (char *)
pgpContextMemAlloc( pool->context, len, 0 );
if( IsNull( pool->pktbuf ) )
err = kPGPError_OutOfMemory;
} else {
void *vpktbuf = pool->pktbuf;
err = pgpContextMemRealloc( pool->context, &vpktbuf, len,
0 );
pool->pktbuf = (char *)vpktbuf;
}
if ( IsPGPError( err ) )
{
ringAllocErr(pool);
return NULL;
}
pool->pktbufalloc = len;
return pool->pktbuf;
}
/*
* File priorities are handled by a "higherpri" mask with each file,
* which is a mask of other files of higher priority than that file.
* If obj->g.mask & pool->filmask && file->higherpri is 0,
* this is the highest-priority file.
*/
/* Set file to the highest priority, except for the memory file */
void
ringFileHighPri(RingFile *file)
{
RingPool *pool = file->set.pool;
unsigned i;
/* Add this file to everything else's higher priority mask */
for (i = 0; i < pool->nfiles; i++)
if (IsntNull(pool->files[i]))
pgpVirtMaskOR (pool, &file->set.mask, &pool->files[i]->higherpri);
/* The only thing higher priority than this file is MEMRING */
pgpVirtMaskCopy (pool, &pool->memringmask, &file->higherpri);
}
/* Set file to the lowest priority */
void
ringFileLowPri(RingFile *file)
{
RingPool *pool = file->set.pool;
unsigned i;
/* Remove this file from everything else's higher priority mask */
for (i = 0; i < pool->nfiles; i++) {
if (IsntNull(pool->files[i])) {
pgpVirtMaskANDNOT (pool, &file->set.mask,
&pool->files[i]->higherpri);
if (pool->files[i] != file)
pgpVirtMaskSetBit (pool, &file->higherpri, i);
}
}
}
/* The mask of sets that this key has *any* secret components in */
static PGPError
ringKeySecMask(RingPool *pool, RingObject const *obj, PGPVirtMask *omask)
{
pgpAssert(OBJISKEY(obj));
pgpVirtMaskCleanup (pool, omask);
for (obj = obj->g.down; obj; obj = obj->g.next)
if (OBJISSEC(obj)) {
pgpVirtMaskOR (pool, &obj->g.mask, omask);
}
return kPGPError_NoErr;
}
/*
* Given an object, find the best RingFile to fetch it from,
* for fetching purposes. Bits set in "avoidmask" are
* NOT valid for fetching, if avoidmask is nonnull.
*/
static RingFile *
ringBestFile(RingPool *pool, union RingObject const *obj,
PGPVirtMask *avoidmask)
{
PGPVirtMask mask, tmpmask;
RingFile *file;
int bit;
pgpVirtMaskInit (pool, &mask);
pgpVirtMaskInit (pool, &tmpmask);
pgpVirtMaskCopy (pool, &obj->g.mask, &mask);
pgpVirtMaskAND (pool, &pool->filemask, &mask);
pgpVirtMaskCopy (pool, &mask, &tmpmask);
if (IsntNull(avoidmask))
pgpVirtMaskANDNOT (pool, avoidmask, &tmpmask);
if (pgpVirtMaskIsEmpty (&tmpmask)) {
pgpVirtMaskCleanup (pool, &mask);
pgpVirtMaskCleanup (pool, &tmpmask);
return NULL;
}
/* find highest-priority fetchable file */
for (;;) {
/* Is least-significant bit set in mask fetchable? */
bit = pgpVirtMaskLSBit (&mask);
pgpVirtMaskCleanup (pool, &tmpmask);
pgpVirtMaskSetBit (pool, &tmpmask, bit);
if (IsNull(avoidmask) ||
!pgpVirtMaskIsOverlapping (&tmpmask, avoidmask)) {
file = pool->files[bit];
/* Is it highest priority? */
pgpVirtMaskCopy (pool, &mask, &tmpmask);
if (IsntNull(avoidmask))
pgpVirtMaskANDNOT (pool, avoidmask, &tmpmask);
if (!pgpVirtMaskIsOverlapping (&tmpmask, &file->higherpri))
break;
pgpAssert(file->f);
}
pgpVirtMaskClearBit (pool, &mask, bit);
pgpAssert(!pgpVirtMaskIsEmpty(&mask));
}
pgpVirtMaskCleanup (pool, &mask);
pgpVirtMaskCleanup (pool, &tmpmask);
return file;
}
/* Macro wrapper to inline the important part */
#define ringReserve(pool, len) \
((pool)->pktbufalloc < (len) ? ringReserve(pool, len) : (pool)->pktbuf)
/*
* This is the routine which fetches a packet from a keyring file.
* It tries the highest-priority file that the object is in which is also
* listed in "avoidmask." If the memory keyring is one of those, it has
* absolute priority. (It is also not verified; it is assumed correct.)
* Otherwise, the object is fetched from the highest-priority open file.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -