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
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.