📄 pgpkeydb.c
字号:
/*____________________________________________________________________________
Copyright (C) 2002 PGP Corporation
All rights reserved.
Manage PGPKeyDBs
$Id: pgpKeyDB.c,v 1.95 2002/08/06 20:11:00 dallen Exp $
____________________________________________________________________________*/
#include <stdio.h>
#include <string.h>
#include "pgpConfig.h"
#include "pgpMemoryMgr.h"
#include "pgpOptionListPriv.h"
#include "pgpPktByte.h"
#include "pgpSigSpec.h"
#include "pgpP11Key.h"
#if HAVE_FCNTL_H
#include <fcntl.h> /* For O_CREAT, O_EXCL */
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifndef W_OK
#define W_OK 2
#endif
#include "pgpKeyPriv.h"
#include "pgpFileRef.h"
#include "pgpFileSpec.h"
#include "pgpFileUtilities.h"
#include "pgpStrings.h"
#include "pgpFileNames.h"
#include "pgpDebug.h"
#include "pgpFile.h"
#include "pgpContext.h"
/* State variable for whether we need to query the backend */
static PGPInt32 sBackendUpdatesNeeded;
struct PGPNotification
{
struct PGPNotification * next; /* Chaining pointer */
PGPConnectRef id; /* Client ID */
PGPKeySetRef newSet; /* Set of new keys */
PGPKeySetRef changeSet; /* Set of changed keys */
};
typedef struct PGPNotification PGPNotification;
static void sRemoveNotification( PGPKeyDB *db );
static void sAddNotification( PGPKeyDB *db );
/***************************** File IO ****************************/
static PGPError
sOpenFile ( PFLFileSpecRef fileRef,
PGPFileType fileType, PGPFlags openFlags, FILE **stdFile )
{
PGPError err;
PGPFileOpenFlags flags = kPGPFileOpenReadWritePerm | kPGPFileOpenLockFile;
#if PGP_UNIX_HPUX || PGP_UNIX_AIX
/*
* This is needed since the sdk service has not been ported to
* AIX or HP-UX This hack allows E-Biz to open the keyring files
* multiple times in read-only mode.
*/
if(!(openFlags & kPGPOpenKeyDBFileOptions_Mutable))
flags = kPGPFileOpenReadPerm | kPGPFileOpenLockFile;
#endif /* PGP_UNIX_HPUX || PGP_UNIX_AIX */
err = pgpFileRefStdIOOpen( fileRef, flags, fileType, stdFile );
if ( IsPGPError( err ) )
{
if ( err == kPGPError_FileNotFound &&
( openFlags & kPGPOpenKeyDBFileOptions_Create ) )
{
err = pgpCreateFile( fileRef, fileType );
if ( IsPGPError( err ) )
goto cleanup;
err = pgpFileRefStdIOOpen( fileRef, flags, fileType, stdFile );
}
/*
* This is for the case when user wants to open a file readonly
* and the file permissions are set for readonly.
*/
else if ( err == kPGPError_FilePermissions
&& !(openFlags & kPGPOpenKeyDBFileOptions_Mutable)
&& ((flags & kPGPFileOpenReadWritePerm) ==
kPGPFileOpenReadWritePerm ) )
{
flags = kPGPFileOpenReadPerm | kPGPFileOpenLockFile;
err = pgpFileRefStdIOOpen( fileRef, flags, fileType, stdFile );
}
if ( IsPGPError( err ) )
goto cleanup;
}
cleanup:
return err;
}
static PGPError
sOpenKeyRings ( PGPKeyDB *kdb )
{
PGPError err;
if( IsntNull( kdb->privFileRef ) )
{
err = sOpenFile( kdb->privFileRef, kPGPFileTypePrivRing,
kdb->openFlags, &kdb->privStdFile );
if( IsPGPError( err ) )
goto error;
}
err = sOpenFile( kdb->pubFileRef, kPGPFileTypePubRing, kdb->openFlags,
&kdb->pubStdFile );
if( IsPGPError( err ) )
goto error;
if( IsntNull( kdb->privFileRef ) )
{
kdb->privFile = pgpFileReadOpen ( kdb->context, kdb->privStdFile,
NULL, NULL );
if ( IsNull( kdb->privFile ) )
{
err = kPGPError_OutOfMemory;
goto error;
}
}
kdb->pubFile = pgpFileReadOpen ( kdb->context, kdb->pubStdFile,
NULL, NULL );
if ( IsNull( kdb->pubFile ) )
{
err = kPGPError_OutOfMemory;
goto error;
}
if( IsntNull( kdb->privFileRef ) )
{
err = pgpReadKeyFile( kdb, kdb->privFile, TRUE );
if( IsPGPError( err ) )
goto error;
}
err = pgpReadKeyFile( kdb, kdb->pubFile, TRUE );
if( IsPGPError( err ) )
goto error;
/* Check for key being on a hardware token */
pgpSyncTokenToKeyDB( kdb->context, kdb, FALSE );
/* Propagate trust from introducer and meta-introducer sigs */
pgpPropagateSignedKeyTrust( kdb );
if( kdb->openFlags & kPGPOpenKeyDBFileOptions_Mutable )
kdb->bmutable = TRUE;
error:
if( IsPGPError( err ) )
{
/* Clean up on error */
if( IsntNull( kdb->pubFile ) )
pgpFileClose( kdb->pubFile );
else if( IsntNull( kdb->pubStdFile ) )
pgpStdIOClose( kdb->pubStdFile );
if( IsntNull( kdb->privFile ) )
pgpFileClose( kdb->privFile );
else if( IsntNull( kdb->privStdFile ) )
pgpStdIOClose( kdb->privStdFile );
kdb->pubFile = kdb->privFile = NULL;
kdb->pubStdFile = kdb->privStdFile = NULL;
}
return err;
}
static PGPError
sWriteObjTrust( PGPKeyDBObj const *obj, PGPFile *outFile1,
PGPFile *outFile2 )
{
PGPByte pkt[5];
PGPSize pktlen;
PGPKeyInfo * kinfo;
PGPUserIDInfo * uinfo;
PGPSigInfo * sinfo;
PGPCRLInfo * cinfo;
pkt[0] = PKTBYTE_BUILD(PKTBYTE_TRUST, 0);
pktlen = 1;
switch (pgpObjectType(obj)) {
case RINGTYPE_KEY:
case RINGTYPE_SUBKEY:
kinfo = pgpKeyToKeyInfo( obj );
pkt[2] = kinfo->trust;
break;
case RINGTYPE_USERID:
/*
* Names have 3 bytes of trust. The first byte
* is a 2.x-compatible trust (validity) byte. The second is
* a validity value (how sure are we that this name
* is correct - computed), and the third is a confidence
* in the named individual as an introducer.
*/
uinfo = pgpUserIDToUserIDInfo( obj );
pkt[2] = uinfo->oldvalidity;
pkt[3] = uinfo->validity;
pkt[4] = uinfo->confidence;
pktlen = 3;
break;
case RINGTYPE_SIG:
/*
* 2.x compatibility kludge: Don't write trust
* on good compromise certificates. PGP 2.x
* maintenance dies (assert fail) if it finds
* trust packets on key sigs.
*/
sinfo = pgpSigToSigInfo( obj );
pkt[2] = sinfo->trust;
if (OBJISKEY(obj->up) && obj->up == sinfo->by
&& sinfo->type == PGP_SIGTYPE_KEY_REVOKE)
return kPGPError_NoErr;
break;
case RINGTYPE_CRL:
cinfo = pgpCRLToCRLInfo( obj );
pkt[2] = cinfo->trust;
break;
default:
pgpAssert(0);
}
pkt[1] = pktlen;
pktlen += 2;
if( IsntNull( outFile1 ) )
{
if (pgpFileWrite(pkt, pktlen, outFile1) != pktlen)
return kPGPError_WriteFailed;
}
if( IsntNull( outFile2 ) )
{
if (pgpFileWrite(pkt, pktlen, outFile2) != pktlen)
return kPGPError_WriteFailed;
}
return kPGPError_NoErr;
}
/*
* Write out specified objects. Secret objs and children go to both files,
* with the keys in public form.
*/
static PGPError
sWriteObj( PGPKeyDBObj *obj, PGPBoolean secflag, PGPFile *privFile,
PGPFile *pubFile )
{
PGPByte const * data;
PGPSize datalen;
PGPBoolean mustfree = FALSE;
PGPError err = kPGPError_NoErr;
data = pgpFetchObject( obj, &datalen );
if( secflag )
{
if( IsntNull( privFile ) )
{
if( pgpFileWrite( data, datalen, privFile ) != datalen )
{
err = kPGPError_WriteFailed;
}
}
}
if( IsntPGPError( err ) )
{
if( OBJISKEY( obj ) && pgpKeyIsSec( obj ) )
{
data = pgpKeyDBObjToPubData( obj, &datalen );
mustfree = TRUE;
}
if( pgpFileWrite( data, datalen, pubFile ) != datalen )
{
err = kPGPError_WriteFailed;
}
}
if( IsntPGPError( err ) )
err = sWriteObjTrust( obj, pubFile, (secflag?privFile:NULL) );
if( mustfree )
PGPFreeData( (PGPByte *)data );
return err;
}
/* Write out new keyring files, overwriting old data */
static PGPError
sWriteKeyRings( PGPKeyDB *kdb )
{
PGPError err;
PGPKeyDBObj * key;
PGPKeyDBObj * child;
PGPKeyDBObj * gchild;
PGPBoolean secflag;
/* Close the main files, releasing our lock */
if( IsntNull( kdb->privFileRef ) )
{
err = (kdb->privFile != NULL) ?
pgpFileClose( kdb->privFile ) : kPGPError_NoErr;
if ( IsPGPError( err ) )
goto cleanup;
kdb->privFile = NULL;
kdb->privStdFile = NULL;
}
err = (kdb->pubFile != NULL) ? pgpFileClose( kdb->pubFile ) : kPGPError_NoErr;
if ( IsPGPError( err ) )
goto cleanup;
kdb->pubFile = NULL;
kdb->pubStdFile = NULL;
/* Re-open keyring files in write mode */
if( IsntNull( kdb->privFileRef ) )
{
err = pgpFileRefStdIOOpen( kdb->privFileRef,
kPGPFileOpenStdWriteFlags
| kPGPFileOpenLockFile,
kPGPFileTypePrivRing,
&kdb->privStdFile );
if ( IsPGPError( err ) )
goto cleanup;
}
err = pgpFileRefStdIOOpen( kdb->pubFileRef,
kPGPFileOpenStdWriteFlags
| kPGPFileOpenLockFile,
kPGPFileTypePubRing,
&kdb->pubStdFile );
if ( IsPGPError( err ) )
goto cleanup;
/* Create PGPFile objects for the keyring files */
if( IsntNull( kdb->privFileRef ) )
{
kdb->privFile = pgpFileWriteOpen( kdb->context, kdb->privStdFile,
NULL );
if ( IsNull( kdb->privFile ) )
{
pgpStdIOClose( kdb->privStdFile );
err = kPGPError_OutOfMemory; /* XXX: Return better error */
goto cleanup;
}
}
kdb->pubFile = pgpFileWriteOpen( kdb->context, kdb->pubStdFile, NULL );
if ( IsNull( kdb->pubFile ) )
{
pgpStdIOClose( kdb->pubStdFile );
err = kPGPError_OutOfMemory; /* XXX: Return better error */
goto cleanup;
}
/* Copy the data to the keyring files */
for (key = kdb->firstKeyInDB; IsntNull(key); key = key->next)
{
if( !pgpKeyDBObjIsReal( key ) )
continue;
secflag = pgpKeyIsSec( key );
err = sWriteObj( key, secflag, kdb->privFile, kdb->pubFile );
if( IsPGPError( err ) )
goto cleanup;
for (child = key->down; IsntNull(child); child = child->next)
{
if( !pgpKeyDBObjIsReal( child ) )
continue;
if( OBJISCRL(child) && !pgpCRLIsCurrent( child, 0) )
continue;
if( OBJISSIG(child) && pgpSigIsSuperceded( child ) )
continue;
err = sWriteObj( child, secflag, kdb->privFile, kdb->pubFile );
if( IsPGPError( err ) )
goto cleanup;
for (gchild = child->down; IsntNull(gchild); gchild = gchild->next)
{
if( !pgpKeyDBObjIsReal( gchild ) )
continue;
if( OBJISCRL(gchild) && !pgpCRLIsCurrent( gchild, 0) )
continue;
if( OBJISSIG(gchild) && pgpSigIsSuperceded( gchild ) )
continue;
err = sWriteObj( gchild, secflag, kdb->privFile, kdb->pubFile);
if( IsPGPError( err ) )
goto cleanup;
}
}
}
/* Make sure the data is written to disk */
if( IsntNull( kdb->privFileRef ) )
{
err = pgpFileClose( kdb->privFile );
if ( IsPGPError( err ) )
goto cleanup;
kdb->privFile = NULL;
kdb->privStdFile = NULL;
}
err = pgpFileClose( kdb->pubFile );
if ( IsPGPError( err ) )
goto cleanup;
kdb->pubFile = NULL;
kdb->pubStdFile = NULL;
/* Reopen & relock the main keyring files to ensure exclusive access */
if( IsntNull( kdb->privFileRef ) )
{
err = pgpFileRefStdIOOpen( kdb->privFileRef,
kPGPFileOpenReadWritePerm |
kPGPFileOpenLockFile,
kPGPFileTypePrivRing,
&kdb->privStdFile );
if ( IsPGPError( err ) )
goto cleanup;
kdb->privFile = pgpFileReadOpen ( kdb->context, kdb->privStdFile,
NULL, NULL );
if ( IsNull( kdb->privFile ) )
{
err = kPGPError_OutOfMemory;
goto cleanup;
}
}
err = pgpFileRefStdIOOpen( kdb->pubFileRef,
kPGPFileOpenReadWritePerm |
kPGPFileOpenLockFile,
kPGPFileTypePubRing,
&kdb->pubStdFile );
if ( IsPGPError( err ) )
goto cleanup;
kdb->pubFile = pgpFileReadOpen ( kdb->context, kdb->pubStdFile,
NULL, NULL );
if ( IsNull( kdb->pubFile ) )
{
err = kPGPError_OutOfMemory;
goto cleanup;
}
cleanup:
return err;
}
/* Update lists when we change the db. This may be time consuming so should
* only be done when we know we are through with changes to the db, not
* every little object addition or deletion.
*/
static PGPError
sKeyDBUpdateLists( PGPKeyDBRef keydb )
{
PGPError err = kPGPError_NoErr;
PGPError rslt;
PGPKeySetRef set;
PGPKeyListRef list;
PGPValidateKeyDB( keydb );
for( set = keydb->firstSetInDB; IsntNull( set ); set = set->nextSetInDB )
{
for( list = set->firstListInSet; IsntNull( list );
list = list->nextListInSet )
{
rslt = pgpUpdateList( list );
if( IsPGPError( rslt ) )
err = rslt;
}
}
return err;
}
/******************** Exported Functions ************************/
PGPBoolean
PGPKeyDBIsMutable (PGPKeyDBRef kdb)
{
if( !pgpKeyDBIsValid( kdb ) )
return FALSE;
pgpEnterBooleanFunction( FALSE );
return kdb->bmutable;
}
PGPBoolean
pgpKeyDBIsDirty (PGPKeyDBRef kdb)
{
pgpa(pgpaPGPKeyDBValid(kdb));
return kdb->bdirty;
}
PGPBoolean
pgpKeyDBUsesTokens (PGPKeyDBRef kdb)
{
pgpa(pgpaPGPKeyDBValid(kdb));
return PFLFileSpecRefIsValid( kdb->pubFileRef );
}
void
pgpKeyDBChanged (PGPKeyDBRef kdb, PGPBoolean redoLists)
{
pgpa(pgpaPGPKeyDBValid(kdb));
kdb->bdirty = TRUE;
if( redoLists )
(void)sKeyDBUpdateLists( kdb );
}
/* Used with pgpContextGetFirstKeyDB to iterate over keydbs */
PGPKeyDBRef
pgpKeyDBNextKeyDB( PGPKeyDBRef kdb )
{
pgpa(pgpaPGPKeyDBValid(kdb));
return kdb->next;
}
PGPError
pgpKeyDBAddObject_internal (PGPKeyDBRef kdb, PGPKeyDBObj *obj,
PGPKeyDBObjRef *pnewobj)
{
PGPKeyDBObj * parobj;
PGPKeyDBObj * newparobj;
PGPInt32 count;
PGPInt32 i, j;
PGPByte const * objdata;
PGPSize objdatalen;
PGPError err = kPGPError_NoErr;
/* New logic goes as follows:
* Find keydb of source object
* Get data for object
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -