2003-07-29 15:48:06 +00:00
/*
2025-02-14 10:24:30 -05:00
* Copyright ( C ) 2013 - 2025 Cisco Systems , Inc . and / or its affiliates . All rights reserved .
2019-01-25 10:15:50 -05:00
* Copyright ( C ) 2007 - 2013 Sourcefire , Inc .
2009-02-13 10:55:45 +00:00
*
* Authors : Tomasz Kojm , Trog , Török Edvin
2003-07-29 15:48:06 +00:00
*
* 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
2006-04-09 19:59:28 +00:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston ,
* MA 02110 - 1301 , USA .
2003-07-29 15:48:06 +00:00
*/
2006-09-13 22:06:13 +00:00
# if HAVE_CONFIG_H
# include "clamav-config.h"
# endif
2003-07-29 15:48:06 +00:00
# include <pthread.h>
2004-02-17 00:08:25 +00:00
# include <errno.h>
2003-07-29 15:48:06 +00:00
# include <signal.h>
2004-02-17 00:08:25 +00:00
# include <stdio.h>
2004-02-20 15:49:29 +00:00
# include <string.h>
2004-02-17 00:08:25 +00:00
# include <time.h>
2004-02-20 15:49:29 +00:00
# include <sys/types.h>
2018-12-03 12:40:13 -05:00
# ifndef _WIN32
2004-02-20 15:49:29 +00:00
# include <sys/socket.h>
2008-07-30 15:20:30 +00:00
# include <sys/time.h>
# include <sys/resource.h>
2009-09-30 00:54:04 +02:00
# include <arpa/inet.h>
2006-09-12 20:55:09 +00:00
# endif
2018-12-03 12:40:13 -05:00
# ifdef HAVE_UNISTD_H
2004-03-01 13:15:55 +00:00
# include <unistd.h>
2006-09-12 20:55:09 +00:00
# endif
2006-09-05 20:45:39 +00:00
2009-02-16 18:27:08 +00:00
# include <fcntl.h>
2009-11-24 10:25:41 +02:00
# ifdef C_SOLARIS
# include <stdio_ext.h>
# endif
2006-09-05 20:45:39 +00:00
Add CMake build tooling
This patch adds experimental-quality CMake build tooling.
The libmspack build required a modification to use "" instead of <> for
header #includes. This will hopefully be included in the libmspack
upstream project when adding CMake build tooling to libmspack.
Removed use of libltdl when using CMake.
Flex & Bison are now required to build.
If -DMAINTAINER_MODE, then GPERF is also required, though it currently
doesn't actually do anything. TODO!
I found that the autotools build system was generating the lexer output
but not actually compiling it, instead using previously generated (and
manually renamed) lexer c source. As a consequence, changes to the .l
and .y files weren't making it into the build. To resolve this, I
removed generated flex/bison files and fixed the tooling to use the
freshly generated files. Flex and bison are now required build tools.
On Windows, this adds a dependency on the winflexbison package,
which can be obtained using Chocolatey or may be manually installed.
CMake tooling only has partial support for building with external LLVM
library, and no support for the internal LLVM (to be removed in the
future). I.e. The CMake build currently only supports the bytecode
interpreter.
Many files used include paths relative to the top source directory or
relative to the current project, rather than relative to each build
target. Modern CMake support requires including internal dependency
headers the same way you would external dependency headers (albeit
with "" instead of <>). This meant correcting all header includes to
be relative to the build targets and not relative to the workspace.
For example, ...
```c
include "../libclamav/clamav.h"
include "clamd/clamd_others.h"
```
... becomes:
```c
// libclamav
include "clamav.h"
// clamd
include "clamd_others.h"
```
Fixes header name conflicts by renaming a few of the files.
Converted the "shared" code into a static library, which depends on
libclamav. The ironically named "shared" static library provides
features common to the ClamAV apps which are not required in
libclamav itself and are not intended for use by downstream projects.
This change was required for correct modern CMake practices but was
also required to use the automake "subdir-objects" option.
This eliminates warnings when running autoreconf which, in the next
version of autoconf & automake are likely to break the build.
libclamav used to build in multiple stages where an earlier stage is
a static library containing utils required by the "shared" code.
Linking clamdscan and clamdtop with this libclamav utils static lib
allowed these two apps to function without libclamav. While this is
nice in theory, the practical gains are minimal and it complicates
the build system. As such, the autotools and CMake tooling was
simplified for improved maintainability and this feature was thrown
out. clamdtop and clamdscan now require libclamav to function.
Removed the nopthreads version of the autotools
libclamav_internal_utils static library and added pthread linking to
a couple apps that may have issues building on some platforms without
it, with the intention of removing needless complexity from the
source. Kept the regular version of libclamav_internal_utils.la
though it is no longer used anywhere but in libclamav.
Added an experimental doxygen build option which attempts to build
clamav.h and libfreshclam doxygen html docs.
The CMake build tooling also may build the example program(s), which
isn't a feature in the Autotools build system.
Changed C standard to C90+ due to inline linking issues with socket.h
when linking libfreshclam.so on Linux.
Generate common.rc for win32.
Fix tabs/spaces in shared Makefile.am, and remove vestigial ifndef
from misc.c.
Add CMake files to the automake dist, so users can try the new
CMake tooling w/out having to build from a git clone.
clamonacc changes:
- Renamed FANOTIFY macro to HAVE_SYS_FANOTIFY_H to better match other
similar macros.
- Added a new clamav-clamonacc.service systemd unit file, based on
the work of ChadDevOps & Aaron Brighton.
- Added missing clamonacc man page.
Updates to clamdscan man page, add missing options.
Remove vestigial CL_NOLIBCLAMAV definitions (all apps now use
libclamav).
Rename Windows mspack.dll to libmspack.dll so all ClamAV-built
libraries have the lib-prefix with Visual Studio as with CMake.
2020-08-13 00:25:34 -07:00
// libclamav
# include "clamav.h"
# include "others.h"
# include "readdb.h"
2024-05-07 09:07:56 -07:00
# include "default.h"
2003-07-29 15:48:06 +00:00
2021-03-04 19:39:50 -08:00
// common
Add CMake build tooling
This patch adds experimental-quality CMake build tooling.
The libmspack build required a modification to use "" instead of <> for
header #includes. This will hopefully be included in the libmspack
upstream project when adding CMake build tooling to libmspack.
Removed use of libltdl when using CMake.
Flex & Bison are now required to build.
If -DMAINTAINER_MODE, then GPERF is also required, though it currently
doesn't actually do anything. TODO!
I found that the autotools build system was generating the lexer output
but not actually compiling it, instead using previously generated (and
manually renamed) lexer c source. As a consequence, changes to the .l
and .y files weren't making it into the build. To resolve this, I
removed generated flex/bison files and fixed the tooling to use the
freshly generated files. Flex and bison are now required build tools.
On Windows, this adds a dependency on the winflexbison package,
which can be obtained using Chocolatey or may be manually installed.
CMake tooling only has partial support for building with external LLVM
library, and no support for the internal LLVM (to be removed in the
future). I.e. The CMake build currently only supports the bytecode
interpreter.
Many files used include paths relative to the top source directory or
relative to the current project, rather than relative to each build
target. Modern CMake support requires including internal dependency
headers the same way you would external dependency headers (albeit
with "" instead of <>). This meant correcting all header includes to
be relative to the build targets and not relative to the workspace.
For example, ...
```c
include "../libclamav/clamav.h"
include "clamd/clamd_others.h"
```
... becomes:
```c
// libclamav
include "clamav.h"
// clamd
include "clamd_others.h"
```
Fixes header name conflicts by renaming a few of the files.
Converted the "shared" code into a static library, which depends on
libclamav. The ironically named "shared" static library provides
features common to the ClamAV apps which are not required in
libclamav itself and are not intended for use by downstream projects.
This change was required for correct modern CMake practices but was
also required to use the automake "subdir-objects" option.
This eliminates warnings when running autoreconf which, in the next
version of autoconf & automake are likely to break the build.
libclamav used to build in multiple stages where an earlier stage is
a static library containing utils required by the "shared" code.
Linking clamdscan and clamdtop with this libclamav utils static lib
allowed these two apps to function without libclamav. While this is
nice in theory, the practical gains are minimal and it complicates
the build system. As such, the autotools and CMake tooling was
simplified for improved maintainability and this feature was thrown
out. clamdtop and clamdscan now require libclamav to function.
Removed the nopthreads version of the autotools
libclamav_internal_utils static library and added pthread linking to
a couple apps that may have issues building on some platforms without
it, with the intention of removing needless complexity from the
source. Kept the regular version of libclamav_internal_utils.la
though it is no longer used anywhere but in libclamav.
Added an experimental doxygen build option which attempts to build
clamav.h and libfreshclam doxygen html docs.
The CMake build tooling also may build the example program(s), which
isn't a feature in the Autotools build system.
Changed C standard to C90+ due to inline linking issues with socket.h
when linking libfreshclam.so on Linux.
Generate common.rc for win32.
Fix tabs/spaces in shared Makefile.am, and remove vestigial ifndef
from misc.c.
Add CMake files to the automake dist, so users can try the new
CMake tooling w/out having to build from a git clone.
clamonacc changes:
- Renamed FANOTIFY macro to HAVE_SYS_FANOTIFY_H to better match other
similar macros.
- Added a new clamav-clamonacc.service systemd unit file, based on
the work of ChadDevOps & Aaron Brighton.
- Added missing clamonacc man page.
Updates to clamdscan man page, add missing options.
Remove vestigial CL_NOLIBCLAMAV definitions (all apps now use
libclamav).
Rename Windows mspack.dll to libmspack.dll so all ClamAV-built
libraries have the lib-prefix with Visual Studio as with CMake.
2020-08-13 00:25:34 -07:00
# include "output.h"
# include "optparser.h"
# include "misc.h"
# include "idmef_logging.h"
2015-06-18 09:33:04 +02:00
2003-07-29 15:48:06 +00:00
# include "server.h"
2004-02-17 00:08:25 +00:00
# include "thrmgr.h"
2004-01-20 10:37:54 +00:00
# include "session.h"
Add CMake build tooling
This patch adds experimental-quality CMake build tooling.
The libmspack build required a modification to use "" instead of <> for
header #includes. This will hopefully be included in the libmspack
upstream project when adding CMake build tooling to libmspack.
Removed use of libltdl when using CMake.
Flex & Bison are now required to build.
If -DMAINTAINER_MODE, then GPERF is also required, though it currently
doesn't actually do anything. TODO!
I found that the autotools build system was generating the lexer output
but not actually compiling it, instead using previously generated (and
manually renamed) lexer c source. As a consequence, changes to the .l
and .y files weren't making it into the build. To resolve this, I
removed generated flex/bison files and fixed the tooling to use the
freshly generated files. Flex and bison are now required build tools.
On Windows, this adds a dependency on the winflexbison package,
which can be obtained using Chocolatey or may be manually installed.
CMake tooling only has partial support for building with external LLVM
library, and no support for the internal LLVM (to be removed in the
future). I.e. The CMake build currently only supports the bytecode
interpreter.
Many files used include paths relative to the top source directory or
relative to the current project, rather than relative to each build
target. Modern CMake support requires including internal dependency
headers the same way you would external dependency headers (albeit
with "" instead of <>). This meant correcting all header includes to
be relative to the build targets and not relative to the workspace.
For example, ...
```c
include "../libclamav/clamav.h"
include "clamd/clamd_others.h"
```
... becomes:
```c
// libclamav
include "clamav.h"
// clamd
include "clamd_others.h"
```
Fixes header name conflicts by renaming a few of the files.
Converted the "shared" code into a static library, which depends on
libclamav. The ironically named "shared" static library provides
features common to the ClamAV apps which are not required in
libclamav itself and are not intended for use by downstream projects.
This change was required for correct modern CMake practices but was
also required to use the automake "subdir-objects" option.
This eliminates warnings when running autoreconf which, in the next
version of autoconf & automake are likely to break the build.
libclamav used to build in multiple stages where an earlier stage is
a static library containing utils required by the "shared" code.
Linking clamdscan and clamdtop with this libclamav utils static lib
allowed these two apps to function without libclamav. While this is
nice in theory, the practical gains are minimal and it complicates
the build system. As such, the autotools and CMake tooling was
simplified for improved maintainability and this feature was thrown
out. clamdtop and clamdscan now require libclamav to function.
Removed the nopthreads version of the autotools
libclamav_internal_utils static library and added pthread linking to
a couple apps that may have issues building on some platforms without
it, with the intention of removing needless complexity from the
source. Kept the regular version of libclamav_internal_utils.la
though it is no longer used anywhere but in libclamav.
Added an experimental doxygen build option which attempts to build
clamav.h and libfreshclam doxygen html docs.
The CMake build tooling also may build the example program(s), which
isn't a feature in the Autotools build system.
Changed C standard to C90+ due to inline linking issues with socket.h
when linking libfreshclam.so on Linux.
Generate common.rc for win32.
Fix tabs/spaces in shared Makefile.am, and remove vestigial ifndef
from misc.c.
Add CMake files to the automake dist, so users can try the new
CMake tooling w/out having to build from a git clone.
clamonacc changes:
- Renamed FANOTIFY macro to HAVE_SYS_FANOTIFY_H to better match other
similar macros.
- Added a new clamav-clamonacc.service systemd unit file, based on
the work of ChadDevOps & Aaron Brighton.
- Added missing clamonacc man page.
Updates to clamdscan man page, add missing options.
Remove vestigial CL_NOLIBCLAMAV definitions (all apps now use
libclamav).
Rename Windows mspack.dll to libmspack.dll so all ClamAV-built
libraries have the lib-prefix with Visual Studio as with CMake.
2020-08-13 00:25:34 -07:00
# include "clamd_others.h"
2004-03-29 00:00:58 +00:00
# include "shared.h"
2003-07-29 15:48:06 +00:00
2004-02-17 00:08:25 +00:00
# define BUFFSIZE 1024
2003-07-29 15:48:06 +00:00
2020-06-02 15:46:31 -04:00
typedef enum {
RELOAD_STAGE__IDLE ,
RELOAD_STAGE__RELOADING ,
RELOAD_STAGE__NEW_DB_AVAILABLE ,
} reload_stage_t ;
struct reload_th_t {
struct cl_settings * settings ;
char * dbdir ;
2020-06-30 22:39:52 -07:00
unsigned int dboptions ;
2020-06-02 15:46:31 -04:00
} ;
/*
* Global variables
*/
2018-12-03 12:40:13 -05:00
int progexit = 0 ;
pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER ;
int reload = 0 ;
time_t reloaded_time = 0 ;
2008-05-12 14:49:25 +00:00
pthread_mutex_t reload_mutex = PTHREAD_MUTEX_INITIALIZER ;
2018-12-03 12:40:13 -05:00
int sighup = 0 ;
2020-06-02 15:46:31 -04:00
2020-06-09 13:54:29 -04:00
static pthread_mutex_t reload_stage_mutex = PTHREAD_MUTEX_INITIALIZER ;
static reload_stage_t reload_stage = RELOAD_STAGE__IDLE ; /* protected by reload_stage_mutex */
struct cl_engine * g_newengine = NULL ; /* protected by reload_stage_mutex */
2020-06-02 15:46:31 -04:00
2014-06-05 12:20:57 -04:00
extern pthread_mutex_t logg_mutex ;
2009-02-12 16:51:09 +00:00
static struct cl_stat dbstat ;
2004-01-20 10:37:54 +00:00
2018-12-03 12:40:13 -05:00
void * event_wake_recv = NULL ;
2010-01-30 04:19:23 +01:00
void * event_wake_accept = NULL ;
2010-01-29 18:57:50 +01:00
2007-02-11 00:41:13 +00:00
static void scanner_thread ( void * arg )
2003-07-29 15:48:06 +00:00
{
2018-12-03 12:40:13 -05:00
client_conn_t * conn = ( client_conn_t * ) arg ;
# ifndef _WIN32
sigset_t sigset ;
2006-09-12 20:55:09 +00:00
# endif
2018-12-03 12:40:13 -05:00
int ret ;
int virus = 0 , errors = 0 ;
2004-02-17 00:08:25 +00:00
2018-12-03 12:40:13 -05:00
# ifndef _WIN32
2003-07-29 15:48:06 +00:00
/* ignore all signals */
sigfillset ( & sigset ) ;
2019-07-12 09:39:26 -07:00
/* The behavior of a process is undefined after it ignores a
2008-02-07 20:47:50 +00:00
* SIGFPE , SIGILL , SIGSEGV , or SIGBUS signal */
sigdelset ( & sigset , SIGFPE ) ;
sigdelset ( & sigset , SIGILL ) ;
sigdelset ( & sigset , SIGSEGV ) ;
# ifdef SIGBUS
sigdelset ( & sigset , SIGBUS ) ;
# endif
2009-02-12 16:51:09 +00:00
sigdelset ( & sigset , SIGTSTP ) ;
sigdelset ( & sigset , SIGCONT ) ;
2003-07-29 15:48:06 +00:00
pthread_sigmask ( SIG_SETMASK , & sigset , NULL ) ;
2006-09-12 20:55:09 +00:00
# endif
2003-07-29 15:48:06 +00:00
2009-02-12 16:51:09 +00:00
ret = command ( conn , & virus ) ;
if ( ret = = - 1 ) {
2018-12-03 12:40:13 -05:00
pthread_mutex_lock ( & exit_mutex ) ;
progexit = 1 ;
pthread_mutex_unlock ( & exit_mutex ) ;
errors = 1 ;
2009-02-12 16:51:09 +00:00
} else
2018-12-03 12:40:13 -05:00
errors = ret ;
2005-01-26 17:28:36 +00:00
2008-11-06 14:27:27 +00:00
thrmgr_setactiveengine ( NULL ) ;
2009-02-12 16:51:09 +00:00
if ( conn - > filename )
2018-12-03 12:40:13 -05:00
free ( conn - > filename ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Finished scanthread \n " ) ;
2021-11-30 11:18:35 -08:00
enum thrmgr_exit exit_code ;
if ( virus ! = 0 ) {
exit_code = EXIT_OTHER ;
} else if ( errors ! = 0 ) {
exit_code = EXIT_ERROR ;
} else {
exit_code = EXIT_OK ;
}
if ( thrmgr_group_finished ( conn - > group , exit_code ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Scanthread: connection shut down (FD %d) \n " , conn - > sd ) ;
2018-12-03 12:40:13 -05:00
/* close connection if we were last in group */
shutdown ( conn - > sd , 2 ) ;
closesocket ( conn - > sd ) ;
2009-02-12 16:51:09 +00:00
}
2008-11-12 16:19:43 +00:00
cl_engine_free ( conn - > engine ) ;
2008-07-29 21:35:58 +00:00
free ( conn ) ;
2004-02-17 00:08:25 +00:00
return ;
2003-07-29 15:48:06 +00:00
}
2009-02-17 20:05:35 +00:00
static int syncpipe_wake_recv_w = - 1 ;
2004-02-17 00:08:25 +00:00
void sighandler_th ( int sig )
2003-07-29 15:48:06 +00:00
{
2009-02-17 20:05:35 +00:00
int action = 0 ;
2018-12-03 12:40:13 -05:00
switch ( sig ) {
case SIGINT :
case SIGTERM :
progexit = 1 ;
action = 1 ;
break ;
# ifdef SIGHUP
case SIGHUP :
sighup = 1 ;
action = 1 ;
break ;
2006-09-12 20:55:09 +00:00
# endif
2004-03-02 12:58:04 +00:00
2018-12-03 12:40:13 -05:00
# ifdef SIGUSR2
case SIGUSR2 :
reload = 1 ;
action = 1 ;
break ;
2006-09-12 20:55:09 +00:00
# endif
2004-03-13 12:50:39 +00:00
2018-12-03 12:40:13 -05:00
default :
break ; /* Take no action on other signals - e.g. SIGPIPE */
2004-02-17 00:08:25 +00:00
}
2009-02-17 20:05:35 +00:00
/* a signal doesn't always wake poll(), for example on FreeBSD */
if ( action & & syncpipe_wake_recv_w ! = - 1 )
2018-12-03 12:40:13 -05:00
if ( write ( syncpipe_wake_recv_w , " " , 1 ) ! = 1 )
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Failed to write to syncpipe \n " ) ;
2004-02-17 00:08:25 +00:00
}
2003-07-29 15:48:06 +00:00
2020-06-02 15:46:31 -04:00
static int need_db_reload ( void )
{
if ( ! dbstat . entries ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " No stats for Database check - forcing reload \n " ) ;
2020-06-02 15:46:31 -04:00
return TRUE ;
}
if ( cl_statchkdir ( & dbstat ) = = 1 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " SelfCheck: Database modification detected. Forcing reload. \n " ) ;
2020-06-02 15:46:31 -04:00
return TRUE ;
}
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " SelfCheck: Database status OK. \n " ) ;
2020-06-02 15:46:31 -04:00
return FALSE ;
}
/**
* @ brief Thread entry point to load the signature databases & compile a new scanning engine .
*
* Once loaded , an event will be set to indicate that the new engine is ready .
*
* @ param arg A reload_th_t structure defining the db directory , db settings , engine settings .
* @ return void *
*/
static void * reload_th ( void * arg )
2004-02-17 00:08:25 +00:00
{
2020-06-02 15:46:31 -04:00
cl_error_t status = CL_EMALFDB ;
struct reload_th_t * rldata = arg ;
2021-04-08 19:16:11 -07:00
struct cl_engine * engine = NULL ;
unsigned int sigs = 0 ;
2018-12-03 12:40:13 -05:00
int retval ;
2020-06-02 15:46:31 -04:00
if ( NULL = = rldata | | NULL = = rldata - > dbdir | | NULL = = rldata - > settings ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " reload_th: Invalid arguments, unable to load signature databases. \n " ) ;
2020-06-02 15:46:31 -04:00
status = CL_EARG ;
goto done ;
}
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Reading databases from %s \n " , rldata - > dbdir ) ;
2020-06-02 15:46:31 -04:00
if ( NULL = = ( engine = cl_engine_new ( ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " reload_th: Can't initialize antivirus engine \n " ) ;
2020-06-02 15:46:31 -04:00
goto done ;
}
retval = cl_engine_settings_apply ( engine , rldata - > settings ) ;
if ( CL_SUCCESS ! = retval ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " reload_th: Failed to apply previous engine settings: %s \n " , cl_strerror ( retval ) ) ;
2020-06-30 22:39:52 -07:00
status = CL_EMEM ;
goto done ;
2020-06-02 15:46:31 -04:00
}
retval = cl_load ( rldata - > dbdir , engine , & sigs , rldata - > dboptions ) ;
if ( CL_SUCCESS ! = retval ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " reload_th: Database load failed: %s \n " , cl_strerror ( retval ) ) ;
2020-06-02 15:46:31 -04:00
goto done ;
}
retval = cl_engine_compile ( engine ) ;
if ( CL_SUCCESS ! = retval ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " reload_th: Database initialization error: can't compile engine: %s \n " , cl_strerror ( retval ) ) ;
2020-06-02 15:46:31 -04:00
goto done ;
}
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Database correctly reloaded (%u signatures) \n " , sigs ) ;
2020-06-02 15:46:31 -04:00
status = CL_SUCCESS ;
done :
if ( NULL ! = rldata ) {
if ( NULL ! = rldata - > settings ) {
cl_engine_settings_free ( rldata - > settings ) ;
2018-12-03 12:40:13 -05:00
}
2020-06-02 15:46:31 -04:00
if ( NULL ! = rldata - > dbdir ) {
free ( rldata - > dbdir ) ;
}
free ( rldata ) ;
}
2003-07-29 15:48:06 +00:00
2020-06-02 15:46:31 -04:00
if ( CL_SUCCESS ! = status ) {
if ( NULL ! = engine ) {
cl_engine_free ( engine ) ;
engine = NULL ;
2018-12-03 12:40:13 -05:00
}
2004-02-17 00:08:25 +00:00
}
2003-07-29 15:48:06 +00:00
2020-06-09 13:54:29 -04:00
pthread_mutex_lock ( & reload_stage_mutex ) ;
2020-06-02 15:46:31 -04:00
reload_stage = RELOAD_STAGE__NEW_DB_AVAILABLE ; /* New DB available */
g_newengine = engine ;
2020-06-09 13:54:29 -04:00
pthread_mutex_unlock ( & reload_stage_mutex ) ;
2020-06-02 15:46:31 -04:00
# ifdef _WIN32
SetEvent ( event_wake_recv ) ;
# else
if ( syncpipe_wake_recv_w ! = - 1 )
if ( write ( syncpipe_wake_recv_w , " " , 1 ) ! = 1 )
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Failed to write to syncpipe \n " ) ;
2020-06-02 15:46:31 -04:00
# endif
return NULL ;
}
/**
* @ brief Reload the database .
*
2021-07-14 15:33:52 -07:00
* @ param [ in , out ] engine The current scan engine , used to copy the settings .
2020-06-09 13:54:29 -04:00
* @ param dboptions The current database options , used to copy the options .
* @ param opts The command line options , used to get the database directory .
* @ return cl_error_t CL_SUCCESS if the reload thread was successfully started . This does not mean that the database has reloaded successfully .
2020-06-02 15:46:31 -04:00
*/
2020-06-09 13:54:29 -04:00
static cl_error_t reload_db ( struct cl_engine * * engine , unsigned int dboptions , const struct optstruct * opts , threadpool_t * thr_pool )
2020-06-02 15:46:31 -04:00
{
cl_error_t status = CL_EMALFDB ;
cl_error_t retval ;
2020-08-02 18:12:37 -04:00
struct reload_th_t * rldata = NULL ;
2020-06-02 15:46:31 -04:00
pthread_t th ;
pthread_attr_t th_attr ;
2020-06-09 13:54:29 -04:00
if ( NULL = = opts | | NULL = = engine ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " reload_db: Invalid arguments, unable to load signature databases. \n " ) ;
2020-06-02 15:46:31 -04:00
status = CL_EARG ;
goto done ;
}
rldata = malloc ( sizeof ( struct reload_th_t ) ) ;
if ( ! rldata ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " Failed to allocate reload context \n " ) ;
2020-06-02 15:46:31 -04:00
status = CL_EMEM ;
goto done ;
}
memset ( rldata , 0 , sizeof ( struct reload_th_t ) ) ;
rldata - > dboptions = dboptions ;
2020-06-09 13:54:29 -04:00
if ( * engine ) {
2018-12-03 12:40:13 -05:00
/* copy current settings */
2020-06-09 13:54:29 -04:00
rldata - > settings = cl_engine_settings_copy ( * engine ) ;
2020-06-02 15:46:31 -04:00
if ( ! rldata - > settings ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " Can't make a copy of the current engine settings \n " ) ;
2020-06-02 15:46:31 -04:00
goto done ;
}
2008-11-12 19:39:31 +00:00
}
2020-06-02 15:46:31 -04:00
rldata - > dbdir = strdup ( optget ( opts , " DatabaseDirectory " ) - > strarg ) ;
if ( ! rldata - > dbdir ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " Can't duplicate the database directory path \n " ) ;
2020-06-02 15:46:31 -04:00
goto done ;
}
2003-07-29 15:48:06 +00:00
2020-06-02 15:46:31 -04:00
if ( dbstat . entries ) {
2018-12-03 12:40:13 -05:00
cl_statfree ( & dbstat ) ;
2020-06-02 15:46:31 -04:00
}
2009-02-12 16:51:09 +00:00
memset ( & dbstat , 0 , sizeof ( struct cl_stat ) ) ;
2020-06-02 15:46:31 -04:00
retval = cl_statinidir ( rldata - > dbdir , & dbstat ) ;
if ( CL_SUCCESS ! = retval ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cl_statinidir() failed: %s \n " , cl_strerror ( retval ) ) ;
2020-06-02 15:46:31 -04:00
goto done ;
2018-12-03 12:40:13 -05:00
}
2020-06-09 13:54:29 -04:00
if ( * engine ) {
if ( ! optget ( opts , " ConcurrentDatabaseReload " ) - > enabled ) {
/*
* If concurrent reload disabled , we ' ll NULL out the current engine and deref it .
* It will only actually be free ' d once the last scan finishes .
*/
thrmgr_setactiveengine ( NULL ) ;
cl_engine_free ( * engine ) ;
* engine = NULL ;
/* Wait for all scans to finish */
thrmgr_wait_for_threads ( thr_pool ) ;
}
}
2020-06-02 15:46:31 -04:00
if ( pthread_attr_init ( & th_attr ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " Failed to init reload thread attributes \n " ) ;
2020-06-02 15:46:31 -04:00
goto done ;
2018-12-03 12:40:13 -05:00
}
2020-06-09 13:54:29 -04:00
if ( optget ( opts , " ConcurrentDatabaseReload " ) - > enabled ) {
/* For concurrent reloads: set detached, so we don't leak thread resources */
pthread_attr_setdetachstate ( & th_attr , PTHREAD_CREATE_DETACHED ) ;
}
2020-06-02 15:46:31 -04:00
retval = pthread_create ( & th , & th_attr , reload_th , rldata ) ;
if ( pthread_attr_destroy ( & th_attr ) )
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Failed to release reload thread attributes \n " ) ;
2020-06-02 15:46:31 -04:00
if ( retval ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " Failed to spawn reload thread \n " ) ;
2020-06-02 15:46:31 -04:00
goto done ;
2004-02-17 00:08:25 +00:00
}
2003-12-12 17:48:47 +00:00
2020-06-09 13:54:29 -04:00
if ( ! optget ( opts , " ConcurrentDatabaseReload " ) - > enabled ) {
/* For non-concurrent reloads: join the thread */
int join_ret = pthread_join ( th , NULL ) ;
switch ( join_ret ) {
case 0 :
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Database reload completed. \n " ) ;
2020-06-09 13:54:29 -04:00
break ;
case EDEADLK :
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " A deadlock was detected when waiting for the database reload thread. \n " ) ;
2020-06-09 13:54:29 -04:00
goto done ;
case ESRCH :
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " Failed to find database reload thread. \n " ) ;
2020-06-09 13:54:29 -04:00
goto done ;
case EINVAL :
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " The database reload thread is not a joinable thread. \n " ) ;
2020-06-09 13:54:29 -04:00
goto done ;
default :
2023-11-26 15:01:19 -08:00
logg ( LOGG_ERROR , " An unknown error occurred when waiting for the database reload thread: %d \n " , join_ret ) ;
2020-06-09 13:54:29 -04:00
goto done ;
}
}
2020-06-02 15:46:31 -04:00
status = CL_SUCCESS ;
2003-07-29 15:48:06 +00:00
2020-06-02 15:46:31 -04:00
done :
if ( CL_SUCCESS ! = status ) {
/*
* Failed to spawn reload thread , so we ' re responsible for cleaning up
* the rldata structure .
*/
if ( NULL ! = rldata ) {
if ( NULL ! = rldata - > settings ) {
cl_engine_settings_free ( rldata - > settings ) ;
}
if ( NULL ! = rldata - > dbdir ) {
free ( rldata - > dbdir ) ;
}
free ( rldata ) ;
}
2003-07-29 15:48:06 +00:00
}
2020-06-02 15:46:31 -04:00
return status ;
2003-07-29 15:48:06 +00:00
}
2009-02-16 18:26:58 +00:00
/*
* zCOMMANDS are delimited by \ 0
* nCOMMANDS are delimited by \ n
* Old - style non - prefixed commands are one packet , optionally delimited by \ n ,
* with trailing \ r | \ n ignored
*/
2009-02-17 18:04:48 +00:00
static const char * get_cmd ( struct fd_buf * buf , size_t off , size_t * len , char * term , int * oldstyle )
2009-02-12 16:51:09 +00:00
{
2010-04-13 16:19:47 +03:00
char * pos ;
2009-02-12 16:51:09 +00:00
if ( ! buf - > off | | off > = buf - > off ) {
2018-12-03 12:40:13 -05:00
* len = 0 ;
return NULL ;
2009-02-12 16:51:09 +00:00
}
* term = ' \n ' ;
2009-02-16 21:27:22 +00:00
switch ( buf - > buffer [ off ] ) {
2018-12-03 12:40:13 -05:00
/* commands terminated by delimiters */
case ' z ' :
* term = ' \0 ' ;
2020-11-06 22:16:23 -08:00
/* fall-through */
2018-12-03 12:40:13 -05:00
case ' n ' :
pos = memchr ( buf - > buffer + off , * term , buf - > off - off ) ;
if ( ! pos ) {
/* we don't have another full command yet */
* len = 0 ;
return NULL ;
}
* pos = ' \0 ' ;
if ( * term ) {
* len = cli_chomp ( buf - > buffer + off ) ;
} else {
* len = pos - buf - > buffer - off ;
}
* oldstyle = 0 ;
return buf - > buffer + off + 1 ;
default :
/* one packet = one command */
if ( off )
return NULL ;
pos = memchr ( buf - > buffer , ' \n ' , buf - > off ) ;
if ( pos ) {
* len = pos - buf - > buffer ;
* pos = ' \0 ' ;
} else {
* len = buf - > off ;
buf - > buffer [ buf - > off ] = ' \0 ' ;
}
cli_chomp ( buf - > buffer ) ;
* oldstyle = 1 ;
return buf - > buffer ;
2009-02-12 16:51:09 +00:00
}
}
2020-06-02 15:46:31 -04:00
int statinidir ( const char * dirname )
2015-06-16 14:56:32 -04:00
{
2018-12-03 12:40:13 -05:00
if ( ! dbstat . entries ) {
memset ( & dbstat , 0 , sizeof ( dbstat ) ) ;
}
2015-06-16 14:56:32 -04:00
2018-12-03 12:40:13 -05:00
return cl_statinidir ( dirname , & dbstat ) ;
2015-06-16 14:56:32 -04:00
}
2009-02-12 16:51:09 +00:00
struct acceptdata {
struct fd_data fds ;
struct fd_data recv_fds ;
2009-02-17 15:59:21 +00:00
pthread_cond_t cond_nfds ;
2025-09-09 10:07:34 -07:00
unsigned initial_fds ;
2009-02-17 15:59:21 +00:00
int max_queue ;
int commandtimeout ;
2009-02-12 16:51:09 +00:00
int syncpipe_wake_recv [ 2 ] ;
int syncpipe_wake_accept [ 2 ] ;
} ;
2025-09-09 10:07:34 -07:00
# define ACCEPTDATA_INIT(mutex1, mutex2) \
{ \
FDS_INIT ( mutex1 ) , FDS_INIT ( mutex2 ) , PTHREAD_COND_INITIALIZER , 0 , 0 , 0 , { - 1 , - 1 } , \
{ \
- 1 , - 1 \
} \
2018-12-03 12:40:13 -05:00
}
2009-02-14 09:14:04 +00:00
2009-02-12 16:51:09 +00:00
static void * acceptloop_th ( void * arg )
{
char buff [ BUFFSIZE + 1 ] ;
size_t i ;
2018-12-03 12:40:13 -05:00
struct acceptdata * data = ( struct acceptdata * ) arg ;
struct fd_data * fds = & data - > fds ;
2009-02-12 16:51:09 +00:00
struct fd_data * recv_fds = & data - > recv_fds ;
2018-12-03 12:40:13 -05:00
int max_queue = data - > max_queue ;
int commandtimeout = data - > commandtimeout ;
2009-02-12 16:51:09 +00:00
2009-05-06 07:56:28 +00:00
pthread_mutex_lock ( fds - > buf_mutex ) ;
2009-02-12 16:51:09 +00:00
for ( ; ; ) {
2018-12-03 12:40:13 -05:00
/* Block waiting for data to become available for reading */
int new_sd = fds_poll_recv ( fds , - 1 , 0 , event_wake_accept ) ;
2010-01-29 20:10:45 +01:00
# ifdef _WIN32
2018-12-03 12:40:13 -05:00
ResetEvent ( event_wake_accept ) ;
2010-01-29 20:10:45 +01:00
# endif
2018-12-03 12:40:13 -05:00
/* TODO: what about sockets that get rm-ed? */
if ( ! fds - > nfds ) {
/* no more sockets to poll, all gave an error */
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " Main socket gone: fatal \n " ) ;
2018-12-03 12:40:13 -05:00
break ;
}
if ( new_sd = = - 1 & & errno ! = EINTR ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " Failed to poll sockets, fatal \n " ) ;
2018-12-03 12:40:13 -05:00
pthread_mutex_lock ( & exit_mutex ) ;
progexit = 1 ;
pthread_mutex_unlock ( & exit_mutex ) ;
break ;
}
/* accept() loop */
for ( i = 0 ; i < fds - > nfds & & new_sd > = 0 ; i + + ) {
struct fd_buf * buf = & fds - > buf [ i ] ;
if ( ! buf - > got_newdata )
continue ;
2010-01-29 20:10:45 +01:00
# ifndef _WIN32
2018-12-03 12:40:13 -05:00
if ( buf - > fd = = data - > syncpipe_wake_accept [ 0 ] ) {
/* dummy sync pipe, just to wake us */
if ( read ( buf - > fd , buff , sizeof ( buff ) ) < 0 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Syncpipe read failed \n " ) ;
2018-12-03 12:40:13 -05:00
}
continue ;
}
2010-01-29 14:44:55 +01:00
# endif
2018-12-03 12:40:13 -05:00
if ( buf - > got_newdata = = - 1 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Acceptloop closed FD: %d \n " , buf - > fd ) ;
2018-12-03 12:40:13 -05:00
shutdown ( buf - > fd , 2 ) ;
closesocket ( buf - > fd ) ;
buf - > fd = - 1 ;
continue ;
}
/* don't accept unlimited number of connections, or
2022-02-16 00:13:55 +01:00
* we ' ll run out of file descriptors */
2018-12-03 12:40:13 -05:00
pthread_mutex_lock ( recv_fds - > buf_mutex ) ;
while ( recv_fds - > nfds > ( unsigned ) max_queue ) {
pthread_mutex_lock ( & exit_mutex ) ;
if ( progexit ) {
pthread_mutex_unlock ( & exit_mutex ) ;
break ;
}
pthread_mutex_unlock ( & exit_mutex ) ;
pthread_cond_wait ( & data - > cond_nfds , recv_fds - > buf_mutex ) ;
}
pthread_mutex_unlock ( recv_fds - > buf_mutex ) ;
pthread_mutex_lock ( & exit_mutex ) ;
if ( progexit ) {
pthread_mutex_unlock ( & exit_mutex ) ;
break ;
}
pthread_mutex_unlock ( & exit_mutex ) ;
/* listen only socket */
new_sd = accept ( fds - > buf [ i ] . fd , NULL , NULL ) ;
if ( new_sd > = 0 ) {
int ret , flags ;
2009-02-16 18:27:08 +00:00
# ifdef F_GETFL
2018-12-03 12:40:13 -05:00
flags = fcntl ( new_sd , F_GETFL , 0 ) ;
if ( flags ! = - 1 ) {
if ( fcntl ( new_sd , F_SETFL , flags | O_NONBLOCK ) = = - 1 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Can't set socket to nonblocking mode, errno %d \n " ,
2018-12-03 12:40:13 -05:00
errno ) ;
}
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Can't get socket flags, errno %d \n " , errno ) ;
2018-12-03 12:40:13 -05:00
}
2009-02-18 18:37:57 +00:00
# else
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Nonblocking sockets not available! \n " ) ;
2009-02-16 18:27:08 +00:00
# endif
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Got new connection, FD %d \n " , new_sd ) ;
2018-12-03 12:40:13 -05:00
pthread_mutex_lock ( recv_fds - > buf_mutex ) ;
ret = fds_add ( recv_fds , new_sd , 0 , commandtimeout ) ;
pthread_mutex_unlock ( recv_fds - > buf_mutex ) ;
if ( ret = = - 1 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " fds_add failed \n " ) ;
2018-12-03 12:40:13 -05:00
closesocket ( new_sd ) ;
continue ;
}
/* notify recvloop */
2010-01-29 14:44:55 +01:00
# ifdef _WIN32
2018-12-03 12:40:13 -05:00
SetEvent ( event_wake_recv ) ;
2010-01-29 14:44:55 +01:00
# else
2018-12-03 12:40:13 -05:00
if ( write ( data - > syncpipe_wake_recv [ 1 ] , " " , 1 ) = = - 1 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " write syncpipe failed \n " ) ;
2018-12-03 12:40:13 -05:00
continue ;
}
2010-01-29 14:44:55 +01:00
# endif
2018-12-03 12:40:13 -05:00
} else if ( errno ! = EINTR ) {
/* very bad - need to exit or restart */
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " accept() failed: %s \n " , cli_strerror ( errno , buff , BUFFSIZE ) ) ;
2018-12-03 12:40:13 -05:00
/* give the poll loop a chance to close disconnected FDs */
break ;
}
}
2009-02-12 16:51:09 +00:00
2018-12-03 12:40:13 -05:00
/* handle progexit */
pthread_mutex_lock ( & exit_mutex ) ;
if ( progexit ) {
pthread_mutex_unlock ( & exit_mutex ) ;
break ;
}
pthread_mutex_unlock ( & exit_mutex ) ;
2009-02-12 16:51:09 +00:00
}
2009-05-06 07:56:28 +00:00
pthread_mutex_unlock ( fds - > buf_mutex ) ;
2009-02-12 16:51:09 +00:00
2018-12-03 12:40:13 -05:00
if ( sd_listen_fds ( 0 ) = = 0 ) {
2016-02-09 13:46:13 -05:00
/* only close the sockets, when not using systemd socket activation */
2025-09-09 10:07:34 -07:00
for ( i = data - > initial_fds ; i < fds - > nfds ; i + + ) {
2016-02-09 13:46:13 -05:00
if ( fds - > buf [ i ] . fd = = - 1 )
continue ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Shutdown: closed fd %d \n " , fds - > buf [ i ] . fd ) ;
2016-02-09 13:46:13 -05:00
shutdown ( fds - > buf [ i ] . fd , 2 ) ;
closesocket ( fds - > buf [ i ] . fd ) ;
}
2009-02-12 16:51:09 +00:00
}
2016-02-09 13:46:13 -05:00
2009-02-12 16:51:09 +00:00
fds_free ( fds ) ;
2012-06-13 03:07:48 +00:00
pthread_mutex_destroy ( fds - > buf_mutex ) ;
2009-02-12 16:51:09 +00:00
pthread_mutex_lock ( & exit_mutex ) ;
progexit = 1 ;
pthread_mutex_unlock ( & exit_mutex ) ;
2010-01-29 14:44:55 +01:00
# ifdef _WIN32
2010-01-29 18:57:50 +01:00
SetEvent ( event_wake_recv ) ;
2010-01-29 14:44:55 +01:00
# else
2009-02-12 16:51:09 +00:00
if ( write ( data - > syncpipe_wake_recv [ 1 ] , " " , 1 ) < 0 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Syncpipe write failed \n " ) ;
2009-02-12 16:51:09 +00:00
}
2010-01-29 14:44:55 +01:00
# endif
2009-02-12 16:51:09 +00:00
return NULL ;
}
2018-12-03 12:40:13 -05:00
static const char * parse_dispatch_cmd ( client_conn_t * conn , struct fd_buf * buf , size_t * ppos , int * error , const struct optstruct * opts , int readtimeout )
2009-02-18 21:34:44 +00:00
{
2010-04-13 16:19:47 +03:00
const char * cmd = NULL ;
2009-02-18 21:34:44 +00:00
int rc ;
size_t cmdlen ;
char term ;
int oldstyle ;
size_t pos = * ppos ;
/* Parse & dispatch commands */
while ( ( conn - > mode = = MODE_COMMAND ) & &
2018-12-03 12:40:13 -05:00
( cmd = get_cmd ( buf , pos , & cmdlen , & term , & oldstyle ) ) ! = NULL ) {
const char * argument ;
enum commands cmdtype ;
if ( conn - > group & & oldstyle ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Received oldstyle command inside IDSESSION: %s \n " , cmd ) ;
2018-12-03 12:40:13 -05:00
conn_reply_error ( conn , " Only nCMDS \\ n and zCMDS \\ 0 are accepted inside IDSESSION. " ) ;
* error = 1 ;
break ;
}
cmdtype = parse_command ( cmd , & argument , oldstyle ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " got command %s (%u, %u), argument: %s \n " ,
2018-12-03 12:40:13 -05:00
cmd , ( unsigned ) cmdlen , ( unsigned ) cmdtype , argument ? argument : " " ) ;
if ( cmdtype = = COMMAND_FILDES ) {
if ( buf - > buffer + buf - > off < = cmd + strlen ( " FILDES \n " ) ) {
/* we need the extra byte from recvmsg */
conn - > mode = MODE_WAITANCILL ;
buf - > mode = MODE_WAITANCILL ;
/* put term back */
buf - > buffer [ pos + cmdlen ] = term ;
cmdlen = 0 ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " RECVTH: mode -> MODE_WAITANCILL \n " ) ;
2018-12-03 12:40:13 -05:00
break ;
}
/* eat extra \0 for controlmsg */
cmdlen + + ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " RECVTH: FILDES command complete \n " ) ;
2018-12-03 12:40:13 -05:00
}
conn - > term = term ;
buf - > term = term ;
if ( ( rc = execute_or_dispatch_command ( conn , cmdtype , argument ) ) < 0 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " Command dispatch failed \n " ) ;
2018-12-03 12:40:13 -05:00
if ( rc = = - 1 & & optget ( opts , " ExitOnOOM " ) - > enabled ) {
pthread_mutex_lock ( & exit_mutex ) ;
progexit = 1 ;
pthread_mutex_unlock ( & exit_mutex ) ;
}
* error = 1 ;
}
if ( thrmgr_group_need_terminate ( conn - > group ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Receive thread: have to terminate group \n " ) ;
2018-12-03 12:40:13 -05:00
* error = CL_ETIMEOUT ;
break ;
}
if ( * error | | ! conn - > group | | rc ) {
if ( rc & & thrmgr_group_finished ( conn - > group , EXIT_OK ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Receive thread: closing conn (FD %d), group finished \n " , conn - > sd ) ;
2018-12-03 12:40:13 -05:00
/* if there are no more active jobs */
shutdown ( conn - > sd , 2 ) ;
closesocket ( conn - > sd ) ;
buf - > fd = - 1 ;
conn - > group = NULL ;
} else if ( conn - > mode ! = MODE_STREAM ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " mode -> MODE_WAITREPLY \n " ) ;
2018-12-03 12:40:13 -05:00
/* no more commands are accepted */
conn - > mode = MODE_WAITREPLY ;
/* Stop monitoring this FD, it will be closed either
2019-05-04 15:54:54 -04:00
* by us , or by the scanner thread .
* Never close a file descriptor that is being
* monitored by poll ( ) / select ( ) from another thread ,
* because this can lead to subtle bugs such as :
* Other thread closes file descriptor - > POLLHUP is
* set , but the poller thread doesn ' t wake up yet .
* Another client opens a connection and sends some
* data . If the socket reuses the previous file descriptor ,
* then POLLIN is set on the file descriptor too .
* When poll ( ) wakes up it sees POLLIN | POLLHUP
* and thinks that the client has sent some data ,
* and closed the connection , so clamd closes the
* connection in turn resulting in a bug .
*
* If we wouldn ' t have poll ( ) - ed the file descriptor
* we closed in another thread , but rather made sure
* that we don ' t put a FD that we ' re about to close
* into poll ( ) ' s list of watched fds ; then POLLHUP
* would be set , but the file descriptor would stay
* open , until we wake up from poll ( ) and close it .
* Thus a new connection won ' t be able to reuse the
* same FD , and there is no bug .
*/
2018-12-03 12:40:13 -05:00
buf - > fd = - 1 ;
}
}
/* we received a command, set readtimeout */
time ( & buf - > timeout_at ) ;
buf - > timeout_at + = readtimeout ;
pos + = cmdlen + 1 ;
if ( conn - > mode = = MODE_STREAM ) {
/* TODO: this doesn't belong here */
buf - > dumpname = conn - > filename ;
buf - > dumpfd = conn - > scanfd ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Receive thread: INSTREAM: %s fd %u \n " , buf - > dumpname , buf - > dumpfd ) ;
2018-12-03 12:40:13 -05:00
}
if ( conn - > mode ! = MODE_COMMAND ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Breaking command loop, mode is no longer MODE_COMMAND \n " ) ;
2018-12-03 12:40:13 -05:00
break ;
}
conn - > id + + ;
2009-02-18 21:34:44 +00:00
}
2018-12-03 12:40:13 -05:00
* ppos = pos ;
buf - > mode = conn - > mode ;
buf - > id = conn - > id ;
2009-02-18 21:34:44 +00:00
buf - > group = conn - > group ;
buf - > quota = conn - > quota ;
if ( conn - > scanfd ! = - 1 & & conn - > scanfd ! = buf - > dumpfd ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Unclaimed file descriptor received, closing: %d \n " , conn - > scanfd ) ;
2018-12-03 12:40:13 -05:00
close ( conn - > scanfd ) ;
/* protocol error */
conn_reply_error ( conn , " PROTOCOL ERROR: ancillary data sent without FILDES. " ) ;
* error = 1 ;
return NULL ;
2009-02-18 21:34:44 +00:00
}
if ( ! * error ) {
2018-12-03 12:40:13 -05:00
/* move partial command to beginning of buffer */
if ( pos < buf - > off ) {
memmove ( buf - > buffer , & buf - > buffer [ pos ] , buf - > off - pos ) ;
buf - > off - = pos ;
} else
buf - > off = 0 ;
if ( buf - > off )
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Moved partial command: %lu \n " , ( unsigned long ) buf - > off ) ;
2018-12-03 12:40:13 -05:00
else
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Consumed entire command \n " ) ;
2018-12-03 12:40:13 -05:00
/* adjust pos to account for the buffer shuffle */
pos = 0 ;
2009-02-18 21:34:44 +00:00
}
* ppos = pos ;
return cmd ;
}
2009-12-16 15:23:25 +01:00
/* static const unsigned char* parse_dispatch_cmd(client_conn_t *conn, struct fd_buf *buf, size_t *ppos, int *error, const struct optstruct *opts, int readtimeout) */
2009-04-06 09:26:11 +00:00
static int handle_stream ( client_conn_t * conn , struct fd_buf * buf , const struct optstruct * opts , int * error , size_t * ppos , int readtimeout )
2009-02-18 21:34:44 +00:00
{
int rc ;
size_t pos = * ppos ;
size_t cmdlen ;
2018-12-03 12:40:13 -05:00
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " mode == MODE_STREAM \n " ) ;
2012-11-28 16:15:44 -08:00
/* we received some data, set readtimeout */
2009-04-06 09:26:11 +00:00
time ( & buf - > timeout_at ) ;
buf - > timeout_at + = readtimeout ;
2012-11-28 16:15:44 -08:00
while ( pos < = buf - > off ) {
2018-12-03 12:40:13 -05:00
if ( ! buf - > chunksize ) {
/* read chunksize */
if ( buf - > off - pos > = 4 ) {
uint32_t cs ;
memmove ( & cs , buf - > buffer + pos , 4 ) ;
pos + = 4 ;
buf - > chunksize = ntohl ( cs ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Got chunksize: %u \n " , buf - > chunksize ) ;
2018-12-03 12:40:13 -05:00
if ( ! buf - > chunksize ) {
/* chunksize 0 marks end of stream */
conn - > scanfd = buf - > dumpfd ;
conn - > term = buf - > term ;
buf - > dumpfd = - 1 ;
buf - > mode = buf - > group ? MODE_COMMAND : MODE_WAITREPLY ;
if ( buf - > mode = = MODE_WAITREPLY )
buf - > fd = - 1 ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Chunks complete \n " ) ;
2018-12-03 12:40:13 -05:00
buf - > dumpname = NULL ;
if ( ( rc = execute_or_dispatch_command ( conn , COMMAND_INSTREAMSCAN , NULL ) ) < 0 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " Command dispatch failed \n " ) ;
2018-12-03 12:40:13 -05:00
if ( rc = = - 1 & & optget ( opts , " ExitOnOOM " ) - > enabled ) {
pthread_mutex_lock ( & exit_mutex ) ;
progexit = 1 ;
pthread_mutex_unlock ( & exit_mutex ) ;
}
* error = 1 ;
} else {
memmove ( buf - > buffer , & buf - > buffer [ pos ] , buf - > off - pos ) ;
buf - > off - = pos ;
* ppos = 0 ;
buf - > id + + ;
return 0 ;
2012-11-28 16:15:44 -08:00
}
2018-12-03 12:40:13 -05:00
}
if ( buf - > chunksize > buf - > quota ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " INSTREAM: Size limit reached, (requested: %lu, max: %lu) \n " ,
2018-12-03 12:40:13 -05:00
( unsigned long ) buf - > chunksize , ( unsigned long ) buf - > quota ) ;
conn_reply_error ( conn , " INSTREAM size limit exceeded. " ) ;
2012-11-28 16:15:44 -08:00
* error = 1 ;
2018-12-03 12:40:13 -05:00
* ppos = pos ;
return - 1 ;
2012-11-28 16:15:44 -08:00
} else {
2018-12-03 12:40:13 -05:00
buf - > quota - = buf - > chunksize ;
2012-11-28 16:15:44 -08:00
}
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Quota Remaining: %lu \n " , buf - > quota ) ;
2018-12-03 12:40:13 -05:00
} else {
/* need more data, so return and wait for some */
memmove ( buf - > buffer , & buf - > buffer [ pos ] , buf - > off - pos ) ;
buf - > off - = pos ;
* ppos = 0 ;
2012-11-28 16:15:44 -08:00
return - 1 ;
}
2018-12-03 12:40:13 -05:00
}
if ( pos + buf - > chunksize < buf - > off )
cmdlen = buf - > chunksize ;
else
cmdlen = buf - > off - pos ;
buf - > chunksize - = cmdlen ;
2019-05-04 15:54:54 -04:00
if ( cli_writen ( buf - > dumpfd , buf - > buffer + pos , cmdlen ) = = ( size_t ) - 1 ) {
2018-12-03 12:40:13 -05:00
conn_reply_error ( conn , " Error writing to temporary file " ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " INSTREAM: Can't write to temporary file. \n " ) ;
2018-12-03 12:40:13 -05:00
* error = 1 ;
}
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Processed %llu bytes of chunkdata, pos %llu \n " , ( long long unsigned ) cmdlen , ( long long unsigned ) pos ) ;
2018-12-03 12:40:13 -05:00
pos + = cmdlen ;
if ( pos = = buf - > off ) {
buf - > off = 0 ;
pos = 0 ;
/* need more data, so return and wait for some */
* ppos = pos ;
2012-11-28 16:15:44 -08:00
return - 1 ;
2018-12-03 12:40:13 -05:00
}
2009-02-18 21:34:44 +00:00
}
* ppos = pos ;
return 0 ;
}
2020-06-02 15:46:31 -04:00
int recvloop ( int * socketds , unsigned nsockets , struct cl_engine * engine , unsigned int dboptions , const struct optstruct * opts )
2003-07-29 15:48:06 +00:00
{
2018-12-03 12:40:13 -05:00
int max_threads , max_queue , readtimeout , ret = 0 ;
struct cl_scan_options options ;
char timestr [ 32 ] ;
# ifndef _WIN32
struct sigaction sigact ;
sigset_t sigset ;
struct rlimit rlim ;
2006-09-12 20:55:09 +00:00
# endif
2018-12-03 12:40:13 -05:00
const struct optstruct * opt ;
char buff [ BUFFSIZE + 1 ] ;
int idletimeout ;
unsigned long long val ;
size_t i , j , rr_last = 0 ;
pthread_t accept_th ;
pthread_mutex_t fds_mutex = PTHREAD_MUTEX_INITIALIZER ;
pthread_mutex_t recvfds_mutex = PTHREAD_MUTEX_INITIALIZER ;
struct acceptdata acceptdata = ACCEPTDATA_INIT ( & fds_mutex , & recvfds_mutex ) ;
struct fd_data * fds = & acceptdata . recv_fds ;
time_t start_time , current_time ;
unsigned int selfchk ;
threadpool_t * thr_pool ;
2004-03-07 23:34:29 +00:00
2025-09-09 10:07:34 -07:00
// Initial sockets will be closed in clamd.c
acceptdata . initial_fds = nsockets ;
2018-12-03 12:40:13 -05:00
# ifndef _WIN32
memset ( & sigact , 0 , sizeof ( struct sigaction ) ) ;
2006-09-12 20:55:09 +00:00
# endif
2003-07-29 15:48:06 +00:00
2023-11-26 15:01:19 -08:00
/* Initialize scan options struct */
2018-12-03 12:40:13 -05:00
memset ( & options , 0 , sizeof ( struct cl_scan_options ) ) ;
2018-07-20 22:28:48 -04:00
2008-11-12 16:19:43 +00:00
/* set up limits */
2019-08-16 17:18:59 -07:00
if ( ( opt = optget ( opts , " MaxScanTime " ) ) - > active ) {
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_MAX_SCANTIME , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cl_engine_set_num(CL_ENGINE_MAX_SCANTIME) failed: %s \n " , cl_strerror ( ret ) ) ;
2019-08-16 17:18:59 -07:00
cl_engine_free ( engine ) ;
return 1 ;
}
}
val = cl_engine_get_num ( engine , CL_ENGINE_MAX_SCANTIME , NULL ) ;
if ( val )
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: Global time limit set to %llu milliseconds. \n " , val ) ;
2019-08-16 17:18:59 -07:00
else
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Limits: Global time limit protection disabled. \n " ) ;
2019-08-16 17:18:59 -07:00
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " MaxScanSize " ) ) - > active ) {
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_MAX_SCANSIZE , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cl_engine_set_num(CL_ENGINE_MAX_SCANSIZE) failed: %s \n " , cl_strerror ( ret ) ) ;
2018-12-03 12:40:13 -05:00
cl_engine_free ( engine ) ;
return 1 ;
}
2003-07-29 15:48:06 +00:00
}
2009-03-12 15:21:36 +00:00
val = cl_engine_get_num ( engine , CL_ENGINE_MAX_SCANSIZE , NULL ) ;
2018-12-03 12:40:13 -05:00
if ( val )
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: Global size limit set to %llu bytes. \n " , val ) ;
2008-11-12 16:19:43 +00:00
else
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Limits: Global size limit protection disabled. \n " ) ;
2008-02-07 02:00:21 +00:00
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " MaxFileSize " ) ) - > active ) {
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_MAX_FILESIZE , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cl_engine_set_num(CL_ENGINE_MAX_FILESIZE) failed: %s \n " , cl_strerror ( ret ) ) ;
2018-12-03 12:40:13 -05:00
cl_engine_free ( engine ) ;
return 1 ;
}
2008-02-12 03:19:50 +00:00
}
2009-03-12 15:21:36 +00:00
val = cl_engine_get_num ( engine , CL_ENGINE_MAX_FILESIZE , NULL ) ;
2018-12-03 12:40:13 -05:00
if ( val )
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: File size limit set to %llu bytes. \n " , val ) ;
2008-11-12 16:19:43 +00:00
else
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Limits: File size limit protection disabled. \n " ) ;
2003-07-29 15:48:06 +00:00
2009-09-30 00:54:04 +02:00
# ifndef _WIN32
2018-12-03 12:40:13 -05:00
if ( getrlimit ( RLIMIT_FSIZE , & rlim ) = = 0 ) {
if ( rlim . rlim_cur < ( rlim_t ) cl_engine_get_num ( engine , CL_ENGINE_MAX_FILESIZE , NULL ) )
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " System limit for file size is lower than engine->maxfilesize \n " ) ;
2018-12-03 12:40:13 -05:00
if ( rlim . rlim_cur < ( rlim_t ) cl_engine_get_num ( engine , CL_ENGINE_MAX_SCANSIZE , NULL ) )
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " System limit for file size is lower than engine->maxscansize \n " ) ;
2008-07-30 15:20:30 +00:00
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Cannot obtain resource limits for file size \n " ) ;
2008-07-30 15:20:30 +00:00
}
# endif
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " MaxRecursion " ) ) - > active ) {
2024-05-07 09:07:56 -07:00
if ( ( 0 = = opt - > numarg ) | | ( opt - > numarg > CLI_MAX_MAXRECLEVEL ) ) {
logg ( LOGG_ERROR , " MaxRecursion set to %zu, but cannot be larger than %u, and cannot be 0. \n " ,
2024-09-09 12:46:33 -04:00
( size_t ) opt - > numarg , CLI_MAX_MAXRECLEVEL ) ;
2024-05-07 09:07:56 -07:00
cl_engine_free ( engine ) ;
return 1 ;
}
2018-12-03 12:40:13 -05:00
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_MAX_RECURSION , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cl_engine_set_num(CL_ENGINE_MAX_RECURSION) failed: %s \n " , cl_strerror ( ret ) ) ;
2018-12-03 12:40:13 -05:00
cl_engine_free ( engine ) ;
return 1 ;
}
2008-02-12 03:19:50 +00:00
}
2009-03-12 15:21:36 +00:00
val = cl_engine_get_num ( engine , CL_ENGINE_MAX_RECURSION , NULL ) ;
2018-12-03 12:40:13 -05:00
if ( val )
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: Recursion level limit set to %u. \n " , ( unsigned int ) val ) ;
2008-11-12 16:19:43 +00:00
else
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Limits: Recursion level limit protection disabled. \n " ) ;
2008-11-12 16:19:43 +00:00
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " MaxFiles " ) ) - > active ) {
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_MAX_FILES , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cl_engine_set_num(CL_ENGINE_MAX_FILES) failed: %s \n " , cl_strerror ( ret ) ) ;
2018-12-03 12:40:13 -05:00
cl_engine_free ( engine ) ;
return 1 ;
}
2008-02-12 03:19:50 +00:00
}
2009-03-12 15:21:36 +00:00
val = cl_engine_get_num ( engine , CL_ENGINE_MAX_FILES , NULL ) ;
2018-12-03 12:40:13 -05:00
if ( val )
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: Files limit set to %u. \n " , ( unsigned int ) val ) ;
2008-11-12 16:19:43 +00:00
else
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Limits: Files limit protection disabled. \n " ) ;
2003-07-29 15:48:06 +00:00
2009-09-30 00:54:04 +02:00
# ifndef _WIN32
2009-04-01 17:19:06 +00:00
if ( getrlimit ( RLIMIT_CORE , & rlim ) = = 0 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG , " Limits: Core-dump limit is %lu. \n " , ( unsigned long ) rlim . rlim_cur ) ;
2009-04-01 17:19:06 +00:00
}
# endif
2008-02-12 03:19:50 +00:00
2012-11-27 17:15:02 -05:00
/* Engine max sizes */
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " MaxEmbeddedPE " ) ) - > active ) {
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_MAX_EMBEDDEDPE , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cli_engine_set_num(CL_ENGINE_MAX_EMBEDDEDPE) failed: %s \n " , cl_strerror ( ret ) ) ;
2012-11-27 17:15:02 -05:00
cl_engine_free ( engine ) ;
return 1 ;
}
}
val = cl_engine_get_num ( engine , CL_ENGINE_MAX_EMBEDDEDPE , NULL ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: MaxEmbeddedPE limit set to %llu bytes. \n " , val ) ;
2012-11-27 17:15:02 -05:00
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " MaxHTMLNormalize " ) ) - > active ) {
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_MAX_HTMLNORMALIZE , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cli_engine_set_num(CL_ENGINE_MAX_HTMLNORMALIZE) failed: %s \n " , cl_strerror ( ret ) ) ;
2012-11-27 17:15:02 -05:00
cl_engine_free ( engine ) ;
return 1 ;
}
}
val = cl_engine_get_num ( engine , CL_ENGINE_MAX_HTMLNORMALIZE , NULL ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: MaxHTMLNormalize limit set to %llu bytes. \n " , val ) ;
2012-11-27 17:15:02 -05:00
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " MaxHTMLNoTags " ) ) - > active ) {
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_MAX_HTMLNOTAGS , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cli_engine_set_num(CL_ENGINE_MAX_HTMLNOTAGS) failed: %s \n " , cl_strerror ( ret ) ) ;
2012-11-27 17:15:02 -05:00
cl_engine_free ( engine ) ;
return 1 ;
}
}
val = cl_engine_get_num ( engine , CL_ENGINE_MAX_HTMLNOTAGS , NULL ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: MaxHTMLNoTags limit set to %llu bytes. \n " , val ) ;
2012-11-27 17:15:02 -05:00
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " MaxScriptNormalize " ) ) - > active ) {
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_MAX_SCRIPTNORMALIZE , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cli_engine_set_num(CL_ENGINE_MAX_SCRIPTNORMALIZE) failed: %s \n " , cl_strerror ( ret ) ) ;
2012-11-27 17:15:02 -05:00
cl_engine_free ( engine ) ;
return 1 ;
}
}
val = cl_engine_get_num ( engine , CL_ENGINE_MAX_SCRIPTNORMALIZE , NULL ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: MaxScriptNormalize limit set to %llu bytes. \n " , val ) ;
2012-11-27 17:15:02 -05:00
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " MaxZipTypeRcg " ) ) - > active ) {
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_MAX_ZIPTYPERCG , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cli_engine_set_num(CL_ENGINE_MAX_ZIPTYPERCG) failed: %s \n " , cl_strerror ( ret ) ) ;
2012-11-27 17:15:02 -05:00
cl_engine_free ( engine ) ;
return 1 ;
}
}
val = cl_engine_get_num ( engine , CL_ENGINE_MAX_ZIPTYPERCG , NULL ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: MaxZipTypeRcg limit set to %llu bytes. \n " , val ) ;
2012-11-27 17:15:02 -05:00
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " MaxPartitions " ) ) - > active ) {
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_MAX_PARTITIONS , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cli_engine_set_num(MaxPartitions) failed: %s \n " , cl_strerror ( ret ) ) ;
2014-02-06 18:55:40 -05:00
cl_engine_free ( engine ) ;
return 1 ;
}
}
val = cl_engine_get_num ( engine , CL_ENGINE_MAX_PARTITIONS , NULL ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: MaxPartitions limit set to %llu. \n " , val ) ;
2014-02-06 18:55:40 -05:00
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " MaxIconsPE " ) ) - > active ) {
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_MAX_ICONSPE , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cli_engine_set_num(MaxIconsPE) failed: %s \n " , cl_strerror ( ret ) ) ;
2014-03-06 18:19:11 -05:00
cl_engine_free ( engine ) ;
return 1 ;
}
}
val = cl_engine_get_num ( engine , CL_ENGINE_MAX_ICONSPE , NULL ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: MaxIconsPE limit set to %llu. \n " , val ) ;
2014-03-06 18:19:11 -05:00
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " MaxRecHWP3 " ) ) - > active ) {
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_MAX_RECHWP3 , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cli_engine_set_num(MaxRecHWP3) failed: %s \n " , cl_strerror ( ret ) ) ;
2016-01-19 14:25:55 -05:00
cl_engine_free ( engine ) ;
return 1 ;
}
}
val = cl_engine_get_num ( engine , CL_ENGINE_MAX_RECHWP3 , NULL ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: MaxRecHWP3 limit set to %llu. \n " , val ) ;
2016-01-19 14:25:55 -05:00
2016-02-08 15:24:30 -05:00
/* options are handled in main (clamd.c) */
2014-08-25 19:11:12 -04:00
val = cl_engine_get_num ( engine , CL_ENGINE_PCRE_MATCH_LIMIT , NULL ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: PCREMatchLimit limit set to %llu. \n " , val ) ;
2014-08-25 19:11:12 -04:00
val = cl_engine_get_num ( engine , CL_ENGINE_PCRE_RECMATCH_LIMIT , NULL ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: PCRERecMatchLimit limit set to %llu. \n " , val ) ;
2014-08-25 19:11:12 -04:00
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " PCREMaxFileSize " ) ) - > active ) {
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_PCRE_MAX_FILESIZE , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cli_engine_set_num(PCREMaxFileSize) failed: %s \n " , cl_strerror ( ret ) ) ;
2014-09-19 02:39:52 -04:00
cl_engine_free ( engine ) ;
return 1 ;
}
}
val = cl_engine_get_num ( engine , CL_ENGINE_PCRE_MAX_FILESIZE , NULL ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Limits: PCREMaxFileSize limit set to %llu. \n " , val ) ;
2014-09-19 02:39:52 -04:00
2018-10-10 06:02:28 -07:00
if ( optget ( opts , " ScanArchive " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Archive support enabled. \n " ) ;
2018-10-10 06:02:28 -07:00
options . parse | = CL_SCAN_PARSE_ARCHIVE ;
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Archive support disabled. \n " ) ;
2024-02-25 12:43:56 -05:00
}
if ( optget ( opts , " ScanImage " ) - > enabled ) {
logg ( LOGG_INFO , " Image (graphics) scanning support enabled. \n " ) ;
options . parse | = CL_SCAN_PARSE_IMAGE ;
} else {
logg ( LOGG_INFO , " Image (graphics) scanning support disabled. \n " ) ;
}
if ( optget ( opts , " ScanImageFuzzyHash " ) - > enabled ) {
logg ( LOGG_INFO , " Detection using image fuzzy hash enabled. \n " ) ;
options . parse | = CL_SCAN_PARSE_IMAGE_FUZZY_HASH ;
} else {
logg ( LOGG_INFO , " Detection using image fuzzy hash disabled. \n " ) ;
2018-10-10 06:02:28 -07:00
}
2003-12-01 22:55:35 +00:00
2018-10-10 06:02:28 -07:00
/* TODO: Remove deprecated option in a future feature release. */
if ( optget ( opts , " ArchiveBlockEncrypted " ) - > enabled ) {
if ( options . parse & CL_SCAN_PARSE_ARCHIVE ) {
logg (
2022-02-16 00:13:55 +01:00
LOGG_WARNING ,
" Using deprecated option \" ArchiveBlockEncrypted \" to alert on "
2018-12-03 12:40:13 -05:00
" encrypted archives _and_ documents. Please update your "
" configuration to use replacement options \" AlertEncrypted \" , or "
" \" AlertEncryptedArchive \" and/or \" AlertEncryptedDoc \" . \n " ) ;
2018-10-10 06:02:28 -07:00
options . heuristic | = CL_SCAN_HEURISTIC_ENCRYPTED_ARCHIVE ;
options . heuristic | = CL_SCAN_HEURISTIC_ENCRYPTED_DOC ;
} else {
logg (
2022-02-16 00:13:55 +01:00
LOGG_WARNING ,
" Using deprecated option \" ArchiveBlockEncrypted \" to alert on "
2018-12-03 12:40:13 -05:00
" encrypted documents. Please update your configuration to use "
" replacement options \" AlertEncrypted \" , or "
" \" AlertEncryptedArchive \" and/or \" AlertEncryptedDoc \" . \n " ) ;
2018-10-10 06:02:28 -07:00
options . heuristic | = CL_SCAN_HEURISTIC_ENCRYPTED_DOC ;
}
}
2004-03-04 02:27:37 +00:00
2018-10-10 06:02:28 -07:00
if ( optget ( opts , " AlertEncrypted " ) - > enabled ) {
if ( options . parse & CL_SCAN_PARSE_ARCHIVE ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Alerting of encrypted archives _and_ documents enabled. \n " ) ;
2018-10-10 06:02:28 -07:00
options . heuristic | = CL_SCAN_HEURISTIC_ENCRYPTED_ARCHIVE ;
options . heuristic | = CL_SCAN_HEURISTIC_ENCRYPTED_DOC ;
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Alerting of encrypted documents enabled. \n " ) ;
2018-10-10 06:02:28 -07:00
options . heuristic | = CL_SCAN_HEURISTIC_ENCRYPTED_DOC ;
}
}
if ( optget ( opts , " AlertEncryptedArchive " ) - > enabled ) {
if ( options . parse & CL_SCAN_PARSE_ARCHIVE ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Alerting of encrypted archives enabled. \n " ) ;
2018-10-10 06:02:28 -07:00
options . heuristic | = CL_SCAN_HEURISTIC_ENCRYPTED_ARCHIVE ;
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Encrypted archive alerting requested, but archive support "
" is disabled! \n " ) ;
2018-10-10 06:02:28 -07:00
}
}
if ( optget ( opts , " AlertEncryptedDoc " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Alerting of encrypted documents enabled. \n " ) ;
2018-10-10 06:02:28 -07:00
options . heuristic | = CL_SCAN_HEURISTIC_ENCRYPTED_DOC ;
2003-07-29 15:48:06 +00:00
}
2018-10-10 06:02:28 -07:00
/* TODO: Remove deprecated option in a future feature release. */
2016-09-20 17:45:40 -04:00
if ( optget ( opts , " BlockMax " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Using deprecated option \" BlockMax \" to enable heuristic alerts "
" when scans exceed set maximums. Please update your configuration "
" to use replacement option \" AlertExceedsMax \" . \n " ) ;
2018-10-10 06:02:28 -07:00
options . heuristic | = CL_SCAN_HEURISTIC_EXCEEDS_MAX ;
} else if ( optget ( opts , " AlertExceedsMax " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Heuristic alerting enabled for scans that exceed set maximums. \n " ) ;
2018-07-20 22:28:48 -04:00
options . heuristic | = CL_SCAN_HEURISTIC_EXCEEDS_MAX ;
2016-09-20 17:45:40 -04:00
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " AlertExceedsMax heuristic detection disabled. \n " ) ;
2016-09-20 17:45:40 -04:00
}
2018-10-10 06:02:28 -07:00
/* TODO: Remove deprecated option in a future feature release. */
2018-10-23 13:20:12 -07:00
if ( ! optget ( opts , " AlgorithmicDetection " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Using deprecated option \" AlgorithmicDetection \" to disable "
" heuristic alerts. Please update your configuration to use "
" replacement option \" HeuristicAlerts \" . \n " ) ;
2018-10-23 13:20:12 -07:00
} else if ( ! optget ( opts , " HeuristicAlerts " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Heuristic alerts disabled. \n " ) ;
2018-12-03 12:40:13 -05:00
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Heuristic alerts enabled. \n " ) ;
2018-12-03 12:40:13 -05:00
options . general | = CL_SCAN_GENERAL_HEURISTICS ;
2005-12-12 18:44:37 +00:00
}
2018-12-03 12:40:13 -05:00
if ( optget ( opts , " ScanPE " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Portable Executable support enabled. \n " ) ;
2018-12-03 12:40:13 -05:00
options . parse | = CL_SCAN_PARSE_PE ;
2006-10-28 22:01:51 +00:00
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Portable Executable support disabled. \n " ) ;
2006-10-28 22:01:51 +00:00
}
2004-08-04 20:11:18 +00:00
2018-12-03 12:40:13 -05:00
if ( optget ( opts , " ScanELF " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " ELF support enabled. \n " ) ;
2018-12-03 12:40:13 -05:00
options . parse | = CL_SCAN_PARSE_ELF ;
2006-10-28 22:01:51 +00:00
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " ELF support disabled. \n " ) ;
2006-10-28 22:01:51 +00:00
}
2018-12-03 12:40:13 -05:00
/* TODO: Remove deprecated option in a future feature release */
2018-10-10 06:02:28 -07:00
if ( optget ( opts , " ScanPE " ) - > enabled | | optget ( opts , " ScanELF " ) - > enabled ) {
2018-12-03 12:40:13 -05:00
if ( ( optget ( opts , " DetectBrokenExecutables " ) - > enabled ) | |
( optget ( opts , " AlertBrokenExecutables " ) - > enabled ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Alerting on broken executables enabled. \n " ) ;
2018-10-10 06:02:28 -07:00
options . heuristic | = CL_SCAN_HEURISTIC_BROKEN ;
}
2004-07-05 23:50:55 +00:00
}
GIF, PNG bugfixes; Add AlertBrokenMedia option
Added a new scan option to alert on broken media (graphics) file
formats. This feature mitigates the risk of malformed media files
intended to exploit vulnerabilities in other software. At present
media validation exists for JPEG, TIFF, PNG, and GIF files.
To enable this feature, set `AlertBrokenMedia yes` in clamd.conf, or
use the `--alert-broken-media` option when using `clamscan`.
These options are disabled by default for now.
Application developers may enable this scan option by enabling
`CL_SCAN_HEURISTIC_BROKEN_MEDIA` for the `heuristic` scan option bit
field.
Fixed PNG parser logic bugs that caused an excess of parsing errors
and fixed a stack exhaustion issue affecting some systems when
scanning PNG files. PNG file type detection was disabled via
signature database update for 0.103.0 to mitigate effects from these
bugs.
Fixed an issue where PNG and GIF files no longer work with Target:5
(graphics) signatures if detected as CL_TYPE_PNG/GIF rather than as
CL_TYPE_GRAPHICS. Target types now support up to 10 possible file
types to make way for additional graphics types in future releases.
Scanning JPEG, TIFF, PNG, and GIF files will no longer return "parse"
errors when file format validation fails. Instead, the scan will alert
with the "Heuristics.Broken.Media" signature prefix and a descriptive
suffix to indicate the issue, provided that the "alert broken media"
feature is enabled.
GIF format validation will no longer fail if the GIF image is missing
the trailer byte, as this appears to be a relatively common issue in
otherwise functional GIF files.
Added a TIFF dynamic configuration (DCONF) option, which was missing.
This will allow us to disable TIFF format validation via signature
database update in the event that it proves to be problematic.
This feature already exists for many other file types.
Added CL_TYPE_JPEG and CL_TYPE_TIFF types.
2020-11-04 15:49:43 -08:00
if ( optget ( opts , " AlertBrokenMedia " ) - > enabled ) {
options . heuristic | = CL_SCAN_HEURISTIC_BROKEN_MEDIA ;
2023-11-26 15:01:19 -08:00
logg ( LOGG_INFO , " Media (Graphics) Format Validation enabled \n " ) ;
GIF, PNG bugfixes; Add AlertBrokenMedia option
Added a new scan option to alert on broken media (graphics) file
formats. This feature mitigates the risk of malformed media files
intended to exploit vulnerabilities in other software. At present
media validation exists for JPEG, TIFF, PNG, and GIF files.
To enable this feature, set `AlertBrokenMedia yes` in clamd.conf, or
use the `--alert-broken-media` option when using `clamscan`.
These options are disabled by default for now.
Application developers may enable this scan option by enabling
`CL_SCAN_HEURISTIC_BROKEN_MEDIA` for the `heuristic` scan option bit
field.
Fixed PNG parser logic bugs that caused an excess of parsing errors
and fixed a stack exhaustion issue affecting some systems when
scanning PNG files. PNG file type detection was disabled via
signature database update for 0.103.0 to mitigate effects from these
bugs.
Fixed an issue where PNG and GIF files no longer work with Target:5
(graphics) signatures if detected as CL_TYPE_PNG/GIF rather than as
CL_TYPE_GRAPHICS. Target types now support up to 10 possible file
types to make way for additional graphics types in future releases.
Scanning JPEG, TIFF, PNG, and GIF files will no longer return "parse"
errors when file format validation fails. Instead, the scan will alert
with the "Heuristics.Broken.Media" signature prefix and a descriptive
suffix to indicate the issue, provided that the "alert broken media"
feature is enabled.
GIF format validation will no longer fail if the GIF image is missing
the trailer byte, as this appears to be a relatively common issue in
otherwise functional GIF files.
Added a TIFF dynamic configuration (DCONF) option, which was missing.
This will allow us to disable TIFF format validation via signature
database update in the event that it proves to be problematic.
This feature already exists for many other file types.
Added CL_TYPE_JPEG and CL_TYPE_TIFF types.
2020-11-04 15:49:43 -08:00
}
2018-12-03 12:40:13 -05:00
if ( optget ( opts , " ScanMail " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Mail files support enabled. \n " ) ;
2018-12-03 12:40:13 -05:00
options . parse | = CL_SCAN_PARSE_MAIL ;
2004-08-18 15:22:48 +00:00
2018-12-03 12:40:13 -05:00
if ( optget ( opts , " ScanPartialMessages " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Mail: RFC1341 handling enabled. \n " ) ;
2018-12-03 12:40:13 -05:00
options . mail | = CL_SCAN_MAIL_PARTIAL_MESSAGE ;
}
2008-07-30 13:54:34 +00:00
2003-07-29 15:48:06 +00:00
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Mail files support disabled. \n " ) ;
2003-07-29 15:48:06 +00:00
}
2018-10-10 06:02:28 -07:00
if ( optget ( opts , " ScanOLE2 " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " OLE2 support enabled. \n " ) ;
2018-10-10 06:02:28 -07:00
options . parse | = CL_SCAN_PARSE_OLE2 ;
2018-12-03 12:40:13 -05:00
/* TODO: Remove deprecated option in a future feature release */
2018-10-10 06:02:28 -07:00
if ( ( optget ( opts , " OLE2BlockMacros " ) - > enabled ) | |
2018-12-03 12:40:13 -05:00
( optget ( opts , " AlertOLE2Macros " ) - > enabled ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " OLE2: Alerting on all VBA macros. \n " ) ;
2018-10-10 06:02:28 -07:00
options . heuristic | = CL_SCAN_HEURISTIC_MACROS ;
}
2004-01-23 11:06:00 +00:00
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " OLE2 support disabled. \n " ) ;
2004-01-23 11:06:00 +00:00
}
2018-12-03 12:40:13 -05:00
if ( optget ( opts , " ScanPDF " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " PDF support enabled. \n " ) ;
2018-12-03 12:40:13 -05:00
options . parse | = CL_SCAN_PARSE_PDF ;
2007-02-22 17:49:57 +00:00
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " PDF support disabled. \n " ) ;
2013-02-05 19:46:56 -05:00
}
2018-12-03 12:40:13 -05:00
if ( optget ( opts , " ScanSWF " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " SWF support enabled. \n " ) ;
2018-12-03 12:40:13 -05:00
options . parse | = CL_SCAN_PARSE_SWF ;
2013-02-05 19:46:56 -05:00
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " SWF support disabled. \n " ) ;
2007-02-22 17:49:57 +00:00
}
2018-12-03 12:40:13 -05:00
if ( optget ( opts , " ScanHTML " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " HTML support enabled. \n " ) ;
2018-12-03 12:40:13 -05:00
options . parse | = CL_SCAN_PARSE_HTML ;
2004-07-02 23:00:58 +00:00
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " HTML support disabled. \n " ) ;
2004-07-02 23:00:58 +00:00
}
2020-01-03 15:53:29 -05:00
# ifdef PRELUDE
if ( optget ( opts , " PreludeEnable " ) - > enabled ) {
if ( ( opt = optget ( opts , " PreludeAnalyzerName " ) ) - > enabled ) {
2019-09-06 10:43:05 -07:00
prelude_initialize_client ( opt - > strarg ) ;
} else {
prelude_initialize_client ( " ClamAV " ) ;
}
}
2020-01-03 15:53:29 -05:00
# endif
2019-09-06 10:43:05 -07:00
2018-12-03 12:40:13 -05:00
if ( optget ( opts , " ScanXMLDOCS " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " XMLDOCS support enabled. \n " ) ;
2018-12-03 12:40:13 -05:00
options . parse | = CL_SCAN_PARSE_XMLDOCS ;
2016-02-02 14:23:13 -05:00
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " XMLDOCS support disabled. \n " ) ;
2016-02-02 14:23:13 -05:00
}
2018-12-03 12:40:13 -05:00
if ( optget ( opts , " ScanHWP3 " ) - > enabled ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " HWP3 support enabled. \n " ) ;
2018-12-03 12:40:13 -05:00
options . parse | = CL_SCAN_PARSE_HWP3 ;
2016-02-02 14:23:13 -05:00
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " HWP3 support disabled. \n " ) ;
2016-02-02 14:23:13 -05:00
}
2023-09-29 12:49:29 -07:00
if ( optget ( opts , " ScanOneNote " ) - > enabled ) {
logg ( LOGG_INFO , " OneNote support enabled. \n " ) ;
options . parse | = CL_SCAN_PARSE_ONENOTE ;
} else {
logg ( LOGG_INFO , " OneNote support disabled. \n " ) ;
}
2018-10-10 06:02:28 -07:00
if ( optget ( opts , " PhishingScanURLs " ) - > enabled ) {
2018-12-03 12:40:13 -05:00
/* TODO: Remove deprecated option in a future feature release */
2018-10-10 06:02:28 -07:00
if ( ( optget ( opts , " PhishingAlwaysBlockCloak " ) - > enabled ) | |
( optget ( opts , " AlertPhishingCloak " ) - > enabled ) ) {
options . heuristic | = CL_SCAN_HEURISTIC_PHISHING_CLOAK ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Phishing: Always checking for cloaked urls \n " ) ;
2018-10-10 06:02:28 -07:00
}
2018-12-03 12:40:13 -05:00
/* TODO: Remove deprecated option in a future feature release */
2018-10-10 06:02:28 -07:00
if ( ( optget ( opts , " PhishingAlwaysBlockSSLMismatch " ) - > enabled ) | |
( optget ( opts , " AlertPhishingSSLMismatch " ) - > enabled ) ) {
options . heuristic | = CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Phishing: Always checking for ssl mismatches \n " ) ;
2018-10-10 06:02:28 -07:00
}
2007-01-12 17:29:09 +00:00
}
2018-12-03 12:40:13 -05:00
/* TODO: Remove deprecated option in a future feature release */
if ( ( optget ( opts , " PartitionIntersection " ) - > enabled ) | |
( optget ( opts , " AlertPartitionIntersection " ) - > enabled ) ) {
2018-07-20 22:28:48 -04:00
options . heuristic | = CL_SCAN_HEURISTIC_PARTITION_INTXN ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Raw DMG: Alert on partitions intersections \n " ) ;
2014-02-06 18:55:40 -05:00
}
2018-12-03 12:40:13 -05:00
if ( optget ( opts , " HeuristicScanPrecedence " ) - > enabled ) {
options . general | = CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Heuristic: precedence enabled \n " ) ;
2008-07-31 10:51:46 +00:00
}
2018-12-03 12:40:13 -05:00
if ( optget ( opts , " StructuredDataDetection " ) - > enabled ) {
2018-07-20 22:28:48 -04:00
options . heuristic | = CL_SCAN_HEURISTIC_STRUCTURED ;
2008-04-18 17:14:20 +00:00
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " StructuredMinCreditCardCount " ) ) - > enabled ) {
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_MIN_CC_COUNT , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cl_engine_set_num(CL_ENGINE_MIN_CC_COUNT) failed: %s \n " , cl_strerror ( ret ) ) ;
2018-12-03 12:40:13 -05:00
cl_engine_free ( engine ) ;
return 1 ;
}
}
val = cl_engine_get_num ( engine , CL_ENGINE_MIN_CC_COUNT , NULL ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Structured: Minimum Credit Card Number Count set to %u \n " , ( unsigned int ) val ) ;
2018-12-03 12:40:13 -05:00
2020-06-09 13:54:29 -04:00
if ( optget ( opts , " StructuredCCOnly " ) - > enabled )
2016-04-21 12:13:57 -04:00
options . heuristic | = CL_SCAN_HEURISTIC_STRUCTURED_CC ;
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " StructuredMinSSNCount " ) ) - > enabled ) {
if ( ( ret = cl_engine_set_num ( engine , CL_ENGINE_MIN_SSN_COUNT , opt - > numarg ) ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " cl_engine_set_num(CL_ENGINE_MIN_SSN_COUNT) failed: %s \n " , cl_strerror ( ret ) ) ;
2018-12-03 12:40:13 -05:00
cl_engine_free ( engine ) ;
return 1 ;
}
}
val = cl_engine_get_num ( engine , CL_ENGINE_MIN_SSN_COUNT , NULL ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Structured: Minimum Social Security Number Count set to %u \n " , ( unsigned int ) val ) ;
2018-12-03 12:40:13 -05:00
if ( optget ( opts , " StructuredSSNFormatNormal " ) - > enabled )
2018-07-20 22:28:48 -04:00
options . heuristic | = CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL ;
2008-04-18 17:14:20 +00:00
2018-12-03 12:40:13 -05:00
if ( optget ( opts , " StructuredSSNFormatStripped " ) - > enabled )
options . heuristic | = CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED ;
2008-04-18 17:14:20 +00:00
}
2025-06-04 10:13:47 -04:00
if ( optget ( opts , " GenerateMetadataJson " ) - > enabled ) {
2021-10-03 21:51:15 -07:00
options . general | = CL_SCAN_GENERAL_COLLECT_METADATA ;
2025-06-04 10:13:47 -04:00
}
if ( optget ( opts , " JsonStoreHTMLURIs " ) - > enabled ) {
options . general | = CL_SCAN_GENERAL_STORE_HTML_URIS ;
}
if ( optget ( opts , " JsonStorePDFURIs " ) - > enabled ) {
options . general | = CL_SCAN_GENERAL_STORE_PDF_URIS ;
}
2021-10-03 21:51:15 -07:00
2025-06-03 19:03:20 -04:00
if ( optget ( opts , " JsonStoreExtraHashes " ) - > enabled ) {
options . general | = CL_SCAN_GENERAL_STORE_EXTRA_HASHES ;
}
2008-12-17 21:42:54 +00:00
selfchk = optget ( opts , " SelfCheck " ) - > numarg ;
2018-12-03 12:40:13 -05:00
if ( ! selfchk ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Self checking disabled. \n " ) ;
2004-02-17 00:08:25 +00:00
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Self checking every %u seconds. \n " , selfchk ) ;
2004-02-17 00:08:25 +00:00
}
2003-07-29 15:48:06 +00:00
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG , " Listening daemon: PID: %u \n " , ( unsigned int ) getpid ( ) ) ;
2018-12-03 12:40:13 -05:00
max_threads = optget ( opts , " MaxThreads " ) - > numarg ;
max_queue = optget ( opts , " MaxQueue " ) - > numarg ;
2009-02-17 15:59:21 +00:00
acceptdata . commandtimeout = optget ( opts , " CommandReadTimeout " ) - > numarg ;
2018-12-03 12:40:13 -05:00
readtimeout = optget ( opts , " ReadTimeout " ) - > numarg ;
2008-11-12 16:19:43 +00:00
2009-09-30 00:54:04 +02:00
# if !defined(_WIN32) && defined(RLIMIT_NOFILE)
2009-04-01 17:19:06 +00:00
if ( getrlimit ( RLIMIT_NOFILE , & rlim ) = = 0 ) {
2018-12-03 12:40:13 -05:00
/* don't warn if default value is too high, silently fix it */
unsigned maxrec ;
int max_max_queue ;
unsigned warn = optget ( opts , " MaxQueue " ) - > active ;
const unsigned clamdfiles = 6 ;
2016-03-14 16:07:45 -04:00
# ifdef C_SOLARIS
2018-12-03 12:40:13 -05:00
int solaris_has_extended_stdio = 0 ;
2016-03-14 16:07:45 -04:00
# endif
2018-12-03 12:40:13 -05:00
/* Condition to not run out of file descriptors:
2022-02-16 00:13:55 +01:00
* MaxThreads * MaxRecursion + ( MaxQueue - MaxThreads ) + CLAMDFILES < RLIMIT_NOFILE
* CLAMDFILES is 6 : 3 standard FD + logfile + 2 FD for reloading the DB
* */
2009-11-24 10:25:41 +02:00
# ifdef C_SOLARIS
2016-03-14 16:07:45 -04:00
2018-12-03 12:40:13 -05:00
/*
2022-02-16 00:13:55 +01:00
* * If compiling 64 bit , then set the solaris_has_extended_stdio
* * flag
*/
2016-03-14 16:07:45 -04:00
# if defined(_LP64)
2018-12-03 12:40:13 -05:00
solaris_has_extended_stdio + + ;
2016-03-14 16:07:45 -04:00
# endif
2011-04-14 13:18:54 +03:00
# ifdef HAVE_ENABLE_EXTENDED_FILE_STDIO
2018-12-03 12:40:13 -05:00
if ( enable_extended_FILE_stdio ( - 1 , - 1 ) = = - 1 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Unable to set extended FILE stdio, clamd will be limited to max 256 open files \n " ) ;
2018-12-03 12:40:13 -05:00
rlim . rlim_cur = rlim . rlim_cur > 255 ? 255 : rlim . rlim_cur ;
} else {
solaris_has_extended_stdio + + ;
}
2016-03-14 16:07:45 -04:00
2009-11-24 10:25:41 +02:00
# elif !defined(_LP64)
2018-12-03 12:40:13 -05:00
if ( solaris_has_extended_stdio & & rlim . rlim_cur > 255 ) {
rlim . rlim_cur = 255 ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Solaris only supports 256 open files for 32-bit processes, you need at least Solaris 10u4, or compile as 64-bit to support more! \n " ) ;
2018-12-03 12:40:13 -05:00
}
2009-11-24 10:25:41 +02:00
# endif
2016-03-14 16:07:45 -04:00
2018-12-03 12:40:13 -05:00
/*
2022-02-16 00:13:55 +01:00
* * If compiling in 64 bit or the file stdio has been extended ,
* * then increase the soft limit for the number of open files
* * as the default is usually 256
*/
2016-03-14 16:07:45 -04:00
2018-12-03 12:40:13 -05:00
if ( solaris_has_extended_stdio ) {
rlim_t saved_soft_limit = rlim . rlim_cur ;
2016-03-14 16:07:45 -04:00
2018-12-03 12:40:13 -05:00
rlim . rlim_cur = rlim . rlim_max ;
if ( setrlimit ( RLIMIT_NOFILE , & rlim ) < 0 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " setrlimit() for RLIMIT_NOFILE to %lu failed: %s \n " ,
2018-12-03 12:40:13 -05:00
( unsigned long ) rlim . rlim_cur , strerror ( errno ) ) ;
rlim . rlim_cur = saved_soft_limit ;
}
} /* If 64bit or has extended stdio */
2016-03-14 16:07:45 -04:00
2009-11-24 10:25:41 +02:00
# endif
2018-12-03 12:40:13 -05:00
opt = optget ( opts , " MaxRecursion " ) ;
maxrec = opt - > numarg ;
max_max_queue = rlim . rlim_cur - maxrec * max_threads - clamdfiles + max_threads ;
if ( max_queue < max_threads ) {
max_queue = max_threads ;
if ( warn )
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " MaxQueue value too low, increasing to: %d \n " , max_queue ) ;
2018-12-03 12:40:13 -05:00
}
if ( max_max_queue < max_threads ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " MaxThreads * MaxRecursion is too high: %d, open file descriptor limit is: %lu \n " ,
2018-12-03 12:40:13 -05:00
maxrec * max_threads , ( unsigned long ) rlim . rlim_cur ) ;
max_max_queue = max_threads ;
}
if ( max_queue > max_max_queue ) {
max_queue = max_max_queue ;
if ( warn )
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " MaxQueue value too high, lowering to: %d \n " , max_queue ) ;
2018-12-03 12:40:13 -05:00
} else if ( max_queue < 2 * max_threads & & max_queue < max_max_queue ) {
max_queue = 2 * max_threads ;
if ( max_queue > max_max_queue )
max_queue = max_max_queue ;
/* always warn here */
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " MaxQueue is lower than twice MaxThreads, increasing to: %d \n " , max_queue ) ;
2018-12-03 12:40:13 -05:00
}
2009-04-01 17:19:06 +00:00
}
# endif
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG , " MaxQueue set to: %d \n " , max_queue ) ;
2009-04-01 17:19:06 +00:00
acceptdata . max_queue = max_queue ;
2018-12-03 12:40:13 -05:00
# ifndef _WIN32
2003-07-29 15:48:06 +00:00
/* set up signal handling */
sigfillset ( & sigset ) ;
sigdelset ( & sigset , SIGINT ) ;
sigdelset ( & sigset , SIGTERM ) ;
2003-09-05 13:10:21 +00:00
sigdelset ( & sigset , SIGSEGV ) ;
2003-09-14 18:55:56 +00:00
sigdelset ( & sigset , SIGHUP ) ;
2004-03-02 12:58:04 +00:00
sigdelset ( & sigset , SIGPIPE ) ;
2004-03-13 12:50:39 +00:00
sigdelset ( & sigset , SIGUSR2 ) ;
2019-07-12 09:39:26 -07:00
/* The behavior of a process is undefined after it ignores a
2008-02-07 20:47:50 +00:00
* SIGFPE , SIGILL , SIGSEGV , or SIGBUS signal */
sigdelset ( & sigset , SIGFPE ) ;
sigdelset ( & sigset , SIGILL ) ;
sigdelset ( & sigset , SIGSEGV ) ;
2018-12-03 12:40:13 -05:00
# ifdef SIGBUS
2008-02-07 20:47:50 +00:00
sigdelset ( & sigset , SIGBUS ) ;
# endif
2009-02-12 16:51:09 +00:00
sigdelset ( & sigset , SIGTSTP ) ;
sigdelset ( & sigset , SIGCONT ) ;
2003-07-29 15:48:06 +00:00
sigprocmask ( SIG_SETMASK , & sigset , NULL ) ;
2008-02-07 20:47:50 +00:00
2003-09-05 13:10:21 +00:00
/* SIGINT, SIGTERM, SIGSEGV */
2003-11-29 03:38:55 +00:00
sigact . sa_handler = sighandler_th ;
2003-07-29 15:48:06 +00:00
sigemptyset ( & sigact . sa_mask ) ;
sigaddset ( & sigact . sa_mask , SIGINT ) ;
sigaddset ( & sigact . sa_mask , SIGTERM ) ;
2003-09-14 18:55:56 +00:00
sigaddset ( & sigact . sa_mask , SIGHUP ) ;
2004-03-02 12:58:04 +00:00
sigaddset ( & sigact . sa_mask , SIGPIPE ) ;
2004-03-13 12:50:39 +00:00
sigaddset ( & sigact . sa_mask , SIGUSR2 ) ;
2003-07-29 15:48:06 +00:00
sigaction ( SIGINT , & sigact , NULL ) ;
sigaction ( SIGTERM , & sigact , NULL ) ;
2004-03-02 12:58:04 +00:00
sigaction ( SIGHUP , & sigact , NULL ) ;
sigaction ( SIGPIPE , & sigact , NULL ) ;
2004-03-13 12:50:39 +00:00
sigaction ( SIGUSR2 , & sigact , NULL ) ;
2006-09-12 20:55:09 +00:00
# endif
2004-02-17 00:08:25 +00:00
2008-12-17 21:42:54 +00:00
idletimeout = optget ( opts , " IdleTimeout " ) - > numarg ;
2004-10-01 00:31:18 +00:00
2018-12-03 12:40:13 -05:00
for ( i = 0 ; i < nsockets ; i + + )
if ( fds_add ( & acceptdata . fds , socketds [ i ] , 1 , 0 ) = = - 1 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " fds_add failed \n " ) ;
2018-12-03 12:40:13 -05:00
cl_engine_free ( engine ) ;
return 1 ;
}
2010-01-29 14:44:55 +01:00
# ifdef _WIN32
2018-12-03 12:40:13 -05:00
event_wake_accept = CreateEvent ( NULL , TRUE , FALSE , NULL ) ;
event_wake_recv = CreateEvent ( NULL , TRUE , FALSE , NULL ) ;
2010-01-29 14:44:55 +01:00
# else
2009-02-12 16:51:09 +00:00
if ( pipe ( acceptdata . syncpipe_wake_recv ) = = - 1 | |
2018-12-03 12:40:13 -05:00
( pipe ( acceptdata . syncpipe_wake_accept ) = = - 1 ) ) {
2009-02-12 16:51:09 +00:00
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " pipe failed \n " ) ;
2018-12-03 12:40:13 -05:00
exit ( - 1 ) ;
2009-02-12 16:51:09 +00:00
}
2009-02-17 20:05:35 +00:00
syncpipe_wake_recv_w = acceptdata . syncpipe_wake_recv [ 1 ] ;
2009-02-17 15:59:21 +00:00
if ( fds_add ( fds , acceptdata . syncpipe_wake_recv [ 0 ] , 1 , 0 ) = = - 1 | |
2018-12-03 12:40:13 -05:00
fds_add ( & acceptdata . fds , acceptdata . syncpipe_wake_accept [ 0 ] , 1 , 0 ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " failed to add pipe fd \n " ) ;
2018-12-03 12:40:13 -05:00
exit ( - 1 ) ;
2009-02-12 16:51:09 +00:00
}
2010-01-29 14:44:55 +01:00
# endif
2009-02-12 16:51:09 +00:00
if ( ( thr_pool = thrmgr_new ( max_threads , idletimeout , max_queue , scanner_thread ) ) = = NULL ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " thrmgr_new failed \n " ) ;
2018-12-03 12:40:13 -05:00
exit ( - 1 ) ;
2004-02-17 00:08:25 +00:00
}
2003-07-29 15:48:06 +00:00
2009-02-12 16:51:09 +00:00
if ( pthread_create ( & accept_th , NULL , acceptloop_th , & acceptdata ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " pthread_create failed \n " ) ;
2018-12-03 12:40:13 -05:00
exit ( - 1 ) ;
2009-02-12 16:51:09 +00:00
}
2003-07-29 15:48:06 +00:00
2009-02-12 16:51:09 +00:00
time ( & start_time ) ;
2018-12-03 12:40:13 -05:00
for ( ; ; ) {
int new_sd ;
/* Block waiting for connection on any of the sockets */
pthread_mutex_lock ( fds - > buf_mutex ) ;
fds_cleanup ( fds ) ;
/* signal that we can accept more connections */
if ( fds - > nfds < = ( unsigned ) max_queue )
pthread_cond_signal ( & acceptdata . cond_nfds ) ;
new_sd = fds_poll_recv ( fds , selfchk ? ( int ) selfchk : - 1 , 1 , event_wake_recv ) ;
2010-01-29 20:10:45 +01:00
# ifdef _WIN32
2018-12-03 12:40:13 -05:00
ResetEvent ( event_wake_recv ) ;
2010-01-29 20:10:45 +01:00
# else
2018-12-03 12:40:13 -05:00
if ( ! fds - > nfds ) {
/* at least the dummy/sync pipe should have remained */
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " All recv() descriptors gone: fatal \n " ) ;
2018-12-03 12:40:13 -05:00
pthread_mutex_lock ( & exit_mutex ) ;
progexit = 1 ;
pthread_mutex_unlock ( & exit_mutex ) ;
pthread_mutex_unlock ( fds - > buf_mutex ) ;
break ;
}
2010-01-29 18:57:50 +01:00
# endif
2018-12-03 12:40:13 -05:00
if ( new_sd = = - 1 & & errno ! = EINTR ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " Failed to poll sockets, fatal \n " ) ;
2018-12-03 12:40:13 -05:00
pthread_mutex_lock ( & exit_mutex ) ;
progexit = 1 ;
pthread_mutex_unlock ( & exit_mutex ) ;
}
if ( fds - > nfds ) i = ( rr_last + 1 ) % fds - > nfds ;
for ( j = 0 ; j < fds - > nfds & & new_sd > = 0 ; j + + , i = ( i + 1 ) % fds - > nfds ) {
size_t pos = 0 ;
int error = 0 ;
struct fd_buf * buf = & fds - > buf [ i ] ;
if ( ! buf - > got_newdata )
continue ;
2009-02-12 16:51:09 +00:00
2010-02-06 16:03:59 +01:00
# ifndef _WIN32
2018-12-03 12:40:13 -05:00
if ( buf - > fd = = acceptdata . syncpipe_wake_recv [ 0 ] ) {
/* dummy sync pipe, just to wake us */
if ( read ( buf - > fd , buff , sizeof ( buff ) ) < 0 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Syncpipe read failed \n " ) ;
2018-12-03 12:40:13 -05:00
}
continue ;
}
2010-01-29 14:44:55 +01:00
# endif
2018-12-03 12:40:13 -05:00
if ( buf - > got_newdata = = - 1 ) {
if ( buf - > mode = = MODE_WAITREPLY ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " mode WAIT_REPLY -> closed \n " ) ;
2018-12-03 12:40:13 -05:00
buf - > fd = - 1 ;
thrmgr_group_terminate ( buf - > group ) ;
thrmgr_group_finished ( buf - > group , EXIT_ERROR ) ;
2016-02-09 13:46:13 -05:00
continue ;
2018-12-03 12:40:13 -05:00
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " client read error or EOF on read \n " ) ;
2018-12-03 12:40:13 -05:00
error = 1 ;
}
}
if ( buf - > fd ! = - 1 & & buf - > got_newdata = = - 2 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Client read timed out \n " ) ;
2018-12-03 12:40:13 -05:00
mdprintf ( buf - > fd , " COMMAND READ TIMED OUT \n " ) ;
error = 1 ;
}
rr_last = i ;
if ( buf - > mode = = MODE_WAITANCILL ) {
buf - > mode = MODE_COMMAND ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " mode -> MODE_COMMAND \n " ) ;
2018-12-03 12:40:13 -05:00
}
while ( ! error & & buf - > fd ! = - 1 & & buf - > buffer & & pos < buf - > off & &
buf - > mode ! = MODE_WAITANCILL ) {
client_conn_t conn ;
const char * cmd = NULL ;
int rc ;
/* New data available to read on socket. */
memset ( & conn , 0 , sizeof ( conn ) ) ;
conn . scanfd = buf - > recvfd ;
buf - > recvfd = - 1 ;
conn . sd = buf - > fd ;
conn . options = & options ;
conn . opts = opts ;
conn . thrpool = thr_pool ;
conn . engine = engine ;
conn . group = buf - > group ;
conn . id = buf - > id ;
conn . quota = buf - > quota ;
conn . filename = buf - > dumpname ;
conn . mode = buf - > mode ;
conn . term = buf - > term ;
/* Parse & dispatch command */
cmd = parse_dispatch_cmd ( & conn , buf , & pos , & error , opts , readtimeout ) ;
if ( conn . mode = = MODE_COMMAND & & ! cmd )
break ;
if ( ! error ) {
if ( buf - > mode = = MODE_WAITREPLY & & buf - > off ) {
/* Client is not supposed to send anything more */
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Client sent garbage after last command: %lu bytes \n " , ( unsigned long ) buf - > off ) ;
2018-12-03 12:40:13 -05:00
buf - > buffer [ buf - > off ] = ' \0 ' ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Garbage: %s \n " , buf - > buffer ) ;
2018-12-03 12:40:13 -05:00
error = 1 ;
} else if ( buf - > mode = = MODE_STREAM ) {
rc = handle_stream ( & conn , buf , opts , & error , & pos , readtimeout ) ;
if ( rc = = - 1 )
break ;
else
continue ;
}
}
if ( error & & error ! = CL_ETIMEOUT ) {
conn_reply_error ( & conn , " Error processing command. " ) ;
}
}
if ( error ) {
if ( buf - > dumpfd ! = - 1 ) {
close ( buf - > dumpfd ) ;
if ( buf - > dumpname ) {
cli_unlink ( buf - > dumpname ) ;
free ( buf - > dumpname ) ;
}
buf - > dumpfd = - 1 ;
}
thrmgr_group_terminate ( buf - > group ) ;
if ( thrmgr_group_finished ( buf - > group , EXIT_ERROR ) ) {
if ( buf - > fd < 0 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Skipping shutdown of bad socket after error (FD %d) \n " , buf - > fd ) ;
2018-12-03 12:40:13 -05:00
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Shutting down socket after error (FD %d) \n " , buf - > fd ) ;
2018-12-03 12:40:13 -05:00
shutdown ( buf - > fd , 2 ) ;
closesocket ( buf - > fd ) ;
}
} else
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Socket not shut down due to active tasks \n " ) ;
2018-12-03 12:40:13 -05:00
buf - > fd = - 1 ;
}
}
pthread_mutex_unlock ( fds - > buf_mutex ) ;
/* handle progexit */
pthread_mutex_lock ( & exit_mutex ) ;
if ( progexit ) {
pthread_mutex_unlock ( & exit_mutex ) ;
pthread_mutex_lock ( fds - > buf_mutex ) ;
if ( sd_listen_fds ( 0 ) = = 0 ) {
/* only close the sockets, when not using systemd socket activation */
for ( i = 0 ; i < fds - > nfds ; i + + ) {
if ( fds - > buf [ i ] . fd = = - 1 )
continue ;
thrmgr_group_terminate ( fds - > buf [ i ] . group ) ;
if ( thrmgr_group_finished ( fds - > buf [ i ] . group , EXIT_ERROR ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG_NV , " Shutdown closed fd %d \n " , fds - > buf [ i ] . fd ) ;
2018-12-03 12:40:13 -05:00
shutdown ( fds - > buf [ i ] . fd , 2 ) ;
closesocket ( fds - > buf [ i ] . fd ) ;
fds - > buf [ i ] . fd = - 1 ;
}
}
}
pthread_mutex_unlock ( fds - > buf_mutex ) ;
break ;
}
pthread_mutex_unlock ( & exit_mutex ) ;
/* SIGHUP */
if ( sighup ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " SIGHUP caught: re-opening log file. \n " ) ;
2018-12-03 12:40:13 -05:00
logg_close ( ) ;
sighup = 0 ;
if ( ! logg_file & & ( opt = optget ( opts , " LogFile " ) ) - > enabled )
logg_file = opt - > strarg ;
}
/* SelfCheck */
if ( selfchk ) {
time ( & current_time ) ;
if ( ( current_time - start_time ) > = ( time_t ) selfchk ) {
2020-06-02 15:46:31 -04:00
if ( need_db_reload ( ) ) {
2018-12-03 12:40:13 -05:00
pthread_mutex_lock ( & reload_mutex ) ;
reload = 1 ;
pthread_mutex_unlock ( & reload_mutex ) ;
2016-02-09 13:46:13 -05:00
}
2018-12-03 12:40:13 -05:00
time ( & start_time ) ;
}
}
/* DB reload */
pthread_mutex_lock ( & reload_mutex ) ;
if ( reload ) {
2020-06-09 13:54:29 -04:00
pthread_mutex_unlock ( & reload_mutex ) ;
2020-06-02 15:46:31 -04:00
/* Reload was requested */
2020-06-09 13:54:29 -04:00
pthread_mutex_lock ( & reload_stage_mutex ) ;
2020-06-02 15:46:31 -04:00
if ( reload_stage = = RELOAD_STAGE__IDLE ) {
/* Reloading not already taking place */
reload_stage = RELOAD_STAGE__RELOADING ;
2020-06-09 13:54:29 -04:00
pthread_mutex_unlock ( & reload_stage_mutex ) ;
if ( CL_SUCCESS ! = reload_db ( & engine , dboptions , opts , thr_pool ) ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Database reload setup failed, keeping the previous instance \n " ) ;
2020-06-09 13:54:29 -04:00
pthread_mutex_lock ( & reload_mutex ) ;
reload = 0 ;
pthread_mutex_unlock ( & reload_mutex ) ;
pthread_mutex_lock ( & reload_stage_mutex ) ;
2020-06-02 15:46:31 -04:00
reload_stage = RELOAD_STAGE__IDLE ;
2020-06-09 13:54:29 -04:00
pthread_mutex_unlock ( & reload_stage_mutex ) ;
2020-06-02 15:46:31 -04:00
}
2020-06-09 13:54:29 -04:00
pthread_mutex_lock ( & reload_stage_mutex ) ;
}
if ( reload_stage = = RELOAD_STAGE__NEW_DB_AVAILABLE ) {
2020-06-02 15:46:31 -04:00
/* New database available */
if ( g_newengine ) {
/* Reload succeeded */
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Activating the newly loaded database... \n " ) ;
2020-06-02 15:46:31 -04:00
thrmgr_setactiveengine ( g_newengine ) ;
2020-06-09 13:54:29 -04:00
if ( optget ( opts , " ConcurrentDatabaseReload " ) - > enabled ) {
/* If concurrent database reload, we now need to free the old engine. */
cl_engine_free ( engine ) ;
}
2020-06-02 15:46:31 -04:00
engine = g_newengine ;
g_newengine = NULL ;
} else {
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Database reload failed, keeping the previous instance \n " ) ;
2020-06-02 15:46:31 -04:00
}
reload_stage = RELOAD_STAGE__IDLE ;
2020-06-09 13:54:29 -04:00
pthread_mutex_unlock ( & reload_stage_mutex ) ;
pthread_mutex_lock ( & reload_mutex ) ;
reload = 0 ;
pthread_mutex_unlock ( & reload_mutex ) ;
2020-06-02 15:46:31 -04:00
time ( & reloaded_time ) ;
2020-06-09 13:54:29 -04:00
} else {
pthread_mutex_unlock ( & reload_stage_mutex ) ;
2016-02-09 13:46:13 -05:00
}
2020-06-09 13:54:29 -04:00
} else {
pthread_mutex_unlock ( & reload_mutex ) ;
2018-12-03 12:40:13 -05:00
}
2004-02-17 00:08:25 +00:00
}
2003-07-29 15:48:06 +00:00
2009-02-12 16:51:09 +00:00
pthread_mutex_lock ( & exit_mutex ) ;
progexit = 1 ;
pthread_mutex_unlock ( & exit_mutex ) ;
2010-01-29 14:44:55 +01:00
# ifdef _WIN32
2010-01-29 18:57:50 +01:00
SetEvent ( event_wake_accept ) ;
2010-01-29 14:44:55 +01:00
# else
2009-02-12 16:51:09 +00:00
if ( write ( acceptdata . syncpipe_wake_accept [ 1 ] , " " , 1 ) < 0 ) {
2022-02-16 00:13:55 +01:00
logg ( LOGG_WARNING , " Write to syncpipe failed \n " ) ;
2009-02-12 16:51:09 +00:00
}
2010-01-29 14:44:55 +01:00
# endif
2005-03-07 00:34:04 +00:00
/* Destroy the thread manager.
* This waits for all current tasks to end
*/
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG , " Waiting for all threads to finish \n " ) ;
2005-03-07 00:34:04 +00:00
thrmgr_destroy ( thr_pool ) ;
2018-12-03 12:40:13 -05:00
if ( engine ) {
thrmgr_setactiveengine ( NULL ) ;
cl_engine_free ( engine ) ;
2008-11-06 14:27:27 +00:00
}
2006-09-14 22:43:31 +00:00
2009-02-12 16:51:09 +00:00
pthread_join ( accept_th , NULL ) ;
fds_free ( fds ) ;
2012-06-13 03:07:48 +00:00
pthread_mutex_destroy ( fds - > buf_mutex ) ;
pthread_cond_destroy ( & acceptdata . cond_nfds ) ;
2010-01-29 14:44:55 +01:00
# ifdef _WIN32
2010-01-29 18:57:50 +01:00
CloseHandle ( event_wake_accept ) ;
CloseHandle ( event_wake_recv ) ;
2010-01-29 14:44:55 +01:00
# else
2009-02-12 16:51:09 +00:00
close ( acceptdata . syncpipe_wake_accept [ 1 ] ) ;
close ( acceptdata . syncpipe_wake_recv [ 1 ] ) ;
2010-01-29 14:44:55 +01:00
# endif
2018-12-03 12:40:13 -05:00
if ( dbstat . entries )
cl_statfree ( & dbstat ) ;
if ( sd_listen_fds ( 0 ) = = 0 ) {
2016-02-09 13:46:13 -05:00
/* only close the sockets, when not using systemd socket activation */
2022-02-16 00:13:55 +01:00
logg ( LOGG_DEBUG , " Shutting down the main socket%s. \n " , ( nsockets > 1 ) ? " s " : " " ) ;
2016-02-09 13:46:13 -05:00
for ( i = 0 ; i < nsockets ; i + + )
shutdown ( socketds [ i ] , 2 ) ;
}
2004-03-01 13:01:49 +00:00
2018-12-03 12:40:13 -05:00
if ( ( opt = optget ( opts , " PidFile " ) ) - > enabled ) {
if ( unlink ( opt - > strarg ) = = - 1 )
2022-02-16 00:13:55 +01:00
logg ( LOGG_ERROR , " Can't unlink the pid file %s \n " , opt - > strarg ) ;
2018-12-03 12:40:13 -05:00
else
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " Pid file removed. \n " ) ;
2004-03-01 13:01:49 +00:00
}
2004-03-01 13:15:55 +00:00
time ( & current_time ) ;
2022-02-16 00:13:55 +01:00
logg ( LOGG_INFO , " --- Stopped at %s " , cli_ctime ( & current_time , timestr , sizeof ( timestr ) ) ) ;
2004-03-01 13:15:55 +00:00
2006-09-14 22:45:57 +00:00
return ret ;
2018-12-03 12:40:13 -05:00
}