--- tcpdump-3.9.4/tcpdump.c.ring 2005-08-23 12:29:41.000000000 +0200 +++ tcpdump-3.9.4/tcpdump.c 2005-12-20 13:32:45.000000000 +0100 @@ -109,7 +109,8 @@ static void ndo_default_print(netdissect_options *, const u_char *, u_int); 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 *, const char *); +static void droproot(const char *, const char *, int); +static void setroot(void); static void ndo_error(netdissect_options *ndo, const char *fmt, ...); static void ndo_warning(netdissect_options *ndo, const char *fmt, ...); @@ -295,6 +296,7 @@ char *WFileName; pcap_t *pd; pcap_dumper_t *p; + char *username; }; static void @@ -366,9 +368,10 @@ #ifndef WIN32 /* Drop root privileges and chroot if necessary */ static void -droproot(const char *username, const char *chroot_dir) +droproot(const char *username, const char *chroot_dir, int set_uid) { struct passwd *pw = NULL; + int res; if (chroot_dir && !username) { fprintf(stderr, "tcpdump: Chroot without dropping root is insecure\n"); @@ -384,8 +387,11 @@ exit(1); } } - if (initgroups(pw->pw_name, pw->pw_gid) != 0 || - setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) { + res = (initgroups(pw->pw_name, pw->pw_gid) != 0) || + (set_uid ? (setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) : + (setegid(pw->pw_gid) != 0 || seteuid(pw->pw_uid) != 0)); + + if (res) { fprintf(stderr, "tcpdump: Couldn't change to '%.32s' uid=%lu gid=%lu: %s\n", username, (unsigned long)pw->pw_uid, @@ -400,6 +406,17 @@ exit(1); } } + +/* Set root privileges */ +static void +setroot(void) +{ + if (setegid(0) != 0 || seteuid(0) != 0) { + fprintf(stderr, "tcpdump: Couldn't change to root uid=0 gid=0: %s\n", + pcap_strerror(errno)); + exit(1); + } +} #endif /* WIN32 */ static int @@ -463,6 +480,7 @@ int devnum; #endif int status; + int set_uid = 1; #ifdef WIN32 u_int UserBufferSize = 1000000; if(wsockinit() != 0) return 1; @@ -972,7 +990,9 @@ dumpinfo.WFileName = WFileName; dumpinfo.pd = pd; dumpinfo.p = p; + dumpinfo.username = username; pcap_userdata = (u_char *)&dumpinfo; + set_uid = 0; } else { callback = dump_packet; pcap_userdata = (u_char *)p; @@ -998,7 +1018,7 @@ */ if (getuid() == 0 || geteuid() == 0) { if (username || chroot_dir) - droproot(username, chroot_dir); + droproot(username, chroot_dir, set_uid); } #endif /* WIN32 */ #ifdef SIGINFO @@ -1181,7 +1201,14 @@ if (name == NULL) error("dump_packet_and_trunc: malloc"); MakeFilename(name, dump_info->WFileName, Cflag_count, WflagChars); +#ifndef WIN32 + setroot(); +#endif /* WIN32 */ dump_info->p = pcap_dump_open(dump_info->pd, name); +#ifndef WIN32 + if (dump_info->username) + droproot(dump_info->username, NULL, 0); +#endif /* WIN32 */ free(name); if (dump_info->p == NULL) error("%s", pcap_geterr(pd));