diff options
author | djm@openbsd.org <djm@openbsd.org> | 2016-04-15 00:30:19 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2016-04-15 11:16:11 +1000 |
commit | dc7990be865450574c7940c9880567f5d2555b37 (patch) | |
tree | 1e36b3a59b4a22b6bd649cadb6118193287d8420 | |
parent | 85bdcd7c92fe7ff133bbc4e10a65c91810f88755 (diff) |
upstream commit
Include directive for ssh_config(5); feedback & ok markus@
Upstream-ID: ae3b76e2e343322b9f74acde6f1e1c5f027d5fff
-rw-r--r-- | readconf.c | 116 | ||||
-rw-r--r-- | readconf.h | 3 | ||||
-rw-r--r-- | ssh.1 | 5 | ||||
-rw-r--r-- | ssh_config.5 | 23 |
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 | ||
133 | static 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); | ||
136 | static 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 | ||
130 | typedef enum { | 142 | typedef 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" | ||
787 | int | 799 | int |
788 | process_config_line(Options *options, struct passwd *pw, const char *host, | 800 | process_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" | ||
809 | static int | ||
810 | process_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 | |||
1586 | int | 1666 | int |
1587 | read_config_file(const char *filename, struct passwd *pw, const char *host, | 1667 | read_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 | ||
1677 | static int | ||
1678 | read_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 |
@@ -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 |
1020 | be listed early in the configuration file as it will not be applied | 1020 | be listed early in the configuration file as it will not be applied |
1021 | to unknown options that appear before it. | 1021 | to unknown options that appear before it. |
1022 | .It Cm Include | ||
1023 | Include the specified configuration file(s). | ||
1024 | Multiple path names may be specified and each pathname may contain | ||
1025 | .Xr glob 3 | ||
1026 | wildcards and, for user configurations, shell-like | ||
1027 | .Dq ~ | ||
1028 | references to user home directories. | ||
1029 | Files without absolute paths are assumed to be in | ||
1030 | .Pa ~/.ssh | ||
1031 | if included in a user configurations file or | ||
1032 | .Pa /etc/ssh | ||
1033 | if included from the system configuration file. | ||
1034 | .Cm Include | ||
1035 | directive may appear inside a | ||
1036 | .Cm Match | ||
1037 | or | ||
1038 | .Cm Host | ||
1039 | block | ||
1040 | to perform conditional inclusion. | ||
1022 | .It Cm IPQoS | 1041 | .It Cm IPQoS |
1023 | Specifies the IPv4 type-of-service or DSCP class for connections. | 1042 | Specifies the IPv4 type-of-service or DSCP class for connections. |
1024 | Accepted values are | 1043 | Accepted values are |