diff options
Diffstat (limited to 'ssh.c')
-rw-r--r-- | ssh.c | 148 |
1 files changed, 106 insertions, 42 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh.c,v 1.420 2015/07/30 00:01:34 djm Exp $ */ | 1 | /* $OpenBSD: ssh.c,v 1.436 2016/02/15 09:47:49 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 |
@@ -105,7 +105,6 @@ | |||
105 | #include "match.h" | 105 | #include "match.h" |
106 | #include "msg.h" | 106 | #include "msg.h" |
107 | #include "uidswap.h" | 107 | #include "uidswap.h" |
108 | #include "roaming.h" | ||
109 | #include "version.h" | 108 | #include "version.h" |
110 | #include "ssherr.h" | 109 | #include "ssherr.h" |
111 | #include "myproposal.h" | 110 | #include "myproposal.h" |
@@ -203,11 +202,9 @@ usage(void) | |||
203 | fprintf(stderr, | 202 | fprintf(stderr, |
204 | "usage: ssh [-1246AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n" | 203 | "usage: ssh [-1246AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n" |
205 | " [-D [bind_address:]port] [-E log_file] [-e escape_char]\n" | 204 | " [-D [bind_address:]port] [-E log_file] [-e escape_char]\n" |
206 | " [-F configfile] [-I pkcs11] [-i identity_file]\n" | 205 | " [-F configfile] [-I pkcs11] [-i identity_file] [-L address]\n" |
207 | " [-L address] [-l login_name] [-m mac_spec]\n" | 206 | " [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n" |
208 | " [-O ctl_cmd] [-o option] [-p port]\n" | 207 | " [-Q query_option] [-R address] [-S ctl_path] [-W host:port]\n" |
209 | " [-Q cipher | cipher-auth | mac | kex | key]\n" | ||
210 | " [-R address] [-S ctl_path] [-W host:port]\n" | ||
211 | " [-w local_tun[:remote_tun]] [user@]hostname [command]\n" | 208 | " [-w local_tun[:remote_tun]] [user@]hostname [command]\n" |
212 | ); | 209 | ); |
213 | exit(255); | 210 | exit(255); |
@@ -252,7 +249,7 @@ resolve_host(const char *name, int port, int logerr, char *cname, size_t clen) | |||
252 | if (port <= 0) | 249 | if (port <= 0) |
253 | port = default_ssh_port(); | 250 | port = default_ssh_port(); |
254 | 251 | ||
255 | snprintf(strport, sizeof strport, "%u", port); | 252 | snprintf(strport, sizeof strport, "%d", port); |
256 | memset(&hints, 0, sizeof(hints)); | 253 | memset(&hints, 0, sizeof(hints)); |
257 | hints.ai_family = options.address_family == -1 ? | 254 | hints.ai_family = options.address_family == -1 ? |
258 | AF_UNSPEC : options.address_family; | 255 | AF_UNSPEC : options.address_family; |
@@ -406,6 +403,17 @@ resolve_canonicalize(char **hostp, int port) | |||
406 | return addrs; | 403 | return addrs; |
407 | } | 404 | } |
408 | 405 | ||
406 | /* If domain name is anchored, then resolve it now */ | ||
407 | if ((*hostp)[strlen(*hostp) - 1] == '.') { | ||
408 | debug3("%s: name is fully qualified", __func__); | ||
409 | fullhost = xstrdup(*hostp); | ||
410 | if ((addrs = resolve_host(fullhost, port, 0, | ||
411 | newname, sizeof(newname))) != NULL) | ||
412 | goto found; | ||
413 | free(fullhost); | ||
414 | goto notfound; | ||
415 | } | ||
416 | |||
409 | /* Don't apply canonicalization to sufficiently-qualified hostnames */ | 417 | /* Don't apply canonicalization to sufficiently-qualified hostnames */ |
410 | ndots = 0; | 418 | ndots = 0; |
411 | for (cp = *hostp; *cp != '\0'; cp++) { | 419 | for (cp = *hostp; *cp != '\0'; cp++) { |
@@ -429,6 +437,7 @@ resolve_canonicalize(char **hostp, int port) | |||
429 | free(fullhost); | 437 | free(fullhost); |
430 | continue; | 438 | continue; |
431 | } | 439 | } |
440 | found: | ||
432 | /* Remove trailing '.' */ | 441 | /* Remove trailing '.' */ |
433 | fullhost[strlen(fullhost) - 1] = '\0'; | 442 | fullhost[strlen(fullhost) - 1] = '\0'; |
434 | /* Follow CNAME if requested */ | 443 | /* Follow CNAME if requested */ |
@@ -440,6 +449,7 @@ resolve_canonicalize(char **hostp, int port) | |||
440 | *hostp = fullhost; | 449 | *hostp = fullhost; |
441 | return addrs; | 450 | return addrs; |
442 | } | 451 | } |
452 | notfound: | ||
443 | if (!options.canonicalize_fallback_local) | 453 | if (!options.canonicalize_fallback_local) |
444 | fatal("%s: Could not resolve host \"%s\"", __progname, *hostp); | 454 | fatal("%s: Could not resolve host \"%s\"", __progname, *hostp); |
445 | debug2("%s: host %s not found in any suffix", __func__, *hostp); | 455 | debug2("%s: host %s not found in any suffix", __func__, *hostp); |
@@ -506,7 +516,7 @@ main(int ac, char **av) | |||
506 | int i, r, opt, exit_status, use_syslog, config_test = 0; | 516 | int i, r, opt, exit_status, use_syslog, config_test = 0; |
507 | char *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile; | 517 | char *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile; |
508 | char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; | 518 | char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; |
509 | char cname[NI_MAXHOST]; | 519 | char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex; |
510 | struct stat st; | 520 | struct stat st; |
511 | struct passwd *pw; | 521 | struct passwd *pw; |
512 | int timeout_ms; | 522 | int timeout_ms; |
@@ -516,8 +526,8 @@ main(int ac, char **av) | |||
516 | struct addrinfo *addrs = NULL; | 526 | struct addrinfo *addrs = NULL; |
517 | struct ssh_digest_ctx *md; | 527 | struct ssh_digest_ctx *md; |
518 | u_char conn_hash[SSH_DIGEST_MAX_LENGTH]; | 528 | u_char conn_hash[SSH_DIGEST_MAX_LENGTH]; |
519 | char *conn_hash_hex; | ||
520 | 529 | ||
530 | ssh_malloc_init(); /* must be called before any mallocs */ | ||
521 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ | 531 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
522 | sanitise_stdfd(); | 532 | sanitise_stdfd(); |
523 | 533 | ||
@@ -627,7 +637,7 @@ main(int ac, char **av) | |||
627 | use_syslog = 1; | 637 | use_syslog = 1; |
628 | break; | 638 | break; |
629 | case 'E': | 639 | case 'E': |
630 | logfile = xstrdup(optarg); | 640 | logfile = optarg; |
631 | break; | 641 | break; |
632 | case 'G': | 642 | case 'G': |
633 | config_test = 1; | 643 | config_test = 1; |
@@ -704,16 +714,18 @@ main(int ac, char **av) | |||
704 | options.gss_deleg_creds = 1; | 714 | options.gss_deleg_creds = 1; |
705 | break; | 715 | break; |
706 | case 'i': | 716 | case 'i': |
707 | if (stat(optarg, &st) < 0) { | 717 | p = tilde_expand_filename(optarg, original_real_uid); |
718 | if (stat(p, &st) < 0) | ||
708 | fprintf(stderr, "Warning: Identity file %s " | 719 | fprintf(stderr, "Warning: Identity file %s " |
709 | "not accessible: %s.\n", optarg, | 720 | "not accessible: %s.\n", p, |
710 | strerror(errno)); | 721 | strerror(errno)); |
711 | break; | 722 | else |
712 | } | 723 | add_identity_file(&options, NULL, p, 1); |
713 | add_identity_file(&options, NULL, optarg, 1); | 724 | free(p); |
714 | break; | 725 | break; |
715 | case 'I': | 726 | case 'I': |
716 | #ifdef ENABLE_PKCS11 | 727 | #ifdef ENABLE_PKCS11 |
728 | free(options.pkcs11_provider); | ||
717 | options.pkcs11_provider = xstrdup(optarg); | 729 | options.pkcs11_provider = xstrdup(optarg); |
718 | #else | 730 | #else |
719 | fprintf(stderr, "no support for PKCS#11.\n"); | 731 | fprintf(stderr, "no support for PKCS#11.\n"); |
@@ -798,6 +810,7 @@ main(int ac, char **av) | |||
798 | if (ciphers_valid(*optarg == '+' ? | 810 | if (ciphers_valid(*optarg == '+' ? |
799 | optarg + 1 : optarg)) { | 811 | optarg + 1 : optarg)) { |
800 | /* SSH2 only */ | 812 | /* SSH2 only */ |
813 | free(options.ciphers); | ||
801 | options.ciphers = xstrdup(optarg); | 814 | options.ciphers = xstrdup(optarg); |
802 | options.cipher = SSH_CIPHER_INVALID; | 815 | options.cipher = SSH_CIPHER_INVALID; |
803 | break; | 816 | break; |
@@ -817,9 +830,10 @@ main(int ac, char **av) | |||
817 | options.ciphers = xstrdup(KEX_CLIENT_ENCRYPT); | 830 | options.ciphers = xstrdup(KEX_CLIENT_ENCRYPT); |
818 | break; | 831 | break; |
819 | case 'm': | 832 | case 'm': |
820 | if (mac_valid(optarg)) | 833 | if (mac_valid(optarg)) { |
834 | free(options.macs); | ||
821 | options.macs = xstrdup(optarg); | 835 | options.macs = xstrdup(optarg); |
822 | else { | 836 | } else { |
823 | fprintf(stderr, "Unknown mac type '%s'\n", | 837 | fprintf(stderr, "Unknown mac type '%s'\n", |
824 | optarg); | 838 | optarg); |
825 | exit(255); | 839 | exit(255); |
@@ -897,8 +911,7 @@ main(int ac, char **av) | |||
897 | subsystem_flag = 1; | 911 | subsystem_flag = 1; |
898 | break; | 912 | break; |
899 | case 'S': | 913 | case 'S': |
900 | if (options.control_path != NULL) | 914 | free(options.control_path); |
901 | free(options.control_path); | ||
902 | options.control_path = xstrdup(optarg); | 915 | options.control_path = xstrdup(optarg); |
903 | break; | 916 | break; |
904 | case 'b': | 917 | case 'b': |
@@ -980,10 +993,8 @@ main(int ac, char **av) | |||
980 | */ | 993 | */ |
981 | if (use_syslog && logfile != NULL) | 994 | if (use_syslog && logfile != NULL) |
982 | fatal("Can't specify both -y and -E"); | 995 | fatal("Can't specify both -y and -E"); |
983 | if (logfile != NULL) { | 996 | if (logfile != NULL) |
984 | log_redirect_stderr_to(logfile); | 997 | log_redirect_stderr_to(logfile); |
985 | free(logfile); | ||
986 | } | ||
987 | log_init(argv0, | 998 | log_init(argv0, |
988 | options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, | 999 | options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, |
989 | SYSLOG_FACILITY_USER, !use_syslog); | 1000 | SYSLOG_FACILITY_USER, !use_syslog); |
@@ -1084,6 +1095,8 @@ main(int ac, char **av) | |||
1084 | "disabling"); | 1095 | "disabling"); |
1085 | options.update_hostkeys = 0; | 1096 | options.update_hostkeys = 0; |
1086 | } | 1097 | } |
1098 | if (options.connection_attempts <= 0) | ||
1099 | fatal("Invalid number of ConnectionAttempts"); | ||
1087 | #ifndef HAVE_CYGWIN | 1100 | #ifndef HAVE_CYGWIN |
1088 | if (original_effective_uid != 0) | 1101 | if (original_effective_uid != 0) |
1089 | options.use_privileged_port = 0; | 1102 | options.use_privileged_port = 0; |
@@ -1122,6 +1135,7 @@ main(int ac, char **av) | |||
1122 | strlcpy(shorthost, thishost, sizeof(shorthost)); | 1135 | strlcpy(shorthost, thishost, sizeof(shorthost)); |
1123 | shorthost[strcspn(thishost, ".")] = '\0'; | 1136 | shorthost[strcspn(thishost, ".")] = '\0'; |
1124 | snprintf(portstr, sizeof(portstr), "%d", options.port); | 1137 | snprintf(portstr, sizeof(portstr), "%d", options.port); |
1138 | snprintf(uidstr, sizeof(uidstr), "%d", pw->pw_uid); | ||
1125 | 1139 | ||
1126 | if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL || | 1140 | if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL || |
1127 | ssh_digest_update(md, thishost, strlen(thishost)) < 0 || | 1141 | ssh_digest_update(md, thishost, strlen(thishost)) < 0 || |
@@ -1164,6 +1178,7 @@ main(int ac, char **av) | |||
1164 | "p", portstr, | 1178 | "p", portstr, |
1165 | "r", options.user, | 1179 | "r", options.user, |
1166 | "u", pw->pw_name, | 1180 | "u", pw->pw_name, |
1181 | "i", uidstr, | ||
1167 | (char *)NULL); | 1182 | (char *)NULL); |
1168 | free(cp); | 1183 | free(cp); |
1169 | } | 1184 | } |
@@ -1184,6 +1199,7 @@ main(int ac, char **av) | |||
1184 | * have yet resolved the hostname. Do so now. | 1199 | * have yet resolved the hostname. Do so now. |
1185 | */ | 1200 | */ |
1186 | if (addrs == NULL && options.proxy_command == NULL) { | 1201 | if (addrs == NULL && options.proxy_command == NULL) { |
1202 | debug2("resolving \"%s\" port %d", host, options.port); | ||
1187 | if ((addrs = resolve_host(host, options.port, 1, | 1203 | if ((addrs = resolve_host(host, options.port, 1, |
1188 | cname, sizeof(cname))) == NULL) | 1204 | cname, sizeof(cname))) == NULL) |
1189 | cleanup_exit(255); /* resolve_host logs the error */ | 1205 | cleanup_exit(255); /* resolve_host logs the error */ |
@@ -1227,8 +1243,10 @@ main(int ac, char **av) | |||
1227 | sensitive_data.keys[i] = NULL; | 1243 | sensitive_data.keys[i] = NULL; |
1228 | 1244 | ||
1229 | PRIV_START; | 1245 | PRIV_START; |
1246 | #if WITH_SSH1 | ||
1230 | sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, | 1247 | sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, |
1231 | _PATH_HOST_KEY_FILE, "", NULL, NULL); | 1248 | _PATH_HOST_KEY_FILE, "", NULL, NULL); |
1249 | #endif | ||
1232 | #ifdef OPENSSL_HAS_ECC | 1250 | #ifdef OPENSSL_HAS_ECC |
1233 | sensitive_data.keys[1] = key_load_private_cert(KEY_ECDSA, | 1251 | sensitive_data.keys[1] = key_load_private_cert(KEY_ECDSA, |
1234 | _PATH_HOST_ECDSA_KEY_FILE, "", NULL); | 1252 | _PATH_HOST_ECDSA_KEY_FILE, "", NULL); |
@@ -1353,6 +1371,10 @@ main(int ac, char **av) | |||
1353 | options.identity_keys[i] = NULL; | 1371 | options.identity_keys[i] = NULL; |
1354 | } | 1372 | } |
1355 | } | 1373 | } |
1374 | for (i = 0; i < options.num_certificate_files; i++) { | ||
1375 | free(options.certificate_files[i]); | ||
1376 | options.certificate_files[i] = NULL; | ||
1377 | } | ||
1356 | 1378 | ||
1357 | exit_status = compat20 ? ssh_session2() : ssh_session(); | 1379 | exit_status = compat20 ? ssh_session2() : ssh_session(); |
1358 | packet_close(); | 1380 | packet_close(); |
@@ -1604,6 +1626,7 @@ ssh_session(void) | |||
1604 | struct winsize ws; | 1626 | struct winsize ws; |
1605 | char *cp; | 1627 | char *cp; |
1606 | const char *display; | 1628 | const char *display; |
1629 | char *proto = NULL, *data = NULL; | ||
1607 | 1630 | ||
1608 | /* Enable compression if requested. */ | 1631 | /* Enable compression if requested. */ |
1609 | if (options.compression) { | 1632 | if (options.compression) { |
@@ -1674,13 +1697,9 @@ ssh_session(void) | |||
1674 | display = getenv("DISPLAY"); | 1697 | display = getenv("DISPLAY"); |
1675 | if (display == NULL && options.forward_x11) | 1698 | if (display == NULL && options.forward_x11) |
1676 | debug("X11 forwarding requested but DISPLAY not set"); | 1699 | debug("X11 forwarding requested but DISPLAY not set"); |
1677 | if (options.forward_x11 && display != NULL) { | 1700 | if (options.forward_x11 && client_x11_get_proto(display, |
1678 | char *proto, *data; | 1701 | options.xauth_location, options.forward_x11_trusted, |
1679 | /* Get reasonable local authentication information. */ | 1702 | options.forward_x11_timeout, &proto, &data) == 0) { |
1680 | client_x11_get_proto(display, options.xauth_location, | ||
1681 | options.forward_x11_trusted, | ||
1682 | options.forward_x11_timeout, | ||
1683 | &proto, &data); | ||
1684 | /* Request forwarding with authentication spoofing. */ | 1703 | /* Request forwarding with authentication spoofing. */ |
1685 | debug("Requesting X11 forwarding with authentication " | 1704 | debug("Requesting X11 forwarding with authentication " |
1686 | "spoofing."); | 1705 | "spoofing."); |
@@ -1770,6 +1789,7 @@ ssh_session2_setup(int id, int success, void *arg) | |||
1770 | extern char **environ; | 1789 | extern char **environ; |
1771 | const char *display; | 1790 | const char *display; |
1772 | int interactive = tty_flag; | 1791 | int interactive = tty_flag; |
1792 | char *proto = NULL, *data = NULL; | ||
1773 | 1793 | ||
1774 | if (!success) | 1794 | if (!success) |
1775 | return; /* No need for error message, channels code sens one */ | 1795 | return; /* No need for error message, channels code sens one */ |
@@ -1777,12 +1797,9 @@ ssh_session2_setup(int id, int success, void *arg) | |||
1777 | display = getenv("DISPLAY"); | 1797 | display = getenv("DISPLAY"); |
1778 | if (display == NULL && options.forward_x11) | 1798 | if (display == NULL && options.forward_x11) |
1779 | debug("X11 forwarding requested but DISPLAY not set"); | 1799 | debug("X11 forwarding requested but DISPLAY not set"); |
1780 | if (options.forward_x11 && display != NULL) { | 1800 | if (options.forward_x11 && client_x11_get_proto(display, |
1781 | char *proto, *data; | 1801 | options.xauth_location, options.forward_x11_trusted, |
1782 | /* Get reasonable local authentication information. */ | 1802 | options.forward_x11_timeout, &proto, &data) == 0) { |
1783 | client_x11_get_proto(display, options.xauth_location, | ||
1784 | options.forward_x11_trusted, | ||
1785 | options.forward_x11_timeout, &proto, &data); | ||
1786 | /* Request forwarding with authentication spoofing. */ | 1803 | /* Request forwarding with authentication spoofing. */ |
1787 | debug("Requesting X11 forwarding with authentication " | 1804 | debug("Requesting X11 forwarding with authentication " |
1788 | "spoofing."); | 1805 | "spoofing."); |
@@ -1936,25 +1953,30 @@ ssh_session2(void) | |||
1936 | options.escape_char : SSH_ESCAPECHAR_NONE, id); | 1953 | options.escape_char : SSH_ESCAPECHAR_NONE, id); |
1937 | } | 1954 | } |
1938 | 1955 | ||
1956 | /* Loads all IdentityFile and CertificateFile keys */ | ||
1939 | static void | 1957 | static void |
1940 | load_public_identity_files(void) | 1958 | load_public_identity_files(void) |
1941 | { | 1959 | { |
1942 | char *filename, *cp, thishost[NI_MAXHOST]; | 1960 | char *filename, *cp, thishost[NI_MAXHOST]; |
1943 | char *pwdir = NULL, *pwname = NULL; | 1961 | char *pwdir = NULL, *pwname = NULL; |
1944 | int i = 0; | ||
1945 | Key *public; | 1962 | Key *public; |
1946 | struct passwd *pw; | 1963 | struct passwd *pw; |
1947 | u_int n_ids; | 1964 | int i; |
1965 | u_int n_ids, n_certs; | ||
1948 | char *identity_files[SSH_MAX_IDENTITY_FILES]; | 1966 | char *identity_files[SSH_MAX_IDENTITY_FILES]; |
1949 | Key *identity_keys[SSH_MAX_IDENTITY_FILES]; | 1967 | Key *identity_keys[SSH_MAX_IDENTITY_FILES]; |
1968 | char *certificate_files[SSH_MAX_CERTIFICATE_FILES]; | ||
1969 | struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES]; | ||
1950 | #ifdef ENABLE_PKCS11 | 1970 | #ifdef ENABLE_PKCS11 |
1951 | Key **keys; | 1971 | Key **keys; |
1952 | int nkeys; | 1972 | int nkeys; |
1953 | #endif /* PKCS11 */ | 1973 | #endif /* PKCS11 */ |
1954 | 1974 | ||
1955 | n_ids = 0; | 1975 | n_ids = n_certs = 0; |
1956 | memset(identity_files, 0, sizeof(identity_files)); | 1976 | memset(identity_files, 0, sizeof(identity_files)); |
1957 | memset(identity_keys, 0, sizeof(identity_keys)); | 1977 | memset(identity_keys, 0, sizeof(identity_keys)); |
1978 | memset(certificate_files, 0, sizeof(certificate_files)); | ||
1979 | memset(certificates, 0, sizeof(certificates)); | ||
1958 | 1980 | ||
1959 | #ifdef ENABLE_PKCS11 | 1981 | #ifdef ENABLE_PKCS11 |
1960 | if (options.pkcs11_provider != NULL && | 1982 | if (options.pkcs11_provider != NULL && |
@@ -1986,6 +2008,7 @@ load_public_identity_files(void) | |||
1986 | if (n_ids >= SSH_MAX_IDENTITY_FILES || | 2008 | if (n_ids >= SSH_MAX_IDENTITY_FILES || |
1987 | strcasecmp(options.identity_files[i], "none") == 0) { | 2009 | strcasecmp(options.identity_files[i], "none") == 0) { |
1988 | free(options.identity_files[i]); | 2010 | free(options.identity_files[i]); |
2011 | options.identity_files[i] = NULL; | ||
1989 | continue; | 2012 | continue; |
1990 | } | 2013 | } |
1991 | cp = tilde_expand_filename(options.identity_files[i], | 2014 | cp = tilde_expand_filename(options.identity_files[i], |
@@ -2004,7 +2027,12 @@ load_public_identity_files(void) | |||
2004 | if (++n_ids >= SSH_MAX_IDENTITY_FILES) | 2027 | if (++n_ids >= SSH_MAX_IDENTITY_FILES) |
2005 | continue; | 2028 | continue; |
2006 | 2029 | ||
2007 | /* Try to add the certificate variant too */ | 2030 | /* |
2031 | * If no certificates have been explicitly listed then try | ||
2032 | * to add the default certificate variant too. | ||
2033 | */ | ||
2034 | if (options.num_certificate_files != 0) | ||
2035 | continue; | ||
2008 | xasprintf(&cp, "%s-cert", filename); | 2036 | xasprintf(&cp, "%s-cert", filename); |
2009 | public = key_load_public(cp, NULL); | 2037 | public = key_load_public(cp, NULL); |
2010 | debug("identity file %s type %d", cp, | 2038 | debug("identity file %s type %d", cp, |
@@ -2021,14 +2049,50 @@ load_public_identity_files(void) | |||
2021 | continue; | 2049 | continue; |
2022 | } | 2050 | } |
2023 | identity_keys[n_ids] = public; | 2051 | identity_keys[n_ids] = public; |
2024 | /* point to the original path, most likely the private key */ | 2052 | identity_files[n_ids] = cp; |
2025 | identity_files[n_ids] = xstrdup(filename); | ||
2026 | n_ids++; | 2053 | n_ids++; |
2027 | } | 2054 | } |
2055 | |||
2056 | if (options.num_certificate_files > SSH_MAX_CERTIFICATE_FILES) | ||
2057 | fatal("%s: too many certificates", __func__); | ||
2058 | for (i = 0; i < options.num_certificate_files; i++) { | ||
2059 | cp = tilde_expand_filename(options.certificate_files[i], | ||
2060 | original_real_uid); | ||
2061 | filename = percent_expand(cp, "d", pwdir, | ||
2062 | "u", pwname, "l", thishost, "h", host, | ||
2063 | "r", options.user, (char *)NULL); | ||
2064 | free(cp); | ||
2065 | |||
2066 | public = key_load_public(filename, NULL); | ||
2067 | debug("certificate file %s type %d", filename, | ||
2068 | public ? public->type : -1); | ||
2069 | free(options.certificate_files[i]); | ||
2070 | options.certificate_files[i] = NULL; | ||
2071 | if (public == NULL) { | ||
2072 | free(filename); | ||
2073 | continue; | ||
2074 | } | ||
2075 | if (!key_is_cert(public)) { | ||
2076 | debug("%s: key %s type %s is not a certificate", | ||
2077 | __func__, filename, key_type(public)); | ||
2078 | key_free(public); | ||
2079 | free(filename); | ||
2080 | continue; | ||
2081 | } | ||
2082 | certificate_files[n_certs] = filename; | ||
2083 | certificates[n_certs] = public; | ||
2084 | ++n_certs; | ||
2085 | } | ||
2086 | |||
2028 | options.num_identity_files = n_ids; | 2087 | options.num_identity_files = n_ids; |
2029 | memcpy(options.identity_files, identity_files, sizeof(identity_files)); | 2088 | memcpy(options.identity_files, identity_files, sizeof(identity_files)); |
2030 | memcpy(options.identity_keys, identity_keys, sizeof(identity_keys)); | 2089 | memcpy(options.identity_keys, identity_keys, sizeof(identity_keys)); |
2031 | 2090 | ||
2091 | options.num_certificate_files = n_certs; | ||
2092 | memcpy(options.certificate_files, | ||
2093 | certificate_files, sizeof(certificate_files)); | ||
2094 | memcpy(options.certificates, certificates, sizeof(certificates)); | ||
2095 | |||
2032 | explicit_bzero(pwname, strlen(pwname)); | 2096 | explicit_bzero(pwname, strlen(pwname)); |
2033 | free(pwname); | 2097 | free(pwname); |
2034 | explicit_bzero(pwdir, strlen(pwdir)); | 2098 | explicit_bzero(pwdir, strlen(pwdir)); |