summaryrefslogtreecommitdiff
path: root/ssh.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2014-02-24 15:57:55 +1100
committerDamien Miller <djm@mindrot.org>2014-02-24 15:57:55 +1100
commit13f97b2286142fd0b8eab94e4ce84fe124eeb752 (patch)
treeb332b16a032b4670b60db1261b6dac48e059d916 /ssh.c
parentbee3a234f3d1ad4244952bcff1b4b7c525330dc2 (diff)
- djm@cvs.openbsd.org 2014/02/23 20:11:36
[readconf.c readconf.h ssh.c ssh_config.5] reparse ssh_config and ~/.ssh/config if hostname canonicalisation changes the hostname. This allows users to write configurations that always refer to canonical hostnames, e.g. CanonicalizeHostname yes CanonicalDomains int.example.org example.org CanonicalizeFallbackLocal no Host *.int.example.org Compression off Host *.example.org User djm ok markus@
Diffstat (limited to 'ssh.c')
-rw-r--r--ssh.c150
1 files changed, 94 insertions, 56 deletions
diff --git a/ssh.c b/ssh.c
index add760ca8..b7dbea2b6 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh.c,v 1.399 2014/02/04 00:24:29 djm Exp $ */ 1/* $OpenBSD: ssh.c,v 1.400 2014/02/23 20:11:36 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,16 +231,26 @@ tilde_expand_paths(char **paths, u_int num_paths)
231 } 231 }
232} 232}
233 233
234/*
235 * Attempt to resolve a host name / port to a set of addresses and
236 * optionally return any CNAMEs encountered along the way.
237 * Returns NULL on failure.
238 * NB. this function must operate with a options having undefined members.
239 */
234static struct addrinfo * 240static struct addrinfo *
235resolve_host(const char *name, u_int port, int logerr, char *cname, size_t clen) 241resolve_host(const char *name, int port, int logerr, char *cname, size_t clen)
236{ 242{
237 char strport[NI_MAXSERV]; 243 char strport[NI_MAXSERV];
238 struct addrinfo hints, *res; 244 struct addrinfo hints, *res;
239 int gaierr, loglevel = SYSLOG_LEVEL_DEBUG1; 245 int gaierr, loglevel = SYSLOG_LEVEL_DEBUG1;
240 246
247 if (port <= 0)
248 port = default_ssh_port();
249
241 snprintf(strport, sizeof strport, "%u", port); 250 snprintf(strport, sizeof strport, "%u", port);
242 memset(&hints, 0, sizeof(hints)); 251 memset(&hints, 0, sizeof(hints));
243 hints.ai_family = options.address_family; 252 hints.ai_family = options.address_family == -1 ?
253 AF_UNSPEC : options.address_family;
244 hints.ai_socktype = SOCK_STREAM; 254 hints.ai_socktype = SOCK_STREAM;
245 if (cname != NULL) 255 if (cname != NULL)
246 hints.ai_flags = AI_CANONNAME; 256 hints.ai_flags = AI_CANONNAME;
@@ -265,6 +275,7 @@ resolve_host(const char *name, u_int port, int logerr, char *cname, size_t clen)
265/* 275/*
266 * Check whether the cname is a permitted replacement for the hostname 276 * Check whether the cname is a permitted replacement for the hostname
267 * and perform the replacement if it is. 277 * and perform the replacement if it is.
278 * NB. this function must operate with a options having undefined members.
268 */ 279 */
269static int 280static int
270check_follow_cname(char **namep, const char *cname) 281check_follow_cname(char **namep, const char *cname)
@@ -281,7 +292,7 @@ check_follow_cname(char **namep, const char *cname)
281 * Don't attempt to canonicalize names that will be interpreted by 292 * Don't attempt to canonicalize names that will be interpreted by
282 * a proxy unless the user specifically requests so. 293 * a proxy unless the user specifically requests so.
283 */ 294 */
284 if (options.proxy_command != NULL && 295 if (!option_clear_or_none(options.proxy_command) &&
285 options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) 296 options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
286 return 0; 297 return 0;
287 debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname); 298 debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname);
@@ -305,9 +316,10 @@ check_follow_cname(char **namep, const char *cname)
305 * Attempt to resolve the supplied hostname after applying the user's 316 * Attempt to resolve the supplied hostname after applying the user's
306 * canonicalization rules. Returns the address list for the host or NULL 317 * canonicalization rules. Returns the address list for the host or NULL
307 * if no name was found after canonicalization. 318 * if no name was found after canonicalization.
319 * NB. this function must operate with a options having undefined members.
308 */ 320 */
309static struct addrinfo * 321static struct addrinfo *
310resolve_canonicalize(char **hostp, u_int port) 322resolve_canonicalize(char **hostp, int port)
311{ 323{
312 int i, ndots; 324 int i, ndots;
313 char *cp, *fullhost, cname_target[NI_MAXHOST]; 325 char *cp, *fullhost, cname_target[NI_MAXHOST];
@@ -315,13 +327,15 @@ resolve_canonicalize(char **hostp, u_int port)
315 327
316 if (options.canonicalize_hostname == SSH_CANONICALISE_NO) 328 if (options.canonicalize_hostname == SSH_CANONICALISE_NO)
317 return NULL; 329 return NULL;
330
318 /* 331 /*
319 * Don't attempt to canonicalize names that will be interpreted by 332 * Don't attempt to canonicalize names that will be interpreted by
320 * a proxy unless the user specifically requests so. 333 * a proxy unless the user specifically requests so.
321 */ 334 */
322 if (options.proxy_command != NULL && 335 if (!option_clear_or_none(options.proxy_command) &&
323 options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) 336 options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
324 return NULL; 337 return NULL;
338
325 /* Don't apply canonicalization to sufficiently-qualified hostnames */ 339 /* Don't apply canonicalization to sufficiently-qualified hostnames */
326 ndots = 0; 340 ndots = 0;
327 for (cp = *hostp; *cp != '\0'; cp++) { 341 for (cp = *hostp; *cp != '\0'; cp++) {
@@ -338,7 +352,9 @@ resolve_canonicalize(char **hostp, u_int port)
338 *cname_target = '\0'; 352 *cname_target = '\0';
339 xasprintf(&fullhost, "%s.%s.", *hostp, 353 xasprintf(&fullhost, "%s.%s.", *hostp,
340 options.canonical_domains[i]); 354 options.canonical_domains[i]);
341 if ((addrs = resolve_host(fullhost, options.port, 0, 355 debug3("%s: attempting \"%s\" => \"%s\"", __func__,
356 *hostp, fullhost);
357 if ((addrs = resolve_host(fullhost, port, 0,
342 cname_target, sizeof(cname_target))) == NULL) { 358 cname_target, sizeof(cname_target))) == NULL) {
343 free(fullhost); 359 free(fullhost);
344 continue; 360 continue;
@@ -355,11 +371,41 @@ resolve_canonicalize(char **hostp, u_int port)
355 return addrs; 371 return addrs;
356 } 372 }
357 if (!options.canonicalize_fallback_local) 373 if (!options.canonicalize_fallback_local)
358 fatal("%s: Could not resolve host \"%s\"", __progname, host); 374 fatal("%s: Could not resolve host \"%s\"", __progname, *hostp);
375 debug2("%s: host %s not found in any suffix", __func__, *hostp);
359 return NULL; 376 return NULL;
360} 377}
361 378
362/* 379/*
380 * Read per-user configuration file. Ignore the system wide config
381 * file if the user specifies a config file on the command line.
382 */
383static void
384process_config_files(struct passwd *pw)
385{
386 char buf[MAXPATHLEN];
387 int r;
388
389 if (config != NULL) {
390 if (strcasecmp(config, "none") != 0 &&
391 !read_config_file(config, pw, host, &options,
392 SSHCONF_USERCONF))
393 fatal("Can't open user config file %.100s: "
394 "%.100s", config, strerror(errno));
395 } else {
396 r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
397 _PATH_SSH_USER_CONFFILE);
398 if (r > 0 && (size_t)r < sizeof(buf))
399 (void)read_config_file(buf, pw, host, &options,
400 SSHCONF_CHECKPERM|SSHCONF_USERCONF);
401
402 /* Read systemwide configuration file after user config. */
403 (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, host,
404 &options, 0);
405 }
406}
407
408/*
363 * Main program for the ssh client. 409 * Main program for the ssh client.
364 */ 410 */
365int 411int
@@ -832,31 +878,54 @@ main(int ac, char **av)
832 if (debug_flag) 878 if (debug_flag)
833 logit("%s, %s", SSH_VERSION, SSLeay_version(SSLEAY_VERSION)); 879 logit("%s, %s", SSH_VERSION, SSLeay_version(SSLEAY_VERSION));
834 880
881 /* Parse the configuration files */
882 process_config_files(pw);
883
884 /* Hostname canonicalisation needs a few options filled. */
885 fill_default_options_for_canonicalization(&options);
886
887 /* If the user has replaced the hostname then take it into use now */
888 if (options.hostname != NULL) {
889 /* NB. Please keep in sync with readconf.c:match_cfg_line() */
890 cp = percent_expand(options.hostname,
891 "h", host, (char *)NULL);
892 free(host);
893 host = cp;
894 }
895
896 /* If canonicalization requested then try to apply it */
897 lowercase(host);
898 if (options.canonicalize_hostname != SSH_CANONICALISE_NO)
899 addrs = resolve_canonicalize(&host, options.port);
900
835 /* 901 /*
836 * Read per-user configuration file. Ignore the system wide config 902 * If canonicalization not requested, or if it failed then try to
837 * file if the user specifies a config file on the command line. 903 * resolve the bare hostname name using the system resolver's usual
904 * search rules. Skip the lookup if a ProxyCommand is being used
905 * unless the user has specifically requested canonicalisation.
838 */ 906 */
839 if (config != NULL) { 907 if (addrs == NULL && (option_clear_or_none(options.proxy_command) ||
840 if (strcasecmp(config, "none") != 0 && 908 options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) {
841 !read_config_file(config, pw, host, &options, 909 if ((addrs = resolve_host(host, options.port, 1,
842 SSHCONF_USERCONF)) 910 cname, sizeof(cname))) == NULL)
843 fatal("Can't open user config file %.100s: " 911 cleanup_exit(255); /* resolve_host logs the error */
844 "%.100s", config, strerror(errno)); 912 check_follow_cname(&host, cname);
845 } else { 913 }
846 r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
847 _PATH_SSH_USER_CONFFILE);
848 if (r > 0 && (size_t)r < sizeof(buf))
849 (void)read_config_file(buf, pw, host, &options,
850 SSHCONF_CHECKPERM|SSHCONF_USERCONF);
851 914
852 /* Read systemwide configuration file after user config. */ 915 /*
853 (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, host, 916 * If the target hostname has changed as a result of canonicalisation
854 &options, 0); 917 * then re-parse the configuration files as new stanzas may match.
918 */
919 if (strcasecmp(host_arg, host) != 0) {
920 debug("Hostname has changed; re-reading configuration");
921 process_config_files(pw);
855 } 922 }
856 923
857 /* Fill configuration defaults. */ 924 /* Fill configuration defaults. */
858 fill_default_options(&options); 925 fill_default_options(&options);
859 926
927 if (options.port == 0)
928 options.port = default_ssh_port();
860 channel_set_af(options.address_family); 929 channel_set_af(options.address_family);
861 930
862 /* Tidy and check options */ 931 /* Tidy and check options */
@@ -899,37 +968,6 @@ main(int ac, char **av)
899 if (options.user == NULL) 968 if (options.user == NULL)
900 options.user = xstrdup(pw->pw_name); 969 options.user = xstrdup(pw->pw_name);
901 970
902 /* Get default port if port has not been set. */
903 if (options.port == 0)
904 options.port = default_ssh_port();
905
906 /* preserve host name given on command line for %n expansion */
907 if (options.hostname != NULL) {
908 /* NB. Please keep in sync with readconf.c:match_cfg_line() */
909 cp = percent_expand(options.hostname,
910 "h", host, (char *)NULL);
911 free(host);
912 host = cp;
913 }
914
915 /* If canonicalization requested then try to apply it */
916 lowercase(host);
917 if (options.canonicalize_hostname != SSH_CANONICALISE_NO)
918 addrs = resolve_canonicalize(&host, options.port);
919 /*
920 * If canonicalization not requested, or if it failed then try to
921 * resolve the bare hostname name using the system resolver's usual
922 * search rules. Skip the lookup if a ProxyCommand is being used
923 * unless the user has specifically requested canonicalisation.
924 */
925 if (addrs == NULL && (options.proxy_command == NULL ||
926 options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) {
927 if ((addrs = resolve_host(host, options.port, 1,
928 cname, sizeof(cname))) == NULL)
929 cleanup_exit(255); /* resolve_host logs the error */
930 check_follow_cname(&host, cname);
931 }
932
933 if (gethostname(thishost, sizeof(thishost)) == -1) 971 if (gethostname(thishost, sizeof(thishost)) == -1)
934 fatal("gethostname: %s", strerror(errno)); 972 fatal("gethostname: %s", strerror(errno));
935 strlcpy(shorthost, thishost, sizeof(shorthost)); 973 strlcpy(shorthost, thishost, sizeof(shorthost));