summaryrefslogtreecommitdiffstats
path: root/readconf.c
diff options
context:
space:
mode:
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 a4ecf7a0..7948ce1c 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.c,v 1.219 2014/04/23 12:42:34 djm Exp $ */
+/* $OpenBSD: readconf.c,v 1.220 2014/07/15 15:54:14 millert Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -18,6 +18,7 @@
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/wait.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -48,9 +49,9 @@
#include "pathnames.h"
#include "log.h"
#include "key.h"
+#include "misc.h"
#include "readconf.h"
#include "match.h"
-#include "misc.h"
#include "buffer.h"
#include "kex.h"
#include "mac.h"
@@ -149,6 +150,7 @@ typedef enum {
oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
+ oStreamLocalBindMask, oStreamLocalBindUnlink,
oIgnoredUnknownOption, oDeprecated, oUnsupported
} OpCodes;
@@ -261,6 +263,8 @@ static struct {
{ "canonicalizehostname", oCanonicalizeHostname },
{ "canonicalizemaxdots", oCanonicalizeMaxDots },
{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
+ { "streamlocalbindmask", oStreamLocalBindMask },
+ { "streamlocalbindunlink", oStreamLocalBindUnlink },
{ "ignoreunknown", oIgnoreUnknown },
{ NULL, oBadOption }
@@ -272,12 +276,13 @@ static struct {
*/
void
-add_local_forward(Options *options, const Forward *newfwd)
+add_local_forward(Options *options, const struct Forward *newfwd)
{
- Forward *fwd;
+ struct Forward *fwd;
#ifndef NO_IPPORT_RESERVED_CONCEPT
extern uid_t original_real_uid;
- if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
+ if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0 &&
+ newfwd->listen_path == NULL)
fatal("Privileged ports can only be forwarded by root.");
#endif
options->local_forwards = xrealloc(options->local_forwards,
@@ -287,8 +292,10 @@ add_local_forward(Options *options, const Forward *newfwd)
fwd->listen_host = newfwd->listen_host;
fwd->listen_port = newfwd->listen_port;
+ fwd->listen_path = newfwd->listen_path;
fwd->connect_host = newfwd->connect_host;
fwd->connect_port = newfwd->connect_port;
+ fwd->connect_path = newfwd->connect_path;
}
/*
@@ -297,9 +304,9 @@ add_local_forward(Options *options, const Forward *newfwd)
*/
void
-add_remote_forward(Options *options, const Forward *newfwd)
+add_remote_forward(Options *options, const struct Forward *newfwd)
{
- Forward *fwd;
+ struct Forward *fwd;
options->remote_forwards = xrealloc(options->remote_forwards,
options->num_remote_forwards + 1,
@@ -308,8 +315,10 @@ add_remote_forward(Options *options, const Forward *newfwd)
fwd->listen_host = newfwd->listen_host;
fwd->listen_port = newfwd->listen_port;
+ fwd->listen_path = newfwd->listen_path;
fwd->connect_host = newfwd->connect_host;
fwd->connect_port = newfwd->connect_port;
+ fwd->connect_path = newfwd->connect_path;
fwd->handle = newfwd->handle;
fwd->allocated_port = 0;
}
@@ -321,7 +330,9 @@ clear_forwardings(Options *options)
for (i = 0; i < options->num_local_forwards; i++) {
free(options->local_forwards[i].listen_host);
+ free(options->local_forwards[i].listen_path);
free(options->local_forwards[i].connect_host);
+ free(options->local_forwards[i].connect_path);
}
if (options->num_local_forwards > 0) {
free(options->local_forwards);
@@ -330,7 +341,9 @@ clear_forwardings(Options *options)
options->num_local_forwards = 0;
for (i = 0; i < options->num_remote_forwards; i++) {
free(options->remote_forwards[i].listen_host);
+ free(options->remote_forwards[i].listen_path);
free(options->remote_forwards[i].connect_host);
+ free(options->remote_forwards[i].connect_path);
}
if (options->num_remote_forwards > 0) {
free(options->remote_forwards);
@@ -715,7 +728,7 @@ process_config_line(Options *options, struct passwd *pw, const char *host,
LogLevel *log_level_ptr;
long long val64;
size_t len;
- Forward fwd;
+ struct Forward fwd;
const struct multistate *multistate_ptr;
struct allowed_cname *cname;
@@ -805,7 +818,7 @@ parse_time:
goto parse_time;
case oGatewayPorts:
- intptr = &options->gateway_ports;
+ intptr = &options->fwd_opts.gateway_ports;
goto parse_flag;
case oExitOnForwardFailure:
@@ -1405,6 +1418,21 @@ parse_int:
intptr = &options->canonicalize_fallback_local;
goto parse_flag;
+ case oStreamLocalBindMask:
+ arg = strdelim(&s);
+ if (!arg || *arg == '\0')
+ fatal("%.200s line %d: Missing StreamLocalBindMask argument.", filename, linenum);
+ /* Parse mode in octal format */
+ value = strtol(arg, &endofnumber, 8);
+ if (arg == endofnumber || value < 0 || value > 0777)
+ fatal("%.200s line %d: Bad mask.", filename, linenum);
+ options->fwd_opts.streamlocal_bind_mask = (mode_t)value;
+ break;
+
+ case oStreamLocalBindUnlink:
+ intptr = &options->fwd_opts.streamlocal_bind_unlink;
+ goto parse_flag;
+
case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
@@ -1502,7 +1530,9 @@ initialize_options(Options * options)
options->forward_x11_timeout = -1;
options->exit_on_forward_failure = -1;
options->xauth_location = NULL;
- options->gateway_ports = -1;
+ options->fwd_opts.gateway_ports = -1;
+ options->fwd_opts.streamlocal_bind_mask = (mode_t)-1;
+ options->fwd_opts.streamlocal_bind_unlink = -1;
options->use_privileged_port = -1;
options->rsa_authentication = -1;
options->pubkey_authentication = -1;
@@ -1615,8 +1645,12 @@ fill_default_options(Options * options)
options->exit_on_forward_failure = 0;
if (options->xauth_location == NULL)
options->xauth_location = _PATH_XAUTH;
- if (options->gateway_ports == -1)
- options->gateway_ports = 0;
+ if (options->fwd_opts.gateway_ports == -1)
+ options->fwd_opts.gateway_ports = 0;
+ if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1)
+ options->fwd_opts.streamlocal_bind_mask = 0177;
+ if (options->fwd_opts.streamlocal_bind_unlink == -1)
+ options->fwd_opts.streamlocal_bind_unlink = 0;
if (options->use_privileged_port == -1)
options->use_privileged_port = 0;
if (options->rsa_authentication == -1)
@@ -1768,22 +1802,92 @@ fill_default_options(Options * options)
/* options->preferred_authentications will be set in ssh */
}
+struct fwdarg {
+ char *arg;
+ int ispath;
+};
+
+/*
+ * parse_fwd_field
+ * parses the next field in a port forwarding specification.
+ * sets fwd to the parsed field and advances p past the colon
+ * or sets it to NULL at end of string.
+ * returns 0 on success, else non-zero.
+ */
+static int
+parse_fwd_field(char **p, struct fwdarg *fwd)
+{
+ char *ep, *cp = *p;
+ int ispath = 0;
+
+ if (*cp == '\0') {
+ *p = NULL;
+ return -1; /* end of string */
+ }
+
+ /*
+ * A field escaped with square brackets is used literally.
+ * XXX - allow ']' to be escaped via backslash?
+ */
+ if (*cp == '[') {
+ /* find matching ']' */
+ for (ep = cp + 1; *ep != ']' && *ep != '\0'; ep++) {
+ if (*ep == '/')
+ ispath = 1;
+ }
+ /* no matching ']' or not at end of field. */
+ if (ep[0] != ']' || (ep[1] != ':' && ep[1] != '\0'))
+ return -1;
+ /* NUL terminate the field and advance p past the colon */
+ *ep++ = '\0';
+ if (*ep != '\0')
+ *ep++ = '\0';
+ fwd->arg = cp + 1;
+ fwd->ispath = ispath;
+ *p = ep;
+ return 0;
+ }
+
+ for (cp = *p; *cp != '\0'; cp++) {
+ switch (*cp) {
+ case '\\':
+ memmove(cp, cp + 1, strlen(cp + 1) + 1);
+ cp++;
+ break;
+ case '/':
+ ispath = 1;
+ break;
+ case ':':
+ *cp++ = '\0';
+ goto done;
+ }
+ }
+done:
+ fwd->arg = *p;
+ fwd->ispath = ispath;
+ *p = cp;
+ return 0;
+}
+
/*
* parse_forward
* parses a string containing a port forwarding specification of the form:
* dynamicfwd == 0
- * [listenhost:]listenport:connecthost:connectport
+ * [listenhost:]listenport|listenpath:connecthost:connectport|connectpath
+ * listenpath:connectpath
* dynamicfwd == 1
* [listenhost:]listenport
* returns number of arguments parsed or zero on error
*/
int
-parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
+parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
{
+ struct fwdarg fwdargs[4];
+ char *p, *cp;
int i;
- char *p, *cp, *fwdarg[4];
- memset(fwd, '\0', sizeof(*fwd));
+ memset(fwd, 0, sizeof(*fwd));
+ memset(fwdargs, 0, sizeof(fwdargs));
cp = p = xstrdup(fwdspec);
@@ -1791,39 +1895,70 @@ parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
while (isspace((u_char)*cp))
cp++;
- for (i = 0; i < 4; ++i)
- if ((fwdarg[i] = hpdelim(&cp)) == NULL)
+ for (i = 0; i < 4; ++i) {
+ if (parse_fwd_field(&cp, &fwdargs[i]) != 0)
break;
+ }
/* Check for trailing garbage */
- if (cp != NULL)
+ if (cp != NULL && *cp != '\0') {
i = 0; /* failure */
+ }
switch (i) {
case 1:
- fwd->listen_host = NULL;
- fwd->listen_port = a2port(fwdarg[0]);
+ if (fwdargs[0].ispath) {
+ fwd->listen_path = xstrdup(fwdargs[0].arg);
+ fwd->listen_port = PORT_STREAMLOCAL;
+ } else {
+ fwd->listen_host = NULL;
+ fwd->listen_port = a2port(fwdargs[0].arg);
+ }
fwd->connect_host = xstrdup("socks");
break;
case 2:
- fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
- fwd->listen_port = a2port(fwdarg[1]);
- fwd->connect_host = xstrdup("socks");
+ if (fwdargs[0].ispath && fwdargs[1].ispath) {
+ fwd->listen_path = xstrdup(fwdargs[0].arg);
+ fwd->listen_port = PORT_STREAMLOCAL;
+ fwd->connect_path = xstrdup(fwdargs[1].arg);
+ fwd->connect_port = PORT_STREAMLOCAL;
+ } else if (fwdargs[1].ispath) {
+ fwd->listen_host = NULL;
+ fwd->listen_port = a2port(fwdargs[0].arg);
+ fwd->connect_path = xstrdup(fwdargs[1].arg);
+ fwd->connect_port = PORT_STREAMLOCAL;
+ } else {
+ fwd->listen_host = xstrdup(fwdargs[0].arg);
+ fwd->listen_port = a2port(fwdargs[1].arg);
+ fwd->connect_host = xstrdup("socks");
+ }
break;
case 3:
- fwd->listen_host = NULL;
- fwd->listen_port = a2port(fwdarg[0]);
- fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
- fwd->connect_port = a2port(fwdarg[2]);
+ if (fwdargs[0].ispath) {
+ fwd->listen_path = xstrdup(fwdargs[0].arg);
+ fwd->listen_port = PORT_STREAMLOCAL;
+ fwd->connect_host = xstrdup(fwdargs[1].arg);
+ fwd->connect_port = a2port(fwdargs[2].arg);
+ } else if (fwdargs[2].ispath) {
+ fwd->listen_host = xstrdup(fwdargs[0].arg);
+ fwd->listen_port = a2port(fwdargs[1].arg);
+ fwd->connect_path = xstrdup(fwdargs[2].arg);
+ fwd->connect_port = PORT_STREAMLOCAL;
+ } else {
+ fwd->listen_host = NULL;
+ fwd->listen_port = a2port(fwdargs[0].arg);
+ fwd->connect_host = xstrdup(fwdargs[1].arg);
+ fwd->connect_port = a2port(fwdargs[2].arg);
+ }
break;
case 4:
- fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
- fwd->listen_port = a2port(fwdarg[1]);
- fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
- fwd->connect_port = a2port(fwdarg[3]);
+ fwd->listen_host = xstrdup(fwdargs[0].arg);
+ fwd->listen_port = a2port(fwdargs[1].arg);
+ fwd->connect_host = xstrdup(fwdargs[2].arg);
+ fwd->connect_port = a2port(fwdargs[3].arg);
break;
default:
i = 0; /* failure */
@@ -1835,29 +1970,42 @@ parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
if (!(i == 1 || i == 2))
goto fail_free;
} else {
- if (!(i == 3 || i == 4))
- goto fail_free;
- if (fwd->connect_port <= 0)
+ if (!(i == 3 || i == 4)) {
+ if (fwd->connect_path == NULL &&
+ fwd->listen_path == NULL)
+ goto fail_free;
+ }
+ if (fwd->connect_port <= 0 && fwd->connect_path == NULL)
goto fail_free;
}
- if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0))
+ if ((fwd->listen_port < 0 && fwd->listen_path == NULL) ||
+ (!remotefwd && fwd->listen_port == 0))
goto fail_free;
-
if (fwd->connect_host != NULL &&
strlen(fwd->connect_host) >= NI_MAXHOST)
goto fail_free;
+ /* XXX - if connecting to a remote socket, max sun len may not match this host */
+ if (fwd->connect_path != NULL &&
+ strlen(fwd->connect_path) >= PATH_MAX_SUN)
+ goto fail_free;
if (fwd->listen_host != NULL &&
strlen(fwd->listen_host) >= NI_MAXHOST)
goto fail_free;
-
+ if (fwd->listen_path != NULL &&
+ strlen(fwd->listen_path) >= PATH_MAX_SUN)
+ goto fail_free;
return (i);
fail_free:
free(fwd->connect_host);
fwd->connect_host = NULL;
+ free(fwd->connect_path);
+ fwd->connect_path = NULL;
free(fwd->listen_host);
fwd->listen_host = NULL;
+ free(fwd->listen_path);
+ fwd->listen_path = NULL;
return (0);
}