# HG changeset patch
# Parent  8d9c1b5cd95ca4e688155323c87f8ced96f53cfa
# extended support for (re-)seeding the OpenSSL PRNG from /dev/random
# bnc#703221, FATE#312172

diff --git a/openssh-6.6p1/audit-bsm.c b/openssh-6.6p1/audit-bsm.c
--- a/openssh-6.6p1/audit-bsm.c
+++ b/openssh-6.6p1/audit-bsm.c
@@ -504,9 +504,15 @@ audit_destroy_sensitive_data(const char 
 	/* not implemented */
 }
 
 void
 audit_generate_ephemeral_server_key(const char *fp)
 {
 	/* not implemented */
 }
+
+void
+audit_linux_prng_seed(long bytes, const char *rf)
+{
+	/* not implemented */
+}
 #endif /* BSM */
diff --git a/openssh-6.6p1/audit-linux.c b/openssh-6.6p1/audit-linux.c
--- a/openssh-6.6p1/audit-linux.c
+++ b/openssh-6.6p1/audit-linux.c
@@ -395,9 +395,31 @@ audit_generate_ephemeral_server_key(cons
 	}
 	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER,
 			buf, NULL, 0, NULL, 1);
 	audit_close(audit_fd);
 	/* do not abort if the error is EPERM and sshd is run as non root user */
 	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
 		error("cannot write into audit");
 }
+
+void
+audit_linux_prng_seed(long bytes, const char *rf)
+{
+	char buf[AUDIT_LOG_SIZE];
+	int audit_fd, audit_ok;
+
+	snprintf(buf, sizeof(buf), "op=prng_seed kind=server bytes=%li source=%s ", bytes, rf);
+	audit_fd = audit_open();
+	if (audit_fd < 0) {
+		if (errno != EINVAL && errno != EPROTONOSUPPORT &&
+					 errno != EAFNOSUPPORT)
+			error("cannot open audit");
+		return;
+	}
+	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_PARAM_CHANGE_USER,
+			buf, NULL, 0, NULL, 1);
+	audit_close(audit_fd);
+	/* do not abort if the error is EPERM and sshd is run as non root user */
+	if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
+		error("cannot write into audit");
+}
 #endif /* USE_LINUX_AUDIT */
diff --git a/openssh-6.6p1/audit.c b/openssh-6.6p1/audit.c
--- a/openssh-6.6p1/audit.c
+++ b/openssh-6.6p1/audit.c
@@ -304,10 +304,16 @@ audit_destroy_sensitive_data(const char 
 /*
  * This will be called on generation of the ephemeral server key
  */
 void
 audit_generate_ephemeral_server_key(const char *)
 {
 	debug("audit create ephemeral server key euid %d fingerprint %s", geteuid(), fp);
 }
+
+void
+audit_linux_prng_seed(long bytes, const char *rf)
+{
+	debug("audit PRNG seed euid %d bytes %li source %s", geteuid(), bytes, rf);
+}
 # endif  /* !defined CUSTOM_SSH_AUDIT_EVENTS */
 #endif /* SSH_AUDIT_EVENTS */
diff --git a/openssh-6.6p1/audit.h b/openssh-6.6p1/audit.h
--- a/openssh-6.6p1/audit.h
+++ b/openssh-6.6p1/audit.h
@@ -61,10 +61,11 @@ void	audit_key(int, int *, const Key *);
 void	audit_unsupported(int);
 void	audit_kex(int, char *, char *, char *);
 void	audit_unsupported_body(int);
 void	audit_kex_body(int, char *, char *, char *, pid_t, uid_t);
 void	audit_session_key_free(int ctos);
 void	audit_session_key_free_body(int ctos, pid_t, uid_t);
 void	audit_destroy_sensitive_data(const char *, pid_t, uid_t);
 void	audit_generate_ephemeral_server_key(const char *);
+void	audit_linux_prng_seed(long, const char *);
 
 #endif /* _SSH_AUDIT_H */
diff --git a/openssh-6.6p1/entropy.c b/openssh-6.6p1/entropy.c
--- a/openssh-6.6p1/entropy.c
+++ b/openssh-6.6p1/entropy.c
@@ -45,16 +45,17 @@
 
 #include "ssh.h"
 #include "misc.h"
 #include "xmalloc.h"
 #include "atomicio.h"
 #include "pathnames.h"
 #include "log.h"
 #include "buffer.h"
+#include "openbsd-compat/port-linux.h"
 
 /*
  * Portable OpenSSH PRNG seeding:
  * If OpenSSL has not "internally seeded" itself (e.g. pulled data from
  * /dev/random), then collect RANDOM_SEED_SIZE bytes of randomness from
  * PRNGd.
  */
 #ifndef OPENSSL_PRNG_ONLY
@@ -229,11 +230,14 @@ seed_rng(void)
 	}
 
 	if (seed_from_prngd(buf, sizeof(buf)) == -1)
 		fatal("Could not obtain seed from PRNGd");
 	RAND_add(buf, sizeof(buf), sizeof(buf));
 	memset(buf, '\0', sizeof(buf));
 
 #endif /* OPENSSL_PRNG_ONLY */
+
+	linux_seed();
+
 	if (RAND_status() != 1)
 		fatal("PRNG is not seeded");
 }
diff --git a/openssh-6.6p1/openbsd-compat/Makefile.in b/openssh-6.6p1/openbsd-compat/Makefile.in
--- a/openssh-6.6p1/openbsd-compat/Makefile.in
+++ b/openssh-6.6p1/openbsd-compat/Makefile.in
@@ -15,17 +15,17 @@ AR=@AR@
 RANLIB=@RANLIB@
 INSTALL=@INSTALL@
 LDFLAGS=-L. @LDFLAGS@
 
 OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o dirname.o fmt_scaled.o getcwd.o getgrouplist.o getopt_long.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o pwcache.o readpassphrase.o realpath.o rresvport.o setenv.o setproctitle.o sha2.o sigact.o strlcat.o strlcpy.o strmode.o strnlen.o strptime.o strsep.o strtonum.o strtoll.o strtoul.o strtoull.o timingsafe_bcmp.o vis.o blowfish.o bcrypt_pbkdf.o explicit_bzero.o
 
 COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o
 
-PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o
+PORTS=port-aix.o port-irix.o port-linux.o port-linux-prng.o port-solaris.o port-tun.o port-uw.o
 
 .c.o:
 	$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
 
 all: libopenbsd-compat.a
 
 $(COMPAT): ../config.h
 $(OPENBSD): ../config.h
diff --git a/openssh-6.6p1/openbsd-compat/port-linux-prng.c b/openssh-6.6p1/openbsd-compat/port-linux-prng.c
new file mode 100644
--- /dev/null
+++ b/openssh-6.6p1/openbsd-compat/port-linux-prng.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2011 Jan F. Chadima <jchadima@redhat.com>
+ *           (c) 2011 Petr Cerny <pcerny@suse.cz>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Linux-specific portability code - prng support
+ */
+
+#include "includes.h"
+#include "defines.h"
+
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <openssl/rand.h>
+
+#include "log.h"
+#include "port-linux.h"
+#include "audit.h"
+
+#define RNG_BYTES_DEFAULT	6L
+#define RNG_ENV_VAR			"SSH_USE_STRONG_RNG"
+
+long rand_bytes = 0;
+char *rand_file = NULL;
+
+static void
+linux_seed_init(void)
+{
+	long elen = 0;
+	char *env = getenv(RNG_ENV_VAR);
+
+	if (env) {
+		errno = 0;
+		elen = strtol(env, NULL, 10);
+		if (errno) {
+			debug("bogus value in the %s environment variable, using default %li\n",
+				RNG_ENV_VAR, RNG_BYTES_DEFAULT);
+		}
+	}
+
+	if (elen)
+		rand_file = "/dev/random";
+	else
+		rand_file = "/dev/urandom";
+
+	rand_bytes = MAX(elen, RNG_BYTES_DEFAULT);
+}
+
+void
+linux_seed(void)
+{
+	long len;
+	if (!rand_file)
+		linux_seed_init();
+
+	errno = 0;
+	len = RAND_load_file(rand_file, rand_bytes);
+	if (len != rand_bytes) {
+		if (errno)
+			fatal ("cannot read from %s, %s", random, strerror(errno));
+		else
+			fatal ("EOF reading %s", random);
+	}
+}
diff --git a/openssh-6.6p1/openbsd-compat/port-linux.h b/openssh-6.6p1/openbsd-compat/port-linux.h
--- a/openssh-6.6p1/openbsd-compat/port-linux.h
+++ b/openssh-6.6p1/openbsd-compat/port-linux.h
@@ -14,16 +14,20 @@
  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #ifndef _PORT_LINUX_H
 #define _PORT_LINUX_H
 
+extern long rand_bytes;
+extern char *rand_file;
+void linux_seed(void);
+
 #ifdef WITH_SELINUX
 int ssh_selinux_enabled(void);
 void ssh_selinux_setup_pty(char *, const char *);
 void ssh_selinux_setup_exec_context(char *);
 void ssh_selinux_change_context(const char *);
 void ssh_selinux_setfscreatecon(const char *);
 #endif
 
diff --git a/openssh-6.6p1/ssh-add.1 b/openssh-6.6p1/ssh-add.1
--- a/openssh-6.6p1/ssh-add.1
+++ b/openssh-6.6p1/ssh-add.1
@@ -156,16 +156,30 @@ or related script.
 (Note that on some machines it
 may be necessary to redirect the input from
 .Pa /dev/null
 to make this work.)
 .It Ev SSH_AUTH_SOCK
 Identifies the path of a
 .Ux Ns -domain
 socket used to communicate with the agent.
+.It Ev SSH_USE_STRONG_RNG
+The reseeding of the OpenSSL random generator is usually done from
+.Cm /dev/urandom .
+If the 
+.Cm SSH_USE_STRONG_RNG
+environment variable is set to value other than
+.Cm 0
+the OpenSSL random generator is reseeded from
+.Cm /dev/random .
+The number of bytes read is defined by the SSH_USE_STRONG_RNG value. 
+Minimum is 6 bytes.
+This setting is not recommended on the computers without the hardware
+random generator because insufficient entropy causes the connection to 
+be blocked until enough entropy is available.
 .El
 .Sh FILES
 .Bl -tag -width Ds
 .It Pa ~/.ssh/identity
 Contains the protocol version 1 RSA authentication identity of the user.
 .It Pa ~/.ssh/id_dsa
 Contains the protocol version 2 DSA authentication identity of the user.
 .It Pa ~/.ssh/id_ecdsa
diff --git a/openssh-6.6p1/ssh-agent.1 b/openssh-6.6p1/ssh-agent.1
--- a/openssh-6.6p1/ssh-agent.1
+++ b/openssh-6.6p1/ssh-agent.1
@@ -196,16 +196,33 @@ Contains the protocol version 2 ED25519 
 .It Pa ~/.ssh/id_rsa
 Contains the protocol version 2 RSA authentication identity of the user.
 .It Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt
 .Ux Ns -domain
 sockets used to contain the connection to the authentication agent.
 These sockets should only be readable by the owner.
 The sockets should get automatically removed when the agent exits.
 .El
+.Sh ENVIRONMENT
+.Bl -tag -width Ds -compact
+.Pp
+.It Pa SSH_USE_STRONG_RNG
+The reseeding of the OpenSSL random generator is usually done from
+.Cm /dev/urandom .
+If the 
+.Cm SSH_USE_STRONG_RNG
+environment variable is set to value other than
+.Cm 0
+the OpenSSL random generator is reseeded from
+.Cm /dev/random .
+The number of bytes read is defined by the SSH_USE_STRONG_RNG value. 
+Minimum is 6 bytes.
+This setting is not recommended on the computers without the hardware
+random generator because insufficient entropy causes the connection to 
+be blocked until enough entropy is available.
 .Sh SEE ALSO
 .Xr ssh 1 ,
 .Xr ssh-add 1 ,
 .Xr ssh-keygen 1 ,
 .Xr sshd 8
 .Sh AUTHORS
 OpenSSH is a derivative of the original and free
 ssh 1.2.12 release by Tatu Ylonen.
diff --git a/openssh-6.6p1/ssh-keygen.1 b/openssh-6.6p1/ssh-keygen.1
--- a/openssh-6.6p1/ssh-keygen.1
+++ b/openssh-6.6p1/ssh-keygen.1
@@ -827,16 +827,33 @@ on all machines
 where the user wishes to log in using public key authentication.
 There is no need to keep the contents of this file secret.
 .Pp
 .It Pa /etc/moduli
 Contains Diffie-Hellman groups used for DH-GEX.
 The file format is described in
 .Xr moduli 5 .
 .El
+.Sh ENVIRONMENT
+.Bl -tag -width Ds -compact
+.Pp
+.It Pa SSH_USE_STRONG_RNG
+The reseeding of the OpenSSL random generator is usually done from
+.Cm /dev/urandom .
+If the 
+.Cm SSH_USE_STRONG_RNG
+environment variable is set to value other than
+.Cm 0
+the OpenSSL random generator is reseeded from
+.Cm /dev/random .
+The number of bytes read is defined by the SSH_USE_STRONG_RNG value. 
+Minimum is 6 bytes.
+This setting is not recommended on the computers without the hardware
+random generator because insufficient entropy causes the connection to 
+be blocked until enough entropy is available.
 .Sh SEE ALSO
 .Xr ssh 1 ,
 .Xr ssh-add 1 ,
 .Xr ssh-agent 1 ,
 .Xr moduli 5 ,
 .Xr sshd 8
 .Rs
 .%R RFC 4716
diff --git a/openssh-6.6p1/ssh-keysign.8 b/openssh-6.6p1/ssh-keysign.8
--- a/openssh-6.6p1/ssh-keysign.8
+++ b/openssh-6.6p1/ssh-keysign.8
@@ -75,16 +75,33 @@ must be set-uid root if host-based authe
 .Pp
 .It Pa /etc/ssh/ssh_host_dsa_key-cert.pub
 .It Pa /etc/ssh/ssh_host_ecdsa_key-cert.pub
 .It Pa /etc/ssh/ssh_host_ed25519_key-cert.pub
 .It Pa /etc/ssh/ssh_host_rsa_key-cert.pub
 If these files exist they are assumed to contain public certificate
 information corresponding with the private keys above.
 .El
+.Sh ENVIRONMENT
+.Bl -tag -width Ds -compact
+.Pp
+.It Pa SSH_USE_STRONG_RNG
+The reseeding of the OpenSSL random generator is usually done from
+.Cm /dev/urandom .
+If the 
+.Cm SSH_USE_STRONG_RNG
+environment variable is set to value other than
+.Cm 0
+the OpenSSL random generator is reseeded from
+.Cm /dev/random .
+The number of bytes read is defined by the SSH_USE_STRONG_RNG value. 
+Minimum is 6 bytes.
+This setting is not recommended on the computers without the hardware
+random generator because insufficient entropy causes the connection to 
+be blocked until enough entropy is available.
 .Sh SEE ALSO
 .Xr ssh 1 ,
 .Xr ssh-keygen 1 ,
 .Xr ssh_config 5 ,
 .Xr sshd 8
 .Sh HISTORY
 .Nm
 first appeared in
diff --git a/openssh-6.6p1/ssh.1 b/openssh-6.6p1/ssh.1
--- a/openssh-6.6p1/ssh.1
+++ b/openssh-6.6p1/ssh.1
@@ -1304,16 +1304,30 @@ reads
 and adds lines of the format
 .Dq VARNAME=value
 to the environment if the file exists and users are allowed to
 change their environment.
 For more information, see the
 .Cm PermitUserEnvironment
 option in
 .Xr sshd_config 5 .
+.It Ev SSH_USE_STRONG_RNG
+The reseeding of the OpenSSL random generator is usually done from
+.Cm /dev/urandom .
+If the 
+.Cm SSH_USE_STRONG_RNG
+environment variable is set to value other than
+.Cm 0
+the OpenSSL random generator is reseeded from
+.Cm /dev/random .
+The number of bytes read is defined by the SSH_USE_STRONG_RNG value. 
+Minimum is 6 bytes.
+This setting is not recommended on the computers without the hardware
+random generator because insufficient entropy causes the connection to 
+be blocked until enough entropy is available.
 .Sh FILES
 .Bl -tag -width Ds -compact
 .It Pa ~/.rhosts
 This file is used for host-based authentication (see above).
 On some machines this file may need to be
 world-readable if the user's home directory is on an NFS partition,
 because
 .Xr sshd 8
diff --git a/openssh-6.6p1/sshd.8 b/openssh-6.6p1/sshd.8
--- a/openssh-6.6p1/sshd.8
+++ b/openssh-6.6p1/sshd.8
@@ -946,16 +946,33 @@ and not group or world-writable.
 .It Pa /var/run/sshd.pid
 Contains the process ID of the
 .Nm
 listening for connections (if there are several daemons running
 concurrently for different ports, this contains the process ID of the one
 started last).
 The content of this file is not sensitive; it can be world-readable.
 .El
+.Sh ENVIRONMENT
+.Bl -tag -width Ds -compact
+.Pp
+.It Pa SSH_USE_STRONG_RNG
+The reseeding of the OpenSSL random generator is usually done from
+.Cm /dev/urandom .
+If the 
+.Cm SSH_USE_STRONG_RNG
+environment variable is set to value other than
+.Cm 0
+the OpenSSL random generator is reseeded from
+.Cm /dev/random .
+The number of bytes read is defined by the SSH_USE_STRONG_RNG value. 
+Minimum is 6 bytes.
+This setting is not recommended on the computers without the hardware
+random generator because insufficient entropy causes the connection to 
+be blocked until enough entropy is available.
 .Sh SEE ALSO
 .Xr scp 1 ,
 .Xr sftp 1 ,
 .Xr ssh 1 ,
 .Xr ssh-add 1 ,
 .Xr ssh-agent 1 ,
 .Xr ssh-keygen 1 ,
 .Xr ssh-keyscan 1 ,
diff --git a/openssh-6.6p1/sshd.c b/openssh-6.6p1/sshd.c
--- a/openssh-6.6p1/sshd.c
+++ b/openssh-6.6p1/sshd.c
@@ -50,16 +50,18 @@
 #ifdef HAVE_SYS_STAT_H
 # include <sys/stat.h>
 #endif
 #ifdef HAVE_SYS_TIME_H
 # include <sys/time.h>
 #endif
 #include "openbsd-compat/sys-tree.h"
 #include "openbsd-compat/sys-queue.h"
+#include "openbsd-compat/port-linux.h"
+
 #include <sys/wait.h>
 
 #include <errno.h>
 #include <fcntl.h>
 #include <netdb.h>
 #ifdef HAVE_PATHS_H
 #include <paths.h>
 #endif
@@ -218,16 +220,23 @@ struct {
 	Key	**host_pubkeys;		/* all public host keys */
 	Key	**host_certificates;	/* all public host certificates */
 	int	have_ssh1_key;
 	int	have_ssh2_key;
 	u_char	ssh1_cookie[SSH_SESSION_KEY_LENGTH];
 } sensitive_data;
 
 /*
+ * Every RESEED_AFTERth connection triggers call to linux_seed() to re-seed the
+ * random pool.
+ */
+#define RESEED_AFTER    100
+static int re_seeding_counter = RESEED_AFTER;
+
+/*
  * Flag indicating whether the RSA server key needs to be regenerated.
  * Is set in the SIGALRM handler and cleared when the key is regenerated.
  */
 static volatile sig_atomic_t key_do_regen = 0;
 
 /* This is set to true when a signal is received. */
 static volatile sig_atomic_t received_sighup = 0;
 static volatile sig_atomic_t received_sigterm = 0;
@@ -1321,16 +1330,23 @@ server_accept_loop(int *sock_in, int *so
 			for (j = 0; j < options.max_startups; j++)
 				if (startup_pipes[j] == -1) {
 					startup_pipes[j] = startup_p[0];
 					if (maxfd < startup_p[0])
 						maxfd = startup_p[0];
 					startups++;
 					break;
 				}
+#ifdef SSH_AUDIT_EVENTS
+			if(!(--re_seeding_counter)) {
+				re_seeding_counter = RESEED_AFTER;
+				linux_seed();
+				audit_linux_prng_seed(rand_bytes, rand_file);
+			}
+#endif
 
 			/*
 			 * Got connection.  Fork a child to handle it, unless
 			 * we are in debugging mode.
 			 */
 			if (debug_flag) {
 				/*
 				 * In debugging mode.  Close the listening
