Blob Blame History Raw
diff -up tcpdump-4.2.1/tcpdump.1.in.eperm tcpdump-4.2.1/tcpdump.1.in
--- tcpdump-4.2.1/tcpdump.1.in.eperm	2012-05-16 15:46:55.009494388 +0200
+++ tcpdump-4.2.1/tcpdump.1.in	2012-05-16 15:47:16.860299598 +0200
@@ -214,6 +214,9 @@ have the name specified with the
 flag, with a number after it, starting at 1 and continuing upward.
 The units of \fIfile_size\fP are millions of bytes (1,000,000 bytes,
 not 1,048,576 bytes).
+
+Note that when used with \fB\-Z\fR option (enabled by default), privileges
+are dropped before opening first savefile.
 .TP
 .B \-d
 Dump the compiled packet-matching code in a human readable form to
@@ -650,7 +653,9 @@ but before opening any savefiles for out
 and the group ID to the primary group of
 .IR user .
 .IP
-This behavior can also be enabled by default at compile time.
+This behavior is enabled by default (\fB\-Z tcpdump\fR), and can
+be disabled by \fB\-Z root\fR.
+
 .IP "\fI expression\fP"
 .RS
 selects which packets will be dumped.
diff -up tcpdump-4.2.1/tcpdump.c.eperm tcpdump-4.2.1/tcpdump.c
--- tcpdump-4.2.1/tcpdump.c.eperm	2012-05-16 15:46:28.321732801 +0200
+++ tcpdump-4.2.1/tcpdump.c	2012-05-16 15:46:42.642604795 +0200
@@ -1289,9 +1289,27 @@ main(int argc, char **argv)
 	 * Switching to the -Z user ID only after opening the first
 	 * savefile doesn't handle the general case.
 	 */
-	if (getuid() == 0 || geteuid() == 0) {
-		if (username || chroot_dir)
-			droproot(username, chroot_dir);
+
+	/* If user is running tcpdump as root and wants to write to the savefile,
+	 * we will check if -C is set and if it is, we will drop root
+	 * privileges right away and consequent call to	pcap_dump_open()
+	 * will most likely fail for the first file. If -C flag is not set we
+	 * will create file as root then change ownership of file to proper
+	 * user(default tcpdump) and drop root privileges.
+	 */
+	int chown_flag = 0;
+	if (WFileName && (getuid() == 0 || geteuid() == 0)) {
+		if (Cflag != 0) {
+			if (username || chroot_dir)
+				droproot(username, chroot_dir);
+		} else {
+			chown_flag = 1;
+		}
+	} else {
+		if (getuid() == 0 || geteuid() == 0) {
+			if (username || chroot_dir)
+				droproot(username, chroot_dir);
+		}
 	}
 #endif /* WIN32 */
 
@@ -1312,6 +1330,40 @@ main(int argc, char **argv)
 		  MakeFilename(dumpinfo.CurrentFileName, WFileName, 0, 0);
 
 		p = pcap_dump_open(pd, dumpinfo.CurrentFileName);
+		
+		/* Change ownership of file and drop root privileges */
+		if (chown_flag) {
+			struct passwd pwd;
+			struct passwd *p_pwd;
+			char *username_buf;
+			long initlen;
+			size_t len;
+
+			initlen = sysconf(_SC_GETPW_R_SIZE_MAX);
+			if (initlen == -1) {
+				len = 1024;
+			} else {
+				len = (size_t) initlen;
+			}
+
+			username_buf = (char *) malloc(len * sizeof(char));
+			if (username_buf == NULL) {
+				error("malloc of username_buf");
+			}
+
+			getpwnam_r(username, &pwd, username_buf, len, &p_pwd);
+			if (p_pwd == NULL) {
+				error("Couldn't find user '%s'", username);
+			}
+
+			chown(dumpinfo.CurrentFileName, pwd.pw_uid, pwd.pw_gid);
+
+			if (username || chroot_dir)
+				droproot(username, chroot_dir);
+							
+			free(username_buf);
+		}
+
 		if (p == NULL)
 			error("%s", pcap_geterr(pd));
 		if (Cflag != 0 || Gflag != 0) {