1 /* 2 * Copyright (c) 1999,2000 Markus Friedl. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 #include "includes.h" 26 RCSID("$FreeBSD$"); 27 RCSID("$OpenBSD: compat.c,v 1.47 2001/04/18 23:43:25 markus Exp $"); 28 29 #include <regex.h> 30 31 #include "packet.h" 32 #include "xmalloc.h" 33 #include "compat.h" 34 #include "log.h" 35 36 int compat13 = 0; 37 int compat20 = 0; 38 int datafellows = 0; 39 40 void 41 enable_compat20(void) 42 { 43 verbose("Enabling compatibility mode for protocol 2.0"); 44 compat20 = 1; 45 } 46 void 47 enable_compat13(void) 48 { 49 verbose("Enabling compatibility mode for protocol 1.3"); 50 compat13 = 1; 51 } 52 /* datafellows bug compatibility */ 53 void 54 compat_datafellows(const char *version) 55 { 56 int i, ret; 57 char ebuf[1024]; 58 regex_t reg; 59 static struct { 60 char *pat; 61 int bugs; 62 } check[] = { 63 { "^OpenSSH[-_]2\\.[012]", 64 SSH_OLD_SESSIONID|SSH_BUG_BANNER| 65 SSH_OLD_DHGEX|SSH_BUG_NOREKEY }, 66 { "^OpenSSH_2\\.3\\.0", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES| 67 SSH_OLD_DHGEX|SSH_BUG_NOREKEY}, 68 { "^OpenSSH_2\\.3\\.", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX| 69 SSH_BUG_NOREKEY}, 70 { "^OpenSSH_2\\.5\\.[01]p1", 71 SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX| 72 SSH_BUG_NOREKEY }, 73 { "^OpenSSH_2\\.5\\.[012]", 74 SSH_OLD_DHGEX|SSH_BUG_NOREKEY }, 75 { "^OpenSSH_2\\.5\\.3", 76 SSH_BUG_NOREKEY }, 77 { "^OpenSSH", 0 }, 78 { "MindTerm", 0 }, 79 { "^2\\.1\\.0", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| 80 SSH_OLD_SESSIONID|SSH_BUG_DEBUG| 81 SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE }, 82 { "^2\\.1 ", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| 83 SSH_OLD_SESSIONID|SSH_BUG_DEBUG| 84 SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE }, 85 { "^2\\.0\\.1[3-9]", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| 86 SSH_OLD_SESSIONID|SSH_BUG_DEBUG| 87 SSH_BUG_PKSERVICE|SSH_BUG_X11FWD| 88 SSH_BUG_PKOK|SSH_BUG_RSASIGMD5| 89 SSH_BUG_HBSERVICE }, 90 { "^2\\.0\\.", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| 91 SSH_OLD_SESSIONID|SSH_BUG_DEBUG| 92 SSH_BUG_PKSERVICE|SSH_BUG_X11FWD| 93 SSH_BUG_PKAUTH|SSH_BUG_PKOK| 94 SSH_BUG_RSASIGMD5 }, 95 { "^2\\.[23]\\.0", SSH_BUG_HMAC|SSH_BUG_RSASIGMD5 }, 96 { "^2\\.3\\.", SSH_BUG_RSASIGMD5 }, 97 { "^2\\.[2-9]\\.", 0 }, 98 { "^2\\.4$", SSH_OLD_SESSIONID }, /* Van Dyke */ 99 { "^3\\.0 SecureCRT", SSH_OLD_SESSIONID }, 100 { "^1\\.7 SecureFX", SSH_OLD_SESSIONID }, 101 { "^1\\.2\\.1[89]", SSH_BUG_IGNOREMSG }, 102 { "^1\\.2\\.2[012]", SSH_BUG_IGNOREMSG }, 103 { "^1\\.3\\.2", SSH_BUG_IGNOREMSG }, /* f-secure */ 104 { "^SSH Compatible Server", /* Netscreen */ 105 SSH_BUG_PASSWORDPAD }, 106 { "^OSU_0", SSH_BUG_PASSWORDPAD }, 107 { "^OSU_1\\.[0-4]", SSH_BUG_PASSWORDPAD }, 108 { "^OSU_1\\.5alpha[1-3]", 109 SSH_BUG_PASSWORDPAD }, 110 { "^SSH_Version_Mapper", 111 SSH_BUG_SCANNER }, 112 { NULL, 0 } 113 }; 114 /* process table, return first match */ 115 for (i = 0; check[i].pat; i++) { 116 ret = regcomp(®, check[i].pat, REG_EXTENDED|REG_NOSUB); 117 if (ret != 0) { 118 regerror(ret, ®, ebuf, sizeof(ebuf)); 119 ebuf[sizeof(ebuf)-1] = '\0'; 120 error("regerror: %s", ebuf); 121 continue; 122 } 123 ret = regexec(®, version, 0, NULL, 0); 124 regfree(®); 125 if (ret == 0) { 126 debug("match: %s pat %s", version, check[i].pat); 127 datafellows = check[i].bugs; 128 return; 129 } 130 } 131 debug("no match: %s", version); 132 } 133 134 #define SEP "," 135 int 136 proto_spec(const char *spec) 137 { 138 char *s, *p, *q; 139 int ret = SSH_PROTO_UNKNOWN; 140 141 if (spec == NULL) 142 return ret; 143 q = s = xstrdup(spec); 144 for ((p = strsep(&q, SEP)); p && *p != '\0'; (p = strsep(&q, SEP))) { 145 switch(atoi(p)) { 146 case 1: 147 if (ret == SSH_PROTO_UNKNOWN) 148 ret |= SSH_PROTO_1_PREFERRED; 149 ret |= SSH_PROTO_1; 150 break; 151 case 2: 152 ret |= SSH_PROTO_2; 153 break; 154 default: 155 log("ignoring bad proto spec: '%s'.", p); 156 break; 157 } 158 } 159 xfree(s); 160 return ret; 161 } 162 163 char * 164 compat_cipher_proposal(char *cipher_prop) 165 { 166 char *orig_prop, *fix_ciphers; 167 char *cp, *tmp; 168 size_t len; 169 170 if (!(datafellows & SSH_BUG_BIGENDIANAES)) 171 return(cipher_prop); 172 173 len = strlen(cipher_prop) + 1; 174 fix_ciphers = xmalloc(len); 175 *fix_ciphers = '\0'; 176 tmp = orig_prop = xstrdup(cipher_prop); 177 while((cp = strsep(&tmp, ",")) != NULL) { 178 if (strncmp(cp, "aes", 3) && strncmp(cp, "rijndael", 8)) { 179 if (*fix_ciphers) 180 strlcat(fix_ciphers, ",", len); 181 strlcat(fix_ciphers, cp, len); 182 } 183 } 184 xfree(orig_prop); 185 debug2("Original cipher proposal: %s", cipher_prop); 186 debug2("Compat cipher proposal: %s", fix_ciphers); 187 if (!*fix_ciphers) 188 fatal("No available ciphers found."); 189 190 return(fix_ciphers); 191 } 192