summaryrefslogtreecommitdiff
path: root/readconf.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2016-07-15 00:24:30 +0000
committerDamien Miller <djm@mindrot.org>2016-07-15 14:20:10 +1000
commited877ef653847d056bb433975d731b7a1132a979 (patch)
tree855230b944a0fc2eebdaa4c037f911e28ff21e17 /readconf.c
parent5c02dd126206a26785379e80f2d3848e4470b711 (diff)
upstream commit
Add a ProxyJump ssh_config(5) option and corresponding -J ssh(1) command-line flag to allow simplified indirection through a SSH bastion or "jump host". These options construct a proxy command that connects to the specified jump host(s) (more than one may be specified) and uses port-forwarding to establish a connection to the next destination. This codifies the safest way of indirecting connections through SSH servers and makes it easy to use. ok markus@ Upstream-ID: fa899cb8b26d889da8f142eb9774c1ea36b04397
Diffstat (limited to 'readconf.c')
-rw-r--r--readconf.c95
1 files changed, 89 insertions, 6 deletions
diff --git a/readconf.c b/readconf.c
index 9dcc383da..cb2999d82 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.c,v 1.256 2016/06/03 04:09:38 dtucker Exp $ */ 1/* $OpenBSD: readconf.c,v 1.257 2016/07/15 00:24:30 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
@@ -170,7 +170,7 @@ typedef enum {
170 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, 170 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
171 oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, 171 oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
172 oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes, 172 oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
173 oPubkeyAcceptedKeyTypes, 173 oPubkeyAcceptedKeyTypes, oProxyJump,
174 oIgnoredUnknownOption, oDeprecated, oUnsupported 174 oIgnoredUnknownOption, oDeprecated, oUnsupported
175} OpCodes; 175} OpCodes;
176 176
@@ -295,6 +295,7 @@ static struct {
295 { "hostbasedkeytypes", oHostbasedKeyTypes }, 295 { "hostbasedkeytypes", oHostbasedKeyTypes },
296 { "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes }, 296 { "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
297 { "ignoreunknown", oIgnoreUnknown }, 297 { "ignoreunknown", oIgnoreUnknown },
298 { "proxyjump", oProxyJump },
298 299
299 { NULL, oBadOption } 300 { NULL, oBadOption }
300}; 301};
@@ -1121,6 +1122,9 @@ parse_char_array:
1121 1122
1122 case oProxyCommand: 1123 case oProxyCommand:
1123 charptr = &options->proxy_command; 1124 charptr = &options->proxy_command;
1125 /* Ignore ProxyCommand if ProxyJump already specified */
1126 if (options->jump_host != NULL)
1127 charptr = &options->jump_host; /* Skip below */
1124parse_command: 1128parse_command:
1125 if (s == NULL) 1129 if (s == NULL)
1126 fatal("%.200s line %d: Missing argument.", filename, linenum); 1130 fatal("%.200s line %d: Missing argument.", filename, linenum);
@@ -1129,6 +1133,18 @@ parse_command:
1129 *charptr = xstrdup(s + len); 1133 *charptr = xstrdup(s + len);
1130 return 0; 1134 return 0;
1131 1135
1136 case oProxyJump:
1137 if (s == NULL) {
1138 fatal("%.200s line %d: Missing argument.",
1139 filename, linenum);
1140 }
1141 len = strspn(s, WHITESPACE "=");
1142 if (parse_jump(s + len, options, *activep) == -1) {
1143 fatal("%.200s line %d: Invalid ProxyJump \"%s\"",
1144 filename, linenum, s + len);
1145 }
1146 return 0;
1147
1132 case oPort: 1148 case oPort:
1133 intptr = &options->port; 1149 intptr = &options->port;
1134parse_int: 1150parse_int:
@@ -1789,6 +1805,10 @@ initialize_options(Options * options)
1789 options->hostname = NULL; 1805 options->hostname = NULL;
1790 options->host_key_alias = NULL; 1806 options->host_key_alias = NULL;
1791 options->proxy_command = NULL; 1807 options->proxy_command = NULL;
1808 options->jump_user = NULL;
1809 options->jump_host = NULL;
1810 options->jump_port = -1;
1811 options->jump_extra = NULL;
1792 options->user = NULL; 1812 options->user = NULL;
1793 options->escape_char = -1; 1813 options->escape_char = -1;
1794 options->num_system_hostfiles = 0; 1814 options->num_system_hostfiles = 0;
@@ -2261,6 +2281,44 @@ parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remo
2261 return (0); 2281 return (0);
2262} 2282}
2263 2283
2284int
2285parse_jump(const char *s, Options *o, int active)
2286{
2287 char *orig, *sdup, *cp;
2288 char *host = NULL, *user = NULL;
2289 int ret = -1, port = -1;
2290
2291 active &= o->proxy_command == NULL && o->jump_host == NULL;
2292
2293 orig = sdup = xstrdup(s);
2294 while ((cp = strsep(&sdup, ",")) && cp != NULL) {
2295 if (active) {
2296 /* First argument and configuration is active */
2297 if (parse_user_host_port(cp, &user, &host, &port) != 0)
2298 goto out;
2299 } else {
2300 /* Subsequent argument or inactive configuration */
2301 if (parse_user_host_port(cp, NULL, NULL, NULL) != 0)
2302 goto out;
2303 }
2304 active = 0; /* only check syntax for subsequent hosts */
2305 }
2306 /* success */
2307 free(orig);
2308 o->jump_user = user;
2309 o->jump_host = host;
2310 o->jump_port = port;
2311 o->proxy_command = xstrdup("none");
2312 user = host = NULL;
2313 if ((cp = strchr(s, ',')) != NULL && cp[1] != '\0')
2314 o->jump_extra = xstrdup(cp + 1);
2315 ret = 0;
2316 out:
2317 free(user);
2318 free(host);
2319 return ret;
2320}
2321
2264/* XXX the following is a near-vebatim copy from servconf.c; refactor */ 2322/* XXX the following is a near-vebatim copy from servconf.c; refactor */
2265static const char * 2323static const char *
2266fmt_multistate_int(int val, const struct multistate *m) 2324fmt_multistate_int(int val, const struct multistate *m)
@@ -2412,7 +2470,7 @@ void
2412dump_client_config(Options *o, const char *host) 2470dump_client_config(Options *o, const char *host)
2413{ 2471{
2414 int i; 2472 int i;
2415 char vbuf[5]; 2473 char buf[8];
2416 2474
2417 /* This is normally prepared in ssh_kex2 */ 2475 /* This is normally prepared in ssh_kex2 */
2418 if (kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->hostkeyalgorithms) != 0) 2476 if (kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->hostkeyalgorithms) != 0)
@@ -2490,7 +2548,6 @@ dump_client_config(Options *o, const char *host)
2490 dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC); 2548 dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC);
2491 dump_cfg_string(oPKCS11Provider, o->pkcs11_provider); 2549 dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
2492 dump_cfg_string(oPreferredAuthentications, o->preferred_authentications); 2550 dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
2493 dump_cfg_string(oProxyCommand, o->proxy_command);
2494 dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types); 2551 dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types);
2495 dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys); 2552 dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
2496 dump_cfg_string(oXAuthLocation, o->xauth_location); 2553 dump_cfg_string(oXAuthLocation, o->xauth_location);
@@ -2551,8 +2608,8 @@ dump_client_config(Options *o, const char *host)
2551 if (o->escape_char == SSH_ESCAPECHAR_NONE) 2608 if (o->escape_char == SSH_ESCAPECHAR_NONE)
2552 printf("escapechar none\n"); 2609 printf("escapechar none\n");
2553 else { 2610 else {
2554 vis(vbuf, o->escape_char, VIS_WHITE, 0); 2611 vis(buf, o->escape_char, VIS_WHITE, 0);
2555 printf("escapechar %s\n", vbuf); 2612 printf("escapechar %s\n", buf);
2556 } 2613 }
2557 2614
2558 /* oIPQoS */ 2615 /* oIPQoS */
@@ -2566,4 +2623,30 @@ dump_client_config(Options *o, const char *host)
2566 /* oStreamLocalBindMask */ 2623 /* oStreamLocalBindMask */
2567 printf("streamlocalbindmask 0%o\n", 2624 printf("streamlocalbindmask 0%o\n",
2568 o->fwd_opts.streamlocal_bind_mask); 2625 o->fwd_opts.streamlocal_bind_mask);
2626
2627 /* oProxyCommand / oProxyJump */
2628 if (o->jump_host == NULL)
2629 dump_cfg_string(oProxyCommand, o->proxy_command);
2630 else {
2631 /* Check for numeric addresses */
2632 i = strchr(o->jump_host, ':') != NULL ||
2633 strspn(o->jump_host, "1234567890.") == strlen(o->jump_host);
2634 snprintf(buf, sizeof(buf), "%d", o->jump_port);
2635 printf("proxyjump %s%s%s%s%s%s%s%s%s\n",
2636 /* optional user */
2637 o->jump_user == NULL ? "" : o->jump_user,
2638 o->jump_user == NULL ? "" : "@",
2639 /* opening [ if hostname is numeric */
2640 i ? "[" : "",
2641 /* mandatory hostname */
2642 o->jump_host,
2643 /* closing ] if hostname is numeric */
2644 i ? "]" : "",
2645 /* optional port number */
2646 o->jump_port <= 0 ? "" : ":",
2647 o->jump_port <= 0 ? "" : buf,
2648 /* optional additional jump spec */
2649 o->jump_extra == NULL ? "" : ",",
2650 o->jump_extra == NULL ? "" : o->jump_extra);
2651 }
2569} 2652}