📄 unix.c
字号:
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 + -