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

📄 unix.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Fire up each randomness source */
	FD_ZERO( &fds );
	for( i = 0; dataSources[ i ].path != NULL && \
				i < FAILSAFE_ARRAYSIZE( dataSources, DATA_SOURCE_INFO ); i++ )
		{
		/* Check for the end-of-lightweight-sources marker */
		if( dataSources[ i ].path[ 0 ] == '\0' )
			{
			/* If we're only polling lightweight sources because we've
			   already obtained entropy from additional sources,we're
			   done */
			if( existingEntropy >= 50 )
				{
#ifdef DEBUG_RANDOM
				puts( __FILE__ ": All lightweight sources polled, exiting "
					  "without polling\nheavyweight ones." );
#endif /* DEBUG_RANDOM */
				break;
				}

			/* We're polling all sources, continue with the heavyweight
			   ones */
			continue;
			}

		/* Since popen() is a fairly heavyweight 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( __FILE__ ": %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 )
			continue;
		if( fileno( dataSources[ i ].pipe ) >= FD_SETSIZE )
			{
			/* The fd is larger than what can be fitted into an fd_set, don't
			   try and use it.  This can happen if the calling app opens a
			   large number of files, since most FD_SET() macros don't
			   perform any safety checks this can cause segfaults and other
			   problems if we don't perform the check ourselves */
			fclose( dataSources[ i ].pipe );
			dataSources[ i ].pipe = NULL;
			continue;
			}

		/* Set up the data source information */
		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 */
		iterationCount = 0;
		while( dataSources[ i ].hasAlternative && \
			   i < FAILSAFE_ARRAYSIZE( dataSources, DATA_SOURCE_INFO ) && \
			   iterationCount++ < FAILSAFE_ITERATIONS_MED ) 
			{
#ifdef DEBUG_RANDOM
			printf( __FILE__ ": Skipping %s.\n", dataSources[ i + 1 ].path );
#endif /* DEBUG_RANDOM */
			i++;
			}
		ENSURES_EXIT( iterationCount < FAILSAFE_ITERATIONS_MED );
					  /* i is checked as part of the loop control */
		}
	ENSURES_EXIT( i < FAILSAFE_ARRAYSIZE( dataSources, DATA_SOURCE_INFO ) );
	gathererInfo = ( GATHERER_INFO * ) gathererBuffer;
	bufPos = sizeof( GATHERER_INFO );	/* Start of buf.has status info */

	/* Suck up all of the data that we can get from each of the sources */
	status = setMonoTimer( &timerInfo, SLOWPOLL_TIMEOUT );
	ENSURES_EXIT( cryptStatusOK( status ) );
	for( moreSources = TRUE, iterationCount = 0;
		 moreSources && bufPos < gathererBufSize && \
			iterationCount < FAILSAFE_ITERATIONS_MAX; 
		 iterationCount++ )
		{
		/* 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() that breaks its own
		   prototype */
		tv.tv_sec = 10;
		tv.tv_usec = 0;
#if defined( __hpux ) && ( OSVERSION == 9 || OSVERSION == 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 < FAILSAFE_ARRAYSIZE( dataSources, DATA_SOURCE_INFO ); 
			 i++ )
			{
			if( dataSources[ i ].pipe != NULL && \
				FD_ISSET( dataSources[ i ].pipeFD, &fds ) )
				usefulness += getEntropySourceData( &dataSources[ i ],
													gathererBuffer + bufPos,
													gathererBufSize - bufPos,
													&bufPos );
			}
		ENSURES_EXIT( i < FAILSAFE_ARRAYSIZE( dataSources, DATA_SOURCE_INFO ) );

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

		/* If we've gone over our time limit, kill anything still hanging
		   around and exit.  This prevents problems with input from blocked
		   sources */
		if( checkMonoTimerExpired( &timerInfo ) )
			{
			for( i = 0; dataSources[ i ].path != NULL && \
						i < FAILSAFE_ARRAYSIZE( dataSources, DATA_SOURCE_INFO ); 
				 i++ )
				{
				if( dataSources[ i ].pipe != NULL )
					{
#ifdef DEBUG_RANDOM
					printf( __FILE__ ": 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;
					}
				}
			ENSURES_EXIT( i < FAILSAFE_ARRAYSIZE( dataSources, DATA_SOURCE_INFO ) );
			moreSources = FALSE;
#ifdef DEBUG_RANDOM
			puts( __FILE__ ": Poll timed out, probably due to blocked data "
				  "source." );
#endif /* DEBUG_RANDOM */
			}
		}
	ENSURES_EXIT( iterationCount < FAILSAFE_ITERATIONS_MAX );
	gathererInfo->usefulness = usefulness;
	gathererInfo->noBytes = bufPos;
#ifdef DEBUG_RANDOM
	printf( __FILE__ ": 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 );
	}

/* Unix slow poll.  If a few of the randomness sources create a large amount
   of output then the slowPoll() stops once the buffer has been filled (but
   before all of the randomness sources have been sucked dry) so that the
   'usefulness' factor remains below the threshold.  For this reason the
   gatherer buffer has to be fairly sizeable on moderately loaded systems.

   An alternative strategy, suggested by Massimo Squillace, is to use a
   chunk of shared memory protected by a semaphore, with the first
   sizeof( int ) bytes at the start serving as a high-water mark.  The
   process forks and waitpid()'s for the child's pid.  The child forks all
   the entropy-gatherers and exits, allowing the parent to resume execution.
   The child's children are inherited by init (double-fork paradigm), when
   each one is finished it takes the semaphore, writes data to the shared
   memory segment at the given offset, updates the offset, releases the
   semaphore again, and exits, to be reaped by init.

   The parent monitors the shared memory offset and when enough data is
   available takes the semaphore, grabs the data, and releases the shared
   memory area and semaphore.  If any children are still running they'll get
   errors when they try to access the semaphore or shared memory and
   silently exit.

   This approach has the advantage that all of the forked processes are
   managed by init rather than having the parent have to wait for them, but
   the disadvantage that the end-of-job handling is rather less rigorous.
   An additional disadvantage is that the existing code has had a lot of
   real-world testing and adaptation to system-specific quirks, which would 
   have to be repeated for any new version */

#define SHARED_BUFSIZE		49152	/* Usually about 25K are filled */

void slowPoll( void )
	{
	struct sigaction act;
	const int pageSize = getSysVar( SYSVAR_PAGESIZE );
	int extraEntropy = 0;

	/* Make sure that we don't start more than one slow poll at a time.  The
	   gathererProcess value may be positive (a PID) or -1 (error), so we
	   compare it to the specific value 0 (= not-used) in the check */
	lockPollingMutex();
	if( gathererProcess	!= 0 )
		{
		unlockPollingMutex();
		return;
		}

	/* The popen()-level slow poll is the screen-scraping interface of last
	   resort that we use only if we can't get the entropy in any other
	   way.  If the system provides entropy from alternate sources, we don't 
	   have have to try the screen-scraping slow poll (a number of these 
	   additional sources, things like procfs and kstats, duplicate the 
	   sources polled in the slow poll anyway, so we're not adding much by 
	   polling these extra sources if we've already got the data directly) */
	extraEntropy += getDevRandomData();
	if( !access( "/proc/interrupts", R_OK ) )
		extraEntropy += getProcFSdata();
	extraEntropy += getEGDdata();
#ifdef USE_KSTAT
	extraEntropy += getKstatData();
#endif /* USE_KSTAT */
#ifdef USE_PROC
	extraEntropy += getProcData();
#endif /* USE_PROC */
#ifdef DEBUG_RANDOM
	printf( __FILE__ ": Got %d additional entropy from direct sources.\n",
			extraEntropy );
	if( extraEntropy >= 100 )
		puts( "  (Skipping full slowpoll since sufficient entropy is "
			  "available)." );
#endif /* DEBUG_RANDOM */
	if( extraEntropy >= 100 )
		{
		/* We got enough entropy from the additional sources, we don't
		   have to go through with the full (heavyweight) poll */
		unlockPollingMutex();
		return;
		}

	/* QNX 4.x doesn't have SYSV shared memory, so we can't go beyond this
	   point, all that we can do is warn the user that they'll have to use
	   the entropy mechanisms for embedded systems (without proper entropy
	   sources) */
#if defined( __QNX__ ) && OSVERSION <= 4
	fprintf( stderr, "cryptlib: QNX 4.x doesn't contain the OS mechanisms "
			 "required to provide\n          system entropy sources that "
			 "can be used for key generation.  In\n          order to use "
			 "cryptlib in this environment, you need to apply the\n"
			 "          randomness mechanisms for embedded systems "
			 "described in the\n          cryptlib manual.\n" );
	abort();
#else

	/* Reset the SIGCHLD handler to the system default.  This is necessary
	   because if the program that cryptlib is a part of installs its own
	   SIGCHLD handler, it will end up reaping the cryptlib children before
	   cryptlib can.  As a result, my_pclose() will call waitpid() on a
	   process that has already been reaped by the installed handler and
	   return an error, so the read data won't be added to the randomness
	   pool */
	memset( &act, 0, sizeof( act ) );
	act.sa_handler = SIG_DFL;
	sigemptyset( &act.sa_mask );
	if( sigaction( SIGCHLD, &act, &gathererOldHandler ) < 0 )
		{
		/* This assumes that stderr is open, i.e. that we're not a daemon
		   (this should be the case at least during the development/debugging
		   stage) */
		fprintf( stderr, "cryptlib: sigaction() failed, errno = %d, "
				 "file " __FILE__ ", line %d.\n", errno, __LINE__ );
		abort();
		}

	/* Check for handler override */
	if( gathererOldHandler.sa_handler != SIG_DFL && \
		gathererOldHandler.sa_handler != SIG_IGN )
		{
#ifdef DEBUG_CONFLICTS
		/* We overwrote the caller's handler, warn them about this */
		fprintf( stderr, "cryptlib: Conflicting SIGCHLD handling detected "
				 "in randomness polling code,\nfile " __FILE__ ", line %d.  "
				 "See the source code for more\ninformation.\n", __LINE__ );
#endif /* DEBUG_CONFLICTS */
		}

	/* 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 )
		{
		/* There was a problem obtaining the shared memory, warn the user
		   and exit */
#ifdef _CRAY
		if( errno == ENOSYS )
			/* Unicos supports shmget/shmat, but older Crays don't implement
			   it and return ENOSYS */
			fprintf( stderr, "cryptlib: SYSV shared memory required for "
					 "random number gathering isn't\n  supported on this "
					 "type of Cray hardware (ENOSYS),\n  file " __FILE__ 
					 ", line %d.\n", __LINE__ );
#endif /* Cray */
#ifdef DEBUG_CONFLICTS
		fprintf( stderr, "cryptlib: shmget()/shmat() failed, errno = %d, "
				 "file " __FILE__ ", line %d.\n", errno, __LINE__ );
#endif /* DEBUG_CONFLICTS */
		if( gathererMemID != -1 )
			shmctl( gathererMemID, IPC_RMID, NULL );
		if( gathererOldHandler.sa_handler != SIG_DFL )
			sigaction( SIGCHLD, &gathererOldHandler, NULL );
		unlockPollingMutex();
		return; /* Something broke */
		}

	/* At this point we have a possible race condition since we need to set
	   the gatherer PID 

⌨️ 快捷键说明

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