diff --git a/src/common/compat.c b/src/common/compat.c
index d88c5f9..73778b7 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1432,6 +1432,125 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
   return 0;
 }
 
+#include <sys/prctl.h>
+#define _LINUX_CAPABILITY_VERSION_1 0x19980330
+#define CAP_CHOWN 0
+#define CAP_DAC_OVERRIDE 1
+#define CAP_DAC_READ_SEARCH 2
+#define CAP_FOWNER 3
+#define CAP_FSETID 4
+#define CAP_KILL 5
+#define CAP_SETGID 6
+#define CAP_SETUID 7
+#define CAP_SETPCAP 8
+#define CAP_LINUX_IMMUTABLE 9
+#define CAP_NET_BIND_SERVICE 10
+#define CAP_NET_BROADCAST 11
+#define CAP_NET_ADMIN 12
+#define CAP_NET_RAW 13
+#define CAP_IPC_LOCK 14
+#define CAP_IPC_OWNER 15
+#define CAP_SYS_MODULE 16
+#define CAP_SYS_RAWIO 17
+#define CAP_SYS_CHROOT 18
+#define CAP_SYS_PTRACE 19
+#define CAP_SYS_PACCT 20
+#define CAP_SYS_ADMIN 21
+#define CAP_SYS_BOOT 22
+#define CAP_SYS_NICE 23
+#define CAP_SYS_RESOURCE 24
+#define CAP_SYS_TIME 25
+#define CAP_SYS_TTY_CONFIG 26
+#define CAP_MKNOD 27
+#define CAP_LEASE 28
+#define CAP_AUDIT_WRITE 29
+#define CAP_AUDIT_CONTROL 30
+#define CAP_SETFCAP 31
+#define CAP_MAC_OVERRIDE 32
+#define CAP_MAC_ADMIN 33
+#define CAP_SYSLOG 34
+#define CAP_WAKE_ALARM 35
+#define CAP_LAST_CAP CAP_WAKE_ALARM
+#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
+#define CAP_TO_INDEX(x) ((x) >> 5)
+#define CAP_TO_MASK(x) (1 << ((x) & 31))
+
+
+/* This part gets called before the setuid stuff */
+int
+pre_capabilities(void)
+{
+  cap_user_header_t hdr;
+  cap_user_data_t data;
+
+  hdr = malloc(sizeof *hdr);
+  data = malloc(sizeof *hdr);
+
+  /* Get the capabilities or bail out */
+  hdr->version = _LINUX_CAPABILITY_VERSION;
+  hdr->pid = 0;
+  if (capget(hdr, data)) {
+    printf("Error getting capabilities: %s", strerror(errno));
+    return -1;
+  }
+
+  /* Set the capabilities or bail out */
+  data->permitted &= CAP_TO_MASK(CAP_NET_BIND_SERVICE)|CAP_TO_MASK(CAP_SETUID)|CAP_TO_MASK(CAP_SETGID)|CAP_TO_MASK(CAP_CHOWN)|CAP_TO_MASK(CAP_FOWNER)|CAP_TO_MASK(CAP_KILL)|CAP_TO_MASK(CAP_NET_BIND_SERVICE)|CAP_TO_MASK(CAP_NET_RAW)|CAP_TO_MASK(CAP_SYS_NICE);
+  data->effective = data->permitted;
+  data->inheritable = 0;
+  if (capset(hdr, data)) {
+    printf("Error setting capabilities: %s", strerror(errno));
+    return -1;
+  }
+
+  /* Keep the capabilities or bail out */
+  if (prctl(PR_SET_KEEPCAPS, 1)) {
+    printf("Error keeping capabilities: %s", strerror(errno));
+    return -1;
+  }
+
+  return 0;
+}
+
+/* this part happens after the setuid: we need to drop setuid, and add the
+   BIND_SERVICE capability back to the active set. */
+int
+post_capabilities(void)
+{
+  cap_user_header_t hdr;
+  cap_user_data_t data;
+
+  hdr = malloc(sizeof *hdr);
+  data = malloc(sizeof *hdr);
+
+  /* Get the capabilities or bail out */
+  hdr->version = _LINUX_CAPABILITY_VERSION;
+  hdr->pid = 0;
+  if (capget(hdr, data)) {
+    printf("2: Error getting capabilities: %s", strerror(errno));
+    return -1;
+  }
+
+  /* Set the capabilities or bail out */
+  data->permitted &= CAP_TO_MASK(CAP_NET_BIND_SERVICE)|CAP_TO_MASK(CAP_SETUID)|CAP_TO_MASK(CAP_SETGID)|CAP_TO_MASK(CAP_CHOWN)|CAP_TO_MASK(CAP_FOWNER)|CAP_TO_MASK(CAP_KILL)|CAP_TO_MASK(CAP_NET_BIND_SERVICE)|CAP_TO_MASK(CAP_NET_RAW)|CAP_TO_MASK(CAP_SYS_NICE);
+ 
+  data->effective = data->permitted;
+  data->inheritable = 0;
+  if (capset(hdr, data)) {
+    printf("2: Error setting capabilities: %s", strerror(errno));
+    return -1;
+  }
+
+  /* If we setuid again, don't retain capabilities. */
+  if (prctl(PR_SET_KEEPCAPS, 0)) {
+    printf("2: Error unkeeping capabilities: %s", strerror(errno));
+    return -1;
+  }
+
+  return 0;
+}
+
+
 #ifndef _WIN32
 /** Log details of current user and group credentials. Return 0 on
  * success. Logs and return -1 on failure.
@@ -1544,6 +1663,8 @@ switch_id(const char *user)
   gid_t old_gid;
   static int have_already_switched_id = 0;
 
+  pre_capabilities();
+
   tor_assert(user);
 
   if (have_already_switched_id)
@@ -1619,7 +1740,6 @@ switch_id(const char *user)
 
   /* We've properly switched egid, gid, euid, uid, and supplementary groups if
    * we're here. */
-
 #if !defined(CYGWIN) && !defined(__CYGWIN__)
   /* If we tried to drop privilege to a group/user other than root, attempt to
    * restore root (E)(U|G)ID, and abort if the operation succeeds */
@@ -1643,6 +1763,7 @@ switch_id(const char *user)
     }
   }
 #endif
+  post_capabilities();
 
   /* Check what really happened */
   if (log_credential_status()) {
diff --git a/src/common/util.c b/src/common/util.c
index 5eb0f9a..f1afd1e 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -1839,7 +1839,7 @@ check_private_dir(const char *dirname, cpd_check_t check,
     running_uid = getuid();
     running_gid = getgid();
   }
-
+#if 0
   if (st.st_uid != running_uid) {
     struct passwd *pw = NULL;
     char *process_ownername = NULL;
@@ -1857,6 +1857,8 @@ check_private_dir(const char *dirname, cpd_check_t check,
     tor_free(process_ownername);
     return -1;
   }
+#endif
+#if 0
   if ((check & CPD_GROUP_OK) && st.st_gid != running_gid) {
     struct group *gr;
     char *process_groupname = NULL;
@@ -1872,6 +1874,7 @@ check_private_dir(const char *dirname, cpd_check_t check,
     tor_free(process_groupname);
     return -1;
   }
+#endif
   if (check & CPD_GROUP_OK) {
     mask = 0027;
   } else {
