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

📄 rndunix.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 3 页
字号:
	void ( *disp )( int );
	const int pageSize = getPageSize();
#if defined( __hpux )
	size_t maxFD = 0;
#else
	int maxFD = 0;
#endif /* OS-specific brokenness */
	int bufPos, i, usefulness = 0;

	/* Make sure we don't start more than one slow poll at a time */
	enterMutex( MUTEX_RANDOMPOLLING );
	if( gathererProcess	)
		{
		exitMutex( MUTEX_RANDOMPOLLING );
		return;
		}

	/* Some systems provide further info which we can grab before we start
	   the slow poll */
	getDevRandomData();
	if( access( "/proc/interrupts", R_OK ) )
		getProcFSdata();
	getEGDdata();
#ifdef USE_KSTAT
	getKstatData();
#endif /* USE_KSTAT */
#ifdef USE_PROC
	getProcData();
#endif /* USE_PROC */

	/* Reset the SIGC(H)LD handler to the system default.  This is necessary
	   because if the program which cryptlib is a part of installs its own
	   SIGC(H)LD handler, it will end up reaping the cryptlib children before
	   cryptlib can.  As a result, my_pclose() will call waitpid() on a
	   process which has already been reaped by the installed handler and
	   return an error, so the read data won't be added to the randomness
	   pool.

	   There are two types of SIGC(H)LD naming, the SysV SIGCLD and the
	   BSD/Posix SIGCHLD, so we need to handle either possibility */
#ifdef SIGCLD
	disp = signal( SIGCLD, SIG_DFL );
#else
	disp = signal( SIGCHLD, SIG_DFL );
#endif /* SIGCLD */
	if( disp != SIG_DFL && disp != SIG_IGN )
		{
		/* The user has installed their own SIGC(H)LD handler, warn them that
		   they need to take special steps to manage this problem.  This is
		   ugly, but it's better than leaving a difficult-to-find problem
		   where the user's SIGC(H)LD handling is pre-empted by cryptlib */
		printf( "Conflicting SIGC(H)LD handling detected in randomness "
				"polling code,\nfile " __FILE__ ", line %d.\n", __LINE__ );
		}

	/* Set up the shared memory */
	gathererBufSize = ( SHARED_BUFSIZE / pageSize ) * ( pageSize + 1 );
	if( ( gathererMemID = shmget( IPC_PRIVATE, gathererBufSize,
								  IPC_CREAT | 0600 ) ) == -1 || \
		( gathererBuffer = ( BYTE * ) shmat( gathererMemID,
											 NULL, 0 ) ) == ( BYTE * ) -1 )
		{
		if( gathererMemID != -1 )
			shmctl( gathererMemID, IPC_RMID, NULL );
		exitMutex( MUTEX_RANDOMPOLLING );
		return; /* Something broke */
		}

	/* At this point we have a possible race condition since we need to set
	   the gatherer PID value inside the mutex but messing with mutexes
	   across a fork() is somewhat messy.  To resolve this, we set the PID
	   to a nonzero value (which marks it as busy) and exit the mutex, then
	   overwrite it with the real PID (also nonzero) from the fork */
	gathererProcess = -1;
	exitMutex( MUTEX_RANDOMPOLLING );

	/* Fork off the gatherer, the parent process returns to the caller */
	if( ( gathererProcess = fork() ) || ( gathererProcess == -1 ) )
		{
		/* If the fork() failed, clear the gatherer process value to make
		   sure we're not locked out of retrying the poll later */
		if( gathererProcess == -1 )
			{
			enterMutex( MUTEX_RANDOMPOLLING );
			gathererProcess = 0;
			exitMutex( MUTEX_RANDOMPOLLING );
			}
		return;	/* Error/parent process returns */
		}

	fclose( stderr );	/* Arrghh!!  It's Stuart code!! */

	/* Fire up each randomness source */
	FD_ZERO( &fds );
	for( i = 0; dataSources[ i ].path != NULL; i++ )
		{
		/* Since popen() is a fairly heavy function, we check to see whether
		   the executable exists before we try to run it */
		if( access( dataSources[ i ].path, X_OK ) )
			{
#ifdef DEBUG_RANDOM
			printf( "%s not present%s\n", dataSources[ i ].path,
					dataSources[ i ].hasAlternative ? ", has alternatives" : "" );
#endif /* DEBUG_RANDOM */
			dataSources[ i ].pipe = NULL;
			}
		else
			dataSources[ i ].pipe = my_popen( &dataSources[ i ] );
		if( dataSources[ i ].pipe != NULL )
			{
			dataSources[ i ].pipeFD = fileno( dataSources[ i ].pipe );
			if( dataSources[ i ].pipeFD > maxFD )
				maxFD = dataSources[ i ].pipeFD;
			fcntl( dataSources[ i ].pipeFD, F_SETFL, O_NONBLOCK );
			FD_SET( dataSources[ i ].pipeFD, &fds );
			dataSources[ i ].length = 0;

			/* If there are alternatives for this command, don't try and
			   execute them */
			while( dataSources[ i ].hasAlternative )
				{
#ifdef DEBUG_RANDOM
				printf( "Skipping %s\n", dataSources[ i + 1 ].path );
#endif /* DEBUG_RANDOM */
				i++;
				}
			}
		}
	gathererInfo = ( GATHERER_INFO * ) gathererBuffer;
	bufPos = sizeof( GATHERER_INFO );	/* Start of buf.has status info */

	/* Suck all the data we can get from each of the sources */
	moreSources = TRUE;
	startTime = time( NULL );
	while( moreSources && bufPos <= gathererBufSize )
		{
		/* Wait for data to become available from any of the sources, with a
		   timeout of 10 seconds.  This adds even more randomness since data
		   becomes available in a nondeterministic fashion.  Kudos to HP's QA
		   department for managing to ship a select() which breaks its own
		   prototype */
		tv.tv_sec = 10;
		tv.tv_usec = 0;
#if defined( __hpux ) && ( OS_VERSION == 9 || OS_VERSION == 0 )
		if( select( maxFD + 1, ( int * ) &fds, NULL, NULL, &tv ) == -1 )
#else
		if( select( maxFD + 1, &fds, NULL, NULL, &tv ) == -1 )
#endif /* __hpux */
			break;

		/* One of the sources has data available, read it into the buffer */
		for( i = 0; dataSources[ i ].path != NULL; i++ )
			if( dataSources[ i ].pipe != NULL && \
				FD_ISSET( dataSources[ i ].pipeFD, &fds ) )
				{
				size_t noBytes;

				if( ( noBytes = fread( gathererBuffer + bufPos, 1,
									   gathererBufSize - bufPos,
									   dataSources[ i ].pipe ) ) == 0 )
					{
					if( my_pclose( &dataSources[ i ] ) == 0 )
						{
						int total = 0;

						/* Try and estimate how much entropy we're getting
						   from a data source */
						if( dataSources[ i ].usefulness )
							if( dataSources[ i ].usefulness < 0 )
								total = ( dataSources[ i ].length + 999 ) / \
										-dataSources[ i ].usefulness;
							else
								total = dataSources[ i ].length / \
										dataSources[ i ].usefulness;
#ifdef DEBUG_RANDOM
						printf( "%s %s contributed %d bytes (compressed), "
								"usefulness = %d\n", dataSources[ i ].path,
								( dataSources[ i ].arg != NULL ) ? \
								dataSources[ i ].arg : "",
								dataSources[ i ].length, total );
#endif /* DEBUG_RANDOM */
						usefulness += total;
						}
					dataSources[ i ].pipe = NULL;
					}
				else
					{
					int currPos = bufPos;
					int endPos = bufPos + noBytes;

					/* Run-length compress the input byte sequence */
					while( currPos < endPos )
						{
						int ch = gathererBuffer[ currPos ];

						/* If it's a single byte, just copy it over */
						if( ch != gathererBuffer[ currPos + 1 ] )
							{
							gathererBuffer[ bufPos++ ] = ch;
							currPos++;
							}
						else
							{
							int count = 0;

							/* It's a run of repeated bytes, replace them with
							   the byte count mod 256 */
							while( ( ch == gathererBuffer[ currPos ] ) && \
								   currPos < endPos )
								{
								count++;
								currPos++;
								}
							gathererBuffer[ bufPos++ ] = count;
							noBytes -= count - 1;
							}
						}

					/* Remember the number of (compressed) bytes of input we
					   obtained */
					dataSources[ i ].length += noBytes;
					}
				}

		/* Check if there is more input available on any of the sources */
		moreSources = FALSE;
		FD_ZERO( &fds );
		for( i = 0; dataSources[ i ].path != NULL; i++ )
			if( dataSources[ i ].pipe != NULL )
				{
				FD_SET( dataSources[ i ].pipeFD, &fds );
				moreSources = TRUE;
				}

		/* If we've gone over our time limit, kill anything still hanging
		   around and exit.  This prevents problems with input from blocked
		   sources */
		if( time( NULL ) > startTime + SLOWPOLL_TIMEOUT )
			{
			for( i = 0; dataSources[ i ].path != NULL; i++ )
				if( dataSources[ i ].pipe != NULL )
					{
#ifdef DEBUG_RANDOM
					printf( "Aborting read of %s due to timeout.\n",
							dataSources[ i ].path );
#endif /* DEBUG_RANDOM */
					fclose( dataSources[ i ].pipe );
					kill( dataSources[ i ].pid, SIGKILL );
					dataSources[ i ].pipe = NULL;
					dataSources[ i ].pid = 0;
					}
			moreSources = FALSE;
#ifdef DEBUG_RANDOM
			puts( "Poll timed out, probably due to blocked data source." );
#endif /* DEBUG_RANDOM */
			}
		}
	gathererInfo->usefulness = usefulness;
	gathererInfo->noBytes = bufPos;
#ifdef DEBUG_RANDOM
	printf( "Got %d bytes, usefulness = %d\n", bufPos, usefulness );
#endif /* DEBUG_RANDOM */

	/* "Thou child of the daemon, ... wilt thou not cease...?" -- Acts 13:10 */
	exit( 0 );
	}

/* Wait for the randomness gathering to finish.  Anything that requires the
   gatherer process to have completed gathering entropy should call
   waitforRandomCompletion(), which will block until the background process
   completes */

void waitforRandomCompletion( void )
	{
	enterMutex( MUTEX_RANDOMPOLLING );
	if( gathererProcess	)
		{
		RESOURCE_DATA msgData;
		GATHERER_INFO *gathererInfo = ( GATHERER_INFO * ) gathererBuffer;
		int quality, status;

		/* Wait for the gathering process to finish, add the randomness it's
		   gathered, and detach the shared memory */
		waitpid( gathererProcess, &status, 0 ); /* Should prob.check status */
		quality = gathererInfo->usefulness * 5;	/* 0-20 -> 0-100 */
		setResourceData( &msgData, gathererBuffer, gathererInfo->noBytes );
		krnlSendMessage( SYSTEM_OBJECT_HANDLE, RESOURCE_IMESSAGE_SETATTRIBUTE_S,
						 &msgData, CRYPT_IATTRIBUTE_RANDOM );
		krnlSendMessage( SYSTEM_OBJECT_HANDLE, RESOURCE_IMESSAGE_SETATTRIBUTE,
						 &quality, CRYPT_IATTRIBUTE_RANDOM_QUALITY );
		zeroise( gathererBuffer, gathererBufSize );
		shmdt( gathererBuffer );
		shmctl( gathererMemID, IPC_RMID, NULL );
		gathererProcess = 0;
		}
	exitMutex( MUTEX_RANDOMPOLLING );
	}

/* Check whether we've forked and we're the child.  The mechanism used varies
   depending on whether we're running in a single-threaded or multithreaded
   environment, for single-threaded we check whether the pid has changed
   since the last check, for multithreaded environments this isn't reliable
   since some systems have per-thread pid's so we need to use
   pthread_atfork() as a trigger to set the pid-changed flag.

   Under Aches, calling pthread_atfork() with any combination of arguments or
   circumstances produces a segfault, so we undefine USE_THREADS to force the
   use of the getpid()-based fork detection */

#if defined( USE_THREADS ) && defined( _AIX )
  #undef USE_THREADS
#endif /* USE_THREADS && _AIX */

#ifdef USE_THREADS

static BOOLEAN forked = FALSE;

BOOLEAN checkForked( void )
	{
	BOOLEAN hasForked;

	/* Read the forked-t flag in a thread-safe manner */
	enterMutex( MUTEX_RANDOMPOLLING );
	hasForked = forked;
	forked = FALSE;
	exitMutex( MUTEX_RANDOMPOLLING );

	return( hasForked );
	}

void setForked( void )
	{
	/* Set the forked-t flag in a thread-safe manner */
	enterMutex( MUTEX_RANDOMPOLLING );
	forked = TRUE;
	exitMutex( MUTEX_RANDOMPOLLING );
	}

#else

BOOLEAN checkForked( void )
	{
	static pid_t originalPID = -1;

	/* Set the initial PID if necessary */
	if( originalPID == -1 )
		originalPID = getpid();

	/* If the pid has changed we've forked and we're the child, remember the
	   new pid */
	if( getpid() != originalPID )
		{
		originalPID = getpid();
		return( TRUE );
		}

	return( FALSE );
	}
#endif /* USE_THREADS */

/* Initialise and clean up any auxiliary randomness-related objects */

void initRandomPolling( void )
	{
	/* If it's multithreaded code, we need to ensure that we're signalled if
	   another thread calls fork().  Hardcoding in the Posix function name at
	   this point is safe because it also works for Solaris threads. We set
	   the forked flag in both the child and the parent to ensure that both
	   sides remix the pool thoroughly */
#ifdef USE_THREADS
	pthread_atfork( NULL, setForked, setForked );
#endif /* USE_THREADS */
	}

⌨️ 快捷键说明

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