"@(#) 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
/*
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 */
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;
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);
#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 },
};
#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);
}
}
+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;
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;
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':
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;
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;
* 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)
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){
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);
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) {
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
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;
* 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)
(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);