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

📄 unix.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 5 页
字号:
			close( procFD );
			}
		}
	zeroise( buffer, 1024 );
	if( procCount < 5 )
		return( 0 );

	/* Produce an estimate of the data's value.  We require that we get at
	   least 5 entries and give them a maximum value of 50 to ensure that
	   some data is still coming from other sources */
	quality = min( procCount * 3, 50 );
	krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE,
					 ( void * ) &quality, CRYPT_IATTRIBUTE_ENTROPY_QUALITY );
	return( quality );
	}

/* Get data from an entropy source */

static int getEntropySourceData( struct RI *dataSource, BYTE *bufPtr,
								 const int bufSize, int *bufPos )
	{
	int bufReadPos = 0, bufWritePos = 0;
	size_t noBytes;

	/* Try and get more data from the source.  If we get zero bytes, the
	   source has sent us all it has */
	if( ( noBytes = fread( bufPtr, 1, bufSize, dataSource->pipe ) ) <= 0 )
		{
		struct rusage rusage;
		int total = 0;

		/* If there's a problem, exit */
		if( my_pclose( dataSource, &rusage ) != 0 )
			return( 0 );

		/* Try and estimate how much entropy we're getting from a data
		   source */
		if( dataSource->usefulness != 0 )
			{
			if( dataSource->usefulness < 0 )
				/* Absolute rating, 1024 / -n */
				total = 1025 / -dataSource->usefulness;
			else
				/* Relative rating, 1024 * n */
				total = dataSource->length / dataSource->usefulness;
			}
#ifdef DEBUG_RANDOM
		printf( "rndunix: %s %s contributed %d bytes (compressed), "
				"usefulness = %d.\n", dataSource->path,
				( dataSource->arg != NULL ) ? dataSource->arg : "",
				dataSource->length, total );
#endif /* DEBUG_RANDOM */

		/* Copy in the last bit of entropy data, the resource usage of the
		   popen()ed child */
		if( sizeof( struct rusage ) < bufSize )
			{
			memcpy( bufPtr, &rusage, sizeof( struct rusage ) );
			*bufPos += sizeof( struct rusage );
			}

		return( total );
		}

	/* Run-length compress the input byte sequence */
	while( bufReadPos < noBytes )
		{
		const int ch = bufPtr[ bufReadPos ];

		/* If it's a single byte or we're at the end of the buffer, just
		   copy it over */
		if( bufReadPos >= bufSize - 1 || ch != bufPtr[ bufReadPos + 1 ] )
			{
			bufPtr[ bufWritePos++ ] = ch;
			bufReadPos++;
			}
		else
			{
			int count = 0;

			/* It's a run of repeated bytes, replace them with the byte
			   count mod 256 */
			while( bufReadPos < noBytes && ( ch == bufPtr[ bufReadPos ] ) )
				{
				count++;
				bufReadPos++;
				}
			bufPtr[ bufWritePos++ ] = count;
			}
		}

	/* Remember the number of (compressed) bytes of input that we obtained */
	*bufPos += bufWritePos;
	dataSource->length += noBytes;

	return( 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 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, which would have to be repeated for any new version */

#define SHARED_BUFSIZE		49152	/* Usually about 25K are filled */
#define SLOWPOLL_TIMEOUT	30		/* Time out after 30 seconds */

void slowPoll( void )
	{
	GATHERER_INFO *gathererInfo;
	BOOLEAN moreSources;
	struct timeval tv;
	struct rlimit rl = { 0, 0 };
	struct sigaction act;
	fd_set fds;
	time_t startTime;
#if defined( _CRAY ) || defined( __hpux ) || defined( _M_XENIX ) || \
	defined( __aux )
  #if defined( _SC_PAGESIZE )
	const int pageSize = sysconf( _SC_PAGESIZE );
  #elif defined( _SC_PAGE_SIZE )
	const int pageSize = sysconf( _SC_PAGE_SIZE );
  #else
	const int pageSize = 4096;
  #endif /* Systems without getpagesize() */
#else
	const int pageSize = getpagesize();
#endif /* Unix variant-specific brokenness */
#if defined( __hpux )
	size_t maxFD = 0;
#else
	int maxFD = 0;
#endif /* OS-specific brokenness */
	int extraEntropy = 0, usefulness = 0;
	int fd, bufPos, i, value;

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

	/* Some systems provide further info that we can grab before we start
	   the slow poll.  If this is sufficient to satisfy the polling
	   requirements, we don't have to try the full 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( "rndunix: 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 */
#if !( defined( __QNX__ ) && OSVERSION <= 4 )

	/* 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 = %s, line = %d.\n", errno, __FILE__, __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 = %s, line = "
					 "%d.\n", __FILE__, __LINE__ );
#endif /* Cray */
#ifdef DEBUG_CONFLICTS
		fprintf( stderr, "cryptlib: shmget()/shmat() failed, errno = %d, "
				 "file = %s, line = %d.\n", errno, __FILE__, __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 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;
	unlockPollingMutex();

	/* Fork off the gatherer, the parent process returns to the caller */
	if( ( gathererProcess = fork() ) != 0 )
		{
		/* If the fork() failed, clean up and reset the gatherer PID to make
		   sure that we're not locked out of retrying the poll later */
		if( gathererProcess == -1 )
			{
#ifdef DEBUG_CONFLICTS
			fprintf( stderr, "cryptlib: fork() failed, errno = %d, "
					 "file = %s, line = %d.\n", errno, __FILE__, __LINE__ );
#endif /* DEBUG_CONFLICTS */
			lockPollingMutex();
			shmctl( gathererMemID, IPC_RMID, NULL );
			sigaction( SIGCHLD, &gathererOldHandler, NULL );
			gathererProcess = 0;
			unlockPollingMutex();
			}
		return;	/* Error/parent process returns */
		}

	/* General housekeeping: Make sure that we can never dump core, and close
	   all inherited file descriptors.  We need to do this because if we
	   don't and the calling app has FILE *'s open, these will be flushed
	   when we call exit() in the child and again when the parent writes to
	   them or closes them, resulting in everything that was present in the
	   FILE * buffer at the time of the fork() being written twice.  An
	   alternative solution would be to call _exit() instead if exit() below,
	   but this is somewhat system-dependant and therefore a bit risky to
	   use.

	   In addition to this we should in theory call cryptEnd() since we
	   don't need any cryptlib objects beyond this point and it'd be a good
	   idea to clean them up to get rid of sensitive data held in memory.
	   However in some cases when using a crypto device or network interface
	   or similar item the shutdown in the child will also shut down the
	   parent item because while cryptlib objects are reference-counted the
	   external items aren't (they're beyond the control of cryptlib).  Even
	   destroying just contexts with keys loaded isn't possible because they
	   may be tied to a device that will propagate the shutdown from the
	   child to the parent via the device.

	   In general the child will be short-lived, and the use in its further
	   children of vfork() or the fact that many modern fork()s have copy-on-
	   write semantics even if no vfork() is available will mean that
	   cryptlib memory is never copied to the child and further children.  It
	   would, however, be better if there were some way to perform a neutron-
	   bomb type shutdown that only zeroises senstive information while
	   leaving structures intact */
	setrlimit( RLIMIT_CORE, &rl );
	for( fd = getdtablesize() - 1; fd > STDOUT_FILENO; fd-- )
		close( fd );
	fclose( stderr );	/* Arrghh!!  It's Stuart code!! */

	/* Fire up each randomness source */
	FD_ZERO( &fds );
	for( i = 0; dataSources[ i ].path != NULL; 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

⌨️ 快捷键说明

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