diff options
author | Nick Mathewson <nickm@torproject.org> | 2015-07-16 15:38:08 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2015-07-16 15:38:08 -0400 |
commit | 2ba6542517fcff4ec4e7051870085cfdb6bc26aa (patch) | |
tree | ee426b30c8df23e3400516e191702a596107239f | |
parent | 90701c1de45ad96b9e4d08938613e754c34f0c3d (diff) | |
parent | 61dcd926aa8cc5080177eb48bcf9dc14a67e527a (diff) | |
download | tor-2ba6542517fcff4ec4e7051870085cfdb6bc26aa.tar.gz tor-2ba6542517fcff4ec4e7051870085cfdb6bc26aa.zip |
Merge remote-tracking branch 'sysrqb/bug15220_026_sysrqb'
-rw-r--r-- | changes/feature15220 | 5 | ||||
-rw-r--r-- | doc/tor.1.txt | 16 | ||||
-rw-r--r-- | src/or/config.c | 92 | ||||
-rw-r--r-- | src/or/connection.c | 46 | ||||
-rw-r--r-- | src/or/or.h | 3 |
5 files changed, 116 insertions, 46 deletions
diff --git a/changes/feature15220 b/changes/feature15220 new file mode 100644 index 0000000000..6cab36dffd --- /dev/null +++ b/changes/feature15220 @@ -0,0 +1,5 @@ + o Minor features (client, unix sockets): + - Add GroupWritable and WorldWritable options to unix-socket based + SocksPort and ControlPort options. These options apply to a single + socket, and override {Control,Socks}SocketsGroupWritable. Closes + ticket 15220. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 6cfad56f08..ca686281b8 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -274,7 +274,7 @@ GENERAL OPTIONS all sockets will be set to this limit. Must be a value between 2048 and 262144, in 1024 byte increments. Default of 8192 is recommended. -[[ControlPort]] **ControlPort** __PORT__|**unix:**__path__|**auto**:: +[[ControlPort]] **ControlPort** __PORT__|**unix:**__path__|**auto** [__flags__]:: If set, Tor will accept connections on this port and allow those connections to control the Tor process using the Tor Control Protocol (described in control-spec.txt). Note: unless you also specify one or @@ -284,6 +284,14 @@ GENERAL OPTIONS method is sufficient to authenticate to Tor.) This option is required for many Tor controllers; most use the value of 9051. Set it to "auto" to have Tor pick a port for you. (Default: 0) + + + Recognized flags are:: + **GroupWritable**;; + Unix domain sockets only: makes the socket get created as + group-writable. + **WorldWritable**;; + Unix domain sockets only: makes the socket get created as + world-writable. [[ControlListenAddress]] **ControlListenAddress** __IP__[:__PORT__]:: Bind the controller listener to this address. If you specify a port, bind @@ -1009,6 +1017,12 @@ The following options are useful only for clients (that is, if **CacheIPv6DNS**;; Tells the client to remember IPv6 DNS answers we receive from exit nodes via this connection. + **GroupWritable**;; + Unix domain sockets only: makes the socket get created as + group-writable. + **WorldWritable**;; + Unix domain sockets only: makes the socket get created as + world-writable. **CacheDNS**;; Tells the client to remember all DNS answers we receive from exit nodes via this connection. diff --git a/src/or/config.c b/src/or/config.c index 2f656647e7..e686f61a26 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -558,7 +558,8 @@ static int parse_dir_authority_line(const char *line, int validate_only); static void port_cfg_free(port_cfg_t *port); static int parse_ports(or_options_t *options, int validate_only, - char **msg_out, int *n_ports_out); + char **msg_out, int *n_ports_out, + int *world_writable_control_socket); static int check_server_ports(const smartlist_t *ports, const or_options_t *options); @@ -1115,7 +1116,7 @@ options_act_reversible(const or_options_t *old_options, char **msg) } /* Adjust the port configuration so we can launch listeners. */ - if (parse_ports(options, 0, msg, &n_ports)) { + if (parse_ports(options, 0, msg, &n_ports, NULL)) { if (!*msg) *msg = tor_strdup("Unexpected problem parsing port config"); goto rollback; @@ -2662,6 +2663,7 @@ options_validate(or_options_t *old_options, or_options_t *options, config_line_t *cl; const char *uname = get_uname(); int n_ports=0; + int world_writable_control_socket=0; tor_assert(msg); *msg = NULL; @@ -2678,7 +2680,8 @@ options_validate(or_options_t *old_options, or_options_t *options, "for details.", uname); } - if (parse_ports(options, 1, msg, &n_ports) < 0) + if (parse_ports(options, 1, msg, &n_ports, + &world_writable_control_socket) < 0) return -1; if (parse_outbound_addresses(options, 1, msg) < 0) @@ -3459,13 +3462,16 @@ options_validate(or_options_t *old_options, or_options_t *options, } } - if (options->ControlPort_set && !options->HashedControlPassword && + if ((options->ControlPort_set || world_writable_control_socket) && + !options->HashedControlPassword && !options->HashedControlSessionPassword && !options->CookieAuthentication) { - log_warn(LD_CONFIG, "ControlPort is open, but no authentication method " + log_warn(LD_CONFIG, "Control%s is %s, but no authentication method " "has been configured. This means that any program on your " "computer can reconfigure your Tor. That's bad! You should " - "upgrade your Tor controller as soon as possible."); + "upgrade your Tor controller as soon as possible.", + options->ControlPort_set ? "Port" : "Socket", + options->ControlPort_set ? "open" : "world writable"); } if (options->CookieAuthFileGroupReadable && !options->CookieAuthFile) { @@ -5700,11 +5706,11 @@ warn_nonlocal_ext_orports(const smartlist_t *ports, const char *portname) } /** Given a list of port_cfg_t in <b>ports</b>, warn any controller port there - * is listening on any non-loopback address. If <b>forbid</b> is true, + * is listening on any non-loopback address. If <b>forbid_nonlocal</b> is true, * then emit a stronger warning and remove the port from the list. */ static void -warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid) +warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid_nonlocal) { int warned = 0; SMARTLIST_FOREACH_BEGIN(ports, port_cfg_t *, port) { @@ -5713,7 +5719,7 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid) if (port->is_unix_addr) continue; if (!tor_addr_is_loopback(&port->addr)) { - if (forbid) { + if (forbid_nonlocal) { if (!warned) log_warn(LD_CONFIG, "You have a ControlPort set to accept " @@ -5741,13 +5747,14 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid) } SMARTLIST_FOREACH_END(port); } -#define CL_PORT_NO_OPTIONS (1u<<0) +#define CL_PORT_NO_STREAM_OPTIONS (1u<<0) #define CL_PORT_WARN_NONLOCAL (1u<<1) #define CL_PORT_ALLOW_EXTRA_LISTENADDR (1u<<2) #define CL_PORT_SERVER_OPTIONS (1u<<3) #define CL_PORT_FORBID_NONLOCAL (1u<<4) #define CL_PORT_TAKES_HOSTNAMES (1u<<5) #define CL_PORT_IS_UNIXSOCKET (1u<<6) +#define CL_PORT_DFLT_GROUP_WRITABLE (1u<<7) #ifdef HAVE_SYS_UN_H @@ -5815,12 +5822,12 @@ config_parse_unix_port(const char *addrport, char **path_out) * If no address is specified, default to <b>defaultaddr</b>. If no * FooPort is given, default to defaultport (if 0, there is no default). * - * If CL_PORT_NO_OPTIONS is set in <b>flags</b>, do not allow stream + * If CL_PORT_NO_STREAM_OPTIONS is set in <b>flags</b>, do not allow stream * isolation options in the FooPort entries. * * If CL_PORT_WARN_NONLOCAL is set in <b>flags</b>, warn if any of the * ports are not on a local address. If CL_PORT_FORBID_NONLOCAL is set, - * this is a contrl port with no password set: don't even allow it. + * this is a control port with no password set: don't even allow it. * * Unless CL_PORT_ALLOW_EXTRA_LISTENADDR is set in <b>flags</b>, warn * if FooListenAddress is set but FooPort is 0. @@ -5850,10 +5857,12 @@ parse_port_config(smartlist_t *out, int retval = -1; const unsigned is_control = (listener_type == CONN_TYPE_CONTROL_LISTENER); const unsigned is_ext_orport = (listener_type == CONN_TYPE_EXT_OR_LISTENER); - const unsigned allow_no_options = flags & CL_PORT_NO_OPTIONS; + const unsigned allow_no_stream_options = flags & CL_PORT_NO_STREAM_OPTIONS; const unsigned use_server_options = flags & CL_PORT_SERVER_OPTIONS; const unsigned warn_nonlocal = flags & CL_PORT_WARN_NONLOCAL; const unsigned forbid_nonlocal = flags & CL_PORT_FORBID_NONLOCAL; + const unsigned default_to_group_writable = + flags & CL_PORT_DFLT_GROUP_WRITABLE; const unsigned allow_spurious_listenaddr = flags & CL_PORT_ALLOW_EXTRA_LISTENADDR; const unsigned takes_hostnames = flags & CL_PORT_TAKES_HOSTNAMES; @@ -5977,7 +5986,7 @@ parse_port_config(smartlist_t *out, ipv4_traffic = 1, ipv6_traffic = 0, prefer_ipv6 = 0, cache_ipv4 = 1, use_cached_ipv4 = 0, cache_ipv6 = 0, use_cached_ipv6 = 0, - prefer_ipv6_automap = 1; + prefer_ipv6_automap = 1, world_writable = 0, group_writable = 0; smartlist_split_string(elts, ports->value, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); @@ -5986,11 +5995,6 @@ parse_port_config(smartlist_t *out, goto err; } - if (allow_no_options && smartlist_len(elts) > 1) { - log_warn(LD_CONFIG, "Too many options on %sPort line", portname); - goto err; - } - /* Now parse the addr/port value */ addrport = smartlist_get(elts, 0); @@ -6050,6 +6054,9 @@ parse_port_config(smartlist_t *out, } } + if (unix_socket_path && default_to_group_writable) + group_writable = 1; + /* Now parse the rest of the options, if any. */ if (use_server_options) { /* This is a server port; parse advertising options */ @@ -6106,10 +6113,11 @@ parse_port_config(smartlist_t *out, const char *elt_orig = elt; if (elt_sl_idx == 0) continue; /* Skip addr:port */ + if (!strcasecmpstart(elt, "SessionGroup=")) { int group = (int)tor_parse_long(elt+strlen("SessionGroup="), 10, 0, INT_MAX, &ok, NULL); - if (!ok) { + if (!ok || !allow_no_stream_options) { log_warn(LD_CONFIG, "Invalid %sPort option '%s'", portname, escaped(elt)); goto err; @@ -6128,6 +6136,20 @@ parse_port_config(smartlist_t *out, elt += 2; } + if (!strcasecmp(elt, "GroupWritable")) { + group_writable = !no; + continue; + } else if (!strcasecmp(elt, "WorldWritable")) { + world_writable = !no; + continue; + } + + if (allow_no_stream_options) { + log_warn(LD_CONFIG, "Unrecognized %sPort option '%s'", + portname, escaped(elt)); + continue; + } + if (takes_hostnames) { if (!strcasecmp(elt, "IPv4Traffic")) { ipv4_traffic = ! no; @@ -6203,6 +6225,12 @@ parse_port_config(smartlist_t *out, goto err; } + if ( (world_writable || group_writable) && ! unix_socket_path) { + log_warn(LD_CONFIG, "You have a %sPort entry with GroupWritable " + "or WorldWritable set, but it is not a unix socket.", portname); + goto err; + } + if (out && port) { size_t namelen = unix_socket_path ? strlen(unix_socket_path) : 0; port_cfg_t *cfg = port_cfg_new(namelen); @@ -6216,6 +6244,8 @@ parse_port_config(smartlist_t *out, cfg->port = port; } cfg->type = listener_type; + cfg->is_world_writable = world_writable; + cfg->is_group_writable = group_writable; cfg->entry_cfg.isolation_flags = isolation; cfg->entry_cfg.session_group = sessiongroup; cfg->server_cfg.no_advertise = no_advertise; @@ -6293,7 +6323,8 @@ count_real_listeners(const smartlist_t *ports, int listenertype) **/ static int parse_ports(or_options_t *options, int validate_only, - char **msg, int *n_ports_out) + char **msg, int *n_ports_out, + int *world_writable_control_socket) { smartlist_t *ports; int retval = -1; @@ -6302,12 +6333,14 @@ parse_ports(or_options_t *options, int validate_only, *n_ports_out = 0; + const unsigned gw_flag = options->SocksSocketsGroupWritable ? + CL_PORT_DFLT_GROUP_WRITABLE : 0; if (parse_port_config(ports, options->SocksPort_lines, options->SocksListenAddress, "Socks", CONN_TYPE_AP_LISTENER, "127.0.0.1", 9050, CL_PORT_WARN_NONLOCAL|CL_PORT_ALLOW_EXTRA_LISTENADDR| - CL_PORT_TAKES_HOSTNAMES) < 0) { + CL_PORT_TAKES_HOSTNAMES|gw_flag) < 0) { *msg = tor_strdup("Invalid SocksPort/SocksListenAddress configuration"); goto err; } @@ -6336,12 +6369,15 @@ parse_ports(or_options_t *options, int validate_only, goto err; } { - unsigned control_port_flags = CL_PORT_NO_OPTIONS | CL_PORT_WARN_NONLOCAL; + unsigned control_port_flags = CL_PORT_NO_STREAM_OPTIONS | + CL_PORT_WARN_NONLOCAL; const int any_passwords = (options->HashedControlPassword || options->HashedControlSessionPassword || options->CookieAuthentication); if (! any_passwords) control_port_flags |= CL_PORT_FORBID_NONLOCAL; + if (options->ControlSocketsGroupWritable) + control_port_flags |= CL_PORT_DFLT_GROUP_WRITABLE; if (parse_port_config(ports, options->ControlPort_lines, @@ -6417,6 +6453,16 @@ parse_ports(or_options_t *options, int validate_only, options->ExtORPort_set = !! count_real_listeners(ports, CONN_TYPE_EXT_OR_LISTENER); + if (world_writable_control_socket) { + SMARTLIST_FOREACH(ports, port_cfg_t *, p, + if (p->type == CONN_TYPE_CONTROL_LISTENER && + p->is_unix_addr && + p->is_world_writable) { + *world_writable_control_socket = 1; + break; + }); + } + if (!validate_only) { if (configured_ports) { SMARTLIST_FOREACH(configured_ports, diff --git a/src/or/connection.c b/src/or/connection.c index 0ecf5d1d2f..2cca6e4cf9 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -979,7 +979,7 @@ unix_socket_purpose_to_string(int purpose) * <b>path</b>. Return 0 if we should go ahead and -1 if we shouldn't. */ static int check_location_for_unix_socket(const or_options_t *options, const char *path, - int purpose) + int purpose, const port_cfg_t *port) { int r = -1; char *p = NULL; @@ -994,10 +994,13 @@ check_location_for_unix_socket(const or_options_t *options, const char *path, goto done; } - if ((purpose == UNIX_SOCKET_PURPOSE_CONTROL_SOCKET && - options->ControlSocketsGroupWritable) || - (purpose == UNIX_SOCKET_PURPOSE_SOCKS_SOCKET && - options->SocksSocketsGroupWritable)) { + if (port->is_world_writable) { + /* World-writable sockets can go anywhere. */ + r = 0; + goto done; + } + + if (port->is_group_writable) { flags |= CPD_GROUP_OK; } @@ -1011,7 +1014,7 @@ check_location_for_unix_socket(const or_options_t *options, const char *path, "who can list a socket can connect to it, so Tor is being " "careful.)", unix_socket_purpose_to_string(purpose), escpath, escdir, - options->ControlSocketsGroupWritable ? " and group" : ""); + port->is_group_writable ? " and group" : ""); tor_free(escpath); tor_free(escdir); goto done; @@ -1206,7 +1209,7 @@ connection_listener_new(const struct sockaddr *listensockaddr, if (check_location_for_unix_socket(options, address, (type == CONN_TYPE_CONTROL_LISTENER) ? UNIX_SOCKET_PURPOSE_CONTROL_SOCKET : - UNIX_SOCKET_PURPOSE_SOCKS_SOCKET) < 0) { + UNIX_SOCKET_PURPOSE_SOCKS_SOCKET, port_cfg) < 0) { goto err; } @@ -1254,24 +1257,23 @@ connection_listener_new(const struct sockaddr *listensockaddr, } #endif - if ((type == CONN_TYPE_CONTROL_LISTENER && - options->ControlSocketsGroupWritable) || - (type == CONN_TYPE_AP_LISTENER && - options->SocksSocketsGroupWritable)) { - /* We need to use chmod; fchmod doesn't work on sockets on all - * platforms. */ - if (chmod(address, 0660) < 0) { - log_warn(LD_FS,"Unable to make %s group-writable.", address); - goto err; + { + unsigned mode; + const char *status; + if (port_cfg->is_world_writable) { + mode = 0666; + status = "world-writable"; + } else if (port_cfg->is_group_writable) { + mode = 0660; + status = "group-writable"; + } else { + mode = 0600; + status = "private"; } - } else if ((type == CONN_TYPE_CONTROL_LISTENER && - !(options->ControlSocketsGroupWritable)) || - (type == CONN_TYPE_AP_LISTENER && - !(options->SocksSocketsGroupWritable))) { /* We need to use chmod; fchmod doesn't work on sockets on all * platforms. */ - if (chmod(address, 0600) < 0) { - log_warn(LD_FS,"Unable to make %s group-writable.", address); + if (chmod(address, mode) < 0) { + log_warn(LD_FS,"Unable to make %s %s.", address, status); goto err; } } diff --git a/src/or/or.h b/src/or/or.h index 946e7e0def..4b3762f00b 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3356,6 +3356,9 @@ typedef struct port_cfg_t { uint8_t type; /**< One of CONN_TYPE_*_LISTENER */ unsigned is_unix_addr : 1; /**< True iff this is an AF_UNIX address. */ + unsigned is_group_writable : 1; + unsigned is_world_writable : 1; + entry_port_cfg_t entry_cfg; server_port_cfg_t server_cfg; |