samba-vscan/nai LEAME,NONE,1.1.2.1 Makefile,NONE,1.1.2.1 vscan-mcdaemon.c,NONE,1.1.2.1 vscan-mcdaemon.conf,NONE,1.1.2.1 vscan-mcdaemon.h,NONE,1.1.2.1 vscan-mcdaemon_core.c,NONE,1.1.2.1 vscan-mcdaemon_core.h,NONE,1.1.2.1

[email protected]
Newsgroups gmane.comp.security.virus.openantivirus.cvs
Message-ID <[email protected]>
Update of /cvsroot/openantivirus/samba-vscan/nai
In directory sc8-pr-cvs1:/tmp/cvs-serv11866/nai

Added Files:
      Tag: VSCAN_0_3
	LEAME Makefile vscan-mcdaemon.c vscan-mcdaemon.conf 
	vscan-mcdaemon.h vscan-mcdaemon_core.c vscan-mcdaemon_core.h 
Log Message:
added; support for NAI uvscan. Contributed by
Arturo Alberto Busleiman


--- NEW FILE: LEAME ---
McAfee Antivirus via McDaemon para Samba-VSCAN (modulo samba-uvscan)
desarrollado por intraRedes S.R.L por encargo de Laboratorios BAGO.

Autor: Arturo Alberto Busleiman <[email protected]>

El modulo samba-uvscan permite a un share Samba analizar archivos de dicho
share en busca de virus. Este analisis lo realiza McAfee uvscan mediante una
aplicacion middleware denominada mcDaemon, la cual realiza un proceso de
preforking y balanceo de carga para mejorar la velocidad de respuesta de
samba-uvscan.

El proceso de instalacion consta de los siguientes pasos:

Desde el directorio raiz de la distribucion fuente de Samba, realizar los
siguientes pasos:

cd sources ; ./configure && make
cd ../examples/VFS ; ./configure && make
cd samba-vscan/vscan-uvscan ; make
cd mcDaemon-v0.1 ; make

En ese mismo directorio se encuentra el archivo de configuracion del modulo
samba-uvscan. Editar el archivo y modificarlo acordemente al sistema.
Tambien se debe editar el archivo MCDaemon y modificar, si asi se desea, el
parametro NUM_MCD. Ese valor indica cuantas instancias prefork de uvscan se
utilizaran: este parametro es un arma de doble filo, manejarse con cuidado.
Un valor de 10 a 20 puede ser lo ideal en un sistema monoprocesador de
1700Mhz, para un stress maximo de 5 analisis simultaneos en una secuencia
continua con diferencias de tiempo menores a 450ms.

Una vez editados los archivos, ejecutar "make install", el cual crea los
directorios y links necesarios y copia los archivos a las ubicaciones
predeterminadas. Mediante chkconfig se habilita la carga de mcDaemon al
inicio del sistema en los runlevels 3 y 5.


--- NEW FILE: Makefile ---
#
# Makefile for vscan-mcdaemon, part of samba-vscan
#
# $Id: Makefile,v 1.1.2.1 2003/12/04 16:24:00 reniar Exp $
#

# Variables

CC = gcc
LIBTOOL = libtool

SAMBA_SRC = ../../../../source
SAMBA_INCL = ../../../../source/include
UBIQX_SRC = ../../../../source/ubiqx
SMBWR_SRC = ../../../../source/smbwrapper
SMBVS_INCL = ../include
SMBVS_GLB = ../global
CFLAGS = -I$(SAMBA_SRC) -I$(SAMBA_INCL) -I$(UBIQX_SRC) -I$(SMBWR_SRC) -I$(SMBVS_INCL) -Wall -g -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -fPIC 
VFS_OBJS = vscan-mcdaemon.so
SOURCES = $(SMBVS_GLB)/vscan-functions.c $(SMBVS_GLB)/vscan-message.c $(SMBVS_GLB)/vscan-quarantine.c $(SMBVS_GLB)/vscan-fileaccesslog.c vscan-mcdaemon.c vscan-mcdaemon_core.c vscan-mcdaemon.h vscan-mcdaemon_core.h
OBJS = vscan-functions.lo vscan-message.lo vscan-quarantine.lo vscan-fileaccesslog.lo vscan-mcdaemon.lo vscan-mcdaemon_core.lo
LIBS = 

# Default target

all: $(VFS_OBJS)

vscan-mcdaemon.so: $(SOURCES)
	$(LIBTOOL) $(CC) $(CFLAGS) -c $(SMBVS_GLB)/vscan-functions.c
	$(LIBTOOL) $(CC) $(CFLAGS) -c $(SMBVS_GLB)/vscan-message.c
	$(LIBTOOL) $(CC) $(CFLAGS) -c $(SMBVS_GLB)/vscan-quarantine.c
	$(LIBTOOL) $(CC) $(CFLAGS) -c $(SMBVS_GLB)/vscan-fileaccesslog.c
	$(LIBTOOL) $(CC) $(CFLAGS) -c vscan-mcdaemon_core.c
	$(LIBTOOL) $(CC) $(CPPFLAGS) $(CFLAGS) -c vscan-mcdaemon.c
	$(LIBTOOL) $(CC) -shared $(LDFLAGS) $(LIBS) $(OBJS) -o vscan-mcdaemon.so


# Misc targets

clean:
	rm -rf .libs
	rm -f core *~ *% *.bak *.so *.lo *.o
		

--- NEW FILE: vscan-mcdaemon.c ---
/* 
 * $Id: vscan-mcdaemon.c,v 1.1.2.1 2003/12/04 16:24:00 reniar Exp $
 *
 * virusscanning VFS module for samba.  Log infected files via syslog
 * facility and block access using McAfee Virus Scanner via McDaemon.
 *
 * Copyleft (C), 2003
 * Arturo 'Buanzo' Busleiman <[email protected]>
 *
 * based on the vscan-samba's vscan-openantivirus module by
 * Rainer Link, 2001-2003
 *               OpenAntiVirus.org <rainer-pBPPa8WU5k41Tgt60Rntydi2O/[email protected]>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *  
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *  
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


#include <includes.h>
#include <vfs.h>

#include "vscan-mcdaemon.h"
#include "vscan-vfs.h"
#include "vscan-functions.h"
#include "vscan-quarantine.h"
#include "vscan-fileaccesslog.h"


fstring config_file;            /* location of config file, either
                                   PARAMCONF or as set via vfs options
                                */

ssize_t max_size;          	/* do not scan files greater than max_size
                                   if max_size = 0, scan any file
                                */

BOOL verbose_file_logging;  	/* log ever file access */

BOOL scan_on_open;         	/* scan a file before it is opened
                                   Defaults to True
                                */

BOOL scan_on_close;        	/* scan a new file put on share or
                                   if file was modified
                                   Defaults to False
                                */

BOOL deny_access_on_error;      /* if connection to daemon fails,  should access to any
                                   file be denied? Defaults to True 
				*/


BOOL deny_access_on_minor_error; /* if daemon returns non-critical error,
                                    should access to the file be denied? */

BOOL send_warning_message;	/* send a warning message using the windows
				   messenger service? */

fstring mcdaemon_ip;              	/* IP McDaemon runs on */
unsigned short int mcdaemon_port; 	/* port number McDaemon listens on */

fstring quarantine_dir;	/* directory for infected files */
fstring quarantine_prefix;	/* prefix    for infected files */

enum infected_file_action_enum infected_file_action; /* what to do with infected files;
                                                        defaults to quarantine */

int max_lrufiles;               /* specified the maximum entries in lrufiles list */
time_t lrufiles_invalidate_time; /* specified the time in seconds after the lifetime
                                    of an entry is expired and entry will be invalidated */



/* module version */
static const char module_id[]="vscan-mcdaemon 0.0.1-PoC";


static BOOL do_parameter(char *param, char *value)
{
        if ( StrCaseCmp("max file size", param) == 0 ) {
                max_size = atoi(value);
                DEBUG(3, ("max file size is: %d\n", max_size));
        } else if ( StrCaseCmp("verbose file logging", param) == 0 ) {
                set_boolean(&verbose_file_logging, value);
                DEBUG(3, ("verbose file logging is: %d\n", verbose_file_logging)
);
        } else if ( StrCaseCmp("scan on open", param) == 0 ) {
                set_boolean(&scan_on_open, value);
                DEBUG(3, ("scan on open: %d\n", scan_on_open));
        } else if ( StrCaseCmp("scan on close", param) == 0 ) {
                set_boolean(&scan_on_close, value);
                DEBUG(3, ("scan on close is: %d\n", scan_on_close));
        } else if ( StrCaseCmp("deny access on error", param) == 0 ) {
                set_boolean(&deny_access_on_error, value);
                DEBUG(3, ("deny access on error is: %d\n", deny_access_on_error));
	} else if ( StrCaseCmp("deny access on minor error", param) == 0 ) {
		set_boolean(&deny_access_on_minor_error, value);
		DEBUG(3, ("deny access on minor error is: %d\n", deny_access_on_minor_error));
	} else if ( StrCaseCmp("send warning message", param) == 0 ) {
		set_boolean(&send_warning_message, value);
		DEBUG(3, ("send warning message is: %d\n", send_warning_message));

        } else if ( StrCaseCmp("infected file action", param) == 0 ) {
		if (StrCaseCmp("quarantine", value) == 0) {
			infected_file_action = INFECTED_QUARANTINE;
		} else if (StrCaseCmp("delete", value) == 0) {
			infected_file_action = INFECTED_DELETE;
		} else if (StrCaseCmp("nothing", value) == 0) {
			infected_file_action = INFECTED_DO_NOTHING;
		} else {
			DEBUG(2, ("samba-vscan: badly formed infected file action in configuration file, parameter %s\n", value));
		}
                DEBUG(3, ("infected file action is: %d\n", infected_file_action));
        } else if ( StrCaseCmp("quarantine directory", param) == 0 ) {
                fstrcpy(quarantine_dir, value);
                DEBUG(3, ("quarantine directory is: %s\n", quarantine_dir));
        } else if ( StrCaseCmp("quarantine prefix", param) == 0 ) {
                fstrcpy(quarantine_prefix, value);
                DEBUG(3, ("quarantine prefix is: %s\n", quarantine_prefix));
        } else if ( StrCaseCmp("max lru files entries", param) == 0 ) {
                max_lrufiles = atoi(value);
                DEBUG(3, ("max lru files entries is: %d\n", max_lrufiles));
        } else if ( StrCaseCmp("lru file entry lifetime", param) == 0 ) {
                lrufiles_invalidate_time = atol(value);
                DEBUG(3, ("lru file entry lifetime is: %li\n", (long)lrufiles_invalidate_time));
        } else if ( StrCaseCmp("mcdaemon ip", param) == 0 ) {
                fstrcpy(mcdaemon_ip, value);
                DEBUG(3, ("McDaemon IP is: %s\n", mcdaemon_ip));
        } else if ( StrCaseCmp("mcdaemon port", param) == 0 ) {
                /* FIXME: mcdaemon_ip is short int ! atoi converts string to int
                   overflow is possible. Should a check be added, if port number
                   is too high? */
                mcdaemon_port = atoi(value);
                DEBUG(3, ("McDaemon port is: %d\n", mcdaemon_port));
	} else
                DEBUG(3, ("unknown parameter: %s\n", param));

        return True;
}

static BOOL do_section(char *section)
{
        /* simply return true, there's only one section :-) */
        return True;
}




/* Implementation of vfs_ops.  */

#if SAMBA_VERSION_MAJOR==3
 /* Samba 3.0 alphaX */
 static int vscan_connect(struct connection_struct *conn, const char *svc, const char *user)
#else
 /* Samba 2.2.x */
 #if SAMBA_VERSION_MINOR==4
  /* Samba 2.2.4 */
  int vscan_connect(struct connection_struct *conn, const char *svc, const char *user)
 #else
  /* Samba 2.2.3-2.2.0 */
  int vscan_connect(struct connection_struct *conn, char *svc, char *user)
 #endif
#endif
{
	#if (SAMBA_VERSION_MAJOR==2 && SAMBA_VERSION_MINOR==4) || SAMBA_VERSION_MAJOR==3
          pstring opts_str;
          #if SAMBA_VERSION_MAJOR==3
           const char *p;
          #else
           char *p;
          #endif
	#endif
        int retval;


        /* set default value for configuration files */
        fstrcpy(config_file, PARAMCONF);

        /* set default value for max file size */
        max_size = VSCAN_MAX_SIZE;

        /* set default value for file logging */
        verbose_file_logging = VSCAN_VERBOSE_FILE_LOGGING;

        /* set default value for scan on open() */
        scan_on_open = VSCAN_SCAN_ON_OPEN;

        /* set default value for scan on close() */
        scan_on_close = VSCAN_SCAN_ON_CLOSE;

        /* set default value for deny access on error */
        deny_access_on_error = VSCAN_DENY_ACCESS_ON_ERROR;

	/* set default value for deny access on minor error */
	deny_access_on_minor_error = VSCAN_DENY_ACCESS_ON_MINOR_ERROR;
 
	/* set default value for send warning message */
	send_warning_message = VSCAN_SEND_WARNING_MESSAGE;

        /* set default value for infected file action */
        infected_file_action = VSCAN_INFECTED_FILE_ACTION;

        /* set default value for quarantine directory */
        fstrcpy(quarantine_dir, VSCAN_QUARANTINE_DIRECTORY);

        /* set default value for quarantine prefix */
        fstrcpy(quarantine_prefix, VSCAN_QUARANTINE_PREFIX);

        /* set default value for McDaemon IP */
        fstrcpy(mcdaemon_ip, VSCAN_MCDAEMON_IP);

        /* set default value for McDaemon port */
        mcdaemon_port = VSCAN_MCDAEMON_PORT;

        /* set default value for maximum lrufile entries */
        max_lrufiles = VSCAN_MAX_LRUFILES;

        /* time after an entry is considered as expired */
        lrufiles_invalidate_time = VSCAN_LRUFILES_INVALIDATE_TIME;


	vscan_syslog("INFO: connect to service %s by user %s", 
	       svc, user);

	#if (SAMBA_VERSION_MAJOR==2 && SAMBA_VERSION_MINOR==4) || SAMBA_VERSION_MAJOR==3
          pstrcpy(opts_str, (const char*) lp_vfs_options(SNUM(conn)));
          if( !*opts_str ) {
                DEBUG(3, ("samba-vscan: no configuration file set - using default value (%s).\n", lp_vfs_options(SNUM(conn))));
          } else {
                p = opts_str;
                if ( next_token(&p, config_file, "=", sizeof(config_file)) ) {
                        trim_string(config_file, " ", " ");
                        if ( !strequal("config-file", config_file) ) {
                                DEBUG(3, ("samba-vscan - connect: options %s is not config-file\n", config_file));
                                /* setting default value */
                                fstrcpy(config_file, PARAMCONF);

                        } else {
                                if ( !next_token(&p, config_file," \n",sizeof(config_file)) ) {
                                        DEBUG(3, ("samba-vscan - connect: no option after config-file=\n"));
                                        /* setting default value */
                                        fstrcpy(config_file, PARAMCONF);
                                } else {
                                        trim_string(config_file, " ", " ");
                                        DEBUG(3, ("samba-vscan - connect: config file name is %s\n", config_file));
                                }
                        }
                }
          }
          retval = pm_process(config_file, do_section, do_parameter);
          DEBUG(10, ("pm_process returned %d\n", retval));
	  if (!retval) vscan_syslog("ERROR: could not parse configuration file '%s'. File not found or not read-able. Using compiled-in defaults", config_file);
	#endif

        /* initialise lrufiles list */
        DEBUG(5, ("init lrufiles list\n"));
        lrufiles_init(max_lrufiles, lrufiles_invalidate_time);


	#if SAMBA_VERSION_MAJOR!=3
	return default_vfs_ops.connect(conn, svc, user);
	#else
	return 0;	/* Success */
	#endif
}

#if SAMBA_VERSION_MAJOR==3
 /* Samba 3.0 alphaX */
 static void vscan_disconnect(struct connection_struct *conn)
#else
 /* Samba 2.2.x */
 void vscan_disconnect(struct connection_struct *conn)
#endif
{

	vscan_syslog("INFO: disconnected");

        lrufiles_destroy_all();

	default_vfs_ops.disconnect(conn);
}


#if SAMBA_VERSION_MAJOR==3
 /* Samba 3.0 alphaX */
 static int vscan_open(struct connection_struct *conn, const char *fname, int flags, mode_t mode)
#else
 /* Samba 2.2.x */
 #if SAMBA_VERSION_MINOR==4
  /* Samba 2.2.4 */
  int vscan_open(struct connection_struct *conn, const char *fname, int flags, mode_t mode)
 #else
  /* Samba 2.2.3 - 2.2.0 */
  int vscan_open(struct connection_struct *conn, char *fname, int flags, mode_t mode)
 #endif
#endif
{
	int retval, must_be_checked;
	SMB_STRUCT_STAT stat_buf;
	int sockfd;
	pstring filepath;
	char client_ip[18];

	int rc;


        /* scan files while opening? */
        if ( !scan_on_open ) {
                DEBUG(3, ("samba-vscan - open: File '%s' not scanned as scan_on_open is not set\n", fname));
                return default_vfs_ops.open(conn, fname, flags, mode);
        }


        if ( (default_vfs_ops.stat(conn, fname, &stat_buf)) != 0 )    /* an error occured */ 
		return default_vfs_ops.open(conn, fname, flags, mode);
	else if ( S_ISDIR(stat_buf.st_mode) ) 	/* is it a directory? */
		 return default_vfs_ops.open(conn, fname, flags, mode);
	else if ( ( stat_buf.st_size > max_size ) && ( max_size > 0 ) ) /* file is too large */
		vscan_syslog("INFO: File %s is larger than specified maximum file size! Not scanned!", fname);
	else if ( stat_buf.st_size == 0 ) /* do not scan empty files */
		return default_vfs_ops.open(conn, fname, flags, mode);
	else  
	{
		/* open socket */
		sockfd = vscan_mcdaemon_init();

                if ( sockfd == -1 && deny_access_on_error ) {
                        /* an error occured - can not communicate to daemon - deny access */
                        vscan_syslog("ERROR: can not communicate to daemon - access denied");
                        errno = EACCES;
                        return -1;
		} else if ( sockfd >= 0 ) 
		{
	                /* Assemble complete file path */       
        	        fstrcpy(filepath, conn->connectpath);
	                fstrcat(filepath, "/");  /* is "/" correct? */
	                fstrcat(filepath, fname);       

			fstrcpy(client_ip, conn->client_address);

                        /* must file actually be scanned? */
                        must_be_checked = lrufiles_must_be_checked(filepath, stat_buf.st_mtime);
                        if ( must_be_checked == -1 ) {
                                /* file has already been checked and marked as infected */
                                /* deny access */
                                if ( verbose_file_logging )
                                        vscan_syslog("File '%s' has already been scanned and marked as infected. Not scanned any more. Access denied", filepath);
			
				/* close socket */
				vscan_mcdaemon_end(sockfd);
				
				/* deny access */
                                errno = EACCES;
                                return -1;
                        } else if ( must_be_checked == 0 )  {
                                /* file has already been checked, not marked as infected and not modified */
                                if ( verbose_file_logging )
                                        vscan_syslog("File '%s' has already been scanned, not marked as infected and not modified. Not scanned anymore. Access granted", filepath);

                                /* close socket */
				vscan_mcdaemon_end(sockfd);
				
				/* grant access */
				return default_vfs_ops.open(conn, fname, flags, mode);
                        }
                        /* ok, we must check the file */

			/* scan file */
			retval = vscan_mcdaemon_scanfile(sockfd, filepath, client_ip);
			if ( retval == -2 && deny_access_on_minor_error ) {
				/* a minor error occured - deny access */
				vscan_syslog("ERROR: daemon failed with a minor error - access to file %s denied", fname);
				vscan_mcdaemon_end(sockfd);
				
                                /* to be safe, remove file from lrufiles */
                                lrufiles_delete(filepath);

                                /* deny access */
				errno = EACCES;
				return -1;
                        } else if ( retval == -1 && deny_access_on_error ) {
                                /* an error occured - can not communicate to daemon - deny access */
                                vscan_syslog("ERROR: can not communicate to daemon - access to file %s denied", fname);
				vscan_mcdaemon_end(sockfd);

				/* to be safe, remove file from lrufiles */
                                lrufiles_delete(filepath);

                                /* deny access */

                                errno = EACCES;
                                return -1;
			} else if ( retval == 1 ) {
				/* close socket */
				vscan_mcdaemon_end(sockfd);
				/* do action ... */
				
				rc = vscan_do_infected_file_action(&default_vfs_ops, conn, filepath, quarantine_dir, quarantine_prefix, infected_file_action);

                                /* add/update file. mark file as infected! */
                                lrufiles_add(filepath, stat_buf.st_mtime, TRUE);

				/* virus found, deny acces */
				errno = EACCES; 
				return -1;
                        } else if ( retval == 0 ) {
                                /* file is clean, add to lrufiles */
                                lrufiles_add(filepath, stat_buf.st_mtime, FALSE);
                        }
		}

		/* close socket */
		vscan_mcdaemon_end(sockfd);

	}
	return default_vfs_ops.open(conn, fname, flags, mode);

}


#if SAMBA_VERSION_MAJOR==3
 /* Samba 3.0 alphaX */
 static int vscan_close(struct files_struct *fsp, int fd)
#else
 /* Samba 2.2.x */
 int vscan_close(struct files_struct *fsp, int fd)
#endif
{
	pstring filepath;
        int retval, rv, rc;
	int sockfd;
	char client_ip[18];

        /* First close the file */
        retval = default_vfs_ops.close(fsp, fd);

        if ( !scan_on_close ) {
                DEBUG(3, ("samba-vscan - close: File '%s' not scanned as scan_on_close is not set\n", fsp->fsp_name));
                return retval;
        }


	/* get the file name */
        fstrcpy(filepath, fsp->conn->connectpath);
        fstrcat(filepath, "/"); 
        fstrcat(filepath, fsp->fsp_name);        
	
        /* Don't scan directorys */
        if ( fsp->is_directory )
            return retval;


	if ( !fsp->modified ) {
                if ( verbose_file_logging ) 
                        vscan_syslog("INFO: file %s was not modified - not scanned", filepath);

		return retval;
	}

	/* scan only file, do nothing */	
        sockfd = vscan_mcdaemon_init();

        if ( sockfd >= 0 ) {
		fstrcpy(client_ip, fsp->conn->client_address);
		rv = vscan_mcdaemon_scanfile(sockfd, filepath, client_ip);
		vscan_mcdaemon_end(sockfd);
		if ( rv == 1 ) {
			/* virus was found */
			rc = vscan_do_infected_file_action(&default_vfs_ops, fsp->conn, filepath, quarantine_dir, quarantine_prefix, infected_file_action);
		}

	}
	return retval;
}




/* VFS initialisation function.  Return initialised vfs_ops structure
   back to SAMBA. */

#if SAMBA_VERSION_MAJOR==3
 /* Samba 3.0 alphaX */
 vfs_op_tuple *vfs_init(int *vfs_version, struct vfs_ops *def_vfs_ops,
			struct smb_vfs_handle_struct *vfs_handle)
#else
 /* Samba 2.2.x */
 #if SAMBA_VERSION_MINOR==4   
  /* Samba 2.2.4 */
  struct vfs_ops *vfs_init(int *vfs_version, struct vfs_ops *def_vfs_ops)
 #elif SAMBA_VERSION_MINOR==2
  /* Samba 2.2.2 / Samba 2.2.3 !!! */
  struct vfs_ops *vfs_init(int* Version, struct vfs_ops *ops)
 #elif SAMBA_VERSION_MINOR==1
  /* Samba 2.2.1 */
  struct vfs_ops *vfs_module_init(int *vfs_version)
 #else
  /* Samba 2.2.0 */
  struct vfs_ops *vfs_init(int *vfs_version)
 #endif
#endif
{
	#if SAMBA_VERSION_MAJOR!=3
 	 #if SAMBA_VERSION_MINOR==4
	  /* Samba 2.2.4 */
	  struct vfs_ops tmp_ops;
	 #endif
	#endif


        openlog("smbd_vscan_mcdaemon", LOG_PID, SYSLOG_FACILITY);

        #if SAMBA_VERSION_MAJOR==3
         /* Samba 3.0 alphaX */
         *vfs_version = SMB_VFS_INTERFACE_VERSION;
         vscan_syslog("samba-vscan (%s) loaded (Samba 3.x), (c) by Rainer Link, OpenAntiVirus.org", module_id);
        #else
         /* Samba 2.2.x */
         #if SAMBA_VERSION_MINOR==4
          /* Samba 2.2.4 */
          *vfs_version = SMB_VFS_INTERFACE_VERSION;
          vscan_syslog("samba-vscan (%s) loaded (Samba >=2.2.4), (c) by Rainer Link, OpenAntiVirus.org", module_id);
         #elif SAMBA_VERSION_MINOR==2
          /* Samba 2.2.2 / Samba 2.2.3 !!! */
          *Version = SMB_VFS_INTERFACE_VERSION;
          vscan_syslog("samba-vscan (%s) loaded (Samba 2.2.2/2.2.3), (c) by Rainer Link, OpenAntiVirus.org", module_id);
         #else
          /* Samba 2.2.1 / Samba 2.2.0 */
          *vfs_version = SMB_VFS_INTERFACE_VERSION;
          vscan_syslog("samba-vscan (%s) loaded (Samba 2.2.0/2.2.1), (c) by Rainer Link, OpenAntiVirus.org",
               module_id);
         #endif
        #endif


	#if SAMBA_VERSION_MAJOR==3
         /* Samba 3.0 alphaX */
	 DEBUG(3, ("Initialising default vfs hooks\n"));
         memcpy(&default_vfs_ops, def_vfs_ops, sizeof(struct vfs_ops));

         /* Remember vfs_handle for further allocation and referencing of 
	    private information in vfs_handle->data
         */
	 vscan_handle = vfs_handle;
	 return vscan_ops;
        #else
         /* Samba 2.2.x */
	 #if SAMBA_VERSION_MINOR==4
	  /* Samba 2.2.4 */

	  *vfs_version = SMB_VFS_INTERFACE_VERSION;
	  memcpy(&tmp_ops, def_vfs_ops, sizeof(struct vfs_ops));
	  tmp_ops.connect = vscan_connect;
	  tmp_ops.disconnect = vscan_disconnect;
	  tmp_ops.open = vscan_open;
	  tmp_ops.close = vscan_close;
	  memcpy(&vscan_ops, &tmp_ops, sizeof(struct vfs_ops));
	  return(&vscan_ops);

	 #else
          /* Samba 2.2.3-2.2.0 */
          return(&vscan_ops);
	 #endif
	#endif
}


#if SAMBA_VERSION_MAJOR==3
/* VFS finalization function */
void vfs_done(connection_struct *conn)
{
        DEBUG(3, ("Finalizing default vfs hooks\n"));
}
#endif

--- NEW FILE: vscan-mcdaemon.conf ---
[samba-vscan]
; run-time configure options for vscan-samba using
; McAfee Virus Scanner via McDaemon
; all options set to default values

; do not scan files larger than X bytes. If set to 0 (default),
; this feature is disable (i.e. all files are scanned)
max file size = 0 

; log all file access (yes/no). If set to yes, every access will
; be logged. If set to no (default), only access to infected files
; will be logged
verbose file logging = no  

; if set to yes (default), a file will be scanned while opening
scan on open = yes

; if set to yes, a file will be scanned while closing (default is no)
scan on close = no 

; if communication to daemon fails, should access to file denied?
; (default: yes)
deny access on error = yes

; if daemon files with a minor error (corruption, etc.),
; should access to file denied?
; (default: yes)
deny access on minor error = yes

; send a warning message via Windows Messenger service
; when virus is found?
; (default: yes)
send warning message = yes

; what to do with an infected file
; quarantine: try to move to quantine directory; delete it if moving fails
; delete:     delete infected file
; nothing:    do nothing
infected file action = quarantine

; where to put infected files - you really want to change this!
; it has to be on the same physical device as the share!
quarantine directory  = /tmp
; prefix for files in quarantine
quarantine prefix = vir-

; as Windows tries to open a file multiple time in a (very) short time
; of period, samba-vscan use a last recently used file mechanism to avoid
; multiple scans of a file. This setting specified the maximum number of
; elements of the last recently used file list. If set to 0, this
; mechanism is disabled completely (default: 100)
max lru files entries = 100

; an entry is invalidad after lru file entry lifetime (in seconds).
; (Default: 5)
lru file entry lifetime = 5


; IP of McDaemon
mcdaemon ip = 127.0.0.1

; port number McDaemon listens on
mcdaemon port = 8128

--- NEW FILE: vscan-mcdaemon.h ---
#ifndef __VSCAN_OAV_H_
#define __VSCAN_OAV_H_

#include "vscan-global.h"

/* default location of samba-style configuration file (needs Samba >= 2.2.4
 or Samba 3.0 */

#define PARAMCONF "/etc/samba/vscan-mcdaemon.conf"


/* False = log only infected file, True = log every file access */

#ifndef VSCAN_VERBOSE_FILE_LOGGING
# define VSCAN_VERBOSE_FILE_LOGGING False   
#endif

/* if a file is bigger than VSCAN_SOPHOS_MAX_SIZE it won't be scanned. Has to be
   specified in bytes! If it set to 0, the file size check is disabled */

#ifndef VSCAN_MAX_SIZE 
# define VSCAN_MAX_SIZE 0 
#endif


/* True = scan files on open */

#ifndef VSCAN_SCAN_ON_OPEN 
# define VSCAN_SCAN_ON_OPEN True 
#endif

/* True = scan files on close */

#ifndef VSCAN_SCAN_ON_CLOSE
# define VSCAN_SCAN_ON_CLOSE False
#endif


/* True = deny access in case of virus scanning failure */

#ifndef VSCAN_DENY_ACCESS_ON_ERROR
# define VSCAN_DENY_ACCESS_ON_ERROR True
#endif 

/* True = deny access in case of minor virus scanning failure */

#ifndef VSCAN_DENY_ACCESS_ON_MINOR_ERROR
# define VSCAN_DENY_ACCESS_ON_MINOR_ERROR True
#endif

/* True = send a warning message via window messenger service for viruses found */

#ifndef VSCAN_SEND_WARNING_MESSAGE
# define VSCAN_SEND_WARNING_MESSAGE True
#endif

/* default infected file action */
#define VSCAN_INFECTED_FILE_ACTION INFECTED_QUARANTINE

/* default quarantine settings; hopefully the user changes this */
#define VSCAN_QUARANTINE_DIRECTORY "/tmp"
#define VSCAN_QUARANTINE_PREFIX    "vir-"

/* set default value for maximum lrufile entries */
#define VSCAN_MAX_LRUFILES 100

/* time after an entry is considered as expired */
#define VSCAN_LRUFILES_INVALIDATE_TIME 5

/* IP:PORT OAV ScannerDaemon listens on */
#define VSCAN_MCDAEMON_IP	"127.0.0.1"
#define VSCAN_MCDAEMON_PORT 	8128

/* End Configuration Section */

#ifndef MAXLINE
 #define MAXLINE 4096
#endif


/* functions by vscan-oav_core */
/* opens a socket */
int vscan_oav_init(void); 
/* scans a file */
int vscan_oav_scanfile(int sockfd, char *scan_file, char* client_ip);
/* closes socket */
void vscan_oav_end(int sockfd);


#endif /* __VSCAN_OAV_H_ */

--- NEW FILE: vscan-mcdaemon_core.c ---
/*
 * $Id: vscan-mcdaemon_core.c,v 1.1.2.1 2003/12/04 16:24:00 reniar Exp $
 * 
 * Core Interface for McAfee Virus Scanner via McDaemon			
 *
 * Copyleft (C) Arturo 'Buanzo' Busleiman, 2003
 *               Arturo 'Buanzo' Busleiman <[email protected]>
 *
 * This software is licensed under the GNU General Public License (GPL)
 * See: http://www.gnu.org/copyleft/gpl.html
 *
*/

#include <includes.h>

#include "vscan-mcdaemon_core.h"
#include "vscan-message.h"
#include "vscan-functions.h"

/* hum, global vars ... */
extern BOOL verbose_file_logging;
extern BOOL send_warning_message;
extern fstring  mcdaemon_ip;
extern unsigned short int mcdaemon_port;


/* initialise socket to McDaemon
   returns -1 on error or the socket descriptor */
int vscan_mcdaemon_init(void)
{

	int sockfd;
	struct sockaddr_in servaddr;

	/* create socket */
        if (( sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
               vscan_syslog("ERROR: can not create socket!\n");
               return -1; 
        }

	bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(mcdaemon_port);

	/* hm, inet_pton may not exist on all systems - FIXME ! */
        if ( inet_pton(AF_INET, mcdaemon_ip, &servaddr.sin_addr) <= 0 ) {
                vscan_syslog("ERROR: inet_pton failed!\n");
                return -1;
	}

	/* connect to socket */
	if ( connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 )
        {
                vscan_syslog("ERROR: can not connect to McDaemon!\n");
                return -1;
        }


	return sockfd;

}

/*
  If virus is found, logs the filename/virusname into syslog
*/
void vscan_mcdaemon_log_virus(char *infected_file, char *result, char* client_ip)
{
        char *str;
        size_t len;

        /* remove "FOUND: " from the result string to get only the virus name */

	len = strlen(result);
        /* sanity check ... */
        if ( len < 7 ) {
            /* hum, sth went wrong ... */
            vscan_syslog_alert("ALERT - Scan result: '%s' infected with virus 'UNKOWN', client: '%s'", infected_file, client_ip);
	    if ( send_warning_message )
		vscan_send_warning_message(infected_file, "UNKNOWN", client_ip);

        } else {
            str = result;
            str+= 7;
            vscan_syslog_alert("ALERT - Scan result: '%s' infected with virus '%s', client: '%s'", infected_file, str, client_ip);
	    if ( send_warning_message )
		vscan_send_warning_message(infected_file, str, client_ip);
        }
}



/*
  Scans a file (*FILE*, not a directory - keep that in mind) for a virus
  Expects socket descriptor and file name to scan for
  Returns -2 on a minor error, -1 on error, 0 if no virus was found, 
  1 if a virus was found 
*/
int vscan_mcdaemon_scanfile(int sockfd, char *scan_file, char* client_ip)
{
	size_t len;
	char recvline[MAXLINE + 1];
	pstring mcafeeCommand;

	FILE *fpin, *fpout;

	fpin = fdopen(sockfd, "r");
	if ( fpin == NULL ) {
		vscan_syslog("ERROR: can not open stream for reading - %s", strerror(errno));
		return -1;
	}

	fpout = fdopen(sockfd, "w");
	if ( fpout == NULL ) {
		vscan_syslog("ERROR: can not open stream for writing - %s", strerror(errno));
		return -1;
	}

	if ( verbose_file_logging )
	        vscan_syslog("INFO: Scanning file : '%s'", scan_file);

	/* McDaemon expects "SCAN <filename>\n" */
	/* what about if the <filename> itself contains '\n'? */
        pstrcpy(mcafeeCommand, "SCAN ");
        pstrcat(mcafeeCommand, scan_file);
        pstrcat(mcafeeCommand, "\n");

	/* NOTE: what happens if scan_file is very long? */

	/* write to socket-stream */
	if ( fputs(mcafeeCommand, fpout) == EOF) {
		vscan_syslog("ERROR: can not send file name to McDaemon!");
		return -1;
	}

	/* hum, instead of flush()ing, use setvbuf to set line-based buffering? */
	if ( fflush(fpout) == EOF ) {
		vscan_syslog("ERROR: can not flush output stream - %s", strerror(errno));
		/* FIXME: shouldn't we return -1 here? */
	}

	/* read from socket-stream */
	if ( fgets(recvline, MAXLINE, fpin) == NULL ) {
		vscan_syslog("ERROR: can not get result from McDaemon!");
		return -1;
	}

	/* Response from McDaemon is either
	   - OK                  file scanned and not infected
	   - FOUND: <virusname>  file scanned and infected
	   - ERROR		 sth went wrong, i.e. file not found
	*/
	if ( strncmp("FOUND", recvline, 5) == 0   ) {
		/* virus found */
		vscan_mcdaemon_log_virus(scan_file, recvline, client_ip);
		return 1;
	} else if ( strncmp("ERROR", recvline, 5) == 0  ) {
		/* ERROR */
		if ( verbose_file_logging )
			vscan_syslog("ERROR: file %s not found, not readable or an error occured", scan_file);
		return -2;
	} else if ( strncmp("OK", recvline, 2) == 0 ) {
		/* OK */
		if ( verbose_file_logging )
			vscan_syslog("INFO: file %s is clean", scan_file);
        } else {
		/* unknown response */
		vscan_syslog("ERROR: unknown response from McDaemon while scanning %s!", scan_file);
		/* FIXME: should we really mark this as a minor error? */
		return -2;
	}	

	return 0;
	
}

/*
  close socket
*/
void vscan_mcdaemon_end(int sockfd)
{
	/* sockfd == -1 indicates an error while connecting to socket */
	if ( sockfd >= 0 ) {
		close(sockfd);
	}

}

--- NEW FILE: vscan-mcdaemon_core.h ---
#ifndef __VSCAN_OAV_CORE_H_
#define __VSCAN_OAV_CORE_H_

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "vscan-mcdaemon.h"

#endif /* __VSCAN_OAV_CORE_H */




-------------------------------------------------------
This SF.net email is sponsored by: SF.net Giveback Program.
Does SourceForge.net help you be more productive?  Does it
help you create better code?  SHARE THE LOVE, and help us help
YOU!  Click Here: http://sourceforge.net/donate/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.