]> The Tcpdump Group git mirrors - tcpdump/blobdiff - tcpdump.c
Add bounds checking.
[tcpdump] / tcpdump.c
index 7e7f516c9b628c752182a0f3a306bcd8b4f0cfba..2e1b533d318a42536087c9666407f5d5335b7874 100644 (file)
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -30,7 +30,7 @@ static const char copyright[] _U_ =
     "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
 The Regents of the University of California.  All rights reserved.\n";
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.229 2004-01-26 02:09:23 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.238 2004-03-23 18:57:33 fenner Exp $ (LBL)";
 #endif
 
 /*
@@ -65,8 +65,10 @@ extern int SIZE_BUF;
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#ifndef WIN32
 #include <pwd.h>
 #include <grp.h>
+#endif /* WIN32 */
 
 #include "interface.h"
 #include "addrtoname.h"
@@ -75,7 +77,7 @@ extern int SIZE_BUF;
 #include "gmt2local.h"
 #include "pcap-missing.h"
 
-static int dflag;              /* print filter code */
+int dflag;                     /* print filter code */
 int eflag;                     /* print ethernet header */
 int fflag;                     /* don't translate "foreign" IP address */
 static int Lflag;              /* list available data link types and exit */
@@ -111,6 +113,7 @@ static int WflagChars = 0;
 const char *dlt_name = NULL;
 
 char *espsecret = NULL;                /* ESP secret key */
+char *tcpmd5secret = NULL;     /* TCP-MD5 secret key */
 
 int packettype;
 
@@ -129,7 +132,7 @@ static void show_dlts_and_exit(pcap_t *pd) __attribute__((noreturn));
 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);
@@ -231,6 +234,12 @@ static struct printer printers[] = {
 #endif
 #ifdef DLT_ENC
        { enc_if_print,         DLT_ENC },
+#endif
+#ifdef DLT_SYMANTEC_FIREWALL
+       { symantec_if_print,    DLT_SYMANTEC_FIREWALL },
+#endif
+#ifdef DLT_APPLE_IP_OVER_IEEE1394
+       { ap1394_if_print,      DLT_APPLE_IP_OVER_IEEE1394 },
 #endif
        { NULL,                 0 },
 };
@@ -312,6 +321,12 @@ show_dlts_and_exit(pcap_t *pd)
 #define B_FLAG_USAGE
 #endif /* WIN32 */
 
+#ifdef HAVE_PCAP_FINDALLDEVS
+#ifndef HAVE_PCAP_IF_T
+#undef HAVE_PCAP_FINDALLDEVS
+#endif
+#endif
+
 #ifdef HAVE_PCAP_FINDALLDEVS
 #define D_FLAG "D"
 #else
@@ -324,15 +339,27 @@ show_dlts_and_exit(pcap_t *pd)
 #define U_FLAG
 #endif
 
-/* Drop root privileges */
+#ifndef WIN32
+/* 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);
@@ -344,6 +371,7 @@ droproot(const char *username)
                exit(1);
        }
 }
+#endif /* WIN32 */
 
 static int
 getWflagChars(int x)
@@ -386,6 +414,7 @@ main(int argc, char **argv)
        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;
@@ -415,7 +444,7 @@ main(int argc, char **argv)
 
        opterr = 0;
        while (
-           (op = getopt(argc, argv, "aA" B_FLAG "c:C:d" D_FLAG "eE:fF:i:lLm:nNOpqr:Rs:StT:u" U_FLAG "vw:W:xXy:YZ:")) != -1)
+           (op = getopt(argc, argv, "aA" B_FLAG "c:C:d" D_FLAG "eE:fF:i:lLm:M:nNOpqr:Rs:StT:u" U_FLAG "vw:W:xXy:YZ:")) != -1)
                switch (op) {
 
                case 'a':
@@ -568,6 +597,14 @@ main(int argc, char **argv)
 #endif
                        break;
 
+               case 'M':
+                       /* TCP-MD5 shared secret */
+#ifndef HAVE_LIBCRYPTO
+                       warning("crypto code not compiled in");
+#endif
+                       tcpmd5secret = optarg;
+                       break;
+
                case 'O':
                        Oflag = 0;
                        break;
@@ -704,6 +741,24 @@ main(int argc, char **argv)
        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) {
+               /* Run with '-Z root' to restore old behaviour */ 
+               if (!username)
+                       username = WITH_USER;
+       }
+#endif
+
        if (RFileName != NULL) {
                int dlt;
                const char *dlt_name;
@@ -718,13 +773,8 @@ main(int argc, char **argv)
                 * people's trace files (especially if we're set-UID
                 * root).
                 */
-               if (username) {
-                       droproot(username);
-               }
-               else {
-                       if (setgid(getgid()) != 0 || setuid(getuid()) != 0 )
-                               fprintf(stderr, "Warning: setgid/setuid failed !\n");
-               }
+               if (setgid(getgid()) != 0 || setuid(getuid()) != 0 )
+                       fprintf(stderr, "Warning: setgid/setuid failed !\n");
 #endif /* WIN32 */
                pd = pcap_open_offline(RFileName, ebuf);
                if (pd == NULL)
@@ -771,6 +821,13 @@ main(int argc, char **argv)
                        error("%s", ebuf);
                else if (*ebuf)
                        warning("%s", ebuf);
+               /*
+                * Let user own process after socket has been opened.
+                */
+#ifndef WIN32
+               if (setgid(getgid()) != 0 || setuid(getuid()) != 0)
+                       fprintf(stderr, "Warning: setgid/setuid failed !\n");
+#endif /* WIN32 */
 #ifdef WIN32
                if(UserBufferSize != 1000000)
                        if(pcap_setbuff(pd, UserBufferSize)==-1){
@@ -808,18 +865,6 @@ main(int argc, char **argv)
                        netmask = 0;
                        warning("%s", ebuf);
                }
-               /*
-                * Let user own process after socket has been opened.
-                */
-#ifndef WIN32
-               if (username) {
-                       droproot(username);
-               }
-               else {
-                       if (setgid(getgid()) != 0 || setuid(getuid()) != 0)
-                               fprintf(stderr, "Warning: setgid/setuid failed !\n");
-               }
-#endif /* WIN32 */
        }
        if (infile)
                cmdbuf = read_infile(infile);
@@ -881,6 +926,16 @@ main(int argc, char **argv)
                callback = print_packet;
                pcap_userdata = (u_char *)&printinfo;
        }
+#ifndef WIN32
+       /*
+        * We cannot do this earlier, because we want to be able to open
+        * the file (if done) for writing before giving up permissions.
+        */
+       if (getuid() == 0 || geteuid() == 0) {
+               if (username || chroot_dir)
+                       droproot(username, chroot_dir);
+       }
+#endif /* WIN32 */
 #ifdef SIGINFO
        (void)setsignal(SIGINFO, requestinfo);
 #endif
@@ -948,16 +1003,6 @@ main(int argc, char **argv)
                (void)fprintf(stderr, "%s: pcap_loop: %s\n",
                    program_name, pcap_geterr(pd));
        }
-#ifdef WITH_USER
-       /* if run as root, drop root; protect against remote sec problems */
-       if (getuid() == 0 || geteuid() == 0) {
-               /* Run with '-Z root' to restore old behaviour */ 
-               if (!username) {
-                       droproot(WITH_USER);
-                       /* does not return if fails */
-               }
-       }
-#endif
        if (RFileName == NULL) {
                /*
                 * We're doing a live capture.  Report the capture
@@ -1251,9 +1296,9 @@ usage(void)
        (void)fprintf(stderr,
 "Usage: %s [-aAd" D_FLAG "eflLnNOpqRStu" U_FLAG "vxX]" B_FLAG_USAGE " [-c count] [ -C file_size ]\n", program_name);
        (void)fprintf(stderr,
-"\t\t[ -E algo:secret ] [ -F file ] [ -i interface ] [ -r file ]\n");
+"\t\t[ -E algo:secret ] [ -F file ] [ -i interface ] [ -M secret ]\n");
        (void)fprintf(stderr,
-"\t\t[ -s snaplen ] [ -T type ] [ -w file ] [ -W filecount ]\n");
+"\t\t[ -r file ] [ -s snaplen ] [ -T type ] [ -w file ] [ -W filecount ]\n");
        (void)fprintf(stderr,
 "\t\t[ -y datalinktype ] [ -Z user ]\n");
        (void)fprintf(stderr,