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

📄 rndunix.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
	/* Create the pipe */
	if( pipe( pipedes ) < 0 )
		return( NULL );

	/* Fork off the child ("vfork() is like an OS orgasm.  All OSes want to
	   do it, but most just end up faking it" - Chris Wedgwood).  If your OS
	   supports it, you should try and use vfork() here because it's rather
	   more efficient and has guaranteed copy-on-write semantics that prevent
	   cryptlib object data from being copied to the child.  Many modern
	   Unixen use COW for forks anyway (e.g. Linux, for which vfork() is just
	   an alias for fork()), so we get most of the benefits of vfork() with a
	   plain fork(), however there's another problem with fork that isn't
	   fixed by COW.  Any large program, when forked, requires (at least
	   temporarily) a lot of address space.  That is, when the process is
	   forked the system needs to allocate many virtual pages (backing store)
	   even if those pages are never used.  If the system doesn't have enough
	   swap space available to support this, the fork() will fail when the
	   system tries to reserver backing store for pages that are never
	   touched.  Even in non-large processes this can cause problems when (as
	   with the randomness-gatherer) many children are forked at once.

	   In the absence of threads the use of pcreate() (which only requires
	   backing store for the new processes' stack, not the entire process)
	   would do the trick, however pcreate() isn't compatible with threads,
	   which makes it of little use for the default thread-enabled cryptlib
	   build

	   Although OSF/1 has vfork(), it has nasty interactions with threading
	   and can cause other problems with handling of children, so we don't
	   use it */
#ifdef HAS_VFORK
	entry->pid = vfork();
#else
	entry->pid = fork();
#endif /* Unixen that have vfork() */
	if( entry->pid == ( pid_t ) -1 )
		{
		/* The fork failed */
		close( pipedes[ 0 ] );
		close( pipedes[ 1 ] );
		return( NULL );
		}

	if( entry->pid == ( pid_t ) 0 )
		{
		struct passwd *passwd;

		/* We are the child.  Make the read side of the pipe be stdout */
		if( dup2( pipedes[ STDOUT_FILENO ], STDOUT_FILENO ) < 0 )
			exit( 127 );

		/* If we're root, give up our permissions to make sure we don't
		   inadvertently read anything sensitive.  If the getpwnam() fails
		   (this can happen if we're chrooted with no "nobody" entry in the
		   local passwd file) we default to -1, which is usually nobody.  We
		   don't check whether this succeeds since it's not a major security
		   problem but just a precaution */
		if( geteuid() == 0 )
			{
			static uid_t gathererUID = ( uid_t ) -1, gathererGID = ( uid_t ) -1;

			if( gathererProcess == ( uid_t ) -1 && \
				( passwd = getpwnam( "nobody" ) ) != NULL )
				{
				gathererUID = passwd->pw_uid;
				gathererGID = passwd->pw_gid;
				}
#if 0		/* Not available on some OSes */
			setgid( gathererGID );
			setegid( gathererGID );
			setuid( gathererUID );
			seteuid( gathererUID );
#else
			setregid( gathererGID, gathererGID );
			setreuid( gathererUID, gathererUID );
#endif /* 0 */
			}

		/* Close the pipe descriptors */
		close( pipedes[ STDIN_FILENO ] );
		close( pipedes[ STDOUT_FILENO ] );

		/* Try and exec the program */
		execl( entry->path, entry->path, entry->arg, NULL );

		/* Die if the exec failed.  Since vfork() doesn't duplicate the stdio
		   buffers (or anything else for that matter), we have to use _exit()
		   rather than exit() to ensure that the shutdown actions don't upset
		   the parent's state */
#ifdef HAS_VFORK
		_exit( 127 );
#else
		exit( 127 );
#endif /* Unixen that have vfork() */
		}

	/* We are the parent.  Close the irrelevant side of the pipe and open the
	   relevant side as a new stream.  Mark our side of the pipe to close on
	   exec, so new children won't see it */
	close( pipedes[ STDOUT_FILENO ] );
	fcntl( pipedes[ STDIN_FILENO ], F_SETFD, FD_CLOEXEC );
	stream = fdopen( pipedes[ STDIN_FILENO ], "r" );
	if( stream == NULL )
		{
		int savedErrno = errno;

		/* The stream couldn't be opened or the child structure couldn't be
		   allocated.  Kill the child and close the other side of the pipe */
		kill( entry->pid, SIGKILL );
		close( pipedes[ STDOUT_FILENO ] );
		waitpid( entry->pid, NULL, 0 );
		entry->pid = 0;
		errno = savedErrno;
		return( NULL );
		}

	return( stream );
	}

static int my_pclose( struct RI *entry, struct rusage *rusage )
	{
	pid_t pid;
	int status = 0;

	/* Close the pipe */
	fclose( entry->pipe );
	entry->pipe = NULL;

	/* Wait for the child to terminate, ignoring the return value from the
	   process because some programs return funny values that would result
	   in the input being discarded even if they executed successfully.
	   This isn't a problem because the result data size threshold will
	   filter out any programs that exit with a usage message without
	   producing useful output */
	do
		/* We use wait4() instead of waitpid() to get the last bit of
		   entropy data, the resource usage of the child */
		pid = wait4( entry->pid, NULL, 0, rusage );
	while( pid == -1 && errno == EINTR );
	if( pid != entry->pid )
		status = -1;
	entry->pid = 0;
	return( status );
	}

/* Unix fast poll - not terribly useful */

#if defined( __hpux ) && ( OSVERSION == 0 || OSVERSION == 9 )

/* PHUX 9.x doesn't support getrusage in libc (wonderful...).  The reason we
   check for a version 0 as well as 9 is that some PHUX unames report the
   version as 09 rather than 9, which looks like version 0 when you take the
   first digit */

#include <syscall.h>

static int getrusage( int who, struct rusage *rusage )
	{
	return( syscall( SYS_getrusage, who, rusage ) );
	}
#endif /* __hpux */

/* SCO has a gettimeofday() prototype but no actual system call that
   implements it, and no getrusage() at all, so we use times() instead */

#ifdef _M_XENIX

#include <sys/times.h>
#endif /* _M_XENIX */

void fastPoll( void )
	{
	RANDOM_STATE randomState;
	BYTE buffer[ RANDOM_BUFSIZE ];
#ifndef _M_XENIX
	struct timeval tv;
	struct rusage rusage;
#else
	struct tms tms;
#endif /* _M_XENIX */
#ifdef _AIX
	timebasestruct_t cpuClockInfo;
#endif /* Aches */
#if ( defined( sun ) && ( OSVERSION >= 5 ) )
	hrtime_t hrTime;
#endif /* Slowaris */

	initRandomData( randomState, buffer, RANDOM_BUFSIZE );

	/* Mix in the process ID.  This doesn't change per process but will
	   change if the process forks, ensuring that the parent and child data
	   differs from the parent */
	addRandomValue( randomState, getpid() );

#ifndef _M_XENIX
	gettimeofday( &tv, NULL );
	addRandomValue( randomState, tv.tv_sec );
	addRandomValue( randomState, tv.tv_usec );

	/* SunOS 5.4 has the function call but no prototypes for it, if you're
	   compiling this under 5.4 you'll have to copy the header files from 5.5
	   or something similar */
	getrusage( RUSAGE_SELF, &rusage );
	addRandomData( randomState, &rusage, sizeof( struct rusage ) );
#else
	/* Merely a subset of getrusage(), but it's the best that we can do */
	times( &tms );
	addRandomData( randomState, &tms, sizeof( struct tms ) );
#endif /* _M_XENIX */
#ifdef _AIX
	/* Add the value of the nanosecond-level CPU clock or time base register */
	read_real_time( &cpuClockInfo, sizeof( timebasestruct_t ) );
	addRandomData( randomState, &cpuClockInfo, sizeof( timebasestruct_t ) );
#endif /* _AIX */
#if ( defined( sun ) && ( OSVERSION >= 5 ) )
	/* Read the Sparc %tick register (equivalent to the P5 TSC).  This is
	   only readable by the kernel by default, although Solaris 8 and newer
	   make it readable in user-space.  To do this portably, we use
	   gethrtime(), which does the same thing */
	hrTime = gethrtime();
	addRandomData( randomState, &hrTime, sizeof( hrtime_t ) );
#endif /* Slowaris */

	/* Flush any remaining data through */
	endRandomData( randomState, 0 );
	}

/* Slowaris-specific slow poll using kstat, which provides kernel statistics.
   Since there can be a hundred or more of these, we use a larger-than-usual
   intermediate buffer to cut down on kernel traffic */

#if ( defined( sun ) && ( OSVERSION >= 5 ) )

#define USE_KSTAT
#include <kstat.h>

#define BIG_RANDOM_BUFSIZE	( RANDOM_BUFSIZE * 2 )

static void getKstatData( void )
	{
	kstat_ctl_t *kc;
	kstat_t *ksp;
	RANDOM_STATE randomState;
	BYTE buffer[ BIG_RANDOM_BUFSIZE ];
	int noEntries = 0;

	/* Try and open a kernel stats handle */
	if( ( kc = kstat_open() ) == NULL )
		return;

	initRandomData( randomState, buffer, BIG_RANDOM_BUFSIZE );

	/* Walk down the chain of stats reading each one.  Since some of the
	   stats can be rather lengthy, we optionally send them directly to
	   the randomness pool rather than using the accumulator */
	for( ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next )
		{
		if( kstat_read( kc, ksp, NULL ) == -1 || \
			!ksp->ks_data_size )
			continue;
		addRandomData( randomState, ksp, sizeof( kstat_t ) );
		if( ksp->ks_data_size > BIG_RANDOM_BUFSIZE )
			{
			RESOURCE_DATA msgData;

			setMessageData( &msgData, ksp->ks_data, ksp->ks_data_size );
			krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S,
							 &msgData, CRYPT_IATTRIBUTE_ENTROPY );
			}
		else
			addRandomData( randomState, ksp->ks_data, ksp->ks_data_size );
		noEntries++;
		}
	kstat_close( kc );

	/* Flush any remaining data through and produce an estimate of its
	   value.  We require that we get at least 50 entries and give them a
	   maximum value of 25 to ensure that some data is still coming from
	   other sources */
	endRandomData( randomState, ( noEntries > 50 ) ? 25 : 0 );
	}
#endif /* Slowaris */

/* SYSV /proc interface, which provides assorted information that usually
   has to be obtained the hard way via a slow poll */

#if ( defined( sun ) && ( OSVERSION >= 5 ) ) || defined( __osf__ ) || \
	  defined( __alpha__ ) || defined( __linux__ )

#define USE_PROC
#include <sys/procfs.h>

static void getProcData( void )
	{
#ifdef PIOCSTATUS
	prstatus_t prStatus;
#endif /* PIOCSTATUS */
#ifdef PIOCPSINFO
	prpsinfo_t prMisc;
#endif /* PIOCPSINFO */
#ifdef PIOCUSAGE
	prusage_t prUsage;
#endif /* PIOCUSAGE */
	RANDOM_STATE randomState;
	BYTE buffer[ RANDOM_BUFSIZE ];
	char fileName[ 128 ];
	int fd, noEntries = 0;

	/* Try and open the process info for this process */
	sPrintf( fileName, "/proc/%d", getpid() );
	if( ( fd = open( fileName, O_RDONLY ) ) == -1 )
		return;

	initRandomData( randomState, buffer, RANDOM_BUFSIZE );

	/* Get the process status information, misc information, and resource
	   usage */
#ifdef PIOCSTATUS
	if( ioctl( fd, PIOCSTATUS, &prStatus ) != -1 )
		{
#ifdef DEBUG_RANDOM
		printf( "PIOCSTATUS contributed %d bytes.\n", sizeof( prstatus_t ) );
#endif /* DEBUG_RANDOM */
		addRandomData( randomState, &prStatus, sizeof( prstatus_t ) );
		noEntries++;
		}
#endif /* PIOCSTATUS */
#ifdef PIOCPSINFO
	if( ioctl( fd, PIOCPSINFO, &prMisc ) != -1 )
		{
#ifdef DEBUG_RANDOM
		printf( "PIOCPSINFO contributed %d bytes.\n", sizeof( prpsinfo_t ) );
#endif /* DEBUG_RANDOM */
		addRandomData( randomState, &prMisc, sizeof( prpsinfo_t ) );
		noEntries++;
		}
#endif /* PIOCPSINFO */
#ifdef PIOCUSAGE
	if( ioctl( fd, PIOCUSAGE, &prUsage ) != -1 )
		{
#ifdef DEBUG_RANDOM

⌨️ 快捷键说明

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