summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.bin/ssh/servconf.c12
-rw-r--r--usr.bin/ssh/servconf.h5
-rw-r--r--usr.bin/ssh/session.c6
-rw-r--r--usr.bin/ssh/sshd.810
-rw-r--r--usr.bin/ssh/sshd.c165
5 files changed, 139 insertions, 59 deletions
diff --git a/usr.bin/ssh/servconf.c b/usr.bin/ssh/servconf.c
index 12cc15260f6..b8481319a3f 100644
--- a/usr.bin/ssh/servconf.c
+++ b/usr.bin/ssh/servconf.c
@@ -12,7 +12,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: servconf.c,v 1.45 2000/06/20 01:39:44 markus Exp $");
+RCSID("$OpenBSD: servconf.c,v 1.46 2000/06/26 21:59:18 markus Exp $");
#include "ssh.h"
#include "servconf.h"
@@ -76,6 +76,7 @@ initialize_server_options(ServerOptions *options)
options->protocol = SSH_PROTO_UNKNOWN;
options->gateway_ports = -1;
options->num_subsystems = 0;
+ options->max_startups = -1;
}
void
@@ -159,6 +160,8 @@ fill_default_server_options(ServerOptions *options)
options->protocol = SSH_PROTO_1|SSH_PROTO_2;
if (options->gateway_ports == -1)
options->gateway_ports = 0;
+ if (options->max_startups == -1)
+ options->max_startups = 10;
}
#define WHITESPACE " \t\r\n="
@@ -183,7 +186,7 @@ typedef enum {
sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile,
- sGatewayPorts, sDSAAuthentication, sXAuthLocation, sSubsystem
+ sGatewayPorts, sDSAAuthentication, sXAuthLocation, sSubsystem, sMaxStartups
} ServerOpCodes;
/* Textual representation of the tokens. */
@@ -239,6 +242,7 @@ static struct {
{ "protocol", sProtocol },
{ "gatewayports", sGatewayPorts },
{ "subsystem", sSubsystem },
+ { "maxstartups", sMaxStartups },
{ NULL, 0 }
};
@@ -638,6 +642,10 @@ parse_flag:
options->num_subsystems++;
break;
+ case sMaxStartups:
+ intptr = &options->max_startups;
+ goto parse_int;
+
default:
fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n",
filename, linenum, cp, opcode);
diff --git a/usr.bin/ssh/servconf.h b/usr.bin/ssh/servconf.h
index c698bc74eac..95593722dd9 100644
--- a/usr.bin/ssh/servconf.h
+++ b/usr.bin/ssh/servconf.h
@@ -13,7 +13,7 @@
*
*/
-/* RCSID("$OpenBSD: servconf.h,v 1.25 2000/06/20 01:39:44 markus Exp $"); */
+/* RCSID("$OpenBSD: servconf.h,v 1.26 2000/06/26 21:59:18 markus Exp $"); */
#ifndef SERVCONF_H
#define SERVCONF_H
@@ -99,6 +99,9 @@ typedef struct {
unsigned int num_subsystems;
char *subsystem_name[MAX_SUBSYSTEMS];
char *subsystem_command[MAX_SUBSYSTEMS];
+
+ int max_startups;
+
} ServerOptions;
/*
* Initializes the server options to special values that indicate that they
diff --git a/usr.bin/ssh/session.c b/usr.bin/ssh/session.c
index fbf515880bd..a7cf187ad06 100644
--- a/usr.bin/ssh/session.c
+++ b/usr.bin/ssh/session.c
@@ -8,7 +8,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.20 2000/06/18 04:42:54 markus Exp $");
+RCSID("$OpenBSD: session.c,v 1.21 2000/06/26 21:59:18 markus Exp $");
#include "xmalloc.h"
#include "ssh.h"
@@ -73,6 +73,8 @@ extern char *__progname;
extern int log_stderr;
extern int debug_flag;
+extern int startup_pipe;
+
/* Local Xauthority file. */
static char *xauthfile;
@@ -145,6 +147,7 @@ do_authenticated(struct passwd * pw)
* authentication.
*/
alarm(0);
+ close(startup_pipe);
/*
* Inform the channel mechanism that we are the server side and that
@@ -1560,6 +1563,7 @@ do_authenticated2(void)
* authentication.
*/
alarm(0);
+ close(startup_pipe);
server_loop2();
if (xauthfile)
xauthfile_cleanup_proc(NULL);
diff --git a/usr.bin/ssh/sshd.8 b/usr.bin/ssh/sshd.8
index bcaac4f2466..516247bd7d9 100644
--- a/usr.bin/ssh/sshd.8
+++ b/usr.bin/ssh/sshd.8
@@ -9,7 +9,7 @@
.\"
.\" Created: Sat Apr 22 21:55:14 1995 ylo
.\"
-.\" $Id: sshd.8,v 1.54 2000/06/17 22:52:34 jakob Exp $
+.\" $Id: sshd.8,v 1.55 2000/06/26 21:59:18 markus Exp $
.\"
.Dd September 25, 1999
.Dt SSHD 8
@@ -435,6 +435,14 @@ QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
The default is INFO.
Logging with level DEBUG violates the privacy of users
and is not recommended.
+.It Cm MaxStartups
+Specifies the maximum number of concurrent unauthenticated connections to the
+.Nm
+daemon.
+Additional connections will be dropped until authentication succeeds or the
+.Cm LoginGraceTime
+expires for a connection.
+The default is 10.
.It Cm PasswordAuthentication
Specifies whether password authentication is allowed.
The default is
diff --git a/usr.bin/ssh/sshd.c b/usr.bin/ssh/sshd.c
index c330c96b638..a224ac468c0 100644
--- a/usr.bin/ssh/sshd.c
+++ b/usr.bin/ssh/sshd.c
@@ -14,7 +14,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.119 2000/06/22 16:32:27 markus Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.120 2000/06/26 21:59:18 markus Exp $");
#include "xmalloc.h"
#include "rsa.h"
@@ -395,6 +395,9 @@ destroy_sensitive_data(void)
key_free(sensitive_data.dsa_host_key);
}
+int *startup_pipes = NULL; /* options.max_startup sized array of fd ints */
+int startup_pipe; /* in child */
+
/*
* Main program for the daemon.
*/
@@ -403,7 +406,7 @@ main(int ac, char **av)
{
extern char *optarg;
extern int optind;
- int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, on = 1;
+ int opt, sock_in = 0, sock_out = 0, newsock, j, i, fdsetsz, on = 1;
pid_t pid;
socklen_t fromlen;
int silent = 0;
@@ -416,6 +419,8 @@ main(int ac, char **av)
struct addrinfo *ai;
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
int listen_sock, maxfd;
+ int startup_p[2];
+ int startups = 0;
/* Save argv[0]. */
saved_argv = av;
@@ -737,6 +742,7 @@ main(int ac, char **av)
/* Arrange to restart on SIGHUP. The handler needs listen_sock. */
signal(SIGHUP, sighup_handler);
+
signal(SIGTERM, sigterm_handler);
signal(SIGQUIT, sigterm_handler);
@@ -744,12 +750,15 @@ main(int ac, char **av)
signal(SIGCHLD, main_sigchld_handler);
/* setup fd set for listen */
+ fdset = NULL;
maxfd = 0;
for (i = 0; i < num_listen_socks; i++)
if (listen_socks[i] > maxfd)
maxfd = listen_socks[i];
- fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
- fdset = (fd_set *)xmalloc(fdsetsz);
+ /* pipes connected to unauthenticated childs */
+ startup_pipes = xmalloc(options.max_startups * sizeof(int));
+ for (i = 0; i < options.max_startups; i++)
+ startup_pipes[i] = -1;
/*
* Stay listening for connections until the system crashes or
@@ -758,80 +767,128 @@ main(int ac, char **av)
for (;;) {
if (received_sighup)
sighup_restart();
- /* Wait in select until there is a connection. */
+ if (fdset != NULL)
+ xfree(fdset);
+ fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
+ fdset = (fd_set *)xmalloc(fdsetsz);
memset(fdset, 0, fdsetsz);
+
for (i = 0; i < num_listen_socks; i++)
FD_SET(listen_socks[i], fdset);
+ for (i = 0; i < options.max_startups; i++)
+ if (startup_pipes[i] != -1)
+ FD_SET(startup_pipes[i], fdset);
+
+ /* Wait in select until there is a connection. */
if (select(maxfd + 1, fdset, NULL, NULL, NULL) < 0) {
if (errno != EINTR)
error("select: %.100s", strerror(errno));
continue;
}
+ for (i = 0; i < options.max_startups; i++)
+ if (startup_pipes[i] != -1 &&
+ FD_ISSET(startup_pipes[i], fdset)) {
+ /*
+ * the read end of the pipe is ready
+ * if the child has closed the pipe
+ * after successfull authentication
+ * or if the child has died
+ */
+ close(startup_pipes[i]);
+ startup_pipes[i] = -1;
+ startups--;
+ }
for (i = 0; i < num_listen_socks; i++) {
if (!FD_ISSET(listen_socks[i], fdset))
continue;
- fromlen = sizeof(from);
- newsock = accept(listen_socks[i], (struct sockaddr *)&from,
- &fromlen);
- if (newsock < 0) {
- if (errno != EINTR && errno != EWOULDBLOCK)
- error("accept: %.100s", strerror(errno));
- continue;
- }
- if (fcntl(newsock, F_SETFL, 0) < 0) {
- error("newsock del O_NONBLOCK: %s", strerror(errno));
- continue;
- }
- /*
- * Got connection. Fork a child to handle it, unless
- * we are in debugging mode.
- */
- if (debug_flag) {
- /*
- * In debugging mode. Close the listening
- * socket, and start processing the
- * connection without forking.
- */
- debug("Server will not fork when running in debugging mode.");
- close_listen_socks();
- sock_in = newsock;
- sock_out = newsock;
- pid = getpid();
- break;
- } else {
+ fromlen = sizeof(from);
+ newsock = accept(listen_socks[i], (struct sockaddr *)&from,
+ &fromlen);
+ if (newsock < 0) {
+ if (errno != EINTR && errno != EWOULDBLOCK)
+ error("accept: %.100s", strerror(errno));
+ continue;
+ }
+ if (fcntl(newsock, F_SETFL, 0) < 0) {
+ error("newsock del O_NONBLOCK: %s", strerror(errno));
+ continue;
+ }
+ if (startups >= options.max_startups) {
+ close(newsock);
+ continue;
+ }
+ if (pipe(startup_p) == -1) {
+ close(newsock);
+ continue;
+ }
+
+ 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;
+ }
+
/*
- * Normal production daemon. Fork, and have
- * the child process the connection. The
- * parent continues listening.
+ * Got connection. Fork a child to handle it, unless
+ * we are in debugging mode.
*/
- if ((pid = fork()) == 0) {
+ if (debug_flag) {
/*
- * Child. Close the listening socket, and start using the
- * accepted socket. Reinitialize logging (since our pid has
- * changed). We break out of the loop to handle the connection.
+ * In debugging mode. Close the listening
+ * socket, and start processing the
+ * connection without forking.
*/
+ debug("Server will not fork when running in debugging mode.");
close_listen_socks();
sock_in = newsock;
sock_out = newsock;
- log_init(av0, options.log_level, options.log_facility, log_stderr);
+ pid = getpid();
break;
+ } else {
+ /*
+ * Normal production daemon. Fork, and have
+ * the child process the connection. The
+ * parent continues listening.
+ */
+ if ((pid = fork()) == 0) {
+ /*
+ * Child. Close the listening and max_startup
+ * sockets. Start using the accepted socket.
+ * Reinitialize logging (since our pid has
+ * changed). We break out of the loop to handle
+ * the connection.
+ */
+ startup_pipe = startup_p[1];
+ for (j = 0; j < options.max_startups; j++)
+ if (startup_pipes[j] != -1)
+ close(startup_pipes[j]);
+ close_listen_socks();
+ sock_in = newsock;
+ sock_out = newsock;
+ log_init(av0, options.log_level, options.log_facility, log_stderr);
+ break;
+ }
}
- }
- /* Parent. Stay in the loop. */
- if (pid < 0)
- error("fork: %.100s", strerror(errno));
- else
- debug("Forked child %d.", pid);
+ /* Parent. Stay in the loop. */
+ if (pid < 0)
+ error("fork: %.100s", strerror(errno));
+ else
+ debug("Forked child %d.", pid);
- /* Mark that the key has been used (it was "given" to the child). */
- key_used = 1;
+ close(startup_p[1]);
- arc4random_stir();
+ /* Mark that the key has been used (it was "given" to the child). */
+ key_used = 1;
- /* Close the new socket (the child is now taking care of it). */
- close(newsock);
- } /* for (i = 0; i < num_listen_socks; i++) */
+ arc4random_stir();
+
+ /* Close the new socket (the child is now taking care of it). */
+ close(newsock);
+ }
/* child process check (or debug mode) */
if (num_listen_socks < 0)
break;