summaryrefslogtreecommitdiff
path: root/readconf.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2014-07-18 14:11:24 +1000
committerDamien Miller <djm@mindrot.org>2014-07-18 14:11:24 +1000
commit7acefbbcbeab725420ea07397ae35992f505f702 (patch)
treebfb07917715d425438dab987a47ccd7a8d7f118b /readconf.c
parent6262d760e00714523633bd989d62e273a3dca99a (diff)
- millert@cvs.openbsd.org 2014/07/15 15:54:14
[PROTOCOL auth-options.c auth-passwd.c auth-rh-rsa.c auth-rhosts.c] [auth-rsa.c auth.c auth1.c auth2-hostbased.c auth2-kbdint.c auth2-none.c] [auth2-passwd.c auth2-pubkey.c auth2.c canohost.c channels.c channels.h] [clientloop.c misc.c misc.h monitor.c mux.c packet.c readconf.c] [readconf.h servconf.c servconf.h serverloop.c session.c ssh-agent.c] [ssh.c ssh_config.5 sshconnect.c sshconnect1.c sshconnect2.c sshd.c] [sshd_config.5 sshlogin.c] Add support for Unix domain socket forwarding. A remote TCP port may be forwarded to a local Unix domain socket and vice versa or both ends may be a Unix domain socket. This is a reimplementation of the streamlocal patches by William Ahern from: http://www.25thandclement.com/~william/projects/streamlocal.html OK djm@ markus@
Diffstat (limited to 'readconf.c')
-rw-r--r--readconf.c224
1 files changed, 186 insertions, 38 deletions
diff --git a/readconf.c b/readconf.c
index a4ecf7a0b..7948ce1cd 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.c,v 1.219 2014/04/23 12:42:34 djm Exp $ */ 1/* $OpenBSD: readconf.c,v 1.220 2014/07/15 15:54:14 millert 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
@@ -18,6 +18,7 @@
18#include <sys/stat.h> 18#include <sys/stat.h>
19#include <sys/socket.h> 19#include <sys/socket.h>
20#include <sys/wait.h> 20#include <sys/wait.h>
21#include <sys/un.h>
21 22
22#include <netinet/in.h> 23#include <netinet/in.h>
23#include <netinet/in_systm.h> 24#include <netinet/in_systm.h>
@@ -48,9 +49,9 @@
48#include "pathnames.h" 49#include "pathnames.h"
49#include "log.h" 50#include "log.h"
50#include "key.h" 51#include "key.h"
52#include "misc.h"
51#include "readconf.h" 53#include "readconf.h"
52#include "match.h" 54#include "match.h"
53#include "misc.h"
54#include "buffer.h" 55#include "buffer.h"
55#include "kex.h" 56#include "kex.h"
56#include "mac.h" 57#include "mac.h"
@@ -149,6 +150,7 @@ typedef enum {
149 oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, 150 oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
150 oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, 151 oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
151 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, 152 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
153 oStreamLocalBindMask, oStreamLocalBindUnlink,
152 oIgnoredUnknownOption, oDeprecated, oUnsupported 154 oIgnoredUnknownOption, oDeprecated, oUnsupported
153} OpCodes; 155} OpCodes;
154 156
@@ -261,6 +263,8 @@ static struct {
261 { "canonicalizehostname", oCanonicalizeHostname }, 263 { "canonicalizehostname", oCanonicalizeHostname },
262 { "canonicalizemaxdots", oCanonicalizeMaxDots }, 264 { "canonicalizemaxdots", oCanonicalizeMaxDots },
263 { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs }, 265 { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
266 { "streamlocalbindmask", oStreamLocalBindMask },
267 { "streamlocalbindunlink", oStreamLocalBindUnlink },
264 { "ignoreunknown", oIgnoreUnknown }, 268 { "ignoreunknown", oIgnoreUnknown },
265 269
266 { NULL, oBadOption } 270 { NULL, oBadOption }
@@ -272,12 +276,13 @@ static struct {
272 */ 276 */
273 277
274void 278void
275add_local_forward(Options *options, const Forward *newfwd) 279add_local_forward(Options *options, const struct Forward *newfwd)
276{ 280{
277 Forward *fwd; 281 struct Forward *fwd;
278#ifndef NO_IPPORT_RESERVED_CONCEPT 282#ifndef NO_IPPORT_RESERVED_CONCEPT
279 extern uid_t original_real_uid; 283 extern uid_t original_real_uid;
280 if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0) 284 if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0 &&
285 newfwd->listen_path == NULL)
281 fatal("Privileged ports can only be forwarded by root."); 286 fatal("Privileged ports can only be forwarded by root.");
282#endif 287#endif
283 options->local_forwards = xrealloc(options->local_forwards, 288 options->local_forwards = xrealloc(options->local_forwards,
@@ -287,8 +292,10 @@ add_local_forward(Options *options, const Forward *newfwd)
287 292
288 fwd->listen_host = newfwd->listen_host; 293 fwd->listen_host = newfwd->listen_host;
289 fwd->listen_port = newfwd->listen_port; 294 fwd->listen_port = newfwd->listen_port;
295 fwd->listen_path = newfwd->listen_path;
290 fwd->connect_host = newfwd->connect_host; 296 fwd->connect_host = newfwd->connect_host;
291 fwd->connect_port = newfwd->connect_port; 297 fwd->connect_port = newfwd->connect_port;
298 fwd->connect_path = newfwd->connect_path;
292} 299}
293 300
294/* 301/*
@@ -297,9 +304,9 @@ add_local_forward(Options *options, const Forward *newfwd)
297 */ 304 */
298 305
299void 306void
300add_remote_forward(Options *options, const Forward *newfwd) 307add_remote_forward(Options *options, const struct Forward *newfwd)
301{ 308{
302 Forward *fwd; 309 struct Forward *fwd;
303 310
304 options->remote_forwards = xrealloc(options->remote_forwards, 311 options->remote_forwards = xrealloc(options->remote_forwards,
305 options->num_remote_forwards + 1, 312 options->num_remote_forwards + 1,
@@ -308,8 +315,10 @@ add_remote_forward(Options *options, const Forward *newfwd)
308 315
309 fwd->listen_host = newfwd->listen_host; 316 fwd->listen_host = newfwd->listen_host;
310 fwd->listen_port = newfwd->listen_port; 317 fwd->listen_port = newfwd->listen_port;
318 fwd->listen_path = newfwd->listen_path;
311 fwd->connect_host = newfwd->connect_host; 319 fwd->connect_host = newfwd->connect_host;
312 fwd->connect_port = newfwd->connect_port; 320 fwd->connect_port = newfwd->connect_port;
321 fwd->connect_path = newfwd->connect_path;
313 fwd->handle = newfwd->handle; 322 fwd->handle = newfwd->handle;
314 fwd->allocated_port = 0; 323 fwd->allocated_port = 0;
315} 324}
@@ -321,7 +330,9 @@ clear_forwardings(Options *options)
321 330
322 for (i = 0; i < options->num_local_forwards; i++) { 331 for (i = 0; i < options->num_local_forwards; i++) {
323 free(options->local_forwards[i].listen_host); 332 free(options->local_forwards[i].listen_host);
333 free(options->local_forwards[i].listen_path);
324 free(options->local_forwards[i].connect_host); 334 free(options->local_forwards[i].connect_host);
335 free(options->local_forwards[i].connect_path);
325 } 336 }
326 if (options->num_local_forwards > 0) { 337 if (options->num_local_forwards > 0) {
327 free(options->local_forwards); 338 free(options->local_forwards);
@@ -330,7 +341,9 @@ clear_forwardings(Options *options)
330 options->num_local_forwards = 0; 341 options->num_local_forwards = 0;
331 for (i = 0; i < options->num_remote_forwards; i++) { 342 for (i = 0; i < options->num_remote_forwards; i++) {
332 free(options->remote_forwards[i].listen_host); 343 free(options->remote_forwards[i].listen_host);
344 free(options->remote_forwards[i].listen_path);
333 free(options->remote_forwards[i].connect_host); 345 free(options->remote_forwards[i].connect_host);
346 free(options->remote_forwards[i].connect_path);
334 } 347 }
335 if (options->num_remote_forwards > 0) { 348 if (options->num_remote_forwards > 0) {
336 free(options->remote_forwards); 349 free(options->remote_forwards);
@@ -715,7 +728,7 @@ process_config_line(Options *options, struct passwd *pw, const char *host,
715 LogLevel *log_level_ptr; 728 LogLevel *log_level_ptr;
716 long long val64; 729 long long val64;
717 size_t len; 730 size_t len;
718 Forward fwd; 731 struct Forward fwd;
719 const struct multistate *multistate_ptr; 732 const struct multistate *multistate_ptr;
720 struct allowed_cname *cname; 733 struct allowed_cname *cname;
721 734
@@ -805,7 +818,7 @@ parse_time:
805 goto parse_time; 818 goto parse_time;
806 819
807 case oGatewayPorts: 820 case oGatewayPorts:
808 intptr = &options->gateway_ports; 821 intptr = &options->fwd_opts.gateway_ports;
809 goto parse_flag; 822 goto parse_flag;
810 823
811 case oExitOnForwardFailure: 824 case oExitOnForwardFailure:
@@ -1405,6 +1418,21 @@ parse_int:
1405 intptr = &options->canonicalize_fallback_local; 1418 intptr = &options->canonicalize_fallback_local;
1406 goto parse_flag; 1419 goto parse_flag;
1407 1420
1421 case oStreamLocalBindMask:
1422 arg = strdelim(&s);
1423 if (!arg || *arg == '\0')
1424 fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
1425 /* Parse mode in octal format */
1426 value = strtol(arg, &endofnumber, 8);
1427 if (arg == endofnumber || value < 0 || value > 0777)
1428 fatal("%.200s line %d: Bad mask.", filename, linenum);
1429 options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
1430 break;
1431
1432 case oStreamLocalBindUnlink:
1433 intptr = &options->fwd_opts.streamlocal_bind_unlink;
1434 goto parse_flag;
1435
1408 case oDeprecated: 1436 case oDeprecated:
1409 debug("%s line %d: Deprecated option \"%s\"", 1437 debug("%s line %d: Deprecated option \"%s\"",
1410 filename, linenum, keyword); 1438 filename, linenum, keyword);
@@ -1502,7 +1530,9 @@ initialize_options(Options * options)
1502 options->forward_x11_timeout = -1; 1530 options->forward_x11_timeout = -1;
1503 options->exit_on_forward_failure = -1; 1531 options->exit_on_forward_failure = -1;
1504 options->xauth_location = NULL; 1532 options->xauth_location = NULL;
1505 options->gateway_ports = -1; 1533 options->fwd_opts.gateway_ports = -1;
1534 options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
1535 options->fwd_opts.streamlocal_bind_unlink = -1;
1506 options->use_privileged_port = -1; 1536 options->use_privileged_port = -1;
1507 options->rsa_authentication = -1; 1537 options->rsa_authentication = -1;
1508 options->pubkey_authentication = -1; 1538 options->pubkey_authentication = -1;
@@ -1615,8 +1645,12 @@ fill_default_options(Options * options)
1615 options->exit_on_forward_failure = 0; 1645 options->exit_on_forward_failure = 0;
1616 if (options->xauth_location == NULL) 1646 if (options->xauth_location == NULL)
1617 options->xauth_location = _PATH_XAUTH; 1647 options->xauth_location = _PATH_XAUTH;
1618 if (options->gateway_ports == -1) 1648 if (options->fwd_opts.gateway_ports == -1)
1619 options->gateway_ports = 0; 1649 options->fwd_opts.gateway_ports = 0;
1650 if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
1651 options->fwd_opts.streamlocal_bind_mask = 0177;
1652 if (options->fwd_opts.streamlocal_bind_unlink == -1)
1653 options->fwd_opts.streamlocal_bind_unlink = 0;
1620 if (options->use_privileged_port == -1) 1654 if (options->use_privileged_port == -1)
1621 options->use_privileged_port = 0; 1655 options->use_privileged_port = 0;
1622 if (options->rsa_authentication == -1) 1656 if (options->rsa_authentication == -1)
@@ -1768,22 +1802,92 @@ fill_default_options(Options * options)
1768 /* options->preferred_authentications will be set in ssh */ 1802 /* options->preferred_authentications will be set in ssh */
1769} 1803}
1770 1804
1805struct fwdarg {
1806 char *arg;
1807 int ispath;
1808};
1809
1810/*
1811 * parse_fwd_field
1812 * parses the next field in a port forwarding specification.
1813 * sets fwd to the parsed field and advances p past the colon
1814 * or sets it to NULL at end of string.
1815 * returns 0 on success, else non-zero.
1816 */
1817static int
1818parse_fwd_field(char **p, struct fwdarg *fwd)
1819{
1820 char *ep, *cp = *p;
1821 int ispath = 0;
1822
1823 if (*cp == '\0') {
1824 *p = NULL;
1825 return -1; /* end of string */
1826 }
1827
1828 /*
1829 * A field escaped with square brackets is used literally.
1830 * XXX - allow ']' to be escaped via backslash?
1831 */
1832 if (*cp == '[') {
1833 /* find matching ']' */
1834 for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
1835 if (*ep == '/')
1836 ispath = 1;
1837 }
1838 /* no matching ']' or not at end of field. */
1839 if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
1840 return -1;
1841 /* NUL terminate the field and advance p past the colon */
1842 *ep++ = '\0';
1843 if (*ep != '\0')
1844 *ep++ = '\0';
1845 fwd->arg = cp + 1;
1846 fwd->ispath = ispath;
1847 *p = ep;
1848 return 0;
1849 }
1850
1851 for (cp = *p; *cp != '\0'; cp++) {
1852 switch (*cp) {
1853 case '\\':
1854 memmove(cp, cp + 1, strlen(cp + 1) + 1);
1855 cp++;
1856 break;
1857 case '/':
1858 ispath = 1;
1859 break;
1860 case ':':
1861 *cp++ = '\0';
1862 goto done;
1863 }
1864 }
1865done:
1866 fwd->arg = *p;
1867 fwd->ispath = ispath;
1868 *p = cp;
1869 return 0;
1870}
1871
1771/* 1872/*
1772 * parse_forward 1873 * parse_forward
1773 * parses a string containing a port forwarding specification of the form: 1874 * parses a string containing a port forwarding specification of the form:
1774 * dynamicfwd == 0 1875 * dynamicfwd == 0
1775 * [listenhost:]listenport:connecthost:connectport 1876 * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
1877 * listenpath:connectpath
1776 * dynamicfwd == 1 1878 * dynamicfwd == 1
1777 * [listenhost:]listenport 1879 * [listenhost:]listenport
1778 * returns number of arguments parsed or zero on error 1880 * returns number of arguments parsed or zero on error
1779 */ 1881 */
1780int 1882int
1781parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd) 1883parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1782{ 1884{
1885 struct fwdarg fwdargs[4];
1886 char *p, *cp;
1783 int i; 1887 int i;
1784 char *p, *cp, *fwdarg[4];
1785 1888
1786 memset(fwd, '\0', sizeof(*fwd)); 1889 memset(fwd, 0, sizeof(*fwd));
1890 memset(fwdargs, 0, sizeof(fwdargs));
1787 1891
1788 cp = p = xstrdup(fwdspec); 1892 cp = p = xstrdup(fwdspec);
1789 1893
@@ -1791,39 +1895,70 @@ parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1791 while (isspace((u_char)*cp)) 1895 while (isspace((u_char)*cp))
1792 cp++; 1896 cp++;
1793 1897
1794 for (i = 0; i < 4; ++i) 1898 for (i = 0; i < 4; ++i) {
1795 if ((fwdarg[i] = hpdelim(&cp)) == NULL) 1899 if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
1796 break; 1900 break;
1901 }
1797 1902
1798 /* Check for trailing garbage */ 1903 /* Check for trailing garbage */
1799 if (cp != NULL) 1904 if (cp != NULL && *cp != '\0') {
1800 i = 0; /* failure */ 1905 i = 0; /* failure */
1906 }
1801 1907
1802 switch (i) { 1908 switch (i) {
1803 case 1: 1909 case 1:
1804 fwd->listen_host = NULL; 1910 if (fwdargs[0].ispath) {
1805 fwd->listen_port = a2port(fwdarg[0]); 1911 fwd->listen_path = xstrdup(fwdargs[0].arg);
1912 fwd->listen_port = PORT_STREAMLOCAL;
1913 } else {
1914 fwd->listen_host = NULL;
1915 fwd->listen_port = a2port(fwdargs[0].arg);
1916 }
1806 fwd->connect_host = xstrdup("socks"); 1917 fwd->connect_host = xstrdup("socks");
1807 break; 1918 break;
1808 1919
1809 case 2: 1920 case 2:
1810 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0])); 1921 if (fwdargs[0].ispath && fwdargs[1].ispath) {
1811 fwd->listen_port = a2port(fwdarg[1]); 1922 fwd->listen_path = xstrdup(fwdargs[0].arg);
1812 fwd->connect_host = xstrdup("socks"); 1923 fwd->listen_port = PORT_STREAMLOCAL;
1924 fwd->connect_path = xstrdup(fwdargs[1].arg);
1925 fwd->connect_port = PORT_STREAMLOCAL;
1926 } else if (fwdargs[1].ispath) {
1927 fwd->listen_host = NULL;
1928 fwd->listen_port = a2port(fwdargs[0].arg);
1929 fwd->connect_path = xstrdup(fwdargs[1].arg);
1930 fwd->connect_port = PORT_STREAMLOCAL;
1931 } else {
1932 fwd->listen_host = xstrdup(fwdargs[0].arg);
1933 fwd->listen_port = a2port(fwdargs[1].arg);
1934 fwd->connect_host = xstrdup("socks");
1935 }
1813 break; 1936 break;
1814 1937
1815 case 3: 1938 case 3:
1816 fwd->listen_host = NULL; 1939 if (fwdargs[0].ispath) {
1817 fwd->listen_port = a2port(fwdarg[0]); 1940 fwd->listen_path = xstrdup(fwdargs[0].arg);
1818 fwd->connect_host = xstrdup(cleanhostname(fwdarg[1])); 1941 fwd->listen_port = PORT_STREAMLOCAL;
1819 fwd->connect_port = a2port(fwdarg[2]); 1942 fwd->connect_host = xstrdup(fwdargs[1].arg);
1943 fwd->connect_port = a2port(fwdargs[2].arg);
1944 } else if (fwdargs[2].ispath) {
1945 fwd->listen_host = xstrdup(fwdargs[0].arg);
1946 fwd->listen_port = a2port(fwdargs[1].arg);
1947 fwd->connect_path = xstrdup(fwdargs[2].arg);
1948 fwd->connect_port = PORT_STREAMLOCAL;
1949 } else {
1950 fwd->listen_host = NULL;
1951 fwd->listen_port = a2port(fwdargs[0].arg);
1952 fwd->connect_host = xstrdup(fwdargs[1].arg);
1953 fwd->connect_port = a2port(fwdargs[2].arg);
1954 }
1820 break; 1955 break;
1821 1956
1822 case 4: 1957 case 4:
1823 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0])); 1958 fwd->listen_host = xstrdup(fwdargs[0].arg);
1824 fwd->listen_port = a2port(fwdarg[1]); 1959 fwd->listen_port = a2port(fwdargs[1].arg);
1825 fwd->connect_host = xstrdup(cleanhostname(fwdarg[2])); 1960 fwd->connect_host = xstrdup(fwdargs[2].arg);
1826 fwd->connect_port = a2port(fwdarg[3]); 1961 fwd->connect_port = a2port(fwdargs[3].arg);
1827 break; 1962 break;
1828 default: 1963 default:
1829 i = 0; /* failure */ 1964 i = 0; /* failure */
@@ -1835,29 +1970,42 @@ parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1835 if (!(i == 1 || i == 2)) 1970 if (!(i == 1 || i == 2))
1836 goto fail_free; 1971 goto fail_free;
1837 } else { 1972 } else {
1838 if (!(i == 3 || i == 4)) 1973 if (!(i == 3 || i == 4)) {
1839 goto fail_free; 1974 if (fwd->connect_path == NULL &&
1840 if (fwd->connect_port <= 0) 1975 fwd->listen_path == NULL)
1976 goto fail_free;
1977 }
1978 if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
1841 goto fail_free; 1979 goto fail_free;
1842 } 1980 }
1843 1981
1844 if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0)) 1982 if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
1983 (!remotefwd && fwd->listen_port == 0))
1845 goto fail_free; 1984 goto fail_free;
1846
1847 if (fwd->connect_host != NULL && 1985 if (fwd->connect_host != NULL &&
1848 strlen(fwd->connect_host) >= NI_MAXHOST) 1986 strlen(fwd->connect_host) >= NI_MAXHOST)
1849 goto fail_free; 1987 goto fail_free;
1988 /* XXX - if connecting to a remote socket, max sun len may not match this host */
1989 if (fwd->connect_path != NULL &&
1990 strlen(fwd->connect_path) >= PATH_MAX_SUN)
1991 goto fail_free;
1850 if (fwd->listen_host != NULL && 1992 if (fwd->listen_host != NULL &&
1851 strlen(fwd->listen_host) >= NI_MAXHOST) 1993 strlen(fwd->listen_host) >= NI_MAXHOST)
1852 goto fail_free; 1994 goto fail_free;
1853 1995 if (fwd->listen_path != NULL &&
1996 strlen(fwd->listen_path) >= PATH_MAX_SUN)
1997 goto fail_free;
1854 1998
1855 return (i); 1999 return (i);
1856 2000
1857 fail_free: 2001 fail_free:
1858 free(fwd->connect_host); 2002 free(fwd->connect_host);
1859 fwd->connect_host = NULL; 2003 fwd->connect_host = NULL;
2004 free(fwd->connect_path);
2005 fwd->connect_path = NULL;
1860 free(fwd->listen_host); 2006 free(fwd->listen_host);
1861 fwd->listen_host = NULL; 2007 fwd->listen_host = NULL;
2008 free(fwd->listen_path);
2009 fwd->listen_path = NULL;
1862 return (0); 2010 return (0);
1863} 2011}