]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
First RelaxDirModeCheck implementation
authorPeter Palfrader <peter@palfrader.org>
Tue, 1 Mar 2016 16:08:14 +0000 (17:08 +0100)
committerPeter Palfrader <peter@palfrader.org>
Tue, 1 Mar 2016 16:08:14 +0000 (17:08 +0100)
doc/tor.1.txt
src/common/util.c
src/common/util.h
src/or/config.c
src/or/connection.c
src/or/or.h
src/test/test_config.c

index d6a68523df72c91dbed2fa3fcf2e8a1af9f4bcc1..a71b04fec7f21b4f414882ea9f5f2cec2af67f3d 100644 (file)
@@ -321,6 +321,9 @@ GENERAL OPTIONS
     **WorldWritable**;;
         Unix domain sockets only: makes the socket get created as
         world-writable.
+    **RelaxDirModeCheck**;;
+        Unix domain sockets only: Do not insist that the directory
+        that holds the socket be read-restricted.
 
 [[ControlListenAddress]] **ControlListenAddress** __IP__[:__PORT__]::
     Bind the controller listener to this address. If you specify a port, bind
index b4355115d16d34876058735d8b4a773b61c28912..ce15d529deb5c6a9ec388e13a31964e453ff08be 100644 (file)
@@ -2063,7 +2063,6 @@ check_private_dir(const char *dirname, cpd_check_t check,
 
 #ifndef _WIN32
   int fd;
-  unsigned unwanted_bits = 0;
   const struct passwd *pw = NULL;
   uid_t running_uid;
   gid_t running_gid;
@@ -2197,12 +2196,17 @@ check_private_dir(const char *dirname, cpd_check_t check,
     close(fd);
     return -1;
   }
+  unsigned unwanted_bits = 0;
   if (check & (CPD_GROUP_OK|CPD_GROUP_READ)) {
     unwanted_bits = 0027;
   } else {
     unwanted_bits = 0077;
   }
-  if ((st.st_mode & unwanted_bits) != 0) {
+  unsigned check_bits_filter = ~0;
+  if (check & CPD_RELAX_DIRMODE_CHECK) {
+    check_bits_filter = 0022;
+  }
+  if ((st.st_mode & unwanted_bits & check_bits_filter) != 0) {
     unsigned new_mode;
     if (check & CPD_CHECK_MODE_ONLY) {
       log_warn(LD_FS, "Permissions on directory %s are too permissive.",
index 9657003105ea8f96b22d34be211b1811885bd636..ebcf88b32ddc58e925588133f834851ff0ebc722 100644 (file)
@@ -357,12 +357,13 @@ file_status_t file_status(const char *filename);
 /** Possible behaviors for check_private_dir() on encountering a nonexistent
  * directory; see that function's documentation for details. */
 typedef unsigned int cpd_check_t;
-#define CPD_NONE 0
-#define CPD_CREATE 1
-#define CPD_CHECK 2
-#define CPD_GROUP_OK 4
-#define CPD_GROUP_READ 8
-#define CPD_CHECK_MODE_ONLY 16
+#define CPD_NONE                 0
+#define CPD_CREATE               (1u << 0)
+#define CPD_CHECK                (1u << 1)
+#define CPD_GROUP_OK             (1u << 2)
+#define CPD_GROUP_READ           (1u << 3)
+#define CPD_CHECK_MODE_ONLY      (1u << 4)
+#define CPD_RELAX_DIRMODE_CHECK  (1u << 5)
 int check_private_dir(const char *dirname, cpd_check_t check,
                       const char *effective_user);
 
index 544b032f3ae353b09cc70d7e7f352cc0f92f8dca..556d285346cec28dcc868108917f9e84432d6fef 100644 (file)
@@ -6325,7 +6325,8 @@ 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, world_writable = 0, group_writable = 0;
+      prefer_ipv6_automap = 1, world_writable = 0, group_writable = 0, relax_dirmode_check = 0,
+      has_used_unix_socket_only_option = 0;
 
     smartlist_split_string(elts, ports->value, NULL,
                            SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
@@ -6478,9 +6479,15 @@ parse_port_config(smartlist_t *out,
 
         if (!strcasecmp(elt, "GroupWritable")) {
           group_writable = !no;
+          has_used_unix_socket_only_option = 1;
           continue;
         } else if (!strcasecmp(elt, "WorldWritable")) {
           world_writable = !no;
+          has_used_unix_socket_only_option = 1;
+          continue;
+        } else if (!strcasecmp(elt, "RelaxDirModeCheck")) {
+          relax_dirmode_check = !no;
+          has_used_unix_socket_only_option = 1;
           continue;
         }
 
@@ -6568,9 +6575,9 @@ 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);
+    if ( has_used_unix_socket_only_option && ! unix_socket_path) {
+      log_warn(LD_CONFIG, "You have a %sPort entry with GroupWritable, "
+               "WorldWritable, or StrictDirModes, but it is not a unix socket.", portname);
       goto err;
     }
 
@@ -6596,6 +6603,7 @@ parse_port_config(smartlist_t *out,
       cfg->type = listener_type;
       cfg->is_world_writable = world_writable;
       cfg->is_group_writable = group_writable;
+      cfg->relax_dirmode_check = relax_dirmode_check;
       cfg->entry_cfg.isolation_flags = isolation;
       cfg->entry_cfg.session_group = sessiongroup;
       cfg->server_cfg.no_advertise = no_advertise;
index 2e1c50889445d9d2bdcf1fe5e74041c0a19ddcb6..4e915f12139ece806caffa298f0d25bf2e683982 100644 (file)
@@ -1014,6 +1014,10 @@ check_location_for_unix_socket(const or_options_t *options, const char *path,
     flags |= CPD_GROUP_OK;
   }
 
+  if (port->relax_dirmode_check) {
+    flags |= CPD_RELAX_DIRMODE_CHECK;
+  }
+
   if (check_private_dir(p, flags, options->User) < 0) {
     char *escpath, *escdir;
     escpath = esc_for_log(path);
index 4d145e45ffc481c09e1cd6b0684839f3f17bfe88..4c295ab9615fe3a544f35d5c8330f3aad00e3a6e 100644 (file)
@@ -3456,6 +3456,7 @@ typedef struct port_cfg_t {
 
   unsigned is_group_writable : 1;
   unsigned is_world_writable : 1;
+  unsigned relax_dirmode_check : 1;
 
   entry_port_cfg_t entry_cfg;
 
index b11848102e7971bf2fa2dc87a8d6d887a0bbc5c0..6d9b4916e3f669c21859c8783b9c4edecbd60b8d 100644 (file)
@@ -4038,6 +4038,13 @@ test_config_parse_port_config__ports__ports_given(void *data)
                           "127.0.0.3", 0, 0);
   tt_int_op(ret, OP_EQ, -1);
 
+  // Test failure if we specify group writable for an IP Port
+  config_free_lines(config_port_invalid); config_port_invalid = NULL;
+  config_port_invalid = mock_config_line("DNSPort", "42 RelaxDirModeCheck");
+  ret = parse_port_config(NULL, config_port_invalid, NULL, "DNS", 0,
+                          "127.0.0.3", 0, 0);
+  tt_int_op(ret, OP_EQ, -1);
+
   // Test success with only a port (this will fail without a default address)
   config_free_lines(config_port_valid); config_port_valid = NULL;
   config_port_valid = mock_config_line("DNSPort", "42");