diff options
Diffstat (limited to 'sshconnect.c')
-rw-r--r-- | sshconnect.c | 187 |
1 files changed, 117 insertions, 70 deletions
diff --git a/sshconnect.c b/sshconnect.c index 0657c37e8..0b1c0901f 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.14 1999/11/24 13:26:23 damien Exp $"); | 11 | RCSID("$Id: sshconnect.c,v 1.15 1999/11/25 00:54:59 damien Exp $"); |
12 | 12 | ||
13 | #ifdef HAVE_OPENSSL | 13 | #ifdef HAVE_OPENSSL |
14 | #include <openssl/bn.h> | 14 | #include <openssl/bn.h> |
@@ -142,8 +142,10 @@ ssh_create_socket(uid_t original_real_uid, int privileged) | |||
142 | { | 142 | { |
143 | int sock; | 143 | int sock; |
144 | 144 | ||
145 | /* If we are running as root and want to connect to a privileged | 145 | /* |
146 | port, bind our own socket to a privileged port. */ | 146 | * If we are running as root and want to connect to a privileged |
147 | * port, bind our own socket to a privileged port. | ||
148 | */ | ||
147 | if (privileged) { | 149 | if (privileged) { |
148 | int p = IPPORT_RESERVED - 1; | 150 | int p = IPPORT_RESERVED - 1; |
149 | 151 | ||
@@ -227,9 +229,11 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr, | |||
227 | !anonymous && geteuid() == 0 && | 229 | !anonymous && geteuid() == 0 && |
228 | port < IPPORT_RESERVED); | 230 | port < IPPORT_RESERVED); |
229 | 231 | ||
230 | /* Connect to the host. We use the user's uid in | 232 | /* |
231 | the hope that it will help with the problems of | 233 | * Connect to the host. We use the user's uid in the |
232 | tcp_wrappers showing the remote uid as root. */ | 234 | * hope that it will help with the problems of |
235 | * tcp_wrappers showing the remote uid as root. | ||
236 | */ | ||
233 | temporarily_use_uid(original_real_uid); | 237 | temporarily_use_uid(original_real_uid); |
234 | if (connect(sock, (struct sockaddr *) hostaddr, sizeof(*hostaddr)) | 238 | if (connect(sock, (struct sockaddr *) hostaddr, sizeof(*hostaddr)) |
235 | >= 0) { | 239 | >= 0) { |
@@ -270,8 +274,12 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr, | |||
270 | !anonymous && geteuid() == 0 && | 274 | !anonymous && geteuid() == 0 && |
271 | port < IPPORT_RESERVED); | 275 | port < IPPORT_RESERVED); |
272 | 276 | ||
273 | /* Connect to the host. We use the user's uid in the hope that | 277 | /* |
274 | it will help with tcp_wrappers showing the remote uid as root. */ | 278 | * Connect to the host. We use the user's |
279 | * uid in the hope that it will help with | ||
280 | * tcp_wrappers showing the remote uid as | ||
281 | * root. | ||
282 | */ | ||
275 | temporarily_use_uid(original_real_uid); | 283 | temporarily_use_uid(original_real_uid); |
276 | if (connect(sock, (struct sockaddr *) hostaddr, | 284 | if (connect(sock, (struct sockaddr *) hostaddr, |
277 | sizeof(*hostaddr)) >= 0) { | 285 | sizeof(*hostaddr)) >= 0) { |
@@ -282,8 +290,12 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr, | |||
282 | debug("connect: %.100s", strerror(errno)); | 290 | debug("connect: %.100s", strerror(errno)); |
283 | restore_uid(); | 291 | restore_uid(); |
284 | 292 | ||
285 | /* Close the failed socket; there appear to be some problems when | 293 | /* |
286 | reusing a socket for which connect() has already returned an error. */ | 294 | * Close the failed socket; there appear to |
295 | * be some problems when reusing a socket for | ||
296 | * which connect() has already returned an | ||
297 | * error. | ||
298 | */ | ||
287 | shutdown(sock, SHUT_RDWR); | 299 | shutdown(sock, SHUT_RDWR); |
288 | close(sock); | 300 | close(sock); |
289 | } | 301 | } |
@@ -300,10 +312,11 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr, | |||
300 | 312 | ||
301 | debug("Connection established."); | 313 | debug("Connection established."); |
302 | 314 | ||
303 | /* Set socket options. We would like the socket to disappear as | 315 | /* |
304 | soon as it has been closed for whatever reason. */ | 316 | * Set socket options. We would like the socket to disappear as soon |
305 | /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, | 317 | * as it has been closed for whatever reason. |
306 | sizeof(on)); */ | 318 | */ |
319 | /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */ | ||
307 | setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on)); | 320 | setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on)); |
308 | linger.l_onoff = 1; | 321 | linger.l_onoff = 1; |
309 | linger.l_linger = 5; | 322 | linger.l_linger = 5; |
@@ -493,8 +506,10 @@ try_rsa_authentication(struct passwd * pw, const char *authfile) | |||
493 | /* Wait for server's response. */ | 506 | /* Wait for server's response. */ |
494 | type = packet_read(&plen); | 507 | type = packet_read(&plen); |
495 | 508 | ||
496 | /* The server responds with failure if it doesn\'t like our key or | 509 | /* |
497 | doesn\'t support RSA authentication. */ | 510 | * The server responds with failure if it doesn\'t like our key or |
511 | * doesn\'t support RSA authentication. | ||
512 | */ | ||
498 | if (type == SSH_SMSG_FAILURE) { | 513 | if (type == SSH_SMSG_FAILURE) { |
499 | debug("Server refused our key."); | 514 | debug("Server refused our key."); |
500 | xfree(comment); | 515 | xfree(comment); |
@@ -514,8 +529,10 @@ try_rsa_authentication(struct passwd * pw, const char *authfile) | |||
514 | debug("Received RSA challenge from server."); | 529 | debug("Received RSA challenge from server."); |
515 | 530 | ||
516 | private_key = RSA_new(); | 531 | private_key = RSA_new(); |
517 | /* Load the private key. Try first with empty passphrase; if it | 532 | /* |
518 | fails, ask for a passphrase. */ | 533 | * Load the private key. Try first with empty passphrase; if it |
534 | * fails, ask for a passphrase. | ||
535 | */ | ||
519 | if (!load_private_key(authfile, "", private_key, NULL)) { | 536 | if (!load_private_key(authfile, "", private_key, NULL)) { |
520 | char buf[300]; | 537 | char buf[300]; |
521 | snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ", | 538 | snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ", |
@@ -720,9 +737,11 @@ try_kerberos_authentication() | |||
720 | 737 | ||
721 | packet_integrity_check(plen, 4 + auth.length, type); | 738 | packet_integrity_check(plen, 4 + auth.length, type); |
722 | 739 | ||
723 | /* If his response isn't properly encrypted with the | 740 | /* |
724 | session key, and the decrypted checksum fails to match, | 741 | * If his response isn't properly encrypted with the session |
725 | he's bogus. Bail out. */ | 742 | * key, and the decrypted checksum fails to match, he's |
743 | * bogus. Bail out. | ||
744 | */ | ||
726 | r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session, | 745 | r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session, |
727 | &foreign, &local, &msg_data); | 746 | &foreign, &local, &msg_data); |
728 | if (r != KSUCCESS) { | 747 | if (r != KSUCCESS) { |
@@ -894,8 +913,10 @@ ssh_exchange_identification() | |||
894 | } | 913 | } |
895 | buf[sizeof(buf) - 1] = 0; | 914 | buf[sizeof(buf) - 1] = 0; |
896 | 915 | ||
897 | /* Check that the versions match. In future this might accept | 916 | /* |
898 | several versions and set appropriate flags to handle them. */ | 917 | * Check that the versions match. In future this might accept |
918 | * several versions and set appropriate flags to handle them. | ||
919 | */ | ||
899 | if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, | 920 | if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, |
900 | remote_version) != 3) | 921 | remote_version) != 3) |
901 | fatal("Bad remote protocol version identification: '%.100s'", buf); | 922 | fatal("Bad remote protocol version identification: '%.100s'", buf); |
@@ -916,9 +937,11 @@ ssh_exchange_identification() | |||
916 | } | 937 | } |
917 | } | 938 | } |
918 | #if 0 | 939 | #if 0 |
919 | /* Removed for now, to permit compatibility with latter versions. | 940 | /* |
920 | The server will reject our version and disconnect if it doesn't | 941 | * Removed for now, to permit compatibility with latter versions. The |
921 | support it. */ | 942 | * server will reject our version and disconnect if it doesn't |
943 | * support it. | ||
944 | */ | ||
922 | if (remote_major != PROTOCOL_MAJOR) | 945 | if (remote_major != PROTOCOL_MAJOR) |
923 | fatal("Protocol major versions differ: %d vs. %d", | 946 | fatal("Protocol major versions differ: %d vs. %d", |
924 | PROTOCOL_MAJOR, remote_major); | 947 | PROTOCOL_MAJOR, remote_major); |
@@ -1086,10 +1109,7 @@ ssh_login(int host_key_valid, | |||
1086 | protocol_flags = packet_get_int(); | 1109 | protocol_flags = packet_get_int(); |
1087 | packet_set_protocol_flags(protocol_flags); | 1110 | packet_set_protocol_flags(protocol_flags); |
1088 | 1111 | ||
1089 | /* Get supported cipher types. */ | ||
1090 | supported_ciphers = packet_get_int(); | 1112 | supported_ciphers = packet_get_int(); |
1091 | |||
1092 | /* Get supported authentication types. */ | ||
1093 | supported_authentications = packet_get_int(); | 1113 | supported_authentications = packet_get_int(); |
1094 | 1114 | ||
1095 | debug("Received server public key (%d bits) and host key (%d bits).", | 1115 | debug("Received server public key (%d bits) and host key (%d bits).", |
@@ -1099,11 +1119,12 @@ ssh_login(int host_key_valid, | |||
1099 | 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4, | 1119 | 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4, |
1100 | SSH_SMSG_PUBLIC_KEY); | 1120 | SSH_SMSG_PUBLIC_KEY); |
1101 | 1121 | ||
1102 | /* Compute the session id. */ | ||
1103 | compute_session_id(session_id, check_bytes, host_key->n, public_key->n); | 1122 | compute_session_id(session_id, check_bytes, host_key->n, public_key->n); |
1104 | 1123 | ||
1105 | /* Check if the host key is present in the user\'s list of known | 1124 | /* |
1106 | hosts or in the systemwide list. */ | 1125 | * Check if the host key is present in the user\'s list of known |
1126 | * hosts or in the systemwide list. | ||
1127 | */ | ||
1107 | host_status = check_host_in_hostfile(options.user_hostfile, host, | 1128 | host_status = check_host_in_hostfile(options.user_hostfile, host, |
1108 | host_key->e, host_key->n, | 1129 | host_key->e, host_key->n, |
1109 | file_key->e, file_key->n); | 1130 | file_key->e, file_key->n); |
@@ -1111,18 +1132,22 @@ ssh_login(int host_key_valid, | |||
1111 | host_status = check_host_in_hostfile(options.system_hostfile, host, | 1132 | host_status = check_host_in_hostfile(options.system_hostfile, host, |
1112 | host_key->e, host_key->n, | 1133 | host_key->e, host_key->n, |
1113 | file_key->e, file_key->n); | 1134 | file_key->e, file_key->n); |
1114 | /* Force accepting of the host key for localhost and 127.0.0.1. | 1135 | /* |
1115 | The problem is that if the home directory is NFS-mounted to | 1136 | * Force accepting of the host key for localhost and 127.0.0.1. The |
1116 | multiple machines, localhost will refer to a different machine | 1137 | * problem is that if the home directory is NFS-mounted to multiple |
1117 | in each of them, and the user will get bogus HOST_CHANGED | 1138 | * machines, localhost will refer to a different machine in each of |
1118 | warnings. This essentially disables host authentication for | 1139 | * them, and the user will get bogus HOST_CHANGED warnings. This |
1119 | localhost; however, this is probably not a real problem. */ | 1140 | * essentially disables host authentication for localhost; however, |
1141 | * this is probably not a real problem. | ||
1142 | */ | ||
1120 | if (local) { | 1143 | if (local) { |
1121 | debug("Forcing accepting of host key for localhost."); | 1144 | debug("Forcing accepting of host key for localhost."); |
1122 | host_status = HOST_OK; | 1145 | host_status = HOST_OK; |
1123 | } | 1146 | } |
1124 | /* Also perform check for the ip address, skip the check if we are | 1147 | /* |
1125 | localhost or the hostname was an ip address to begin with */ | 1148 | * Also perform check for the ip address, skip the check if we are |
1149 | * localhost or the hostname was an ip address to begin with | ||
1150 | */ | ||
1126 | if (options.check_host_ip && !local && strcmp(host, ip)) { | 1151 | if (options.check_host_ip && !local && strcmp(host, ip)) { |
1127 | RSA *ip_key = RSA_new(); | 1152 | RSA *ip_key = RSA_new(); |
1128 | ip_key->n = BN_new(); | 1153 | ip_key->n = BN_new(); |
@@ -1226,13 +1251,18 @@ ssh_login(int host_key_valid, | |||
1226 | error("Add correct host key in %.100s to get rid of this message.", | 1251 | error("Add correct host key in %.100s to get rid of this message.", |
1227 | options.user_hostfile); | 1252 | options.user_hostfile); |
1228 | 1253 | ||
1229 | /* If strict host key checking is in use, the user will | 1254 | /* |
1230 | have to edit the key manually and we can only abort. */ | 1255 | * If strict host key checking is in use, the user will have |
1256 | * to edit the key manually and we can only abort. | ||
1257 | */ | ||
1231 | if (options.strict_host_key_checking) | 1258 | if (options.strict_host_key_checking) |
1232 | fatal("Host key for %.200s has changed and you have requested strict checking.", host); | 1259 | fatal("Host key for %.200s has changed and you have requested strict checking.", host); |
1233 | 1260 | ||
1234 | /* If strict host key checking has not been requested, allow the connection | 1261 | /* |
1235 | but without password authentication or agent forwarding. */ | 1262 | * If strict host key checking has not been requested, allow |
1263 | * the connection but without password authentication or | ||
1264 | * agent forwarding. | ||
1265 | */ | ||
1236 | if (options.password_authentication) { | 1266 | if (options.password_authentication) { |
1237 | error("Password authentication is disabled to avoid trojan horses."); | 1267 | error("Password authentication is disabled to avoid trojan horses."); |
1238 | options.password_authentication = 0; | 1268 | options.password_authentication = 0; |
@@ -1241,11 +1271,13 @@ ssh_login(int host_key_valid, | |||
1241 | error("Agent forwarding is disabled to avoid trojan horses."); | 1271 | error("Agent forwarding is disabled to avoid trojan horses."); |
1242 | options.forward_agent = 0; | 1272 | options.forward_agent = 0; |
1243 | } | 1273 | } |
1244 | /* XXX Should permit the user to change to use the new id. | 1274 | /* |
1245 | This could be done by converting the host key to an | 1275 | * XXX Should permit the user to change to use the new id. |
1246 | identifying sentence, tell that the host identifies | 1276 | * This could be done by converting the host key to an |
1247 | itself by that sentence, and ask the user if he/she | 1277 | * identifying sentence, tell that the host identifies itself |
1248 | whishes to accept the authentication. */ | 1278 | * by that sentence, and ask the user if he/she whishes to |
1279 | * accept the authentication. | ||
1280 | */ | ||
1249 | break; | 1281 | break; |
1250 | } | 1282 | } |
1251 | 1283 | ||
@@ -1255,9 +1287,11 @@ ssh_login(int host_key_valid, | |||
1255 | /* Generate a session key. */ | 1287 | /* Generate a session key. */ |
1256 | arc4random_stir(); | 1288 | arc4random_stir(); |
1257 | 1289 | ||
1258 | /* Generate an encryption key for the session. The key is a 256 | 1290 | /* |
1259 | bit random number, interpreted as a 32-byte key, with the least | 1291 | * Generate an encryption key for the session. The key is a 256 bit |
1260 | significant 8 bits being the first byte of the key. */ | 1292 | * random number, interpreted as a 32-byte key, with the least |
1293 | * significant 8 bits being the first byte of the key. | ||
1294 | */ | ||
1261 | for (i = 0; i < 32; i++) { | 1295 | for (i = 0; i < 32; i++) { |
1262 | if (i % 4 == 0) | 1296 | if (i % 4 == 0) |
1263 | rand = arc4random(); | 1297 | rand = arc4random(); |
@@ -1265,9 +1299,11 @@ ssh_login(int host_key_valid, | |||
1265 | rand >>= 8; | 1299 | rand >>= 8; |
1266 | } | 1300 | } |
1267 | 1301 | ||
1268 | /* According to the protocol spec, the first byte of the session | 1302 | /* |
1269 | key is the highest byte of the integer. The session key is | 1303 | * According to the protocol spec, the first byte of the session key |
1270 | xored with the first 16 bytes of the session id. */ | 1304 | * is the highest byte of the integer. The session key is xored with |
1305 | * the first 16 bytes of the session id. | ||
1306 | */ | ||
1271 | key = BN_new(); | 1307 | key = BN_new(); |
1272 | BN_set_word(key, 0); | 1308 | BN_set_word(key, 0); |
1273 | for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) { | 1309 | for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) { |
@@ -1278,8 +1314,10 @@ ssh_login(int host_key_valid, | |||
1278 | BN_add_word(key, session_key[i]); | 1314 | BN_add_word(key, session_key[i]); |
1279 | } | 1315 | } |
1280 | 1316 | ||
1281 | /* Encrypt the integer using the public key and host key of the | 1317 | /* |
1282 | server (key with smaller modulus first). */ | 1318 | * Encrypt the integer using the public key and host key of the |
1319 | * server (key with smaller modulus first). | ||
1320 | */ | ||
1283 | if (BN_cmp(public_key->n, host_key->n) < 0) { | 1321 | if (BN_cmp(public_key->n, host_key->n) < 0) { |
1284 | /* Public key has smaller modulus. */ | 1322 | /* Public key has smaller modulus. */ |
1285 | if (BN_num_bits(host_key->n) < | 1323 | if (BN_num_bits(host_key->n) < |
@@ -1354,8 +1392,10 @@ ssh_login(int host_key_valid, | |||
1354 | /* We will no longer need the session key here. Destroy any extra copies. */ | 1392 | /* We will no longer need the session key here. Destroy any extra copies. */ |
1355 | memset(session_key, 0, sizeof(session_key)); | 1393 | memset(session_key, 0, sizeof(session_key)); |
1356 | 1394 | ||
1357 | /* Expect a success message from the server. Note that this | 1395 | /* |
1358 | message will be received in encrypted form. */ | 1396 | * Expect a success message from the server. Note that this message |
1397 | * will be received in encrypted form. | ||
1398 | */ | ||
1359 | packet_read_expect(&payload_len, SSH_SMSG_SUCCESS); | 1399 | packet_read_expect(&payload_len, SSH_SMSG_SUCCESS); |
1360 | 1400 | ||
1361 | debug("Received encrypted confirmation."); | 1401 | debug("Received encrypted confirmation."); |
@@ -1366,9 +1406,11 @@ ssh_login(int host_key_valid, | |||
1366 | packet_send(); | 1406 | packet_send(); |
1367 | packet_write_wait(); | 1407 | packet_write_wait(); |
1368 | 1408 | ||
1369 | /* The server should respond with success if no authentication is | 1409 | /* |
1370 | needed (the user has no password). Otherwise the server | 1410 | * The server should respond with success if no authentication is |
1371 | responds with failure. */ | 1411 | * needed (the user has no password). Otherwise the server responds |
1412 | * with failure. | ||
1413 | */ | ||
1372 | type = packet_read(&payload_len); | 1414 | type = packet_read(&payload_len); |
1373 | 1415 | ||
1374 | /* check whether the connection was accepted without authentication. */ | 1416 | /* check whether the connection was accepted without authentication. */ |
@@ -1410,8 +1452,10 @@ ssh_login(int host_key_valid, | |||
1410 | } | 1452 | } |
1411 | #endif /* KRB4 */ | 1453 | #endif /* KRB4 */ |
1412 | 1454 | ||
1413 | /* Use rhosts authentication if running in privileged socket and | 1455 | /* |
1414 | we do not wish to remain anonymous. */ | 1456 | * Use rhosts authentication if running in privileged socket and we |
1457 | * do not wish to remain anonymous. | ||
1458 | */ | ||
1415 | if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) && | 1459 | if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) && |
1416 | options.rhosts_authentication) { | 1460 | options.rhosts_authentication) { |
1417 | debug("Trying rhosts authentication."); | 1461 | debug("Trying rhosts authentication."); |
@@ -1428,8 +1472,10 @@ ssh_login(int host_key_valid, | |||
1428 | packet_disconnect("Protocol error: got %d in response to rhosts auth", | 1472 | packet_disconnect("Protocol error: got %d in response to rhosts auth", |
1429 | type); | 1473 | type); |
1430 | } | 1474 | } |
1431 | /* Try .rhosts or /etc/hosts.equiv authentication with RSA host | 1475 | /* |
1432 | authentication. */ | 1476 | * Try .rhosts or /etc/hosts.equiv authentication with RSA host |
1477 | * authentication. | ||
1478 | */ | ||
1433 | if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) && | 1479 | if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) && |
1434 | options.rhosts_rsa_authentication && host_key_valid) { | 1480 | options.rhosts_rsa_authentication && host_key_valid) { |
1435 | if (try_rhosts_rsa_authentication(local_user, own_host_key)) | 1481 | if (try_rhosts_rsa_authentication(local_user, own_host_key)) |
@@ -1438,10 +1484,11 @@ ssh_login(int host_key_valid, | |||
1438 | /* Try RSA authentication if the server supports it. */ | 1484 | /* Try RSA authentication if the server supports it. */ |
1439 | if ((supported_authentications & (1 << SSH_AUTH_RSA)) && | 1485 | if ((supported_authentications & (1 << SSH_AUTH_RSA)) && |
1440 | options.rsa_authentication) { | 1486 | options.rsa_authentication) { |
1441 | /* Try RSA authentication using the authentication agent. | 1487 | /* |
1442 | The agent is tried first because no passphrase is | 1488 | * Try RSA authentication using the authentication agent. The |
1443 | needed for it, whereas identity files may require | 1489 | * agent is tried first because no passphrase is needed for |
1444 | passphrases. */ | 1490 | * it, whereas identity files may require passphrases. |
1491 | */ | ||
1445 | if (try_agent_authentication()) | 1492 | if (try_agent_authentication()) |
1446 | return; | 1493 | return; |
1447 | 1494 | ||