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

📄 sendmsg.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*							Kernel Message Dispatcher						*
*						Copyright Peter Gutmann 1997-2007					*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "crypt.h"
  #include "acl.h"
  #include "kernel.h"
#else
  #include "crypt.h"
  #include "kernel/acl.h"
  #include "kernel/kernel.h"
#endif /* Compiler-specific includes */

/* A pointer to the kernel data block */

static KERNEL_DATA *krnlData = NULL;

/* The ACL used to check objects passed as message parameters, in this case
   for cert sign/sig-check messages */

static const MESSAGE_ACL FAR_BSS messageParamACLTbl[] = {
	/* Certs can only be signed by (private-key) PKC contexts */
	{ MESSAGE_CRT_SIGN,
	  { ST_CTX_PKC,
		ST_NONE } },

	/* Signatures can be checked with a raw PKC context or a cert or cert
	   chain.  The object being checked can also be checked against a CRL,
	   against revocation data in a cert store, or against an RTCS or OCSP
	   responder */
	{ MESSAGE_CRT_SIGCHECK,
	  { ST_CTX_PKC | ST_CERT_CERT | ST_CERT_CERTCHAIN | ST_CERT_CRL | \
					 ST_KEYSET_DBMS,
		ST_SESS_RTCS | ST_SESS_OCSP } },

	{ MESSAGE_NONE, { ST_NONE, ST_NONE } },
	{ MESSAGE_NONE, { ST_NONE, ST_NONE } }
	};

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Sometimes a message is explicitly non-routable (i.e. it has to be sent
   directly to the appropriate target object).  The following function checks
   that the target object is one of the required types */

int checkTargetType( const int objectHandle, const long targets )
	{
	const OBJECT_TYPE target = targets & 0xFF;
	const OBJECT_TYPE altTarget = targets >> 8;
	OBJECT_INFO *objectTable = krnlData->objectTable;

	/* Precondition: Source is a valid object, destination(s) are valid
	   target(s) */
	PRE( isValidObject( objectHandle ) );
	PRE( isValidType( target ) );
	PRE( altTarget == OBJECT_TYPE_NONE || isValidType( altTarget ) );

	/* Check whether the object matches the required type.  We don't have to
	   check whether the alternative target has a value or not since the
	   object can never be a OBJECT_TYPE_NONE */
	if( !isValidObject( objectHandle ) || \
		( objectTable[ objectHandle ].type != target && \
		  objectTable[ objectHandle ].type != altTarget ) )
		return( CRYPT_ERROR );

	/* Postcondition */
	POST( objectTable[ objectHandle ].type == target || \
		  objectTable[ objectHandle ].type == altTarget );

	return( objectHandle );
	}

/* Find the ACL for a parameter object */

CHECK_RETVAL \
static const MESSAGE_ACL *findParamACL( const MESSAGE_TYPE message )
	{
	int i;

	/* Precondition: It's a message that takes an object parameter */
	PRE( isParamMessage( message ) );

	/* Find the ACL entry for this message type.  There's no need to 
	   explicitly handle the internal-error condition since any loop
	   exit is treated as an error */
	for( i = 0; messageParamACLTbl[ i ].type != MESSAGE_NONE && \
				i < FAILSAFE_ARRAYSIZE( messageParamACLTbl, MESSAGE_ACL ); 
		 i++ )
		{
		if( messageParamACLTbl[ i ].type == message )
			return( &messageParamACLTbl[ i ] );
		}

	/* Postcondition: We found a matching ACL entry */
	POST( FALSE );

	retIntError_Null();
	}

/* Wait for an object to become available so that we can use it, with a
   timeout for blocked objects.  This is an internal function which is used
   when mapping an object handle to object data, and is never called
   directly.  As an aid in identifying objects acting as bottlenecks, we
   provide a function to warn about excessive waiting, along with information
   on the object that was waited on, in debug mode.  A wait count threshold
   of 100 is generally high enough to avoid false positives caused by (for
   example) network subsystem delays */

#define MAX_WAITCOUNT				10000
#define WAITCOUNT_WARN_THRESHOLD	100

#if !defined( NDEBUG ) && !defined( __WIN16__ )

#include <stdio.h>

static void waitWarn( const int objectHandle, const int waitCount )
	{
	static const char *objectTypeNames[] = {
		"None", "Context", "Keyset", "Envelope", "Certificate", "Device",
		"Session", "User", "None", "None"
		};
	const OBJECT_INFO *objectInfoPtr = &krnlData->objectTable[ objectHandle ];
	char buffer[ 128 + 8 ];

	assert( isValidObject( objectHandle ) );
	assert( waitCount > WAITCOUNT_WARN_THRESHOLD && \
			waitCount <= MAX_WAITCOUNT );

	REQUIRES_V( isValidType( objectInfoPtr->type ) );
	if( objectHandle == SYSTEM_OBJECT_HANDLE )
		strlcpy_s( buffer, 128, "system object" );
	else
		{
		if( objectHandle == DEFAULTUSER_OBJECT_HANDLE )
			strlcpy_s( buffer, 128, "default user object" );
		else
			{
			sprintf_s( buffer, 128, "object %d (%s, subtype %lX)",
					   objectHandle, objectTypeNames[ objectInfoPtr->type ],
					   objectInfoPtr->subType );
			}
		}
	fprintf( stderr, "\nWarning: Thread %X waited %d iteration%s for %s.\n",
			 THREAD_SELF(), waitCount, ( waitCount == 1 ) ? "" : "s",
			 buffer );
	}
#endif /* Debug mode only */

int waitForObject( const int objectHandle, OBJECT_INFO **objectInfoPtrPtr )
	{
	OBJECT_INFO *objectTable = krnlData->objectTable;
	const int uniqueID = objectTable[ objectHandle ].uniqueID;
	int waitCount = 0;

	/* Preconditions: The object is in use by another thread */
	PRE( isValidObject( objectHandle ) );
	PRE( isInUse( objectHandle ) && !isObjectOwner( objectHandle ) );

	/* Sanity-check the state */
	REQUIRES( objectHandle == SYSTEM_OBJECT_HANDLE || \
			  objectHandle == DEFAULTUSER_OBJECT_HANDLE || \
			  isHandleRangeValid( objectHandle ) );

	/* While the object is busy, put the thread to sleep ("Pauzele lungi si
	   dese; Cheia marilor succese").  This is the only really portable way
	   to wait on the resource, which gives up this thread's timeslice to
	   allow other threads (including the one using the object) to run.
	   Somewhat better methods methods such as mutexes with timers are
	   difficult to manage portably across different platforms */
	while( isValidObject( objectHandle ) && \
		   objectTable[ objectHandle ].uniqueID == uniqueID && \
		   isInUse( objectHandle ) && waitCount < MAX_WAITCOUNT && \
		   krnlData->shutdownLevel < SHUTDOWN_LEVEL_MESSAGES )
		{
		objectTable = NULL;
		MUTEX_UNLOCK( objectTable );
		waitCount++;
		THREAD_YIELD();
		MUTEX_LOCK( objectTable );
		objectTable = krnlData->objectTable;
		}
#if !defined( NDEBUG ) && !defined( __WIN16__ )
	if( waitCount > WAITCOUNT_WARN_THRESHOLD )
		{
		/* If we waited more than WAITCOUNT_WARN_THRESHOLD iterations for
		   something this could be a sign of a resource usage bottleneck
		   (typically caused by users who don't understand threading), warn
		   the user that there's a potential problem */
		waitWarn( objectHandle, waitCount );
		}
#endif /* NDEBUG on systems with stdio */

	/* If cryptlib is shutting down, exit */
	if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MESSAGES )
		return( CRYPT_ERROR_PERMISSION );

	/* If we timed out waiting for the object, return a timeout error */
	if( waitCount >= MAX_WAITCOUNT )
		{
		assert( DEBUG_WARN );
		return( CRYPT_ERROR_TIMEOUT );
		}

	/* Make sure that nothing happened to the object while we were waiting
	   on it */
	if( !isValidObject( objectHandle ) || \
		objectTable[ objectHandle ].uniqueID != uniqueID )
		return( CRYPT_ERROR_SIGNALLED );

	/* Update the object info pointer in case the object table was updated
	   while we had yielded control */
	*objectInfoPtrPtr = &objectTable[ objectHandle ];

	/* Postconditions: The object is available for use */
	POST( isValidObject( objectHandle ) );
	POST( !isInUse( objectHandle ) );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*									Message Routing							*
*																			*
****************************************************************************/

/* Find the ultimate target of an object attribute manipulation message by
   walking down the chain of controlling -> dependent objects.  For example
   a message targeted at a device and sent to a certificate would be routed
   to the cert's dependent object (which would typically be a context).
   The device message targeted at the context would in turn be routed to the
   context's dependent device, which is its final destination */

int findTargetType( const int originalObjectHandle, const long targets )
	{
	const OBJECT_TYPE target = targets & 0xFF;
	const OBJECT_TYPE altTarget1 = ( targets >> 8 ) & 0xFF;
	const OBJECT_TYPE altTarget2 = ( targets >> 16 ) & 0xFF;
	OBJECT_INFO *objectTable = krnlData->objectTable;
	OBJECT_TYPE type = objectTable[ originalObjectHandle ].type;
	int objectHandle = originalObjectHandle, iterations;

	/* Preconditions: Source is a valid object, destination(s) are valid
	   target(s) */
	PRE( isValidObject( objectHandle ) );
	PRE( isValidType( target ) );
	PRE( altTarget1 == OBJECT_TYPE_NONE || isValidType( altTarget1 ) );
	PRE( altTarget2 == OBJECT_TYPE_NONE || isValidType( altTarget2 ) );

	/* Route the request through any dependent objects as required until we
	   reach the required target object type.  "And thou shalt make
	   loops..." -- Exodus 26:4 */
	for( iterations = 0; \
		 iterations < 3 && isValidObject( objectHandle ) && \
		   !( target == type || \
			  ( altTarget1 != OBJECT_TYPE_NONE && altTarget1 == type ) || \
			  ( altTarget2 != OBJECT_TYPE_NONE && altTarget2 == type ) ); \
		 iterations++ )
		{
		/* Loop invariants.  "Fifty loops thou shalt make" -- Exodus 26:5
		   (some of the OT verses shouldn't be taken too literally,
		   apparently the 50 used here merely means "many" as in "more than
		   one or two" in the same way that "40 days and nights" is now
		   generally taken as meaning "Lots, but that's as far as we're
		   prepared to count") */
		INV( isValidObject( objectHandle ) );
		INV( iterations < 3 );

		/* Find the next potential target object */
		if( target == OBJECT_TYPE_DEVICE && \
			objectTable[ objectHandle ].dependentDevice != CRYPT_ERROR )
			objectHandle = objectTable[ objectHandle ].dependentDevice;
		else
			{
			if( target == OBJECT_TYPE_USER )
				{
				/* If we've reached the system object (the parent of all 
				   other objects) we can't go any further */
				objectHandle = ( objectHandle != SYSTEM_OBJECT_HANDLE ) ? \
							   objectTable[ objectHandle ].owner : CRYPT_ERROR;
				}
			else
				objectHandle = objectTable[ objectHandle ].dependentObject;
			}
		if( isValidObject( objectHandle ) )
			type = objectTable[ objectHandle ].type;

		/* If we've got a new object, it has the same owner as the original
		   target candidate */
		POST( !isValidObject( objectHandle ) || \
			  isSameOwningObject( originalObjectHandle, objectHandle ) || \
			  objectTable[ originalObjectHandle ].owner == objectHandle );
		}
	ENSURES( iterations < 3 );

	/* Postcondition: We ran out of options or we reached the target object */
	POST( iterations < 3 );
	POST( objectHandle == CRYPT_ERROR || \
		  ( isValidObject( objectHandle ) && \
		    ( isSameOwningObject( originalObjectHandle, objectHandle ) || \
			  objectTable[ originalObjectHandle ].owner == objectHandle ) && \
			( target == type || \
			  ( altTarget1 != OBJECT_TYPE_NONE && altTarget1 == type ) || \
			  ( altTarget2 != OBJECT_TYPE_NONE && altTarget2 == type ) ) ) );

	return( isValidObject( objectHandle ) ? \
			objectHandle : CRYPT_ARGERROR_OBJECT );
	}

/* Find the ultimate target of a compare message by walking down the chain
   of controlling -> dependent objects.  For example a message targeted at a
   device and sent to a certificate would be routed to the cert's dependent

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -