Index: trunk/Makefile.in
===================================================================
--- trunk/Makefile.in	(revision 309)
+++ trunk/Makefile.in	(revision 310)
@@ -125,5 +125,6 @@
 	sh_processcheck.h sh_portcheck.h sh_pthread.h sh_string.h \
 	sh_log_check.h sh_log_evalrule.h sh_log_correlate.h \
-	sh_log_mark.h sh_log_repeat.h sh_inotify.h sh_registry.h sh_ipvx.h
+	sh_log_mark.h sh_log_repeat.h sh_inotify.h sh_registry.h sh_ipvx.h \
+	sh_restrict.h
 
 
@@ -167,5 +168,5 @@
 	$(srcsrc)/sh_inotify.c $(srcsrc)/sh_log_repeat.c \
 	$(srcsrc)/sh_audit.c $(srcsrc)/sh_registry.c \
-	$(srcsrc)/sh_ipvx.c \
+	$(srcsrc)/sh_ipvx.c $(srcsrc)/sh_restrict.c $(srcsrc)/sh_filetype.c \
 	$(srcsrc)/t-test1.c
 
@@ -187,5 +188,5 @@
 	sh_log_correlate.o sh_log_mark.o sh_log_repeat.o \
 	sh_pthread.o sh_string.o sh_inotify.o dnmalloc.o \
-	sh_audit.o sh_registry.o sh_ipvx.o
+	sh_audit.o sh_registry.o sh_ipvx.o sh_restrict.o sh_filetype.o
 
 KERN = kern_head.h kern_head.c
@@ -1702,11 +1703,11 @@
 
 
-samhain.o: $(srcsrc)/samhain.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_files.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_getopt.h $(srcinc)/sh_readconf.h $(srcinc)/sh_hash.h $(srcinc)/sh_nmail.h $(srcinc)/sh_tiger.h $(srcinc)/sh_gpg.h $(srcinc)/sh_mem.h $(srcinc)/sh_forward.h $(srcinc)/sh_tools.h $(srcinc)/sh_hash.h $(srcinc)/sh_extern.h $(srcinc)/sh_modules.h $(srcinc)/sh_ignore.h $(srcinc)/sh_prelink.h sh_MK.h $(srcinc)/sh_schedule.h 
-sh_unix.o: $(srcsrc)/sh_unix.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_mem.h $(srcinc)/sh_hash.h $(srcinc)/sh_tools.h $(srcinc)/sh_ipvx.h $(srcinc)/sh_tiger.h $(srcinc)/sh_prelink.h $(srcinc)/sh_pthread.h $(srcinc)/sh_static.h $(srcinc)/sh_prelude.h $(srcinc)/zAVLTree.h $(srcinc)/sh_ignore.h 
+samhain.o: $(srcsrc)/samhain.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_files.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_getopt.h $(srcinc)/sh_readconf.h $(srcinc)/sh_hash.h $(srcinc)/sh_restrict.h $(srcinc)/sh_nmail.h $(srcinc)/sh_tiger.h $(srcinc)/sh_gpg.h $(srcinc)/sh_mem.h $(srcinc)/sh_forward.h $(srcinc)/sh_tools.h $(srcinc)/sh_hash.h $(srcinc)/sh_extern.h $(srcinc)/sh_modules.h $(srcinc)/sh_ignore.h $(srcinc)/sh_prelink.h sh_MK.h $(srcinc)/sh_schedule.h 
+sh_unix.o: $(srcsrc)/sh_unix.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_mem.h $(srcinc)/sh_hash.h $(srcinc)/sh_tools.h $(srcinc)/sh_restrict.h $(srcinc)/sh_ipvx.h $(srcinc)/sh_tiger.h $(srcinc)/sh_prelink.h $(srcinc)/sh_pthread.h $(srcinc)/sh_static.h $(srcinc)/sh_prelude.h $(srcinc)/zAVLTree.h $(srcinc)/sh_ignore.h 
 sh_utils.o: $(srcsrc)/sh_utils.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_tiger.h $(srcinc)/sh_entropy.h $(srcinc)/sh_pthread.h 
 sh_error.o: $(srcsrc)/sh_error.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_cat.h $(srcinc)/sh_database.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_tiger.h $(srcinc)/sh_nmail.h $(srcinc)/sh_forward.h $(srcinc)/sh_prelude.h $(srcinc)/sh_pthread.h $(srcinc)/sh_tools.h $(srcinc)/sh_extern.h 
 sh_files.o: $(srcsrc)/sh_files.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_files.h $(srcinc)/sh_tiger.h $(srcinc)/sh_hash.h $(srcinc)/sh_ignore.h $(srcinc)/zAVLTree.h $(srcinc)/CuTest.h 
 sh_getopt.o: $(srcsrc)/sh_getopt.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_getopt.h $(srcinc)/sh_files.h $(srcinc)/sh_utils.h $(srcinc)/sh_mail.h $(srcinc)/sh_forward.h $(srcinc)/sh_hash.h $(srcinc)/sh_extern.h 
-sh_readconf.o: $(srcsrc)/sh_readconf.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_calls.h $(srcinc)/sh_error.h $(srcinc)/sh_extern.h $(srcinc)/sh_files.h $(srcinc)/sh_forward.h $(srcinc)/sh_gpg.h $(srcinc)/sh_hash.h $(srcinc)/sh_ignore.h $(srcinc)/sh_database.h $(srcinc)/sh_mail.h $(srcinc)/sh_modules.h $(srcinc)/sh_nmail.h $(srcinc)/sh_prelink.h $(srcinc)/sh_prelude.h $(srcinc)/sh_tiger.h $(srcinc)/sh_tools.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h 
+sh_readconf.o: $(srcsrc)/sh_readconf.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_calls.h $(srcinc)/sh_error.h $(srcinc)/sh_extern.h $(srcinc)/sh_files.h $(srcinc)/sh_forward.h $(srcinc)/sh_gpg.h $(srcinc)/sh_hash.h $(srcinc)/sh_ignore.h $(srcinc)/sh_database.h $(srcinc)/sh_mail.h $(srcinc)/sh_modules.h $(srcinc)/sh_nmail.h $(srcinc)/sh_prelink.h $(srcinc)/sh_prelude.h $(srcinc)/sh_tiger.h $(srcinc)/sh_tools.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_restrict.h 
 sh_tiger0.o: $(srcsrc)/sh_tiger0.c Makefile config_xor.h $(srcinc)/sh_tiger.h $(srcinc)/sh_unix.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_pthread.h $(srcinc)/sh_string.h 
 sh_tiger1.o: $(srcsrc)/sh_tiger1.c Makefile config_xor.h 
@@ -1785,2 +1786,4 @@
 sh_registry.o: $(srcsrc)/sh_registry.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_modules.h $(srcinc)/sh_hash.h $(srcinc)/sh_tiger.h 
 sh_ipvx.o: $(srcsrc)/sh_ipvx.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_ipvx.h 
+sh_restrict.o: $(srcsrc)/sh_restrict.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_error_min.h $(srcinc)/sh_string.h $(srcinc)/sh_utils.h $(srcinc)/sh_restrict.h $(srcinc)/CuTest.h 
+sh_filetype.o: $(srcsrc)/sh_filetype.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_error_min.h $(srcinc)/sh_utils.h 
Index: trunk/configure.ac
===================================================================
--- trunk/configure.ac	(revision 309)
+++ trunk/configure.ac	(revision 310)
@@ -12,5 +12,5 @@
 dnl start
 dnl
-AM_INIT_AUTOMAKE(samhain, 2.8.1)
+AM_INIT_AUTOMAKE(samhain, 2.8.2)
 AC_DEFINE([SAMHAIN], 1, [Application is samhain])
 AC_CANONICAL_HOST
Index: trunk/depend.dep
===================================================================
--- trunk/depend.dep	(revision 309)
+++ trunk/depend.dep	(revision 310)
@@ -1,11 +1,11 @@
 
 # DO NOT DELETE THIS LINE
-samhain.o: $(srcsrc)/samhain.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_files.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_getopt.h $(srcinc)/sh_readconf.h $(srcinc)/sh_hash.h $(srcinc)/sh_nmail.h $(srcinc)/sh_tiger.h $(srcinc)/sh_gpg.h $(srcinc)/sh_mem.h $(srcinc)/sh_forward.h $(srcinc)/sh_tools.h $(srcinc)/sh_hash.h $(srcinc)/sh_extern.h $(srcinc)/sh_modules.h $(srcinc)/sh_ignore.h $(srcinc)/sh_prelink.h sh_MK.h $(srcinc)/sh_schedule.h 
-sh_unix.o: $(srcsrc)/sh_unix.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_mem.h $(srcinc)/sh_hash.h $(srcinc)/sh_tools.h $(srcinc)/sh_ipvx.h $(srcinc)/sh_tiger.h $(srcinc)/sh_prelink.h $(srcinc)/sh_pthread.h $(srcinc)/sh_static.h $(srcinc)/sh_prelude.h $(srcinc)/zAVLTree.h $(srcinc)/sh_ignore.h 
+samhain.o: $(srcsrc)/samhain.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_files.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_getopt.h $(srcinc)/sh_readconf.h $(srcinc)/sh_hash.h $(srcinc)/sh_restrict.h $(srcinc)/sh_nmail.h $(srcinc)/sh_tiger.h $(srcinc)/sh_gpg.h $(srcinc)/sh_mem.h $(srcinc)/sh_forward.h $(srcinc)/sh_tools.h $(srcinc)/sh_hash.h $(srcinc)/sh_extern.h $(srcinc)/sh_modules.h $(srcinc)/sh_ignore.h $(srcinc)/sh_prelink.h sh_MK.h $(srcinc)/sh_schedule.h 
+sh_unix.o: $(srcsrc)/sh_unix.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_mem.h $(srcinc)/sh_hash.h $(srcinc)/sh_tools.h $(srcinc)/sh_restrict.h $(srcinc)/sh_ipvx.h $(srcinc)/sh_tiger.h $(srcinc)/sh_prelink.h $(srcinc)/sh_pthread.h $(srcinc)/sh_static.h $(srcinc)/sh_prelude.h $(srcinc)/zAVLTree.h $(srcinc)/sh_ignore.h 
 sh_utils.o: $(srcsrc)/sh_utils.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_tiger.h $(srcinc)/sh_entropy.h $(srcinc)/sh_pthread.h 
 sh_error.o: $(srcsrc)/sh_error.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_cat.h $(srcinc)/sh_database.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_tiger.h $(srcinc)/sh_nmail.h $(srcinc)/sh_forward.h $(srcinc)/sh_prelude.h $(srcinc)/sh_pthread.h $(srcinc)/sh_tools.h $(srcinc)/sh_extern.h 
 sh_files.o: $(srcsrc)/sh_files.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_files.h $(srcinc)/sh_tiger.h $(srcinc)/sh_hash.h $(srcinc)/sh_ignore.h $(srcinc)/zAVLTree.h $(srcinc)/CuTest.h 
 sh_getopt.o: $(srcsrc)/sh_getopt.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_getopt.h $(srcinc)/sh_files.h $(srcinc)/sh_utils.h $(srcinc)/sh_mail.h $(srcinc)/sh_forward.h $(srcinc)/sh_hash.h $(srcinc)/sh_extern.h 
-sh_readconf.o: $(srcsrc)/sh_readconf.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_calls.h $(srcinc)/sh_error.h $(srcinc)/sh_extern.h $(srcinc)/sh_files.h $(srcinc)/sh_forward.h $(srcinc)/sh_gpg.h $(srcinc)/sh_hash.h $(srcinc)/sh_ignore.h $(srcinc)/sh_database.h $(srcinc)/sh_mail.h $(srcinc)/sh_modules.h $(srcinc)/sh_nmail.h $(srcinc)/sh_prelink.h $(srcinc)/sh_prelude.h $(srcinc)/sh_tiger.h $(srcinc)/sh_tools.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h 
+sh_readconf.o: $(srcsrc)/sh_readconf.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_calls.h $(srcinc)/sh_error.h $(srcinc)/sh_extern.h $(srcinc)/sh_files.h $(srcinc)/sh_forward.h $(srcinc)/sh_gpg.h $(srcinc)/sh_hash.h $(srcinc)/sh_ignore.h $(srcinc)/sh_database.h $(srcinc)/sh_mail.h $(srcinc)/sh_modules.h $(srcinc)/sh_nmail.h $(srcinc)/sh_prelink.h $(srcinc)/sh_prelude.h $(srcinc)/sh_tiger.h $(srcinc)/sh_tools.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_restrict.h 
 sh_tiger0.o: $(srcsrc)/sh_tiger0.c Makefile config_xor.h $(srcinc)/sh_tiger.h $(srcinc)/sh_unix.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_pthread.h $(srcinc)/sh_string.h 
 sh_tiger1.o: $(srcsrc)/sh_tiger1.c Makefile config_xor.h 
@@ -86,2 +86,4 @@
 sh_registry.o: $(srcsrc)/sh_registry.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_modules.h $(srcinc)/sh_hash.h $(srcinc)/sh_tiger.h 
 sh_ipvx.o: $(srcsrc)/sh_ipvx.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_ipvx.h 
+sh_restrict.o: $(srcsrc)/sh_restrict.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_error_min.h $(srcinc)/sh_string.h $(srcinc)/sh_utils.h $(srcinc)/sh_restrict.h $(srcinc)/CuTest.h 
+sh_filetype.o: $(srcsrc)/sh_filetype.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_error_min.h $(srcinc)/sh_utils.h 
Index: trunk/depend.sum
===================================================================
--- trunk/depend.sum	(revision 309)
+++ trunk/depend.sum	(revision 310)
@@ -1,1 +1,1 @@
-2854740038
+2589357922
Index: trunk/docs/Changelog
===================================================================
--- trunk/docs/Changelog	(revision 309)
+++ trunk/docs/Changelog	(revision 310)
@@ -1,5 +1,8 @@
 2.8.2:
-	* Fix hardcoded path for temp directory in deploxment scripts
+	* add function to skip checksumming
+	* Fix missing check for recursion depth >= 0 if not IgnoreAll
+	* Fix hardcoded path for temp directory in deployment scripts
 	* Fix bad compile on CentOS 4.8 with gcc 4.1.2
+	* Fix minor bug in check_samhain.pl (pointed out by J.-S. Eon long ago)
 
 2.8.1:
Index: trunk/include/sh_restrict.h
===================================================================
--- trunk/include/sh_restrict.h	(revision 310)
+++ trunk/include/sh_restrict.h	(revision 310)
@@ -0,0 +1,9 @@
+#ifndef SH_RESTRICT_H
+#define SH_RESTRICT_H
+
+int  sh_restrict_define(const char * str);
+void sh_restrict_purge ();
+int  sh_restrict_this(const char * path, UINT64 size, UINT64 perm, SL_TICKET fh);
+int  sh_restrict_add_ftype(const char * str);
+
+#endif
Index: trunk/scripts/check_samhain.pl.in
===================================================================
--- trunk/scripts/check_samhain.pl.in	(revision 309)
+++ trunk/scripts/check_samhain.pl.in	(revision 310)
@@ -28,5 +28,5 @@
 use Getopt::Long;
 use vars qw($PROGNAME $SAMHAIN $opt_V $opt_h $opt_v $verbose $opt_w $opt_c $opt_t $status $msg $state $retval);
-use lib  utils.pm;
+use lib  "utils.pm";
 use utils qw(%ERRORS &print_revision);
 
Index: trunk/src/samhain.c
===================================================================
--- trunk/src/samhain.c	(revision 309)
+++ trunk/src/samhain.c	(revision 310)
@@ -71,4 +71,5 @@
 #include "sh_readconf.h"
 #include "sh_hash.h"
+#include "sh_restrict.h"
 
 #include "sh_nmail.h"
@@ -1786,4 +1787,5 @@
 #endif
 #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+	      sh_restrict_purge ();
 
 
Index: trunk/src/sh_files.c
===================================================================
--- trunk/src/sh_files.c	(revision 309)
+++ trunk/src/sh_files.c	(revision 310)
@@ -1147,5 +1147,5 @@
   p = sh_files_C_dequote(p, &len);
   if (!p || len == 0)
-    SL_RETURN((-1), _("sh_files_pushdir"));
+    SL_RETURN((-1), _("sh_files_pushfile"));
 
   if (len >= PATH_MAX) 
@@ -1544,6 +1544,17 @@
   
 
-  if (rdepth < (-1) || tail == p || rdepth > 99)
-    rdepth = (-2);
+  if (tail == p)
+    {
+      /* Setting to an invalid number will force MaxRecursionLevel,
+       * see sh_files_setrec_int()
+       */
+      rdepth = (-2);
+    }
+  else if ( (rdepth < (-1) || rdepth > 99) || 
+	    ((rdepth == (-1)) && (class != SH_LEVEL_ALLIGNORE)) )
+    {
+      SH_FREE(p);
+      SL_RETURN((-1), _("sh_files_pushdir"));
+    }
 
   len = sl_strlen(tail);
Index: trunk/src/sh_filetype.c
===================================================================
--- trunk/src/sh_filetype.c	(revision 310)
+++ trunk/src/sh_filetype.c	(revision 310)
@@ -0,0 +1,634 @@
+/* SAMHAIN file system integrity testing                                   */
+/* Copyright (C) 2011 Rainer Wichmann                                      */
+/*                                                                         */
+/*  This program is free software; you can redistribute it                 */
+/*  and/or modify                                                          */
+/*  it under the terms of the GNU General Public License as                */
+/*  published by                                                           */
+/*  the Free Software Foundation; either version 2 of the License, or      */
+/*  (at your option) any later version.                                    */
+/*                                                                         */
+/*  This program is distributed in the hope that it will be useful,        */
+/*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
+/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
+/*  GNU General Public License for more details.                           */
+/*                                                                         */
+/*  You should have received a copy of the GNU General Public License      */
+/*  along with this program; if not, write to the Free Software            */
+/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
+
+#include "config_xor.h"
+
+#ifndef NULL
+#if !defined(__cplusplus)
+#define NULL ((void*)0)
+#else
+#define NULL (0)
+#endif
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+#include "samhain.h"
+#include "sh_mem.h"
+#include "sh_error_min.h"
+#include "sh_utils.h"
+
+#define FIL__ _("sh_filetype.c")
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+/* #define SH_FILE_MAIN 1 */
+#ifdef  SH_FILE_MAIN
+#include <stdio.h>
+#define _(a) a
+#define N_(a) a
+#define sl_strlcpy strncpy
+#endif
+
+#define SH_FTYPE_MAX 32
+
+/* List of filetype description, in the format: 
+ * offset : type(0=text, 1=binary) : length(if binary) : G1 : G2 : G3 : Name : Teststring
+ *
+ * This list is mostly taken from the 'filetype' library by Paul L Daniels.
+ *
+ * Copyright (c) 2003, PLD
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or 
+ * without modification, are permitted provided that the 
+ * following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above 
+ *  copyright notice, this list of conditions and the following 
+ *  disclaimer.
+ *  
+ *  * Redistributions in binary form must reproduce the above 
+ *  copyright notice, this list of conditions and the following 
+ *  disclaimer in the documentation and/or other materials provided 
+ *  with the distribution.
+ *  
+ *  * Neither the name of the PLD nor the names of its contributors 
+ *  may be used to endorse or promote products derived from this software 
+ *  without specific prior written permission.
+ *  
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+ *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
+ *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+char * sh_ftype_list[] = {
+
+  N_("6:0:0:IMAGE:COMPRESSED:JPG:JFIF Jpeg:JFIF"),
+  N_("0:0:0:IMAGE:COMPRESSED:PNG:PNG:=89PNG=0d=0a=1a=0a"),
+  N_("0:0:0:IMAGE:COMPRESSED:JPG:JFIF Jpeg:=FF=D8=FF"),
+  N_("0:0:0:IMAGE:COMPRESSED:GIF:GIF:GIF97a"),
+  N_("0:0:0:IMAGE:COMPRESSED:GIF:GIF:GIF89a"),
+  N_("0:0:0:IMAGE:COMPRESSED:GIF:GIF:GIF87a"),
+  N_("0:1:4:IMAGE:COMPRESSED:TIFF:TIFF-LE:II=2A=00"),
+  N_("0:1:4:IMAGE:COMPRESSED:TIFF:TIFF-BE:MM=00=2A"),
+  N_("0:1:2:IMAGE:COMPRESSED:PCX:PCX25:=0A=00"),
+  N_("0:1:2:IMAGE:COMPRESSED:PCX:PCX28WP:=0A=02"),
+  N_("0:1:2:IMAGE:COMPRESSED:PCX:PCX28NP:=0A=03"),
+  N_("0:1:2:IMAGE:COMPRESSED:PCX:PCX30:=0A=05"),
+  N_("0:0:0:IMAGE:RAW:BMP:Bitmap:BM"),
+  N_("0:0:0:IMAGE:RAW:XPM:XPM:/* XPM */"),
+  N_("0:0:0:IMAGE:SPECIAL:AUTOCAD:DWT:AC=31=30=31"),
+  N_("0:0:0:IMAGE:SPECIAL:AUTOCAD:DWF:(DWF V"),
+  N_("0:0:0:IMAGE:SPECIAL:AUTOCAD:WMF:=D7=CD=C6=9A"),
+  N_("0:0:0:IMAGE:SPECIAL:AUTOCAD:DWG:AC10"),
+  N_("8:0:0:IMAGE:SPECIAL:COREL:CorelDraw:CDR"),
+  N_("0:0:0:IMAGE:SPECIAL:FITS:Fits file:SIMPLE=20=20="),
+  N_("1536:0:0:IMAGE:SPECIAL:VISIO:VisioDraw:Visio"),
+  N_("128:0:0:IMAGE:SPECIAL:DICM:DICOM medical:DICM"),
+  N_("0:0:0:IMAGE:SPECIAL:PHS:Photoshop:8BPS"),
+  N_("0:0:0:IMAGE:SPECIAL:XCF:Gimp XCF:gimp xcf"),
+  N_("0:0:0:MOVIE:COMPRESSED:RIFF:RIFF/AVI Movie:RIFF"),
+  N_("0:0:0:MOVIE:RAW:MOV:SGI Movie:MOVI:.mov SGI Movie"),
+  N_("0:1:4:MOVIE:COMPRESSED:MPG:Mpeg 2:=00=00=01=BA"),
+  N_("0:1:4:MOVIE:COMPRESSED:MPG:Mpeg 2:=00=00=01=B3"),
+  N_("4:0:0:MOVIE:COMPRESSED:QT:QuickTime:moov"),
+  N_("4:0:0:MOVIE:COMPRESSED:QT:QuickTime:mdat"),
+  N_("36:0:0:MOVIE:COMPRESSED:QT:QuickTime:moov"),
+  N_("36:0:0:MOVIE:COMPRESSED:QT:QuickTime:mdat"),
+  N_("68:0:0:MOVIE:COMPRESSED:QT:QuickTime:moov"),
+  N_("68:0:0:MOVIE:COMPRESSED:QT:QuickTime:mdat"),
+  N_("0:1:3:MOVIE:COMPRESSED:FLI:FLIC animation:=00=11=AF"),
+  N_("0:0:0:MOVIE:COMPRESSED:FLASH:Flash data:FWS"),
+  N_("0:0:0:MOVIE:COMPRESSED:FLASH:Flash data:CWS"),
+  N_("0:0:0:MOVIE:COMPRESSED:FLASH:Flash video:FLV"),
+  N_("0:0:0:MOVIE:COMPRESSED:WMV:WMV:=30=26=B2=75=8E=66=CF"),
+  N_("0:0:0:AUDIO:RAW:SND:Sun Audio:.snd"),
+  N_("0:0:0:AUDIO:RAW:EMOD:EMOD:Mod"),
+  N_("1080:0:0:AUDIO:RAW:MOD:SoundTracker (.M.K):.M.K"),
+  N_("1080:0:0:AUDIO:RAW:MOD:SoundTracker (M.K.):M.K."),
+  N_("1080:0:0:AUDIO:RAW:MOD:NoiseTracker:N.T."),
+  N_("1080:0:0:AUDIO:RAW:MOD:SoundTracker (M!K!):M!K!"),
+  N_("1080:0:0:AUDIO:RAW:MOD:SoundTracker (M&K!):M&K!"),
+  N_("8:0:0:AUDIO:RAW:WAVE:Wave:WAVE"),
+  N_("0:1:4:AUDIO:RAW:DEC:DEC-Audio:=00=64=73=2E"),
+  N_("0:0:0:AUDIO:STANDARD:MIDI:Midi:MThd"),
+  N_("0:0:0:AUDIO:COMPRESSED:REAL:RealMedia:.RMF"),
+  N_("0:0:0:AUDIO:COMPRESSED:OGG:Ogg Vorbis:OggS"),
+  N_("0:0:0:AUDIO:COMPRESSED:FLAC:Flac:fLaC"),
+  N_("0:1:5:AUDIO:COMPRESSED:MP3:MP3 Audio:=49=44=33=02=00"),
+  N_("0:1:5:AUDIO:COMPRESSED:MP3:MP3 Audio:=49=44=33=03=00"),
+  N_("0:1:5:AUDIO:COMPRESSED:MP3:MP3 Audio:=49=44=33=04=00"),
+  N_("0:1:2:AUDIO:COMPRESSED:MP3:MP3 Audio:=ff=fb"),
+  N_("0:1:2:AUDIO:COMPRESSED:MP3:MP3 Audio:=ff=fa"),
+  N_("2:0:0:ARCHIVE:COMPRESSED:LHA:Lha 0:-lh0-"),
+  N_("2:0:0:ARCHIVE:COMPRESSED:LHA:Lha 1:-lh1-"),
+  N_("2:0:0:ARCHIVE:COMPRESSED:LHA:Lha 4:-lz4-"),
+  N_("2:0:0:ARCHIVE:COMPRESSED:LHA:Lha z5:-lz5-"),
+  N_("2:0:0:ARCHIVE:COMPRESSED:LHA:Lha 5:-lh5-"),
+  N_("0:0:0:ARCHIVE:COMPRESSED:RAR:RarArchive:Rar!"),
+  N_("0:0:0:ARCHIVE:COMPRESSED:ZIP:PkZip:PK=03=04"),
+  N_("0:0:0:ARCHIVE:COMPRESSED:7Z:7-Zip:=37=7A=BC=AF=27=1C"),
+  N_("0:0:0:ARCHIVE:COMPRESSED:COMPRESS:Compress:=1F=89"),
+  N_("0:0:0:ARCHIVE:COMPRESSED:GZIP:Gzip:=1F=8B"),
+  N_("0:0:0:ARCHIVE:COMPRESSED:BZIP2:Bzip2:BZh"),
+  N_("0:0:0:ARCHIVE:COMPRESSED:ARJ:ARJ:=60=ea"),
+  N_("0:0:0:ARCHIVE:COMPRESSED:ARJ:ARJ:=ea=60"),
+  N_("0:0:0:ARCHIVE:COMPRESSED:HPAK:HPack:HPAK"),
+  N_("0:0:0:ARCHIVE:COMPRESSED:JAM:Jam:=E9,=01JAM"),
+  N_("0:0:0:ARCHIVE:COMPRESSED:SQUISH:Squish:SQSH"),
+  N_("0:1:8:ARCHIVE:COMPRESSED:CAB:MS Cabinet:MSCF=00=00=00=00"),
+  N_("20:0:0:ARCHIVE:COMPRESSED:ZOO:Zoo:=FD=C4=A7=DC"),
+  N_("0:0:0:ARCHIVE:COMPRESSED:XPK:Amiga XPK Archive:XPKF"),
+  N_("0:0:0:ARCHIVE:PACKAGE:RPM:RPM:=ED=AB=EE=DB"),
+  N_("0:0:0:ARCHIVE:PACKAGE:DEB:DEB:!<arch>=0A""debian"),
+  N_("0:0:0:ARCHIVE:UNIX:AR:AR:!<arch>"),
+  N_("0:0:0:ARCHIVE:UNIX:AR:AR:<ar>"),
+  N_("257:1:8:ARCHIVE:UNIX:TAR:TAR:ustar=20=20=00"),
+  N_("257:1:6:ARCHIVE:UNIX:TAR:TAR:ustar=00"),
+  N_("0:0:0:LIBRARY:JAVA:CLASS:Java:=CA=FE=BA=BE"),
+  N_("2108:0:0:DOCUMENT:OFFICE:WORD:Word v5:MSWordDoc"),
+  N_("2112:0:0:DOCUMENT:OFFICE:WORD:Word v5:MSWordDoc"),
+  N_("2080:0:0:DOCUMENT:OFFICE:EXCEL:Excel v4:Microsoft Excel"),
+  N_("2080:0:0:DOCUMENT:OFFICE:WORD:MS Word:Microsoft Word"),
+  N_("0:0:0:DOCUMENT:OFFICE:WORD:Word:=94=A6=2E"),
+  N_("512:1:19:DOCUMENT:OFFICE:WORD:Word:R=00o=00o=00t=00 =00""E=00n=00t=00r=00y"),
+  N_("0:1:9:DOCUMENT:OFFICE:ALL:MSOffice:=D0=CF=11=E0=A1=B1=1A=E1=00"),
+  N_("0:0:0:DOCUMENT:ADOBE:PDF:PortableDocument:%PDF-"),
+  N_("0:0:0:DOCUMENT:ADOBE:EPS:EncapsulatedPS:%!PS-ADOBE EPS"),
+  N_("0:0:0:DOCUMENT:STANDARD:RTF:RichText:{\\rtf"),
+  N_("6:1:4:DOCUMENT:STANDARD:RTF:RichText Compressed:=00=00LZ"),
+  N_("6:0:0:DOCUMENT:ID:VCARD:VCARD:vcard"),
+  N_("0:0:0:EXECUTABLE:DOS:EXE:DosExe:MZ"),
+  N_("0:0:0:EXECUTABLE:DOS:EXE:DosExe:LZ"),
+  N_("0:0:0:EXECUTABLE:DOS:COM:DosCom 1:=E9"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Bourne:#!/bin/sh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Bourne:#! /bin/sh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Bourne:#!/bin/bash"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Bourne:#! /bin/bash"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Bourne:#!/usr/bin/bash"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Bourne:#! /usr/bin/bash"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Csh:#!/usr/bin/csh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Csh:#! /usr/bin/csh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Csh:#!/bin/csh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Csh:#! /bin/csh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Korn:#! /usr/bin/ksh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Korn:#!/usr/bin/ksh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Korn:#! /bin/ksh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Korn:#!/bin/ksh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Tenex:#!/usr/bin/tcsh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Tenex:#! /usr/bin/tcsh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Tenex:#!/bin/tcsh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Tenex:#! /bin/tcsh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Zsh:#!/usr/bin/zsh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Zsh:#! /usr/bin/zsh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Zsh:#!/bin/zsh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Zsh:#! /bin/zsh"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:ash:#!/usr/bin/ash"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:ash:#! /usr/bin/ash"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:ash:#!/bin/ash"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:ash:#! /bin/ash"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#!/usr/bin/nawk"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#! /usr/bin/nawk"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#!/bin/nawk"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#! /bin/nawk"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#!/bin/gawk"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#! /bin/gawk"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#!/bin/awk"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#! /bin/awk"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:perl:#!/usr/bin/perl"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:perl:#! /usr/bin/perl"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:perl:#!/bin/perl"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:perl:#! /bin/perl"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Shell script:#!/"),
+  N_("0:0:0:EXECUTABLE:UNIX:SHELL:Shell script:#! /"),
+  N_("0:0:0:EXECUTABLE:UNIX:ELF:Linux ELF32:=7f""ELF=01"),
+  N_("0:0:0:EXECUTABLE:UNIX:ELF:Linux ELF:=7f""ELF=02"),
+  N_("0:0:0:EXECUTABLE:DOS:COM:DosCom 2:=8c"),
+  N_("0:0:0:EXECUTABLE:DOS:COM:DosCom 3:=eb"),
+  N_("0:0:0:EXECUTABLE:DOS:COM:DosCom 4:=b8"),
+  N_("0:1:4:EXECUTABLE:AMIGAOS:EXECUTABLE:AmigaOS Executable:=00=00=03=F3"),
+  N_("0:1:20:DATABASE:ANY:ACCESS:MSAccess:=00=01=00=00Standard=20Jet=20""DB=00"),
+  N_("0:1:2:DATABASE:ANY:MYSQL:MySQL database:=fe=01"),
+  N_("0:1:4:DATABASE:ANY:MYSQL:MySQL database:=fe=fe=03=00"),
+  N_("0:1:4:DATABASE:ANY:MYSQL:MySQL database:=fe=fe=07=00"),
+  N_("0:1:4:DATABASE:ANY:MYSQL:MySQL database:=fe=fe=05=00"),
+  N_("0:1:4:DATABASE:ANY:MYSQL:MySQL database:=fe=fe=06=00"),
+  
+  NULL, 
+  NULL, 
+  NULL, 
+  NULL, 
+
+  NULL, 
+  NULL, 
+  NULL, 
+  NULL, 
+
+  NULL, 
+  NULL, 
+  NULL, 
+  NULL, 
+
+  NULL, 
+  NULL, 
+  NULL, 
+  NULL, 
+
+  NULL,
+};
+
+static unsigned int    sh_ftype_def = 0;
+
+#define SH_FTYPE_ADD  16
+
+struct sh_ftype_rec {
+  size_t offset;
+  size_t length;
+  char   pattern[SH_FTYPE_MAX];
+
+  char   type[SH_FTYPE_MAX];
+};
+
+
+struct sh_ftype_rec ** sh_ftype_arr = NULL;
+static unsigned int    sh_ftype_nn  = 0;
+
+#if !defined(SH_FILE_MAIN)
+
+static unsigned int    sh_ftype_usr = 0;
+
+extern char * unquote_string (const char * str, size_t len);
+
+int sh_restrict_add_ftype(const char * str)
+{
+  size_t len;
+  char * cond;
+
+  if (sh_ftype_def == 0)
+    {
+      while(sh_ftype_list[sh_ftype_def] != NULL) ++sh_ftype_def;
+    }
+
+  if (!str) 
+    {
+      if (sh_ftype_usr > 0)
+	{
+	  unsigned int i, j = sh_ftype_def;
+	  
+	  for (i = 0; i < sh_ftype_usr; ++i)
+	    {
+	      SH_FREE(sh_ftype_list[j+i]);
+	      sh_ftype_list[j+i] = NULL;
+	    }   
+	  sh_ftype_usr = 0;
+	}
+
+      if (sh_ftype_arr)
+	{
+	  unsigned int i = 0;
+	  
+	  while(sh_ftype_arr[i] != NULL)
+	    {
+	      SH_FREE(sh_ftype_arr[i]);
+	      ++i;
+	    }
+	  SH_FREE(sh_ftype_arr);
+	  sh_ftype_arr = NULL;
+	}
+    }
+  else if (sh_ftype_usr < SH_FTYPE_ADD)
+    {
+      len = strlen(str);
+      cond = unquote_string(str, len);
+      sh_ftype_list[sh_ftype_def+sh_ftype_usr] = cond;
+      ++sh_ftype_usr;
+    }
+  else
+    {
+      return -1;
+    }
+  return 0;
+}
+
+
+#endif
+
+
+static int init_record(unsigned int n, char * define,
+		       struct sh_ftype_rec * record)
+{
+  unsigned int offset, dtype, length, i = 0, xn = 0;
+  char type[SH_FTYPE_MAX];
+  char pattern[SH_FTYPE_MAX];
+
+  char * end;
+  char * start;
+  
+  offset = strtoul(define, &end, 0);
+  if (*end != ':')
+    return -1;
+
+  start = end; ++start;
+  dtype  = strtoul(start,  &end, 0);
+  if (*end != ':')
+    return -1;
+
+  start = end; ++start;
+  length = strtoul(start,  &end, 0);
+  if (*end != ':')
+    return -1;
+  
+  start = end; ++start;
+
+  while (*start && (i < sizeof(type)))
+    {
+      type[i] = *start; ++start;
+      if (type[i] == ':') 
+	++xn;
+      if (xn == 3)
+	{
+	  type[i] = '\0';
+	  break;
+	}
+      ++i;
+    }
+  if (xn != 3)
+    return -1;
+
+  start = strchr(start, ':');
+
+  if (!start)
+    return -1;
+
+  ++start;
+
+  if (dtype == 0)
+    {
+      sl_strlcpy(pattern, start, sizeof(pattern));
+      length = strlen(pattern);
+    }
+  else if (length <= sizeof(pattern))
+    {
+      memcpy(pattern, start, length);
+    }
+  else
+    {
+      return -1;
+    }
+
+  /* fprintf(stderr, "FIXME: %d %d %s ", dtype, length, type); */
+  /**
+  if (dtype == 0)
+    fprintf(stderr, "%s\n", pattern);
+  else
+    {
+      int k;
+      for (k = 0; k < length; ++k)
+	fprintf(stderr, "0x%X", (unsigned int) (pattern[k]));
+      fprintf(stderr, "\n");
+    }
+  **/
+
+  for (i = 0; i < n; ++i)
+    {
+      if (sh_ftype_arr[i]->length <= length &&
+	  sh_ftype_arr[i]->offset == offset)
+	{
+	  if (0 == memcmp(sh_ftype_arr[i]->pattern, pattern, 
+			  sh_ftype_arr[i]->length))
+	    {
+#ifdef  SH_FILE_MAIN
+	      fprintf(stderr, 
+		      "Pattern %d (%s / %s) override by earlier pattern %d (%s / %s)\n",
+		      n, type, pattern,
+		      i, sh_ftype_arr[i]->type, sh_ftype_arr[i]->pattern);
+#else
+	      char errbuf[256];
+	      
+	      sl_snprintf(errbuf, sizeof(errbuf),
+			  _("Pattern %d (%s) override by earlier pattern %d (%s)"),
+			  n, type,
+			  i, sh_ftype_arr[i]->type);
+	      sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+			      errbuf,
+			      _("init_record"));
+#endif
+	    }
+	}
+    }
+
+
+  record->offset = offset;
+  record->length = length;
+  memcpy(record->pattern, pattern, length);
+  sl_strlcpy(record->type, type, SH_FTYPE_MAX);
+
+  return 0;
+}
+
+static void file_arr_init()
+{
+  unsigned int i, nn = 0;
+
+  if (sh_ftype_def == 0)
+    {
+      while(sh_ftype_list[sh_ftype_def] != NULL) ++sh_ftype_def;
+    }
+
+  while (sh_ftype_list[nn] != NULL) ++nn;
+
+#ifdef  SH_FILE_MAIN
+  printf("%d definitions found, defined = %d\n", nn, sh_ftype_def);
+#endif
+
+#ifdef  SH_FILE_MAIN
+  sh_ftype_arr = malloc((nn+1) * sizeof(struct sh_ftype_rec *));
+#else
+  sh_ftype_arr = SH_ALLOC((nn+1) * sizeof(struct sh_ftype_rec *));
+#endif
+
+  for(i = 0; i < nn; i++)
+    {
+#ifdef  SH_FILE_MAIN
+      sh_ftype_arr[i] = malloc(sizeof(struct sh_ftype_rec));
+#else
+      sh_ftype_arr[i] = SH_ALLOC(sizeof(struct sh_ftype_rec));
+#endif
+
+      memset(sh_ftype_arr[i], 0, sizeof(struct sh_ftype_rec));
+      if (i < sh_ftype_def) 
+	{
+	  char   * p  = _(sh_ftype_list[i]);
+	  size_t len  = strlen(p);
+	  char * cond = unquote_string(p, len); 
+	  
+	  init_record(i,             cond, sh_ftype_arr[i]);
+	}
+      else 
+	{
+	  init_record(i, sh_ftype_list[i], sh_ftype_arr[i]);
+	}
+    }
+  sh_ftype_arr[nn] = NULL;
+  sh_ftype_nn      = nn;
+
+  return;
+}
+
+static char * check_filetype(char * filetype, 
+			     const char * buffer, size_t buflen)
+{
+  unsigned int i;
+  const char * p;
+
+  if (!sh_ftype_arr)
+    {
+      file_arr_init();
+    }
+  
+  for (i = 0; i < sh_ftype_nn; ++i)
+    {
+      if (sh_ftype_arr[i]->length > 0 && 
+	  (sh_ftype_arr[i]->length + sh_ftype_arr[i]->offset) < buflen)
+	{
+	  p = &buffer[sh_ftype_arr[i]->offset];
+
+#if 0
+	  {
+	    int dd;
+	    /* fprintf(stderr, "FIXME: %03d comp %d:%d  ", i, 
+	       sh_ftype_arr[i]->offset, sh_ftype_arr[i]->length); */
+	    for (dd = 0; dd < sh_ftype_arr[i]->length; ++dd) {
+	      fprintf(stderr, "0x%X ", sh_ftype_arr[i]->pattern[dd]);
+	    }
+	    for (dd = 0; dd < sh_ftype_arr[i]->length; ++dd) {
+	      fprintf(stderr, "0x%X ", p[dd]);
+	    }
+	    fprintf(stderr, "\n");
+	  }
+#endif
+
+	  if (0 == memcmp(p, sh_ftype_arr[i]->pattern, sh_ftype_arr[i]->length))
+	    {
+	      sl_strlcpy(filetype, sh_ftype_arr[i]->type, SH_FTYPE_MAX);
+	      return (filetype);
+	    }
+	}
+    }
+
+  if (buflen > 0) {
+
+    int flag = 0;
+
+    p = buffer;
+    for (i = 0; i < buflen; ++i) {
+      if (*p == '\0')
+	{
+	  sl_strlcpy(filetype, _("FILE:BINARY:UNKNOWN"), SH_FTYPE_MAX);
+	  goto out;
+	}
+      else if (!isgraph((int)*p) && !isspace((int)*p))
+	{
+	  flag = 1;
+	}
+      ++p;
+    }
+    if (flag == 0)
+      {
+	sl_strlcpy(filetype, _("FILE:TEXT:ASCII"), SH_FTYPE_MAX);
+	goto out;
+      }
+  }
+  sl_strlcpy(filetype, _("FILE:UNKNOWN:UNKNOWN"), SH_FTYPE_MAX);
+ out:
+  return filetype;
+}
+
+#if !defined(SH_FILE_MAIN)
+
+int matches_filetype(SL_TICKET ft, char * test_type)
+{
+  char buffer[3072];
+  char filetype[SH_FTYPE_MAX];
+  long len;
+
+  len = sl_read_timeout (ft, buffer, sizeof(buffer), 12, SL_TRUE);
+
+  sl_rewind(ft);
+
+  if (len > 0)
+    {
+      check_filetype(filetype, buffer, len);
+    }
+  else
+    {
+      sl_strlcpy(filetype, _("FILE:UNKNOWN:UNKNOWN"), SH_FTYPE_MAX);
+    }
+
+  if (0 == strcmp(filetype, test_type))
+    {
+      return 1;
+    }
+
+  return 0;
+}
+
+#else
+/* SH_FILE_MAIN */
+#include <unistd.h>
+
+int main (int argc, char * argv[])
+{
+  char buffer[3072];
+  char filetype[SH_FTYPE_MAX];
+  size_t len;
+
+  FILE * fh = fopen(argv[1], "r");
+
+  if (fh)
+    {
+      int fd = fileno(fh);
+
+      len = read(fd, buffer, 3072);
+
+      check_filetype(filetype, buffer, len);
+
+      fprintf(stdout, "%s: %s\n", argv[1], filetype);
+
+      return 0;
+    }
+  return 1;
+}
+#endif
+
+#endif
+/* #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
Index: trunk/src/sh_readconf.c
===================================================================
--- trunk/src/sh_readconf.c	(revision 309)
+++ trunk/src/sh_readconf.c	(revision 310)
@@ -48,4 +48,5 @@
 #include "sh_unix.h"
 #include "sh_utils.h"
+#include "sh_restrict.h"
 
 
@@ -942,8 +943,14 @@
     sh_files_pushfile_prelink },
 
-  { N_("ignoreadded"), SH_SECTION_MISC,   SH_SECTION_NONE, 
+  { N_("ignoreadded"),   SH_SECTION_MISC,   SH_SECTION_NONE, 
     sh_ignore_add_new },
   { N_("ignoremissing"), SH_SECTION_MISC,   SH_SECTION_NONE, 
     sh_ignore_add_del },
+
+  { N_("skipchecksum"),  SH_SECTION_MISC,   SH_SECTION_NONE, 
+    sh_restrict_define },
+  { N_("filetype"),      SH_SECTION_MISC,   SH_SECTION_NONE, 
+    sh_restrict_add_ftype },
+
 
   { N_("filecheckscheduleone"), SH_SECTION_MISC,   SH_SECTION_NONE, 
Index: trunk/src/sh_restrict.c
===================================================================
--- trunk/src/sh_restrict.c	(revision 310)
+++ trunk/src/sh_restrict.c	(revision 310)
@@ -0,0 +1,671 @@
+/* SAMHAIN file system integrity testing                                   */
+/* Copyright (C) 2011 Rainer Wichmann                                      */
+/*                                                                         */
+/*  This program is free software; you can redistribute it                 */
+/*  and/or modify                                                          */
+/*  it under the terms of the GNU General Public License as                */
+/*  published by                                                           */
+/*  the Free Software Foundation; either version 2 of the License, or      */
+/*  (at your option) any later version.                                    */
+/*                                                                         */
+/*  This program is distributed in the hope that it will be useful,        */
+/*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
+/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
+/*  GNU General Public License for more details.                           */
+/*                                                                         */
+/*  You should have received a copy of the GNU General Public License      */
+/*  along with this program; if not, write to the Free Software            */
+/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
+
+#include "config_xor.h"
+
+#ifndef NULL
+#if !defined(__cplusplus)
+#define NULL ((void*)0)
+#else
+#define NULL (0)
+#endif
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+#ifdef HAVE_REGEX_H
+#include <sys/types.h>
+#include <regex.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "samhain.h"
+#include "sh_mem.h"
+#include "sh_error_min.h"
+#include "sh_string.h"
+#include "sh_utils.h"
+#include "sh_restrict.h"
+
+#define FIL__ _("sh_restrict.c")
+
+#define SH_COND_NOT    (1 << 0)
+#define SH_COND_PREFIX (1 << 1)
+#define SH_COND_REGEX  (1 << 2)
+#define SH_COND_SIZE   (1 << 3)
+#define SH_COND_PERM   (1 << 4)
+#define SH_COND_FTYPE  (1 << 5)
+#define SH_COND_PINCL  (1 << 6)
+
+#define SH_COND_MAX 6
+
+struct sh_restrict_cond {
+
+  unsigned char cond_type[SH_COND_MAX];
+
+#ifdef HAVE_REGEX_H
+  regex_t *     cond_preg[SH_COND_MAX];
+#endif
+
+  char  *       cond_str[SH_COND_MAX];
+
+  UINT64        cond_int[SH_COND_MAX];
+
+  struct sh_restrict_cond * next;
+};
+
+static struct sh_restrict_cond * sh_restrict_list = NULL;
+
+extern int matches_filetype(SL_TICKET ft, char * test_type);
+
+#ifdef HAVE_REGEX_H
+static int matches_regex (const char * path, const regex_t * regex)
+{
+  SL_ENTER(_("matches_regex"));
+
+  if (0 == regexec(regex, path, 0, NULL, 0))
+    {
+      SL_RETURN(1, _("matches_regex"));
+    }
+  SL_RETURN(0, _("matches_regex"));
+}
+#else
+static int matches_string (const char * path, const char * string)
+{
+  SL_ENTER(_("matches_string"));
+  
+  if (NULL == strstr(path, string))
+    {
+      SL_RETURN(0, _("matches_string"));
+    }
+  SL_RETURN(1, _("matches_string"));
+}
+#endif
+
+static int matches_prefix (const char * path, const char * prefix)
+{
+  size_t path_len;
+  size_t pref_len;
+
+  SL_ENTER(_("matches_prefix"));
+
+  path_len = sl_strlen(path);
+  pref_len = sl_strlen(prefix);
+  
+  if (path_len >= pref_len)
+    {
+      if (0 == strncmp(path, prefix, pref_len))
+	{
+	  SL_RETURN(1, _("matches_prefix"));
+	}
+    }
+  SL_RETURN(0, _("matches_prefix"));
+}
+
+static int exceeds_size (UINT64 size, UINT64 maxsize)
+{
+  SL_ENTER(_("exceeds_size"));
+
+  if (size > maxsize)
+    {
+      SL_RETURN(1, _("exceeds_size"));
+    }
+  SL_RETURN(0, _("exceeds_size"));
+}
+
+static int matches_perm (UINT64 perm, UINT64 needed_perm)
+{
+  SL_ENTER(_("matches_perm"));
+
+  if (needed_perm == (perm & 07777))
+    {
+      SL_RETURN(1, _("matches_perm"));
+    }
+  SL_RETURN(0, _("matches_perm"));
+}
+
+static int includes_perm (UINT64 perm, UINT64 needed_perm)
+{
+  UINT64 tmp = perm & 07777;
+
+  SL_ENTER(_("includes_perm"));
+
+  if (needed_perm == (tmp & needed_perm))
+    {
+      SL_RETURN(1, _("includes_perm"));
+    }
+  SL_RETURN(0, _("includes_perm"));
+}
+
+static int sh_restrict_test(const char * path, 
+			    UINT64 size, UINT64 perm, SL_TICKET fh,
+			    struct sh_restrict_cond * current)
+{
+  int i;
+  unsigned char flag;
+  int res = 0;
+
+  (void) fh;
+
+  SL_ENTER(_("sh_restrict_test"));
+
+  for (i = 0; i < SH_COND_MAX; ++i)
+    {
+      flag = current->cond_type[i];
+
+      if (flag != 0)
+	{
+	  if      ((flag & (SH_COND_PREFIX)) != 0) {
+	    res = matches_prefix(path, current->cond_str[i]);
+	  }
+	  else if ((flag & (SH_COND_REGEX)) != 0) {
+#ifdef HAVE_REGEX_H
+	    res = matches_regex(path, current->cond_preg[i]);
+#else
+	    res = matches_string(path, current->cond_str[i]);
+#endif
+	  }
+	  else if ((flag & (SH_COND_SIZE)) != 0) {
+	    res = exceeds_size(size, current->cond_int[i]);
+	  }
+	  else if ((flag & (SH_COND_PERM)) != 0) {
+	    res = matches_perm(perm, current->cond_int[i]);
+	  }
+	  else if ((flag & (SH_COND_PINCL)) != 0) {
+	    res = includes_perm(perm, current->cond_int[i]);
+	  }
+	  else if ((flag & (SH_COND_FTYPE)) != 0) {
+	    res = matches_filetype(fh, current->cond_str[i]);
+	  }
+
+	  /* Does condition hold?
+	   */
+	  if ((flag & (SH_COND_NOT)) != 0) {
+	    /* 
+	     * Condition negated, ok if false (res == 0)
+	     */
+	    if (0 != res) {
+	      SL_RETURN(0, _("sh_restrict_this"));
+	    }
+	  }
+	  else {
+	    /* Condition ok if true (res != 0) */
+	    if (0 == res) {
+	      SL_RETURN(0, _("sh_restrict_this"));
+	    }
+	  }
+	}
+      else
+	{
+	  break;
+	}
+    }
+
+  /* All conditions true, restricted 
+   */
+  SL_RETURN(1, _("sh_restrict_this"));
+}
+
+/* >>>>>>>>>> Evaluate the list <<<<<<<<<< */
+
+int sh_restrict_this(const char * path, UINT64 size, UINT64 perm, SL_TICKET fh)
+{
+  struct sh_restrict_cond * current = sh_restrict_list;
+
+  SL_ENTER(_("sh_restrict_this"));
+
+  if (!current) 
+    {
+      SL_RETURN(0, _("sh_restrict_this"));
+    }
+
+  while (current) 
+    {
+      if (0 != sh_restrict_test(path, size, perm, fh, current))
+	{
+	  /* The current conditions are true, restricted
+	   */
+	  SL_RETURN(1, _("sh_restrict_this"));
+	}
+      current = current->next;
+    }
+
+  SL_RETURN(0, _("sh_restrict_this"));
+}
+
+
+/* >>>>>>>>>> Purge the list <<<<<<<<<< */
+
+static void sh_restrict_delete (struct sh_restrict_cond * current)
+{
+  int i;
+
+  if (current->next)
+    {
+      sh_restrict_delete(current->next);
+    }
+
+  for (i = 0; i < SH_COND_MAX; ++i)
+    {
+      if (current->cond_str[i]) {
+	SH_FREE(current->cond_str[i]);
+      }
+#ifdef HAVE_REGEX_H
+      if (current->cond_preg[i]) {
+	regfree(current->cond_preg[i]);
+	SH_FREE(current->cond_preg[i]);
+      }
+#endif
+    }
+  SH_FREE(current);
+  return;
+}
+
+void sh_restrict_purge ()
+{
+  struct sh_restrict_cond * current = sh_restrict_list;
+
+  sh_restrict_list = NULL;
+  if (current)
+    sh_restrict_delete(current);
+
+  sh_restrict_add_ftype(NULL);
+
+  return;
+}
+
+/* >>>>>>>>>> Create the list <<<<<<<<<< */
+
+static char * get_com(char * str)
+{
+  char * s;
+  char * e;
+
+  /* skip leading WS 
+   */
+  for (s = str; *s && isspace((int)*s); ++s) /* nothing */;
+
+  e = strchr(s, '(');
+  if (e && (e != s))
+    {
+      *e = '\0'; --e;
+      while ( (e != s) && isspace((int)*e) )
+	{
+	  *e = '\0'; --e;
+	}
+      if (e != s)
+	return s;
+    }
+  return NULL;
+}
+
+static char * get_arg(char * str)
+{
+  char * s;
+  char * e;
+
+  s = strchr(str, '(');
+
+  if (s)
+    {
+      ++s;
+      
+      /* skip leading WS 
+       */
+      for (; *s && isspace((int)*s); ++s) /* nothing */;
+
+      e = strrchr(s, ')');
+      if (e && (e != s))
+	{
+	  /* strip trailing space */
+	  *e = '\0'; --e;
+	  while ( (e != s) && isspace((int)*e) )
+	    {
+	      *e = '\0'; --e;
+	    }
+	  
+	  if (e != s)
+	    return s;
+	}
+    }
+  return NULL;
+}
+
+static int set_cond(struct sh_restrict_cond * current, int i, 
+		    char * com, char * arg)
+{
+  if (!com || !arg || (i >= SH_COND_MAX))
+    return -1;
+
+  if      (0 == strcmp(com, _("match_prefix")))
+    {
+      current->cond_str[i] = sh_util_strdup(arg);
+      current->cond_type[i] |= SH_COND_PREFIX;
+    }
+  else if (0 == strcmp(com, _("match_regex")))
+    {
+#ifdef HAVE_REGEX_H
+      regex_t * preg = SH_ALLOC(sizeof(regex_t)); 
+
+      if (0 != regcomp(preg, arg, REG_NOSUB|REG_EXTENDED))
+	{
+	  SH_FREE(preg);
+	  return (-1);
+	}
+      current->cond_preg[i] = preg;
+#else
+      current->cond_str[i] = sh_util_strdup(arg);
+#endif
+      current->cond_type[i] |= SH_COND_REGEX;
+    }
+  else if (0 == strcmp(com, _("size_exceeds")))
+    {
+      current->cond_int[i] = (UINT64) strtoul(arg, (char **) NULL, 0);
+      current->cond_type[i] |= SH_COND_SIZE;
+    }
+  else if (0 == strcmp(com, _("match_permission")))
+    {
+      current->cond_int[i] = (UINT64) strtoul(arg, (char **) NULL, 8);
+      current->cond_type[i] |= SH_COND_PERM;
+    }
+  else if (0 == strcmp(com, _("have_permission")))
+    {
+      current->cond_int[i] = (UINT64) strtoul(arg, (char **) NULL, 8);
+      current->cond_type[i] |= SH_COND_PINCL;
+    }
+  else if (0 == strcmp(com, _("match_filetype")))
+    {
+      current->cond_str[i] = sh_util_strdup(arg);
+      current->cond_type[i] |= SH_COND_FTYPE;
+    }
+  else
+    {
+      return (-1);
+    }
+  return 0;
+}
+
+/* Format is [!]cond1(arg), cond2(arg), ... 
+ */
+int sh_restrict_define(const char * str)
+{
+  SL_ENTER(_("sh_restrict_define"));
+
+  if (str) 
+    {
+      size_t lengths[SH_COND_MAX];
+      unsigned int nfields = SH_COND_MAX;
+      char ** array;
+      sh_string * def = sh_string_new_from_lchar(str, strlen(str));
+
+      array = split_array_list(sh_string_str(def), &nfields, lengths);
+
+      if (array && nfields > 0)
+	{
+	  char * p;
+	  char * q;
+	  unsigned int i;
+	  struct sh_restrict_cond * current = 
+	    SH_ALLOC(sizeof(struct sh_restrict_cond));
+
+	  current->next = NULL;
+	  for (i = 0; i < SH_COND_MAX; ++i)
+	    {
+	      current->cond_int[i]  = 0; 
+	      current->cond_type[i] = 0;
+	      current->cond_str[i] = NULL;
+#ifdef HAVE_REGEX_H
+	      current->cond_preg[i] = NULL;
+#endif
+	    }
+      
+	  for (i = 0; i < nfields; ++i) 
+	    {
+	      if (i == SH_COND_MAX)
+		{
+		  sh_restrict_delete (current);
+		  sh_string_destroy(&def);
+		  SH_FREE(array);
+		  SL_RETURN((-1), _("sh_restrict_define"));
+		}
+	      
+	      p = array[i];
+
+	      if (*p == '!')
+		{
+		  current->cond_type[i] |= SH_COND_NOT;
+		  ++p;
+		}
+
+	      q = get_arg(p);
+	      p = get_com(p);
+
+	      if (!q || !p || (0 != set_cond(current, i, p, q)))
+		{
+		  sh_restrict_delete (current);
+		  sh_string_destroy(&def);
+		  SH_FREE(array);
+		  SL_RETURN((-1), _("sh_restrict_define"));
+		}
+	    }
+
+	  SH_FREE(array);
+
+	  current->next = sh_restrict_list;
+	  sh_restrict_list = current;
+	}
+
+      sh_string_destroy(&def);
+      SL_RETURN(0, _("sh_restrict_define"));
+    }
+
+  SL_RETURN((-1), _("sh_restrict_define"));
+}
+
+
+/* #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
+#endif
+
+#ifdef SH_CUTEST
+#include "CuTest.h"
+
+void Test_restrict (CuTest *tc) {
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+  char str[256];
+  char * p;
+  char * q;
+  int  res;
+  SL_TICKET fd;
+  char buf[1024];
+
+  strcpy(str, "match(this)");
+  p = get_arg(str);
+  q = get_com(str);
+  CuAssertPtrNotNull(tc, p);
+  CuAssertPtrNotNull(tc, q);
+  CuAssertStrEquals(tc, "match", q);
+  CuAssertStrEquals(tc, "this",  p);
+  
+  strcpy(str, "  match( this)");
+  p = get_arg(str);
+  q = get_com(str);
+  CuAssertPtrNotNull(tc, p);
+  CuAssertPtrNotNull(tc, q);
+  CuAssertStrEquals(tc, "match", q);
+  CuAssertStrEquals(tc, "this",  p);
+  
+  strcpy(str, "  match ( this ) ");
+  p = get_arg(str);
+  q = get_com(str);
+  CuAssertPtrNotNull(tc, p);
+  CuAssertPtrNotNull(tc, q);
+  CuAssertStrEquals(tc, "match", q);
+  CuAssertStrEquals(tc, "this",  p);
+  
+  strcpy(str, "  match   (this   ) ");
+  p = get_arg(str);
+  q = get_com(str);
+  CuAssertPtrNotNull(tc, p);
+  CuAssertPtrNotNull(tc, q);
+  CuAssertStrEquals(tc, "match", q);
+  CuAssertStrEquals(tc, "this",  p);
+  
+  strcpy(str, "size_exceeds(800), match_prefix(/home), match_regex(.*\\.mpg) ");
+  CuAssertTrue(tc, sh_restrict_list == NULL);
+  res = sh_restrict_define(str);
+  CuAssertIntEquals(tc,0,res);
+  CuAssertPtrNotNull(tc, sh_restrict_list);
+
+  sh_restrict_purge();
+  CuAssertTrue(tc, sh_restrict_list == NULL);
+
+  strcpy(str, "size_exceeds(800), match_prefix(/home), match_regex(.*\\.mpg), match_permission(0755) ");
+  CuAssertTrue(tc, sh_restrict_list == NULL);
+  res = sh_restrict_define(str);
+  CuAssertIntEquals(tc,0,res);
+  CuAssertPtrNotNull(tc, sh_restrict_list);
+
+  strcpy(str, "size_exceeds(800), match_prefix(/foo), have_permission(0100)");
+  res = sh_restrict_define(str);
+  CuAssertIntEquals(tc,0,res);
+  CuAssertPtrNotNull(tc, sh_restrict_list);
+
+  res = sh_restrict_this("/home/foo.mpg", 1000, 0755, 0);
+  CuAssertIntEquals(tc,1,res);
+
+  res = sh_restrict_this("/foo.mpg",      1000, 0755, 0);
+  CuAssertIntEquals(tc,1,res);
+
+  /* size too small */
+  res = sh_restrict_this("/foo.mpg",       600, 0755, 0);
+  CuAssertIntEquals(tc,0,res);
+
+  /* no execute permission */
+  res = sh_restrict_this("/foo.mpg",       600, 0644, 0);
+  CuAssertIntEquals(tc,0,res);
+
+  /* regex does not match */
+   res = sh_restrict_this("/home/foo",     1000, 0755, 0);
+  CuAssertIntEquals(tc,0,res);
+
+  /* wrong permission */
+  res = sh_restrict_this("/home/foo.mpg", 1000, 0705, 0);
+  CuAssertIntEquals(tc,0,res);
+  
+  /* size too small */
+  res = sh_restrict_this("/home/foo.mpg",  600, 0755, 0);
+  CuAssertIntEquals(tc,0,res);
+  
+  /* wrong prefix */
+  res = sh_restrict_this("/hoff/foo.mpg", 1000, 0755, 0);
+  CuAssertIntEquals(tc,0,res);
+  
+  sh_restrict_purge();
+  CuAssertTrue(tc, sh_restrict_list == NULL);
+
+  fd = sl_open_fastread(FIL__, __LINE__, "/bin/sh", SL_NOPRIV);
+  CuAssertTrue(tc, fd > 0);
+
+  strcpy(str, "match_prefix(/bin), match_filetype(EXECUTABLE:UNIX:ELF)");
+  res = sh_restrict_define(str);
+  CuAssertIntEquals(tc,0,res);
+  CuAssertPtrNotNull(tc, sh_restrict_list);
+
+  res = sh_restrict_this("/bin/sh", 1000, 0755, fd);
+  CuAssertIntEquals(tc,1,res);
+
+  sl_close(fd);
+
+  sh_restrict_purge();
+  CuAssertTrue(tc, sh_restrict_list == NULL);
+
+  strcpy(str, "match_filetype(FILE:TEXT:COPYING)");
+  res = sh_restrict_define(str);
+  CuAssertIntEquals(tc,0,res);
+  CuAssertPtrNotNull(tc, sh_restrict_list);
+
+  p = getcwd(buf, sizeof(buf));
+  CuAssertPtrNotNull(tc, p);
+
+  strcpy(str, "0:0:0:FILE:TEXT:COPYING:Copying:=0a=53=41=4d=48=41=49=4e");
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+
+  sl_strlcat(buf, "/COPYING", sizeof(buf));
+  fd = sl_open_fastread(FIL__, __LINE__, buf, SL_NOPRIV);
+  CuAssertTrue(tc, fd > 0);
+
+  res = sh_restrict_this(buf, 1000, 0755, fd);
+  CuAssertIntEquals(tc,1,res);
+
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,-1,res);
+
+  sh_restrict_purge();
+  CuAssertTrue(tc, sh_restrict_list == NULL);
+
+  res = sh_restrict_add_ftype(str);
+  CuAssertIntEquals(tc,0,res);
+  
+#else
+  (void) tc;
+/* #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
+#endif
+
+}
+#endif
+
+
Index: trunk/src/sh_unix.c
===================================================================
--- trunk/src/sh_unix.c	(revision 309)
+++ trunk/src/sh_unix.c	(revision 310)
@@ -98,4 +98,5 @@
 #include "sh_hash.h"
 #include "sh_tools.h"
+#include "sh_restrict.h"
 #include "sh_ipvx.h"
 #include "sh_tiger.h"
@@ -3749,5 +3750,7 @@
       if (fileHash != NULL)
 	{
-	  if ((theFile->check_mask & MODI_CHK) == 0)
+	  if ((theFile->check_mask & MODI_CHK) == 0 ||
+	      sh_restrict_this(theFile->fullpath, (UINT64) fbuf.st_size, 
+			       (UINT64) fbuf.st_mode, rval_open))
 	    {
 	      sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
@@ -3802,5 +3805,7 @@
       if (fileHash != NULL)
 	{
-	  if ((theFile->check_mask & MODI_CHK) == 0)
+	  if ((theFile->check_mask & MODI_CHK) == 0 ||
+	      sh_restrict_this(theFile->fullpath, (UINT64) fbuf.st_size, 
+			       (UINT64) fbuf.st_mode, rval_open))
 	    {
 	      sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
Index: trunk/test/testtimesrv.sh
===================================================================
--- trunk/test/testtimesrv.sh	(revision 309)
+++ trunk/test/testtimesrv.sh	(revision 310)
@@ -325,4 +325,5 @@
 	while [ $tmp -lt 2 ]; do
 	    one_sec_sleep
+	    let "count = count + 1" >/dev/null
 	    if [ $count -gt 12 ]; then
 		[ -z "$verbose" ] || log_msg_fail "policy count (after)";
