diff options
Diffstat (limited to 'ssh.c')
-rw-r--r-- | ssh.c | 344 |
1 files changed, 225 insertions, 119 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh.c,v 1.464 2017/09/21 19:16:53 markus Exp $ */ | 1 | /* $OpenBSD: ssh.c,v 1.475 2018/02/23 15:58:38 markus 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 |
@@ -168,6 +168,10 @@ char *config = NULL; | |||
168 | */ | 168 | */ |
169 | char *host; | 169 | char *host; |
170 | 170 | ||
171 | /* Various strings used to to percent_expand() arguments */ | ||
172 | static char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; | ||
173 | static char uidstr[32], *host_arg, *conn_hash_hex; | ||
174 | |||
171 | /* socket address the host resolves to */ | 175 | /* socket address the host resolves to */ |
172 | struct sockaddr_storage hostaddr; | 176 | struct sockaddr_storage hostaddr; |
173 | 177 | ||
@@ -197,19 +201,19 @@ static void | |||
197 | usage(void) | 201 | usage(void) |
198 | { | 202 | { |
199 | fprintf(stderr, | 203 | fprintf(stderr, |
200 | "usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n" | 204 | "usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface]\n" |
201 | " [-D [bind_address:]port] [-E log_file] [-e escape_char]\n" | 205 | " [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]\n" |
202 | " [-F configfile] [-I pkcs11] [-i identity_file]\n" | 206 | " [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11]\n" |
203 | " [-J [user@]host[:port]] [-L address] [-l login_name] [-m mac_spec]\n" | 207 | " [-i identity_file] [-J [user@]host[:port]] [-L address]\n" |
204 | " [-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address]\n" | 208 | " [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n" |
205 | " [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]]\n" | 209 | " [-Q query_option] [-R address] [-S ctl_path] [-W host:port]\n" |
206 | " [user@]hostname [command]\n" | 210 | " [-w local_tun[:remote_tun]] destination [command]\n" |
207 | ); | 211 | ); |
208 | exit(255); | 212 | exit(255); |
209 | } | 213 | } |
210 | 214 | ||
211 | static int ssh_session2(struct ssh *); | 215 | static int ssh_session2(struct ssh *, struct passwd *); |
212 | static void load_public_identity_files(void); | 216 | static void load_public_identity_files(struct passwd *); |
213 | static void main_sigchld_handler(int); | 217 | static void main_sigchld_handler(int); |
214 | 218 | ||
215 | /* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */ | 219 | /* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */ |
@@ -267,6 +271,40 @@ resolve_host(const char *name, int port, int logerr, char *cname, size_t clen) | |||
267 | return res; | 271 | return res; |
268 | } | 272 | } |
269 | 273 | ||
274 | /* Returns non-zero if name can only be an address and not a hostname */ | ||
275 | static int | ||
276 | is_addr_fast(const char *name) | ||
277 | { | ||
278 | return (strchr(name, '%') != NULL || strchr(name, ':') != NULL || | ||
279 | strspn(name, "0123456789.") == strlen(name)); | ||
280 | } | ||
281 | |||
282 | /* Returns non-zero if name represents a valid, single address */ | ||
283 | static int | ||
284 | is_addr(const char *name) | ||
285 | { | ||
286 | char strport[NI_MAXSERV]; | ||
287 | struct addrinfo hints, *res; | ||
288 | |||
289 | if (is_addr_fast(name)) | ||
290 | return 1; | ||
291 | |||
292 | snprintf(strport, sizeof strport, "%u", default_ssh_port()); | ||
293 | memset(&hints, 0, sizeof(hints)); | ||
294 | hints.ai_family = options.address_family == -1 ? | ||
295 | AF_UNSPEC : options.address_family; | ||
296 | hints.ai_socktype = SOCK_STREAM; | ||
297 | hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV; | ||
298 | if (getaddrinfo(name, strport, &hints, &res) != 0) | ||
299 | return 0; | ||
300 | if (res == NULL || res->ai_next != NULL) { | ||
301 | freeaddrinfo(res); | ||
302 | return 0; | ||
303 | } | ||
304 | freeaddrinfo(res); | ||
305 | return 1; | ||
306 | } | ||
307 | |||
270 | /* | 308 | /* |
271 | * Attempt to resolve a numeric host address / port to a single address. | 309 | * Attempt to resolve a numeric host address / port to a single address. |
272 | * Returns a canonical address string. | 310 | * Returns a canonical address string. |
@@ -372,20 +410,10 @@ resolve_canonicalize(char **hostp, int port) | |||
372 | char *cp, *fullhost, newname[NI_MAXHOST]; | 410 | char *cp, *fullhost, newname[NI_MAXHOST]; |
373 | struct addrinfo *addrs; | 411 | struct addrinfo *addrs; |
374 | 412 | ||
375 | if (options.canonicalize_hostname == SSH_CANONICALISE_NO) | ||
376 | return NULL; | ||
377 | |||
378 | /* | 413 | /* |
379 | * Don't attempt to canonicalize names that will be interpreted by | 414 | * Attempt to canonicalise addresses, regardless of |
380 | * a proxy unless the user specifically requests so. | 415 | * whether hostname canonicalisation was requested |
381 | */ | 416 | */ |
382 | direct = option_clear_or_none(options.proxy_command) && | ||
383 | options.jump_host == NULL; | ||
384 | if (!direct && | ||
385 | options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) | ||
386 | return NULL; | ||
387 | |||
388 | /* Try numeric hostnames first */ | ||
389 | if ((addrs = resolve_addr(*hostp, port, | 417 | if ((addrs = resolve_addr(*hostp, port, |
390 | newname, sizeof(newname))) != NULL) { | 418 | newname, sizeof(newname))) != NULL) { |
391 | debug2("%s: hostname %.100s is address", __func__, *hostp); | 419 | debug2("%s: hostname %.100s is address", __func__, *hostp); |
@@ -398,6 +426,30 @@ resolve_canonicalize(char **hostp, int port) | |||
398 | return addrs; | 426 | return addrs; |
399 | } | 427 | } |
400 | 428 | ||
429 | /* | ||
430 | * If this looks like an address but didn't parse as one, it might | ||
431 | * be an address with an invalid interface scope. Skip further | ||
432 | * attempts at canonicalisation. | ||
433 | */ | ||
434 | if (is_addr_fast(*hostp)) { | ||
435 | debug("%s: hostname %.100s is an unrecognised address", | ||
436 | __func__, *hostp); | ||
437 | return NULL; | ||
438 | } | ||
439 | |||
440 | if (options.canonicalize_hostname == SSH_CANONICALISE_NO) | ||
441 | return NULL; | ||
442 | |||
443 | /* | ||
444 | * Don't attempt to canonicalize names that will be interpreted by | ||
445 | * a proxy unless the user specifically requests so. | ||
446 | */ | ||
447 | direct = option_clear_or_none(options.proxy_command) && | ||
448 | options.jump_host == NULL; | ||
449 | if (!direct && | ||
450 | options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) | ||
451 | return NULL; | ||
452 | |||
401 | /* If domain name is anchored, then resolve it now */ | 453 | /* If domain name is anchored, then resolve it now */ |
402 | if ((*hostp)[strlen(*hostp) - 1] == '.') { | 454 | if ((*hostp)[strlen(*hostp) - 1] == '.') { |
403 | debug3("%s: name is fully qualified", __func__); | 455 | debug3("%s: name is fully qualified", __func__); |
@@ -456,14 +508,14 @@ resolve_canonicalize(char **hostp, int port) | |||
456 | * file if the user specifies a config file on the command line. | 508 | * file if the user specifies a config file on the command line. |
457 | */ | 509 | */ |
458 | static void | 510 | static void |
459 | process_config_files(const char *host_arg, struct passwd *pw, int post_canon) | 511 | process_config_files(const char *host_name, struct passwd *pw, int post_canon) |
460 | { | 512 | { |
461 | char buf[PATH_MAX]; | 513 | char buf[PATH_MAX]; |
462 | int r; | 514 | int r; |
463 | 515 | ||
464 | if (config != NULL) { | 516 | if (config != NULL) { |
465 | if (strcasecmp(config, "none") != 0 && | 517 | if (strcasecmp(config, "none") != 0 && |
466 | !read_config_file(config, pw, host, host_arg, &options, | 518 | !read_config_file(config, pw, host, host_name, &options, |
467 | SSHCONF_USERCONF | (post_canon ? SSHCONF_POSTCANON : 0))) | 519 | SSHCONF_USERCONF | (post_canon ? SSHCONF_POSTCANON : 0))) |
468 | fatal("Can't open user config file %.100s: " | 520 | fatal("Can't open user config file %.100s: " |
469 | "%.100s", config, strerror(errno)); | 521 | "%.100s", config, strerror(errno)); |
@@ -471,13 +523,13 @@ process_config_files(const char *host_arg, struct passwd *pw, int post_canon) | |||
471 | r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, | 523 | r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, |
472 | _PATH_SSH_USER_CONFFILE); | 524 | _PATH_SSH_USER_CONFFILE); |
473 | if (r > 0 && (size_t)r < sizeof(buf)) | 525 | if (r > 0 && (size_t)r < sizeof(buf)) |
474 | (void)read_config_file(buf, pw, host, host_arg, | 526 | (void)read_config_file(buf, pw, host, host_name, |
475 | &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | | 527 | &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | |
476 | (post_canon ? SSHCONF_POSTCANON : 0)); | 528 | (post_canon ? SSHCONF_POSTCANON : 0)); |
477 | 529 | ||
478 | /* Read systemwide configuration file after user config. */ | 530 | /* Read systemwide configuration file after user config. */ |
479 | (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, | 531 | (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, |
480 | host, host_arg, &options, | 532 | host, host_name, &options, |
481 | post_canon ? SSHCONF_POSTCANON : 0); | 533 | post_canon ? SSHCONF_POSTCANON : 0); |
482 | } | 534 | } |
483 | } | 535 | } |
@@ -510,10 +562,9 @@ main(int ac, char **av) | |||
510 | { | 562 | { |
511 | struct ssh *ssh = NULL; | 563 | struct ssh *ssh = NULL; |
512 | int i, r, opt, exit_status, use_syslog, direct, timeout_ms; | 564 | int i, r, opt, exit_status, use_syslog, direct, timeout_ms; |
513 | int config_test = 0, opt_terminated = 0; | 565 | int was_addr, config_test = 0, opt_terminated = 0; |
514 | char *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile; | 566 | char *p, *cp, *line, *argv0, buf[PATH_MAX], *logfile; |
515 | char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; | 567 | char cname[NI_MAXHOST]; |
516 | char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex; | ||
517 | struct stat st; | 568 | struct stat st; |
518 | struct passwd *pw; | 569 | struct passwd *pw; |
519 | extern int optind, optreset; | 570 | extern int optind, optreset; |
@@ -612,7 +663,7 @@ main(int ac, char **av) | |||
612 | 663 | ||
613 | again: | 664 | again: |
614 | while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" | 665 | while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" |
615 | "ACD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { | 666 | "AB:CD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { |
616 | switch (opt) { | 667 | switch (opt) { |
617 | case '1': | 668 | case '1': |
618 | fatal("SSH protocol v.1 is no longer supported"); | 669 | fatal("SSH protocol v.1 is no longer supported"); |
@@ -846,14 +897,18 @@ main(int ac, char **av) | |||
846 | options.control_master = SSHCTL_MASTER_YES; | 897 | options.control_master = SSHCTL_MASTER_YES; |
847 | break; | 898 | break; |
848 | case 'p': | 899 | case 'p': |
849 | options.port = a2port(optarg); | 900 | if (options.port == -1) { |
850 | if (options.port <= 0) { | 901 | options.port = a2port(optarg); |
851 | fprintf(stderr, "Bad port '%s'\n", optarg); | 902 | if (options.port <= 0) { |
852 | exit(255); | 903 | fprintf(stderr, "Bad port '%s'\n", |
904 | optarg); | ||
905 | exit(255); | ||
906 | } | ||
853 | } | 907 | } |
854 | break; | 908 | break; |
855 | case 'l': | 909 | case 'l': |
856 | options.user = optarg; | 910 | if (options.user == NULL) |
911 | options.user = optarg; | ||
857 | break; | 912 | break; |
858 | 913 | ||
859 | case 'L': | 914 | case 'L': |
@@ -918,6 +973,9 @@ main(int ac, char **av) | |||
918 | case 'b': | 973 | case 'b': |
919 | options.bind_address = optarg; | 974 | options.bind_address = optarg; |
920 | break; | 975 | break; |
976 | case 'B': | ||
977 | options.bind_interface = optarg; | ||
978 | break; | ||
921 | case 'F': | 979 | case 'F': |
922 | config = optarg; | 980 | config = optarg; |
923 | break; | 981 | break; |
@@ -933,16 +991,38 @@ main(int ac, char **av) | |||
933 | av += optind; | 991 | av += optind; |
934 | 992 | ||
935 | if (ac > 0 && !host) { | 993 | if (ac > 0 && !host) { |
936 | if (strrchr(*av, '@')) { | 994 | int tport; |
995 | char *tuser; | ||
996 | switch (parse_ssh_uri(*av, &tuser, &host, &tport)) { | ||
997 | case -1: | ||
998 | usage(); | ||
999 | break; | ||
1000 | case 0: | ||
1001 | if (options.user == NULL) { | ||
1002 | options.user = tuser; | ||
1003 | tuser = NULL; | ||
1004 | } | ||
1005 | free(tuser); | ||
1006 | if (options.port == -1 && tport != -1) | ||
1007 | options.port = tport; | ||
1008 | break; | ||
1009 | default: | ||
937 | p = xstrdup(*av); | 1010 | p = xstrdup(*av); |
938 | cp = strrchr(p, '@'); | 1011 | cp = strrchr(p, '@'); |
939 | if (cp == NULL || cp == p) | 1012 | if (cp != NULL) { |
940 | usage(); | 1013 | if (cp == p) |
941 | options.user = p; | 1014 | usage(); |
942 | *cp = '\0'; | 1015 | if (options.user == NULL) { |
943 | host = xstrdup(++cp); | 1016 | options.user = p; |
944 | } else | 1017 | p = NULL; |
945 | host = xstrdup(*av); | 1018 | } |
1019 | *cp++ = '\0'; | ||
1020 | host = xstrdup(cp); | ||
1021 | free(p); | ||
1022 | } else | ||
1023 | host = p; | ||
1024 | break; | ||
1025 | } | ||
946 | if (ac > 1 && !opt_terminated) { | 1026 | if (ac > 1 && !opt_terminated) { |
947 | optind = optreset = 1; | 1027 | optind = optreset = 1; |
948 | goto again; | 1028 | goto again; |
@@ -994,9 +1074,9 @@ main(int ac, char **av) | |||
994 | if (logfile != NULL) | 1074 | if (logfile != NULL) |
995 | log_redirect_stderr_to(logfile); | 1075 | log_redirect_stderr_to(logfile); |
996 | log_init(argv0, | 1076 | log_init(argv0, |
997 | options.log_level == SYSLOG_LEVEL_NOT_SET ? | 1077 | options.log_level == SYSLOG_LEVEL_NOT_SET ? |
998 | SYSLOG_LEVEL_INFO : options.log_level, | 1078 | SYSLOG_LEVEL_INFO : options.log_level, |
999 | options.log_facility == SYSLOG_FACILITY_NOT_SET ? | 1079 | options.log_facility == SYSLOG_FACILITY_NOT_SET ? |
1000 | SYSLOG_FACILITY_USER : options.log_facility, | 1080 | SYSLOG_FACILITY_USER : options.log_facility, |
1001 | !use_syslog); | 1081 | !use_syslog); |
1002 | 1082 | ||
@@ -1026,16 +1106,22 @@ main(int ac, char **av) | |||
1026 | options.hostname = xstrdup(host); | 1106 | options.hostname = xstrdup(host); |
1027 | } | 1107 | } |
1028 | 1108 | ||
1029 | /* If canonicalization requested then try to apply it */ | 1109 | /* Don't lowercase addresses, they will be explicitly canonicalised */ |
1030 | lowercase(host); | 1110 | if ((was_addr = is_addr(host)) == 0) |
1031 | if (options.canonicalize_hostname != SSH_CANONICALISE_NO) | 1111 | lowercase(host); |
1112 | |||
1113 | /* | ||
1114 | * Try to canonicalize if requested by configuration or the | ||
1115 | * hostname is an address. | ||
1116 | */ | ||
1117 | if (options.canonicalize_hostname != SSH_CANONICALISE_NO || was_addr) | ||
1032 | addrs = resolve_canonicalize(&host, options.port); | 1118 | addrs = resolve_canonicalize(&host, options.port); |
1033 | 1119 | ||
1034 | /* | 1120 | /* |
1035 | * If CanonicalizePermittedCNAMEs have been specified but | 1121 | * If CanonicalizePermittedCNAMEs have been specified but |
1036 | * other canonicalization did not happen (by not being requested | 1122 | * other canonicalization did not happen (by not being requested |
1037 | * or by failing with fallback) then the hostname may still be changed | 1123 | * or by failing with fallback) then the hostname may still be changed |
1038 | * as a result of CNAME following. | 1124 | * as a result of CNAME following. |
1039 | * | 1125 | * |
1040 | * Try to resolve the bare hostname name using the system resolver's | 1126 | * Try to resolve the bare hostname name using the system resolver's |
1041 | * usual search rules and then apply the CNAME follow rules. | 1127 | * usual search rules and then apply the CNAME follow rules. |
@@ -1177,6 +1263,7 @@ main(int ac, char **av) | |||
1177 | if (options.user == NULL) | 1263 | if (options.user == NULL) |
1178 | options.user = xstrdup(pw->pw_name); | 1264 | options.user = xstrdup(pw->pw_name); |
1179 | 1265 | ||
1266 | /* Set up strings used to percent_expand() arguments */ | ||
1180 | if (gethostname(thishost, sizeof(thishost)) == -1) | 1267 | if (gethostname(thishost, sizeof(thishost)) == -1) |
1181 | fatal("gethostname: %s", strerror(errno)); | 1268 | fatal("gethostname: %s", strerror(errno)); |
1182 | strlcpy(shorthost, thishost, sizeof(shorthost)); | 1269 | strlcpy(shorthost, thishost, sizeof(shorthost)); |
@@ -1194,24 +1281,11 @@ main(int ac, char **av) | |||
1194 | ssh_digest_free(md); | 1281 | ssh_digest_free(md); |
1195 | conn_hash_hex = tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1)); | 1282 | conn_hash_hex = tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1)); |
1196 | 1283 | ||
1197 | if (options.local_command != NULL) { | 1284 | /* |
1198 | debug3("expanding LocalCommand: %s", options.local_command); | 1285 | * Expand tokens in arguments. NB. LocalCommand is expanded later, |
1199 | cp = options.local_command; | 1286 | * after port-forwarding is set up, so it may pick up any local |
1200 | options.local_command = percent_expand(cp, | 1287 | * tunnel interface name allocated. |
1201 | "C", conn_hash_hex, | 1288 | */ |
1202 | "L", shorthost, | ||
1203 | "d", pw->pw_dir, | ||
1204 | "h", host, | ||
1205 | "l", thishost, | ||
1206 | "n", host_arg, | ||
1207 | "p", portstr, | ||
1208 | "r", options.user, | ||
1209 | "u", pw->pw_name, | ||
1210 | (char *)NULL); | ||
1211 | debug3("expanded LocalCommand: %s", options.local_command); | ||
1212 | free(cp); | ||
1213 | } | ||
1214 | |||
1215 | if (options.remote_command != NULL) { | 1289 | if (options.remote_command != NULL) { |
1216 | debug3("expanding RemoteCommand: %s", options.remote_command); | 1290 | debug3("expanding RemoteCommand: %s", options.remote_command); |
1217 | cp = options.remote_command; | 1291 | cp = options.remote_command; |
@@ -1230,7 +1304,6 @@ main(int ac, char **av) | |||
1230 | free(cp); | 1304 | free(cp); |
1231 | buffer_append(&command, options.remote_command, | 1305 | buffer_append(&command, options.remote_command, |
1232 | strlen(options.remote_command)); | 1306 | strlen(options.remote_command)); |
1233 | |||
1234 | } | 1307 | } |
1235 | 1308 | ||
1236 | if (options.control_path != NULL) { | 1309 | if (options.control_path != NULL) { |
@@ -1311,7 +1384,7 @@ main(int ac, char **av) | |||
1311 | sensitive_data.keys = NULL; | 1384 | sensitive_data.keys = NULL; |
1312 | sensitive_data.external_keysign = 0; | 1385 | sensitive_data.external_keysign = 0; |
1313 | if (options.hostbased_authentication) { | 1386 | if (options.hostbased_authentication) { |
1314 | sensitive_data.nkeys = 9; | 1387 | sensitive_data.nkeys = 11; |
1315 | sensitive_data.keys = xcalloc(sensitive_data.nkeys, | 1388 | sensitive_data.keys = xcalloc(sensitive_data.nkeys, |
1316 | sizeof(struct sshkey)); /* XXX */ | 1389 | sizeof(struct sshkey)); /* XXX */ |
1317 | for (i = 0; i < sensitive_data.nkeys; i++) | 1390 | for (i = 0; i < sensitive_data.nkeys; i++) |
@@ -1338,6 +1411,10 @@ main(int ac, char **av) | |||
1338 | _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL); | 1411 | _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL); |
1339 | sensitive_data.keys[8] = key_load_private_type(KEY_DSA, | 1412 | sensitive_data.keys[8] = key_load_private_type(KEY_DSA, |
1340 | _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL); | 1413 | _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL); |
1414 | sensitive_data.keys[9] = key_load_private_cert(KEY_XMSS, | ||
1415 | _PATH_HOST_XMSS_KEY_FILE, "", NULL); | ||
1416 | sensitive_data.keys[10] = key_load_private_type(KEY_XMSS, | ||
1417 | _PATH_HOST_XMSS_KEY_FILE, "", NULL, NULL); | ||
1341 | PRIV_END; | 1418 | PRIV_END; |
1342 | 1419 | ||
1343 | if (options.hostbased_authentication == 1 && | 1420 | if (options.hostbased_authentication == 1 && |
@@ -1345,7 +1422,8 @@ main(int ac, char **av) | |||
1345 | sensitive_data.keys[5] == NULL && | 1422 | sensitive_data.keys[5] == NULL && |
1346 | sensitive_data.keys[6] == NULL && | 1423 | sensitive_data.keys[6] == NULL && |
1347 | sensitive_data.keys[7] == NULL && | 1424 | sensitive_data.keys[7] == NULL && |
1348 | sensitive_data.keys[8] == NULL) { | 1425 | sensitive_data.keys[8] == NULL && |
1426 | sensitive_data.keys[9] == NULL) { | ||
1349 | #ifdef OPENSSL_HAS_ECC | 1427 | #ifdef OPENSSL_HAS_ECC |
1350 | sensitive_data.keys[1] = key_load_cert( | 1428 | sensitive_data.keys[1] = key_load_cert( |
1351 | _PATH_HOST_ECDSA_KEY_FILE); | 1429 | _PATH_HOST_ECDSA_KEY_FILE); |
@@ -1366,6 +1444,10 @@ main(int ac, char **av) | |||
1366 | _PATH_HOST_RSA_KEY_FILE, NULL); | 1444 | _PATH_HOST_RSA_KEY_FILE, NULL); |
1367 | sensitive_data.keys[8] = key_load_public( | 1445 | sensitive_data.keys[8] = key_load_public( |
1368 | _PATH_HOST_DSA_KEY_FILE, NULL); | 1446 | _PATH_HOST_DSA_KEY_FILE, NULL); |
1447 | sensitive_data.keys[9] = key_load_cert( | ||
1448 | _PATH_HOST_XMSS_KEY_FILE); | ||
1449 | sensitive_data.keys[10] = key_load_public( | ||
1450 | _PATH_HOST_XMSS_KEY_FILE, NULL); | ||
1369 | sensitive_data.external_keysign = 1; | 1451 | sensitive_data.external_keysign = 1; |
1370 | } | 1452 | } |
1371 | } | 1453 | } |
@@ -1401,7 +1483,7 @@ main(int ac, char **av) | |||
1401 | } | 1483 | } |
1402 | } | 1484 | } |
1403 | /* load options.identity_files */ | 1485 | /* load options.identity_files */ |
1404 | load_public_identity_files(); | 1486 | load_public_identity_files(pw); |
1405 | 1487 | ||
1406 | /* optionally set the SSH_AUTHSOCKET_ENV_NAME varibale */ | 1488 | /* optionally set the SSH_AUTHSOCKET_ENV_NAME varibale */ |
1407 | if (options.identity_agent && | 1489 | if (options.identity_agent && |
@@ -1465,7 +1547,7 @@ main(int ac, char **av) | |||
1465 | } | 1547 | } |
1466 | 1548 | ||
1467 | skip_connect: | 1549 | skip_connect: |
1468 | exit_status = ssh_session2(ssh); | 1550 | exit_status = ssh_session2(ssh, pw); |
1469 | packet_close(); | 1551 | packet_close(); |
1470 | 1552 | ||
1471 | if (options.control_path != NULL && muxserver_sock != -1) | 1553 | if (options.control_path != NULL && muxserver_sock != -1) |
@@ -1485,29 +1567,29 @@ control_persist_detach(void) | |||
1485 | 1567 | ||
1486 | debug("%s: backgrounding master process", __func__); | 1568 | debug("%s: backgrounding master process", __func__); |
1487 | 1569 | ||
1488 | /* | 1570 | /* |
1489 | * master (current process) into the background, and make the | 1571 | * master (current process) into the background, and make the |
1490 | * foreground process a client of the backgrounded master. | 1572 | * foreground process a client of the backgrounded master. |
1491 | */ | 1573 | */ |
1492 | switch ((pid = fork())) { | 1574 | switch ((pid = fork())) { |
1493 | case -1: | 1575 | case -1: |
1494 | fatal("%s: fork: %s", __func__, strerror(errno)); | 1576 | fatal("%s: fork: %s", __func__, strerror(errno)); |
1495 | case 0: | 1577 | case 0: |
1496 | /* Child: master process continues mainloop */ | 1578 | /* Child: master process continues mainloop */ |
1497 | break; | 1579 | break; |
1498 | default: | 1580 | default: |
1499 | /* Parent: set up mux slave to connect to backgrounded master */ | 1581 | /* Parent: set up mux slave to connect to backgrounded master */ |
1500 | debug2("%s: background process is %ld", __func__, (long)pid); | 1582 | debug2("%s: background process is %ld", __func__, (long)pid); |
1501 | stdin_null_flag = ostdin_null_flag; | 1583 | stdin_null_flag = ostdin_null_flag; |
1502 | options.request_tty = orequest_tty; | 1584 | options.request_tty = orequest_tty; |
1503 | tty_flag = otty_flag; | 1585 | tty_flag = otty_flag; |
1504 | close(muxserver_sock); | 1586 | close(muxserver_sock); |
1505 | muxserver_sock = -1; | 1587 | muxserver_sock = -1; |
1506 | options.control_master = SSHCTL_MASTER_NO; | 1588 | options.control_master = SSHCTL_MASTER_NO; |
1507 | muxclient(options.control_path); | 1589 | muxclient(options.control_path); |
1508 | /* muxclient() doesn't return on success. */ | 1590 | /* muxclient() doesn't return on success. */ |
1509 | fatal("Failed to connect to new control master"); | 1591 | fatal("Failed to connect to new control master"); |
1510 | } | 1592 | } |
1511 | if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { | 1593 | if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { |
1512 | error("%s: open(\"/dev/null\"): %s", __func__, | 1594 | error("%s: open(\"/dev/null\"): %s", __func__, |
1513 | strerror(errno)); | 1595 | strerror(errno)); |
@@ -1562,7 +1644,7 @@ ssh_confirm_remote_forward(struct ssh *ssh, int type, u_int32_t seq, void *ctxt) | |||
1562 | channel_update_permitted_opens(ssh, rfwd->handle, -1); | 1644 | channel_update_permitted_opens(ssh, rfwd->handle, -1); |
1563 | } | 1645 | } |
1564 | } | 1646 | } |
1565 | 1647 | ||
1566 | if (type == SSH2_MSG_REQUEST_FAILURE) { | 1648 | if (type == SSH2_MSG_REQUEST_FAILURE) { |
1567 | if (options.exit_on_forward_failure) { | 1649 | if (options.exit_on_forward_failure) { |
1568 | if (rfwd->listen_path != NULL) | 1650 | if (rfwd->listen_path != NULL) |
@@ -1624,7 +1706,7 @@ ssh_init_stdio_forwarding(struct ssh *ssh) | |||
1624 | } | 1706 | } |
1625 | 1707 | ||
1626 | static void | 1708 | static void |
1627 | ssh_init_forwarding(struct ssh *ssh) | 1709 | ssh_init_forwarding(struct ssh *ssh, char **ifname) |
1628 | { | 1710 | { |
1629 | int success = 0; | 1711 | int success = 0; |
1630 | int i; | 1712 | int i; |
@@ -1682,14 +1764,15 @@ ssh_init_forwarding(struct ssh *ssh) | |||
1682 | 1764 | ||
1683 | /* Initiate tunnel forwarding. */ | 1765 | /* Initiate tunnel forwarding. */ |
1684 | if (options.tun_open != SSH_TUNMODE_NO) { | 1766 | if (options.tun_open != SSH_TUNMODE_NO) { |
1685 | if (client_request_tun_fwd(ssh, options.tun_open, | 1767 | if ((*ifname = client_request_tun_fwd(ssh, |
1686 | options.tun_local, options.tun_remote) == -1) { | 1768 | options.tun_open, options.tun_local, |
1769 | options.tun_remote)) == NULL) { | ||
1687 | if (options.exit_on_forward_failure) | 1770 | if (options.exit_on_forward_failure) |
1688 | fatal("Could not request tunnel forwarding."); | 1771 | fatal("Could not request tunnel forwarding."); |
1689 | else | 1772 | else |
1690 | error("Could not request tunnel forwarding."); | 1773 | error("Could not request tunnel forwarding."); |
1691 | } | 1774 | } |
1692 | } | 1775 | } |
1693 | } | 1776 | } |
1694 | 1777 | ||
1695 | static void | 1778 | static void |
@@ -1798,20 +1881,41 @@ ssh_session2_open(struct ssh *ssh) | |||
1798 | } | 1881 | } |
1799 | 1882 | ||
1800 | static int | 1883 | static int |
1801 | ssh_session2(struct ssh *ssh) | 1884 | ssh_session2(struct ssh *ssh, struct passwd *pw) |
1802 | { | 1885 | { |
1803 | int id = -1; | 1886 | int devnull, id = -1; |
1887 | char *cp, *tun_fwd_ifname = NULL; | ||
1804 | 1888 | ||
1805 | /* XXX should be pre-session */ | 1889 | /* XXX should be pre-session */ |
1806 | if (!options.control_persist) | 1890 | if (!options.control_persist) |
1807 | ssh_init_stdio_forwarding(ssh); | 1891 | ssh_init_stdio_forwarding(ssh); |
1808 | ssh_init_forwarding(ssh); | 1892 | |
1893 | ssh_init_forwarding(ssh, &tun_fwd_ifname); | ||
1894 | |||
1895 | if (options.local_command != NULL) { | ||
1896 | debug3("expanding LocalCommand: %s", options.local_command); | ||
1897 | cp = options.local_command; | ||
1898 | options.local_command = percent_expand(cp, | ||
1899 | "C", conn_hash_hex, | ||
1900 | "L", shorthost, | ||
1901 | "d", pw->pw_dir, | ||
1902 | "h", host, | ||
1903 | "l", thishost, | ||
1904 | "n", host_arg, | ||
1905 | "p", portstr, | ||
1906 | "r", options.user, | ||
1907 | "u", pw->pw_name, | ||
1908 | "T", tun_fwd_ifname == NULL ? "NONE" : tun_fwd_ifname, | ||
1909 | (char *)NULL); | ||
1910 | debug3("expanded LocalCommand: %s", options.local_command); | ||
1911 | free(cp); | ||
1912 | } | ||
1809 | 1913 | ||
1810 | /* Start listening for multiplex clients */ | 1914 | /* Start listening for multiplex clients */ |
1811 | if (!packet_get_mux()) | 1915 | if (!packet_get_mux()) |
1812 | muxserver_listen(ssh); | 1916 | muxserver_listen(ssh); |
1813 | 1917 | ||
1814 | /* | 1918 | /* |
1815 | * If we are in control persist mode and have a working mux listen | 1919 | * If we are in control persist mode and have a working mux listen |
1816 | * socket, then prepare to background ourselves and have a foreground | 1920 | * socket, then prepare to background ourselves and have a foreground |
1817 | * client attach as a control slave. | 1921 | * client attach as a control slave. |
@@ -1820,18 +1924,18 @@ ssh_session2(struct ssh *ssh) | |||
1820 | * after the connection is fully established (in particular, | 1924 | * after the connection is fully established (in particular, |
1821 | * async rfwd replies have been received for ExitOnForwardFailure). | 1925 | * async rfwd replies have been received for ExitOnForwardFailure). |
1822 | */ | 1926 | */ |
1823 | if (options.control_persist && muxserver_sock != -1) { | 1927 | if (options.control_persist && muxserver_sock != -1) { |
1824 | ostdin_null_flag = stdin_null_flag; | 1928 | ostdin_null_flag = stdin_null_flag; |
1825 | ono_shell_flag = no_shell_flag; | 1929 | ono_shell_flag = no_shell_flag; |
1826 | orequest_tty = options.request_tty; | 1930 | orequest_tty = options.request_tty; |
1827 | otty_flag = tty_flag; | 1931 | otty_flag = tty_flag; |
1828 | stdin_null_flag = 1; | 1932 | stdin_null_flag = 1; |
1829 | no_shell_flag = 1; | 1933 | no_shell_flag = 1; |
1830 | tty_flag = 0; | 1934 | tty_flag = 0; |
1831 | if (!fork_after_authentication_flag) | 1935 | if (!fork_after_authentication_flag) |
1832 | need_controlpersist_detach = 1; | 1936 | need_controlpersist_detach = 1; |
1833 | fork_after_authentication_flag = 1; | 1937 | fork_after_authentication_flag = 1; |
1834 | } | 1938 | } |
1835 | /* | 1939 | /* |
1836 | * ControlPersist mux listen socket setup failed, attempt the | 1940 | * ControlPersist mux listen socket setup failed, attempt the |
1837 | * stdio forward setup that we skipped earlier. | 1941 | * stdio forward setup that we skipped earlier. |
@@ -1839,7 +1943,7 @@ ssh_session2(struct ssh *ssh) | |||
1839 | if (options.control_persist && muxserver_sock == -1) | 1943 | if (options.control_persist && muxserver_sock == -1) |
1840 | ssh_init_stdio_forwarding(ssh); | 1944 | ssh_init_stdio_forwarding(ssh); |
1841 | 1945 | ||
1842 | if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) | 1946 | if (!no_shell_flag) |
1843 | id = ssh_session2_open(ssh); | 1947 | id = ssh_session2_open(ssh); |
1844 | else { | 1948 | else { |
1845 | packet_set_interactive( | 1949 | packet_set_interactive( |
@@ -1863,6 +1967,22 @@ ssh_session2(struct ssh *ssh) | |||
1863 | ssh_local_cmd(options.local_command); | 1967 | ssh_local_cmd(options.local_command); |
1864 | 1968 | ||
1865 | /* | 1969 | /* |
1970 | * stdout is now owned by the session channel; clobber it here | ||
1971 | * so future channel closes are propagated to the local fd. | ||
1972 | * NB. this can only happen after LocalCommand has completed, | ||
1973 | * as it may want to write to stdout. | ||
1974 | */ | ||
1975 | if (!need_controlpersist_detach) { | ||
1976 | if ((devnull = open(_PATH_DEVNULL, O_WRONLY)) == -1) | ||
1977 | error("%s: open %s: %s", __func__, | ||
1978 | _PATH_DEVNULL, strerror(errno)); | ||
1979 | if (dup2(devnull, STDOUT_FILENO) < 0) | ||
1980 | fatal("%s: dup2() stdout failed", __func__); | ||
1981 | if (devnull > STDERR_FILENO) | ||
1982 | close(devnull); | ||
1983 | } | ||
1984 | |||
1985 | /* | ||
1866 | * If requested and we are not interested in replies to remote | 1986 | * If requested and we are not interested in replies to remote |
1867 | * forwarding requests, then let ssh continue in the background. | 1987 | * forwarding requests, then let ssh continue in the background. |
1868 | */ | 1988 | */ |
@@ -1881,12 +2001,10 @@ ssh_session2(struct ssh *ssh) | |||
1881 | 2001 | ||
1882 | /* Loads all IdentityFile and CertificateFile keys */ | 2002 | /* Loads all IdentityFile and CertificateFile keys */ |
1883 | static void | 2003 | static void |
1884 | load_public_identity_files(void) | 2004 | load_public_identity_files(struct passwd *pw) |
1885 | { | 2005 | { |
1886 | char *filename, *cp, thishost[NI_MAXHOST]; | 2006 | char *filename, *cp; |
1887 | char *pwdir = NULL, *pwname = NULL; | ||
1888 | struct sshkey *public; | 2007 | struct sshkey *public; |
1889 | struct passwd *pw; | ||
1890 | int i; | 2008 | int i; |
1891 | u_int n_ids, n_certs; | 2009 | u_int n_ids, n_certs; |
1892 | char *identity_files[SSH_MAX_IDENTITY_FILES]; | 2010 | char *identity_files[SSH_MAX_IDENTITY_FILES]; |
@@ -1925,11 +2043,6 @@ load_public_identity_files(void) | |||
1925 | #endif /* ENABLE_PKCS11 */ | 2043 | #endif /* ENABLE_PKCS11 */ |
1926 | if ((pw = getpwuid(original_real_uid)) == NULL) | 2044 | if ((pw = getpwuid(original_real_uid)) == NULL) |
1927 | fatal("load_public_identity_files: getpwuid failed"); | 2045 | fatal("load_public_identity_files: getpwuid failed"); |
1928 | pwname = xstrdup(pw->pw_name); | ||
1929 | pwdir = xstrdup(pw->pw_dir); | ||
1930 | if (gethostname(thishost, sizeof(thishost)) == -1) | ||
1931 | fatal("load_public_identity_files: gethostname: %s", | ||
1932 | strerror(errno)); | ||
1933 | for (i = 0; i < options.num_identity_files; i++) { | 2046 | for (i = 0; i < options.num_identity_files; i++) { |
1934 | if (n_ids >= SSH_MAX_IDENTITY_FILES || | 2047 | if (n_ids >= SSH_MAX_IDENTITY_FILES || |
1935 | strcasecmp(options.identity_files[i], "none") == 0) { | 2048 | strcasecmp(options.identity_files[i], "none") == 0) { |
@@ -1939,8 +2052,8 @@ load_public_identity_files(void) | |||
1939 | } | 2052 | } |
1940 | cp = tilde_expand_filename(options.identity_files[i], | 2053 | cp = tilde_expand_filename(options.identity_files[i], |
1941 | original_real_uid); | 2054 | original_real_uid); |
1942 | filename = percent_expand(cp, "d", pwdir, | 2055 | filename = percent_expand(cp, "d", pw->pw_dir, |
1943 | "u", pwname, "l", thishost, "h", host, | 2056 | "u", pw->pw_name, "l", thishost, "h", host, |
1944 | "r", options.user, (char *)NULL); | 2057 | "r", options.user, (char *)NULL); |
1945 | free(cp); | 2058 | free(cp); |
1946 | public = key_load_public(filename, NULL); | 2059 | public = key_load_public(filename, NULL); |
@@ -1985,8 +2098,8 @@ load_public_identity_files(void) | |||
1985 | for (i = 0; i < options.num_certificate_files; i++) { | 2098 | for (i = 0; i < options.num_certificate_files; i++) { |
1986 | cp = tilde_expand_filename(options.certificate_files[i], | 2099 | cp = tilde_expand_filename(options.certificate_files[i], |
1987 | original_real_uid); | 2100 | original_real_uid); |
1988 | filename = percent_expand(cp, "d", pwdir, | 2101 | filename = percent_expand(cp, "d", pw->pw_dir, |
1989 | "u", pwname, "l", thishost, "h", host, | 2102 | "u", pw->pw_name, "l", thishost, "h", host, |
1990 | "r", options.user, (char *)NULL); | 2103 | "r", options.user, (char *)NULL); |
1991 | free(cp); | 2104 | free(cp); |
1992 | 2105 | ||
@@ -2019,11 +2132,6 @@ load_public_identity_files(void) | |||
2019 | memcpy(options.certificate_files, | 2132 | memcpy(options.certificate_files, |
2020 | certificate_files, sizeof(certificate_files)); | 2133 | certificate_files, sizeof(certificate_files)); |
2021 | memcpy(options.certificates, certificates, sizeof(certificates)); | 2134 | memcpy(options.certificates, certificates, sizeof(certificates)); |
2022 | |||
2023 | explicit_bzero(pwname, strlen(pwname)); | ||
2024 | free(pwname); | ||
2025 | explicit_bzero(pwdir, strlen(pwdir)); | ||
2026 | free(pwdir); | ||
2027 | } | 2135 | } |
2028 | 2136 | ||
2029 | static void | 2137 | static void |
@@ -2036,7 +2144,5 @@ main_sigchld_handler(int sig) | |||
2036 | while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || | 2144 | while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || |
2037 | (pid < 0 && errno == EINTR)) | 2145 | (pid < 0 && errno == EINTR)) |
2038 | ; | 2146 | ; |
2039 | |||
2040 | signal(sig, main_sigchld_handler); | ||
2041 | errno = save_errno; | 2147 | errno = save_errno; |
2042 | } | 2148 | } |