Index: trunk/config.h.in
===================================================================
--- trunk/config.h.in	(revision 510)
+++ trunk/config.h.in	(revision 511)
@@ -606,4 +606,7 @@
 /* Define to 1 if you have the `hasmntopt' function. */
 #undef HAVE_HASMNTOPT
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#undef HAVE_IFADDRS_H
 
 /* Define to 1 if you have the `inet_aton' function. */
Index: trunk/configure.ac
===================================================================
--- trunk/configure.ac	(revision 510)
+++ trunk/configure.ac	(revision 511)
@@ -12,5 +12,5 @@
 dnl start
 dnl
-AM_INIT_AUTOMAKE(samhain, 4.1.5)
+AM_INIT_AUTOMAKE(samhain, 4.1.6)
 AC_DEFINE([SAMHAIN], 1, [Application is samhain])
 AC_CANONICAL_HOST
@@ -245,5 +245,5 @@
 	sys/mman.h sys/param.h sys/inotify.h \
 	sys/vfs.h mntent.h \
-	sys/select.h sys/socket.h netinet/in.h \
+	sys/select.h sys/socket.h netinet/in.h ifaddrs.h \
 	regex.h glob.h fnmatch.h \
 	linux/ext2_fs.h linux/fs.h ext2fs/ext2_fs.h asm/segment.h \
Index: trunk/docs/Changelog
===================================================================
--- trunk/docs/Changelog	(revision 510)
+++ trunk/docs/Changelog	(revision 511)
@@ -1,2 +1,10 @@
+4.1.6:
+	* add portcheck option 'PortCheckDevice = device' to monitor a
+	device regardless of address assigned to it (patch by Anton H., plus
+	some additions)
+	* fix case sensitivity of severity/class options (issue raised by
+	Anton H.).
+	* clarify restrictions for ProcessCheckPSArg (user manual)
+
 4.1.5:
 	* fix memory leak in server (reported by C. Doerr).
Index: trunk/src/samhain.c
===================================================================
--- trunk/src/samhain.c	(revision 510)
+++ trunk/src/samhain.c	(revision 511)
@@ -1375,5 +1375,5 @@
       else
 	{
-	  sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_MOD_OK,
+	  sh_error_handle ((-1), FIL__, __LINE__, status, MSG_MOD_OK,
 			   _(modList[modnum].name));
 	  modList[modnum].initval = status;
Index: trunk/src/sh_portcheck.c
===================================================================
--- trunk/src/sh_portcheck.c	(revision 510)
+++ trunk/src/sh_portcheck.c	(revision 511)
@@ -33,8 +33,13 @@
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+#include <netdb.h>
+#endif
 #include <errno.h>
 #include <unistd.h>
@@ -182,4 +187,10 @@
 static int sh_portchk_add_interface (const char * str);
 
+#if defined(HAVE_IFADDRS_H)
+/* Exported interface to add an ethernet device
+ */
+static int sh_portchk_add_device (const char * str);
+#endif
+
 /* verify whether port/interface is blacklisted (do not check)
  */
@@ -286,4 +297,10 @@
         sh_portchk_set_active,
     },
+#if defined(HAVE_IFADDRS_H)
+    {
+        N_("portcheckdevice"),
+        sh_portchk_add_device,
+    },
+#endif
     {
         N_("portcheckinterface"),
@@ -1119,12 +1136,15 @@
  */
 
-#define SH_IFACE_MAX 16
+#define SH_IFACE_MAX 64
+#define SH_IFACE_ADDR 0
+#define SH_IFACE_DEV  1
 
 struct portchk_interfaces {
-  struct sh_sockaddr iface[SH_IFACE_MAX];
-  int            used;
+  struct sh_sockaddr iface;
+  int            type;
 };
 
-static struct portchk_interfaces iface_list;
+static struct portchk_interfaces iface_list[SH_IFACE_MAX];
+static int iface_list_used   = 0;
 static int iface_initialized = 0;
 
@@ -1159,5 +1179,5 @@
   if (iface_initialized == 0)
     {
-      iface_list.used   = 0;
+      iface_list_used   = 0;
       iface_initialized = 1;
     }
@@ -1167,5 +1187,5 @@
   hent = sh_gethostbyname(portchk_hostname);
   i = 0;
-  while (hent && hent->h_addr_list[i] && (iface_list.used < SH_IFACE_MAX))
+  while (hent && hent->h_addr_list[i] && (iface_list_used < SH_IFACE_MAX))
     {
       struct sockaddr_in sin;
@@ -1175,7 +1195,7 @@
       sh_ipvx_save(&iface_tmp, AF_INET, (struct sockaddr *)&sin);
 
-      for (j = 0; j < iface_list.used; ++j)
-	{
-	  if (0 == sh_ipvx_cmp(&iface_tmp, &(iface_list.iface[j])))
+      for (j = 0; j < iface_list_used; ++j)
+	{
+	  if (0 == sh_ipvx_cmp(&iface_tmp, &(iface_list[j].iface)))
 	    {
 	      goto next_iface;
@@ -1183,14 +1203,15 @@
 	}
 
-      sh_ipvx_save(&(iface_list.iface[iface_list.used]), 
+      sh_ipvx_save(&(iface_list[iface_list_used].iface), 
 		   AF_INET, (struct sockaddr *)&sin);
+      iface_list[iface_list_used].type = SH_IFACE_ADDR;
       
       if (portchk_debug)
 	{
 	  char buf[256];
-	  sh_ipvx_ntoa(buf, sizeof(buf), &(iface_list.iface[iface_list.used]));
+	  sh_ipvx_ntoa(buf, sizeof(buf), &(iface_list[iface_list_used].iface));
 	  fprintf(stderr, _("added interface[%d]: %s\n"), i, buf); 
 	}
-      ++iface_list.used;
+      ++iface_list_used;
 
     next_iface:
@@ -1208,18 +1229,18 @@
       struct sh_sockaddr iface_tmp;
 
-      while ((p != NULL) && (iface_list.used < SH_IFACE_MAX))
+      while ((p != NULL) && (iface_list_used < SH_IFACE_MAX))
 	{
 	  sh_ipvx_save(&iface_tmp, p->ai_family, p->ai_addr);
 
-          for (j = 0; j < iface_list.used; ++j)
+          for (j = 0; j < iface_list_used; ++j)
 	    {
 	      if (portchk_debug)
 		{
 		  char buf1[256], buf2[256];
-		  sh_ipvx_ntoa(buf1, sizeof(buf1), &(iface_list.iface[j]));
+		  sh_ipvx_ntoa(buf1, sizeof(buf1), &(iface_list[j].iface));
 		  sh_ipvx_ntoa(buf2, sizeof(buf2), &iface_tmp);
 		  fprintf(stderr, _("check interface[%d]: %s vs %s\n"), j, buf1, buf2); 
 		}
-	      if (0 == sh_ipvx_cmp(&iface_tmp, &(iface_list.iface[j])))
+	      if (0 == sh_ipvx_cmp(&iface_tmp, &(iface_list[j].iface)))
 		{
 		  if (portchk_debug) 
@@ -1228,15 +1249,15 @@
 		}
 	    }
-	  sh_ipvx_save(&(iface_list.iface[iface_list.used]), 
+	  sh_ipvx_save(&(iface_list[iface_list_used].iface), 
 		       p->ai_family, p->ai_addr);
-
+	  iface_list[iface_list_used].type = SH_IFACE_ADDR;
 	  if (portchk_debug)
 	    {
 	      char buf[256];
-	      sh_ipvx_ntoa(buf, sizeof(buf), &(iface_list.iface[iface_list.used]));
-	      fprintf(stderr, _("added interface[%d]: %s\n"), iface_list.used, buf); 
+	      sh_ipvx_ntoa(buf, sizeof(buf), &(iface_list[iface_list_used].iface));
+	      fprintf(stderr, _("added interface[%d]: %s\n"), iface_list_used, buf); 
 	    }
 
-	  ++iface_list.used;
+	  ++iface_list_used;
 
 	next_iface:
@@ -1247,7 +1268,7 @@
 #endif
 
-  for (i = 0; i < iface_list.used; ++i)
-    {
-      sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), &(iface_list.iface[i]));
+  for (i = 0; i < iface_list_used; ++i)
+    {
+      sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), &(iface_list[i].iface));
       sl_snprintf(errbuf, sizeof(errbuf), _("added interface: %s"), ipbuf);
 
@@ -1285,4 +1306,5 @@
 	   (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
     {
+      (void) sh_portchk_init_internal();
       return SH_MOD_THREAD;
     }
@@ -1291,5 +1313,5 @@
 }
 
-
+static void dev_list_kill();
 
 #if !defined(TEST_ONLY)
@@ -1305,4 +1327,6 @@
   sh_portchk_maxport = -1;
 
+  dev_list_kill();
+  
   portlist_udp = sh_portchk_kill_list (portlist_udp);
   portlist_tcp = sh_portchk_kill_list (portlist_tcp);
@@ -1345,7 +1369,7 @@
   /* Check all interfaces for this host
    */
-  while (i < iface_list.used)
-    {
-      memcpy(&paddr, &(iface_list.iface[i]), sizeof(paddr));
+  while (i < iface_list_used)
+    {
+      memcpy(&paddr, &(iface_list[i].iface), sizeof(paddr));
 
       if (paddr.ss_family != domain)
@@ -1577,5 +1601,5 @@
 void * sh_dummy_1564_str    = NULL; /* fix clobbered by.. warning */
 
-static int sh_portchk_add_interface (const char * str)
+static int sh_portchk_add_interface_int (const char * str, int type)
 {
   struct sh_sockaddr saddr;
@@ -1587,5 +1611,5 @@
   if (iface_initialized == 0)
     {
-      iface_list.used   = 0;
+      iface_list_used   = 0;
       iface_initialized = 1;
     }
@@ -1609,5 +1633,5 @@
 	  return -1;
 
-	if (iface_list.used == SH_IFACE_MAX)
+	if (iface_list_used == SH_IFACE_MAX)
 	  return -1;
 
@@ -1619,6 +1643,7 @@
 	SH_MUTEX_UNLOCK(mutex_thread_nolog);
 	
-	memcpy (&(iface_list.iface[iface_list.used]), &(saddr), sizeof(saddr));
-	++iface_list.used;
+	memcpy (&(iface_list[iface_list_used].iface), &(saddr), sizeof(saddr));
+	iface_list[iface_list_used].type = type;
+	++iface_list_used;
       }
   } while (*str);
@@ -1627,4 +1652,228 @@
   return 0;
 }
+
+static int sh_portchk_add_interface (const char * str)
+{
+  return sh_portchk_add_interface_int (str, SH_IFACE_ADDR);
+}
+
+#if defined(HAVE_IFADDRS_H)
+/* 
+ * subroutines to add a device
+ */
+void * sh_dummy_1651_ifa    = NULL; /* fix clobbered by.. warning */
+
+static int portchk_add_device_int (const char * buf)
+{
+  struct ifaddrs *ifaddr, *ifa;
+  int family;
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+  char host[NI_MAXHOST];
+
+  sh_dummy_1651_ifa = (void*) &ifa;
+  
+  if (getifaddrs(&ifaddr) == -1)
+    {
+      volatile int nerr = errno;
+      char errbuf[SH_ERRBUF_SIZE];
+      sh_error_message(errno, errbuf, sizeof(errbuf));
+      SH_MUTEX_LOCK(mutex_thread_nolog);
+      sh_error_handle((-1), FIL__, __LINE__, nerr, MSG_E_SUBGEN, 
+		      errbuf, _("getifaddrs"));
+      SH_MUTEX_UNLOCK(mutex_thread_nolog);
+      return -1;
+    }
+
+  for ( ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
+    {
+      if (ifa->ifa_addr == NULL)
+	continue;
+      
+      if (strcmp(ifa->ifa_name, buf) == 0)
+	{
+	  volatile int s = 0;
+          family = ifa->ifa_addr->sa_family;
+	  
+          if (family == AF_INET)
+	    {
+	      s = getnameinfo( ifa->ifa_addr, sizeof(struct sockaddr_in),
+			       host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST );
+	      
+	      if (s == 0)
+		{
+		  if (sh_portchk_add_interface_int(host, SH_IFACE_DEV) < 0)
+		    {
+		      freeifaddrs(ifaddr);
+		      return -1;
+		    }
+		}
+	    }
+	  
+#if defined(USE_IPVX)
+          if (family == AF_INET6)
+	    {
+	      s = getnameinfo( ifa->ifa_addr, sizeof(struct sockaddr_in6),
+			       host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST );
+	      
+	      if (s == 0)
+		{
+		  if (sh_portchk_add_interface_int(host, SH_IFACE_DEV) < 0)
+		    {
+		      freeifaddrs(ifaddr);
+		      return -1;
+		    }
+		}
+	    }
+#endif
+	  
+	  if (s != 0)
+	    {
+	      char errbuf[SH_ERRBUF_SIZE];
+	      sl_strlcpy(errbuf, buf,             sizeof(errbuf));
+	      sl_strlcat(errbuf, ": ",            sizeof(errbuf));
+	      sl_strlcat(errbuf, gai_strerror(s), sizeof(errbuf));
+	      SH_MUTEX_LOCK(mutex_thread_nolog);
+	      sh_error_handle((-1), FIL__, __LINE__, s, MSG_E_SUBGEN, 
+			      errbuf, _("getnameinfo"));
+	      SH_MUTEX_UNLOCK(mutex_thread_nolog);
+	    }
+	  
+        }
+    }
+
+  freeifaddrs(ifaddr);
+  return 0;
+}
+
+struct added_dev {
+  char dev[64];
+  struct added_dev * next;
+};
+
+static struct added_dev * dev_list = NULL;
+
+static void dev_list_add (char * buf)
+{
+  struct added_dev * new = SH_ALLOC(sizeof(struct added_dev));
+  sl_strlcpy(new->dev, buf, 64);
+  new->next = dev_list;
+  dev_list  = new;
+  return;
+}
+
+static void dev_list_kill ()
+{
+  struct added_dev * old;
+  struct added_dev * new = dev_list;
+  dev_list = NULL;
+
+  while (new)
+    {
+      old = new;
+      new = new->next;
+      SH_FREE(old);
+    }
+  return;
+}
+ 
+static int sh_portchk_add_device (const char * str)
+{
+  char buf[64];
+                
+  do {
+
+    while (*str == ',' || *str == ' ' || *str == '\t') ++str;
+
+    if (*str)
+      {
+	unsigned int i = 0;
+	while (*str && i < (sizeof(buf)-1) &&
+	       *str != ',' && *str != ' ' && *str != '\t') {
+	  buf[i] = *str; ++str; ++i;
+	}
+	buf[i] = '\0';
+	
+	if (portchk_add_device_int (buf) < 0)
+	  return -1;
+	
+	dev_list_add(buf);
+      }
+  } while (*str);
+
+  return 0;
+}
+
+static int iface_comp (const void *a, const void *b)
+{
+  const struct portchk_interfaces * aa = (struct portchk_interfaces *) a;
+  const struct portchk_interfaces * bb = (struct portchk_interfaces *) b;
+  return (aa->type - bb->type);
+}
+
+static void iface_qsort()
+{
+  qsort(&iface_list[0], iface_list_used, sizeof(struct portchk_interfaces),
+	iface_comp);
+  return;
+}
+
+static void recheck_devices()
+{
+  if (dev_list)
+    {
+      struct added_dev * dev = dev_list;
+      int i, j;
+
+      if (portchk_debug)
+	{
+	  for (j = 0; j < iface_list_used; ++j)
+	    {
+	      char buf[SH_IP_BUF];
+	      struct portchk_interfaces * aa = &(iface_list[j]);
+	      sh_ipvx_ntoa(buf, sizeof(buf), &(aa->iface));
+	      fprintf(stderr, _("presort: iface[%d] type(%d) %s\n"), j, iface_list[j].type, buf);
+	    }
+	}
+
+      iface_qsort();
+      
+      if (portchk_debug)
+	{
+	  for (j = 0; j < iface_list_used; ++j)
+	    {
+	      char buf[SH_IP_BUF];
+	      struct portchk_interfaces * aa = &(iface_list[j]);
+	      sh_ipvx_ntoa(buf, sizeof(buf), &(aa->iface));
+	      fprintf(stderr, _("postsor: iface[%d] type(%d) %s\n"), j, iface_list[j].type, buf);
+	    }
+	}
+
+      i = 0;
+      for (j = 0; j < iface_list_used; ++j)
+	if (iface_list[j].type == SH_IFACE_DEV) ++i;
+      iface_list_used -= i;
+
+      if (portchk_debug)
+	{
+	  for (j = 0; j < iface_list_used; ++j)
+	    {
+	      char buf[SH_IP_BUF];
+	      struct portchk_interfaces * aa = &(iface_list[j]);
+	      sh_ipvx_ntoa(buf, sizeof(buf), &(aa->iface));
+	      fprintf(stderr, _("postdel: iface[%d] type(%d) %s\n"), j, iface_list[j].type, buf);
+	    }
+	}
+
+      while (dev)
+	{
+	  portchk_add_device_int (dev->dev);
+	  dev = dev->next;
+	}
+    }
+  return;
+}
+#endif
 
 /* verify whether port/interface is blacklisted (do not check)
@@ -1928,4 +2177,9 @@
 
       sh_portchk_reset_lists();
+
+#if defined(HAVE_IFADDRS_H)
+      recheck_devices();
+#endif
+
       if ((0 != geteuid()) && (min_port < 1024))
 	{
