]> The Tcpdump Group git mirrors - tcpdump/blobdiff - tcpdump.c
provide multiline output for PIM Joins/Grafts/Graft-Acks
[tcpdump] / tcpdump.c
index a3fce5251ca59cdebf66763b427d65284a9c6823..4dc2fe0aa39e4569d758982eb0de21518f71a555 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.226 2004-01-22 09:35:50 hannes Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.235 2004-03-17 19:40:42 guy Exp $ (LBL)";
 #endif
 
 /*
@@ -78,11 +78,11 @@ extern int SIZE_BUF;
 int dflag;                     /* print filter code */
 int eflag;                     /* print ethernet header */
 int fflag;                     /* don't translate "foreign" IP address */
-int Lflag;                     /* list available data link types and exit */
+static int Lflag;              /* list available data link types and exit */
 int nflag;                     /* leave addresses as numbers */
 int Nflag;                     /* remove domains from printed host names */
-int Oflag = 1;                 /* run filter code optimizer */
-int pflag;                     /* don't go promiscuous */
+static int Oflag = 1;          /* run filter code optimizer */
+static int pflag;              /* don't go promiscuous */
 int qflag;                     /* quick (shorter) output */
 int Rflag = 1;                 /* print sequence # field in AH/ESP*/
 int sflag = 0;                 /* use the libsmi to translate OIDs */
@@ -93,9 +93,20 @@ int uflag = 0;                       /* Print undecoded NFS handles */
 int vflag;                     /* verbose */
 int xflag;                     /* print packet in hex */
 int Xflag;                     /* print packet in ascii as well as hex */
-off_t Cflag = 0;                /* rotate dump files after this many bytes */
+static off_t Cflag = 0;                /* rotate dump files after this many bytes */
 int Aflag = 0;                  /* print packet only in ascii observing LF, CR, TAB, SPACE */
-int dlt = -1;          /* if != -1, ask libpcap for the DLT it names */
+static int dlt = -1;           /* if != -1, ask libpcap for the DLT it names */
+static int Cflag_count = 0;    /* Keep track of which file number we're writing */
+static int Wflag = 0;          /* recycle output files after this number of files */
+static int WflagChars = 0;
+
+/*
+ * Define the maximum number of files for the -C flag, and how many
+ * characters can be added to a filename for the -C flag (which
+ * should be enough to handle MAX_CFLAG - 1).
+ */
+#define MAX_CFLAG      1000000
+#define MAX_CFLAG_CHARS        6
 
 const char *dlt_name = NULL;
 
@@ -118,7 +129,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);
@@ -220,6 +231,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 },
 };
@@ -313,13 +330,26 @@ show_dlts_and_exit(pcap_t *pd)
 #define U_FLAG
 #endif
 
-/* Drop root privileges */
-void droproot(const char *username)
+/* Drop root privileges and chroot if necessary */
+static void
+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);
@@ -332,12 +362,36 @@ void droproot(const char *username)
        }
 }
 
+static int
+getWflagChars(int x)
+{
+       int c = 0;
+
+       x -= 1;
+       while (x > 0) {
+               c += 1;
+               x /= 10;
+       }
+
+       return c;
+}
+
+
+static void
+MakeFilename(char *buffer, char *orig_name, int cnt, int max_chars)
+{
+       if (cnt == 0 && max_chars == 0)
+               strcpy(buffer, orig_name);
+       else
+               sprintf(buffer, "%s%0*d", orig_name, max_chars, cnt);
+}
+
 int
 main(int argc, char **argv)
 {
        register int cnt, op, i;
        bpf_u_int32 localnet, netmask;
-       register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName;
+       register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName, *WFileNameAlt;
        pcap_handler callback;
        int type;
        struct bpf_program fcode;
@@ -349,6 +403,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;
@@ -378,7 +433,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:xXy:YZ:")) != -1)
+           (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)
                switch (op) {
 
                case 'a':
@@ -612,6 +667,13 @@ main(int argc, char **argv)
                        WFileName = optarg;
                        break;
 
+               case 'W':
+                       Wflag = atoi(optarg);
+                       if (Wflag < 0) 
+                               error("invalid number of output files %s", optarg);
+                       WflagChars = getWflagChars(Wflag);
+                       break;
+
                case 'x':
                        ++xflag;
                        break;
@@ -660,6 +722,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;
@@ -674,13 +754,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)
@@ -727,6 +802,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){
@@ -764,18 +846,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);
@@ -805,7 +875,13 @@ main(int argc, char **argv)
        if (pcap_setfilter(pd, &fcode) < 0)
                error("%s", pcap_geterr(pd));
        if (WFileName) {
-               pcap_dumper_t *p = pcap_dump_open(pd, WFileName);
+               pcap_dumper_t *p;
+
+               WFileNameAlt = (char *)malloc(strlen(WFileName) + MAX_CFLAG_CHARS + 1);
+               if (WFileNameAlt == NULL)
+                       error("malloc of WFileNameAlt");
+               MakeFilename(WFileNameAlt, WFileName, 0, WflagChars);
+               p = pcap_dump_open(pd, WFileNameAlt);
                if (p == NULL)
                        error("%s", pcap_geterr(pd));
                if (Cflag != 0) {
@@ -831,6 +907,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
@@ -977,38 +1063,10 @@ info(register int verbose)
        infoprint = 0;
 }
 
-static void
-reverse(char *s)
-{
-       int i, j, c;
-
-       for (i = 0, j = strlen(s) - 1; i < j; i++, j--) {
-               c = s[i];
-               s[i] = s[j];
-               s[j] = c;
-       }
-}
-
-
-static void
-swebitoa(unsigned int n, char *s)
-{
-       unsigned int i;
-
-       i = 0;
-       do {
-               s[i++] = n % 10 + '0';
-       } while ((n /= 10) > 0);
-
-       s[i] = '\0';
-       reverse(s);
-}
-
 static void
 dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
 {
        struct dump_info *dump_info;
-       static uint cnt = 2;
        char *name;
 
        ++packets_captured;
@@ -1023,13 +1081,22 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
         * file could put it over Cflag.
         */
        if (ftell((FILE *)dump_info->p) > Cflag) {
-               name = (char *) malloc(strlen(dump_info->WFileName) + 4);
+               /*
+                * Close the current file and open a new one.
+                */
+               pcap_dump_close(dump_info->p);
+               Cflag_count++;
+               if (Wflag > 0) {
+                       if (Cflag_count >= Wflag)
+                               Cflag_count = 0;
+               } else {
+                       if (Cflag_count >= MAX_CFLAG)
+                               error("too many output files");
+               }
+               name = (char *)malloc(strlen(dump_info->WFileName) + MAX_CFLAG_CHARS + 1);
                if (name == NULL)
                        error("dump_packet_and_trunc: malloc");
-               strcpy(name, dump_info->WFileName);
-               swebitoa(cnt, name + strlen(dump_info->WFileName));
-               cnt++;
-               pcap_dump_close(dump_info->p);
+               MakeFilename(name, dump_info->WFileName, Cflag_count, WflagChars);
                dump_info->p = pcap_dump_open(dump_info->pd, name);
                free(name);
                if (dump_info->p == NULL)
@@ -1212,7 +1279,9 @@ usage(void)
        (void)fprintf(stderr,
 "\t\t[ -E algo:secret ] [ -F file ] [ -i interface ] [ -r file ]\n");
        (void)fprintf(stderr,
-"\t\t[ -s snaplen ] [ -T type ] [ -w file ] [ -y datalinktype ] [ -Z user ]\n");
+"\t\t[ -s snaplen ] [ -T type ] [ -w file ] [ -W filecount ]\n");
+       (void)fprintf(stderr,
+"\t\t[ -y datalinktype ] [ -Z user ]\n");
        (void)fprintf(stderr,
 "\t\t[ expression ]\n");
        exit(1);