- (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