samba-vscan/kav5 Makefile,NONE,1.1.2.1 kav5cli.c,NONE,1.1.2.1 make.sh,NONE,1.1.2.1 vscan-kav5.c,NONE,1.1.2.1 vscan-kav5.conf,NONE,1.1.2.1 vscan-kav5.h,NONE,1.1.2.1 vscan-kav5_core.c,NONE,1.1.2.1 vscan-kav5_core.h,NONE,1.1.2.1
Rainer Link <[email protected]>
| Newsgroups | gmane.comp.security.virus.openantivirus.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/openantivirus/samba-vscan/kav5
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31114/kav5
Added Files:
Tag: VSCAN_0_3
Makefile kav5cli.c make.sh vscan-kav5.c vscan-kav5.conf
vscan-kav5.h vscan-kav5_core.c vscan-kav5_core.h
Log Message:
initial support for Kaspersky AntiVirus 5.x by Tobias Reifenberger
--- NEW FILE: make.sh ---
#!/bin/sh
CC="gcc -DCLI -I."
$CC -c kav5cli.c
$CC -c vscan-kav5_core.c
$CC -o kav5cli kav5cli.o vscan-kav5_core.o
--- NEW FILE: vscan-kav5.h ---
#ifndef __VSCAN_KAV5_H_
#define __VSCAN_KAV5_H_
/* Configuration Section :-) */
/* Clam AntiVirus (aveserver) stuff:
socket name of Clam daemon */
#define VSCAN_AVESERVER_SOCKET_NAME "/var/run/aveserver"
/* default location of samba-style configuration file (needs Samba >= 2.2.4
or Samba 3.0 */
#define PARAMCONF "/etc/samba/vscan-kav5.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_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
/* MIME-types of files to be exluded from scanning; that's an
semi-colon seperated list */
#define VSCAN_FT_EXCLUDE_LIST ""
/* End Configuration Section */
#endif /* __VSCAN_KAV5_H_ */
--- NEW FILE: vscan-kav5_core.c ---
/*
* $Id: vscan-kav5_core.c,v 1.1.2.1 2004/04/30 20:26:29 reniar Exp $
*
* Core Interface for Kaspersky's aveserver (KAV5).
*
* Copyright (C) Tobias Reifenberger, 2004
* <[email protected]>
*
* This software is licensed under the GNU General Public License (GPL)
* See: http://www.gnu.org/copyleft/gpl.html
*
*/
#ifndef CLI
#include "vscan-global.h"
#endif
#include "vscan-kav5.h"
#include "vscan-kav5_core.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
/* functions used internally */
int vscan_kav5_read(int sockfd, char *buf, size_t bufsize);
int vscan_kav5_write(int sockfd, char *buf);
#ifdef CLI
void vscan_syslog(const char *printMessage, ...);
int vscan_send_warning_message(const char *filename, const char *virname, const char *ipaddr);
#endif
// C O M M A N D S
//
// SCAN <options> <file>
// xmQPRSTUWabcdefghi scan without cure
// xmQPRSTUWabcdefghil scan with cure
//
// KEYS
//
//
// R E S P O N S E C O D E S
//
// 2xx Status Codes
// 200 OK
// 201 Server status message (HELLO)
// 220 File is clean
// 230 File is infected
// 231 File is infected and can't be cured
//
// 3xx Info (format 3xx-MESSAGE !)
// 301 KEYINFO
// 321 Scanned Content
// 322 Virus found in Content
// 324 Info Virus summary ?!?
// 325 Container found, scanning
//
// 5xx ??internal server error msg's??
// 520 Path is relative
// 525 File not found
// 526 Not a file
#define KAV5_COMMAND_QUIT "QUIT\r\n"
#define KAV5_COMMAND_SCAN "SCAN xmQPRSTUWabcdefghil %s\r\n"
#define KAV5_CODE_BYE "200"
#define KAV5_CODE_HELLO "201"
#define KAV5_CODE_FILE_CLEAN "220"
#define KAV5_CODE_FILE_INFECTED "230"
#define KAV5_CODE_FILE_INFECTED_NOCURE "231"
#define KAV5_CODE_PATH_RELATIVE "520"
#define KAV5_CODE_FILE_NOT_FOUND "525"
#define KAV5_CODE_NOT_A_FILE "526"
#define KAV5_CODE_INFO_VIRUS "324"
#ifdef CLI
int verbose_file_logging = 1;
int send_warning_message = 1;
char aveserver_socket_name[] = "/var/run/aveserver";
#define DEBUG(lev, v)
#else
extern BOOL verbose_file_logging;
extern BOOL send_warning_message;
extern fstring aveserver_socket_name;
#endif
#define KAV5_BUFSIZE 1024
//
// P A R T I
//
// low level helper functions
//
/*
* Reads at least one response-line from aveserver
* into the buffer buf.
*
* expects: socket descriptor
* pointer to recv. buffer
* size of buffer
*
* returns: total bytes read
* -1 in case of error
*/
int vscan_kav5_read(int sockfd, char *buf, size_t bufsize) {
size_t clen; //
size_t tlen; //
size_t i;
char *bufpos;
bzero(buf, bufsize);
bufpos = buf;
tlen = 0;
do {
clen = read(sockfd, bufpos, bufsize-tlen-1);
tlen += clen;
//vscan_syslog("R '%s'", bufpos);
bufpos = bufpos+clen;
if(clen<0) {
// someting is wrong
DEBUG(2, ("ERROR: reading from server (%s)\n", strerror(errno)));
vscan_syslog("ERROR: reading from server (%s)", strerror(errno));
return -1;
}
} while(bufpos[-1]!='\n');
if((bufpos-buf)<6) {
// this should never happen. minimum "XXX \r\n" expected!
DEBUG(2, ("ERROR: server sent incorrect data ('%s')\n", buf));
vscan_syslog("ERROR: reading from server (%s)", strerror(errno));
return -1;
}
/* terminate lines with \0 instead of \r\n */
for(i=0; i<tlen; i++) {
if(buf[i]=='\r' || buf[i]=='\n') {
buf[i]='\0';
}
}
return tlen;
}
/*
* writes string (command) to aveserver
*
* expects: socket descriptor
* pointer to send buffer
*
* returns: total bytes written
* -1 in case of error
*/
int vscan_kav5_write(int sockfd, char *buf)
{
DEBUG(4, ("> '%s'\n", buf));
vscan_syslog("> '%s'", buf);
return send(sockfd, buf, strlen(buf), 0);
}
/*
* If virus is found, logs the filename/virusname into syslog
*/
void vscan_kav5_log_virus(char *infected_file, char *results, char *client_ip)
{
DEBUG(2, ("ALERT: File '%s' is infected with virus '%s' (requested by '%s').\n", infected_file, results, client_ip));
if(send_warning_message)
vscan_send_warning_message(infected_file, results, client_ip);
}
//
// P A R T I I
//
// interface to vscan
//
/*
* initialize connection to aveserver
*
* returns: socket descriptor
* -1 on error
*
*/
int vscan_kav5_attach(void)
{
int sockfd;
struct sockaddr_un servaddr;
char buf[KAV5_BUFSIZE];
size_t len = 0;
/* create socket */
if((sockfd=socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
DEBUG(2, ("ERROR: can not create socket for vscan-kav5!\n"));
return -1;
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_UNIX;
#ifdef CLI
strncpy(servaddr.sun_path, aveserver_socket_name, sizeof(servaddr.sun_path)-1);
#else
safe_strcpy(servaddr.sun_path, aveserver_socket_name, sizeof(servaddr.sun_path)-1);
#endif
/* connect to socket */
if(connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
DEBUG(2, ("ERROR: can't connect to aveserver (socket: '%s', errstr: '%s')!\n", aveserver_socket_name, strerror(errno)));
return -1;
}
bzero(buf, sizeof(buf));
len = vscan_kav5_read(sockfd, buf, sizeof(buf)-1);
if(len<0) {
return -1;
}
DEBUG(4, ("< %s\n", buf));
if(strncmp(KAV5_CODE_HELLO, buf, sizeof(KAV5_CODE_HELLO)-1)!=0) {
DEBUG(2, ("ERROR: aveserver is not responding correctly (socket: '%s', reply: '%s')!\n", aveserver_socket_name, buf));
close(sockfd);
return -1;
}
return sockfd;
}
/*
* close connection to aveserver
*
*/
int vscan_kav5_detach(int sockfd)
{
char buf[KAV5_BUFSIZE];
/* sockfd == -1 indicates an error while connecting to socket */
if(sockfd >= 0) {
DEBUG(4, ("> %s", KAV5_COMMAND_QUIT));
vscan_kav5_write(sockfd, KAV5_COMMAND_QUIT);
if(vscan_kav5_read(sockfd, buf, sizeof(buf))<0) {
return -1;
}
DEBUG(4, ("< %s\n", buf));
close(sockfd);
}
return 1;
}
/*
* Scans a file (*FILE*, not a directory - keep that in mind) for a virus
*
* expects: socket descriptor, file name to scan for and client ip
*
* returns: 0 if no virus was found
* 1 if a virus was found
* -1 on error
* -2 on minor error
*/
int vscan_kav5_scanfile(int sockfd, char *scan_file, char *client_ip)
{
size_t len = 0;
char buf[KAV5_BUFSIZE], info_virus[KAV5_BUFSIZE], *sptr, *cmd;
DEBUG(2, ("scanning: '%s'\n", scan_file));
if(sockfd<0) {
DEBUG(2, ("vscan-kav5: connection not initialized"));
return -1;
}
/* prepare and send scan command */
snprintf(buf, sizeof(buf)-1, KAV5_COMMAND_SCAN, scan_file);
vscan_kav5_write(sockfd, buf);
/* process results */
while(len=vscan_kav5_read(sockfd, buf, sizeof(buf))) {
/* Sometimes aveserver sends multiple commands per line.
* We have to live with that...
*/
cmd = buf;
do {
vscan_syslog("< '%s'", cmd);
/*
* status messages
*/
if(strncmp(KAV5_CODE_INFO_VIRUS, cmd, sizeof(KAV5_CODE_INFO_VIRUS)-1)==0) {
sptr = strchr(cmd, '/');
bzero(info_virus, sizeof(info_virus));
strncpy(info_virus, cmd+4, (sptr-cmd-4-1));
vscan_kav5_log_virus(scan_file, info_virus, client_ip);
}
else if(cmd[0]=='3') {
DEBUG(4, ("< '%s'\n", cmd));
}
/*
* 'end of process' messages
*/
else if(strncmp(KAV5_CODE_FILE_CLEAN, cmd, sizeof(KAV5_CODE_FILE_CLEAN)-1)==0) {
DEBUG(2, ("code: file clean\n"));
return 0;
}
else if(strncmp(KAV5_CODE_FILE_INFECTED, cmd, sizeof(KAV5_CODE_FILE_INFECTED)-1)==0) {
DEBUG(2, ("code: file infected [%s]\n", info_virus));
return 1;
}
else if(strncmp(KAV5_CODE_FILE_INFECTED_NOCURE, cmd, sizeof(KAV5_CODE_FILE_INFECTED_NOCURE)-1)==0) {
DEBUG(2, ("code: file infected (no cure) [%s]\n", info_virus));
return 1;
}
else if(strncmp(KAV5_CODE_FILE_NOT_FOUND, cmd, sizeof(KAV5_CODE_FILE_NOT_FOUND)-1)==0) {
DEBUG(2, ("code: file not found! [%s]\n", scan_file));
return -2;
}
else if(strncmp(KAV5_CODE_NOT_A_FILE, cmd, sizeof(KAV5_CODE_NOT_A_FILE)-1)==0) {
DEBUG(2, ("code: not a file! [%s]\n", scan_file));
return -2;
}
else if(strncmp(KAV5_CODE_PATH_RELATIVE, cmd, sizeof(KAV5_CODE_PATH_RELATIVE)-1)==0) {
DEBUG(2, ("code: file has no absolute path! [%s]\n", scan_file));
return -1;
}
else if(cmd[0]=='2') {
DEBUG(2, ("code: UNKNOWN STATUSCODE '%s'\n", cmd));
return -1;
}
else if(cmd[0]=='5') {
DEBUG(2, ("code: UNKNOWN ERRORCODE '%s'\n", cmd));
return -1;
}
else {
DEBUG(2, ("code: UNKNOWN CODE '%s'\n", cmd));
return -1;
}
cmd = strchr(cmd, '\0')+2;
} while(cmd<(buf+len));
}// while(read)
return -1;
}
#ifdef CLI
/* print a message via syslog */
void vscan_syslog(const char *printMessage, ...)
{
char printMsg[512];
va_list argptr;
va_start(argptr, printMessage);
vsnprintf(printMsg, sizeof(printMsg)-1, printMessage, argptr);
va_end(argptr);
printf("%s\n", printMsg);
}
int vscan_send_warning_message(const char *filename, const char *virname, const char *ipaddr)
{
printf("Virus '%s' found in '%s' => %s\n", virname, filename, ipaddr);
return 1;
}
#endif
/*EOF*/
--- NEW FILE: vscan-kav5.c ---
/*
* $Id: vscan-kav5.c,v 1.1.2.1 2004/04/30 20:26:29 reniar Exp $
*
* virusscanning VFS module for samba. Log infected files via syslog
* facility and block access using Kaspersky's aveserver (Version 5).
*
* Copyright (C) Tobias Reifenberger, 2004
* <[email protected]>
*
* Copyright (C) Rainer Link, 2001-2003
* OpenAntiVirus.org <rainer-pBPPa8WU5k41Tgt60Rntydi2O/[email protected]>
* Dariusz Markowicz <[email protected]>, 2003
*
* Copyright (C) Stefan (metze) Metzmacher, 2003
* <[email protected]>
*
* based on the audit VFS module by
* Copyright (C) Tim Potter, 1999-2000
* Copyright (C) Alexander Bokovoy, 2002
*
*
* Credits to
* - Dave Collier-Brown for his VFS tutorial (http://www.geocities.com/orville_torpid/papers/vfs_tutorial.html)
* - REYNAUD Jean-Samuel for helping me to solve some general Samba VFS issues at the first place
* - Simon Harrison for his solution without Samba VFS (http://www.smh.uklinux.net/linux/sophos.html)
* - the whole Samba Team :)
*
* 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 "vscan-global.h"
#include "vscan-kav5.h"
#include "vscan-kav5_core.h"
#include "vscan-vfs.h"
#define VSCAN_MODULE_STR "vscan-kav5"
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 using SAVI fails, should access to any
file be denied? */
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 aveserver_socket_name; /* name of aveserver socket */
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 */
pstring exclude_file_types; /* list of file types which should be excluded from scanning */
int kav5socket = -1;
/* module version */
static const char module_id[]=VSCAN_MODULE_STR" "SAMBA_VSCAN_VERSION_STR;
static BOOL do_parameter(const char *param, const 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("aveserver socket name", param) == 0) {
fstrcpy(aveserver_socket_name, value);
DEBUG(3, ("aveserver socket name is %s\n", aveserver_socket_name));
} else if ( StrCaseCmp("exclude file types", param) == 0 ) {
pstrcpy(exclude_file_types, value);
DEBUG(3, ("exclude file types is: %s\n", exclude_file_types));
} else
DEBUG(3, ("unknown parameter: %s\n", param));
return True;
}
static BOOL do_section(const char *section)
{
/* simply return true, there's only one section :-) */
return True;
}
/* Implementation of vfs_ops. */
#if (SMB_VFS_INTERFACE_VERSION >= 6)
static int vscan_connect(vfs_handle_struct *handle, connection_struct *conn, const char *svc, const char *user)
#else
static int vscan_connect(struct connection_struct *conn, PROTOTYPE_CONST char *svc, PROTOTYPE_CONST char *user)
#endif
{
#if (SAMBA_VERSION_MAJOR==2 && SAMBA_VERSION_RELEASE>=4) || SAMBA_VERSION_MAJOR==3
#if !(SMB_VFS_INTERFACE_VERSION >= 6)
pstring opts_str;
PROTOTYPE_CONST char *p;
#endif
#endif
int retval;
#if (SMB_VFS_INTERFACE_VERSION >= 6)
vscan_syslog("samba-vscan (%s) connected (Samba 3.0), (c) by Rainer Link, OpenAntiVirus.org", module_id);
#endif
/* 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;
/* name of aveserver socket */
fstrcpy(aveserver_socket_name, VSCAN_AVESERVER_SOCKET_NAME);
/* 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;
/* file type exclude ist */
pstrcpy(exclude_file_types, VSCAN_FT_EXCLUDE_LIST);
vscan_syslog("INFO: connect to service %s by user %s",
svc, user);
#if (SAMBA_VERSION_MAJOR==2 && SAMBA_VERSION_RELEASE>=4) || SAMBA_VERSION_MAJOR==3
#if (SMB_VFS_INTERFACE_VERSION >= 6)
fstrcpy(config_file, lp_parm_const_string(SNUM(conn),VSCAN_MODULE_STR,"config-file",PARAMCONF));
#else
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));
}
}
}
}
#endif /* #if (SMB_VFS_INTERFACE_VERSION >= 6)*/
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 connection to aveserver */
kav5socket = vscan_kav5_attach();
/* initialise lrufiles list */
DEBUG(5, ("init lrufiles list\n"));
lrufiles_init(max_lrufiles, lrufiles_invalidate_time);
/* initialise filetype */
DEBUG(5, ("init file type\n"));
filetype_init(0, exclude_file_types);
#if (SMB_VFS_INTERFACE_VERSION >= 6)
return SMB_VFS_NEXT_CONNECT(handle, conn, svc, user);
#else
return default_vfs_ops.connect(conn, svc, user);
#endif
}
#if (SMB_VFS_INTERFACE_VERSION >= 6)
static void vscan_disconnect(vfs_handle_struct *handle, connection_struct *conn)
#else/* Samba 3.0 alphaX */
static void vscan_disconnect(struct connection_struct *conn)
#endif
{
vscan_syslog("INFO: disconnected");
/* close connection to aveserver */
vscan_kav5_detach(kav5socket);
lrufiles_destroy_all();
filetype_close();
#if (SMB_VFS_INTERFACE_VERSION >= 6)
SMB_VFS_NEXT_DISCONNECT(handle, conn);
#else
default_vfs_ops.disconnect(conn);
#endif
}
#if (SMB_VFS_INTERFACE_VERSION >= 6)
static int vscan_open(vfs_handle_struct *handle, connection_struct *conn, const char *fname, int flags, mode_t mode)
#else
static int vscan_open(struct connection_struct *conn, PROTOTYPE_CONST char *fname, int flags, mode_t mode)
#endif
{
int retval, must_be_checked;
SMB_STRUCT_STAT stat_buf;
pstring filepath;
char client_ip[CLIENT_IP_SIZE];
int rc;
/* Assemble complete file path */
pstrcpy(filepath, conn->connectpath);
pstrcat(filepath, "/");
pstrcat(filepath, fname);
/* 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));
#if (SMB_VFS_INTERFACE_VERSION >= 6)
return SMB_VFS_NEXT_OPEN(handle, conn, fname, flags, mode);
#else
return default_vfs_ops.open(conn, fname, flags, mode);
#endif
}
#if (SMB_VFS_INTERFACE_VERSION >= 6)
if ( (SMB_VFS_NEXT_STAT(handle, conn, fname, &stat_buf)) != 0 ) /* an error occured */
return SMB_VFS_NEXT_OPEN(handle, conn, fname, flags, mode);
#else
if ( (default_vfs_ops.stat(conn, fname, &stat_buf)) != 0 ) /* an error occured */
return default_vfs_ops.open(conn, fname, flags, mode);
#endif
else if ( S_ISDIR(stat_buf.st_mode) ) /* is it a directory? */
#if (SMB_VFS_INTERFACE_VERSION >= 6)
return SMB_VFS_NEXT_OPEN(handle, conn, fname, flags, mode);
#else
return default_vfs_ops.open(conn, fname, flags, mode);
#endif
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 */
#if (SMB_VFS_INTERFACE_VERSION >= 6)
return SMB_VFS_NEXT_OPEN(handle, conn, fname, flags, mode);
#else
return default_vfs_ops.open(conn, fname, flags, mode);
#endif
else if ( filetype_skipscan(filepath) == 1 ) {
if ( verbose_file_logging )
vscan_syslog("File '%s' not scanned as file type is on exclude list", filepath);
#if (SMB_VFS_INTERFACE_VERSION >= 6)
return SMB_VFS_NEXT_OPEN(handle, conn, fname, flags, mode);
#else
return default_vfs_ops.open(conn, fname, flags, mode);
#endif
} else
{
/* open socket */
//kav5socket = vscan_kav5_attach();
if ( kav5socket == -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 ( kav5socket >= 0 ) {
safe_strcpy(client_ip, conn->client_address, CLIENT_IP_SIZE -1);
/* 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_kav5_detach(kav5socket);
/* 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_kav5_detach(kav5socket);
/* grant access */
#if (SMB_VFS_INTERFACE_VERSION >= 6)
return SMB_VFS_NEXT_OPEN(handle, conn, fname, flags, mode);
#else
return default_vfs_ops.open(conn, fname, flags, mode);
#endif
}
/* ok, we must check the file */
/* scan file */
retval = vscan_kav5_scanfile(kav5socket, 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_kav5_detach(kav5socket);
/* 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 aveserver - access to file %s denied", fname);
//vscan_kav5_detach(kav5socket);
/* to be safe, remove file from lrufiles */
lrufiles_delete(filepath);
/* deny access */
errno = EACCES;
return -1;
} else if ( retval == 1 ) {
/* virus found */
//vscan_kav5_detach(kav5socket);
/* do action ... */
#if (SMB_VFS_INTERFACE_VERSION >= 6)
rc = vscan_do_infected_file_action(handle, conn, filepath, quarantine_dir, quarantine_prefix, infected_file_action);
#else
rc = vscan_do_infected_file_action(&default_vfs_ops, conn, filepath, quarantine_dir, quarantine_prefix, infected_file_action);
#endif
/* 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_kav5_detach(kav5socket);
}
#if (SMB_VFS_INTERFACE_VERSION >= 6)
return SMB_VFS_NEXT_OPEN(handle, conn, fname, flags, mode);
#else
return default_vfs_ops.open(conn, fname, flags, mode);
#endif
}
#if (SMB_VFS_INTERFACE_VERSION >= 6)
static int vscan_close(vfs_handle_struct *handle, files_struct *fsp, int fd)
#else
static int vscan_close(struct files_struct *fsp, int fd)
#endif
{
pstring filepath;
int retval, rv, rc;
char client_ip[CLIENT_IP_SIZE];
/* First close the file */
#if (SMB_VFS_INTERFACE_VERSION >= 6)
retval = SMB_VFS_NEXT_CLOSE(handle, fsp, fd);
#else
retval = default_vfs_ops.close(fsp, fd);
#endif
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 */
pstrcpy(filepath, fsp->conn->connectpath);
pstrcat(filepath, "/");
pstrcat(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;
}
/* don't scan files which are in the list of exclude file types */
if ( filetype_skipscan(filepath) == 1 ) {
if ( verbose_file_logging )
vscan_syslog("File '%s' not scanned as file type is on exclude list", filepath);
return retval;
}
//kav5socket = vscan_kav5_attach();
if ( kav5socket >= 0 ) {
safe_strcpy(client_ip, fsp->conn->client_address, CLIENT_IP_SIZE -1);
/* scan only file, do nothing */
rv = vscan_kav5_scanfile(kav5socket, filepath, client_ip);
//vscan_kav5_detach(kav5socket);
if ( rv == 1 ) {
/* virus was found */
#if (SMB_VFS_INTERFACE_VERSION >= 6)
rc = vscan_do_infected_file_action(handle, fsp->conn, filepath, quarantine_dir, quarantine_prefix, infected_file_action);
#else
rc = vscan_do_infected_file_action(&default_vfs_ops, fsp->conn, filepath, quarantine_dir, quarantine_prefix, infected_file_action);
#endif
}
}
return retval;
}
#if (SMB_VFS_INTERFACE_VERSION >= 6)
/* Samba 3.0 */
NTSTATUS init_module(void)
{
NTSTATUS ret;
ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, VSCAN_MODULE_STR, vscan_ops);
openlog("smbd_"VSCAN_MODULE_STR, LOG_PID, SYSLOG_FACILITY);
vscan_syslog("samba-vscan (%s) registered (Samba 3.0), (c) by Rainer Link, OpenAntiVirus.org", module_id);
DEBUG(5,("samba-vscan (%s) registered (Samba 3.0), (c) by Rainer Link, OpenAntiVirus.org\n", module_id));
return ret;
}
#else
/* 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_RELEASE>=4
/* Samba 2.2.4 */
struct vfs_ops *vfs_init(int *vfs_version, struct vfs_ops *def_vfs_ops)
#elif SAMBA_VERSION_RELEASE==2
/* Samba 2.2.2 / Samba 2.2.3 !!! */
struct vfs_ops *vfs_init(int* Version, struct vfs_ops *ops)
#elif SAMBA_VERSION_RELEASE==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_RELEASE>=4
/* Samba 2.2.4 */
struct vfs_ops tmp_ops;
#endif
#endif
openlog("smbd_"VSCAN_MODULE_STR, 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_RELEASE>=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_RELEASE==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_RELEASE>=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
#endif /* #if (SMB_VFS_INTERFACE_VERSION >= 6) */
--- NEW FILE: Makefile ---
#
# Makefile for vscan-kav5, part of samba-vscan
#
# $Id: Makefile,v 1.1.2.1 2004/04/30 20:26:29 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-kav5.so
SOURCES = $(SMBVS_GLB)/vscan-functions.c $(SMBVS_GLB)/vscan-message.c $(SMBVS_GLB)/vscan-quarantine.c $(SMBVS_GLB)/vscan-fileaccesslog.c vscan-kav5.c vscan-kav5_core.c vscan-kav5.h
OBJS = vscan-functions.lo vscan-message.lo vscan-quarantine.lo vscan-fileaccesslog.lo vscan-kav5.lo vscan-kav5_core.lo
LIBS =
# Default target
all: $(VFS_OBJS)
vscan-kav5.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) $(CPPFLAGS) $(CFLAGS) -c vscan-kav5_core.c
$(LIBTOOL) $(CC) $(CPPFLAGS) $(CFLAGS) -c vscan-kav5.c
$(LIBTOOL) $(CC) -shared $(LDFLAGS) $(LIBS) $(OBJS) -o vscan-kav5.so
# Misc targets
clean:
rm -rf .libs
rm -f core *~ *% *.bak *.so *.lo *.o
--- NEW FILE: vscan-kav5.conf ---
[samba-vscan]
; run-time configuration for vscan-samba using
; aveserver
; all options are 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 yes)
scan on close = yes
; if communication to aveserver 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. (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
; exclude files from being scanned based on the MIME-type! Semi-colon
; seperated list (default: empty list). Use this with care!
exclude file types =
; socket name of aveserver (default: /var/run/aveserver)
aveserver socket name = /var/run/aveserver
--- NEW FILE: vscan-kav5_core.h ---
#ifndef __VSCAN_KAV5_CORE_H_
#define __VSCAN_KAV5_CORE_H_
/* functions by vscan-kav5_core */
/* initializes socket & connection */
int vscan_kav5_attach(void);
/* closes socket & connection */
int vscan_kav5_detach(int sockfd);
/* scans a file */
int vscan_kav5_scanfile(int sockfd, char *scan_file, char *client_ip);
#endif /* __VSCAN_KAV5_CORE_H_ */
--- NEW FILE: kav5cli.c ---
#include <stdio.h>
#include <vscan-kav5.h>
#include <vscan-kav5_core.h>
int main(int argc, char **argv) {
int kav5_socket, i;
kav5_socket = vscan_kav5_attach();
if(kav5_socket<1)
exit(1);
for(i=1; argv[i]!=NULL; i++) {
vscan_kav5_scanfile(kav5_socket, argv[i], "127.0.0.1");
}
vscan_kav5_detach(kav5_socket);
}
-------------------------------------------------------
This SF.Net email is sponsored by: Oracle 10g
Get certified on the hottest thing ever to hit the market... Oracle 10g.
Take an Oracle 10g class now, and we'll give you the exam FREE.
http://ads.osdn.com/?ad_id=3149&alloc_id=8166&op=click