summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--readconf.c116
-rw-r--r--readconf.h3
-rw-r--r--ssh.15
-rw-r--r--ssh_config.523
4 files changed, 131 insertions, 16 deletions
diff --git a/readconf.c b/readconf.c
index d63e5961d..b348c9683 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.c,v 1.251 2016/04/06 06:42:17 djm Exp $ */ 1/* $OpenBSD: readconf.c,v 1.252 2016/04/15 00:30:19 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,6 +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#ifdef USE_SYSTEM_GLOB
43# include <glob.h>
44#else
45# include "openbsd-compat/glob.h"
46#endif
42#ifdef HAVE_UTIL_H 47#ifdef HAVE_UTIL_H
43#include <util.h> 48#include <util.h>
44#endif 49#endif
@@ -125,11 +130,18 @@
125 130
126*/ 131*/
127 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
128/* Keyword tokens. */ 140/* Keyword tokens. */
129 141
130typedef enum { 142typedef enum {
131 oBadOption, 143 oBadOption,
132 oHost, oMatch, 144 oHost, oMatch, oInclude,
133 oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, 145 oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
134 oGatewayPorts, oExitOnForwardFailure, 146 oGatewayPorts, oExitOnForwardFailure,
135 oPasswordAuthentication, oRSAAuthentication, 147 oPasswordAuthentication, oRSAAuthentication,
@@ -258,6 +270,7 @@ static struct {
258 { "controlmaster", oControlMaster }, 270 { "controlmaster", oControlMaster },
259 { "controlpersist", oControlPersist }, 271 { "controlpersist", oControlPersist },
260 { "hashknownhosts", oHashKnownHosts }, 272 { "hashknownhosts", oHashKnownHosts },
273 { "include", oInclude },
261 { "tunnel", oTunnel }, 274 { "tunnel", oTunnel },
262 { "tunneldevice", oTunnelDevice }, 275 { "tunneldevice", oTunnelDevice },
263 { "localcommand", oLocalCommand }, 276 { "localcommand", oLocalCommand },
@@ -783,22 +796,32 @@ static const struct multistate multistate_canonicalizehostname[] = {
783 * Processes a single option line as used in the configuration files. This 796 * Processes a single option line as used in the configuration files. This
784 * only sets those values that have not already been set. 797 * only sets those values that have not already been set.
785 */ 798 */
786#define WHITESPACE " \t\r\n"
787int 799int
788process_config_line(Options *options, struct passwd *pw, const char *host, 800process_config_line(Options *options, struct passwd *pw, const char *host,
789 const char *original_host, char *line, const char *filename, 801 const char *original_host, char *line, const char *filename,
790 int linenum, int *activep, int flags) 802 int linenum, int *activep, int flags)
791{ 803{
804 return process_config_line_depth(options, pw, host, original_host,
805 line, filename, linenum, activep, flags, 0);
806}
807
808#define WHITESPACE " \t\r\n"
809static int
810process_config_line_depth(Options *options, struct passwd *pw, const char *host,
811 const char *original_host, char *line, const char *filename,
812 int linenum, int *activep, int flags, int depth)
813{
792 char *s, **charptr, *endofnumber, *keyword, *arg, *arg2; 814 char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
793 char **cpptr, fwdarg[256]; 815 char **cpptr, fwdarg[256];
794 u_int i, *uintptr, max_entries = 0; 816 u_int i, *uintptr, max_entries = 0;
795 int negated, opcode, *intptr, value, value2, cmdline = 0; 817 int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
796 LogLevel *log_level_ptr; 818 LogLevel *log_level_ptr;
797 long long val64; 819 long long val64;
798 size_t len; 820 size_t len;
799 struct Forward fwd; 821 struct Forward fwd;
800 const struct multistate *multistate_ptr; 822 const struct multistate *multistate_ptr;
801 struct allowed_cname *cname; 823 struct allowed_cname *cname;
824 glob_t gl;
802 825
803 if (activep == NULL) { /* We are processing a command line directive */ 826 if (activep == NULL) { /* We are processing a command line directive */
804 cmdline = 1; 827 cmdline = 1;
@@ -1258,6 +1281,8 @@ parse_keytypes:
1258 *activep = 0; 1281 *activep = 0;
1259 arg2 = NULL; 1282 arg2 = NULL;
1260 while ((arg = strdelim(&s)) != NULL && *arg != '\0') { 1283 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1284 if ((flags & SSHCONF_NEVERMATCH) != 0)
1285 break;
1261 negated = *arg == '!'; 1286 negated = *arg == '!';
1262 if (negated) 1287 if (negated)
1263 arg++; 1288 arg++;
@@ -1290,7 +1315,7 @@ parse_keytypes:
1290 if (value < 0) 1315 if (value < 0)
1291 fatal("%.200s line %d: Bad Match condition", filename, 1316 fatal("%.200s line %d: Bad Match condition", filename,
1292 linenum); 1317 linenum);
1293 *activep = value; 1318 *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
1294 break; 1319 break;
1295 1320
1296 case oEscapeChar: 1321 case oEscapeChar:
@@ -1418,6 +1443,63 @@ parse_keytypes:
1418 intptr = &options->visual_host_key; 1443 intptr = &options->visual_host_key;
1419 goto parse_flag; 1444 goto parse_flag;
1420 1445
1446 case oInclude:
1447 if (cmdline)
1448 fatal("Include directive not supported as a "
1449 "command-line option");
1450 value = 0;
1451 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1452 /*
1453 * Ensure all paths are anchored. User configuration
1454 * files may begin with '~/' but system configurations
1455 * must not. If the path is relative, then treat it
1456 * as living in ~/.ssh for user configurations or
1457 * /etc/ssh for system ones.
1458 */
1459 if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0)
1460 fatal("%.200s line %d: bad include path %s.",
1461 filename, linenum, arg);
1462 if (*arg != '/' && *arg != '~') {
1463 xasprintf(&arg2, "%s/%s",
1464 (flags & SSHCONF_USERCONF) ?
1465 "~/" _PATH_SSH_USER_DIR : SSHDIR, arg);
1466 } else
1467 arg2 = xstrdup(arg);
1468 memset(&gl, 0, sizeof(gl));
1469 r = glob(arg2, GLOB_TILDE, NULL, &gl);
1470 if (r == GLOB_NOMATCH) {
1471 debug("%.200s line %d: include %s matched no "
1472 "files",filename, linenum, arg2);
1473 continue;
1474 } else if (r != 0 || gl.gl_pathc < 0)
1475 fatal("%.200s line %d: glob failed for %s.",
1476 filename, linenum, arg2);
1477 free(arg2);
1478 oactive = *activep;
1479 for (i = 0; i < (u_int)gl.gl_pathc; i++) {
1480 debug3("%.200s line %d: Including file %s "
1481 "depth %d%s", filename, linenum,
1482 gl.gl_pathv[i], depth,
1483 oactive ? "" : " (parse only)");
1484 r = read_config_file_depth(gl.gl_pathv[i],
1485 pw, host, original_host, options,
1486 flags | SSHCONF_CHECKPERM |
1487 (oactive ? 0 : SSHCONF_NEVERMATCH),
1488 activep, depth + 1);
1489 /*
1490 * don't let Match in includes clobber the
1491 * containing file's Match state.
1492 */
1493 *activep = oactive;
1494 if (r != 1)
1495 value = -1;
1496 }
1497 globfree(&gl);
1498 }
1499 if (value != 0)
1500 return value;
1501 break;
1502
1421 case oIPQoS: 1503 case oIPQoS:
1422 arg = strdelim(&s); 1504 arg = strdelim(&s);
1423 if ((value = parse_ipqos(arg)) == -1) 1505 if ((value = parse_ipqos(arg)) == -1)
@@ -1576,22 +1658,35 @@ parse_keytypes:
1576 return 0; 1658 return 0;
1577} 1659}
1578 1660
1579
1580/* 1661/*
1581 * Reads the config file and modifies the options accordingly. Options 1662 * Reads the config file and modifies the options accordingly. Options
1582 * should already be initialized before this call. This never returns if 1663 * should already be initialized before this call. This never returns if
1583 * there is an error. If the file does not exist, this returns 0. 1664 * there is an error. If the file does not exist, this returns 0.
1584 */ 1665 */
1585
1586int 1666int
1587read_config_file(const char *filename, struct passwd *pw, const char *host, 1667read_config_file(const char *filename, struct passwd *pw, const char *host,
1588 const char *original_host, Options *options, int flags) 1668 const char *original_host, Options *options, int flags)
1589{ 1669{
1670 int active = 1;
1671
1672 return read_config_file_depth(filename, pw, host, original_host,
1673 options, flags, &active, 0);
1674}
1675
1676#define READCONF_MAX_DEPTH 16
1677static int
1678read_config_file_depth(const char *filename, struct passwd *pw,
1679 const char *host, const char *original_host, Options *options,
1680 int flags, int *activep, int depth)
1681{
1590 FILE *f; 1682 FILE *f;
1591 char line[1024]; 1683 char line[1024];
1592 int active, linenum; 1684 int linenum;
1593 int bad_options = 0; 1685 int bad_options = 0;
1594 1686
1687 if (depth < 0 || depth > READCONF_MAX_DEPTH)
1688 fatal("Too many recursive configuration includes");
1689
1595 if ((f = fopen(filename, "r")) == NULL) 1690 if ((f = fopen(filename, "r")) == NULL)
1596 return 0; 1691 return 0;
1597 1692
@@ -1611,13 +1706,12 @@ read_config_file(const char *filename, struct passwd *pw, const char *host,
1611 * Mark that we are now processing the options. This flag is turned 1706 * Mark that we are now processing the options. This flag is turned
1612 * on/off by Host specifications. 1707 * on/off by Host specifications.
1613 */ 1708 */
1614 active = 1;
1615 linenum = 0; 1709 linenum = 0;
1616 while (fgets(line, sizeof(line), f)) { 1710 while (fgets(line, sizeof(line), f)) {
1617 /* Update line number counter. */ 1711 /* Update line number counter. */
1618 linenum++; 1712 linenum++;
1619 if (process_config_line(options, pw, host, original_host, 1713 if (process_config_line_depth(options, pw, host, original_host,
1620 line, filename, linenum, &active, flags) != 0) 1714 line, filename, linenum, activep, flags, depth) != 0)
1621 bad_options++; 1715 bad_options++;
1622 } 1716 }
1623 fclose(f); 1717 fclose(f);
diff --git a/readconf.h b/readconf.h
index c84d068bd..5f4451066 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.h,v 1.113 2016/01/14 16:17:40 markus Exp $ */ 1/* $OpenBSD: readconf.h,v 1.114 2016/04/15 00:30:19 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -179,6 +179,7 @@ typedef struct {
179#define SSHCONF_CHECKPERM 1 /* check permissions on config file */ 179#define SSHCONF_CHECKPERM 1 /* check permissions on config file */
180#define SSHCONF_USERCONF 2 /* user provided config file not system */ 180#define SSHCONF_USERCONF 2 /* user provided config file not system */
181#define SSHCONF_POSTCANON 4 /* After hostname canonicalisation */ 181#define SSHCONF_POSTCANON 4 /* After hostname canonicalisation */
182#define SSHCONF_NEVERMATCH 8 /* Match/Host never matches; internal only */
182 183
183#define SSH_UPDATE_HOSTKEYS_NO 0 184#define SSH_UPDATE_HOSTKEYS_NO 0
184#define SSH_UPDATE_HOSTKEYS_YES 1 185#define SSH_UPDATE_HOSTKEYS_YES 1
diff --git a/ssh.1 b/ssh.1
index cc5334338..85309ecc4 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.369 2016/02/17 07:38:19 jmc Exp $ 36.\" $OpenBSD: ssh.1,v 1.370 2016/04/15 00:30:19 djm Exp $
37.Dd $Mdocdate: February 17 2016 $ 37.Dd $Mdocdate: April 15 2016 $
38.Dt SSH 1 38.Dt SSH 1
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -503,6 +503,7 @@ For full details of the options listed below, and their possible values, see
503.It HostName 503.It HostName
504.It IdentityFile 504.It IdentityFile
505.It IdentitiesOnly 505.It IdentitiesOnly
506.It Include
506.It IPQoS 507.It IPQoS
507.It KbdInteractiveAuthentication 508.It KbdInteractiveAuthentication
508.It KbdInteractiveDevices 509.It KbdInteractiveDevices
diff --git a/ssh_config.5 b/ssh_config.5
index caf13a62d..880f11049 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.228 2016/02/20 23:01:46 sobrado Exp $ 36.\" $OpenBSD: ssh_config.5,v 1.229 2016/04/15 00:30:19 djm Exp $
37.Dd $Mdocdate: February 20 2016 $ 37.Dd $Mdocdate: April 15 2016 $
38.Dt SSH_CONFIG 5 38.Dt SSH_CONFIG 5
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -1019,6 +1019,25 @@ It is recommended that
1019.Cm IgnoreUnknown 1019.Cm IgnoreUnknown
1020be listed early in the configuration file as it will not be applied 1020be listed early in the configuration file as it will not be applied
1021to unknown options that appear before it. 1021to unknown options that appear before it.
1022.It Cm Include
1023Include the specified configuration file(s).
1024Multiple path names may be specified and each pathname may contain
1025.Xr glob 3
1026wildcards and, for user configurations, shell-like
1027.Dq ~
1028references to user home directories.
1029Files without absolute paths are assumed to be in
1030.Pa ~/.ssh
1031if included in a user configurations file or
1032.Pa /etc/ssh
1033if included from the system configuration file.
1034.Cm Include
1035directive may appear inside a
1036.Cm Match
1037or
1038.Cm Host
1039block
1040to perform conditional inclusion.
1022.It Cm IPQoS 1041.It Cm IPQoS
1023Specifies the IPv4 type-of-service or DSCP class for connections. 1042Specifies the IPv4 type-of-service or DSCP class for connections.
1024Accepted values are 1043Accepted values are