+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
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
@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
#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;
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]);
}
} 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!
*/
#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"
#include "ssh2.h"
#include "auth.h"
#include "session.h"
-#include "dispatch.h"
-
/* import */
extern ServerOptions options;
*/
#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"
#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. */
ssh_get_authentication_socket()
{
const char *authsocket;
- int sock;
+ int sock, len;
struct sockaddr_un sunaddr;
authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
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)
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
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));
- 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);
+ buffer_init(&request);
+ buffer_put_char(&request, SSH_AGENTC_REQUEST_RSA_IDENTITIES);
- /* 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;
+ if (ssh_request_reply(auth, &request, &auth->identities) == 0) {
+ buffer_free(&request);
+ return 0;
}
+ 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);
int
ssh_get_next_identity(AuthenticationConnection *auth,
- BIGNUM *e, BIGNUM *n, char **comment)
+ BIGNUM *e, BIGNUM *n, char **comment)
{
unsigned int bits;
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);
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;
- }
-
- /* 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);
+ type = buffer_get_char(&buffer);
- /* 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. */
ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
{
Buffer buffer;
- unsigned char buf[8192];
- int len;
+ int type;
buffer_init(&buffer);
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);
}
/*
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);
}
/*
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);
+ type = buffer_get_char(&buffer);
+ buffer_free(&buffer);
+ return decode_reply(type);
}
-/*
- * Read for reply from agent. returns 1 for success, 0 on error
- */
-
int
-ssh_agent_get_reply(AuthenticationConnection *auth)
+decode_reply(int type)
{
- 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);
switch (type) {
case SSH_AGENT_FAILURE:
-log("SSH_AGENT_FAILURE");
+ log("SSH_AGENT_FAILURE");
return 0;
case SSH_AGENT_SUCCESS:
return 1;
#include <unistd.h>
#include "bsd-misc.h"
+#include "bsd-arc4random.h"
static int _gettemp(char *, int *, int, int);
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(
*/
#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"
*/
#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"
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;
}
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. */
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;
*
*/
-/* 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
char *subsystem_name[MAX_SUBSYSTEMS];
char *subsystem_command[MAX_SUBSYSTEMS];
+ int max_startups_begin;
+ int max_startups_rate;
int max_startups;
} ServerOptions;
*/
#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"
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,
extern int log_stderr;
extern int debug_flag;
+extern unsigned int utmp_len;
extern int startup_pipe;
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();
/* 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. */
/* 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);
-
- /* Check if .hushlogin exists. */
- snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);
- quiet_login = stat(line, &st) >= 0;
+ /* record login, etc. similar to login(1) */
+ if (command == NULL && !options.use_login)
+ do_login(s);
-#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);
}
}
+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.
} 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. */
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.
.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
.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.
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
.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
.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
.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
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.
.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.
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
.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.
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
.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:
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,
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
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
.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.
*/
#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"
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();
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 */
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;
/* 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);
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);
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;
}
UseLogin no
#Subsystem sftp /usr/local/sbin/sftpd
+#MaxStartups 10:30:60