summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.bin/ssh/clientloop.c166
-rw-r--r--usr.bin/ssh/compat.c6
-rw-r--r--usr.bin/ssh/myproposal.h20
-rw-r--r--usr.bin/ssh/ssh.c162
-rw-r--r--usr.bin/ssh/sshconnect.c345
5 files changed, 633 insertions, 66 deletions
diff --git a/usr.bin/ssh/clientloop.c b/usr.bin/ssh/clientloop.c
index a5bfa0a5b49..744f63bebfa 100644
--- a/usr.bin/ssh/clientloop.c
+++ b/usr.bin/ssh/clientloop.c
@@ -12,10 +12,11 @@
*
* The main loop for the interactive session (client side).
*
+ * SSH2 support added by Markus Friedl.
*/
#include "includes.h"
-RCSID("$Id: clientloop.c,v 1.15 2000/03/28 20:31:26 markus Exp $");
+RCSID("$Id: clientloop.c,v 1.16 2000/04/04 15:19:42 markus Exp $");
#include "xmalloc.h"
#include "ssh.h"
@@ -24,6 +25,7 @@ RCSID("$Id: clientloop.c,v 1.15 2000/03/28 20:31:26 markus Exp $");
#include "authfd.h"
#include "readconf.h"
+#include "ssh2.h"
#include "compat.h"
#include "channels.h"
#include "dispatch.h"
@@ -75,6 +77,10 @@ static unsigned long stdin_bytes, stdout_bytes, stderr_bytes;
static int quit_pending; /* Set to non-zero to quit the client loop. */
static int escape_char; /* Escape character. */
+
+void client_init_dispatch(void);
+int session_ident = -1;
+
/* Returns the user\'s terminal to normal mode if it had been put in raw mode. */
void
@@ -273,23 +279,32 @@ client_make_packets_from_stdin_data()
void
client_check_window_change()
{
- /* Send possible window change message to the server. */
- if (received_window_change_signal) {
- struct winsize ws;
-
- /* Clear the window change indicator. */
- received_window_change_signal = 0;
-
- /* Read new window size. */
- if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) >= 0) {
- /* Successful, send the packet now. */
- packet_start(SSH_CMSG_WINDOW_SIZE);
- packet_put_int(ws.ws_row);
- packet_put_int(ws.ws_col);
- packet_put_int(ws.ws_xpixel);
- packet_put_int(ws.ws_ypixel);
- packet_send();
- }
+ struct winsize ws;
+
+ if (! received_window_change_signal)
+ return;
+ /** XXX race */
+ received_window_change_signal = 0;
+
+ if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
+ return;
+
+ debug("client_check_window_change: changed");
+
+ if (compat20) {
+ channel_request_start(session_ident, "window-change", 0);
+ packet_put_int(ws.ws_col);
+ packet_put_int(ws.ws_row);
+ packet_put_int(ws.ws_xpixel);
+ packet_put_int(ws.ws_ypixel);
+ packet_send();
+ } else {
+ packet_start(SSH_CMSG_WINDOW_SIZE);
+ packet_put_int(ws.ws_row);
+ packet_put_int(ws.ws_col);
+ packet_put_int(ws.ws_xpixel);
+ packet_put_int(ws.ws_ypixel);
+ packet_send();
}
}
@@ -301,21 +316,28 @@ client_check_window_change()
void
client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
{
+ /*debug("client_wait_until_can_do_something"); */
+
/* Initialize select masks. */
FD_ZERO(readset);
/* Read from the connection, unless our buffers are full. */
- if (buffer_len(&stdout_buffer) < buffer_high &&
- buffer_len(&stderr_buffer) < buffer_high &&
- channel_not_very_much_buffered_data())
+ if (!compat20) {
+ if (buffer_len(&stdout_buffer) < buffer_high &&
+ buffer_len(&stderr_buffer) < buffer_high &&
+ channel_not_very_much_buffered_data())
+ FD_SET(connection_in, readset);
+ } else {
FD_SET(connection_in, readset);
+ }
/*
* Read from stdin, unless we have seen EOF or have very much
* buffered data to send to the server.
*/
- if (!stdin_eof && packet_not_very_much_data_to_write())
- FD_SET(fileno(stdin), readset);
+ if (!compat20)
+ if (!stdin_eof && packet_not_very_much_data_to_write())
+ FD_SET(fileno(stdin), readset);
FD_ZERO(writeset);
@@ -326,14 +348,17 @@ client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
if (packet_have_data_to_write())
FD_SET(connection_out, writeset);
- /* Select stdout if have data in buffer. */
- if (buffer_len(&stdout_buffer) > 0)
- FD_SET(fileno(stdout), writeset);
+ if (!compat20) {
+ /* Select stdout if have data in buffer. */
+ if (buffer_len(&stdout_buffer) > 0)
+ FD_SET(fileno(stdout), writeset);
- /* Select stderr if have data in buffer. */
- if (buffer_len(&stderr_buffer) > 0)
- FD_SET(fileno(stderr), writeset);
+ /* Select stderr if have data in buffer. */
+ if (buffer_len(&stderr_buffer) > 0)
+ FD_SET(fileno(stderr), writeset);
+ }
+/* move UP XXX */
/* Update maximum file descriptor number, if appropriate. */
if (channel_max_fd() > max_fd)
max_fd = channel_max_fd();
@@ -420,6 +445,7 @@ client_process_input(fd_set * readset)
if (FD_ISSET(connection_in, readset)) {
/* Read as much as possible. */
len = read(connection_in, buf, sizeof(buf));
+/*debug("read connection_in len %d", len); XXX */
if (len == 0) {
/* Received EOF. The remote host has closed the connection. */
snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n",
@@ -447,6 +473,10 @@ client_process_input(fd_set * readset)
}
packet_process_incoming(buf, len);
}
+
+ if (compat20)
+ return;
+
/* Read input from stdin. */
if (FD_ISSET(fileno(stdin), readset)) {
/* Read as much as possible. */
@@ -703,8 +733,6 @@ client_process_buffered_input_packets()
* character for terminating or suspending the session.
*/
-void client_init_dispatch(void);
-
int
client_loop(int have_pty, int escape_char_arg)
{
@@ -753,7 +781,8 @@ client_loop(int have_pty, int escape_char_arg)
enter_raw_mode();
/* Check if we should immediately send of on stdin. */
- client_check_initial_eof_on_stdin();
+ if(!compat20)
+ client_check_initial_eof_on_stdin();
/* Main loop of the client for the interactive session mode. */
while (!quit_pending) {
@@ -762,11 +791,17 @@ client_loop(int have_pty, int escape_char_arg)
/* Process buffered packets sent by the server. */
client_process_buffered_input_packets();
+ if (compat20 && !channel_still_open()) {
+ debug("!channel_still_open.");
+ break;
+ }
+
/*
* Make packets of buffered stdin data, and buffer them for
* sending to the server.
*/
- client_make_packets_from_stdin_data();
+ if(!compat20)
+ client_make_packets_from_stdin_data();
/*
* Make packets from buffered channel data, and buffer them
@@ -806,7 +841,8 @@ client_loop(int have_pty, int escape_char_arg)
* Process output to stdout and stderr. Output to the
* connection is processed elsewhere (above).
*/
- client_process_output(&writeset);
+ if(!compat20)
+ client_process_output(&writeset);
/* Send as much buffered packet data as possible to the sender. */
if (FD_ISSET(connection_out, &writeset))
@@ -918,6 +954,19 @@ client_input_exit_status(int type, int plen)
}
void
+client_init_dispatch_20()
+{
+ dispatch_init(&dispatch_protocol_error);
+ dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
+ dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data);
+ dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
+ dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
+ dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
+ dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
+ dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
+ dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
+}
+void
client_init_dispatch_13()
{
dispatch_init(NULL);
@@ -944,8 +993,55 @@ client_init_dispatch_15()
void
client_init_dispatch()
{
- if (compat13)
+ if (compat20)
+ client_init_dispatch_20();
+ else if (compat13)
client_init_dispatch_13();
else
client_init_dispatch_15();
}
+
+void
+client_input_channel_req(int id, void *arg)
+{
+ Channel *c = NULL;
+ unsigned int len;
+ int success = 0;
+ int reply;
+ char *rtype;
+
+ rtype = packet_get_string(&len);
+ reply = packet_get_char();
+
+ log("session_input_channel_req: rtype %s reply %d", rtype, reply);
+
+ c = channel_lookup(id);
+ if (c == NULL)
+ fatal("session_input_channel_req: channel %d: bad channel", id);
+
+ if (session_ident == -1) {
+ error("client_input_channel_req: no channel %d", id);
+ } else if (id != session_ident) {
+ error("client_input_channel_req: bad channel %d != %d",
+ id, session_ident);
+ } else if (strcmp(rtype, "exit-status") == 0) {
+ success = 1;
+ exit_status = packet_get_int();
+ }
+ if (reply) {
+ packet_start(success ?
+ SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
+ packet_put_int(c->remote_id);
+ packet_send();
+ }
+ xfree(rtype);
+}
+
+void
+client_set_session_ident(int id)
+{
+ debug("client_set_session_ident: id %d", id);
+ session_ident = id;
+ channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST,
+ client_input_channel_req, (void *)0);
+}
diff --git a/usr.bin/ssh/compat.c b/usr.bin/ssh/compat.c
index a4579b46013..a9a3e755e28 100644
--- a/usr.bin/ssh/compat.c
+++ b/usr.bin/ssh/compat.c
@@ -28,7 +28,7 @@
*/
#include "includes.h"
-RCSID("$Id: compat.c,v 1.6 2000/04/03 07:07:15 markus Exp $");
+RCSID("$Id: compat.c,v 1.7 2000/04/04 15:19:42 markus Exp $");
#include "ssh.h"
#include "packet.h"
@@ -40,7 +40,9 @@ int datafellows = 0;
void
enable_compat20(void)
{
- fatal("protocol 2.0 not implemented");
+ verbose("Enabling compatibility mode for protocol 2.0");
+ compat20 = 1;
+ packet_set_ssh2_format();
}
void
enable_compat13(void)
diff --git a/usr.bin/ssh/myproposal.h b/usr.bin/ssh/myproposal.h
new file mode 100644
index 00000000000..7e4baff9dd0
--- /dev/null
+++ b/usr.bin/ssh/myproposal.h
@@ -0,0 +1,20 @@
+#define KEX_DEFAULT_KEX "diffie-hellman-group1-sha1"
+#define KEX_DEFAULT_PK_ALG "ssh-dss"
+#define KEX_DEFAULT_ENCRYPT "blowfish-cbc,3des-cbc,arcfour,cast128-cbc"
+#define KEX_DEFAULT_MAC "hmac-sha1,hmac-md5,hmac-ripemd160@openssh.com"
+#define KEX_DEFAULT_COMP "zlib,none"
+#define KEX_DEFAULT_LANG ""
+
+
+static const char *myproposal[PROPOSAL_MAX] = {
+ KEX_DEFAULT_KEX,
+ KEX_DEFAULT_PK_ALG,
+ KEX_DEFAULT_ENCRYPT,
+ KEX_DEFAULT_ENCRYPT,
+ KEX_DEFAULT_MAC,
+ KEX_DEFAULT_MAC,
+ KEX_DEFAULT_COMP,
+ KEX_DEFAULT_COMP,
+ KEX_DEFAULT_LANG,
+ KEX_DEFAULT_LANG
+};
diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c
index bbfb9b50928..35dc45d2d1b 100644
--- a/usr.bin/ssh/ssh.c
+++ b/usr.bin/ssh/ssh.c
@@ -11,7 +11,7 @@
*/
#include "includes.h"
-RCSID("$Id: ssh.c,v 1.44 2000/03/28 20:31:28 markus Exp $");
+RCSID("$Id: ssh.c,v 1.45 2000/04/04 15:19:42 markus Exp $");
#include "xmalloc.h"
#include "ssh.h"
@@ -20,6 +20,9 @@ RCSID("$Id: ssh.c,v 1.44 2000/03/28 20:31:28 markus Exp $");
#include "authfd.h"
#include "readconf.h"
#include "uidswap.h"
+
+#include "ssh2.h"
+#include "compat.h"
#include "channels.h"
/* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
@@ -31,6 +34,10 @@ int debug_flag = 0;
int tty_flag = 0;
+/* don't exec a shell */
+int no_shell_flag = 0;
+int no_tty_flag = 0;
+
/*
* Flag indicating that nothing should be read from stdin. This can be set
* on the command line.
@@ -80,6 +87,9 @@ RSA *host_private_key = NULL;
/* Original real UID. */
uid_t original_real_uid;
+/* command to be executed */
+Buffer command;
+
/* Prints a help message to the user. This function never returns. */
void
@@ -94,9 +104,9 @@ usage()
fprintf(stderr, " -k Disable Kerberos ticket and AFS token forwarding.\n");
#endif /* AFS */
fprintf(stderr, " -x Disable X11 connection forwarding.\n");
- fprintf(stderr, " -X Enable X11 connection forwarding.\n");
fprintf(stderr, " -i file Identity for RSA authentication (default: ~/.ssh/identity).\n");
fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n");
+ fprintf(stderr, " -T Do not allocate a tty.\n");
fprintf(stderr, " -v Verbose; display verbose debugging messages.\n");
fprintf(stderr, " -V Display version number only.\n");
fprintf(stderr, " -P Don't allocate a privileged port.\n");
@@ -113,6 +123,7 @@ usage()
fprintf(stderr, " These cause %s to listen for connections on a port, and\n", av0);
fprintf(stderr, " forward them to the other side by connecting to host:port.\n");
fprintf(stderr, " -C Enable compression.\n");
+ fprintf(stderr, " -N Do not execute a shell or command.\n");
fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n");
fprintf(stderr, " -4 Use IPv4 only.\n");
fprintf(stderr, " -6 Use IPv6 only.\n");
@@ -158,23 +169,22 @@ rsh_connect(char *host, char *user, Buffer * command)
exit(1);
}
+int ssh_session(void);
+int ssh_session2(void);
+
/*
* Main program for the ssh client.
*/
int
main(int ac, char **av)
{
- int i, opt, optind, type, exit_status, ok, authfd;
+ int i, opt, optind, exit_status, ok;
u_short fwd_port, fwd_host_port;
char *optarg, *cp, buf[256];
- Buffer command;
- struct winsize ws;
struct stat st;
struct passwd *pw, pwcopy;
- int interactive = 0, dummy;
- int have_pty = 0;
+ int dummy;
uid_t original_effective_uid;
- int plen;
/*
* Save the original real uid. It will be needed later (uid-swapping
@@ -318,7 +328,7 @@ main(int ac, char **av)
case 'V':
fprintf(stderr, "SSH Version %s, protocol version %d.%d.\n",
SSH_VERSION, PROTOCOL_MAJOR, PROTOCOL_MINOR);
- fprintf(stderr, "Compiled with SSL.\n");
+ fprintf(stderr, "Compiled with SSL (0x%8.8lx).\n", SSLeay());
if (opt == 'V')
exit(0);
debug_flag = 1;
@@ -387,6 +397,15 @@ main(int ac, char **av)
options.compression = 1;
break;
+ case 'N':
+ no_shell_flag = 1;
+ no_tty_flag = 1;
+ break;
+
+ case 'T':
+ no_tty_flag = 1;
+ break;
+
case 'o':
dummy = 1;
if (process_config_line(&options, host ? host : "", optarg,
@@ -447,6 +466,10 @@ main(int ac, char **av)
fprintf(stderr, "Pseudo-terminal will not be allocated because stdin is not a terminal.\n");
tty_flag = 0;
}
+ /* force */
+ if (no_tty_flag)
+ tty_flag = 0;
+
/* Get user data. */
pw = getpwuid(original_real_uid);
if (!pw) {
@@ -612,6 +635,23 @@ main(int ac, char **av)
if (host_private_key_loaded)
RSA_free(host_private_key); /* Destroys contents safely */
+ exit_status = compat20 ? ssh_session2() : ssh_session();
+ packet_close();
+ return exit_status;
+}
+
+int
+ssh_session(void)
+{
+ int type;
+ int i;
+ int plen;
+ int interactive = 0;
+ int have_tty = 0;
+ struct winsize ws;
+ int authfd;
+ char *cp;
+
/* Enable compression if requested. */
if (options.compression) {
debug("Requesting compression at level %d.", options.compression_level);
@@ -665,7 +705,7 @@ main(int ac, char **av)
type = packet_read(&plen);
if (type == SSH_SMSG_SUCCESS) {
interactive = 1;
- have_pty = 1;
+ have_tty = 1;
} else if (type == SSH_SMSG_FAILURE)
log("Warning: Remote host failed or refused to allocate a pseudo tty.");
else
@@ -794,11 +834,103 @@ main(int ac, char **av)
}
/* Enter the interactive session. */
- exit_status = client_loop(have_pty, tty_flag ? options.escape_char : -1);
+ return client_loop(have_tty, tty_flag ? options.escape_char : -1);
+}
- /* Close the connection to the remote host. */
- packet_close();
+void
+init_local_fwd(void)
+{
+ int i;
+ /* Initiate local TCP/IP port forwardings. */
+ for (i = 0; i < options.num_local_forwards; i++) {
+ debug("Connections to local port %d forwarded to remote address %.200s:%d",
+ options.local_forwards[i].port,
+ options.local_forwards[i].host,
+ options.local_forwards[i].host_port);
+ channel_request_local_forwarding(options.local_forwards[i].port,
+ options.local_forwards[i].host,
+ options.local_forwards[i].host_port,
+ options.gateway_ports);
+ }
+}
+
+extern void client_set_session_ident(int id);
+
+void
+client_init(int id, void *arg)
+{
+ int len;
+ debug("client_init id %d arg %d", id, (int)arg);
+
+ if (no_shell_flag)
+ goto done;
+
+ if (tty_flag) {
+ struct winsize ws;
+ char *cp;
+ cp = getenv("TERM");
+ if (!cp)
+ cp = "";
+ /* Store window size in the packet. */
+ if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
+ memset(&ws, 0, sizeof(ws));
+
+ channel_request_start(id, "pty-req", 0);
+ packet_put_cstring(cp);
+ packet_put_int(ws.ws_col);
+ packet_put_int(ws.ws_row);
+ packet_put_int(ws.ws_xpixel);
+ packet_put_int(ws.ws_ypixel);
+ packet_put_cstring(""); /* XXX: encode terminal modes */
+ packet_send();
+ /* XXX wait for reply */
+ }
+ len = buffer_len(&command);
+ if (len > 0) {
+ if (len > 900)
+ len = 900;
+ debug("Sending command: %.*s", len, buffer_ptr(&command));
+ channel_request_start(id, "exec", 0);
+ packet_put_string(buffer_ptr(&command), len);
+ packet_send();
+ } else {
+ channel_request(id, "shell", 0);
+ }
+ /* channel_callback(id, SSH2_MSG_OPEN_CONFIGMATION, client_init, 0); */
+done:
+ /* register different callback, etc. XXX */
+ client_set_session_ident(id);
+}
+
+int
+ssh_session2(void)
+{
+ int window, packetmax, id;
+ int in = dup(STDIN_FILENO);
+ int out = dup(STDOUT_FILENO);
+ int err = dup(STDERR_FILENO);
+
+ if (in < 0 || out < 0 || err < 0)
+ fatal("dump in/out/err failed");
+
+ /* should be pre-session */
+ init_local_fwd();
+
+ window = 32*1024;
+ if (tty_flag) {
+ packetmax = window/8;
+ } else {
+ window *= 2;
+ packetmax = window/2;
+ }
+
+ id = channel_new(
+ "session", SSH_CHANNEL_OPENING, in, out, err,
+ window, packetmax, CHAN_EXTENDED_WRITE, xstrdup("client-session"));
+
+
+ channel_open(id);
+ channel_register_callback(id, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, client_init, (void *)0);
- /* Exit with the status returned by the program on the remote side. */
- exit(exit_status);
+ return client_loop(tty_flag, tty_flag ? options.escape_char : -1);
}
diff --git a/usr.bin/ssh/sshconnect.c b/usr.bin/ssh/sshconnect.c
index 07277986949..3999d95ea86 100644
--- a/usr.bin/ssh/sshconnect.c
+++ b/usr.bin/ssh/sshconnect.c
@@ -5,15 +5,18 @@
* Created: Sat Mar 18 22:15:47 1995 ylo
* Code to connect to a remote host, and to perform the client side of the
* login (authentication) dialog.
+ *
+ * SSH2 support added by Markus Friedl.
*/
#include "includes.h"
-RCSID("$OpenBSD: sshconnect.c,v 1.58 2000/03/23 22:15:33 markus Exp $");
+RCSID("$OpenBSD: sshconnect.c,v 1.59 2000/04/04 15:19:43 markus Exp $");
#include <ssl/bn.h>
#include "xmalloc.h"
#include "rsa.h"
#include "ssh.h"
+#include "buffer.h"
#include "packet.h"
#include "authfd.h"
#include "cipher.h"
@@ -22,10 +25,18 @@ RCSID("$OpenBSD: sshconnect.c,v 1.58 2000/03/23 22:15:33 markus Exp $");
#include "compat.h"
#include "readconf.h"
+#include "bufaux.h"
#include <ssl/rsa.h>
#include <ssl/dsa.h>
+
+#include "ssh2.h"
#include <ssl/md5.h>
+#include <ssl/dh.h>
+#include <ssl/hmac.h>
+#include "kex.h"
+#include "myproposal.h"
#include "key.h"
+#include "dsa.h"
#include "hostfile.h"
/* Session id for the current session. */
@@ -34,6 +45,9 @@ unsigned char session_id[16];
/* authentications supported by server */
unsigned int supported_authentications;
+static char *client_version_string = NULL;
+static char *server_version_string = NULL;
+
extern Options options;
extern char *__progname;
@@ -949,6 +963,21 @@ try_password_authentication(char *prompt)
return 0;
}
+char *
+chop(char *s)
+{
+ char *t = s;
+ while (*t) {
+ if(*t == '\n' || *t == '\r') {
+ *t = '\0';
+ return s;
+ }
+ t++;
+ }
+ return s;
+
+}
+
/*
* Waits for the server identification string, and sends our own
* identification string.
@@ -971,7 +1000,7 @@ ssh_exchange_identification()
if (buf[i] == '\r') {
buf[i] = '\n';
buf[i + 1] = 0;
- break;
+ continue; /**XXX wait for \n */
}
if (buf[i] == '\n') {
buf[i + 1] = 0;
@@ -979,17 +1008,21 @@ ssh_exchange_identification()
}
}
buf[sizeof(buf) - 1] = 0;
+ server_version_string = xstrdup(buf);
/*
* Check that the versions match. In future this might accept
* several versions and set appropriate flags to handle them.
*/
- if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
- remote_version) != 3)
+ if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n",
+ &remote_major, &remote_minor, remote_version) != 3)
fatal("Bad remote protocol version identification: '%.100s'", buf);
debug("Remote protocol version %d.%d, remote software version %.100s",
remote_major, remote_minor, remote_version);
+/*** XXX option for disabling 2.0 or 1.5 */
+ compat_datafellows(remote_version);
+
/* Check if the remote protocol version is too old. */
if (remote_major == 1 && remote_minor < 3)
fatal("Remote machine has too old SSH software version.");
@@ -1002,6 +1035,10 @@ ssh_exchange_identification()
options.forward_agent = 0;
}
}
+ if ((remote_major == 2 && remote_minor == 0) ||
+ (remote_major == 1 && remote_minor == 99)) {
+ enable_compat20();
+ }
#if 0
/*
* Removed for now, to permit compatibility with latter versions. The
@@ -1012,16 +1049,19 @@ ssh_exchange_identification()
fatal("Protocol major versions differ: %d vs. %d",
PROTOCOL_MAJOR, remote_major);
#endif
-
/* Send our own protocol version identification. */
snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
- PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION);
+ compat20 ? 2 : PROTOCOL_MAJOR,
+ compat20 ? 0 : PROTOCOL_MINOR,
+ SSH_VERSION);
if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf))
fatal("write: %.100s", strerror(errno));
+ client_version_string = xstrdup(buf);
+ chop(client_version_string);
+ chop(server_version_string);
+ debug("Local version string %.100s", client_version_string);
}
-int ssh_cipher_default = SSH_CIPHER_3DES;
-
int
read_yes_or_no(const char *prompt, int defval)
{
@@ -1271,6 +1311,278 @@ check_rsa_host_key(char *host, struct sockaddr *hostaddr, RSA *host_key)
}
/*
+ * SSH2 key exchange
+ */
+void
+ssh_kex2(char *host, struct sockaddr *hostaddr)
+{
+ Kex *kex;
+ char *cprop[PROPOSAL_MAX];
+ char *sprop[PROPOSAL_MAX];
+ Buffer *client_kexinit;
+ Buffer *server_kexinit;
+ int payload_len, dlen;
+ unsigned int klen, kout;
+ char *ptr;
+ char *signature = NULL;
+ unsigned int slen;
+ char *server_host_key_blob = NULL;
+ Key *server_host_key;
+ unsigned int sbloblen;
+ DH *dh;
+ BIGNUM *dh_server_pub = 0;
+ BIGNUM *shared_secret = 0;
+ int i;
+ unsigned char *kbuf;
+ unsigned char *hash;
+
+/* KEXINIT */
+
+ debug("Sending KEX init.");
+ if (options.cipher == SSH_CIPHER_ARCFOUR ||
+ options.cipher == SSH_CIPHER_3DES_CBC ||
+ options.cipher == SSH_CIPHER_CAST128_CBC ||
+ options.cipher == SSH_CIPHER_BLOWFISH_CBC) {
+ myproposal[PROPOSAL_ENC_ALGS_CTOS] = cipher_name(options.cipher);
+ myproposal[PROPOSAL_ENC_ALGS_STOC] = cipher_name(options.cipher);
+ }
+ if (options.compression) {
+ myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib";
+ myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
+ } else {
+ myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none";
+ myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
+ }
+ for (i = 0; i < PROPOSAL_MAX; i++)
+ cprop[i] = xstrdup(myproposal[i]);
+
+ client_kexinit = kex_init(cprop);
+ packet_start(SSH2_MSG_KEXINIT);
+ packet_put_raw(buffer_ptr(client_kexinit), buffer_len(client_kexinit));
+ packet_send();
+ packet_write_wait();
+
+ debug("done");
+
+ packet_read_expect(&payload_len, SSH2_MSG_KEXINIT);
+
+ /* save payload for session_id */
+ server_kexinit = xmalloc(sizeof(*server_kexinit));
+ buffer_init(server_kexinit);
+ ptr = packet_get_raw(&payload_len);
+ buffer_append(server_kexinit, ptr, payload_len);
+
+ /* skip cookie */
+ for (i = 0; i < 16; i++)
+ (void) packet_get_char();
+ /* kex init proposal strings */
+ for (i = 0; i < PROPOSAL_MAX; i++) {
+ sprop[i] = packet_get_string(NULL);
+ debug("got kexinit string: %s", sprop[i]);
+ }
+ i = (int) packet_get_char();
+ debug("first kex follow == %d", i);
+ i = packet_get_int();
+ debug("reserved == %d", i);
+
+ debug("done read kexinit");
+ kex = kex_choose_conf(cprop, sprop, 0);
+
+/* KEXDH */
+
+ debug("Sending SSH2_MSG_KEXDH_INIT.");
+
+ /* generate and send 'e', client DH public key */
+ dh = new_dh_group1();
+ packet_start(SSH2_MSG_KEXDH_INIT);
+ packet_put_bignum2(dh->pub_key);
+ packet_send();
+ packet_write_wait();
+
+#ifdef DEBUG_KEXDH
+ fprintf(stderr, "\np= ");
+ bignum_print(dh->p);
+ fprintf(stderr, "\ng= ");
+ bignum_print(dh->g);
+ fprintf(stderr, "\npub= ");
+ bignum_print(dh->pub_key);
+ fprintf(stderr, "\n");
+ DHparams_print_fp(stderr, dh);
+#endif
+
+ debug("Wait SSH2_MSG_KEXDH_REPLY.");
+
+ packet_read_expect(&payload_len, SSH2_MSG_KEXDH_REPLY);
+
+ debug("Got SSH2_MSG_KEXDH_REPLY.");
+
+ /* key, cert */
+ server_host_key_blob = packet_get_string(&sbloblen);
+ server_host_key = dsa_serverkey_from_blob(server_host_key_blob, sbloblen);
+ if (server_host_key == NULL)
+ fatal("cannot decode server_host_key_blob");
+
+ check_host_key(host, hostaddr, server_host_key);
+
+ /* DH paramter f, server public DH key */
+ dh_server_pub = BN_new();
+ if (dh_server_pub == NULL)
+ fatal("dh_server_pub == NULL");
+ packet_get_bignum2(dh_server_pub, &dlen);
+
+#ifdef DEBUG_KEXDH
+ fprintf(stderr, "\ndh_server_pub= ");
+ bignum_print(dh_server_pub);
+ fprintf(stderr, "\n");
+ debug("bits %d", BN_num_bits(dh_server_pub));
+#endif
+
+ /* signed H */
+ signature = packet_get_string(&slen);
+
+ klen = DH_size(dh);
+ kbuf = xmalloc(klen);
+ kout = DH_compute_key(kbuf, dh_server_pub, dh);
+#ifdef DEBUG_KEXDH
+ debug("shared secret: len %d/%d", klen, kout);
+ fprintf(stderr, "shared secret == ");
+ for (i = 0; i< kout; i++)
+ fprintf(stderr, "%02x", (kbuf[i])&0xff);
+ fprintf(stderr, "\n");
+#endif
+ shared_secret = BN_new();
+
+ BN_bin2bn(kbuf, kout, shared_secret);
+ memset(kbuf, 0, klen);
+ xfree(kbuf);
+
+ /* calc and verify H */
+ hash = kex_hash(
+ client_version_string,
+ server_version_string,
+ buffer_ptr(client_kexinit), buffer_len(client_kexinit),
+ buffer_ptr(server_kexinit), buffer_len(server_kexinit),
+ server_host_key_blob, sbloblen,
+ dh->pub_key,
+ dh_server_pub,
+ shared_secret
+ );
+ buffer_clear(client_kexinit);
+ buffer_clear(server_kexinit);
+ xfree(client_kexinit);
+ xfree(server_kexinit);
+#ifdef DEBUG_KEXDH
+ fprintf(stderr, "hash == ");
+ for (i = 0; i< 20; i++)
+ fprintf(stderr, "%02x", (hash[i])&0xff);
+ fprintf(stderr, "\n");
+#endif
+ dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20);
+ key_free(server_host_key);
+
+ kex_derive_keys(kex, hash, shared_secret);
+ packet_set_kex(kex);
+
+ /* have keys, free DH */
+ DH_free(dh);
+
+ debug("Wait SSH2_MSG_NEWKEYS.");
+ packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS);
+ debug("GOT SSH2_MSG_NEWKEYS.");
+
+ debug("send SSH2_MSG_NEWKEYS.");
+ packet_start(SSH2_MSG_NEWKEYS);
+ packet_send();
+ packet_write_wait();
+ debug("done: send SSH2_MSG_NEWKEYS.");
+
+ /* send 1st encrypted/maced/compressed message */
+ packet_start(SSH2_MSG_IGNORE);
+ packet_put_cstring("markus");
+ packet_send();
+ packet_write_wait();
+
+ debug("done: KEX2.");
+}
+/*
+ * Authenticate user
+ */
+void
+ssh_userauth2(int host_key_valid, RSA *own_host_key,
+ uid_t original_real_uid, char *host)
+{
+ int type;
+ int plen;
+ unsigned int dlen;
+ int partial;
+ struct passwd *pw;
+ char *server_user, *local_user;
+ char *auths;
+ char *password;
+ char *service = "ssh-connection"; // service name
+
+ debug("send SSH2_MSG_SERVICE_REQUEST");
+ packet_start(SSH2_MSG_SERVICE_REQUEST);
+ packet_put_cstring("ssh-userauth");
+ packet_send();
+ packet_write_wait();
+
+ type = packet_read(&plen);
+ if (type != SSH2_MSG_SERVICE_ACCEPT) {
+ fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
+ }
+ /* payload empty for ssh-2.0.13 ?? */
+ /* reply = packet_get_string(&payload_len); */
+ debug("got SSH2_MSG_SERVICE_ACCEPT");
+
+ /*XX COMMONCODE: */
+ /* 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;
+
+ /* INITIAL request for auth */
+ packet_start(SSH2_MSG_USERAUTH_REQUEST);
+ packet_put_cstring(server_user);
+ packet_put_cstring(service);
+ packet_put_cstring("none");
+ packet_send();
+ packet_write_wait();
+
+ for (;;) {
+ type = packet_read(&plen);
+ if (type == SSH2_MSG_USERAUTH_SUCCESS)
+ break;
+ if (type != SSH2_MSG_USERAUTH_FAILURE)
+ fatal("access denied: %d", type);
+ /* SSH2_MSG_USERAUTH_FAILURE means: try again */
+ auths = packet_get_string(&dlen);
+ debug("authentications that can continue: %s", auths);
+ partial = packet_get_char();
+ if (partial)
+ debug("partial success");
+ if (strstr(auths, "password") == NULL)
+ fatal("passwd auth not supported: %s", auths);
+ xfree(auths);
+ /* try passwd */
+ password = read_passphrase("password: ", 0);
+ packet_start(SSH2_MSG_USERAUTH_REQUEST);
+ packet_put_cstring(server_user);
+ packet_put_cstring(service);
+ packet_put_cstring("password");
+ packet_put_char(0);
+ packet_put_cstring(password);
+ memset(password, 0, strlen(password));
+ xfree(password);
+ packet_send();
+ packet_write_wait();
+ }
+ debug("ssh-userauth2 successfull");
+}
+
+/*
* SSH1 key exchange
*/
void
@@ -1281,6 +1593,7 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
RSA *host_key;
RSA *public_key;
int bits, rbits;
+ int ssh_cipher_default = SSH_CIPHER_3DES;
unsigned char session_key[SSH_SESSION_KEY_LENGTH];
unsigned char cookie[8];
unsigned int supported_ciphers;
@@ -1628,12 +1941,16 @@ ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost,
/* 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);
+ if (compat20) {
+ ssh_kex2(host, hostaddr);
+ ssh_userauth2(host_key_valid, own_host_key, original_real_uid, host);
+ } else {
+ supported_authentications = 0;
+ ssh_kex(host, hostaddr);
+ if (supported_authentications == 0)
+ fatal("supported_authentications == 0.");
+ ssh_userauth(host_key_valid, own_host_key, original_real_uid, host);
+ }
}