Index: trunk/Makefile.in
===================================================================
--- trunk/Makefile.in	(revision 75)
+++ trunk/Makefile.in	(revision 76)
@@ -1668,5 +1668,5 @@
 exepack_mkdata.o: $(srcsrc)/exepack_mkdata.c Makefile config.h $(srcinc)/minilzo.h 
 minilzo.o: $(srcsrc)/minilzo.c Makefile $(srcinc)/minilzo.h 
-slib.o: $(srcsrc)/slib.c Makefile config_xor.h $(srcinc)/slib.h $(srcinc)/sh_calls.h $(srcinc)/sh_static.h 
+slib.o: $(srcsrc)/slib.c Makefile config_xor.h $(srcinc)/slib.h $(srcinc)/sh_calls.h $(srcinc)/sh_static.h $(srcinc)/sh_mem.h 
 rijndael-alg-fst.o: $(srcsrc)/rijndael-alg-fst.c Makefile config_xor.h $(srcinc)/rijndael-alg-fst.h $(srcinc)/rijndael-boxes-fst.h 
 rijndael-api-fst.o: $(srcsrc)/rijndael-api-fst.c Makefile config_xor.h $(srcinc)/rijndael-alg-fst.h $(srcinc)/rijndael-api-fst.h 
Index: trunk/configure.ac
===================================================================
--- trunk/configure.ac	(revision 75)
+++ trunk/configure.ac	(revision 76)
@@ -29,4 +29,5 @@
 
 GCC_STACK_PROTECT_CC
+
 
 AC_HEADER_STDC
@@ -392,5 +393,6 @@
 if test "$sh_HAVE_LONG_LONG" = "yes"; then
    AC_CHECK_SIZEOF(unsigned long long, 4)
-   if test "$ac_cv_sizeof_unsigned_long_long" = "8"; then
+   sh_sizeof_unsigned_long_long=`echo "$ac_cv_sizeof_unsigned_long_long" | sed 's%[^0-9]%%g'`
+   if test "$sh_sizeof_unsigned_long_long" = "8"; then
       AC_DEFINE(HAVE_LONG_LONG_64, 1, [Define if you have 64bit long long])
    fi
@@ -403,25 +405,21 @@
 
 AC_CHECK_SIZEOF(unsigned long,  4)
-AC_CHECK_SIZEOF(unsigned int ,  4)
+AC_CHECK_SIZEOF(unsigned int,   4)
 AC_CHECK_SIZEOF(unsigned short, 2)
     
 
-if test "$ac_cv_sizeof_unsigned_long" = "4"; then
+sh_sizeof_unsigned_long=`echo "$ac_cv_sizeof_unsigned_long" | sed 's%[^0-9]%%g'`
+if test "$sh_sizeof_unsigned_long"  = "4"; then
 	AC_DEFINE(HAVE_LONG_32)
 fi
-if test "$ac_cv_sizeof_unsigned_long" = "8"; then
+if test "$sh_sizeof_unsigned_long"  = "8"; then
 	AC_DEFINE(HAVE_LONG_64)
 fi
-if test "$ac_cv_sizeof_unsigned_int" = "4"; then
+sh_sizeof_unsigned_int=`echo "$ac_cv_sizeof_unsigned_int" | sed 's%[^0-9]%%g'`
+if test "$sh_sizeof_unsigned_int"   = "4"; then
 	AC_DEFINE(HAVE_INT_32)
 fi
-
-dnl
-dnl For Alpha
-dnl
-if test "$ac_cv_sizeof_unsigned_int_" = "4"; then
-	AC_DEFINE(HAVE_INT_32)
-fi
-if test "$ac_cv_sizeof_unsigned_short" = "4"; then
+sh_sizeof_unsigned_short=`echo "$ac_cv_sizeof_unsigned_short" | sed 's%[^0-9]%%g'`
+if test "$sh_sizeof_unsigned_short" = "4"; then
 	AC_DEFINE(HAVE_SHORT_32)
 fi
@@ -528,4 +526,5 @@
 AC_C_CONST
 AC_C_BIGENDIAN
+AC_C_RESTRICT
 
 AM_SA_SIGACTION_WORKS
Index: trunk/depend.dep
===================================================================
--- trunk/depend.dep	(revision 75)
+++ trunk/depend.dep	(revision 76)
@@ -46,5 +46,5 @@
 exepack_mkdata.o: $(srcsrc)/exepack_mkdata.c Makefile config.h $(srcinc)/minilzo.h 
 minilzo.o: $(srcsrc)/minilzo.c Makefile $(srcinc)/minilzo.h 
-slib.o: $(srcsrc)/slib.c Makefile config_xor.h $(srcinc)/slib.h $(srcinc)/sh_calls.h $(srcinc)/sh_static.h 
+slib.o: $(srcsrc)/slib.c Makefile config_xor.h $(srcinc)/slib.h $(srcinc)/sh_calls.h $(srcinc)/sh_static.h $(srcinc)/sh_mem.h 
 rijndael-alg-fst.o: $(srcsrc)/rijndael-alg-fst.c Makefile config_xor.h $(srcinc)/rijndael-alg-fst.h $(srcinc)/rijndael-boxes-fst.h 
 rijndael-api-fst.o: $(srcsrc)/rijndael-api-fst.c Makefile config_xor.h $(srcinc)/rijndael-alg-fst.h $(srcinc)/rijndael-api-fst.h 
Index: trunk/depend.sum
===================================================================
--- trunk/depend.sum	(revision 75)
+++ trunk/depend.sum	(revision 76)
@@ -1,1 +1,1 @@
-1289129628
+2835584241
Index: trunk/docs/Changelog
===================================================================
--- trunk/docs/Changelog	(revision 75)
+++ trunk/docs/Changelog	(revision 76)
@@ -1,2 +1,11 @@
+2.3.1:
+	* fix compile error in sh_portcheck.c (problem on cygwin
+	  reported by J. D. Fiori)
+	* check filenames ending in space (also for utf8 spaces)
+	* check and escape csv formatted db listing
+	* cache results of sl_trustfile_euid()
+	* trustfile: use 4096 for MAXFILENAME, switch to strncpy
+	* CL option -v|--version for info on version and compiled-in options
+	
 2.3.0a:
 	* fix compile failure with portcheck + stealth (reported by lucas)
Index: trunk/include/samhain.h
===================================================================
--- trunk/include/samhain.h	(revision 75)
+++ trunk/include/samhain.h	(revision 76)
@@ -301,4 +301,21 @@
  **************************************************/
 
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+#define SH_GNUC_NULL_TERMINATED __attribute__((__sentinel__))
+#else
+#define SH_GNUC_NULL_TERMINATED
+#endif
+
+/* The semantics of the built-in are that it is expected that expr == const
+ * for __builtin_expect ((expr), const)
+ */
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define SH_LIKELY(expr)   (__builtin_expect((expr), 1))
+#define SH_UNLIKELY(expr) (__builtin_expect((expr), 0))
+#else
+#define SH_LIKELY(expr) (expr)
+#define SH_UNLIKELY(expr) (expr)
+#endif
+
 /* signal-safe log function
  */
Index: trunk/include/sh_utils.h
===================================================================
--- trunk/include/sh_utils.h	(revision 75)
+++ trunk/include/sh_utils.h	(revision 76)
@@ -61,4 +61,5 @@
 
 char * sh_util_strdup (const char * str);
+char * sh_util_strdup_l (const char * str, size_t len);
 char * sh_util_strsep (char **str, const char *delim);
 
@@ -143,5 +144,5 @@
  * Arhument list must be NULL terminated.
  */
-char * sh_util_strconcat (const char * arg1, ...);
+char * sh_util_strconcat (const char * arg1, ...) SH_GNUC_NULL_TERMINATED;
 
 /* check if string is numeric only
Index: trunk/include/slib.h
===================================================================
--- trunk/include/slib.h	(revision 75)
+++ trunk/include/slib.h	(revision 76)
@@ -293,5 +293,5 @@
    * ---------------------------------------------------------------- */
 
-  SL_TICKET sl_make_ticket (int fd, char * path);
+  SL_TICKET sl_make_ticket (int fd, const char * path);
 
   /* Open for writing.
@@ -365,4 +365,8 @@
    */
   int sl_write_line (SL_TICKET ticket, void * msg, long nbytes);
+
+  /* As above, but only for non-constant strings.
+   */
+  int sl_write_line_fast (SL_TICKET ticket, void * msg, long nbytes);
 
   /* Drop all metadata for file descriptors >= fd.
@@ -414,5 +418,7 @@
 #define SL_NOPRIV  0x34
 
-#define MAXFILENAME	2048
+/* Suitable for Linux
+ */
+#define MAXFILENAME	4096
 
 
Index: trunk/man/samhain.8
===================================================================
--- trunk/man/samhain.8	(revision 75)
+++ trunk/man/samhain.8	(revision 76)
@@ -60,4 +60,7 @@
 .B samhain
 \-c | \-\-copyright
+
+.B samhain
+\-v | \-\-version
 
 .B samhain
@@ -325,7 +328,12 @@
 
 .B samhain
+\-v | \-\-version 
+
+Show version and compiled-in options.
+
+.B samhain
 \-h | \-\-help 
 
-Print supported options (depending on compilation options).
+Print supported command line options (depending on compilation options).
 
 .B samhain
Index: trunk/man/samhainrc.5
===================================================================
--- trunk/man/samhainrc.5	(revision 75)
+++ trunk/man/samhainrc.5	(revision 76)
@@ -304,4 +304,101 @@
 Limit files per seconds for SUID check. 
 .TP
+.I "[Mounts]"
+Configuration for checking mounts.
+.br
+.BI MountCheckActive= 0|1
+Switch off/on this module.
+.br
+.BI MountCheckInterval= seconds
+  The interval between checks (default 300).
+.br
+.BI SeverityMountMissing= severity 
+Severity for reports on missing mounts. 
+.br
+.BI SeverityOptionMissing= severity 
+Severity for reports on missing mount options. 
+.br
+.BI CheckMount= path
+[mount_options]
+.br
+Mount point to check. Mount options must be given as 
+comma-separated list, separated by a blank from the preceding mount point.
+.TP
+.I "[UserFiles]"
+Configuration for checking paths relative to user home directories.
+.br
+.BI UserFilesActive= 0|1
+Switch off/on this module.
+.br
+.BI UserFilesName= filename 
+policy
+.br
+Files to check for under each $HOME. Allowed values for 'policy'
+are: allignore, attributes, logfiles, loggrow, noignore (default), 
+readonly, user0, user1, user2, user3, and user4.
+.br
+.BI UserFilesCheckUids= uid_list
+A list of UIDs where we want to check. The default
+is all. Ranges (e.g. 100-500) are allowed. If there is an open range (e.g.
+1000-), it must be last in the list.
+.TP
+.I "[ProcessCheck]"
+Settings for finding hidden/fake,required processes on the local host.
+.br
+.BI ProcessCheckActive= 0|1 
+Switch off/on the check.
+.br
+.BI ProcessCheckInterval= seconds
+  The interval between checks (default 300).
+.br
+.BI SeverityProcessCheck= severity 
+Severity for events (default crit). 
+.br
+.BI ProcessCheckMinPID= pid
+The minimum PID to check (default 0).
+.br
+.BI ProcessCheckMaxPID= pid
+The maximum PID to check (default 32767).
+.br
+.BI ProcessCheckPSPath= path 
+The path to ps (autodetected at compile time).
+.br
+.BI ProcessCheckPSArg= argument 
+The argument to ps (autodetected at compile time).
+Must yield PID in first column.
+.br
+.BI ProcessCheckExists= regular_expression
+Check for existence of a process matching the given regular expression.
+.TP
+.I "[PortCheck]"
+Settings for checking open ports on the local host.
+.br
+.BI PortCheckActive= 0|1 
+Switch off/on the check.
+.br
+.BI PortCheckInterval= seconds
+  The interval between checks (default 300).
+.br
+.BI PortCheckUDP= yes|no
+Whether to check UPD ports as well (default yes). 
+.br
+.BI SeverityPortCheck= severity 
+Severity for events (default crit). 
+.br
+.BI PortCheckInterface= ip_address 
+Additional interface to check.
+.br
+.BI PortCheckOptional= ip_address:list 
+Ports that may, but need not be open. The ip_address is the one
+of the interface, the list must be
+comma or whitespace separated, each item must be (port|service)/protocol,
+e.g. 22/tcp,nfs/tcp/nfs/udp.
+.br
+.BI PortCheckRequired= ip_address:list 
+Ports that are required to be open. The ip_address is the one
+of the interface, the list must be
+comma or whitespace separated, each item must be (port|service)/protocol,
+e.g. 22/tcp,nfs/tcp/nfs/udp.
+.TP
 .I "[Database]"
 Settings for 
Index: trunk/src/cutest_sh_hash.c
===================================================================
--- trunk/src/cutest_sh_hash.c	(revision 75)
+++ trunk/src/cutest_sh_hash.c	(revision 76)
@@ -63,3 +63,59 @@
 
 
+void Test_csv_escape_ok (CuTest *tc) {
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
 
+  extern char * csv_escape(const char * str);
+
+  char   test0[80];
+  char   expec[80];
+  char  *ret;
+
+  strcpy(test0, "foobar");
+  strcpy(expec, "\"foobar\"");
+  ret = csv_escape(test0);
+  CuAssertStrEquals(tc, expec, ret);
+
+  strcpy(test0, "\"foobar\"");
+  strcpy(expec, "\"\"\"foobar\"\"\"");
+  ret = csv_escape(test0);
+  CuAssertStrEquals(tc, expec, ret);
+
+  strcpy(test0, "foo,bar");
+  strcpy(expec, "\"foo,bar\"");
+  ret = csv_escape(test0);
+  CuAssertStrEquals(tc, expec, ret);
+
+  strcpy(test0, "foob,\"a\"r");
+  strcpy(expec, "\"foob,\"\"a\"\"r\"");
+  ret = csv_escape(test0);
+  CuAssertStrEquals(tc, expec, ret);
+
+  strcpy(test0, "\",\"foobar\",\"");
+  strcpy(expec, "\"\"\",\"\"foobar\"\",\"\"\"");
+  ret = csv_escape(test0);
+  CuAssertStrEquals(tc, expec, ret);
+
+  strcpy(test0, "");
+  strcpy(expec, "");
+  ret = csv_escape(test0);
+  CuAssertStrEquals(tc, expec, ret);
+
+  strcpy(test0, "a");
+  strcpy(expec, "\"a\"");
+  ret = csv_escape(test0);
+  CuAssertStrEquals(tc, expec, ret);
+
+  strcpy(test0, "foo\"bar");
+  strcpy(expec, "\"foo\"\"bar\"");
+  ret = csv_escape(test0);
+  CuAssertStrEquals(tc, expec, ret);
+
+#else
+  (void) tc; /* fix compiler warning */
+#endif
+  return;
+}
+
+
+
Index: trunk/src/cutest_sh_utils.c
===================================================================
--- trunk/src/cutest_sh_utils.c	(revision 75)
+++ trunk/src/cutest_sh_utils.c	(revision 76)
@@ -6,4 +6,72 @@
 #include "samhain.h"
 #include "sh_utils.h"
+
+void Test_sl_strlcpy (CuTest *tc) {
+  int ret;
+  char out[] = "aaaaaa";
+  char in[]  = "bbb";
+
+  ret = sl_strlcpy (NULL, NULL, 0);
+  CuAssertIntEquals(tc, ret, SL_ENONE);
+
+  ret = sl_strlcpy (NULL, in, 0);
+  CuAssertIntEquals(tc, ret, SL_ENULL);
+
+  ret = sl_strlcpy (out, NULL, 0);
+  CuAssertIntEquals(tc, ret, SL_ENONE);
+
+  ret = sl_strlcpy (out, in, 0);
+  CuAssertIntEquals(tc, ret, SL_ENONE);
+
+  ret = sl_strlcpy (out, NULL, 7);
+  CuAssertIntEquals(tc, ret, SL_ENONE);
+  CuAssertStrEquals(tc, "", out);
+
+  out[0] = 'a';
+  ret = sl_strlcpy (out, in, 4);
+  CuAssertIntEquals(tc, ret, SL_ENONE);
+  CuAssertStrEquals(tc, "bbb", out);
+  CuAssertStrEquals(tc, "aa", &out[4]);
+  
+  return;
+}
+
+void Test_sl_strlcat (CuTest *tc) {
+  int ret;
+  char out[16] = "aaaaaa";
+  char in[16]  = "bbb";
+
+  ret = sl_strlcat (NULL, NULL, 0);
+  CuAssertIntEquals(tc, ret, SL_ENONE);
+
+  ret = sl_strlcat (NULL, in, 0);
+  CuAssertIntEquals(tc, ret, SL_ENONE);
+
+  ret = sl_strlcat (out, NULL, 0);
+  CuAssertIntEquals(tc, ret, SL_ENONE);
+
+  ret = sl_strlcat (out, in, 0);
+  CuAssertIntEquals(tc, ret, SL_ENONE);
+
+  ret = sl_strlcat (out, NULL, sizeof(out));
+  CuAssertIntEquals(tc, ret, SL_ENONE);
+  CuAssertStrEquals(tc, "aaaaaa", out);
+
+  ret = sl_strlcat (out, in, 7);
+  CuAssertIntEquals(tc, ret, SL_ETRUNC);
+  CuAssertStrEquals(tc, "aaaaaa", out);
+
+  ret = sl_strlcat (out, in, 8);
+  CuAssertIntEquals(tc, ret, SL_ETRUNC);
+  CuAssertStrEquals(tc, "aaaaaab", out);
+
+  ret = sl_strlcat (out, in, sizeof(out));
+  CuAssertIntEquals(tc, ret, SL_ENONE);
+  CuAssertStrEquals(tc, "aaaaaabbbb", out);
+
+  CuAssertStrEquals(tc, "bbb", in);
+
+  return;
+}
 
 void Test_sh_util_acl_compact (CuTest *tc) {
@@ -238,4 +306,8 @@
   CuAssertIntEquals(tc, ret, S_FALSE);
 
+  /* switch on utf8 checking for sh_util_obscurename() */
+
+  ret = sh_util_obscure_utf8("Y");
+  CuAssertIntEquals(tc, ret, 0);
 
   ret = sh_util_obscure_ok ("0x01,0x02,0x03");
@@ -244,24 +316,54 @@
   ret = sh_util_valid_utf8 (input);
   CuAssertIntEquals(tc, ret, S_TRUE);
+  ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+  CuAssertIntEquals(tc, ret, 0);
 
   input[0] = '\t';
   ret = sh_util_valid_utf8 (input);
   CuAssertIntEquals(tc, ret, S_FALSE);
+  ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+  CuAssertIntEquals(tc, ret, -1);
 
   input[0] = 0x01;
   ret = sh_util_valid_utf8 (input);
   CuAssertIntEquals(tc, ret, S_TRUE);
+  ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+  CuAssertIntEquals(tc, ret, 0);
 
   input[0] = 0x02;
   ret = sh_util_valid_utf8 (input);
   CuAssertIntEquals(tc, ret, S_TRUE);
+  ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+  CuAssertIntEquals(tc, ret, 0);
 
   input[0] = 0x03;
   ret = sh_util_valid_utf8 (input);
   CuAssertIntEquals(tc, ret, S_TRUE);
+  ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+  CuAssertIntEquals(tc, ret, 0);
 
   input[0] = 0x04;
   ret = sh_util_valid_utf8 (input);
   CuAssertIntEquals(tc, ret, S_FALSE);
+  ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+  CuAssertIntEquals(tc, ret, -1);
+
+  input[0] = 'f';
+  ret = sh_util_valid_utf8 (input);
+  CuAssertIntEquals(tc, ret, S_TRUE);
+  ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+  CuAssertIntEquals(tc, ret, 0);
+
+  input[5] = ' ';
+  ret = sh_util_valid_utf8 (input);
+  CuAssertIntEquals(tc, ret, S_FALSE);
+  ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+  CuAssertIntEquals(tc, ret, -1);
+
+  input[5] = 'r'; input[3] = ' ';
+  ret = sh_util_valid_utf8 (input);
+  CuAssertIntEquals(tc, ret, S_TRUE);
+  ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+  CuAssertIntEquals(tc, ret, 0);
 
 
@@ -277,4 +379,9 @@
   char input[16] = "foobar";
 
+  /* switch off utf8 checking for sh_util_obscurename() */
+
+  ret = sh_util_obscure_utf8("N");
+  CuAssertIntEquals(tc, ret, 0);
+
   ret = sh_util_obscure_ok ("0xA1,0xA2,0xA3");
   CuAssertIntEquals(tc, ret, 0);
@@ -303,4 +410,15 @@
   CuAssertIntEquals(tc, ret, -1);
 
+  input[0] = 'f';
+  ret = sh_util_obscurename (0, input, S_FALSE /* no log message */);
+  CuAssertIntEquals(tc, ret, 0);
+
+  input[5] = ' ';
+  ret = sh_util_obscurename (0, input, S_FALSE /* no log message */);
+  CuAssertIntEquals(tc, ret, -1);
+
+  input[5] = 'r'; input[3] = ' ';
+  ret = sh_util_obscurename (0, input, S_FALSE /* no log message */);
+  CuAssertIntEquals(tc, ret, 0);
 #else
   CuAssertIntEquals(tc, ret, 0);
Index: trunk/src/sh_database.c
===================================================================
--- trunk/src/sh_database.c	(revision 75)
+++ trunk/src/sh_database.c	(revision 76)
@@ -1197,29 +1197,25 @@
   long len;
 
-  if (!end    || !val   || !size)
-    return end;
-
-  if (val[0] == '\0')
-    {
-      return end;
-    }
-  else
-    {
-      if (*size > 1)
+  if (!((end == NULL) || (val == NULL) || (size == NULL)))
+    {
+      if (val[0] != '\0')
 	{
-	  *end = ','; ++end; (*size) -= 1;
-	  if (flag == 1) { *end = '\''; ++end; (*size) -= 1; }
-	  *end = '\0';
+	  if (*size > 1)
+	    {
+	      *end = ','; ++end; (*size) -= 1;
+	      if (flag == 1) { *end = '\''; ++end; (*size) -= 1; }
+	      *end = '\0';
+	    }
+	  len = (long) strlen(val);
+	  if ((long) *size > (len+1))
+	    {
+	      (void) sl_strlcat(end, val, (size_t) *size);
+	      end   += len; (*size) -= len;
+	      if (flag == 1) { *end = '\''; ++end;  (*size) -= 1; }
+	      *end = '\0'; 
+	    }
 	}
-      len = (long) strlen(val);
-      if ((long) *size > (len+1))
-	{
-	  (void) sl_strlcat(end, val, (size_t) *size);
-	  end   += len; (*size) -= len;
-	  if (flag == 1) { *end = '\''; ++end;  (*size) -= 1; }
-	  *end = '\0'; 
-	}
-    }
-
+    }
+  
   return end;
 }
@@ -1250,4 +1246,7 @@
   char md5out[33];
   int  cnt;
+
+  size_t len_val;
+  size_t len_col;
 
   SL_ENTER(_("sh_database_entry"));
@@ -1331,8 +1330,11 @@
   /*@+type@*/
 
-  size   =  (int) (SH_QUERY_MAX - strlen(values));
-  end    =  values + strlen(values);
-  c_size =  1023   - (int) strlen(columns); /* sizeof(colums) == 1024 */
-  c_end  =  columns + strlen(columns);
+  len_val = strlen(values);
+  size    =  (int) (SH_QUERY_MAX - len_val);
+  end     =  values + len_val;
+
+  len_col = strlen(columns);
+  c_size  =  1023   - (int) len_col; /* sizeof(colums) == 1024 */
+  c_end   =  columns + len_col;
 
   i = 4;
@@ -1354,16 +1356,22 @@
 	  if (p != end)
 	    {
-	      /* 
-	       * 'host' is a reserved word in SQL
-	       */
-	      if (attr_tab[i].val == SH_SLOT_HOST)
-		c_end = null_or_val (c_end, _("fromhost"), &c_size,0);
-	      /* 
-	       * 'group' is a reserved word in SQL
-	       */
-	      else if (attr_tab[i].val == SH_SLOT_GROUP)
-		c_end = null_or_val (c_end, _("grp"), &c_size,0);
+	      if ((attr_tab[i].val != SH_SLOT_HOST) &&
+		  (attr_tab[i].val != SH_SLOT_GROUP))
+		{
+		  c_end = null_or_val (c_end, attr_tab[i].attr, &c_size,0);
+		}
 	      else
-		c_end = null_or_val (c_end, attr_tab[i].attr, &c_size,0);
+		{
+		  /* 
+		   * 'host' is a reserved word in SQL
+		   */
+		  if (attr_tab[i].val == SH_SLOT_HOST)
+		    c_end = null_or_val (c_end, _("fromhost"), &c_size,0);
+		  /* 
+		   * 'group' is a reserved word in SQL
+		   */
+		  else /* if (attr_tab[i].val == SH_SLOT_GROUP) */
+		    c_end = null_or_val (c_end, _("grp"), &c_size,0);
+		}
 	    }
 	  /*@-type@*//* byte* versus char[..] */
@@ -1523,27 +1531,37 @@
   unsigned char * p = (unsigned char *) p_in;
 
-  while (*p != '\0') 
-    {
-      if (*p == '\\')
+  if (*p != '\0')
+    {
+      do 
 	{
-	  escp = (escp == 1) ? 0 : 1;
-	}
-      else if ((*p == '\'' || *p == '\"') && escp == 0)
-	{
-	  retv = S_FALSE;
-	}
-      else if (*p > 0x7F)
-	{
-	  retv = S_FALSE;
-	}
-      else 
-	{
-	  escp = 0;
-	}
-      ++p;
-    }
-  if (escp == 1) 
-    retv = S_FALSE;
-  return retv;
+	  if (*p <=  0x7F)
+	    {
+	      if (escp == 0)
+		{
+		  if      (!((*p == '\'') || (*p == '\"') || (*p != '\\'))) 
+		    /* do nothing */;
+		  else if (*p == '\\') escp = 1;
+		  else    retv = S_FALSE; /* (*p == '\'' || *p == '\"') */
+		}
+	      else /* escp == 1 */
+		{
+		  escp = 0;
+		}
+	    }
+	  else /* *p > 0x7F */
+	    {
+	      retv = S_FALSE;
+	    }
+	  
+	  ++p;
+	  
+	} 
+      while (*p != '\0');
+    }
+
+  if (escp == 0)
+    return retv;
+  else
+    return S_FALSE;
 }
 
@@ -1580,5 +1598,5 @@
     SL_RETURN (NULL, _("sh_database_parse"));
 
-  while ((p != NULL) && (*p != '\0') && (*p != '>'))
+  while ((*p != '\0') && (*p != '>'))
     {
       if (p[0] == 'l' && p[1] == 'o' && p[2] == 'g' &&
@@ -1631,9 +1649,11 @@
   /* non-whitespace 
    */
-  i = 0;
   for (i=0; i < 64; ++i)
     {
-      key_str[i] = p[i];
-      if (p[i] == '=')
+      if (p[i] != '=')
+	{
+	  key_str[i] = p[i];
+	}
+      else
 	{
 	  key_str[i] = '\0';
@@ -1653,13 +1673,44 @@
 	{
 	  q = strchr(&p[j+2], '"');
-	  if (!q)
-	    {
-	      SL_RETURN(NULL, _("sh_database_parse"));
-	    }
-	  else
+	  if (q)
 	    {
 	      *q = '\0';
 
-	      if (S_FALSE == is_escaped(&p[j+2])) {
+	      if (S_TRUE == is_escaped(&p[j+2])) {
+
+		if      (res->val == 1)
+		  (void) sl_strlcpy(db_entry->sev, &p[j+2], 
+				    (size_t)res->size);
+		else if (res->val == 2)
+		  {
+		    z = strchr(&p[j+2], 'T');
+		    if (z) *z = ' ';
+		    (void) sl_strlcpy(db_entry->time, &p[j+2],  20);
+		  }
+		else if (res->val == 3)
+		  (void) sl_strlcpy(db_entry->host, &p[j+2], 
+				    (size_t) res->size);
+		else if (res->val == 4)
+		  (void) sl_strlcpy(db_entry->msg,  &p[j+2], 
+				    (size_t) res->size);
+		else if (res->size != 0)
+		  {
+		    (void) sl_strlcpy( (((char *)(db_entry))+ res->off),
+				       &p[j+2], 
+				       (size_t) res->size);
+		  }
+		else if (res->val >= START_SEC_LONGS)
+		  {
+		    db_entry->long_data[res->val-START_SEC_LONGS]
+		      = atol(&p[j+2]);
+		  }
+
+		*q = '"';
+		p  = q; 
+		++p;
+
+		goto parse;
+	      }
+	      else { /* S_FALSE == is_escaped(&p[j+2]) */
 		sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
 				_("Message not properly escaped"), 
@@ -1667,37 +1718,8 @@
 		SL_RETURN(NULL, _("sh_database_parse"));
 	      }
-
-	      if      (res->val == 1)
-		(void) sl_strlcpy(db_entry->sev, &p[j+2], 
-				  (size_t)res->size);
-	      else if (res->val == 2)
-		{
-		  z = strchr(&p[j+2], 'T');
-		  if (z) *z = ' ';
-		  (void) sl_strlcpy(db_entry->time, &p[j+2],  20);
-		}
-	      else if (res->val == 3)
-		(void) sl_strlcpy(db_entry->host, &p[j+2], 
-				  (size_t) res->size);
-	      else if (res->val == 4)
-		(void) sl_strlcpy(db_entry->msg,  &p[j+2], 
-				  (size_t) res->size);
-	      else if (res->size != 0)
-		{
-		  (void) sl_strlcpy( (((char *)(db_entry))+ res->off),
-				     &p[j+2], 
-				     (size_t) res->size);
-		}
-	      else if (res->val >= START_SEC_LONGS)
-		{
-		  db_entry->long_data[res->val-START_SEC_LONGS]
-		    = atol(&p[j+2]);
-		}
-
-	      *q = '"';
-	      p  = q; 
-	      ++p;
-
-	      goto parse;
+	    }
+	  else /* q == NULL */
+	    {
+	      SL_RETURN(NULL, _("sh_database_parse"));
 	    }
 	}
Index: trunk/src/sh_getopt.c
===================================================================
--- trunk/src/sh_getopt.c	(revision 75)
+++ trunk/src/sh_getopt.c	(revision 76)
@@ -65,4 +65,5 @@
 #endif
 static int sh_getopt_copyright (const char * dummy);
+static int sh_getopt_version (const char * dummy);
 
 static opttable_t op_table[] = {
@@ -265,4 +266,9 @@
     HAS_ARG_NO, 
     sh_getopt_usage },
+  { N_("version"),  
+    'v', 
+    N_("Show version and compiled-in options"),  
+    HAS_ARG_NO, 
+    sh_getopt_version },
 #if defined(HAVE_LIBPRELUDE) && defined(HAVE_LIBPRELUDE_9)
   /* need to skip over these */
@@ -301,8 +307,235 @@
 };
 
+
+static void sh_getopt_print_log_facilities ()
+{
+  fputs (_("Compiled-in log facilities:"), stdout);
+
+#ifndef DEFAULT_CONSOLE
+  printf (_(" console (/dev/console)"));
+#else
+  if (0 == strcmp (DEFAULT_CONSOLE, _("NULL")))
+    printf (_(" console (/dev/console)"));
+  else
+    printf (_(" console (%s)"), DEFAULT_CONSOLE);
+#endif
+  fputs  (_(", syslog"), stdout);
+  printf (_(", logfile (%s)"), DEFAULT_ERRFILE);
+
+#if defined(WITH_EXTERNAL)
+  fputs (_(", external program"), stdout);
+#endif
+
+#if defined(WITH_MESSAGE_QUEUE)
+  fputs (_(", message queue"), stdout);
+#endif
+ 
+#if defined(WITH_DATABASE)
+  fputs (_(", database"), stdout);
+#ifdef WITH_ODBC
+  fputs (_(" (odbc)"), stdout);
+#endif
+#ifdef WITH_ORACLE
+  fputs (_(" (Oracle)"), stdout);
+#endif
+#ifdef WITH_POSTGRES
+  fputs (_(" (PostgreSQL)"), stdout);
+#endif
+#ifdef WITH_MYSQL 
+  fputs (_(" (MySQL)"), stdout);
+#endif
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+  fputs (_(", server"), stdout);
+#endif
+
+#if defined(SH_WITH_MAIL)
+  fputs (_(", email"), stdout);
+#endif
+
+#ifdef HAVE_LIBPRELUDE
+#ifdef HAVE_LIBPRELUDE_8
+  fputs (_(", prelude (0.8)"), stdout);
+#else
+  fputs (_(", prelude (0.9+)"), stdout);
+#endif
+#endif
+
+  fputc ('\n', stdout);
+  return;
+}
+
+static void sh_getopt_print_options ()
+{
+  int num = 0;
+
+
+#if defined(SH_STANDALONE)
+  if (num > 0) fputc ('\n', stdout);
+  fputs (_("Standalone executable"), stdout); ++num;
+#endif
+#if defined(SH_WITH_CLIENT)
+  if (num > 0) fputc ('\n', stdout);
+  printf (_("Client executable (port %d)"), SH_DEFAULT_PORT); ++num;
+#endif
+#if defined(SH_WITH_CLIENT)
+  if (num > 0) fputc ('\n', stdout);
+  printf (_("Server executable (port %d, user %s)"), 
+	  SH_DEFAULT_PORT, DEFAULT_IDENT); 
+  ++num;
+#endif
+
+  fputs (_(", compiled-in options:"), stdout);
+
+#if defined(HAVE_EGD_RANDOM)
+  if (num > 0) fputc ('\n', stdout);
+  printf (_(" use entropy gathering daemon (%s)"), EGD_SOCKET_NAME); ++num;
+#endif
+#if defined(HAVE_UNIX_RANDOM)
+  if (num > 0) fputc ('\n', stdout);
+  fputs (_(" use unix entropy gatherer"), stdout); ++num;
+#endif
+#if defined(HAVE_URANDOM)
+  if (num > 0) fputc ('\n', stdout);
+  printf (_(" use entropy device (%s)"), NAME_OF_DEV_RANDOM); ++num;
+#endif
+
+#ifdef WITH_GPG
+  if (num > 0) fputc ('\n', stdout);
+  printf (_(" GnuPG signatures (%s)"), DEFAULT_GPG_PATH); ++num;
+#ifdef HAVE_GPG_CHECKSUM
+  if (num > 0) fputc ('\n', stdout);
+  printf (_("   -- GnuPG checksum:  %s"), GPG_HASH); ++num;
+#endif
+#ifdef USE_FINGERPRINT
+  if (num > 0) fputc ('\n', stdout);
+  printf (_("   -- Key fingerprint: %s"), SH_GPG_FP); ++num;
+#endif
+#endif
+
+#if defined(SL_DEBUG)
+  if (num > 0) fputc ('\n', stdout);
+  fputs (_(" debug build"), stdout); ++num;
+#endif
+#if defined(SCREW_IT_UP)
+  if (num > 0) fputc ('\n', stdout);
+  fputs (_(" anti-debugger"), stdout); ++num;
+#endif
+#if defined(SH_USE_XML)
+  if (num > 0) fputc ('\n', stdout);
+  fputs (_(" xml log format"), stdout); ++num;
+#endif
+#if defined(HAVE_NTIME)
+  if (num > 0) fputc ('\n', stdout);
+  fputs (_(" use time server"), stdout); ++num;
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+#if defined(USE_XATTR)
+  if (num > 0) fputc ('\n', stdout);
+  fputs (_(" check SELinux attributes"), stdout); ++num;
+#endif
+#if defined(USE_ACL)
+  if (num > 0) fputc ('\n', stdout);
+  fputs (_(" check Posix ACLs"), stdout); ++num;
+#endif
+#if defined(RELOAD_DATABASE)
+  if (num > 0) fputc ('\n', stdout);
+  fputs (_(" fetch database on reload"), stdout); ++num;
+#endif
+#endif
+
+#if defined(SH_WITH_SERVER)
+
+#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_STRUCT_CMSGCRED) && !defined(HAVE_STRUCT_FCRED) && !(defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
+  if (num > 0) fputc ('\n', stdout);
+  fputs (_(" command socket authentication: use SetSocketPassword"), stdout); 
+  ++num;
+#else
+  if (num > 0) fputc ('\n', stdout);
+  fputs (_(" command socket authentication: use SetSocketAllowUID"), stdout); 
+  ++num;
+#endif
+
+#if defined(SH_USE_LIBWRAP)
+  if (num > 0) fputc ('\n', stdout);
+  fputs (_(" support tcp wrapper"), stdout); ++num;
+#endif
+#if defined(INET_SYSLOG)
+  if (num > 0) fputc ('\n', stdout);
+  fputs (_(" support listening on 514/udp (syslog)"), stdout); ++num;
+#endif
+#endif
+
+  if (num == 0)
+    fputs (_(" none"), stdout);
+  fputc ('\n', stdout);
+  return;
+}
+
+static void sh_getopt_print_modules ()
+{
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) 
+  int num = 0;
+  
+  fputs (_("Compiled-in modules:"), stdout);
+#ifdef SH_USE_UTMP
+  if (num > 0) fputc (',', stdout);
+  fputs (_(" login/logout"), stdout); ++num;
+#endif
+#ifdef SH_USE_MOUNTS
+  if (num > 0) fputc (',', stdout);
+  fputs (_(" mount options"), stdout); ++num;
+#endif
+#ifdef SH_USE_USERFILES
+  if (num > 0) fputc (',', stdout);
+  fputs (_(" userfiles"), stdout); ++num;
+#endif
+#ifdef SH_USE_KERN
+  if (num > 0) fputc (',', stdout);
+  fputs (_(" kernel"), stdout); ++num;
+#endif
+#ifdef SH_USE_SUIDCHK
+  if (num > 0) fputc (',', stdout);
+  fputs (_(" suid"), stdout); ++num;
+#endif
+#ifdef SH_USE_PROCESSCHECK
+  if (num > 0) fputc (',', stdout);
+  fputs (_(" processes"), stdout); ++num;
+#endif
+#ifdef SH_USE_PORTCHECK
+  if (num > 0) fputc (',', stdout);
+  fputs (_(" ports"), stdout); ++num;
+#endif
+  if (num == 0)
+    fputs (_(" none"), stdout);
+  fputc ('\n', stdout);
+#endif
+  return;
+}
+
+static int sh_getopt_version (const char * dummy)
+{
+  (void) dummy;
+  fprintf (stdout,
+	   _("This is samhain (%s), "\
+	     "(c) 1999-2006 Rainer Wichmann (http://la-samhna.de).\n"),
+	   VERSION);
+  fprintf (stdout, _("This software comes with ABSOLUTELY NO WARRANTY. "));
+  fprintf (stdout, _("Use at own risk.\n\n"));
+
+  sh_getopt_print_log_facilities ();
+  sh_getopt_print_modules ();
+  sh_getopt_print_options ();
+
+  _exit (EXIT_SUCCESS);
+  /*@notreached@*/
+  return 0; /* make compilers happy */
+}
 static int sh_getopt_copyright (const char * dummy)
 {
   fprintf (stdout, 
-	   _("Copyright (C) 1999-2005 Rainer Wichmann"\
+	   _("Copyright (C) 1999-2006 Rainer Wichmann"\
 	     " (http://la-samhna.de).\n\n"));
 
@@ -378,5 +611,5 @@
   fprintf (stdout,
 	   _("This is samhain (%s), "\
-	     "(c) 1999-2005 Rainer Wichmann (http://la-samhna.de).\n"),
+	     "(c) 1999-2006 Rainer Wichmann (http://la-samhna.de).\n"),
 	   VERSION);
   fprintf (stdout, _("This software comes with ABSOLUTELY NO WARRANTY. "));
Index: trunk/src/sh_hash.c
===================================================================
--- trunk/src/sh_hash.c	(revision 75)
+++ trunk/src/sh_hash.c	(revision 76)
@@ -1460,22 +1460,23 @@
   if (sh.flag.update == S_FALSE)
     {
-      if (pushdata_stdout == S_FALSE)
-	{
-	  pushdata_fd = -1;
-	  if ( SL_ISERROR(pushdata_fd = sl_open_write(file_path('D', 'W'), SL_YESPRIV))) {
-	    SH_FREE(fullpath);
-	    SH_FREE(linkpath);
-	    sh_error_handle((-1), FIL__, __LINE__, pushdata_fd, MSG_E_ACCESS,
-			    geteuid(), file_path('D', 'W'));
-	    SL_RET0(_("sh_hash_pushdata"));
-	  }
-	  if ( SL_ISERROR(status = sl_forward(pushdata_fd))) {
-	    SH_FREE(fullpath);
-	    SH_FREE(linkpath);
-	    sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
-			    _("Fast forward failed"), _("sh_hash_pushdata"),
-			    file_path('D', 'W'));
-	    SL_RET0(_("sh_hash_pushdata"));
-	  }
+      if (pushdata_stdout == S_FALSE && pushdata_fd == -1)
+	{
+	  if ( SL_ISERROR(pushdata_fd = sl_open_write(file_path('D', 'W'), SL_YESPRIV))) 
+	    {
+	      SH_FREE(fullpath);
+	      SH_FREE(linkpath);
+	      sh_error_handle((-1), FIL__, __LINE__, pushdata_fd, MSG_E_ACCESS,
+			      geteuid(), file_path('D', 'W'));
+	      SL_RET0(_("sh_hash_pushdata"));
+	    }
+	  if ( SL_ISERROR(status = sl_forward(pushdata_fd))) 
+	    {
+	      SH_FREE(fullpath);
+	      SH_FREE(linkpath);
+	      sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
+			      _("Fast forward failed"), _("sh_hash_pushdata"),
+			      file_path('D', 'W'));
+	      SL_RET0(_("sh_hash_pushdata"));
+	    }
 	}
     }
@@ -1726,8 +1727,8 @@
     {
       sl_write      (pushdata_fd,       &p, sizeof(sh_filestore_t));
-      sl_write_line (pushdata_fd, fullpath,    sl_strlen(fullpath));
-      sl_write_line (pushdata_fd, linkpath,    sl_strlen(linkpath));
+      sl_write_line_fast (pushdata_fd, fullpath, sl_strlen(fullpath));
+      sl_write_line_fast (pushdata_fd, linkpath, sl_strlen(linkpath));
       if (attr_string)
-	sl_write_line (pushdata_fd, attr_string,    sl_strlen(attr_string));
+	sl_write_line_fast (pushdata_fd, attr_string, sl_strlen(attr_string));
     } else {
       fwrite (&p, sizeof(sh_filestore_t), 1, stdout);
@@ -1742,6 +1743,9 @@
   if ((sh.flag.update != S_TRUE) && (pushdata_stdout == S_FALSE))
     {
-      sl_close (pushdata_fd);
-      pushdata_fd = -1;
+      if (sh.flag.checkSum != SH_CHECK_INIT || (buf == NULL && fileHash == NULL))
+	{
+	  sl_close (pushdata_fd);
+	  pushdata_fd = -1;
+	}
     }
 
@@ -3413,10 +3417,88 @@
     return 0;
 }
+
+/* Always quote the string, except if it is empty. Qoute quotes by
+ * doubling them.
+ */
+char * csv_escape(const char * str)
+{
+  const  char * p = str;
+  const  char * q;
+
+  size_t size       = 0;
+  size_t flag_quote = 0;
+  int    flag_comma = 0;
+  char * new;
+  char * pnew;
+
+  if (p)
+    {
+
+      while (*p) 
+	{
+	  if (*p == ',')
+	    flag_comma = 1;
+	  else if (*p == '"')
+	    ++flag_quote;
+	  
+	  ++size; ++p;
+	}
+
+      if (sl_ok_adds(size, flag_quote))
+	size += flag_quote;      /* double each quote */
+      else
+	return NULL;
+
+      if (sl_ok_adds(size, 3))
+	size += 3; /* two quotes and terminating null */
+      else
+	return NULL;
+      
+      new = SH_ALLOC(size);
+      
+      if (flag_quote != 0)
+	{
+	  new[0] = '"';
+	  pnew = &new[1];
+	  q    = str;
+	  while (*q)
+	    {
+	      *pnew = *q;
+	      if (*pnew == '"')
+		{
+		  ++pnew; *pnew = '"';
+		}
+	      ++pnew; ++q;
+	    }
+	  *pnew = '"'; ++pnew;
+	  *pnew = '\0';
+	}
+      else
+	{
+	  if (size > 3) 
+	    {
+	      new[0] = '"';
+	      sl_strlcpy (&new[1], str, size-1);
+	      new[size-2] = '"';
+	      new[size-1] = '\0';
+	    }
+	  else
+	    {
+	      new[0] = '\0';
+	    }
+	}
+
+      return new;
+    }
+  return NULL;
+}
+
+
  
 void sh_hash_list_db_entry_full_detail (sh_file_t * p)
 {
   char * tmp;
+  char * esc;
   char   str[81];
-  size_t i;
 
   if (ListWithDelimiter == S_TRUE)
@@ -3464,28 +3546,48 @@
 
   tmp = sh_util_safe_name(p->fullpath);
-  printf( _(" %s"), tmp);
+  if (ListWithDelimiter != S_TRUE)
+    {
+      printf( _(" %s"), tmp);
+    }
+  else
+    {
+      esc = csv_escape(tmp);
+      printf( _(" %s,"), (esc != NULL) ? esc : _("(null)"));
+      if (esc)
+	SH_FREE(esc);
+    }
   SH_FREE(tmp);
-  if (ListWithDelimiter == S_TRUE)
-    putchar(',');
 
   if ('l' == p->theFile.c_mode[0])
     {
       tmp = sh_util_safe_name(p->linkpath);
-      if (ListWithDelimiter == S_TRUE)
-	printf(_(" %s"), tmp);
+      if (ListWithDelimiter != S_TRUE)
+	{
+	  printf(_(" -> %s"), tmp);
+	}
       else
-	printf(_(" -> %s"), tmp);
+	{
+	  esc = csv_escape(tmp);
+	  printf( _(" %s,"), (esc != NULL) ? esc : _("(null)"));
+	  if (esc)
+	    SH_FREE(esc);
+	}
       SH_FREE(tmp);
     }
-  if (ListWithDelimiter == S_TRUE)
-    putchar(',');
 
   if (p->attr_string)
     {
       tmp = sh_util_safe_name(p->attr_string);
-      if (ListWithDelimiter == S_TRUE) {
-	for (i = 0; i < strlen(tmp); ++i) 
-	  if (tmp[i] == ',') tmp[i] = ';';
-      }
+      if (ListWithDelimiter != S_TRUE) 
+	{
+	  printf(_(" %s"), tmp);
+	}
+      else
+	{
+	  esc = csv_escape(tmp);
+	  printf( _(" %s"), (esc != NULL) ? esc : _("(null)"));
+	  if (esc)
+	    SH_FREE(esc);
+	}
       printf(_(" %s"), tmp);
       SH_FREE(tmp);
Index: trunk/src/sh_portcheck.c
===================================================================
--- trunk/src/sh_portcheck.c	(revision 75)
+++ trunk/src/sh_portcheck.c	(revision 76)
@@ -40,4 +40,9 @@
 #include <unistd.h>
 
+#define PORTCHK_VERSION "1.0"
+
+#if defined(TEST_ONLY) || (defined(SH_USE_PORTCHECK) && (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)))
+
+
 #define PORTMAP
 #include <rpc/rpc.h>
@@ -48,9 +53,4 @@
 #include <rpc/pmap_prot.h>
 #include <netdb.h>
-
-#define PORTCHK_VERSION "1.0"
-
-#if defined(TEST_ONLY) || (defined(SH_USE_PORTCHECK) && (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)))
-
 
 /*
Index: trunk/src/sh_processcheck.c
===================================================================
--- trunk/src/sh_processcheck.c	(revision 75)
+++ trunk/src/sh_processcheck.c	(revision 76)
@@ -591,4 +591,6 @@
 }
 
+/* FIXME: add open, statvfs, sched_getaffinity
+ */
 static short sh_processes_check (pid_t pid, short res)
 {
Index: trunk/src/sh_tiger0.c
===================================================================
--- trunk/src/sh_tiger0.c	(revision 75)
+++ trunk/src/sh_tiger0.c	(revision 76)
@@ -331,12 +331,5 @@
 	sh.statistics.bytes_hashed += 64;
 	++nblocks; ncount = 0;
-	for (i = 0; i < 56; i += 4) 
-	  {
-	    bbuf[i]   = (sh_byte) '\0';
-	    bbuf[i+1] = (sh_byte) '\0';
-	    bbuf[i+2] = (sh_byte) '\0';
-	    bbuf[i+3] = (sh_byte) '\0';
-	  }
-        /* memset(bbuf, 0, 56 ); */ 
+        sl_memset(bbuf, 0, 56 ); 
       }
 
@@ -361,24 +354,6 @@
 #endif
 
-    for (i = 0; i < 64; i += 4) 
-      {
-	bbuf[i]   = (sh_byte) '\0';
-	bbuf[i+1] = (sh_byte) '\0';
-	bbuf[i+2] = (sh_byte) '\0';
-	bbuf[i+3] = (sh_byte) '\0';
-      }
-
-    bptr = buffer;
-
-    memcpy(bptr, bbuf,     64); bptr +=    64;
-    memcpy(bptr, bbuf,     64); bptr +=    64;
-    memcpy(bptr, buffer,  128); bptr +=   128;
-    memcpy(bptr, buffer,  256); bptr +=   256;
-    memcpy(bptr, buffer,  512); bptr +=   512;
-    memcpy(bptr, buffer, 1024); bptr +=  1024;
-    memcpy(bptr, buffer, 2048); bptr +=  2048;
-    memcpy(bptr, buffer, 4096); bptr +=  4096;
-    memcpy(bptr, buffer, 8192); bptr +=  8192;
-    memcpy(bptr, buffer,16384);
+    sl_memset (bbuf,   '\0', sizeof(bbuf));
+    sl_memset (buffer, '\0', sizeof(buffer));
 
     if (what == TIGER_FILE)
Index: trunk/src/sh_unix.c
===================================================================
--- trunk/src/sh_unix.c	(revision 75)
+++ trunk/src/sh_unix.c	(revision 76)
@@ -3551,14 +3551,4 @@
   SL_ENTER(_("sh_unix_test_and_lock"));
 
-  if (filename != NULL)
-    {
-      status = retry_lstat (FIL__, __LINE__, filename, &buf);
-
-      /* no logfile to lock
-       */
-      if (status < 0)
-	SL_RETURN((-1),_("sh_unix_test_and_lock"));
-    }
-
   status = retry_lstat (FIL__, __LINE__, lockfile, &buf);
 
@@ -3573,4 +3563,12 @@
 	    sh.flag.islocked = GOOD;
 	  SL_RETURN((0),_("sh_unix_test_and_lock"));
+	}
+      else
+	{
+	  sh_error_handle ((-1), FIL__, __LINE__, status,
+			   MSG_E_SUBGEN, 
+			   (filename == NULL) ? _("Cannot create PID file") : _("Cannot create lock file"),
+			   _("sh_unix_test_and_lock"));
+	  SL_RETURN((-1),_("sh_unix_test_and_lock"));
 	}
     }
@@ -3590,8 +3588,8 @@
       else
 	{
-	   sh_error_handle ((-1), FIL__, __LINE__, status,
-			    MSG_E_SUBGEN, 
-			    (filename == NULL) ? _("Cannot create PID file") : _("Cannot create lock file"),
-			    _("sh_unix_test_and_lock"));
+	  sh_error_handle ((-1), FIL__, __LINE__, status,
+			   MSG_E_SUBGEN, 
+			   (filename == NULL) ? _("Cannot create PID file") : _("Cannot create lock file"),
+			   _("sh_unix_test_and_lock"));
 	  SL_RETURN((-1),_("sh_unix_test_and_lock"));
 	}
@@ -3617,5 +3615,6 @@
       /* read the PID in the lock file
        */
-      status = sh_unix_getline (fd, line_in, sizeof(line_in));
+      status = sl_read (fd, line_in, sizeof(line_in));
+      line_in[sizeof(line_in)-1] = '\0';
 
       /* convert to numeric
@@ -3797,6 +3796,4 @@
 int sh_unix_lock (char * lockfile, char * flag)
 {
-  struct stat buf;
-  int status;
   int filed;
   int errnum;
@@ -3805,19 +3802,9 @@
   extern int get_the_fd (SL_TICKET ticket);
 
-
-  status = retry_lstat (FIL__, __LINE__, lockfile, &buf);
-  
   SL_ENTER(_("sh_unix_lock"));
 
-  if (0 == status) 
-    {
-      if (flag != NULL)
-	sh.flag.islocked       = BAD;
-      SL_RETURN((-1),_("sh_unix_lock"));
-    }
-
   sprintf (myPid, "%ld\n", (long) getpid());           /* known to fit  */
 
-  fd = sl_open_write (lockfile, SL_YESPRIV);
+  fd = sl_open_safe_rdwr (lockfile, SL_YESPRIV);       /* fails if file exists */
 
   if (!SL_ISERROR(fd))
Index: trunk/src/sh_utils.c
===================================================================
--- trunk/src/sh_utils.c	(revision 75)
+++ trunk/src/sh_utils.c	(revision 76)
@@ -268,5 +268,27 @@
   return out;
 }
-    
+
+
+char * sh_util_strdup_l (const char * str, size_t len)
+{
+  char * p = NULL;
+
+  SL_ENTER(_("sh_util_strdup_l"));
+
+  SH_VALIDATE_NE(str, NULL);
+  SH_VALIDATE_NE(len, 0);
+
+  if (sl_ok_adds (len, 1))
+    {
+      p   = SH_ALLOC (len + 1);
+      (void) sl_strlcpy (p, str, len+1);
+    }
+  else
+    {
+      safe_fatal(_("integer overflow in sh_util_strdup_l"), FIL__, __LINE__);
+    }
+  SL_RETURN( p, _("sh_util_strdup_l"));
+}
+
 char * sh_util_strdup (const char * str) 
 {
@@ -1413,10 +1435,20 @@
 
 static unsigned char sh_obscure_index[256];
+static int sh_obscure_no_check = S_FALSE;
 
 int sh_util_valid_utf8 (const unsigned char * str) 
 {
+  const int     sh_val_utf8_1 = 1;
+  const int     sh_val_utf8_2 = 2;
+  const int     sh_val_utf8_3 = 3;
+  const int     sh_val_utf8_4 = 4;
+
   size_t        len = strlen((char *)str);
   size_t        l   = 0;
-  unsigned char c;
+  int           typ = 0;
+  unsigned char c     = '\0';
+  unsigned char c2[2] = { 0x00, 0x00 };
+  unsigned char c3[3] = { 0x00, 0x00, 0x00 };
+
 
 #define SH_VAL_UTF8_1 ((c != '\0') && ((c & 0x80) == 0x00))
@@ -1425,5 +1457,6 @@
 #define SH_VAL_UTF8_4 ((c != '\0') && ((c & 0xF8) == 0xF0)) /* 1111 0xxx */
 #define SH_VAL_UTF8_N ((c != '\0') && ((c & 0xC0) == 0x80)) /* 10xx xxxx */
-#define SH_VAL_BAD    ((c == '"') || (c == '\t') || (c == '\b') || (c == '\f') || (c == '\n') || \
+#define SH_VAL_BAD    ((c == '"')  || (c == '\t') || (c == '\b') || \
+                       (c == '\f') || (c == '\n') || \
                        (c == '\r') || (c == '\v') || iscntrl((int) c) || \
                        (c != ' ' && !isgraph ((int) c)))
@@ -1435,28 +1468,57 @@
       if      (SH_VAL_UTF8_1) 
 	{
-	  if (SH_VAL_BAD && (sh_obscure_index[c] != 1)) return S_FALSE;
-	  ++l; continue; /* ASCII character */
+	  if (!(SH_VAL_BAD && (sh_obscure_index[c] != 1)))
+	    {
+	      typ = sh_val_utf8_1;
+	      ++l; continue;
+	    }
+	  else
+	    {
+	      return S_FALSE;
+	    }
 	} 
       else if (SH_VAL_UTF8_2) 
 	{ 
-	  if ((c & 0x3e) == 0x00) 
-	    return S_FALSE; /* overlong 2-byte seq. */
-	  ++l; if (l == len) return S_FALSE; c = str[l];
-	  if(!SH_VAL_UTF8_N) return S_FALSE; 
-	  ++l; continue;
-	  
+	  typ = sh_val_utf8_2;
+	  c2[0] = c;
+	  if ((c & 0x3e) != 0x00) /* !(overlong 2-byte seq.) */
+	    {
+	      ++l; 
+	      if (l != len) {
+		c = str[l];
+		if(SH_VAL_UTF8_N) {
+		  c2[1] = c;
+		  ++l; continue;
+		} 
+		else {
+		  return S_FALSE;
+		} 
+	      } 
+	      else {
+		return S_FALSE; 
+	      }
+	    }
+	  else
+	    {
+	      return S_FALSE; /* overlong 2-byte seq. */
+	    }
 	} 
       else if (SH_VAL_UTF8_3) 
 	{
+	  typ = sh_val_utf8_3;
+	  c3[0] = c;
 	  ++l; if (l == len) return S_FALSE; c = str[l];
 	  if(!SH_VAL_UTF8_N) return S_FALSE;
 	  if (((str[l-1] & 0x1F) == 0x00) && ((c & 0x60) == 0x00))
 	    return S_FALSE; /* overlong 3-byte seq. */
+	  c3[1] = c;
 	  ++l; if (l == len) return S_FALSE; c = str[l];
 	  if(!SH_VAL_UTF8_N) return S_FALSE;
+	  c3[2] = c;
 	  ++l; continue;
 	} 
       else if (SH_VAL_UTF8_4) 
 	{
+	  typ = sh_val_utf8_4;
 	  ++l; if (l == len) return S_FALSE; c = str[l];
 	  if(!SH_VAL_UTF8_N) return S_FALSE;
@@ -1471,5 +1533,53 @@
       return S_FALSE;
     }
-  return S_TRUE;
+
+  /* last character is invisible (space or else)
+   */
+  if (typ == sh_val_utf8_1)
+    { 
+      if (c != ' ')
+	return S_TRUE;
+      else
+	return S_FALSE;
+    }
+  else if (typ == sh_val_utf8_2)
+    {
+      if (c2[0] == 0xC2 && c2[1] == 0xA0) /* nbsp */
+	return S_FALSE;
+      else
+	return S_TRUE;
+    }
+  else if (typ == sh_val_utf8_3)
+    {
+      if (c3[0] == 0xE2) 
+	{
+	  if (c3[1] == 0x80 && c3[2] >= 0x80 && c3[2] <= 0x8F)
+	    return S_FALSE; /* various spaces, left-to-right, right-to-left */
+	  else if (c3[1] == 0x80 && (c3[2] == 0xA8 || c3[2] == 0xA9 || 
+				     c3[2] == 0xAD || c3[2] == 0xAF))
+	    return S_FALSE; /* line sep, para sep, zw word joiner, nnbsp */
+	  else if (c3[1] == 0x81 && (c3[2] == 0xA0 || c3[2] == 0xA1 || 
+				     c3[2] == 0x9F))
+	    return S_FALSE; /* word joiner, function app, math space */
+	  else
+	    return S_TRUE;
+	}
+      else if (c3[0] == 0xE3 && c3[1] == 0x80 && c3[2] == 0x80)
+	{
+	  return S_FALSE; /* ideographic space */
+	}
+      else if (c3[0] == 0xEF && c3[1] == 0xBB && c3[2] == 0xBF)
+	{
+	  return S_FALSE; /* zwnbsp */
+	}
+      else
+	{
+	  return S_TRUE;
+	}
+    }
+  else
+    {
+      return S_TRUE;
+    }
 }
 
@@ -1488,6 +1598,9 @@
 	  sh_obscure_index[i] = (unsigned char)1;
 	}
+      sh_obscure_no_check = S_TRUE;
       SL_RETURN(0, _("sh_util_obscure_ok"));
     }
+
+  sh_obscure_no_check = S_FALSE;
 
   for (i = 0; i < 255; ++i)
@@ -1526,5 +1639,6 @@
   SL_ENTER(_("sh_util_obscure_utf8"));
   i = sh_util_flagval(c, &(sh_obscure_check_utf8));
-
+  if (sh_obscure_check_utf8 == S_TRUE)
+    sh_obscure_no_check = S_FALSE;
   SL_RETURN(i, _("sh_util_obscure_utf8"));
 }
@@ -1536,4 +1650,5 @@
   char * safe;
   unsigned int i;
+  size_t len = 0;
 
   SL_ENTER(_("sh_util_obscurename"));
@@ -1541,36 +1656,48 @@
   ASSERT_RET((name != NULL), _("name != NULL"), (0))
 
-  if (sh_obscure_check_utf8 == S_TRUE)
-    {
-      if (S_FALSE == sh_util_valid_utf8(name))
-	{
-	  goto err;
-	}
-      SL_RETURN((0),_("sh_util_obscurename"));
-    }
-
-  /* -- Check name. --
-   */
-  while (*name != '\0') 
-    {
-      if ( (*name) >  0x7F || (*name) == '"'  || (*name) == '\t' ||
-	   (*name) == '\b' || (*name) == '\f' || 
-	   (*name) == '\n' || (*name) == '\r' ||
-	   (*name) == '\v' || iscntrl((int) *name) || 
-	   ((*name) != ' ' && !isgraph ((int) *name)) ) 
-	{
-	  i = (unsigned char) *name;
-	  if (sh_obscure_index[i] != (unsigned char)1)
+  if (sh_obscure_no_check == S_FALSE)
+    {
+      if (sh_obscure_check_utf8 != S_TRUE)
+	{
+	  /* -- Check name. --
+	   */
+	  while (*name != '\0') 
+	    {
+	      if ( (*name) >  0x7F || (*name) == '"'  || (*name) == '\t' ||
+		   (*name) == '\b' || (*name) == '\f' || 
+		   (*name) == '\n' || (*name) == '\r' ||
+		   (*name) == '\v' || iscntrl((int) *name) || 
+		   ((*name) != ' ' && !isgraph ((int) *name)) ) 
+		{
+		  i = (unsigned char) *name;
+		  if (sh_obscure_index[i] != (unsigned char)1)
+		    {
+		      goto err;
+		    }
+		}
+	      name++; ++len;
+	    }
+
+	  /* Check for blank at end of name
+	   */
+	  if ((len > 0) && (name_orig[len-1] == ' '))
 	    {
 	      goto err;
 	    }
 	}
-      name++;
-    }
-
+      else
+	{
+	  if (S_FALSE == sh_util_valid_utf8(name))
+	    {
+	      goto err;
+	    }
+	  SL_RETURN((0),_("sh_util_obscurename"));
+	}
+    }
+      
   SL_RETURN((0),_("sh_util_obscurename"));
 
  err:
-
+  
   if (flag == S_TRUE)
     {
@@ -1822,5 +1949,5 @@
 }
 
-char * sh_util_strconcat (const char * arg1, ...)
+char * sh_util_strconcat (const char * arg1, ...) 
 {
   size_t    length, l2;
Index: trunk/src/slib.c
===================================================================
--- trunk/src/slib.c	(revision 75)
+++ trunk/src/slib.c	(revision 76)
@@ -48,4 +48,6 @@
 #define FD_ZERO(p)      memset((char *)(p), '\0', sizeof(*(p)))
 #endif
+
+#define SH_REAL_SET
 
 #include "slib.h"
@@ -566,16 +568,10 @@
   
 /*
- * A memset that does not get optimized away
+ * Have memset in a different translation unit (i.e. this) to prevent 
+ * it to get optimized away
  */
 void *sl_memset(void *s, int c, size_t n)
 {
-  volatile char *p = (char *) s;
-
-  if (s != NULL)
-    {
-      while (n--)
-	*p++ = c;
-    }
-  return s;
+  return memset(s, c,n);
 }
 
@@ -870,33 +866,33 @@
   register const char * q;
 
-  if (dst == NULL)
-    return SL_ENONE;
-  if (src == NULL || *src == '\0') 
-    return SL_ENONE;
-
-  if (siz > 0) {
-
-    /* How much free space do we have ?
-     */
-    dst_end  = strlen(dst);
-    dst_free = siz - dst_end - 1;
-
-    p = &dst[dst_end];
-    q = src;
-
-    while (dst_free > 0 && *q != '\0')
-      {
-	*p++ = *q++;
-	--dst_free;
-      }
-
-    /* NULL terminate dst.
-     */
-    *p = '\0';
-
-    if (*q != '\0') 
-      return SL_ETRUNC;
-  }
-
+  if (!(dst == NULL || src == NULL || *src == '\0'))
+    {
+      if (siz > 0) 
+	{
+
+	  /* How much free space do we have ?
+	   */
+	  dst_end  = strlen(dst);
+	  dst_free = siz - dst_end - 1;
+	  
+	  p = &dst[dst_end];
+	  q = src;
+	  
+	  while (dst_free > 0 && *q != '\0')
+	    {
+	      *p++ = *q++;
+	      --dst_free;
+	    }
+	
+	  /* NULL terminate dst.
+	   */
+	  *p = '\0';
+	
+	  if (*q == '\0')
+	    return SL_ENONE;
+	  else
+	    return SL_ETRUNC;
+	}
+    }
   return SL_ENONE;
 }
@@ -917,24 +913,27 @@
   /* SL_ENTER(_("sl_strlcpy")); */
 
-  if (dst == NULL)
-    return SL_ENULL;
-  if (src == NULL)
-    { 
+  if (!((dst == NULL) || (src == NULL))) 
+    {
+      if (siz > 0) {
+	/* copy siz-1 characters 
+	 */
+	(void) strncpy(dst, src, siz-1);
+
+	/* NULL terminate
+	 */
+	dst[siz-1] = '\0';
+      }
+      return SL_ENONE;
+    }
+  else if (src == NULL)
+    {
       if (siz > 0) 
 	dst[0] = '\0';
       return SL_ENONE;
     }
-
-
-  if (siz > 0) {
-    /* copy siz-1 characters 
-     */
-    (void) strncpy(dst, src, siz-1);
-
-    /* NULL terminate
-     */
-    dst[siz-1] = '\0';
-  }
-  return SL_ENONE;
+  else
+    {
+      return SL_ENULL;
+    } 
 }
 
@@ -1574,5 +1573,5 @@
 }
 
-SL_TICKET sl_make_ticket (int fd, char * filename)
+SL_TICKET sl_make_ticket (int fd, const char * filename)
 {
   size_t    len;
@@ -2376,4 +2375,21 @@
 }
 
+int sl_write_line_fast (SL_TICKET ticket, void * msg, long nbytes)
+{
+  int  status;
+  char * p = (char *) msg;
+
+  SL_ENTER(_("sl_write_line_fast"));
+
+  /* Here nbytes is strlen(msg), so p[nbytes] is the terminating '\0'
+   * Overwrite the terminator, write out, then write back the terminator.
+   */
+  p[nbytes] = '\n';
+  status = sl_write(ticket,  msg, nbytes+1);
+  p[nbytes] = '\0';
+
+  SL_IRETURN(status, _("sl_write_line_fast"));
+}
+
 
 /* ---------------------------------------------------------------- 
@@ -2389,5 +2405,4 @@
 extern char  tf_path[MAXFILENAME];	/* Error path for trust function. */
 extern uid_t tf_euid;	                /* Space for EUID of process.     */
-
 
 char * sl_error_string(int errorcode)
@@ -2490,7 +2505,59 @@
 }
 
+#include "sh_mem.h"
+extern char * sh_util_strdup (const char * str);
+
+struct sl_trustfile_store {
+  char * filename;
+  uid_t  teuid;
+  struct sl_trustfile_store * next;
+};
+
+static struct sl_trustfile_store * sl_trusted_files = NULL;
+
+void sl_add_trusted_file(char * filename, uid_t teuid)
+{
+  struct sl_trustfile_store *new = SH_ALLOC(sizeof(struct sl_trustfile_store));
+
+  new->filename = sh_util_strdup (filename);
+  new->teuid    = teuid;
+  new->next     = sl_trusted_files;
+
+  sl_trusted_files = new;
+  return;
+}
+
+char * sl_check_trusted_file(char * filename, uid_t teuid)
+{
+  struct sl_trustfile_store *new = sl_trusted_files;
+
+  while (new)
+    {
+      if ((new->teuid == teuid) && (0 == strcmp(new->filename, filename)))
+	return filename;
+      new = new->next;
+    }
+
+  return NULL;
+}
+
+void sl_clear_trusted_file(struct sl_trustfile_store * file)
+{
+  if (file)
+    {
+      if (file->next != NULL)
+	sl_clear_trusted_file(file->next);
+      SH_FREE(file->filename);
+      SH_FREE(file);
+    }
+  return;
+}
+
 int sl_trustfile_euid(char * filename, uid_t teuid)
 {
-  long status;
+  long          status;
+  static time_t old = 0;
+  static time_t now;
+
   SL_ENTER(_("sl_trustfile_euid"));
 
@@ -2499,6 +2566,24 @@
     SL_IRETURN(SL_EBADNAME, _("sl_trustfile_euid"));
 
+  now = time(NULL);
+  if (now < (old + 300))
+    {
+      if (NULL != sl_check_trusted_file(filename, teuid))
+	{
+	  sl_strlcpy(tf_path, filename, sizeof(tf_path));
+	  SL_IRETURN(SL_ENONE, _("sl_trustfile_euid"));
+	}
+    }
+  else
+    {
+      sl_clear_trusted_file(sl_trusted_files);
+      sl_trusted_files = NULL;
+      old = now;
+    }
+
   tf_euid = teuid;
   status = sl_trustfile(filename, NULL, NULL);
+  if (status == SL_ENONE)
+    sl_add_trusted_file(filename, teuid);
   SL_IRETURN(status, _("sl_trustfile_euid"));
 }
Index: trunk/src/trustfile.c
===================================================================
--- trunk/src/trustfile.c	(revision 75)
+++ trunk/src/trustfile.c	(revision 76)
@@ -687,9 +687,10 @@
       if (retry_lstat(FIL__, __LINE__, fexp, &stbuf) < 0)
 	{
-	  (void) strcpy(tf_path, fexp);                  /* known to fit  */
+	  (void) strncpy(tf_path, fexp, sizeof(tf_path));
+	  tf_path[sizeof(tf_path)-1] = '\0';
 #ifdef TRUST_MAIN
 	  fprintf(stderr, "---------------------------------------------\n");
-	      fprintf(stderr, "trustfile: ESTAT: stat(%s) failed, maybe the file does not exist\n",
-		      fexp);
+	  fprintf(stderr, "trustfile: ESTAT: stat(%s) failed,\n", fexp);
+	  fprintf(stderr, "maybe the file does not exist\n");
 	  fprintf(stderr, "---------------------------------------------\n");
 #endif
@@ -781,5 +782,6 @@
 		  /* yes -- error 
 		   */
-		  (void) strcpy(tf_path, fexp);          /* known to fit  */
+		  (void) strncpy(tf_path, fexp, sizeof(tf_path));
+		  tf_path[sizeof(tf_path)-1] = '\0';
 #ifdef TRUST_MAIN
 		  fprintf(stderr, "---------------------------------------------\n");
@@ -850,5 +852,7 @@
 	  fprintf(stderr, "---------------------------------------------\n");
 #endif 
-	  (void) strcpy(tf_path, fexp);                  /* known to fit  */
+	  (void) strncpy(tf_path, fexp, sizeof(tf_path));
+	  tf_path[sizeof(tf_path)-1] = '\0';
+
 	  tf_baduid = (uid_t) stbuf.st_uid;
 	  SL_IRETURN(SL_EBADUID, _("sl_trustfile"));
@@ -887,5 +891,7 @@
 	  fprintf(stderr, "---------------------------------------------\n");
 #endif 
-	  (void) strcpy(tf_path, fexp);                  /* known to fit  */
+	  (void) strncpy(tf_path, fexp, sizeof(tf_path));
+	  tf_path[sizeof(tf_path)-1] = '\0';
+
 	  tf_badgid = (gid_t) stbuf.st_gid;
 	  SL_IRETURN(SL_EBADGID, _("sl_trustfile"));
@@ -909,5 +915,7 @@
 	  fprintf(stderr, "---------------------------------------------\n");
 #endif 
-	  (void) strcpy(tf_path, fexp);                  /* known to fit  */
+	  (void) strncpy(tf_path, fexp, sizeof(tf_path));
+	  tf_path[sizeof(tf_path)-1] = '\0';
+
 	  SL_IRETURN(SL_EBADOTH, _("sl_trustfile"));
 	}
@@ -932,5 +940,7 @@
    * yes, it can be trusted
    */
-  (void) strcpy(tf_path, fexp);                      /* known to fit  */
+  (void) strncpy(tf_path, fexp, sizeof(tf_path));
+  tf_path[sizeof(tf_path)-1] = '\0';
+
   SL_IRETURN(SL_ENONE, _("sl_trustfile"));
 }
Index: trunk/test/testhash.sh
===================================================================
--- trunk/test/testhash.sh	(revision 75)
+++ trunk/test/testhash.sh	(revision 76)
@@ -37,5 +37,5 @@
 	fi
 	#
-	${TOP_SRCDIR}/configure --quiet $TRUST --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file --enable-debug
+	${TOP_SRCDIR}/configure --quiet $TRUST --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file 
 	#
 	fail=0
