From f8934f638c734f7f56d8b32b745586ea36ceda3b Mon Sep 17 00:00:00 2001 From: markus Date: Wed, 12 Apr 2000 07:45:43 +0000 Subject: [PATCH] add Cipher and Protocol options to ssh/sshd, e.g.: ssh -o 'Protocol 1,2' if you prefer proto 1, ssh -o 'Ciphers arcfour,3des-cbc' --- usr.bin/ssh/README.openssh2 | 19 +++++---- usr.bin/ssh/cipher.c | 34 ++++++++++++++-- usr.bin/ssh/cipher.h | 5 ++- usr.bin/ssh/compat.c | 31 ++++++++++++++- usr.bin/ssh/compat.h | 9 ++++- usr.bin/ssh/readconf.c | 31 ++++++++++++++- usr.bin/ssh/readconf.h | 4 +- usr.bin/ssh/servconf.c | 67 +++++++++++++++++++------------ usr.bin/ssh/servconf.h | 4 +- usr.bin/ssh/ssh.c | 9 +++-- usr.bin/ssh/ssh.h | 14 ++++--- usr.bin/ssh/sshconnect.c | 78 ++++++++++++++++++++++--------------- usr.bin/ssh/sshd.c | 68 +++++++++++++++++++++----------- 13 files changed, 268 insertions(+), 105 deletions(-) diff --git a/usr.bin/ssh/README.openssh2 b/usr.bin/ssh/README.openssh2 index 59f8cf9f689..bdf78bf5843 100644 --- a/usr.bin/ssh/README.openssh2 +++ b/usr.bin/ssh/README.openssh2 @@ -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 $ diff --git a/usr.bin/ssh/cipher.c b/usr.bin/ssh/cipher.c index b5dc9f5e480..9c19da6a048 100644 --- a/usr.bin/ssh/cipher.c +++ b/usr.bin/ssh/cipher.c @@ -12,14 +12,17 @@ */ #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 /* + * 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, diff --git a/usr.bin/ssh/cipher.h b/usr.bin/ssh/cipher.h index 7831963871a..bf08d897fb1 100644 --- a/usr.bin/ssh/cipher.h +++ b/usr.bin/ssh/cipher.h @@ -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. diff --git a/usr.bin/ssh/compat.c b/usr.bin/ssh/compat.c index 0b309dbb8d9..5e9e60a5f66 100644 --- a/usr.bin/ssh/compat.c +++ b/usr.bin/ssh/compat.c @@ -28,10 +28,12 @@ */ #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; +} diff --git a/usr.bin/ssh/compat.h b/usr.bin/ssh/compat.h index 2e0928c7629..524cfe0ea86 100644 --- a/usr.bin/ssh/compat.h +++ b/usr.bin/ssh/compat.h @@ -26,13 +26,20 @@ * (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; diff --git a/usr.bin/ssh/readconf.c b/usr.bin/ssh/readconf.c index e3133521924..c735099b2be 100644 --- a/usr.bin/ssh/readconf.c +++ b/usr.bin/ssh/readconf.c @@ -14,13 +14,14 @@ */ #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 : ""); + 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 : ""); + 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); diff --git a/usr.bin/ssh/readconf.h b/usr.bin/ssh/readconf.h index 1d22002fa3f..a88b36fbb90 100644 --- a/usr.bin/ssh/readconf.h +++ b/usr.bin/ssh/readconf.h @@ -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. */ diff --git a/usr.bin/ssh/servconf.c b/usr.bin/ssh/servconf.c index 14d351c8a4b..a67c440e61e 100644 --- a/usr.bin/ssh/servconf.c +++ b/usr.bin/ssh/servconf.c @@ -12,11 +12,12 @@ */ #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 : ""); + filename, linenum, cp ? cp : ""); 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 : ""); + filename, linenum, cp ? cp : ""); 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 : ""); + 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 : ""); + 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); diff --git a/usr.bin/ssh/servconf.h b/usr.bin/ssh/servconf.h index 6b6ea9f8cb4..f4abace337b 100644 --- a/usr.bin/ssh/servconf.h +++ b/usr.bin/ssh/servconf.h @@ -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 diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c index 35dc45d2d1b..ecf3e824546 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.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); diff --git a/usr.bin/ssh/ssh.h b/usr.bin/ssh/ssh.h index c8db7daeb77..2c1d443e0c1 100644 --- a/usr.bin/ssh/ssh.h +++ b/usr.bin/ssh/ssh.h @@ -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 @@ -46,14 +46,16 @@ /* * 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 diff --git a/usr.bin/ssh/sshconnect.c b/usr.bin/ssh/sshconnect.c index e8b4f16b9ac..2f8c63c59b2 100644 --- a/usr.bin/ssh/sshconnect.c +++ b/usr.bin/ssh/sshconnect.c @@ -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 #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) { diff --git a/usr.bin/ssh/sshd.c b/usr.bin/ssh/sshd.c index 088da20c550..6c2258452d7 100644 --- a/usr.bin/ssh/sshd.c +++ b/usr.bin/ssh/sshd.c @@ -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++) -- 2.20.1