Index: trunk/docs/Changelog
===================================================================
--- trunk/docs/Changelog	(revision 92)
+++ trunk/docs/Changelog	(revision 93)
@@ -1,5 +1,12 @@
+2.3.3:
+	* fix bug with leading slashes in liked path of symlinks within
+	  the root directory
+	* sh_kern.c: check PCI ROM (Linux), refactor code
+	* move file descriptor closing more towards program startup
+	* kernel check: support OpenBSD 4.0 (wishlist)
+	* fix samhain_hide module (in-)compatibility with recent kernels
+	  (reported by Jonny Halfmoon)
+
 2.3.2:
-	* move file descriptor closing more towards program startup
-	* fix samhain_hide module (in-)compatibility with recent kernels
 	* fix regression in full stealth mode (incorrect comparison of
 	  bytes read vs. maximum capacity), reported by B. Fleming
Index: trunk/docs/README.UPGRADE
===================================================================
--- trunk/docs/README.UPGRADE	(revision 92)
+++ trunk/docs/README.UPGRADE	(revision 93)
@@ -1,4 +1,15 @@
 
-from lower to 2.3.x: database scheme has changed slightly
+to 2.3.3 and higher: a bug has been fixed that resulted in an additional
+  slash at the beginning of the linked path of symlinks in the root
+  directory (symlinks in other directories were not affected)
+
+  -- this may cause spurious warnings about modified links, if you check
+     against a database created with an earlier version of samhain 
+
+
+
+from lower to 2.3.x: the database scheme has changed slightly. 
+  To upgrade, use the following SQL commands in the command-line
+  client of your database:
 
   -- MySQL:
Index: trunk/include/samhain.h
===================================================================
--- trunk/include/samhain.h	(revision 92)
+++ trunk/include/samhain.h	(revision 93)
@@ -124,4 +124,6 @@
   SH_CHECK_CHECK   = 2
 };
+
+#define SH_KEY_NULL _("000000000000000000000000000000000000000000000000")
 
 /**************************************************
Index: trunk/include/sh_utils.h
===================================================================
--- trunk/include/sh_utils.h	(revision 92)
+++ trunk/include/sh_utils.h	(revision 93)
@@ -102,5 +102,9 @@
 int sh_util_obscure_ok (const char * str);
 
-/* read a hexchar
+/* output a hexchar[2]
+ */
+char * sh_util_charhex( unsigned char c );
+
+/* read a hexchar, return int value (0-15)
  */
 int sh_util_hexchar( char c );
Index: trunk/src/cutest_sh_utils.c
===================================================================
--- trunk/src/cutest_sh_utils.c	(revision 92)
+++ trunk/src/cutest_sh_utils.c	(revision 93)
@@ -143,4 +143,22 @@
   char res3[] = "/";
 
+  char input4[] = "///foo//bar";
+  char res4[] = "///foo";
+
+  char input5[] = "//foo///bar///";
+  char res5[] = "//foo";
+
+  char input6[] = "///";
+  char res6[] = "///";
+
+  char input7[] = "//f///b///";
+  char res7[] = "//f";
+
+  char input8[] = "/f/b/";
+  char res8[] = "/f";
+
+  char input9[] = "/f/b";
+  char res9[] = "/f";
+
   ret = sh_util_dirname(input0);
   CuAssertPtrNotNull(tc, ret);
@@ -158,4 +176,28 @@
   CuAssertPtrNotNull(tc, ret);
   CuAssertStrEquals(tc, res3, ret);
+
+  ret = sh_util_dirname(input4);
+  CuAssertPtrNotNull(tc, ret);
+  CuAssertStrEquals(tc, res4, ret);
+
+  ret = sh_util_dirname(input5);
+  CuAssertPtrNotNull(tc, ret);
+  CuAssertStrEquals(tc, res5, ret);
+
+  ret = sh_util_dirname(input6);
+  CuAssertPtrNotNull(tc, ret);
+  CuAssertStrEquals(tc, res6, ret);
+
+  ret = sh_util_dirname(input7);
+  CuAssertPtrNotNull(tc, ret);
+  CuAssertStrEquals(tc, res7, ret);
+
+  ret = sh_util_dirname(input8);
+  CuAssertPtrNotNull(tc, ret);
+  CuAssertStrEquals(tc, res8, ret);
+
+  ret = sh_util_dirname(input9);
+  CuAssertPtrNotNull(tc, ret);
+  CuAssertStrEquals(tc, res9, ret);
   return;
 }
@@ -179,4 +221,10 @@
   char res4[] = "bar";
 
+  char input5[] = "/foo///bar///";
+  char res5[] = "bar";
+
+  char input6[] = "//foo";
+  char res6[] = "foo";
+
   ret = sh_util_basename(input0);
   CuAssertPtrNotNull(tc, ret);
@@ -198,4 +246,12 @@
   CuAssertPtrNotNull(tc, ret);
   CuAssertStrEquals(tc, res4, ret);
+
+  ret = sh_util_basename(input5);
+  CuAssertPtrNotNull(tc, ret);
+  CuAssertStrEquals(tc, res5, ret);
+
+  ret = sh_util_basename(input6);
+  CuAssertPtrNotNull(tc, ret);
+  CuAssertStrEquals(tc, res6, ret);
 
   return;
Index: trunk/src/sh_hash.c
===================================================================
--- trunk/src/sh_hash.c	(revision 92)
+++ trunk/src/sh_hash.c	(revision 93)
@@ -1926,21 +1926,4 @@
  ******************************************************************/
 
-static char * sh_hash_charhex( unsigned char i )
-{
-  static char i2h[2];
-  int j, k;
-
-  j = i / 16;
-  k = i - (j*16);
-
-  if (j < 10) i2h[0] = '0'+j;
-  else        i2h[0] = 'A'+(j-10);
-  
-  if (k < 10) i2h[1] = '0'+k;
-  else        i2h[1] = 'A'+(k-10);
-
-  return i2h;
-}
-
 void sh_hash_push2db (char * key, unsigned long val1, 
 		      unsigned long val2, unsigned long val3,
@@ -1975,5 +1958,5 @@
       for (i = 0; i < size; ++i)
 	{
-	  p = sh_hash_charhex (str[i]);
+	  p = sh_util_charhex (str[i]);
 	  tmpFile.linkpath[2*i]   = p[0];
 	  tmpFile.linkpath[2*i+1] = p[1];
@@ -1983,20 +1966,16 @@
   else
     {
-      tmpFile.c_mode[0] = '-';  
-      tmpFile.c_mode[1] = '-'; tmpFile.c_mode[2]  = '-';
-      tmpFile.c_mode[3] = '-'; tmpFile.c_mode[4]  = '-'; 
-      tmpFile.c_mode[5] = '-'; tmpFile.c_mode[6]  = '-'; 
-      tmpFile.c_mode[7] = '-'; tmpFile.c_mode[8]  = '-'; 
-      tmpFile.c_mode[9] = '-'; tmpFile.c_mode[10] = '\0'; 
-      tmpFile.linkpath[0] = '-'; tmpFile.linkpath[1] = '\0';
+      for (i = 0; i < 10; ++i) 
+	tmpFile.c_mode[i] = '-';
+      tmpFile.c_mode[10] = '\0'; 
+      tmpFile.linkpath[0] = '-'; 
+      tmpFile.linkpath[1] = '\0';
     }
 
   if (sh.flag.checkSum == SH_CHECK_CHECK && 
       sh.flag.update == S_TRUE)
-    sh_hash_pushdata_memory (&tmpFile, 
-			     _("000000000000000000000000000000000000000000000000"));
-  else
-    sh_hash_pushdata (&tmpFile, 
-		      _("000000000000000000000000000000000000000000000000"));
+    sh_hash_pushdata_memory (&tmpFile, SH_KEY_NULL);
+  else
+    sh_hash_pushdata (&tmpFile, SH_KEY_NULL);
 
   return;
@@ -2018,5 +1997,5 @@
   if (0 == sh_hash_get_it (key, &tmpFile))
     {
-      *val1  = tmpFile.size;
+      *val1 = tmpFile.size;
       *val2 = tmpFile.mtime;
       *val3 = tmpFile.ctime;
@@ -2701,12 +2680,13 @@
 	  maxcomp = KEY_LEN;
 	}
-
-    if ( sl_strncmp (linkHash, p->linkpath, maxcomp) != 0 &&
-	 (theFile->check_mask & MODI_LNK) != 0)
-      {
-	modi_mask |= MODI_LNK;
-	change_code[1] = 'L';
-	TPT ((0, FIL__, __LINE__, _("mod=<link>")));
-      } 
+      
+
+      if ( sl_strncmp (linkHash, p->linkpath, maxcomp) != 0 &&
+	   (theFile->check_mask & MODI_LNK) != 0)
+	{
+	  modi_mask |= MODI_LNK;
+	  change_code[1] = 'L';
+	  TPT ((0, FIL__, __LINE__, _("mod=<link>")));
+	} 
     }
 
Index: trunk/src/sh_kern.c
===================================================================
--- trunk/src/sh_kern.c	(revision 92)
+++ trunk/src/sh_kern.c	(revision 93)
@@ -23,8 +23,4 @@
 #define SH_SYSCALL_CODE
 
-#ifdef HOST_IS_I86LINUX
-#define SH_IDT_TABLE
-#define SH_PROC_CHECK
-#endif
 
 #include <stdio.h>
@@ -156,4 +152,6 @@
 #endif
 
+/* This is the module 'reconfigure' function, which is a no-op.
+ */
 int sh_kern_null()
 {
@@ -161,11 +159,117 @@
 }
 
-#ifdef SH_IDT_TABLE
+#define SH_KERN_DBPUSH 0
+#define SH_KERN_DBPOP  1
+
+char * sh_kern_db_syscall (int num, char * prefix,
+		   void * in_name, unsigned long * addr,
+			   unsigned int * code1, unsigned int * code2,
+			   int * size, int direction)
+{
+  char            path[128];
+  char          * p = NULL;
+  unsigned long   x1 = 0, x2 = 0;
+  unsigned char * name = (unsigned char *) in_name;
+
+  sl_snprintf(path, 128, "K_%s_%04d", prefix, num);
+
+  if (direction == SH_KERN_DBPUSH) 
+    {
+      x1 = *code1;
+      x2 = *code2;
+
+      sh_hash_push2db (path, *addr, x1, x2,
+		       name, (name == NULL) ? 0 : (*size));
+    }
+  else
+    {
+      p = sh_hash_db2pop (path, addr,  &x1, &x2, size);
+      *code1 = (unsigned int) x1;
+      *code2 = (unsigned int) x2;
+    }
+  return p;
+}
+
+static char * sh_kern_pathmsg (char * msg, size_t msg_len,
+			       int num, char * prefix,
+			       unsigned char * old, size_t old_len,
+			       unsigned char * new, size_t new_len)
+{
+  size_t k;
+  char   tmp[128];
+  char  *p;
+  char  *linkpath_old;
+  char  *linkpath_new;
+
+#ifdef SH_USE_XML
+  sl_snprintf(tmp, sizeof(tmp), _("path=\"K_%s_%04d\" "), 
+	      prefix, num);
+#else
+  sl_snprintf(tmp, sizeof(tmp), _("path=<K_%s_%04d> "), 
+	      prefix, num);
+#endif
+  sl_strlcpy(msg, tmp, msg_len);
+
+  if (SL_TRUE == sl_ok_muls(old_len, 2) &&
+      SL_TRUE == sl_ok_adds(old_len * 2, 1))
+    linkpath_old = SH_ALLOC(old_len * 2 + 1);
+  else
+    return msg;
+
+  if (SL_TRUE == sl_ok_muls(new_len, 2) &&
+      SL_TRUE == sl_ok_adds(new_len * 2, 1))
+    linkpath_new = SH_ALLOC(new_len * 2 + 1);
+  else
+    return msg;
+
+  for (k = 0; k < old_len; ++k)
+    {
+      p = sh_util_charhex (old[k]);
+      linkpath_old[2*k]   = p[0];
+      linkpath_old[2*k+1] = p[1];
+      linkpath_old[2*k+2] = '\0';
+    }
+
+  for (k = 0; k < new_len; ++k)
+    {
+      p = sh_util_charhex (new[k]);
+      linkpath_new[2*k]   = p[0];
+      linkpath_new[2*k+1] = p[1];
+      linkpath_new[2*k+2] = '\0';
+    
+}
+#ifdef SH_USE_XML
+  sl_strlcat(msg, _("link_old=\""),    msg_len);
+  sl_strlcat(msg, linkpath_old,        msg_len);
+  sl_strlcat(msg, _("\" link_new=\""), msg_len);
+  sl_strlcat(msg, linkpath_new,        msg_len);
+  sl_strlcat(msg, _("\""),             msg_len);
+#else
+  sl_strlcat(msg, _("link_old=<"),     msg_len);
+  sl_strlcat(msg, linkpath_old,        msg_len);
+  sl_strlcat(msg, _(">, link_new=<"),  msg_len);
+  sl_strlcat(msg, linkpath_new,        msg_len);
+  sl_strlcat(msg, _(">"),              msg_len);
+#endif
+
+  SH_FREE(linkpath_old);
+  SH_FREE(linkpath_new);
+
+  return msg;
+}
+ 
+#ifdef HOST_IS_LINUX
+
+/*
+ * Interrupt Descriptor Table
+ */
 
 #include <asm/segment.h>
 
 #define SH_MAXIDT   256
-unsigned char sh_idt_table[SH_MAXIDT * 8];
-char * sh_strseg(unsigned short segment)
+
+static unsigned char sh_idt_table[SH_MAXIDT * 8];
+
+static char * sh_strseg(unsigned short segment)
 {
   switch (segment) {
@@ -182,162 +286,7 @@
   }
 }
-/* ifdef SH_IDT_TABLE */
-#endif
-
-static char * sh_kern_charhex( unsigned char i )
-{
-  static char i2h[2];
-  int j, k;
-
-  j = i / 16;
-  k = i - (j*16);
-
-  if (j < 10) i2h[0] = '0'+j;
-  else        i2h[0] = 'A'+(j-10);
-  
-  if (k < 10) i2h[1] = '0'+k;
-  else        i2h[1] = 'A'+(k-10);
-
-  return i2h;
-}
-
-static void sh_kern_push2db (char * name, unsigned long addr, 
-			     unsigned long code1, unsigned long code2,
-			     unsigned char * code, int size)
-{
-  file_type   tmpFile;
-  int         i = 0;
-  char      * p;
-
-  tmpFile.attr_string = NULL;
-
-  sl_strlcpy(tmpFile.fullpath, name, PATH_MAX);
-  tmpFile.size  = addr;
-  tmpFile.mtime = code1;
-  tmpFile.ctime = code2;
-
-  tmpFile.atime = 0;
-  tmpFile.mode  = 0;
-  tmpFile.owner = 0;
-  tmpFile.group = 0;
-  sl_strlcpy(tmpFile.c_owner, _("root"), 5);
-  sl_strlcpy(tmpFile.c_group, _("root"), 5);
-
-  if ((code != NULL) && (size < (PATH_MAX/2)-1))
-    {
-      tmpFile.c_mode[0] = 'l';  
-      tmpFile.c_mode[1] = 'r'; tmpFile.c_mode[2]  = 'w';
-      tmpFile.c_mode[3] = 'x'; tmpFile.c_mode[4]  = 'r'; 
-      tmpFile.c_mode[5] = 'w'; tmpFile.c_mode[6]  = 'x'; 
-      tmpFile.c_mode[7] = 'r'; tmpFile.c_mode[8]  = 'w'; 
-      tmpFile.c_mode[9] = 'x'; tmpFile.c_mode[10] = '\0'; 
-      for (i = 0; i < size; ++i)
-	{
-	  p = sh_kern_charhex (code[i]);
-	  tmpFile.linkpath[2*i]   = p[0];
-	  tmpFile.linkpath[2*i+1] = p[1];
-	  tmpFile.linkpath[2*i+2] = '\0';
-	}
-    }
-  else
-    {
-      tmpFile.c_mode[0] = '-';  
-      tmpFile.c_mode[1] = '-'; tmpFile.c_mode[2]  = '-';
-      tmpFile.c_mode[3] = '-'; tmpFile.c_mode[4]  = '-'; 
-      tmpFile.c_mode[5] = '-'; tmpFile.c_mode[6]  = '-'; 
-      tmpFile.c_mode[7] = '-'; tmpFile.c_mode[8]  = '-'; 
-      tmpFile.c_mode[9] = '-'; tmpFile.c_mode[10] = '\0'; 
-      tmpFile.linkpath[0] = '-'; tmpFile.linkpath[1] = '\0';
-    }
-
-  if (sh.flag.checkSum == SH_CHECK_CHECK && sh.flag.update == S_TRUE)
-    sh_hash_pushdata_memory (&tmpFile, 
-			     _("000000000000000000000000000000000000000000000000"));
-  else
-    sh_hash_pushdata (&tmpFile, 
-		      _("000000000000000000000000000000000000000000000000"));
-  return;
-}
-
-extern int sh_util_hextobinary (char * binary, const char * hex, int bytes);
-
-static char * sh_kern_db2pop (char * name, unsigned long * addr, 
-			      unsigned long * code1, unsigned long * code2,
-			      int * size)
-{
-  file_type   tmpFile;
-  char      * p;
-  int         i;
-
-  if (0 == sh_hash_get_it (name, &tmpFile))
-    {
-      *addr  = tmpFile.size;
-      *code1 = tmpFile.mtime;
-      *code2 = tmpFile.ctime;
-
-      if (tmpFile.linkpath[0] != '-')
-	{
-	  p = SH_ALLOC(PATH_MAX);
-	  i = sh_util_hextobinary (p, tmpFile.linkpath, 
-				   strlen(tmpFile.linkpath));
-	  if (i == 0)
-	    {
-	      *size = (strlen(tmpFile.linkpath)/2);
-	      p[*size] = '\0';
-	      return p;
-	    }
-	  else
-	    {
-	      SH_FREE(p);
-	      *size = 0;
-	      return NULL;
-	    }
-	}
-      else
-	{
-	  *size = 0;
-	  return NULL;
-	}
-    }
-  else
-    {
-      *size = 0;
-      *addr = 0;
-      return NULL;
-    }
-}
-
-char * sh_kern_db_syscall (int num, char * prefix,
-			   void * in_name, unsigned long * addr,
-			   unsigned int * code1, unsigned int * code2,
-			   int * size, int direction)
-{
-  char            path[128];
-  char          * p = NULL;
-  unsigned long   x1 = 0, x2 = 0;
-  unsigned char * name = (unsigned char *) in_name;
-
-  sl_snprintf(path, 128, "K_%s_%04d", prefix, num);
-
-  if (direction == 0) 
-    {
-      x1 = *code1;
-      x2 = *code2;
-
-      sh_kern_push2db (path, *addr, x1, x2,
-		       name, (name == NULL) ? 0 : (*size));
-    }
-  else
-    {
-      p = sh_kern_db2pop (path, addr,  &x1, &x2, size);
-      *code1 = (unsigned int) x1;
-      *code2 = (unsigned int) x2;
-    }
-  return p;
-}
- 
-#ifdef HOST_IS_LINUX
-
-int sh_kern_data_init ()
+
+
+static int sh_kern_data_init ()
 {
   unsigned long store0 = 0;
@@ -346,10 +295,9 @@
   char        * databuf;
 
-#ifdef SH_SYSCALL_CODE
   /* system_call code
    */
   databuf = sh_kern_db_syscall (0, _("system_call"), 
 				NULL, &store0, &store1, &store2,
-				&datasize, 1);
+				&datasize, SH_KERN_DBPOP);
   if (datasize == sizeof(system_call_code))
     {
@@ -364,5 +312,4 @@
       return -1;
     }
-#endif
 
   /* syscall address and code
@@ -372,5 +319,5 @@
       databuf = sh_kern_db_syscall (i, _("syscall"), 
 				    NULL, &store0, &store1, &store2,
-				    &datasize, 1);
+				    &datasize, SH_KERN_DBPOP);
       sh_syscalls[i].addr = store0;
       if (store0 == 0) {
@@ -380,5 +327,5 @@
 	return -1;
       }
-#ifdef SH_SYSCALL_CODE
+
       sh_syscalls[i].code[0] = (unsigned int) store1; 
       sh_syscalls[i].code[1] = (unsigned int) store2;
@@ -387,8 +334,6 @@
 			_("syscall code not found in database"), 
 			_("sh_kern_data_init"));
-	/* fprintf(stderr, "Syscall #%d\n", i); */
-	/* return -1; */
       }
-#endif 
+
       if (databuf != NULL) {
 	SH_FREE(databuf);
@@ -397,5 +342,4 @@
     }
 
-#ifdef SH_IDT_TABLE
   if (ShKernIDT == S_TRUE)
     {
@@ -405,5 +349,5 @@
 					NULL, 
 					&store0, &store1, &store2,
-					&datasize, 1);
+					&datasize, SH_KERN_DBPOP);
 	  if (datasize == 8) {
 	    memcpy(&idt_table[j*8], databuf, 8);
@@ -417,10 +361,8 @@
 	}
     }
-#endif
 
   return 0;
 }
 
-#ifdef SH_PROC_CHECK
 
 /*
@@ -495,5 +437,5 @@
   */          
 };
-#endif
+
 
 static int sh_kern_kmem_read (int fd, unsigned long addr, 
@@ -540,28 +482,289 @@
 }
 
-int sh_kern_check_internal ()
+
+static int check_init (int * init_retval)
 {
   static int is_init = 0;
-  int kd;
-  int res;
-  pid_t mpid;
-  int mpipe[2];
-  int i, j, status = 0;
-  /* unsigned int kaddr; */
-  unsigned long kmem_call_table[512];
-
-#ifdef SH_PROC_CHECK
-  struct inode_operations proc_root_inode;
-  struct proc_dir_entry proc_root_dir;
-#endif
-
-#ifdef SH_SYSCALL_CODE
-  unsigned int kmem_code_table[512][2];
-#endif
-#ifdef SH_IDT_TABLE
+
+  SL_ENTER(_("check_init"));
+
+  if (is_init == 0)
+    {
+      if (sh.flag.checkSum != SH_CHECK_INIT && sh.flag.update != S_TRUE)
+	{
+	  if (0 == sh_kern_data_init()) {
+	    is_init = 1;
+	  } else {
+	    sh_error_handle (ShKernSeverity, FIL__, __LINE__, 1, 
+			     MSG_E_SUBGEN,
+			     _("could not initialize kernel check - switching off"),
+			     _("check_init") );
+	    ShKernActive = S_FALSE;
+	    *init_retval = is_init;
+	    SL_RETURN( (-1), _("check_init"));
+	  }
+	}
+      else if ((sh.flag.checkSum == SH_CHECK_INIT || 
+		sh.flag.checkSum == SH_CHECK_CHECK) && 
+	       (sh.flag.update == S_TRUE))
+	{
+	  if (0 == sh_kern_data_init()) {
+	    is_init = 1;
+	  } else {
+	    sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, 0, 
+			     MSG_E_SUBGEN,
+			     _("no or incomplete data in baseline database for kernel check"),
+			     _("check_init") );
+	  }
+	}
+    }
+  *init_retval = is_init;
+  SL_RETURN( (0), _("check_init"));
+}
+
+#define SH_KERN_SIZ 512
+#define SH_KERN_SCC 256
+
+static void run_child(int kd, int mpipe[2])
+{
+  int j;
+
+  unsigned long kmem_call_table[SH_KERN_SIZ];
+  unsigned int  kmem_code_table[SH_KERN_SIZ][2];
+
   unsigned char  buf[6];
   unsigned short idt_size;
   unsigned long  idt_addr;
-  /* int            k, curr_keep = 0; */
+
+  unsigned char new_system_call_code[SH_KERN_SCC];
+
+  struct inode_operations proc_root_inode;
+  struct proc_dir_entry   proc_root_dir;
+
+  int status = close(mpipe[0]);
+
+  setpgid(0, 0);
+	  
+  /* Seek to the system call table (at kaddr) and read it into
+   * the kmem_call_table array
+   */
+  if(status == 0)
+    {
+      retry_msleep (0, ShKernDelay); /* milliseconds */
+      
+      if (sh_kern_read_data (kd, kaddr, 
+			     (unsigned char *) &kmem_call_table, 
+			     sizeof(kmem_call_table)))
+	{
+	  status = -2;
+	}
+    }
+
+  /* 
+   * Seek to the system call address (at sh_syscalls[j].addr) and 
+   * read first 8 bytes into the array kmem_code_table[j][] (2 * unsigned int)
+   */
+  if(status == 0)
+    {
+      memset(kmem_code_table, 0, sizeof(kmem_code_table));
+      for (j = 0; j < SH_MAXCALLS; ++j) 
+	{
+	  if (sh_syscalls[j].addr == 0UL) {
+	    sh_syscalls[j].addr = kmem_call_table[j];
+	  }
+
+	  if (sh_syscalls[j].name == NULL || 
+	      sh_syscalls[j].addr == 0UL)
+	    break;
+
+	  if ((sh.flag.checkSum == SH_CHECK_INIT || 
+	       sh.flag.checkSum == SH_CHECK_CHECK) && 
+	      (sh.flag.update == S_TRUE))
+	    {
+	      sh_kern_read_data (kd, kmem_call_table[j], 
+				 (unsigned char *) &(kmem_code_table[j][0]),
+				 2 * sizeof(unsigned int));
+	    }
+	  else
+	    {
+	      sh_kern_read_data (kd, sh_syscalls[j].addr, 
+				 (unsigned char *) &(kmem_code_table[j][0]),
+				 2 * sizeof(unsigned int));
+	    }
+	}
+    }
+
+  if(status == 0)
+    {
+      /* 
+       * Get the address and size of Interrupt Descriptor Table,
+       * and read the content into the global array sh_idt_table[]
+       */
+      __asm__ volatile ("sidt %0": "=m" (buf));
+      idt_size = *((unsigned short *) &buf[0]);
+      idt_addr = *((unsigned long *)  &buf[2]);
+      idt_size = (idt_size + 1)/8;
+      
+      if (idt_size > SH_MAXIDT)
+	idt_size = SH_MAXIDT;
+      
+      memset(sh_idt_table, '\0', SH_MAXIDT*8);
+      sh_kern_read_data (kd, idt_addr, 
+			 (unsigned char *) sh_idt_table, idt_size*8);
+    }
+
+  /* 
+   * Seek to the system_call address (at system_call_addr) and 
+   * read first 256 bytes into new_system_call_code[]
+   *
+   * system_call_addr is defined in the include file.
+   */
+  if(status == 0)
+    {
+      sh_kern_read_data (kd, system_call_addr, 
+			 (unsigned char *) new_system_call_code, SH_KERN_SCC);
+    }
+  
+  /* 
+   * Seek to proc_root and read the structure.
+   * Seek to proc_root_inode_operations and get the structure.
+   */
+  if(status == 0)
+    {
+      sh_kern_read_data (kd, proc_root, 
+			 (unsigned char *) &proc_root_dir, 
+			 sizeof(proc_root_dir));
+      sh_kern_read_data (kd, proc_root_iops, 
+			 (unsigned char *) &proc_root_inode, 
+			 sizeof(proc_root_inode));
+    }
+  
+  /*
+   * Write out data to the pipe
+   */
+  if(status == 0)
+    {
+      status = write(mpipe[1], &kmem_call_table, sizeof(kmem_call_table));
+
+      if(status > 0)
+	status = write(mpipe[1], &kmem_code_table, sizeof(kmem_code_table));
+
+      if(status > 0)
+	status = write(mpipe[1], &sh_idt_table, sizeof(sh_idt_table));
+
+      if(status > 0)
+	status = write(mpipe[1], new_system_call_code, SH_KERN_SCC);
+
+      if(status > 0)
+	status = write(mpipe[1], &proc_root_dir, sizeof(proc_root_dir));
+
+      if(status > 0)
+	status = write(mpipe[1], &proc_root_inode, sizeof(proc_root_inode));
+    }
+  _exit( (status >= 0) ? 0 : status);
+}
+
+
+struct sh_kernel_info {
+  unsigned long kmem_call_table[SH_KERN_SIZ];
+  unsigned int  kmem_code_table[SH_KERN_SIZ][2];
+
+  unsigned char new_system_call_code[SH_KERN_SCC];
+
+  struct inode_operations proc_root_inode;
+  struct proc_dir_entry   proc_root_dir;
+};
+
+static int read_from_child(pid_t mpid, int * mpipe, 
+			   struct sh_kernel_info * kinfo)
+{
+  int  res;
+  int  status;
+  long size;
+
+  /* Close reading side of pipe, and wait some milliseconds
+   */
+  close (mpipe[1]);
+  retry_msleep (0, ShKernDelay); /* milliseconds */
+
+  size = SH_KERN_SIZ * sizeof(unsigned long);
+
+  if (size != read(mpipe[0], &(kinfo->kmem_call_table), size))
+    status = -4;
+  else
+    status = 0;
+
+  if(status == 0)
+    {
+      size = sizeof(unsigned int) * 2 * SH_KERN_SIZ;
+
+      if (size != read(mpipe[0], &(kinfo->kmem_code_table), size))
+	status = -5;
+      else
+	status = 0;
+    }
+
+  if(status == 0)
+    {
+      memset(sh_idt_table, '\0', SH_MAXIDT*8);
+      if (sizeof(sh_idt_table) != 
+	  read(mpipe[0], &sh_idt_table, sizeof(sh_idt_table)))
+	status = -5;
+      else
+	status = 0;
+    }
+
+  if(status == 0)
+    {
+      size = SH_KERN_SCC;
+
+      if (size != read(mpipe[0], &(kinfo->new_system_call_code), size))
+	status = -6;
+      else
+	status = 0;
+    }
+  
+  if(status == 0)
+    {
+      size = sizeof (struct proc_dir_entry);
+
+      if (size != read(mpipe[0], &(kinfo->proc_root_dir), size))
+	status = -7;
+      else
+	status = 0;
+    }
+
+  if(status == 0)
+    {
+      size = sizeof (struct inode_operations);
+
+      if (size != read(mpipe[0], &(kinfo->proc_root_inode), size))
+	status = -8;
+      else
+	status = 0;
+    }
+
+  if (status < 0)
+    res = waitpid(mpid, NULL,    WNOHANG|WUNTRACED);
+  else 
+    {
+      res = waitpid(mpid, &status, WNOHANG|WUNTRACED);
+      if (res == 0 && 0 != WIFEXITED(status))
+	status = WEXITSTATUS(status);
+    }
+  close (mpipe[0]);
+  if (res <= 0)
+    {
+      aud_kill(FIL__, __LINE__, mpid, 9);
+      waitpid(mpid, NULL, 0);
+    }
+  return status;
+}
+
+
+static void check_idt_table(int is_init)
+{
+  int            i, j;
+
   unsigned short idt_offset_lo, idt_offset_hi, idt_selector;
   unsigned char  idt_reserved, idt_flag;
@@ -573,621 +776,10 @@
   unsigned long  sh_idt_iaddr;
   char           idt_type, sh_idt_type;
-#endif
-
-  unsigned char new_system_call_code[256];
-
-#ifdef SH_USE_LKM
-  static int check_getdents      = 0;
-  /* #ifdef __NR_getdents64 */
-  static int check_getdents64    = 0;
-  /* #endif */
-  static int copy_if_next        = -1;
-  static int copy_if_next_64     = -1;
-#endif
 
   unsigned long store0;
   unsigned int  store1, store2;
   int           datasize;
-  int           mod_syscall_addr = 0;
-  int           mod_syscall_code = 0;
-  UINT64        size_old  = 0, size_new = 0;
-  UINT64        mtime_old = 0, mtime_new = 0;
-  UINT64        ctime_old = 0, ctime_new = 0;
-  char          tmp[128];
   char          msg[2*SH_BUFSIZE];
-  char timstr_o[32];
-  char timstr_n[32];
-  char * p;
-  int    k;
-  char * linkpath_old;
-  char * linkpath_new;
-
-  int           max_system_call = (SYS_CALL_LOC < 128) ? 128 : SYS_CALL_LOC;
-
-  SL_ENTER(_("sh_kern_check_internal"));
-
-  
-  if (is_init == 0)
-    {
-      if (sh.flag.checkSum != SH_CHECK_INIT && sh.flag.update != S_TRUE)
-	{
-	  if (0 == sh_kern_data_init()) {
-	    is_init = 1;
-	  } else {
-	    sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, 
-			     MSG_E_SUBGEN,
-			     _("could not initialize - switching off"),
-			     _("kern_check_internal") );
-	    ShKernActive = S_FALSE;
-	    SL_RETURN( (-1), _("sh_kern_check_internal"));
-	  }
-	}
-      else if ((sh.flag.checkSum == SH_CHECK_INIT || 
-		sh.flag.checkSum == SH_CHECK_CHECK) && 
-	       (sh.flag.update == S_TRUE))
-	{
-	  if (0 == sh_kern_data_init()) {
-	    is_init = 1;
-	  } else {
-	    sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, status, 
-			     MSG_E_SUBGEN,
-			     _("no or incomplete data in baseline database"),
-			     _("kern_check_internal") );
-	  }
-	}
-    }
-
-  /*
-   * kaddr is the address of the sys_call_table
-   */
-
-  if (kaddr == (unsigned int) -1)
-    {
-      sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_E_SUBGEN,
-		       _("no address for sys_call_table - switching off"),
-		       _("kern_check_internal") );
-      ShKernActive = S_FALSE;
-      SL_RETURN( (-1), _("sh_kern_check_internal"));
-    }
-  
-  kd = aud_open(FIL__, __LINE__, SL_YESPRIV, _("/dev/kmem"), O_RDONLY, 0);
-  
-  if (kd < 0)
-    {
-      status = errno;
-      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
-		       _("error opening /dev/kmem"),
-		       _("kern_check_internal") );
-      SL_RETURN( (-1), _("sh_kern_check_internal"));
-    }
-
-  status = aud_pipe(FIL__, __LINE__, mpipe);
-
-  if (status == 0)
-    {
-      mpid = aud_fork(FIL__, __LINE__);
-
-      switch (mpid) 
-	{
-	case -1:
-	  status = -1;
-	  break;
-	case 0:                       /* child */
-	  status = close(mpipe[0]);
-	  setpgid(0, 0);
-	  
-	  /* Seek to the system call table (at kaddr) and read it into
-	   * the kmem_call_table array
-	   */
-	  if(status == 0)
-	    {
-	      retry_msleep (0, ShKernDelay); /* milliseconds */
-	      
-	      if (sh_kern_read_data (kd, kaddr, 
-				     (unsigned char *) &kmem_call_table, 
-				     sizeof(kmem_call_table)))
-		{
-		  status = -2;
-		}
-	    }
-
-#ifdef SH_SYSCALL_CODE
-	  /* 
-	   * Seek to the system call address (at sh_syscalls[j].addr) and 
-	   * read first 8 bytes into kmem_code_table[j][] (2 * unsigned int)
-	   */
-	  if(status == 0)
-	    {
-	      memset(kmem_code_table, 0, sizeof(kmem_code_table));
-	      for (j = 0; j < SH_MAXCALLS; ++j) 
-		{
-
-		  if (sh_syscalls[j].addr == 0UL) {
-		    sh_syscalls[j].addr = kmem_call_table[j];
-		  }
-
-		  if (sh_syscalls[j].name == NULL || 
-		      sh_syscalls[j].addr == 0UL)
-		    break;
-
-		  if ((sh.flag.checkSum == SH_CHECK_INIT || 
-		       sh.flag.checkSum == SH_CHECK_CHECK) && 
-		      (sh.flag.update == S_TRUE))
-		    {
-		      sh_kern_read_data (kd, kmem_call_table[j], 
-					 (unsigned char *) &(kmem_code_table[j][0]),
-					 2 * sizeof(unsigned int));
-		    }
-		  else
-		    {
-		      sh_kern_read_data (kd, sh_syscalls[j].addr, 
-					 (unsigned char *) &(kmem_code_table[j][0]),
-					 2 * sizeof(unsigned int));
-		    }
-		}
-	    }
-#endif
-
-#ifdef SH_IDT_TABLE
-	  if(status == 0)
-	    {
-	      /* 
-	       * Get the address and size of Interrupt Descriptor Table,
-	       * and read the content into sh_idt_table[]
-	       */
-	      __asm__ volatile ("sidt %0": "=m" (buf));
-	      idt_size = *((unsigned short *) &buf[0]);
-	      idt_addr = *((unsigned long *)  &buf[2]);
-	      idt_size = (idt_size + 1)/8;
-
-	      if (idt_size > SH_MAXIDT)
-		idt_size = SH_MAXIDT;
-
-	      memset(sh_idt_table, '\0', SH_MAXIDT*8);
-	      sh_kern_read_data (kd, idt_addr, 
-				 (unsigned char *) sh_idt_table, idt_size*8);
-	    }
-#endif
-
-	  /* 
-	   * Seek to the system_call address (at system_call_addr) and 
-	   * read first 256 bytes into new_system_call_code[]
-	   *
-	   * system_call_addr is defined in the include file.
-	   */
-	  if(status == 0)
-	    {
-	      sh_kern_read_data (kd, system_call_addr, 
-				 (unsigned char *) new_system_call_code, 256);
-	    }
-
-
-	  /* 
-	   * Seek to proc_root and read the structure.
-	   * Seek to proc_root_inode_operations and get the structure.
-	   */
-#ifdef SH_PROC_CHECK
-	  if(status == 0)
-	    {
-	      sh_kern_read_data (kd, proc_root, 
-				 (unsigned char *) &proc_root_dir, 
-				 sizeof(proc_root_dir));
-	      sh_kern_read_data (kd, proc_root_iops, 
-				 (unsigned char *) &proc_root_inode, 
-				 sizeof(proc_root_inode));
-	    }
-#endif
-
-	  if(status == 0)
-	    {
-	      status = 
-		write(mpipe[1], &kmem_call_table, sizeof(kmem_call_table));
-#ifdef SH_SYSCALL_CODE
-	      if(status > 0)
-		{
-		  status = 
-		    write(mpipe[1], &kmem_code_table, sizeof(kmem_code_table));
-		}
-#endif
-#ifdef SH_IDT_TABLE
-	      if(status > 0)
-		{
-		  status = 
-		    write(mpipe[1], &sh_idt_table, sizeof(sh_idt_table));
-		}
-#endif
-	      if(status > 0)
-		{
-		  status = 
-		    write(mpipe[1], new_system_call_code, 256);
-		}
-#ifdef SH_PROC_CHECK
-	      if(status > 0)
-		{
-		  status = 
-		    write(mpipe[1], &proc_root_dir, sizeof(proc_root_dir));
-		}
-	      if(status > 0)
-		{
-		  status = 
-		    write(mpipe[1], &proc_root_inode, sizeof(proc_root_inode));
-		}
-#endif
-	    }
-	  _exit( (status >= 0) ? 0 : status);
-	  break;
-	  
-	default:
-	  close (mpipe[1]);
-	  close (kd);
-	  retry_msleep (0, ShKernDelay); /* milliseconds */
-	  if (sizeof(kmem_call_table) != 
-	      read(mpipe[0], &kmem_call_table, sizeof(kmem_call_table)))
-	    status = -4;
-	  else
-	    status = 0;
-
-#ifdef SH_SYSCALL_CODE
-	  if(status == 0)
-	    {
-	      if (sizeof(kmem_code_table) != 
-		  read(mpipe[0], &kmem_code_table, sizeof(kmem_code_table)))
-		status = -5;
-	      else
-		status = 0;
-	    }
-#endif	  
-
-#ifdef SH_IDT_TABLE
-	  if(status == 0)
-	    {
-	      memset(sh_idt_table, '\0', SH_MAXIDT*8);
-	      if (sizeof(sh_idt_table) != 
-		  read(mpipe[0], &sh_idt_table, sizeof(sh_idt_table)))
-		status = -5;
-	      else
-		status = 0;
-	    }
-#endif	  
-
-	  if(status == 0)
-	    {
-	      if (256 != read(mpipe[0], new_system_call_code, 256))
-		status = -6;
-	      else
-		status = 0;
-	    }
-
-#ifdef SH_PROC_CHECK
-	  if(status == 0)
-	    {
-	      if (sizeof(proc_root_dir) !=
-		  read(mpipe[0], &proc_root_dir, sizeof(proc_root_dir)))
-		status = -7;
-	      else
-		status = 0;
-	    }
-	  if(status == 0)
-	    {
-	      if (sizeof(proc_root_inode) !=
-		  read(mpipe[0], &proc_root_inode, sizeof(proc_root_inode)))
-		status = -8;
-	      else
-		status = 0;
-	    }
-#endif
-
-	  if (status < 0)
-	    res = waitpid(mpid, NULL,    WNOHANG|WUNTRACED);
-	  else 
-	    {
-	      res = waitpid(mpid, &status, WNOHANG|WUNTRACED);
-	      if (res == 0 && 0 != WIFEXITED(status))
-		status = WEXITSTATUS(status);
-	    }
-	  close (mpipe[0]);
-	  if (res <= 0)
-	    {
-	      aud_kill(FIL__, __LINE__, mpid, 9);
-	      waitpid(mpid, NULL, 0);
-	    }
-	  break;
-	}
-    }
-
-  if ( status < 0)
-    {
-      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
-		       _("error reading from /dev/kmem"),
-		       _("kern_check_internal") );
-      SL_RETURN( (-1), _("sh_kern_check_internal"));
-    }
-
-  /* Check the proc_root inode.
-   *
-   * This will detect adore-ng.
-   */
-  if ( (unsigned int) *proc_root_inode.lookup != proc_root_lookup)
-    {
-      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_KERN_PROC,
-		       _("proc_root_inode_operations.lookup != proc_root_lookup"));
-    }
-  else if (    (((unsigned int) * &proc_root_dir.proc_iops) != proc_root_iops)
-	    && (proc_root_dir.size != proc_root_iops)
-	    && (((unsigned int) * &proc_root_dir.proc_fops) != proc_root_iops)
-	    )
-    {
-      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_KERN_PROC,
-		       _("proc_root.proc_iops != proc_root_inode_operations"));
-    }
-
-  /* Check the system_call syscall gate.
-   *
-   * Stored(old) is system_call_code[]
-   */
-  if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
-    {
-      store0 = 0; store1 = 0; store2 = 0;
-      datasize = sizeof(system_call_code);
-      sh_kern_db_syscall (0, _("system_call"), 
-			  new_system_call_code, &store0, &store1, &store2,
-			  &datasize, 0);
-    }
-
-  if ((sh.flag.checkSum != SH_CHECK_INIT) || 
-      (sh.flag.update == S_TRUE && is_init == 1))
-    {
-      for (i = 0; i < (max_system_call + 4); ++i) 
-	{
-	  if (system_call_code[i] != new_system_call_code[i])
-	    {
-#ifdef SH_USE_XML
-	      sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", 
-			  _("system_call"), 0);
-#else
-	      sl_snprintf(tmp, 128, "path=<K_%s_%04d>, ", 
-			  _("system_call"), 0);
-#endif
-	      sl_strlcpy(msg, tmp, SH_BUFSIZE);
-
-	      linkpath_old = SH_ALLOC(520);
-	      linkpath_new = SH_ALLOC(520);
-	      for (k = 0; k < 256; ++k)
-		{
-		  p = sh_kern_charhex (system_call_code[k]);
-		  linkpath_old[2*k]   = p[0];
-		  linkpath_old[2*k+1] = p[1];
-		  linkpath_old[2*k+2] = '\0';
-		}
-	      for (k = 0; k < 256; ++k)
-		{
-		  p = sh_kern_charhex (new_system_call_code[k]);
-		  linkpath_new[2*k]   = p[0];
-		  linkpath_new[2*k+1] = p[1];
-		  linkpath_new[2*k+2] = '\0';
-		}
-#ifdef SH_USE_XML
-	      sl_strlcat(msg, _("link_old=\""),    2*SH_BUFSIZE);
-	      sl_strlcat(msg, linkpath_old,        2*SH_BUFSIZE);
-	      sl_strlcat(msg, _("\" link_new=\""), 2*SH_BUFSIZE);
-	      sl_strlcat(msg, linkpath_new,        2*SH_BUFSIZE);
-	      sl_strlcat(msg, _("\""),             2*SH_BUFSIZE);
-#else
-	      sl_strlcat(msg, _("link_old=<"),     2*SH_BUFSIZE);
-	      sl_strlcat(msg, linkpath_old,        2*SH_BUFSIZE);
-	      sl_strlcat(msg, _(">, link_new=<"),   2*SH_BUFSIZE);
-	      sl_strlcat(msg, linkpath_new,        2*SH_BUFSIZE);
-	      sl_strlcat(msg, _(">"),              2*SH_BUFSIZE);
-#endif
-
-	      sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
-			       status, MSG_KERN_GATE,
-			       new_system_call_code[i], 0,
-			       system_call_code[i], 0,
-			       0, _("system_call (interrupt handler)"),
-			       msg);
-	      
-	      SH_FREE(linkpath_old);
-	      SH_FREE(linkpath_new);
-
-	      for (j = 0; j < (max_system_call + 4); ++j)
-		system_call_code[j] = new_system_call_code[j];
-	      break;
-	    }
-	}
-    }
-  
-  /* Check the individual syscalls
-   *
-   * Stored(old) is sh_syscalls[] array.
-   */
-  if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
-    {
-      for (i = 0; i < SH_MAXCALLS; ++i) 
-	{
-	  store0 = kmem_call_table[i]; 
-#ifdef SH_SYSCALL_CODE
-	  store1 = kmem_code_table[i][0]; store2 = kmem_code_table[i][1];
-#else
-	  store1 = 0; store2 = 0;
-#endif
-	  sh_kern_db_syscall (i, _("syscall"), 
-			      NULL, &store0, &store1, &store2,
-			      0, 0);
-	}
-    }
-
-  if ((sh.flag.checkSum != SH_CHECK_INIT) || 
-      (sh.flag.update == S_TRUE && is_init == 1))
-    {
-      for (i = 0; i < SH_MAXCALLS; ++i) 
-	{
-	  if (sh_syscalls[i].name == NULL /* || sh_syscalls[i].addr == 0UL */)
-	    break;
-
-#ifdef SH_USE_LKM
-	  if (sh_syscalls[i].addr != kmem_call_table[i])
-	    {
-	      if (check_getdents == 0 && 
-		  0 == strcmp(_(sh_syscalls[i].name), _("sys_getdents")))
-		{
-		  check_getdents = 1;
-		  sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, 
-				   status, MSG_E_SUBGEN,
-				   _("Modified kernel syscall (expected)."),
-				   _(sh_syscalls[i].name) );
-		  copy_if_next = i;
-		  sh_syscalls[i].addr = kmem_call_table[i];
-		  continue;
-		}
-	      /* #ifdef __NR_getdents64 */
-	      else if  (check_getdents64 == 0 && 
-			0 == strcmp(_(sh_syscalls[i].name), 
-				    _("sys_getdents64")))
-		{
-		  check_getdents64 = 1;
-		  sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, 
-				   status, MSG_E_SUBGEN,
-				   _("Modified kernel syscall (expected)."),
-				   _(sh_syscalls[i].name) );
-		  copy_if_next_64 = i;
-		  sh_syscalls[i].addr = kmem_call_table[i];
-		  continue;
-		}
-	      /* #endif */
-	      else
-		{
-		  size_old = sh_syscalls[i].addr;
-		  size_new = kmem_call_table[i];
-		  mod_syscall_addr = 1;
-		  /*
-		  sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
-				   status, MSG_KERN_POLICY,
-				   kmem_call_table[i],
-				   sh_syscalls[i].addr,
-				   i, _(sh_syscalls[i].name)
-				   );
-		  */
-		}
-	      sh_syscalls[i].addr = kmem_call_table[i];
-	    }
-#else
-	  if (sh_syscalls[i].addr != kmem_call_table[i])
-	    {
-	      size_old = sh_syscalls[i].addr;
-	      size_new = kmem_call_table[i];
-	      mod_syscall_addr = 1;
-	      /*
-	      sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
-			       status, MSG_KERN_POLICY,
-			       kmem_call_table[i],
-			       sh_syscalls[i].addr,
-			       i, _(sh_syscalls[i].name)
-			       );
-	      */
-	      sh_syscalls[i].addr = kmem_call_table[i];
-	    }
-#endif
-
-
-	  /* Check the code at syscall address
-	   *
-	   * Stored(old) is sh_syscalls[]
-	   */
-#ifdef SH_SYSCALL_CODE
-	  if ( (mod_syscall_addr == 0) && 
-	       ((sh_syscalls[i].code[0] != kmem_code_table[i][0]) || 
-		(sh_syscalls[i].code[1] != kmem_code_table[i][1]))
-	       )
-	    {
-	      mtime_old = sh_syscalls[i].code[0];
-	      mtime_new = kmem_code_table[i][0];
-	      ctime_old = sh_syscalls[i].code[1];
-	      ctime_new = kmem_code_table[i][1];
-	      mod_syscall_code = 1;
-
-#ifdef SH_USE_LKM
-	      if (i == copy_if_next)
-		{
-		  mod_syscall_code =  0;
-		  copy_if_next     = -1;
-		}
-	      if (i == copy_if_next_64)
-		{
-		  mod_syscall_code =  0;
-		  copy_if_next_64  = -1;
-		}
-#endif
-
-	      /*
-	      sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
-			       status, MSG_KERN_POL_CO,
-			       kmem_code_table[i][0],  kmem_code_table[i][1],
-			       sh_syscalls[i].code[0], sh_syscalls[i].code[1],
-			       i, _(sh_syscalls[i].name)
-			       );
-	      */
-	      sh_syscalls[i].code[0] = kmem_code_table[i][0];
-	      sh_syscalls[i].code[1] = kmem_code_table[i][1];
-	    }
-#endif
-	  /*
-	   * Build the error message, if something has been
-	   * detected.
-	   */
-	  if ((mod_syscall_addr != 0) || (mod_syscall_code != 0))
-	    {
-#ifdef SH_USE_XML
-	      sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", 
-			  _("syscall"), i);
-#else
-	      sl_snprintf(tmp, 128, "path=<K_%s_%04d>, ", 
-			  _("syscall"), i);
-#endif
-	      sl_strlcpy(msg, tmp, SH_BUFSIZE);
-
-	      if (mod_syscall_addr != 0)
-		{
-		  sl_snprintf(tmp, 128, sh_hash_size_format(),
-			      size_old, size_new);
-		  sl_strlcat(msg, tmp, SH_BUFSIZE); 
-		}
-	      if (mod_syscall_code != 0)
-		{
-		  sl_strlcpy (timstr_o, sh_unix_gmttime (ctime_old), 32);
-		  sl_strlcpy (timstr_n, sh_unix_gmttime (ctime_new), 32);
-#ifdef SH_USE_XML
-		  sl_snprintf(tmp, 128, 
-			      _("ctime_old=\"%s\" ctime_new=\"%s\" "), 
-			      timstr_o, timstr_n);
-#else
-		  sl_snprintf(tmp, 128, 
-			      _("ctime_old=<%s>, ctime_new=<%s>, "), 
-			      timstr_o, timstr_n);
-#endif
-		  sl_strlcat(msg, tmp, SH_BUFSIZE); 
-		  sl_strlcpy (timstr_o, sh_unix_gmttime (mtime_old), 32);
-		  sl_strlcpy (timstr_n, sh_unix_gmttime (mtime_new), 32);
-#ifdef SH_USE_XML
-		  sl_snprintf(tmp, 128, 
-			      _("mtime_old=\"%s\" mtime_new=\"%s\" "), 
-			      timstr_o, timstr_n);
-#else
-		  sl_snprintf(tmp, 128, 
-			      _("mtime_old=<%s>, mtime_new=<%s> "), 
-			      timstr_o, timstr_n);
-#endif
-		  sl_strlcat(msg, tmp, SH_BUFSIZE); 
-		}
-	      sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
-			       status, MSG_KERN_SYSCALL,
-			       i, _(sh_syscalls[i].name), msg);
-	      mod_syscall_addr = 0;
-	      mod_syscall_code = 0;
-	    }
-	}
-    }
-
-#ifdef SH_IDT_TABLE
+
   if (ShKernIDT == S_TRUE)
     {
@@ -1200,5 +792,5 @@
 				  &sh_idt_table[j*8], 
 				  &store0, &store1, &store2,
-				  &datasize, 0);
+				  &datasize, SH_KERN_DBPUSH);
 	    }
 	}
@@ -1275,42 +867,11 @@
 		  else { sh_dpl = -1; sh_idt_type = 'U'; }
 		  
-#ifdef SH_USE_XML
-		  sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", 
-			      _("idt_table"), j);
-#else
-		  sl_snprintf(tmp, 128, "path=<K_%s_%04d> ", 
-			      _("idt_table"), j);
-#endif
-		  sl_strlcpy(msg, tmp, SH_BUFSIZE);
-
-		  linkpath_old = SH_ALLOC(32);
-		  linkpath_new = SH_ALLOC(32);
-		  for (k = 0; k < 8; ++k)
-		    {
-		      p = sh_kern_charhex (idt_table[i+k]);
-		      linkpath_old[2*k]   = p[0];
-		      linkpath_old[2*k+1] = p[1];
-		      linkpath_old[2*k+2] = '\0';
-		    }
-		  for (k = 0; k < 8; ++k)
-		    {
-		      p = sh_kern_charhex (sh_idt_table[i+k]);
-		      linkpath_new[2*k]   = p[0];
-		      linkpath_new[2*k+1] = p[1];
-		      linkpath_new[2*k+2] = '\0';
-		    }
-#ifdef SH_USE_XML
-		  sl_snprintf(tmp, 128,
-			      _("link_old=\"%s\" link_new=\"%s\" "), 
-			      linkpath_old, linkpath_new);
-#else
-		  sl_snprintf(tmp, 128,
-			      _("link_old=<%s> link_new=<%s> "), 
-			      linkpath_old, linkpath_new);
-#endif
-		  sl_strlcat(msg, tmp, SH_BUFSIZE);
+		  sh_kern_pathmsg (msg, SH_BUFSIZE,
+				   j, _("idt_table"),
+				   &idt_table[i], 8,
+				   &sh_idt_table[i], 8);
 
 		  sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
-				   status, MSG_KERN_IDT,
+				   0, MSG_KERN_IDT,
 				   j, 
 				   sh_idt_iaddr, sh_strseg(sh_idt_selector), 
@@ -1319,7 +880,4 @@
 				   (int) dpl, idt_type, msg);
 		  
-		  SH_FREE(linkpath_old);
-		  SH_FREE(linkpath_new);
-
 		  memcpy(&idt_table[i], &sh_idt_table[i], 8);
 		}
@@ -1327,5 +885,469 @@
 	}
     }
-#endif
+}
+
+
+#define SYS_BUS_PCI _("/sys/bus/pci/devices")
+#include <dirent.h>
+
+static void check_rom (char * pcipath, char * name)
+{
+  file_type       theFile;
+  char            fileHash[2*(KEY_LEN + 1)];
+  int             status;
+  char          * tmp;
+  extern unsigned long sh_files_maskof (int class);
+
+  (void) sl_strlcpy (theFile.fullpath, pcipath, PATH_MAX);
+  theFile.check_mask  = sh_files_maskof(SH_LEVEL_READONLY);
+  theFile.reported    = S_FALSE;
+  theFile.attr_string = NULL;
+  
+  status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_RO], 
+			    name, &theFile, fileHash, 0);
+
+  if (status != 0)
+    {
+      tmp = sh_util_safe_name(pcipath);
+      sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
+		       0, MSG_E_SUBGPATH,
+		       _("Could not check PCI ROM"),
+		       _("check_rom"),
+		       tmp);
+      SH_FREE(tmp);
+      return;
+    }
+
+  if ( sh.flag.checkSum == SH_CHECK_INIT ) 
+    {
+      sh_hash_pushdata (&theFile, fileHash);
+    }
+  else if (sh.flag.checkSum == SH_CHECK_CHECK ) 
+    {
+      sh_hash_compdata (SH_LEVEL_READONLY, &theFile, fileHash, NULL, -1);
+    }
+
+  return;
+}
+
+static void check_pci_rom (char * pcipath, char * name)
+{
+  struct stat buf;
+  int         fd;
+
+  if (0 == stat(pcipath, &buf))
+    {
+      /* Need to write "1" to the file to enable the ROM. Afterwards,
+       * write "0" to disable it.
+       */
+      fd = open ( pcipath, O_RDWR );
+      write( fd, "1", 1 );
+      close ( fd );
+
+      check_rom(pcipath, name);
+
+      fd = open ( pcipath, O_RDWR );
+      write( fd, "0", 1 );
+      close ( fd );
+    }
+  return;
+}
+
+static void check_pci()
+{
+  char pci_dir[256];
+  char * pcipath;
+  DIR * df;
+  struct dirent * entry;
+
+  sl_strlcpy(pci_dir, SYS_BUS_PCI, sizeof(pci_dir));
+
+  df = opendir(pci_dir);
+  if (df)
+    {
+      while (NULL != (entry = readdir(df)))
+	{
+	  if (0 == strcmp(entry->d_name, ".") && 
+	      0 == strcmp(entry->d_name, ".."))
+	    continue;
+
+	  pcipath = sh_util_strconcat(pci_dir, "/", 
+				      entry->d_name, "/rom", NULL);
+	  check_pci_rom(pcipath, entry->d_name);
+	  SH_FREE(pcipath);
+	}
+      closedir(df);
+    }
+}
+
+/* -- Check the proc_root inode.
+ *
+ * This will detect adore-ng.
+ */
+static void check_proc_root (struct sh_kernel_info * kinfo)
+{
+  struct inode_operations proc_root_inode;
+  struct proc_dir_entry   proc_root_dir;
+
+  memcpy (&proc_root_inode, &(kinfo->proc_root_inode), sizeof(struct inode_operations));
+  memcpy (&proc_root_dir,   &(kinfo->proc_root_dir),   sizeof(struct proc_dir_entry));
+
+  if ( (unsigned int) *proc_root_inode.lookup != proc_root_lookup)
+    {
+      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_KERN_PROC,
+		       _("proc_root_inode_operations.lookup != proc_root_lookup"));
+    }
+  else if (    (((unsigned int) * &proc_root_dir.proc_iops) != proc_root_iops)
+	    && (proc_root_dir.size != proc_root_iops)
+	    && (((unsigned int) * &proc_root_dir.proc_fops) != proc_root_iops)
+	    )
+    {
+      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_KERN_PROC,
+		       _("proc_root.proc_iops != proc_root_inode_operations"));
+    }
+  return;
+}
+
+/* -- Check the system_call syscall gate.
+ *
+ * Stored(old) is system_call_code[]
+ */
+static void check_syscall_gate(int is_init, struct sh_kernel_info * kinfo)
+{
+  int           i, j;
+  unsigned long store0;
+  unsigned int  store1, store2;
+  int           datasize;
+  int           max_system_call = (SYS_CALL_LOC < 128) ? 128 : SYS_CALL_LOC;
+  char          msg[2*SH_BUFSIZE];
+  
+  if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
+    {
+      store0 = 0; store1 = 0; store2 = 0;
+      datasize = SH_KERN_SCC;
+      sh_kern_db_syscall (0, _("system_call"), 
+			  &(kinfo->new_system_call_code), &store0, &store1, &store2,
+			  &datasize, SH_KERN_DBPUSH);
+    }
+
+  if ((sh.flag.checkSum != SH_CHECK_INIT) || 
+      (sh.flag.update == S_TRUE && is_init == 1))
+    {
+      for (i = 0; i < (max_system_call + 4); ++i) 
+	{
+	  if (system_call_code[i] != kinfo->new_system_call_code[i])
+	    {
+
+	      sh_kern_pathmsg (msg, sizeof(msg),
+			       0, _("system_call"),
+			       system_call_code, SH_KERN_SCC,
+			       kinfo->new_system_call_code, SH_KERN_SCC);
+
+	      sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
+			       0, MSG_KERN_GATE,
+			       kinfo->new_system_call_code[i], 0,
+			       system_call_code[i], 0,
+			       0, _("system_call (interrupt handler)"),
+			       msg);
+	      
+	      for (j = 0; j < (max_system_call + 4); ++j)
+		system_call_code[j] = kinfo->new_system_call_code[j];
+	      break;
+	    }
+	}
+    }
+  return;
+}
+
+static void check_system_calls (int is_init, struct sh_kernel_info * kinfo)
+{
+  int           i;
+
+#ifdef SH_USE_LKM
+  static int check_getdents      = 0;
+  /* #ifdef __NR_getdents64 */
+  static int check_getdents64    = 0;
+  /* #endif */
+  static int copy_if_next        = -1;
+  static int copy_if_next_64     = -1;
+#endif
+
+  unsigned long store0;
+  unsigned int  store1, store2;
+  int           mod_syscall_addr = 0;
+  int           mod_syscall_code = 0;
+  UINT64        size_old  = 0, size_new = 0;
+  UINT64        mtime_old = 0, mtime_new = 0;
+  UINT64        ctime_old = 0, ctime_new = 0;
+  char          tmp[128];
+  char          msg[2*SH_BUFSIZE];
+  char timstr_o[32];
+  char timstr_n[32];
+
+  if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
+    {
+      for (i = 0; i < SH_MAXCALLS; ++i) 
+	{
+	  store0 = kinfo->kmem_call_table[i]; 
+	  store1 = kinfo->kmem_code_table[i][0]; store2 = kinfo->kmem_code_table[i][1];
+	  sh_kern_db_syscall (i, _("syscall"), 
+			      NULL, &store0, &store1, &store2,
+			      0, SH_KERN_DBPUSH);
+	}
+    }
+
+  if ((sh.flag.checkSum != SH_CHECK_INIT) || 
+      (sh.flag.update == S_TRUE && is_init == 1))
+    {
+      for (i = 0; i < SH_MAXCALLS; ++i) 
+	{
+	  if (sh_syscalls[i].name == NULL /* || sh_syscalls[i].addr == 0UL */)
+	    break;
+
+#ifdef SH_USE_LKM
+	  if (sh_syscalls[i].addr != kinfo->kmem_call_table[i])
+	    {
+	      if (check_getdents == 0 && 
+		  0 == strcmp(_(sh_syscalls[i].name), _("sys_getdents")))
+		{
+		  check_getdents = 1;
+		  sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, 
+				   0, MSG_E_SUBGEN,
+				   _("Modified kernel syscall (expected)."),
+				   _(sh_syscalls[i].name) );
+		  copy_if_next = i;
+		  sh_syscalls[i].addr = kinfo->kmem_call_table[i];
+		  continue;
+		}
+	      /* #ifdef __NR_getdents64 */
+	      else if  (check_getdents64 == 0 && 
+			0 == strcmp(_(sh_syscalls[i].name), 
+				    _("sys_getdents64")))
+		{
+		  check_getdents64 = 1;
+		  sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, 
+				   0, MSG_E_SUBGEN,
+				   _("Modified kernel syscall (expected)."),
+				   _(sh_syscalls[i].name) );
+		  copy_if_next_64 = i;
+		  sh_syscalls[i].addr = kinfo->kmem_call_table[i];
+		  continue;
+		}
+	      /* #endif */
+	      else
+		{
+		  size_old = sh_syscalls[i].addr;
+		  size_new = kinfo->kmem_call_table[i];
+		  mod_syscall_addr = 1;
+		}
+	      sh_syscalls[i].addr = kinfo->kmem_call_table[i];
+	    }
+#else
+	  if (sh_syscalls[i].addr != kinfo->kmem_call_table[i])
+	    {
+	      size_old = sh_syscalls[i].addr;
+	      size_new = kinfo->kmem_call_table[i];
+	      mod_syscall_addr = 1;
+	      sh_syscalls[i].addr = kinfo->kmem_call_table[i];
+	    }
+#endif
+
+
+	  /* -- Check the code at syscall address
+	   *
+	   * Stored(old) is sh_syscalls[]
+	   */
+	  if ( (mod_syscall_addr == 0) && 
+	       ((sh_syscalls[i].code[0] != kinfo->kmem_code_table[i][0]) || 
+		(sh_syscalls[i].code[1] != kinfo->kmem_code_table[i][1]))
+	       )
+	    {
+	      mtime_old = sh_syscalls[i].code[0];
+	      mtime_new = kinfo->kmem_code_table[i][0];
+	      ctime_old = sh_syscalls[i].code[1];
+	      ctime_new = kinfo->kmem_code_table[i][1];
+	      mod_syscall_code = 1;
+
+#ifdef SH_USE_LKM
+	      if (i == copy_if_next)
+		{
+		  mod_syscall_code =  0;
+		  copy_if_next     = -1;
+		}
+	      if (i == copy_if_next_64)
+		{
+		  mod_syscall_code =  0;
+		  copy_if_next_64  = -1;
+		}
+#endif
+
+	      sh_syscalls[i].code[0] = kinfo->kmem_code_table[i][0];
+	      sh_syscalls[i].code[1] = kinfo->kmem_code_table[i][1];
+	    }
+
+	  /* Build the error message, if something has been
+	   * detected.
+	   */
+	  if ((mod_syscall_addr != 0) || (mod_syscall_code != 0))
+	    {
+#ifdef SH_USE_XML
+	      sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", 
+			  _("syscall"), i);
+#else
+	      sl_snprintf(tmp, 128, "path=<K_%s_%04d>, ", 
+			  _("syscall"), i);
+#endif
+	      sl_strlcpy(msg, tmp, SH_BUFSIZE);
+
+	      if (mod_syscall_addr != 0)
+		{
+		  sl_snprintf(tmp, 128, sh_hash_size_format(),
+			      size_old, size_new);
+		  sl_strlcat(msg, tmp, SH_BUFSIZE); 
+		}
+	      if (mod_syscall_code != 0)
+		{
+		  sl_strlcpy (timstr_o, sh_unix_gmttime (ctime_old), 32);
+		  sl_strlcpy (timstr_n, sh_unix_gmttime (ctime_new), 32);
+#ifdef SH_USE_XML
+		  sl_snprintf(tmp, 128, 
+			      _("ctime_old=\"%s\" ctime_new=\"%s\" "), 
+			      timstr_o, timstr_n);
+#else
+		  sl_snprintf(tmp, 128, 
+			      _("ctime_old=<%s>, ctime_new=<%s>, "), 
+			      timstr_o, timstr_n);
+#endif
+		  sl_strlcat(msg, tmp, SH_BUFSIZE); 
+		  sl_strlcpy (timstr_o, sh_unix_gmttime (mtime_old), 32);
+		  sl_strlcpy (timstr_n, sh_unix_gmttime (mtime_new), 32);
+#ifdef SH_USE_XML
+		  sl_snprintf(tmp, 128, 
+			      _("mtime_old=\"%s\" mtime_new=\"%s\" "), 
+			      timstr_o, timstr_n);
+#else
+		  sl_snprintf(tmp, 128, 
+			      _("mtime_old=<%s>, mtime_new=<%s> "), 
+			      timstr_o, timstr_n);
+#endif
+		  sl_strlcat(msg, tmp, SH_BUFSIZE); 
+		}
+	      sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
+			       0, MSG_KERN_SYSCALL,
+			       i, _(sh_syscalls[i].name), msg);
+	      mod_syscall_addr = 0;
+	      mod_syscall_code = 0;
+	    }
+	}
+    }
+  return;
+}
+ 
+int sh_kern_check_internal ()
+{
+  int kd;
+  int is_init;
+  pid_t mpid;
+  int mpipe[2];
+  int status = 0;
+
+  struct sh_kernel_info kinfo;
+
+
+  SL_ENTER(_("sh_kern_check_internal"));
+
+  /* -- Check whether initialisation is required; if yes, initialize.
+   */
+
+  if (0 != check_init(&is_init))
+    {
+      SL_RETURN( (-1), _("sh_kern_check_internal"));
+    }
+
+
+  /* -- Open /dev/kmem and fork subprocess to read from it.
+   */
+   
+  if (kaddr == (unsigned int) -1) /* kaddr = address of the sys_call_table */
+    {
+      sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_E_SUBGEN,
+		       _("no address for sys_call_table - switching off"),
+		       _("kern_check_internal") );
+      ShKernActive = S_FALSE;
+      SL_RETURN( (-1), _("sh_kern_check_internal"));
+    }
+  
+  kd = aud_open(FIL__, __LINE__, SL_YESPRIV, _("/dev/kmem"), O_RDONLY, 0);
+  
+  if (kd < 0)
+    {
+      status = errno;
+      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+		       _("error opening /dev/kmem"),
+		       _("kern_check_internal") );
+      SL_RETURN( (-1), _("sh_kern_check_internal"));
+    }
+
+  status = aud_pipe(FIL__, __LINE__, mpipe);
+
+  if (status == 0)
+    {
+      mpid = aud_fork(FIL__, __LINE__);
+
+      switch (mpid) 
+	{
+	case -1:
+	  status = -1;
+	  break;
+	case 0: 
+
+	  /* -- Child process reads /dev/kmem and writes to pipe
+	   */
+	  run_child(kd, mpipe);
+	  break;
+	  
+	  /* -- Parent process reads from child via pipe
+	   */
+	default:
+	  close(kd);
+	  status = read_from_child(mpid, mpipe, &kinfo);
+	  break;
+	}
+    }
+
+  if ( status < 0)
+    {
+      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+		       _("error reading from /dev/kmem"),
+		       _("kern_check_internal") );
+      SL_RETURN( (-1), _("sh_kern_check_internal"));
+    }
+
+  /* -- Check the proc_root inode.
+   *
+   * This will detect adore-ng.
+   */
+  check_proc_root( &kinfo );
+
+
+  /* -- Check the system_call syscall gate.
+   *
+   * Stored(old) is system_call_code[]
+   */
+  check_syscall_gate( is_init, &kinfo );
+
+  /* -- Check the individual syscalls
+   *
+   * Stored(old) is sh_syscalls[] array.
+   */
+  check_system_calls ( is_init, &kinfo );
+
+  /* -- Check the Interrupt Descriptor Table
+   */
+  check_idt_table(is_init);
+
+  /* -- Check PCI ROM
+   */
+  check_pci();
 
   SL_RETURN( (0), _("sh_kern_check_internal"));
@@ -1333,4 +1355,10 @@
 /* ifdef HOST_IS_LINUX */
 #else
+
+/********************************************************
+ *
+ *  --- BSD ---
+ *
+ ********************************************************/
 
 #include <err.h>
@@ -1370,5 +1398,5 @@
       databuf = sh_kern_db_syscall (i, _("syscall"), 
 				    NULL, &store0, &store1, &store2,
-				    &datasize, 1);
+				    &datasize, SH_KERN_DBPOP);
       sh_syscalls[i].addr = store0;
       if (databuf != NULL) { SH_FREE(databuf); }
@@ -1561,5 +1589,5 @@
 	  sh_kern_db_syscall (i, _("syscall"), 
 			      NULL, &store0, &store1, &store2,
-			      0, 0);
+			      0, SH_KERN_DBPUSH);
 	}
     }
@@ -1615,8 +1643,4 @@
 	      sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
 			       status, MSG_KERN_SYSCALL,
-			       /*
-			       syscall_addr,
-			       sh_syscalls[i].addr,
-			       */
 			       i, _(sh_syscalls[i].name),
 			       msg);
@@ -1682,8 +1706,4 @@
 		  sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
 				   status, MSG_KERN_SYSCALL,
-				   /*
-				   syscall_code[0],  syscall_code[1],
-				   sh_syscalls[i].code[0], sh_syscalls[i].code[1],
-				   */
 				   i, _(sh_syscalls[i].name),
 				   msg);
@@ -1960,5 +1980,2 @@
 /* #ifdef SH_USE_KERN */
 #endif
-
-
-
Index: trunk/src/sh_tiger0.c
===================================================================
--- trunk/src/sh_tiger0.c	(revision 92)
+++ trunk/src/sh_tiger0.c	(revision 93)
@@ -1589,6 +1589,5 @@
     }
 
-   SL_RETURN( _("000000000000000000000000000000000000000000000000"), 
-	      _("sh_tiger_hash_internal"));
+   SL_RETURN( SH_KEY_NULL, _("sh_tiger_hash_internal"));
 }
 
Index: trunk/src/sh_unix.c
===================================================================
--- trunk/src/sh_unix.c	(revision 92)
+++ trunk/src/sh_unix.c	(revision 93)
@@ -893,7 +893,5 @@
   sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
 		  message, _("sh_unix_self_hash"));
-  if (0 == sl_strcmp(sh.exec.hash,
-		     _("000000000000000000000000000000000000000000000000")
-		     ))
+  if (0 == sl_strcmp(sh.exec.hash, SH_KEY_NULL ))
     {
       dlog(1, FIL__, __LINE__, 
@@ -2895,7 +2893,5 @@
 
  out:
-  sl_strlcpy(fileHash,
-	     _("000000000000000000000000000000000000000000000000"),
-	     KEY_LEN+1);
+  sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
   SL_RETURN( -1, _("sh_unix_checksum_size"));
 }
@@ -3193,7 +3189,5 @@
     {
       if (fileHash != NULL)
-	sl_strlcpy(fileHash,
-		   _("000000000000000000000000000000000000000000000000"),
-		   KEY_LEN+1);
+	sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
     }
   
@@ -3211,7 +3205,5 @@
 	  if ((theFile->check_mask & MODI_CHK) == 0)
 	    {
-	      sl_strlcpy(fileHash,
-			 _("000000000000000000000000000000000000000000000000"),
-			 KEY_LEN+1);
+	      sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
 	    }
 	  else if ((theFile->check_mask & MODI_PREL) != 0 && 
@@ -3221,7 +3213,5 @@
 	      if (0 != sh_prelink_run (theFile->fullpath, 
 				       fileHash, alert_timeout))
-		sl_strlcpy(fileHash,
-			   _("000000000000000000000000000000000000000000000000"),
-			   KEY_LEN+1);
+		sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
 	    }
 	  else
@@ -3255,7 +3245,5 @@
 	  if ((theFile->check_mask & MODI_CHK) == 0)
 	    {
-	      sl_strlcpy(fileHash,
-			 _("000000000000000000000000000000000000000000000000"),
-			 KEY_LEN+1);
+	      sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
 	    }
 	  else if (policy == SH_LEVEL_PRELINK &&
@@ -3265,7 +3253,5 @@
 	      if (0 != sh_prelink_run (theFile->fullpath, 
 				       fileHash, alert_timeout))
-		sl_strlcpy(fileHash,
-			   _("000000000000000000000000000000000000000000000000"),
-			   KEY_LEN+1);
+		sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
 	    }
 	  else
@@ -3295,7 +3281,5 @@
       fstat_return = errno;
       if (fileHash != NULL)
-	sl_strlcpy(fileHash, 
-		   _("000000000000000000000000000000000000000000000000"), 
-		   KEY_LEN + 1);
+	sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
 
       if ((theFile->check_mask & MODI_CHK) != 0)
@@ -3483,13 +3467,22 @@
       {
 	tmp = sh_util_dirname(theFile->fullpath);
-	sl_strlcpy (theFile->linkpath, 
-		    tmp, 
-		    PATH_MAX);
-	SH_FREE(tmp);
-	sl_strlcat (theFile->linkpath, 
-		    "/", PATH_MAX);
-	sl_strlcat (theFile->linkpath, 
-		    linknamebuf, 
-		    PATH_MAX);
+	if (tmp) {
+	  sl_strlcpy (theFile->linkpath, tmp, PATH_MAX);
+	  SH_FREE(tmp);
+	} else {
+	  theFile->linkpath[0] = '\0';
+	}
+	/*
+	 * Only attach '/' if not root directory. Handle "//", which
+	 * according to POSIX is implementation-defined, and may be
+	 * different from "/" (however, three or more '/' will collapse
+	 * to one).
+	 */
+	tmp = theFile->linkpath; while (*tmp == '/') ++tmp;
+	if (*tmp != '\0')
+	  {
+	    sl_strlcat (theFile->linkpath, "/", PATH_MAX);
+	  }
+	sl_strlcat (theFile->linkpath, linknamebuf, PATH_MAX);
       }
     
Index: trunk/src/sh_utils.c
===================================================================
--- trunk/src/sh_utils.c	(revision 92)
+++ trunk/src/sh_utils.c	(revision 93)
@@ -554,5 +554,6 @@
 }
 
-/* can't inline (AIX)
+/* read a hexchar, return int value (0-15)
+ * can't inline (AIX)
  */
 int sh_util_hexchar( const char c )
@@ -567,4 +568,21 @@
   else return -1;
   /*@-charint@*/
+}
+
+char * sh_util_charhex( unsigned char i )
+{
+  static char i2h[2];
+  int j, k;
+
+  j = i / 16;
+  k = i - (j*16);
+
+  if (j < 10) i2h[0] = '0'+j;
+  else        i2h[0] = 'A'+(j-10);
+  
+  if (k < 10) i2h[1] = '0'+k;
+  else        i2h[1] = 'A'+(k-10);
+
+  return i2h;
 }
 
@@ -1718,34 +1736,55 @@
   char * retval;
   size_t len;
+  char * tmp;
 
   SL_ENTER(_("sh_util_dirname"));
 
   ASSERT_RET ((fullpath != NULL), _("fullpath != NULL"), (NULL))
-
-  len = sl_strlen (fullpath);  /* fullpath[i] is terminating '\0' */
-
-  if (len > 1 && fullpath[len-1] == '/') /* skip trailing '/' */
+  ASSERT_RET ((*fullpath == '/'), _("*fullpath == '/'"), (NULL))
+
+  retval = sh_util_strdup(fullpath);
+
+  tmp    = retval;
+  while (*tmp == '/') ++tmp;
+
+  /* (1) only leading slashes -- return exact copy 
+   */
+  if (*tmp == '\0')
+    {
+      SL_RETURN(retval, _("sh_util_dirname"));
+    }
+
+  /* (2) there are non-slash characters, so delete trailing slashes
+   */
+  len    = sl_strlen (retval);     /* retval[len] is terminating '\0' */
+
+  while (len > 1 && retval[len-1] == '/')    /* delete trailing slash */
+    {
+      retval[len-1] = '\0';
+      --len;
+    }
+
+  /* (3) now delete all non-slash characters up to the preceding slash
+   */
+  while (len > 1 && retval[len-1] != '/') {
+    retval[len-1] = '\0';
     --len;
-
-  while (len > 0) {
+  }
+
+  /* (4a) only leading slashes left, so return this
+   */
+  if (&(retval[len]) == tmp)
+    {
+      SL_RETURN(retval, _("sh_util_dirname"));
+    }
+
+  /* (4b) strip trailing slash(es) of parent directory
+   */
+  while (len > 1 && retval[len-1] == '/') {
+    retval[len-1] = '\0';
     --len;
-    if (fullpath[len] == '/') 
-      {
-	if (len == 0) ++len; /* copy the '/' to output */
-	break;
-      }
   }
-
-  /* -- Not an absolute path. --
-   */
-  if ((len == 0) && (fullpath[len] != '/'))
-    { 
-      SL_RETURN(NULL, _("sh_util_dirname"));
-    }
-
-  retval = SH_ALLOC(len + 1);
-  (void) sl_strlcpy (retval, fullpath, len+1);
-
   SL_RETURN(retval, _("sh_util_dirname"));
+
 }
 
@@ -1754,8 +1793,9 @@
 char * sh_util_basename(const char * fullpath)
 {
-  char * retval = NULL;
-  char * tmp;
-  char * c;
-  size_t len;
+  char       * retval = NULL;
+  const char * tmp;
+  char       * tmp2;
+  char       * c;
+  size_t       len;
 
   SL_ENTER(_("sh_util_basename"));
@@ -1763,27 +1803,29 @@
   ASSERT_RET ((fullpath != NULL), _("fullpath != NULL"), (NULL))
 
-  c = strrchr(fullpath, '/');
-  len = sl_strlen (c);
-
-  if (c == fullpath)
-    {
-      if (len <= 1)
-	retval = sh_util_strdup(c);
+  tmp = fullpath; while (*tmp == '/') ++tmp;
+  if (*tmp == '\0')
+    {
+      retval = sh_util_strdup(fullpath);
+    }
+  else
+    {
+      tmp2 = sh_util_strdup(tmp);
+      len  = sl_strlen (tmp2);
+
+      while (len > 1 && tmp2[len-1] == '/')
+	{
+	  tmp2[len-1] = '\0';
+	  --len;
+	}
+
+      c = strrchr(tmp2, '/');
+      if (c)
+	{
+	  retval = sh_util_strdup(++c);
+	  SH_FREE(tmp2);
+	}
       else
-	retval = sh_util_strdup(++c);
-    }
-  else
-    {
-      if (len > 1)
-	{
-	  retval = sh_util_strdup(++c);
-	}
-      else
-	{
-	  /* input ends in '/' */
-	  tmp = sh_util_strdup(fullpath);
-	  tmp[strlen(tmp)-1] = '\0';
-	  retval = sh_util_basename(tmp);
-	  SH_FREE(tmp);
+	{
+	  retval = tmp2;
 	}
     }
