- Update to latest OpenBSD CVS:
- [auth-rsa.c]
- fix user/1056, sshd keeps restrictions; dbt@meat.net
- [sshconnect.c]
- disable agent fwding for proto 1.3, remove abuse of auth-rsa flags.
- destroy keys earlier
- split key exchange (kex) and user authentication (user-auth), ok: provos@
- [sshd.c]
- no need for poll.h; from bright@wintelcom.net
- disable agent fwding for proto 1.3, remove abuse of auth-rsa flags.
- split key exchange (kex) and user authentication (user-auth), ok: provos@
diff --git a/ChangeLog b/ChangeLog
index d49ac0b..25ca7e0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
20000120
- Don't use getaddrinfo on AIX
+ - Update to latest OpenBSD CVS:
+ - [auth-rsa.c]
+ - fix user/1056, sshd keeps restrictions; dbt@meat.net
+ - [sshconnect.c]
+ - disable agent fwding for proto 1.3, remove abuse of auth-rsa flags.
+ - destroy keys earlier
+ - split key exchange (kex) and user authentication (user-auth), ok: provos@
+ - [sshd.c]
+ - no need for poll.h; from bright@wintelcom.net
+ - disable agent fwding for proto 1.3, remove abuse of auth-rsa flags.
+ - split key exchange (kex) and user authentication (user-auth), ok: provos@
20000119
- SCO compile fixes from Gary E. Miller <gem@rellim.com>
diff --git a/auth-rsa.c b/auth-rsa.c
index bc53b04..9d9e749 100644
--- a/auth-rsa.c
+++ b/auth-rsa.c
@@ -16,7 +16,7 @@
*/
#include "includes.h"
-RCSID("$Id: auth-rsa.c,v 1.11 1999/12/06 00:47:28 damien Exp $");
+RCSID("$Id: auth-rsa.c,v 1.12 2000/01/20 11:44:09 damien Exp $");
#include "rsa.h"
#include "packet.h"
@@ -415,7 +415,22 @@
packet_send_debug("Your host '%.200s' is not permitted to use this key for login.",
get_canonical_hostname());
xfree(patterns);
+ /* key invalid for this host, reset flags */
authenticated = 0;
+ no_agent_forwarding_flag = 0;
+ no_port_forwarding_flag = 0;
+ no_pty_flag = 0;
+ no_x11_forwarding_flag = 0;
+ while (custom_environment) {
+ struct envstring *ce = custom_environment;
+ custom_environment = ce->next;
+ xfree(ce->s);
+ xfree(ce);
+ }
+ if (forced_command) {
+ xfree(forced_command);
+ forced_command = NULL;
+ }
break;
}
xfree(patterns);
diff --git a/ssh.1.in b/ssh.1.in
index d2ac0f2..b93e1c8 100644
--- a/ssh.1.in
+++ b/ssh.1.in
@@ -9,7 +9,7 @@
.\"
.\" Created: Sat Apr 22 21:55:14 1995 ylo
.\"
-.\" $Id: ssh.1.in,v 1.2 2000/01/14 04:45:51 damien Exp $
+.\" $Id: ssh.1.in,v 1.3 2000/01/20 11:44:09 damien Exp $
.\"
.Dd September 25, 1999
.Dt SSH 1
@@ -33,16 +33,16 @@
.Op Fl p Ar port
.Oo Fl L Xo
.Sm off
-.Ar host :
.Ar port :
+.Ar host :
.Ar hostport
.Sm on
.Xc
.Oc
.Oo Fl R Xo
.Sm off
-.Ar host :
.Ar port :
+.Ar host :
.Ar hostport
.Sm on
.Xc
@@ -302,6 +302,8 @@
The recommended way to start X11 programs at a remote site is with
something like
.Ic ssh -f host xterm .
+.It Fl g
+Allows remote hosts to connect to local forwarded ports.
.It Fl i Ar identity_file
Selects the file from which the identity (private key) for
RSA authentication is read. Default is
@@ -312,8 +314,6 @@
.Fl i
options (and multiple identities specified in
configuration files).
-.It Fl g
-Allows remote hosts to connect to local forwarded ports.
.It Fl k
Disables forwarding of Kerberos tickets and AFS tokens. This may
also be specified on a per-host basis in the configuration file.
@@ -378,7 +378,9 @@
.It Fl C
Requests compression of all data (including stdin, stdout, stderr, and
data for forwarded X11 and TCP/IP connections). The compression
-algorithm is the same used by gzip, and the
+algorithm is the same used by
+.Xr gzip 1 ,
+and the
.Dq level
can be controlled by the
.Cm CompressionLevel
@@ -486,6 +488,15 @@
.Dq yes
or
.Dq no .
+.It Cm CheckHostIP
+If this flag is set to
+.Dq yes ,
+ssh will additionally check the host ip address in the
+.Pa known_hosts
+file. This allows ssh to detect if a host key changed due to DNS spoofing.
+If the option is set to
+.Dq no ,
+the check will not be executed.
.It Cm Cipher
Specifies the cipher to use for encrypting the session. Currently,
.Dq blowfish ,
@@ -502,7 +513,8 @@
Specifies the compression level to use if compression is enable. The
argument must be an integer from 1 (fast) to 9 (slow, best). The
default level is 6, which is good for most applications. The meaning
-of the values is the same as in GNU GZIP.
+of the values is the same as in
+.Xr gzip 1 .
.It Cm ConnectionAttempts
Specifies the number of tries (one per second) to make before falling
back to rsh or exiting. The argument must be an integer. This may be
@@ -610,12 +622,6 @@
host:port. Multiple forwardings may be specified, and additional
forwardings can be given on the command line. Only the root can
forward privileged ports.
-.It Cm PasswordAuthentication
-Specifies whether to use password authentication. The argument to
-this keyword must be
-.Dq yes
-or
-.Dq no .
.It Cm LogLevel
Gives the verbosity level that is used when logging messages from
.Nm ssh .
@@ -625,6 +631,12 @@
.It Cm NumberOfPasswordPrompts
Specifies the number of password prompts before giving up. The
argument to this keyword must be an integer. Default is 3.
+.It Cm PasswordAuthentication
+Specifies whether to use password authentication. The argument to
+this keyword must be
+.Dq yes
+or
+.Dq no .
.It Cm Port
Specifies the port number to connect on the remote host. Default is
22.
@@ -689,15 +701,6 @@
.Dq no .
The default is
.Dq no .
-.It Cm CheckHostIP
-If this flag is set to
-.Dq yes ,
-ssh will additionally check the host ip address in the
-.Pa known_hosts
-file. This allows ssh to detect if a host key changed due to DNS spoofing.
-If the option is set to
-.Dq no ,
-the check will not be executed.
.It Cm StrictHostKeyChecking
If this flag is set to
.Dq yes ,
@@ -717,13 +720,6 @@
.Dq yes
or
.Dq no .
-.It Cm User
-Specifies the user to log in as. This can be useful if you have a
-different user name in different machines. This saves the trouble of
-having to remember to give the user name on the command line.
-.It Cm UserKnownHostsFile
-Specifies a file to use instead of
-.Pa $HOME/.ssh/known_hosts .
.It Cm UsePrivilegedPort
Specifies whether to use a privileged port for outgoing connections.
The argument must be
@@ -738,6 +734,13 @@
.Cm RhostsAuthentication
and
.Cm RhostsRSAAuthentication .
+.It Cm User
+Specifies the user to log in as. This can be useful if you have a
+different user name in different machines. This saves the trouble of
+having to remember to give the user name on the command line.
+.It Cm UserKnownHostsFile
+Specifies a file to use instead of
+.Pa $HOME/.ssh/known_hosts .
.It Cm UseRsh
Specifies that rlogin/rsh should be used for this host. It is
possible that the host does not at all support the
diff --git a/sshconnect.c b/sshconnect.c
index 068c230..5e2a344 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -8,7 +8,7 @@
*/
#include "includes.h"
-RCSID("$Id: sshconnect.c,v 1.22 2000/01/19 02:45:07 damien Exp $");
+RCSID("$OpenBSD: sshconnect.c,v 1.53 2000/01/18 09:42:17 markus Exp $");
#ifdef HAVE_OPENSSL
#include <openssl/bn.h>
@@ -34,6 +34,9 @@
/* Session id for the current session. */
unsigned char session_id[16];
+/* authentications supported by server */
+unsigned int supported_authentications;
+
extern Options options;
extern char *__progname;
@@ -988,9 +991,8 @@
/* We speak 1.3, too. */
if (remote_major == 1 && remote_minor == 3) {
enable_compat13();
- if (options.forward_agent && strcmp(remote_version, "OpenSSH-1.1") != 0) {
- log("Agent forwarding disabled, remote version '%s' is not compatible.",
- remote_version);
+ if (options.forward_agent) {
+ log("Agent forwarding disabled for protocol 1.3");
options.forward_agent = 0;
}
}
@@ -1274,63 +1276,31 @@
}
/*
- * Starts a dialog with the server, and authenticates the current user on the
- * server. This does not need any extra privileges. The basic connection
- * to the server must already have been established before this is called.
- * User is the remote user; if it is NULL, the current local user name will
- * be used. Anonymous indicates that no rhosts authentication will be used.
- * If login fails, this function prints an error and never returns.
- * This function does not require super-user privileges.
+ * SSH1 key exchange
*/
void
-ssh_login(int host_key_valid,
- RSA *own_host_key,
- const char *orighost,
- struct sockaddr *hostaddr,
- uid_t original_real_uid)
+ssh_kex(char *host, struct sockaddr *hostaddr)
{
- int i, type;
- struct passwd *pw;
+ int i;
BIGNUM *key;
RSA *host_key;
RSA *public_key;
int bits, rbits;
unsigned char session_key[SSH_SESSION_KEY_LENGTH];
- const char *server_user, *local_user;
- char *host, *cp;
- unsigned char check_bytes[8];
- unsigned int supported_ciphers, supported_authentications;
+ unsigned char cookie[8];
+ unsigned int supported_ciphers;
unsigned int server_flags, client_flags;
int payload_len, clen, sum_len = 0;
u_int32_t rand = 0;
- /* Convert the user-supplied hostname into all lowercase. */
- host = xstrdup(orighost);
- for (cp = host; *cp; cp++)
- if (isupper(*cp))
- *cp = tolower(*cp);
-
- /* Exchange protocol version identification strings with the server. */
- ssh_exchange_identification();
-
- /* Put the connection into non-blocking mode. */
- packet_set_nonblocking();
-
- /* Get local user name. Use it as server user if no user name was given. */
- pw = getpwuid(original_real_uid);
- if (!pw)
- fatal("User id %d not found from user database.", original_real_uid);
- local_user = xstrdup(pw->pw_name);
- server_user = options.user ? options.user : local_user;
-
debug("Waiting for server public key.");
/* Wait for a public key packet from the server. */
packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY);
- /* Get check bytes from the packet. */
+ /* Get cookie from the packet. */
for (i = 0; i < 8; i++)
- check_bytes[i] = packet_get_char();
+ cookie[i] = packet_get_char();
/* Get the public key. */
public_key = RSA_new();
@@ -1383,7 +1353,7 @@
client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN;
- compute_session_id(session_id, check_bytes, host_key->n, public_key->n);
+ compute_session_id(session_id, cookie, host_key->n, public_key->n);
/* Generate a session key. */
arc4random_stir();
@@ -1445,6 +1415,10 @@
rsa_public_encrypt(key, key, public_key);
}
+ /* Destroy the public keys since we no longer need them. */
+ RSA_free(public_key);
+ RSA_free(host_key);
+
if (options.cipher == SSH_CIPHER_NOT_SET) {
if (cipher_mask() & supported_ciphers & (1 << ssh_cipher_default))
options.cipher = ssh_cipher_default;
@@ -1466,12 +1440,13 @@
packet_start(SSH_CMSG_SESSION_KEY);
packet_put_char(options.cipher);
- /* Send the check bytes back to the server. */
+ /* Send the cookie back to the server. */
for (i = 0; i < 8; i++)
- packet_put_char(check_bytes[i]);
+ packet_put_char(cookie[i]);
- /* Send the encrypted encryption key. */
+ /* Send and destroy the encrypted encryption key integer. */
packet_put_bignum(key);
+ BN_clear_free(key);
/* Send protocol flags. */
packet_put_int(client_flags);
@@ -1480,11 +1455,6 @@
packet_send();
packet_write_wait();
- /* Destroy the session key integer and the public keys since we no longer need them. */
- BN_clear_free(key);
- RSA_free(public_key);
- RSA_free(host_key);
-
debug("Sent encrypted session key.");
/* Set the encryption key. */
@@ -1500,6 +1470,26 @@
packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
debug("Received encrypted confirmation.");
+}
+
+/*
+ * Authenticate user
+ */
+void
+ssh_userauth(int host_key_valid, RSA *own_host_key,
+ uid_t original_real_uid, char *host)
+{
+ int i, type;
+ int payload_len;
+ struct passwd *pw;
+ const char *server_user, *local_user;
+
+ /* Get local user name. Use it as server user if no user name was given. */
+ pw = getpwuid(original_real_uid);
+ if (!pw)
+ fatal("User id %d not found from user database.", original_real_uid);
+ local_user = xstrdup(pw->pw_name);
+ server_user = options.user ? options.user : local_user;
/* Send the name of the user to log in as on the server. */
packet_start(SSH_CMSG_USER);
@@ -1618,3 +1608,37 @@
fatal("Permission denied.");
/* NOTREACHED */
}
+
+/*
+ * Starts a dialog with the server, and authenticates the current user on the
+ * server. This does not need any extra privileges. The basic connection
+ * to the server must already have been established before this is called.
+ * If login fails, this function prints an error and never returns.
+ * This function does not require super-user privileges.
+ */
+void
+ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost,
+ struct sockaddr *hostaddr, uid_t original_real_uid)
+{
+ char *host, *cp;
+
+ /* Convert the user-supplied hostname into all lowercase. */
+ host = xstrdup(orighost);
+ for (cp = host; *cp; cp++)
+ if (isupper(*cp))
+ *cp = tolower(*cp);
+
+ /* Exchange protocol version identification strings with the server. */
+ ssh_exchange_identification();
+
+ /* Put the connection into non-blocking mode. */
+ packet_set_nonblocking();
+
+ supported_authentications = 0;
+ /* key exchange */
+ ssh_kex(host, hostaddr);
+ if (supported_authentications == 0)
+ fatal("supported_authentications == 0.");
+ /* authenticate user */
+ ssh_userauth(host_key_valid, own_host_key, original_real_uid, host);
+}
diff --git a/sshd.8.in b/sshd.8.in
index 671fe4c..7448fd1 100644
--- a/sshd.8.in
+++ b/sshd.8.in
@@ -9,7 +9,7 @@
.\"
.\" Created: Sat Apr 22 21:55:14 1995 ylo
.\"
-.\" $Id: sshd.8.in,v 1.3 2000/01/17 11:02:18 damien Exp $
+.\" $Id: sshd.8.in,v 1.4 2000/01/20 11:44:10 damien Exp $
.\"
.Dd September 25, 1999
.Dt SSHD 8
@@ -242,7 +242,7 @@
.Pp
.It Cm DenyUsers
This keyword can be followed by a number of user names, separated
-by spaces. Login is allowed disallowed for user names that match
+by spaces. Login is disallowed for user names that match
one of the patterns.
.Ql \&*
and
@@ -436,17 +436,17 @@
.Xr login 1
is used. The default is
.Dq no .
-.It Cm X11Forwarding
-Specifies whether X11 forwarding is permitted. The default is
-.Dq yes .
-Note that disabling X11 forwarding does not improve security in any
-way, as users can always install their own forwarders.
.It Cm X11DisplayOffset
Specifies the first display number available for
.Nm sshd Ns 's
X11 forwarding. This prevents
.Nm
from interfering with real X11 servers.
+.It Cm X11Forwarding
+Specifies whether X11 forwarding is permitted. The default is
+.Dq yes .
+Note that disabling X11 forwarding does not improve security in any
+way, as users can always install their own forwarders.
.El
.Sh LOGIN PROCESS
When a user successfully logs in,
diff --git a/sshd.c b/sshd.c
index 371b2a5..03a9ce1 100644
--- a/sshd.c
+++ b/sshd.c
@@ -11,7 +11,7 @@
*/
#include "includes.h"
-RCSID("$Id: sshd.c,v 1.51 2000/01/19 03:36:50 damien Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.79 2000/01/18 13:45:05 markus Exp $");
#include "xmalloc.h"
#include "rsa.h"
@@ -131,8 +131,8 @@
RSA *public_key;
/* Prototypes for various functions defined later in this file. */
-void do_connection();
-void do_authentication(char *user);
+void do_ssh_kex();
+void do_authentication();
void do_authloop(struct passwd * pw);
void do_fake_authloop(char *user);
void do_authenticated(struct passwd * pw);
@@ -835,11 +835,8 @@
packet_disconnect("Your ssh version is too old and is no longer supported. Please install a newer version.");
if (remote_major == 1 && remote_minor == 3) {
+ /* note that this disables agent-forwarding */
enable_compat13();
- if (strcmp(remote_version, "OpenSSH-1.1") != 0) {
- debug("Agent forwarding disabled, remote version is not compatible.");
- no_agent_forwarding_flag = 1;
- }
}
/*
* Check that the connection comes from a privileged port. Rhosts-
@@ -863,8 +860,11 @@
packet_set_nonblocking();
- /* Handle the connection. */
- do_connection();
+ /* perform the key exchange */
+ do_ssh_kex();
+
+ /* authenticate user and start session */
+ do_authentication();
#ifdef KRB4
/* Cleanup user's ticket cache file. */
@@ -888,20 +888,17 @@
}
/*
- * Process an incoming connection. Protocol version identifiers have already
- * been exchanged. This sends server key and performs the key exchange.
- * Server and host keys will no longer be needed after this functions.
+ * SSH1 key exchange
*/
void
-do_connection()
+do_ssh_kex()
{
int i, len;
+ int plen, slen;
BIGNUM *session_key_int;
unsigned char session_key[SSH_SESSION_KEY_LENGTH];
- unsigned char check_bytes[8];
- char *user;
+ unsigned char cookie[8];
unsigned int cipher_type, auth_mask, protocol_flags;
- int plen, slen, ulen;
u_int32_t rand = 0;
/*
@@ -916,7 +913,7 @@
for (i = 0; i < 8; i++) {
if (i % 4 == 0)
rand = arc4random();
- check_bytes[i] = rand & 0xff;
+ cookie[i] = rand & 0xff;
rand >>= 8;
}
@@ -927,7 +924,7 @@
*/
packet_start(SSH_SMSG_PUBLIC_KEY);
for (i = 0; i < 8; i++)
- packet_put_char(check_bytes[i]);
+ packet_put_char(cookie[i]);
/* Store our public server RSA key. */
packet_put_int(BN_num_bits(public_key->n));
@@ -990,7 +987,7 @@
/* Get check bytes from the packet. These must match those we
sent earlier with the public key packet. */
for (i = 0; i < 8; i++)
- if (check_bytes[i] != packet_get_char())
+ if (cookie[i] != packet_get_char())
packet_disconnect("IP Spoofing check bytes do not match.");
debug("Encryption type: %.200s", cipher_name(cipher_type));
@@ -1038,10 +1035,15 @@
sensitive_data.private_key);
}
- compute_session_id(session_id, check_bytes,
+ compute_session_id(session_id, cookie,
sensitive_data.host_key->n,
sensitive_data.private_key->n);
+ /* Destroy the private and public keys. They will no longer be needed. */
+ RSA_free(public_key);
+ RSA_free(sensitive_data.private_key);
+ RSA_free(sensitive_data.host_key);
+
/*
* Extract session key from the decrypted integer. The key is in the
* least significant 256 bits of the integer; the first byte of the
@@ -1056,13 +1058,13 @@
memset(session_key, 0, sizeof(session_key));
BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len);
+ /* Destroy the decrypted integer. It is no longer needed. */
+ BN_clear_free(session_key_int);
+
/* Xor the first 16 bytes of the session key with the session id. */
for (i = 0; i < 16; i++)
session_key[i] ^= session_id[i];
- /* Destroy the decrypted integer. It is no longer needed. */
- BN_clear_free(session_key_int);
-
/* Set the session key. From this on all communications will be encrypted. */
packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, cipher_type);
@@ -1075,24 +1077,9 @@
packet_start(SSH_SMSG_SUCCESS);
packet_send();
packet_write_wait();
-
- /* Get the name of the user that we wish to log in as. */
- packet_read_expect(&plen, SSH_CMSG_USER);
-
- /* Get the user name. */
- user = packet_get_string(&ulen);
- packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
-
- /* Destroy the private and public keys. They will no longer be needed. */
- RSA_free(public_key);
- RSA_free(sensitive_data.private_key);
- RSA_free(sensitive_data.host_key);
-
- setproctitle("%s", user);
- /* Do the authentication. */
- do_authentication(user);
}
+
/*
* Check if the user is allowed to log in via ssh. If user is listed in
* DenyUsers or user's primary group is listed in DenyGroups, false will
@@ -1168,13 +1155,23 @@
/*
* Performs authentication of an incoming connection. Session key has already
- * been exchanged and encryption is enabled. User is the user name to log
- * in as (received from the client).
+ * been exchanged and encryption is enabled.
*/
void
-do_authentication(char *user)
+do_authentication()
{
struct passwd *pw, pwcopy;
+ int plen, ulen;
+ char *user;
+
+ /* Get the name of the user that we wish to log in as. */
+ packet_read_expect(&plen, SSH_CMSG_USER);
+
+ /* Get the user name. */
+ user = packet_get_string(&ulen);
+ packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
+
+ setproctitle("%s", user);
#ifdef AFS
/* If machine has AFS, set process authentication group. */
@@ -1771,7 +1768,7 @@
#endif /* XAUTH_PATH */
case SSH_CMSG_AGENT_REQUEST_FORWARDING:
- if (no_agent_forwarding_flag) {
+ if (no_agent_forwarding_flag || compat13) {
debug("Authentication agent forwarding not permitted for this authentication.");
goto fail;
}