logo       

samba-vscan/antivir Makefile,NONE,1.1.2.1 vscan-antivir.c,NONE,1.1.2.1 vsca: msg#00002

Subject: samba-vscan/antivir Makefile,NONE,1.1.2.1 vscan-antivir.c,NONE,1.1.2.1 vscan-antivir.conf,NONE,1.1.2.1 vscan-antivir.h,NONE,1.1.2.1 vscan-antivir_core.c,NONE,1.1.2.1 vscan-antivir_core.h,NONE,1.1.2.1
Update of /cvsroot/openantivirus/samba-vscan/antivir
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30758/antivir

Added Files:
      Tag: VSCAN_0_3
        Makefile vscan-antivir.c vscan-antivir.conf vscan-antivir.h 
        vscan-antivir_core.c vscan-antivir_core.h 
Log Message:
added support for AntiVir, contributed by the H+BEDV folks. Param parsing
not yet up-to-date for sheduled 0.3.6 release


--- NEW FILE: vscan-antivir.h ---
#ifndef __VSCAN_ANTIVIR_H_
#define __VSCAN_ANTIVIR_H_

#include "vscan-global.h"

/* Configuration Section :-) */

/* program name for scanner process */
#define VSCAN_ANTIVIR_PROGRAM_NAME      "/usr/lib/AntiVir/antivir"

/* enable scan in archive files */
#define VSCAN_AVARCH_ENABLED            0
/* maximum compression ratio of files in archive */
#define VSCAN_AVARCH_MAXRATIO           150
/* maximum archived file size (in bytes) */
#define VSCAN_AVARCH_MAXFILESIZE        (1024 * 1048576)
/* maximum recursion level */
#define VSCAN_AVARCH_MAXRECLEVEL        5

/* non virus types of alerts (all off by default) */
#define VSCAN_AVDETECT_DIALER           0
#define VSCAN_AVDETECT_GAME             0
#define VSCAN_AVDETECT_JOKE             0
#define VSCAN_AVDETECT_PMS              0
#define VSCAN_AVDETECT_SPY              0
#define VSCAN_AVDETECT_ALLTYPES         0

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

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


/* False = log only concerning 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 True
#endif

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

#ifndef VSCAN_DENY_ACCESS_ON_ERROR
# define VSCAN_DENY_ACCESS_ON_ERROR True
#endif

/* True = deny access in case of minor 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 alerts found 
*/

#ifndef VSCAN_SEND_WARNING_MESSAGE
# define VSCAN_SEND_WARNING_MESSAGE True
#endif

/* default concerning 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 */

/* functions by vscan-antivir_core */

/* user connects to a share (might startup scanner daemon) */
int vscan_antivir_connect(void);

/* prepare a scan (might open a socket) */
int vscan_antivir_init(void);

/* scan a file */
int vscan_antivir_scanfile(int sockfd, char *scan_file, char *client_ip);

/* end a scan (might close a socket) */
void vscan_antivir_end(int sockfd);

/* user disconnects from a share (might shutdown scanner daemon) */
void vscan_antivir_disconnect(void);


#endif /* __VSCAN_ANTIVIR_H_ */

--- NEW FILE: vscan-antivir_core.c ---
/*
 * $Id: vscan-antivir_core.c,v 1.1.2.1 2004/11/17 19:21:04 reniar Exp $
 *
 * Core Interface for the H+BEDV AntiVir Scanner
 *
 * Copyright (C) Rainer Link, 2001-2002
 *               OpenAntiVirus.org 
<rainer-pBPPa8WU5k41Tgt60Rntydi2O/JbrIOy@xxxxxxxxxxxxxxxx>
 *               Dariusz Markowicz 
<dariusz-UZsDlYnqr8oyTh+JdRw4UA@xxxxxxxxxxxxxxxx>, 2003
 *               H+BEDV Datentechnik GmbH 
<unix_support-qmGPETzO5JyELgA04lAiVw@xxxxxxxxxxxxxxxx>, 2004
 *
 * This software is licensed under the GNU General Public License (GPL)
 * See: http://www.gnu.org/copyleft/gpl.html
 *
 */

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

/* use select(2) or poll(2) to drain antivir(1)'s greeting after process
 * startup?  we default to poll(2) since we cannot guarantee the file
 * descriptor to be <= 1023 */
#undef USE_SELECT
#if defined USE_SELECT
  #include <sys/select.h>
#else
  #include <sys/poll.h>
#endif

#include "vscan-global.h"
#include "vscan-antivir_core.h"

/* used when scanning files */
extern BOOL verbose_file_logging;
extern BOOL send_warning_message;

/* used to startup the scanner process */
extern fstring antivir_program_name;
extern BOOL antivir_arch_scan_enable;
extern int antivir_arch_max_ratio;
extern ssize_t antivir_arch_max_size;
extern int antivir_arch_max_recursion;
extern int antivir_detect_dialer;
extern int antivir_detect_game;
extern int antivir_detect_joke;
extern int antivir_detect_pms;
extern int antivir_detect_spy;
extern int antivir_detect_alltypes;

/* used to manage the scanner process */
static int conn_count = 0;
static int antivir_fd_write = -1;
static int antivir_fd_read = -1;
static FILE *antivir_file_read = NULL;
static pid_t antivir_scanner_pid = 0;

static int connect_to_scanner(void);
static void disconnect_from_scanner(void);

/* user connects to a share (might startup scanner daemon) */
int vscan_antivir_connect(void) {

        /* only act on the very first connection for this smbd process */
        conn_count++;
        if (conn_count > 1)
                return(0);

        if (connect_to_scanner() < 0)
                return(-1);

        return(0);
}

/* user disconnects from a share (might shutdown scanner daemon) */
void vscan_antivir_disconnect(void) {
        conn_count--;
        if (conn_count == 0)
                disconnect_from_scanner();
}

/*
 * introduces a scan request, (re)connect to the scanner process;
 * returns -1 on error or 0 on success
 */
int vscan_antivir_init(void)
{
        int rc;

        rc = connect_to_scanner();

        return(rc);
}

/*
 * If an alert was found, logs the filename and concern into syslog
 */
void vscan_antivir_log_alert(char *concerning_file, char *results, char 
*client_ip) {
        vscan_syslog_alert("ALERT - Scan result: found '%s' in file '%s', 
client: '%s'", results, concerning_file, client_ip);
        if ( send_warning_message )
                vscan_send_warning_message(concerning_file, results, client_ip);
}

/*
 * avoid non printables in the scanner communication protocol
 * XXX: does the condition need further splitting on EBCDIC machines?
 * but OTOH isprint(3) does not really match what we would need here
 */
static int needsescape(const char c) {
        return(((c <= ' ') || (c > '~') || (c == '\\')) ? 1 : 0);
#if 0
        /* will this do better / more portable? */
        if (c == '\\')
                return(1);
        if (isspace((int)c))
                return(1);
        if (isprint((int)c))
                return(0);
        return(1);
#endif
}

/*
 * Scans a file (NOT a directory) for concerns
 *
 * Gets the vscan_antivir_init() return value (not really needed), the name of
 * the file to scan and an IP to send notification to
 *
 * Returns
 * -2 on minor error,
 * -1 on error,
 *  0 if nothing was found,
 *  1 if a concern was found
 */
int vscan_antivir_scanfile(int sockfd, char *scan_file, char *client_ip) {
        char *request;
        size_t len;
        int bEsc;
        char escbuff[5];        /* "\\xNN" plus NUL */
        char buff[1024];
        char *p1, *p2;

        /* (re)connect to the scanner process */
        if (connect_to_scanner() < 0)
                return(-1);

        /* prepare antivir command (SCAN request) */
        /* +1 is for '\0' termination --metze */
        /* +3 for every special (non printable) char (escape) */
        len = strlen("SCAN:") + strlen(scan_file) + strlen("\n") + 1;
        bEsc = 0;
        for (p1 = scan_file; (p1 != NULL) && (*p1 != '\0'); p1++) {
                if (needsescape(*p1)) {
                        len += 3;
                        bEsc++;
                }
        }
        request = (char *)malloc(len);
        if (NULL == request) {
                vscan_syslog("ERROR: can not allocate memory");
                return -1; /* error allocating memory */
        }
        safe_strcpy(request, "SCAN:", len-1);
        if (! bEsc) {
                /* simple concatenation of the complete filename */
                safe_strcat(request, scan_file, len-1);
        } else {
                /* a more expensive approach to avoid non printable chars in 
the protocol */
                /* XXX TODO optimization (memcpy() with a fork?) */
                for (p1 = scan_file; (p1 != NULL) && (*p1 != '\0'); p1++) {
                        if (needsescape(*p1)) {
                                snprintf(escbuff, sizeof(escbuff), "\\x%02X", 
(*((unsigned char *)p1)) & 0xFF);
                        } else {
                                /* there must be an easier way to accomplish 
this :) */
                                snprintf(escbuff, sizeof(escbuff), "%c", *p1);
                        }
                        safe_strcat(request, escbuff, len - 1);
                }
        }
        snprintf(escbuff, sizeof(escbuff), "\n");
        safe_strcat(request, escbuff, len - 1);

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

        /* send request */
        len = write(antivir_fd_write, request, strlen(request));
        if (len != strlen(request)) {
                free(request);
                vscan_syslog("ERROR: can not write to the antivir socket");
                return -1; /* error writing to the antivir socket */
        }
        free(request);
        request = NULL;

        /* get response (in a loop, we might have to skip some lines) */
        do {
                memset(buff, 0, sizeof(buff));
                p1 = fgets((char *)&buff, sizeof(buff), antivir_file_read);
                if (p1 == NULL)
                        break;
                /* remove trailing spaces */
                p1 = buff + strlen(buff);
                while ((p1 > buff) && (isspace((int)*(p1-1)))) {
                        p1--;
                        *p1 = '\0';
                }

                /* an updater might have restarted our scanner process */
                if (strncmp(buff, "Running in DEMO mode.", strlen("Running in 
DEMO mode.")) == 0) {
                        /* log a warning? */
                        continue;
                }
                if (strncmp(buff, "BANNER ", strlen("BANNER ")) == 0) {
                        continue;
                }

                /*
                 * we got a response to our request;
                 * do NOT close the scanner, reuse it for multiple scans
                 */

                /* split response into keyword and (optional) parameter */
                p1 = buff;
                p2 = strchr(p1, ':');
                if (p2 == NULL)
                        p2 = p1 + strlen(p1);
                if (*p2 == ':') {
                        *p2 = '\0';
                        p2++;
                }
                while (isspace((int)*p2))
                        p2++;

                /* found an alert */
                if (strcmp(p1, "FOUND") == 0) {
                        vscan_antivir_log_alert(scan_file, p2, client_ip);
                        return 1;
                /* file good */
                } else if (strcmp(p1, "OK") == 0) {
                        if (verbose_file_logging) {
                                vscan_syslog("INFO: file %s is clean", 
scan_file);
                        }
                        return 0;
                /* no explicit check for "ERROR", caught here, too */
                } else {
                        if (verbose_file_logging) {
                                vscan_syslog("ERROR: file %s not found, not 
readable or an error occured", scan_file);
                        }
                        return -2;
                }
        } while (0);

        /* read error or EOF, close the scanner process */
        disconnect_from_scanner();

        vscan_syslog("ERROR: can not get result from antivir");
        return -1;
}


/*
 * ends a scan request
 *
 * gets the vscan_antivir_init() return value (not really needed)
 */
void vscan_antivir_end(int sockfd) {

        /* leave the connection open, we will reuse it for the
         * next file to scan and close it on (last) disconnect
         */
        /* EMPTY */
}

/*
 * connect or reconnect to a scanner process;
 * returns -1 on errors, non negative codes otherwise
 */
static int connect_to_scanner(void) {
        int execargc;
        char *execargv[16];
        int rc;
        int fdreq[2];
        int fdrsp[2];
        pid_t pid;
        char buff[256];
        struct timeval tv;
        int fd;

        /*
         * check if the scanner process is alive (handles dangling
         * connections); we do not strictly need this but I want to
         * avoid SIGPIPEs (we're in a shared object, attached to an
         * smbd(8) process -- would SIG_IGN be appropriate? read(2)
         * and fgets(3) would return errors, anyway ...)
         */
        if ((antivir_scanner_pid != 0) && (kill(antivir_scanner_pid, 0) != 0))
                disconnect_from_scanner();

        /* shortcut for "already (completely) open?" */
        if ((antivir_fd_write != -1) && (antivir_fd_read != -1) &&
            (antivir_file_read != NULL) && (antivir_scanner_pid != 0))
                return(0);

        /* one of the parameters might be wrong, close what is left open (if 
any) */
        disconnect_from_scanner();

        /* open up a new scanner process ... */

#define DEL_CMD_WORDS do {                       \
        while (execargc > 0) {                   \
                execargc--;                      \
                free(execargv[execargc]);        \
        }                                        \
} while (0)

#define ADD_CMD_WORD(word) do {                                          \
        char *copy;                                                      \
                                                                         \
        if (word != NULL) {                                              \
                copy = strdup(word);                                     \
                if (copy == NULL) {                                      \
                        DEL_CMD_WORDS;                                   \
                        return(-1);                                      \
                }                                                        \
        } else {                                                         \
                copy = NULL;                                             \
        }                                                                \
        execargv[execargc] = copy;                                       \
        execargc++;                                                      \
        if (execargc >= sizeof(execargv) / sizeof(execargv[0])) {        \
                DEL_CMD_WORDS;                                           \
                disconnect_from_scanner();                               \
                return(-1);                                              \
        }                                                                \
        execargv[execargc] = NULL;                                       \
} while (0)

        /* ... build a command line ... */
        {
                execargc = 0;
                ADD_CMD_WORD(antivir_program_name);
                ADD_CMD_WORD("--samba-vscan");
                if (antivir_arch_scan_enable) {
                        char printbuff[40];

                        ADD_CMD_WORD("--scan-in-archive");
                        /* for some reason the %z format spec did not work :( */
                        snprintf(printbuff, sizeof(printbuff), 
"--archive-max-size=%lld", (long long)antivir_arch_max_size);
                        ADD_CMD_WORD(printbuff);
                        snprintf(printbuff, sizeof(printbuff), 
"--archive-max-recursion=%d", antivir_arch_max_recursion);
                        ADD_CMD_WORD(printbuff);
                        snprintf(printbuff, sizeof(printbuff), 
"--archive-max-ratio=%d", antivir_arch_max_ratio);
                        ADD_CMD_WORD(printbuff);
                }
                /* optionally add a "--temp=" option? */
                if (antivir_detect_alltypes)
                        ADD_CMD_WORD("--alltypes");
                if (antivir_detect_dialer)
                        ADD_CMD_WORD("--with-dialer");
                if (antivir_detect_game)
                        ADD_CMD_WORD("--with-game");
                if (antivir_detect_joke)
                        ADD_CMD_WORD("--with-joke");
                if (antivir_detect_pms)
                        ADD_CMD_WORD("--with-pms");
                if (antivir_detect_spy)
                        ADD_CMD_WORD("--with-spy");
        }

        /* ... setup a communication pipe ... */
        rc = pipe(fdreq);
        if (rc < 0) {
                DEL_CMD_WORDS;
                disconnect_from_scanner();
                return(-1);
        }
        rc = pipe(fdrsp);
        if (rc < 0) {
                DEL_CMD_WORDS;
                disconnect_from_scanner();
                return(-1);
        }

        /* ... fork off the process ... */
        pid = fork();
        switch (pid) {
        case -1:        /* failure */
                DEL_CMD_WORDS;
                disconnect_from_scanner();
                return(-1);
        case 0:         /* the child (scanner) */
                /* redirect stdin */
                rc = dup2(fdreq[0], STDIN_FILENO);
                if (rc == -1)
                        exit(1);
                close(fdreq[0]); /* redirected */
                fdreq[0] = -1;
                close(fdreq[1]); /* not needed */
                fdreq[1] = -1;
                /* redirect stdout */
                rc = dup2(fdrsp[1], STDOUT_FILENO);
                if (rc == -1)
                        exit(1);
                close(fdrsp[1]); /* redirected */
                fdrsp[1] = -1;
                close(fdrsp[0]); /* not needed */
                fdrsp[0] = -1;
                /* redirect stderr */
                fclose(stderr); freopen("/dev/null", "w", stderr);
                /* close all fds */
                /* XXX how to portably get the max fd?
                 *   fd = open("/dev/null", O_RDONLY);
                 * does not work reliably in the smbd(8) case,
                 * since there is a gap in the fd sequence
                 */
                fd = 1024; /* aux upper limit */
                while (fd > STDERR_FILENO) {
                        close(fd);
                        fd--;
                }
                /* execute the scanner process */
                rc = execvp(execargv[0], execargv);
                /* UNREACH */
                exit(1);
        default:        /* parent (samba-vscan) */
                /* release the command line */
                DEL_CMD_WORDS;
                /* get the read/write handles to the scanner process */
                close(fdreq[0]); fdreq[0] = -1;
                antivir_fd_write = fdreq[1];
                close(fdrsp[1]); fdrsp[1] = -1;
                antivir_fd_read = fdrsp[0];
                /* drain banners / greetings / help or synopsis on errors / etc 
*/
                tv.tv_sec = 1; tv.tv_usec = 0;
                do {
                        ssize_t ct;
#if defined USE_SELECT
                        fd_set r;

                        FD_ZERO(&r);
                        FD_SET(antivir_fd_read, &r);
                        rc = select(antivir_fd_read + 1, &r, NULL, NULL, &tv);
                        tv.tv_sec = 0; tv.tv_usec = 0;
                        if (rc < 0) {
                                vscan_syslog("ERROR: Can not read from scanner 
- %s", strerror(errno));
                                disconnect_from_scanner();
                                return -1;
                        }
                        if (rc == 0)
                                break;
                        if (! FD_ISSET(antivir_fd_read, &r))
                                break;
#else /* USE_SELECT */
                        struct pollfd pfd[1];

                        memset(pfd, 0, sizeof(pfd));
                        pfd[0].fd = antivir_fd_read;
                        pfd[0].events = POLLIN;
                        rc = poll(pfd, 1, tv.tv_sec * 1000);
                        tv.tv_sec = 0; tv.tv_usec = 0;
                        if (rc < 0) {
                                vscan_syslog("ERROR: Can not read from scanner 
- %s", strerror(errno));
                                disconnect_from_scanner();
                                return -1;
                        }
                        if (rc == 0)
                                break;
#endif /* USE_SELECT */
                        ct = read(antivir_fd_read, buff, sizeof(buff));
                        if (ct <= 0) {
                                vscan_syslog("ERROR: Can not read from scanner 
- %s", strerror(errno));
                                disconnect_from_scanner();
                                return -1;
                        }
                } while (1);
                /* convert "int fd" to "FILE *" for fgets(3) */
                antivir_file_read = fdopen(antivir_fd_read, "r");
                if (antivir_file_read == NULL) {
                        vscan_syslog("ERROR: Can not read from scanner - %s", 
strerror(errno));
                        disconnect_from_scanner();
                        return -1;
                }
                /* scanner process gone after the greeting? */
                if (kill(pid, 0) != 0) {
                        vscan_syslog("ERROR: scanner disappeared at connect 
time");
                        disconnect_from_scanner();
                        return(-1);
                }
                antivir_scanner_pid = pid;
                /* connection setup done, now we're happy */
                return(0);
        }
        /* UNREACH */
        return(-1);
}

/*
 * invalidate the scanner process
 * (detach and clear vars after use or failure)
 */
static void disconnect_from_scanner(void) {
        if (antivir_fd_write != -1) {
                close(antivir_fd_write);
                antivir_fd_write = -1;
        }
        /* XXX drain possible input? */
        if (antivir_file_read != NULL) {
                fclose(antivir_file_read);
                antivir_file_read = NULL;
                antivir_fd_read = -1;
        } else if (antivir_fd_read != -1) {
                close(antivir_fd_read);
                antivir_fd_read = -1;
        }
        antivir_scanner_pid = 0;
}

--- NEW FILE: vscan-antivir_core.h ---
#ifndef __VSCAN_ANTIVIR_CORE_H_
#define __VSCAN_ANTIVIR_CORE_H_

#include "vscan-antivir.h"

#endif /* __VSCAN_ANTIVIR_CORE_H */

--- NEW FILE: Makefile ---
#
# Makefile for vscan-antivir, part of samba-vscan
#
# $Id: Makefile,v 1.1.2.1 2004/11/17 19:21:04 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-antivir.so
SOURCES = $(SMBVS_GLB)/vscan-functions.c $(SMBVS_GLB)/vscan-message.c 
$(SMBVS_GLB)/vscan-quarantine.c $(SMBVS_GLB)/vscan-fileaccesslog.c 
vscan-antivir.c vscan-antivir_core.c vscan-antivir.h vscan-antivir_core.h
OBJS = vscan-functions.lo vscan-message.lo vscan-quarantine.lo 
vscan-fileaccesslog.lo vscan-antivir.lo vscan-antivir_core.lo
LIBS = 


# Default target

all: $(VFS_OBJS)

vscan-antivir.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-antivir_core.c
        $(LIBTOOL) $(CC) $(CPPFLAGS) $(CFLAGS) -c vscan-antivir.c
        $(LIBTOOL) $(CC) -shared $(LDFLAGS) $(LIBS) $(OBJS) -o vscan-antivir.so


# Misc targets

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

--- NEW FILE: vscan-antivir.conf ---

[samba-vscan]
; run-time configuration for vscan-samba using
; antivir
; 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 files containing
; an alert 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 antivir fails, should access to file be denied?
; (default: yes)
deny access on error = yes

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

; send a warning message via Windows Messenger service
; when an alert was found?
; (default: yes)
send warning message = yes

; what to do with a file containing an alert
; quarantine: try to move to quantine directory; delete it if moving fails
; delete:     delete concerning file
; nothing:    do nothing (default)
concerning file action = quarantine

; where to put concerning files - you really want to change this!
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 =


; executable name of antivir (default: /usr/lib/AntiVir/antivir)
antivir program name = /usr/lib/AntiVir/antivir

; enable scan of archive files
antivir scan in archive = no

; maximum compression ratio of files in archive (default: 150)
antivir max ratio in archive = 150

; maximum archived file size, in bytes (default: 1 GB)
antivir max archived file size = 1073741824

; maximum recursion level (default: 5)
antivir max recursion level = 5

; detect non virus alerts, too, i.e. different kinds of unwanted software
; (default: off)
antivir detect dialer = no
antivir detect game = no
antivir detect joke = no
antivir detect pms = no
antivir detect spy = no

; a cumulative switch to enable *all* of the above categories
antivir detect alltypes = no


--- NEW FILE: vscan-antivir.c ---
/*
 * $Id: vscan-antivir.c,v 1.1.2.1 2004/11/17 19:21:04 reniar Exp $
 *
 * virusscanning VFS module for samba.  Log concerning files via syslog
 * facility and block access using the H+BEDV AntiVir scanner.
 *
 * Copyright (C) Rainer Link, 2001-2003
 *               OpenAntiVirus.org 
<rainer-pBPPa8WU5k41Tgt60Rntydi2O/JbrIOy@xxxxxxxxxxxxxxxx>
 *               Dariusz Markowicz 
<dariusz-UZsDlYnqr8oyTh+JdRw4UA@xxxxxxxxxxxxxxxx>, 2003
 * Copyright (C) Stefan (metze) Metzmacher, 2003
 *               <metze-pz2UNc6q77cb1SvskN2V4Q@xxxxxxxxxxxxxxxx>
 * Copyright (C) H+BEDV Datentechnik GmbH, 2004
 *               <unix_support-qmGPETzO5JyELgA04lAiVw@xxxxxxxxxxxxxxxx>
 *
 * 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-antivir.h"

#include "vscan-vfs.h"

#define VSCAN_MODULE_STR "vscan-antivir"

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 True
                                */

BOOL deny_access_on_error;      /* if communication to the scanner 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? */

enum infected_file_action_enum concerning_file_action; /* what to do with 
concerning files;
                                                        defaults to quarantine 
*/

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

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 */

fstring antivir_program_name;   /* name of antivir executable */

BOOL antivir_arch_scan_enable;  /* archive related settings for the AntiVir 
scanner */
int antivir_arch_max_ratio;
ssize_t antivir_arch_max_size;
int antivir_arch_max_recursion;

BOOL antivir_detect_dialer;       /* non virus type alerts related settings for 
the AntiVir scanner */
BOOL antivir_detect_game;
BOOL antivir_detect_joke;
BOOL antivir_detect_pms;
BOOL antivir_detect_spy;
BOOL antivir_detect_alltypes;

/* 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 = atoll(value);
                /* the %z format spec for size_t does not work :( */
                DEBUG(3, ("max file size is: %lld\n", (long long)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("concerning file action", param) == 0)
#if 1 /* for compatibility */
                || (StrCaseCmp("infected file action", param) == 0)
#endif
        ) {
                if (StrCaseCmp("quarantine", value) == 0) {
                        concerning_file_action = INFECTED_QUARANTINE;
                } else if (StrCaseCmp("delete", value) == 0) {
                        concerning_file_action = INFECTED_DELETE;
                } else if (StrCaseCmp("nothing", value) == 0) {
                        concerning_file_action = INFECTED_DO_NOTHING;
                } else {
                        DEBUG(2, ("samba-vscan: badly formed concerning file 
action in configuration file, parameter %s\n", value));
                }
                DEBUG(3, ("concerning file action is: %d\n", 
concerning_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("exclude file types", param) == 0 ) {
                pstrcpy(exclude_file_types, value);
                DEBUG(3, ("exclude file types is: %s\n", exclude_file_types));
        } else if ( StrCaseCmp("antivir program name", param) == 0) {
                fstrcpy(antivir_program_name, value);
                DEBUG(3, ("antivir program name is %s\n", 
antivir_program_name));
        } else if ( StrCaseCmp("antivir scan in archive", param) == 0) {
                set_boolean(&antivir_arch_scan_enable, value);
                DEBUG(3, ("antivir scan in archive is %d\n", 
antivir_arch_scan_enable));
        } else if ( StrCaseCmp("antivir max ratio in archive", param) == 0) {
                antivir_arch_max_ratio = atoi(value);
                DEBUG(3, ("antivir max ratio in archive is %d\n", 
antivir_arch_max_ratio));
        } else if ( StrCaseCmp("antivir max archived file size", param) == 0) {
                antivir_arch_max_size = atoll(value);
                DEBUG(3, ("antivir max archived file size is %lld\n", (long 
long)antivir_arch_max_size));
        } else if ( StrCaseCmp("antivir max recursion level", param) == 0) {
                antivir_arch_max_recursion = atoi(value);
                DEBUG(3, ("antivir max recursion level is %d\n", 
antivir_arch_max_recursion));
        } else if ( StrCaseCmp("antivir detect dialer", param) == 0) {
                set_boolean(&antivir_detect_dialer, value);
                DEBUG(3, ("antivir detect dialer is %d\n", 
antivir_detect_dialer));
        } else if ( StrCaseCmp("antivir detect game", param) == 0) {
                set_boolean(&antivir_detect_game, value);
                DEBUG(3, ("antivir detect game is %d\n", antivir_detect_game));
        } else if ( StrCaseCmp("antivir detect joke", param) == 0) {
                set_boolean(&antivir_detect_joke, value);
                DEBUG(3, ("antivir detect joke is %d\n", antivir_detect_joke));
        } else if ( StrCaseCmp("antivir detect pms", param) == 0) {
                set_boolean(&antivir_detect_pms, value);
                DEBUG(3, ("antivir detect pms is %d\n", antivir_detect_pms));
        } else if ( StrCaseCmp("antivir detect spy", param) == 0) {
                set_boolean(&antivir_detect_spy, value);
                DEBUG(3, ("antivir detect spy is %d\n", antivir_detect_spy));
        } else if ( StrCaseCmp("antivir detect alltypes", param) == 0) {
                set_boolean(&antivir_detect_alltypes, value);
                DEBUG(3, ("antivir detect alltypes is %d\n", 
antivir_detect_alltypes));
        } else
                DEBUG(3, ("unknown parameter: %s\n", param));
                /* return False; ? */

        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;

        /* 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);

        /* name of AntiVir executable file */
        fstrcpy(antivir_program_name, VSCAN_ANTIVIR_PROGRAM_NAME);

        /* AntiVir archive related settings */
        antivir_arch_scan_enable = VSCAN_AVARCH_ENABLED;
        antivir_arch_max_ratio = VSCAN_AVARCH_MAXRATIO;
        antivir_arch_max_size = VSCAN_AVARCH_MAXFILESIZE;
        antivir_arch_max_recursion = VSCAN_AVARCH_MAXRECLEVEL;

        /* AntiVir non virus alerts related settings */
        antivir_detect_dialer = VSCAN_AVDETECT_DIALER;
        antivir_detect_game = VSCAN_AVDETECT_GAME;
        antivir_detect_joke = VSCAN_AVDETECT_JOKE;
        antivir_detect_pms = VSCAN_AVDETECT_PMS;
        antivir_detect_spy = VSCAN_AVDETECT_SPY;
        antivir_detect_alltypes = VSCAN_AVDETECT_ALLTYPES;

        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 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);

        /* tell core we have a(nother) session, ignore return code */
        (void)vscan_antivir_connect();

        #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
{

        /* tell core the (one) session has gone */
        vscan_antivir_disconnect();

        vscan_syslog("INFO: disconnected");

        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;
        int sockfd;
        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
        {
                /* prepare file scan, (re)open connection to the scanner */
                sockfd = vscan_antivir_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 ) {
                        /* we now have a scanner */
                        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 
containing an alert */
                                /* deny access */
                                if ( verbose_file_logging )
                                        vscan_syslog("File '%s' has already 
been scanned and marked as containing an alert. Not scanned any more. Access 
denied", filepath);

                                /* postprocess file scan */
                                vscan_antivir_end(sockfd);

                                /* deny access */
                                errno = EACCES;
                                return -1;
                        } else if ( must_be_checked == 0 )  {
                                /* file has already been checked, not marked as 
containing an alert and not modified */
                                if ( verbose_file_logging )
                                        vscan_syslog("File '%s' has already 
been scanned, not marked as containing an alert and not modified. Not scanned 
anymore. Access granted", filepath);

                                /* postprocess file scan */
                                vscan_antivir_end(sockfd);

                                /* 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_antivir_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_antivir_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);
                                /* to be safe, remove file from lrufiles */
                                lrufiles_delete(filepath);

                                /* deny access */

                                errno = EACCES;
                                return -1;
                        } else if ( retval == 1 ) {
                                /* an alert was found */
                                vscan_antivir_end(sockfd);
                                /* do action ... */

#if (SMB_VFS_INTERFACE_VERSION >= 6)
                                rc = vscan_do_infected_file_action(handle, 
conn, filepath, quarantine_dir, quarantine_prefix, concerning_file_action);
#else
                                rc = 
vscan_do_infected_file_action(&default_vfs_ops, conn, filepath, quarantine_dir, 
quarantine_prefix, concerning_file_action);
#endif

                                /* add/update file. mark file as containing an 
alert! */
                                lrufiles_add(filepath, stat_buf.st_mtime, True);

                                /* alert 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);
                        }
                }

                /* scan done, post process file scan */
                vscan_antivir_end(sockfd);
        }
#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;
        int sockfd;
        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;
        }


        sockfd = vscan_antivir_init();
        if ( sockfd >= 0 ) {
                safe_strcpy(client_ip, fsp->conn->client_address, 
CLIENT_IP_SIZE -1);
                /* scan only file, do nothing */
                rv = vscan_antivir_scanfile(sockfd, filepath, client_ip);
                vscan_antivir_end(sockfd);
                if ( rv == 1 ) {
                        /* alert was found */
#if (SMB_VFS_INTERFACE_VERSION >= 6)
                        rc = vscan_do_infected_file_action(handle, fsp->conn, 
filepath, quarantine_dir, quarantine_prefix, concerning_file_action);
#else
                        rc = vscan_do_infected_file_action(&default_vfs_ops, 
fsp->conn, filepath, quarantine_dir, quarantine_prefix, concerning_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) */



-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8


<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

Recently Viewed:
qnx.openqnx.dev...    politics.lenini...    audio.emagic.ex...    tex.texinfo.gen...    handhelds.linux...    ietf.sipping/20...    lang.erlang.gen...    cygwin.talk/200...    yellowdog.gener...    mozilla.devel.l...    xfree86.newbie/...    openbsd.ports/2...    db.oracle.devel...    kde.kalyxo.deve...    user-groups.lin...    bbc.cvs/2003-04...    gnu.libtool.bug...    redhat.k12osn/2...    emulators.wine....    freebsd.devel.d...    search.xapian.g...    java.izpack.use...    network.mrtg.us...    windows.total-c...   
Home | blog view | USPTO Patent Archive | advertise | OSDir is an inevitable website. super tiny logo

Free Magazines

Cisco News
Receive a free quarterly e-newsletter with exclusive articles on how Cisco IT uses its own products and solutions to enable the business.
subscribe

Systems Management News, the newspaper for IT systems administration and data center managers! Each issue of Systems Management News is chock-full of news and analysis to help you understand what's happening in your field.
subscribe

The Enterprise Newsweekly eWeek is the essential technology information source for builders of e-business.
subscribe

Oracle Magazine Oracle Magazine contains technology strategy articles, sample code, tips, Oracle and partner news, how to articles for developers and DBAs, and more. Oracle (NASDAQ: ORCL) is the world's largest enterprise software company.
subscribe

Total Telecom Total Telecom is "The Economist of the communications industry".
subscribe