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