Hi,

This is my view on how chroot should be done (note: I haven't bothered 
to add a cmd-line argument, if you think that should be added, it's 
trivial), and the trivial setuid patch as well.

This doesn't try to automatically create directories or whatever, but 
relies on the compile time option (e.g. /var/empty) but is IMHO better 
in some sense.

-- 
Pekka Savola                 "You each name yourselves king, yet the
Netcore Oy                    kingdom bleeds."
Systems. Networks. Security. -- George R.R. Martin: A Clash of Kings
--- tcpdump.c~  Wed Feb 25 10:00:06 2004
+++ tcpdump.c   Wed Feb 25 10:00:06 2004
@@ -906,8 +906,10 @@
         * We cannot do this earlier, because we want to be able to open
         * the file (if done) for writing before giving up permissions.
         */
-       if (username || chroot_dir)
-               droproot(username, chroot_dir);
+       if (getuid() == 0 || geteuid() == 0) {
+               if (username || chroot_dir)
+                       droproot(username, chroot_dir);
+       }
 #endif /* WIN32 */
 #ifdef SIGINFO
        (void)setsignal(SIGINFO, requestinfo);
diff -ur -x configure tcpdump-2004.02.24/acconfig.h tcpdump-2004.02.23.new/acconfig.h
--- tcpdump-2004.02.24/acconfig.h       Thu Jan 22 11:51:30 2004
+++ tcpdump-2004.02.23.new/acconfig.h   Wed Feb 25 09:04:41 2004
@@ -129,3 +129,6 @@
 
 /* define if should drop privileges by default */
 #undef WITH_USER
+
+/* define if should chroot when dropping privileges */
+#undef WITH_CHROOT
diff -ur -x configure tcpdump-2004.02.24/configure.in 
tcpdump-2004.02.23.new/configure.in
--- tcpdump-2004.02.24/configure.in     Sat Jan 31 07:26:51 2004
+++ tcpdump-2004.02.23.new/configure.in Wed Feb 25 09:23:03 2004
@@ -111,6 +111,15 @@
        AC_MSG_RESULT(no)
 fi
 
+AC_ARG_WITH(chroot, [  --with-chroot=DIRECTORY when dropping privileges, chroot to 
DIRECTORY])
+AC_MSG_CHECKING([where to chroot to])
+if test ! -z "$with_chroot" ; then
+        AC_DEFINE_UNQUOTED(WITH_CHROOT, "$withval")
+       AC_MSG_RESULT(to \"$withval\")
+else
+       AC_MSG_RESULT(no)
+fi
+
 AC_MSG_CHECKING([whether to enable ipv6])
 AC_ARG_ENABLE(ipv6,
 [  --enable-ipv6           enable ipv6 (with ipv4) support
diff -ur -x configure tcpdump-2004.02.24/tcpdump.c tcpdump-2004.02.23.new/tcpdump.c
--- tcpdump-2004.02.24/tcpdump.c        Tue Feb 24 10:12:18 2004
+++ tcpdump-2004.02.23.new/tcpdump.c    Wed Feb 25 09:56:25 2004
@@ -129,7 +129,7 @@
 static void print_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
 static void dump_packet_and_trunc(u_char *, const struct pcap_pkthdr *, const u_char 
*);
 static void dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
-static void droproot(const char *);
+static void droproot(const char *, const char *);
 
 #ifdef SIGINFO
 RETSIGTYPE requestinfo(int);
@@ -324,15 +324,26 @@
 #define U_FLAG
 #endif
 
-/* Drop root privileges */
+/* Drop root privileges and chroot if necessary */
 static void
-droproot(const char *username)
+droproot(const char *username, const char *chroot_dir)
 {
        struct passwd *pw = NULL;
 
+       if (chroot_dir && !username) {
+               fprintf(stderr, "Chroot without dropping root is insecure\n");
+               exit(1);
+       }
+       
        pw = getpwnam(username);
        if (pw) {
-               if (initgroups(pw->pw_name, 0) != 0 || setgid(pw->pw_gid) != 0 ||
+               if (chroot_dir) {
+                       if (chroot(chroot_dir) != 0 || chdir (".") != 0) {
+                               fprintf(stderr, "Couldn't chroot/chdir to '%.64s'\n", 
chroot_dir);
+                               exit(1);
+                       }
+               }
+               if (initgroups(pw->pw_name, pw->pw_gid) != 0 || setgid(pw->pw_gid) != 
0 ||
                                 setuid(pw->pw_uid) != 0) {
                        fprintf(stderr, "Couldn't change to '%.32s' uid=%d gid=%d\n", 
username, 
                                                        pw->pw_uid, pw->pw_gid);
@@ -386,6 +397,7 @@
        u_char *pcap_userdata;
        char ebuf[PCAP_ERRBUF_SIZE];
        char *username = NULL;
+       char *chroot_dir = NULL;
 #ifdef HAVE_PCAP_FINDALLDEVS
        pcap_if_t *devpointer;
        int devnum;
@@ -704,6 +716,15 @@
        if (tflag > 0)
                thiszone = gmt2local(0);
 
+#ifdef WITH_CHROOT
+       /* if run as root, prepare for chrooting */
+       if (getuid() == 0 || geteuid() == 0) {
+               /* future extensibility for cmd-line arguments */
+               if (!chroot_dir)
+                       chroot_dir = WITH_CHROOT;
+       }
+#endif
+
 #ifdef WITH_USER
        /* if run as root, prepare for dropping root privileges */
        if (getuid() == 0 || geteuid() == 0) {
@@ -885,9 +906,8 @@
         * We cannot do this earlier, because we want to be able to open
         * the file (if done) for writing before giving up permissions.
         */
-       if (username) {
-               droproot(username);
-       }
+       if (username || chroot_dir)
+               droproot(username, chroot_dir);
 #endif /* WIN32 */
 #ifdef SIGINFO
        (void)setsignal(SIGINFO, requestinfo);

Reply via email to