diff options
Diffstat (limited to 'ssh.c')
-rw-r--r-- | ssh.c | 119 |
1 files changed, 100 insertions, 19 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh.c,v 1.507 2019/09/13 04:27:35 djm Exp $ */ | 1 | /* $OpenBSD: ssh.c,v 1.519 2020/02/07 03:54:44 dtucker Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -65,6 +65,7 @@ | |||
65 | #include <stdio.h> | 65 | #include <stdio.h> |
66 | #include <stdlib.h> | 66 | #include <stdlib.h> |
67 | #include <string.h> | 67 | #include <string.h> |
68 | #include <stdarg.h> | ||
68 | #include <unistd.h> | 69 | #include <unistd.h> |
69 | #include <limits.h> | 70 | #include <limits.h> |
70 | #include <locale.h> | 71 | #include <locale.h> |
@@ -167,6 +168,12 @@ char *config = NULL; | |||
167 | */ | 168 | */ |
168 | char *host; | 169 | char *host; |
169 | 170 | ||
171 | /* | ||
172 | * A config can specify a path to forward, overriding SSH_AUTH_SOCK. If this is | ||
173 | * not NULL, forward the socket at this path instead. | ||
174 | */ | ||
175 | char *forward_agent_sock_path = NULL; | ||
176 | |||
170 | /* Various strings used to to percent_expand() arguments */ | 177 | /* Various strings used to to percent_expand() arguments */ |
171 | static char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; | 178 | static char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; |
172 | static char uidstr[32], *host_arg, *conn_hash_hex; | 179 | static char uidstr[32], *host_arg, *conn_hash_hex; |
@@ -595,6 +602,7 @@ main(int ac, char **av) | |||
595 | struct addrinfo *addrs = NULL; | 602 | struct addrinfo *addrs = NULL; |
596 | struct ssh_digest_ctx *md; | 603 | struct ssh_digest_ctx *md; |
597 | u_char conn_hash[SSH_DIGEST_MAX_LENGTH]; | 604 | u_char conn_hash[SSH_DIGEST_MAX_LENGTH]; |
605 | size_t n, len; | ||
598 | 606 | ||
599 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ | 607 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
600 | sanitise_stdfd(); | 608 | sanitise_stdfd(); |
@@ -728,13 +736,16 @@ main(int ac, char **av) | |||
728 | break; | 736 | break; |
729 | case 'Q': | 737 | case 'Q': |
730 | cp = NULL; | 738 | cp = NULL; |
731 | if (strcmp(optarg, "cipher") == 0) | 739 | if (strcmp(optarg, "cipher") == 0 || |
740 | strcasecmp(optarg, "Ciphers") == 0) | ||
732 | cp = cipher_alg_list('\n', 0); | 741 | cp = cipher_alg_list('\n', 0); |
733 | else if (strcmp(optarg, "cipher-auth") == 0) | 742 | else if (strcmp(optarg, "cipher-auth") == 0) |
734 | cp = cipher_alg_list('\n', 1); | 743 | cp = cipher_alg_list('\n', 1); |
735 | else if (strcmp(optarg, "mac") == 0) | 744 | else if (strcmp(optarg, "mac") == 0 || |
745 | strcasecmp(optarg, "MACs") == 0) | ||
736 | cp = mac_alg_list('\n'); | 746 | cp = mac_alg_list('\n'); |
737 | else if (strcmp(optarg, "kex") == 0) | 747 | else if (strcmp(optarg, "kex") == 0 || |
748 | strcasecmp(optarg, "KexAlgorithms") == 0) | ||
738 | cp = kex_alg_list('\n'); | 749 | cp = kex_alg_list('\n'); |
739 | else if (strcmp(optarg, "key") == 0) | 750 | else if (strcmp(optarg, "key") == 0) |
740 | cp = sshkey_alg_list(0, 0, 0, '\n'); | 751 | cp = sshkey_alg_list(0, 0, 0, '\n'); |
@@ -742,14 +753,26 @@ main(int ac, char **av) | |||
742 | cp = sshkey_alg_list(1, 0, 0, '\n'); | 753 | cp = sshkey_alg_list(1, 0, 0, '\n'); |
743 | else if (strcmp(optarg, "key-plain") == 0) | 754 | else if (strcmp(optarg, "key-plain") == 0) |
744 | cp = sshkey_alg_list(0, 1, 0, '\n'); | 755 | cp = sshkey_alg_list(0, 1, 0, '\n'); |
756 | else if (strcmp(optarg, "key-sig") == 0 || | ||
757 | strcasecmp(optarg, "PubkeyAcceptedKeyTypes") == 0 || | ||
758 | strcasecmp(optarg, "HostKeyAlgorithms") == 0 || | ||
759 | strcasecmp(optarg, "HostbasedKeyTypes") == 0 || | ||
760 | strcasecmp(optarg, "HostbasedAcceptedKeyTypes") == 0) | ||
761 | cp = sshkey_alg_list(0, 0, 1, '\n'); | ||
745 | else if (strcmp(optarg, "sig") == 0) | 762 | else if (strcmp(optarg, "sig") == 0) |
746 | cp = sshkey_alg_list(0, 1, 1, '\n'); | 763 | cp = sshkey_alg_list(0, 1, 1, '\n'); |
747 | else if (strcmp(optarg, "protocol-version") == 0) | 764 | else if (strcmp(optarg, "protocol-version") == 0) |
748 | cp = xstrdup("2"); | 765 | cp = xstrdup("2"); |
749 | else if (strcmp(optarg, "help") == 0) { | 766 | else if (strcmp(optarg, "compression") == 0) { |
767 | cp = xstrdup(compression_alg_list(0)); | ||
768 | len = strlen(cp); | ||
769 | for (n = 0; n < len; n++) | ||
770 | if (cp[n] == ',') | ||
771 | cp[n] = '\n'; | ||
772 | } else if (strcmp(optarg, "help") == 0) { | ||
750 | cp = xstrdup( | 773 | cp = xstrdup( |
751 | "cipher\ncipher-auth\nkex\nkey\n" | 774 | "cipher\ncipher-auth\ncompression\nkex\n" |
752 | "key-cert\nkey-plain\nmac\n" | 775 | "key\nkey-cert\nkey-plain\nkey-sig\nmac\n" |
753 | "protocol-version\nsig"); | 776 | "protocol-version\nsig"); |
754 | } | 777 | } |
755 | if (cp == NULL) | 778 | if (cp == NULL) |
@@ -952,7 +975,11 @@ main(int ac, char **av) | |||
952 | break; | 975 | break; |
953 | 976 | ||
954 | case 'C': | 977 | case 'C': |
978 | #ifdef WITH_ZLIB | ||
955 | options.compression = 1; | 979 | options.compression = 1; |
980 | #else | ||
981 | error("Compression not supported, disabling."); | ||
982 | #endif | ||
956 | break; | 983 | break; |
957 | case 'N': | 984 | case 'N': |
958 | no_shell_flag = 1; | 985 | no_shell_flag = 1; |
@@ -1230,11 +1257,21 @@ main(int ac, char **av) | |||
1230 | strcmp(options.proxy_command, "-") == 0 && | 1257 | strcmp(options.proxy_command, "-") == 0 && |
1231 | options.proxy_use_fdpass) | 1258 | options.proxy_use_fdpass) |
1232 | fatal("ProxyCommand=- and ProxyUseFDPass are incompatible"); | 1259 | fatal("ProxyCommand=- and ProxyUseFDPass are incompatible"); |
1233 | if (options.control_persist && | 1260 | if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK) { |
1234 | options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK) { | 1261 | if (options.control_persist && options.control_path != NULL) { |
1235 | debug("UpdateHostKeys=ask is incompatible with ControlPersist; " | 1262 | debug("UpdateHostKeys=ask is incompatible with " |
1236 | "disabling"); | 1263 | "ControlPersist; disabling"); |
1237 | options.update_hostkeys = 0; | 1264 | options.update_hostkeys = 0; |
1265 | } else if (sshbuf_len(command) != 0 || | ||
1266 | options.remote_command != NULL || | ||
1267 | options.request_tty == REQUEST_TTY_NO) { | ||
1268 | debug("UpdateHostKeys=ask is incompatible with " | ||
1269 | "remote command execution; disabling"); | ||
1270 | options.update_hostkeys = 0; | ||
1271 | } else if (options.log_level < SYSLOG_LEVEL_INFO) { | ||
1272 | /* no point logging anything; user won't see it */ | ||
1273 | options.update_hostkeys = 0; | ||
1274 | } | ||
1238 | } | 1275 | } |
1239 | if (options.connection_attempts <= 0) | 1276 | if (options.connection_attempts <= 0) |
1240 | fatal("Invalid number of ConnectionAttempts"); | 1277 | fatal("Invalid number of ConnectionAttempts"); |
@@ -1344,6 +1381,22 @@ main(int ac, char **av) | |||
1344 | exit(0); | 1381 | exit(0); |
1345 | } | 1382 | } |
1346 | 1383 | ||
1384 | /* Expand SecurityKeyProvider if it refers to an environment variable */ | ||
1385 | if (options.sk_provider != NULL && *options.sk_provider == '$' && | ||
1386 | strlen(options.sk_provider) > 1) { | ||
1387 | if ((cp = getenv(options.sk_provider + 1)) == NULL) { | ||
1388 | debug("Authenticator provider %s did not resolve; " | ||
1389 | "disabling", options.sk_provider); | ||
1390 | free(options.sk_provider); | ||
1391 | options.sk_provider = NULL; | ||
1392 | } else { | ||
1393 | debug2("resolved SecurityKeyProvider %s => %s", | ||
1394 | options.sk_provider, cp); | ||
1395 | free(options.sk_provider); | ||
1396 | options.sk_provider = xstrdup(cp); | ||
1397 | } | ||
1398 | } | ||
1399 | |||
1347 | if (muxclient_command != 0 && options.control_path == NULL) | 1400 | if (muxclient_command != 0 && options.control_path == NULL) |
1348 | fatal("No ControlPath specified for \"-O\" command"); | 1401 | fatal("No ControlPath specified for \"-O\" command"); |
1349 | if (options.control_path != NULL) { | 1402 | if (options.control_path != NULL) { |
@@ -1369,7 +1422,7 @@ main(int ac, char **av) | |||
1369 | timeout_ms = options.connection_timeout * 1000; | 1422 | timeout_ms = options.connection_timeout * 1000; |
1370 | 1423 | ||
1371 | /* Open a connection to the remote host. */ | 1424 | /* Open a connection to the remote host. */ |
1372 | if (ssh_connect(ssh, host_arg, host, addrs, &hostaddr, options.port, | 1425 | if (ssh_connect(ssh, host, host_arg, addrs, &hostaddr, options.port, |
1373 | options.address_family, options.connection_attempts, | 1426 | options.address_family, options.connection_attempts, |
1374 | &timeout_ms, options.tcp_keep_alive) != 0) | 1427 | &timeout_ms, options.tcp_keep_alive) != 0) |
1375 | exit(255); | 1428 | exit(255); |
@@ -1481,13 +1534,39 @@ main(int ac, char **av) | |||
1481 | } | 1534 | } |
1482 | } | 1535 | } |
1483 | 1536 | ||
1537 | if (options.forward_agent && (options.forward_agent_sock_path != NULL)) { | ||
1538 | p = tilde_expand_filename(options.forward_agent_sock_path, getuid()); | ||
1539 | cp = percent_expand(p, | ||
1540 | "d", pw->pw_dir, | ||
1541 | "h", host, | ||
1542 | "i", uidstr, | ||
1543 | "l", thishost, | ||
1544 | "r", options.user, | ||
1545 | "u", pw->pw_name, | ||
1546 | (char *)NULL); | ||
1547 | free(p); | ||
1548 | |||
1549 | if (cp[0] == '$') { | ||
1550 | if (!valid_env_name(cp + 1)) { | ||
1551 | fatal("Invalid ForwardAgent environment variable name %s", cp); | ||
1552 | } | ||
1553 | if ((p = getenv(cp + 1)) != NULL) | ||
1554 | forward_agent_sock_path = p; | ||
1555 | else | ||
1556 | options.forward_agent = 0; | ||
1557 | free(cp); | ||
1558 | } else { | ||
1559 | forward_agent_sock_path = cp; | ||
1560 | } | ||
1561 | } | ||
1562 | |||
1484 | /* Expand ~ in known host file names. */ | 1563 | /* Expand ~ in known host file names. */ |
1485 | tilde_expand_paths(options.system_hostfiles, | 1564 | tilde_expand_paths(options.system_hostfiles, |
1486 | options.num_system_hostfiles); | 1565 | options.num_system_hostfiles); |
1487 | tilde_expand_paths(options.user_hostfiles, options.num_user_hostfiles); | 1566 | tilde_expand_paths(options.user_hostfiles, options.num_user_hostfiles); |
1488 | 1567 | ||
1489 | signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ | 1568 | ssh_signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ |
1490 | signal(SIGCHLD, main_sigchld_handler); | 1569 | ssh_signal(SIGCHLD, main_sigchld_handler); |
1491 | 1570 | ||
1492 | /* Log into the remote system. Never returns if the login fails. */ | 1571 | /* Log into the remote system. Never returns if the login fails. */ |
1493 | ssh_login(ssh, &sensitive_data, host, (struct sockaddr *)&hostaddr, | 1572 | ssh_login(ssh, &sensitive_data, host, (struct sockaddr *)&hostaddr, |
@@ -2012,7 +2091,8 @@ load_public_identity_files(struct passwd *pw) | |||
2012 | struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES]; | 2091 | struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES]; |
2013 | int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES]; | 2092 | int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES]; |
2014 | #ifdef ENABLE_PKCS11 | 2093 | #ifdef ENABLE_PKCS11 |
2015 | struct sshkey **keys; | 2094 | struct sshkey **keys = NULL; |
2095 | char **comments = NULL; | ||
2016 | int nkeys; | 2096 | int nkeys; |
2017 | #endif /* PKCS11 */ | 2097 | #endif /* PKCS11 */ |
2018 | 2098 | ||
@@ -2031,18 +2111,19 @@ load_public_identity_files(struct passwd *pw) | |||
2031 | options.num_identity_files < SSH_MAX_IDENTITY_FILES && | 2111 | options.num_identity_files < SSH_MAX_IDENTITY_FILES && |
2032 | (pkcs11_init(!options.batch_mode) == 0) && | 2112 | (pkcs11_init(!options.batch_mode) == 0) && |
2033 | (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL, | 2113 | (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL, |
2034 | &keys)) > 0) { | 2114 | &keys, &comments)) > 0) { |
2035 | for (i = 0; i < nkeys; i++) { | 2115 | for (i = 0; i < nkeys; i++) { |
2036 | if (n_ids >= SSH_MAX_IDENTITY_FILES) { | 2116 | if (n_ids >= SSH_MAX_IDENTITY_FILES) { |
2037 | sshkey_free(keys[i]); | 2117 | sshkey_free(keys[i]); |
2118 | free(comments[i]); | ||
2038 | continue; | 2119 | continue; |
2039 | } | 2120 | } |
2040 | identity_keys[n_ids] = keys[i]; | 2121 | identity_keys[n_ids] = keys[i]; |
2041 | identity_files[n_ids] = | 2122 | identity_files[n_ids] = comments[i]; /* transferred */ |
2042 | xstrdup(options.pkcs11_provider); /* XXX */ | ||
2043 | n_ids++; | 2123 | n_ids++; |
2044 | } | 2124 | } |
2045 | free(keys); | 2125 | free(keys); |
2126 | free(comments); | ||
2046 | } | 2127 | } |
2047 | #endif /* ENABLE_PKCS11 */ | 2128 | #endif /* ENABLE_PKCS11 */ |
2048 | for (i = 0; i < options.num_identity_files; i++) { | 2129 | for (i = 0; i < options.num_identity_files; i++) { |