2018-12-03 13:17:07 -05:00
/*
2019-06-05 15:33:26 -04:00
* Copyright ( C ) 2019 Cisco Systems , Inc . and / or its affiliates . All rights reserved .
2018-12-03 13:17:07 -05:00
*
2019-06-05 15:33:26 -04:00
* Authors : Mickey Sola
2018-12-03 13:17:07 -05:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston ,
* MA 02110 - 1301 , USA .
*/
# if HAVE_CONFIG_H
# include "clamav-config.h"
# endif
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# ifdef HAVE_UNISTD_H
# include <unistd.h>
# endif
# ifndef _WIN32
# include <sys/time.h>
# endif
# include <time.h>
# include <signal.h>
2019-06-20 16:54:08 -04:00
# if defined(FANOTIFY)
# include <sys/fanotify.h>
# include <fcntl.h>
# endif
2018-12-03 13:17:07 -05:00
2019-06-05 11:52:45 -04:00
# include "../libclamav/clamav.h"
# include "../libclamav/others.h"
# include "../shared/output.h"
# include "../shared/misc.h"
# include "../shared/optparser.h"
# include "../shared/actions.h"
# include "./clamonacc.h"
2019-02-20 18:31:11 -05:00
# include "./client/onaccess_client.h"
2019-02-28 13:13:14 -05:00
# include "./fanotif/onaccess_fan.h"
# include "./inotif/onaccess_ddd.h"
2019-05-09 12:42:33 -04:00
# include "./scan/onaccess_scque.h"
2018-12-03 13:17:07 -05:00
2019-02-28 13:13:14 -05:00
pthread_t ddd_pid = 0 ;
2019-05-16 13:05:48 -07:00
pthread_t scque_pid = 0 ;
2018-12-03 13:17:07 -05:00
2019-06-10 17:39:41 -04:00
static int startup_checks ( struct onas_context * ctx ) ;
2018-12-03 13:17:07 -05:00
int main ( int argc , char * * argv )
{
2019-02-28 13:13:14 -05:00
const struct optstruct * opts ;
2019-04-04 10:43:19 -04:00
const struct optstruct * clamdopts ;
2019-02-28 13:13:14 -05:00
struct onas_context * ctx ;
int ret = 0 ;
/* Initialize context */
ctx = onas_init_context ( ) ;
if ( ctx = = NULL ) {
2019-03-22 15:29:59 -04:00
logg ( " !Clamonacc: can't initialize context \n " ) ;
2019-02-28 13:13:14 -05:00
return 2 ;
}
2018-12-03 13:17:07 -05:00
2019-02-28 13:13:14 -05:00
/* Parse out all our command line options */
2019-04-02 13:47:48 -04:00
opts = optparse ( NULL , argc , argv , 1 , OPT_CLAMONACC , OPT_CLAMSCAN , NULL ) ;
2019-02-28 13:13:14 -05:00
if ( opts = = NULL ) {
2019-03-22 15:29:59 -04:00
logg ( " !Clamonacc: can't parse command line options \n " ) ;
2019-02-28 13:13:14 -05:00
return 2 ;
}
ctx - > opts = opts ;
2018-12-03 13:17:07 -05:00
2019-06-10 17:39:41 -04:00
clamdopts = optparse ( optget ( opts , " config-file " ) - > strarg , 0 , NULL , 1 , OPT_CLAMD , 0 , NULL ) ;
if ( clamdopts = = NULL ) {
logg ( " !Clamonacc: can't parse clamd configuration file %s \n " , optget ( opts , " config-file " ) - > strarg ) ;
return 2 ;
}
ctx - > clamdopts = clamdopts ;
2019-06-14 14:52:20 -04:00
ret = startup_checks ( ctx ) ;
if ( ret ) {
goto clean_up ;
}
# ifndef _WIN32
if ( ! optget ( ctx - > opts , " foreground " ) - > enabled ) {
if ( - 1 = = daemonize ( ) ) {
logg ( " !Clamonacc: could not daemonize \n " ) ;
return 2 ;
}
}
# endif
2019-06-10 17:39:41 -04:00
/* Setup our client */
switch ( onas_setup_client ( & ctx ) ) {
case CL_SUCCESS :
if ( CL_SUCCESS = = onas_check_client_connection ( & ctx ) ) {
break ;
}
case CL_BREAK :
ret = 0 ;
logg ( " *Clamonacc: not setting up client \n " ) ;
goto clean_up ;
break ;
case CL_EARG :
default :
logg ( " !Clamonacc: can't setup client \n " ) ;
ret = 2 ;
goto clean_up ;
break ;
}
2019-05-17 12:34:54 -04:00
ctx - > maxthreads = optget ( ctx - > clamdopts , " OnAccessMaxThreads " ) - > numarg ;
2019-05-09 12:42:33 -04:00
/* Setup our event queue */
switch ( onas_scanque_start ( & ctx ) ) {
case CL_SUCCESS :
break ;
case CL_BREAK :
case CL_EARG :
case CL_ECREAT :
default :
ret = 2 ;
logg ( " !Clamonacc: can't setup event consumer queue \n " ) ;
goto clean_up ;
break ;
}
2019-02-28 13:13:14 -05:00
# if defined(FANOTIFY)
/* Setup fanotify */
switch ( onas_setup_fanotif ( & ctx ) ) {
case CL_SUCCESS :
break ;
case CL_BREAK :
ret = 0 ;
goto clean_up ;
break ;
case CL_EARG :
default :
mprintf ( " !Clamonacc: can't setup fanotify \n " ) ;
ret = 2 ;
goto clean_up ;
break ;
}
2018-12-03 13:17:07 -05:00
2019-02-28 13:13:14 -05:00
if ( ctx - > ddd_enabled ) {
/* Setup inotify and kickoff DDD system */
switch ( onas_enable_inotif_ddd ( & ctx ) ) {
case CL_SUCCESS :
break ;
case CL_BREAK :
ret = 0 ;
goto clean_up ;
break ;
case CL_EARG :
default :
mprintf ( " !Clamonacc: can't setup fanotify \n " ) ;
ret = 2 ;
goto clean_up ;
break ;
}
2018-12-03 13:17:07 -05:00
}
2019-02-28 13:13:14 -05:00
# else
mprintf ( " !Clamonacc: currently, this application only runs on linux systems with fanotify enabled \n " ) ;
goto clean_up ;
# endif
2018-12-03 13:17:07 -05:00
2019-03-28 11:55:23 -04:00
logg ( " *Clamonacc: beginning event loops \n " ) ;
2019-02-28 13:13:14 -05:00
/* Kick off event loop(s) */
ret = onas_start_eloop ( & ctx ) ;
2018-12-03 13:17:07 -05:00
2019-02-28 13:13:14 -05:00
/* Clean up */
clean_up :
onas_cleanup ( ctx ) ;
2018-12-03 13:17:07 -05:00
exit ( ret ) ;
2019-02-28 13:13:14 -05:00
}
2018-12-03 13:17:07 -05:00
2019-02-28 13:13:14 -05:00
struct onas_context * onas_init_context ( void ) {
struct onas_context * ctx = ( struct onas_context * ) cli_malloc ( sizeof ( struct onas_context ) ) ;
if ( NULL = = ctx ) {
return NULL ;
2018-12-03 13:17:07 -05:00
}
2019-02-28 13:13:14 -05:00
memset ( ctx , 0 , sizeof ( struct onas_context ) ) ;
return ctx ;
}
2018-12-03 13:17:07 -05:00
2019-03-26 11:34:54 -04:00
cl_error_t onas_check_client_connection ( struct onas_context * * ctx ) {
2018-12-03 13:17:07 -05:00
2019-04-25 16:11:39 -04:00
cl_error_t err = CL_SUCCESS ;
2019-03-26 11:34:54 -04:00
/* 0 local, non-zero remote, errno set on error */
2019-04-25 16:11:39 -04:00
( * ctx ) - > isremote = onas_check_remote ( ctx , & err ) ;
2019-05-07 18:00:47 -04:00
if ( CL_SUCCESS = = err ) {
2019-03-26 11:34:54 -04:00
logg ( " *Clamonacc: " ) ;
( * ctx ) - > isremote ? logg ( " *daemon is remote \n " ) : logg ( " *daemon is local \n " ) ;
}
2019-05-07 18:00:47 -04:00
return err ? CL_EACCES : CL_SUCCESS ;
2019-02-28 13:13:14 -05:00
}
2018-12-03 13:17:07 -05:00
2019-02-28 13:13:14 -05:00
int onas_start_eloop ( struct onas_context * * ctx ) {
int ret = 0 ;
2018-12-03 13:17:07 -05:00
2019-02-28 13:13:14 -05:00
if ( ! ctx | | ! * ctx ) {
mprintf ( " !Clamonacc: unable to start clamonacc. (bad context) \n " ) ;
return CL_EARG ;
}
2019-06-05 11:52:45 -04:00
# if defined(FANOTIFY)
2019-02-28 13:13:14 -05:00
ret = onas_fan_eloop ( ctx ) ;
# endif
return ret ;
2018-12-03 13:17:07 -05:00
}
2019-06-10 17:39:41 -04:00
static int startup_checks ( struct onas_context * ctx ) {
2019-06-20 16:54:08 -04:00
# if defined(FANOTIFY)
char faerr [ 128 ] ;
# endif
2019-06-10 17:39:41 -04:00
int ret = 0 ;
cl_error_t err = CL_SUCCESS ;
if ( optget ( ctx - > opts , " help " ) - > enabled ) {
help ( ) ;
ret = 2 ;
goto done ;
}
if ( optget ( ctx - > opts , " version " ) - > enabled ) {
onas_print_server_version ( & ctx ) ;
ret = 2 ;
goto done ;
}
2019-06-20 16:54:08 -04:00
# if defined(FANOTIFY)
ctx - > fan_fd = fanotify_init ( FAN_CLASS_CONTENT | FAN_UNLIMITED_QUEUE | FAN_UNLIMITED_MARKS , O_LARGEFILE | O_RDONLY ) ;
if ( ctx - > fan_fd < 0 ) {
logg ( " !Clamonacc: fanotify_init failed: %s \n " , cli_strerror ( errno , faerr , sizeof ( faerr ) ) ) ;
if ( errno = = EPERM )
logg ( " !Clamonacc: clamonacc must have elevated permissions ... exiting ... \n " ) ;
ret = 2 ;
goto done ;
}
# endif
2019-06-14 14:52:20 -04:00
if ( curl_global_init ( CURL_GLOBAL_NOTHING ) ) {
ret = 2 ;
goto done ;
}
2019-06-10 17:39:41 -04:00
if ( 0 = = onas_check_remote ( & ctx , & err ) ) {
if ( ! optget ( ctx - > clamdopts , " OnAccessExcludeUID " ) - > enabled & &
! optget ( ctx - > clamdopts , " OnAccessExcludeUname " ) - > enabled ) {
logg ( " !Clamonacc: neither OnAccessExcludeUID or OnAccessExcludeUname is specified ... it is reccomended you exclude the clamd instance UID or uname to prevent infinite event scanning loops \n " ) ;
ret = 2 ;
goto done ;
}
}
done :
return ret ;
}
2018-12-03 13:17:07 -05:00
void help ( void )
{
mprintf_stdout = 1 ;
mprintf ( " \n " ) ;
mprintf ( " ClamAV: On Access Scanning Application and Client %s \n " , get_version ( ) ) ;
mprintf ( " By The ClamAV Team: https://www.clamav.net/about.html#credits \n " ) ;
2019-06-05 15:33:26 -04:00
mprintf ( " (C) 2019 Cisco Systems, Inc. \n " ) ;
2018-12-03 13:17:07 -05:00
mprintf ( " \n " ) ;
mprintf ( " clamonacc [options] [file/directory/-] \n " ) ;
mprintf ( " \n " ) ;
mprintf ( " --help -h Show this help \n " ) ;
mprintf ( " --version -V Print version number and exit \n " ) ;
mprintf ( " --verbose -v Be verbose \n " ) ;
mprintf ( " --log=FILE -l FILE Save scanning output to FILE \n " ) ;
2019-06-03 16:56:35 -04:00
mprintf ( " --foreground -F Output to foreground and do not daemonize \n " ) ;
2019-02-28 13:13:14 -05:00
mprintf ( " --watch-list=FILE -w FILE Watch directories from FILE \n " ) ;
2019-07-08 15:44:36 -04:00
mprintf ( " --exclude-list=FILE -e FILE Exclude directories from FILE \n " ) ;
2018-12-03 13:17:07 -05:00
mprintf ( " --remove Remove infected files. Be careful! \n " ) ;
mprintf ( " --move=DIRECTORY Move infected files into DIRECTORY \n " ) ;
mprintf ( " --copy=DIRECTORY Copy infected files into DIRECTORY \n " ) ;
mprintf ( " --config-file=FILE Read configuration from FILE. \n " ) ;
mprintf ( " --allmatch -z Continue scanning within file after finding a match. \n " ) ;
mprintf ( " --fdpass Pass filedescriptor to clamd (useful if clamd is running as a different user) \n " ) ;
mprintf ( " --stream Force streaming files to clamd (for debugging and unit testing) \n " ) ;
mprintf ( " \n " ) ;
exit ( 0 ) ;
}
2019-02-28 13:13:14 -05:00
void * onas_cleanup ( struct onas_context * ctx ) {
onas_context_cleanup ( ctx ) ;
logg_close ( ) ;
}
void * onas_context_cleanup ( struct onas_context * ctx ) {
close ( ctx - > fan_fd ) ;
optfree ( ( struct optstruct * ) ctx - > opts ) ;
2019-04-04 10:43:19 -04:00
optfree ( ( struct optstruct * ) ctx - > clamdopts ) ;
2019-02-28 13:13:14 -05:00
ctx - > opts = NULL ;
ctx - > clamdopts = NULL ;
free ( ctx ) ;
}