📄 pgpkeydb.c
字号:
* Add object to this keydb
* Problem: what if object is a sig? We need to add parents too
* But if we are iterating and adding all objects, it is wasteful
* to re-add all parents.
* Unless we can check quickly if we have them.
* This is similar to logic in initial read.
* In fact it might be identical - read each object and its data,
* add in self-contained way to keydb.
* No, better to read each object's data into a buffer, add that.
* So the low level add function takes an object's data, and takes
* a parent object, and adds it. If parent is null then it puts it
* in as a top level key.
* Problem is this requires us to parse it twice as we are reading
* from keyring. Not really, just have to parse the type of the
* packet.
*/
/* Count how far we are from the top (0=top, 1=one layer down, etc.) */
parobj = obj;
count = 0;
while( !OBJISTOPKEY(parobj) )
{
++count;
parobj = parobj->up;
}
pgpAssert( count <= 2 );
/* Add object and its parents, starting from the top and working down */
newparobj = NULL;
for (i=count; i>=0; --i)
{
parobj = obj;
for (j=0; j<i; ++j)
parobj = parobj->up;
/* Check our local cache of parents */
if( (count-i) < 2 && kdb->oldobjs[count-i] == parobj )
{
newparobj = kdb->newobjs[count-i];
continue;
}
objdata = pgpFetchObject( parobj, &objdatalen );
/*
* This is the low level add function, also used during keyring
* read. It returns the object we added. Should be optimized to
* be fast for the case where we are adding an already existing
* object.
*/
newparobj = pgpAddObject(objdata, objdatalen, kdb, newparobj, FALSE,
&err);
if( IsPGPError( err ) || IsNull( newparobj ) )
goto error;
pgpCopyObjectTrust( parobj, newparobj );
/* Cache our results */
if( count-i < 2 )
{
kdb->oldobjs[count-i] = parobj;
kdb->newobjs[count-i] = newparobj;
}
}
pgpKeyDBChanged( kdb, FALSE );
if( IsntNull( pnewobj ) )
*pnewobj = newparobj;
error:
return err;
}
PGPError
pgpKeyDBAddObject (PGPKeyDBRef kdb, PGPKeyDBObj *obj, PGPKeyDBObjRef *pnewobj)
{
PGPError err = kPGPError_NoErr;
if( pgpFrontEndKeyDB( kdb ) )
{
PGPUInt32 *newobjs;
PGPSize newobjslen;
PGPUInt32 newobjid;
err = pgpKeyDBAddObject_back( PGPPeekKeyDBContext(kdb), kdb->id,
pgpKeyDBObjID(obj), &newobjs,
&newobjslen, &newobjid );
if( IsPGPError( err ) )
return err;
err = pgpAddFromKeyArray( kdb, NULL, newobjs, 1, FALSE );
PGPFreeData( newobjs );
pgpKeyDBChanged( kdb, FALSE );
if( IsntNull( pnewobj ) )
(void)PGPFindNode( kdb->idToObj, newobjid,
(PGPUserValue *)pnewobj );
return err;
}
return pgpKeyDBAddObject_internal( kdb, obj, pnewobj );
}
PGPError
pgpKeyDBRemoveObject_internal (PGPKeyDBRef kdb, PGPKeyDBObj *obj)
{
PGPError err;
(void) kdb;
pgpAssert( PGPPeekKeyDBObjKeyDB(obj) == kdb );
/* Don't allow deletion of last userid on key */
if( OBJISUSERID( obj ) )
{
PGPKeyDBObj * parent;
PGPKeyDBObj * child;
PGPUInt32 useridcount;
useridcount = 0;
parent = obj->up;
pgpAssert( OBJISTOPKEY( parent ) );
for( child=parent->down; IsntNull(child); child=child->next )
{
if( !pgpKeyDBObjIsReal( child ) )
continue;
if( OBJISUSERID( obj ) )
{
++useridcount;
}
}
if( useridcount < 2 )
return kPGPError_BadParams;
}
/* Don't allow deletion of last self-signature on a userid */
if( OBJISSIG( obj ) && OBJISUSERID( obj->up ) )
{
PGPKeyDBObj * parent;
PGPKeyDBObj * topkey;
PGPKeyDBObj * child;
PGPUInt32 selfsigcount;
selfsigcount = 0;
parent = obj->up;
topkey = parent->up;
pgpAssert( OBJISUSERID( parent ) );
pgpAssert( OBJISTOPKEY( topkey ) );
if( OBJISSIG( obj )
&& pgpSigMaker( obj ) == topkey )
{
for( child=parent->down; IsntNull(child); child=child->next )
{
if( !pgpKeyDBObjIsReal( child ) )
continue;
if( OBJISSIG( child )
&& pgpSigMaker( child ) == topkey
&& (pgpSigType( child ) & 0xf0) == PGP_SIGTYPE_KEY_GENERIC
&& !pgpSigRevoked( child ) )
{
++selfsigcount;
}
}
if( selfsigcount < 2 )
return kPGPError_DeletingSelfSig;
}
}
err = pgpMarkKeyDBObjectDeleted( obj );
pgpKeyDBChanged ( kdb, FALSE );
return err;
}
PGPError
pgpKeyDBRemoveObject (PGPKeyDBRef kdb, PGPKeyDBObj *obj)
{
PGPError err;
(void) kdb;
pgpAssert( PGPPeekKeyDBObjKeyDB(obj) == kdb );
if( !pgpKeyDBObjIsReal( obj ) )
return kPGPError_BadParams;
if( pgpFrontEndKeyDB( kdb ) )
{
err = pgpKeyDBRemoveObject_back( PGPPeekKeyDBContext(kdb), kdb->id,
pgpKeyDBObjID(obj) );
if( IsPGPError( err ) )
return err;
pgpMarkKeyDBObjectDeleted( obj );
pgpKeyDBChanged ( kdb, FALSE );
return err;
}
return pgpKeyDBRemoveObject_internal( kdb, obj );
}
/* True if a front end keydb */
PGPBoolean
pgpFrontEndKeyDB( PGPKeyDBRef kdb )
{
return kdb->id != 0;
}
/* Flush any necessary changes out to backing store if present */
PGPError
pgpKeyDBFlush_internal (PGPKeyDBRef kdb, PGPKeySetRef changedSet)
{
PGPError error;
if (!kdb->bmutable)
return kPGPError_ItemIsReadOnly;
if (!kdb->bdirty)
return kPGPError_NoErr;
/* Recheck sigs before writing out */
error = pgpCheckKeyRingSigs_internal( kdb->rootSet, NULL, FALSE, 0, 0,
changedSet);
if( IsPGPError( error ) )
return error;
error = pgpPropagateTrustInternal( kdb->rootSet, NULL, PGPGetTime(),
changedSet );
if( IsPGPError( error ) )
return error;
pgpAssert( IsntNull( kdb->pubFile ) );
error = sWriteKeyRings (kdb);
if (error)
return error;
kdb->bdirty = 0;
return kPGPError_NoErr;
}
static PGPError
pgpKeyDBFlushInternal (PGPKeyDBRef kdb)
{
PGPError err;
if( pgpFrontEndKeyDB( kdb ) ) {
PGPUInt32 *changelist;
PGPSize changelistsize;
if( IsPGPError( err = pgpKeyDBFlush_back( PGPPeekKeyDBContext(kdb),
kdb->id, &changelist, &changelistsize ) ) )
return err;
err = pgpKeyRefreshFromList( kdb, changelist, changelistsize );
kdb->bdirty = 0;
return err;
}
return pgpKeyDBFlush_internal( kdb, NULL );
}
PGPError
PGPFilterKeyDB( PGPKeyDBRef keyDB, PGPFilterRef filter,PGPKeySetRef *resultSet)
{
PGPValidateKeyDB( keyDB );
pgpEnterPGPErrorFunction();
return PGPFilterKeySet( keyDB->rootSet, filter, resultSet );
}
PGPBoolean
pgpKeyDBIsValid( PGPKeyDB const * keyDB)
{
return( IsntNull( keyDB ) && keyDB->fixedMagic == kPGPKeyDBMagic );
}
#if PGP_DEBUG /* [ */
PGPBoolean
pgpaInternalPGPKeyDBValid(
pgpaCallPrefixDef,
PGPKeyDB const * keyDB,
char const * varName)
{
pgpaAddrValid(keyDB, PGPKeyDB);
pgpaFailIf((keyDB->refCount <= 0) && !keyDB->bcached, (pgpaFmtPrefix, "refCount <= 0"));
pgpaFmtMsg((pgpaFmtPrefix,
"pgpaPGPKeyDBValid failed on %s (%p)", varName, keyDB));
return pgpaFailed;
}
#endif /* ] PGP_DEBUG */
PGPError
PGPIncKeyDBRefCount( PGPKeyDBRef kdb )
{
PGPValidateKeyDB( kdb );
pgpEnterPGPErrorFunction();
++kdb->refCount;
return kPGPError_NoErr;
}
void
pgpKeyDBDestroy_internal (PGPKeyDBRef kdb)
{
PGPKeySetRef set;
PGPKeyDBRef kdbprev;
PGPNotification * nt;
pgpAssertAddrValid( kdb, PGPKeyDB );
/* First flush out any changes, even if not last copy of keydb */
if( kdb->bmutable )
{
/* Mac does not use front-end/back-end distinction the same way */
#if !PGP_MACINTOSH
if( !pgpFrontEndKeyDB( kdb ) )
#endif
pgpKeyDBFlushInternal( kdb );
}
if( kdb->refCount <= 1 &&
! ( kdb->bcached && (PGPGetTime() < kdb->cacheclose) ) )
{
PGPUInt32 id = kdb->id;
PGPContextRef context = kdb->context;
if( kdb->pubFile )
pgpFileClose( kdb->pubFile );
if( kdb->pubFileRef )
PFLFreeFileSpec( kdb->pubFileRef );
if( kdb->privFile )
pgpFileClose( kdb->privFile );
if( kdb->privFileRef )
PFLFreeFileSpec( kdb->privFileRef );
for( set=kdb->firstSetInDB; IsntNull(set); )
{
pgpFreeKeySet( set, TRUE );
/* Freeing keyset fixes up list so we can just stay at beginning */
set = kdb->firstSetInDB;
}
memPoolEmpty( &kdb->objPool );
memPoolEmpty( &kdb->structPool );
memPoolEmpty( &kdb->pathpool );
memPoolEmpty( &kdb->regexps );
PGPDisposeBinaryTree( kdb->idToObj );
/* Unlink kdb from context list */
kdbprev = pgpContextGetFirstKeyDB( kdb->context );
if( kdbprev == kdb )
{
pgpContextSetFirstKeyDB( kdb->context, kdb->next );
} else {
while( kdbprev->next != kdb )
kdbprev = kdbprev->next;
kdbprev->next = kdb->next;
}
nt = kdb->notifies;
while( IsntNull( nt ) )
{
PGPNotification *ntnext = nt->next;
PGPFreeData( nt );
nt = ntnext;
}
PGPFreeData( kdb );
if( id != 0 )
{
pgpFreeKeyDB_back( context, id );
}
} else {
if( !pgpFrontEndKeyDB( kdb ) )
sRemoveNotification( kdb );
--kdb->refCount;
}
return;
}
static void
pgpKeyDBDestroyInternal (PGPKeyDBRef kdb)
{
pgpKeyDBDestroy_internal( kdb );
}
PGPError
PGPFreeKeyDB(PGPKeyDBRef kdb)
{
PGPValidateKeyDB( kdb );
pgpEnterPGPErrorFunction();
pgpKeyDBDestroyInternal( kdb );
return kPGPError_NoErr;
}
/* Call periodically to check for expiration of cached keydbs */
/* This is called from a different thread than the main one */
/* The caller must arrange for non-contention with the main thread */
void
pgpExpireKeyDBCache( PGPContextRef context )
{
PGPTime curtime;
PGPKeyDBRef kdb;
PGPKeyDBRef kdbnext;
curtime = PGPGetTime();
kdb = pgpContextGetFirstKeyDB( context );
while( IsntNull( kdb ) )
{
kdbnext = pgpKeyDBNextKeyDB( kdb );
if( kdb->refCount < 1 &&
! ( kdb->bcached && (PGPGetTime() < kdb->cacheclose) ) )
{
pgpKeyDBDestroyInternal( kdb );
}
kdb = kdbnext;
}
}
/* Call to find out if any keydbs are currently cached */
/* The caller must arrange for non-contention with the main thread */
PGPBoolean
pgpIsKeyDBCached( PGPContextRef context )
{
PGPKeyDBRef kdb;
PGPKeyDBRef kdbnext;
kdb = pgpContextGetFirstKeyDB( context );
while( IsntNull( kdb ) )
{
kdbnext = pgpKeyDBNextKeyDB( kdb );
if( kdb->bcached )
return TRUE;
kdb = kdbnext;
}
return FALSE;
}
/* Call to clear all cached keydbs */
PGPError
pgpPurgeKeyDBCache_internal( PGPContextRef context )
{
PGPKeyDBRef kdb;
PGPKeyDBRef kdbnext;
kdb = pgpContextGetFirstKeyDB( context );
while( IsntNull( kdb ) )
{
kdbnext = pgpKeyDBNextKeyDB( kdb );
if( kdb->refCount < 1 )
{
kdb->bcached = FALSE;
kdb->cacheclose = (PGPTime)0;
kdb->refCount = 1; /* Suppress warnings on invalid keydb */
pgpKeyDBDestroyInternal( kdb );
}
kdb = kdbnext;
}
return kPGPError_NoErr;
}
/* Call to clear all cached keydbs */
PGPError
PGPPurgeKeyDBCache( PGPContextRef context )
{
pgpEnterPGPErrorFunction();
PGPValidateContext( context );
if (pgpRPCEnabled())
return pgpPurgeKeyDBCache_back(context);
return pgpPurgeKeyDBCache_internal(context);
}
PGPError
pgpCacheKeyDB_internal( PGPKeyDBRef keydb, PGPUInt32 timeoutSeconds )
{
PGPValidateKeyDB( keydb );
keydb->bcached = TRUE;
keydb->cacheclose = PGPGetTime() + timeoutSeconds;
return kPGPError_NoErr;
}
/*
* Call to set a keydb as cached so we don't close it when the last
* user stops using it.
*/
PGPError
PGPCacheKeyDB( PGPKeyDBRef keydb, PGPUInt32 timeoutSeconds )
{
PGPValidateKeyDB( keydb );
pgpEnterPGPErrorFunction();
if (pgpRPCEnabled())
return pgpCacheKeyDB_back( keydb->context, keydb->id, timeoutSeconds );
return pgpCacheKeyDB_internal(keydb, timeoutSeconds);
}
static void
pgpKeyDBInit( PGPContextRef context, PGPKeyDB *kdb )
{
pgpClearMemory( kdb, sizeof(*kdb) );
kdb->fixedMagic = kPGPKeyDBMagic;
kdb->context = context;
kdb->refCount = 1;
memPoolInit( context, &kdb->objPool);
memPoolInit( context, &kdb->structPool );
memPoolInit( context, &kdb->pathpool );
memPoolInit( context, &kdb->regexps );
PGPNewBinaryTree( PGPPeekContextMemoryMgr(context), &kdb->idToObj );
kdb->rootSet = pgpRootSet( kdb );
/* Link kdb into context list */
kdb->next = pgpContextGetFirstKeyDB( context );
pgpContextSetFirstKeyDB( context, kdb );
/* Register for notifications if we are backend */
sAddNotification( kdb );
}
PGPKeySet *
pgpKeyDBPeekRootSet( PGPKeyDB *kdb )
{
pgpa(pgpaPGPKeyDBValid(kdb));
return kdb->rootSet;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -