⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgpkeydb.c

📁 PGP8.0源码 请认真阅读您的文件包然后写出其具体功能
💻 C
📖 第 1 页 / 共 3 页
字号:
/*____________________________________________________________________________
        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 + -