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);
}