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

📄 ssh-rand-helper.c

📁 OpenSSL Source code for SFTP, SSH, and many others
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2001-2002 Damien Miller.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "includes.h"#include <openssl/rand.h>#include <openssl/sha.h>#include <openssl/crypto.h>/* SunOS 4.4.4 needs this */#ifdef HAVE_FLOATINGPOINT_H# include <floatingpoint.h>#endif /* HAVE_FLOATINGPOINT_H */#include "misc.h"#include "xmalloc.h"#include "atomicio.h"#include "pathnames.h"#include "log.h"RCSID("$Id: ssh-rand-helper.c,v 1.7 2002/06/09 19:41:49 mouring Exp $");/* Number of bytes we write out */#define OUTPUT_SEED_SIZE	48/* Length of on-disk seedfiles */#define SEED_FILE_SIZE		1024/* Maximum number of command-line arguments to read from file */#define NUM_ARGS		10/* Minimum number of usable commands to be considered sufficient */#define MIN_ENTROPY_SOURCES	16/* Path to on-disk seed file (relative to user's home directory */#ifndef SSH_PRNG_SEED_FILE# define SSH_PRNG_SEED_FILE      _PATH_SSH_USER_DIR"/prng_seed"#endif/* Path to PRNG commands list */#ifndef SSH_PRNG_COMMAND_FILE# define SSH_PRNG_COMMAND_FILE   SSHDIR "/ssh_prng_cmds"#endif#ifdef HAVE___PROGNAMEextern char *__progname;#elsechar *__progname;#endif#ifndef offsetof# define offsetof(type, member) ((size_t) &((type *)0)->member)#endif#define WHITESPACE " \t\n"#ifndef RUSAGE_SELF# define RUSAGE_SELF 0#endif#ifndef RUSAGE_CHILDREN# define RUSAGE_CHILDREN 0#endif#if !defined(PRNGD_SOCKET) && !defined(PRNGD_PORT)# define USE_SEED_FILES#endiftypedef struct {	/* Proportion of data that is entropy */	double rate;	/* Counter goes positive if this command times out */	unsigned int badness;	/* Increases by factor of two each timeout */	unsigned int sticky_badness;	/* Path to executable */	char *path;	/* argv to pass to executable */	char *args[NUM_ARGS]; /* XXX: arbitrary limit */	/* full command string (debug) */	char *cmdstring;} entropy_cmd_t;/* slow command timeouts (all in milliseconds) *//* static int entropy_timeout_default = ENTROPY_TIMEOUT_MSEC; */static int entropy_timeout_current = ENTROPY_TIMEOUT_MSEC;/* this is initialised from a file, by prng_read_commands() */static entropy_cmd_t *entropy_cmds = NULL;/* Prototypes */double stir_from_system(void);double stir_from_programs(void);double stir_gettimeofday(double entropy_estimate);double stir_clock(double entropy_estimate);double stir_rusage(int who, double entropy_estimate);double hash_command_output(entropy_cmd_t *src, char *hash);int get_random_bytes_prngd(unsigned char *buf, int len,     unsigned short tcp_port, char *socket_path);/* * Collect 'len' bytes of entropy into 'buf' from PRNGD/EGD daemon * listening either on 'tcp_port', or via Unix domain socket at * * 'socket_path'. * Either a non-zero tcp_port or a non-null socket_path must be  * supplied. * Returns 0 on success, -1 on error */intget_random_bytes_prngd(unsigned char *buf, int len,     unsigned short tcp_port, char *socket_path){	int fd, addr_len, rval, errors;	char msg[2];	struct sockaddr_storage addr;	struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;	struct sockaddr_un *addr_un = (struct sockaddr_un *)&addr;	mysig_t old_sigpipe;	/* Sanity checks */	if (socket_path == NULL && tcp_port == 0)		fatal("You must specify a port or a socket");	if (socket_path != NULL &&	    strlen(socket_path) >= sizeof(addr_un->sun_path))		fatal("Random pool path is too long");	if (len > 255)		fatal("Too many bytes to read from PRNGD");	memset(&addr, '\0', sizeof(addr));	if (tcp_port != 0) {		addr_in->sin_family = AF_INET;		addr_in->sin_addr.s_addr = htonl(INADDR_LOOPBACK);		addr_in->sin_port = htons(tcp_port);		addr_len = sizeof(*addr_in);	} else {		addr_un->sun_family = AF_UNIX;		strlcpy(addr_un->sun_path, socket_path,		    sizeof(addr_un->sun_path));		addr_len = offsetof(struct sockaddr_un, sun_path) +		    strlen(socket_path) + 1;	}	old_sigpipe = mysignal(SIGPIPE, SIG_IGN);	errors = 0;	rval = -1;reopen:	fd = socket(addr.ss_family, SOCK_STREAM, 0);	if (fd == -1) {		error("Couldn't create socket: %s", strerror(errno));		goto done;	}	if (connect(fd, (struct sockaddr*)&addr, addr_len) == -1) {		if (tcp_port != 0) {			error("Couldn't connect to PRNGD port %d: %s",			    tcp_port, strerror(errno));		} else {			error("Couldn't connect to PRNGD socket \"%s\": %s",			    addr_un->sun_path, strerror(errno));		}		goto done;	}	/* Send blocking read request to PRNGD */	msg[0] = 0x02;	msg[1] = len;	if (atomicio(write, fd, msg, sizeof(msg)) != sizeof(msg)) {		if (errno == EPIPE && errors < 10) {			close(fd);			errors++;			goto reopen;		}		error("Couldn't write to PRNGD socket: %s",		    strerror(errno));		goto done;	}	if (atomicio(read, fd, buf, len) != len) {		if (errno == EPIPE && errors < 10) {			close(fd);			errors++;			goto reopen;		}		error("Couldn't read from PRNGD socket: %s",		    strerror(errno));		goto done;	}	rval = 0;done:	mysignal(SIGPIPE, old_sigpipe);	if (fd != -1)		close(fd);	return rval;}doublestir_gettimeofday(double entropy_estimate){	struct timeval tv;	if (gettimeofday(&tv, NULL) == -1)		fatal("Couldn't gettimeofday: %s", strerror(errno));	RAND_add(&tv, sizeof(tv), entropy_estimate);	return entropy_estimate;}doublestir_clock(double entropy_estimate){#ifdef HAVE_CLOCK	clock_t c;	c = clock();	RAND_add(&c, sizeof(c), entropy_estimate);	return entropy_estimate;#else /* _HAVE_CLOCK */	return 0;#endif /* _HAVE_CLOCK */}doublestir_rusage(int who, double entropy_estimate){#ifdef HAVE_GETRUSAGE	struct rusage ru;	if (getrusage(who, &ru) == -1)		return 0;	RAND_add(&ru, sizeof(ru), entropy_estimate);	return entropy_estimate;#else /* _HAVE_GETRUSAGE */	return 0;#endif /* _HAVE_GETRUSAGE */}static inttimeval_diff(struct timeval *t1, struct timeval *t2){	int secdiff, usecdiff;	secdiff = t2->tv_sec - t1->tv_sec;	usecdiff = (secdiff*1000000) + (t2->tv_usec - t1->tv_usec);	return (int)(usecdiff / 1000);}doublehash_command_output(entropy_cmd_t *src, char *hash){	char buf[8192];	fd_set rdset;	int bytes_read, cmd_eof, error_abort, msec_elapsed, p[2];	int status, total_bytes_read;	static int devnull = -1;	pid_t pid;	SHA_CTX sha;	struct timeval tv_start, tv_current;	debug3("Reading output from \'%s\'", src->cmdstring);	if (devnull == -1) {		devnull = open("/dev/null", O_RDWR);		if (devnull == -1)			fatal("Couldn't open /dev/null: %s", 			    strerror(errno));	}	if (pipe(p) == -1)		fatal("Couldn't open pipe: %s", strerror(errno));	(void)gettimeofday(&tv_start, NULL); /* record start time */	switch (pid = fork()) {		case -1: /* Error */			close(p[0]);			close(p[1]);			fatal("Couldn't fork: %s", strerror(errno));			/* NOTREACHED */		case 0: /* Child */			dup2(devnull, STDIN_FILENO);			dup2(p[1], STDOUT_FILENO);			dup2(p[1], STDERR_FILENO);			close(p[0]);			close(p[1]);			close(devnull);			execv(src->path, (char**)(src->args));			debug("(child) Couldn't exec '%s': %s", 			    src->cmdstring, strerror(errno));			_exit(-1);		default: /* Parent */			break;	}	RAND_add(&pid, sizeof(&pid), 0.0);	close(p[1]);	/* Hash output from child */	SHA1_Init(&sha);	cmd_eof = error_abort = msec_elapsed = total_bytes_read = 0;	while (!error_abort && !cmd_eof) {		int ret;		struct timeval tv;		int msec_remaining;		(void) gettimeofday(&tv_current, 0);		msec_elapsed = timeval_diff(&tv_start, &tv_current);		if (msec_elapsed >= entropy_timeout_current) {			error_abort=1;			continue;		}		msec_remaining = entropy_timeout_current - msec_elapsed;		FD_ZERO(&rdset);		FD_SET(p[0], &rdset);		tv.tv_sec = msec_remaining / 1000;		tv.tv_usec = (msec_remaining % 1000) * 1000;		ret = select(p[0] + 1, &rdset, NULL, NULL, &tv);		RAND_add(&tv, sizeof(tv), 0.0);		switch (ret) {		case 0:			/* timer expired */			error_abort = 1;			break;		case 1:			/* command input */			do {				bytes_read = read(p[0], buf, sizeof(buf));			} while (bytes_read == -1 && errno == EINTR);			RAND_add(&bytes_read, sizeof(&bytes_read), 0.0);			if (bytes_read == -1) {				error_abort = 1;				break;			} else if (bytes_read) {				SHA1_Update(&sha, buf, bytes_read);				total_bytes_read += bytes_read;			} else {				cmd_eof = 1;			}			break;		case -1:		default:			/* error */			debug("Command '%s': select() failed: %s", 			    src->cmdstring, strerror(errno));			error_abort = 1;			break;		}	}	SHA1_Final(hash, &sha);	close(p[0]);	debug3("Time elapsed: %d msec", msec_elapsed);	if (waitpid(pid, &status, 0) == -1) {	       error("Couldn't wait for child '%s' completion: %s",		   src->cmdstring, strerror(errno));		return 0.0;	}	RAND_add(&status, sizeof(&status), 0.0);	if (error_abort) {		/*		 * Closing p[0] on timeout causes the entropy command to		 * SIGPIPE. Take whatever output we got, and mark this 		 * command as slow 		 */		debug2("Command '%s' timed out", src->cmdstring);		src->sticky_badness *= 2;		src->badness = src->sticky_badness;		return total_bytes_read;	}	if (WIFEXITED(status)) {		if (WEXITSTATUS(status) == 0) {			return total_bytes_read;		} else {			debug2("Command '%s' exit status was %d",			    src->cmdstring, WEXITSTATUS(status));			src->badness = src->sticky_badness = 128;			return 0.0;		}	} else if (WIFSIGNALED(status)) {		debug2("Command '%s' returned on uncaught signal %d !",		    src->cmdstring, status);		src->badness = src->sticky_badness = 128;		return 0.0;	} else		return 0.0;}doublestir_from_system(void){	double total_entropy_estimate;

⌨️ 快捷键说明

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