diff --git a/configure.in b/configure.in
index 33d9484167386bc07a40be793962d5be7c4da682..7933cf767852dc590e1d7aec240f38e23f12a31b 100644
--- a/configure.in
+++ b/configure.in
@@ -130,7 +130,7 @@ LIBS="$saved_LIBS -lcrypto -lssl"
 
 dnl The warning message here is no longer strictly accurate.
 
-AC_CHECK_HEADERS(unistd.h string.h signal.h netdb.h ctype.h poll.h sys/stat.h sys/poll.h sys/types.h sys/fcntl.h sys/ioctl.h sys/socket.h sys/time.h netinet/in.h arpa/inet.h errno.h assert.h time.h, , AC_MSG_WARN(some headers were not found, compilation may fail))
+AC_CHECK_HEADERS(unistd.h string.h signal.h netdb.h ctype.h poll.h sys/stat.h sys/poll.h sys/types.h sys/fcntl.h sys/ioctl.h sys/socket.h sys/time.h netinet/in.h arpa/inet.h errno.h assert.h time.h pwd.h grp.h, , AC_MSG_WARN(some headers were not found, compilation may fail))
 
 dnl These headers are not essential
 
diff --git a/src/or/config.c b/src/or/config.c
index 8bc0e17ffa22e99b0aed977fa342530f1b0007a0..c049b681fc8abb25e61c728f4787e52f59a53006 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -162,6 +162,8 @@ static void config_assign(or_options_t *options, struct config_line *list) {
     config_compare(list, "ExitPolicy",     CONFIG_TYPE_STRING, &options->ExitPolicy) ||
     config_compare(list, "SocksBindAddress",CONFIG_TYPE_STRING,&options->SocksBindAddress) ||
     config_compare(list, "ORBindAddress",  CONFIG_TYPE_STRING, &options->ORBindAddress) ||
+    config_compare(list, "User",           CONFIG_TYPE_STRING, &options->User) ||
+    config_compare(list, "Group",           CONFIG_TYPE_STRING, &options->Group) ||
 
     /* int options */
     config_compare(list, "MaxConn",         CONFIG_TYPE_INT, &options->MaxConn) ||
diff --git a/src/or/main.c b/src/or/main.c
index a7bd83adf1b9c465978a33e83a56f5691bdb7951..1d6511f521a30a43871d3bae9a53fb58174e4119 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -599,7 +599,7 @@ static int do_main_loop(void) {
                         (uint16_t) options.DirPort);
 
   for(;;) {
-#ifndef MS_WIN32 /* do signal stuff only on unix */
+#ifndef MS_WINDOWS /* do signal stuff only on unix */
     if(please_dumpstats) {
       /* prefer to log it at INFO, but make sure we always see it */
       dumpstats(options.loglevel>LOG_INFO ? options.loglevel : LOG_INFO);
@@ -670,14 +670,14 @@ static int do_main_loop(void) {
 
 static void catch(int the_signal) {
 
-#ifndef MS_WIN32 /* do signal stuff only on unix */
+#ifndef MS_WINDOWS /* do signal stuff only on unix */
   switch(the_signal) {
 //    case SIGABRT:
     case SIGTERM:
     case SIGINT:
       log(LOG_ERR,"Catching signal %d, exiting cleanly.", the_signal);
-      /* we don't care if there was an error when we unlink,
-         nothing we could do about it anyways */
+      /* we don't care if there was an error when we unlink, nothing
+         we could do about it anyways */
       unlink(options.PidFile);
       exit(0);
     case SIGHUP:
@@ -767,6 +767,7 @@ void daemonize(void) {
 }
 
 void write_pidfile(char *filename) {
+#ifndef MS_WINDOWS
   FILE *pidfile;
 
   if ((pidfile = fopen(filename, "w")) == NULL) {
@@ -776,6 +777,52 @@ void write_pidfile(char *filename) {
     fprintf(pidfile, "%d", getpid());
     fclose(pidfile);
   }
+#endif
+}
+
+int switch_user(char *user) {
+#ifndef MS_WINDOWS
+  int status;
+  struct passwd *pw = NULL;
+
+  pw = getpwnam(user);
+  if(pw == NULL) {
+    log_fn(LOG_ERR,"User '%s' not found.", user);
+    return -1;
+  }
+  status = setuid(pw->pw_uid);
+  if (status != 0) {
+    log_fn(LOG_ERR,"Error setting UID: %s", strerror(errno));
+    return -1;
+  }
+  status = setgid(pw->pw_gid);
+  if (status != 0) {
+    log_fn(LOG_ERR,"Error setting GID: %s", strerror(errno));
+    return -1;
+  }
+
+  return 0;
+#endif
+}
+
+int switch_group(char *group) {
+#ifndef MS_WINDOWS
+  int status;
+  struct group *gr = NULL;
+
+  gr = getgrnam(group);
+  if(gr == NULL) {
+    log_fn(LOG_ERR,"Group '%s' not found.", group);
+    return -1;
+  }
+  status = setgid(gr->gr_gid);
+  if (status != 0) {
+    log_fn(LOG_ERR,"Error setting GID: %s", strerror(errno));
+    return -1;
+  }
+
+  return 0;
+#endif
 }
 
 int tor_main(int argc, char *argv[]) {
@@ -802,6 +849,19 @@ int tor_main(int argc, char *argv[]) {
   /* write our pid to the pid file */
   write_pidfile(options.PidFile);
 
+  /* now that we've written the pid file, we can switch the user and group */
+  if(options.User) {
+    if(switch_user(options.User) != 0) {
+      return -1;
+    }
+  }
+
+  if(options.Group) {
+    if(switch_group(options.Group) != 0) {
+      return -1;
+    }
+  }
+
   if(options.RunAsDaemon)
     daemonize();
 
diff --git a/src/or/or.h b/src/or/or.h
index 85ce9092b81da2ddf3408540b0b0fe5f3c656ede..bc96e0869223dc028c9015e3afb693a513470276 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -72,6 +72,12 @@
 #ifdef HAVE_TIME_H
 #include <time.h>
 #endif
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
 #ifdef HAVE_WINSOCK_H
 #include <winsock.h>
 #endif
@@ -428,6 +434,8 @@ typedef struct {
    char *ExitPolicy;
    char *SocksBindAddress;
    char *ORBindAddress;
+   char *User;
+   char *Group;
    double CoinWeight;
    int ORPort;
    int SocksPort;