Merge remote-tracking branch 'sysrqb/bug15220_026_sysrqb'
This commit is contained in:
commit
2ba6542517
|
@ -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.
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue