Hi,

The attached patch does:
 * add -U to drop root privileges after getting socket.  A very good
solution if you for some reason are using tcpdump all the time in
background (e.g. some analysis etc.).
 * -u was missing from manpage header usage/the body
 * Around r-t some man page entries were ordered wrong.
 * -R missing from tcpdump.c usage

Sorry for a big one, this just kept getting better as I realized man page
was out of sync :-)

Notes:
 - strdup used once.  I'm confident ;-)
 - can we assume getpwnam and pwd.h on those ancient systems?
 - -u for dropping privileges would have been preferred, but decode NFS
handles already has it.
 - if (optarg) always matches as far as I can see (if optarg wouldn't
exist, there would be usage() generated by optarg()), so:

+               case 'U':
+                       if ( optarg ) {
+                               username = strdup(optarg);
+                       }
+                       else {
+                               fprintf(stderr, "%s: Need username after -u\n", 
+program_name);
+                               usage();
+                               /* NOTREACHED */
+                       }
+                       break;

might just be:

+               case 'U':
+                       username = strdup(optarg);
+                       break;



Food for thought:
 - should some of those weirder options like -u be moved to be handled
with -v?


The droproot patch was created for tcpdump-3.4 by Jarno Huuskonen
<[EMAIL PROTECTED]>.

http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=20231

-- 
Pekka Savola                  "Tell me of difficulties surmounted,
Netcore Oy                    not those you stumble over and fall"
Systems. Networks. Security.   -- Robert Jordan: A Crown of Swords
diff -uNr tcpdump/tcpdump.1 tcpdump.droproot/tcpdump.1
--- tcpdump/tcpdump.1   Wed Jan  3 19:50:17 2001
+++ tcpdump.droproot/tcpdump.1  Wed Jan  3 21:17:05 2001
@@ -27,7 +27,7 @@
 .na
 .B tcpdump
 [
-.B \-adeflnNOpqRStvxX
+.B \-adeflnNOpqRStuvxX
 ] [
 .B \-c
 .I count
@@ -70,6 +70,10 @@
 .I algo:secret
 ]
 [
+.B \-U
+.I username
+]
+[
 .I expression
 ]
 .br
@@ -200,6 +204,12 @@
 Read packets from \fIfile\fR (which was created with the -w option).
 Standard input is used if \fIfile\fR is ``-''.
 .TP
+.B \-R
+Assume ESP/AH packets to be based on old specification (RFC1825 to RFC1829).
+If specified, \fItcpdump\fP will not print replay prevention field.
+Since there is no protocol version field in ESP/AH specification,
+\fItcpdump\fP cannot deduce the version of ESP/AH protocol.
+.TP
 .B \-s
 Snarf \fIsnaplen\fP bytes of data from each packet rather than the
 default of 68 (with SunOS's NIT, the minimum is actually 96).
@@ -215,6 +225,15 @@
 capture the protocol information you're interested in.  Setting
 \fIsnaplen\fP to 0 means use the required length to catch whole packets.
 .TP
+.B \-S
+Print absolute, rather than relative, TCP sequence numbers.
+.TP
+.B \-t
+\fIDon't\fP print a timestamp on each dump line.
+.TP
+.B \-tt
+Print an unformatted timestamp on each dump line.
+.TP
 .B \-T
 Force packets selected by "\fIexpression\fP" to be interpreted the
 specified \fItype\fR. Currently known types are
@@ -227,20 +246,14 @@
 and
 \fBwb\fR (distributed White Board).
 .TP
-.B \-R
-Assume ESP/AH packets to be based on old specification (RFC1825 to RFC1829).
-If specified, \fItcpdump\fP will not print replay prevention field.
-Since there is no protocol version field in ESP/AH specification,
-\fItcpdump\fP cannot deduce the version of ESP/AH protocol.
+.B \-u
+Print undecoded NFS handles.
 .TP
-.B \-S
-Print absolute, rather than relative, TCP sequence numbers.
-.TP
-.B \-t
-\fIDon't\fP print a timestamp on each dump line.
-.TP
-.B \-tt
-Print an unformatted timestamp on each dump line.
+.B \-U
+Drops root privileges and changes user ID to
+.I username
+and group ID to the primary group of
+.IR username .
 .TP
 .B \-v
 (Slightly more) verbose output.  For example, the time to live,
diff -uNr tcpdump/tcpdump.c tcpdump.droproot/tcpdump.c
--- tcpdump/tcpdump.c   Thu Dec 21 12:43:24 2000
+++ tcpdump.droproot/tcpdump.c  Wed Jan  3 21:21:20 2001
@@ -51,7 +51,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <ctype.h>
-
+#include <pwd.h>
 
 #include "interface.h"
 #include "addrtoname.h"
@@ -152,6 +152,24 @@
 extern int opterr;
 extern char *optarg;
 
+/* Drop root privileges */
+void droproot(const char *username)
+{
+       struct passwd *pw = NULL;
+       pw = getpwnam( username );
+       if ( pw ) {
+               if ( 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)
 {
@@ -163,6 +181,7 @@
        RETSIGTYPE (*oldhandler)(int);
        u_char *pcap_userdata;
        char ebuf[PCAP_ERRBUF_SIZE];
+       char *username = NULL;
 
        cnt = -1;
        device = NULL;
@@ -202,7 +202,7 @@
        
        opterr = 0;
        while (
-           (op = getopt(argc, argv, "ac:deE:fF:i:lm:nNOpqr:Rs:StT:uvw:xXY")) != -1)
+           (op = getopt(argc, argv, "ac:deE:fF:i:lm:nNOpqr:Rs:StT:uU:vw:xXY")) != -1)
                switch (op) {
 
                case 'a':
@@ -313,6 +332,17 @@
                case 'u':
                        ++uflag;
                        break;
+               
+               case 'U':
+                       if ( optarg ) {
+                               username = strdup(optarg);
+                       }
+                       else {
+                               fprintf(stderr, "%s: Need username after -U\n", 
+program_name);
+                               usage();
+                               /* NOTREACHED */
+                       }
+                       break;
                        
                case 'v':
                        ++vflag;
@@ -357,7 +387,13 @@
                 * Also, this prevents the user from reading anyone's
                 * trace file.
                 */
-               setuid(getuid());
+               if ( username ) {
+                       droproot( username );
+               }
+               else {
+                       if ( setgid(getgid()) < 0 || setuid(getuid()) < 0 )
+                               fprintf(stderr, "Warning: setgid/setuid failed!\n");
+               }
 
                pd = pcap_open_offline(RFileName, ebuf);
                if (pd == NULL)
@@ -388,7 +424,13 @@
                /*
                 * Let user own process after socket has been opened.
                 */
-               setuid(getuid());
+               if ( username ) {
+                       droproot( username );
+               }
+               else {
+                       if ( setgid(getgid()) < 0 || setuid(getuid()) < 0 )
+                               fprintf(stderr, "Warning: setgid/setuid failed !\n");
+               }
        }
        if (infile)
                cmdbuf = read_infile(infile);
@@ -502,10 +544,10 @@
        (void)fprintf(stderr, "%s version %s\n", program_name, version);
        (void)fprintf(stderr, "libpcap version %s\n", pcap_version);
        (void)fprintf(stderr,
-"Usage: %s [-adeflnNOpqStuvxX] [-c count] [ -F file ]\n", program_name);
+"Usage: %s [-adeflnNOpqRStuvxX] [-c count] [ -F file ]\n", program_name);
        (void)fprintf(stderr,
 "\t\t[ -i interface ] [ -r file ] [ -s snaplen ]\n");
        (void)fprintf(stderr,
-"\t\t[ -T type ] [ -w file ] [ expression ]\n");
+"\t\t[ -T type ] [ -w file ] [-U username] [ expression ]\n");
        exit(-1);
 }

Reply via email to