Index: /trunk/configure.ac
===================================================================
--- /trunk/configure.ac	(revision 320)
+++ /trunk/configure.ac	(revision 321)
@@ -12,5 +12,5 @@
 dnl start
 dnl
-AM_INIT_AUTOMAKE(samhain, 2.8.2)
+AM_INIT_AUTOMAKE(samhain, 2.8.3)
 AC_DEFINE([SAMHAIN], 1, [Application is samhain])
 AC_CANONICAL_HOST
@@ -1974,4 +1974,5 @@
 
 sh_insmod_cmd=": # no kernel module"
+sh_insmod_pre=": # no kernel module"
 sh_lkm=""
 lkm_inc=""
@@ -2151,10 +2152,6 @@
 
 			   sh_lkm="${sh_lkm} samhain_kmem.ko"
-			   echo "${sh_insmod_cmd}" | grep 'no kernel module' >/dev/null
-			   if [ $? -eq 0 ]; then
-			      sh_insmod_cmd="modprobe ${install_name}_kmem"
-			   else
-			      sh_insmod_cmd="modprobe ${install_name}_kmem; ${sh_insmod_cmd}"
-			   fi
+			   sh_insmod_pre="modprobe ${install_name}_kmem"
+
 			fi
 		else
@@ -2168,4 +2165,5 @@
 AC_SUBST(sh_lkm)
 AC_SUBST(sh_insmod_cmd)
+AC_SUBST(sh_insmod_pre)
 
 AC_SUBST(systemmap)
Index: /trunk/docs/Changelog
===================================================================
--- /trunk/docs/Changelog	(revision 320)
+++ /trunk/docs/Changelog	(revision 321)
@@ -1,3 +1,14 @@
 2.8.3:
+	* init scripts: load samhain_kmem.ko before samhain starts
+	* slib.c: eliminate mutex from sl_create_ticket()
+	* sh_entropy.c: move pthread usage out of child
+	* sh_hash.c, sh_pthread.c, sh_pthread.h: sh_hash_hashdelete()
+	  needs deadlock detection, may be called from within sh_hash_init() 
+	  via atexit handler on error condition
+	* sh_suidchk.c, sh_calls.c, sh_calls.h: need a nosub version of lstat()
+	  to use with relative path after chdir()
+	* samhain.c, sh_calls.c, sh_calls.h: only run (l)stat() in subprocess
+	  after reading config file (to allow disabling)
+	* sh_unix.c: run sh_sub_kill() in parent after forking the daemon
 	* fix zeroing of result from getnameinfo() (problem reported by Richard)
 	* fix spurious warnings about unsupported address family (reported
Index: /trunk/include/sh_sub.h
===================================================================
--- /trunk/include/sh_sub.h	(revision 320)
+++ /trunk/include/sh_sub.h	(revision 321)
@@ -2,4 +2,5 @@
 #define SH_SUB_H
 
+void sh_kill_sub ();
 int sh_sub_stat  (const char *path, struct stat *buf);
 int sh_sub_lstat (const char *path, struct stat *buf);
Index: /trunk/init/samhain.startGentoo.in
===================================================================
--- /trunk/init/samhain.startGentoo.in	(revision 320)
+++ /trunk/init/samhain.startGentoo.in	(revision 321)
@@ -9,4 +9,5 @@
 start() {
 	ebegin "Starting @install_name@"
+	@sh_insmod_pre@
 	/sbin/start-stop-daemon --start --quiet  --exec @sbindir@/@install_name@
 	eend $?
Index: /trunk/init/samhain.startLSB.in
===================================================================
--- /trunk/init/samhain.startLSB.in	(revision 320)
+++ /trunk/init/samhain.startLSB.in	(revision 321)
@@ -87,4 +87,9 @@
 case "$1" in
   start)
+        #
+        # Preloaded kernel module
+        #
+        @sh_insmod_pre@
+	#
 	${DAEMON} start
 	ERRNUM=$?
Index: /trunk/init/samhain.startLinux.in
===================================================================
--- /trunk/init/samhain.startLinux.in	(revision 320)
+++ /trunk/init/samhain.startLinux.in	(revision 321)
@@ -140,4 +140,8 @@
 	fi
 	#
+	# Preloaded kernel module
+	#
+	@sh_insmod_pre@
+	#
 	case "$DISTRO" in
 	debian)
Index: /trunk/src/sh_extern.c
===================================================================
--- /trunk/src/sh_extern.c	(revision 320)
+++ /trunk/src/sh_extern.c	(revision 321)
@@ -569,4 +569,10 @@
   char  infomsg[256];
 
+#ifdef WCONTINUED
+      int wflags = WNOHANG|WUNTRACED|WCONTINUED;
+#else
+      int wflags = WNOHANG|WUNTRACED;
+#endif
+
   SL_ENTER(_("sh_ext_pclose"));
 
@@ -586,5 +592,5 @@
 
     nochmal:
-      retval = waitpid(task->pid, &(task->exit_status), WNOHANG|WUNTRACED);
+      retval = waitpid(task->pid, &(task->exit_status), wflags);
       /*@-bufferoverflowhigh@*/
       if (task->pid == retval)
@@ -614,5 +620,5 @@
 	      (void) aud_kill (FIL__, __LINE__, task->pid, 9);
 	      (void) retry_msleep (0, 30);
-	      (void) waitpid (task->pid, NULL, WNOHANG|WUNTRACED);
+	      (void) waitpid (task->pid, NULL, wflags);
 	    }
 	  else
Index: /trunk/src/sh_ipvx.c
===================================================================
--- /trunk/src/sh_ipvx.c	(revision 320)
+++ /trunk/src/sh_ipvx.c	(revision 321)
@@ -52,5 +52,5 @@
 static int sh_ipvx_is_ipv6 (const char * addr)
 {
-  int j;
+  int j, k = 0;
   char c;
   int len = sl_strlen(addr);
@@ -63,4 +63,8 @@
 	( c != ':') && ( c != '.'))
       return (1 == 0);
+    else if (c == ':')
+      ++k;
+    else if (c == '.' && k < 3)
+      return (1 == 0); /* ::ffff:ipv4 */
   }
   return (1 == 1);
@@ -234,5 +238,6 @@
     }
 #else
-  port = ntohs(((struct sockaddr_in *)sa).sin_port);
+  (void) sa_family;
+  port = ntohs(((struct sockaddr_in *)sa)->sin_port);
 #endif
   return port;
Index: /trunk/src/sh_kern.c
===================================================================
--- /trunk/src/sh_kern.c	(revision 320)
+++ /trunk/src/sh_kern.c	(revision 321)
@@ -746,4 +746,10 @@
   int  errcode;
 
+#ifdef WCONTINUED
+      int wflags = WNOHANG|WUNTRACED|WCONTINUED;
+#else
+      int wflags = WNOHANG|WUNTRACED;
+#endif
+
   /* Close reading side of pipe, and wait some milliseconds
    */
@@ -820,8 +826,8 @@
 
   if (status < 0)
-    res = waitpid(mpid, NULL,    WNOHANG|WUNTRACED);
+    res = waitpid(mpid, NULL,    wflags);
   else 
     {
-      res = waitpid(mpid, &status, WNOHANG|WUNTRACED);
+      res = waitpid(mpid, &status, wflags);
       if (res == 0 && 0 != WIFEXITED(status))
 	status = WEXITSTATUS(status);
Index: /trunk/src/sh_sub.c
===================================================================
--- /trunk/src/sh_sub.c	(revision 320)
+++ /trunk/src/sh_sub.c	(revision 321)
@@ -20,4 +20,9 @@
 #include "config_xor.h"
 
+/* 0->1 for debug */ 
+#if 0
+#define SH_SUB_DBG 1
+#endif
+
 #ifndef NULL
 #if !defined(__cplusplus)
@@ -62,15 +67,21 @@
 static ssize_t sh_sub_read(int fd, void *buf, size_t count);
 
-static void sh_kill_sub()
+void sh_kill_sub()
 {
   SH_MUTEX_LOCK(mutex_sub);
+
   if (sh_child_pid != -1)
     {
       int status;
+#ifdef WCONTINUED
+      int wflags = WNOHANG|WUNTRACED|WCONTINUED;
+#else
+      int wflags = WNOHANG|WUNTRACED;
+#endif
 
       close (parent2child[1]);
       close (child2parent[0]);
 
-      fprintf(stderr, "FIXME kill_sub %d\n", (int) sh_child_pid);
+      /* fprintf(stderr, "FIXME kill_sub %d\n", (int) sh_child_pid); */
 
       /* Let's be rude. */
@@ -80,10 +91,11 @@
 
       if (sh_wait_ret == 0)
-	sh_wait_ret = waitpid(          -1, &status, WNOHANG|WUNTRACED);
+	sh_wait_ret = waitpid(          -1, &status, wflags);
       else
-	sh_wait_ret = waitpid(sh_child_pid, &status, WNOHANG|WUNTRACED);
+	sh_wait_ret = waitpid(sh_child_pid, &status, wflags);
 
       sh_child_pid = -1;
     }
+
   SH_MUTEX_UNLOCK(mutex_sub);
   return;
@@ -93,5 +105,5 @@
 {
   pid_t res;
-  int   retval = 0;
+  volatile int   retval = 0;
 
   SH_MUTEX_LOCK(mutex_sub);
@@ -162,4 +174,12 @@
 	      ++fd;
 	    }
+
+	  /*
+	  for (i = 0; i < 3; ++i)
+	    {
+	      if ( fcntl(i, F_GETFL, 0) == (-1))
+		(void) open(_("/dev/null"), O_RDWR, 0);
+	    }
+	  */
 
 	  /* reset signal handling 
@@ -275,5 +295,5 @@
   do {
 
-    // fprintf(stderr, "FIXME wait_com polling..\n");
+    /* fprintf(stderr, "FIXME wait_com polling..\n"); */
 
     do {
@@ -307,10 +327,10 @@
 	    outbuf.errnum = errno;
 
-	    // fprintf(stderr, "FIXME wait_com writing..\n");
+	    /* fprintf(stderr, "FIXME wait_com writing..\n"); */
 
 	    ret = sh_sub_write(child2parent[1], &outbuf, sizeof(outbuf));
 	    if (ret < 0)
 	      {
-		fprintf(stderr, "FIXME wait_com return 1\n");
+		/* fprintf(stderr, "FIXME wait_com return 1\n"); */
 		return;
 	      }
@@ -318,10 +338,10 @@
 	else /* sh_sub_read() < 0 */
 	  {
-	    fprintf(stderr, "FIXME wait_com return 2\n");
+	    /* fprintf(stderr, "FIXME wait_com return 2\n"); */
 	    return;
 	  }
       }
     
-    // fprintf(stderr, "FIXME wait_com next..\n");
+    /* fprintf(stderr, "FIXME wait_com next..\n"); */
 
   } while (1 == 1);
@@ -362,4 +382,24 @@
 }
 
+#ifdef SH_SUB_DBG
+#include <stdarg.h>
+static void debug_it (const char *fmt, ...)
+{
+  char msg[256];
+  va_list ap;
+
+  int fd = open("debug.it", O_CREAT|O_WRONLY|O_APPEND, 0666);
+
+  va_start(ap, fmt);
+  vsnprintf(msg, sizeof(msg), fmt, ap);  /* flawfinder: ignore */
+  va_end(ap);
+
+  write(fd, msg, strlen(msg));
+  write(fd, "\n", 1);
+  close(fd);
+  return;
+}
+#endif
+
 static int sh_sub_stat_int(const char *path, struct stat *buf, char command)
 {
@@ -397,8 +437,14 @@
  start:
 
+#ifdef SH_SUB_DBG
+  debug_it("%d sh_child_pid %d\n", (int)getpid(), (int) sh_child_pid);
+#endif
+
   if (sh_child_pid == -1)
     sh_create_sub();
 
-  // fprintf(stderr, "FIXME stat_sub %s\n", inbuf.path);
+#ifdef SH_SUB_DBG
+  debug_it("%d stat_sub %s (%d)\n", (int)getpid(), inbuf.path, (int) sh_child_pid);
+#endif
 
   SH_MUTEX_LOCK(mutex_sub_work);
@@ -412,5 +458,7 @@
     }
 
-  // fprintf(stderr, "FIXME stat_sub polling..\n");
+#ifdef SH_SUB_DBG
+  debug_it("%d stat_sub polling..\n", (int)getpid());
+#endif
 
   pfds.fd     = child2parent[0];
@@ -428,5 +476,7 @@
     }
 
-  // fprintf(stderr, "FIXME stat_sub reading..\n");
+#ifdef SH_SUB_DBG
+  debug_it("%d stat_sub reading..\n", (int)getpid());
+#endif
 
   retval = sh_sub_read (child2parent[0], &outbuf, sizeof(outbuf));
@@ -444,5 +494,7 @@
   if      (sflag == 0)
     {
-      // fprintf(stderr, "FIXME stat_sub done..\n");
+#ifdef SH_SUB_DBG
+      debug_it("%d stat_sub done..\n", (int)getpid());
+#endif
       memcpy(buf, &(outbuf.sbuf), sizeof(struct stat));
       errno = outbuf.errnum;
@@ -451,5 +503,9 @@
   else if (sflag == 1)
     {
+#ifdef SH_SUB_DBG
+      debug_it("%d stat_sub error..\n", (int)getpid());
+#endif
       /* could not read, thus subprocess may have gone */
+      sflag = 0;
       goto start;
     }
Index: /trunk/src/sh_unix.c
===================================================================
--- /trunk/src/sh_unix.c	(revision 320)
+++ /trunk/src/sh_unix.c	(revision 321)
@@ -1909,4 +1909,6 @@
   char errbuf[SH_ERRBUF_SIZE];
 
+  extern void sh_kill_sub();
+
   SL_ENTER(_("sh_unix_init"));
 
@@ -1918,5 +1920,7 @@
     case 0:  break;                             /* child process continues */
     case -1: SL_RETURN((-1),_("sh_unix_init")); /* error                   */
-    default: aud__exit(FIL__, __LINE__, 0);     /* parent process exits    */
+    default:                                    /* parent process exits    */
+      sh_kill_sub(); 
+      aud__exit(FIL__, __LINE__, 0);
     }
 
@@ -1932,5 +1936,7 @@
     case 0:  break;                             /* child process continues */
     case -1: SL_RETURN((-1),_("sh_unix_init")); /* error                   */
-    default: aud__exit(FIL__, __LINE__, 0);     /* parent process exits    */
+    default:                                    /* parent process exits    */
+      sh_kill_sub(); 
+      aud__exit(FIL__, __LINE__, 0);
     }
 
Index: /trunk/test/testrun_1c.sh
===================================================================
--- /trunk/test/testrun_1c.sh	(revision 320)
+++ /trunk/test/testrun_1c.sh	(revision 321)
@@ -340,5 +340,5 @@
 		$MAKE  'DBGDEF=-DSH_SUIDTESTDIR=\"${BASE}\"' >/dev/null 2>&1
 		if test x$? = x0; then
-		    [ -z "$verbose" ] || log_msg_ok "make..."; 
+		    [ -z "$verbose" ] || log_msg_ok "make DBGDEF=-DSH_SUIDTESTDIR=${BASE} ..."; 
 		else
 		    [ -z "$quiet" ] &&   log_msg_fail "make..."; 
