[svn:qpsmtpd] rev 448 - in trunk: . plugins/virus
[email protected] 22 Jun 2005 20:06:54 -0000
| Newsgroups | perl.cvs.qpsmtpd |
|---|---|
| Message-ID | <[email protected]> |
Author: jpeacock
Date: Wed Jun 22 13:06:54 2005
New Revision: 448
Added:
trunk/plugins/virus/sophie
Modified:
trunk/ (props changed)
Log:
New AV plugin. Uses SOPHOS Antivirus via Sophie resident daemon.
Added: trunk/plugins/virus/sophie
==============================================================================
--- (empty file)
+++ trunk/plugins/virus/sophie Wed Jun 22 13:06:54 2005
@@ -0,0 +1,199 @@
+#!/usr/bin/perl -w
+use IO::Socket;
+
+sub register {
+ my ( $self, $qp, @args ) = @_;
+ $self->register_hook( "data_post", "sophiescan" );
+
+ %{ $self->{"_sophie"} } = @args;
+
+ # Set some sensible defaults
+ $self->{"_sophie"}->{"sophie_socket"} ||= "/var/run/sophie";
+ $self->{"_sophie"}->{"deny_viruses"} ||= "yes";
+ $self->{"_sophie"}->{"max_size"} ||= 128;
+}
+
+sub sophiescan {
+ my ( $self, $transaction ) = @_;
+ $DB::single = 1;
+
+ if ( $transaction->body_size > $self->{"_sophie"}->{"max_size"} * 1024 ) {
+ $self->log( LOGNOTICE, "Declining due to body_size" );
+ return (DECLINED);
+ }
+
+ # Ignore non-multipart emails
+ my $content_type = $transaction->header->get('Content-Type');
+ $content_type =~ s/\s/ /g if defined $content_type;
+ unless ( $content_type
+ && $content_type =~ m!\bmultipart/.*\bboundary="?([^"]+)!i )
+ {
+ $self->log( LOGWARN, "non-multipart mail - skipping" );
+ return DECLINED;
+ }
+
+ my $filename = $transaction->body_filename;
+ unless ($filename) {
+ $self->log( LOGWARN, "Cannot process due to lack of filename" );
+ return (DECLINED); # unless $filename;
+ }
+
+ my $mode = ( stat( $self->spool_dir() ) )[2];
+ if ( $mode & 07077 ) { # must be sharing spool directory with external app
+ $self->log( LOGWARN,
+ "Changing permissions on file to permit scanner access" );
+ chmod $mode, $filename;
+ }
+
+ my ($SOPHIE, $response);
+ socket(\*SOPHIE, AF_UNIX, SOCK_STREAM, 0)
+ || die "Couldn't create socket ($!)\n";
+
+ connect(\*SOPHIE, pack_sockaddr_un $self->{"_sophie"}->{"sophie_socket"})
+ || die "Couldn't connect() to the socket ($!)\n";
+
+ syswrite(\*SOPHIE, $filename."\n", length($filename)+1);
+ sysread(\*SOPHIE, $response, 256);
+ close (\*SOPHIE);
+
+ my $virus;
+
+ if ( ($virus) = ( $response =~ m/^1:?(.*)?$/ ) ) {
+ $self->log( LOGERROR, "One or more virus(es) found: $virus" );
+
+ if ( lc( $self->{"_sophie"}->{"deny_viruses"} ) eq "yes" ) {
+ return ( DENY,
+ "Virus"
+ . ( $virus =~ /,/ ? "es " : " " )
+ . "Found: $virus" );
+ }
+ else {
+ $transaction->header->add( 'X-Virus-Found', 'Yes' );
+ $transaction->header->add( 'X-Virus-Details', $virus );
+ return (DECLINED);
+ }
+ }
+
+ $transaction->header->add( 'X-Virus-Checked',
+ "Checked by SOPHIE on " . $self->qp->config("me") );
+
+ return (DECLINED);
+}
+
+=head1 NAME
+
+sophie scanner
+
+=head1 DESCRIPTION
+
+A qpsmtpd plugin for virus scanning using the SOPHOS scan daemon, Sophie.
+
+=head1 RESTRICTIONS
+
+The Sophie scan daemon must have at least read access to the qpsmtpd spool
+directory in order to sucessfully scan the messages. You can ensure this
+by running Sophie as the same user as qpsmtpd does (by far the easiest
+method) or by doing the following:
+
+=over 4
+
+=item * Change the group ownership of the spool directory to be a group
+of which the Sophie user is a member or add the Sophie user to the same group
+as the qpsmtpd user.
+
+=item * Change the permissions of the qpsmtpd spool directory to 0750 (this
+will emit a warning when the qpsmtpd service starts up, but can be safely
+ignored).
+
+=item * Make sure that all directories above the spool directory (to the
+root) are g+x so that the group has directory traversal rights; it is not
+necessary for the group to have any read rights except to the spool
+directory itself.
+
+=back
+
+It may be helpful to temporary grant the Sophie user a shell and test to
+make sure you can cd into the spool directory and read files located there.
+Remember to remove the shell from the Sophieav user when you are done
+testing.
+
+Note also that the contents of config/spool_dir must be the full path to the
+spool directory (not a relative path) in order for the scanner to locate the
+file.
+
+=head1 INSTALL AND CONFIG
+
+Place this plugin in the plugin/virus directory beneath the standard
+qpsmtpd installation. If you installed Sophie with the default path, you
+can use this plugin with default options (nothing specified):
+
+=over 4
+
+=item B<Sophie_socket>
+
+Full path to the Sophie socket defaults to /var/run/Sophie.
+
+=item B<deny_viruses>
+
+Whether the scanner will automatically delete messages which have viruses.
+Takes either 'yes' or 'no' (defaults to 'yes'). If set to 'no' it will add
+a header to the message with the virus results.
+
+=item B<max_size>
+
+The maximum size, in kilobytes, of messages to scan; defaults to 128k.
+
+=back
+
+=head1 REQUIREMENTS
+
+This module requires the Sophie daemon, available here:
+
+L<http://www.clanfield.info/sophie/>
+
+which in turn requires the libsavi.so library (available with the Sophos
+Anti-Virus for Linux or Unix).
+
+The following changes to F</etc/sophie.cfg> B<should> be made:
+
+=over 4
+
+=item user: qmaild
+
+Change the "user" parameter to match the qpsmtpd user.
+
+=item group: nofiles
+
+Change the "group" parameter to match the qpsmtpd group.
+
+=item umask: 0001
+
+If you don't change the umask, only the above user/group will be able to scan.
+
+=back
+
+The following changes to F</etc/sophie.savi> B<must> be made:
+
+=over 4
+
+=item Mime: 1
+
+This option will permit the SAVI engine to directly scan e-mail messages.
+
+=back
+
+=head1 AUTHOR
+
+John Peacock <[email protected]>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2005 John Peacock
+
+Based heavily on the clamav plugin
+
+This plugin is licensed under the same terms as the qpsmtpd package itself.
+Please see the LICENSE file included with qpsmtpd for details.
+
+=cut
+