Index: /trunk/docs/Changelog
===================================================================
--- /trunk/docs/Changelog	(revision 2)
+++ /trunk/docs/Changelog	(revision 3)
@@ -1,6 +1,10 @@
+
 2.1.1:
+	* sh_calls.c: protect sh_calls_set_bind_addr against overriding
+	* comINSTALL, updateDB: use locking
+	* samhainadmin.pl: use locking
 	* fix typos in samhainrc.solaris (noticed by Robby Cauwerts)
 	* improve zAVLSearch (remove redundant strcmp)
-	* use AVL tree in sh_files.c instead of linked list (scales way better)
+	* use AVL tree in sh_files.c instead of linked list (better scaling)
 	* fix bug with suidcheck (no update/check in one-shot mode with
 	  schedule instead of check interval; noticed by R. Rati)
Index: /trunk/dsys/comINSTALL
===================================================================
--- /trunk/dsys/comINSTALL	(revision 2)
+++ /trunk/dsys/comINSTALL	(revision 3)
@@ -340,7 +340,24 @@
     #---------------------------------------------------------------------
 
+    instlock="${yule_conf}.lockdir";
+    trap "rm -rf ${instlock}" 1 2 13 15
+
+    if test x"$simulate" = x0
+    then
+	#
+	# A lockfile will not work, because 'root' can write anyway.
+	# However, 'mkdir' an existing directory will fail even for root
+	#
+	until (umask 222; mkdir "${instlock}") 2>/dev/null   # test & set
+	do
+	   printINFO "Waiting for lock"
+	   sleep 1
+	done
+    fi
+
     Replace=`"${yule_exec}" -P "${is_passwd}" | sed s%HOSTNAME%${host}%g`
     if test "x$Replace" = x
     then
+	rm -rf "${instlock}"
 	printFATAL "Could not execute ${yule_exec} -P ${is_passwd}."
     fi
@@ -356,5 +373,9 @@
             then
 	        Seen=y
-		echo "$Replace" >>"$tmpF" || printFATAL "Cannot write new server configuration."
+		echo "$Replace" >>"$tmpF" 
+		if [ $? -ne 0 ]; then
+			rm -rf "${instlock}"
+			printFATAL "Cannot write new server configuration."
+		fi
 	    fi
         else
@@ -363,5 +384,9 @@
 		:
 	    else
-		echo "$line" >>"$tmpF" || printFATAL "Cannot write new server configuration."
+		echo "$line" >>"$tmpF"
+		if [ $? -ne 0 ]; then
+			rm -rf "${instlock}"
+			printFATAL "Cannot write new server configuration."
+		fi
             fi
         fi
@@ -380,8 +405,27 @@
     if test x"$simulate" = x0
     then
-        ageFILE "${yule_conf}" || printFATAL "Could not backup ${yule_conf}."
-        rm -f "${yule_conf}" && { cp "$tmpF"  "${yule_conf}" || printFATAL "Could not write new server config. Backup is ${yule_conf}.1"; }
-        chown ${rcfile_owner}:${rcfile_group} "${yule_conf}" || printFATAL "Could not chown ${rcfile_owner}:${rcfile_group} ${yule_conf}"
-        chmod ${rcfile_perm} "${yule_conf}" || printFATAL "Could not chmod ${rcfile_perm} ${yule_conf}"
+        ageFILE "${yule_conf}"
+	if [ $? -ne 0 ]; then
+		rm -rf "${instlock}"
+		printFATAL "Could not backup ${yule_conf}"
+	fi
+
+        rm -f "${yule_conf}" && cp "$tmpF"  "${yule_conf}"
+	if [ $? -ne 0 ]; then
+		rm -rf "${instlock}"
+		printFATAL "Could not write new server config. Backup is ${yule_conf}.1"
+	fi
+
+        chown ${rcfile_owner}:${rcfile_group} "${yule_conf}"
+	if [ $? -ne 0 ]; then
+		rm -rf "${instlock}"
+		printFATAL "Could not chown ${rcfile_owner}:${rcfile_group} ${yule_conf}"
+	fi
+
+        chmod ${rcfile_perm} "${yule_conf}"
+	if [ $? -ne 0 ]; then
+		rm -rf "${instlock}"
+		printFATAL "Could not chmod ${rcfile_perm} ${yule_conf}"
+	fi
     else
         printINFO "Backup and update ${yule_conf}"
@@ -423,4 +467,5 @@
 	sleep 5
 	#
+	rm -rf "${instlock}"
     else
         printINFO "Reloading server configuration."
@@ -428,4 +473,5 @@
 
     printLOG "Server configuration updated and reloaded."
+
 
     #---------------------------------------------------------------------
Index: /trunk/dsys/funcINSTALL
===================================================================
--- /trunk/dsys/funcINSTALL	(revision 2)
+++ /trunk/dsys/funcINSTALL	(revision 3)
@@ -91,4 +91,18 @@
         DATABASE="${basedir}/${defdatabase}"
     fi
+
+    updlock="${DATABASE}.lockdir"
+    trap "rm -rf ${updlock}" 1 2 13 15
+
+    #
+    # A lockfile will not work, because 'root' can write anyway.
+    # However, 'mkdir' an existing directory will fail even for root
+    #
+    until (umask 222; mkdir "${updlock}") 2>/dev/null   # test & set
+    do
+       printINFO "Waiting for lock"
+       sleep 1
+    done
+
 
     IDATE=`date +"%Y-%m-%d %H:%M:%S"`
@@ -223,7 +237,16 @@
     fi
 
-    chown ${rcfile_owner}:${rcfile_group} "${DATABASE}" || printFATAL "Could not chown ${rcfile_owner}:${rcfile_group} ${DATABASE}"
-    chmod ${rcfile_perm} "${DATABASE}" || printFATAL "Could not chmod ${rcfile_perm} ${DATABASE}"
-
+    chown ${rcfile_owner}:${rcfile_group} "${DATABASE}"
+    if [ $? -ne 0 ]; then
+    	rm -rf "${instlock}"
+    	printFATAL "Could not chown ${rcfile_owner}:${rcfile_group} ${DATABASE}"
+    fi
+    chmod ${rcfile_perm} "${DATABASE}"
+    if [ $? -ne 0 ]; then
+    	rm -rf "${instlock}"
+    	printFATAL "Could not chmod ${rcfile_perm} ${DATABASE}"
+    fi
+
+    rm -rf "${updlock}"
 }
 
Index: /trunk/man/samhain.8
===================================================================
--- /trunk/man/samhain.8	(revision 2)
+++ /trunk/man/samhain.8	(revision 3)
@@ -14,5 +14,5 @@
 {
 .I \-t update|\-\-set\-checksum\-test=update
-} [\-r DEPTH|\-\-recursion=DEPTH] [log-options]
+} [\-D | \-\-daemon | \-\-foreground] [\-\-forever] [\-r DEPTH|\-\-recursion=DEPTH] [log-options]
 
 .B samhain 
@@ -195,4 +195,20 @@
 [\-r DEPTH|\-\-recursion=DEPTH]
 Set the (global) recursion depth.
+.TP
+[\-D|\-\-daemon]
+Run as daemon. File checks are performed as specified by the timing
+options in the configuration file. Updates are saved after each file check.
+.TP
+[\-\-foreground]
+Run in the foreground. This will cause samhain to exit after the update,
+unless the option
+.I "\-\-forever"
+is used.
+.TP
+[\-\-forever]
+If not running as daemon, do not exit after finishing the update, but
+loop forever, and perform checks with corresponding database updates
+according to the timing options in the
+configuration file.
 
 .PP
Index: /trunk/scripts/samhainadmin.pl.in
===================================================================
--- /trunk/scripts/samhainadmin.pl.in	(revision 2)
+++ /trunk/scripts/samhainadmin.pl.in	(revision 3)
@@ -23,7 +23,9 @@
 use Getopt::Long;
 use File::Basename;
+use File::Copy;
 use File::stat;
 use File::Temp qw/ tempfile tempdir unlink0 /;
 use IO::Handle;
+use Fcntl qw(:DEFAULT :flock);
 
 File::Temp->safe_level( File::Temp::HIGH );
@@ -36,4 +38,5 @@
 my $return_from_sign = 0;
 my $no_print_examine = 0;
+my $no_remove_lock   = 0;
 my $base = basename($0);
 
@@ -42,4 +45,7 @@
 my $daemon   = "@sbindir@/@install_name@";
 my $gpg      = "@mygpg@";
+
+$cfgfile  =~ s/^REQ_FROM_SERVER//;
+$datafile =~ s/^REQ_FROM_SERVER//;
 
 $gpg = "gpg" if ($gpg eq "");
@@ -186,5 +192,5 @@
 
     my $dir = tempdir( CLEANUP => 1 );
-    $filename = $dir . "/exa_jhfdbilw";
+    $filename = $dir . "/exa_jhfdbilw." . $$;
     open $fh, ">$filename" or die "Cannot open $filename";
     autoflush $fh 1;
@@ -281,6 +287,7 @@
     open FH, "<$file1" or die "Cannot open file $file1 for read: $!";
     if (!($file1 =~ /^\-$/)) {
+	flock(FH, LOCK_EX) unless ($no_remove_lock == 1);
 	my $dir = tempdir( CLEANUP => 1 ) or die "Tempdir failed";
-	$filename = $dir . "/rem_iqegBCQb";
+	$filename = $dir . "/rem_iqegBCQb." . $$;
 	open $fh, ">$filename" or die "Cannot open $filename";
 	$stats = stat($file1);
@@ -313,9 +320,10 @@
     }
     if (!($file1 =~ /^\-$/)) {
-	my $command = "cp $filename $file1";
-	system ($command) == 0
-	    or die "system $command failed: $?";
+	copy("$filename", "$file1") 
+	    or die "Copy $filename to $file1 failed: $!";
 	chmod $stats->mode, $file1;
 	chown $stats->uid, $stats->gid, $file1;
+	flock(FH, LOCK_UN) unless ($no_remove_lock == 1);
+	close FH;
     }
     unlink0( $fh, $filename ) or die "Cannot unlink $filename safely";
@@ -386,5 +394,5 @@
     if ($file1 =~ /^\-$/) {
 	my $dir = tempdir( CLEANUP => 1 ) or die "Tempdir failed";
-	$filename1 = $dir . "/sig_vs8827sd";
+	$filename1 = $dir . "/sig_vs8827sd." . $$;
 	open $fh1, ">$filename1" or die "Cannot open $filename1";
 	$flag1 = 1;
@@ -419,10 +427,14 @@
 	$fileout = '-';
     } else {
+	open (LOCKFILE, "<$file1") or die "Cannot open $file1: $!";
+	flock(LOCKFILE, LOCK_EX);
 	$no_print_examine = 1;
+	$no_remove_lock   = 1;
 	if (examine() < 2) {
 	    remove();
 	}
 	$fileout = $file1 . ".asc";
-	$stats   = stat($file1);
+	$stats   = stat($file1)
+	    or die "No file $file1: $!";
     }
 
@@ -446,8 +458,9 @@
 	die ("Signed file is smaller than unsigned file") 
 	    unless ($st_new->size > $st_old->size);
-	system ("mv $fileout $file2") == 0
-	    or die "system mv $fileout $file2 failed: $?";
+	move("$fileout", "$file2") 
+	    or die "Move $fileout to $file2 failed: $!";
 	chmod $stats->mode, $file2;
 	chown $stats->uid, $stats->gid, $file2;
+	flock(LOCKFILE, LOCK_UN);
     }
 
Index: /trunk/src/sh_calls.c
===================================================================
--- /trunk/src/sh_calls.c	(revision 2)
+++ /trunk/src/sh_calls.c	(revision 3)
@@ -138,4 +138,12 @@
 int sh_calls_set_bind_addr (char * str)
 {
+  static int reject = 0;
+
+  if (reject == 1)
+    return (0);
+
+  if (sh.flag.opts == S_TRUE)  
+    reject = 1;
+
   if (0 == /*@-unrecog@*/inet_aton(str, &bind_addr)/*@+unrecog@*/) 
     {
Index: /trunk/src/sh_database.c
===================================================================
--- /trunk/src/sh_database.c	(revision 2)
+++ /trunk/src/sh_database.c	(revision 3)
@@ -38,4 +38,6 @@
 #include "sh_error.h"
 #include "sh_utils.h"
+
+extern int safe_logger (int signal, int method, pid_t thepid);
 
 #undef  FIL__
@@ -1009,5 +1011,5 @@
 {
   int               status = 0;
-  char            * p;
+  const char      * p;
   static MYSQL    * db_conn = NULL;
   static SH_TIMEOUT sh_timer = { 0, 3600, S_TRUE };
@@ -1447,4 +1449,8 @@
 	  retv = S_FALSE;
 	}
+      else if (*p == '\"' && escp == 0)
+	{
+	  retv = S_FALSE;
+	}
       else 
 	{
@@ -1453,4 +1459,6 @@
       ++p;
     }
+  if (escp == 1) 
+    retv = S_FALSE;
   return retv;
 }
@@ -1546,4 +1554,7 @@
 
 	      if (S_FALSE == is_escaped(&p[j+2])) {
+		sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+				_("Message not properly escaped"), 
+				_("sh_database_parse"));
 		SL_RETURN(NULL, _("sh_database_parse"));
 	      }
Index: /trunk/src/sh_forward.c
===================================================================
--- /trunk/src/sh_forward.c	(revision 2)
+++ /trunk/src/sh_forward.c	(revision 3)
@@ -1944,4 +1944,6 @@
   SL_RET0(_("free_client"));
 }
+
+extern int safe_logger (int signal, int method, pid_t thepid);
 
 int sh_forward_register_client (char * str)
Index: /trunk/src/sh_hash.c
===================================================================
--- /trunk/src/sh_hash.c	(revision 2)
+++ /trunk/src/sh_hash.c	(revision 3)
@@ -653,4 +653,5 @@
 {
   sh_file_t * p;
+  sh_file_t * q;
   int key;
 
@@ -674,7 +675,10 @@
 	      strlen(s->fullpath) == strlen(p->fullpath))
 	    {
-	      SH_FREE(s->fullpath);
-	      if(s->linkpath)
-		SH_FREE(s->linkpath);
+	      q = p->next;
+	      SH_FREE(p->fullpath);
+	      if(p->linkpath)
+		SH_FREE(p->linkpath);
+	      memcpy(p, s, sizeof(sh_file_t));
+	      p->next = q;
 	      SH_FREE(s);
 	      s = NULL;
Index: /trunk/src/sh_kern.c
===================================================================
--- /trunk/src/sh_kern.c	(revision 2)
+++ /trunk/src/sh_kern.c	(revision 3)
@@ -859,5 +859,5 @@
    * Stored(old) is system_call_code[]
    */
-  if (sh.flag.checkSum == SH_CHECK_INIT)
+  if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
     {
       store0 = 0; store1 = 0; store2 = 0;
@@ -935,5 +935,5 @@
    * Stored(old) is sh_syscalls[] array.
    */
-  if (sh.flag.checkSum == SH_CHECK_INIT)
+  if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
     {
       for (i = 0; i < SH_MAXCALLS; ++i) 
@@ -1125,5 +1125,5 @@
   if (ShKernIDT == S_TRUE)
     {
-      if (sh.flag.checkSum == SH_CHECK_INIT)
+      if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
 	{
 	  datasize = 8;
@@ -1447,5 +1447,5 @@
    * Stored(old) is sh_syscalls[] array.
    */
-  if (sh.flag.checkSum == SH_CHECK_INIT)
+  if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
     {
       for (i = 0; i < SH_MAXCALLS; ++i) 
