diff -ur tcpdump-2004.01.21/tcpdump.1 tcpdump-2004.01.21.droproot/tcpdump.1 --- tcpdump-2004.01.21/tcpdump.1 Thu Jan 15 21:55:56 2004 +++ tcpdump-2004.01.21.droproot/tcpdump.1 Wed Jan 21 19:36:41 2004 @@ -83,6 +83,10 @@ .B \-y .I datalinktype ] +[ +.B \-Z +.I user +] .ti +8 [ .I expression @@ -541,6 +545,12 @@ .TP .B \-y Set the data link type to use while capturing packets to \fIdatalinktype\fP. +.TP +.B \-Z +Drops privileges (if root) and changes user ID to +.I user +and the group ID to the primary group of +.IR user . .IP "\fI expression\fP" .RS selects which packets will be dumped. Only in tcpdump-2004.01.21.droproot: tcpdump.1.orig diff -ur tcpdump-2004.01.21/tcpdump.c tcpdump-2004.01.21.droproot/tcpdump.c --- tcpdump-2004.01.21/tcpdump.c Thu Jan 15 21:56:50 2004 +++ tcpdump-2004.01.21.droproot/tcpdump.c Wed Jan 21 19:33:42 2004 @@ -65,6 +65,7 @@ #include #include #include +#include #include "interface.h" #include "addrtoname.h" @@ -310,6 +311,25 @@ #define U_FLAG #endif +/* Drop root privileges */ +void droproot(const char *username) +{ + struct passwd *pw = NULL; + pw = getpwnam(username); + if (pw) { + if (initgroups(pw->pw_name, NULL) != 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); + exit(1); + } + } + else { + fprintf(stderr, "Couldn't find user '%.32s'\n", username); + exit(1); + } +} + int main(int argc, char **argv) { @@ -326,6 +346,7 @@ struct dump_info dumpinfo; u_char *pcap_userdata; char ebuf[PCAP_ERRBUF_SIZE]; + char *username = NULL; #ifdef HAVE_PCAP_FINDALLDEVS pcap_if_t *devpointer; int devnum; @@ -355,7 +376,7 @@ 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:Y")) != -1) + (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) switch (op) { case 'a': @@ -619,6 +640,16 @@ } break; #endif + case 'Z': + if (optarg) { + username = strdup(optarg); + } + else { + usage(); + /* NOTREACHED */ + } + break; + default: usage(); /* NOTREACHED */ @@ -641,7 +672,13 @@ * people's trace files (especially if we're set-UID * root). */ - setuid(getuid()); + if (username) { + droproot(username); + } + else { + 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) @@ -729,7 +766,13 @@ * Let user own process after socket has been opened. */ #ifndef WIN32 - setuid(getuid()); + if (username) { + droproot(username); + } + else { + if (setgid(getgid()) != 0 || setuid(getuid()) != 0) + fprintf(stderr, "Warning: setgid/setuid failed !\n"); + } #endif /* WIN32 */ } if (infile) @@ -1167,7 +1210,7 @@ (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 ]\n"); +"\t\t[ -s snaplen ] [ -T type ] [ -w file ] [ -y datalinktype ] [ -Z user ]\n"); (void)fprintf(stderr, "\t\t[ expression ]\n"); exit(1); Only in tcpdump-2004.01.21.droproot: tcpdump.c.orig