瀏覽代碼

added User and Group options -- if you set them, tor will try to
setuid and setgid respectively, and die if it can't.

(If the User option is set, tor will setgid to the user's gid as well.)

This happens after the pidfile is created, so that in cases where tor
needs to be root to work with the pidfile, it will at least be able to
create it, although it won't be able to delete it. That sucks, but
it's somewhat better than not being able to create the pidfile in the
first place.


svn:r652

Steven Hazel 20 年之前
父節點
當前提交
b1eca56b77
共有 4 個文件被更改,包括 75 次插入5 次删除
  1. 1 1
      configure.in
  2. 2 0
      src/or/config.c
  3. 64 4
      src/or/main.c
  4. 8 0
      src/or/or.h

+ 1 - 1
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
 

+ 2 - 0
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) ||

+ 64 - 4
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();
 

+ 8 - 0
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;