add Cipher and Protocol options to ssh/sshd, e.g.:
authormarkus <markus@openbsd.org>
Wed, 12 Apr 2000 07:45:43 +0000 (07:45 +0000)
committermarkus <markus@openbsd.org>
Wed, 12 Apr 2000 07:45:43 +0000 (07:45 +0000)
ssh -o 'Protocol 1,2' if you prefer proto 1, ssh -o 'Ciphers arcfour,3des-cbc'

13 files changed:
usr.bin/ssh/README.openssh2
usr.bin/ssh/cipher.c
usr.bin/ssh/cipher.h
usr.bin/ssh/compat.c
usr.bin/ssh/compat.h
usr.bin/ssh/readconf.c
usr.bin/ssh/readconf.h
usr.bin/ssh/servconf.c
usr.bin/ssh/servconf.h
usr.bin/ssh/ssh.c
usr.bin/ssh/ssh.h
usr.bin/ssh/sshconnect.c
usr.bin/ssh/sshd.c

index 59f8cf9..bdf78bf 100644 (file)
@@ -1,4 +1,13 @@
-$Id: README.openssh2,v 1.2 2000/04/06 21:28:22 markus Exp $
+$Id: README.openssh2,v 1.3 2000/04/12 07:45:43 markus Exp $
+
+howto:
+       1) generate server key:
+               $ umask 077
+               $ openssl dsaparam 1024 -out dsa1024.pem
+               $ openssl gendsa -out /etc/ssh_dsa_key dsa1024.pem -rand /dev/arandom
+       2) enable ssh2:
+               server: add 'Protocol 2,1' to /etc/sshd_config
+               client: ssh -o 'Protocol 2,1', or add to .ssh/config
 
 works:
        secsh-transport: works w/o rekey
@@ -11,11 +20,7 @@ works:
                tcp-forwarding: -L works
        dss: verification works,
                key database in ~/.ssh/known_hosts with bits == 0 hack
-       dss: signature works, keygen w/ openssl:
-               $ umask 077
-               $ openssl dsaparam 1024 -out dsa1024.pem
-               $ openssl gendsa -out /etc/ssh_dsa_key dsa1024.pem -rand /dev/arandom
-               start sshd with '-2' flag
+       dss: signature works, keygen w/ openssl
        client interops w/ sshd2, lshd
        server interops w/ ssh2, lsh, ssh.com's Windows client, SecureCRT
        server supports multiple concurrent sessions (e.g. with SSH.com Windows client)
@@ -33,4 +38,4 @@ todo:
        sftp
 
 -markus
-$Date: 2000/04/06 21:28:22 $
+$Date: 2000/04/12 07:45:43 $
index b5dc9f5..9c19da6 100644 (file)
  */
 
 #include "includes.h"
-RCSID("$Id: cipher.c,v 1.23 2000/04/12 00:18:20 deraadt Exp $");
+RCSID("$Id: cipher.c,v 1.24 2000/04/12 07:45:43 markus Exp $");
 
 #include "ssh.h"
 #include "cipher.h"
+#include "xmalloc.h"
 
 #include <ssl/md5.h>
 
 /*
+ * This is used by SSH1:
+ *
  * What kind of triple DES are these 2 routines?
  *
  * Why is there a redundant initialization vector?
@@ -75,7 +78,7 @@ SSH_3CBC_DECRYPT(des_key_schedule ks1,
 }
 
 /*
- * SSH uses a variation on Blowfish, all bytes must be swapped before
+ * SSH1 uses a variation on Blowfish, all bytes must be swapped before
  * and after encryption/decryption. Thus the swap_bytes stuff (yuk).
  */
 static void
@@ -161,10 +164,34 @@ cipher_name(int cipher)
 {
        if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) ||
            cipher_names[cipher] == NULL)
-               fatal("cipher_name: bad cipher number: %d", cipher);
+               fatal("cipher_name: bad cipher name: %d", cipher);
        return cipher_names[cipher];
 }
 
+/* Returns 1 if the name of the ciphers are valid. */
+
+#define        CIPHER_SEP      ","
+int
+ciphers_valid(const char *names)
+{
+       char *ciphers;
+       char *p;
+       int i;
+
+       if (strcmp(names, "") == 0)
+               return 0;
+       ciphers = xstrdup(names);
+       for ((p = strtok(ciphers, CIPHER_SEP)); p; (p = strtok(NULL, CIPHER_SEP))) {
+               i = cipher_number(p);
+               if (i == -1 || !(cipher_mask2() & (1 << i))) {
+                       xfree(ciphers);
+                       return 0;
+               }
+       }
+       xfree(ciphers);
+       return 1;
+}
+
 /*
  * Parses the name of the cipher.  Returns the number of the corresponding
  * cipher, or -1 on error.
@@ -265,7 +292,6 @@ cipher_set_key(CipherContext *context, int cipher, const unsigned char *key,
        memset(padded, 0, sizeof(padded));
 }
 
-
 void 
 cipher_set_key_iv(CipherContext * context, int cipher,
     const unsigned char *key, int keylen, 
index 7831963..bf08d89 100644 (file)
@@ -11,7 +11,7 @@
  * 
  */
 
-/* RCSID("$Id: cipher.h,v 1.13 2000/04/04 21:37:27 markus Exp $"); */
+/* RCSID("$Id: cipher.h,v 1.14 2000/04/12 07:45:43 markus Exp $"); */
 
 #ifndef CIPHER_H
 #define CIPHER_H
@@ -78,6 +78,9 @@ const char *cipher_name(int cipher);
  */
 int     cipher_number(const char *name);
 
+/* returns 1 if all ciphers are supported (ssh2 only) */
+int     ciphers_valid(const char *names);
+
 /*
  * Selects the cipher to use and sets the key.  If for_encryption is true,
  * the key is setup for encryption; otherwise it is setup for decryption.
index 0b309db..5e9e60a 100644 (file)
  */
 
 #include "includes.h"
-RCSID("$Id: compat.c,v 1.9 2000/04/12 06:37:02 markus Exp $");
+RCSID("$Id: compat.c,v 1.10 2000/04/12 07:45:43 markus Exp $");
 
 #include "ssh.h"
 #include "packet.h"
+#include "xmalloc.h"
+#include "compat.h"
 
 int compat13 = 0;
 int compat20 = 0;
@@ -71,3 +73,30 @@ compat_datafellows(const char *version)
                }
        }
 }
+
+#define        SEP     ","
+int
+proto_spec(const char *spec)
+{
+       char *s = xstrdup(spec);
+       char *p;
+       int ret = SSH_PROTO_UNKNOWN;
+
+       for ((p = strtok(s, SEP)); p; (p = strtok(NULL, SEP))) {
+               switch(atoi(p)) {
+               case 1:
+                       if (ret == SSH_PROTO_UNKNOWN)
+                               ret |= SSH_PROTO_1_PREFERRED;
+                       ret |= SSH_PROTO_1;
+                       break;
+               case 2:
+                       ret |= SSH_PROTO_2;
+                       break;
+               default:
+                       log("ignoring bad proto spec: '%s'.", p);
+                       break;
+               }
+       }
+       xfree(s);
+       return ret;
+}
index 2e0928c..524cfe0 100644 (file)
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/* RCSID("$Id: compat.h,v 1.5 2000/04/03 07:07:15 markus Exp $"); */
+/* RCSID("$Id: compat.h,v 1.6 2000/04/12 07:45:44 markus Exp $"); */
 
 #ifndef COMPAT_H
 #define COMPAT_H
+
+#define        SSH_PROTO_UNKNOWN       0x00
+#define        SSH_PROTO_1             0x01
+#define        SSH_PROTO_1_PREFERRED   0x02
+#define        SSH_PROTO_2             0x04
+
 void    enable_compat13(void);
 void    enable_compat20(void);
 void    compat_datafellows(const char *s);
+int    proto_spec(const char *spec);
 extern int compat13;
 extern int compat20;
 extern int datafellows;
index e313352..c735099 100644 (file)
  */
 
 #include "includes.h"
-RCSID("$Id: readconf.c,v 1.24 2000/03/28 20:31:28 markus Exp $");
+RCSID("$Id: readconf.c,v 1.25 2000/04/12 07:45:44 markus Exp $");
 
 #include "ssh.h"
 #include "cipher.h"
 #include "readconf.h"
 #include "match.h"
 #include "xmalloc.h"
+#include "compat.h"
 
 /* Format of the configuration file:
 
@@ -103,7 +104,7 @@ typedef enum {
        oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
        oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
        oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
-       oUsePrivilegedPort, oLogLevel
+       oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol
 } OpCodes;
 
 /* Textual representations of the tokens. */
@@ -134,6 +135,8 @@ static struct {
        { "proxycommand", oProxyCommand },
        { "port", oPort },
        { "cipher", oCipher },
+       { "ciphers", oCiphers },
+       { "protocol", oProtocol },
        { "remoteforward", oRemoteForward },
        { "localforward", oLocalForward },
        { "user", oUser },
@@ -444,6 +447,26 @@ parse_int:
                        *intptr = value;
                break;
 
+       case oCiphers:
+               cp = strtok(NULL, WHITESPACE);
+               if (!ciphers_valid(cp))
+                       fatal("%.200s line %d: Bad cipher spec '%s'.",
+                             filename, linenum, cp ? cp : "<NONE>");
+               if (*activep && options->ciphers == NULL)
+                       options->ciphers = xstrdup(cp);
+               break;
+
+       case oProtocol:
+               intptr = &options->protocol;
+               cp = strtok(NULL, WHITESPACE);
+               value = proto_spec(cp);
+               if (value == SSH_PROTO_UNKNOWN)
+                       fatal("%.200s line %d: Bad protocol spec '%s'.",
+                             filename, linenum, cp ? cp : "<NONE>");
+               if (*activep && *intptr == SSH_PROTO_UNKNOWN)
+                       *intptr = value;
+               break;
+
        case oLogLevel:
                intptr = (int *) &options->log_level;
                cp = strtok(NULL, WHITESPACE);
@@ -616,6 +639,8 @@ initialize_options(Options * options)
        options->connection_attempts = -1;
        options->number_of_password_prompts = -1;
        options->cipher = -1;
+       options->ciphers = NULL;
+       options->protocol = SSH_PROTO_UNKNOWN;
        options->num_identity_files = 0;
        options->hostname = NULL;
        options->proxy_command = NULL;
@@ -689,6 +714,8 @@ fill_default_options(Options * options)
        /* Selected in ssh_login(). */
        if (options->cipher == -1)
                options->cipher = SSH_CIPHER_NOT_SET;
+       if (options->protocol == SSH_PROTO_UNKNOWN)
+               options->protocol = SSH_PROTO_1;
        if (options->num_identity_files == 0) {
                options->identity_files[0] =
                        xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
index 1d22002..a88b36f 100644 (file)
@@ -13,7 +13,7 @@
  * 
  */
 
-/* RCSID("$Id: readconf.h,v 1.13 1999/12/01 13:59:15 markus Exp $"); */
+/* RCSID("$Id: readconf.h,v 1.14 2000/04/12 07:45:44 markus Exp $"); */
 
 #ifndef READCONF_H
 #define READCONF_H
@@ -64,6 +64,8 @@ typedef struct {
        int     number_of_password_prompts;     /* Max number of password
                                                 * prompts. */
        int     cipher;         /* Cipher to use. */
+       char   *ciphers;        /* Ciphers in order of preference. */
+       int     protocol;       /* Protocol in order of preference. */
        char   *hostname;       /* Real host to connect. */
        char   *proxy_command;  /* Proxy command for connecting the host. */
        char   *user;           /* User to log in as. */
index 14d351c..a67c440 100644 (file)
  */
 
 #include "includes.h"
-RCSID("$Id: servconf.c,v 1.32 2000/04/06 08:55:22 markus Exp $");
+RCSID("$Id: servconf.c,v 1.33 2000/04/12 07:45:44 markus Exp $");
 
 #include "ssh.h"
 #include "servconf.h"
 #include "xmalloc.h"
+#include "compat.h"
 
 /* add listen address */
 void add_listen_addr(ServerOptions *options, char *addr);
@@ -68,6 +69,8 @@ initialize_server_options(ServerOptions *options)
        options->num_deny_users = 0;
        options->num_allow_groups = 0;
        options->num_deny_groups = 0;
+       options->ciphers = NULL;
+       options->protocol = SSH_PROTO_UNKNOWN;
 }
 
 void 
@@ -139,6 +142,8 @@ fill_default_server_options(ServerOptions *options)
                options->permit_empty_passwd = 0;
        if (options->use_login == -1)
                options->use_login = 0;
+       if (options->protocol == SSH_PROTO_UNKNOWN)
+               options->protocol = SSH_PROTO_1;
 }
 
 #define WHITESPACE " \t\r\n"
@@ -162,7 +167,7 @@ typedef enum {
        sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
        sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
        sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
-       sIgnoreUserKnownHosts, sDSAKeyFile
+       sIgnoreUserKnownHosts, sDSAKeyFile, sCiphers, sProtocol
 } ServerOpCodes;
 
 /* Textual representation of the tokens. */
@@ -211,6 +216,8 @@ static struct {
        { "denyusers", sDenyUsers },
        { "allowgroups", sAllowGroups },
        { "denygroups", sDenyGroups },
+       { "ciphers", sCiphers },
+       { "protocol", sProtocol },
        { NULL, 0 }
 };
 
@@ -494,7 +501,7 @@ parse_flag:
                        value = log_facility_number(cp);
                        if (value == (SyslogFacility) - 1)
                                fatal("%.200s line %d: unsupported log facility '%s'\n",
-                                 filename, linenum, cp ? cp : "<NONE>");
+                                   filename, linenum, cp ? cp : "<NONE>");
                        if (*intptr == -1)
                                *intptr = (SyslogFacility) value;
                        break;
@@ -505,55 +512,67 @@ parse_flag:
                        value = log_level_number(cp);
                        if (value == (LogLevel) - 1)
                                fatal("%.200s line %d: unsupported log level '%s'\n",
-                                 filename, linenum, cp ? cp : "<NONE>");
+                                   filename, linenum, cp ? cp : "<NONE>");
                        if (*intptr == -1)
                                *intptr = (LogLevel) value;
                        break;
 
                case sAllowUsers:
                        while ((cp = strtok(NULL, WHITESPACE))) {
-                               if (options->num_allow_users >= MAX_ALLOW_USERS) {
-                                       fprintf(stderr, "%s line %d: too many allow users.\n",
-                                               filename, linenum);
-                                       exit(1);
-                               }
+                               if (options->num_allow_users >= MAX_ALLOW_USERS)
+                                       fatal("%s line %d: too many allow users.\n",
+                                           filename, linenum);
                                options->allow_users[options->num_allow_users++] = xstrdup(cp);
                        }
                        break;
 
                case sDenyUsers:
                        while ((cp = strtok(NULL, WHITESPACE))) {
-                               if (options->num_deny_users >= MAX_DENY_USERS) {
-                                       fprintf(stderr, "%s line %d: too many deny users.\n",
-                                               filename, linenum);
-                                       exit(1);
-                               }
+                               if (options->num_deny_users >= MAX_DENY_USERS)
+                                       fatal( "%s line %d: too many deny users.\n",
+                                           filename, linenum);
                                options->deny_users[options->num_deny_users++] = xstrdup(cp);
                        }
                        break;
 
                case sAllowGroups:
                        while ((cp = strtok(NULL, WHITESPACE))) {
-                               if (options->num_allow_groups >= MAX_ALLOW_GROUPS) {
-                                       fprintf(stderr, "%s line %d: too many allow groups.\n",
-                                               filename, linenum);
-                                       exit(1);
-                               }
+                               if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
+                                       fatal("%s line %d: too many allow groups.\n",
+                                           filename, linenum);
                                options->allow_groups[options->num_allow_groups++] = xstrdup(cp);
                        }
                        break;
 
                case sDenyGroups:
                        while ((cp = strtok(NULL, WHITESPACE))) {
-                               if (options->num_deny_groups >= MAX_DENY_GROUPS) {
-                                       fprintf(stderr, "%s line %d: too many deny groups.\n",
-                                               filename, linenum);
-                                       exit(1);
-                               }
+                               if (options->num_deny_groups >= MAX_DENY_GROUPS)
+                                       fatal("%s line %d: too many deny groups.\n",
+                                           filename, linenum);
                                options->deny_groups[options->num_deny_groups++] = xstrdup(cp);
                        }
                        break;
 
+               case sCiphers:
+                       cp = strtok(NULL, WHITESPACE);
+                       if (!ciphers_valid(cp))
+                               fatal("%s line %d: Bad cipher spec '%s'.",
+                                   filename, linenum, cp ? cp : "<NONE>");
+                       if (options->ciphers == NULL)
+                               options->ciphers = xstrdup(cp);
+                       break;
+
+               case sProtocol:
+                       intptr = &options->protocol;
+                       cp = strtok(NULL, WHITESPACE);
+                       value = proto_spec(cp);
+                       if (value == SSH_PROTO_UNKNOWN)
+                               fatal("%s line %d: Bad protocol spec '%s'.",
+                                     filename, linenum, cp ? cp : "<NONE>");
+                       if (*intptr == SSH_PROTO_UNKNOWN)
+                               *intptr = value;
+                       break;
+
                default:
                        fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n",
                                filename, linenum, cp, opcode);
index 6b6ea9f..f4abace 100644 (file)
@@ -13,7 +13,7 @@
  * 
  */
 
-/* RCSID("$Id: servconf.h,v 1.16 2000/04/06 08:55:22 markus Exp $"); */
+/* RCSID("$Id: servconf.h,v 1.17 2000/04/12 07:45:44 markus Exp $"); */
 
 #ifndef SERVCONF_H
 #define SERVCONF_H
@@ -48,6 +48,8 @@ typedef struct {
                                         * searching at */
        int     strict_modes;   /* If true, require string home dir modes. */
        int     keepalives;     /* If true, set SO_KEEPALIVE. */
+       char   *ciphers;        /* Ciphers in order of preference. */
+       int     protocol;       /* Protocol in order of preference. */
        SyslogFacility log_facility;    /* Facility for system logging. */
        LogLevel log_level;     /* Level for system logging. */
        int     rhosts_authentication;  /* If true, permit rhosts
index 35dc45d..ecf3e82 100644 (file)
@@ -11,7 +11,7 @@
  */
 
 #include "includes.h"
-RCSID("$Id: ssh.c,v 1.45 2000/04/04 15:19:42 markus Exp $");
+RCSID("$Id: ssh.c,v 1.46 2000/04/12 07:45:44 markus Exp $");
 
 #include "xmalloc.h"
 #include "ssh.h"
@@ -32,6 +32,7 @@ int IPv4or6 = AF_UNSPEC;
 /* Flag indicating whether debug mode is on.  This can be set on the command line. */
 int debug_flag = 0;
 
+/* Flag indicating whether a tty should be allocated */
 int tty_flag = 0;
 
 /* don't exec a shell */
@@ -326,8 +327,10 @@ main(int ac, char **av)
 
                case 'v':
                case 'V':
-                       fprintf(stderr, "SSH Version %s, protocol version %d.%d.\n",
-                           SSH_VERSION, PROTOCOL_MAJOR, PROTOCOL_MINOR);
+                       fprintf(stderr, "SSH Version %s, protocol versions %d.%d/%d.%d.\n",
+                           SSH_VERSION,
+                           PROTOCOL_MAJOR_1, PROTOCOL_MINOR_1,
+                           PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2);
                        fprintf(stderr, "Compiled with SSL (0x%8.8lx).\n", SSLeay());
                        if (opt == 'V')
                                exit(0);
index c8db7da..2c1d443 100644 (file)
@@ -13,7 +13,7 @@
  * 
  */
 
-/* RCSID("$Id: ssh.h,v 1.36 2000/04/06 08:55:22 markus Exp $"); */
+/* RCSID("$Id: ssh.h,v 1.37 2000/04/12 07:45:44 markus Exp $"); */
 
 #ifndef SSH_H
 #define SSH_H
 /*
  * Major protocol version.  Different version indicates major incompatiblity
  * that prevents communication.
- */
-#define PROTOCOL_MAJOR         1
-
-/*
+ *
  * Minor protocol version.  Different version indicates minor incompatibility
  * that does not prevent interoperation.
  */
-#define PROTOCOL_MINOR         5
+#define PROTOCOL_MAJOR_1       1
+#define PROTOCOL_MINOR_1       5
+
+/* We support both SSH1 and SSH2 */
+#define PROTOCOL_MAJOR_2       2
+#define PROTOCOL_MINOR_2       0
 
 /*
  * Name for the service.  The port named by this service overrides the
index e8b4f16..2f8c63c 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshconnect.c,v 1.63 2000/04/12 07:03:06 markus Exp $");
+RCSID("$OpenBSD: sshconnect.c,v 1.64 2000/04/12 07:45:44 markus Exp $");
 
 #include <ssl/bn.h>
 #include "xmalloc.h"
@@ -986,7 +986,7 @@ void
 ssh_exchange_identification()
 {
        char buf[256], remote_version[256];     /* must be same size! */
-       int remote_major, remote_minor, i;
+       int remote_major, remote_minor, i, mismatch;
        int connection_in = packet_get_connection_in();
        int connection_out = packet_get_connection_out();
 
@@ -1020,39 +1020,51 @@ ssh_exchange_identification()
        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.");
-
-       /* We speak 1.3, too. */
-       if (remote_major == 1 && remote_minor == 3) {
-               enable_compat13();
-               if (options.forward_agent) {
-                       log("Agent forwarding disabled for protocol 1.3");
-                       options.forward_agent = 0;
+       mismatch = 0;
+
+       switch(remote_major) {
+       case 1:
+               if (remote_minor == 99 &&
+                   (options.protocol & SSH_PROTO_2) &&
+                   !(options.protocol & SSH_PROTO_1_PREFERRED)) {
+                       enable_compat20();
+                       break;
                }
+               if (!(options.protocol & SSH_PROTO_1)) {
+                       mismatch = 1;
+                       break;
+               }
+               if (remote_minor < 3) {
+                       fatal("Remote machine has too old SSH software version.");
+               } else if (remote_minor == 3) {
+                       /* We speak 1.3, too. */
+                       enable_compat13();
+                       if (options.forward_agent) {
+                               log("Agent forwarding disabled for protocol 1.3");
+                               options.forward_agent = 0;
+                       }
+               }
+               break;
+       case 2:
+               if (options.protocol & SSH_PROTO_2) {
+                       enable_compat20();
+                       break;
+               }
+               /* FALLTHROUGH */
+       default: 
+               mismatch = 1;
+               break;
        }
-       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
-        * server will reject our version and disconnect if it doesn't
-        * support it.
-        */
-       if (remote_major != PROTOCOL_MAJOR)
+       if (mismatch)
                fatal("Protocol major versions differ: %d vs. %d",
-                     PROTOCOL_MAJOR, remote_major);
-#endif
+                   (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
+                   remote_major);
+
        /* Send our own protocol version identification. */
        snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
-           compat20 ? 2 : PROTOCOL_MAJOR,
-           compat20 ? 0 : PROTOCOL_MINOR,
+           compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
+           compat20 ? PROTOCOL_MINOR_1 : PROTOCOL_MINOR_1,
            SSH_VERSION);
        if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf))
                fatal("write: %.100s", strerror(errno));
@@ -1339,11 +1351,15 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
 /* KEXINIT */
 
        debug("Sending KEX init.");
-        if (options.cipher == SSH_CIPHER_ARCFOUR ||
+       if (options.ciphers != NULL) {
+               myproposal[PROPOSAL_ENC_ALGS_CTOS] = 
+               myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
+       } else 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_CTOS] =
                myproposal[PROPOSAL_ENC_ALGS_STOC] = cipher_name(options.cipher);
        }
        if (options.compression) {
index 088da20..6c22584 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.101 2000/04/12 07:03:06 markus Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.102 2000/04/12 07:45:44 markus Exp $");
 
 #include "xmalloc.h"
 #include "rsa.h"
@@ -64,9 +64,6 @@ char *config_file_name = SERVER_CONFIG_FILE;
  */
 int IPv4or6 = AF_UNSPEC;
 
-/* Flag indicating whether SSH2 is enabled */
-int allow_ssh2 = 0;
-
 /*
  * Debug mode flag.  This can be set on the command line.  If debug
  * mode is enabled, extra debugging output will be sent to the system
@@ -271,16 +268,24 @@ chop(char *s)
 void
 sshd_exchange_identification(int sock_in, int sock_out)
 {
-       int i;
+       int i, mismatch;
        int remote_major, remote_minor;
+       int major, minor;
        char *s;
        char buf[256];                  /* Must not be larger than remote_version. */
        char remote_version[256];       /* Must be at least as big as buf. */
 
-       snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
-                allow_ssh2 ? 1  : PROTOCOL_MAJOR,
-                allow_ssh2 ? 99 : PROTOCOL_MINOR,
-                SSH_VERSION);
+       if (options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) {
+               major = PROTOCOL_MAJOR_1;
+               minor = 99;
+       } else if (options.protocol & SSH_PROTO_2) {
+               major = PROTOCOL_MAJOR_2;
+               minor = PROTOCOL_MINOR_2;
+       } else {
+               major = PROTOCOL_MAJOR_1;
+               minor = PROTOCOL_MINOR_1;
+       }
+       snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", major, minor, SSH_VERSION);
        server_version_string = xstrdup(buf);
 
        if (client_version_string == NULL) {
@@ -301,7 +306,6 @@ sshd_exchange_identification(int sock_in, int sock_out)
                                buf[i] = '\n';
                                buf[i + 1] = 0;
                                continue;
-                               //break;
                        }
                        if (buf[i] == '\n') {
                                /* buf[i] == '\n' */
@@ -332,8 +336,13 @@ sshd_exchange_identification(int sock_in, int sock_out)
 
        compat_datafellows(remote_version);
 
+       mismatch = 0;
        switch(remote_major) {
        case 1:
+               if (!(options.protocol & SSH_PROTO_1)) {
+                       mismatch = 1;
+                       break;
+               }
                if (remote_minor < 3) {
                        packet_disconnect("Your ssh version is too old and"
                            "is no longer supported.  Please install a newer version.");
@@ -341,27 +350,37 @@ sshd_exchange_identification(int sock_in, int sock_out)
                        /* note that this disables agent-forwarding */
                        enable_compat13();
                }
-               if (remote_minor != 99)
-                      break;
-               /* FALLTHROUGH */
+               if (remote_minor == 99) {
+                       if (options.protocol & SSH_PROTO_2)
+                               enable_compat20();
+                       else
+                               mismatch = 1;
+               }
+               break;
        case 2:
-               if (allow_ssh2) {
+               if (options.protocol & SSH_PROTO_2) {
                        enable_compat20();
                        break;
                }
                /* FALLTHROUGH */
        default: 
+               mismatch = 1;
+               break;
+       }
+       chop(server_version_string);
+       chop(client_version_string);
+       debug("Local version string %.200s", server_version_string);
+
+       if (mismatch) {
                s = "Protocol major versions differ.\n";
                (void) atomicio(write, sock_out, s, strlen(s));
                close(sock_in);
                close(sock_out);
-               log("Protocol major versions differ for %s: %d vs. %d",
-                   get_remote_ipaddr(), PROTOCOL_MAJOR, remote_major);
+               log("Protocol major versions differ for %s: %.200s vs. %.200s",
+                   get_remote_ipaddr(),
+                   server_version_string, client_version_string);
                fatal_cleanup();
-               break;
        }
-       chop(server_version_string);
-       chop(client_version_string);
 }
 
 /*
@@ -397,11 +416,8 @@ main(int ac, char **av)
        initialize_server_options(&options);
 
        /* Parse command-line arguments. */
-       while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ246")) != EOF) {
+       while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ46")) != EOF) {
                switch (opt) {
-               case '2':
-                       allow_ssh2 = 1;
-                       break;
                case '4':
                        IPv4or6 = AF_INET;
                        break;
@@ -580,6 +596,7 @@ main(int ac, char **av)
                public_key = RSA_new();
                sensitive_data.private_key = RSA_new();
 
+               /* XXX check options.protocol */
                log("Generating %d bit RSA key.", options.server_key_bits);
                rsa_generate_key(sensitive_data.private_key, public_key,
                                 options.server_key_bits);
@@ -1107,6 +1124,11 @@ do_ssh2_kex()
 
 /* KEXINIT */
 
+       if (options.ciphers != NULL) {
+               myproposal[PROPOSAL_ENC_ALGS_CTOS] = 
+               myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
+       }
+
        debug("Sending KEX init.");
 
        for (i = 0; i < PROPOSAL_MAX; i++)