diff options
author | Damien Miller <djm@mindrot.org> | 2013-10-17 11:47:23 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2013-10-17 11:47:23 +1100 |
commit | 0faf747e2f77f0f7083bcd59cbed30c4b5448444 (patch) | |
tree | 1f1b80f60be01d61f284070affc314d1b97b6b69 | |
parent | d77b81f856e078714ec6b0f86f61c20249b7ead4 (diff) |
- djm@cvs.openbsd.org 2013/10/16 02:31:47
[readconf.c readconf.h roaming_client.c ssh.1 ssh.c ssh_config.5]
[sshconnect.c sshconnect.h]
Implement client-side hostname canonicalisation to allow an explicit
search path of domain suffixes to use to convert unqualified host names
to fully-qualified ones for host key matching.
This is particularly useful for host certificates, which would otherwise
need to list unqualified names alongside fully-qualified ones (and this
causes a number of problems).
"looks fine" markus@
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | readconf.c | 113 | ||||
-rw-r--r-- | readconf.h | 22 | ||||
-rw-r--r-- | roaming_client.c | 8 | ||||
-rw-r--r-- | ssh.1 | 9 | ||||
-rw-r--r-- | ssh.c | 183 | ||||
-rw-r--r-- | ssh_config.5 | 75 | ||||
-rw-r--r-- | sshconnect.c | 74 | ||||
-rw-r--r-- | sshconnect.h | 8 |
9 files changed, 426 insertions, 76 deletions
@@ -3,6 +3,16 @@ | |||
3 | - jmc@cvs.openbsd.org 2013/10/15 14:10:25 | 3 | - jmc@cvs.openbsd.org 2013/10/15 14:10:25 |
4 | [ssh.1 ssh_config.5] | 4 | [ssh.1 ssh_config.5] |
5 | tweak previous; | 5 | tweak previous; |
6 | - djm@cvs.openbsd.org 2013/10/16 02:31:47 | ||
7 | [readconf.c readconf.h roaming_client.c ssh.1 ssh.c ssh_config.5] | ||
8 | [sshconnect.c sshconnect.h] | ||
9 | Implement client-side hostname canonicalisation to allow an explicit | ||
10 | search path of domain suffixes to use to convert unqualified host names | ||
11 | to fully-qualified ones for host key matching. | ||
12 | This is particularly useful for host certificates, which would otherwise | ||
13 | need to list unqualified names alongside fully-qualified ones (and this | ||
14 | causes a number of problems). | ||
15 | "looks fine" markus@ | ||
6 | 16 | ||
7 | 20131015 | 17 | 20131015 |
8 | - (djm) OpenBSD CVS Sync | 18 | - (djm) OpenBSD CVS Sync |
diff --git a/readconf.c b/readconf.c index 9340effd0..de8eb7cd3 100644 --- a/readconf.c +++ b/readconf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.c,v 1.207 2013/10/14 23:28:23 djm Exp $ */ | 1 | /* $OpenBSD: readconf.c,v 1.208 2013/10/16 02:31:45 djm 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 |
@@ -144,6 +144,8 @@ typedef enum { | |||
144 | oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, | 144 | oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, |
145 | oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, | 145 | oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, |
146 | oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, | 146 | oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, |
147 | oCanonicalDomains, oCanonicaliseHostname, oCanonicaliseMaxDots, | ||
148 | oCanonicaliseFallbackLocal, oCanonicalisePermittedCNAMEs, | ||
147 | oIgnoredUnknownOption, oDeprecated, oUnsupported | 149 | oIgnoredUnknownOption, oDeprecated, oUnsupported |
148 | } OpCodes; | 150 | } OpCodes; |
149 | 151 | ||
@@ -257,6 +259,11 @@ static struct { | |||
257 | { "ipqos", oIPQoS }, | 259 | { "ipqos", oIPQoS }, |
258 | { "requesttty", oRequestTTY }, | 260 | { "requesttty", oRequestTTY }, |
259 | { "proxyusefdpass", oProxyUseFdpass }, | 261 | { "proxyusefdpass", oProxyUseFdpass }, |
262 | { "canonicaldomains", oCanonicalDomains }, | ||
263 | { "canonicalisefallbacklocal", oCanonicaliseFallbackLocal }, | ||
264 | { "canonicalisehostname", oCanonicaliseHostname }, | ||
265 | { "canonicalisemaxdots", oCanonicaliseMaxDots }, | ||
266 | { "canonicalisepermittedcnames", oCanonicalisePermittedCNAMEs }, | ||
260 | { "ignoreunknown", oIgnoreUnknown }, | 267 | { "ignoreunknown", oIgnoreUnknown }, |
261 | 268 | ||
262 | { NULL, oBadOption } | 269 | { NULL, oBadOption } |
@@ -535,6 +542,34 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw, | |||
535 | return result; | 542 | return result; |
536 | } | 543 | } |
537 | 544 | ||
545 | /* Check and prepare a domain name: removes trailing '.' and lowercases */ | ||
546 | static void | ||
547 | valid_domain(char *name, const char *filename, int linenum) | ||
548 | { | ||
549 | size_t i, l = strlen(name); | ||
550 | u_char c, last = '\0'; | ||
551 | |||
552 | if (l == 0) | ||
553 | fatal("%s line %d: empty hostname suffix", filename, linenum); | ||
554 | if (!isalpha((u_char)name[0]) && !isdigit((u_char)name[0])) | ||
555 | fatal("%s line %d: hostname suffix \"%.100s\" " | ||
556 | "starts with invalid character", filename, linenum, name); | ||
557 | for (i = 0; i < l; i++) { | ||
558 | c = tolower((u_char)name[i]); | ||
559 | name[i] = (char)c; | ||
560 | if (last == '.' && c == '.') | ||
561 | fatal("%s line %d: hostname suffix \"%.100s\" contains " | ||
562 | "consecutive separators", filename, linenum, name); | ||
563 | if (c != '.' && c != '-' && !isalnum(c) && | ||
564 | c != '_') /* technically invalid, but common */ | ||
565 | fatal("%s line %d: hostname suffix \"%.100s\" contains " | ||
566 | "invalid characters", filename, linenum, name); | ||
567 | last = c; | ||
568 | } | ||
569 | if (name[l - 1] == '.') | ||
570 | name[l - 1] = '\0'; | ||
571 | } | ||
572 | |||
538 | /* | 573 | /* |
539 | * Returns the number of the token pointed to by cp or oBadOption. | 574 | * Returns the number of the token pointed to by cp or oBadOption. |
540 | */ | 575 | */ |
@@ -609,6 +644,14 @@ static const struct multistate multistate_requesttty[] = { | |||
609 | { "auto", REQUEST_TTY_AUTO }, | 644 | { "auto", REQUEST_TTY_AUTO }, |
610 | { NULL, -1 } | 645 | { NULL, -1 } |
611 | }; | 646 | }; |
647 | static const struct multistate multistate_canonicalisehostname[] = { | ||
648 | { "true", SSH_CANONICALISE_YES }, | ||
649 | { "false", SSH_CANONICALISE_NO }, | ||
650 | { "yes", SSH_CANONICALISE_YES }, | ||
651 | { "no", SSH_CANONICALISE_NO }, | ||
652 | { "always", SSH_CANONICALISE_ALWAYS }, | ||
653 | { NULL, -1 } | ||
654 | }; | ||
612 | 655 | ||
613 | /* | 656 | /* |
614 | * Processes a single option line as used in the configuration files. This | 657 | * Processes a single option line as used in the configuration files. This |
@@ -628,6 +671,7 @@ process_config_line(Options *options, struct passwd *pw, const char *host, | |||
628 | size_t len; | 671 | size_t len; |
629 | Forward fwd; | 672 | Forward fwd; |
630 | const struct multistate *multistate_ptr; | 673 | const struct multistate *multistate_ptr; |
674 | struct allowed_cname *cname; | ||
631 | 675 | ||
632 | if (activep == NULL) { /* We are processing a command line directive */ | 676 | if (activep == NULL) { /* We are processing a command line directive */ |
633 | cmdline = 1; | 677 | cmdline = 1; |
@@ -1263,6 +1307,62 @@ parse_int: | |||
1263 | intptr = &options->proxy_use_fdpass; | 1307 | intptr = &options->proxy_use_fdpass; |
1264 | goto parse_flag; | 1308 | goto parse_flag; |
1265 | 1309 | ||
1310 | case oCanonicalDomains: | ||
1311 | value = options->num_canonical_domains != 0; | ||
1312 | while ((arg = strdelim(&s)) != NULL && *arg != '\0') { | ||
1313 | valid_domain(arg, filename, linenum); | ||
1314 | if (!*activep || value) | ||
1315 | continue; | ||
1316 | if (options->num_canonical_domains >= MAX_CANON_DOMAINS) | ||
1317 | fatal("%s line %d: too many hostname suffixes.", | ||
1318 | filename, linenum); | ||
1319 | options->canonical_domains[ | ||
1320 | options->num_canonical_domains++] = xstrdup(arg); | ||
1321 | } | ||
1322 | break; | ||
1323 | |||
1324 | case oCanonicalisePermittedCNAMEs: | ||
1325 | value = options->num_permitted_cnames != 0; | ||
1326 | while ((arg = strdelim(&s)) != NULL && *arg != '\0') { | ||
1327 | /* Either '*' for everything or 'list:list' */ | ||
1328 | if (strcmp(arg, "*") == 0) | ||
1329 | arg2 = arg; | ||
1330 | else { | ||
1331 | lowercase(arg); | ||
1332 | if ((arg2 = strchr(arg, ':')) == NULL || | ||
1333 | arg2[1] == '\0') { | ||
1334 | fatal("%s line %d: " | ||
1335 | "Invalid permitted CNAME \"%s\"", | ||
1336 | filename, linenum, arg); | ||
1337 | } | ||
1338 | *arg2 = '\0'; | ||
1339 | arg2++; | ||
1340 | } | ||
1341 | if (!*activep || value) | ||
1342 | continue; | ||
1343 | if (options->num_permitted_cnames >= MAX_CANON_DOMAINS) | ||
1344 | fatal("%s line %d: too many permitted CNAMEs.", | ||
1345 | filename, linenum); | ||
1346 | cname = options->permitted_cnames + | ||
1347 | options->num_permitted_cnames++; | ||
1348 | cname->source_list = xstrdup(arg); | ||
1349 | cname->target_list = xstrdup(arg2); | ||
1350 | } | ||
1351 | break; | ||
1352 | |||
1353 | case oCanonicaliseHostname: | ||
1354 | intptr = &options->canonicalise_hostname; | ||
1355 | multistate_ptr = multistate_canonicalisehostname; | ||
1356 | goto parse_multistate; | ||
1357 | |||
1358 | case oCanonicaliseMaxDots: | ||
1359 | intptr = &options->canonicalise_max_dots; | ||
1360 | goto parse_int; | ||
1361 | |||
1362 | case oCanonicaliseFallbackLocal: | ||
1363 | intptr = &options->canonicalise_fallback_local; | ||
1364 | goto parse_flag; | ||
1365 | |||
1266 | case oDeprecated: | 1366 | case oDeprecated: |
1267 | debug("%s line %d: Deprecated option \"%s\"", | 1367 | debug("%s line %d: Deprecated option \"%s\"", |
1268 | filename, linenum, keyword); | 1368 | filename, linenum, keyword); |
@@ -1426,6 +1526,11 @@ initialize_options(Options * options) | |||
1426 | options->request_tty = -1; | 1526 | options->request_tty = -1; |
1427 | options->proxy_use_fdpass = -1; | 1527 | options->proxy_use_fdpass = -1; |
1428 | options->ignored_unknown = NULL; | 1528 | options->ignored_unknown = NULL; |
1529 | options->num_canonical_domains = 0; | ||
1530 | options->num_permitted_cnames = 0; | ||
1531 | options->canonicalise_max_dots = -1; | ||
1532 | options->canonicalise_fallback_local = -1; | ||
1533 | options->canonicalise_hostname = -1; | ||
1429 | } | 1534 | } |
1430 | 1535 | ||
1431 | /* | 1536 | /* |
@@ -1579,6 +1684,12 @@ fill_default_options(Options * options) | |||
1579 | options->request_tty = REQUEST_TTY_AUTO; | 1684 | options->request_tty = REQUEST_TTY_AUTO; |
1580 | if (options->proxy_use_fdpass == -1) | 1685 | if (options->proxy_use_fdpass == -1) |
1581 | options->proxy_use_fdpass = 0; | 1686 | options->proxy_use_fdpass = 0; |
1687 | if (options->canonicalise_max_dots == -1) | ||
1688 | options->canonicalise_max_dots = 1; | ||
1689 | if (options->canonicalise_fallback_local == -1) | ||
1690 | options->canonicalise_fallback_local = 1; | ||
1691 | if (options->canonicalise_hostname == -1) | ||
1692 | options->canonicalise_hostname = SSH_CANONICALISE_NO; | ||
1582 | #define CLEAR_ON_NONE(v) \ | 1693 | #define CLEAR_ON_NONE(v) \ |
1583 | do { \ | 1694 | do { \ |
1584 | if (v != NULL && strcasecmp(v, "none") == 0) { \ | 1695 | if (v != NULL && strcasecmp(v, "none") == 0) { \ |
diff --git a/readconf.h b/readconf.h index cde8b5242..4a210897e 100644 --- a/readconf.h +++ b/readconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.h,v 1.97 2013/10/14 22:22:03 djm Exp $ */ | 1 | /* $OpenBSD: readconf.h,v 1.98 2013/10/16 02:31:46 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -29,7 +29,13 @@ typedef struct { | |||
29 | /* Data structure for representing option data. */ | 29 | /* Data structure for representing option data. */ |
30 | 30 | ||
31 | #define MAX_SEND_ENV 256 | 31 | #define MAX_SEND_ENV 256 |
32 | #define SSH_MAX_HOSTS_FILES 256 | 32 | #define SSH_MAX_HOSTS_FILES 32 |
33 | #define MAX_CANON_DOMAINS 32 | ||
34 | |||
35 | struct allowed_cname { | ||
36 | char *source_list; | ||
37 | char *target_list; | ||
38 | }; | ||
33 | 39 | ||
34 | typedef struct { | 40 | typedef struct { |
35 | int forward_agent; /* Forward authentication agent. */ | 41 | int forward_agent; /* Forward authentication agent. */ |
@@ -140,9 +146,21 @@ typedef struct { | |||
140 | 146 | ||
141 | int proxy_use_fdpass; | 147 | int proxy_use_fdpass; |
142 | 148 | ||
149 | int num_canonical_domains; | ||
150 | char *canonical_domains[MAX_CANON_DOMAINS]; | ||
151 | int canonicalise_hostname; | ||
152 | int canonicalise_max_dots; | ||
153 | int canonicalise_fallback_local; | ||
154 | int num_permitted_cnames; | ||
155 | struct allowed_cname permitted_cnames[MAX_CANON_DOMAINS]; | ||
156 | |||
143 | char *ignored_unknown; /* Pattern list of unknown tokens to ignore */ | 157 | char *ignored_unknown; /* Pattern list of unknown tokens to ignore */ |
144 | } Options; | 158 | } Options; |
145 | 159 | ||
160 | #define SSH_CANONICALISE_NO 0 | ||
161 | #define SSH_CANONICALISE_YES 1 | ||
162 | #define SSH_CANONICALISE_ALWAYS 2 | ||
163 | |||
146 | #define SSHCTL_MASTER_NO 0 | 164 | #define SSHCTL_MASTER_NO 0 |
147 | #define SSHCTL_MASTER_YES 1 | 165 | #define SSHCTL_MASTER_YES 1 |
148 | #define SSHCTL_MASTER_AUTO 2 | 166 | #define SSHCTL_MASTER_AUTO 2 |
diff --git a/roaming_client.c b/roaming_client.c index 81c496827..2fb623121 100644 --- a/roaming_client.c +++ b/roaming_client.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: roaming_client.c,v 1.5 2013/05/17 00:13:14 djm Exp $ */ | 1 | /* $OpenBSD: roaming_client.c,v 1.6 2013/10/16 02:31:46 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2004-2009 AppGate Network Security AB | 3 | * Copyright (c) 2004-2009 AppGate Network Security AB |
4 | * | 4 | * |
@@ -259,10 +259,10 @@ wait_for_roaming_reconnect(void) | |||
259 | if (c != '\n' && c != '\r') | 259 | if (c != '\n' && c != '\r') |
260 | continue; | 260 | continue; |
261 | 261 | ||
262 | if (ssh_connect(host, &hostaddr, options.port, | 262 | if (ssh_connect(host, NULL, &hostaddr, options.port, |
263 | options.address_family, 1, &timeout_ms, | 263 | options.address_family, 1, &timeout_ms, |
264 | options.tcp_keep_alive, options.use_privileged_port, | 264 | options.tcp_keep_alive, options.use_privileged_port) == 0 && |
265 | options.proxy_command) == 0 && roaming_resume() == 0) { | 265 | roaming_resume() == 0) { |
266 | packet_restore_state(); | 266 | packet_restore_state(); |
267 | reenter_guard = 0; | 267 | reenter_guard = 0; |
268 | fprintf(stderr, "[connection resumed]\n"); | 268 | fprintf(stderr, "[connection resumed]\n"); |
@@ -33,8 +33,8 @@ | |||
33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | .\" | 35 | .\" |
36 | .\" $OpenBSD: ssh.1,v 1.337 2013/10/15 14:10:25 jmc Exp $ | 36 | .\" $OpenBSD: ssh.1,v 1.338 2013/10/16 02:31:46 djm Exp $ |
37 | .Dd $Mdocdate: October 15 2013 $ | 37 | .Dd $Mdocdate: October 16 2013 $ |
38 | .Dt SSH 1 | 38 | .Dt SSH 1 |
39 | .Os | 39 | .Os |
40 | .Sh NAME | 40 | .Sh NAME |
@@ -417,6 +417,11 @@ For full details of the options listed below, and their possible values, see | |||
417 | .It AddressFamily | 417 | .It AddressFamily |
418 | .It BatchMode | 418 | .It BatchMode |
419 | .It BindAddress | 419 | .It BindAddress |
420 | .It CanonicalDomains | ||
421 | .It CanonicaliseFallbackLocal | ||
422 | .It CanonicaliseHostname | ||
423 | .It CanonicaliseMaxDots | ||
424 | .It CanonicalisePermittedCNAMEs | ||
420 | .It ChallengeResponseAuthentication | 425 | .It ChallengeResponseAuthentication |
421 | .It CheckHostIP | 426 | .It CheckHostIP |
422 | .It Cipher | 427 | .It Cipher |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh.c,v 1.384 2013/10/14 23:31:01 djm Exp $ */ | 1 | /* $OpenBSD: ssh.c,v 1.385 2013/10/16 02:31:46 djm 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 |
@@ -231,6 +231,134 @@ tilde_expand_paths(char **paths, u_int num_paths) | |||
231 | } | 231 | } |
232 | } | 232 | } |
233 | 233 | ||
234 | static struct addrinfo * | ||
235 | resolve_host(const char *name, u_int port, int logerr, char *cname, size_t clen) | ||
236 | { | ||
237 | char strport[NI_MAXSERV]; | ||
238 | struct addrinfo hints, *res; | ||
239 | int gaierr, loglevel = SYSLOG_LEVEL_DEBUG1; | ||
240 | |||
241 | snprintf(strport, sizeof strport, "%u", port); | ||
242 | bzero(&hints, sizeof(hints)); | ||
243 | hints.ai_family = options.address_family; | ||
244 | hints.ai_socktype = SOCK_STREAM; | ||
245 | if (cname != NULL) | ||
246 | hints.ai_flags = AI_CANONNAME; | ||
247 | if ((gaierr = getaddrinfo(name, strport, &hints, &res)) != 0) { | ||
248 | if (logerr || (gaierr != EAI_NONAME && gaierr != EAI_NODATA)) | ||
249 | loglevel = SYSLOG_LEVEL_ERROR; | ||
250 | do_log2(loglevel, "%s: Could not resolve hostname %.100s: %s", | ||
251 | __progname, name, ssh_gai_strerror(gaierr)); | ||
252 | return NULL; | ||
253 | } | ||
254 | if (cname != NULL && res->ai_canonname != NULL) { | ||
255 | if (strlcpy(cname, res->ai_canonname, clen) >= clen) { | ||
256 | error("%s: host \"%s\" cname \"%s\" too long (max %lu)", | ||
257 | __func__, name, res->ai_canonname, (u_long)clen); | ||
258 | if (clen > 0) | ||
259 | *cname = '\0'; | ||
260 | } | ||
261 | } | ||
262 | return res; | ||
263 | } | ||
264 | |||
265 | /* | ||
266 | * Check whether the cname is a permitted replacement for the hostname | ||
267 | * and perform the replacement if it is. | ||
268 | */ | ||
269 | static int | ||
270 | check_follow_cname(char **namep, const char *cname) | ||
271 | { | ||
272 | int i; | ||
273 | struct allowed_cname *rule; | ||
274 | |||
275 | if (*cname == '\0' || options.num_permitted_cnames == 0 || | ||
276 | strcmp(*namep, cname) == 0) | ||
277 | return 0; | ||
278 | if (options.canonicalise_hostname == SSH_CANONICALISE_NO) | ||
279 | return 0; | ||
280 | /* | ||
281 | * Don't attempt to canonicalise names that will be interpreted by | ||
282 | * a proxy unless the user specifically requests so. | ||
283 | */ | ||
284 | if (options.proxy_command != NULL && | ||
285 | options.canonicalise_hostname != SSH_CANONICALISE_ALWAYS) | ||
286 | return 0; | ||
287 | debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname); | ||
288 | for (i = 0; i < options.num_permitted_cnames; i++) { | ||
289 | rule = options.permitted_cnames + i; | ||
290 | if (match_pattern_list(*namep, rule->source_list, | ||
291 | strlen(rule->source_list), 1) != 1 || | ||
292 | match_pattern_list(cname, rule->target_list, | ||
293 | strlen(rule->target_list), 1) != 1) | ||
294 | continue; | ||
295 | verbose("Canonicalised DNS aliased hostname " | ||
296 | "\"%s\" => \"%s\"", *namep, cname); | ||
297 | free(*namep); | ||
298 | *namep = xstrdup(cname); | ||
299 | return 1; | ||
300 | } | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * Attempt to resolve the supplied hostname after applying the user's | ||
306 | * canonicalisation rules. Returns the address list for the host or NULL | ||
307 | * if no name was found after canonicalisation. | ||
308 | */ | ||
309 | static struct addrinfo * | ||
310 | resolve_canonicalise(char **hostp, u_int port) | ||
311 | { | ||
312 | int i, ndots; | ||
313 | char *cp, *fullhost, cname_target[NI_MAXHOST]; | ||
314 | struct addrinfo *addrs; | ||
315 | |||
316 | if (options.canonicalise_hostname == SSH_CANONICALISE_NO) | ||
317 | return NULL; | ||
318 | /* | ||
319 | * Don't attempt to canonicalise names that will be interpreted by | ||
320 | * a proxy unless the user specifically requests so. | ||
321 | */ | ||
322 | if (options.proxy_command != NULL && | ||
323 | options.canonicalise_hostname != SSH_CANONICALISE_ALWAYS) | ||
324 | return NULL; | ||
325 | /* Don't apply canonicalisation to sufficiently-qualified hostnames */ | ||
326 | ndots = 0; | ||
327 | for (cp = *hostp; *cp != '\0'; cp++) { | ||
328 | if (*cp == '.') | ||
329 | ndots++; | ||
330 | } | ||
331 | if (ndots > options.canonicalise_max_dots) { | ||
332 | debug3("%s: not canonicalising hostname \"%s\" (max dots %d)", | ||
333 | __func__, *hostp, options.canonicalise_max_dots); | ||
334 | return NULL; | ||
335 | } | ||
336 | /* Attempt each supplied suffix */ | ||
337 | for (i = 0; i < options.num_canonical_domains; i++) { | ||
338 | *cname_target = '\0'; | ||
339 | xasprintf(&fullhost, "%s.%s.", *hostp, | ||
340 | options.canonical_domains[i]); | ||
341 | if ((addrs = resolve_host(fullhost, options.port, 0, | ||
342 | cname_target, sizeof(cname_target))) == NULL) { | ||
343 | free(fullhost); | ||
344 | continue; | ||
345 | } | ||
346 | /* Remove trailing '.' */ | ||
347 | fullhost[strlen(fullhost) - 1] = '\0'; | ||
348 | /* Follow CNAME if requested */ | ||
349 | if (!check_follow_cname(&fullhost, cname_target)) { | ||
350 | debug("Canonicalised hostname \"%s\" => \"%s\"", | ||
351 | *hostp, fullhost); | ||
352 | } | ||
353 | free(*hostp); | ||
354 | *hostp = fullhost; | ||
355 | return addrs; | ||
356 | } | ||
357 | if (!options.canonicalise_fallback_local) | ||
358 | fatal("%s: Could not resolve host \"%s\"", __progname, host); | ||
359 | return NULL; | ||
360 | } | ||
361 | |||
234 | /* | 362 | /* |
235 | * Main program for the ssh client. | 363 | * Main program for the ssh client. |
236 | */ | 364 | */ |
@@ -240,12 +368,14 @@ main(int ac, char **av) | |||
240 | int i, r, opt, exit_status, use_syslog; | 368 | int i, r, opt, exit_status, use_syslog; |
241 | char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg, *logfile; | 369 | char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg, *logfile; |
242 | char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; | 370 | char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; |
371 | char cname[NI_MAXHOST]; | ||
243 | struct stat st; | 372 | struct stat st; |
244 | struct passwd *pw; | 373 | struct passwd *pw; |
245 | int timeout_ms; | 374 | int timeout_ms; |
246 | extern int optind, optreset; | 375 | extern int optind, optreset; |
247 | extern char *optarg; | 376 | extern char *optarg; |
248 | Forward fwd; | 377 | Forward fwd; |
378 | struct addrinfo *addrs = NULL; | ||
249 | 379 | ||
250 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ | 380 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
251 | sanitise_stdfd(); | 381 | sanitise_stdfd(); |
@@ -630,9 +760,9 @@ main(int ac, char **av) | |||
630 | usage(); | 760 | usage(); |
631 | options.user = p; | 761 | options.user = p; |
632 | *cp = '\0'; | 762 | *cp = '\0'; |
633 | host = ++cp; | 763 | host = xstrdup(++cp); |
634 | } else | 764 | } else |
635 | host = *av; | 765 | host = xstrdup(*av); |
636 | if (ac > 1) { | 766 | if (ac > 1) { |
637 | optind = optreset = 1; | 767 | optind = optreset = 1; |
638 | goto again; | 768 | goto again; |
@@ -644,6 +774,9 @@ main(int ac, char **av) | |||
644 | if (!host) | 774 | if (!host) |
645 | usage(); | 775 | usage(); |
646 | 776 | ||
777 | lowercase(host); | ||
778 | host_arg = xstrdup(host); | ||
779 | |||
647 | OpenSSL_add_all_algorithms(); | 780 | OpenSSL_add_all_algorithms(); |
648 | ERR_load_crypto_strings(); | 781 | ERR_load_crypto_strings(); |
649 | 782 | ||
@@ -728,6 +861,10 @@ main(int ac, char **av) | |||
728 | strcmp(options.proxy_command, "-") == 0 && | 861 | strcmp(options.proxy_command, "-") == 0 && |
729 | options.proxy_use_fdpass) | 862 | options.proxy_use_fdpass) |
730 | fatal("ProxyCommand=- and ProxyUseFDPass are incompatible"); | 863 | fatal("ProxyCommand=- and ProxyUseFDPass are incompatible"); |
864 | #ifndef HAVE_CYGWIN | ||
865 | if (original_effective_uid != 0) | ||
866 | options.use_privileged_port = 0; | ||
867 | #endif | ||
731 | 868 | ||
732 | /* reinit */ | 869 | /* reinit */ |
733 | log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog); | 870 | log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog); |
@@ -762,10 +899,26 @@ main(int ac, char **av) | |||
762 | options.port = default_ssh_port(); | 899 | options.port = default_ssh_port(); |
763 | 900 | ||
764 | /* preserve host name given on command line for %n expansion */ | 901 | /* preserve host name given on command line for %n expansion */ |
765 | host_arg = host; | ||
766 | if (options.hostname != NULL) { | 902 | if (options.hostname != NULL) { |
767 | host = percent_expand(options.hostname, | 903 | cp = percent_expand(options.hostname, |
768 | "h", host, (char *)NULL); | 904 | "h", host, (char *)NULL); |
905 | free(host); | ||
906 | host = cp; | ||
907 | } | ||
908 | |||
909 | /* If canonicalisation requested then try to apply it */ | ||
910 | if (options.canonicalise_hostname != SSH_CANONICALISE_NO) | ||
911 | addrs = resolve_canonicalise(&host, options.port); | ||
912 | /* | ||
913 | * If canonicalisation not requested, or if it failed then try to | ||
914 | * resolve the bare hostname name using the system resolver's usual | ||
915 | * search rules. | ||
916 | */ | ||
917 | if (addrs == NULL) { | ||
918 | if ((addrs = resolve_host(host, options.port, 1, | ||
919 | cname, sizeof(cname))) == NULL) | ||
920 | cleanup_exit(255); /* resolve_host logs the error */ | ||
921 | check_follow_cname(&host, cname); | ||
769 | } | 922 | } |
770 | 923 | ||
771 | if (gethostname(thishost, sizeof(thishost)) == -1) | 924 | if (gethostname(thishost, sizeof(thishost)) == -1) |
@@ -803,16 +956,15 @@ main(int ac, char **av) | |||
803 | timeout_ms = options.connection_timeout * 1000; | 956 | timeout_ms = options.connection_timeout * 1000; |
804 | 957 | ||
805 | /* Open a connection to the remote host. */ | 958 | /* Open a connection to the remote host. */ |
806 | if (ssh_connect(host, &hostaddr, options.port, | 959 | if (ssh_connect(host, addrs, &hostaddr, options.port, |
807 | options.address_family, options.connection_attempts, &timeout_ms, | 960 | options.address_family, options.connection_attempts, |
808 | options.tcp_keep_alive, | 961 | &timeout_ms, options.tcp_keep_alive, |
809 | #ifdef HAVE_CYGWIN | 962 | options.use_privileged_port) != 0) |
810 | options.use_privileged_port, | 963 | exit(255); |
811 | #else | 964 | |
812 | original_effective_uid == 0 && options.use_privileged_port, | 965 | freeaddrinfo(addrs); |
813 | #endif | 966 | packet_set_timeout(options.server_alive_interval, |
814 | options.proxy_command) != 0) | 967 | options.server_alive_count_max); |
815 | exit(255); | ||
816 | 968 | ||
817 | if (timeout_ms > 0) | 969 | if (timeout_ms > 0) |
818 | debug3("timeout: %d ms remain after connect", timeout_ms); | 970 | debug3("timeout: %d ms remain after connect", timeout_ms); |
@@ -1621,4 +1773,3 @@ main_sigchld_handler(int sig) | |||
1621 | signal(sig, main_sigchld_handler); | 1773 | signal(sig, main_sigchld_handler); |
1622 | errno = save_errno; | 1774 | errno = save_errno; |
1623 | } | 1775 | } |
1624 | |||
diff --git a/ssh_config.5 b/ssh_config.5 index 3eaaa536a..3c1f87bef 100644 --- a/ssh_config.5 +++ b/ssh_config.5 | |||
@@ -33,8 +33,8 @@ | |||
33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | .\" | 35 | .\" |
36 | .\" $OpenBSD: ssh_config.5,v 1.170 2013/10/15 14:10:25 jmc Exp $ | 36 | .\" $OpenBSD: ssh_config.5,v 1.171 2013/10/16 02:31:46 djm Exp $ |
37 | .Dd $Mdocdate: October 15 2013 $ | 37 | .Dd $Mdocdate: October 16 2013 $ |
38 | .Dt SSH_CONFIG 5 | 38 | .Dt SSH_CONFIG 5 |
39 | .Os | 39 | .Os |
40 | .Sh NAME | 40 | .Sh NAME |
@@ -200,6 +200,77 @@ Note that this option does not work if | |||
200 | .Cm UsePrivilegedPort | 200 | .Cm UsePrivilegedPort |
201 | is set to | 201 | is set to |
202 | .Dq yes . | 202 | .Dq yes . |
203 | .It Cm CanonicalDomains | ||
204 | when | ||
205 | .Cm CanonicaliseHostname | ||
206 | is enabled, this option specifies the list of domain suffixes in which to | ||
207 | search for the specified destination host. | ||
208 | .It Cm CanonicaliseFallbackLocal | ||
209 | specified whether to fail with an error when hostname canonicalisation fails. | ||
210 | The default of | ||
211 | .Dq no | ||
212 | will attempt to lookup the unqualified hostname using the system resolver's | ||
213 | search rules. | ||
214 | A value of | ||
215 | .Dq yes | ||
216 | will cause | ||
217 | .Xr ssh 1 | ||
218 | to fail instantly if | ||
219 | .Cm CanonicaliseHostname | ||
220 | is enabled and the target hostname cannot be found in any of the domains | ||
221 | specified by | ||
222 | .Cm CanonicalDomains . | ||
223 | .It Cm CanonicaliseHostname | ||
224 | controls whether explicit hostname canonicalisation is performed. | ||
225 | The default | ||
226 | .Dq no | ||
227 | is not to perform any name rewriting and let the system resolver handle all | ||
228 | hostname lookups. | ||
229 | If set to | ||
230 | .Dq yes | ||
231 | then, for connections that do not use a | ||
232 | .Cm ProxyCommand , | ||
233 | .Xr ssh 1 | ||
234 | will attempt to canonicalise the hostname specified on the command line | ||
235 | using the | ||
236 | .Cm CanonicalDomains | ||
237 | suffixes and | ||
238 | .Cm CanonicalisePermittedCNAMEs | ||
239 | rules. | ||
240 | If | ||
241 | .Cm CanonicaliseHostname | ||
242 | is set to | ||
243 | .Dq always , | ||
244 | then canonicalisation is applied to proxied connections to. | ||
245 | .It Cm CanonicaliseMaxDots | ||
246 | specifies the maximum number of dot characters in a hostname name before | ||
247 | canonicalisation is disabled. | ||
248 | The default of | ||
249 | .Dq 1 | ||
250 | allows a single dot (i.e. hostname.subdomain) | ||
251 | .It Cm CanonicalisePermittedCNAMEs | ||
252 | specifies rules to determine whether CNAMEs should be followed when | ||
253 | canonicalising hostnames. | ||
254 | The rules consist of one or more arguments of | ||
255 | .Sm off | ||
256 | .Ar source_domain_list : Ar target_domain_list | ||
257 | .Sm on | ||
258 | where | ||
259 | .Ar source_domain_list | ||
260 | is a pattern-list of domains that are may follow CNAMEs in canonicalisation | ||
261 | and | ||
262 | .Ar target_domain_list | ||
263 | is a pattern-list of domains that they may resove to. | ||
264 | .Pp | ||
265 | For example, | ||
266 | .Dq *.a.example.com:*.b.example.com,*.c.example.com | ||
267 | will allow hostnames matching | ||
268 | .Dq *.a.example.com | ||
269 | to be canonicalised to names in the | ||
270 | .Dq *.b.example.com | ||
271 | or | ||
272 | .Dq *.c.example.com | ||
273 | domains. | ||
203 | .It Cm ChallengeResponseAuthentication | 274 | .It Cm ChallengeResponseAuthentication |
204 | Specifies whether to use challenge-response authentication. | 275 | Specifies whether to use challenge-response authentication. |
205 | The argument to this keyword must be | 276 | The argument to this keyword must be |
diff --git a/sshconnect.c b/sshconnect.c index aee38198b..3cdc46149 100644 --- a/sshconnect.c +++ b/sshconnect.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect.c,v 1.240 2013/09/19 01:26:29 djm Exp $ */ | 1 | /* $OpenBSD: sshconnect.c,v 1.241 2013/10/16 02:31:46 djm 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 |
@@ -86,7 +86,7 @@ expand_proxy_command(const char *proxy_command, const char *user, | |||
86 | { | 86 | { |
87 | char *tmp, *ret, strport[NI_MAXSERV]; | 87 | char *tmp, *ret, strport[NI_MAXSERV]; |
88 | 88 | ||
89 | snprintf(strport, sizeof strport, "%hu", port); | 89 | snprintf(strport, sizeof strport, "%d", port); |
90 | xasprintf(&tmp, "exec %s", proxy_command); | 90 | xasprintf(&tmp, "exec %s", proxy_command); |
91 | ret = percent_expand(tmp, "h", host, "p", strport, | 91 | ret = percent_expand(tmp, "h", host, "p", strport, |
92 | "r", options.user, (char *)NULL); | 92 | "r", options.user, (char *)NULL); |
@@ -170,8 +170,6 @@ ssh_proxy_fdpass_connect(const char *host, u_short port, | |||
170 | 170 | ||
171 | /* Set the connection file descriptors. */ | 171 | /* Set the connection file descriptors. */ |
172 | packet_set_connection(sock, sock); | 172 | packet_set_connection(sock, sock); |
173 | packet_set_timeout(options.server_alive_interval, | ||
174 | options.server_alive_count_max); | ||
175 | 173 | ||
176 | return 0; | 174 | return 0; |
177 | } | 175 | } |
@@ -187,16 +185,6 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) | |||
187 | pid_t pid; | 185 | pid_t pid; |
188 | char *shell; | 186 | char *shell; |
189 | 187 | ||
190 | if (!strcmp(proxy_command, "-")) { | ||
191 | packet_set_connection(STDIN_FILENO, STDOUT_FILENO); | ||
192 | packet_set_timeout(options.server_alive_interval, | ||
193 | options.server_alive_count_max); | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | if (options.proxy_use_fdpass) | ||
198 | return ssh_proxy_fdpass_connect(host, port, proxy_command); | ||
199 | |||
200 | if ((shell = getenv("SHELL")) == NULL || *shell == '\0') | 188 | if ((shell = getenv("SHELL")) == NULL || *shell == '\0') |
201 | shell = _PATH_BSHELL; | 189 | shell = _PATH_BSHELL; |
202 | 190 | ||
@@ -258,8 +246,6 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) | |||
258 | 246 | ||
259 | /* Set the connection file descriptors. */ | 247 | /* Set the connection file descriptors. */ |
260 | packet_set_connection(pout[0], pin[1]); | 248 | packet_set_connection(pout[0], pin[1]); |
261 | packet_set_timeout(options.server_alive_interval, | ||
262 | options.server_alive_count_max); | ||
263 | 249 | ||
264 | /* Indicate OK return */ | 250 | /* Indicate OK return */ |
265 | return 0; | 251 | return 0; |
@@ -429,33 +415,18 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr, | |||
429 | * and %p substituted for host and port, respectively) to use to contact | 415 | * and %p substituted for host and port, respectively) to use to contact |
430 | * the daemon. | 416 | * the daemon. |
431 | */ | 417 | */ |
432 | int | 418 | static int |
433 | ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | 419 | ssh_connect_direct(const char *host, struct addrinfo *aitop, |
434 | u_short port, int family, int connection_attempts, int *timeout_ms, | 420 | struct sockaddr_storage *hostaddr, u_short port, int family, |
435 | int want_keepalive, int needpriv, const char *proxy_command) | 421 | int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv) |
436 | { | 422 | { |
437 | int gaierr; | ||
438 | int on = 1; | 423 | int on = 1; |
439 | int sock = -1, attempt; | 424 | int sock = -1, attempt; |
440 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; | 425 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
441 | struct addrinfo hints, *ai, *aitop; | 426 | struct addrinfo *ai; |
442 | 427 | ||
443 | debug2("ssh_connect: needpriv %d", needpriv); | 428 | debug2("ssh_connect: needpriv %d", needpriv); |
444 | 429 | ||
445 | /* If a proxy command is given, connect using it. */ | ||
446 | if (proxy_command != NULL) | ||
447 | return ssh_proxy_connect(host, port, proxy_command); | ||
448 | |||
449 | /* No proxy command. */ | ||
450 | |||
451 | memset(&hints, 0, sizeof(hints)); | ||
452 | hints.ai_family = family; | ||
453 | hints.ai_socktype = SOCK_STREAM; | ||
454 | snprintf(strport, sizeof strport, "%u", port); | ||
455 | if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) | ||
456 | fatal("%s: Could not resolve hostname %.100s: %s", __progname, | ||
457 | host, ssh_gai_strerror(gaierr)); | ||
458 | |||
459 | for (attempt = 0; attempt < connection_attempts; attempt++) { | 430 | for (attempt = 0; attempt < connection_attempts; attempt++) { |
460 | if (attempt > 0) { | 431 | if (attempt > 0) { |
461 | /* Sleep a moment before retrying. */ | 432 | /* Sleep a moment before retrying. */ |
@@ -467,7 +438,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
467 | * sequence until the connection succeeds. | 438 | * sequence until the connection succeeds. |
468 | */ | 439 | */ |
469 | for (ai = aitop; ai; ai = ai->ai_next) { | 440 | for (ai = aitop; ai; ai = ai->ai_next) { |
470 | if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) | 441 | if (ai->ai_family != AF_INET && |
442 | ai->ai_family != AF_INET6) | ||
471 | continue; | 443 | continue; |
472 | if (getnameinfo(ai->ai_addr, ai->ai_addrlen, | 444 | if (getnameinfo(ai->ai_addr, ai->ai_addrlen, |
473 | ntop, sizeof(ntop), strport, sizeof(strport), | 445 | ntop, sizeof(ntop), strport, sizeof(strport), |
@@ -500,8 +472,6 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
500 | break; /* Successful connection. */ | 472 | break; /* Successful connection. */ |
501 | } | 473 | } |
502 | 474 | ||
503 | freeaddrinfo(aitop); | ||
504 | |||
505 | /* Return failure if we didn't get a successful connection. */ | 475 | /* Return failure if we didn't get a successful connection. */ |
506 | if (sock == -1) { | 476 | if (sock == -1) { |
507 | error("ssh: connect to host %s port %s: %s", | 477 | error("ssh: connect to host %s port %s: %s", |
@@ -519,12 +489,28 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
519 | 489 | ||
520 | /* Set the connection. */ | 490 | /* Set the connection. */ |
521 | packet_set_connection(sock, sock); | 491 | packet_set_connection(sock, sock); |
522 | packet_set_timeout(options.server_alive_interval, | ||
523 | options.server_alive_count_max); | ||
524 | 492 | ||
525 | return 0; | 493 | return 0; |
526 | } | 494 | } |
527 | 495 | ||
496 | int | ||
497 | ssh_connect(const char *host, struct addrinfo *addrs, | ||
498 | struct sockaddr_storage *hostaddr, u_short port, int family, | ||
499 | int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv) | ||
500 | { | ||
501 | if (options.proxy_command == NULL) { | ||
502 | return ssh_connect_direct(host, addrs, hostaddr, port, family, | ||
503 | connection_attempts, timeout_ms, want_keepalive, needpriv); | ||
504 | } else if (strcmp(options.proxy_command, "-") == 0) { | ||
505 | packet_set_connection(STDIN_FILENO, STDOUT_FILENO); | ||
506 | return 0; /* Always succeeds */ | ||
507 | } else if (options.proxy_use_fdpass) { | ||
508 | return ssh_proxy_fdpass_connect(host, port, | ||
509 | options.proxy_command); | ||
510 | } | ||
511 | return ssh_proxy_connect(host, port, options.proxy_command); | ||
512 | } | ||
513 | |||
528 | static void | 514 | static void |
529 | send_client_banner(int connection_out, int minor1) | 515 | send_client_banner(int connection_out, int minor1) |
530 | { | 516 | { |
@@ -1265,7 +1251,7 @@ void | |||
1265 | ssh_login(Sensitive *sensitive, const char *orighost, | 1251 | ssh_login(Sensitive *sensitive, const char *orighost, |
1266 | struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms) | 1252 | struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms) |
1267 | { | 1253 | { |
1268 | char *host, *cp; | 1254 | char *host; |
1269 | char *server_user, *local_user; | 1255 | char *server_user, *local_user; |
1270 | 1256 | ||
1271 | local_user = xstrdup(pw->pw_name); | 1257 | local_user = xstrdup(pw->pw_name); |
@@ -1273,9 +1259,7 @@ ssh_login(Sensitive *sensitive, const char *orighost, | |||
1273 | 1259 | ||
1274 | /* Convert the user-supplied hostname into all lowercase. */ | 1260 | /* Convert the user-supplied hostname into all lowercase. */ |
1275 | host = xstrdup(orighost); | 1261 | host = xstrdup(orighost); |
1276 | for (cp = host; *cp; cp++) | 1262 | lowercase(host); |
1277 | if (isupper(*cp)) | ||
1278 | *cp = (char)tolower(*cp); | ||
1279 | 1263 | ||
1280 | /* Exchange protocol version identification strings with the server. */ | 1264 | /* Exchange protocol version identification strings with the server. */ |
1281 | ssh_exchange_identification(timeout_ms); | 1265 | ssh_exchange_identification(timeout_ms); |
diff --git a/sshconnect.h b/sshconnect.h index fd7f7f7c6..0ea6e99f6 100644 --- a/sshconnect.h +++ b/sshconnect.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect.h,v 1.27 2010/11/29 23:45:51 djm Exp $ */ | 1 | /* $OpenBSD: sshconnect.h,v 1.28 2013/10/16 02:31:47 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
@@ -31,9 +31,9 @@ struct Sensitive { | |||
31 | int external_keysign; | 31 | int external_keysign; |
32 | }; | 32 | }; |
33 | 33 | ||
34 | int | 34 | struct addrinfo; |
35 | ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int, | 35 | int ssh_connect(const char *, struct addrinfo *, struct sockaddr_storage *, |
36 | int *, int, int, const char *); | 36 | u_short, int, int, int *, int, int); |
37 | void ssh_kill_proxy_command(void); | 37 | void ssh_kill_proxy_command(void); |
38 | 38 | ||
39 | void ssh_login(Sensitive *, const char *, struct sockaddr *, u_short, | 39 | void ssh_login(Sensitive *, const char *, struct sockaddr *, u_short, |