File arpwatch-2.1a11-drop-privs.dif of Package arpwatch
diff -ruN ../arpwatch-2.1a15.orig/arpwatch.c ./arpwatch.c
--- ../arpwatch-2.1a15.orig/arpwatch.c 2008-11-12 15:16:19.000000000 +0100
+++ ./arpwatch.c 2008-11-12 16:31:50.000000000 +0100
@@ -64,6 +64,8 @@
#include <string.h>
#include <syslog.h>
#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
#include <pcap.h>
@@ -152,6 +154,52 @@
#endif
__dead void usage(void) __attribute__((volatile));
+void dropprivileges(const char* user)
+{
+ struct passwd* pw;
+ pw = getpwnam( user );
+ if ( pw ) {
+ char *arpfiledir;
+ char *lastslash;
+
+ arpfiledir = malloc(strlen(arpfile)+1);
+ if(arpfiledir == NULL) {
+ syslog(LOG_ERR, "Fatal: malloc().");
+ exit(1);
+ }
+ strcpy(arpfiledir, arpfile);
+ lastslash = strrchr(arpfiledir, '/');
+ if(lastslash == NULL) {
+ syslog(LOG_ERR, "Fatal: cannot determine directory of %s", arpfile);
+ exit(1);
+ }
+ lastslash[0]='\0';
+
+
+ /* files arp.dat.eth0- and arp.dat.eth0.new that are created
+ as backup/lastversion and for temporary storage are
+ deleted before created again. */
+ if ( chown ( arpfile, pw->pw_uid, pw->pw_gid) != 0 ||
+ chown ( arpfiledir, pw->pw_uid, pw->pw_gid) != 0 ) {
+ syslog(LOG_ERR, "Fatal: could not chown %s and %s to %d,%d).",
+ arpfiledir,arpfile, pw->pw_uid, pw->pw_gid);
+ exit(1);
+ }
+ free(arpfiledir);
+ if ( initgroups(pw->pw_name, pw->pw_gid) != 0 || setgid(pw->pw_gid) != 0 ||
+ setuid(pw->pw_uid) != 0 ) {
+ syslog(LOG_ERR, "Fatal: Couldn't change to user/group '%.32s' uid=%d gid=%d", user,
+ pw->pw_uid, pw->pw_gid);
+ exit(1);
+ }
+ }
+ else {
+ syslog(LOG_ERR, "No such user: '%.32s'", user);
+ exit(1);
+ }
+ syslog(LOG_DEBUG, "arpwatch running as uid=%d gid=%d", getuid(), getgid());
+}
+
int
main(int argc, char **argv)
{
@@ -164,6 +212,7 @@
register char *interface, *rfilename;
struct bpf_program code;
char errbuf[PCAP_ERRBUF_SIZE];
+ char* serveruser = NULL;
if (argv[0] == NULL)
prog = "arpwatch";
@@ -181,7 +230,7 @@
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':
@@ -213,6 +262,16 @@
rfilename = optarg;
break;
+ case 'u':
+ if ( optarg ) {
+ serveruser = strdup(optarg);
+ }
+ else {
+ fprintf(stderr, "%s: Need username after -u\n", prog);
+ usage();
+ }
+ break;
+
default:
usage();
}
@@ -295,8 +354,11 @@
* Revert to non-privileged user after opening sockets
* (not needed on most systems).
*/
- setgid(getgid());
- setuid(getuid());
+ /*setgid(getgid());*/
+ /*setuid(getuid());*/
+ if ( serveruser ) {
+ dropprivileges( serveruser );
+ }
/* Must be ethernet or fddi or tokenring */
linktype = pcap_datalink(pd);
@@ -842,6 +904,6 @@
(void)fprintf(stderr, "Version %s\n", version);
(void)fprintf(stderr, "usage: %s [-dN] [-f datafile] [-i interface]"
- " [-n net[/width]] [-r file]\n", prog);
+ " [-n net[/width]] [-r file] [-u username]\n", prog);
exit(1);
}