tpop3d-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[tpop3d-discuss] Option to chroot() for virtual servers


From: Travis Miller
Subject: [tpop3d-discuss] Option to chroot() for virtual servers
Date: Sun, 15 Dec 2002 18:48:54 -0600
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20020605

Chris (and everyone else):

A little history: We currently use tpop3d for hosting email for "virtual" users (ie, they do not exist in /etc/passwd). To do this, all of the mail boxes are owned by the same user "mailspool" in group "mailspool" and the pop3 user is authenticated via mysql.

And the idea: So to improve a little on security I thought I would try patching tpop3d to chroot() to the mail spool and setgid()/setuid() to a non-privledeged user right before net_loop() in main.c. I have attached a patch that seems to work for this as long as you have a copy of /etc/passwd and /etc/group in /path/to/spools/etc. When you do not have copies in the there, auth_mysql fails at parse_uid(),parse_gid and all the other passwd/group system calls (of course). Of course, it breaks other things such as kill -HUP also....

My Question:
Does this seem like a worth while advantage to add?

It does mean leaving open file descriptors after the chroot(), setuid()... is that fact not worth worrying with with chroot'ing in the first place?

Would it be worth the effort to code in a work around for all the uid/gid calls when chroot() is enabled?

And lastly, I am no code wizard, so comments/ideas on methods of implementing this? (mine is very basic!)

(The attached patch is against 1.4.2, chroot is enabled via configure with --enable-chroot)

Travis
address@hidden
diff -u tpop3d-1.4.2/configure.in tpop3d-1.4.2-chroot/configure.in
--- tpop3d-1.4.2/configure.in   2002-06-27 15:08:46.000000000 -0500
+++ tpop3d-1.4.2-chroot/configure.in    2002-12-15 17:53:25.000000000 -0600
@@ -198,6 +198,13 @@
     [enable_drac=$enableval],
     [enable_drac=no])
 
+dnl Enable chroot()ed server 
+AC_ARG_ENABLE(chroot,
+        [ --enable-choot                       Enable support for chroot()'d 
server.
+                                      [default=no]],
+    [enable_chroot=$enableval],
+    [enable_chroot=no])
+
 dnl Some options mainly useful for development/debugging.
 
 dnl Note the ugliness I've used to put a note in the output of
@@ -331,6 +338,11 @@
     AC_DEFINE(USE_DRAC,1,[Enables notification of a DRAC daemon.])
 fi
 
+if test x"$enable_chroot" = x"yes"
+then
+    AC_DEFINE(WITH_CHROOT,1,[Enables ablilty to chroot() server.])
+fi
+
 if test x"$enable_backtrace" = x"yes"
 then
     AC_DEFINE(APPALLING_BACKTRACE_HACK,1,[Produce a backtrace if the program 
crashes.])
Common subdirectories: tpop3d-1.4.2/darwin and tpop3d-1.4.2-chroot/darwin
Common subdirectories: tpop3d-1.4.2/init.d and tpop3d-1.4.2-chroot/init.d
diff -u tpop3d-1.4.2/main.c tpop3d-1.4.2-chroot/main.c
--- tpop3d-1.4.2/main.c 2002-06-25 15:28:00.000000000 -0500
+++ tpop3d-1.4.2-chroot/main.c  2002-12-15 17:41:31.000000000 -0600
@@ -32,6 +32,11 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
+#if defined(WITH_CHROOT)
+#include <pwd.h>
+#include <grp.h>
+#endif
+
 #include <sys/socket.h>
 #include <sys/time.h>
 #include <sys/types.h>
@@ -453,6 +458,77 @@
 
 #define EXIT_REMOVING_PIDFILE(n) do { if (pidfile) remove_pid_file(pidfile); 
exit((n)); } while (0)
 
+#if defined(WITH_CHROOT)
+/* do_chroot:
+ * Jail the server to a particular section of the file system.  This, of 
course, is not
+ * useful if we are still root; so we drop root priviledges also... This has a 
*large*
+ * effect on how the rest of the server works, it may currently break things.  
Returns 0
+ * on failure and 1 on success.
+ */
+int do_chroot(void) {
+    struct passwd *pw;
+    struct group *gr;
+    int new_uid;
+    int new_gid;
+    char *path;
+    char *tmp;
+
+    /* Get the path to chroot() to */
+    if ((path = config_get_string("chroot-path")) == NULL) {
+        log_print(LOG_INFO, _("do_chroot: could not determine 
chroot-path"),path);
+        return(0);
+    }
+
+    /* We need to know what user to setuid() to after chroot(), first attemt 
to get
+    * the username from the config, if that fails try to get the uid. */
+    if ((tmp = config_get_string("chroot-user")) != NULL) {
+        if ((pw = getpwnam(tmp)) != NULL) {
+            new_uid = pw->pw_uid;
+        } else {
+            log_print(LOG_INFO, _("do_chroot: could not determine chroot-user 
(chroot-user: %s)"),tmp);
+            return(0);
+        }
+    } else if (config_get_int("chroot-uid",&new_uid) != 1) {
+        log_print(LOG_INFO, _("do_chroot: could not determine 
chroot-user"),new_uid);
+        return(0);
+    }
+
+    /* Now we do the exact same thing for the setgid() call */
+    if ((tmp = config_get_string("chroot-group")) != NULL) {
+        if ((gr = getgrnam(tmp)) != NULL) {
+            new_gid = gr->gr_gid;
+        } else {
+            log_print(LOG_INFO, _("do_chroot: could not determine chroot-group 
(chroot-group: %s)"),tmp);
+            return(0);
+        }
+    } else if (config_get_int("chroot-gid",&new_gid) != 1) {
+        log_print(LOG_INFO, _("do_chroot: could not determine chroot-group"));
+        return(0);
+    }
+
+    /* chroot and chdir */
+    if (chroot(path) == -1) {
+        log_print(LOG_INFO, _("do_chroot: chroot(%s) failed!"),path);
+        return(0);
+    } else if (chdir("/") == -1) {
+        log_print(LOG_INFO, _("do_chroot: chdir(/) failed!"));
+        return(0);
+    }
+
+    /* become a non-root user, too easy to break chroot() as root */
+    if (setgid((gid_t)new_gid) == -1) {
+        log_print(LOG_ERR, "do_chroot: setgid(%d)",new_gid);
+        return(0);
+    } else if (setuid((uid_t)new_uid) == -1) {
+        log_print(LOG_ERR, "do_chroot: setuid(%d)",new_uid);
+        return(0);
+    }
+
+    /* Success! */
+    return(1);
+}
+#endif
+
 /* usage:
  * Print usage information.
  */
@@ -747,6 +823,19 @@
         EXIT_REMOVING_PIDFILE(1);
     } else log_print(LOG_INFO, _("%d authentication drivers successfully 
loaded"), na);
    
+#if defined(WITH_CHROOT)
+    /* Now that we have all the open file descriptors and everything else that 
we should
+     * need, we can chroot(). */
+    if (config_get_bool("chroot")) {
+        int cr = do_chroot();
+        if (!cr) {
+            log_print(LOG_ERR, _("Unable to successfully chroot(); 
aborting."));
+            log_print(LOG_ERR, _("you may wish to check your config file %s"), 
configfile);
+            EXIT_REMOVING_PIDFILE(1);
+        } else log_print(LOG_INFO, _("Successfully chroot()'d"));
+    }
+#endif
+
     net_loop();
 
     if (!post_fork)

reply via email to

[Prev in Thread] Current Thread [Next in Thread]