diff options
Diffstat (limited to 'sshconnect.c')
-rw-r--r-- | sshconnect.c | 246 |
1 files changed, 135 insertions, 111 deletions
diff --git a/sshconnect.c b/sshconnect.c index e6175f11b..d96f8e026 100644 --- a/sshconnect.c +++ b/sshconnect.c | |||
@@ -8,7 +8,7 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include "includes.h" | 10 | #include "includes.h" |
11 | RCSID("$Id: sshconnect.c,v 1.17 1999/12/07 04:38:32 damien Exp $"); | 11 | RCSID("$Id: sshconnect.c,v 1.18 1999/12/13 23:47:16 damien Exp $"); |
12 | 12 | ||
13 | #ifdef HAVE_OPENSSL | 13 | #ifdef HAVE_OPENSSL |
14 | #include <openssl/bn.h> | 14 | #include <openssl/bn.h> |
@@ -156,8 +156,10 @@ ssh_create_socket(uid_t original_real_uid, int privileged) | |||
156 | fatal("rresvport: %.100s", strerror(errno)); | 156 | fatal("rresvport: %.100s", strerror(errno)); |
157 | debug("Allocated local port %d.", p); | 157 | debug("Allocated local port %d.", p); |
158 | } else { | 158 | } else { |
159 | /* Just create an ordinary socket on arbitrary port. We | 159 | /* |
160 | use the user's uid to create the socket. */ | 160 | * Just create an ordinary socket on arbitrary port. We use |
161 | * the user's uid to create the socket. | ||
162 | */ | ||
161 | temporarily_use_uid(original_real_uid); | 163 | temporarily_use_uid(original_real_uid); |
162 | sock = socket(AF_INET, SOCK_STREAM, 0); | 164 | sock = socket(AF_INET, SOCK_STREAM, 0); |
163 | if (sock < 0) | 165 | if (sock < 0) |
@@ -209,9 +211,11 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr, | |||
209 | /* No host lookup made yet. */ | 211 | /* No host lookup made yet. */ |
210 | hp = NULL; | 212 | hp = NULL; |
211 | 213 | ||
212 | /* Try to connect several times. On some machines, the first time | 214 | /* |
213 | will sometimes fail. In general socket code appears to behave | 215 | * Try to connect several times. On some machines, the first time |
214 | quite magically on many machines. */ | 216 | * will sometimes fail. In general socket code appears to behave |
217 | * quite magically on many machines. | ||
218 | */ | ||
215 | for (attempt = 0; attempt < connection_attempts; attempt++) { | 219 | for (attempt = 0; attempt < connection_attempts; attempt++) { |
216 | if (attempt > 0) | 220 | if (attempt > 0) |
217 | debug("Trying again..."); | 221 | debug("Trying again..."); |
@@ -1087,39 +1091,21 @@ read_yes_or_no(const char *prompt, int defval) | |||
1087 | } | 1091 | } |
1088 | 1092 | ||
1089 | /* | 1093 | /* |
1090 | * Starts a dialog with the server, and authenticates the current user on the | 1094 | * check whether the supplied host key is valid, return only if ok. |
1091 | * server. This does not need any extra privileges. The basic connection | ||
1092 | * to the server must already have been established before this is called. | ||
1093 | * User is the remote user; if it is NULL, the current local user name will | ||
1094 | * be used. Anonymous indicates that no rhosts authentication will be used. | ||
1095 | * If login fails, this function prints an error and never returns. | ||
1096 | * This function does not require super-user privileges. | ||
1097 | */ | 1095 | */ |
1096 | |||
1098 | void | 1097 | void |
1099 | ssh_login(int host_key_valid, | 1098 | check_host_key(char *host, |
1100 | RSA *own_host_key, | 1099 | struct sockaddr_in *hostaddr, |
1101 | const char *orighost, | 1100 | RSA *host_key) |
1102 | struct sockaddr_in *hostaddr, | ||
1103 | uid_t original_real_uid) | ||
1104 | { | 1101 | { |
1105 | int i, type; | 1102 | RSA *file_key; |
1106 | struct passwd *pw; | 1103 | char *ip = NULL; |
1107 | BIGNUM *key; | ||
1108 | RSA *host_key, *file_key; | ||
1109 | RSA *public_key; | ||
1110 | int bits, rbits; | ||
1111 | unsigned char session_key[SSH_SESSION_KEY_LENGTH]; | ||
1112 | const char *server_user, *local_user; | ||
1113 | char *cp, *host, *ip = NULL; | ||
1114 | char hostline[1000], *hostp; | 1104 | char hostline[1000], *hostp; |
1115 | unsigned char check_bytes[8]; | ||
1116 | unsigned int supported_ciphers, supported_authentications, protocol_flags; | ||
1117 | HostStatus host_status; | 1105 | HostStatus host_status; |
1118 | HostStatus ip_status; | 1106 | HostStatus ip_status; |
1119 | int host_ip_differ = 0; | 1107 | int host_ip_differ = 0; |
1120 | int local = (ntohl(hostaddr->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; | 1108 | int local = (ntohl(hostaddr->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; |
1121 | int payload_len, clen, sum_len = 0; | ||
1122 | u_int32_t rand = 0; | ||
1123 | 1109 | ||
1124 | /* | 1110 | /* |
1125 | * Turn off check_host_ip for proxy connects, since | 1111 | * Turn off check_host_ip for proxy connects, since |
@@ -1131,88 +1117,14 @@ ssh_login(int host_key_valid, | |||
1131 | if (options.check_host_ip) | 1117 | if (options.check_host_ip) |
1132 | ip = xstrdup(inet_ntoa(hostaddr->sin_addr)); | 1118 | ip = xstrdup(inet_ntoa(hostaddr->sin_addr)); |
1133 | 1119 | ||
1134 | /* Convert the user-supplied hostname into all lowercase. */ | 1120 | /* |
1135 | host = xstrdup(orighost); | 1121 | * Store the host key from the known host file in here so that we can |
1136 | for (cp = host; *cp; cp++) | 1122 | * compare it with the key for the IP address. |
1137 | if (isupper(*cp)) | 1123 | */ |
1138 | *cp = tolower(*cp); | ||
1139 | |||
1140 | /* Exchange protocol version identification strings with the server. */ | ||
1141 | ssh_exchange_identification(); | ||
1142 | |||
1143 | /* Put the connection into non-blocking mode. */ | ||
1144 | packet_set_nonblocking(); | ||
1145 | |||
1146 | /* Get local user name. Use it as server user if no user name was given. */ | ||
1147 | pw = getpwuid(original_real_uid); | ||
1148 | if (!pw) | ||
1149 | fatal("User id %d not found from user database.", original_real_uid); | ||
1150 | local_user = xstrdup(pw->pw_name); | ||
1151 | server_user = options.user ? options.user : local_user; | ||
1152 | |||
1153 | debug("Waiting for server public key."); | ||
1154 | |||
1155 | /* Wait for a public key packet from the server. */ | ||
1156 | packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY); | ||
1157 | |||
1158 | /* Get check bytes from the packet. */ | ||
1159 | for (i = 0; i < 8; i++) | ||
1160 | check_bytes[i] = packet_get_char(); | ||
1161 | |||
1162 | /* Get the public key. */ | ||
1163 | public_key = RSA_new(); | ||
1164 | bits = packet_get_int();/* bits */ | ||
1165 | public_key->e = BN_new(); | ||
1166 | packet_get_bignum(public_key->e, &clen); | ||
1167 | sum_len += clen; | ||
1168 | public_key->n = BN_new(); | ||
1169 | packet_get_bignum(public_key->n, &clen); | ||
1170 | sum_len += clen; | ||
1171 | |||
1172 | rbits = BN_num_bits(public_key->n); | ||
1173 | if (bits != rbits) { | ||
1174 | log("Warning: Server lies about size of server public key: " | ||
1175 | "actual size is %d bits vs. announced %d.", rbits, bits); | ||
1176 | log("Warning: This may be due to an old implementation of ssh."); | ||
1177 | } | ||
1178 | /* Get the host key. */ | ||
1179 | host_key = RSA_new(); | ||
1180 | bits = packet_get_int();/* bits */ | ||
1181 | host_key->e = BN_new(); | ||
1182 | packet_get_bignum(host_key->e, &clen); | ||
1183 | sum_len += clen; | ||
1184 | host_key->n = BN_new(); | ||
1185 | packet_get_bignum(host_key->n, &clen); | ||
1186 | sum_len += clen; | ||
1187 | |||
1188 | rbits = BN_num_bits(host_key->n); | ||
1189 | if (bits != rbits) { | ||
1190 | log("Warning: Server lies about size of server host key: " | ||
1191 | "actual size is %d bits vs. announced %d.", rbits, bits); | ||
1192 | log("Warning: This may be due to an old implementation of ssh."); | ||
1193 | } | ||
1194 | /* Store the host key from the known host file in here so that we | ||
1195 | can compare it with the key for the IP address. */ | ||
1196 | file_key = RSA_new(); | 1124 | file_key = RSA_new(); |
1197 | file_key->n = BN_new(); | 1125 | file_key->n = BN_new(); |
1198 | file_key->e = BN_new(); | 1126 | file_key->e = BN_new(); |
1199 | 1127 | ||
1200 | /* Get protocol flags. */ | ||
1201 | protocol_flags = packet_get_int(); | ||
1202 | packet_set_protocol_flags(protocol_flags); | ||
1203 | |||
1204 | supported_ciphers = packet_get_int(); | ||
1205 | supported_authentications = packet_get_int(); | ||
1206 | |||
1207 | debug("Received server public key (%d bits) and host key (%d bits).", | ||
1208 | BN_num_bits(public_key->n), BN_num_bits(host_key->n)); | ||
1209 | |||
1210 | packet_integrity_check(payload_len, | ||
1211 | 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4, | ||
1212 | SSH_SMSG_PUBLIC_KEY); | ||
1213 | |||
1214 | compute_session_id(session_id, check_bytes, host_key->n, public_key->n); | ||
1215 | |||
1216 | /* | 1128 | /* |
1217 | * Check if the host key is present in the user\'s list of known | 1129 | * Check if the host key is present in the user\'s list of known |
1218 | * hosts or in the systemwide list. | 1130 | * hosts or in the systemwide list. |
@@ -1372,9 +1284,121 @@ ssh_login(int host_key_valid, | |||
1372 | */ | 1284 | */ |
1373 | break; | 1285 | break; |
1374 | } | 1286 | } |
1375 | |||
1376 | if (options.check_host_ip) | 1287 | if (options.check_host_ip) |
1377 | xfree(ip); | 1288 | xfree(ip); |
1289 | } | ||
1290 | |||
1291 | /* | ||
1292 | * Starts a dialog with the server, and authenticates the current user on the | ||
1293 | * server. This does not need any extra privileges. The basic connection | ||
1294 | * to the server must already have been established before this is called. | ||
1295 | * User is the remote user; if it is NULL, the current local user name will | ||
1296 | * be used. Anonymous indicates that no rhosts authentication will be used. | ||
1297 | * If login fails, this function prints an error and never returns. | ||
1298 | * This function does not require super-user privileges. | ||
1299 | */ | ||
1300 | void | ||
1301 | ssh_login(int host_key_valid, | ||
1302 | RSA *own_host_key, | ||
1303 | const char *orighost, | ||
1304 | struct sockaddr_in *hostaddr, | ||
1305 | uid_t original_real_uid) | ||
1306 | { | ||
1307 | int i, type; | ||
1308 | struct passwd *pw; | ||
1309 | BIGNUM *key; | ||
1310 | RSA *host_key; | ||
1311 | RSA *public_key; | ||
1312 | int bits, rbits; | ||
1313 | unsigned char session_key[SSH_SESSION_KEY_LENGTH]; | ||
1314 | const char *server_user, *local_user; | ||
1315 | char *host, *cp; | ||
1316 | unsigned char check_bytes[8]; | ||
1317 | unsigned int supported_ciphers, supported_authentications; | ||
1318 | unsigned int server_flags, client_flags; | ||
1319 | int payload_len, clen, sum_len = 0; | ||
1320 | u_int32_t rand = 0; | ||
1321 | |||
1322 | /* Convert the user-supplied hostname into all lowercase. */ | ||
1323 | host = xstrdup(orighost); | ||
1324 | for (cp = host; *cp; cp++) | ||
1325 | if (isupper(*cp)) | ||
1326 | *cp = tolower(*cp); | ||
1327 | |||
1328 | /* Exchange protocol version identification strings with the server. */ | ||
1329 | ssh_exchange_identification(); | ||
1330 | |||
1331 | /* Put the connection into non-blocking mode. */ | ||
1332 | packet_set_nonblocking(); | ||
1333 | |||
1334 | /* Get local user name. Use it as server user if no user name was given. */ | ||
1335 | pw = getpwuid(original_real_uid); | ||
1336 | if (!pw) | ||
1337 | fatal("User id %d not found from user database.", original_real_uid); | ||
1338 | local_user = xstrdup(pw->pw_name); | ||
1339 | server_user = options.user ? options.user : local_user; | ||
1340 | |||
1341 | debug("Waiting for server public key."); | ||
1342 | |||
1343 | /* Wait for a public key packet from the server. */ | ||
1344 | packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY); | ||
1345 | |||
1346 | /* Get check bytes from the packet. */ | ||
1347 | for (i = 0; i < 8; i++) | ||
1348 | check_bytes[i] = packet_get_char(); | ||
1349 | |||
1350 | /* Get the public key. */ | ||
1351 | public_key = RSA_new(); | ||
1352 | bits = packet_get_int();/* bits */ | ||
1353 | public_key->e = BN_new(); | ||
1354 | packet_get_bignum(public_key->e, &clen); | ||
1355 | sum_len += clen; | ||
1356 | public_key->n = BN_new(); | ||
1357 | packet_get_bignum(public_key->n, &clen); | ||
1358 | sum_len += clen; | ||
1359 | |||
1360 | rbits = BN_num_bits(public_key->n); | ||
1361 | if (bits != rbits) { | ||
1362 | log("Warning: Server lies about size of server public key: " | ||
1363 | "actual size is %d bits vs. announced %d.", rbits, bits); | ||
1364 | log("Warning: This may be due to an old implementation of ssh."); | ||
1365 | } | ||
1366 | /* Get the host key. */ | ||
1367 | host_key = RSA_new(); | ||
1368 | bits = packet_get_int();/* bits */ | ||
1369 | host_key->e = BN_new(); | ||
1370 | packet_get_bignum(host_key->e, &clen); | ||
1371 | sum_len += clen; | ||
1372 | host_key->n = BN_new(); | ||
1373 | packet_get_bignum(host_key->n, &clen); | ||
1374 | sum_len += clen; | ||
1375 | |||
1376 | rbits = BN_num_bits(host_key->n); | ||
1377 | if (bits != rbits) { | ||
1378 | log("Warning: Server lies about size of server host key: " | ||
1379 | "actual size is %d bits vs. announced %d.", rbits, bits); | ||
1380 | log("Warning: This may be due to an old implementation of ssh."); | ||
1381 | } | ||
1382 | |||
1383 | /* Get protocol flags. */ | ||
1384 | server_flags = packet_get_int(); | ||
1385 | packet_set_protocol_flags(server_flags); | ||
1386 | |||
1387 | supported_ciphers = packet_get_int(); | ||
1388 | supported_authentications = packet_get_int(); | ||
1389 | |||
1390 | debug("Received server public key (%d bits) and host key (%d bits).", | ||
1391 | BN_num_bits(public_key->n), BN_num_bits(host_key->n)); | ||
1392 | |||
1393 | packet_integrity_check(payload_len, | ||
1394 | 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4, | ||
1395 | SSH_SMSG_PUBLIC_KEY); | ||
1396 | |||
1397 | check_host_key(host, hostaddr, host_key); | ||
1398 | |||
1399 | client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN; | ||
1400 | |||
1401 | compute_session_id(session_id, check_bytes, host_key->n, public_key->n); | ||
1378 | 1402 | ||
1379 | /* Generate a session key. */ | 1403 | /* Generate a session key. */ |
1380 | arc4random_stir(); | 1404 | arc4random_stir(); |
@@ -1465,7 +1489,7 @@ ssh_login(int host_key_valid, | |||
1465 | packet_put_bignum(key); | 1489 | packet_put_bignum(key); |
1466 | 1490 | ||
1467 | /* Send protocol flags. */ | 1491 | /* Send protocol flags. */ |
1468 | packet_put_int(SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN); | 1492 | packet_put_int(client_flags); |
1469 | 1493 | ||
1470 | /* Send the packet now. */ | 1494 | /* Send the packet now. */ |
1471 | packet_send(); | 1495 | packet_send(); |