summaryrefslogtreecommitdiff
path: root/readconf.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2014-10-07 13:33:15 +0100
committerColin Watson <cjwatson@debian.org>2014-10-07 14:27:30 +0100
commitf0b009aea83e9ff3a50be30f51012099a5143c16 (patch)
tree3825e6f7e3b7ea4481d06ed89aba9a7a95150df5 /readconf.c
parent47f0bad4330b16ec3bad870fcf9839c196e42c12 (diff)
parent762c062828f5a8f6ed189ed6e44ad38fd92f8b36 (diff)
Merge 6.7p1.
* New upstream release (http://www.openssh.com/txt/release-6.7): - sshd(8): The default set of ciphers and MACs has been altered to remove unsafe algorithms. In particular, CBC ciphers and arcfour* are disabled by default. The full set of algorithms remains available if configured explicitly via the Ciphers and MACs sshd_config options. - ssh(1), sshd(8): 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 (closes: #236718). - ssh(1), ssh-keygen(1): Add support for SSHFP DNS records for ED25519 key types. - sftp(1): Allow resumption of interrupted uploads. - ssh(1): When rekeying, skip file/DNS lookups of the hostkey if it is the same as the one sent during initial key exchange. - sshd(8): Allow explicit ::1 and 127.0.0.1 forwarding bind addresses when GatewayPorts=no; allows client to choose address family. - sshd(8): Add a sshd_config PermitUserRC option to control whether ~/.ssh/rc is executed, mirroring the no-user-rc authorized_keys option. - ssh(1): Add a %C escape sequence for LocalCommand and ControlPath that expands to a unique identifer based on a hash of the tuple of (local host, remote user, hostname, port). Helps avoid exceeding miserly pathname limits for Unix domain sockets in multiplexing control paths. - sshd(8): Make the "Too many authentication failures" message include the user, source address, port and protocol in a format similar to the authentication success / failure messages. - Use CLOCK_BOOTTIME in preference to CLOCK_MONOTONIC when it is available. It considers time spent suspended, thereby ensuring timeouts (e.g. for expiring agent keys) fire correctly (closes: #734553). - Use prctl() to prevent sftp-server from accessing /proc/self/{mem,maps}. * Restore TCP wrappers support, removed upstream in 6.7. It is true that dropping this reduces preauth attack surface in sshd. On the other hand, this support seems to be quite widely used, and abruptly dropping it (from the perspective of users who don't read openssh-unix-dev) could easily cause more serious problems in practice. It's not entirely clear what the right long-term answer for Debian is, but it at least probably doesn't involve dropping this feature shortly before a freeze. * Replace patch to disable OpenSSL version check with an updated version of Kurt Roeckx's patch from #732940 to just avoid checking the status field.
Diffstat (limited to 'readconf.c')
-rw-r--r--readconf.c235
1 files changed, 197 insertions, 38 deletions
diff --git a/readconf.c b/readconf.c
index 5429fc2ad..29338b619 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.c,v 1.218 2014/02/23 20:11:36 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>
@@ -50,9 +51,9 @@
50#include "pathnames.h" 51#include "pathnames.h"
51#include "log.h" 52#include "log.h"
52#include "key.h" 53#include "key.h"
54#include "misc.h"
53#include "readconf.h" 55#include "readconf.h"
54#include "match.h" 56#include "match.h"
55#include "misc.h"
56#include "buffer.h" 57#include "buffer.h"
57#include "kex.h" 58#include "kex.h"
58#include "mac.h" 59#include "mac.h"
@@ -153,6 +154,7 @@ typedef enum {
153 oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, 154 oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
154 oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, 155 oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
155 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, 156 oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
157 oStreamLocalBindMask, oStreamLocalBindUnlink,
156 oProtocolKeepAlives, oSetupTimeOut, 158 oProtocolKeepAlives, oSetupTimeOut,
157 oIgnoredUnknownOption, oDeprecated, oUnsupported 159 oIgnoredUnknownOption, oDeprecated, oUnsupported
158} OpCodes; 160} OpCodes;
@@ -276,6 +278,8 @@ static struct {
276 { "canonicalizehostname", oCanonicalizeHostname }, 278 { "canonicalizehostname", oCanonicalizeHostname },
277 { "canonicalizemaxdots", oCanonicalizeMaxDots }, 279 { "canonicalizemaxdots", oCanonicalizeMaxDots },
278 { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs }, 280 { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
281 { "streamlocalbindmask", oStreamLocalBindMask },
282 { "streamlocalbindunlink", oStreamLocalBindUnlink },
279 { "ignoreunknown", oIgnoreUnknown }, 283 { "ignoreunknown", oIgnoreUnknown },
280 { "protocolkeepalives", oProtocolKeepAlives }, 284 { "protocolkeepalives", oProtocolKeepAlives },
281 { "setuptimeout", oSetupTimeOut }, 285 { "setuptimeout", oSetupTimeOut },
@@ -289,12 +293,13 @@ static struct {
289 */ 293 */
290 294
291void 295void
292add_local_forward(Options *options, const Forward *newfwd) 296add_local_forward(Options *options, const struct Forward *newfwd)
293{ 297{
294 Forward *fwd; 298 struct Forward *fwd;
295#ifndef NO_IPPORT_RESERVED_CONCEPT 299#ifndef NO_IPPORT_RESERVED_CONCEPT
296 extern uid_t original_real_uid; 300 extern uid_t original_real_uid;
297 if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0) 301 if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0 &&
302 newfwd->listen_path == NULL)
298 fatal("Privileged ports can only be forwarded by root."); 303 fatal("Privileged ports can only be forwarded by root.");
299#endif 304#endif
300 options->local_forwards = xrealloc(options->local_forwards, 305 options->local_forwards = xrealloc(options->local_forwards,
@@ -304,8 +309,10 @@ add_local_forward(Options *options, const Forward *newfwd)
304 309
305 fwd->listen_host = newfwd->listen_host; 310 fwd->listen_host = newfwd->listen_host;
306 fwd->listen_port = newfwd->listen_port; 311 fwd->listen_port = newfwd->listen_port;
312 fwd->listen_path = newfwd->listen_path;
307 fwd->connect_host = newfwd->connect_host; 313 fwd->connect_host = newfwd->connect_host;
308 fwd->connect_port = newfwd->connect_port; 314 fwd->connect_port = newfwd->connect_port;
315 fwd->connect_path = newfwd->connect_path;
309} 316}
310 317
311/* 318/*
@@ -314,9 +321,9 @@ add_local_forward(Options *options, const Forward *newfwd)
314 */ 321 */
315 322
316void 323void
317add_remote_forward(Options *options, const Forward *newfwd) 324add_remote_forward(Options *options, const struct Forward *newfwd)
318{ 325{
319 Forward *fwd; 326 struct Forward *fwd;
320 327
321 options->remote_forwards = xrealloc(options->remote_forwards, 328 options->remote_forwards = xrealloc(options->remote_forwards,
322 options->num_remote_forwards + 1, 329 options->num_remote_forwards + 1,
@@ -325,8 +332,10 @@ add_remote_forward(Options *options, const Forward *newfwd)
325 332
326 fwd->listen_host = newfwd->listen_host; 333 fwd->listen_host = newfwd->listen_host;
327 fwd->listen_port = newfwd->listen_port; 334 fwd->listen_port = newfwd->listen_port;
335 fwd->listen_path = newfwd->listen_path;
328 fwd->connect_host = newfwd->connect_host; 336 fwd->connect_host = newfwd->connect_host;
329 fwd->connect_port = newfwd->connect_port; 337 fwd->connect_port = newfwd->connect_port;
338 fwd->connect_path = newfwd->connect_path;
330 fwd->handle = newfwd->handle; 339 fwd->handle = newfwd->handle;
331 fwd->allocated_port = 0; 340 fwd->allocated_port = 0;
332} 341}
@@ -338,7 +347,9 @@ clear_forwardings(Options *options)
338 347
339 for (i = 0; i < options->num_local_forwards; i++) { 348 for (i = 0; i < options->num_local_forwards; i++) {
340 free(options->local_forwards[i].listen_host); 349 free(options->local_forwards[i].listen_host);
350 free(options->local_forwards[i].listen_path);
341 free(options->local_forwards[i].connect_host); 351 free(options->local_forwards[i].connect_host);
352 free(options->local_forwards[i].connect_path);
342 } 353 }
343 if (options->num_local_forwards > 0) { 354 if (options->num_local_forwards > 0) {
344 free(options->local_forwards); 355 free(options->local_forwards);
@@ -347,7 +358,9 @@ clear_forwardings(Options *options)
347 options->num_local_forwards = 0; 358 options->num_local_forwards = 0;
348 for (i = 0; i < options->num_remote_forwards; i++) { 359 for (i = 0; i < options->num_remote_forwards; i++) {
349 free(options->remote_forwards[i].listen_host); 360 free(options->remote_forwards[i].listen_host);
361 free(options->remote_forwards[i].listen_path);
350 free(options->remote_forwards[i].connect_host); 362 free(options->remote_forwards[i].connect_host);
363 free(options->remote_forwards[i].connect_path);
351 } 364 }
352 if (options->num_remote_forwards > 0) { 365 if (options->num_remote_forwards > 0) {
353 free(options->remote_forwards); 366 free(options->remote_forwards);
@@ -362,6 +375,7 @@ add_identity_file(Options *options, const char *dir, const char *filename,
362 int userprovided) 375 int userprovided)
363{ 376{
364 char *path; 377 char *path;
378 int i;
365 379
366 if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES) 380 if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
367 fatal("Too many identity files specified (max %d)", 381 fatal("Too many identity files specified (max %d)",
@@ -372,6 +386,16 @@ add_identity_file(Options *options, const char *dir, const char *filename,
372 else 386 else
373 (void)xasprintf(&path, "%.100s%.100s", dir, filename); 387 (void)xasprintf(&path, "%.100s%.100s", dir, filename);
374 388
389 /* Avoid registering duplicates */
390 for (i = 0; i < options->num_identity_files; i++) {
391 if (options->identity_file_userprovided[i] == userprovided &&
392 strcmp(options->identity_files[i], path) == 0) {
393 debug2("%s: ignoring duplicate key %s", __func__, path);
394 free(path);
395 return;
396 }
397 }
398
375 options->identity_file_userprovided[options->num_identity_files] = 399 options->identity_file_userprovided[options->num_identity_files] =
376 userprovided; 400 userprovided;
377 options->identity_files[options->num_identity_files++] = path; 401 options->identity_files[options->num_identity_files++] = path;
@@ -721,7 +745,7 @@ process_config_line(Options *options, struct passwd *pw, const char *host,
721 LogLevel *log_level_ptr; 745 LogLevel *log_level_ptr;
722 long long val64; 746 long long val64;
723 size_t len; 747 size_t len;
724 Forward fwd; 748 struct Forward fwd;
725 const struct multistate *multistate_ptr; 749 const struct multistate *multistate_ptr;
726 struct allowed_cname *cname; 750 struct allowed_cname *cname;
727 751
@@ -811,7 +835,7 @@ parse_time:
811 goto parse_time; 835 goto parse_time;
812 836
813 case oGatewayPorts: 837 case oGatewayPorts:
814 intptr = &options->gateway_ports; 838 intptr = &options->fwd_opts.gateway_ports;
815 goto parse_flag; 839 goto parse_flag;
816 840
817 case oExitOnForwardFailure: 841 case oExitOnForwardFailure:
@@ -1433,6 +1457,21 @@ parse_int:
1433 intptr = &options->canonicalize_fallback_local; 1457 intptr = &options->canonicalize_fallback_local;
1434 goto parse_flag; 1458 goto parse_flag;
1435 1459
1460 case oStreamLocalBindMask:
1461 arg = strdelim(&s);
1462 if (!arg || *arg == '\0')
1463 fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
1464 /* Parse mode in octal format */
1465 value = strtol(arg, &endofnumber, 8);
1466 if (arg == endofnumber || value < 0 || value > 0777)
1467 fatal("%.200s line %d: Bad mask.", filename, linenum);
1468 options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
1469 break;
1470
1471 case oStreamLocalBindUnlink:
1472 intptr = &options->fwd_opts.streamlocal_bind_unlink;
1473 goto parse_flag;
1474
1436 case oDeprecated: 1475 case oDeprecated:
1437 debug("%s line %d: Deprecated option \"%s\"", 1476 debug("%s line %d: Deprecated option \"%s\"",
1438 filename, linenum, keyword); 1477 filename, linenum, keyword);
@@ -1529,7 +1568,9 @@ initialize_options(Options * options)
1529 options->forward_x11_timeout = -1; 1568 options->forward_x11_timeout = -1;
1530 options->exit_on_forward_failure = -1; 1569 options->exit_on_forward_failure = -1;
1531 options->xauth_location = NULL; 1570 options->xauth_location = NULL;
1532 options->gateway_ports = -1; 1571 options->fwd_opts.gateway_ports = -1;
1572 options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
1573 options->fwd_opts.streamlocal_bind_unlink = -1;
1533 options->use_privileged_port = -1; 1574 options->use_privileged_port = -1;
1534 options->rsa_authentication = -1; 1575 options->rsa_authentication = -1;
1535 options->pubkey_authentication = -1; 1576 options->pubkey_authentication = -1;
@@ -1647,8 +1688,12 @@ fill_default_options(Options * options)
1647 options->exit_on_forward_failure = 0; 1688 options->exit_on_forward_failure = 0;
1648 if (options->xauth_location == NULL) 1689 if (options->xauth_location == NULL)
1649 options->xauth_location = _PATH_XAUTH; 1690 options->xauth_location = _PATH_XAUTH;
1650 if (options->gateway_ports == -1) 1691 if (options->fwd_opts.gateway_ports == -1)
1651 options->gateway_ports = 0; 1692 options->fwd_opts.gateway_ports = 0;
1693 if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
1694 options->fwd_opts.streamlocal_bind_mask = 0177;
1695 if (options->fwd_opts.streamlocal_bind_unlink == -1)
1696 options->fwd_opts.streamlocal_bind_unlink = 0;
1652 if (options->use_privileged_port == -1) 1697 if (options->use_privileged_port == -1)
1653 options->use_privileged_port = 0; 1698 options->use_privileged_port = 0;
1654 if (options->rsa_authentication == -1) 1699 if (options->rsa_authentication == -1)
@@ -1811,22 +1856,92 @@ fill_default_options(Options * options)
1811 /* options->preferred_authentications will be set in ssh */ 1856 /* options->preferred_authentications will be set in ssh */
1812} 1857}
1813 1858
1859struct fwdarg {
1860 char *arg;
1861 int ispath;
1862};
1863
1864/*
1865 * parse_fwd_field
1866 * parses the next field in a port forwarding specification.
1867 * sets fwd to the parsed field and advances p past the colon
1868 * or sets it to NULL at end of string.
1869 * returns 0 on success, else non-zero.
1870 */
1871static int
1872parse_fwd_field(char **p, struct fwdarg *fwd)
1873{
1874 char *ep, *cp = *p;
1875 int ispath = 0;
1876
1877 if (*cp == '\0') {
1878 *p = NULL;
1879 return -1; /* end of string */
1880 }
1881
1882 /*
1883 * A field escaped with square brackets is used literally.
1884 * XXX - allow ']' to be escaped via backslash?
1885 */
1886 if (*cp == '[') {
1887 /* find matching ']' */
1888 for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
1889 if (*ep == '/')
1890 ispath = 1;
1891 }
1892 /* no matching ']' or not at end of field. */
1893 if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
1894 return -1;
1895 /* NUL terminate the field and advance p past the colon */
1896 *ep++ = '\0';
1897 if (*ep != '\0')
1898 *ep++ = '\0';
1899 fwd->arg = cp + 1;
1900 fwd->ispath = ispath;
1901 *p = ep;
1902 return 0;
1903 }
1904
1905 for (cp = *p; *cp != '\0'; cp++) {
1906 switch (*cp) {
1907 case '\\':
1908 memmove(cp, cp + 1, strlen(cp + 1) + 1);
1909 cp++;
1910 break;
1911 case '/':
1912 ispath = 1;
1913 break;
1914 case ':':
1915 *cp++ = '\0';
1916 goto done;
1917 }
1918 }
1919done:
1920 fwd->arg = *p;
1921 fwd->ispath = ispath;
1922 *p = cp;
1923 return 0;
1924}
1925
1814/* 1926/*
1815 * parse_forward 1927 * parse_forward
1816 * parses a string containing a port forwarding specification of the form: 1928 * parses a string containing a port forwarding specification of the form:
1817 * dynamicfwd == 0 1929 * dynamicfwd == 0
1818 * [listenhost:]listenport:connecthost:connectport 1930 * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
1931 * listenpath:connectpath
1819 * dynamicfwd == 1 1932 * dynamicfwd == 1
1820 * [listenhost:]listenport 1933 * [listenhost:]listenport
1821 * returns number of arguments parsed or zero on error 1934 * returns number of arguments parsed or zero on error
1822 */ 1935 */
1823int 1936int
1824parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd) 1937parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1825{ 1938{
1939 struct fwdarg fwdargs[4];
1940 char *p, *cp;
1826 int i; 1941 int i;
1827 char *p, *cp, *fwdarg[4];
1828 1942
1829 memset(fwd, '\0', sizeof(*fwd)); 1943 memset(fwd, 0, sizeof(*fwd));
1944 memset(fwdargs, 0, sizeof(fwdargs));
1830 1945
1831 cp = p = xstrdup(fwdspec); 1946 cp = p = xstrdup(fwdspec);
1832 1947
@@ -1834,39 +1949,70 @@ parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1834 while (isspace((u_char)*cp)) 1949 while (isspace((u_char)*cp))
1835 cp++; 1950 cp++;
1836 1951
1837 for (i = 0; i < 4; ++i) 1952 for (i = 0; i < 4; ++i) {
1838 if ((fwdarg[i] = hpdelim(&cp)) == NULL) 1953 if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
1839 break; 1954 break;
1955 }
1840 1956
1841 /* Check for trailing garbage */ 1957 /* Check for trailing garbage */
1842 if (cp != NULL) 1958 if (cp != NULL && *cp != '\0') {
1843 i = 0; /* failure */ 1959 i = 0; /* failure */
1960 }
1844 1961
1845 switch (i) { 1962 switch (i) {
1846 case 1: 1963 case 1:
1847 fwd->listen_host = NULL; 1964 if (fwdargs[0].ispath) {
1848 fwd->listen_port = a2port(fwdarg[0]); 1965 fwd->listen_path = xstrdup(fwdargs[0].arg);
1966 fwd->listen_port = PORT_STREAMLOCAL;
1967 } else {
1968 fwd->listen_host = NULL;
1969 fwd->listen_port = a2port(fwdargs[0].arg);
1970 }
1849 fwd->connect_host = xstrdup("socks"); 1971 fwd->connect_host = xstrdup("socks");
1850 break; 1972 break;
1851 1973
1852 case 2: 1974 case 2:
1853 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0])); 1975 if (fwdargs[0].ispath && fwdargs[1].ispath) {
1854 fwd->listen_port = a2port(fwdarg[1]); 1976 fwd->listen_path = xstrdup(fwdargs[0].arg);
1855 fwd->connect_host = xstrdup("socks"); 1977 fwd->listen_port = PORT_STREAMLOCAL;
1978 fwd->connect_path = xstrdup(fwdargs[1].arg);
1979 fwd->connect_port = PORT_STREAMLOCAL;
1980 } else if (fwdargs[1].ispath) {
1981 fwd->listen_host = NULL;
1982 fwd->listen_port = a2port(fwdargs[0].arg);
1983 fwd->connect_path = xstrdup(fwdargs[1].arg);
1984 fwd->connect_port = PORT_STREAMLOCAL;
1985 } else {
1986 fwd->listen_host = xstrdup(fwdargs[0].arg);
1987 fwd->listen_port = a2port(fwdargs[1].arg);
1988 fwd->connect_host = xstrdup("socks");
1989 }
1856 break; 1990 break;
1857 1991
1858 case 3: 1992 case 3:
1859 fwd->listen_host = NULL; 1993 if (fwdargs[0].ispath) {
1860 fwd->listen_port = a2port(fwdarg[0]); 1994 fwd->listen_path = xstrdup(fwdargs[0].arg);
1861 fwd->connect_host = xstrdup(cleanhostname(fwdarg[1])); 1995 fwd->listen_port = PORT_STREAMLOCAL;
1862 fwd->connect_port = a2port(fwdarg[2]); 1996 fwd->connect_host = xstrdup(fwdargs[1].arg);
1997 fwd->connect_port = a2port(fwdargs[2].arg);
1998 } else if (fwdargs[2].ispath) {
1999 fwd->listen_host = xstrdup(fwdargs[0].arg);
2000 fwd->listen_port = a2port(fwdargs[1].arg);
2001 fwd->connect_path = xstrdup(fwdargs[2].arg);
2002 fwd->connect_port = PORT_STREAMLOCAL;
2003 } else {
2004 fwd->listen_host = NULL;
2005 fwd->listen_port = a2port(fwdargs[0].arg);
2006 fwd->connect_host = xstrdup(fwdargs[1].arg);
2007 fwd->connect_port = a2port(fwdargs[2].arg);
2008 }
1863 break; 2009 break;
1864 2010
1865 case 4: 2011 case 4:
1866 fwd->listen_host = xstrdup(cleanhostname(fwdarg[0])); 2012 fwd->listen_host = xstrdup(fwdargs[0].arg);
1867 fwd->listen_port = a2port(fwdarg[1]); 2013 fwd->listen_port = a2port(fwdargs[1].arg);
1868 fwd->connect_host = xstrdup(cleanhostname(fwdarg[2])); 2014 fwd->connect_host = xstrdup(fwdargs[2].arg);
1869 fwd->connect_port = a2port(fwdarg[3]); 2015 fwd->connect_port = a2port(fwdargs[3].arg);
1870 break; 2016 break;
1871 default: 2017 default:
1872 i = 0; /* failure */ 2018 i = 0; /* failure */
@@ -1878,29 +2024,42 @@ parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
1878 if (!(i == 1 || i == 2)) 2024 if (!(i == 1 || i == 2))
1879 goto fail_free; 2025 goto fail_free;
1880 } else { 2026 } else {
1881 if (!(i == 3 || i == 4)) 2027 if (!(i == 3 || i == 4)) {
1882 goto fail_free; 2028 if (fwd->connect_path == NULL &&
1883 if (fwd->connect_port <= 0) 2029 fwd->listen_path == NULL)
2030 goto fail_free;
2031 }
2032 if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
1884 goto fail_free; 2033 goto fail_free;
1885 } 2034 }
1886 2035
1887 if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0)) 2036 if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
2037 (!remotefwd && fwd->listen_port == 0))
1888 goto fail_free; 2038 goto fail_free;
1889
1890 if (fwd->connect_host != NULL && 2039 if (fwd->connect_host != NULL &&
1891 strlen(fwd->connect_host) >= NI_MAXHOST) 2040 strlen(fwd->connect_host) >= NI_MAXHOST)
1892 goto fail_free; 2041 goto fail_free;
2042 /* XXX - if connecting to a remote socket, max sun len may not match this host */
2043 if (fwd->connect_path != NULL &&
2044 strlen(fwd->connect_path) >= PATH_MAX_SUN)
2045 goto fail_free;
1893 if (fwd->listen_host != NULL && 2046 if (fwd->listen_host != NULL &&
1894 strlen(fwd->listen_host) >= NI_MAXHOST) 2047 strlen(fwd->listen_host) >= NI_MAXHOST)
1895 goto fail_free; 2048 goto fail_free;
1896 2049 if (fwd->listen_path != NULL &&
2050 strlen(fwd->listen_path) >= PATH_MAX_SUN)
2051 goto fail_free;
1897 2052
1898 return (i); 2053 return (i);
1899 2054
1900 fail_free: 2055 fail_free:
1901 free(fwd->connect_host); 2056 free(fwd->connect_host);
1902 fwd->connect_host = NULL; 2057 fwd->connect_host = NULL;
2058 free(fwd->connect_path);
2059 fwd->connect_path = NULL;
1903 free(fwd->listen_host); 2060 free(fwd->listen_host);
1904 fwd->listen_host = NULL; 2061 fwd->listen_host = NULL;
2062 free(fwd->listen_path);
2063 fwd->listen_path = NULL;
1905 return (0); 2064 return (0);
1906} 2065}