summaryrefslogtreecommitdiff
path: root/readconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'readconf.c')
-rw-r--r--readconf.c266
1 files changed, 241 insertions, 25 deletions
diff --git a/readconf.c b/readconf.c
index dc22360d1..5cd51f3e6 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.c,v 1.250 2016/02/08 23:40:12 djm Exp $ */ 1/* $OpenBSD: readconf.c,v 1.259 2016/07/22 03:35:11 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
@@ -39,8 +39,11 @@
39#include <stdio.h> 39#include <stdio.h>
40#include <string.h> 40#include <string.h>
41#include <unistd.h> 41#include <unistd.h>
42#include <pwd.h> 42#ifdef USE_SYSTEM_GLOB
43#include <grp.h> 43# include <glob.h>
44#else
45# include "openbsd-compat/glob.h"
46#endif
44#ifdef HAVE_UTIL_H 47#ifdef HAVE_UTIL_H
45#include <util.h> 48#include <util.h>
46#endif 49#endif
@@ -127,17 +130,24 @@
127 130
128*/ 131*/
129 132
133static int read_config_file_depth(const char *filename, struct passwd *pw,
134 const char *host, const char *original_host, Options *options,
135 int flags, int *activep, int depth);
136static int process_config_line_depth(Options *options, struct passwd *pw,
137 const char *host, const char *original_host, char *line,
138 const char *filename, int linenum, int *activep, int flags, int depth);
139
130/* Keyword tokens. */ 140/* Keyword tokens. */
131 141
132typedef enum { 142typedef enum {
133 oBadOption, 143 oBadOption,
134 oHost, oMatch, 144 oHost, oMatch, oInclude,
135 oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, 145 oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
136 oGatewayPorts, oExitOnForwardFailure, 146 oGatewayPorts, oExitOnForwardFailure,
137 oPasswordAuthentication, oRSAAuthentication, 147 oPasswordAuthentication, oRSAAuthentication,
138 oChallengeResponseAuthentication, oXAuthLocation, 148 oChallengeResponseAuthentication, oXAuthLocation,
139 oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, 149 oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
140 oCertificateFile, oAddKeysToAgent, 150 oCertificateFile, oAddKeysToAgent, oIdentityAgent,
141 oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, 151 oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
142 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, 152 oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
143 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, 153 oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
@@ -162,7 +172,7 @@ typedef enum {
162 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, 172 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
163 oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, 173 oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
164 oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes, 174 oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
165 oPubkeyAcceptedKeyTypes, 175 oPubkeyAcceptedKeyTypes, oProxyJump,
166 oProtocolKeepAlives, oSetupTimeOut, 176 oProtocolKeepAlives, oSetupTimeOut,
167 oIgnoredUnknownOption, oDeprecated, oUnsupported 177 oIgnoredUnknownOption, oDeprecated, oUnsupported
168} OpCodes; 178} OpCodes;
@@ -220,6 +230,7 @@ static struct {
220 { "identitiesonly", oIdentitiesOnly }, 230 { "identitiesonly", oIdentitiesOnly },
221 { "certificatefile", oCertificateFile }, 231 { "certificatefile", oCertificateFile },
222 { "addkeystoagent", oAddKeysToAgent }, 232 { "addkeystoagent", oAddKeysToAgent },
233 { "identityagent", oIdentityAgent },
223 { "hostname", oHostName }, 234 { "hostname", oHostName },
224 { "hostkeyalias", oHostKeyAlias }, 235 { "hostkeyalias", oHostKeyAlias },
225 { "proxycommand", oProxyCommand }, 236 { "proxycommand", oProxyCommand },
@@ -273,6 +284,7 @@ static struct {
273 { "controlmaster", oControlMaster }, 284 { "controlmaster", oControlMaster },
274 { "controlpersist", oControlPersist }, 285 { "controlpersist", oControlPersist },
275 { "hashknownhosts", oHashKnownHosts }, 286 { "hashknownhosts", oHashKnownHosts },
287 { "include", oInclude },
276 { "tunnel", oTunnel }, 288 { "tunnel", oTunnel },
277 { "tunneldevice", oTunnelDevice }, 289 { "tunneldevice", oTunnelDevice },
278 { "localcommand", oLocalCommand }, 290 { "localcommand", oLocalCommand },
@@ -296,6 +308,7 @@ static struct {
296 { "hostbasedkeytypes", oHostbasedKeyTypes }, 308 { "hostbasedkeytypes", oHostbasedKeyTypes },
297 { "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes }, 309 { "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
298 { "ignoreunknown", oIgnoreUnknown }, 310 { "ignoreunknown", oIgnoreUnknown },
311 { "proxyjump", oProxyJump },
299 { "protocolkeepalives", oProtocolKeepAlives }, 312 { "protocolkeepalives", oProtocolKeepAlives },
300 { "setuptimeout", oSetupTimeOut }, 313 { "setuptimeout", oSetupTimeOut },
301 314
@@ -311,12 +324,17 @@ void
311add_local_forward(Options *options, const struct Forward *newfwd) 324add_local_forward(Options *options, const struct Forward *newfwd)
312{ 325{
313 struct Forward *fwd; 326 struct Forward *fwd;
314#ifndef NO_IPPORT_RESERVED_CONCEPT
315 extern uid_t original_real_uid; 327 extern uid_t original_real_uid;
328 int i;
329
316 if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0 && 330 if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0 &&
317 newfwd->listen_path == NULL) 331 newfwd->listen_path == NULL)
318 fatal("Privileged ports can only be forwarded by root."); 332 fatal("Privileged ports can only be forwarded by root.");
319#endif 333 /* Don't add duplicates */
334 for (i = 0; i < options->num_local_forwards; i++) {
335 if (forward_equals(newfwd, options->local_forwards + i))
336 return;
337 }
320 options->local_forwards = xreallocarray(options->local_forwards, 338 options->local_forwards = xreallocarray(options->local_forwards,
321 options->num_local_forwards + 1, 339 options->num_local_forwards + 1,
322 sizeof(*options->local_forwards)); 340 sizeof(*options->local_forwards));
@@ -339,7 +357,13 @@ void
339add_remote_forward(Options *options, const struct Forward *newfwd) 357add_remote_forward(Options *options, const struct Forward *newfwd)
340{ 358{
341 struct Forward *fwd; 359 struct Forward *fwd;
360 int i;
342 361
362 /* Don't add duplicates */
363 for (i = 0; i < options->num_remote_forwards; i++) {
364 if (forward_equals(newfwd, options->remote_forwards + i))
365 return;
366 }
343 options->remote_forwards = xreallocarray(options->remote_forwards, 367 options->remote_forwards = xreallocarray(options->remote_forwards,
344 options->num_remote_forwards + 1, 368 options->num_remote_forwards + 1,
345 sizeof(*options->remote_forwards)); 369 sizeof(*options->remote_forwards));
@@ -789,22 +813,32 @@ static const struct multistate multistate_canonicalizehostname[] = {
789 * Processes a single option line as used in the configuration files. This 813 * Processes a single option line as used in the configuration files. This
790 * only sets those values that have not already been set. 814 * only sets those values that have not already been set.
791 */ 815 */
792#define WHITESPACE " \t\r\n"
793int 816int
794process_config_line(Options *options, struct passwd *pw, const char *host, 817process_config_line(Options *options, struct passwd *pw, const char *host,
795 const char *original_host, char *line, const char *filename, 818 const char *original_host, char *line, const char *filename,
796 int linenum, int *activep, int flags) 819 int linenum, int *activep, int flags)
797{ 820{
821 return process_config_line_depth(options, pw, host, original_host,
822 line, filename, linenum, activep, flags, 0);
823}
824
825#define WHITESPACE " \t\r\n"
826static int
827process_config_line_depth(Options *options, struct passwd *pw, const char *host,
828 const char *original_host, char *line, const char *filename,
829 int linenum, int *activep, int flags, int depth)
830{
798 char *s, **charptr, *endofnumber, *keyword, *arg, *arg2; 831 char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
799 char **cpptr, fwdarg[256]; 832 char **cpptr, fwdarg[256];
800 u_int i, *uintptr, max_entries = 0; 833 u_int i, *uintptr, max_entries = 0;
801 int negated, opcode, *intptr, value, value2, cmdline = 0; 834 int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
802 LogLevel *log_level_ptr; 835 LogLevel *log_level_ptr;
803 long long val64; 836 long long val64;
804 size_t len; 837 size_t len;
805 struct Forward fwd; 838 struct Forward fwd;
806 const struct multistate *multistate_ptr; 839 const struct multistate *multistate_ptr;
807 struct allowed_cname *cname; 840 struct allowed_cname *cname;
841 glob_t gl;
808 842
809 if (activep == NULL) { /* We are processing a command line directive */ 843 if (activep == NULL) { /* We are processing a command line directive */
810 cmdline = 1; 844 cmdline = 1;
@@ -1123,6 +1157,9 @@ parse_char_array:
1123 1157
1124 case oProxyCommand: 1158 case oProxyCommand:
1125 charptr = &options->proxy_command; 1159 charptr = &options->proxy_command;
1160 /* Ignore ProxyCommand if ProxyJump already specified */
1161 if (options->jump_host != NULL)
1162 charptr = &options->jump_host; /* Skip below */
1126parse_command: 1163parse_command:
1127 if (s == NULL) 1164 if (s == NULL)
1128 fatal("%.200s line %d: Missing argument.", filename, linenum); 1165 fatal("%.200s line %d: Missing argument.", filename, linenum);
@@ -1131,6 +1168,18 @@ parse_command:
1131 *charptr = xstrdup(s + len); 1168 *charptr = xstrdup(s + len);
1132 return 0; 1169 return 0;
1133 1170
1171 case oProxyJump:
1172 if (s == NULL) {
1173 fatal("%.200s line %d: Missing argument.",
1174 filename, linenum);
1175 }
1176 len = strspn(s, WHITESPACE "=");
1177 if (parse_jump(s + len, options, *activep) == -1) {
1178 fatal("%.200s line %d: Invalid ProxyJump \"%s\"",
1179 filename, linenum, s + len);
1180 }
1181 return 0;
1182
1134 case oPort: 1183 case oPort:
1135 intptr = &options->port; 1184 intptr = &options->port;
1136parse_int: 1185parse_int:
@@ -1284,6 +1333,8 @@ parse_keytypes:
1284 *activep = 0; 1333 *activep = 0;
1285 arg2 = NULL; 1334 arg2 = NULL;
1286 while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 1335 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1336 if ((flags & SSHCONF_NEVERMATCH) != 0)
1337 break;
1287 negated = *arg == '!'; 1338 negated = *arg == '!';
1288 if (negated) 1339 if (negated)
1289 arg++; 1340 arg++;
@@ -1316,7 +1367,7 @@ parse_keytypes:
1316 if (value < 0) 1367 if (value < 0)
1317 fatal("%.200s line %d: Bad Match condition", filename, 1368 fatal("%.200s line %d: Bad Match condition", filename,
1318 linenum); 1369 linenum);
1319 *activep = value; 1370 *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
1320 break; 1371 break;
1321 1372
1322 case oEscapeChar: 1373 case oEscapeChar:
@@ -1446,6 +1497,63 @@ parse_keytypes:
1446 intptr = &options->visual_host_key; 1497 intptr = &options->visual_host_key;
1447 goto parse_flag; 1498 goto parse_flag;
1448 1499
1500 case oInclude:
1501 if (cmdline)
1502 fatal("Include directive not supported as a "
1503 "command-line option");
1504 value = 0;
1505 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1506 /*
1507 * Ensure all paths are anchored. User configuration
1508 * files may begin with '~/' but system configurations
1509 * must not. If the path is relative, then treat it
1510 * as living in ~/.ssh for user configurations or
1511 * /etc/ssh for system ones.
1512 */
1513 if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0)
1514 fatal("%.200s line %d: bad include path %s.",
1515 filename, linenum, arg);
1516 if (*arg != '/' && *arg != '~') {
1517 xasprintf(&arg2, "%s/%s",
1518 (flags & SSHCONF_USERCONF) ?
1519 "~/" _PATH_SSH_USER_DIR : SSHDIR, arg);
1520 } else
1521 arg2 = xstrdup(arg);
1522 memset(&gl, 0, sizeof(gl));
1523 r = glob(arg2, GLOB_TILDE, NULL, &gl);
1524 if (r == GLOB_NOMATCH) {
1525 debug("%.200s line %d: include %s matched no "
1526 "files",filename, linenum, arg2);
1527 continue;
1528 } else if (r != 0 || gl.gl_pathc < 0)
1529 fatal("%.200s line %d: glob failed for %s.",
1530 filename, linenum, arg2);
1531 free(arg2);
1532 oactive = *activep;
1533 for (i = 0; i < (u_int)gl.gl_pathc; i++) {
1534 debug3("%.200s line %d: Including file %s "
1535 "depth %d%s", filename, linenum,
1536 gl.gl_pathv[i], depth,
1537 oactive ? "" : " (parse only)");
1538 r = read_config_file_depth(gl.gl_pathv[i],
1539 pw, host, original_host, options,
1540 flags | SSHCONF_CHECKPERM |
1541 (oactive ? 0 : SSHCONF_NEVERMATCH),
1542 activep, depth + 1);
1543 /*
1544 * don't let Match in includes clobber the
1545 * containing file's Match state.
1546 */
1547 *activep = oactive;
1548 if (r != 1)
1549 value = -1;
1550 }
1551 globfree(&gl);
1552 }
1553 if (value != 0)
1554 return value;
1555 break;
1556
1449 case oIPQoS: 1557 case oIPQoS:
1450 arg = strdelim(&s); 1558 arg = strdelim(&s);
1451 if ((value = parse_ipqos(arg)) == -1) 1559 if ((value = parse_ipqos(arg)) == -1)
@@ -1582,6 +1690,10 @@ parse_keytypes:
1582 multistate_ptr = multistate_yesnoaskconfirm; 1690 multistate_ptr = multistate_yesnoaskconfirm;
1583 goto parse_multistate; 1691 goto parse_multistate;
1584 1692
1693 case oIdentityAgent:
1694 charptr = &options->identity_agent;
1695 goto parse_string;
1696
1585 case oDeprecated: 1697 case oDeprecated:
1586 debug("%s line %d: Deprecated option \"%s\"", 1698 debug("%s line %d: Deprecated option \"%s\"",
1587 filename, linenum, keyword); 1699 filename, linenum, keyword);
@@ -1604,22 +1716,35 @@ parse_keytypes:
1604 return 0; 1716 return 0;
1605} 1717}
1606 1718
1607
1608/* 1719/*
1609 * Reads the config file and modifies the options accordingly. Options 1720 * Reads the config file and modifies the options accordingly. Options
1610 * should already be initialized before this call. This never returns if 1721 * should already be initialized before this call. This never returns if
1611 * there is an error. If the file does not exist, this returns 0. 1722 * there is an error. If the file does not exist, this returns 0.
1612 */ 1723 */
1613
1614int 1724int
1615read_config_file(const char *filename, struct passwd *pw, const char *host, 1725read_config_file(const char *filename, struct passwd *pw, const char *host,
1616 const char *original_host, Options *options, int flags) 1726 const char *original_host, Options *options, int flags)
1617{ 1727{
1728 int active = 1;
1729
1730 return read_config_file_depth(filename, pw, host, original_host,
1731 options, flags, &active, 0);
1732}
1733
1734#define READCONF_MAX_DEPTH 16
1735static int
1736read_config_file_depth(const char *filename, struct passwd *pw,
1737 const char *host, const char *original_host, Options *options,
1738 int flags, int *activep, int depth)
1739{
1618 FILE *f; 1740 FILE *f;
1619 char line[1024]; 1741 char line[1024];
1620 int active, linenum; 1742 int linenum;
1621 int bad_options = 0; 1743 int bad_options = 0;
1622 1744
1745 if (depth < 0 || depth > READCONF_MAX_DEPTH)
1746 fatal("Too many recursive configuration includes");
1747
1623 if ((f = fopen(filename, "r")) == NULL) 1748 if ((f = fopen(filename, "r")) == NULL)
1624 return 0; 1749 return 0;
1625 1750
@@ -1638,13 +1763,12 @@ read_config_file(const char *filename, struct passwd *pw, const char *host,
1638 * Mark that we are now processing the options. This flag is turned 1763 * Mark that we are now processing the options. This flag is turned
1639 * on/off by Host specifications. 1764 * on/off by Host specifications.
1640 */ 1765 */
1641 active = 1;
1642 linenum = 0; 1766 linenum = 0;
1643 while (fgets(line, sizeof(line), f)) { 1767 while (fgets(line, sizeof(line), f)) {
1644 /* Update line number counter. */ 1768 /* Update line number counter. */
1645 linenum++; 1769 linenum++;
1646 if (process_config_line(options, pw, host, original_host, 1770 if (process_config_line_depth(options, pw, host, original_host,
1647 line, filename, linenum, &active, flags) != 0) 1771 line, filename, linenum, activep, flags, depth) != 0)
1648 bad_options++; 1772 bad_options++;
1649 } 1773 }
1650 fclose(f); 1774 fclose(f);
@@ -1676,6 +1800,9 @@ initialize_options(Options * options)
1676 options->forward_x11 = -1; 1800 options->forward_x11 = -1;
1677 options->forward_x11_trusted = -1; 1801 options->forward_x11_trusted = -1;
1678 options->forward_x11_timeout = -1; 1802 options->forward_x11_timeout = -1;
1803 options->stdio_forward_host = NULL;
1804 options->stdio_forward_port = 0;
1805 options->clear_forwardings = -1;
1679 options->exit_on_forward_failure = -1; 1806 options->exit_on_forward_failure = -1;
1680 options->xauth_location = NULL; 1807 options->xauth_location = NULL;
1681 options->fwd_opts.gateway_ports = -1; 1808 options->fwd_opts.gateway_ports = -1;
@@ -1719,6 +1846,10 @@ initialize_options(Options * options)
1719 options->hostname = NULL; 1846 options->hostname = NULL;
1720 options->host_key_alias = NULL; 1847 options->host_key_alias = NULL;
1721 options->proxy_command = NULL; 1848 options->proxy_command = NULL;
1849 options->jump_user = NULL;
1850 options->jump_host = NULL;
1851 options->jump_port = -1;
1852 options->jump_extra = NULL;
1722 options->user = NULL; 1853 options->user = NULL;
1723 options->escape_char = -1; 1854 options->escape_char = -1;
1724 options->num_system_hostfiles = 0; 1855 options->num_system_hostfiles = 0;
@@ -1727,7 +1858,6 @@ initialize_options(Options * options)
1727 options->num_local_forwards = 0; 1858 options->num_local_forwards = 0;
1728 options->remote_forwards = NULL; 1859 options->remote_forwards = NULL;
1729 options->num_remote_forwards = 0; 1860 options->num_remote_forwards = 0;
1730 options->clear_forwardings = -1;
1731 options->log_level = SYSLOG_LEVEL_NOT_SET; 1861 options->log_level = SYSLOG_LEVEL_NOT_SET;
1732 options->preferred_authentications = NULL; 1862 options->preferred_authentications = NULL;
1733 options->bind_address = NULL; 1863 options->bind_address = NULL;
@@ -1752,6 +1882,7 @@ initialize_options(Options * options)
1752 options->local_command = NULL; 1882 options->local_command = NULL;
1753 options->permit_local_command = -1; 1883 options->permit_local_command = -1;
1754 options->add_keys_to_agent = -1; 1884 options->add_keys_to_agent = -1;
1885 options->identity_agent = NULL;
1755 options->visual_host_key = -1; 1886 options->visual_host_key = -1;
1756 options->ip_qos_interactive = -1; 1887 options->ip_qos_interactive = -1;
1757 options->ip_qos_bulk = -1; 1888 options->ip_qos_bulk = -1;
@@ -1800,8 +1931,19 @@ fill_default_options(Options * options)
1800 options->forward_x11_trusted = 1; 1931 options->forward_x11_trusted = 1;
1801 if (options->forward_x11_timeout == -1) 1932 if (options->forward_x11_timeout == -1)
1802 options->forward_x11_timeout = 1200; 1933 options->forward_x11_timeout = 1200;
1934 /*
1935 * stdio forwarding (-W) changes the default for these but we defer
1936 * setting the values so they can be overridden.
1937 */
1803 if (options->exit_on_forward_failure == -1) 1938 if (options->exit_on_forward_failure == -1)
1804 options->exit_on_forward_failure = 0; 1939 options->exit_on_forward_failure =
1940 options->stdio_forward_host != NULL ? 1 : 0;
1941 if (options->clear_forwardings == -1)
1942 options->clear_forwardings =
1943 options->stdio_forward_host != NULL ? 1 : 0;
1944 if (options->clear_forwardings == 1)
1945 clear_forwardings(options);
1946
1805 if (options->xauth_location == NULL) 1947 if (options->xauth_location == NULL)
1806 options->xauth_location = _PATH_XAUTH; 1948 options->xauth_location = _PATH_XAUTH;
1807 if (options->fwd_opts.gateway_ports == -1) 1949 if (options->fwd_opts.gateway_ports == -1)
@@ -1898,8 +2040,6 @@ fill_default_options(Options * options)
1898 } 2040 }
1899 if (options->log_level == SYSLOG_LEVEL_NOT_SET) 2041 if (options->log_level == SYSLOG_LEVEL_NOT_SET)
1900 options->log_level = SYSLOG_LEVEL_INFO; 2042 options->log_level = SYSLOG_LEVEL_INFO;
1901 if (options->clear_forwardings == 1)
1902 clear_forwardings(options);
1903 if (options->no_host_authentication_for_localhost == - 1) 2043 if (options->no_host_authentication_for_localhost == - 1)
1904 options->no_host_authentication_for_localhost = 0; 2044 options->no_host_authentication_for_localhost = 0;
1905 if (options->identities_only == -1) 2045 if (options->identities_only == -1)
@@ -1977,6 +2117,7 @@ fill_default_options(Options * options)
1977 CLEAR_ON_NONE(options->proxy_command); 2117 CLEAR_ON_NONE(options->proxy_command);
1978 CLEAR_ON_NONE(options->control_path); 2118 CLEAR_ON_NONE(options->control_path);
1979 CLEAR_ON_NONE(options->revoked_host_keys); 2119 CLEAR_ON_NONE(options->revoked_host_keys);
2120 /* options->identity_agent distinguishes NULL from 'none' */
1980 /* options->user will be set in the main program if appropriate */ 2121 /* options->user will be set in the main program if appropriate */
1981 /* options->hostname will be set in the main program if appropriate */ 2122 /* options->hostname will be set in the main program if appropriate */
1982 /* options->host_key_alias should not be set by default */ 2123 /* options->host_key_alias should not be set by default */
@@ -2192,6 +2333,54 @@ parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remo
2192 return (0); 2333 return (0);
2193} 2334}
2194 2335
2336int
2337parse_jump(const char *s, Options *o, int active)
2338{
2339 char *orig, *sdup, *cp;
2340 char *host = NULL, *user = NULL;
2341 int ret = -1, port = -1, first;
2342
2343 active &= o->proxy_command == NULL && o->jump_host == NULL;
2344
2345 orig = sdup = xstrdup(s);
2346 first = active;
2347 do {
2348 if ((cp = strrchr(sdup, ',')) == NULL)
2349 cp = sdup; /* last */
2350 else
2351 *cp++ = '\0';
2352
2353 if (first) {
2354 /* First argument and configuration is active */
2355 if (parse_user_host_port(cp, &user, &host, &port) != 0)
2356 goto out;
2357 } else {
2358 /* Subsequent argument or inactive configuration */
2359 if (parse_user_host_port(cp, NULL, NULL, NULL) != 0)
2360 goto out;
2361 }
2362 first = 0; /* only check syntax for subsequent hosts */
2363 } while (cp != sdup);
2364 /* success */
2365 if (active) {
2366 o->jump_user = user;
2367 o->jump_host = host;
2368 o->jump_port = port;
2369 o->proxy_command = xstrdup("none");
2370 user = host = NULL;
2371 if ((cp = strrchr(s, ',')) != NULL && cp != s) {
2372 o->jump_extra = xstrdup(s);
2373 o->jump_extra[cp - s] = '\0';
2374 }
2375 }
2376 ret = 0;
2377 out:
2378 free(orig);
2379 free(user);
2380 free(host);
2381 return ret;
2382}
2383
2195/* XXX the following is a near-vebatim copy from servconf.c; refactor */ 2384/* XXX the following is a near-vebatim copy from servconf.c; refactor */
2196static const char * 2385static const char *
2197fmt_multistate_int(int val, const struct multistate *m) 2386fmt_multistate_int(int val, const struct multistate *m)
@@ -2343,7 +2532,7 @@ void
2343dump_client_config(Options *o, const char *host) 2532dump_client_config(Options *o, const char *host)
2344{ 2533{
2345 int i; 2534 int i;
2346 char vbuf[5]; 2535 char buf[8];
2347 2536
2348 /* This is normally prepared in ssh_kex2 */ 2537 /* This is normally prepared in ssh_kex2 */
2349 if (kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->hostkeyalgorithms) != 0) 2538 if (kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->hostkeyalgorithms) != 0)
@@ -2364,6 +2553,7 @@ dump_client_config(Options *o, const char *host)
2364 dump_cfg_fmtint(oCompression, o->compression); 2553 dump_cfg_fmtint(oCompression, o->compression);
2365 dump_cfg_fmtint(oControlMaster, o->control_master); 2554 dump_cfg_fmtint(oControlMaster, o->control_master);
2366 dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign); 2555 dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
2556 dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
2367 dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure); 2557 dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
2368 dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash); 2558 dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
2369 dump_cfg_fmtint(oForwardAgent, o->forward_agent); 2559 dump_cfg_fmtint(oForwardAgent, o->forward_agent);
@@ -2412,6 +2602,7 @@ dump_client_config(Options *o, const char *host)
2412 dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms); 2602 dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms);
2413 dump_cfg_string(oHostKeyAlias, o->host_key_alias); 2603 dump_cfg_string(oHostKeyAlias, o->host_key_alias);
2414 dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types); 2604 dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types);
2605 dump_cfg_string(oIdentityAgent, o->identity_agent);
2415 dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices); 2606 dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices);
2416 dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX); 2607 dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX);
2417 dump_cfg_string(oLocalCommand, o->local_command); 2608 dump_cfg_string(oLocalCommand, o->local_command);
@@ -2419,7 +2610,6 @@ dump_client_config(Options *o, const char *host)
2419 dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC); 2610 dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
2420 dump_cfg_string(oPKCS11Provider, o->pkcs11_provider); 2611 dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
2421 dump_cfg_string(oPreferredAuthentications, o->preferred_authentications); 2612 dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
2422 dump_cfg_string(oProxyCommand, o->proxy_command);
2423 dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types); 2613 dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types);
2424 dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys); 2614 dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
2425 dump_cfg_string(oXAuthLocation, o->xauth_location); 2615 dump_cfg_string(oXAuthLocation, o->xauth_location);
@@ -2480,8 +2670,8 @@ dump_client_config(Options *o, const char *host)
2480 if (o->escape_char == SSH_ESCAPECHAR_NONE) 2670 if (o->escape_char == SSH_ESCAPECHAR_NONE)
2481 printf("escapechar none\n"); 2671 printf("escapechar none\n");
2482 else { 2672 else {
2483 vis(vbuf, o->escape_char, VIS_WHITE, 0); 2673 vis(buf, o->escape_char, VIS_WHITE, 0);
2484 printf("escapechar %s\n", vbuf); 2674 printf("escapechar %s\n", buf);
2485 } 2675 }
2486 2676
2487 /* oIPQoS */ 2677 /* oIPQoS */
@@ -2495,4 +2685,30 @@ dump_client_config(Options *o, const char *host)
2495 /* oStreamLocalBindMask */ 2685 /* oStreamLocalBindMask */
2496 printf("streamlocalbindmask 0%o\n", 2686 printf("streamlocalbindmask 0%o\n",
2497 o->fwd_opts.streamlocal_bind_mask); 2687 o->fwd_opts.streamlocal_bind_mask);
2688
2689 /* oProxyCommand / oProxyJump */
2690 if (o->jump_host == NULL)
2691 dump_cfg_string(oProxyCommand, o->proxy_command);
2692 else {
2693 /* Check for numeric addresses */
2694 i = strchr(o->jump_host, ':') != NULL ||
2695 strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
2696 snprintf(buf, sizeof(buf), "%d", o->jump_port);
2697 printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
2698 /* optional additional jump spec */
2699 o->jump_extra == NULL ? "" : o->jump_extra,
2700 o->jump_extra == NULL ? "" : ",",
2701 /* optional user */
2702 o->jump_user == NULL ? "" : o->jump_user,
2703 o->jump_user == NULL ? "" : "@",
2704 /* opening [ if hostname is numeric */
2705 i ? "[" : "",
2706 /* mandatory hostname */
2707 o->jump_host,
2708 /* closing ] if hostname is numeric */
2709 i ? "]" : "",
2710 /* optional port number */
2711 o->jump_port <= 0 ? "" : ":",
2712 o->jump_port <= 0 ? "" : buf);
2713 }
2498} 2714}