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

📄 unix.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 5 页
字号:
			   already obtained entropy from additional sources,we're
			   done */
			if( extraEntropy >= 50 )
				{
#ifdef DEBUG_RANDOM
				puts( "rndunix: 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 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( "rndunix: %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( "rndunix: 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 that we can get from each of the sources */
	moreSources = TRUE;
	startTime = getTime();
	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() 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++ )
			if( dataSources[ i ].pipe != NULL && \
				FD_ISSET( dataSources[ i ].pipeFD, &fds ) )
				usefulness += getEntropySourceData( &dataSources[ i ],
													gathererBuffer + bufPos,
													gathererBufSize - bufPos,
													&bufPos );

		/* 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++ )
			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( getTime() > startTime + SLOWPOLL_TIMEOUT )
			{
			for( i = 0; dataSources[ i ].path != NULL; i++ )
				if( dataSources[ i ].pipe != NULL )
					{
#ifdef DEBUG_RANDOM
					printf( "rndunix: 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( "rndunix: Poll timed out, probably due to blocked data "
				  "source." );
#endif /* DEBUG_RANDOM */
			}
		}
	gathererInfo->usefulness = usefulness;
	gathererInfo->noBytes = bufPos;
#ifdef DEBUG_RANDOM
	printf( "rndunix: 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 );
#endif /* !QNX 4.x */
	}

/* Wait for the randomness gathering to finish.  Cray Unicos doesn't have
   sched_yield() and OpenBSD has its sched_yield() in libpthread so it
   doesn't exist if we're not building with USE_THREADS, in which case we
   have to no-op it out */

#if defined( _CRAY ) || \
	( defined( __OpenBSD__ ) && !defined( USE_THREADS ) )
  #define sched_yield()
#endif /* Systems without sched_yield() */

void waitforRandomCompletion( const BOOLEAN force )
	{
	lockPollingMutex();
	if( gathererProcess	)
		{
		RESOURCE_DATA msgData;
		GATHERER_INFO *gathererInfo = ( GATHERER_INFO * ) gathererBuffer;
		int quality, status;

		/* If this is a forced shutdown, be fairly assertive with the
		   gathering process */
		if( force )
			{
			/* Politely ask the the gatherer to shut down and (try and)
			   yield our timeslice a few times so that the shutdown can
			   take effect. This is unfortunately somewhat implementation-
			   dependant in that in some cases it'll only yield the current
			   thread's timeslice, or if it's a high-priority thread it'll
			   be scheduled again before any lower-priority threads get to
			   run */
			kill( gathererProcess, SIGTERM );
			sched_yield();
			sched_yield();
			sched_yield();	/* Well, sync is done three times too... */

			/* If the gatherer is still running, ask again, less
			   politely this time */
#if 1
			if( kill( gathererProcess, 0 ) != -1 || errno != ESRCH )
#else
			if( getpgid( pid ) > 0 || errno == EPERM )
#endif /* 1 */
				kill( gathererProcess, SIGKILL );
			}

		/* Wait for the gathering process to finish, add the randomness it's
		   gathered, detach and delete the shared memory (the latter is
		   necessary because otherwise the unused ID hangs around until the
		   process terminates), and restore the original signal handler if we
		   replaced someone else's one.  We don't check for errors at this
		   point (except in the debug version) since this is an invisible
		   internal routine for which we can't easily recover from problems.
		   Any problems are caught at a higher level by the randomness-
		   quality checking */
		waitpid( gathererProcess, &status, 0 );
		if( gathererInfo->noBytes > 0 && !force )
			{
			quality = min( gathererInfo->usefulness * 5, 100 );	/* 0-20 -> 0-100 */
			setMessageData( &msgData, gathererBuffer, gathererInfo->noBytes );
			status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
									  IMESSAGE_SETATTRIBUTE_S,
									  &msgData, CRYPT_IATTRIBUTE_ENTROPY );
			assert( cryptStatusOK( status ) );
			if( quality > 0 )
				{
				/* On some very cut-down embedded systems the entropy
				   quality can be zero, so we only send a quality estimate
				   if there's actually something there */
				status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
										  IMESSAGE_SETATTRIBUTE,
										  &quality,
										  CRYPT_IATTRIBUTE_ENTROPY_QUALITY );
				assert( cryptStatusOK( status ) );
				}
			}
		zeroise( gathererBuffer, gathererBufSize );
#if !( defined( __QNX__ ) && OSVERSION <= 4 )
		shmdt( gathererBuffer );
		shmctl( gathererMemID, IPC_RMID, NULL );
		if( gathererOldHandler.sa_handler != SIG_DFL )
			{
			struct sigaction oact;

			/* We replaced someone else's handler for the slow poll,
			   reinstate the original one.  Since someone else could have in
			   turn replaced our handler, we check for this and warn the
			   user if necessary */
			sigaction( SIGCHLD, NULL, &oact );
			if( oact.sa_handler != SIG_DFL )
				{
#ifdef DEBUG_CONFLICTS
				/* The current handler isn't the one that we installed, warn
				   the user */
				fprintf( stderr, "cryptlib: SIGCHLD handler was replaced "
						 "while slow poll was in progress,\nfile " __FILE__
						 ", line %d.  See the source code for more\n"
						 "information.\n", __LINE__ );
#endif /* DEBUG_CONFLICTS */
				}
			else
				/* Our handler is still in place, replace it with the
				   original one */
				sigaction( SIGCHLD, &gathererOldHandler, NULL );
			}
#endif /* !QNX 4.x */
		gathererProcess = 0;
		}
	unlockPollingMutex();
	}

/* 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.  In addition some other
   environments don't support the call, so we exclude those as well.  FreeBSD
   is a particular pain because of its highly confusing use of -RELEASE,
   -STABLE, and -CURRENT while maintaining the same version, it's present in
   5.x-CURRENT but not 5.x-RELEASE or -STABLE, so we have to exclude it for
   all 5.x to be safe */

#if defined( USE_THREADS ) && \
	( defined( _AIX ) || defined( _CRAY ) || defined( __MVS__ ) || \
	  defined( _MPRAS ) || defined( __APPLE__ ) || \
	  ( defined( __FreeBSD__ ) && OSVERSION <= 5 ) )
  #undef USE_THREADS
#endif /* USE_THREADS && OSes without pthread_atfork() */

#ifdef USE_THREADS

static BOOLEAN forked = FALSE;

BOOLEAN checkForked( void )
	{
	BOOLEAN hasForked;

	/* Read the forked-t flag in a thread-safe manner */
	lockPollingMutex();
	hasForked = forked;
	forked = FALSE;
	unlockPollingMutex();

	return( hasForked );
	}

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

#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 );

	pthread_mutex_init( &gathererMutex, NULL );
#endif /* USE_THREADS */
	}

void endRandomPolling( void )
	{
#ifdef USE_THREADS
	pthread_mutex_destroy( &gathererMutex );
#endif /* USE_THREADS */
	}

⌨️ 快捷键说明

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