Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37504691
en ru br
Репозитории ALT
S:0.5.10-alt1
5.1: 20080706-alt1.1
www.altlinux.org/Changes

Группа :: Система/Серверы
Пакет: c-icap

 Главная   Изменения   Спек   Патчи   Sources   Загрузить   Gear   Bugs and FR  Repocop 

Патч: c-icap-20080706-alt.patch
Скачать


 Makefile.am                          |    6 +-
 Makefile.in                          |    6 +-
 c-icap.conf.in                       |   58 ++-
 configure                            |    6 +-
 configure.in                         |    4 +-
 contrib/get_file.pl                  |    2 +-
 filetype.c                           |    2 +-
 include/debug.h                      |    2 +-
 services/Makefile.am                 |    2 +-
 services/Makefile.in                 |    4 +-
 services/clamav/srv_clamav.c         |    2 +-
 services/url_filter/Makefile.am      |   12 +
 services/url_filter/Makefile.in      |  501 +++++++++++++++++++
 services/url_filter/makefile.w32     |   15 +
 services/url_filter/srv_url_filter.c |  892 ++++++++++++++++++++++++++++++++++
 15 files changed, 1481 insertions(+), 33 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 2e86d25..45937b2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -28,7 +28,7 @@ c_icap_SOURCES = aserver.c request.c cfg_param.c \
 # libicapapi ......
 libicapapi_la_CFLAGS= -Iinclude/ @ZLIB_ADD_FLAG@ -DCI_BUILD_LIB
 
-libicapapi_la_LIBADD = @ZLIB_ADD_LDFLAG@
+libicapapi_la_LIBADD = @ZLIB_ADD_LDFLAG@ @DL_ADD_FLAG@ @THREADS_LDADD@
 libicapapi_la_LDFLAGS= -shared -version-info 0:1:0
 
 
@@ -71,10 +71,6 @@ install-data-local:
 	if test ! -f $(DESTDIR)$(CONFIGDIR)/c-icap.magic; then $(INSTALL) c-icap.magic $(DESTDIR)$(CONFIGDIR)/c-icap.magic; fi
 	$(mkinstalldirs)  $(DESTDIR)$(LOGDIR); 
 	$(mkinstalldirs)  $(DESTDIR)$(SOCKDIR);
-	chgrp nobody $(DESTDIR)$(LOGDIR)
-	chmod 775 $(DESTDIR)$(LOGDIR)
-	chgrp nobody $(DESTDIR)$(SOCKDIR)
-	chmod 775 $(DESTDIR)$(SOCKDIR)
 
 EXTRA_DIST= RECONF INSTALL.txt include/config-w32.h makefile.w32 c-icap.conf c_icap_dll.mak c-icap.conf.in c-icap.magic  c_icap.mak c_icap.def \
              contrib/get_file.pl contrib/convert_old_magic.pl \
diff --git a/Makefile.in b/Makefile.in
index 8ce6f2a..b6dadf8 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -294,7 +294,7 @@ c_icap_SOURCES = aserver.c request.c cfg_param.c \
 
 # libicapapi ......
 libicapapi_la_CFLAGS = -Iinclude/ @ZLIB_ADD_FLAG@ -DCI_BUILD_LIB
-libicapapi_la_LIBADD = @ZLIB_ADD_LDFLAG@
+libicapapi_la_LIBADD = @ZLIB_ADD_LDFLAG@ @DL_ADD_FLAG@ @THREADS_LDADD@
 libicapapi_la_LDFLAGS = -shared -version-info 0:1:0
 
 #c_icap the main server 
@@ -1306,10 +1306,6 @@ install-data-local:
 	if test ! -f $(DESTDIR)$(CONFIGDIR)/c-icap.magic; then $(INSTALL) c-icap.magic $(DESTDIR)$(CONFIGDIR)/c-icap.magic; fi
 	$(mkinstalldirs)  $(DESTDIR)$(LOGDIR); 
 	$(mkinstalldirs)  $(DESTDIR)$(SOCKDIR);
-	chgrp nobody $(DESTDIR)$(LOGDIR)
-	chmod 775 $(DESTDIR)$(LOGDIR)
-	chgrp nobody $(DESTDIR)$(SOCKDIR)
-	chmod 775 $(DESTDIR)$(SOCKDIR)
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/c-icap.conf.in b/c-icap.conf.in
index 2fbe4cc..665f418 100644
--- a/c-icap.conf.in
+++ b/c-icap.conf.in
@@ -3,7 +3,7 @@
 #
 
 
-PidFile /var/run/c-icap.pid
+PidFile /var/run/c-icap/c-icap.pid
 CommandsSocket /var/run/c-icap/c-icap.ctl
 Timeout 300
 KeepAlive On
@@ -19,26 +19,26 @@ MaxRequestsPerChild  0
 
 
 Port 1344 
-User wwwrun
+User _c_icap
 Group nobody
 
 
 #ServerAdmin you@your.address # Not implemented yet
 #ServerName localhost:1344 # Not implemented yet
 
-TmpDir /var/tmp
+TmpDir /var/cache/c-icap
 MaxMemObject 131072
 
-ServerLog @prefix@/var/log/server.log
-AccessLog @prefix@/var/log/access.log
+ServerLog /var/log/c-icap/server.log
+AccessLog /var/log/c-icap/access.log
 #DebugLevel 3
 
-ModulesDir @prefix@/lib/c_icap
+ModulesDir @libdir@/c-icap
 Module logger sys_logger.so
 Module perl_handler perl_handler.so
 
-sys_logger.Prefix "C-ICAP:"
-sys_logger.Facility local1
+sys_logger.Prefix "C-ICAP"
+sys_logger.Facility daemon
 
 ##Specify wich logger to use......
 #Logger sys_logger
@@ -89,7 +89,7 @@ Logger file_logger
 #AuthMethod basic file_basic 
 
 
-ServicesDir @prefix@/lib/c_icap
+ServicesDir @libdir@/c-icap
 Service echo_module srv_echo.so
 Service url_check_module srv_url_check.so
 Service antivirus_module srv_clamav.so
@@ -112,7 +112,7 @@ srv_clamav.StartSendPercentDataAfter 2M
 # The Maximum object to be scanned.
 srv_clamav.MaxObjectSize  5M
 #The directory which clamav library will use as temporary.
-#srv_clamav.ClamAvTmpDir /var/tmp
+#srv_clamav.ClamAvTmpDir /var/cache/c-icap
 #Sets the maximum number of files in archive.)i Set it to 0 to disable it
 srv_clamav.ClamAvMaxFilesInArchive 0
 #Sets the maximal archived file size. Set it to 0 to disable it.
@@ -122,10 +122,46 @@ srv_clamav.ClamAvMaxRecLevel 5
 
 # And here the viralator-like mode.
 # where to save documents
-srv_clamav.VirSaveDir /srv/www/htdocs/downloads/
+srv_clamav.VirSaveDir /var/www/html/downloads/
 # from where the documents can be retrieved (you can find the get_file.pl script in contrib dir)
 srv_clamav.VirHTTPServer  "http://fortune/cgi-bin/get_file.pl?usename=%f&remove=1&file="
 # The refresh  rate....
 srv_clamav.VirUpdateTime   15
 # For which filetypes the "virelator like mode" will be used.
 srv_clamav.VirScanFileTypes ARCHIVE EXECUTABLE
+
+Service url_filter_module srv_url_filter.so
+
+# Memcached server list for url_filter
+url_filter.MemcachedServers "127.0.0.1:11211"
+
+# host2cat server for url_filter
+url_filter.Host2CatServer "127.0.0.1:6666"
+
+# Database settings
+url_filter.DBEngine "sqlite3"
+#url_filter.DBHost "localhost"
+#url_filter.DBPort "5432"
+url_filter.DBName "/var/cache/host2cat/filter.db"
+#url_filter.DBUser "username"
+#url_filter.DBPass "password"
+
+url_filter.RedirectUrl "http://www.google.com"
+
+#url_filter.ClientIPHeader "X-Client-IP"
+#url_filter.AuthUserHeader "X-Authenticated-User"
+#url_filter.AuthUserPrefix "Local://"
+#url_filter.AuthUserEncoded 0
+
+# Default policy settings
+# Values are: 0 - accept, 1 - reject, 2 - redirect
+#url_filter.DBOpenErrorPolicy	1
+#url_filter.DBQueryErrorPolicy	0
+#url_filter.UnknownRolePolicy	1
+#url_filter.MemcachedConnectErrorPolicy	1
+#url_filter.MemcachedMissPolicy		0
+#url_filter.EmptyCategoryPolicy		0
+#url_filter.CategoryNotFoundPolicy	1
+
+# Default value - LOG_INFO
+#url_filter.SyslogPriority		6
diff --git a/configure b/configure
index 00dc733..4791a03 100755
--- a/configure
+++ b/configure
@@ -719,7 +719,7 @@ MAKEFLAGS=
 SHELL=${CONFIG_SHELL-/bin/sh}
 
 # Identity of this package.
-PACKAGE_NAME='c_icap'
+PACKAGE_NAME='c-icap'
 PACKAGE_TARNAME='c_icap'
 PACKAGE_VERSION='060708rc3'
 PACKAGE_STRING='c_icap 060708rc3'
@@ -2306,7 +2306,7 @@ fi
 
 
 # Define the identity of the package.
- PACKAGE='c_icap'
+ PACKAGE='c-icap'
  VERSION='060708rc3'
 
 
@@ -13714,7 +13714,7 @@ else
 fi
 
 
-ac_config_files="$ac_config_files Makefile c-icap.conf services/Makefile services/echo/Makefile services/url_check/Makefile services/clamav/Makefile modules/Makefile"
+ac_config_files="$ac_config_files Makefile c-icap.conf services/Makefile services/echo/Makefile services/url_check/Makefile services/clamav/Makefile modules/Makefile services/url_filter/Makefile"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
diff --git a/configure.in b/configure.in
index afcaab0..a42c217 100644
--- a/configure.in
+++ b/configure.in
@@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script.
 
 
 #AC_INIT(c_icap,m4_normalize(m4_include([VERSION.m4])))
-AC_INIT(c_icap,060708rc3)
+AC_INIT(c-icap,060708rc3)
 
 AC_CONFIG_SRCDIR(aserver.c)
 AM_MAINTAINER_MODE
@@ -417,4 +417,4 @@ AM_CONDITIONAL(ISCYGWIN,[test a"$iscygwin" != a])
 AM_CONDITIONAL(USEPERL,[test a"$perlcore" != a])
 AM_CONDITIONAL(USECLAMAV,[test a"$clamav" != ano])
 
-AC_OUTPUT([Makefile c-icap.conf services/Makefile services/echo/Makefile services/url_check/Makefile services/clamav/Makefile modules/Makefile])
+AC_OUTPUT([Makefile c-icap.conf services/Makefile services/echo/Makefile services/url_check/Makefile services/clamav/Makefile modules/Makefile services/url_filter/Makefile])
diff --git a/contrib/get_file.pl b/contrib/get_file.pl
index f14d315..9860749 100644
--- a/contrib/get_file.pl
+++ b/contrib/get_file.pl
@@ -24,7 +24,7 @@ else{
 }
 
 
-$filename="/srv/www/htdocs/downloads/".$args{"file"};
+$filename="/var/www/html/downloads/".$args{"file"};
 my(@stat)=stat $filename;
 binmode(STDOUT);
 if(open (F,"<$filename")){
diff --git a/filetype.c b/filetype.c
index e019b12..a1bb997 100644
--- a/filetype.c
+++ b/filetype.c
@@ -299,7 +299,7 @@ int ci_magics_db_file_add(struct ci_magics_db *db, char *filename)
      struct ci_magic_record record;
      FILE *f;
 
-     if ((f = fopen(filename, "r+")) == NULL) {
+     if ((f = fopen(filename, "r")) == NULL) {
           ci_debug_printf(1, "Error opening magic file: %s\n", filename);
           return 0;
      }
diff --git a/include/debug.h b/include/debug.h
index 684ace6..ea44f12 100644
--- a/include/debug.h
+++ b/include/debug.h
@@ -36,7 +36,7 @@ CI_DECLARE_FUNC(void) __ldebug_printf(int i,const char *format, ...);
 
 #else
  extern void (*__log_error)(void *req, const char *format,... );
-#define ci_debug_printf(i, args...) if(i<=CI_DEBUG_LEVEL){ if(__log_error) (*__log_error)(NULL,args); if(CI_DEBUG_STDOUT) printf(args);}
+#define ci_debug_printf(i, args...) if(i<=CI_DEBUG_LEVEL){ if(CI_DEBUG_STDOUT) printf(args); if(__log_error) (*__log_error)(NULL,args);}
 #endif
 
 
diff --git a/services/Makefile.am b/services/Makefile.am
index 8396ed3..2e5dabd 100644
--- a/services/Makefile.am
+++ b/services/Makefile.am
@@ -3,7 +3,7 @@
 
 #SUBDIRS = @BUILD_SERVICES@
 
-SUBDIRS=echo url_check
+SUBDIRS=echo url_check url_filter
 
 if USECLAMAV
 SUBDIRS += clamav
diff --git a/services/Makefile.in b/services/Makefile.in
index c7373ea..240a387 100644
--- a/services/Makefile.in
+++ b/services/Makefile.in
@@ -58,7 +58,7 @@ RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
   distclean-recursive maintainer-clean-recursive
 ETAGS = etags
 CTAGS = ctags
-DIST_SUBDIRS = echo url_check clamav
+DIST_SUBDIRS = echo url_check clamav url_filter
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -185,7 +185,7 @@ sysconfdir = @sysconfdir@
 target_alias = @target_alias@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-SUBDIRS = echo url_check $(am__append_1)
+SUBDIRS = echo url_check url_filter $(am__append_1)
 all: all-recursive
 
 .SUFFIXES:
diff --git a/services/clamav/srv_clamav.c b/services/clamav/srv_clamav.c
index 0ad512f..4f4fe23 100644
--- a/services/clamav/srv_clamav.c
+++ b/services/clamav/srv_clamav.c
@@ -144,7 +144,7 @@ static struct ci_conf_entry conf_variables[] = {
 
 
 CI_DECLARE_MOD_DATA ci_service_module_t service = {
-     "srv_clamav",              /*Module name */
+     "clamav",              /*Module name */
      "Clamav/Antivirus service",        /*Module short description */
      ICAP_RESPMOD | ICAP_REQMOD,        /*Service type responce or request modification */
      srvclamav_init_service,    /*init_service. */
diff --git a/services/url_filter/Makefile.am b/services/url_filter/Makefile.am
new file mode 100644
index 0000000..5a7f19a
--- /dev/null
+++ b/services/url_filter/Makefile.am
@@ -0,0 +1,12 @@
+
+pkglib_LTLIBRARIES=srv_url_filter.la
+INCLUDES = -I$(top_srcdir)
+
+srv_url_filter_la_LIBADD = @MODULES_LIBADD@ -lmemcache -lopendbx
+srv_url_filter_la_CFLAGS=  -I../../include/
+srv_url_filter_la_LDFLAGS= -no-undefined -module -avoid-version
+srv_url_filter_la_SOURCES = srv_url_filter.c
+
+
+
+EXTRA_DIST= makefile.w32 srv_url_filter.def
diff --git a/services/url_filter/Makefile.in b/services/url_filter/Makefile.in
new file mode 100644
index 0000000..b89fc7d
--- /dev/null
+++ b/services/url_filter/Makefile.in
@@ -0,0 +1,501 @@
+# Makefile.in generated by automake 1.8.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+SOURCES = $(srv_url_filter_la_SOURCES)
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+subdir = services/url_filter
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(mkdir_p)
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+pkglibLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+srv_url_filter_la_DEPENDENCIES =
+am_srv_url_filter_la_OBJECTS = srv_url_filter_la-srv_url_filter.lo
+srv_url_filter_la_OBJECTS = $(am_srv_url_filter_la_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES =  \
+@AMDEP_TRUE@	./$(DEPDIR)/srv_url_filter_la-srv_url_filter.Plo
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(srv_url_filter_la_SOURCES)
+DIST_SOURCES = $(srv_url_filter_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DL_ADD_FLAG = @DL_ADD_FLAG@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+ISCYGWIN_FALSE = @ISCYGWIN_FALSE@
+ISCYGWIN_TRUE = @ISCYGWIN_TRUE@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MODULES_LIBADD = @MODULES_LIBADD@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THREADS_LDADD = @THREADS_LDADD@
+THREADS_LDFLAGS = @THREADS_LDFLAGS@
+USECLAMAV_FALSE = @USECLAMAV_FALSE@
+USECLAMAV_TRUE = @USECLAMAV_TRUE@
+USEPERL_FALSE = @USEPERL_FALSE@
+USEPERL_TRUE = @USEPERL_TRUE@
+VERSION = @VERSION@
+ZLIB_ADD_FLAG = @ZLIB_ADD_FLAG@
+ZLIB_ADD_LDFLAG = @ZLIB_ADD_LDFLAG@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_AS = @ac_ct_AS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DLLTOOL = @ac_ct_DLLTOOL@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_OBJDUMP = @ac_ct_OBJDUMP@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+clamavinc = @clamavinc@
+clamavlib = @clamavlib@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+perlccflags = @perlccflags@
+perlcore = @perlcore@
+perlldflags = @perlldflags@
+perllib = @perllib@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+pkglib_LTLIBRARIES = srv_url_filter.la
+INCLUDES = -I$(top_srcdir)
+srv_url_filter_la_LIBADD = @MODULES_LIBADD@ -lmemcache -lopendbx
+srv_url_filter_la_CFLAGS = -I../../include/ -I@prefix@/include
+srv_url_filter_la_LDFLAGS = -no-undefined -module -avoid-version -L@prefix@/lib
+srv_url_filter_la_SOURCES = srv_url_filter.c
+EXTRA_DIST = makefile.w32 srv_url_filter.def
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  services/url_filter/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  services/url_filter/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(mkdir_p) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  if test -f $$p; then \
+	    f="`echo $$p | sed -e 's|^.*/||'`"; \
+	    echo " $(LIBTOOL) --mode=install $(pkglibLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	    $(LIBTOOL) --mode=install $(pkglibLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(pkglibdir)/$$f"; \
+	  else :; fi; \
+	done
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	    p="`echo $$p | sed -e 's|^.*/||'`"; \
+	  echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$p'"; \
+	  $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$p"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" = "$$p" && dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+srv_url_filter.la: $(srv_url_filter_la_OBJECTS) $(srv_url_filter_la_DEPENDENCIES) 
+	$(LINK) -rpath $(pkglibdir) $(srv_url_filter_la_LDFLAGS) $(srv_url_filter_la_OBJECTS) $(srv_url_filter_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srv_url_filter_la-srv_url_filter.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+srv_url_filter_la-srv_url_filter.o: srv_url_filter.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(srv_url_filter_la_CFLAGS) $(CFLAGS) -MT srv_url_filter_la-srv_url_filter.o -MD -MP -MF "$(DEPDIR)/srv_url_filter_la-srv_url_filter.Tpo" -c -o srv_url_filter_la-srv_url_filter.o `test -f 'srv_url_filter.c' || echo '$(srcdir)/'`srv_url_filter.c; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/srv_url_filter_la-srv_url_filter.Tpo" "$(DEPDIR)/srv_url_filter_la-srv_url_filter.Po"; else rm -f "$(DEPDIR)/srv_url_filter_la-srv_url_filter.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='srv_url_filter.c' object='srv_url_filter_la-srv_url_filter.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/srv_url_filter_la-srv_url_filter.Po' tmpdepfile='$(DEPDIR)/srv_url_filter_la-srv_url_filter.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(srv_url_filter_la_CFLAGS) $(CFLAGS) -c -o srv_url_filter_la-srv_url_filter.o `test -f 'srv_url_filter.c' || echo '$(srcdir)/'`srv_url_filter.c
+
+srv_url_filter_la-srv_url_filter.obj: srv_url_filter.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(srv_url_filter_la_CFLAGS) $(CFLAGS) -MT srv_url_filter_la-srv_url_filter.obj -MD -MP -MF "$(DEPDIR)/srv_url_filter_la-srv_url_filter.Tpo" -c -o srv_url_filter_la-srv_url_filter.obj `if test -f 'srv_url_filter.c'; then $(CYGPATH_W) 'srv_url_filter.c'; else $(CYGPATH_W) '$(srcdir)/srv_url_filter.c'; fi`; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/srv_url_filter_la-srv_url_filter.Tpo" "$(DEPDIR)/srv_url_filter_la-srv_url_filter.Po"; else rm -f "$(DEPDIR)/srv_url_filter_la-srv_url_filter.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='srv_url_filter.c' object='srv_url_filter_la-srv_url_filter.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/srv_url_filter_la-srv_url_filter.Po' tmpdepfile='$(DEPDIR)/srv_url_filter_la-srv_url_filter.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(srv_url_filter_la_CFLAGS) $(CFLAGS) -c -o srv_url_filter_la-srv_url_filter.obj `if test -f 'srv_url_filter.c'; then $(CYGPATH_W) 'srv_url_filter.c'; else $(CYGPATH_W) '$(srcdir)/srv_url_filter.c'; fi`
+
+srv_url_filter_la-srv_url_filter.lo: srv_url_filter.c
+@am__fastdepCC_TRUE@	if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(srv_url_filter_la_CFLAGS) $(CFLAGS) -MT srv_url_filter_la-srv_url_filter.lo -MD -MP -MF "$(DEPDIR)/srv_url_filter_la-srv_url_filter.Tpo" -c -o srv_url_filter_la-srv_url_filter.lo `test -f 'srv_url_filter.c' || echo '$(srcdir)/'`srv_url_filter.c; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/srv_url_filter_la-srv_url_filter.Tpo" "$(DEPDIR)/srv_url_filter_la-srv_url_filter.Plo"; else rm -f "$(DEPDIR)/srv_url_filter_la-srv_url_filter.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='srv_url_filter.c' object='srv_url_filter_la-srv_url_filter.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/srv_url_filter_la-srv_url_filter.Plo' tmpdepfile='$(DEPDIR)/srv_url_filter_la-srv_url_filter.TPlo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(srv_url_filter_la_CFLAGS) $(CFLAGS) -c -o srv_url_filter_la-srv_url_filter.lo `test -f 'srv_url_filter.c' || echo '$(srcdir)/'`srv_url_filter.c
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$tags$$unique" \
+	  || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	     $$tags $$unique
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-pkglibLTLIBRARIES
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-exec \
+	install-exec-am install-info install-info-am install-man \
+	install-pkglibLTLIBRARIES install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-info-am \
+	uninstall-pkglibLTLIBRARIES
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/services/url_filter/makefile.w32 b/services/url_filter/makefile.w32
new file mode 100644
index 0000000..67b87d6
--- /dev/null
+++ b/services/url_filter/makefile.w32
@@ -0,0 +1,15 @@
+!include <win32.mak>
+
+all: srv_url_filter.Dll
+
+.c.obj:
+	$(cc) /I..\..\include /I..\..\ $(cdebug) $(cflags) $(cvarsdll) -I. -DCI_BUILD_MODULE -DUNICODE $*.c
+
+srv_url_filter.Dll: srv_url_filter.obj
+	$(link) $(linkdebug) $(dlllflags) /LIBPATH:..\..\ c_icap.lib -def:srv_url_filter.def -out:$*.Dll $** $(DLL_ENTRY)  $(EXTRA_LIBS)
+
+clean:
+	del *.obj *.dll *.lib
+
+
+
diff --git a/services/url_filter/srv_url_filter.c b/services/url_filter/srv_url_filter.c
new file mode 100644
index 0000000..eaca9e9
--- /dev/null
+++ b/services/url_filter/srv_url_filter.c
@@ -0,0 +1,892 @@
+/*
+ *  Copyright (C) 2004 Christos Tsantilas
+ *
+ *  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 "c-icap.h"
+#include "service.h"
+#include "header.h"
+#include "body.h"
+#include "simple_api.h"
+#include "debug.h"
+#include "ci_threads.h"
+#include <memcache.h>
+#include <errno.h>
+#undef HAVE_CONFIG_H
+#include <odbx.h>
+#include <regex.h>
+#include <syslog.h>
+#ifndef REG_BASIC
+#define REG_BASIC 0
+#endif
+
+#define CACHETTL	3600
+
+struct memcache *mc;
+
+int    url_filter_init_service(ci_service_xdata_t *srv_xdata,struct ci_server_conf *server_conf);
+int    url_filter_post_init_service(ci_service_xdata_t *srv_xdata,struct ci_server_conf *server_conf);
+void   url_filter_close_service (ci_service_xdata_t *srv_xdata);
+void * url_filter_init_request_data(ci_request_t *req);
+void   url_filter_release_data(void *data);
+int    url_filter_process(ci_request_t *);
+int    url_filter_check_preview(char *preview_data,int preview_data_len,ci_request_t *);
+int    url_filter_io(char *wbuf,int *wlen,char *rbuf,int *rlen,int iseof,ci_request_t *req);
+//int    url_filter_write(char *buf,int len ,int iseof,request_t *req);
+//int    url_filter_read(char *buf,int len,request_t *req);
+static unsigned dotip2int (char *str);
+static unsigned str2int (const char *str);
+
+static char	*MemcachedServers;
+static char	*Host2CatServer;
+static char	*DBEngine;
+static char	*DBHost;
+static char	*DBPort;
+static char	*DBName;
+static char	*DBUser;
+static char	*DBPass;
+static char	*RedirectUrl;
+static char	*ClientIPHeader = "X-Client-IP";
+static char	*AuthUserHeader = "X-Authenticated-User";
+static char	*AuthUserPrefix;
+static int	AuthUserEncoded = 1;
+// Values 0 - ACCEPT, 1 - REJECT, 2 - REDIRECT
+static int	DBOpenErrorPolicy = 1;	// SQLite database doesn't opened
+static int	DBQueryErrorPolicy = 0;	// Error executing SQLite query
+static int	UnknownRolePolicy = 1;		// Can't find role for user@ip
+static int	MemcachedConnectErrorPolicy = 1;// No connection to memcached server(s)
+static int	MemcachedMissPolicy = 0;	// Host category missed at memcached server(s)
+static int	EmptyCategoryPolicy = 0;	// No categories for host
+static int	CategoryNotFoundPolicy = 1;	// Host categories doesn't exists in roles definition
+static int	SyslogPriority = LOG_INFO;	// Priority for syslog()
+
+static int	fd = -1;
+static struct sockaddr_in	addr;
+static odbx_t	*dbh;
+
+static ci_thread_mutex_t mtx;
+
+static struct ci_conf_entry conf_variables[]={
+     {"MemcachedServers",&MemcachedServers,ci_cfg_set_str,NULL},
+     {"Host2CatServer",&Host2CatServer,ci_cfg_set_str,NULL},
+     {"DBEngine",&DBEngine,ci_cfg_set_str,NULL},
+     {"DBHost",&DBHost,ci_cfg_set_str,NULL},
+     {"DBPort",&DBPort,ci_cfg_set_str,NULL},
+     {"DBName",&DBName,ci_cfg_set_str,NULL},
+     {"DBUser",&DBUser,ci_cfg_set_str,NULL},
+     {"DBPass",&DBPass,ci_cfg_set_str,NULL},
+     {"RedirectUrl",&RedirectUrl,ci_cfg_set_str,NULL},
+     {"ClientIPHeader",&ClientIPHeader,ci_cfg_set_str,NULL},
+     {"AuthUserHeader",&AuthUserHeader,ci_cfg_set_str,NULL},
+     {"AuthUserPrefix",&AuthUserPrefix,ci_cfg_set_str,NULL},
+     {"AuthUserEncoded",&AuthUserEncoded,ci_cfg_set_int,NULL},
+     {"DBOpenErrorPolicy",&DBOpenErrorPolicy,ci_cfg_set_int,NULL},
+     {"DBQueryErrorPolicy",&DBQueryErrorPolicy,ci_cfg_set_int,NULL},
+     {"UnknownRolePolicy",&UnknownRolePolicy,ci_cfg_set_int,NULL},
+     {"MemcachedConnectErrorPolicy",&MemcachedConnectErrorPolicy,ci_cfg_set_int,NULL},
+     {"MemcachedMissPolicy",&MemcachedMissPolicy,ci_cfg_set_int,NULL},
+     {"EmptyCategoryPolicy",&EmptyCategoryPolicy,ci_cfg_set_int,NULL},
+     {"CategoryNotFoundPolicy",&CategoryNotFoundPolicy,ci_cfg_set_int,NULL},
+     {"SyslogPriority",&SyslogPriority,ci_cfg_set_int,NULL},
+     {NULL,NULL,NULL,NULL}
+};
+
+
+//service_module echo={
+CI_DECLARE_MOD_DATA ci_service_module_t service={
+     "url_filter",
+     "Url Filter service",
+     ICAP_REQMOD,
+     url_filter_init_service, /* init_service*/
+     url_filter_post_init_service, /*post_init_service*/
+     url_filter_close_service, /*close_Service*/
+     url_filter_init_request_data,/* init_request_data*/
+     url_filter_release_data, /*Release request data*/
+     url_filter_check_preview,
+     url_filter_process,
+     url_filter_io,
+     conf_variables,
+     NULL
+};
+ 
+struct url_filter_data{
+     ci_cached_file_t *body;
+     int denied;
+};
+
+enum http_methods {HTTP_UNKNOWN=0,HTTP_GET, HTTP_POST};
+
+struct http_info{
+    int http_major;
+    int http_minor;
+    int method;
+    char site[CI_MAXHOSTNAMELEN+1];
+    char page[1024]; /*I think it is enough*/
+//    char server_ip [CI_IPLEN + 1];
+    char *client_ip;
+    char auth_user [MAX_USERNAME_LEN + 1];
+};
+
+
+int url_filter_init_service(ci_service_xdata_t *srv_xdata,struct ci_server_conf *server_conf){
+    unsigned int xops;
+    printf("Initialization of url_filter module......\n");
+    ci_service_set_preview(srv_xdata, 0);
+    xops = CI_XCLIENTIP | CI_XSERVERIP;
+    xops |= CI_XAUTHENTICATEDUSER | CI_XAUTHENTICATEDGROUPS;
+    ci_service_set_xopts(srv_xdata, xops);
+    return CI_OK;
+}
+
+int url_filter_post_init_service (ci_service_xdata_t *srv_xdata,struct ci_server_conf *server_conf)
+{
+	int	nservers, retval;
+	char	*p, *p1, *ep;
+
+	if (!MemcachedServers || !*MemcachedServers) {
+		ci_debug_printf (1, "Empty MemcachedServers list\n");
+		return CI_ERROR;
+	}
+
+	if (!(mc = mc_new ())) {
+		ci_debug_printf (1, "No memory for mc structure\n");
+		return CI_ERROR;
+	}
+
+	ep = MemcachedServers + strlen(MemcachedServers);
+	for (nservers = 0, p = MemcachedServers; p < ep; p = p1 + 1) {
+		// p points to beginning of server, p1 points to end of server
+		p1 = strchr (p, ',');
+		if (!p1)        p1 = p + strlen (p);
+
+		if (p1 == p) {
+			ci_debug_printf (5, "Empty server in '%s' - ignored\n", MemcachedServers);
+		} else if ((retval = mc_server_add5 (mc, p, p1 - p))) {
+			ci_debug_printf (5, "server add for server %.*s returns %d\n", (int)(p1 - p), p, retval);
+		} else {
+			nservers++;
+			ci_debug_printf (5, "server %.*s successfully added\n", (int)(p1 - p), p);
+		}
+	}
+
+	if (!nservers) {
+		ci_debug_printf (1, "No servers added\n");
+		mc_free (mc);
+		mc = NULL;
+		return CI_ERROR;
+	}
+
+	if (!Host2CatServer || !*Host2CatServer) {
+		ci_debug_printf (1, "Empty Host2CatServer\n");
+		return CI_ERROR;
+	}
+
+	if (!(p = strchr (Host2CatServer, ':'))) {
+		ci_debug_printf (1, "No port number in Host2CatServer %s\n", Host2CatServer);
+		return CI_ERROR;
+	}
+
+	*p = 0;
+	bzero (&addr, sizeof addr);
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons (atoi (p + 1));
+	inet_pton (AF_INET, Host2CatServer, &addr.sin_addr);
+	*p = ':';
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd == -1) {
+		ci_debug_printf (1, "Can't open UDP socket to Host2CatServer: %s\n", strerror (errno));
+		return CI_ERROR;
+	}
+
+	if (!DBEngine || !*DBEngine) {
+		ci_debug_printf (1, "Empty DBEngine\n");
+		return CI_ERROR;
+	}
+
+	retval = odbx_init (&dbh, DBEngine, DBHost, DBPort);
+	if (retval != ODBX_ERR_SUCCESS) {
+		ci_debug_printf (1, "Error initializing DB handle: %s\n", odbx_error (dbh, retval));
+		return CI_ERROR;
+	}
+
+	if (!DBName || !*DBName) {
+		ci_debug_printf (1, "Empty DBName\n");
+		return CI_ERROR;
+	}
+
+	retval = odbx_bind_simple (dbh, DBName, DBUser, DBPass);
+	if (retval != ODBX_ERR_SUCCESS) {
+		ci_debug_printf (1, "Error binding to database: %s\n", odbx_error (dbh, retval));
+		odbx_finish (dbh);
+		dbh = NULL;
+		return CI_ERROR;
+	}
+
+	if (!RedirectUrl || !*RedirectUrl)	ci_debug_printf (1, "Empty redirect URL\n");
+
+	if (ci_thread_mutex_init(&mtx))
+		return CI_ERROR;
+
+	return CI_OK;
+}
+
+
+void url_filter_close_service (ci_service_xdata_t *srv_xdata)
+{
+	if (mc) {
+		mc_free (mc);
+		mc = NULL;
+	}
+	if (fd != -1)	close (fd);
+	if (dbh) {
+		odbx_unbind (dbh);
+		odbx_finish (dbh);
+	}
+
+	ci_thread_mutex_destroy(&mtx);
+}
+
+void *url_filter_init_request_data(ci_request_t *req){
+    struct url_filter_data *uc=malloc(sizeof(struct url_filter_data));
+    uc->body=NULL;
+    uc->denied = 0;
+    return uc; /*Get from a pool of pre-allocated structs better......*/
+}
+
+
+void url_filter_release_data(void *data){
+    struct url_filter_data *uc=data;
+    if(uc->body)
+	ci_cached_file_destroy(uc->body);
+    free(uc); /*Return object to pool.....*/
+}
+
+
+static int get_http_info(ci_request_t *req,ci_headers_list_t *req_header , struct http_info *httpinf){
+    char *str;
+    int i;
+
+        /*Now get the site name*/
+    str=ci_headers_value(req_header,"Host");
+    strncpy(httpinf->site,str,CI_MAXHOSTNAMELEN);
+    httpinf->site[CI_MAXHOSTNAMELEN]='\0';
+
+    str=req_header->headers[0];
+    if(str[0]=='g' || str[0]=='G') /*Get request....*/
+	httpinf->method=HTTP_GET;
+    else if(str[0]=='p' || str[0]=='P') /*post request....*/
+	httpinf->method=HTTP_POST;
+    else{
+	 httpinf->method=HTTP_UNKNOWN;
+	return 0;
+    }
+    if((str=strchr(str,' '))==NULL){ /*The request must have the form:GETPOST page HTTP/X.X */
+	 return 0;
+    }
+    while(*str==' ') str++;
+    i=0;
+    while(*str!=' ' && *str!='\0' && i<1022) /*copy page to the struct.*/
+	httpinf->page[i++]=*str++;
+    httpinf->page[i]='\0';
+
+    if(*str!=' '){ /*Where is the protocol info?????*/
+	 return 0;
+    }
+    while(*str==' ') str++;
+    if(*str!='H' || *(str+4)!='/'){ /*Not in HTTP/X.X form*/
+	 return 0;
+    }
+    str+=5;
+    httpinf->http_major=strtol(str,&str,10);
+    if(*str!='.'){
+	 return 0;
+    }
+    str++;
+    httpinf->http_minor=strtol(str,&str,10);
+
+    
+    return 1;
+}
+
+static int check_destination (struct http_info *httpinf, int policy)
+{
+	odbx_result_t	*sth;
+	unsigned	ip, role = 0, *ncats;
+	int	i, rc = CategoryNotFoundPolicy, retval;
+	char	*cats = NULL, *p, *p1, buf [1024], rname[64], *uname;
+	char	key[64], *val = NULL;
+	int	valsz, found;
+
+	uname = AuthUserPrefix && *AuthUserPrefix && !strncmp (httpinf->auth_user, AuthUserPrefix, strlen (AuthUserPrefix)) ? httpinf->auth_user + strlen (AuthUserPrefix) : httpinf->auth_user;
+	ip = dotip2int (httpinf->client_ip);
+	snprintf (key, sizeof key, "%s@%s", uname, httpinf->client_ip);
+	ci_debug_printf (5, "Uname: %s\n", uname);
+	ci_debug_printf (5, "IP: %s\n", httpinf->client_ip);
+	ci_debug_printf (5, "URL: %s\n", httpinf->page);
+	ci_debug_printf (5, "Host: %s\n", httpinf->site);
+
+	if (!dbh) {
+		ci_debug_printf (1, "DB handle doesn't opened\n");
+		rc = DBOpenErrorPolicy;
+		goto print_log;
+	}
+
+	// Find user role
+	ci_thread_mutex_lock(&mtx);
+	val = mc_aget(mc, key, strlen(key));
+	ci_thread_mutex_unlock(&mtx);
+	if (val) {
+		char *ptr;
+
+		ci_debug_printf(5, "Found role in cache\n");
+		role = strtol(val, NULL, 10);
+		ptr = strchr(val, ':') + 1;
+		strlcpy(rname, ptr, sizeof rname);
+		free(val);
+		goto cached_role;
+	}
+
+	snprintf (buf, sizeof buf, "SELECT u.addr, u.mask, u.rolid, r.rname FROM users u, roles r WHERE u.uname = '%s' AND u.rolid = r.rolid ORDER BY mask DESC", uname);
+
+	ci_thread_mutex_lock(&mtx);
+	retval = odbx_query (dbh, buf, strlen (buf));
+	if (retval != ODBX_ERR_SUCCESS) {
+		ci_debug_printf (1, "Error executing SQL query '%s': %s\n", buf, odbx_error (dbh, retval));
+		rc = DBQueryErrorPolicy;
+		ci_thread_mutex_unlock(&mtx);
+		goto print_log;
+	}
+
+	retval = odbx_result (dbh, &sth, NULL, 0);
+	ci_thread_mutex_unlock(&mtx);
+	if (retval < 0) {
+		ci_debug_printf (1, "Error getting SQL query result '%s': %s\n", buf, odbx_error (dbh, retval));
+		rc = DBQueryErrorPolicy;
+		goto print_log;
+	}
+
+	while ((retval = odbx_row_fetch (sth)) != 0) {
+		unsigned	net, mask;
+		if (retval < 0) {
+			ci_debug_printf (1, "Error fetching result row '%s', :%s\n", buf, odbx_error (dbh, retval));
+			break;
+		}
+		net = str2int (odbx_field_value (sth, 0));
+		mask = str2int (odbx_field_value (sth, 1));
+		if ((ip & mask) == net) {
+			role = str2int (odbx_field_value (sth, 2));
+			strlcpy (rname, odbx_field_value (sth, 3), sizeof rname);
+			break;
+		}
+	}
+
+	// Find default role
+	if (!role) {
+		odbx_result_free (sth);
+		snprintf (buf, sizeof buf, "SELECT u.addr, u.mask, u.rolid, r.rname FROM users u, roles r WHERE u.uname = '%s' AND u.rolid = r.rolid ORDER BY mask DESC", "");
+
+		ci_thread_mutex_lock(&mtx);
+		retval = odbx_query (dbh, buf, strlen (buf));
+		if (retval != ODBX_ERR_SUCCESS) {
+			ci_debug_printf (1, "Error executing SQL query '%s': %s\n", buf, odbx_error (dbh, retval));
+			rc = DBQueryErrorPolicy;
+			ci_thread_mutex_unlock(&mtx);
+			goto print_log;
+		}
+
+		retval = odbx_result (dbh, &sth, NULL, 0);
+		ci_thread_mutex_unlock(&mtx);
+		if (retval < 0) {
+			ci_debug_printf (1, "Error getting SQL query result '%s': %s\n", buf, odbx_error (dbh, retval));
+			rc = DBQueryErrorPolicy;
+			goto print_log;
+		}
+
+		while ((retval = odbx_row_fetch (sth)) != 0) {
+			unsigned	net, mask;
+			if (retval < 0) {
+				ci_debug_printf (1, "Error fetching result row '%s', :%s\n", buf, odbx_error (dbh, retval));
+				break;
+			}
+			net = str2int (odbx_field_value (sth, 0));
+			mask = str2int (odbx_field_value (sth, 1));
+			if ((ip & mask) == net) {
+				role = str2int (odbx_field_value (sth, 2));
+				strlcpy (rname, odbx_field_value (sth, 3), sizeof rname);
+				break;
+			}
+		}
+	}
+	odbx_result_free (sth);
+
+	if (role) {
+		snprintf(buf, sizeof buf, "%d:%s", role, rname);
+		ci_thread_mutex_lock(&mtx);
+		mc_add(mc, key, strlen(key), buf, strlen(buf) + 1, CACHETTL, 0);
+		ci_thread_mutex_unlock(&mtx);
+	}
+
+cached_role:
+	ci_debug_printf (5, "Role: %s\n", role ? rname : "UNKNOWN");
+	if (!role) {
+		rc = UnknownRolePolicy;
+		goto print_log;
+	}
+
+	// Read URL list
+	snprintf (key, sizeof key, "url:%s", rname);
+	ci_thread_mutex_lock(&mtx);
+	val = mc_aget(mc, key, strlen(key));
+	ci_thread_mutex_unlock(&mtx);
+	if (val) {
+		char *s;
+
+		ci_debug_printf(5, "Found URL list in cache\n");
+
+		for (s = val; *s;) {
+			regex_t	preg;
+			const char *url;
+			int action;
+
+			action = strtol(s, NULL, 10);
+			url = strchr(s, ':') + 1;
+			s = strchr(url, ' ');
+			*s++ = '\0';
+		
+			ci_debug_printf(9, "checking url %s against list: "
+			    "action %d, regex %s", httpinf->page, action, url);
+			rc = regcomp(&preg, url, REG_BASIC | REG_ICASE |
+			    REG_NOSUB);
+			if (rc) {
+				ci_debug_printf(1, "Error compiling regular "
+				    "expression '%s': %d\n", url, rc);
+				continue;
+			}
+			rc = regexec(&preg, httpinf->page, 0, NULL, 0);
+			regfree(&preg);
+			if (!rc) {
+				free(val);
+				rc = action;
+				goto print_log;
+			}
+		}
+		free(val);
+		goto cached_urls;
+	}
+
+	snprintf (buf, sizeof buf, "SELECT l.url, l.action FROM lists l, hierarchy h WHERE h.child = %d AND h.parent = l.rolid ORDER BY action DESC, rolid, stars, length (l.url)", role);
+
+	ci_thread_mutex_lock(&mtx);
+	retval = odbx_query (dbh, buf, strlen (buf));
+	if (retval != ODBX_ERR_SUCCESS) {
+		ci_debug_printf (1, "Error executing SQL query '%s': %s\n", buf, odbx_error (dbh, retval));
+		rc = DBQueryErrorPolicy;
+		ci_thread_mutex_unlock(&mtx);
+		goto print_log;
+	}
+
+	retval = odbx_result (dbh, &sth, NULL, 0);
+	ci_thread_mutex_unlock(&mtx);
+	if (retval < 0) {
+		ci_debug_printf (1, "Error getting SQL query result '%s': %s\n", buf, odbx_error (dbh, retval));
+		rc = DBQueryErrorPolicy;
+		goto print_log;
+	}
+
+
+	// Check URL list
+	val = NULL;
+	valsz = 1;
+	found = 0;
+	while ((retval = odbx_row_fetch (sth)) != 0) {
+		regex_t	preg;
+		const char	*url;
+		int	action;
+
+		if (retval < 0) {
+			ci_debug_printf (1, "Error fetching result row '%s': %s\n", buf, odbx_error (dbh, retval));
+			break;
+		}
+
+		if (val != (void *)-1) {
+			char *ptr;
+			int len;
+
+			len = strlen(odbx_field_value(sth, 0)) +
+			    strlen(odbx_field_value(sth, 1)) + 2;
+			if ((ptr = realloc(val, valsz + len)) == NULL) {
+				free(val);
+				val = (void *)-1;
+			} else {
+				val = ptr;
+				asprintf(&ptr, "%s:%s ",
+				    odbx_field_value(sth, 1),
+				    odbx_field_value(sth, 0));
+				if (ptr == NULL) {
+					free(val);
+					val = (void *)-1;
+				} else {
+					strcat(val, ptr);
+					valsz += len;
+				}
+			}
+		}
+
+		url = odbx_field_value (sth, 0);
+		action = str2int (odbx_field_value (sth, 1));
+		ci_debug_printf (9, "checking url %s against list: action %d, regex %s", httpinf->page, action, url);
+		rc = regcomp (&preg, url, REG_BASIC | REG_ICASE | REG_NOSUB);
+		if (rc) {
+			ci_debug_printf (1, "Error compiling regular expression '%s': %d\n", url, rc);
+			continue;
+		}
+		rc = regexec (&preg, httpinf->page, 0, NULL, 0);
+		regfree (&preg);
+		if (!rc && !found) {
+			found = 1;
+			rc = action;
+		}
+	}
+	odbx_result_free (sth);
+
+	if (val && val != (void *)-1) {
+		ci_thread_mutex_lock(&mtx);
+		mc_add(mc, key, strlen(key), val, strlen(val) + 1,
+		    CACHETTL, 0);
+		ci_thread_mutex_unlock(&mtx);
+		free(val);
+	}
+
+	if (found)
+		goto print_log;
+
+cached_urls:
+	// Get host category
+	if (!mc) {
+		rc = MemcachedConnectErrorPolicy;
+		goto print_log;
+	}
+	ci_thread_mutex_lock(&mtx);
+	cats = mc_aget (mc, (char *) httpinf->site, strlen (httpinf->site));
+	ci_thread_mutex_unlock(&mtx);
+	ci_debug_printf (5, "Cats: %s\n", cats ? cats : "MISSED");
+	if (!cats) {
+		if (fd != -1)	sendto (fd, httpinf->site, strlen (httpinf->site) + 1, 0, (struct sockaddr *)&addr, sizeof addr);
+		rc = MemcachedMissPolicy;
+		goto print_log;
+	}
+	if (!*cats) {
+		rc = EmptyCategoryPolicy;
+		goto print_log;
+	}
+
+	// Convert cats to array of unsigned
+	for (i = 1, p = strchr (cats, ':'); p; p = strchr (p + 1, ':'), i++)
+		;
+	ncats = calloc (i + 1, sizeof (unsigned));
+	for (i = 0, p = cats, p1 = strchr (p, ':'); *p; p1 = strchr (p, ':'), i++) {
+		if (p1)	*p1 = 0;
+		ncats [i] = str2int (p);
+		if (p1) {
+			*p1 = ':';
+			p = p1 + 1;
+		} else
+			p += strlen (p);
+	}
+	ncats [i] = 0;
+		
+	// Read category list
+	snprintf(key, sizeof key, "cat:%d", role);
+	ci_thread_mutex_lock(&mtx);
+	val = mc_aget(mc, key, strlen(key));
+	ci_thread_mutex_unlock(&mtx);
+	if (val) {
+		char *s;
+
+		ci_debug_printf(5, "Found category list in cache\n");
+
+		for (s = val; *s;) {
+			char *catstr;
+			int cat, action;
+			unsigned *u;
+
+			action = strtol(s, NULL, 10);
+			catstr = strchr(s, ':') + 1;
+			s = strchr(catstr, ' ');
+			*s++ = '\0';
+
+			cat = str2int(catstr);
+			for (u = ncats; *u; u++) {
+				ci_debug_printf(9, "checking host category %d "
+				    "against REJECT and REDIRECT category %d\n",
+				    *u, cat);
+				if (cat == *u) {
+					free(val);
+					rc = action;
+					goto print_log;
+				}
+			}
+		}
+
+		free(val);
+		goto print_log;
+	}
+
+	snprintf (buf, sizeof buf, "SELECT p.cat, p.action FROM perms p, hierarchy h WHERE h.child = %d AND h.parent = p.rolid ORDER BY action DESC, rolid", role);
+
+	ci_thread_mutex_lock(&mtx);
+	retval = odbx_query (dbh, buf, strlen (buf));
+	if (retval != ODBX_ERR_SUCCESS) {
+		ci_debug_printf (1, "Error executing SQL query '%s': %s\n", buf, odbx_error (dbh, retval));
+		free (ncats);
+		rc = DBQueryErrorPolicy;
+		ci_thread_mutex_unlock(&mtx);
+		goto print_log;
+	}
+
+	retval = odbx_result (dbh, &sth, NULL, 0);
+	ci_thread_mutex_unlock(&mtx);
+	if (retval < 0) {
+		ci_debug_printf (1, "Error getting SQL query result '%s': %s\n", buf, odbx_error (dbh, retval));
+		free (ncats);
+		rc = DBQueryErrorPolicy;
+		goto print_log;
+	}
+
+	// Check category list
+	val = NULL;
+	valsz = 1;
+	found = 0;
+	while ((retval = odbx_row_fetch (sth)) != 0) {
+		int	cat, action;
+		unsigned *u;
+
+		if (retval < 0) {
+			ci_debug_printf (1, "Error fetching result row '%s': %s\n", buf, odbx_error (dbh, retval));
+			break;
+		}
+
+		if (val != (void *)-1) {
+			char *ptr;
+			int len;
+
+			len = strlen(odbx_field_value(sth, 0)) +
+			    strlen(odbx_field_value(sth, 1)) + 2;
+			if ((ptr = realloc(val, valsz + len)) == NULL) {
+				free(val);
+				val = (void *)-1;
+			} else {
+				val = ptr;
+				asprintf(&ptr, "%s:%s ",
+				    odbx_field_value(sth, 1),
+				    odbx_field_value(sth, 0));
+				if (ptr == NULL) {
+					free(val);
+					val = (void *)-1;
+				} else {
+					strcat(val, ptr);
+					valsz += len;
+				}
+			}
+		}
+
+		cat = str2int (odbx_field_value (sth, 0));
+		action = str2int (odbx_field_value (sth, 1));
+		for (u = ncats; *u; u++) {
+			ci_debug_printf (9, "checking host category %d against REJECT and REDIRECT category %d\n", *u, cat);
+			if (cat == *u && !found) {
+				found = 1;
+				rc = action;
+			}
+		}
+	}
+	free (ncats);
+	odbx_result_free (sth);
+
+	if (val && val != (void *)-1) {
+		ci_thread_mutex_lock(&mtx);
+		mc_add(mc, key, strlen(key), val, strlen(val) + 1,
+		    CACHETTL, 0);
+		ci_thread_mutex_unlock(&mtx);
+		free(val);
+	}
+
+print_log:
+	// uname, ip, url, role, cats, action
+	syslog (SyslogPriority, "%s %s %s %s %s %s",
+		uname,
+		httpinf->client_ip,
+		httpinf->page,
+		role ? rname : "-",
+		cats ? cats : "-",
+		rc == 0 ? "ACCEPT" : rc == 1 ? "REJECT" : "REDIRECT"
+	);
+	if (cats)	free (cats);
+	return rc;
+}
+
+static char *reject_message="<H1>Permition deny!<H1>";
+static char *redirect_message="<H1>You are redirected!<H1>";
+//static char *server_ip = "X-Server-IP";
+
+int url_filter_check_preview(char *preview_data,int preview_data_len, ci_request_t *req){
+    ci_headers_list_t* req_header;
+    struct url_filter_data *uc=ci_service_data(req);
+    struct http_info httpinf;
+    int rc;
+
+    if((req_header=ci_http_request_headers(req))==NULL) /*It is not possible but who knows .....*/
+	return CI_ERROR;
+
+//    httpinf.server_ip = ci_headers_value (req->request_header, server_ip);
+//    ci_conn_remote_ip (req->connection, httpinf.server_ip);
+    httpinf.client_ip = ci_headers_value (req->request_header, ClientIPHeader);
+    httpinf.auth_user [0] = 0;
+    if (AuthUserEncoded)
+    	ci_base64_decode (ci_headers_value (req->request_header, AuthUserHeader), httpinf.auth_user, MAX_USERNAME_LEN);
+    else
+    	strncpy(httpinf.auth_user,ci_headers_value (req->request_header, AuthUserHeader),MAX_USERNAME_LEN);
+
+    get_http_info(req,req_header, &httpinf);
+
+    ci_debug_printf(9,"URL  to host %s\n",httpinf.site);
+    ci_debug_printf(9,"URL  page %s\n",httpinf.page);
+
+    rc=check_destination(&httpinf, 1);
+    ci_debug_printf (5, "Action: %s\n", rc == 0 ? "ACCEPT" : rc == 1 ? "REJECT" : "REDIRECT");
+
+    if (!rc) {
+	 /*if we are inside preview negotiation or client allow204 responces oudsite of preview then*/
+	 if(preview_data || ci_req_allow204(req)) 
+	      return CI_MOD_ALLOW204;
+	 
+	 /*
+	   Squid does not support preview of data in reqmod requests neither 204 responces outside preview
+	   so we need to read all the body if exists and send it back to squid.
+	   Allocate a new body for it 
+	 */
+	 if(ci_req_hasbody(req)){
+	      int clen=ci_http_content_lenght(req)+100;
+	      uc->body=ci_cached_file_new(clen);
+	 }
+
+    } else if (rc == 2 && RedirectUrl && *RedirectUrl) {
+	 char	buf [strlen (RedirectUrl) + 20];
+	 /*The URL is not a good one so....*/
+	 ci_debug_printf(9,"Oh!!! we are going to redirect this site.....\n");
+
+	 uc->denied = 1;
+	 uc->body=ci_cached_file_new(strlen(redirect_message)+10);
+	 ci_http_response_create(req,1,1); /*Build the responce headers*/
+
+	 ci_http_response_add_header(req,"HTTP/1.1 302 Found");/*Send an 302 Found http responce to web client*/
+	 ci_http_response_add_header(req,"Server: C-ICAP");
+	 snprintf (buf, sizeof buf, "Location: %s", RedirectUrl);
+	 ci_http_response_add_header(req,buf);
+	 ci_http_response_add_header(req,"Content-Type: text/html");
+	 ci_http_response_add_header(req,"Content-Language: en");
+	 
+	 ci_cached_file_write(uc->body,redirect_message,strlen(redirect_message),1);
+    } else {
+	 /*The URL is not a good one so....*/
+	 ci_debug_printf(9,"Oh!!! we are going to deny this site.....\n");
+
+	 uc->denied = 1;
+	 uc->body=ci_cached_file_new(strlen(reject_message)+10);
+	 ci_http_response_create(req,1,1); /*Build the responce headers*/
+
+	 ci_http_response_add_header(req,"HTTP/1.1 403 Forbidden");/*Send an 403 Forbidden http responce to web client*/
+	 ci_http_response_add_header(req,"Server: C-ICAP");
+	 ci_http_response_add_header(req,"Content-Type: text/html");
+	 ci_http_response_add_header(req,"Content-Language: en");
+	 
+	 ci_cached_file_write(uc->body,reject_message,strlen(reject_message),1);
+    }
+
+    unlock_data(req);
+    return CI_MOD_CONTINUE;
+}
+
+
+int url_filter_process(ci_request_t *req){
+
+/*
+	  printf("Buffer size=%d, Data size=%d\n ",
+		 ((struct membuf *)b)->bufsize,((struct membuf *)b)->endpos);
+*/  
+//    printf("url_filter process\n");
+     return CI_MOD_DONE;     
+}
+
+int url_filter_io(char *wbuf, int *wlen, char *rbuf, int *rlen, int iseof,
+                  ci_request_t * req)
+{
+     int ret;
+     struct url_filter_data *uc = ci_service_data(req);
+     if (!uc->body)
+          return CI_ERROR;
+
+     ret = CI_OK;
+     if (uc->denied == 0) {
+          if (rbuf && rlen) {
+               *rlen = ci_cached_file_write(uc->body, rbuf, *rlen, iseof);
+               if (*rlen == CI_ERROR)
+                    ret = CI_ERROR;
+          }
+          else if (iseof)
+               ci_cached_file_write(uc->body, NULL, 0, iseof);
+     }
+
+     if (wbuf && wlen) {
+          *wlen = ci_cached_file_read(uc->body, wbuf, *wlen);
+          if (*wlen == CI_ERROR)
+               ret = CI_ERROR;
+     }
+
+     return ret;
+}
+
+static unsigned dotip2int (char *str)
+{
+	unsigned	ip = 0, byte = 0;
+
+	for (; *str; str++) {
+		if (*str == '.') {
+			ip <<= 8;
+			ip += byte;
+			byte = 0;
+		} else {
+			byte *= 10;
+			byte += *str - '0';
+		}
+	}
+	ip <<= 8;
+	ip += byte;
+	return ip;
+}
+
+static unsigned str2int (const char *str)
+{
+	unsigned	ip = 0;
+
+	if (!str)	return 0;
+	for (; *str; str++) {
+		ip *= 10;
+		ip += *str - '0';
+	}
+	return ip;
+}
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin