summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2014-10-08 22:20:25 +0000
committerDamien Miller <djm@mindrot.org>2014-10-13 11:41:48 +1100
commit957fbceb0f3166e41b76fdb54075ab3b9cc84cba (patch)
tree7c8bc1f0090201400383e51d84a7fda79995e513
parent5c0dafd38bf66feeeb45fa0741a5baf5ad8039ba (diff)
upstream commit
Tweak config reparsing with host canonicalisation Make the second pass through the config files always run when hostname canonicalisation is enabled. Add a "Match canonical" criteria that allows ssh_config Match blocks to trigger only in the second config pass. Add a -G option to ssh that causes it to parse its configuration and dump the result to stdout, similar to "sshd -T" Allow ssh_config Port options set in the second config parse phase to be applied (they were being ignored). bz#2267 bz#2286; ok markus
-rw-r--r--readconf.c450
-rw-r--r--readconf.h10
-rw-r--r--ssh-keysign.c4
-rw-r--r--ssh.114
-rw-r--r--ssh.c80
-rw-r--r--ssh_config.555
6 files changed, 504 insertions, 109 deletions
diff --git a/readconf.c b/readconf.c
index 7948ce1cd..869a1c4d8 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.c,v 1.220 2014/07/15 15:54:14 millert Exp $ */ 1/* $OpenBSD: readconf.c,v 1.221 2014/10/08 22:20:25 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
@@ -41,6 +41,9 @@
41#ifdef HAVE_UTIL_H 41#ifdef HAVE_UTIL_H
42#include <util.h> 42#include <util.h>
43#endif 43#endif
44#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
45# include <vis.h>
46#endif
44 47
45#include "xmalloc.h" 48#include "xmalloc.h"
46#include "ssh.h" 49#include "ssh.h"
@@ -56,6 +59,7 @@
56#include "kex.h" 59#include "kex.h"
57#include "mac.h" 60#include "mac.h"
58#include "uidswap.h" 61#include "uidswap.h"
62#include "myproposal.h"
59 63
60/* Format of the configuration file: 64/* Format of the configuration file:
61 65
@@ -135,7 +139,7 @@ typedef enum {
135 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, 139 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
136 oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts, 140 oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
137 oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs, 141 oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
138 oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, 142 oPubkeyAuthentication,
139 oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, 143 oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
140 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, 144 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
141 oHostKeyAlgorithms, oBindAddress, oPKCS11Provider, 145 oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
@@ -212,7 +216,7 @@ static struct {
212 { "globalknownhostsfile", oGlobalKnownHostsFile }, 216 { "globalknownhostsfile", oGlobalKnownHostsFile },
213 { "globalknownhostsfile2", oDeprecated }, 217 { "globalknownhostsfile2", oDeprecated },
214 { "userknownhostsfile", oUserKnownHostsFile }, 218 { "userknownhostsfile", oUserKnownHostsFile },
215 { "userknownhostsfile2", oDeprecated }, 219 { "userknownhostsfile2", oDeprecated },
216 { "connectionattempts", oConnectionAttempts }, 220 { "connectionattempts", oConnectionAttempts },
217 { "batchmode", oBatchMode }, 221 { "batchmode", oBatchMode },
218 { "checkhostip", oCheckHostIP }, 222 { "checkhostip", oCheckHostIP },
@@ -466,7 +470,7 @@ execute_in_shell(const char *cmd)
466 if (!WIFEXITED(status)) { 470 if (!WIFEXITED(status)) {
467 error("command '%.100s' exited abnormally", cmd); 471 error("command '%.100s' exited abnormally", cmd);
468 return -1; 472 return -1;
469 } 473 }
470 debug3("command returned status %d", WEXITSTATUS(status)); 474 debug3("command returned status %d", WEXITSTATUS(status));
471 return WEXITSTATUS(status); 475 return WEXITSTATUS(status);
472} 476}
@@ -476,11 +480,12 @@ execute_in_shell(const char *cmd)
476 */ 480 */
477static int 481static int
478match_cfg_line(Options *options, char **condition, struct passwd *pw, 482match_cfg_line(Options *options, char **condition, struct passwd *pw,
479 const char *host_arg, const char *filename, int linenum) 483 const char *host_arg, const char *original_host, int post_canon,
484 const char *filename, int linenum)
480{ 485{
481 char *arg, *attrib, *cmd, *cp = *condition, *host; 486 char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
482 const char *ruser; 487 const char *ruser;
483 int r, port, result = 1, attributes = 0; 488 int r, port, this_result, result = 1, attributes = 0, negate;
484 size_t len; 489 size_t len;
485 char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; 490 char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
486 491
@@ -497,21 +502,38 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
497 } else 502 } else
498 host = xstrdup(host_arg); 503 host = xstrdup(host_arg);
499 504
500 debug3("checking match for '%s' host %s", cp, host); 505 debug2("checking match for '%s' host %s originally %s",
501 while ((attrib = strdelim(&cp)) && *attrib != '\0') { 506 cp, host, original_host);
502 attributes++; 507 while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') {
508 criteria = NULL;
509 this_result = 1;
510 if ((negate = attrib[0] == '!'))
511 attrib++;
512 /* criteria "all" and "canonical" have no argument */
503 if (strcasecmp(attrib, "all") == 0) { 513 if (strcasecmp(attrib, "all") == 0) {
504 if (attributes != 1 || 514 if (attributes > 1 ||
505 ((arg = strdelim(&cp)) != NULL && *arg != '\0')) { 515 ((arg = strdelim(&cp)) != NULL && *arg != '\0')) {
506 error("'all' cannot be combined with other " 516 error("%.200s line %d: '%s' cannot be combined "
507 "Match attributes"); 517 "with other Match attributes",
518 filename, linenum, oattrib);
508 result = -1; 519 result = -1;
509 goto out; 520 goto out;
510 } 521 }
511 *condition = cp; 522 if (result)
512 result = 1; 523 result = negate ? 0 : 1;
513 goto out; 524 goto out;
514 } 525 }
526 attributes++;
527 if (strcasecmp(attrib, "canonical") == 0) {
528 r = !!post_canon; /* force bitmask member to boolean */
529 if (r == (negate ? 1 : 0))
530 this_result = result = 0;
531 debug3("%.200s line %d: %smatched '%s'",
532 filename, linenum,
533 this_result ? "" : "not ", oattrib);
534 continue;
535 }
536 /* All other criteria require an argument */
515 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') { 537 if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
516 error("Missing Match criteria for %s", attrib); 538 error("Missing Match criteria for %s", attrib);
517 result = -1; 539 result = -1;
@@ -519,31 +541,25 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
519 } 541 }
520 len = strlen(arg); 542 len = strlen(arg);
521 if (strcasecmp(attrib, "host") == 0) { 543 if (strcasecmp(attrib, "host") == 0) {
522 if (match_hostname(host, arg, len) != 1) 544 criteria = xstrdup(host);
523 result = 0; 545 r = match_hostname(host, arg, len) == 1;
524 else 546 if (r == (negate ? 1 : 0))
525 debug("%.200s line %d: matched 'Host %.100s' ", 547 this_result = result = 0;
526 filename, linenum, host);
527 } else if (strcasecmp(attrib, "originalhost") == 0) { 548 } else if (strcasecmp(attrib, "originalhost") == 0) {
528 if (match_hostname(host_arg, arg, len) != 1) 549 criteria = xstrdup(original_host);
529 result = 0; 550 r = match_hostname(original_host, arg, len) == 1;
530 else 551 if (r == (negate ? 1 : 0))
531 debug("%.200s line %d: matched " 552 this_result = result = 0;
532 "'OriginalHost %.100s' ",
533 filename, linenum, host_arg);
534 } else if (strcasecmp(attrib, "user") == 0) { 553 } else if (strcasecmp(attrib, "user") == 0) {
535 if (match_pattern_list(ruser, arg, len, 0) != 1) 554 criteria = xstrdup(ruser);
536 result = 0; 555 r = match_pattern_list(ruser, arg, len, 0) == 1;
537 else 556 if (r == (negate ? 1 : 0))
538 debug("%.200s line %d: matched 'User %.100s' ", 557 this_result = result = 0;
539 filename, linenum, ruser);
540 } else if (strcasecmp(attrib, "localuser") == 0) { 558 } else if (strcasecmp(attrib, "localuser") == 0) {
541 if (match_pattern_list(pw->pw_name, arg, len, 0) != 1) 559 criteria = xstrdup(pw->pw_name);
542 result = 0; 560 r = match_pattern_list(pw->pw_name, arg, len, 0) == 1;
543 else 561 if (r == (negate ? 1 : 0))
544 debug("%.200s line %d: matched " 562 this_result = result = 0;
545 "'LocalUser %.100s' ",
546 filename, linenum, pw->pw_name);
547 } else if (strcasecmp(attrib, "exec") == 0) { 563 } else if (strcasecmp(attrib, "exec") == 0) {
548 if (gethostname(thishost, sizeof(thishost)) == -1) 564 if (gethostname(thishost, sizeof(thishost)) == -1)
549 fatal("gethostname: %s", strerror(errno)); 565 fatal("gethostname: %s", strerror(errno));
@@ -556,47 +572,49 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
556 "d", pw->pw_dir, 572 "d", pw->pw_dir,
557 "h", host, 573 "h", host,
558 "l", thishost, 574 "l", thishost,
559 "n", host_arg, 575 "n", original_host,
560 "p", portstr, 576 "p", portstr,
561 "r", ruser, 577 "r", ruser,
562 "u", pw->pw_name, 578 "u", pw->pw_name,
563 (char *)NULL); 579 (char *)NULL);
564 if (result != 1) { 580 if (result != 1) {
565 /* skip execution if prior predicate failed */ 581 /* skip execution if prior predicate failed */
566 debug("%.200s line %d: skipped exec \"%.100s\"", 582 debug3("%.200s line %d: skipped exec "
567 filename, linenum, cmd); 583 "\"%.100s\"", filename, linenum, cmd);
568 } else { 584 free(cmd);
569 r = execute_in_shell(cmd); 585 continue;
570 if (r == -1) { 586 }
571 fatal("%.200s line %d: match exec " 587 r = execute_in_shell(cmd);
572 "'%.100s' error", filename, 588 if (r == -1) {
573 linenum, cmd); 589 fatal("%.200s line %d: match exec "
574 } else if (r == 0) { 590 "'%.100s' error", filename,
575 debug("%.200s line %d: matched " 591 linenum, cmd);
576 "'exec \"%.100s\"'", filename,
577 linenum, cmd);
578 } else {
579 debug("%.200s line %d: no match "
580 "'exec \"%.100s\"'", filename,
581 linenum, cmd);
582 result = 0;
583 }
584 } 592 }
593 criteria = xstrdup(cmd);
585 free(cmd); 594 free(cmd);
595 /* Force exit status to boolean */
596 r = r == 0;
597 if (r == (negate ? 1 : 0))
598 this_result = result = 0;
586 } else { 599 } else {
587 error("Unsupported Match attribute %s", attrib); 600 error("Unsupported Match attribute %s", attrib);
588 result = -1; 601 result = -1;
589 goto out; 602 goto out;
590 } 603 }
604 debug3("%.200s line %d: %smatched '%s \"%.100s\"' ",
605 filename, linenum, this_result ? "": "not ",
606 oattrib, criteria);
607 free(criteria);
591 } 608 }
592 if (attributes == 0) { 609 if (attributes == 0) {
593 error("One or more attributes required for Match"); 610 error("One or more attributes required for Match");
594 result = -1; 611 result = -1;
595 goto out; 612 goto out;
596 } 613 }
597 debug3("match %sfound", result ? "" : "not ");
598 *condition = cp;
599 out: 614 out:
615 if (result != -1)
616 debug2("match %sfound", result ? "" : "not ");
617 *condition = cp;
600 free(host); 618 free(host);
601 return result; 619 return result;
602} 620}
@@ -719,7 +737,8 @@ static const struct multistate multistate_canonicalizehostname[] = {
719#define WHITESPACE " \t\r\n" 737#define WHITESPACE " \t\r\n"
720int 738int
721process_config_line(Options *options, struct passwd *pw, const char *host, 739process_config_line(Options *options, struct passwd *pw, const char *host,
722 char *line, const char *filename, int linenum, int *activep, int userconfig) 740 const char *original_host, char *line, const char *filename,
741 int linenum, int *activep, int flags)
723{ 742{
724 char *s, **charptr, *endofnumber, *keyword, *arg, *arg2; 743 char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
725 char **cpptr, fwdarg[256]; 744 char **cpptr, fwdarg[256];
@@ -775,7 +794,9 @@ parse_time:
775 if (!arg || *arg == '\0') 794 if (!arg || *arg == '\0')
776 fatal("%s line %d: missing time value.", 795 fatal("%s line %d: missing time value.",
777 filename, linenum); 796 filename, linenum);
778 if ((value = convtime(arg)) == -1) 797 if (strcmp(arg, "none") == 0)
798 value = -1;
799 else if ((value = convtime(arg)) == -1)
779 fatal("%s line %d: invalid time value.", 800 fatal("%s line %d: invalid time value.",
780 filename, linenum); 801 filename, linenum);
781 if (*activep && *intptr == -1) 802 if (*activep && *intptr == -1)
@@ -812,7 +833,7 @@ parse_time:
812 case oForwardX11Trusted: 833 case oForwardX11Trusted:
813 intptr = &options->forward_x11_trusted; 834 intptr = &options->forward_x11_trusted;
814 goto parse_flag; 835 goto parse_flag;
815 836
816 case oForwardX11Timeout: 837 case oForwardX11Timeout:
817 intptr = &options->forward_x11_timeout; 838 intptr = &options->forward_x11_timeout;
818 goto parse_time; 839 goto parse_time;
@@ -947,7 +968,8 @@ parse_time:
947 if (*intptr >= SSH_MAX_IDENTITY_FILES) 968 if (*intptr >= SSH_MAX_IDENTITY_FILES)
948 fatal("%.200s line %d: Too many identity files specified (max %d).", 969 fatal("%.200s line %d: Too many identity files specified (max %d).",
949 filename, linenum, SSH_MAX_IDENTITY_FILES); 970 filename, linenum, SSH_MAX_IDENTITY_FILES);
950 add_identity_file(options, NULL, arg, userconfig); 971 add_identity_file(options, NULL,
972 arg, flags & SSHCONF_USERCONF);
951 } 973 }
952 break; 974 break;
953 975
@@ -1195,8 +1217,8 @@ parse_int:
1195 if (cmdline) 1217 if (cmdline)
1196 fatal("Host directive not supported as a command-line " 1218 fatal("Host directive not supported as a command-line "
1197 "option"); 1219 "option");
1198 value = match_cfg_line(options, &s, pw, host, 1220 value = match_cfg_line(options, &s, pw, host, original_host,
1199 filename, linenum); 1221 flags & SSHCONF_POSTCANON, filename, linenum);
1200 if (value < 0) 1222 if (value < 0)
1201 fatal("%.200s line %d: Bad Match condition", filename, 1223 fatal("%.200s line %d: Bad Match condition", filename,
1202 linenum); 1224 linenum);
@@ -1444,7 +1466,7 @@ parse_int:
1444 return 0; 1466 return 0;
1445 1467
1446 default: 1468 default:
1447 fatal("process_config_line: Unimplemented opcode %d", opcode); 1469 fatal("%s: Unimplemented opcode %d", __func__, opcode);
1448 } 1470 }
1449 1471
1450 /* Check that there is no garbage at end of line. */ 1472 /* Check that there is no garbage at end of line. */
@@ -1464,7 +1486,7 @@ parse_int:
1464 1486
1465int 1487int
1466read_config_file(const char *filename, struct passwd *pw, const char *host, 1488read_config_file(const char *filename, struct passwd *pw, const char *host,
1467 Options *options, int flags) 1489 const char *original_host, Options *options, int flags)
1468{ 1490{
1469 FILE *f; 1491 FILE *f;
1470 char line[1024]; 1492 char line[1024];
@@ -1495,8 +1517,8 @@ read_config_file(const char *filename, struct passwd *pw, const char *host,
1495 while (fgets(line, sizeof(line), f)) { 1517 while (fgets(line, sizeof(line), f)) {
1496 /* Update line number counter. */ 1518 /* Update line number counter. */
1497 linenum++; 1519 linenum++;
1498 if (process_config_line(options, pw, host, line, filename, 1520 if (process_config_line(options, pw, host, original_host,
1499 linenum, &active, flags & SSHCONF_USERCONF) != 0) 1521 line, filename, linenum, &active, flags) != 0)
1500 bad_options++; 1522 bad_options++;
1501 } 1523 }
1502 fclose(f); 1524 fclose(f);
@@ -2009,3 +2031,295 @@ parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remo
2009 fwd->listen_path = NULL; 2031 fwd->listen_path = NULL;
2010 return (0); 2032 return (0);
2011} 2033}
2034
2035/* XXX the following is a near-vebatim copy from servconf.c; refactor */
2036static const char *
2037fmt_multistate_int(int val, const struct multistate *m)
2038{
2039 u_int i;
2040
2041 for (i = 0; m[i].key != NULL; i++) {
2042 if (m[i].value == val)
2043 return m[i].key;
2044 }
2045 return "UNKNOWN";
2046}
2047
2048static const char *
2049fmt_intarg(OpCodes code, int val)
2050{
2051 if (val == -1)
2052 return "unset";
2053 switch (code) {
2054 case oAddressFamily:
2055 return fmt_multistate_int(val, multistate_addressfamily);
2056 case oVerifyHostKeyDNS:
2057 case oStrictHostKeyChecking:
2058 return fmt_multistate_int(val, multistate_yesnoask);
2059 case oControlMaster:
2060 return fmt_multistate_int(val, multistate_controlmaster);
2061 case oTunnel:
2062 return fmt_multistate_int(val, multistate_tunnel);
2063 case oRequestTTY:
2064 return fmt_multistate_int(val, multistate_requesttty);
2065 case oCanonicalizeHostname:
2066 return fmt_multistate_int(val, multistate_canonicalizehostname);
2067 case oProtocol:
2068 switch (val) {
2069 case SSH_PROTO_1:
2070 return "1";
2071 case SSH_PROTO_2:
2072 return "2";
2073 case (SSH_PROTO_1|SSH_PROTO_2):
2074 return "2,1";
2075 default:
2076 return "UNKNOWN";
2077 }
2078 default:
2079 switch (val) {
2080 case 0:
2081 return "no";
2082 case 1:
2083 return "yes";
2084 default:
2085 return "UNKNOWN";
2086 }
2087 }
2088}
2089
2090static const char *
2091lookup_opcode_name(OpCodes code)
2092{
2093 u_int i;
2094
2095 for (i = 0; keywords[i].name != NULL; i++)
2096 if (keywords[i].opcode == code)
2097 return(keywords[i].name);
2098 return "UNKNOWN";
2099}
2100
2101static void
2102dump_cfg_int(OpCodes code, int val)
2103{
2104 printf("%s %d\n", lookup_opcode_name(code), val);
2105}
2106
2107static void
2108dump_cfg_fmtint(OpCodes code, int val)
2109{
2110 printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
2111}
2112
2113static void
2114dump_cfg_string(OpCodes code, const char *val)
2115{
2116 if (val == NULL)
2117 return;
2118 printf("%s %s\n", lookup_opcode_name(code), val);
2119}
2120
2121static void
2122dump_cfg_strarray(OpCodes code, u_int count, char **vals)
2123{
2124 u_int i;
2125
2126 for (i = 0; i < count; i++)
2127 printf("%s %s\n", lookup_opcode_name(code), vals[i]);
2128}
2129
2130static void
2131dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
2132{
2133 u_int i;
2134
2135 printf("%s", lookup_opcode_name(code));
2136 for (i = 0; i < count; i++)
2137 printf(" %s", vals[i]);
2138 printf("\n");
2139}
2140
2141static void
2142dump_cfg_forwards(OpCodes code, u_int count, const struct Forward *fwds)
2143{
2144 const struct Forward *fwd;
2145 u_int i;
2146
2147 /* oDynamicForward */
2148 for (i = 0; i < count; i++) {
2149 fwd = &fwds[i];
2150 if (code == oDynamicForward &&
2151 strcmp(fwd->connect_host, "socks") != 0)
2152 continue;
2153 if (code == oLocalForward &&
2154 strcmp(fwd->connect_host, "socks") == 0)
2155 continue;
2156 printf("%s", lookup_opcode_name(code));
2157 if (fwd->listen_port == PORT_STREAMLOCAL)
2158 printf(" %s", fwd->listen_path);
2159 else if (fwd->listen_host == NULL)
2160 printf(" %d", fwd->listen_port);
2161 else {
2162 printf(" [%s]:%d",
2163 fwd->listen_host, fwd->listen_port);
2164 }
2165 if (code != oDynamicForward) {
2166 if (fwd->connect_port == PORT_STREAMLOCAL)
2167 printf(" %s", fwd->connect_path);
2168 else if (fwd->connect_host == NULL)
2169 printf(" %d", fwd->connect_port);
2170 else {
2171 printf(" [%s]:%d",
2172 fwd->connect_host, fwd->connect_port);
2173 }
2174 }
2175 printf("\n");
2176 }
2177}
2178
2179void
2180dump_client_config(Options *o, const char *host)
2181{
2182 int i;
2183 char vbuf[5];
2184
2185 /* Most interesting options first: user, host, port */
2186 dump_cfg_string(oUser, o->user);
2187 dump_cfg_string(oHostName, host);
2188 dump_cfg_int(oPort, o->port);
2189
2190 /* Flag options */
2191 dump_cfg_fmtint(oAddressFamily, o->address_family);
2192 dump_cfg_fmtint(oBatchMode, o->batch_mode);
2193 dump_cfg_fmtint(oCanonicalizeFallbackLocal, o->canonicalize_fallback_local);
2194 dump_cfg_fmtint(oCanonicalizeHostname, o->canonicalize_hostname);
2195 dump_cfg_fmtint(oChallengeResponseAuthentication, o->challenge_response_authentication);
2196 dump_cfg_fmtint(oCheckHostIP, o->check_host_ip);
2197 dump_cfg_fmtint(oCompression, o->compression);
2198 dump_cfg_fmtint(oControlMaster, o->control_master);
2199 dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
2200 dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
2201 dump_cfg_fmtint(oForwardAgent, o->forward_agent);
2202 dump_cfg_fmtint(oForwardX11, o->forward_x11);
2203 dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
2204 dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports);
2205#ifdef GSSAPI
2206 dump_cfg_fmtint(oGssAuthentication, o->gss_authentication);
2207 dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds);
2208#endif /* GSSAPI */
2209 dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts);
2210 dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication);
2211 dump_cfg_fmtint(oIdentitiesOnly, o->identities_only);
2212 dump_cfg_fmtint(oKbdInteractiveAuthentication, o->kbd_interactive_authentication);
2213 dump_cfg_fmtint(oNoHostAuthenticationForLocalhost, o->no_host_authentication_for_localhost);
2214 dump_cfg_fmtint(oPasswordAuthentication, o->password_authentication);
2215 dump_cfg_fmtint(oPermitLocalCommand, o->permit_local_command);
2216 dump_cfg_fmtint(oProtocol, o->protocol);
2217 dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass);
2218 dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
2219 dump_cfg_fmtint(oRequestTTY, o->request_tty);
2220 dump_cfg_fmtint(oRhostsRSAAuthentication, o->rhosts_rsa_authentication);
2221 dump_cfg_fmtint(oRSAAuthentication, o->rsa_authentication);
2222 dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
2223 dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
2224 dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);
2225 dump_cfg_fmtint(oTunnel, o->tun_open);
2226 dump_cfg_fmtint(oUsePrivilegedPort, o->use_privileged_port);
2227 dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns);
2228 dump_cfg_fmtint(oVisualHostKey, o->visual_host_key);
2229
2230 /* Integer options */
2231 dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots);
2232 dump_cfg_int(oCompressionLevel, o->compression_level);
2233 dump_cfg_int(oConnectionAttempts, o->connection_attempts);
2234 dump_cfg_int(oForwardX11Timeout, o->forward_x11_timeout);
2235 dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
2236 dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
2237 dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
2238
2239 /* String options */
2240 dump_cfg_string(oBindAddress, o->bind_address);
2241 dump_cfg_string(oCiphers, o->ciphers ? o->ciphers : KEX_CLIENT_ENCRYPT);
2242 dump_cfg_string(oControlPath, o->control_path);
2243 dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms ? o->hostkeyalgorithms : KEX_DEFAULT_PK_ALG);
2244 dump_cfg_string(oHostKeyAlias, o->host_key_alias);
2245 dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
2246 dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX);
2247 dump_cfg_string(oLocalCommand, o->local_command);
2248 dump_cfg_string(oLogLevel, log_level_name(o->log_level));
2249 dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
2250 dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
2251 dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
2252 dump_cfg_string(oProxyCommand, o->proxy_command);
2253 dump_cfg_string(oXAuthLocation, o->xauth_location);
2254
2255 dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
2256 dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);
2257 dump_cfg_forwards(oRemoteForward, o->num_remote_forwards, o->remote_forwards);
2258
2259 /* String array options */
2260 dump_cfg_strarray(oIdentityFile, o->num_identity_files, o->identity_files);
2261 dump_cfg_strarray_oneline(oCanonicalDomains, o->num_canonical_domains, o->canonical_domains);
2262 dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
2263 dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
2264 dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
2265
2266 /* Special cases */
2267
2268 /* oConnectTimeout */
2269 if (o->connection_timeout == -1)
2270 printf("connecttimeout none\n");
2271 else
2272 dump_cfg_int(oConnectTimeout, o->connection_timeout);
2273
2274 /* oTunnelDevice */
2275 printf("tunneldevice");
2276 if (o->tun_local == SSH_TUNID_ANY)
2277 printf(" any");
2278 else
2279 printf(" %d", o->tun_local);
2280 if (o->tun_remote == SSH_TUNID_ANY)
2281 printf(":any");
2282 else
2283 printf(":%d", o->tun_remote);
2284 printf("\n");
2285
2286 /* oCanonicalizePermittedCNAMEs */
2287 if ( o->num_permitted_cnames > 0) {
2288 printf("canonicalizePermittedcnames");
2289 for (i = 0; i < o->num_permitted_cnames; i++) {
2290 printf(" %s:%s", o->permitted_cnames[i].source_list,
2291 o->permitted_cnames[i].target_list);
2292 }
2293 printf("\n");
2294 }
2295
2296 /* oCipher */
2297 if (o->cipher != SSH_CIPHER_NOT_SET)
2298 printf("Cipher %s\n", cipher_name(o->cipher));
2299
2300 /* oControlPersist */
2301 if (o->control_persist == 0 || o->control_persist_timeout == 0)
2302 dump_cfg_fmtint(oControlPersist, o->control_persist);
2303 else
2304 dump_cfg_int(oControlPersist, o->control_persist_timeout);
2305
2306 /* oEscapeChar */
2307 if (o->escape_char == SSH_ESCAPECHAR_NONE)
2308 printf("escapechar none\n");
2309 else {
2310 vis(vbuf, o->escape_char, VIS_WHITE, 0);
2311 printf("escapechar %s\n", vbuf);
2312 }
2313
2314 /* oIPQoS */
2315 printf("ipqos %s ", iptos2str(o->ip_qos_interactive));
2316 printf("%s\n", iptos2str(o->ip_qos_bulk));
2317
2318 /* oRekeyLimit */
2319 printf("rekeylimit %lld %d\n",
2320 (long long)o->rekey_limit, o->rekey_interval);
2321
2322 /* oStreamLocalBindMask */
2323 printf("streamlocalbindmask 0%o\n",
2324 o->fwd_opts.streamlocal_bind_mask);
2325}
diff --git a/readconf.h b/readconf.h
index 0b9cb777a..7b58d01f3 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.h,v 1.102 2014/07/15 15:54:14 millert Exp $ */ 1/* $OpenBSD: readconf.h,v 1.103 2014/10/08 22:20:25 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -164,17 +164,19 @@ typedef struct {
164 164
165#define SSHCONF_CHECKPERM 1 /* check permissions on config file */ 165#define SSHCONF_CHECKPERM 1 /* check permissions on config file */
166#define SSHCONF_USERCONF 2 /* user provided config file not system */ 166#define SSHCONF_USERCONF 2 /* user provided config file not system */
167#define SSHCONF_POSTCANON 4 /* After hostname canonicalisation */
167 168
168void initialize_options(Options *); 169void initialize_options(Options *);
169void fill_default_options(Options *); 170void fill_default_options(Options *);
170void fill_default_options_for_canonicalization(Options *); 171void fill_default_options_for_canonicalization(Options *);
171int process_config_line(Options *, struct passwd *, const char *, char *, 172int process_config_line(Options *, struct passwd *, const char *,
172 const char *, int, int *, int); 173 const char *, char *, const char *, int, int *, int);
173int read_config_file(const char *, struct passwd *, const char *, 174int read_config_file(const char *, struct passwd *, const char *,
174 Options *, int); 175 const char *, Options *, int);
175int parse_forward(struct Forward *, const char *, int, int); 176int parse_forward(struct Forward *, const char *, int, int);
176int default_ssh_port(void); 177int default_ssh_port(void);
177int option_clear_or_none(const char *); 178int option_clear_or_none(const char *);
179void dump_client_config(Options *o, const char *host);
178 180
179void add_local_forward(Options *, const struct Forward *); 181void add_local_forward(Options *, const struct Forward *);
180void add_remote_forward(Options *, const struct Forward *); 182void add_remote_forward(Options *, const struct Forward *);
diff --git a/ssh-keysign.c b/ssh-keysign.c
index d95bb7d9d..6b73319e0 100644
--- a/ssh-keysign.c
+++ b/ssh-keysign.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keysign.c,v 1.42 2014/04/29 18:01:49 markus Exp $ */ 1/* $OpenBSD: ssh-keysign.c,v 1.43 2014/10/08 22:20:25 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2002 Markus Friedl. All rights reserved. 3 * Copyright (c) 2002 Markus Friedl. All rights reserved.
4 * 4 *
@@ -187,7 +187,7 @@ main(int argc, char **argv)
187 187
188 /* verify that ssh-keysign is enabled by the admin */ 188 /* verify that ssh-keysign is enabled by the admin */
189 initialize_options(&options); 189 initialize_options(&options);
190 (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, "", &options, 0); 190 (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, "", "", &options, 0);
191 fill_default_options(&options); 191 fill_default_options(&options);
192 if (options.enable_ssh_keysign != 1) 192 if (options.enable_ssh_keysign != 1)
193 fatal("ssh-keysign not enabled in %s", 193 fatal("ssh-keysign not enabled in %s",
diff --git a/ssh.1 b/ssh.1
index 1c889b6c4..34fe635e4 100644
--- a/ssh.1
+++ b/ssh.1
@@ -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.349 2014/08/30 15:33:50 sobrado Exp $ 36.\" $OpenBSD: ssh.1,v 1.350 2014/10/08 22:20:25 djm Exp $
37.Dd $Mdocdate: August 30 2014 $ 37.Dd $Mdocdate: October 8 2014 $
38.Dt SSH 1 38.Dt SSH 1
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -43,7 +43,7 @@
43.Sh SYNOPSIS 43.Sh SYNOPSIS
44.Nm ssh 44.Nm ssh
45.Bk -words 45.Bk -words
46.Op Fl 1246AaCfgKkMNnqsTtVvXxYy 46.Op Fl 1246AaCfgGKkMNnqsTtVvXxYy
47.Op Fl b Ar bind_address 47.Op Fl b Ar bind_address
48.Op Fl c Ar cipher_spec 48.Op Fl c Ar cipher_spec
49.Op Fl D Oo Ar bind_address : Oc Ns Ar port 49.Op Fl D Oo Ar bind_address : Oc Ns Ar port
@@ -251,6 +251,14 @@ then a client started with
251.Fl f 251.Fl f
252will wait for all remote port forwards to be successfully established 252will wait for all remote port forwards to be successfully established
253before placing itself in the background. 253before placing itself in the background.
254.It Fl G
255Causes
256.Nm
257to print its configuration after evaluating
258.Cm Host
259and
260.Cm Match
261blocks and exit.
254.It Fl g 262.It Fl g
255Allows remote hosts to connect to local forwarded ports. 263Allows remote hosts to connect to local forwarded ports.
256If used on a multiplexed connection, then this option must be specified 264If used on a multiplexed connection, then this option must be specified
diff --git a/ssh.c b/ssh.c
index 26e9681b7..97f6e821d 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh.c,v 1.407 2014/07/17 07:22:19 djm Exp $ */ 1/* $OpenBSD: ssh.c,v 1.408 2014/10/08 22:20:25 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
@@ -384,27 +384,49 @@ resolve_canonicalize(char **hostp, int port)
384 * file if the user specifies a config file on the command line. 384 * file if the user specifies a config file on the command line.
385 */ 385 */
386static void 386static void
387process_config_files(struct passwd *pw) 387process_config_files(const char *host_arg, struct passwd *pw, int post_canon)
388{ 388{
389 char buf[MAXPATHLEN]; 389 char buf[MAXPATHLEN];
390 int r; 390 int r;
391 391
392 if (config != NULL) { 392 if (config != NULL) {
393 if (strcasecmp(config, "none") != 0 && 393 if (strcasecmp(config, "none") != 0 &&
394 !read_config_file(config, pw, host, &options, 394 !read_config_file(config, pw, host, host_arg, &options,
395 SSHCONF_USERCONF)) 395 SSHCONF_USERCONF | (post_canon ? SSHCONF_POSTCANON : 0)))
396 fatal("Can't open user config file %.100s: " 396 fatal("Can't open user config file %.100s: "
397 "%.100s", config, strerror(errno)); 397 "%.100s", config, strerror(errno));
398 } else { 398 } else {
399 r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, 399 r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
400 _PATH_SSH_USER_CONFFILE); 400 _PATH_SSH_USER_CONFFILE);
401 if (r > 0 && (size_t)r < sizeof(buf)) 401 if (r > 0 && (size_t)r < sizeof(buf))
402 (void)read_config_file(buf, pw, host, &options, 402 (void)read_config_file(buf, pw, host, host_arg,
403 SSHCONF_CHECKPERM|SSHCONF_USERCONF); 403 &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF |
404 (post_canon ? SSHCONF_POSTCANON : 0));
404 405
405 /* Read systemwide configuration file after user config. */ 406 /* Read systemwide configuration file after user config. */
406 (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, host, 407 (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw,
407 &options, 0); 408 host, host_arg, &options,
409 post_canon ? SSHCONF_POSTCANON : 0);
410 }
411}
412
413/* Rewrite the port number in an addrinfo list of addresses */
414static void
415set_addrinfo_port(struct addrinfo *addrs, int port)
416{
417 struct addrinfo *addr;
418
419 for (addr = addrs; addr != NULL; addr = addr->ai_next) {
420 switch (addr->ai_family) {
421 case AF_INET:
422 ((struct sockaddr_in *)addr->ai_addr)->
423 sin_port = htons(port);
424 break;
425 case AF_INET6:
426 ((struct sockaddr_in6 *)addr->ai_addr)->
427 sin6_port = htons(port);
428 break;
429 }
408 } 430 }
409} 431}
410 432
@@ -414,7 +436,7 @@ process_config_files(struct passwd *pw)
414int 436int
415main(int ac, char **av) 437main(int ac, char **av)
416{ 438{
417 int i, r, opt, exit_status, use_syslog; 439 int i, r, opt, exit_status, use_syslog, config_test = 0;
418 char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg, *logfile; 440 char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg, *logfile;
419 char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; 441 char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV];
420 char cname[NI_MAXHOST]; 442 char cname[NI_MAXHOST];
@@ -507,7 +529,7 @@ main(int ac, char **av)
507 529
508 again: 530 again:
509 while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" 531 while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
510 "ACD:E:F:I:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { 532 "ACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
511 switch (opt) { 533 switch (opt) {
512 case '1': 534 case '1':
513 options.protocol = SSH_PROTO_1; 535 options.protocol = SSH_PROTO_1;
@@ -540,6 +562,9 @@ main(int ac, char **av)
540 case 'E': 562 case 'E':
541 logfile = xstrdup(optarg); 563 logfile = xstrdup(optarg);
542 break; 564 break;
565 case 'G':
566 config_test = 1;
567 break;
543 case 'Y': 568 case 'Y':
544 options.forward_x11 = 1; 569 options.forward_x11 = 1;
545 options.forward_x11_trusted = 1; 570 options.forward_x11_trusted = 1;
@@ -788,9 +813,9 @@ main(int ac, char **av)
788 break; 813 break;
789 case 'o': 814 case 'o':
790 line = xstrdup(optarg); 815 line = xstrdup(optarg);
791 if (process_config_line(&options, pw, host ? host : "", 816 if (process_config_line(&options, pw,
792 line, "command-line", 0, NULL, SSHCONF_USERCONF) 817 host ? host : "", host ? host : "", line,
793 != 0) 818 "command-line", 0, NULL, SSHCONF_USERCONF) != 0)
794 exit(255); 819 exit(255);
795 free(line); 820 free(line);
796 break; 821 break;
@@ -899,7 +924,7 @@ main(int ac, char **av)
899 ); 924 );
900 925
901 /* Parse the configuration files */ 926 /* Parse the configuration files */
902 process_config_files(pw); 927 process_config_files(host_arg, pw, 0);
903 928
904 /* Hostname canonicalisation needs a few options filled. */ 929 /* Hostname canonicalisation needs a few options filled. */
905 fill_default_options_for_canonicalization(&options); 930 fill_default_options_for_canonicalization(&options);
@@ -911,6 +936,8 @@ main(int ac, char **av)
911 "h", host, (char *)NULL); 936 "h", host, (char *)NULL);
912 free(host); 937 free(host);
913 host = cp; 938 host = cp;
939 free(options.hostname);
940 options.hostname = xstrdup(host);
914 } 941 }
915 942
916 /* If canonicalization requested then try to apply it */ 943 /* If canonicalization requested then try to apply it */
@@ -945,12 +972,22 @@ main(int ac, char **av)
945 } 972 }
946 973
947 /* 974 /*
948 * If the target hostname has changed as a result of canonicalisation 975 * If canonicalisation is enabled then re-parse the configuration
949 * then re-parse the configuration files as new stanzas may match. 976 * files as new stanzas may match.
950 */ 977 */
951 if (strcasecmp(host_arg, host) != 0) { 978 if (options.canonicalize_hostname != 0) {
952 debug("Hostname has changed; re-reading configuration"); 979 debug("Re-reading configuration after hostname "
953 process_config_files(pw); 980 "canonicalisation");
981 free(options.hostname);
982 options.hostname = xstrdup(host);
983 process_config_files(host_arg, pw, 1);
984 /*
985 * Address resolution happens early with canonicalisation
986 * enabled and the port number may have changed since, so
987 * reset it in address list
988 */
989 if (addrs != NULL && options.port > 0)
990 set_addrinfo_port(addrs, options.port);
954 } 991 }
955 992
956 /* Fill configuration defaults. */ 993 /* Fill configuration defaults. */
@@ -1052,6 +1089,11 @@ main(int ac, char **av)
1052 } 1089 }
1053 free(conn_hash_hex); 1090 free(conn_hash_hex);
1054 1091
1092 if (config_test) {
1093 dump_client_config(&options, host);
1094 exit(0);
1095 }
1096
1055 if (muxclient_command != 0 && options.control_path == NULL) 1097 if (muxclient_command != 0 && options.control_path == NULL)
1056 fatal("No ControlPath specified for \"-O\" command"); 1098 fatal("No ControlPath specified for \"-O\" command");
1057 if (options.control_path != NULL) 1099 if (options.control_path != NULL)
diff --git a/ssh_config.5 b/ssh_config.5
index 4396aa907..b702e323f 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.192 2014/08/30 15:33:50 sobrado Exp $ 36.\" $OpenBSD: ssh_config.5,v 1.193 2014/10/08 22:20:25 djm Exp $
37.Dd $Mdocdate: August 30 2014 $ 37.Dd $Mdocdate: October 8 2014 $
38.Dt SSH_CONFIG 5 38.Dt SSH_CONFIG 5
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -65,7 +65,10 @@ The configuration files contain sections separated by
65.Dq Host 65.Dq Host
66specifications, and that section is only applied for hosts that 66specifications, and that section is only applied for hosts that
67match one of the patterns given in the specification. 67match one of the patterns given in the specification.
68The matched host name is the one given on the command line. 68The matched host name is usually the one given on the command line
69(see the
70.Cm CanonicalizeHostname
71option for exceptions.)
69.Pp 72.Pp
70Since the first obtained value for each parameter is used, more 73Since the first obtained value for each parameter is used, more
71host-specific declarations should be given near the beginning of the 74host-specific declarations should be given near the beginning of the
@@ -109,10 +112,12 @@ A single
109.Ql * 112.Ql *
110as a pattern can be used to provide global 113as a pattern can be used to provide global
111defaults for all hosts. 114defaults for all hosts.
112The host is the 115The host is usually the
113.Ar hostname 116.Ar hostname
114argument given on the command line (i.e. the name is not converted to 117argument given on the command line
115a canonicalized host name before matching). 118(see the
119.Cm CanonicalizeHostname
120option for exceptions.)
116.Pp 121.Pp
117A pattern entry may be negated by prefixing it with an exclamation mark 122A pattern entry may be negated by prefixing it with an exclamation mark
118.Pq Sq !\& . 123.Pq Sq !\& .
@@ -134,19 +139,40 @@ or
134keyword) to be used only when the conditions following the 139keyword) to be used only when the conditions following the
135.Cm Match 140.Cm Match
136keyword are satisfied. 141keyword are satisfied.
137Match conditions are specified using one or more keyword/criteria pairs 142Match conditions are specified using one or more critera
138or the single token 143or the single token
139.Cm all 144.Cm all
140which matches all criteria. 145which always matches.
141The available keywords are: 146The available criteria keywords are:
147.Cm canonical ,
142.Cm exec , 148.Cm exec ,
143.Cm host , 149.Cm host ,
144.Cm originalhost , 150.Cm originalhost ,
145.Cm user , 151.Cm user ,
146and 152and
147.Cm localuser . 153.Cm localuser .
154The
155.Cm all
156criteria must appear alone or immediately after
157.Cm canonical.
158Other criteria may be combined arbitrarily.
159All criteria but
160.Cm all
161and
162.Cm canonical
163require an argument.
164Criteria may be negated by prepending an exclamation mark
165.Pq Sq !\& .
148.Pp 166.Pp
149The 167The
168.Cm canonical
169keywork matches only when the configuration file is being re-parsed
170after hostname canonicalization (see the
171.Cm CanonicalizeHostname
172option.)
173This may be useful to specify conditions that work with canonical host
174names only.
175The
150.Cm exec 176.Cm exec
151keyword executes the specified command under the user's shell. 177keyword executes the specified command under the user's shell.
152If the command returns a zero exit status then the condition is considered true. 178If the command returns a zero exit status then the condition is considered true.
@@ -179,7 +205,9 @@ The criteria for the
179keyword are matched against the target hostname, after any substitution 205keyword are matched against the target hostname, after any substitution
180by the 206by the
181.Cm Hostname 207.Cm Hostname
182option. 208or
209.Cm CanonicalizeHostname
210options.
183The 211The
184.Cm originalhost 212.Cm originalhost
185keyword matches against the hostname as it was specified on the command-line. 213keyword matches against the hostname as it was specified on the command-line.
@@ -264,10 +292,11 @@ is set to
264.Dq always , 292.Dq always ,
265then canonicalization is applied to proxied connections too. 293then canonicalization is applied to proxied connections too.
266.Pp 294.Pp
267If this option is enabled and canonicalisation results in the target hostname 295If this option is enabled, then the configuration files are processed
268changing, then the configuration files are processed again using the new 296again using the new target name to pick up any new configuration in matching
269target name to pick up any new configuration in matching
270.Cm Host 297.Cm Host
298and
299.Cm Match
271stanzas. 300stanzas.
272.It Cm CanonicalizeMaxDots 301.It Cm CanonicalizeMaxDots
273Specifies the maximum number of dot characters in a hostname before 302Specifies the maximum number of dot characters in a hostname before