- Do not bail if the interface does not have an IP assigned. - time_t format string fixes - add -u flag, to drop privileges to that user Index: arpwatch.c --- arpwatch.c.orig +++ arpwatch.c @@ -63,6 +63,9 @@ struct rtentry; #include #include +#include +#include + #include #include "gnuc.h" @@ -141,6 +144,24 @@ int sanity_ether(struct ether_header *, struct ether_a int sanity_fddi(struct fddi_header *, struct ether_arp *, int); __dead void usage(void) __attribute__((volatile)); +void dropprivileges(const char* user) +{ + struct passwd* pw; + pw = getpwnam( user ); + if ( pw ) { + if ( initgroups(pw->pw_name, pw->pw_gid) != 0 || setgid(pw->pw_gid) != 0 || + setuid(pw->pw_uid) != 0 ) { + syslog(LOG_ERR, "Couldn't change to '%.32s' uid=%d gid=%d", user,pw->pw_uid, pw->pw_gid); + exit(1); + } + } + else { + syslog(LOG_ERR, "Couldn't find user '%.32s' in /etc/passwd", user); + exit(1); + } + syslog(LOG_INFO, "Running as uid=%d gid=%d", getuid(), getgid()); +} + int main(int argc, char **argv) { @@ -153,6 +174,7 @@ main(int argc, char **argv) register char *interface, *rfilename; struct bpf_program code; char errbuf[PCAP_ERRBUF_SIZE]; + char* username = NULL; if (argv[0] == NULL) prog = "arpwatch"; @@ -170,7 +192,7 @@ main(int argc, char **argv) interface = NULL; rfilename = NULL; pd = NULL; - while ((op = getopt(argc, argv, "df:i:n:Nr:")) != EOF) + while ((op = getopt(argc, argv, "df:i:n:Nr:u:")) != EOF) switch (op) { case 'd': @@ -202,6 +224,19 @@ main(int argc, char **argv) rfilename = optarg; break; + case 'u': + if ( optarg ) { + username = strdup(optarg); + if (username == NULL) { + fprintf(stderr, "strdup -u username failed"); + exit(1); + } + } else { + fprintf(stderr, "%s: Need username after -u\n", prog); + usage(); + } + break; + default: usage(); } @@ -223,9 +258,11 @@ main(int argc, char **argv) /* Determine network and netmask */ if (pcap_lookupnet(interface, &net, &netmask, errbuf) < 0) { - (void)fprintf(stderr, "%s: bad interface %s: %s\n", - prog, interface, errbuf); - exit(1); + (void)fprintf(stderr, + "%s: WARNING: cannot determine net/mask: %s\n", + prog, errbuf); + net = 0; + netmask = 0; } /* Drop into the background if not debugging */ @@ -279,12 +316,16 @@ main(int argc, char **argv) #endif } + if ( username ) { + dropprivileges( username ); + } else { /* * Revert to non-privileged user after opening sockets * (not needed on most systems). */ - setgid(getgid()); - setuid(getuid()); + setgid(getgid()); + setuid(getuid()); + } /* Must be ethernet or fddi */ linktype = pcap_datalink(pd); @@ -401,7 +442,7 @@ process_ether(register u_char *u, register const struc t = h->ts.tv_sec; can_checkpoint = 0; if (!ent_add(sia, sea, t, NULL)) - syslog(LOG_ERR, "ent_add(%s, %s, %ld) failed", + syslog(LOG_ERR, "ent_add(%s, %s, %lld) failed", intoa(sia), e2str(sea), t); can_checkpoint = 1; } @@ -550,7 +591,7 @@ process_fddi(register u_char *u, register const struct t = h->ts.tv_sec; can_checkpoint = 0; if (!ent_add(sia, sea, t, NULL)) - syslog(LOG_ERR, "ent_add(%s, %s, %ld) failed", + syslog(LOG_ERR, "ent_add(%s, %s, %lld) failed", intoa(sia), e2str(sea), t); can_checkpoint = 1; } @@ -750,7 +791,7 @@ usage(void) extern char version[]; (void)fprintf(stderr, "Version %s\n", version); - (void)fprintf(stderr, "usage: %s [-dN] [-f datafile] [-i interface]" + (void)fprintf(stderr, "usage: %s [-dN] [-f datafile] [-i interface] [-u username]" " [-n net[/width]] [-r file]\n", prog); exit(1); }