- (djm) OpenBSD CVS changes:
   - markus@cvs.openbsd.org  2000/07/22 03:14:37
     [servconf.c servconf.h sshd.8 sshd.c sshd_config]
     random early drop; ok theo, niels
   - deraadt@cvs.openbsd.org 2000/07/26 11:46:51
     [ssh.1]
     typo
   - deraadt@cvs.openbsd.org 2000/08/01 11:46:11
     [sshd.8]
     many fixes from pepper@mail.reppep.com
   - provos@cvs.openbsd.org  2000/08/01 13:01:42
     [Makefile.in util.c aux.c]
     rename aux.c to util.c to help with cygwin port
   - deraadt@cvs.openbsd.org 2000/08/02 00:23:31
     [authfd.c]
     correct sun_len; Alexander@Leidinger.net
   - provos@cvs.openbsd.org  2000/08/02 10:27:17
     [readconf.c sshd.8]
     disable kerberos authentication by default
   - provos@cvs.openbsd.org  2000/08/02 11:27:05
     [sshd.8 readconf.c auth-krb4.c]
     disallow kerberos authentication if we can't verify the TGT; from
     dugsong@
     kerberos authentication is on by default only if you have a srvtab.
   - markus@cvs.openbsd.org  2000/08/04 14:30:07
     [auth.c]
     unused
   - markus@cvs.openbsd.org  2000/08/04 14:30:35
     [sshd_config]
     MaxStartups
   - markus@cvs.openbsd.org  2000/08/15 13:20:46
     [authfd.c]
     cleanup; ok niels@
   - markus@cvs.openbsd.org  2000/08/17 14:05:10
     [session.c]
     cleanup login(1)-like jobs, no duplicate utmp entries
   - markus@cvs.openbsd.org  2000/08/17 14:06:34
     [session.c sshd.8 sshd.c]
      sshd -u len, similar to telnetd
diff --git a/ChangeLog b/ChangeLog
index 0e122cf..2f5cee9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,44 @@
+20000818
+ - (djm) OpenBSD CVS changes:
+   - markus@cvs.openbsd.org  2000/07/22 03:14:37
+     [servconf.c servconf.h sshd.8 sshd.c sshd_config]
+     random early drop; ok theo, niels
+   - deraadt@cvs.openbsd.org 2000/07/26 11:46:51
+     [ssh.1]
+     typo
+   - deraadt@cvs.openbsd.org 2000/08/01 11:46:11
+     [sshd.8]
+     many fixes from pepper@mail.reppep.com
+   - provos@cvs.openbsd.org  2000/08/01 13:01:42
+     [Makefile.in util.c aux.c]
+     rename aux.c to util.c to help with cygwin port
+   - deraadt@cvs.openbsd.org 2000/08/02 00:23:31
+     [authfd.c]
+     correct sun_len; Alexander@Leidinger.net
+   - provos@cvs.openbsd.org  2000/08/02 10:27:17
+     [readconf.c sshd.8]
+     disable kerberos authentication by default
+   - provos@cvs.openbsd.org  2000/08/02 11:27:05
+     [sshd.8 readconf.c auth-krb4.c]
+     disallow kerberos authentication if we can't verify the TGT; from
+     dugsong@
+     kerberos authentication is on by default only if you have a srvtab.
+   - markus@cvs.openbsd.org  2000/08/04 14:30:07
+     [auth.c]
+     unused
+   - markus@cvs.openbsd.org  2000/08/04 14:30:35
+     [sshd_config]
+     MaxStartups
+   - markus@cvs.openbsd.org  2000/08/15 13:20:46
+     [authfd.c]
+     cleanup; ok niels@
+   - markus@cvs.openbsd.org  2000/08/17 14:05:10
+     [session.c]
+     cleanup login(1)-like jobs, no duplicate utmp entries
+   - markus@cvs.openbsd.org  2000/08/17 14:06:34
+     [session.c sshd.8 sshd.c]
+      sshd -u len, similar to telnetd
+
 20000816
  - (djm) Replacement for inet_ntoa for Irix (which breaks on gcc)
  - (djm) Fix strerror replacement for old SunOS. Based on patch from 
diff --git a/Makefile.in b/Makefile.in
index 0aaaa68..ff34c49 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -34,7 +34,7 @@
 
 TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS)
 
-LIBSSH_OBJS=atomicio.o authfd.o authfile.o aux.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o dsa.o fingerprint.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o 
+LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o dsa.o fingerprint.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o util.o uuencode.o xmalloc.o 
 
 LIBOPENBSD_COMPAT_OBJS=bsd-arc4random.o bsd-base64.o bsd-bindresvport.o bsd-daemon.o bsd-inet_aton.o bsd-inet_ntoa.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-sigaction.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bsd-strsep.o fake-getaddrinfo.o fake-getnameinfo.o next-posix.o
 
diff --git a/acconfig.h b/acconfig.h
index 6c25c8f..8660771 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -6,6 +6,9 @@
 
 @TOP@
 
+/* Define if your system's struct sockaddr_un has a sun_len member */
+#undef HAVE_SUN_LEN_IN_SOCKADDR_UN
+
 /* Define if you system's inet_ntoa is busted (e.g. Irix gcc issue) */
 #undef BROKEN_INET_NTOA
 
diff --git a/auth-krb4.c b/auth-krb4.c
index e32089b..ae2b2a3 100644
--- a/auth-krb4.c
+++ b/auth-krb4.c
@@ -9,7 +9,7 @@
 #include "ssh.h"
 #include "servconf.h"
 
-RCSID("$OpenBSD: auth-krb4.c,v 1.15 2000/06/22 23:54:59 djm Exp $");
+RCSID("$OpenBSD: auth-krb4.c,v 1.16 2000/08/02 17:27:04 provos Exp $");
 
 #ifdef KRB4
 char *ticket = NULL;
@@ -82,11 +82,12 @@
 			if (r == RD_AP_UNDEC) {
 				/*
 				 * Probably didn't have a srvtab on
-				 * localhost. Allow login.
+				 * localhost. Disallow login.
 				 */
 				log("Kerberos V4 TGT for %s unverifiable, "
 				    "no srvtab installed? krb_rd_req: %s",
 				    pw->pw_name, krb_err_txt[r]);
+				goto kerberos_auth_failure;
 			} else if (r != KSUCCESS) {
 				log("Kerberos V4 %s ticket unverifiable: %s",
 				    KRB4_SERVICE_NAME, krb_err_txt[r]);
@@ -94,12 +95,13 @@
 			}
 		} else if (r == KDC_PR_UNKNOWN) {
 			/*
-			 * Allow login if no rcmd service exists, but
+			 * Disallow login if no rcmd service exists, and
 			 * log the error.
 			 */
 			log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s "
 			    "not registered, or srvtab is wrong?", pw->pw_name,
 			krb_err_txt[r], KRB4_SERVICE_NAME, phost);
+			goto kerberos_auth_failure;
 		} else {
 			/*
 			 * TGT is bad, forget it. Possibly spoofed!
diff --git a/auth.c b/auth.c
index 5aeeec6..dc3e821 100644
--- a/auth.c
+++ b/auth.c
@@ -5,7 +5,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth.c,v 1.7 2000/05/17 21:37:24 deraadt Exp $");
+RCSID("$OpenBSD: auth.c,v 1.8 2000/08/04 20:30:07 markus Exp $");
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -30,8 +30,6 @@
 #include "ssh2.h"
 #include "auth.h"
 #include "session.h"
-#include "dispatch.h"
-
 
 /* import */
 extern ServerOptions options;
diff --git a/authfd.c b/authfd.c
index 227c992..a34e111 100644
--- a/authfd.c
+++ b/authfd.c
@@ -14,7 +14,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: authfd.c,v 1.22 2000/07/16 08:27:20 markus Exp $");
+RCSID("$OpenBSD: authfd.c,v 1.24 2000/08/15 19:20:46 markus Exp $");
 
 #include "ssh.h"
 #include "rsa.h"
@@ -31,7 +31,7 @@
 #include "kex.h"
 
 /* helper */
-int ssh_agent_get_reply(AuthenticationConnection *auth);
+int	decode_reply(int type);
 
 /* Returns the number of the authentication fd, or -1 if there is none. */
 
@@ -39,7 +39,7 @@
 ssh_get_authentication_socket()
 {
 	const char *authsocket;
-	int sock;
+	int sock, len;
 	struct sockaddr_un sunaddr;
 
 	authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
@@ -48,6 +48,11 @@
 
 	sunaddr.sun_family = AF_UNIX;
 	strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
+#ifdef HAVE_SUN_LEN_IN_SOCKADDR_UN
+	sunaddr.sun_len = len = SUN_LEN(&sunaddr)+1;
+#else /* HAVE_SUN_LEN_IN_SOCKADDR_UN */
+	len = SUN_LEN(&sunaddr)+1;
+#endif /* HAVE_SUN_LEN_IN_SOCKADDR_UN */
 
 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
 	if (sock < 0)
@@ -58,13 +63,67 @@
 		close(sock);
 		return -1;
 	}
-	if (connect(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
+	if (connect(sock, (struct sockaddr *) & sunaddr, len) < 0) {
 		close(sock);
 		return -1;
 	}
 	return sock;
 }
 
+int
+ssh_request_reply(AuthenticationConnection *auth,
+    Buffer *request, Buffer *reply)
+{
+	int l, len;
+	char buf[1024];
+
+	/* Get the length of the message, and format it in the buffer. */
+	len = buffer_len(request);
+	PUT_32BIT(buf, len);
+
+	/* Send the length and then the packet to the agent. */
+	if (atomicio(write, auth->fd, buf, 4) != 4 ||
+	    atomicio(write, auth->fd, buffer_ptr(request),
+	    buffer_len(request)) != buffer_len(request)) {
+		error("Error writing to authentication socket.");
+		return 0;
+	}
+	/*
+	 * Wait for response from the agent.  First read the length of the
+	 * response packet.
+	 */
+	len = 4;
+	while (len > 0) {
+		l = read(auth->fd, buf + 4 - len, len);
+		if (l <= 0) {
+			error("Error reading response length from authentication socket.");
+			return 0;
+		}
+		len -= l;
+	}
+
+	/* Extract the length, and check it for sanity. */
+	len = GET_32BIT(buf);
+	if (len > 256 * 1024)
+		fatal("Authentication response too long: %d", len);
+
+	/* Read the rest of the response in to the buffer. */
+	buffer_clear(reply);
+	while (len > 0) {
+		l = len;
+		if (l > sizeof(buf))
+			l = sizeof(buf);
+		l = read(auth->fd, buf, l);
+		if (l <= 0) {
+			error("Error reading response from authentication socket.");
+			return 0;
+		}
+		buffer_append(reply, (char *) buf, l);
+		len -= l;
+	}
+	return 1;
+}
+
 /*
  * Closes the agent socket if it should be closed (depends on how it was
  * obtained).  The argument must have been returned by
@@ -133,62 +192,35 @@
 
 int
 ssh_get_first_identity(AuthenticationConnection *auth,
-		       BIGNUM *e, BIGNUM *n, char **comment)
+    BIGNUM *e, BIGNUM *n, char **comment)
 {
-	unsigned char msg[8192];
-	int len, l;
+	Buffer request;
+	int type;
 
 	/*
 	 * Send a message to the agent requesting for a list of the
 	 * identities it can represent.
 	 */
-	PUT_32BIT(msg, 1);
-	msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
-	if (atomicio(write, auth->fd, msg, 5) != 5) {
-		error("write auth->fd: %.100s", strerror(errno));
+	buffer_init(&request);
+	buffer_put_char(&request, SSH_AGENTC_REQUEST_RSA_IDENTITIES);
+
+	buffer_clear(&auth->identities);
+	if (ssh_request_reply(auth, &request, &auth->identities) == 0) {
+		buffer_free(&request);
 		return 0;
 	}
-	/* Read the length of the response.  XXX implement timeouts here. */
-	len = 4;
-	while (len > 0) {
-		l = read(auth->fd, msg + 4 - len, len);
-		if (l <= 0) {
-			error("read auth->fd: %.100s", strerror(errno));
-			return 0;
-		}
-		len -= l;
-	}
-
-	/*
-	 * Extract the length, and check it for sanity.  (We cannot trust
-	 * authentication agents).
-	 */
-	len = GET_32BIT(msg);
-	if (len < 1 || len > 256 * 1024)
-		fatal("Authentication reply message too long: %d\n", len);
-
-	/* Read the packet itself. */
-	buffer_clear(&auth->identities);
-	while (len > 0) {
-		l = len;
-		if (l > sizeof(msg))
-			l = sizeof(msg);
-		l = read(auth->fd, msg, l);
-		if (l <= 0)
-			fatal("Incomplete authentication reply.");
-		buffer_append(&auth->identities, (char *) msg, l);
-		len -= l;
-	}
+	buffer_free(&request);
 
 	/* Get message type, and verify that we got a proper answer. */
-	buffer_get(&auth->identities, (char *) msg, 1);
-	if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
-		fatal("Bad authentication reply message type: %d", msg[0]);
+	type = buffer_get_char(&auth->identities);
+	if (type != SSH_AGENT_RSA_IDENTITIES_ANSWER)
+		fatal("Bad authentication reply message type: %d", type);
 
 	/* Get the number of entries in the response and check it for sanity. */
 	auth->howmany = buffer_get_int(&auth->identities);
 	if (auth->howmany > 1024)
-		fatal("Too many identities in authentication reply: %d\n", auth->howmany);
+		fatal("Too many identities in authentication reply: %d\n",
+		    auth->howmany);
 
 	/* Return the first entry (if any). */
 	return ssh_get_next_identity(auth, e, n, comment);
@@ -203,7 +235,7 @@
 
 int
 ssh_get_next_identity(AuthenticationConnection *auth,
-		      BIGNUM *e, BIGNUM *n, char **comment)
+    BIGNUM *e, BIGNUM *n, char **comment)
 {
 	unsigned int bits;
 
@@ -240,23 +272,22 @@
 
 int
 ssh_decrypt_challenge(AuthenticationConnection *auth,
-		      BIGNUM* e, BIGNUM *n, BIGNUM *challenge,
-		      unsigned char session_id[16],
-		      unsigned int response_type,
-		      unsigned char response[16])
+    BIGNUM* e, BIGNUM *n, BIGNUM *challenge,
+    unsigned char session_id[16],
+    unsigned int response_type,
+    unsigned char response[16])
 {
 	Buffer buffer;
-	unsigned char buf[8192];
-	int len, l, i;
+	int success = 0;
+	int i;
+	int type;
 
-	/* Response type 0 is no longer supported. */
 	if (response_type == 0)
-		fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
+		fatal("Compatibility with ssh protocol version "
+		    "1.0 no longer supported.");
 
-	/* Format a message to the agent. */
-	buf[0] = SSH_AGENTC_RSA_CHALLENGE;
 	buffer_init(&buffer);
-	buffer_append(&buffer, (char *) buf, 1);
+	buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE);
 	buffer_put_int(&buffer, BN_num_bits(n));
 	buffer_put_bignum(&buffer, e);
 	buffer_put_bignum(&buffer, n);
@@ -264,77 +295,27 @@
 	buffer_append(&buffer, (char *) session_id, 16);
 	buffer_put_int(&buffer, response_type);
 
-	/* Get the length of the message, and format it in the buffer. */
-	len = buffer_len(&buffer);
-	PUT_32BIT(buf, len);
-
-	/* Send the length and then the packet to the agent. */
-	if (atomicio(write, auth->fd, buf, 4) != 4 ||
-	    atomicio(write, auth->fd, buffer_ptr(&buffer),
-	    buffer_len(&buffer)) != buffer_len(&buffer)) {
-		error("Error writing to authentication socket.");
-error_cleanup:
+	if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
 		buffer_free(&buffer);
 		return 0;
 	}
-	/*
-	 * Wait for response from the agent.  First read the length of the
-	 * response packet.
-	 */
-	len = 4;
-	while (len > 0) {
-		l = read(auth->fd, buf + 4 - len, len);
-		if (l <= 0) {
-			error("Error reading response length from authentication socket.");
-			goto error_cleanup;
-		}
-		len -= l;
-	}
+	type = buffer_get_char(&buffer);
 
-	/* Extract the length, and check it for sanity. */
-	len = GET_32BIT(buf);
-	if (len > 256 * 1024)
-		fatal("Authentication response too long: %d", len);
-
-	/* Read the rest of the response in tothe buffer. */
-	buffer_clear(&buffer);
-	while (len > 0) {
-		l = len;
-		if (l > sizeof(buf))
-			l = sizeof(buf);
-		l = read(auth->fd, buf, l);
-		if (l <= 0) {
-			error("Error reading response from authentication socket.");
-			goto error_cleanup;
-		}
-		buffer_append(&buffer, (char *) buf, l);
-		len -= l;
-	}
-
-	/* Get the type of the packet. */
-	buffer_get(&buffer, (char *) buf, 1);
-
-	/* Check for agent failure message. */
-	if (buf[0] == SSH_AGENT_FAILURE) {
+	if (type == SSH_AGENT_FAILURE) {
 		log("Agent admitted failure to authenticate using the key.");
-		goto error_cleanup;
+	} else if (type != SSH_AGENT_RSA_RESPONSE) {
+		fatal("Bad authentication response: %d", type);
+	} else {
+		success = 1;
+		/*
+		 * Get the response from the packet.  This will abort with a
+		 * fatal error if the packet is corrupt.
+		 */
+		for (i = 0; i < 16; i++)
+			response[i] = buffer_get_char(&buffer);
 	}
-	/* Now it must be an authentication response packet. */
-	if (buf[0] != SSH_AGENT_RSA_RESPONSE)
-		fatal("Bad authentication response: %d", buf[0]);
-
-	/*
-	 * Get the response from the packet.  This will abort with a fatal
-	 * error if the packet is corrupt.
-	 */
-	for (i = 0; i < 16; i++)
-		response[i] = buffer_get_char(&buffer);
-
-	/* The buffer containing the packet is no longer needed. */
 	buffer_free(&buffer);
-
-	/* Correct answer. */
-	return 1;
+	return success;
 }
 
 /* Encode key for a message to the agent. */
@@ -378,8 +359,7 @@
 ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
 {
 	Buffer buffer;
-	unsigned char buf[8192];
-	int len;
+	int type;
 
 	buffer_init(&buffer);
 
@@ -395,21 +375,13 @@
 		return 0;
 		break;
 	}
-
-	/* Get the length of the message, and format it in the buffer. */
-	len = buffer_len(&buffer);
-	PUT_32BIT(buf, len);
-
-	/* Send the length and then the packet to the agent. */
-	if (atomicio(write, auth->fd, buf, 4) != 4 ||
-	    atomicio(write, auth->fd, buffer_ptr(&buffer),
-	    buffer_len(&buffer)) != buffer_len(&buffer)) {
-		error("Error writing to authentication socket.");
+	if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
 		buffer_free(&buffer);
 		return 0;
 	}
+	type = buffer_get_char(&buffer);
 	buffer_free(&buffer);
-	return ssh_agent_get_reply(auth);
+	return decode_reply(type);
 }
 
 /*
@@ -421,30 +393,21 @@
 ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
 {
 	Buffer buffer;
-	unsigned char buf[5];
-	int len;
+	int type;
 
-	/* Format a message to the agent. */
 	buffer_init(&buffer);
 	buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
 	buffer_put_int(&buffer, BN_num_bits(key->n));
 	buffer_put_bignum(&buffer, key->e);
 	buffer_put_bignum(&buffer, key->n);
 
-	/* Get the length of the message, and format it in the buffer. */
-	len = buffer_len(&buffer);
-	PUT_32BIT(buf, len);
-
-	/* Send the length and then the packet to the agent. */
-	if (atomicio(write, auth->fd, buf, 4) != 4 ||
-	    atomicio(write, auth->fd, buffer_ptr(&buffer),
-	    buffer_len(&buffer)) != buffer_len(&buffer)) {
-		error("Error writing to authentication socket.");
+	if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
 		buffer_free(&buffer);
 		return 0;
 	}
+	type = buffer_get_char(&buffer);
 	buffer_free(&buffer);
-	return ssh_agent_get_reply(auth);
+	return decode_reply(type);
 }
 
 /*
@@ -455,73 +418,27 @@
 int
 ssh_remove_all_identities(AuthenticationConnection *auth)
 {
-	unsigned char buf[5];
+	Buffer buffer;
+	int type;
 
-	/* Get the length of the message, and format it in the buffer. */
-	PUT_32BIT(buf, 1);
-	buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
+	buffer_init(&buffer);
+	buffer_put_char(&buffer, SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES);
 
-	/* Send the length and then the packet to the agent. */
-	if (atomicio(write, auth->fd, buf, 5) != 5) {
-		error("Error writing to authentication socket.");
+	if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
+		buffer_free(&buffer);
 		return 0;
 	}
-	return ssh_agent_get_reply(auth);
-}
-
-/*
- * Read for reply from agent. returns 1 for success, 0 on error
- */
-
-int 
-ssh_agent_get_reply(AuthenticationConnection *auth)
-{
-	Buffer buffer;
-	unsigned char buf[8192];
-	int len, l, type;
-
-	/*
-	 * Wait for response from the agent.  First read the length of the
-	 * response packet.
-	 */
-	len = 4;
-	while (len > 0) {
-		l = read(auth->fd, buf + 4 - len, len);
-		if (l <= 0) {
-			error("Error reading response length from authentication socket.");
-			buffer_free(&buffer);
-			return 0;
-		}
-		len -= l;
-	}
-
-	/* Extract the length, and check it for sanity. */
-	len = GET_32BIT(buf);
-	if (len > 256 * 1024)
-		fatal("Response from agent too long: %d", len);
-
-	/* Read the rest of the response in to the buffer. */
-	buffer_init(&buffer);
-	while (len > 0) {
-		l = len;
-		if (l > sizeof(buf))
-			l = sizeof(buf);
-		l = read(auth->fd, buf, l);
-		if (l <= 0) {
-			error("Error reading response from authentication socket.");
-			buffer_free(&buffer);
-			return 0;
-		}
-		buffer_append(&buffer, (char *) buf, l);
-		len -= l;
-	}
-
-	/* Get the type of the packet. */
 	type = buffer_get_char(&buffer);
 	buffer_free(&buffer);
+	return decode_reply(type);
+}
+
+int 
+decode_reply(int type)
+{
 	switch (type) {
 	case SSH_AGENT_FAILURE:
-log("SSH_AGENT_FAILURE");
+		log("SSH_AGENT_FAILURE");
 		return 0;
 	case SSH_AGENT_SUCCESS:
 		return 1;
diff --git a/bsd-mktemp.c b/bsd-mktemp.c
index 7c02ea1..23831fa 100644
--- a/bsd-mktemp.c
+++ b/bsd-mktemp.c
@@ -52,6 +52,7 @@
 #include <unistd.h>
 
 #include "bsd-misc.h"
+#include "bsd-arc4random.h"
 
 static int _gettemp(char *, int *, int, int);
 
diff --git a/configure.in b/configure.in
index 974d0df..e946701 100644
--- a/configure.in
+++ b/configure.in
@@ -686,6 +686,22 @@
 OSSH_CHECK_HEADER_FOR_FIELD(ut_time, utmpx.h, HAVE_TIME_IN_UTMPX)
 OSSH_CHECK_HEADER_FOR_FIELD(ut_tv, utmpx.h, HAVE_TV_IN_UTMPX)
 
+AC_CACHE_CHECK([for sun_len field in struct sockaddr_un],
+		ac_cv_have_sun_len_in_struct_sockaddr_un, [
+	AC_TRY_COMPILE(
+		[
+#include <sys/types.h>
+#include <sys/socket.h>
+		],
+		[ struct sockaddr_un s; s.sun_len = 1; ],
+		[ ac_cv_have_sun_len_in_struct_sockaddr_un="yes" ],
+		[ ac_cv_have_sun_len_in_struct_sockaddr_un="no" ],
+	)
+])
+if test "x$ac_cv_have_sun_len_in_struct_sockaddr_un" = "xyes" ; then
+	AC_DEFINE(HAVE_SUN_LEN_IN_SOCKADDR_UN)
+fi
+
 AC_CACHE_CHECK([for ss_family field in struct sockaddr_storage],
 		ac_cv_have_ss_family_in_struct_ss, [
 	AC_TRY_COMPILE(
diff --git a/readconf.c b/readconf.c
index 06cfaa1..f31b1c4 100644
--- a/readconf.c
+++ b/readconf.c
@@ -14,7 +14,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: readconf.c,v 1.43 2000/07/14 22:59:46 markus Exp $");
+RCSID("$OpenBSD: readconf.c,v 1.45 2000/08/02 17:27:04 provos Exp $");
 
 #include "ssh.h"
 #include "cipher.h"
diff --git a/servconf.c b/servconf.c
index 477204c..6affb51 100644
--- a/servconf.c
+++ b/servconf.c
@@ -12,7 +12,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: servconf.c,v 1.49 2000/07/14 22:59:46 markus Exp $");
+RCSID("$OpenBSD: servconf.c,v 1.50 2000/07/22 09:14:36 markus Exp $");
 
 #include "ssh.h"
 #include "servconf.h"
@@ -76,6 +76,8 @@
 	options->protocol = SSH_PROTO_UNKNOWN;
 	options->gateway_ports = -1;
 	options->num_subsystems = 0;
+	options->max_startups_begin = -1;
+	options->max_startups_rate = -1;
 	options->max_startups = -1;
 }
 
@@ -162,6 +164,10 @@
 		options->gateway_ports = 0;
 	if (options->max_startups == -1)
 		options->max_startups = 10;
+	if (options->max_startups_rate == -1)
+		options->max_startups_rate = 100;		/* 100% */
+	if (options->max_startups_begin == -1)
+		options->max_startups_begin = options->max_startups;
 }
 
 /* Keyword tokens. */
@@ -644,6 +650,22 @@
 			break;
 
 		case sMaxStartups:
+			arg = strdelim(&cp);
+			if (!arg || *arg == '\0')
+				fatal("%s line %d: Missing MaxStartups spec.",
+				      filename, linenum);
+			if (sscanf(arg, "%d:%d:%d",
+			    &options->max_startups_begin,
+			    &options->max_startups_rate,
+			    &options->max_startups) == 3) {
+				if (options->max_startups_begin >
+				    options->max_startups ||
+				    options->max_startups_rate > 100 ||
+				    options->max_startups_rate < 1)
+				fatal("%s line %d: Illegal MaxStartups spec.",
+				      filename, linenum);
+				break;
+			}
 			intptr = &options->max_startups;
 			goto parse_int;
 
diff --git a/servconf.h b/servconf.h
index 9559372..3b65c6a 100644
--- a/servconf.h
+++ b/servconf.h
@@ -13,7 +13,7 @@
  *
  */
 
-/* RCSID("$OpenBSD: servconf.h,v 1.26 2000/06/26 21:59:18 markus Exp $"); */
+/* RCSID("$OpenBSD: servconf.h,v 1.27 2000/07/22 09:14:36 markus Exp $"); */
 
 #ifndef SERVCONF_H
 #define SERVCONF_H
@@ -100,6 +100,8 @@
 	char   *subsystem_name[MAX_SUBSYSTEMS];
 	char   *subsystem_command[MAX_SUBSYSTEMS];
 
+	int	max_startups_begin;
+	int	max_startups_rate;
 	int	max_startups;
 
 }       ServerOptions;
diff --git a/session.c b/session.c
index e68718a..d65b069 100644
--- a/session.c
+++ b/session.c
@@ -8,7 +8,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.23 2000/07/11 08:11:33 deraadt Exp $");
+RCSID("$OpenBSD: session.c,v 1.25 2000/08/17 20:06:34 markus Exp $");
 
 #include "xmalloc.h"
 #include "ssh.h"
@@ -85,6 +85,7 @@
 void	session_proctitle(Session *s);
 void	do_exec_pty(Session *s, const char *command, struct passwd * pw);
 void	do_exec_no_pty(Session *s, const char *command, struct passwd * pw);
+void	do_login(Session *s);
 
 void
 do_child(const char *command, struct passwd * pw, const char *term,
@@ -101,6 +102,7 @@
 
 extern int log_stderr;
 extern int debug_flag;
+extern unsigned int utmp_len;
 
 extern int startup_pipe;
 
@@ -523,35 +525,14 @@
 void
 do_exec_pty(Session *s, const char *command, struct passwd * pw)
 {
-	FILE *f;
-	char buf[100], *time_string;
-	char line[256];
-	const char *hostname;
 	int fdout, ptyfd, ttyfd, ptymaster;
-	int quiet_login;
 	pid_t pid;
-	socklen_t fromlen;
-	struct sockaddr_storage from;
-	struct stat st;
-	time_t last_login_time;
 
 	if (s == NULL)
 		fatal("do_exec_pty: no session");
 	ptyfd = s->ptyfd;
 	ttyfd = s->ttyfd;
 
-	/* Get remote host name. */
-	hostname = get_canonical_hostname();
-
-	/*
-	 * Get the time when the user last logged in.  Buf will be set to
-	 * contain the hostname the last login was from.
-	 */
-	if (!options.use_login) {
-		last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
-						      buf, sizeof(buf));
-	}
-
 #ifdef USE_PAM
 			do_pam_session(pw->pw_name, s->tty);
 			do_pam_setcred();
@@ -559,10 +540,7 @@
 
 	/* Fork the child. */
 	if ((pid = fork()) == 0) {
-		pid = getpid();
-
-		/* Child.  Reinitialize the log because the pid has
-		   changed. */
+		/* Child.  Reinitialize the log because the pid has changed. */
 		log_init(__progname, options.log_level, options.log_facility, log_stderr);
 
 		/* Close the master side of the pseudo tty. */
@@ -586,82 +564,10 @@
 		/* Close the extra descriptor for the pseudo tty. */
 		close(ttyfd);
 
-/* XXXX ? move to do_child() ??*/
-		/*
-		 * Get IP address of client.  This is needed because we want
-		 * to record where the user logged in from.  If the
-		 * connection is not a socket, let the ip address be 0.0.0.0.
-		 */
-		memset(&from, 0, sizeof(from));
-		if (packet_connection_is_on_socket()) {
-			fromlen = sizeof(from);
-			if (getpeername(packet_get_connection_in(),
-			     (struct sockaddr *) & from, &fromlen) < 0) {
-				debug("getpeername: %.100s", strerror(errno));
-				fatal_cleanup();
-			}
-		}
-		/* Record that there was a login on that terminal. */
-		if (!options.use_login || command != NULL)
-			record_login(pid, s->tty, pw->pw_name, pw->pw_uid, 
-			    hostname, (struct sockaddr *)&from);
+		/* record login, etc. similar to login(1) */
+		if (command == NULL && !options.use_login)
+			do_login(s);
 
-		/* Check if .hushlogin exists. */
-		snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);
-		quiet_login = stat(line, &st) >= 0;
-
-#ifdef USE_PAM
-		if (!quiet_login)
-			print_pam_messages();
-#endif /* USE_PAM */
-
-		/*
-		 * If the user has logged in before, display the time of last
-		 * login. However, don't display anything extra if a command
-		 * has been specified (so that ssh can be used to execute
-		 * commands on a remote machine without users knowing they
-		 * are going to another machine). Login(1) will do this for
-		 * us as well, so check if login(1) is used
-		 */
-		if (command == NULL && last_login_time != 0 && !quiet_login &&
-		    !options.use_login) {
-			/* Convert the date to a string. */
-			time_string = ctime(&last_login_time);
-			/* Remove the trailing newline. */
-			if (strchr(time_string, '\n'))
-				*strchr(time_string, '\n') = 0;
-			/* Display the last login time.  Host if displayed
-			   if known. */
-			if (strcmp(buf, "") == 0)
-				printf("Last login: %s\r\n", time_string);
-			else
-				printf("Last login: %s from %s\r\n", time_string, buf);
-		}
-		/*
-		 * Print /etc/motd unless a command was specified or printing
-		 * it was disabled in server options or login(1) will be
-		 * used.  Note that some machines appear to print it in
-		 * /etc/profile or similar.
-		 */
-		if (command == NULL && options.print_motd && !quiet_login &&
-		    !options.use_login) {
-			/* Print /etc/motd if it exists. */
-			f = fopen("/etc/motd", "r");
-			if (f) {
-				while (fgets(line, sizeof(line), f))
-					fputs(line, stdout);
-				fclose(f);
-			}
-		}
-#if defined(WITH_AIXAUTHENTICATE)
-		/*
-		 * AIX handles the lastlog info differently.  Display it here.
-		 */
-		if (command == NULL && aixloginmsg && *aixloginmsg &&
-		    !quiet_login && !options.use_login) {
-			printf("%s\n", aixloginmsg);
-		}
-#endif
 		/* Do common processing for the child, such as execing the command. */
 		do_child(command, pw, s->term, s->display, s->auth_proto,
 		    s->auth_data, s->tty);
@@ -699,6 +605,87 @@
 	}
 }
 
+const char *
+get_remote_name_or_ip(void)
+{
+	static const char *remote = "";
+	if (utmp_len > 0)
+		remote = get_canonical_hostname();
+	if (utmp_len == 0 || strlen(remote) > utmp_len)
+		remote = get_remote_ipaddr();
+	return remote;
+}
+
+/* administrative, login(1)-like work */
+void
+do_login(Session *s)
+{
+	FILE *f;
+	char *time_string;
+	char buf[256];
+	socklen_t fromlen;
+	struct sockaddr_storage from;
+	struct stat st;
+	time_t last_login_time;
+	struct passwd * pw = s->pw;
+	pid_t pid = getpid();
+
+	/*
+	 * Get IP address of client. If the connection is not a socket, let
+	 * the address be 0.0.0.0.
+	 */
+	memset(&from, 0, sizeof(from));
+	if (packet_connection_is_on_socket()) {
+		fromlen = sizeof(from);
+		if (getpeername(packet_get_connection_in(),
+		     (struct sockaddr *) & from, &fromlen) < 0) {
+			debug("getpeername: %.100s", strerror(errno));
+			fatal_cleanup();
+		}
+	}
+
+	/* Record that there was a login on that tty from the remote host. */
+	record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
+	    get_remote_name_or_ip(), (struct sockaddr *)&from);
+
+	/* Done if .hushlogin exists. */
+	snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);
+	if (stat(buf, &st) >= 0)
+		return;
+
+#ifdef USE_PAM
+	print_pam_messages();
+#endif /* USE_PAM */
+#ifdef WITH_AIXAUTHENTICATE
+	if (aixloginmsg && *aixloginmsg)
+		printf("%s\n", aixloginmsg);
+#endif /* WITH_AIXAUTHENTICATE */
+
+	/*
+	 * Get the time when the user last logged in.  'buf' will be set
+	 * to contain the hostname the last login was from. 
+	 */
+	last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
+	    buf, sizeof(buf));
+	if (last_login_time != 0) {
+		time_string = ctime(&last_login_time);
+		if (strchr(time_string, '\n'))
+			*strchr(time_string, '\n') = 0;
+		if (strcmp(buf, "") == 0)
+			printf("Last login: %s\r\n", time_string);
+		else
+			printf("Last login: %s from %s\r\n", time_string, buf);
+	}
+	if (options.print_motd) {
+		f = fopen("/etc/motd", "r");
+		if (f) {
+			while (fgets(buf, sizeof(buf), f))
+				fputs(buf, stdout);
+			fclose(f);
+		}
+	}
+}
+
 /*
  * Sets the value of the given variable in the environment.  If the variable
  * already exists, its value is overriden.
@@ -1265,8 +1252,9 @@
 		} else {
 			/* Launch login(1). */
 
-			execl(LOGIN_PROGRAM, "login", "-h", get_remote_ipaddr(),
-			      "-p", "-f", "--", pw->pw_name, NULL);
+			execl(LOGIN_PROGRAM, "login",
+			     "-h", get_remote_name_or_ip(),
+			     "-p", "-f", "--", pw->pw_name, NULL);
 
 			/* Login couldn't be executed, die. */
 
diff --git a/ssh.1 b/ssh.1
index cd56e7b..39368e0 100644
--- a/ssh.1
+++ b/ssh.1
@@ -9,7 +9,7 @@
 .\"
 .\" Created: Sat Apr 22 21:55:14 1995 ylo
 .\"
-.\" $Id: ssh.1,v 1.28 2000/06/07 09:55:44 djm Exp $
+.\" $Id: ssh.1,v 1.29 2000/08/18 03:59:06 djm Exp $
 .\"
 .Dd September 25, 1999
 .Dt SSH 1
@@ -994,7 +994,7 @@
 this variable is not set.
 .It Ev TZ
 The timezone variable is set to indicate the present timezone if it
-was set when the daemon was started (e.i., the daemon passes the value
+was set when the daemon was started (i.e., the daemon passes the value
 on to new connections).
 .It Ev USER
 Set to the name of the user logging in.
diff --git a/sshd.8 b/sshd.8
index b6aefe4..c8b99df 100644
--- a/sshd.8
+++ b/sshd.8
@@ -9,7 +9,7 @@
 .\"
 .\" Created: Sat Apr 22 21:55:14 1995 ylo
 .\"
-.\" $Id: sshd.8,v 1.25 2000/07/11 07:31:39 djm Exp $
+.\" $Id: sshd.8,v 1.26 2000/08/18 03:59:06 djm Exp $
 .\"
 .Dd September 25, 1999
 .Dt SSHD 8
@@ -26,6 +26,7 @@
 .Op Fl h Ar host_key_file
 .Op Fl k Ar key_gen_time
 .Op Fl p Ar port
+.Op Fl u Ar len
 .Op Fl V Ar client_protocol_id
 .Sh DESCRIPTION
 .Nm
@@ -104,7 +105,7 @@
 .Pp
 .Ss SSH protocol version 2
 .Pp
-Version 2 works similar:
+Version 2 works similarly:
 Each host has a host-specific DSA key used to identify the host.
 However, when the daemon starts, it does not generate a server key.
 Forward security is provided through a Diffie-Hellman key agreement.
@@ -211,6 +212,22 @@
 Nothing is sent to the system log.
 Normally the beginning,
 authentication, and termination of each connection is logged.
+.It Fl u Ar len
+This option is used to specify the size of the field
+in the
+.Li utmp
+structure that holds the remote host name.
+If the resolved host name is longer than
+.Ar len ,
+the dotted decimal value will be used instead.
+This allows hosts with very long host names that
+overflow this field to still be uniquely identified.
+Specifying
+.Fl u0
+indicates that only dotted decimal addresses
+should be put into the
+.Pa utmp
+file.
 .It Fl Q
 Do not print an error message if RSA support is missing.
 .It Fl V Ar client_protocol_id
@@ -257,7 +274,7 @@
 .Ql ?
 can be used as
 wildcards in the patterns.
-Only group names are valid, a numerical group ID isn't recognized.
+Only group names are valid; a numerical group ID isn't recognized.
 By default login is allowed regardless of the primary group.
 .Pp
 .It Cm AllowUsers
@@ -270,7 +287,7 @@
 .Ql ?
 can be used as
 wildcards in the patterns.
-Only user names are valid, a numerical user ID isn't recognized.
+Only user names are valid; a numerical user ID isn't recognized.
 By default login is allowed regardless of the user name.
 .Pp
 .It Cm Ciphers
@@ -294,7 +311,7 @@
 .Ql ?
 can be used as
 wildcards in the patterns.
-Only group names are valid, a numerical group ID isn't recognized.
+Only group names are valid; a numerical group ID isn't recognized.
 By default login is allowed regardless of the primary group.
 .Pp
 .It Cm DenyUsers
@@ -305,7 +322,7 @@
 and
 .Ql ?
 can be used as wildcards in the patterns.
-Only user names are valid, a numerical user ID isn't recognized.
+Only user names are valid; a numerical user ID isn't recognized.
 By default login is allowed regardless of the user name.
 .It Cm DSAAuthentication
 Specifies whether DSA authentication is allowed.
@@ -321,7 +338,7 @@
 .Dq no .
 The default is
 .Dq no .
-.It Cm HostDsaKey
+.It Cm HostDSAKey
 Specifies the file containing the private DSA host key (default
 .Pa /etc/ssh_host_dsa_key )
 used by SSH protocol 2.0.
@@ -383,7 +400,8 @@
 This can be in the form of a Kerberos ticket, or if
 .Cm PasswordAuthentication
 is yes, the password provided by the user will be validated through
-the Kerberos KDC.
+the Kerberos KDC.  To use this option, the server needs a 
+Kerberos servtab which allows the verification of the KDC's identity.
 Default is
 .Dq yes .
 .It Cm KerberosOrLocalPasswd
@@ -443,11 +461,28 @@
 .Cm LoginGraceTime
 expires for a connection.
 The default is 10.
+.Pp
+Alternatively, random early drop can be enabled by specifying
+the three colon separated values
+.Dq start:rate:full
+(e.g. "10:30:60").
+.Nm
+will refuse connection attempts with a probabillity of
+.Dq rate/100
+(30%)
+if there are currently
+.Dq start
+(10)
+unauthenticated connections.
+The probabillity increases linearly and all connection attempts
+are refused if the number of unauthenticated connections reaches
+.Dq full
+(60).
 .It Cm PasswordAuthentication
 Specifies whether password authentication is allowed.
 The default is
 .Dq yes .
-Note that this option applies to both protocol version 1 and 2.
+Note that this option applies to both protocol versions 1 and 2.
 .It Cm PermitEmptyPasswords
 When password authentication is allowed, it specifies whether the
 server allows login to accounts with empty password strings.
@@ -568,7 +603,7 @@
 is used for interactive login sessions.
 Note that
 .Xr login 1
-is not never for remote command execution.
+is never used for remote command execution.
 The default is
 .Dq no .
 .It Cm X11DisplayOffset
@@ -666,7 +701,7 @@
 .Pa identity.pub
 file and edit it.
 .Pp
-The options (if present) consists of comma-separated option
+The options (if present) consist of comma-separated option
 specifications.
 No spaces are permitted, except within double quotes.
 The following option specifications are supported:
@@ -740,7 +775,7 @@
 files contain host public keys for all known hosts.
 The global file should
 be prepared by the administrator (optional), and the per-user file is
-maintained automatically: whenever the user connects an unknown host
+maintained automatically: whenever the user connects from an unknown host
 its key is added to the per-user file.
 .Pp
 Each line in these files contains the following fields: hostnames,
@@ -815,7 +850,7 @@
 listening for connections (if there are several daemons running
 concurrently for different ports, this contains the pid of the one
 started last).
-The contents of this file are not sensitive; it can be world-readable.
+The content of this file is not sensitive; it can be world-readable.
 .It Pa $HOME/.ssh/authorized_keys
 Lists the RSA keys that can be used to log into the user's account.
 This file must be readable by root (which may on some machines imply
@@ -843,7 +878,7 @@
 authentication to check the public key of the host.
 The key must be listed in one of these files to be accepted.
 The client uses the same files
-to verify that the remote host is the one we intended to connect.
+to verify that the remote host is the one it intended to connect.
 These files should be writable only by root/the owner.
 .Pa /etc/ssh_known_hosts
 should be world-readable, and
@@ -882,7 +917,7 @@
 .Pa .rhosts .
 However, this file is
 not used by rlogin and rshd, so using this permits access using SSH only.
-.Pa /etc/hosts.equiv
+.It Pa /etc/hosts.equiv
 This file is used during
 .Pa .rhosts
 authentication.
diff --git a/sshd.c b/sshd.c
index b6db074..ae02f2c 100644
--- a/sshd.c
+++ b/sshd.c
@@ -14,7 +14,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.123 2000/07/18 01:25:01 djm Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.125 2000/08/17 20:06:34 markus Exp $");
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -139,6 +139,9 @@
 unsigned char *session_id2 = NULL;
 int session_id2_len = 0;
 
+/* record remote hostname or ip */
+unsigned int utmp_len = MAXHOSTNAMELEN;
+
 /* Prototypes for various functions defined later in this file. */
 void do_ssh1_kex();
 void do_ssh2_kex();
@@ -400,6 +403,35 @@
 		key_free(sensitive_data.dsa_host_key);
 }
 
+/*
+ * returns 1 if connection should be dropped, 0 otherwise.
+ * dropping starts at connection #max_startups_begin with a probability
+ * of (max_startups_rate/100). the probability increases linearly until
+ * all connections are dropped for startups > max_startups
+ */
+int
+drop_connection(int startups)
+{
+	double p, r;
+
+	if (startups < options.max_startups_begin)
+		return 0;
+	if (startups >= options.max_startups)
+		return 1;
+	if (options.max_startups_rate == 100)
+		return 1;
+
+	p  = 100 - options.max_startups_rate;
+	p *= startups - options.max_startups_begin;
+	p /= (double) (options.max_startups - options.max_startups_begin);
+	p += options.max_startups_rate;
+	p /= 100.0;
+	r = arc4random() / (double) UINT_MAX;
+
+	debug("drop_connection: p %g, r %g", p, r);
+	return (r < p) ? 1 : 0;
+}
+
 int *startup_pipes = NULL;	/* options.max_startup sized array of fd ints */
 int startup_pipe;		/* in child */
 
@@ -441,7 +473,7 @@
 	initialize_server_options(&options);
 
 	/* Parse command-line arguments. */
-	while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ46")) != EOF) {
+	while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:diqQ46")) != EOF) {
 		switch (opt) {
 		case '4':
 			IPv4or6 = AF_INET;
@@ -488,6 +520,9 @@
 			/* only makes sense with inetd_flag, i.e. no listen() */
 			inetd_flag = 1;
 			break;
+		case 'u':
+			utmp_len = atoi(optarg);
+			break;
 		case '?':
 		default:
 			fprintf(stderr, "sshd version %s\n", SSH_VERSION);
@@ -503,6 +538,7 @@
 			fprintf(stderr, "  -b bits    Size of server RSA key (default: 768 bits)\n");
 			fprintf(stderr, "  -h file    File from which to read host key (default: %s)\n",
 			    HOST_KEY_FILE);
+			fprintf(stderr, "  -u len     Maximum hostname length for utmp recording\n");
 			fprintf(stderr, "  -4         Use IPv4 only\n");
 			fprintf(stderr, "  -6         Use IPv6 only\n");
 			exit(1);
@@ -823,7 +859,8 @@
 					error("newsock del O_NONBLOCK: %s", strerror(errno));
 					continue;
 				}
-				if (startups >= options.max_startups) {
+				if (drop_connection(startups) == 1) {
+					debug("drop connection #%d", startups);
 					close(newsock);
 					continue;
 				}
diff --git a/sshd_config b/sshd_config
index d3bab84..a97b780 100644
--- a/sshd_config
+++ b/sshd_config
@@ -51,3 +51,4 @@
 UseLogin no
 
 #Subsystem	sftp	/usr/local/sbin/sftpd
+#MaxStartups 10:30:60