There are a couple of issues regarding egd support in OpenSSH.
1) SIGPIPE is not ignored for the master listener daemon. I put
the signal() call early on since it needs to be before
get_random_bytes() is called but it could also be placed in the
EGD version of get_random_bytes(). For some reason, with prngd
I am getting SIGPIPE even though the prngd processes is not
dying. get_random_bytes() also needs to check for EPIPE and
reconnect to the daemon if it gets that.
2) If there are currently SOMAXCONN connections to the entropy
daemon, further ones will return ECONNREFUSED. It seems like
some kind of connect || sleep loop is needed here. I used
usleep() which not all OSes support. I've included the usleep.c
from OpenBSD which uses nanosleep() but since not every OS has
that either, a version using select() should probably be used
when the OS has no nanosleep. Also, the sleep is for only
a total of 1 second before giving up. Perhaps it should be longer.
I've included patches for these at the end of this message.
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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"
#ifndef HAVE_USLEEP
#if defined(LIBC_SCCS) && !defined(lint)
static char rcsid[] = "$OpenBSD: usleep.c,v 1.7 1998/02/08 22:44:09 tholo
Exp $";
#endif /* LIBC_SCCS and not lint */
/* XXX - if no nanosleep() just use select */
int
usleep(useconds)
unsigned int useconds;
{
struct timespec rqt;
if (useconds == 0)
return(0);
rqt.tv_sec = useconds / 1000000;
rqt.tv_nsec = (useconds % 1000000) * 1000;
return(nanosleep(&rqt, NULL));
}
#endif /* !HAVE_USLEEP */
--- sshd.c.DIST Mon Feb 12 07:38:08 2001
+++ sshd.c Mon Feb 12 07:36:18 2001
@@ -505,6 +505,9 @@
/* Initialize configuration options to their default values. */
initialize_server_options(&options);
+ /* Ignore SIGPIPE */
+ signal(SIGPIPE, SIG_IGN);
+
/* Parse command-line arguments. */
while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:diqQ46")) != EOF) {
switch (opt) {
--- entropy.c.DIST Mon Oct 16 03:13:43 2000
+++ entropy.c Mon Feb 12 11:00:53 2001
@@ -69,6 +69,7 @@
char msg[2];
struct sockaddr_un addr;
int addr_len;
+ int i, rval;
/* Sanity checks */
if (sizeof(EGD_SOCKET) > sizeof(addr.sun_path))
@@ -81,13 +82,25 @@
strlcpy(addr.sun_path, EGD_SOCKET, sizeof(addr.sun_path));
addr_len = offsetof(struct sockaddr_un, sun_path) + sizeof(EGD_SOCKET);
+reopen:
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == -1) {
error("Couldn't create AF_UNIX socket: %s", strerror(errno));
return(0);
}
- if (connect(fd, (struct sockaddr*)&addr, addr_len) == -1) {
+ /*
+ * We may get ECONNREFUSED due to small SOMAXCONN in the daemon.
+ * This will retry for at most one second (XXX - longer?)
+ */
+ for (i = 0; i < 1000 &&
+ (rval == connect(fd, (struct sockaddr*)&addr, addr_len)) == -1
&&
+ errno == ECONNREFUSED;
+ i++) {
+ usleep(1000);
+ }
+
+ if (rval == -1) {
error("Couldn't connect to EGD socket \"%s\": %s",
addr.sun_path, strerror(errno));
close(fd);
@@ -99,6 +112,10 @@
msg[1] = len;
if (atomicio(write, fd, msg, sizeof(msg)) != sizeof(msg)) {
+ if (errno == EPIPE) {
+ close(fd);
+ goto reopen;
+ }
error("Couldn't write to EGD socket \"%s\": %s",
EGD_SOCKET, strerror(errno));
close(fd);
@@ -106,6 +123,10 @@
}
if (atomicio(read, fd, buf, len) != len) {
+ if (errno == EPIPE) {
+ close(fd);
+ goto reopen;
+ }
error("Couldn't read from EGD socket \"%s\": %s",
EGD_SOCKET, strerror(errno));
close(fd);