http://wiki.qmailtoaster.org:80/index.php?title=Special:NewPages&feed=atomQmailToaster - New pages [en]2024-03-29T06:33:48ZFrom QmailToasterMediaWiki 1.41.0http://wiki.qmailtoaster.org:80/index.php?title=DAViCalDAViCal2024-03-28T06:09:15Z<p>Ebroch: </p>
<hr />
<div> EL 8/9 <br />
<br />
// Disable selinux, update & reboot<br />
# sed -i-e "s|^SELINUX=.*$|SELINUX=disabled|" /etc/selinux/config<br />
# cat /etc/selinux/config<br />
# setenforce 0<br />
# getenforce<br />
# yum -y update<br><br />
// Install PostgreSQL and dependencies<br />
# yum -y install httpd git php php-pgsql php-gettext postgresql-server perl-DBD-Pg perl-YAML<br><br />
// Install DAViCal calendar and contacts server<br />
# cd /usr/share<br />
# git clone https://gitlab.com/davical-project/davical.git && \<br />
git clone https://gitlab.com/davical-project/awl.git && \<br />
rm -rf ./davical/.git/ && rm -rf ./awl/.git/<br><br />
// PostgreSQL initialization<br />
# /usr/bin/postgresql-setup initdb<br><br />
// PostgreSQL user database configuration<br />
# file=/var/lib/pgsql/data/pg_hba.conf<br />
# mv $file $file.bak<br />
# num=`grep -n "# TYPE DATABASE USER ADDRESS METHOD" $file.bak \<br />
| awk -F: '{print $1}'` && ((num++))<br />
# awk -v n=$num -v s="local davical davical_app trust\nlocal davical davical_dba trust" \<br />
'NR == n {print s} {print}' $file.bak > $file<br />
# cat $file<br><br />
// PostgreSQL service enable and start<br />
# systemctl enable --now postgresql && systemctl status postgresql<br><br />
// Create PostgreSQL DAViCal database (Save password which is output after database creation) <br />
# sudo -u postgres /usr/share/davical/dba/create-database.sh<br><br />
// If this is a migration import database from old server<br />
(On old server)<br />
# pg_dump davical > davical.psql<br />
# scp davical.psql root@'new server ip':/root <br />
(On new server)<br />
# sudo -u postgres dropdb davical<br />
# sudo -u postgres createdb davical<br />
# sudo -u postgres psql davical < /root/davical.psql<br><br />
// Create Apache and DAViCal configuration directories<br />
# mkdir /etc/httpd/sites-available && mkdir /etc/httpd/sites-enabled && mkdir /etc/davical<br><br />
// Create DAViCal virtual host in Apache, enable the site, and start Apache<br />
# tee -a /etc/httpd/sites-available/davical2.whitehorsetc.com.conf <<END<br />
<VirtualHost *:80><br />
DocumentRoot /usr/share/davical/htdocs<br />
DirectoryIndex index.php index.html<br />
ServerName davical2.whitehorsetc.com<br />
ServerAlias davical2.whitehorsetc.com<br />
Alias /images/ /usr/share/davical/htdocs/images/<br />
<Directory /usr/share/davical/htdocs/><br />
AllowOverride None<br />
Require all granted<br />
</Directory><br />
php_value include_path /usr/share/awl/inc<br />
php_value magic_quotes_gpc 0<br />
php_value register_globals 0<br />
php_value error_reporting "E_ALL & ~E_NOTICE"<br />
php_value default_charset "utf-8"<br />
</VirtualHost><br />
END<br><br />
# cat /etc/httpd/sites-available/davical2.whitehorsetc.com.conf<br />
# ln -s /etc/httpd/sites-available/davical2.whitehorsetc.com.conf \<br />
/etc/httpd/sites-enabled/davical2.whitehorsetc.com.conf<br />
# ls -l /etc/httpd/sites-enabled<br />
# cp -p /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.bak<br><br />
# tee -a /etc/httpd/conf/httpd.conf <<END<br />
# Include the virtual host configurations:<br />
IncludeOptional sites-enabled/*.conf<br />
END<br><br />
# cat /etc/httpd/conf/httpd.conf<br />
# systemctl enable --now httpd && systemctl status httpd<br><br />
// Configure DAViCal to connect to database<br />
# tee -a /etc/davical/davical2.whitehorsetc.com-conf.php <<END<br />
<?php<br />
\$c->domain_name = "davical2.whitehorsetc.com";<br />
\$c->sysabbr = 'DAViCal';<br />
\$c->admin_email = 'postmaster@whitehorsetc.com';<br />
\$c->system_name = "Example DAViCal Server";<br />
\$c->pg_connect[] = 'dbname=davical port=5432 user=davical_app';<br />
?><br />
END<br><br />
# cat /etc/davical/davical2.whitehorsetc.com-conf.php<br><br />
Create DNS entry for your DAViCal Calendar & Contact server, <br />
browse to it, and enter users and groups: http://davical2.whitehorsetc.com/<br />
Use 'admin' and password output at database creation (noted above in green font) to log in<br><br />
*Note: 1) Replace 'davical2.whitehorsetc.com' wherever found with your hostname<br />
2) Select items in red (tee to END), paste in terminal, and return<br />
3) DAViCal CalDav Store<br />
4) Https security should be implemented over the internet<br><br />
Text version of this outline...possibly, for a script<br><br />
Clients:<br />
1) Outlook (CalDav plugin necessary. CalDav Synchronizer)<br />
2) Thunderbird (Lightning)<br />
3) One Calendar<br><br />
// List databases (Linux command line)<br />
# sudo -u postgres psql -l<br />
// Database commands from psql<br />
# sudo -u postgres psql<br />
postgres=# help<br />
You are using psql, the command-line interface to PostgreSQL.<br />
Type: \copyright for distribution terms<br />
\h for help with SQL commands<br />
\? for help with psql commands<br />
\g or terminate with semicolon to execute query<br />
\q to quit<br />
// List databases<br />
postgres=# \l<br />
// Access database for manipulation<br />
postgres=# \c 'database'</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=CalendarCalendar2024-03-28T06:07:27Z<p>Ebroch: /* Davical */</p>
<hr />
<div>== [[DAViCal]] ==</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=ActiveSync_(Z-push)ActiveSync (Z-push)2024-03-27T22:09:15Z<p>Ebroch: </p>
<hr />
<div> ActiveSync Z-push install<br />
# dnf config-manager --set-enabled powertools -y<br />
# dnf -y install php-imap php-cli php-soap php-process php-mbstring php-pecl-memcached<br />
# cd /usr/share<br />
# wget https://github.com/Z-Hub/Z-Push/archive/refs/tags/2.7.1.tar.gz<br />
# tar zxvf 2.7.1.tar.gz<br />
# mkdir /usr/share/z-push /var/log/z-push /var/lib/z-push<br />
# chown -R apache: /usr/share/z-push<br />
# chown apache:apache /var/lib/z-push /var/log/z-push<br />
# cp -R Z-Push-2.7.1/* /usr/share/z-push/<br />
# dnf -y install <br />
# perl -pi -e "s/'IMAP_FOLDER_CONFIGURED', false/'IMAP_FOLDER_CONFIGURED', true/g" /usr/share/z-push/src/backend/imap/config.php<br />
# <nowiki>perl -pi -e "s/'TIMEZONE', ''/'TIMEZONE', 'America\/Denver'/g" /usr/share/z-push/src/config.php</nowiki><br />
# <nowiki>perl -pi -e "s/'BACKEND_PROVIDER', ''/'BACKEND_PROVIDER', 'BackendIMAP'/g" /usr/share/z-push/src/config.php</nowiki><br />
# printf '%s\n' \<br />
'#' \<br />
'# Z-push' \<br />
'#' \<br />
'RewriteEngine On' \<br />
'RewriteCond %{HTTPS} off<br />
'RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}' \<br />
'# Z-Push - ActiveSync over-the-air - default Apache configuration' \<br />
' <IfModule mod_alias.c>' \<br />
' Alias /Microsoft-Server-ActiveSync /usr/share/z-push/src/index.php' \<br />
' </IfModule>' \<br />
' <Directory /usr/share/z-push/src>' \<br />
' # Don't list a directory index, follow symlinks (maybe state dir is somewhere linked)' \<br />
' DirectoryIndex index.php' \<br />
' Options -Indexes +FollowSymLinks' \<br />
' AllowOverride none' \<br />
' <IfModule !mod_authz_core.c>' \<br />
' Order allow,deny' \<br />
' allow from all' \<br />
' </IfModule>' \<br />
' <IfModule mod_authz_core.c>' \<br />
' Require all granted' \<br />
' </IfModule>' \<br />
' <Files "config.php">' \<br />
' <IfModule mod_authz_core.c>' \<br />
' Require all denied' \<br />
' </IfModule>' \<br />
' </Files>' \<br />
'</Directory>' \<br />
> /etc/httpd/conf.d/z-push.conf<br><br />
# systemctl restart httpd<br><br />
Configure Outlook email client on tablet or phone (Tested: Samsung Galaxy Tab S2, and Samsung S7 Edge, iPhone X)<br />
On tablet or smart phone open Outlook<br />
Go to 'Add Accout'<br />
Go to 'Add an email account'<br />
Enter email address<br />
Go to 'Manual setup'<br />
Select 'Exchange'<br />
Go to 'Advanced Setup'<br />
Enter email account (client@domain.com) -> Next<br />
Enter mail server -> (mail.domain.com) -> Next<br />
Enter domain\username (client@domain.com) -> Next<br />
Enter password (password) -> Next -> Done<br />
Connect (on mine its a check mark, select it)<br />
Outlook (Exchange) should sync now</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=AfterlogicAfterlogic2024-03-27T21:42:16Z<p>Ebroch: </p>
<hr />
<div> Installation<br />
# mkdir /usr/share/webmaillite<br />
# cd /usr/share/webmaillite<br />
# wget https://afterlogic.org/download/webmail_php.zip<br />
# yum -y install unzip<br />
# unzip webmail_php.zip<br />
# chown -R apache.apache /usr/share/webmaillite/data<br />
# chown -R apache.apache /usr/share/webmaillite/adminpanel<br />
# vi /usr/share/webmaillite/data/settings/config.json <br />
Set 'RedirectToHttps' to true<br />
# vi /usr/share/webmaillite/data/settings/modules/TwoFactorAuth.config.json<br />
Set 'Disable' to false <br />
'ShowRecommendationToConfigure' to true <br />
'AllowSecurityKeys to true<br />
# printf '%s\n' \<br />
'Alias /wmail /usr/share/webmaillite' \<br />
'<Directory /usr/share/webmaillite/>' \<br />
' <IfModule mod_authz_core.c>' \<br />
' # Apache 2.4' \<br />
' Require local' \<br />
' Require all granted' \<br />
' </IfModule>' \<br />
'<IfModule !mod_authz_core.c>' \<br />
' # Apache 2.2' \<br />
' Order Deny,Allow' \<br />
' Require all granted' \<br />
' Allow from all' \<br />
' </IfModule>' \<br />
'</Directory>' \<br />
> /etc/httpd/conf.d/webmaillite.conf<br />
# systemctl restart httpd<br />
# MYSQLPW=<mypassword><br />
# mysqladmin create afterlogic -uroot -p$MYSQLPW<br />
# mysqladmin -uroot -p$MYSQLPW reload<br />
# mysqladmin -uroot -p$MYSQLPW refresh<br />
# mysql -p$MYSQLPW -e "CREATE USER afterlogic@localhost IDENTIFIED BY 'p4ssw3rd'"<br />
# mysql -p$MYSQLPW -e "GRANT ALL PRIVILEGES ON afterlogic.* TO afterlogic@localhost"<br />
# mysqladmin -uroot -p$MYSQLPW reload<br />
# mysqladmin -uroot -p$MYSQLPW refresh<br />
Open browser to http://ip.address.of.server/wmail/adminpanel to login: (username: superadmin, password: <blank>), and change password<br />
Go to 'Database Settings' and enter settings <br />
1) SQL Login: afterlogic<br />
2) SQL Password: SsEeCcRrEeTt<br />
3) Database Name: afterlogic<br />
4) Host: 127.0.0.1<br />
5) Test connection (Button)<br />
6) Create/Update tables (Button)<br />
7) Update Configuration (Button)<br />
8) Save<br />
Go to 'Mail Servers' and enter settings<br />
1) Display Name: <To Suit><br />
2) IMAP Server: 127.0.0.1<br />
3) SMTP Server: 127.0.0.1<br />
4) Leave everything else unchanged<br />
5) Save<br />
Logout<br />
Login with any Mail Server user account<br />
More Information: [https://afterlogic.com/docs/webmail-lite-8/configuring-webmail Here]</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=RainloopRainloop2024-03-27T21:35:15Z<p>Ebroch: </p>
<hr />
<div> Install rainloop<br />
1) # wget https://www.rainloop.net/repository/webmail/rainloop-community-latest.zip<br />
or<br />
# https://www.rainloop.net/repository/webmail/rainloop-latest.zip <br />
2) # unzip rainloop-community-latest.zip -d /usr/share/rainloop<br />
3) # find /usr/share/rainloop -type d -exec chmod 755 {} \;<br />
4) # find /usr/share/rainloop -type f -exec chmod 644 {} \;<br />
5) # chown -R apache:apache /usr/share/rainloop<br />
6) # printf '%s\n' \<br />
'#' \<br />
'# Rainloop Webmail is a browser-based multilingual IMAP client' \<br />
'#' \<br />
'RewriteEngine On' \<br />
'RewriteCond %{HTTPS} off' \<br />
'RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}' \<br />
'Alias /rlmail /usr/share/rainloop' \<br />
'<Directory /usr/share/rainloop/>' \<br />
' Options +Indexes +FollowSymLinks +ExecCGI' \<br />
' AllowOverride All' \<br />
' Require all granted' \<br />
' ErrorLog "/var/log/httpd/rainloop_error_log"' \<br />
' TransferLog "/var/log/httpd/rainloop_access_log"' \<br />
'</Directory>' \<br />
'<Directory /usr/share/rainloop/data/>' \<br />
' Require all denied' \<br />
'</Directory>' \<br />
> /etc/httpd/conf.d/rainloop.conf<br><br />
7) # yum -y install php-xml<br />
8) # systemctl restart httpd<br><br />
Configure (username: admin, password: 12345)<br />
9) https://yourserver/rlmail/?admin/<br />
10) Add your domain, IMAP server, SMTP server, ...Do not use short login<br />
11) Add contact support if needed. Requires DB support.<br><br />
Login to email account<br />
12) https://yourserver/rlmail <br />
13) Additional Tutorial<br />
14) 2-Factor Authentication</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=RoundcubeRoundcube2024-03-27T20:28:08Z<p>Ebroch: </p>
<hr />
<div> EL 8 & 9 should already have roundcubemail installed, otherwise...<br />
# dnf -y install epel-release<br />
# dnf config-manager --set-enabled powertools<br />
# dnf -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm<br />
# dnf -y module reset php<br />
# dnf module install php:remi-8.1<br />
# yum -y install git yum-utils epel-release php-mysql roundcubemail<br />
# mysql --defaults-extra-file=$credfile -e "create database roundcube character set utf8 collate utf8_bin"<br />
# mysql --defaults-extra-file=$credfile -e "CREATE USER roundcube@localhost IDENTIFIED BY 'p4ssw3rd'"<br />
# mysql --defaults-extra-file=$credfile -e "GRANT ALL PRIVILEGES ON roundcube.* TO roundcube@localhost"<br />
# mysql --defaults-extra-file=$credfile roundcube < /usr/share/roundcubemail/SQL/mysql.initial.sql<br />
# cp -p /etc/httpd/conf.d/roundcubemail.conf /etc/httpd/conf.d/roundcubemail.conf.bak<br />
# wget -O /etc/roundcubemail/config.inc.php http://www.qmailtoaster.org/rc.default.config.rhelgt7<br />
# wget -O /etc/httpd/conf.d/roundcubemail.conf http://www.qmailtoaster.org/rc.httpd.config<br />
# sed -i 's/\;date.timezone.*/date.timezone = "America\/Denver"/' /etc/php.ini | sleep 2 | cat /etc/php.ini | grep date.timezone.*=<br />
# systemctl restart httpd<br />
<br />
Access https://my.roundcube.server/email<br />
<br />
Add password support (Everyone should logout of roundcube at this point)<br />
[http://wiki.qmailtoaster.org/index.php?title=Vpopmail_daemon Enable vpopmaild]<br />
# wget -O /usr/share/roundcubemail/plugins/password/config.inc.php http://www.qmailtoaster.org/rc.password.config<br />
# [ "`grep \'password\', /etc/roundcubemail/config.inc.php`" = "" ] && \<br />
perl -ni -le 'BEGIN{ $q=chr(39), $pw="password" } print; print " $q$pw$q," if /$config.*'plugins'.*=.*array/' \<br />
/etc/roundcubemail/config.inc.php<br />
<br />
Add Carddav (Everyone should logout of roundcube at this point)<br />
# cd /usr/share/roundcubemail/plugins<br />
# git clone https://github.com/blind-coder/rcmcarddav carddav<br />
# cd carddav<br />
# curl -sS https://getcomposer.org/installer | php<br />
# php composer.phar install<br />
# [ "`grep \'carddav\', /etc/roundcubemail/config.inc.php`" = "" ] && \<br />
perl -ni -le 'BEGIN{ $q=chr(39), $cd="carddav" } print; print " $q$cd$q," if /$config.*'plugins'.*=.*array/' \<br />
/etc/roundcubemail/config.inc.php<br />
<br />
</pre></div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=WebmailWebmail2024-03-27T20:25:47Z<p>Ebroch: Created page with "== Roundcube == == Rainloop == == Afterlogic =="</p>
<hr />
<div>== [[Roundcube]] ==<br />
== [[Rainloop]] ==<br />
== [[Afterlogic]] ==</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=HordeHorde2024-03-27T20:20:33Z<p>Ebroch: Created page with "The Horde Project is a PHP framework for webmail and related applications. Go to [http://www.horde.org The Horde Project] for more details. The instructions below for Centos 5.x come from a meld of a post from Anil Aliyan on the Qmail-Toaster list and [http://wiki.horde.org/CentOS5InstallationNotes The Horde Wiki]. == '''Setup''' == '''Step 1.''' Install some additional applications and their dependencies to your server. Note, as far as I know all of these applicati..."</p>
<hr />
<div>The Horde Project is a PHP framework for webmail and related applications. Go to [http://www.horde.org The Horde Project] for more details.<br />
<br />
The instructions below for Centos 5.x come from a meld of a post from Anil Aliyan on the Qmail-Toaster list and [http://wiki.horde.org/CentOS5InstallationNotes The Horde Wiki].<br />
<br />
<br />
== '''Setup''' ==<br />
'''Step 1.''' Install some additional applications and their dependencies to your server. Note, as far as I know all of these applications are needed.<br />
<br />
<blockquote><br />
<pre><br />
yum install GeoIP geoip-devel gd ImageMagick ImageMagick-devel ImageMagick-perl php-mbstring php-gettext php-gd php-xml php-mcrypt php-pecl-Fileinfo php-devel php-imap<br />
</pre><br />
</blockquote><br />
<br />
If any of the above mentioned applications cannot be found, you may want to install rpmforge.<br />
<br />
'''Step 2.''' Install applications into the PHP extensions library. This step has 2 parts.<br />
<br />
Run the following command and respond to requests with their defaults (note at the time of this writing, I had issues with the ImageMagick application. I found a solution on [http://pecl.php.net/bugs/bug.php?id=18057 the pecl.php.net web site].<br />
<br />
<blockquote><br />
<pre><br />
pecl install Imagick json LZF geoip<br />
</pre><br />
</blockquote><br />
<br />
After you have successfully ran the command and answered the defaults, pecl will tell you to add some extensions to your php.ini file. Add those lines in your php.ini file under the section "Dynamic Extensions". The four lines are as follows.<br />
<br />
<blockquote><br />
<pre><br />
extension=imagick.so<br />
extension=geoip.so<br />
extension=lzf.so<br />
extension=json.so<br />
</pre><br />
</blockquote><br />
<br />
You will also will want to change the memory limit line in the php.ini file to read 128M. I believe by default it is set to 32M.<br />
<br />
'''Step 3.''' Modify your Apache webserver configuration. In my case, I am installing Horde in the subfolder horde. I create the file /etc/httpd/conf.d/horde.conf with the following content which is from the horde wiki site mentioned at the top.<br />
<br />
<blockquote><br />
<pre><br />
#<br />
# Horde<br />
#<br />
<br />
Alias /horde /var/www/html/horde<br />
<br />
<Directory /var/www/html/horde><br />
# Uncomment the following 3 lines to make Horde locally accessible only<br />
#Order Deny,Allow<br />
#Deny from all<br />
#Allow from 127.0.0.1<br />
<br />
Options +FollowSymLinks<br />
<br />
# horde.org's recommended PHP settings:<br />
php_admin_flag safe_mode off<br />
php_admin_flag magic_quotes_runtime off<br />
php_flag session.use_trans_sid off<br />
php_flag session.auto_start off<br />
php_admin_flag file_uploads on<br />
# Optional - required for weather block in Horde to function<br />
php_admin_flag allow_url_fopen on<br />
<br />
# If horde dies while trying to handle large email file attachments,<br />
# you are probably hitting PHP's memory limit. Raise that limit here,<br />
# but use caution<br />
# Set to your preference - memory_limit should be at least 32M<br />
# and be greater than the value set for post_max_size<br />
#php_value memory_limit 32M<br />
#php_value post_max_size 20M<br />
#php_value upload_max_filesize 10M<br />
<br />
# /usr/share/pear is needed for PEAR. /var/www/html/horde is needed for Horde itself<br />
# TODO: Set an appropriate include_path, too. Might even increase speed a bit.<br />
php_admin_value open_basedir "/var/www/html/horde:/var/www/html/horde/config:/usr/share/pear:/tmp"<br />
php_admin_flag register_globals off<br />
</Directory><br />
<br />
<Directory /var/www/html/horde/config><br />
Order Deny,Allow<br />
Deny from all<br />
</Directory><br />
<br />
# Deny access to files that are not served directly by the webserver<br />
<DirectoryMatch "^/var/www/html/horde/(.*/)?(config|lib|locale|po|scripts|templates)/(.*)?"><br />
Order Deny,Allow<br />
Deny from all<br />
</DirectoryMatch><br />
<br />
# Deny access to the test.php files except from localhost<br />
#<LocationMatch "^/horde/(.*/)?test.php"><br />
# Order Deny,Allow<br />
# Deny from all<br />
# Allow from 127.0.0.1<br />
#</LocationMatch><br />
</pre><br />
</blockquote><br />
<br />
The last section of the file is marked out with pound signs because we want to still test to make sure all of the php modules are installed. You will want to make sure the permission on this file is 0644.<br />
<br />
Go ahead now and restart your web server.<br />
<br />
<blockquote><br />
<pre><br />
service httpd restart<br />
</pre><br />
</blockquote><br />
<br />
You are now ready to install Horde.<br />
<br />
== '''Install''' ==<br />
'''Step 1.''' Download and expand the tarball. Note that I choose the folder name horde and the version at the time of this writing is 1.2.6 so my instructions will reflect that.<br />
<blockquote><br />
<pre><br />
cd /var/www/html<br />
wget ftp://ftp.horde.org/pub/horde-webmail/horde-webmail-latest.tar.gz<br />
tar -xzvf horde-webmail-latest.tar.gz<br />
mv horde-webmail-1.2.6 horde<br />
</pre><br />
</blockquote><br />
<br />
<br />
'''Step 2.''' At this point, we can do some testing if you left out the section regarding the test.php from your apache configuration file. Open your web browser to your mail server and the test.php file (ie http://your-mail-server-name/horde/test.php). You should find that the php modules are all available but postgres and another optional module. If not, you will need to do some research and fix the issues.<br />
<br />
'''Step 3.''' Change the password that horde will use to access your mysql backend. Edit the file '/var/www/html/horde/scripts/sql/create.mysql.sql' and change the password. At the top of the file it clearly states the default password and suggests that you change it. You can change the database name, username and password if you wish; I suggest only changing the password for simplicity.<br />
<br />
'''Step 4.''' Run the setup script. It is a text based menu that is pretty easy to follow.<br />
<blockquote><br />
<pre><br />
cd /var/www/html/horde<br />
php scripts/setup.php<br />
</pre><br />
</blockquote><br />
<br />
a. Choose "Configure database settings", so press 1 and enter.<br><br />
b. We want to use mysql, so type mysql and enter.<br><br />
c. We want persistent connections, so type 1 and enter.<br><br />
d. In our example the username from step 3 is horde, so type horde as the username and enter.<br><br />
e. Type the password that you selected in step 3 for the password and enter.<br><br />
f. We are going to use UNIX sockets to connect, so type unix and enter.<br><br />
g. The default for Centos 5 for the socket is /var/lib/mysql/mysql.sock, so type it and enter.<br><br />
h. In our example the db name from step 3 is horde, so type horde as the db name and enter.<br><br />
i. Press enter to accept the default charset.<br><br />
j. We want to use SSL to connect, so press 1 and enter.<br><br />
k. Leave the Certification Authority blank and enter.<br><br />
l. We are using one server, so type false and enter.<br><br />
m. Now we need to create the database, so choose "Create database or tables" by pressing 2 and enter.<br><br />
n. Have the application create the database, press y and enter. All of the responses should be "OK".<br><br />
o. I did not do anything nor do I know about METAR weather stations, so press n and enter.<br><br />
p. Press 0 to exit the text based installer.<br />
<br />
'''Step 5.''' The installation is complete, we now need to add the user and password from Step 3 to the mysql server. This can be done many ways, below is how I do it (The password is deliminated by <> in this example. Make sure to remove the <> and use the password you decided on in Step 3. Remember that I used the default username and db name both horde)<br />
<br />
<blockquote><br />
<pre><br />
mysql -u root -p <root mysql password><br />
<br />
mysql> grant all on horde.* to horde@localhost;<br />
mysql> set password for horde@localhost = password('<password>');<br />
mysql> exit;<br />
</pre><br />
</blockquote><br />
<br />
'''Step 6.''' You should now be able to use horde by going to your mail server and the horde directory (ie http://your-mail-server-name/horde). We want to secure the installation now so that no one can ruin your installation. This is a two part process.<br />
<br />
First uncomment out the lines at the bottom of the file /etc/httpd/conf.d/horde.conf for the test.php file and restart your web server.<br />
<blockquote><br />
<pre><br />
service httpd restart<br />
</pre><br />
</blockquote><br />
<br />
Second secure the files (This is taken from the horde wiki site link at the top).<br />
<blockquote><br />
<pre><br />
chown apache:root -R /var/www/html/horde/config<br />
chown apache:root -R /var/www/html/horde/*/config<br />
chmod -R go-rwx /var/www/html/horde/config<br />
chmod -R go-rwx /var/www/html/horde/*/config<br />
chown -R root:root /var/www/html/horde/scripts<br />
chown -R root:root /var/www/html/horde/*/scripts<br />
chmod -R go-rwx /var/www/html/horde/scripts<br />
chmod -R go-rwx /var/www/html/horde/*/scripts<br />
chmod a-rwx /var/www/html/horde/test.php<br />
chmod a-rwx /var/www/html/horde/*/test.php<br />
</pre><br />
</blockquote><br />
<br />
Everything should be configured, secure and working on your server. The username, as it is with squirrelmail is the users full email address.</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=NextcloudNextcloud2024-03-27T19:36:47Z<p>Ebroch: </p>
<hr />
<div>[https://www.howtoforge.com/how-to-install-nextcloud-on-rocky-linux Nextcloud Install]<br />
<br />
<pre>Assumes EL8, Apache, MySQL, & PHP installed<br />
Assumes Firewall ports are opened</pre><br />
<pre><br />
<br />
Necessary php packages<br />
dnf -y install epel-release<br />
dnf config-manager --set-enabled powertools<br />
dnf -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm<br />
dnf -y module reset php<br />
dnf module install php:remi-8.1<br />
dnf install php-mbstring php-gd php-pecl-zip php-xml php-json unzip php php-cli php-mysqlnd php-zip php-devel \<br />
php-gd php-mcrypt php-curl php-xml php-pear php-bcmath php-json php-pdo php-pecl-apcu \<br />
php-pecl-apcu-devel php-ldap<br />
<br />
Modify /etc/php.ini<br />
file_uploads = On<br />
allow_url_fopen = On<br />
memory_limit = 512M<br />
upload_max_filesize = 500M<br />
post_max_size = 600M <br />
max_execution_time = 300<br />
display_errors = Off<br />
date.timezone = America/Denver<br />
<br />
Modify /etc/php.d/10-opcache.ini<br />
opcache.enable = 1<br />
opcache.interned_strings_buffer = 8<br />
opcache.max_accelerated_files = 10000<br />
opcache.memory_consumption = 128<br />
opcache.save_comments = 1<br />
opcache.revalidate_freq = 1<br />
<br />
Nextcloud package<br />
wget https://download.nextcloud.com/server/releases/latest.zip<br />
unzip latest.zip -d /var/www/html<br />
mkdir /var/www/html/nextcloud/data<br />
chown -R apache:apache /var/www/html/nextcloud/*<br />
chcon -h system_u:object_r:httpd_sys_content_t /var/www/html/nextcloud/ -R<br />
<br />
Database Setup<br />
MYSQLPW='your password'<br />
credfile=~/sql.cnf<br />
echo -e "[client]\nuser=root\npassword=$MYSQLPW\nhost=localhost" > $credfile<br />
mysql --defaults-extra-file=$credfile -e "CREATE USER nextcloud@localhost IDENTIFIED BY 'p@ssw0rd'"<br />
mysql --defaults-extra-file=$credfile -e "GRANT ALL ON nextcloud.* TO nextcloud@localhost"<br />
mysql --defaults-extra-file=$credfile -e "CREATE DATABASE nextcloud;"<br />
mysql --defaults-extra-file=$credfile -e "FLUSH PRIVILEGES;"<br />
<br />
Restart Apache<br />
systemctl restart httpd<br />
<br />
Admin Configuration (remember mysql username, password, and db)<br />
http://nextcloud.host.tld.or.ip/nextcloud<br />
<br />
After admin is configured<br />
Add users<br />
Add Groupware (Mail, Contacts, Calendar, Desktop, TOTP two-factor authentication)<br />
<br />
Users create there own account<br />
<br />
Secure Nextcloud with SSL<br />
</pre></div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Open-XchangeOpen-Xchange2024-03-27T19:26:33Z<p>Ebroch: </p>
<hr />
<div>[https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Open-Xchange_Installation_Guide_for_RHEL8 AppSuite:Open-Xchange Installation Guide for RHEL8 & Derivatives]<br />
<pre><br />
#!/bin/bash<br />
<br />
# Enter domain, mx(local postfix), imap server, postmaster account password, and ox/mysql administrative password<br />
DOMAIN=domain.tld<br />
MX=localhost.localdomain<br />
IMAP=mx.domain.tld<br />
POSTMASTERPW=postpass<br />
MYSQLPW=mysqlpw<br />
<br />
[ ! $DOMAIN ] && echo "No domain" && exit 1<br />
echo $DOMAIN<br />
[ ! $MX ] && echo "No mx" && exit 1<br />
echo $MX<br />
[ ! $IMAP ] && echo "No mx" && exit 1<br />
echo $IMAP<br />
[ ! $POSTMASTERPW ] && echo "No postmaster password" && exit 1<br />
echo $POSTMASTERPW<br />
[ ! $MYSQLPW ] && echo "No MySQL/OX admin password" && exit 1<br />
echo $MYSQLPW<br />
<br />
echo -e "[client]\nuser=root\npassword=$MYSQLPW\nhost=localhost" > $credfile<br />
<br />
# Disable SELinux<br />
setenforce 0 && sed -i -e 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config && getenforce<br />
<br />
# Open necessary firewall port, and disable selinux<br />
TAB="$(printf '\t')" && GREEN=$(tput setaf 2) && RED=$(tput setaf 1) && NORMAL=$(tput sgr0) && \<br />
systemctl start firewalld && systemctl enable firewalld && \<br />
ports=(80 443 3306) && \<br />
for index in ${!ports[*]}; do echo -n "Opening port: ${ports[$index]} : ";tput setaf 2;firewall-cmd --zone=public --add-port=${ports[$index]}/tcp \<br />
--permanent;tput sgr0; done && firewall-cmd --zone=public --add-port=53/udp --permanent && \<br />
echo -n "Reload firewall settings : " && tput setaf 2 && firewall-cmd --reload && tput sgr0<br />
<br />
dnf -y install mysql-server httpd postfix rsyslog<br />
systemctl enable --now httpd mysqld <br />
postconf maillog_file=/var/log/maillog<br />
systemctl enable --now postfix<br />
mysqladmin -uroot password $MYSQLPW<br />
mysqladmin --defaults-extra-file=$credfile reload<br />
mysqladmin --defaults-extra-file=$credfile refresh<br />
<br />
# Create OX repo<br />
OXREPO=/etc/yum.repos.d/ox.repo<br />
tee -a $OXREPO <<END<br />
[ox-appsuiteui]<br />
name=Open-Xchange-appsuiteui<br />
baseurl=https://software.open-xchange.com/products/appsuite/stable/appsuiteui/RHEL8/<br />
gpgkey=https://software.open-xchange.com/0xDFD4BCF6-oxbuildkey.pub<br />
enabled=1<br />
gpgcheck=1<br />
metadata_expire=0m<br />
<br />
[ox-backend]<br />
name=Open-Xchange-backend<br />
baseurl=https://software.open-xchange.com/products/appsuite/stable/backend/RHEL8/<br />
gpgkey=https://software.open-xchange.com/0xDFD4BCF6-oxbuildkey.pub<br />
enabled=1<br />
gpgcheck=1<br />
metadata_expire=0m<br />
<br />
# if you have a valid maintenance subscription, please uncomment the<br />
# following and add the ldb account data to the url so that the most recent<br />
# packages get installed<br />
<br />
[ox-updates-appsuiteui]<br />
name=Open-Xchange Updates-appsuiteui<br />
baseurl=https://LDBACCOUNT:LDBPASSWORD@software.open-xchange.com/products/appsuite/stable/appsuiteui/updates/RHEL8/<br />
gpgkey=https://software.open-xchange.com/oxbuildkey.pub<br />
enabled=0<br />
gpgcheck=1<br />
metadata_expire=0m<br />
<br />
[ox-updates-backend]<br />
name=Open-Xchange Updates-backend<br />
baseurl=https://LDBACCOUNT:LDBPASSWORD@software.open-xchange.com/products/appsuite/stable/backend/updates/RHEL8/<br />
gpgkey=https://software.open-xchange.com/oxbuildkey.pub<br />
enabled=0<br />
gpgcheck=1<br />
metadata_expire=0m<br />
END<br />
<br />
# Install Open Xchange<br />
dnf install open-xchange \<br />
open-xchange-authentication-database \<br />
open-xchange-grizzly open-xchange-admin \<br />
open-xchange-appsuite open-xchange-appsuite-backend \<br />
open-xchange-appsuite-manifest<br />
<br />
echo PATH=$PATH:/opt/open-xchange/sbin/ >> ~/.bashrc && . ~/.bashrc<br />
mysql --defaults-extra-file=/root/sql.cnf -e "CREATE USER 'openexchange'@'localhost' IDENTIFIED BY '$MYSQLPW'"<br />
mysql --defaults-extra-file=/root/sql.cnf -e "GRANT ALL PRIVILEGES ON *.* TO openexchange@localhost"<br />
<br />
/opt/open-xchange/sbin/initconfigdb --configdb-pass=$MYSQLPW<br />
/opt/open-xchange/sbin/oxinstaller --no-license --servername=oxserver --configdb-pass=$MYSQLPW \<br />
--master-pass=$MYSQLPW --network-listener-host=localhost --servermemory 2048<br />
<br />
systemctl enable --now open-xchange<br />
systemctl status open-xchange<br />
<br />
mkdir /var/opt/filestore<br />
chown open-xchange:open-xchange /var/opt/filestore<br />
/opt/open-xchange/sbin/registerfilestore -A oxadminmaster -P $MYSQLPW -t file:/var/opt/filestore -s 1000000<br />
/opt/open-xchange/sbin/registerdatabase -A oxadminmaster -P $MYSQLPW -n oxdatabase -p $MYSQLPW -m true<br />
<br />
mv /etc/httpd/conf.d/welcome.conf /etc/httpd/conf.d/welcome.conf.bak<br />
<br />
# OX Apache configuration & proxy<br />
OXPROXY=/etc/httpd/conf.d/proxy_http.conf<br />
OXCONF=/etc/httpd/conf.d/ox.conf<br />
tee -a $OXPROXY <<END<br />
LoadModule proxy_http_module modules/mod_proxy_http.so<br />
<br />
<IfModule mod_proxy_http.c><br />
ProxyRequests Off<br />
ProxyStatus On<br />
# When enabled, this option will pass the Host: line from the incoming request to the proxied host.<br />
ProxyPreserveHost On<br />
# Please note that the servlet path to the soap API has changed:<br />
<Location /webservices><br />
# restrict access to the soap provisioning API<br />
Order Deny,Allow<br />
Deny from all<br />
Allow from 127.0.0.1<br />
# you might add more ip addresses / networks here<br />
# Allow from 192.168 10 172.16<br />
</Location><br />
<br />
# The old path is kept for compatibility reasons<br />
<Location /servlet/axis2/services><br />
Order Deny,Allow<br />
Deny from all<br />
Allow from 127.0.0.1<br />
</Location><br />
<br />
# Enable the balancer manager mentioned in<br />
# https://oxpedia.org/wiki/index.php?title=AppSuite:Running_a_cluster#Updating_a_Cluster<br />
<IfModule mod_status.c><br />
<Location /balancer-manager><br />
SetHandler balancer-manager<br />
Order Deny,Allow<br />
Deny from all<br />
Allow from 127.0.0.1<br />
</Location><br />
</IfModule><br />
<br />
<Proxy balancer://oxcluster><br />
Order deny,allow<br />
Allow from all<br />
# multiple server setups need to have the hostname inserted instead localhost<br />
BalancerMember http://localhost:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1<br />
# Enable and maybe add additional hosts running OX here<br />
# BalancerMember http://oxhost2:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 route=APP2<br />
ProxySet stickysession=JSESSIONID|jsessionid scolonpathdelim=On<br />
SetEnv proxy-initial-not-pooled<br />
SetEnv proxy-sendchunked<br />
</Proxy><br />
<br />
# The standalone documentconverter(s) within your setup (if installed)<br />
# Make sure to restrict access to backends only<br />
# See: http://httpd.apache.org/docs/$YOUR_VERSION/mod/mod_authz_host.html#allow for more infos<br />
#<Proxy balancer://oxcluster_docs><br />
# Order Deny,Allow<br />
# Deny from all<br />
# Allow from backend1IP<br />
# BalancerMember http://converter_host:8009 timeout=100 smax=0 ttl=60 retry=60 loadfactor=50 keepalive=On route=APP3<br />
# ProxySet stickysession=JSESSIONID|jsessionid scolonpathdelim=On<br />
# SetEnv proxy-initial-not-pooled<br />
# SetEnv proxy-sendchunked<br />
#</Proxy><br />
# Define another Proxy Container with different timeout for the sync clients. Microsoft recommends a minimum value of 15 minutes.<br />
# Setting the value lower than the one defined as com.openexchange.usm.eas.ping.max_heartbeat in eas.properties will lead to connection<br />
# timeouts for clients. See http://support.microsoft.com/?kbid=905013 for additional information.<br />
#<br />
# NOTE for Apache versions < 2.4:<br />
# When using a single node system or using BalancerMembers that are assigned to other balancers please add a second hostname for that<br />
# BalancerMember's IP so Apache can treat it as additional BalancerMember with a different timeout.<br />
#<br />
# Example from /etc/hosts: 127.0.0.1 localhost localhost_sync<br />
#<br />
# Alternatively select one or more hosts of your cluster to be restricted to handle only eas/usm requests<br />
<Proxy balancer://eas_oxcluster><br />
Order deny,allow<br />
Allow from all<br />
# multiple server setups need to have the hostname inserted instead localhost<br />
BalancerMember http://localhost_sync:8009 timeout=1900 smax=0 ttl=60 retry=60 loadfactor=50 route=APP1<br />
# Enable and maybe add additional hosts running OX here<br />
# BalancerMember http://oxhost2:8009 timeout=1900 smax=0 ttl=60 retry=60 loadfactor=50 route=APP2<br />
ProxySet stickysession=JSESSIONID|jsessionid scolonpathdelim=On<br />
SetEnv proxy-initial-not-pooled<br />
SetEnv proxy-sendchunked<br />
</Proxy><br />
<br />
# When specifying additional mappings via the ProxyPass directive be aware that the first matching rule wins. Overlapping urls of<br />
# mappings have to be ordered from longest URL to shortest URL.<br />
#<br />
# Example:<br />
# ProxyPass /ajax balancer://oxcluster_with_100s_timeout/ajax<br />
# ProxyPass /ajax/test balancer://oxcluster_with_200s_timeout/ajax/test<br />
#<br />
# Requests to /ajax/test would have a timeout of 100s instead of 200s<br />
#<br />
# See:<br />
# - http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypass Ordering ProxyPass Directives<br />
# - http://httpd.apache.org/docs/current/mod/mod_proxy.html#workers Worker Sharing<br />
ProxyPass /ajax balancer://oxcluster/ajax<br />
ProxyPass /appsuite/api balancer://oxcluster/ajax<br />
ProxyPass /drive balancer://oxcluster/drive<br />
ProxyPass /infostore balancer://oxcluster/infostore<br />
ProxyPass /realtime balancer://oxcluster/realtime<br />
ProxyPass /servlet balancer://oxcluster/servlet<br />
ProxyPass /webservices balancer://oxcluster/webservices<br />
<br />
#ProxyPass /documentconverterws balancer://oxcluster_docs/documentconverterws<br />
<br />
ProxyPass /usm-json balancer://eas_oxcluster/usm-json<br />
ProxyPass /Microsoft-Server-ActiveSync balancer://eas_oxcluster/Microsoft-Server-ActiveSync<br />
<br />
</IfModule><br />
END<br />
tee -a $OXCONF <<END<br />
<VirtualHost *:80><br />
ServerAdmin webmaster@localhost<br />
<br />
DocumentRoot /var/www/html/<br />
<Directory /var/www/html/><br />
Options -Indexes +FollowSymLinks +MultiViews<br />
AllowOverride None<br />
Order allow,deny<br />
allow from all<br />
RedirectMatch ^/$ /appsuite/<br />
</Directory><br />
<br />
<Directory /var/www/html/appsuite><br />
Options None +SymLinksIfOwnerMatch<br />
AllowOverride Indexes FileInfo<br />
</Directory><br />
</VirtualHost><br />
END<br />
<br />
systemctl restart httpd<br />
<br />
# Create context<br />
/opt/open-xchange/sbin/createcontext -A oxadminmaster -P $MYSQLPW -c 1 -u oxadmin -d "Cntxt Admin" -g Admin \<br />
-s User -p $MYSQLPW -L defaultcontext -e oxadmin@${DOMAIN} -q 1024 --access-combination-name=groupware_standard<br />
<br />
# Create user with above context<br />
/opt/open-xchange/sbin/createuser -c 1 -A oxadmin -P $MYSQLPW -u postmaster -d "Postmaster ($DOMAIN)" -g $DOMAIN \<br />
-s User -p $POSTMASTERPW -e postmaster@${DOMAIN} --imaplogin postmaster@${DOMAIN} --imapserver $IMAP --smtpserver $MX<br />
</pre></div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=GroupwareGroupware2024-03-27T19:22:22Z<p>Ebroch: /* Open X-change */</p>
<hr />
<div>=== [[Open-Xchange]]===<br />
<br />
=== [[Nextcloud]]===<br />
=== [[Horde]]===</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=IMAP/SMTP_Authentication_testsIMAP/SMTP Authentication tests2024-03-27T19:02:05Z<p>Ebroch: </p>
<hr />
<div><pre><br />
IMAPS, SMTPS, & Submission connection test script <br />
<br />
#!/bin/bash<br />
<br />
read -p "Enter a valid remote email account to which QMT will send mail: " ruser<br />
if [ -z "$ruser" ]<br />
then<br />
echo "No remote user entered, exiting..."<br />
exit 1<br />
fi<br />
<br />
user=postmaster<br />
host=`hostname -I`<br />
<br />
DOMAINS=/home/vpopmail/domains<br />
user=postmaster<br />
DOMAINS=/home/vpopmail/domains<br />
<br />
for domain in `ls $DOMAINS`<br />
do<br />
pass=`/home/vpopmail/bin/vuserinfo $user@$domain | grep "clear passwd: " | sed 's/clear passwd: //'`<br />
done<br />
if [ -z "$domain" ]<br />
then<br />
echo "No domain..."<br />
exit 1<br />
fi<br />
<br />
curl -v --insecure -I imaps://${user}%40${domain}:${pass}@localhost &> ./xxx<br />
yyy=`cat ./xxx | grep "OK Logged in"`<br />
if [[ ! -z $yyy ]]<br />
then<br />
echo -n "IMAPS: $user@$domain --> " && tput setaf 2 && echo "success" && tput sgr0<br />
else<br />
echo -n "IMAPS: $user@$domain --> " && tput setaf 1 && echo "failure" && tput sgr0<br />
fi<br />
<br />
dswak=/usr/local/bin<br />
[ ! -f $dswak/swaks ] && \<br />
wget -P $dswak http://www.jetmore.org/john/code/swaks/latest/swaks &> /dev/null && chown root.root $dswak/swaks && chmod +x $dswak/swaks<br />
swaks --to $ruser --from $user@$domain --server $host --port 587 --ehlo test -tls --auth login \<br />
--auth-user $user@$domain --auth-password $pass &> ./xxx<br />
yyy=`cat xxx | grep "250 ok "`<br />
if [[ ! -z $yyy ]]<br />
then<br />
echo -n "Submission: $user@$doain --> " && tput setaf 2 && echo "success" && tput sgr0<br />
else<br />
echo -n "Submission: $user@$domain --> " && tput setaf 1 && echo "failure" && tput sgr0<br />
fi<br />
rm -f ./xxx<br />
swaks --to $ruser --from $user@$domain --server $host --port 465 --ehlo test -tlsc --auth login \<br />
--auth-user $user@$domain --auth-password $pass &> ./xxx<br />
yyy=`cat xxx | grep "250 ok "`<br />
if [[ ! -z $yyy ]]<br />
then<br />
echo -n "SMTPS: $user@$domain --> " && tput setaf 2 && echo "success" && tput sgr0<br />
else<br />
echo -n "SMTPS: $user@$domain --> " && tput setaf 1 && echo "failure" && tput sgr0<br />
fi<br />
rm -f ./xxx<br />
<br />
<br />
Check passwords<br />
# vpopmailpasswd=`cat filepasswd` <br />
# echo "select pw_passwd from localdomain_tld where pw_name='user'" | \<br />
mysql -u root -p$vpopmailpasswd vpopmail | grep -v pw_passwd | sed 's/\$1\$//' | cut -f1 -d"$" > saltfile<br />
# usersalt=`cat saltfile`<br />
# userpasswd=`cat fileuserpasswd` /* Put your user's password in this file */<br />
# userhash0=`openssl passwd -1 -salt $usersalt $userpasswd`<br />
# userhash1=`echo "select pw_passwd from localdomain_tld where pw_name='user'" | \<br />
mysql -u root -p$vpopmailpasswd vpopmail | grep -v pw_passwd`<br />
# [ "$userhash0" = "$userhash1" ] && echo "Matched passwords" || echo "Unmatched passwords"<br />
<br />
Script to test all IMAP accounts (post migration)<br />
<br />
#!/bin/bash<br />
<br />
# Change fqdn to suit<br />
fqdn=mail.whitehorsetc.com<br />
<br />
for domain in `ls /home/vpopmail/domains`<br />
do<br />
for user in `ls /home/vpopmail/domains/$domain`<br />
do<br />
pass=`/home/vpopmail/bin/vuserinfo $user@$domain | grep "clear passwd: " | sed 's/clear passwd: //'`<br />
[ ! -z $pass ] && curl -v imaps://${user}%40${domain}:${pass}@${fqdn}/ &> tmpcon && \<br />
tmpconok=`cat tmpcon | grep "OK Logged in"` && \<br />
[[ ! -z $tmpconok ]] && (echo "$user@$domain --> success" || echo "$user@$domain --> failed")<br />
done<br />
done<br />
<br />
rm tmpcon<br />
exit 0<br />
</pre></div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Qmail_queueQmail queue2024-03-27T18:58:25Z<p>Ebroch: Created page with "Queue creation # qmailctl stop # mv /var/qmail/queue /var/qmail/queue.bak # queue_repair.py -c --split 23 --no-bigtodo /var/qmail # qmailctl start Queue repair # qmailctl stop # queue_repair.py -r # qmailctl start # qmailctl queue More to come..."</p>
<hr />
<div>Queue creation<br />
# qmailctl stop<br />
# mv /var/qmail/queue /var/qmail/queue.bak<br />
# queue_repair.py -c --split 23 --no-bigtodo /var/qmail<br />
# qmailctl start<br />
Queue repair<br />
# qmailctl stop<br />
# queue_repair.py -r<br />
# qmailctl start<br />
# qmailctl queue<br />
More to come...</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Dspam_w/PostgreSQLDspam w/PostgreSQL2024-03-27T05:01:17Z<p>Ebroch: Created page with "<pre> Assumes Dspam is already installed (1) Install and start postgresql # dnf install postgresql-server postgresql-contrib dspam-pgsql # postgresql-setup --initdb # systemctl enable --now postgresql # systemctl status postgresql (2) Edit postgres files: # /var/lib/pgsql/data/postgresql.conf listen_addresses = '0.0.0.0' # IPv4 listen_addresses = '*' # IPv4/6 port = 5432 # /var/lib/pgsql/data/pg_hba.conf # IPv4 local connections: #hos..."</p>
<hr />
<div><pre><br />
Assumes Dspam is already installed<br />
<br />
(1) Install and start postgresql<br />
# dnf install postgresql-server postgresql-contrib dspam-pgsql<br />
# postgresql-setup --initdb<br />
# systemctl enable --now postgresql<br />
# systemctl status postgresql<br />
<br />
<br />
(2) Edit postgres files:<br />
# /var/lib/pgsql/data/postgresql.conf<br />
listen_addresses = '0.0.0.0' # IPv4<br />
listen_addresses = '*' # IPv4/6<br />
port = 5432 <br />
# /var/lib/pgsql/data/pg_hba.conf<br />
# IPv4 local connections:<br />
#host all all 127.0.0.1/32 ident<br />
host all all 127.0.0.1/32 md5<br />
<br />
(3) PostgreSQL User/DB creation:<br />
# adduser dspampg<br />
# passwd dspampg (p4ssw3rd)<br />
# su - postgres<br />
$ createdb dspam<br />
$ psql -d dspam -f /usr/share/dspam/sql-scripts/pgsql/pgsql_objects.sql<br />
$ psql -d dspam -f /usr/share/dspam/sql-scripts/pgsql/virtual_users.sql<br />
$ psql dspam<br />
dspam=#<br />
dspam=# \d<br />
List of relations<br />
Schema | Name | Type | Owner<br />
--------+------------------------+----------+----------<br />
public | dspam_preferences | table | postgres<br />
public | dspam_signature_data | table | postgres<br />
public | dspam_stats | table | postgres<br />
public | dspam_token_data | table | postgres<br />
public | dspam_virtual_uids | table | postgres<br />
public | dspam_virtual_uids_seq | sequence | postgres<br />
(6 rows)<br />
<br />
dspam=# \q<br />
$<br />
$ psql template1<br />
template1=# CREATE USER dspampg WITH PASSWORD 'p4ssw3rd';<br />
template1=# GRANT ALL PRIVILEGES ON DATABASE dspam TO dspampg;<br />
template1=# \q<br />
$ psql -c "ALTER USER dspampg WITH SUPERUSER" (May not need to do the next 3 commands)<br />
$ psql -d dspam -c "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public to dspampg"<br />
$ psql -d dspam -c "GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public to dspampg"<br />
$ psql -d dspam -c "GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public to dspampg"<br />
$ exit<br />
# systemctl restart postgresql<br />
<br />
<br />
<br />
(4) Dspam configuration:<br />
# vi /etc/dspam.conf (comment mysql, uncomment pgsql)<br />
(1)<br />
#StorageDriver /usr/lib64/dspam/libmysql_drv.so<br />
StorageDriver /usr/lib64/dspam/libpgsql_drv.so<br />
<br />
(2)<br />
#<br />
# Storage driver settings: Specific to a particular storage driver. Uncomment<br />
# the configuration specific to your installation, if applicable.<br />
#<br />
#MySQLServer /var/lib/mysql/mysql.sock<br />
#MySQLPort<br />
#MySQLUser dspam<br />
#MySQLPass p4ssw3rd<br />
#MySQLDb dspam<br />
#MySQLCompress true<br />
#MySQLReconnect true<br />
<br />
<br />
# --- PostgreSQL ---<br />
<br />
# For PgSQLServer you can Use a TCP/IP address or a socket. If your socket is<br />
# in /var/run/postgresql/.s.PGSQL.5432 specify just the path where the socket<br />
# resits (without .s.PGSQL.5432).<br />
<br />
PgSQLServer 127.0.0.1<br />
PgSQLPort 5432<br />
PgSQLUser dspampg<br />
PgSQLPass p4ssw3rd<br />
PgSQLDb dspam<br />
<br />
(5) Restart dspam<br />
# systemctl restart dspam<br />
# systemctl status dspam<br />
<br />
<br />
(6) Test connection with dspam paramters to PostreSQL<br />
# psql -h 127.0.0.1 -U dspampg -d dspam --port=5432 --password<br />
password: <br />
psql (13.13)<br />
Type "help" for help.<br />
<br />
dspam=><br />
dspam=>\q<br />
<success><br />
</pre></div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Alias_DomainsAlias Domains2024-03-27T04:56:13Z<p>Ebroch: Created page with " Create alias domain Qmail & Dovecot 1) Create alias domain table and insert alias domain a) # mysql -u root -p vpopmail b) MariaDB [vpopmail]> create table aliasdomains ( domain char(96) not null, alias char(96) not null); c) MariaDB [vpopmail]> insert into aliasdomains (domain,alias) values ('domain.com','domain.org'); 2) Change dovecot mysql password query password_query = SELECT CONCAT( pw_name ,'@', pw_domain ) AS user, \ pw_passwd AS password, \..."</p>
<hr />
<div> Create alias domain Qmail & Dovecot<br />
1) Create alias domain table and insert alias domain<br />
a) # mysql -u root -p vpopmail<br />
b) MariaDB [vpopmail]> create table aliasdomains ( domain char(96) not null, alias char(96) not null);<br />
c) MariaDB [vpopmail]> insert into aliasdomains (domain,alias) values ('domain.com','domain.org');<br />
2) Change dovecot mysql password query<br />
password_query = SELECT CONCAT( pw_name ,'@', pw_domain ) AS user, \<br />
pw_passwd AS password, \<br />
pw_dir as userdb_home, \<br />
89 AS userdb_uid, \<br />
89 AS userdb_gid \<br />
FROM vpopmail vp \<br />
LEFT JOIN aliasdomains ad ON ad.alias = '%d' \<br />
WHERE ( vp.pw_domain = ad.domain OR vp.pw_domain = '%d') AND ( vp.pw_name = '%n' )<br />
3) Test Dovecot:<br />
doveadm auth test user@domain.com 'password'<br />
doveadm auth test user@domain.org 'password'<br />
4) Create domain alias for Qmail ( /var/qmail/users/assign )<br />
a) # /home/vpopmail/bin/vaddaliasdomain domain.com domain.org <br />
# cat /var/qmail/users/assign<br />
+domainA.com-:domainA.com:89:89:/home/vpopmail/domains/domainA.com:-::<br />
+domain.com-:domain.com:89:89:/home/vpopmail/domains/domain.com:-::<br />
+domain.org-:whitehorsetc.com:89:89:/home/vpopmail/domains/domain.com:-:: (addition)</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Shutting_down_Qmail_manuallyShutting down Qmail manually2024-03-27T04:51:25Z<p>Ebroch: Created page with "<pre> If for whatever reason qmail is started twice or already started shut it down manually... # qmailctl stop # ps aux | grep svscan | grep -v grep root 6398 0.0 0.0 4416 912 pts/0 S 13:32 0:00 svscan # kill 6398 # ps aux | grep supervise | grep -v grep root 6400 0.0 0.0 4248 916 pts/0 S 13:32 0:00 supervise send root 6401 0.0 0.0 4248 880 pts/0 S 13:32 0:00 supervise log root 6402..."</p>
<hr />
<div><pre><br />
If for whatever reason qmail is started twice or already started shut it down manually...<br />
<br />
# qmailctl stop<br />
# ps aux | grep svscan | grep -v grep<br />
root 6398 0.0 0.0 4416 912 pts/0 S 13:32 0:00 svscan<br />
# kill 6398<br />
# ps aux | grep supervise | grep -v grep<br />
root 6400 0.0 0.0 4248 916 pts/0 S 13:32 0:00 supervise send<br />
root 6401 0.0 0.0 4248 880 pts/0 S 13:32 0:00 supervise log<br />
root 6402 0.0 0.0 4248 828 pts/0 S 13:32 0:00 supervise smtp<br />
root 6403 0.0 0.0 4248 916 pts/0 S 13:32 0:00 supervise log<br />
root 6404 0.0 0.0 4248 916 pts/0 S 13:32 0:00 supervise smtps<br />
root 6405 0.0 0.0 4248 824 pts/0 S 13:32 0:00 supervise log<br />
root 6406 0.0 0.0 4248 928 pts/0 S 13:32 0:00 supervise submission<br />
root 6407 0.0 0.0 4248 824 pts/0 S 13:32 0:00 supervise log<br />
# kill 6400 6401 6402 6403 6404 6405 6406 6407<br />
# ps aux | grep tcpserver | grep -v grep <br />
vpopmail 6411 0.0 0.0 6540 1576 pts/0 S 13:32 0:00 /usr/bin/tcpserver -v -R -H -l host.domain.tld -x ... /var/qmail/bin/qmail-smtpd ...<br />
vpopmail 6413 0.0 0.0 4416 860 pts/0 S 13:32 0:00 /usr/bin/tcpserver -v -R -H -l host.domain.tld -x ... /var/qmail/bin/qmail-smtpd ...<br />
vpopmail 6415 0.0 0.0 4416 960 pts/0 S 13:32 0:00 /usr/bin/tcpserver -v -R -H -l host.domain.tld -x ... /var/qmail/bin/qmail-smtpd ...<br />
# kill 6411 6413 6415<br />
# ps aux | grep qmail-send | grep -v grep<br />
qmails 6408 0.0 0.0 8664 976 pts/0 S 13:32 0:00 qmail-send<br />
# kill 6408<br />
</pre></div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Control_Files_ListControl Files List2024-03-27T04:16:03Z<p>Ebroch: </p>
<hr />
<div><pre><br />
Qmail Control Files<br />
Qmail is controlled by a large set of control files stored in /var/qmail/control. Unlike some other MTAs that group everything into one huge <br />
file that they have to parse to figure out what's what, qmail puts each different kind of information into a separate file, so that each <br />
file needs little or no parsing. All files are lines of plain text (although a few files are compiled into CDB databases before use). <br />
Some, noted below, allow comment lines with a # at the beginning of the line. In files where each line contains multiple fields, the <br />
fields are separated by colons.<br />
<br />
Most of the control files are optional, and qmail uses a reasonable default in most cases if a file isn't present. The only files that are <br />
absolutely essential are me, which contains the hostname of the local host, and rcpthosts, which lists the names of the domains for which <br />
this host accepts mail.<br />
<br />
<br />
List of Default Qmail Control Files<br />
Here's a list of all the control files in alphabetical order, noting which component uses each one. Many of the optional patches introduce<br />
new control files, which are discussed during the description of the patch.<br />
</pre><br />
<br />
badmailfrom (qmail-smtpd)<br />
Envelope addresses not allowed to send mail. If the envelope From address on an incoming message matches an entry in badmailfrom, <br />
the SMTP daemon will reject every recipient address. Entries may be either email addresses, or @dom.ain to reject every address in <br />
a domain. This is a primitive form of spam filtering. These days, it's mostly useful to block quickly a mailbomb or flood of rejection <br />
messages.<br />
<br />
bouncefrom (qmail-send)<br />
Default: MAILER-DAEMON. The mailbox of the return address to put in bounce messages. I've never found any reason to change it.<br />
<br />
bouncehost (qmail-send)<br />
Default: me. The domain of the return address to put in bounce messages. I've never found any need to change it, although it's possible <br />
that if your mail host is mail.example.com, you might want to have the bounces come from example.com.<br />
<br />
concurrencylocal (qmail-send)<br />
Default: 10. The maximum number of simultaneous local deliveries. Unless you have very slow delivery programs, the default is adequate <br />
for all but very large systems. Keep in mind that if you have slow delivery programs, it is quite possible to have all 10 or however many <br />
running as the same user, so be sure that the per-user process limit is high enough to permit them all to run.<br />
<br />
concurrencyremote (qmail-send)<br />
Default: 20. The maximum number of simultaneous remote deliveries. The default is adequate for small systems, but too low for large <br />
systems or systems that host mailing lists. You should adjust it so that qmail uses as much of your outgoing bandwidth as you want it <br />
to. In the distributed version of qmail, you can increase this up to 120, which is enough for a moderately busy system with mailing lists <br />
sharing a T1 with other services. See Chapter 16 for advice on increasing it past 120 on large systems.<br />
<br />
defaultdomain (qmail-inject)<br />
Default: the literal string defaultdomain. The domain to add to unqualified host names (names with no dot) on outgoing mail. That is, if <br />
someone injects a message with a sender or recipient address of fred@bad and this file contains example.com, the address is rewritten as <br />
fred@bad.example.com. You invariably want to set this to the local domain. Note that only mail injected via qmail-inject has its header <br />
addresses rewritten. Addresses in mail that arrives via SMTP or is injected directly via qmail-queue aren't modified.<br />
<br />
defaulthost (qmail-inject)<br />
Default: me. Similar to defaultdomain; the domain to add to addresses in outgoing mail that have no domain at all. If defaulthost doesn't <br />
contain a dot, defaultdomain is added, too. Set this to the name of the local domain.<br />
<br />
databytes (qmail-smtpd)<br />
Default: 0, meaning no limit. The maximum message size to accept via SMTP. I usually set it to about 1/10 the size of the typical amount <br />
of free space on the partition where the qmail queue resides, to keep a single bloated incoming message from causing qmail to run out of <br />
disk space. The DATABYTES environment variable overrides the control file, so if there are certain systems from which you want to accept <br />
huge messages, you can put entries into the SMTP rules file to permit that. For example:<br><br />
# allow 50 megabyte powerpoints from the boss<br />
209.58.173.10:allow,DATABYTES="50000000"<br />
# allow 20 meg outgoing mail from nearby hosts<br />
172.16.15.1-127.:allow,RELAYCLIENT="",DATABYTES="20000000"<br />
<br />
doublebouncehost (qmail-send)<br />
Default: me. The domain to which to send double-bounce messages. There's rarely any reason to change it.<br />
<br />
doublebounceto (qmail-send)<br />
Default: postmaster. The mailbox to which to send double-bounce messages, that is, they go to doublebounceto@doublebouncehost. You can also<br />
send these messages to a special mailbox that you examine rarely, or because these days there are vast numbers of double bounces caused by <br />
spam with fake return addresses, you can set it to nobody or some other address that just throws them away.<br />
<br />
envnoathost (qmail-send)<br />
Default: me. The domain to add to envelope recipient addresses with no domain. This value is used by qmail-send, while defaultdomain is <br />
used by qmail-inject, so in practice this value is used to fix up mail received by SMTP. The default value is fine, unless you receive a lot <br />
of spam with bare addresses, in which case you can set it to something like invalid to make incoming mail with no domain bounce.<br />
<br />
helohost (qmail-remote)<br />
Default: me. The domain to use in the HELO command of outgoing SMTP sessions. The default is fine.<br />
<br />
idhost (qmail-inject)<br />
Default: me. The domain to use when creating Message-ID: lines in outgoing mail. The default is fine. If you want to do something special <br />
with message ID's, you can provide them yourself on mail you send, in which case qmail won't alter them.<br />
<br />
localiphost (qmail-smtpd)<br />
Default: me. When qmail-smtpd sees incoming mail to an address using a dotted quad rather than a domain name, like fred@[10.11.12.99], and <br />
the IP address is one on this host, it substitutes in localiphost. The default is usually fine unless you want to change it to the local mail <br />
domain.<br />
<br />
locals (qmail-send)<br />
Default: me. Domains to treat as local. Any addresses in domains listed in this file are considered to be local and are routed using the <br />
local delivery rules. All local domains are equivalent; if foo.org and bar.com both appear in locals, the addresses fred@foo.org and <br />
fred@bar.com are handled identically.[†] This file always includes the name of the local host (the same as what's in me) and generally <br />
includes the local domain as well and any other domains that may have been used for the same set of addresses. For example, the locals file <br />
on my mail server tom.iecc.com also includes iecc.com (the current local domain), iecc.cambridge.ma.us (its old name), and iecc.us <br />
(a trendy vanity equivalent.)<br><br />
Note that local domains are not the same as virtual domains, nor are they the same as the SMTP recipient domains listed in rcpthosts.<br />
<br />
me (qmail-send)<br />
Default: none; this file is required. The name of the current host. This should be the same as what the hostname command returns.<br />
<br />
morercpthosts (qmail-smtpd and qmail-newmrh)<br />
Default: none. More domains for which this host accepts SMTP mail. The contents of this file are compiled into morercpthosts.cdb by <br />
qmail-newmrh. The SMTP daemon consults the cdb file after it checks rcpthosts. If a host accepts mail for more than about 50 domains, <br />
Dan suggests that you put the 50 busiest into rcpthosts and the rest into morercpthosts.<br />
<br />
percenthack (qmail-send)<br />
Default: none. The "percent hack" is a primitive form of source routing introduced by sendmail in the early 1980s. If you send mail to <br />
user%in.side@out.side, the mail would be sent to out.side, where the address would be rewritten to user@in.side and sent along to in.side. <br />
In the past 20 years, most of the connectivity problems that require source routing have been solved, and for the ones that remain there <br />
are better tools such as smtproutes (described later), so the percent hack is obsolete. If for some reason you absolutely need it <br />
(you have an ancient mission-critical program for which all the source code has been lost that sends mail using the percent hack, perhaps) <br />
any addresses in domains listed in percenthack are scanned for percent signs and rewritten. In the previous example, out.side would have to <br />
be listed there.<br><br />
If a domain listed in percenthack is also listed in rcpthosts, your system is an open relay, because spammers can send mail anywhere through <br />
your system by putting the actual target address in percent form inside an address in the listed domain. Yes, spammers actually do so. <br />
The solution is simple: don't do it.<br />
<br />
plusdomain (qmail-inject)<br />
Default: me. If the domain part of an address in an injected message ends with a plus sign, the contents of plusdomain are appended to the <br />
end. In environments with many subdomains of a single main domain, say east.bigcorp.com, west.bigcorp.com, and south.bigcorp.com, this lets<br />
people abbreviate addresses to fred@south+. No longer widely used.<br />
<br />
qmqpservers (qmail-qmqpc)<br />
Default: none. A list of servers to which messages can be queued using QMQP. See Chapter 17.<br />
<br />
queuelifetime (qmail-send)<br />
Default: 604800 seconds (a week). How long to keep trying to deliver a message. More precisely, if qmail tries to send a message and the <br />
attempt fails with a temporary error, the error is treated as permanent if the message is older than queuelifetime, in which case the message <br />
bounces.<br><br />
The default time of a week is reasonable, but you might want to decrease it to three or four days if you'd rather know sooner that a message <br />
isn't getting through, at the risk that the destination host might have come back to life if you'd waited longer.<br />
<br />
rcpthosts (qmail-smtpd)<br />
Default: every domain. The list of domains for which this host accepts SMTP mail. It is extremely important that this file exist. If it <br />
doesn't, qmail will accept mail destined for anywhere and will be an "open relay," and a magnet for spammers.<br /><br />
If you receive mail for more than 50 domains, see morercpthosts.<br />
<br />
smtpgreeting (qmail-smtpd)<br />
Default: me. When another hosts connects via SMTP to send you mail, the greeting string to send. The default is fine.<br />
<br />
smtproutes (qmail-remote)<br />
Default: none. Explicit routes to use to deliver outgoing mail, overriding MX data. Each line is of one of these forms:<br />
<br />
domain:relay<br />
domain:relay:port<br />
Domain is the domain in the destination email address, relay is the name of the host to which to deliver the mail, and the optional <br />
port is the port number if not the standard port 25.<br><br />
The domain can use wildcards; if it starts with a dot, it matches any target domain that ends with that domain. If the domain is empty, <br />
it matches all addresses, providing "smarthost" routing to send all mail to a single smarthost for delivery. If relay is empty, qmail uses <br />
the standard MX lookup, letting you override a broader wildcard or smarthost route.<br><br />
Most systems can get by without smtproutes, but there are three situations where it can come in handy. The first is a smarthost, mentioned<br />
previously, if your computer is on a dialup, DSL, or cable modem, and the smarthost is your ISP's outgoing mail server. The second is to <br />
temporarily patch around broken MX records or mail relays. The third is to route mail for private domains within your network.<br />
<br />
timeoutconnect (qmail-remote)<br />
Default: 60 seconds. How long to wait for a remote server to accept the initial connection to send mail. Unless you need to exchange mail <br />
with extremely slow and overloaded remote servers, don't change it.<br />
<br />
timeoutremote (qmail-remote)<br />
Default: 1200 seconds. Once a remote server is connected, how long to wait for each response before giving up. The default of 20 minutes <br />
is extremely conservative, and can lead to all of your remote sending slots being tied up while waiting for somnolent remote hosts to <br />
time out. Unless you communicate with extraordinarily slow and overloaded remote servers, you can drop it to a minute.<br />
<br />
timeoutsmtpd (qmail-smtpd)<br />
Default: 1200 seconds. How long qmail-smtpd waits for each response from a remote client before timing out and giving up. As with <br />
timeoutremote, you can decrease this to a minute unless you have some really slow remote clients.<br />
<br />
virtualdomains (qmail-send)<br />
Default: none. The list of virtual users and domains for which this system receives mail. If you don't handle any virtual domains, you don't <br />
need this file.<br /><br />
The virtual domain scheme works by taking the mailbox in the virtual domain, prepending a string and a hyphen to create a local address, and <br />
redeliver-ing the mail to the local address. The virtual domain file lists the prepend string to use for each virtual user and domain. <br />
(See Chapter 12.) Each line is of one of these forms:<br /><br />
user@dom.ain:string (1)<br />
dom.ain:string (2)<br />
.domain:string (3)<br />
domain: (4)<br />
:string (5)<br />
Form (1) controls mail to a specific address. Forms (2) and (3) control mail to any address in a domain or in subdomains of a domain, <br />
respectively. Form (4), with an empty prepend, is used to create an exception to a domain that would otherwise be handled by a line of <br />
form (3) or (5) and means to handle the domain normally, not as a virtual domain. Form (5) is a catchall and controls all domains not <br />
listed in locals or elsewhere in virtualdomains.<br /><br />
If a domain erroneously appears both in locals and virtualdomains, the listing in locals takes precedence. Don't do that.<br />
<br />
Check your Current settiings<br />
You will want to run the qmail-showctl<br />
<br />
/var/qmail/bin/qmail-showctl</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=PHP_upgrade_7.x_to_8.1PHP upgrade 7.x to 8.12024-03-27T04:05:53Z<p>Ebroch: </p>
<hr />
<div> [[7.x_to_8.x|Steps 1) thru 3)]] <br />
4) Requires Squirrelmail upgrade<br />
5) # dnf update squirrelmail<br />
or manually<br />
5) # cp /etc/httpd/conf.d/squirrelmail.conf /etc/httpd/conf.d/squirrelmail.conf.bak<br />
6) # dnf remove squirrelmail<br />
7) # wget http://snapshots.squirrelmail.org/squirrelmail-20230327_0200-SVN.stable.tar.gz<br />
8) # tar zxvf squirrelmail-20230327_0200-SVN.stable.tar.gz<br />
9) # cp -Rp squirrelmail.stable/squirrelmail /usr/share<br />
10) # cp /etc/httpd/conf.d/squirrelmail.conf.bak /etc/httpd/conf.d/squirrelmail.conf<br />
11) # /usr/share/squirrelmail/config/configure<br />
12) Option 3 Folder Defaults<br />
13) Set Folder Defaults (below)<br />
1. Default Folder Prefix<br />
2. Show Folder Prefix Option : false<br />
3. Trash Folder : Trash<br />
4. Sent Folder : Sent<br />
5. Drafts Folder : Drafts<br />
6. By default, move to trash : true<br />
7. By default, save sent messages : true<br />
8. By default, save as draft : true<br />
9. List Special Folders First : true<br />
10. Show Special Folders Color : true<br />
11. Auto Expunge : true<br />
12. Default Sub. of INBOX : false<br />
13. Show 'Contain Sub.' Option : true<br />
14. Default Unseen Notify : 2<br />
15. Default Unseen Type : 1<br />
16. Auto Create Special Folders : true<br />
17. Folder Delete Bypasses Trash : false<br />
18. Enable /NoSelect folder fix : false<br />
14) Save data<br />
15) Quit config<br />
16) # mkdir /var/local/squirrelmail/data /var/local/squirrelmail/attach<br />
17) # chown -R apache:apache /var/local/squirrelmail<br />
18) # chown -R apache:apache /usr/share/squirrelmail<br />
16) Open browser and navigate to Squirrelmail</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Securing_SquirrelMailSecuring SquirrelMail2024-03-27T04:05:19Z<p>Ebroch: </p>
<hr />
<div>== [[ Configure ]] ==<br />
== [[ PHP upgrade 7.x to 8.1 ]] ==</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=7.x_to_8.x7.x to 8.x2024-03-27T04:02:44Z<p>Ebroch: </p>
<hr />
<div>Tested EL8 Derivatives<br><br />
1) # dnf module reset php<br />
2) # dnf module install php:remi-8.1<br />
3) # dnf update<br><br />
[[PHP_upgrade_7.x_to_8.1|Squirrelmail]] update necessary</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=PHPPHP2024-03-27T03:59:13Z<p>Ebroch: Created page with "== 7.x to 8.x =="</p>
<hr />
<div>== [[ 7.x to 8.x ]] ==</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Vpopmail_daemonVpopmail daemon2024-03-27T01:10:52Z<p>Ebroch: </p>
<hr />
<div><pre><br />
# cd /var/qmail/supervise && qmailctl stop <br />
# install -d -m1751 vpopmaild && chmod 1700 vpopmaild && chown qmaill:qmail vpopmaild && install -d -m751 vpopmaild/log && chmod 0700 vpopmaild/log<br />
# printf '%s\n' \<br />
'#!/bin/sh' \<br />
'QMAILDUID=`id -u vpopmail`' \<br />
'NOFILESGID=`id -g vpopmail`' \<br />
'VPOPD=/home/vpopmail/bin/vpopmaild' \<br />
'' \<br />
'exec 2>&1' 'exec /usr/bin/tcpserver -vRHD -u "$QMAILDUID" -g "$NOFILESGID" 127.0.0.1 89 $VPOPD' \<br />
>./vpopmaild/run<br />
<br />
# printf '%s\n' \<br />
'#!/bin/sh' \<br />
'LOGSIZE=`cat /var/qmail/control/logsize`' \<br />
'LOGCOUNT=`cat /var/qmail/control/logcount`' \<br />
'exec /usr/bin/setuidgid qmaill \' \<br />
' /usr/bin/multilog t s$LOGSIZE n$LOGCOUNT \' \<br />
' /var/log/qmail/vpopmaild 2>&1' \<br />
> ./vpopmaild/log/run<br />
<br />
# chown -R qmaill:qmail vpopmaild && chmod 0751 ./vpopmaild/run && chmod 0751 ./vpopmaild/log/run<br />
# qmailctl start && firewall-cmd --zone=public --add-port=89/tcp --permanent && firewall-cmd --reload<br />
# yum -y install telnet<br />
# telnet 127.0.0.1 89<br />
Trying 127.0.0.1...<br />
Connected to 127.0.0.1.<br />
Escape character is '^]'.<br />
+OK<br />
quit<br />
+OK<br />
Connection closed by foreign host.<br />
</pre></div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=VpopmailVpopmail2024-03-27T01:09:03Z<p>Ebroch: Created page with "== Vpopmail daemon =="</p>
<hr />
<div>== [[Vpopmail daemon]] ==</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=LDALDA2024-03-26T23:28:47Z<p>Ebroch: </p>
<hr />
<div> # yum -y install dovecot-pigeonhole<br />
Add to /etc/dovecot/dovecot.conf<br />
mail_location = maildir:~/Maildir<br />
protocols = $protocols imap pop3 sieve<br />
plugin {<br />
sieve = ~/.dovecot.sieve<br />
sieve_dir = ~/.sieve<br />
}<br />
service managesieve-login {<br />
inet_listener sieve {<br />
port = 4190<br />
}<br />
}<br />
protocol lda {<br />
mail_plugins = $mail_plugins sieve<br />
.<br />
.<br />
.<br />
}<br />
# cd /home/vpopmail/domains/domain.tld/user<br />
# mkdir .sieve<br />
# touch .sieve/user.sieve<br />
# ln -s .sieve/user.sieve .dovecot.sieve<br />
# chown -R vpopmail:vchkpw .sieve<br />
# chown vpopmail:vchkpw .dovecot.sieve<br />
# chmod 700 .sieve<br />
Add Sieve rules to .sieve/user.sieve<br />
Enable Dovecot LDA formatted logging<br />
Add to /etc/dovecot/dovecot.conf<br />
protocol lda {<br />
deliver_log_format = From:<%f>-<%e> :: Subject:<%s> :: Status:<%$> :: MsgID:<%m> :: Size<%p> :: vSize<%w><br />
log_path = /var/log/dovecot-lda/dovecot-lda-errors.log<br />
info_log_path = /var/log/dovecot-lda/dovecot-lda.log<br />
}<br />
# mkdir /var/log/dovecot-lda<br />
# chmod 770 /var/log/dovecot-lda<br />
# chown vpopmail:vchkpw /var/log/dovecot-lda<br />
# touch /etc/logrotate.d/dovecot-lda<br />
Enable Dovecot LDA for QMT<br />
# Edit /home/vpopmail/domains/yourdomain.tld/.qmail-default<br />
Remove '|/home/vpopmail/bin/vdelivermail '' bounce-no-mailbox'<br />
Add '|/var/qmail/bin/preline -f /usr/libexec/dovecot/deliver -d $EXT@$USER -o postmaster_address=postmaster@yourdomain.tld'<br />
# systemctl restart dovecot</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=DovecotDovecot2024-03-26T23:28:15Z<p>Ebroch: </p>
<hr />
<div>== [[LDA]] ==</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=EzMLM_CommandsEzMLM Commands2024-03-26T22:13:29Z<p>Ebroch: Created page with " 1. Create a mailing list A. Create domain 1) # /home/vpopmail/bin/vadddomain mydomain.com 'password' B. Create ezmlm mailling list w/features ezmlm flags Flags: -5 List owner Flags: -Afpqut (No archive, Subject prefix, Public, Service requests, List members only, Trailer) 1) # ezmlm-make -5 postmaster@mydomain.com -Afpqut \ /home/vpopmail/domains/mydomain.com/mydomain-list \ /home/vpopma..."</p>
<hr />
<div> 1. Create a mailing list<br />
A. Create domain<br />
1) # /home/vpopmail/bin/vadddomain mydomain.com 'password'<br />
B. Create ezmlm mailling list w/features ezmlm flags<br />
Flags: -5 List owner<br />
Flags: -Afpqut (No archive, Subject prefix, Public, Service requests, List members only, Trailer)<br />
1) # ezmlm-make -5 postmaster@mydomain.com -Afpqut \<br />
/home/vpopmail/domains/mydomain.com/mydomain-list \<br />
/home/vpopmail/domains/mydomain.com/.qmail-mydomain-list \<br />
mydomain-list mydomain.com<br />
2) # chown -R vpopmail:vchkpw /home/vpopmail/domains/mydomain.com/mydomain-list<br />
3) # echo "Reply-To: <#l#>@<#h#>" >> /home/vpopmail/domains/mydomain.com/mydomain-list/headeradd<br />
2. Remove a mailing list<br />
A. # rm -rf /home/vpopmail/domains/mydomain.com/mydomain-list \<br />
/home/vpopmail/domains/mydomain.com/.qmail-mydomain-list*<br />
3. Change mailing list features<br />
A. Remove subject prefix<br />
1) # ezmlm-make -+ -F /home/vpopmail/domains/mydomain.com/mydomain-list \<br />
/home/vpopmail/domains/mydomain.com/.qmail-mydomain-list \<br />
mydomain-list mydomain.com<br />
B. Add subject prefix<br />
1) # ezmlm-make -+ -f /home/vpopmail/domains/mydomain.com/mydomain-list \<br />
/home/vpopmail/domains/mydomain.com/.qmail-mydomain-list \<br />
mydomain-list mydomain.com<br />
C. More to come...<br />
4. Allow mailing list to be archived publically<br />
A. For 'www.mail-archive.com' add 'archive@mail-archive.com' to your lists' subscribers<br />
1) Remove X-No-Archive flag<br />
a) # vi /home/vpopmail/domains/mydomain.com/mydomain-list/headeradd<br />
1) Remove line: X-No-Archive: yes<br />
2) Access www.mail-archive.com mailing list<br />
a) Open browser and browse to https://www.mail-archive.com/mydomain-list@mydomain.com/<br />
B. More to come...</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Fail2banFail2ban2024-03-26T21:55:54Z<p>Ebroch: </p>
<hr />
<div> Install fail2ban<br />
# yum install fail2ban -y<br><br />
Create the filter definition files in filter.d<br />
# cat >/etc/fail2ban/filter.d/qmail-smtp-authnotavail.conf << EOL<br />
[Definition]<br />
#Looks for failed auth outside TLS to SMTP<br />
failregex = 503 auth not available \(\#5\.3\.3\) - <HOST><br />
ignoreregex =<br />
EOL<br><br />
# cat >/etc/fail2ban/filter.d/qmail-smtps-auth.conf<< EOL<br />
[Definition]<br />
#Looks for failed password logins to SMTP<br />
failregex = vchkpw-smtps: password fail ([^)]*) [^@]*@[^:]*:<HOST><br />
ignoreregex =<br />
EOL<br><br />
# cat >/etc/fail2ban/filter.d/qmail-smtps-passfail.conf<< EOL<br />
[Definition]<br />
#Looks for failed password logins to SMTP<br />
failregex = vchkpw-smtps: password fail ([^)]*) [^@]*@[^:]*:<HOST><br />
ignoreregex =<br />
EOL<br><br />
# cat >/etc/fail2ban/filter.d/qmail-smtps-usernotfound.conf<< EOL<br />
[Definition]<br />
failregex = vchkpw-smtps: vpopmail user not found .*:<HOST><br />
ignoreregex =<br />
EOL<br><br />
# cat >/etc/fail2ban/filter.d/qmail-submission-passfail.conf<< EOL<br />
[Definition]<br />
failregex = vchkpw-submission: password fail ([^)]*) [^@]*@[^:]*:<HOST><br />
ignoreregex =<br />
EOL<br><br />
# cat >/etc/fail2ban/filter.d/qmail-submission-usernotfound.conf<< EOL<br />
[Definition]<br />
failregex = vchkpw-submission: vpopmail user not found .*:<HOST><br />
ignoreregex =<br />
EOL<br><br />
Create jail.local<br />
# cat >>/etc/fail2ban/jail.d/jail.local << EOL<br />
[qmail-submission-passfail]<br />
enabled = true<br />
filter = qmail-submission-passfail<br />
action = iptables[name=QMAIL-SUBMISSION, port=587, protocol=tcp]<br />
logpath = /var/log/maillog<br />
maxretry = 3<br />
bantime = 86400<br />
findtime = 3600<br />
backend = auto<br><br />
[qmail-submission-usernotfound]<br />
enabled = true<br />
filter = qmail-submission-usernotfound<br />
action = iptables[name=QMAIL-SUBMISSION, port=587, protocol=tcp]<br />
logpath = /var/log/maillog<br />
maxretry = 3<br />
bantime = 86400<br />
findtime = 3600<br />
backend = auto<br><br />
[qmail-smtps-passfail]<br />
enabled = true<br />
filter = qmail-smtps-passfail<br />
action = iptables[name=QMAIL-SMTPS, port=465, protocol=tcp]<br />
logpath = /var/log/maillog<br />
maxretry = 3<br />
bantime = 86400<br />
findtime = 3600<br />
backend = auto<br><br />
[qmail-smtps-usernotfound]<br />
enabled = true<br />
filter = qmail-smtps-usernotfound<br />
action = iptables[name=QMAIL-SMTPS, port=465, protocol=tcp]<br />
logpath = /var/log/maillog<br />
maxretry = 3<br />
bantime = 86400<br />
findtime = 3600<br />
backend = auto<br><br />
[qmail-smtp-authnotavail]<br />
enabled = true<br />
filter = qmail-smtp-authnotavail<br />
action = iptables[name=QMAIL-SMTP, port=25, protocol=tcp]<br />
logpath = /var/log/qmail/smtptx/current<br />
maxretry = 3<br />
bantime = 86400<br />
findtime = 300<br />
backend = auto<br><br />
EOL<br />
<br />
Set up Authorization not available<br />
In order to log SMTP transactions do the following:<br />
1) # qmailctl stop<br />
2) Add 'SMTP_DEBUG="1"' to /etc/tcprules.d/tcp.smtp <br />
3) Replace contents of '/var/qmail/supervise/smtp/log/run' script with below to log transactions to different file: <br />
#!/bin/sh<br />
LOGSIZE=`cat /var/qmail/control/logsize`<br />
LOGCOUNT=`cat /var/qmail/control/logcount`<br />
exec /usr/bin/setuidgid qmaill \<br />
/usr/bin/multilog t s$LOGSIZE n$LOGCOUNT \<br />
'-*' '+@* server:[*' '+@* client:[*' /var/log/qmail/smtptx \<br />
'+*' '-@* server:[*' '-@* client:[*' /var/log/qmail/smtp 2>&1<br />
4) # qmailctl start && qmailctl cdb<br />
5) # tail -f /var/log/qmail/smtptx/current | tai64nlocal<br />
<br />
Start fail2ban<br />
# systemctl start fail2ban<br />
<br />
Script to check blocking<br />
# cat >./f2bstat << EOL<br />
#!/bin/bash<br />
for FILTER in qmail-submission-passfail \<br />
qmail-submission-usernotfound \<br />
qmail-smtps-passfail \<br />
qmail-smtps-usernotfound \<br />
qmail-smtp-authnotavail<br />
do<br />
fail2ban-client status $FILTER<br />
echo ""<br />
done<br />
EOL<br />
<br />
Set permissions & run script (w/output sample)<br />
# chmod 755 ./f2bstat && ./f2bstat<br />
<br />
qmail-submission-passfail:<br><br />
Status for the jail: qmail-submission-passfail<br />
|- Filter<br />
| |- Currently failed: 1<br />
| |- Total failed: 1<br />
| `- File list: /var/log/maillog<br />
`- Actions<br />
|- Currently banned: 0<br />
|- Total banned: 0<br />
`- Banned IP list:<br />
<br />
qmail-submission-usernotfound:<br><br />
Status for the jail: qmail-submission-usernotfound<br />
|- Filter<br />
| |- Currently failed: 7<br />
| |- Total failed: 7<br />
| `- File list: /var/log/maillog<br />
`- Actions<br />
|- Currently banned: 0<br />
|- Total banned: 0<br />
`- Banned IP list:<br />
<br />
qmail-smtps-passfail:<br><br />
Status for the jail: qmail-smtps-passfail<br />
|- Filter<br />
| |- Currently failed: 0<br />
| |- Total failed: 0<br />
| `- File list: /var/log/maillog<br />
`- Actions<br />
|- Currently banned: 0<br />
|- Total banned: 0<br />
`- Banned IP list:<br />
<br />
qmail-smtps-usernotfound:<br><br />
Status for the jail: qmail-smtps-usernotfound<br />
|- Filter<br />
| |- Currently failed: 0<br />
| |- Total failed: 0<br />
| `- File list: /var/log/maillog<br />
`- Actions<br />
|- Currently banned: 2<br />
|- Total banned: 2<br />
`- Banned IP list: 5.34.207.174 212.70.149.72<br />
<br />
qmail-smtp-authnotavail:<br><br />
Status for the jail: qmail-smtp-authnotavail<br />
|- Filter<br />
| |- Currently failed: 0<br />
| |- Total failed: 0<br />
| `- File list: /var/log/qmail/smtptx/current<br />
`- Actions<br />
|- Currently banned: 0<br />
|- Total banned: 0<br />
`- Banned IP list:</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Spam_ThrottleSpam Throttle2024-03-26T21:52:12Z<p>Ebroch: </p>
<hr />
<div> [[https://www.mail-archive.com/toaster@shupp.org/msg02791.html Spam Throttle]]:<br />
[[https://www.tnpi.net/internet/mail/toaster/filtering/patches.shtml More]];<br><br />
If you are interested in implementing spam throttle, read the following man pages:<br><br />
man qmail-spamthrottle<br />
man qmail-spamt<br />
mail qmail-newst<br />
<br />
If you just want some reasonable defaults, do this:<br><br />
echo "::1501:120000::1000::::" > /var/qmail/control/spamt<br />
echo "." >> /var/qmail/control/spamt<br />
/var/qmail/bin/qmail-newst</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=AmavisAmavis2024-03-26T21:29:41Z<p>Ebroch: </p>
<hr />
<div> For testing until production stability proven.<br />
<br />
Get Amavis Qmail queue<br />
# wget -O /var/qmail/bin/qmail-queue.smtp https://github.com/qmtoaster/amavis/blob/main/qmail-queue.smtp.cos8?raw=true<br />
# chown qmailq:qmail /var/qmail/bin/qmail-queue.smtp<br />
# chmod 4711 /var/qmail/bin/qmail-queue.smtp<br />
<br />
Build Your Own qmail-queue.smtp<br />
wget https://raw.githubusercontent.com/qmtoaster/amavis/main/qmail-amavisd-0.94.patch<br />
wget https://raw.githubusercontent.com/qmtoaster/amavis/main/qmail-amavisd-0.94.tgz<br />
tar zxvf qmail-amavisd-0.94.tgz<br />
cd qmail-amavisd-0.94<br />
patch < ../qmail-amavisd-0.94.patch<br />
make<br />
cp qmail-queue.smtp /var/qmail/bin<br />
chown qmailq:qmail /var/qmail/bin/qmail-queue.smtp<br />
chmod 4711 /var/qmail/bin/qmail-queue.smtp<br />
<br />
Install Amavis & edit config, run clamd under Amavis, start both services<br />
# yum --enablerepo=epel,PowerTools -y install amavisd-new lz4 perl-Digest-SHA1 perl-IO-stringy<br />
# yum --enablerepo=fedora cabextract<br />
# wget https://www.rarlab.com/rar/rarlinux-x64-6.0.b1.tar.gz<br />
# tar zxvf rarlinux-x64-6.0.b1.tar.gz<br />
# cd rar<br />
# cp rar unrar /usr/local/bin<br />
# sed -i 's/%i.conf/amavisd.conf/' /usr/lib/systemd/system/clamd@.service<br />
# systemctl daemon-reload<br />
# systemctl restart clamd@scan<br />
# vi /etc/amavisd/amavisd.conf<br />
$mydomain = 'domain.tld';<br />
$myhostname = 'mx.domain.tld';<br />
$notify_method = 'smtp:[127.0.0.1]:10025';<br />
$forward_method = 'smtp:[127.0.0.1]:10025';<br />
# systemctl enable --now amavisd<br />
<br />
Create tcp rules for qmail smtp & qmail amavis<br />
# mv /etc/tcprules.d/tcp.smtp /etc/tcprules.d/tcp.smtp.bak<br />
<br />
tee /etc/tcprules.d/tcp.amavis.smtp > /dev/null <<EOT<br />
127.:allow,RELAYCLIENT="",RBLSMTPD="",NOP0FCHECK="1"<br />
:allow,CHKUSER_RCPTLIMIT="50",CHKUSER_WRONGRCPTLIMIT="10",QMAILQUEUE="/var/qmail/bin/qmail-queue.smtp",NOP0FCHECK="1"<br />
EOT<br />
<br />
tee /etc/tcprules.d/tcp.smtp > /dev/null <<EOT<br />
127.:allow,RELAYCLIENT="",RBLSMTPD="",NOP0FCHECK="1"<br />
:allow,CHKUSER_RCPTLIMIT="50",CHKUSER_WRONGRCPTLIMIT="10",QMAILQUEUE="/var/qmail/bin/qmail-queue",NOP0FCHECK="1"<br />
EOT<br />
<br />
Edit/Create run files for qmail smtp & qmail amavis<br />
# cp -Rp /var/qmail/supervise/smtp /var/qmail/supervise/smtp2<br />
<br />
tee /var/qmail/supervise/smtp/run > /dev/null <<EOT<br />
#!/bin/sh<br />
QMAILDUID=`id -u vpopmail`<br />
NOFILESGID=`id -g vpopmail`<br />
MAXSMTPD=`cat /var/qmail/control/concurrencyincoming`<br />
SMTPD="/var/qmail/bin/qmail-smtpd"<br />
TCP_CDB="/etc/tcprules.d/tcp.amavis.smtp.cdb"<br />
HOSTNAME=`hostname`<br />
VCHKPW="/home/vpopmail/bin/vchkpw"<br />
export SMTPAUTH="-"<br><br />
exec /usr/bin/softlimit -m 64000000 \<br />
/usr/bin/tcpserver -v -R -H -l $HOSTNAME -x $TCP_CDB -c "$MAXSMTPD" \<br />
-u "$QMAILDUID" -g "$NOFILESGID" 0 smtp \<br />
$SMTPD $VCHKPW /bin/true 2>&1<br><br />
EOT<br />
<br />
tee /var/qmail/supervise/smtp2/run > /dev/null <<EOT<br />
#!/bin/sh<br />
QMAILDUID=`id -u vpopmail`<br />
NOFILESGID=`id -g vpopmail`<br />
MAXSMTPD=`cat /var/qmail/control/concurrencyincoming`<br />
SMTPD="/var/qmail/bin/qmail-smtpd"<br />
TCP_CDB="/etc/tcprules.d/tcp.smtp.cdb"<br />
HOSTNAME=`hostname`<br />
VCHKPW="/home/vpopmail/bin/vchkpw"<br />
export SMTPAUTH="-"<br />
export FORCETLS=0<br><br />
exec /usr/bin/softlimit -m 64000000 \<br />
/usr/bin/tcpserver -v -R -H -l $HOSTNAME -x $TCP_CDB -c "$MAXSMTPD" \<br />
-u "$QMAILDUID" -g "$NOFILESGID" 0 10025 \<br />
$SMTPD $VCHKPW /bin/true 2>&1<br><br />
EOT<br />
<br />
tee /var/qmail/supervise/smtp2/log/run > /dev/null <<EOT<br />
#!/bin/sh<br />
LOGSIZE=`cat /var/qmail/control/logsize`<br />
LOGCOUNT=`cat /var/qmail/control/logcount`<br />
exec /usr/bin/setuidgid qmaill \<br />
/usr/bin/multilog t s$LOGSIZE n$LOGCOUNT \<br />
/var/log/qmail/smtp2 2>&1<br><br />
EOT<br />
<br />
Add Amavis Dspam support<br />
<br />
Install Dspam (skip 'install per domain')<br />
# wget https://raw.githubusercontent.com/qmtoaster/dspam/master/dspamdb.sh<br />
# chmod 755 dspamdb.sh<br />
# ./dpsamdb.sh<br />
<br />
Add Under $dspam = 'dspam'<br />
# vi /etc/amavisd/amavisd.conf<br />
<br />
@spam_scanners = (<br />
['DSPAM', 'Amavis::SpamControl::ExtProg', 'dspam',<br />
[ qw(--user amavis --deliver=stdout) ],<br />
],<br />
);<br />
<br />
Add under 'Trust vpopmail'<br />
# vi /etc/dspam.conf<br />
Trust amavis<br />
<br />
Start & stat qmail<br />
# qmailctl start<br />
# qmailctl stat<br><br />
send: up (pid 253068) 97100 seconds<br />
smtp: up (pid 253065) 97100 seconds<br />
smtp2: up (pid 253071) 97100 seconds<br />
smtps: up (pid 253067) 97100 seconds<br />
submission: up (pid 253073) 97100 seconds<br />
send/log: up (pid 253064) 97100 seconds<br />
smtp2/log: up (pid 253070) 97100 seconds<br />
smtp/log: up (pid 253066) 97100 seconds<br />
smtps/log: up (pid 253072) 97100 seconds<br />
submission/log: up (pid 253069) 97100 seconds<br />
<br />
Test with Swaks<br />
# swaks --to myuser@domain.tld,myuser2@domain.tld --from myuser@remotedomain.tld --server mx.domain.tld -tls<br />
=== Trying 192.168.16.75:25...<br />
=== Connected to 192.168.16.75.<br />
<- 220 localhost - Welcome to Qmail Toaster Ver. 1.03-3.3.1.qt.md.el8 SMTP Server ESMTP<br />
-> EHLO mx.domain.tld<br />
<- 250-localhost - Welcome to Qmail Toaster Ver. 1.03-3.3.1.qt.md.el8 SMTP Server<br />
<- 250-STARTTLS<br />
<- 250-PIPELINING<br />
<- 250-8BITMIME<br />
<- 250 SIZE 20971520<br />
-> STARTTLS<br />
<- 220 ready for tls<br />
=== TLS started with cipher TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256<br />
=== TLS no local certificate set<br />
=== TLS peer DN="/O=Qmail Toaster Server/OU=Test Certificate/CN=localhost"<br />
~> EHLO mx.domain.tld<br />
<~ 250-localhost - Welcome to Qmail Toaster Ver. 1.03-3.3.1.qt.md.el8 SMTP Server<br />
<~ 250-PIPELINING<br />
<~ 250-8BITMIME<br />
<~ 250 SIZE 20971520<br />
~> MAIL FROM:<myuser@remotedomain.tld><br />
<~ 250 ok<br />
~> RCPT TO:<myuser@domain.tld><br />
<~ 250 ok<br />
~> RCPT TO:<myuser2@domain.tld><br />
<~ 250 ok<br />
~> DATA<br />
<~ 354 go ahead<br />
~> Date: Sun, 29 Nov 2020 14:58:40 -0700<br />
~> To: myuser@domain.tld,myuser2@domain.tld<br />
~> From: myuser@remotedomain.tld<br />
~> Subject: test Sun, 29 Nov 2020 14:58:40 -0700<br />
~> Message-Id: <20201129145840.009255@mx.domain.tld><br />
~> X-Mailer: swaks v20170101.0 jetmore.org/john/code/swaks/<br />
~><br />
~> This is a test mailing<br />
~><br />
~> .<br />
<~ 250 ok 1606687121 qp 308705<br />
~> QUIT<br />
<~ 221 localhost - Welcome to Qmail Toaster Ver. 1.03-3.3.1.qt.md.el8 SMTP Server<br />
=== Connection closed with remote host.<br />
<br />
All Amavis output is in the maillog (/var/log/maillog).<br />
<br />
Email headers will contain<br />
X-Virus-Scanned: amavisd-new at domain.tld<br />
<br />
Email headers will show Amavis routing<br />
Return-Path: <br />
Delivered-To: myemail@domain.tld<br />
Received: (qmail 266650 invoked by uid 89); 29 Nov 2020 00:43:58 -0000<br />
Received: from unknown (HELO localhost) (127.0.0.1)<br />
by localhost.localdomain with SMTP; 29 Nov 2020 00:43:58 -0000<br />
X-DSPAM-Processed: Sat Nov 28 17:43:58 2020<br />
X-DSPAM-Confidence: 0.9899<br />
X-DSPAM-Probability: 0.0000<br />
X-Virus-Scanned: amavisd-new at domain.tld<br />
X-DSPAM-Result: Whitelisted<br />
X-DSPAM-Signature: 1,5fc2eece2666485921812939<br />
Received: from unknown ([127.0.0.1])<br />
by localhost (mx.domain.tld [127.0.0.1]) (amavisd-new, port 10024)<br />
with SMTP id kma806hO5pyA; Sat, 28 Nov 2020 17:43:57 -0700 (MST)<br />
Received: from unknown (HELO mx.remotedomain.tld) (xxx.xxx.xxx.xxx)<br />
by localhost.localdomain with ESMTPS (ECDHE-RSA-AES256-GCM-SHA384 encrypted); 29 Nov 2020 00:43:57 -0000<br />
Received-SPF: none (localhost.localdomain: domain at remotedomain.tld does not designate permitted sender hosts)<br />
<br />
<br />
<br />
Other spam scanners operable with Amavis<br />
<br />
@spam_scanners = (<br />
['CRM114', 'Amavis::SpamControl::ExtProg', 'crm',<br />
[ qw(-u /var/amavis/home/.crm114 mailreaver.crm<br />
--dontstore --report_only --stats_only<br />
--good_threshold=8 --spam_threshold=-8) ],<br />
mail_body_size_limit => 64000, score_factor => -0.20,<br />
],<br />
);<br />
<br />
Other AV scanners operable with Amavis<br />
ESET NODE32<br />
Avast<br />
Trend Micro<br />
Kaspersky<br />
Sophos<br />
F-Secure<br />
...<br />
<br />
Questions, comments, suggestions, corrections...contact Eric on the QMT list</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=SimscanSimscan2024-03-26T20:30:06Z<p>Ebroch: /* Control */</p>
<hr />
<div>== Scanning ==<br />
<br />
In /etc/tcprules.d/tcp.smtp set environment variable QMAILQUEUE to simscan binary <br />
...,QMAILQUEUE="/var/qmail/bin/simscan",...<br />
Rebuild tcp.smtp<br />
# qmailctl cdb<br />
<br />
== Control ==<br />
<br />
Simscan's control file is /var/qmail/control/simcontrol<br />
It's format looks like thus:<br><br />
:clam=yes,spam=yes,spam_hits=9.5,spam_passthru=yes,attach=.vbs:.lnk:.scr:.wsh:.hta:.pif<br />
This tells simscan for all domains to scan with ClamAV, Spamassassin, filter attachments, queueing all mail after filtering<br><br />
Consider the following format:<br><br />
domain.tld:dspam=yes,rspam=yes,clam=yes,spam=yes,spam_passthru=yes,...<br />
This tells simscan for domain.tld to scan with Dspam, Rspam, ClamAV, Spamassassin,...<br><br />
Upon edit of simcontrol the file must be put into proper format for use, run<br />
# qmailctl cdb<br />
<br />
== Ramdisk ==<br />
<br />
Use htop or other program to determine available memory for ramdisk (size=)<br />
# clamgid=$(test -z "$(cat /etc/passwd | grep ^clamav)" && id -g clamscan 2>/dev/null || id -g clamav 2>/dev/null) && echo $clamgid<br />
# qmailctl stop<br />
# mount -t tmpfs -o size=1024m,nodev,noexec,noatime,uid=$clamgid,gid=0,mode=0750 myramdisk /var/qmail/simscan<br />
# ls -ld /var/qmail/simscan<br />
drwxr-x--- 2 clamscan root 6 Aug 17 13:28 /var/qmail/simscan<br />
# qmailctl start<br />
# df -h /var/qmail/simscan<br />
Filesystem Size Used Avail Use% Mounted on<br />
myramdisk 1.0G 0 1.0G 0% /var/qmail/simscan<br />
# cp /etc/fstab /etc/fstab.bak<br />
# echo "myramdisk /var/qmail/simscan tmpfs size=1024m,nodev,noexec,noatime,uid=$clamgid,gid=0,mode=0750 0 0" >> /etc/fstab<br />
Make sure /etc/fstab file is okay before a reboot<br />
# cat /etc/fstab<br />
<br />
== Filtering ==<br />
<br />
FEDORAREPO=<br />
Install Dspam, Rspam, SA userprefs<br />
<br />
# Begin Fedora Install CentOS 8 ***** ONLY *****<br />
rel=`grep "release 8" /etc/*-release`<br />
if [[ ! -z $rel ]]<br />
then<br />
rel=8<br />
FEDORAREPO=--enablerepo=fedora<br />
sites=( https://d2lzkl7pfhq30w.cloudfront.net/pub/archive/fedora/linux/releases/28/Everything/x86_64/os/ <br />
http://mirror.math.princeton.edu/pub/fedora-archive/fedora/linux/releases/28/Everything/x86_64/os/ <br />
http://pubmirror1.math.uh.edu/fedora-buffet/archive/fedora/linux/releases/28/Everything/x86_64/os/ <br />
https://pubmirror2.math.uh.edu/fedora-buffet/archive/fedora/linux/releases/28/Everything/x86_64/os/ <br />
http://mirrors.kernel.org/fedora-buffet/archive/fedora/linux/releases/28/Everything/x86_64/os/ <br />
https://dl.fedoraproject.org/pub/archive/fedora/linux/releases/28/Everything/x86_64/os/ )<br />
printf '%s\n%s\n%s\n%s\n%s\n%s\n' '[fedora]' 'name=Fedora 28' 'mirrorlist=file:///etc/yum.repos.d/fedoramirrors' \<br />
'enabled=0' 'gpgcheck=0' 'priority=100' > /etc/yum.repos.d/fedora28.repo<br />
printf '%s\n%s\n%s\n%s\n%s\n%s\n' "${sites[0]}" "${sites[1]}" "${sites[2]}" "{$sites[3]}" "${sites[4]}" "${sites[5]}" \<br />
> /etc/yum.repos.d/fedoramirrors<br />
else<br />
rel=7<br />
fi<br />
# End Fedora Install CentOS 8 ***** ONLY *****<br />
<br />
# Begin DSpam DB Install, Skip if already installed<br />
wget https://raw.githubusercontent.com/qmtoaster/dspam/master/dspamdb.sql<br />
if [ "$?" != "0" ]; then<br />
echo "Error downloading dspam db: ($?), exiting..."<br />
exit 1<br />
fi<br />
MYSQLPW=<br />
# Get DB password for administrator and check validity.<br />
if [ -z "$MYSQLPW" ]; then<br />
read -s -p "Enter MySQL/MariaDB admin password to create dspam database: " MYSQLPW<br />
fi<br />
credfile=~/sql.cnf<br />
echo -e "[client]\nuser=root\npassword='$MYSQLPW'\nhost=localhost" > $credfile<br />
mysqladmin --defaults-extra-file=$credfile status > /dev/null 2>&1<br />
if [ "$?" != "0" ]; then<br />
echo "Bad MySQL/MariaDB administrator password or MySQL/MariaDB is not running. Exiting..."<br />
exit 1<br />
fi<br />
echo ""<br />
echo "Dropping Dspam database if it exists already..."<br />
mysql --defaults-extra-file=$credfile -e "use dspam" &> /dev/null<br />
[ "$?" = "0" ] && mysqldump --defaults-extra-file=$credfile dspam > dspam.sql \<br />
&& mysql --defaults-extra-file=$credfile -e "drop database dspam" \<br />
&& echo "dspam db saved to dspam.sql and dropped..."<br />
<br />
# Create dspam with correct permissions<br />
echo "Creating Dspam database..."<br />
mysqladmin --defaults-extra-file=$credfile reload<br />
mysqladmin --defaults-extra-file=$credfile refresh<br />
mysqladmin --defaults-extra-file=$credfile create dspam<br />
mysqladmin --defaults-extra-file=$credfile reload<br />
mysqladmin --defaults-extra-file=$credfile refresh<br />
echo "Adding dspam users and privileges..."<br />
mysql --defaults-extra-file=$credfile -e "CREATE USER dspam@localhost IDENTIFIED BY 'p4ssw3rd'"<br />
mysql --defaults-extra-file=$credfile -e "GRANT ALL PRIVILEGES ON dspam.* TO dspam@localhost"<br />
mysqladmin --defaults-extra-file=$credfile reload<br />
mysqladmin --defaults-extra-file=$credfile refresh<br />
echo "Done with dspam database..."<br />
mysql --defaults-extra-file=$credfile dspam < dspamdb.sql<br />
mysqladmin --defaults-extra-file=$credfile reload<br />
mysqladmin --defaults-extra-file=$credfile refresh<br />
# End DSpam DB install<br />
<br />
<br />
# Rspam Installation:<br />
wget https://rspamd.com/rpm-stable/centos-$rel/rspamd.repo -O /etc/yum.repos.d/rspamd.repo<br />
<br />
dnf $FEDORAREPO --enablerepo=qmt-devel install dspam dspam-libs dspam-client dspam-mysql dspam-web rspamd<br />
systemctl enable --now dspam<br />
systemctl status dspam<br />
systemctl enable --now rspamd<br />
systemctl status rspamd<br />
<br />
# Update Simscan<br />
dnf --enablerepo=qmt-devel update simscan<br />
<br />
# Up qmail limits<br />
sed -i 's/softlimit -m.*\\/softlimit -m 256000000 \\/' /var/qmail/supervise/smtp/run<br />
qmailctl stop<br />
qmailctl start<br />
<br />
<br />
# SA user prefs<br />
<br />
# Create SA DB and load table into MySQL<br />
cat >> ./sadb.sql << EOF<br />
CREATE TABLE userpref (<br />
username varchar(100) NOT NULL default '',<br />
preference varchar(30) NOT NULL default '',<br />
value varchar(100) NOT NULL default '',<br />
prefid int(11) NOT NULL auto_increment,<br />
PRIMARY KEY (prefid),<br />
KEY username (username)<br />
) ENGINE=InnoDB;<br />
EOF<br />
mysqladmin --defaults-extra-file=$credfile create spamassassin<br />
mysql --defaults-extra-file=$credfile -e "CREATE USER spamassassin@localhost IDENTIFIED BY 'p4ssw3rd'"<br />
mysql --defaults-extra-file=$credfile -e "GRANT ALL PRIVILEGES ON spamassassin.* TO spamassassin@localhost"<br />
mysqladmin --defaults-extra-file=$credfile reload<br />
mysqladmin --defaults-extra-file=$credfile refresh<br />
mysql --defaults-extra-file=$credfile spamassassin < sadb.sql<br />
<br />
# Read SA SQL DB<br />
cat >> /etc/mail/spamassassin/sql.cf << EOF<br />
user_scores_dsn DBI:mysql:spamassassin:localhost:3306<br />
user_scores_sql_password p4ssw3rd<br />
user_scores_sql_username spamassassin<br />
user_scores_sql_custom_query SELECT preference, value FROM _TABLE_ WHERE username = _USERNAME_ OR username = '$GLOBAL' OR username = <br />
CONCAT('%',_DOMAIN_) ORDER BY username ASC<br />
EOF<br />
echo "include sql.cf" >> /etc/mail/spamassassin/local.cf<br />
<br />
# Add Per User Settings in SA SQL DB (Yours may differ)<br />
echo "INSERT INTO userpref (username,preference,value) VALUES ('\$GLOBAL','required_hits','5.0');" | mysql -u root -p spamassassin<br />
echo "INSERT INTO userpref (username,preference,value) VALUES ('user@dom.com','required_hits','7.0');" | mysql -u root -p spamassassin<br />
echo "INSERT INTO userpref (username,preference,value) VALUES ('globalspam','required_hits','5.0');" | mysql -u root -p spamassassin<br />
echo "select * from userpref" | mysql -u root -p spamassassin<br />
<br />
# Tell SA Daemon To Use SQL DB<br />
sed -i 's/SPAMDOPTIONS=".*"/SPAMDOPTIONS="--create-prefs -m10 -q -x -u clamscan"/' /etc/sysconfig/spamassassin<br />
<br />
# Bayesian Filtering<br />
mkdir /etc/mail/spamassassin/.spamassassin<br />
chown -R clamscan:clamscan /etc/mail/spamassassin/.spamassassin<br />
cat >> /etc/mail/spamassassin/bayes.cf << EOF<br />
use_bayes 1<br />
use_bayes_rules 1<br />
bayes_auto_learn 1<br />
bayes_path /etc/mail/spamassassin/.spamassassin/bayes<br />
bayes_auto_learn_threshold_spam 6.0<br />
bayes_file_mode 0775<br />
EOF<br />
echo "include bayes.cf" >> /etc/mail/spamassassin/local.cf<br />
systemctl restart spamassassin<br />
<br />
<br />
# Tell simscan, append to simcontrol, reload cdb<br />
dspam=yes,rspam=yes,regex<br />
optional: dspamuser=globalspam (Otherwise the first envelope 'rcpt to' address is used)<br />
optional: spamuser=globalspam (Add to userprefs table)<br />
optional: remove spam_hits=* (Otherwise userprefs will not be used)<br />
qmailctl cdb<br />
<br />
# This is my configuration:<br />
:clam=yes,spam=yes,rspam=yes,dspam=yes,spam_passthru=yes,attach=.exe:.pif:.scr</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Secure_Qmail_web_administrationSecure Qmail web administration2024-03-20T18:55:03Z<p>Ebroch: </p>
<hr />
<div>'''Secure QMT Apache configuration file (/etc/httpd/conf/toaster.conf). Use 'aclnet' parameters suited for your configuration.'''<br />
<pre><br />
<toaster.conf><br />
RewriteEngine On<br />
RewriteCond %{HTTPS} !=on<br />
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]<br />
Define aclnet "172.16.1.0/24 192.168.9.0/24 127.0.0.1"<br />
<IfModule mod_alias.c><br />
ScriptAlias /mail/ /usr/share/toaster/cgi-bin/<br />
Alias /admin-toaster /usr/share/toaster/htdocs/admin/<br />
Alias /stats-toaster/ /usr/share/toaster/htdocs/mrtg/<br />
Alias /images-toaster/ /usr/share/toaster/htdocs/images/<br />
Alias /scripts/ /usr/share/toaster/htdocs/scripts/<br />
Alias /qmailadmin /usr/share/qmailadmin/<br />
</IfModule><br />
<Directory /usr/share/qmailadmin><br />
AddHandler cgi-script .cgi<br />
AddHandler cgi-script qmailadmin<br />
DirectoryIndex index.cgi qmailadmin index.html<br />
Options +Indexes +FollowSymLinks +ExecCGI<br />
<RequireAll><br />
Require ip ${aclnet}<br />
</RequireAll><br />
</Directory><br />
<Directory /usr/share/toaster/htdocs><br />
Options -Indexes +FollowSymLinks +MultiViews<br />
AllowOverride All<br />
<RequireAll><br />
Require ip ${aclnet}<br />
</RequireAll><br />
</Directory><br />
<Directory /usr/share/toaster/htdocs/admin><br />
<RequireAll><br />
AuthType Basic<br />
AuthName "Qmail Toaster v. 1.3 Admin"<br />
AuthUserFile /usr/share/toaster/include/admin.htpasswd<br />
Require valid-user<br />
Require ip ${aclnet}<br />
</RequireAll><br />
</Directory><br />
<Directory /usr/share/toaster/htdocs/mrtg><br />
AllowOverride All<br />
<RequireAll><br />
AuthType Basic<br />
AuthName "Qmail Toaster v. 1.3 Admin"<br />
AuthUserFile /usr/share/toaster/include/admin.htpasswd<br />
Require valid-user<br />
Require ip ${aclnet}<br />
</RequireAll><br />
</Directory><br />
<Directory /usr/share/toaster/cgi-bin/vqadmin><br />
AllowOverride All<br />
Options ExecCGI<br />
<RequireAll><br />
AuthType Basic<br />
AuthName "Qmail Toaster v. 1.3 Admin"<br />
AuthUserFile /usr/share/toaster/include/admin.htpasswd<br />
require valid-user<br />
Require ip ${aclnet}<br />
</RequireAll><br />
</Directory><br />
<Directory /usr/share/toaster/cgi-bin><br />
AllowOverride All<br />
Options ExecCGI<br />
<RequireAll><br />
Require ip ${aclnet}<br />
</RequireAll><br />
</Directory><br />
</toaster.conf><br />
</pre></div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Initial_ConfigurationInitial Configuration2024-03-20T16:05:55Z<p>Ebroch: Created page with "Add a domain: /home/vpopmail/bin/vadddomain your-domain.com Add a user: /home/vpopmail/bin/vadduser you@your-domain.com Edit /etc/php.ini and set register_globals = On service httpd restart Bring up your browser and go to: http://www.your-domain.com/admin-toaster/ Username: admin Password: toaster Change your password . . . Edit /etc/php.ini and set register_globals = Off service httpd restart Check your m..."</p>
<hr />
<div>Add a domain:<br />
/home/vpopmail/bin/vadddomain your-domain.com <br />
<br />
Add a user:<br />
/home/vpopmail/bin/vadduser you@your-domain.com <br />
<br />
Edit /etc/php.ini and set register_globals = On<br />
service httpd restart<br />
<br />
Bring up your browser and go to:<br />
http://www.your-domain.com/admin-toaster/<br />
Username: admin<br />
Password: toaster<br />
Change your password . . .<br />
<br />
Edit /etc/php.ini and set register_globals = Off<br />
service httpd restart<br />
<br />
Check your mail server:<br />
http://www.your-domain.com/webmail<br />
login with your full email address and your password<br />
Send yourself an email - should show right away<br />
Send an email to yourself if you have another address<br />
Go to your other email account and reply to the message you sent<br />
<br />
If Isoqlog doesn't show right away, do this:<br />
sh /usr/share/toaster/isoqlog/bin/cron.sh</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=QMT_WikiQMT Wiki2024-03-18T22:17:29Z<p>Ebroch: </p>
<hr />
<div><pre><br />
On old machine<br />
Backup old QMT Wiki<br />
# /usr/bin/mysqldump -uqmtwikiuser -pqmtwikipass -hlocalhost qmtwiki --single-transaction > qmtwiki.sql<br />
<br />
On new machine<br />
Download latest MediaWiki<br />
<br />
# cd /var/www<br />
# https://releases.wikimedia.org/mediawiki/1.41/mediawiki-1.41.0.tar.gz<br />
# tar zxvf mediawiki-1.41.0.tar.gz<br />
# tee /root/sql.cnf<<EOF<br />
[client]<br />
user=root<br />
password='mypass'<br />
host=localhost<br />
EOF<br />
</pre><br />
Create MySQL DB, restore old database (last step) if upgrading...skip restore if this is a new wiki<br />
<pre><br />
# mysqladmin --defaults-extra-file=$credfile create qmtwiki<br />
# mysql --defaults-extra-file=$credfile -e "CREATE USER qmtwikiuser@localhost IDENTIFIED BY 'qmtwikipass'" <br />
# mysql --defaults-extra-file=$credfile -e "GRANT ALL PRIVILEGES ON qmtwiki.* TO qmtwikiuser@localhost"<br />
# mysql -u root -p qmtwiki < qmtwiki.sql<br />
</pre><br />
Configure Apache<br />
<pre><br />
# tee /etc/httpd/sites-available/wiki.mydomain.com.conf<<EOF<br />
<VirtualHost *:80><br />
ServerName wiki.mydomain.com<br />
DocumentRoot /var/www/mediawiki-1.41.0<br />
<Directory /><br />
Options FollowSymLinks<br />
AllowOverride None<br />
</Directory><br />
ErrorLog /var/log/httpd/wiki.mydomain.com-error.log<br />
LogLevel debug<br />
CustomLog /var/log/httpd/wiki.mydomain.com-access.log combined<br />
</VirtualHost><br />
EOF<br />
</pre><br />
Configure new, or upgrade old, wiki, and use db parameters specified above when prompted<br />
<pre><br />
# http://wiki.mydomain.com/mw-config<br />
</pre></div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Wish_ListWish List2024-03-16T17:10:58Z<p>Ebroch: Created page with "Have you found a patch, or know of some free software you'd like to see included with the Qmail-Toaster? You've come to the right place! Please edit a section below with your request. ====rblsmtpd & tcpserver timeouts==== '''Requestor:''' Jean-Paul van de Plasse '''Date:''' 1/9/07 '''Status:''' On Devel Site (1/14/2007) '''Description:''' If I am not mistaken the timeout is default 60 secs per rbl, normally one would think this would not give to much problems. But t..."</p>
<hr />
<div>Have you found a patch, or know of some free software you'd like to see included with the Qmail-Toaster? You've come to the right place! Please edit a section below with your request.<br />
<br />
<br />
====rblsmtpd & tcpserver timeouts====<br />
'''Requestor:''' Jean-Paul van de Plasse<br />
<br />
'''Date:''' 1/9/07<br />
<br />
'''Status:''' On Devel Site (1/14/2007)<br />
<br />
'''Description:''' If I am not mistaken the timeout is default 60 secs per rbl, normally one would think this would not give to much problems. But then again if your timeout on the client side is lowish and 1 or 2 are not working you will get this kind of problems/slowness..<br />
Maybe we could incorporate this patch http://www.gossamer-threads.com/lists/qmail/users/123473<br />
since that looks at the total time of the rblsmtp session instead of per blacklist. The patches applied without any problems, using it now for some testing.<br />
<br />
I made a subset of the patch on the page above, figured the connection limits are better to be solved using iptables.<br />
<br />
The patch allows you to set a environment var RBLTIMEOUT="seconds". After seconds rblsmtp will timeout and continue with qmail-smtpd. The logfile will contain a message that a timeout happened and on which rbl this was. (Not necessary the one causing the timeout but mostly it will be).<br />
<br />
You can set the var in /etc/tcprules.d/tcp.smtp as RBLTIMEOUT="45" .<br />
Or any other timeout you wish..<br />
<br />
Download at http://iserve01.i-serve.net/rblsmtp.c.rbltimeout.patch<br />
<br />
====LDAP Integration====<br />
'''Requestor:''' SV<br />
<br />
'''Date:''' 1-9-2007<br />
<br />
'''Status:''' This isn't a QmailToaster goal, we're not moving in that direction. Use [http://www.qmail-ldap.org qmail-ldap.org] instructions for LDAP support.<br />
<br />
'''Description:''' Use an existing LDAP server for account management, vs MySQL. [http://www.qmail-ldap.org qmail-ldap.org]<br />
<br />
'''ES Reply''' (1-12-2007) The Toaster uses vpopmail for account management, which provides most if not all of the features of qmail-ldap, so providing qmail-ldap as part of the Toaster would be impractical. However, vpopmail '''does''' have the capability to use LDAP in place of MySQL for authentication, as does courier-authlib, so it would be feasible (possibly somewhat trivial depending on your skill level) to modify vpopmail-toaster and courier-authlib-toaster yourself to use LDAP in place of MySQL. If someone were to successfully create vpopmail-toaster and courier-authlib-toaster ldap configurations, the developers might consider incorporating this into the 'stock' Toaster. Note, you might run into a problem with squirrelmail address books, as I don't know where they're stored in the Toaster configuration. There might also be other Toaster packages which use MySQL that I'm not aware of.<br />
<br />
====Clamav 0.90 patch====<br />
'''Requestor:''' Nikki Locke<br />
<br />
'''Date:''' 2007-02-19<br />
<br />
'''Description:''' We need a clamav 0.90 patch, as all earlier versions are now out of date, and the old patches do not work on clamav 0.90.<br />
<br />
Below is my attampt at a patch - feel free to use this in its entirety, or improve it.<br />
<br />
No warranty expressed or implied - I just did the minimum to get the patch to go through, and ran it on my CentOS box for a couple of days. I did find the live clamd.conf file did not get updated by install, and had to update it manually.<br />
<br />
<pre><br />
diff -urN original/etc/clamd.conf ./etc/clamd.conf<br />
--- original/etc/clamd.conf 2007-02-12 18:18:42.000000000 +0000<br />
+++ ./etc/clamd.conf 2007-02-15 15:31:47.000000000 +0000<br />
@@ -5,13 +5,13 @@<br />
<br />
<br />
# Comment or remove the line below.<br />
-Example<br />
+#Example<br />
<br />
# Uncomment this option to enable logging.<br />
# LogFile must be writable for the user running daemon.<br />
# A full path is required.<br />
# Default: disabled<br />
-#LogFile /tmp/clamd.log<br />
+LogFile stderr<br />
<br />
# By default the log file is locked for writing - the lock protects against<br />
# running clamd multiple times (if want to run another clamd, please<br />
@@ -36,7 +36,7 @@<br />
# Also log clean files. Useful in debugging but drastically increases the<br />
# log size.<br />
# Default: no<br />
-#LogClean yes<br />
+LogClean yes<br />
<br />
# Use system logger (can work together with LogFile).<br />
# Default: no<br />
@@ -49,7 +49,7 @@<br />
<br />
# Enable verbose logging.<br />
# Default: no<br />
-#LogVerbose yes<br />
+LogVerbose yes<br />
<br />
# This option allows you to save a process identifier of the listening<br />
# daemon (main thread).<br />
@@ -153,7 +153,7 @@<br />
<br />
# Don't fork into background.<br />
# Default: no<br />
-#Foreground yes<br />
+Foreground yes<br />
<br />
# Enable debug messages in libclamav.<br />
# Default: no<br />
@@ -207,7 +207,7 @@<br />
<br />
# Enable internal e-mail scanner.<br />
# Default: yes<br />
-#ScanMail yes<br />
+ScanMail yes<br />
<br />
# If an email contains URLs ClamAV can download and scan them.<br />
# WARNING: This option may open your system to a DoS attack.<br />
diff -urN original/clamd/clamd.c ./clamd/clamd.c<br />
--- original/clamd/clamd.c 2007-02-12 20:55:24.000000000 +0000<br />
+++ ./clamd/clamd.c 2007-02-15 15:26:08.000000000 +0000<br />
@@ -229,10 +229,14 @@<br />
if((cpt = cfgopt(copt, "LogFile"))->enabled) {<br />
logg_file = cpt->strarg;<br />
if(strlen(logg_file) < 2 || (logg_file[0] != '/' && logg_file[0] != '\\' && logg_file[1] != ':')) {<br />
- fprintf(stderr, "ERROR: LogFile requires full path.\n");<br />
- logg_close();<br />
- freecfg(copt);<br />
- return 1;<br />
+ if (strcmp(logg_file,"stderr")!=0) {<br />
+ fprintf(stderr, "ERROR: LogFile requires full path.\n");<br />
+ logg_close();<br />
+ freecfg(copt);<br />
+ return 1;<br />
+ } else {<br />
+ use_stderr=1;<br />
+ }<br />
}<br />
time(&currtime);<br />
if(logg("#+++ Started at %s", ctime(&currtime))) {<br />
diff -urN original/shared/output.c ./shared/output.c<br />
--- original/shared/output.c 2006-08-30 23:41:21.000000000 +0100<br />
+++ ./shared/output.c 2007-02-15 15:29:21.000000000 +0000<br />
@@ -138,7 +138,9 @@<br />
pthread_mutex_lock(&logg_mutex);<br />
#endif<br />
if(logg_file) {<br />
- if(!logg_fd) {<br />
+ if(use_stderr) {<br />
+ logg_fd = stderr;<br />
+ } else if(!logg_fd) {<br />
old_umask = umask(0037);<br />
if((logg_fd = fopen(logg_file, "a")) == NULL) {<br />
umask(old_umask);<br />
@@ -161,7 +163,7 @@<br />
}<br />
}<br />
<br />
- if(logg_size) {<br />
+ if(logg_size && !use_stderr) {<br />
if(stat(logg_file, &sb) != -1) {<br />
if(sb.st_size > logg_size) {<br />
logg_file = NULL;<br />
diff -urN original/shared/output.h ./shared/output.h<br />
--- original/shared/output.h 2007-02-13 21:14:38.000000000 +0000<br />
+++ ./shared/output.h 2007-02-15 15:22:24.000000000 +0000<br />
@@ -29,6 +29,7 @@<br />
<br />
int mdprintf(int desc, const char *str, ...);<br />
<br />
+int use_stderr;<br />
int logg(const char *str, ...);<br />
<br />
void logg_close(void);<br />
diff -urN original/etc/freshclam.conf ./etc/freshclam.conf<br />
--- original/etc/freshclam.conf 2007-02-11 09:54:46.000000000 +0000<br />
+++ ./etc/freshclam.conf 2007-02-15 15:22:56.000000000 +0000<br />
@@ -5,7 +5,7 @@<br />
<br />
<br />
# Comment or remove the line below.<br />
-Example<br />
+#Example<br />
<br />
# Path to the database directory.<br />
# WARNING: It must match clamd.conf's directive!<br />
@@ -14,7 +14,7 @@<br />
<br />
# Path to the log file (make sure it has proper permissions)<br />
# Default: disabled<br />
-#UpdateLogFile /var/log/freshclam.log<br />
+UpdateLogFile /var/log/freshclam.log<br />
<br />
# Enable verbose logging.<br />
# Default: no<br />
</pre><br />
<br />
====EXTTODO patch for silly qmail syndrome====<br />
'''Requestor:''' KBS Ramachandra<br />
<br />
'''Date:''' 10-Aug-2007<br />
<br />
'''Description:''' Would like the '''exttodo patch''' in '''QmailToaster''' to handle the silly qmail syndrome. I manage a shared server with high mail injection rates. While the pre-processing queue keeps building up, qmail-send only delivers one local message at a time. I think that this is an essential patch for a toaster configuration. URL to the patch: [http://www.nrg4u.com/qmail/ext_todo-20030105.patch]<br />
<br />
====Increased Mail Store/Quota====<br />
'''Requestor:''' Roxanne Sandesara<br />
<br />
'''Date:''' 09/17/2007<br />
<br />
'''Status:''' Requested<br />
<br />
'''Description:''' Currently there seems to be a limit of 1gb to the allowable content for a given account on the server. I would like to find a way to increase this. Various web-mail services allow as much as 5gb, and especially in a business environment where getting rid of mail and thusly business intelligence is frowned upon, it is not hard at all to accumulate quite a bit of mail in just a few years. QmailAdmin allows setting a quota of 2gb, but the server reports full and will not upload anything more once it gets up to 1gb. And I'd like to be able to exceed even 2gb.<br />
<br />
====chkuser Settings Review====<br />
'''Requestor:''' Jake Vickers<br />
<br />
'''Date:''' 07/01/2009<br />
<br />
'''Status:''' Requested<br />
<br />
'''Description:''' chkuser, unfortunately, must be configured at compile time. Let's look at all the various options available (current version at time of writing is 2.0.9), see what we're currently doing, and decide whether or not they should be changed. This job is too big for this page; let's take it to [[chkuser Settings]].</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Replacing_Courier_IMAP_with_Dovecot_IMAPReplacing Courier IMAP with Dovecot IMAP2024-03-16T17:10:01Z<p>Ebroch: Created page with "If your QMT is running Courier IMAP and you're experiencing poor IMAP performance with large mailboxes, this is your solution. Dovecot runs efficiently on relatively low powered hosts, with accounts having in excess of 10G of mail. Thanks go to Phil and Scott for contributing to the first wiki content regarding dovecot. Their work helped to lay the foundation for getting dovecot integrated into QMT. Since then, this process has become much simpler. Dovecot is schedule..."</p>
<hr />
<div>If your QMT is running Courier IMAP and you're experiencing poor IMAP performance with large mailboxes, this is your solution. Dovecot runs efficiently on relatively low powered hosts, with accounts having in excess of 10G of mail.<br />
<br />
Thanks go to Phil and Scott for contributing to the first wiki content regarding dovecot. Their work helped to lay the foundation for getting dovecot integrated into QMT. Since then, this process has become much simpler. <br />
<br />
Dovecot is scheduled to be included as the 'stock' IMAP software in QMTv1.5. The following procedure is for using dovecot on a QMTv1.3.x host.<br />
<br />
'''WARNING:'''<br />
This is not a minor adjustment. This is a procedure to replace Courier IMAP and qmail-pop3d with Dovecot. There is a possibility of mistakes leading to data corruption or more commonly, your users having to re-download all stored mail. In any case, you should test this on a non-production installation matching your production server before doing this in production.<br />
<br />
Now that the scary part is over, the part where most problems will occur is in the Mailbox Conversion step. If that is not done correctly, it can cause your users to have to re-download their mail. The rest is relatively straight forward and safe.<br />
<br />
=== Install ===<br />
<br />
RPMS are available for CentOS 5 i386 and x86_64 in the [http://qtp.qmailtoaster.com/repos QmailToaster-Plus (QTP) repository]. If your QMT is running an available distro/version/arch and you have qmailtoaster-plus.repo installed, you can use yum to install dovecot:<br />
# rpm -Uvh http://qtp.qmailtoaster.com/trac/downloads/1<br />
# yum --enablerepo=qtp-CentOS install dovecot<br />
<br />
If your QMT is running on a different distro/version, you'll need to download the source rpm, then build and install the binary rpm for your distro/version, e.g:<br />
# cd /my/rpmbuild/SRPMS<br />
# wget http://qtp.qmailtoaster.com/repos/SRPMS/dovecot-2.0.11-2.qtp.src.rpm<br />
# rpmbuild --rebuild dovecot-*.src.rpm<br />
# rpm -ivh ../RPMS/*86*/dovecot-*.rpm<br />
That might not work exactly, but you get the idea.<br />
<br />
=== Configure ===<br />
<br />
The configuration files included in the rpm should work as is. There is an ''/etc/dovecot/toaster.conf'' file which contains settings particular to QMT. This file should not typically be changed much.<br />
<br />
You may want to do things for your environment such as creating shared folders. Any changes you need to make should be added to the ''/etc/dovecot/local.conf'' file, which is also included, but not required.<br />
<br />
The ''/etc/dovecot/dovecot.conf'' file is the main configuration file. It simply contains include directives for these 2 files. It is probably best not to modify this file directly.<br />
<br />
There is also an ''/etc/dovecot/conf.d/'' directory which contains examples of many dovecot configuration parameters. Be aware that these configuration files are not active, so don't make configuration changes there. Modify your local.conf file instead to make changes effective.<br />
<br />
=== Stop Courier, qmail Services ===<br />
<br />
First we need to stop Courier IMAP:<br />
# cd /var/qmail/supervise<br />
# touch imap4/down imap4/log/down<br />
# touch imap4-ssl/down imap4-ssl/log/down<br />
# service qmail stop<br />
<br />
=== Convert the mailboxes ===<br />
<br />
This is the part you really should test. The success or failure of this part will determine how transparent your migration is to your users. You'll not likely loose any mail (you have backups, right??), but your users might end up having to re-subscribe to folders and/or re-download email headers, depending on the client software they use.<br />
<br />
First we’ll get the conversion script:<br />
# cd /usr/local/sbin<br />
# wget http://www.dovecot.org/tools/courier-dovecot-migrate.pl<br />
...<br />
# chmod 0700 courier-dovecot-migrate.pl<br />
# cd ~vpopmail/domains<br />
<br />
This command will do a "dry run" to make sure things will work correctly...<br />
# /usr/local/sbin/courier-dovecot-migrate.pl --recursive<br />
<br />
You should see your user accounts scroll by and say something like “UIDLIST not found” but nothing else. At the end of the script you should have 0 ERRORS.<br />
<br />
This command actually does the conversion.<br />
# /usr/local/sbin/courier-dovecot-migrate.pl --recursive --convert<br />
<br />
If everything went well, you can proceed. If not, you might want to post a message to the qmail-toaster list to get some help.<br />
<br />
=== Start Dovecot, qmail Services ===<br />
<br />
Now we can start dovecot and qmail:<br />
# service qmail start<br />
# chkconfig dovecot on<br />
# service dovecot start<br />
<br />
=== Testing ===<br />
# tail /var/log/dovecot.log<br />
should show that dovecot has started, with no errors.<br />
<br />
You should telnet to the server on ports 143 and 993 to test the connections.<br />
<br />
=== SquirrelMail Configuration ===<br />
Squirrelmail needs some adjustments in order to work best with dovecot. This ''/etc/squirrelmail/config_local.php'' file should work for you:<br />
<pre><br />
<?php<br />
####################<br />
# Local configuration for Qmail Toaster<br />
# configure to suit your requirements<br />
<br />
# these are in toaster config,<br />
# changed/removed for stock dovecot (w/out courier compat config)<br />
# $imap_server_type = 'courier';<br />
# $optional_delimiter = '.';<br />
# $default_folder_prefix = 'INBOX.';<br />
# $delete_folder = true;<br />
# $show_contain_subfolders_option = false;<br />
<br />
# these should be added to the toaster config (imho)<br />
$org_name = "QmailToaster";<br />
# $org_logo = SM_PATH . 'images/sm_logo.png';<br />
# $org_logo_width = '308';<br />
# $org_logo_height = '111';<br />
# $org_title = "SquirrelMail $version";<br />
$provider_uri = 'http://www.qmailtoaster.org/';<br />
$provider_name = 'QmailToaster';<br />
<br />
# these were added so SM authenticates,<br />
# eliminating need for 127.: line in /etc/tcprules.d/tcp.smtp file<br />
$smtpServerAddress = 'localhost';<br />
$smtpPort = 587;<br />
$smtp_auth_mech = 'login';<br />
<br />
# these were added/changed for dovecot imap<br />
$imapServerAddress = 'localhost';<br />
$imap_server_type = 'dovecot';<br />
# squirrelmail doesn't support starttls until v1.5.1, so we'll use digest-md5<br />
#$use_imap_tls = true;<br />
$imap_auth_mech = 'digest-md5';<br />
<br />
# these are what's left from stock QMT configuration<br />
$useSendmail = false;<br />
$optional_delimiter = 'detect';<br />
$default_folder_prefix = '';<br />
$show_prefix_option = false;<br />
$force_username_lowercase = true;<br />
$hide_sm_attributions = true;<br />
$plugins[] = 'calendar';<br />
$plugins[] = 'notes';<br />
$plugins[] = 'filters';<br />
$plugins[] = 'quota_usage';<br />
$plugins[] = 'unsafe_image_rules';<br />
$plugins[] = 'qmailadmin_login';<br />
<br />
?><br />
</pre><br />
<br />
=== Timekeeping ===<br />
Dovecot is very sensitive to variations in time, and will terminate if it detects a rather small variance. This is particularly problematic in VM guests. You should be running ntpd on your QMT to keep accurate time. In order to start dovecot automatically in the event that dovecot terminates itself, this script run every few minutes as cron job will do the trick:<br />
#!/bin/sh<br />
# check if dovecot's running, and start it if it's not<br />
# shubes - 20090206 - created<br />
service dovecot status >/dev/null 2>&1 || \<br />
service dovecot start >/dev/null 2>&1<br />
<br />
It is suggested that you name the script "dovecot-check" and put it in the /usr/local/sbin directory. Don't forget to "chmod +x /usr/local/sbin/dovecot-check" so that the script will execute!<br />
<br />
In order so that this runs every five minutes, add this line to your crontab:<br />
<br />
0-59/5 * * * * /usr/local/sbin/dovecot-check 2>&1 > /dev/null<br />
<br />
=== Dovecot POP3 ===<br />
In order to use dovecot for POP3 as well as IMAP, you need to stop the qmail pop3 service, and configure dovecot to handle it.<br />
# cd /var/qmail/supervise/<br />
# touch pop3/down pop3/log/down<br />
# touch pop3-ssl/down pop3-ssl/log/down<br />
# service qmail stop<br />
# service qmail start<br />
<br />
Edit ''/etc/dovecot/toaster.conf'', adding pop3 to the protocols parameter:<br />
protocols = imap pop3<br />
<br />
Edit ''/etc/dovecot/local.conf'', adding a section for protocol pop3:<br />
protocol pop3 {<br />
pop3_client_workarounds = outlook-no-nuls oe-ns-eoh<br />
pop3_fast_size_lookups = yes<br />
pop3_lock_session = yes<br />
# %f format is compatible with qmail-pop3d<br />
# pop3_uidl_format = %f<br />
}<br />
If you have users who use pop3 and have left messages on the server (the messages would be located in their Maildir/cur directory), then you should uncomment the pop3_uidl_format line. Otherwise, these messages would be downloaded again by dovecot.<br />
<br />
If you want to change over to dovecot's UIDL format, you can remove the messages in the Maildir/cur directory. '''Be absolutely sure that the users are using pop3 and not imap if you do this'''. Messages which have not been downloaded yet would be in their Maildir/new directory.<br />
<br />
Then restart dovecot:<br />
# service dovecot restart<br />
<br />
That should do it for you.<br />
<br />
=== Upgrading ===<br />
In the case of all upgrades, be sure to review the [http://wiki1.dovecot.org/action/show/Upgrading?action=show&redirect=UpgradingDovecot dovecot wiki] regarding upgrades for the versions you're upgrading from/to. There may be considerations there for your particular environment that are not mentioned here.<br />
==== dovecot 2.0.x rpm ====<br />
Once you're running dovecot v2.0.x from the QTP repo, upgrading to subsequent releases from that repo is simple:<br />
# yum --enablerepo=qtp-CentOS update dovecot<br />
# service dovecot restart<br />
Version 2.0.11 is current as of this writing, so versions beyond 2.0.x might have other considerations.<br />
<br />
==== dovecot 1.x.x rpm ====<br />
If you are upgrading from an rpm of dovecot version 1.x, you need to migrate your configuration settings to the new config file syntax. The easiest way to do this is to run the new doveconf program against your previous dovecot.conf file, then manually apply any custom settings you had (shared folders and such) to the new local.conf file. After upgrading the rpm package, do:<br />
# cd /etc/dovecot<br />
# doveconf -n >dovecot-2.conf.old<br />
# mv dovecot.conf dovecot-1.conf<br />
# mv dovecot.conf.rpmnew dovecot.conf<br />
If you were running a pretty much 'stock' configuration, you will probably be able to use the new configuration as is, after renaming the dovecot.conf files to activate the new one, as above. To be sure you're carrying forward your previous settings, review the dovecot-2.conf.old file and add any settings you have there '''which are not already in the toaster.conf file''' to the '''local.conf''' file.<br />
<br />
==== dovecot 1.x.x non-rpm ====<br />
If you installed dovecot using the procedure that was previously here on the wiki (the old-fashioned manual way), you should remove that installation before installing the RPM, but be sure to save your configuration file first:<br />
# mkdir /etc/dovecot<br />
# cp /usr/local/etc/dovecot.conf /etc/dovecot/dovecot.conf<br />
# cd /the/directory/you/installed/from<br />
# sudo make uninstall<br />
Then install the RPM as in a new install, and follow the notes for upgrading your configuration settings. You will not need to convert mailboxes, but you will need to disable any supervise scripts which you created:<br />
# cd /var/qmail/supervise<br />
# mv dovecot .dovecot<br />
By hiding the dovecot supervise directory, this will prevent it from attempting to start.<br />
<br />
'''Dovecot without ipv6'''<br />
<br />
after disabling ip V6 dovecot will not start, telling <br />
<br />
"Fatal: listen(143) failed: Address already in use"<br />
<br />
In dovecots configfile replace the line:<br />
<br />
listen = *, ::<br />
<br />
with <br />
<br />
listen = *<br />
<br />
like that it only listens on ipv4 and starts perfectly<br />
<br />
=== Questions ===<br />
If there are any questions or comments about this, please post to the list.<br />
<br />
=== Corrections ===<br />
If you see something here that needs correction, by all means, correct it! :)</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Autorespond-toasterAutorespond-toaster2024-03-16T17:07:27Z<p>Ebroch: Created page with "'''Change Log''' * Wed Nov 01 2006 Erik A. Espinoza <espinoza@forcenetworks.com> 2.0.4-1.3.2 ** Add Fedora Core 6 support * Mon Jun 05 2006 Nick Hemmesch <nick@ndhsoft.com> 2.0.4-1.3.1 ** Add SuSE 10.1 support * Sat May 13 2006 Nick Hemmesch <nick@ndhsoft.com> 2.0.4-1.2.9 ** Add Fedora Core 5 support * Sun Nov 20 2005 Nick Hemmesch <nick@ndhsoft.com> 2.0.4-1.2.8 ** Add SuSE 10.0 and Mandriva 2006.0 support * Sat Oct 15 2005 Nick Hemmesch <nick@ndhsoft.com> 2.0.4-1.2.7 **..."</p>
<hr />
<div>'''Change Log'''<br />
* Wed Nov 01 2006 Erik A. Espinoza <espinoza@forcenetworks.com> 2.0.4-1.3.2<br />
** Add Fedora Core 6 support<br />
* Mon Jun 05 2006 Nick Hemmesch <nick@ndhsoft.com> 2.0.4-1.3.1<br />
** Add SuSE 10.1 support<br />
* Sat May 13 2006 Nick Hemmesch <nick@ndhsoft.com> 2.0.4-1.2.9<br />
** Add Fedora Core 5 support<br />
* Sun Nov 20 2005 Nick Hemmesch <nick@ndhsoft.com> 2.0.4-1.2.8<br />
** Add SuSE 10.0 and Mandriva 2006.0 support<br />
* Sat Oct 15 2005 Nick Hemmesch <nick@ndhsoft.com> 2.0.4-1.2.7<br />
** Add Fedora Core 4 x86_64 support<br />
* Sat Oct 01 2005 Nick Hemmesch <nick@ndhsoft.com> 2.0.4-1.2.6<br />
** Add CentOS 4 x86_64 support<br />
* Wed Jun 29 2005 Nick Hemmesch <nick@ndhsoft.com> 2.0.4-1.2.5<br />
** Add Fedora Core 4 support<br />
* Fri Jun 03 2005 Torbjorn Turpeinen <tobbe@nyvalls.se> 2.0.4-1.2.4<br />
** Gnu/Linux Mandrake 10.0,10.1,10.2 support<br />
* Sun Feb 27 2005 Nick Hemmesch <nick@ndhsoft.com> 2.0.4-1.2.3<br />
** Add Fedora Core 3 support<br />
** Add CentOS 4 support<br />
* Fri Jun 04 2004 Nick Hemmesch <nick@ndhsoft.com> 2.0.4-1.2.2<br />
** Udpate to autorespond 2.0.4<br />
* Thu Jun 03 2004 Nick Hemmesch <nick@ndhsoft.com> 2.0.2-1.0.8<br />
** Add Fedora Core 2 support<br />
* Mon Dec 29 2003 Nick Hemmesch <nick@ndhsoft.com> 2.0.2-1.0.7<br />
** Add Fedora Core 1 support<br />
* Sun Nov 23 2003 Nick Hemmesch <nick@ndhsoft.com> 2.0.2-1.0.6<br />
** Add Trustix 2.0 support<br />
* Thu May 15 2003 Miguel Beccari <miguel.beccari@clikka.com> 2.0.2-1.0.5<br />
** Clean-ups on SPEC file: compilation banner, better gcc detects<br />
** Detect gcc-3.2.3<br />
** Red Hat Linux 9.0 support (nick@ndhsoft.com)<br />
** Gnu/Linux Mandrake 9.2 support<br />
* Wed Apr 02 2003 Miguel Beccari <miguel.beccari@clikka.com> 2.0.2-1.0.4<br />
** Clean-ups<br />
* Mon Mar 31 2003 Miguel Beccari <miguel.beccari@clikka.com> 2.0.2-1.0.3<br />
** Conectiva Linux 7.0 support<br />
* Sat Feb 01 2003 Miguel Beccari <miguel.beccari@clikka.com> 2.0.2-1.0.2<br />
** Redo Macros to prepare supporting larger RPM OS. We could be able to compile (and use) packages under every RPM based distribution: we just need to write right requirements.<br />
* Sat Jan 25 2003 Miguel Beccari <miguel.beccari@clikka.com> 2.0.2-1.0-1<br />
** Added MDK 9.1 support<br />
** Try to use gcc-3.2.1<br />
** Added very little patch to compile with newest GLIBC<br />
** Support dor new RPM-4.0.4<br />
* Sat Oct 05 2002 Miguel Beccari <miguel.beccari@clikka.com> 2.0.2-0.9.2<br />
** Soft clean-ups<br />
* Sun Sep 29 2002 Miguel Beccari <miguel.beccari@clikka.com> 2.0.2-0.9.1<br />
** RPM macros to detect Mandrake, RedHat, Trustix are OK again. They are very basic but they should work.<br />
* Fri Sep 27 2002 Miguel Beccari <miguel.beccari@clikka.com> 0.8.2.0.2-1<br />
** Rebuilded under 0.8 tree.<br />
** Important comments translated from Italian to English.<br />
** Written rpm rebuilds instruction at the top of the file (in english).<br />
* Thu Aug 29 2002 Miguel Beccari <miguel.beccari@clikka.com> 0.7.2.0.2-2<br />
** Deleted Mandrake Release Autodetection (creates problems)<br />
* Fri Aug 16 2002 Miguel Beccari <miguel.beccari@clikka.com> 0.7.2.0.2-1<br />
** New version: 0.7 toaster (rebuild with 0.7 spec)<br />
* Tue Aug 13 2002 Miguel Beccari <miguel.beccari@clikka.com> 0.6.2.0.2-1<br />
** New version: 0.6 toaster.<br />
* Mon Aug 12 2002 Miguel Beccari <miguel.beccari@clikka.com> 0.5.2.0.2-1<br />
** Checks for gcc-3.2 (default compiler from now)<br />
** New version: 0.5 toaster.<br />
* Thu Aug 08 2002 Miguel Beccari <miguel.beccari@clikka.com> 0.4.2.0.2-1<br />
** Rebuild against 0.4 toaster<br />
* Tue Jul 30 2002 Miguel Beccari <miguel.beccari@clikka.com> 0.3.2.0.2-2<br />
** Now packages have got 'no sex': you can rebuild them with command line flags for specifics targets that are: RedHat, Trustix, and of course Mandrake (that is default)<br />
* Sun Jul 28 2002 Miguel Beccari <miguel.beccari@clikka.com> 0.3.2.0.2.1mdk<br />
** toaster v. 0.3: now it is possible upgrading safely because of 'pversion' that is package version and 'version' that is toaster version<br />
* Thu Jul 25 2002 Miguel Beccari <miguel.beccari@clikka.com> 0.2-2.0.2.1mdk<br />
** toaster v. 0.2<br />
* Thu Jul 18 2002 Miguel Beccari <miguel.beccari@clikka.com> 0.1-2.0.2.2mdk<br />
** Added tests for gcc-3.1.1<br />
** Added toaster version (we will need to mantain it too): is vtoaster 0.1<br />
* Mon Jul 15 2002 Miguel Beccari <miguel.beccari@clikka.com> 2.0.2-1mdk<br />
** First RPM package.</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Project_Change_LogProject Change Log2024-03-16T17:06:57Z<p>Ebroch: Created page with "The following change log is from the prior main web site. '''08/06/2012''' - Updated all packages to current upstream releases. These packages carry a 1.4.n QMT version. '''07/31/2011''' - Updated clamav to 0.97.2. This is a bugfix release and if you were experiencing issues with odd hangs of clamav it is recommended you upgrade. For more information, [http://git.clamav.net/gitweb?p=clamav-devel.git;a=blob_plain;f=ChangeLog;hb=clamav-0.97.2 here are the release notes]...."</p>
<hr />
<div>The following change log is from the prior main web site.<br />
<br />
'''08/06/2012''' - Updated all packages to current upstream releases. These packages carry a 1.4.n QMT version.<br />
<br />
'''07/31/2011''' - Updated clamav to 0.97.2. This is a bugfix release and if you were experiencing issues with odd hangs of clamav it is recommended you upgrade. For more information, [http://git.clamav.net/gitweb?p=clamav-devel.git;a=blob_plain;f=ChangeLog;hb=clamav-0.97.2 here are the release notes].<br />
<br />
'''06/30/2011''' - Updated clamav to 0.97.1. This is a bugfix release. For more information, [http://git.clamav.net/gitweb?p=clamav-devel.git;a=blob_plain;f=ChangeLog;hb=clamav-0.97.1 here are the release notes].<br />
<br />
'''02/22/2011''' - Updated clamav to 0.97. This is another bugfix release and adds some speed enhancements. For more information, read the [http://git.clamav.net/gitweb?p=clamav-devel.git;a=blob_plain;f=ChangeLog;hb=clamav-0.97 release notes].<br />
<br />
'''01/28/2011''' - Updated Qmailadmin to 1.2.15. This is a minor update, mainly to change an image used in Qmailadmin that was copyrighted.<br />
<br />
'''12/20/2010''' - Updated clamav to 0.96.5. This is a bugfix release that fixes some bugs left over from the last release. The changelog is available [http://git.clamav.net/gitweb?p=clamav-devel.git;a=blob_plain;f=ChangeLog;hb=clamav-0.96.5 here] at clamav's website.<br />
<br />
'''10/30/2010''' - Updated clamav to 0.96.4. This is a bugfix release and it's recommended to update to this version. The changelog is available [http://git.clamav.net/gitweb?p=clamav-devel.git;a=blob_plain;f=ChangeLog;hb=clamav-0.96.4 here] at clamav's website.<br />
<br />
'''09/22/2010''' - Updated clamav to 0.96.3 today. This update fixes some problems with the PDF parser and the internal bzip2 library. A full changelog is available [http://git.clamav.net/gitweb?p=clamav-devel.git;a=blob_plain;f=ChangeLog;hb=clamav-0.96.3 here] at the clamav website. Enjoy!<br />
<br />
'''08/17/2010''' - Updated clamav to 0.96.2 today. This is a bugfix release with some minor improvements. See the [http://www.clamav.net/ clamav website] for more information. Clamav's [http://git.clamav.net/gitweb?p=clamav-devel.git;a=blob_plain;f=ChangeLog;hb=clamav-0.96.2 changelog] is available for review as well.<br />
<br />
'''06/03/2010''' - Updated clamav to 0.96.1. This is a bugfix release.<br />
<br />
'''05/15/2010''' - Yet another weekend of problems. The person who was letting me have a server on their network at a discount decided to shut the server down again for reasons I will not go into here. I have the webpage back obviously, and will get email back up shortly. Some of the other services (like QTP) wi ll take me a couple of days.<br />
<br />
'''05/01/2010''' - I have changed the infrastructure around some. Downloads are now linked to the mirrors list. All downloads will be routed to mirrors.qmailtoaster.net for download. I will keep the old locations for downloads until 6-1-2010 and once that date rolls around the old links will no longer work.<br />
<br />
'''04/11/2010''' - A new version of ClamAV was released and I have updated the package on the site for this. Since a new version of Squirrelmail was also released, I updated this package as well.<br />
<br />
'''10/29/2009''' - A new version of ClamAV was released on 10-28-2009 and I have updated the current package on the site. I have tested this package under CentOS 5 without any issues. This is a bugfix release, and is a recommended update. The release notes are available [http://git.clamav.net/gitweb?p=clamav-devel.git;a=blob_plain;f=ChangeLog;hb=master here] from clamav.net.<br />
<br />
'''10/02/2009''' - Updated qmail-toaster to fix an issue with named pipes that on some systems would corrupt the queue/trigger.<br />
09/07/2009 - Updated the clamav-toaster, qmail-toaster, and ucspi-tcp-toaster packages so they they will work more efficiently with Qmailtoaster-Plus and qtp-newmodel. You do not need to upgrade your packages if you're running the current version at this time. The only changes made to the packages were for a timing change in the pre-build portion of the RPM installation. Those were the only changes made.<br />
<br />
'''08/13/2009''' - Incremented the simscan minor version number to better align with current version schema and current/legacy scripts. Other changes to note are: the hard ceiling for spam deletion was increased from 20 to 40 and the simscan package will now no longer overwrite the tcp.smtp file and wipe out any customizations you may have added.<br />
<br />
'''06/16/2009''' - Rolled courier-authlib back to 0.59.2 since the new version did not contain the proper vpopmail patches to function with Qmail. Thanks to slamp for pointing this out. Sorry everyone! You'll need to replace the newer version of courier-authlib with this older (but updated!) version immediately.<br />
<br />
'''06/15/2009''' - Released a new version of all packages today. Updated ClamAV to 0.95.2. Updated Squirrelmail to 1.4.19 and courier-authlib to 0.62.2. Added Mandriva 2009 support. Also added Fedora 11 and Fedora 11 x86_64 support.<br />
<br />
'''05/20/2009''' - We now have a video magazine! We will produce a weekly video on how to install, configure, tweak, and troubleshoot your Qmailtoaster system. Come and visit us today!<br />
<br />
'''05/13/2009''' - Updated all the QMT packages to add Fedora 9 x86_64 and Fedora 10 x86_64 support. I also updated simscan to version 1.4.0, thanks to Steve Huff for the testing and the modified spec file. Qmailadmin was updated to the latest STABLE release (1.2.12) and updated Squirrelmail to version 1.4.18 to fix some potential security issues. The softlimits for the daemons were increased for x86_64 builds to resolve a common issue noted on the mailing list.<br />
<br />
'''04/16/2009''' - Updated clamav to version 0.95.1.<br />
<br />
'''03/31/2009''' - Upgraded to the latest clamav (0.95.0). This package has not been extensively tested, so we're not having it show in qtp-newmodel or qtp-ami-up2date until the community has had a couple days to test it and report any bugs.<br />
<br />
'''03/08/2009''' - Changed the website around to make it easier for me to manage and to hopefully make important data easier to find.<br />
<br />
'''03/06/2009''' - Added a patch to djbdns to fix a security exploit where the cache could become poisoned. Documented and confirmed [http://securityandthe.net/2009/03/05/security-issue-in-djbdns-confirmed/ here].<br />
<br />
'''02/26/2009''' - Updated the current.txt file and moved the old versions of the packages.<br />
<br />
'''02/20/2009''' - Updated packages for new distros.<br />
<br />
'''12/11/2008''' - Updated Squirrelmail to 1.4.17 to resolve security vulnerability CVE-2008-2379.<br />
<br />
'''12/04/2008''' - Updated ClamAV 0.94.2 package.<br />
<br />
'''10/17/2008''' - Updated ClamAV 0.94.1 package.<br />
<br />
'''08/03/2008''' - Updated ClamAV 0.94 package.<br />
<br />
'''07/11/2008''' - Updated ClamAV, SpamAssassin, SquirrelMail packages<br />
<br />
'''07/06/2008''' - Updated ClamAV 0.93.1 package.<br />
<br />
'''04/19/2008''' - Updated ClamAV 0.93 package NOTE: be sure to remove prior versions of ClamAV before building this new one, otherwise it will cause a circular dependency.</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Change_LogsChange Logs2024-03-16T17:06:28Z<p>Ebroch: Created page with "====Project Change Log==== ====autorespond-toaster==== ====clamav-toaster==== ====control-panel-toaster==== ====courier-authlib-toaster==== ====courier-imap-toaster==== ====daemontools-toaster==== ====djbdns==== ====ezmlm-toaster==== ====isoqlog-toaster==== ====libdomainkeys-toaster==== ====maildrop-toaster==== ====qmailadmin-toaster==== ====qmailmrtg-toaster==== ====qmail-toaster==== ====ripmime-toaster====..."</p>
<hr />
<div>====[[Project Change Log]]====<br />
====[[autorespond-toaster]]====<br />
====[[clamav-toaster]]====<br />
====[[control-panel-toaster]]====<br />
====[[courier-authlib-toaster]]====<br />
====[[courier-imap-toaster]]====<br />
====[[daemontools-toaster]]====<br />
====[[djbdns]]====<br />
====[[ezmlm-toaster]]====<br />
====[[isoqlog-toaster]]====<br />
====[[libdomainkeys-toaster]]====<br />
====[[maildrop-toaster]]====<br />
====[[qmailadmin-toaster]]====<br />
====[[qmailmrtg-toaster]]====<br />
====[[qmail-toaster]]====<br />
====[[ripmime-toaster]]====<br />
====[[simscan-toaster]]====<br />
====[[spamassassin-toaster]]====<br />
====[[squirrelmail-toaster]]====<br />
====[[ucspi-tcp-toaster]]====<br />
====[[vpopmail-toaster]]====<br />
====[[vqadmin-toaster]]====<br />
====[[zlib]]====</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Webmail_ClientWebmail Client2024-03-16T17:01:59Z<p>Ebroch: Created page with "(This page is still underdevelopment) Below are lists of Webmail Client that can be use with QmailToaster == AfterLogic lite == http://www.afterlogic.com/products/webmail-lite == atmail == http://atmail.org/ == eGroupware == http://www.egroupware.org/ == Hastymail == http://www.hastymail.org/ == Horde == http://www.horde.org/ == Nutsmail == http://nutsmail.com == RoundCube == http://roundcube.net == Squirrelmail == http://squirrelmail.org/ == SquirrelOutlook ==..."</p>
<hr />
<div>(This page is still underdevelopment)<br />
Below are lists of Webmail Client that can be use with QmailToaster<br />
<br />
== AfterLogic lite ==<br />
http://www.afterlogic.com/products/webmail-lite<br />
<br />
== atmail ==<br />
http://atmail.org/<br />
<br />
== eGroupware ==<br />
http://www.egroupware.org/<br />
<br />
== Hastymail ==<br />
http://www.hastymail.org/<br />
<br />
== Horde ==<br />
http://www.horde.org/<br />
<br />
== Nutsmail ==<br />
http://nutsmail.com<br />
<br />
== RoundCube ==<br />
http://roundcube.net<br />
<br />
== Squirrelmail ==<br />
http://squirrelmail.org/<br />
<br />
== SquirrelOutlook ==<br />
http://sourceforge.net/projects/squirreloutlook/</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Squirrelmail_Global_Address_BookSquirrelmail Global Address Book2024-03-16T17:01:36Z<p>Ebroch: Created page with "From: http://www.mail-archive.com/qmailtoaster-list@qmailtoaster.com/msg14851.html Below are my way to provide Squirrelmail Global Address Book for my users. 1. create sqweb_gabook.sh and sqweb_gabook.php in one folder 2. chmod +x sqweb_gabook.sh 3. edit parameters on both files 4. run sqweb_gabook.sh for first time 5. edit squirrelmail config to load your newly created global address book. More info: http://www.squirrelmail.org/docs/admin/admin-7.html#ss7.5 6. to..."</p>
<hr />
<div>From: http://www.mail-archive.com/qmailtoaster-list@qmailtoaster.com/msg14851.html<br />
<br />
Below are my way to provide Squirrelmail Global Address Book for my users.<br />
<br />
1. create sqweb_gabook.sh and sqweb_gabook.php in one folder<br />
<br />
2. chmod +x sqweb_gabook.sh<br />
<br />
3. edit parameters on both files<br />
<br />
4. run sqweb_gabook.sh for first time<br />
<br />
5. edit squirrelmail config to load your newly created global address book. More info: http://www.squirrelmail.org/docs/admin/admin-7.html#ss7.5<br />
<br />
6. to provide latest global address book in your Webmail you may want run this script daily or weekly via crontab<br />
<br />
<br />
This scripts are far more than perfect but atleast it does it job to provide me a global address book for my company domain.<br />
<br />
<br />
#!/bin/bash<br />
# sqweb_gabook.sh<br />
# squirrelmail global address book updater<br />
#<br />
# PakOgah <pakogah@pala.bo-tak.info><br />
# ver 0.1 (2 Aug 2007)<br />
# - initial script<br />
# ver 0.3 (3 Aug 2007)<br />
# - add full path and test if php script exist<br />
# - add detail documentation<br />
# <br />
# need more enhancements<br />
# - use 2 script to create one global address book, if it were only 1 script it would be simpler<br />
# - these scripts only can generate one global address book for one domain<br />
# - and thus 1 global address book is configured with your Squirrelmail<br />
# so if your webmail support multidomain, the global address book didn't<br />
# - can't update dynamicly if there are changes in email account and/or milist<br />
# you have run it again via cron (weekly/daily)<br />
# - user which his email address listed can't update his info<br />
# (I am setup my squirrelmail with policy no one can change global address book)<br />
<br />
<br />
# variables section edited here<br />
# your domain<br />
DOMAIN="pala.bo-tak.info"<br />
# where this bash and php script reside<br />
SCRIPT_LOC="/root/scripts"<br />
MILISDIR="/home/vpopmail/domains/$DOMAIN"<br />
FILENAME=$DOMAIN"_gabook"<br />
GLOBAL_ABOOK="/var/lib/squirrelmail/$FILENAME"<br />
<br />
#===========================<br />
# process here<br />
#===========================<br />
echo "#Squirrelmail global address book updater..."<br />
rm -f $GLOBAL_ABOOK<br />
touch $GLOBAL_ABOOK<br />
<br />
# export email address <br />
# make sure sqweb_gabook.php is in same folder<br />
# there are some variable inside it please change them to suit your need<br />
if [ -e $SCRIPT_LOC/sqweb_gabook.php ]; then<br />
php $SCRIPT_LOC/sqweb_gabook.php<br />
fi<br />
<br />
# export milist<br />
CWD=`pwd`<br />
cd $MILISDIR<br />
for milisname in $(ls -1);<br />
do<br />
if [ -e $milisname/config ]; then<br />
echo "$milisname|$milisname|MailingList|[EMAIL PROTECTED]|" >> <br />
$GLOBAL_ABOOK<br />
fi<br />
done<br />
<br />
cd $CWD<br />
echo "Global Address for $DOMAIN is available at "$GLOBAL_ABOOK<br />
echo "Enter the fullpath using Squirrelmail config utility"<br />
echo "select 6. Address Books option and configure address book in 3. Global file address book"<br />
echo "More info: http://www.squirrelmail.org/docs/admin/admin-7.html#ss7.5";<br />
<br />
<br />
<br />
<br />
<br />
<?php<br />
/*<br />
# sqweb_gabook.php<br />
# squirrelmail global address book updater<br />
# this file is needed by sqweb-gabook.sh<br />
#<br />
# PakOgah <pakogah@pala.bo-tak.info><br />
# ver 0.1 (2 Aug 2007)<br />
# - initial script<br />
# ver 0.3 (3 Aug 2007)<br />
# - add full path and test if php script exist<br />
# - add detail documentation<br />
#<br />
# need more enhancements<br />
# - use 2 script to create one global address book, if it were only 1 script it would be simpler<br />
# - these scripts only can generate one global address book for one domain<br />
# - and thus 1 global address book is configured with your Squirrelmail<br />
# so if your webmail support multidomain, the global address book didn't<br />
# - can't update dynamicly if there are changes in email account and/or milist<br />
# you have run it again via cron (weekly/daily)<br />
# - user which his email address listed can't update his info<br />
# (I am setup my squirrelmail with policy no one can change global address book)<br />
*/<br />
// configuration <br />
// your domain name<br />
$domainname="pala.bo-tak.info";<br />
// your domain table name inside vpopmail database<br />
$tablename="pala_bo_tak_info";<br />
$username="vpopmail";<br />
$password="SsEeCcRrEeTt";<br />
$database="vpopmail";<br />
$hostname="localhost";<br />
$filename=$domainname."_gabook";<br />
$global_abook="/var/lib/squirrelmail/".$filename;<br />
<br />
// process<br />
$handle = fopen($global_abook, 'a');<br />
$conn = mysql_connect($hostname, $username, $password) or die ('Error <br />
connecting to mysql');<br />
mysql_select_db($database);<br />
<br />
$query="select pw_name,pw_gecos from $tablename";<br />
$result = mysql_query($query);<br />
<br />
while(list($email,$name)= mysql_fetch_row($result))<br />
{<br />
$data=$email."|".$name."||".$email."@".$domainname."|\n";<br />
fwrite($handle, $data);<br />
} <br />
mysql_close($conn);<br />
fclose($handle);<br />
?></div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Clickable_BannerClickable Banner2024-03-16T17:01:13Z<p>Ebroch: Created page with "* Login as root to your server * Go to Squirrelmail folder cd /usr/share/squirrelmail/src * Make a backup of the original login.php cp login.php login.php.org * Edit the file login.php vi login.php * Add the text right at the bottom of the file, after: <pre> do_hook('login_bottom'); ?> <div style="text-align: center;"><a h ref=" your_url " target="_blank"> <img height="60" width="468" alt="any text h..."</p>
<hr />
<div>* Login as root to your server<br />
* Go to Squirrelmail folder<br />
cd /usr/share/squirrelmail/src<br />
* Make a backup of the original login.php<br />
cp login.php login.php.org<br />
* Edit the file login.php<br />
vi login.php<br />
* Add the text right at the bottom of the file, after:<br />
<pre><br />
do_hook('login_bottom');<br />
?><br />
<br />
<br />
<div style="text-align: center;"><a h ref=" your_url " target="_blank"><br />
<img height="60" width="468" alt="any text here" src="../images/yourimage.png"></a></div><br />
</body></html><br />
</pre><br />
<br />
* Copy your image in "png" format to (using sftp or ant other means) /usr/share/squirrelmail/images<br />
<br />
* Check permissions, should be owned by root:root, and 0644 if not run these commands:<br />
<br />
cd /usr/share/squirrelmail/images<br />
chown root:root yourimage.png<br />
chmod 644 yourimage.png<br />
<br />
* Load up your webmail site, you should see your new clickable image.<br />
<br />
<br />
Notes:<br />
Remove space from html code<br />
<br />
Originally my image would NOT show up. To fix, I copied the default logo (sm_logo.png) to my PC, opened it in an image editor, select all, hit delete. I also opened my logo, did select all, copy, and paste it onto the now empty default squirrelmail logo.<br />
<br />
Saved as sm_logo2.png, copied back to /usr/share/squirrelmail/image, and set the correct logo name in the login.php file and Voila</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Resolving_apparent_login_failures_with_SMTP_and_POPResolving apparent login failures with SMTP and POP2024-03-16T17:00:44Z<p>Ebroch: Created page with "Following upgrades or initial installations, you may find that your mail client is unable to connect successfully to your SMTP submission port or to the POP3 port. Some mail clients will report this as a password error; others may simply report a generic problem. One possibility is that the 'vchkpw' daemon does not have enough memory to run. You can test this by hand-simulating a POP session with, for example: '''telnet yourhost.com pop3''' Trying 1.2...."</p>
<hr />
<div>Following upgrades or initial installations, you may find that your mail client is unable to connect successfully to your SMTP submission port or to the POP3 port. Some mail clients will report this as a password error; others may simply report a generic problem.<br />
<br />
One possibility is that the 'vchkpw' daemon does not have enough memory to run. You can test this by hand-simulating a POP session with, for example:<br />
<br />
'''telnet yourhost.com pop3'''<br />
<br />
Trying 1.2.3.4...<br />
<br />
Connected to yourhost.com.<br />
<br />
Escape character is '^]'.<br />
<br />
+OK <21223.1390353263@yourhost.com><br />
<br />
'''USER <yourlogin>'''<br />
<br />
+OK <br />
<br />
'''PASS <yourpass>'''<br />
<br />
(user input is shown in '''bold''').<br />
<br />
The server should respond at this point with '+OK'. If it responds:<br />
<br />
/home/vpopmail/bin/vchkpw: error while loading shared libraries: libresolv.so.2: failed to map segment from shared object: Cannot allocate memory<br />
-ERR authorization failed<br />
<br />
you have probably encountered a memory problem. To resolve this, do:<br />
<br />
vi /var/qmail/supervise/*/run<br />
<br />
Step through the files one by one, checking each one for a line that resembles:<br />
<br />
/usr/bin/softlimit -m 48000000<br />
<br />
In each such file, change the '48000000' to '64000000'. Then restart qmail with:<br />
<br />
qmailctl stop<br />
qmailctl start<br />
<br />
and try your POP session again. If it now succeeds, the problem is probably resolved. If not, try raising the limit again.</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=How_to_set_up_a_mail_list_so_that_you_can_email_ALL_of_your_domains_at_one_timeHow to set up a mail list so that you can email ALL of your domains at one time2024-03-16T16:59:26Z<p>Ebroch: Created page with "Have you ever wanted to email all the user accounts on all domains on your server at the SAME time (server downtime notifications, etc)? Now you can and the best part is that it is very simple to do! The first thing you need to do is to create a mailinglist on your default domain (does not have to be the default domain, however usually this is your domain anyway). I would suggest making the name of the list something obtuse (not easy to guess so as to prevent spam) and..."</p>
<hr />
<div>Have you ever wanted to email all the user accounts on all domains on your server at the SAME time (server downtime notifications, etc)? Now you can and the best part is that it is very simple to do!<br />
<br />
The first thing you need to do is to create a mailinglist on your default domain (does not have to be the default domain, however usually this is your domain anyway). I would suggest making the name of the list something obtuse (not easy to guess so as to prevent spam) and also set it so that only moderators can post (another spam stopping trick).<br />
<br />
Once you have set up your mailing list, copy the script below into a file called "list-create.sh". Put this file into your /etc/cron.daily directory <br />
<br />
# vi /etc/cron.daily/list-create.sh<br />
#!/bin/sh<br />
# script name: list-create.sh<br />
# function: delete member and re-subscribe existing email accounts on all domain<br />
# in your server into a mailing list for public announcement<br />
#<br />
# 06/15/2010 - Scott Hughes <scott@renshawauto.net><br />
# Initial creation of script to create an import text file of all<br />
# users on system and then import it into an already created<br />
# ezmlm mailing list.<br />
#<br />
# 04/16/2011 - Scott Hughes <scott@renshawauto.net><br />
# Added the complete removal of list subscribers before list<br />
# generation to take care of deleted accounts. Thanks to Pak Ogah<br />
# for the idea.<br />
#<br />
# 04/19/2011 - PakOgah <PakOgah@pala.bo-tak.info><br />
# Use variables for mailing list name<br />
<br />
# Name of your mailinglist<br />
mailinglist="mylist@mydomain.com"<br />
<br />
# Do not edit codes below:<br />
echo "All user mailing list generation..."<br />
<br />
# Separate domain and listname<br />
listname=${mailinglist%@*}<br />
domainname=${mailinglist#*@}<br />
<br />
# Deleting current subscribers from mailing list<br />
rm -f /home/vpopmail/domains/$domainname/$listname/subscribers/*<br />
<br />
# Generate mailing list import file<br />
#/home/vpopmail/bin/vpopbull -n -V > ~/alluserslist.txt<br />
<br />
# Import List into ezmlm mailing list<br />
~vpopmail/bin/vpopbull -n -V | ezmlm-sub ~vpopmail/domains/$domainname/$listname<br />
<br />
exit 0<br />
<br />
Then change the permissions so that it is executable:<br />
#chmod +x /etc/cron.daily/list-create.sh<br />
<br />
That's all you have to do. When the script runs it will first delete all the current subscribers and then re-create them from the domains and users on your server.<br />
<br />
Enjoy!</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=How_to_Setup_DKIM_with_Qmail_ToasterHow to Setup DKIM with Qmail Toaster2024-03-16T16:58:22Z<p>Ebroch: </p>
<hr />
<div>Source: [https://manuel.mausz.at/coding/qmail-dkim/ Manuel Mausz'] Perl script<br />
<br />
1. DKIM sign all email with global key<br />
<br />
'''Set up signing framework'''<br />
# yum -y install perl-XML-Simple perl-Mail-DKIM perl-XML-Parser<br />
# qmailctl stop<br />
# cd /var/qmail/bin<br />
# mv qmail-remote qmail-remote.orig<br />
<!--# wget -P /var/qmail/bin https://raw.githubusercontent.com/qmtoaster/dkim/master/qmail-remote--><br />
<!--# wget https://manuel.mausz.at/coding/qmail-dkim/qmail-dkim-0.3.pl--><br />
# wget https://raw.githubusercontent.com/qmtoaster/dkim/master/mail-dkim-0.3.pl<br />
# chmod 755 mail-dkim-0.3.pl && chown root:qmail mail-dkim-0.3.pl<br />
# ln -s mail-dkim-0.3.pl qmail-remote<br />
# mkdir /var/qmail/control/dkim<br />
# chown -R qmailr:qmail /var/qmail/control/dkim<br />
# cd /var/qmail/control/dkim<br />
# wget https://raw.githubusercontent.com/qmtoaster/dkim/master/signconf.xml<br />
# openssl genrsa -out global.key 2048 && chmod 644 global.key<br />
# openssl rsa -in global.key -pubout -out global.txt<br />
# perl -pi -e 's/-----BEGIN PUBLIC KEY-----/dkim1._domainkey IN TXT "k=rsa; p=/g; s/-----END PUBLIC KEY-----/"/g; s/\n//g' global.txt<br />
# qmailctl start<br />
# cat signconf.xml<span style="color:tomato"><br />
<dkimsign><br />
&lt;!-- per default sign all mails using dkim --&gt;<br />
<global algorithm="rsa-sha1" domain="/var/qmail/control/me" keyfile="/var/qmail/control/dkim/global.key" method="simple" selector="dkim1"><br />
<types id="dkim" /><br />
<types id="domainkey" method="nofws" /><br />
</global><br />
</dkimsign></span><br />
# cat global.txt<span style="color:tomato"><br />
dkim1._domainkey IN TXT "k=rsa; p=******************************"</span><br><br />
'''Create DNS TXT record from the above file 'public.txt''''<br />
Host Text<br />
dkim1._domainkey v=DKIM1; k=rsa; p=*************************<br><br />
'''Your DKIM global key setup is done. Send email to Yahoo or GMail, inspect header.'''<br />
<br />
2. DKIM sign domain with specific key<br />
# cd /var/qmail/control/dkim<br />
# openssl genrsa -out dom.com.key 2048 && chmod 644 dom.com.key<br />
# openssl rsa -in dom.com.key -pubout -out dom.com.txt<br />
# perl -pi -e 's/-----BEGIN PUBLIC KEY-----/dkim1._domainkey IN TXT "k=rsa; p=/g; s/-----END PUBLIC KEY-----/"/g; s/\n//g' dom.com.txt<br />
# cat dom.com.txt<span style="color:tomato"><br />
dkim1._domainkey IN TXT "k=rsa; p=******************************"</span><br><br />
'''Create DNS TXT record from the above file 'dom.com.txt''''<br />
Host Text<br />
dkim1._domainkey v=DKIM1; k=rsa; p=*************************<br><br />
# cat signconf.xml<span style="color:tomato"><br />
<dkimsign><br />
&lt;!-- per default sign all mails using dkim --&gt;<br />
<global algorithm="rsa-sha1" domain="/var/qmail/control/me" keyfile="/var/qmail/control/dkim/global.key" method="simple" selector="dkim1"><br />
<types id="dkim" /><br />
<types id="domainkey" method="nofws" /><br />
</global><span style="color:red"><strong><br><br />
&lt;!-- dkim sign dom.com --&gt;<br />
<dom.com domain="dom.com" keyfile="/var/qmail/control/dkim/dom.com.key" selector="dkim1"><br />
<types id="dkim" /><br />
<types id="domainkey" method="nofws" /><br />
</dom.com></span></strong><br><br />
</dkimsign></span><br />
3. DKIM no signing for domain<br />
<br />
# cd /var/qmail/control/dkim<br />
# cat signconf.xml<span style="color:tomato"><br />
<dkimsign><br />
&lt;!-- per default sign all mails using dkim --&gt;<br />
<global algorithm="rsa-sha1" domain="/var/qmail/control/me" keyfile="/var/qmail/control/dkim/global.key" method="simple" selector="dkim1"><br />
<types id="dkim" /><br />
<types id="domainkey" method="nofws" /><br />
</global><br><br />
&lt;!-- dkim sign dom.com --&gt;<br />
<dom.com domain="dom.com" keyfile="/var/qmail/control/dkim/dom.com.key" selector="dkim1"><br />
<types id="dkim" /><br />
<types id="domainkey" method="nofws" /><br />
</dom.com><br><span style="color:red"><strong><strong><br />
&lt;!-- no dkim signing nosigndom.com --&gt;<br />
<nosigndom.com /></span></strong><br><br />
</dkimsign></span><br />
<br />
4. DKIM verification (Spamassassin preferred):<br />
<br />
Assumes: <br />
a. 'QMAILQUEUE="/var/qmail/bin/simscan"' defined in /etc/tcprules.d/tcp.smtp <br />
b. /var/qmail/bin/qmail-queue is a link.<br />
c. 'export DKVERIFY=1' and '/usr/bin/softlimit -m 128000000' in /var/qmail/supervise/smtp/run<br />
# qmailctl stop<br />
# cd /var/qmail/bin<br />
# wget http://www.qmailtoaster.org/dkimverify.pl<br />
# wget http://www.qmailtoaster.org/qmail-queue.pl.sh<br />
# chown root:root dkimverify.pl<br />
# chown qmailq:qmail qmail-queue.pl.sh<br />
# chmod 755 dkimverify.pl<br />
# chmod 4777 qmail-queue.pl.sh<br />
# unlink qmail-queue<br />
# ln -s qmail-queue.pl.sh qmail-queue<br />
# qmailctl start<br />
Send email to user on the host<br />
Check email header dkim verification<br />
<br />
<br />
Notes: <br />
1) In order to test your settings, simply send an email to: check-auth@verifier.port25.com and/or check-auth2@verifier.port25.com<br />
with the suject of "test" (without the quotes) and "Just testing" in the body (also without quotes). It is best but not required<br />
to have a subject and body because this service will also show you how spamassassin rated your email. If you have a GMAIL/Yahoo<br />
email account sending to either or both accounts DKIM signatures could be verified.<br />
Click to test<br />
2) To test your DKIM signature wiith OpenDKIM's 'opendkim-testkey' utility install opendkim and run the utility:<br />
a) # yum install epel-release opendkim*<br />
b) # opendkim-testkey -vvvv -d otherdomain.com -k /var/qmail/control/dkim/otherdomain.com.key -s dkim1<br><br />
opendkim-testkey: using default configfile /etc/opendkim.conf<br />
opendkim-testkey: /var/qmail/control/dkim/otherdomain.com.key: WARNING: unsafe permissions<br />
opendkim-testkey: key loaded from /var/qmail/control/dkim/otherdomain.com.key<br />
opendkim-testkey: checking key 'dkim1._domainkey.otherdomain.com'<br />
opendkim-testkey: key OK<br><br />
3) Testing DKIM signatures sending from Roundcube webmail I found that plain text formatted email caused DKIM failure sending<br />
to port25.com and GMAIL recipients, but when sending the same email in Roundcube's html format the DKIM signature was verified<br />
and passed. The same email DKIM signature passed with Squirrelmail, Thunderbird, and OpenDKIM's 'opendkim-testkey' program. It <br />
seems that certain email clients will add or subtract characters in the email header causing DKIM to fail. This may be happening <br />
in Roundcube while other clients do not affect the email header adversely. I have a help request in the Roundcube user's list<br />
for this issue. Hopefully, this issue is merely a configuration setting, if not, that it is resolved soon.</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=TCP_Server_limits_configurationTCP Server limits configuration2024-03-16T16:56:26Z<p>Ebroch: Created page with "http://iserve01.i-serve.net/ucspi-tcp-toaster-0.88-1.3.4.src.rpm The variables are: (1) MAXLOAD maximum 1-minute load average * 100. For example, if you have line :allow,MAXLOAD="350" in your rules file from which you created .cdb, the connection will be accepted only if load average is below 3.50 (2) MAXCONNIP maximum connections from one IP address. tcpserver's -c flag defines maximum number of allowed connections, but it can be abused i..."</p>
<hr />
<div>http://iserve01.i-serve.net/ucspi-tcp-toaster-0.88-1.3.4.src.rpm<br />
<br />
The variables are:<br />
<br />
(1) MAXLOAD <br />
maximum 1-minute load average * 100. For example, if you have line<br />
:allow,MAXLOAD="350" <br />
in your rules file from which you created .cdb, the connection will be<br />
accepted only if load average is below 3.50<br />
<br />
<br />
(2) MAXCONNIP<br />
maximum connections from one IP address. tcpserver's -c flag defines<br />
maximum number of allowed connections, but it can be abused if<br />
just one host goes wild and eats all the connections - no other host<br />
would be able to connect then. If you created your .cdb with:<br />
:allow,MAXCONNIP="5"<br />
and run tcpserver -c 50, then each IP address would be able to have at <br />
most 5 concurrent connections, while there still could connect 50<br />
clients total.<br />
0 is valid value and means 'always reject'<br />
<br />
(3) MAXCONNC<br />
<br />
maximum connections from whole C-class (256 addresses). Extension of<br />
MAXCONNIP, as sometimes the problematic client has a whole farm of<br />
client machines with different IP addresses instead of just one IP<br />
address, and they all try to connect. It might have been more useful to<br />
be able to specify CIDR block than C-class, but I've decided to KISS.<br />
<br />
for example tcpserver -c 200, and .cdb with:<br />
:allow,MAXCONNC="15"<br />
will allow at most 15 host from any x.y.z.0/24 address block, while<br />
still allowing up to 200 total connections.<br />
0 is valid value and means 'always reject'<br />
<br />
(4) DIEMSG<br />
<br />
if set and one of the above limits is exceeded, this is the message <br />
to be sent to client (CRLF is always added to the text) before terminating<br />
connection. If unset, the connection simply terminates (after 1 sec delay) <br />
if limit is exceeded.<br />
<br />
For example:<br />
DIEMSG="421 example.com Service temporarily not available, closing <br />
transmission channel"<br />
<br />
Notes: <br />
<br />
- if a connection is dropped due to some of those variables set, it will be<br />
flagged (if you run tcpserver -v) with "LOAD:", "MAXCONNIP:" or<br />
"MAXCONNC:" at the end of the "tcpserver: deny" line. If that bothers you<br />
(eg. you have a strict log parsers), don't apply that chunk of the patch.<br />
<br />
<br />
When you make changes, please check that they work as expected. <br />
<br />
Examples (for tcprules created .cdb)<br />
(a) 192.168.:allow,MAXLOAD="1000"<br />
:allow,MAXCONNIP="3"<br />
<br />
this would allow any connection from your local LAN (192.168.*.*<br />
addresses) if system load is less than 10.00. non-LAN connections would<br />
be accepted only if clients from that IP address have not already opened<br />
more than 2 connections (as your connection would be last allowed -- 3rd)<br />
<br />
(b) 192.168.:allow<br />
5.6.7.8:allow,MAXCONNIP="3"<br />
1.2.:allow,MAXLOAD="500",MAXCONNIP="1",MAXCONNC="5"<br />
:allow,MAXLOAD="1000",MAXCONNIP="3",DIEMSG="421 example.com unavailable"<br />
<br />
if client connects from 192.168.*.* (ex: your LAN), it is allowed.<br />
if it connects from 5.6.7.8 (ex: little abusive customer of yours),<br />
it is allowed unless there are already 3active connections from 5.6.7.8<br />
to this service<br />
if it connects from 1.2.*.* (ex: some problematic networks which caused<br />
you grief in the past) it will connect only if load is less than 5.0,<br />
there is less than 5 active connections from whole C class<br />
(1.2.*.0/24), and if that specific IP address does not already have<br />
connection open.<br />
in all other cases, the client will be permitted to connect if load is<br />
less than 10.00 and client has 2 or less connections open. If load is<br />
higher than 10.00 or there are 3 or more connections open from this<br />
client, the message "421 example.com unavailable" will be returned to <br />
the client and connection terminated.</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Rsync_your_backupsRsync your backups2024-03-16T16:55:52Z<p>Ebroch: Created page with "== Rsync your backups == This is a quick guide on how to setup rsync to replicate your backups made using the backup script to other servers across the Internet. Why would you do this? Lets say that you're already making backups using the backup script. Now lets say the hard drive physically fails. How do you get all of your emails, accounts, domains, etc. back? You don't. Start rebuilding them by hand. Enter rsync. It's an easy way to allow you to copy/move your fil..."</p>
<hr />
<div>== Rsync your backups ==<br />
<br />
This is a quick guide on how to setup rsync to replicate your backups made using the backup script to other servers across the Internet. Why would you do this? Lets say that you're already making backups using the backup script. Now lets say the hard drive physically fails. How do you get all of your emails, accounts, domains, etc. back? You don't. Start rebuilding them by hand.<br />
<br />
<br />
Enter rsync. It's an easy way to allow you to copy/move your files across the Internet. In this example, we're going to do this over an SSH tunnel for security. There are other ways to do this, such as setting up NFS and a share to copy the archives to, so do your research and planning for what will provide you with the features you need.<br />
<br />
This example does '''not''' allow you to create a cluster system. The ''only'' thing it does is put a copy of your backup files on another machine so that in the event of a physical failure you can restore your system. This backup will not be an instantaneous copy of your system; it will only be a copy of the QMail-Toaster system at the time the backu script was run. Nothing more, nothing less. With that said, here we go:<br />
<br />
First thing we should do is log into the machine that we're going to send the archives to. In this example, we'll call the machine that QMail-Toaster is currently running on qt1.example.com, and the machine that we're sending the backup to as bak1.example.com. We're also going to assume that you will be using your root account on both machines; this is not the most secure method, so if you are ultra-paranoid you may want to search the Internet a little to see how to accomplish this with unprivileged accounts, or use a keychain daemon. The bulk of this example will still apply. So from qt1.example.com, execute this (assuming you have not changed your SSH ports):<br />
<br />
<pre>ssh bak1.example.com</pre><br />
<br />
If this is the first time this macine has logged into bak1.example.com, it should warn you that the fingerprint is not on file, and ask if you want to create it. Answer yes, and login with your password. You have now cached the fingerprint of the machine. Go ahead and type <pre>exit</pre> to log out of bak1.example.com and you should now be back in qt1.example.com. <br />
<br />
Next we're going to go ahead and create a RSA key to allow qt1.example.com to create SSH tunnels to bak1.example.com without having to use a password. Why? To create CRON jobs that allow you to copy your backup files to bak1.example.com without you having to actually monitor the process or be there.<br />
<br />
Okay, on qt1.example.com, type this to create the RSA key:<br />
<br />
<pre>ssh-keygen -t rsa</pre><br />
<br />
Just hit enter when it asks for a passphrase, or look at a keychain daemon.<br />
<br />
<br />
And now you can either view the contents of the file and paste it on bak1.example.com, or use scp to copy the file to bak1.example.com:<br />
<br />
<pre>scp ~/.ssh/id_rsa.pub bak1.example.com:</pre><br />
<br />
And enter your password again. Now we just need to move the RSA key into the proper location on bak1.example.com:<br />
<br />
<pre>ssh bak1.example.com</pre><br />
<br />
<pre>cat id_pub.rsa >> ~/.ssh/authorized_keys</pre><br />
<br />
<pre>chmod 600 ~/.ssh/authorized_keys</pre><br />
<br />
<pre>mkdir qmtbackup</pre><br />
<br />
And that should be it. <pre>exit</pre> out of bak1.example.com, and now try to SSH to it; it should not ask you for a password now. Whoopie! Okay, <pre>exit</pre> back out of bak1.example.com, and let's create a cron job to send your backup of QMail-Toaster to a folder called /root/qmtbackup on bak1.example.com created in the previous step. Type:<br />
<pre>crontab -e</pre><br />
<br />
This will put you in (default) vi for editing the cron tabs. Hit '''i''' to begin inserting text.<br />
<br />
<pre>0 1 * * * qmail-backup.sh</pre><br />
<br />
This tells your system to run the qmail-backup.sh script (qtp-backup.sh if installed via QTPlus) at 1:00am every night. Adjust to your taste; I try and run my during "slow" times. Depending on the size of your system (and mail) it can take anywhere from 3 minutes to run, to over 3 hours. You may want to run the command manually once to see how long it will take on your system. We're going to assume it take 15 minutes to run in this example. Since we have this vital information, let's go ahead and tell the system to send the backup to bak1.example.com, over a SSH tunnel and compress the data during transit to minimize bandwidth and time, as well as deleting any old copies of the backup:<br />
<br />
<pre>15 2 * * * rsync -az --delete -e ssh /backup/qmailbackup/ root@bak1.example.com:~/qmtbackup/</pre><br />
<br />
This crontab tells your system to copy the backup to bak1.example.com at 2:15am (I gave it an extra hour to complete the backup, just in case), and to remove any old copies. Okay, what it's actually doing is syncing the dirs between the two systems, so ''whatever'' is in /backup/qmailbackup on qmt1.example.com will mirror (sync) to ~/qmtbackup on bak1.example.com every night at 2:15am. If you put other files in /backup/qmailbackup on qt1.example.com, it will also get copied to ~/qmtbackup on bak1.example.com. Whatever gets deleted from /backup/qmailbackup on qt1.example.com will also be deleted from ~/qmtbackup on bak1.example.com. If you don't want to remove any files, just remove the ''--delete'' directive from the crontab. Okay, let's wrap it up. crontab -e normally uses vi as it's editor, so hit ''escape'' to get out of insert mode, then enter:<br />
<pre>:x</pre><br />
To write the file and exit out of vi. That's it. It will now do a backup of your mail server at 1am, and copy the backup file to your backup machine at 2:15am in the event that you need to restore from a backup.</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Recovering_from_a_blown_upgradeRecovering from a blown upgrade2024-03-16T16:55:26Z<p>Ebroch: Created page with "===Recovering from a blown upgrade=== A few weeks ago someone posted a message about how he did an upgrade on a production server and it stopped working. He was getting the message "451 qq write error or disk full (#4.3.0)" I had this same problem happen today. While I do not know what caused it, I suspect that not turning off monit had something to do with it, as monit would have tried to restart qmail every few minutes. Again, this is just a suspicion. The tangibl..."</p>
<hr />
<div>===Recovering from a blown upgrade===<br />
A few weeks ago someone posted a message about how he did an upgrade on a production server and it stopped working. He was getting the message<br />
"451 qq write error or disk full (#4.3.0)"<br />
<br />
I had this same problem happen today. While I do not know what caused it, I suspect that not turning off monit had something to do with it, as monit would have tried to restart qmail every few minutes. Again, this is just a suspicion.<br />
<br />
The tangible results of this upgrade failure was that many files and folders throughout the qmail installation ended up being owned by named:named.<br />
<br />
One thing you should know about my system is that /home/vpopmail is a softlink to /var/qmail. This allows me to have less directories to back up and to follow a scheme that I used on earlier (pre-toaster) setups. So when I refer to the /var/qmail/domains directory, it is likely to be /home/vpopmail/domains for you if you do not have your schema set up as do I,<br />
<br />
What needs to be done to revive the system is to do a lot of ownership changes and some mode changes.<br />
<br />
First I ran queue_repair.py -r. I do not know that it actually did a lot of good because things it said that it did, when I checked it did not, but I include it here for thoroughness.<br />
<br />
Here are the changes I had to make:<br />
<pre><br />
chown root:root /usr/sbin/httpd<br />
cd /var/qmail ; chown -R qmaill:qmail supervise<br />
cd /var/qmail/bin; chown root:qmail qmail-clean qmail-lspawn qmail-rspawn qmail-send qmail-smtpd<br />
cd /var/qmail/domains ; chown -R vpopmail:vchkpw *<br />
cd /var/qmail/etc ; chown vpopmail:vchkpw vpopmail.mysql*<br />
cd /var/log/qmail ; chown -R qmaill:qmail *<br />
cd /var/qmail/queue ; chown -R qmailq:qmail todo<br />
cd /var/qmail/queue/todo ; chmod 644 *<br />
</pre><br />
I have no idea of how apache (httpd) got changed, but it had monit sending me alerts, so that was what I had changed first.<br />
<br />
So that's my list of things that needed to be fixed to get a messed-up toaster upgrade back to working condition. Hopefully it will save someone the half hour of work it took me to figure it all out.<br />
<br />
==[[User Tips & Tricks]]==</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Rebuilding_cdb_filesRebuilding cdb files2024-03-16T16:55:04Z<p>Ebroch: Created page with "===Rebuilding cdb files=== I cannot seem to remember the commands to rebuild the cdbs, so I bashed one up to do it for me, automagically...put it in /etc/cron.hourly...this way all your cdbs are never more than an hour old. #!/bin/bash #rebuilds simcontrol.cdb /var/qmail/bin/simscanmk sleep 2 #rebuilds simversions.cdb /var/qmail/bin/simscanmk -g sleep 2 #rebuilds badloadertypes--rare-ok to comment out /var/qmail/bin/qmail-badloadertypes sleep 2 #rebuilds badm..."</p>
<hr />
<div>===Rebuilding cdb files===<br />
<br />
I cannot seem to remember the commands to rebuild the cdbs, so I bashed one up to do it for me, automagically...put it in /etc/cron.hourly...this way all your cdbs are never more than an hour old.<br />
#!/bin/bash<br />
#rebuilds simcontrol.cdb<br />
/var/qmail/bin/simscanmk<br />
sleep 2<br />
#rebuilds simversions.cdb<br />
/var/qmail/bin/simscanmk -g<br />
sleep 2<br />
#rebuilds badloadertypes--rare-ok to comment out<br />
/var/qmail/bin/qmail-badloadertypes<br />
sleep 2<br />
#rebuilds badmimetypes--rare-ok to comment out<br />
/var/qmail/bin/qmail-badmimetypes<br />
sleep 2<br />
#rebuilds tcp.smtp and reloads new configs<br />
qmailctl cdb<br />
#eof<br />
WORKSFORME. (don't forget to chmod +x the file you save that as, like I did)<br />
<br />
<br />
Note, as of QmailToaster v1.3,<br />
# qmailctl cdb<br />
does it all, so there's no more need for this.<br />
<br />
==[[User Tips & Tricks]]==</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=Qmail_Log_Backup_ScriptQmail Log Backup Script2024-03-16T16:54:30Z<p>Ebroch: Created page with "Qmail Log Backup Script to backup your qmail log files without increasing the value of logsize and logcount control files by tar.gz-ed to another folder Filename: /etc/cron.daily/backupqmaillog.sh so it can run everyday. #!/bin/bash # # qmaillog backup utility # version 0.1 # pakogah@pala.bo-tak.info # 4 Aug 2007 # this qmaillog backup utility by default will backup # today qmail's send and smtp log into /home/backuplog # and keep it for the next 7 days # enh..."</p>
<hr />
<div>Qmail Log Backup Script to backup your qmail log files without increasing the value of logsize and logcount control files by tar.gz-ed to another folder<br />
<br />
Filename: /etc/cron.daily/backupqmaillog.sh so it can run everyday.<br />
<br />
#!/bin/bash<br />
#<br />
# qmaillog backup utility<br />
# version 0.1<br />
# pakogah@pala.bo-tak.info<br />
# 4 Aug 2007<br />
# this qmaillog backup utility by default will backup<br />
# today qmail's send and smtp log into /home/backuplog<br />
# and keep it for the next 7 days<br />
# enhancement are always welcome<br />
<br />
<br />
# where your qmail log folder<br />
# QMAILLOG=/var/log/qmail<br />
QMAILLOG=/var/log/qmail<br />
# what log is going to backup ?<br />
# by default only smtp and send log only<br />
# possible log to backup are:<br />
# LOGS="authlib clamd imap4 imap4-ssl pop3 pop3-ssl send smtp spamd submission"<br />
LOGS="send smtp"<br />
# your backup destination<br />
# folder will be created automatically<br />
# BACKUP_DEST=/home/backuplog<br />
BACKUP_DEST=/home/backuplog<br />
# how long you will save the backup<br />
# BACKUP_AGE=7 # days<br />
BACKUP_AGE=7 # days<br />
<br />
# ============================<br />
# process<br />
# ============================<br />
DATE=`date +%Y%m%d`<br />
TMPFILE=/tmp/backuplist<br />
DAILY_AGE=1 # day<br />
DAILY_AGE_MINS=$[ $DAILY_AGE * 60 * 24 ]<br />
BACKUP_AGE_MINS=$[ $BACKUP_AGE * 60 * 24 ]<br />
<br />
for i in $LOGS;<br />
do<br />
mkdir -p $BACKUP_DEST/$i<br />
find $QMAILLOG/$i/* -cmin -$DAILY_AGE_MINS -exec ls -1 {} \; > $TMPFILE<br />
tar czf $BACKUP_DEST/$i/$i-$DATE.tar.gz -T $TMPFILE<br />
rm -f $TMPFILE<br />
find $BACKUP_DEST/$i/*.tar.gz -cmin +$BACKUP_AGE_MINS -exec rm -f {} \;<br />
done<br />
# ============================<br />
<br />
from http://www.mail-archive.com/qmailtoaster-list@qmailtoaster.com/msg14988.html</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=MySQL_-_Tuning_for_QMTMySQL - Tuning for QMT2024-03-16T16:54:00Z<p>Ebroch: Created page with "For those who aren't MySQL DBA's, here is a good start to tuning the QMT MySQL. Here is a guy that wrote a nice script for testing the current performance and makes recommendations for improvement. http://www.day32.com/MySQL and for additional tool you can use MySQLTuner from http://mysqltuner.com In order for the script to have a good snapshot of what is happening, your MySQL should be running for at least 48 hours. When I ran it, it recommended the following: long..."</p>
<hr />
<div>For those who aren't MySQL DBA's, here is a good start to tuning the QMT MySQL.<br />
<br />
Here is a guy that wrote a nice script for testing the<br />
current performance and makes recommendations for improvement.<br />
http://www.day32.com/MySQL<br />
and for additional tool you can use MySQLTuner from<br />
http://mysqltuner.com<br />
<br />
In order for the script to have a good snapshot of what is<br />
happening, your MySQL should be running for at least 48 hours.<br />
<br />
When I ran it, it recommended the following:<br />
long_query_time = 5 << WAS 10<br/><br />
query-cache-type = 1 << WAS NOT RUNNING<br/><br />
query-cache-size = 20M << JUST A STARTING POINT <br/><br />
table_cache = 100 << WAS RUNNING 64 AND FULL. There are 78<br />
tables in my database so I just picked 100.<br />
<br />
Also, Randy added:<br />
I recommend adding a query-cache-limit = 1M so that large, infrequent<br />
queries don't hog your cache. Also, make sure your key-buffer is set<br />
properly. Look at top or vmstat and see if you're using any swap<br />
space. If so, keep all your buffers small until you add more RAM. In<br />
fact, make sure your buffers total no more than 80% available RAM.<br />
Your problem could be that there's too much unnecessary disk<br />
thrashing.<br />
<br />
As Randy pointed out, tuning MySQL or just about anything in QMT is pretty much an art instead of a science. Because of hardware, installed apps, system load, etc differences these numbers might not work for you but they are a good start (Your mileage may vary!). You should test thoroughly.<br />
<br />
[[Randy's no brainer my.cnf for QMT]] <br/><br />
set-variable = max_connections=400 <br/><br />
set-variable = query_cache_type=1 <br/><br />
set-variable = query_cache_limit=1M <br/><br />
set-variable = query_cache_size=16M <br/><br />
set-variable = thread_cache_size=8 <br/><br />
log-slow-queries <br/><br />
long_query_time=2 <br/><br />
set-variable = key_buffer_size=512M <br/><br />
set-variable = table_cache=256 <br/><br />
set-variable = sort_buffer_size=4M <br/><br />
set-variable = read_buffer_size=1M <br/><br />
To do: ...MySQL5 my.cnf</div>Ebrochhttp://wiki.qmailtoaster.org:80/index.php?title=How_to_integrate_qms-analog_for_nicely_log_statsHow to integrate qms-analog for nicely log stats2024-03-16T16:53:33Z<p>Ebroch: Created page with "Tried a while ago qmailrocks and liked qms-analog option and sometimes would have saved me from long log debugging on qmailtoaster. now I have some time and decided to refresh qms-analog script to new qmail-scanner. '''BEWARE''' this patch might contain some errors please use it only in testing environment ! '''Install Dependencies''' cpan Time::HiRes DB_File Sys::Syslog MIME::Base64 yum install sharutils unzip perl-suidperl '''Download qmailanalog''' wget..."</p>
<hr />
<div>Tried a while ago qmailrocks and liked qms-analog option and sometimes would have saved me from long log debugging on qmailtoaster.<br />
now I have some time and decided to refresh qms-analog script to new qmail-scanner. <br />
<br />
'''BEWARE''' this patch might contain some errors please use it only in testing environment !<br />
<br />
'''Install Dependencies'''<br />
<br />
cpan Time::HiRes DB_File Sys::Syslog MIME::Base64<br />
yum install sharutils unzip perl-suidperl<br />
<br />
'''Download qmailanalog'''<br />
<br />
wget http://cr.yp.to/software/qmailanalog-0.70.tar.gz<br />
<br />
'''Download errno.patch'''<br />
<br />
wget http://www.qmailrocks.org/downloads/patches/0.70-errno.patch<br />
<br />
tar xzf qmailanalog-0.70.tar.gz<br />
cd qmailanalog-0.70<br />
patch < ../0.70-errno.patch<br />
make && make setup check<br />
cd ..<br />
<br />
'''Download qlogtools'''<br />
<br />
wget http://untroubled.org/qlogtools/qlogtools-3.1.tar.gz<br />
<br />
'''Download errno patch'''<br />
<br />
wget http://www.qmailrocks.org/downloads/patches/qlogtools_errno.patch<br />
tar xzf qlogtools-3.1.tar.gz<br />
cd qlogtools-3.1<br />
patch < ../qlogtools_errno.patch<br />
make<br />
mkdir /usr/local/man<br />
./installer<br />
cd ..<br />
'''Download and install qms-analog from http://www.qms-analog.teel.ws/'''<br />
<br />
tar xzf qms-analog-0.4.4.tar.gz<br />
cd qms-analog-0.4.4<br />
make all<br />
make install<br />
<br />
'''Edit qmailstats, replace qmail-send, qmail-smtpd qmail-pop3d with correct daemons and qmailscand with qscan, then copy it to qmail bin folder'''<br />
<br />
cp qmailstats /var/qmail/bin/qmailstats<br />
chmod 750 /var/qmail/bin/qmailstats<br />
<br />
'''Add an entry to crontab'''<br />
<br />
crontab -e<br />
0 3 * * * /var/qmail/bin/qmailstats 1>/dev/null 2>/dev/null<br />
<br />
'''Download qmail-scanner-2.01 with st patch'''<br />
<br />
wget http://toribio.apollinare.org/qmail-scanner/download/q-s-2.01st-20070204.tgz<br />
<br />
'''Copy this patch to some file, for ex qmail-scanner-2.01-st-qms.patch (sorry no link available)''' without '''START STOP'''<br />
<br />
'''START'''<br />
<br />
diff -Naur qmail-scanner-2.01st/configure qmail-scanner-2.01st-qms/configure<br />
--- qmail-scanner-2.01st/configure 2007-03-01 13:23:26.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/configure 2007-09-09 09:49:00.000000000 +0300<br />
@@ -10,8 +10,8 @@<br />
<br />
umask 007<br />
<br />
-OLD_LANG="$LANG" <br />
-LANG=C <br />
+OLD_LANG="$LANG"<br />
+LANG=C<br />
export LANG OLD_LANG<br />
<br />
JH_VERSION=`grep 'my $VERSION' qmail-scanner-queue.template|cut -d= -f2|sed -e 's/\"//g' -e 's/\;//g'`<br />
@@ -22,7 +22,7 @@<br />
export QS_VERSION<br />
<br />
echo<br />
-echo " Building Qmail-Scanner $QS_VERSION..."<br />
+echo " Building Qmail-Scanner-QMS $QS_VERSION..."<br />
<br />
if [ "`id |grep root`" = "" ]; then<br />
cat<<EOF<br />
@@ -95,9 +95,14 @@<br />
ARCHIVEDIR="archives"<br />
REDUNDANT="yes"<br />
FIX_MIME="2"<br />
-DISABLE_EOL_CHECK="0"<br />
+DISABLE_EOL_CHECK="1"<br />
DEBUG_LEVEL="0"<br />
+QMS_LOG="1"<br />
+QMS_MONITOR="no"<br />
+QMS_MON_ACCOUNTS=""<br />
+QMS_MON_DESTINATIONS=""<br />
FORCE_UNZIP="0"<br />
+QUARANTINE_PASSWORD_PROTECTED="0"<br />
DESCRIPTIVE_HEADERS="0"<br />
ADMIN_DESCRIPTION="System Anti-Virus Administrator"<br />
NOTIFY_ADDRESSES="psender,nmlvadm"<br />
@@ -119,6 +124,7 @@<br />
# st patch options<br />
QS_GROUP=""<br />
MINI_DEBUG="1"<br />
+ADMIN_FROMNAME="System Anti-Virus Administrator"<br />
DESCR_HEADERS_TEXT="X-Qmail-Scanner"<br />
SETTINGS_P_D="0"<br />
VIRUS_DELETE="0"<br />
@@ -181,10 +187,16 @@<br />
--max-scan-size) if [ "$2" != "" ]; then shift ; fi ; MAX_SCAN_SIZE="$1" ;;<br />
--lang) if [ "$2" != "" ]; then shift ; fi ; QSLANG="$1" ;;<br />
--debug) if [ "$2" != "" ] ; then shift ; fi ; DEBUG_LEVEL="$1" ;;<br />
+ --qms-log) if [ "$2" != "" ] ; then shift ; fi ; QMS_LOG="$1" ;;<br />
+ --qms-monitor) if [ "$2" != "" ] ; then shift ; fi ; QMS_MONITOR="$1" ;;<br />
+ --qms-monitor-accts) if [ "$2" != "" ] ; then shift ; fi ; QMS_MON_ACCOUNTS="$1" ;;<br />
+ --qms-monitor-dests) if [ "$2" != "" ] ; then shift ; fi ; QMS_MON_DESTINATIONS="$1" ;; <br />
--unzip)<br />
boolean_opt $2 $1 ; FORCE_UNZIP="$RET_VAL" ; if [ "`echo $2 | egrep -i '^\-'`" = "" ] ; then shift ; fi ;;<br />
--max-zip-size) if [ "$2" != "" -a "`echo $2|grep '\-'`" = "" -a "`echo $2|egrep '^[0-9]+$'`" != "" ] ; then shift ; fi ; MAX_ZIP_SIZE="$1" ;;<br />
--max-unpacked-files) if [ "$2" != "" -a "`echo $2|grep '\-'`" = "" -a "`echo $2|egrep '^[0-9]+$'`" != "" ] ; then shift ; fi ; MAX_UNPACKED_FILES="$1" ;;<br />
+ --block-password-protected)<br />
+ boolean_opt $2 $1 ; QUARANTINE_PASSWORD_PROTECTED="$RET_VAL" ; if [ "`echo $2 | egrep -i '^\-'`" = "" ] ; then shift ; fi ;;<br />
--add-dscr-hdrs) if [ "$2" != "" ] ; then shift ; fi ; DESCRIPTIVE_HEADERS="$1" ;;<br />
--scanners) if [ "$2" != "" -a "`echo $2|grep '\-'`" = "" ] ; then shift ; fi ; FIND_SCANNERS="$1" ;;<br />
--skip-text-msgs)<br />
@@ -358,6 +370,12 @@<br />
<br />
--max-unpacked-files <number-files> (defaults to 10000 files)<br />
<br />
+ --block-password-protected [yes|no] (defaults to "no")<br />
+ Setting this to "yes" allows you to quarantine any<br />
+ incoming zip files that are password protected.<br />
+ This is primarily to stop viruses such as Bagle which<br />
+ arrive within a password-protected zip file.<br />
+ <br />
--max-scan-size <number-bytes> (defaults to 100 Mbytes)<br />
Email messages (raw size) larger than this <br />
number (in bytes) will skip all AV and Spam <br />
@@ -380,7 +398,7 @@<br />
Defaults to "2" enables a bunch of extra MIME checks that<br />
have proven to be very useful.<br />
<br />
- --ignore-eol-check [yes|no] (defaults to "no")<br />
+ --ignore-eol-check [yes|no] (defaults to "yes")<br />
Making this "yes" stops Qmail-Scanner<br />
from treating "\r" or "\0" chars in the headers of <br />
MIME mail messages as being suspicious enough to quarantine<br />
@@ -411,6 +429,33 @@<br />
Logs only important information, mail headers, blocks,<br />
errors and elapsed time. If set to 2, it will log the<br />
parent pid (ppid) and the message size.<br />
+ --qms-log [yes|no] (default: yes)<br />
+ Whether or not event logging is turned on. On (yes)<br />
+ by default. Useful for qmail-scanner statistics.<br />
+ <br />
+ --qms-monitor [yes|no] (default: no)<br />
+ Whether or not qms-monitor Account Monitoring is turned on.<br />
+ <br />
+ --qms-monitor-accts ["acct1@domain2.com,acct2@domain3.com"]<br />
+ List of email accounts to be monitored.<br />
+ <br />
+ --qms-monitor-dests ["monitor.domain.com/acct1.domain2/Maildir/new,<br />
+ monitor.domain.com/acct2.domain3/Maildir/new"]<br />
+ List of destination paths for monitored email messages.<br />
+ Note 1: locations here will be saved underneath<br />
+ .../qmailscan/qms-monitor; a cron job can later<br />
+ copy from that location to an alternate email<br />
+ domain used for account monitoring.<br />
+ Note 2: each entry in this array corresponds to the email<br />
+ address in the same location of the<br />
+ qms-monitor-accts list above - i.e.,<br />
+ qms-monitor-accts[2] msgs get stored at<br />
+ qms-monitor-dests[2] - thus, ORDER DOES MATTER.<br />
+ Note 3: DO NOT include a leading "/" on these paths -<br />
+ they will typically be entries that ultimately<br />
+ belong in /home/vpopmail/domains - i.e., starting<br />
+ with the domain name.<br />
+ <br />
<br />
--batch [yes|no] (default: no = ask for confirm)<br />
Do not confirm configure information (mainly for scripting)<br />
@@ -1679,6 +1724,39 @@<br />
LOCAL_DOMAINS_ARRAY="`echo $LDA|sed 's/^,//g'`"<br />
fi<br />
<br />
+## qms-monitor<br />
+if [ "`echo $QMS_MONITOR|egrep -i '^no|^0'`" != "" ]; then<br />
+ QMS_MONITOR="0"<br />
+ echo "qms-monitor = no"<br />
+else<br />
+ QMS_MONITOR="1"<br />
+ echo "qms-monitor = yes"<br />
+<br />
+ # clean up the lists a bit<br />
+ QMS_MON_ACCOUNTS="`echo $QMS_MON_ACCOUNTS|sed -e 's/\"//g' -e 's/ //g'`"<br />
+ if [ "$QMS_MON_ACCOUNTS" ]; then<br />
+ LDA=""<br />
+ for dom in `echo $QMS_MON_ACCOUNTS|sed 's/,/ /g'`<br />
+ do<br />
+ dom="`echo $dom|sed -e 's/@/qms_at_sign/g'`"<br />
+ LDA="$LDA,'$dom'"<br />
+ done<br />
+ QMS_MON_ACCOUNTS="`echo $LDA|sed 's/^,//g'`"<br />
+ fi<br />
+<br />
+ QMS_MON_DESTINATIONS="`echo $QMS_MON_DESTINATIONS|sed -e 's/\"//g' -e 's/ //g'`"<br />
+ if [ "$QMS_MON_DESTINATIONS" ]; then<br />
+ LDA=""<br />
+ for dom in `echo $QMS_MON_DESTINATIONS|sed 's/,/ /g'`<br />
+ do<br />
+ LDA="$LDA,'$dom'"<br />
+ done<br />
+ QMS_MON_DESTINATIONS="`echo $LDA|sed 's/^,//g'`"<br />
+ fi<br />
+<br />
+fi<br />
+<br />
+<br />
if [ "$MIME_UNPACKER" = "reformime" ]; then<br />
if [ "$UNMIME_BINARY" = "" ]<br />
then<br />
@@ -1930,6 +2008,14 @@<br />
fi<br />
fi<br />
<br />
+if [ "`echo $QMS_LOG|egrep -i '^no|^0'`" != "" ]; then<br />
+ QMS_LOG="0"<br />
+ echo "qms-log=no"<br />
+else<br />
+ QMS_LOG="1"<br />
+ echo "qms-log=yes"<br />
+fi<br />
+<br />
if [ "$LOG_DETAILS" != "" ]; then<br />
echo "log-details=$LOG_DETAILS"<br />
fi<br />
@@ -1952,6 +2038,10 @@<br />
echo "redundant-scanning=$REDUNDANT" <br />
fi<br />
<br />
+if [ "$QUARANTINE_PASSWORD_PROTECTED" != "" ]; then<br />
+ echo "block-password-protected=$QUARANTINE_PASSWORD_PROTECTED"<br />
+fi<br />
+<br />
if [ "$ARCHIVEIT" != "0" ]; then<br />
if [ "$ARCHIVEIT" = "1" ]; then <br />
ASTRING="everything"<br />
@@ -2201,6 +2291,12 @@<br />
s?HOST_RELEASE?$HOST_RELEASE?g;<br />
s?HOST_HARDWARE?$HOST_HARDWARE?g;<br />
s?DEBUG_LEVEL?$DEBUG_LEVEL?g;<br />
+s?QMS_LOG?$QMS_LOG?g;<br />
+s?QMS_MONITOR?$QMS_MONITOR?g;<br />
+s?QMS_MON_ACCOUNTS?$QMS_MON_ACCOUNTS?g;<br />
+s?QMS_MON_DESTINATIONS?$QMS_MON_DESTINATIONS?g;<br />
+s?QUARANTINE_PASSWORD_PROTECTED?$QUARANTINE_PASSWORD_PROTECTED?g;<br />
+s?ADMIN_FROMNAME?$ADMIN_FROMNAME?g;<br />
s?DESCRIPTIVE_HEADERS?$DESCRIPTIVE_HEADERS?g;<br />
s?CMDLINE?$CMDLINE?g;<br />
s?PERL5?$PERL5?g;<br />
@@ -2309,8 +2405,10 @@<br />
s?SA_DEBUG?$SA_DEBUG?g;<br />
s?SA_HDR_REPORT?$SA_HDR_REPORT?g;<br />
s?SPAMD_SOCKET?$SPAMD_SOCKET?g;" qmail-scanner-queue.template > qmail-scanner-queue.pl-1<br />
-perl -pe 's/%%/\$/g' qmail-scanner-queue.pl-1 > qmail-scanner-queue.pl<br />
+perl -pe 's/%%/\$/g' qmail-scanner-queue.pl-1 > qmail-scanner-queue.pl-2<br />
rm -f qmail-scanner-queue.pl-1<br />
+perl -pe 's/qms_at_sign/@/g' qmail-scanner-queue.pl-2 > qmail-scanner-queue.pl<br />
+rm -f qmail-scanner-queue.pl-2<br />
<br />
cat sub-attachments.pl >> qmail-scanner-queue.pl<br />
<br />
diff -Naur qmail-scanner-2.01st/qmail-scanner-queue.pl qmail-scanner-2.01st-qms/qmail-scanner-queue.pl<br />
--- qmail-scanner-2.01st/qmail-scanner-queue.pl 1970-01-01 02:00:00.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/qmail-scanner-queue.pl 2007-09-09 09:31:33.000000000 +0300<br />
@@ -0,0 +1,3982 @@<br />
+#!/usr/bin/perl -T<br />
+#<br />
+# File: qmail-scanner-queue.pl<br />
+# Version: 2.01 - st - patch - 20070204<br />
+#<br />
+# Author: Jason L. Haar <jhaar - users.sourceforge.net><br />
+# <br />
+# Patch by: Salvatore Toribio <toribio - pusc.it><br />
+#<br />
+# Patched for Event Logging by: Mark S. Teel <mteel@users.sourceforge.net><br />
+# Version: 1.22 - patched: st-qms - 20040530<br />
+#<br />
+# Patched for Account Monitoring by Mark S. Teel <mteel@users.sourceforge.net><br />
+# Version: 1.22 - patched: st-qms-monitor - 20040919<br />
+#<br />
+# Patched for Version 1.24 and merge of qms-monitor functions<br />
+# by Mark S. Teel <mteel@users.sourceforge.net><br />
+# Version: 1.24 - patched: st-qms - 20041102<br />
+#<br />
+# Patched for Version 1.25<br />
+# by Mark S. Teel <mteel@users.sourceforge.net><br />
+# Version: 1.25 - patched: st-qms - 20050618<br />
+#<br />
+# See the file README-st-patch for information about the patch<br />
+# This version deletes/rejects spam based in Chris Hine's patch for v1.16<br />
+#<br />
+# Each user could has his own scanners and sa_settings.<br />
+# <br />
+# This file was auto-generated by:<br />
+#<br />
+# ./configure --qs-user qscand --admin root --domain mail.netech.ro --admin-description "System Anti-Virus Administrator" --notify psender,nmlvadm --local-domains mail.netech.ro --silent-viruses auto --virus-to-delete 0 --skip-text-msgs 1 --lang en_GB --debug 0 --minidebug 1 --add-dscr-hdrs 0 --dscr-hdrs-text "X-Qmail-Scanner" --normalize yes --archive 0 --settings-per-domain 0 --max-scan-size 100000000 --unzip 0 --max-zip-size 1000000000 --max-unpacked-files 10000 --redundant 0 --log-details syslog --log-crypto 0 --fix-mime 2 --ignore-eol-check 1 --sa-delta 0 --sa-alt 0 --sa-debug 0 --sa-report 0 --sa-quarantine 0 --sa-delete 0 --sa-reject 0 --scanners "auto" --install 1<br />
+# <br />
+# Description: This is a replacement/add-on for Qmail 1.0.3's qmail-queue.<br />
+# It can call several blocking programs - such as virus scanners - on every <br />
+# SMTP-received Email message, checking for viruses and blocked filenames, <br />
+# only allowing the message to continue if it passes the tests.<br />
+#<br />
+# Copyright (C) 1999,2000,2001-2006 the people mentioned above<br />
+#<br />
+# This program is free software; you can redistribute it and/or modify<br />
+# it under the terms of the GNU General Public License as published by<br />
+# the Free Software Foundation; either version 1, or (at your option)<br />
+# any later version. See <URL:http://www.gnu.org/copyleft/gpl.html><br />
+# for a copy.<br />
+# <br />
+# This program is distributed in the hope that it will be useful,<br />
+# but WITHOUT ANY WARRANTY; without even the implied warranty of<br />
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br />
+# GNU General Public License for more details.<br />
+#<br />
+# The software is provided as is. Please bear in mind that we have <br />
+# done this in my spare time. While it is as accurate as we could <br />
+# make it there is a reasonable chance that there are mistakes <br />
+# somewhere in here. If you email me and tell me about them, I will <br />
+# be happy to fix them but I can't take responsibility for your system. <br />
+# Basically use this at your own risk. <br />
+#<br />
+#####################################################################<br />
+<br />
+#####################################################################<br />
+##<br />
+## Required Packages<br />
+##<br />
+## Qmail-1.03<br />
+## Perl 5.005_03+<br />
+## Maildrop-0.73<br />
+## Bruce Guenter's QMAILQUEUE patch <URL:http://www.qmail.org/qmailqueue-patch><br />
+## Perl module Time::HiRes and DB_File<br />
+##<br />
+##<br />
+## So-far tested Virus scanners:<br />
+## Trend's Virus scanner for Linux<br />
+## MacAfee's (NAI's) virus scanner for Linux<br />
+## Sophos's virus scanner for Linux<br />
+## H+BEDV's antivir scanner for Linux<br />
+## F-Secure's fsav scanner for Linux<br />
+## P-Prot for Linux<br />
+## Sophie (daemonized Sophos scanner)<br />
+## Trophie (daemonized Trend scanner)<br />
+## ...and more - see README for full list<br />
+## <br />
+#####################################################################<br />
+<br />
+#####################################################################<br />
+##<br />
+## Site-specific config<br />
+##<br />
+#####################################################################<br />
+<br />
+<br />
+delete @ENV{qw(IFS CDPATH ENV BASH_ENV QMAILMFTFILE QMAILINJECT)};<br />
+<br />
+use strict 'vars', 'subs';<br />
+<br />
+#Set locale to "C" (English). That way any string checks on forked apps <br />
+#will tend to be in English - simplifying/standardizing regex matches<br />
+my $orig_locale=$ENV{'LC_ALL'};<br />
+$ENV{'LC_ALL'}= $ENV{'LANG'} = $ENV{'LANGUAGE'} = 'C';<br />
+POSIX::setlocale(&POSIX::LC_ALL,'C');<br />
+<br />
+use Sys::Syslog qw(:DEFAULT setlogsock);<br />
+setlogsock('unix');<br />
+<br />
+my $VERSION="2.01";<br />
+my $st_version="20070204";<br />
+$VERSION.='st';<br />
+<br />
+#Mail header to add to each scanned message to report stuff in...<br />
+#Default is to not generate them ($descriptive_hdrs = 0) - as that<br />
+#info is also in the Received: headers...<br />
+my $descriptive_hdrs=0;<br />
+my $V_HEADER="X-Qmail-Scanner";<br />
+my($qsmsgid);<br />
+$qsmsgid=tolower("$V_HEADER-message-id");<br />
+<br />
+my($qscan_account)='qscand';<br />
+<br />
+#From: line information used when making reports<br />
+my $V_FROM='root@mail.netech.ro';<br />
+my $V_FROMNAME='System Anti-Virus Administrator';<br />
+<br />
+# Address carbon-copied on any virus reports<br />
+my $QUARANTINE_CC='root@mail.netech.ro';<br />
+<br />
+#Array of local domains that are checked against for<br />
+#deciding whether or not to send recipient alerts to<br />
+my @local_domains_array=('mail.netech.ro');<br />
+<br />
+# qms: save local domains list string<br />
+my $local_domains_string="'mail.netech.ro'";<br />
+<br />
+<br />
+######## qms-monitor: selective account monitoring/archiving<br />
+###<br />
+### Description:<br />
+### 1) qms-monitor will archive ALL email msgs SENT OR RECEIVED for<br />
+### any email address listed below<br />
+### 2) Messages are archived to $qms_monitor_home - they can be left<br />
+### there for manual examination, or a cron script can be run periodically<br />
+### to move them into a "monitor" email domain so that the mail can be<br />
+### partitioned into individual monitor domain accounts and read with<br />
+### any email client<br />
+########<br />
+<br />
+my $qms_monitor_enabled='0';<br />
+<br />
+### qms_monitor_array: add email addresses of local domains to be monitored<br />
+my @qms_monitor_array=();<br />
+<br />
+### qms_monitor_dest_array: add destination for email message copies<br />
+# Note 1: locations here will be saved underneath $qms_monitor_home;<br />
+# a cron job can later copy from that location to an alternate<br />
+# email domain used for account monitoring.<br />
+# Note 2: each entry in this array corresponds to the email address in the<br />
+# same location of the @qms_monitor_array above - i.e.,<br />
+# @qms_monitor_array[2] msgs get stored at<br />
+# @qms_monitor_dest_array[2] - thus, ORDER DOES MATTER.<br />
+# Note 3: DO NOT include a leading "/" on these paths - they will typically<br />
+# be entries that ultimately belong in /home/vpopmail/domains -<br />
+# i.e., starting with the domain name.<br />
+###<br />
+my @qms_monitor_dest_array=();<br />
+<br />
+######## qms-monitor BLOCK END<br />
+<br />
+# Array of virus that we don't want to inform the sender of.<br />
+my @silent_viruses_array=('klez','bugbear','hybris','yaha','braid','nimda','tanatos','sobig','winevar','palyh','fizzer','gibe','cailont','lovelorn','swen','dumaru','sober','hawawi','hawaii','holar-i','mimail','poffer','bagle','worm.galil','mydoom','worm.sco','tanx','novarg','@mm','cissy','cissi','qizy','bugler','dloade','netsky','spam');<br />
+<br />
+# st: Virus that will be deleted without notifying anyone,<br />
+# you can add other viruses in the form "virus1|virus2|virus3".<br />
+# Most of the viruses in the 'silent_viruses_array' could be<br />
+# added to this list safely.<br />
+# i.e. "mydoom|worm.sco|novarg|tanx|bagle|netsky|somefool|roca|agobot|dumaru|sober|lovgate|klez|rox|zafi|(PIF|SCR|CPL) files|mybot|mabutu"<br />
+my $virus_to_delete="";<br />
+<br />
+#Array of virtual headers used within perlscanner <br />
+my @virtualheaders_array=("MAILFROM","RCPTTO","REMOTEIPADDR","ZIPPASSWORDPROTECTED","ISSENSITIVEANDNOCRYPTO","CRYPTODETAILS","FILELENGTHTOOLONG","FILEDOUBLEBARRELED","FILECLSID");<br />
+<br />
+#Addresses that should be alerted of any quarantined Email<br />
+my $NOTIFY_ADDRS='psender,nmlvadm';<br />
+<br />
+#Try to fix bad MIME messages before passing to MIME unpacker<br />
+my $BAD_MIME_CHECKS='2';<br />
+<br />
+#Block password protected zip files<br />
+#my $BLOCK_PASSWORD_PROTECTED_ARCHIVES='0';<br />
+<br />
+#Disable just the EOL char check instead of all of BAD_MIME_CHECKS<br />
+my $IGNORE_EOL_CHECK='1';<br />
+<br />
+# The full path to qmail programs we'll need.<br />
+my $qmailinject = '/var/qmail/bin/qmail-inject';<br />
+my $qmailqueue = '/var/qmail/bin/qmail-queue';<br />
+<br />
+# What directory to use for storing temporary files.<br />
+my $scandir = '/var/spool/qscan';<br />
+<br />
+#Where the Q-S configs are<br />
+my $configdir = '/var/spool/qscan';<br />
+<br />
+#Where the Q-S logs live<br />
+my $logdir = '/var/spool/qscan';<br />
+<br />
+#What maildir folder to store working files in<br />
+my $wmaildir='working';<br />
+<br />
+#What maildir folder to store virus-infected msgs in<br />
+my $vmaildir='viruses';<br />
+<br />
+#What maildir folder to store policy-blocked msgs in<br />
+my $pmaildir='policy';<br />
+<br />
+#What maildir folder to store high-scoring SPAM in (instead of passing it on)<br />
+#NOTE: this only gets used if 0 set <br />
+# st: see below '$smaildir_site'<br />
+#my $smaildir='spam';<br />
+<br />
+#What maildir folder to archive received Email in instead of deleting<br />
+my $archiveit='0';<br />
+my $archivedir='archives';<br />
+<br />
+#Name of file in $scandir where debugging output goes<br />
+my $debuglog="qmail-queue.log";<br />
+<br />
+#Name of file where quarantine reports go (for long-term storage)<br />
+my $quarantinelog="quarantine.log";<br />
+<br />
+# qms: Name of file where usable logs for analysis are written<br />
+my $eventlog="qms-events.log";<br />
+<br />
+#Generate nice random filename<br />
+my ($sysname, $hostname, $release, $version, $machine) = uname();<br />
+#my $hostname='mail.netech.ro'; #could get via call I suppose...<br />
+<br />
+#If you trust the virus scanners handling of mbox format itself<br />
+#you may want to let it have a go at the "raw" message, and original<br />
+#zip files if present<br />
+my $redundant_scanning='0';<br />
+<br />
+#If you want to log via file/syslog information of all Email<br />
+# that passes through your system (from/to/subj/size/attachments)<br />
+my $log_details="syslog";<br />
+<br />
+#If you'd like Q-S to report which messages are PGP or S/MIME,<br />
+#turn this on<br />
+my $log_crypto="0";<br />
+<br />
+# qms-monitor - the root for temporary storage<br />
+my $qms_monitor_home = "$scandir/qms-monitor";<br />
+<br />
+#Max size of message allowed to be scanned - 100Mbytes by default <br />
+#DO NOT SET LOWER THAN 10Mbytes!!!!!<br />
+my $MAX_SCAN_SIZE=100000000;<br />
+<br />
+#bypass all AV/Spam scanning - but still do perlscan checks<br />
+my $SKIP_SCANNING=0;<br />
+<br />
+# st: If $sa_subject is defined and fast_spamassassin mode is selected,<br />
+# a tag will be added to the subject indicating how the message is to<br />
+# be considered as spam, in this way:<br />
+# LOW: required_hits < score < required_hits + sa_delta<br />
+# MEDIUM: required_hits + sa_delta < score < required_hits + 2 * sa_delta<br />
+# HIGH: required_hits + 2 * sa_delta < score<br />
+# Be aware, 2*sa_delta must be lower than sa_quarantine.<br />
+# 'required_hits' is the value set in the SpamAssassin configuration file.<br />
+my $sa_delta_site='0';<br />
+<br />
+# st: Spam messages with a score higher than<br />
+# (required_hits + sa_quarantine) should be quarantined.<br />
+# Only relevant if SpamAssassin is used.<br />
+# Score of 0 means deliver all messages. Defaults to 0.<br />
+my $sa_quarantine_site='0';<br />
+<br />
+# st: Some people wants to quarantine spam in a different<br />
+# maildir folder than viruses, maybe to run sa-learn.<br />
+# The default is:<br />
+# my $smaildir_site='spam'; <br />
+# You can set it per user/domain in the file 'settings_per_domain.txt'<br />
+# WARNING: if $smaildir it is not in the same 'file system' (partition)<br />
+# than $wmaildir, you have to change the routine 'sub email_quarantine_report'<br />
+# you will find the code commented in that routine.<br />
+# (in the official version 2.00 this setting has been added)<br />
+my $smaildir_site='spam';<br />
+<br />
+# st: address to send a copy of the mails 'quarantined'<br />
+# as spam for admin puropose (I thought), almost unmodifyed.<br />
+# Enable $sa_fwd_verbose if you want the X-Spam headers in<br />
+# the forwarded message.<br />
+my $sa_forward_site='';<br />
+my $sa_fwd_verbose_site='0';<br />
+<br />
+# st: Spam messages with a score higher than<br />
+# (required_hits + sa_delete) should be deleted (or rejected).<br />
+# Only relevant if SpamAssassin is used. Score of 0<br />
+# means deliver all messages. Defaults to 0.<br />
+# If sa-quarantine is set, sa-delete must be greater.<br />
+my $sa_delete_site='0';<br />
+<br />
+# st: If you enable sa-reject and sa-delete is properly set,<br />
+# messages with a score higher than (required_hits + sa_delete)<br />
+# will be rejected before the smtp session is closed.<br />
+# Otherwise they are just dropped silently. (1/0)<br />
+my $sa_reject_site='0';<br />
+<br />
+# st: Use the alternative subroutine for spamassassin, it runs<br />
+# ALWAYS in *fast_spamassassin* mode and doesn't pass the '-u' option<br />
+# to spamc. So if you want to run in *verbose_spamassasin* mode or you<br />
+# want to use the sql per user preferences for spamassassin, you have<br />
+# to disable this option and run the standard spamassassin routine.<br />
+# It also allows to log the spamassassin report. (1/0)<br />
+my $sa_alt='0';<br />
+<br />
+# st: If sa_alt is enabled an you enable this option, you will<br />
+# have a beautiful log with the tests and the scores of<br />
+# spamassassin in the file qmail-queue.log, and you<br />
+# can add the X-Spam-Report header enabling the<br />
+# option below. (1/0)<br />
+my $sa_debug='0';<br />
+<br />
+# st: If sa_alt and sa_debug are enabled, *qmail-scanner* will<br />
+# add the X-Spam-Report header to the messages if you<br />
+# enable this option. (1/0)<br />
+my $sa_hdr_report_site='0';<br />
+<br />
+# st: Enable this option to do not pass to spamassassin messages<br />
+# from MAILER-DAEMON, see READMEpatched for details. (1/0)<br />
+my $SA_SKIP_MD='0';<br />
+<br />
+##############################################<br />
+# st: SETTINGS PER DOMAIN<br />
+##############################################<br />
+<br />
+# st: Enable or diasable scanner per domain (1/0)<br />
+my $settings_pd='0';<br />
+<br />
+# Array of virus scanners used must point to subroutines<br />
+my @scanner_array=();<br />
+<br />
+# st: @scanners_installed is the array with all scanners installed<br />
+# in the computer, if you disable $settings_pd qmail-scanner will fall to<br />
+# this array. Don't modify it unless you really know what you do.<br />
+my @scanners_installed=("clamdscan_scanner","spamassassin","perlscan_scanner");<br />
+<br />
+# st: @scanners_default if $settings_pd is enabled qmail-scanner will<br />
+# use this array for the users/domains that don't have a custom<br />
+# scanner_array set in the $settings_per_domain.txt file.<br />
+# You can set it to "none" to skip all the scanners, even perlscan.<br />
+# If you want to skip the scanners only for a particular user/domain<br />
+# set his scanners list to "none" in the $settings_per_domain.txt file.<br />
+my @scanners_default=("clamdscan_scanner","spamassassin","perlscan_scanner");<br />
+<br />
+# st: DB file (without extension) where per domain/user scanners<br />
+# are saved, edit $settings_per_domain.txt and run<br />
+# "qmail-scanner-queue.pl -p" to generate $settings_per_domain.db<br />
+my $settings_per_domain="$scandir/settings_per_domain";<br />
+<br />
+# st: if spamassassin has sql user settings, then run spamassassin<br />
+# per each recipient. Again verbose_spamassassin is a pain, so sa_alt will<br />
+# be run after the first recipient. (1/0)<br />
+my $sa_sql='0';<br />
+<br />
+# The following variable MUST NOT be modified, qmail-scanner will set<br />
+# them by its own for each recipient.<br />
+my $domain_returnpath='';<br />
+my $domain_one_recip='';<br />
+my $sa_rcpt='0';<br />
+my (%found_event);<br />
+#<br />
+my $sa_subject='';<br />
+my $sa_quarantine='';<br />
+my $sa_delta='';<br />
+my $sa_delete='';<br />
+my $sa_reject='';<br />
+my $sa_forward='';<br />
+my $sa_fwd_verbose='';<br />
+my $sa_hdr_report='';<br />
+my $smaildir='';<br />
+<br />
+<br />
+##############################################<br />
+<br />
+#Full path to file in which virus-scanner versioning info is kept<br />
+my $versionfile="$logdir/qmail-scanner-queue-version.txt";<br />
+<br />
+#DB file (without extension) where bad filenames are kept.<br />
+# You edit $db_filename.txt, and "qmail-scanner-queue.pl -g" generates $db_filename.db<br />
+my $db_filename="$configdir/quarantine-events";<br />
+<br />
+# st: configurable in st-patch<br />
+# This rule exists but is never <br />
+# expected to trigger normally (defaults 10,000, is stupidly high). <br />
+my $MAX_NUM_UNPACKED_FILES='10000';<br />
+<br />
+#What locale is used on this system<br />
+#$sys_locale="LOCALE";<br />
+<br />
+#Full paths to binaries used within this script follow - small performance<br />
+#improvement :-)<br />
+<br />
+<br />
+my $mimeunpacker_binary='/usr/bin/reformime ';<br />
+my $unzip_binary='/usr/bin/unzip';<br />
+my $unzip_options='-Pxx3160615524xx';<br />
+my $max_zip_size='1000000000';<br />
+my $tnef_binary='';<br />
+my $rm_binary='/bin/rm';<br />
+my $grep_binary='/bin/grep';<br />
+my $find_binary='/usr/bin/find';<br />
+my $uudecode_binary='/usr/bin/uudecode';<br />
+my $uudecode_pipe='-o -';<br />
+<br />
+<br />
+my $uvscan_binary='';<br />
+my $csav_binary='';<br />
+my $nod32_binary='';<br />
+my $nod32upd_binary='';<br />
+my $sweep_binary='';<br />
+my $sophie_binary='';<br />
+my $trophie_binary='';<br />
+my $iscan_binary='';<br />
+my $hbedv_binary='';<br />
+my $hbedv_options='';<br />
+my $avp_binary='';<br />
+my $avpdaemon_binary='';<br />
+my $fprot_binary='';<br />
+my $fsecure_binary='';<br />
+my $inocucmd_binary='';<br />
+my $ravlin_binary='';<br />
+my $vexira_binary='';<br />
+my $bitdefender_binary='';<br />
+my $clamscan_binary='/usr/bin/clamscan';<br />
+my $clamscan_options="-r -m --unzip --unrar --unzoo --lha --disable-summary --max-recursion=10 --max-space=100000";<br />
+my $clamdscan_binary='/usr/bin/clamdscan';<br />
+my $clamdscan_options="--no-summary";<br />
+<br />
+# st: I have returned to my own way to set the (1.25st)<br />
+my $spamc_binary='/usr/bin/spamc -t 30';<br />
+<br />
+# st: whether or not to run spamassassin in fast or verbose mod<br />
+# remember that the routine sa_alt always set sa_fast to 1, by her own.<br />
+# Please run in fast mode, you can break the verbose mode with your personal<br />
+# local.cf, so better run in fast mode (If you like SA REPORT read the docs).<br />
+#my $spamc_options='SPAMC_OPTIONS';<br />
+my $sa_fast='1';<br />
+<br />
+my $sa_subject_site=""; # st: if fast_spamassassin mode is selected<br />
+my $spamassassin_binary='/usr/bin/spamassassin ';<br />
+<br />
+# st: If somebody is using spamassassin with unix socket...<br />
+my $spamd_socket='';<br />
+$spamc_binary.=" -U $spamd_socket" if ($spamd_socket ne "");<br />
+<br />
+my ($sa_comment,$sa_level);<br />
+my $sa_symbol='+';<br />
+my ($tag_score,$tag_sa_score);<br />
+my $SNEAKY_WINDOWS_EXTENSIONS="exe|w[pm][szd]|vcf|nws|cmd|bat|pif|sc[rt]|dll|ocx|do[ct]|xl[swt]|p[po]t|pps|vb[se]?|hta|p[lm]|sh[bs]|hlp|chm|eml|ws[cfh]|ad[ep]|jse?|md[abew]|ms[ip]|reg|as[dfx]|cil|cpl";<br />
+my $VALID_WINDOWS_EXTENSIONS="rtf|pdf|sav|htm|html|pst|ost|txt|gif|jpeg|mpeg|jpg|png|mny|wav|tif|$SNEAKY_WINDOWS_EXTENSIONS";<br />
+my $passwd_protected_zip;<br />
+<br />
+#Little workaround. Apparently people send docs of the form "my.domainname.com.doc" - so you can get false positives<br />
+#due to ".com". So don't add ".com" to SNEAKY_WINDOWS_EXTENSIONS until after VALID_WINDOWS_EXTENSIONS is defined<br />
+#So now "file.com.tif" won't trigger, but file.tif.com will.<br />
+$SNEAKY_WINDOWS_EXTENSIONS="$SNEAKY_WINDOWS_EXTENSIONS|com";<br />
+<br />
+<br />
+$ENV{'PATH'}='/bin:/usr/bin';<br />
+<br />
+my $SCANINFO='';<br />
+<br />
+my $MAX_FILE_LENGTH=100;<br />
+my $MAX_NUM_HDRS=140;<br />
+my $QE_LEN=20;<br />
+<br />
+#Maximum amount of time we allow Q-S to run before returning<br />
+# a temp failure. This is so remote SMTP servers don't get confused<br />
+# over whether or not they have delivered to a SMTP server<br />
+# that's refused to say "OK" for over an hour...<br />
+# We'll default to 20 minutes. If the scanner loop takes more than 20 <br />
+# minutes to scan the message, then something *must* be wrong with the<br />
+# scanner. <br />
+my $MAXTIME=20*60;<br />
+<br />
+#Finally, are you sure your virus scanners can unpack zip files? <br />
+#Turn this on to force Qmail-Scanner to unzip for you<br />
+my $force_unzip=0;<br />
+<br />
+#Descriptive string to use in generated Email<br />
+my $destring="virus";<br />
+<br />
+#####################################################################<br />
+## <br />
+## End of site-specific settings<br />
+##<br />
+#####################################################################<br />
+<br />
+<br />
+<br />
+#Want debugging? Enable this and read $logdir/qmail-queue.log<br />
+my $DEBUG='0';<br />
+<br />
+# st: Minimal debug only works if $DEBUG=0<br />
+# If set to 2, the parent pid is written to the logs, and also<br />
+# the message size<br />
+my $MINIDEBUG='1';<br />
+<br />
+# qms: Want meaningful event logs? Enable this and read $scandir/qms-events.log<br />
+my $EVENTLOG='1'; <br />
+<br />
+my @uufile_list = ();<br />
+my @attachment_list = ();<br />
+my @zipfile_list = ();<br />
+<br />
+#Want microsec times for debugging<br />
+use Time::HiRes qw ( usleep ualarm gettimeofday tv_interval );<br />
+use POSIX;<br />
+use DB_File;<br />
+<br />
+use vars qw/ $opt_v $opt_V $opt_h $opt_g $opt_r $opt_z $opt_p $opt_d $opt_s/;<br />
+<br />
+use Getopt::Std;<br />
+<br />
+#my ($opt_v,$opt_h,$opt_g,$opt_r,$opt_z);<br />
+<br />
+getopts('vVhgrzpds');<br />
+<br />
+my ($start_time,$last_time);<br />
+$start_time = $last_time = [gettimeofday];<br />
+<br />
+(my $prog=$0) =~ s/^.*\///g;<br />
+<br />
+if ( $opt_h ) {<br />
+ print "<br />
+<br />
+ $prog $VERSION-$st_version<br />
+<br />
+ -h - This help<br />
+ -v - show details about this install. <br />
+ Please include in any bug reports.<br />
+ -V - show details about this install<br />
+ and some configuration information.<br />
+ -z - gather virus scanner/DAT versions <br />
+ and cleanup old temp files<br />
+ -g - generate perlscanner database<br />
+ -r - read from perlscanner database<br />
+<br />
+ -p - generate settings per domain database<br />
+ -d - display settings per domain database<br />
+ -s - sort the text file $settings_per_domain.txt\n\n";<br />
+ exit;<br />
+}<br />
+<br />
+# st: I need the localtime at this point for the routine read_spd<br />
+#Get current timestamp for logs<br />
+my ($sec,$min,$hour,$mday,$mon,$year,$nowtime);<br />
+($sec,$min,$hour,$mday,$mon,$year) = localtime(time);<br />
+<br />
+if ( $opt_g || $opt_r) {<br />
+ &generate_quarantine_db;<br />
+ exit 0;<br />
+} elsif ($opt_p) {<br />
+ &generate_spd;<br />
+ exit 0;<br />
+} elsif ($opt_d || $opt_s) {<br />
+ &read_spd;<br />
+ exit 0;<br />
+} elsif ($opt_v || $opt_V) {<br />
+ &show_version;<br />
+ exit 0;<br />
+}<br />
+<br />
+<br />
+chdir($scandir);<br />
+umask(0007);<br />
+<br />
+if (! -d "$scandir/tmp") {<br />
+ mkdir("$scandir/tmp",0750) || &error_condition("cannot create $scandir/tmp - $!");<br />
+}<br />
+<br />
+my ($quarantine_event,$quarantine_event_tmp)=0;<br />
+my ($quarantine_DOS,$quarantine_spam)=0;<br />
+<br />
+my $file_id = &uniq_id();<br />
+<br />
+#For security reasons, tighten the follow vars...<br />
+$ENV{'SHELL'} = '/bin/sh' if exists $ENV{SHELL};<br />
+$ENV{'TMP'} = $ENV{'TMPDIR'} = "$scandir/tmp/$file_id";<br />
+#$ENV{'QMAILSUSER'} = $ENV{'QMAILSHOST'} = '';<br />
+<br />
+<br />
+<br />
+if ($mimeunpacker_binary =~ /reformime/) {<br />
+ $mimeunpacker_binary .= " -x$ENV{'TMPDIR'}/";<br />
+} elsif ($mimeunpacker_binary =~ /ripmime/) {<br />
+ $mimeunpacker_binary .= " --unique_names --no-ole --paranoid -i - -d $ENV{'TMPDIR'}/";<br />
+}<br />
+<br />
+#Get current timestamp for logs<br />
+my ($sec,$min,$hour,$mday,$mon,$year,$nowtime);<br />
+($sec,$min,$hour,$mday,$mon,$year) = localtime(time); <br />
+my ($smtp_sender,$remote_smtp_ip,$remote_smtp_auth,$real_uid,$effective_uid);<br />
+<br />
+$real_uid=$<;<br />
+$effective_uid=$>;<br />
+<br />
+# st: I will need the process number, and other variables, later<br />
+my $nprocess=$$;<br />
+my $nppid=getppid;<br />
+if ($nppid == 1) {<br />
+ # The parent pid is dead, maybe a message with BLFs<br />
+ warn "$V_HEADER-$VERSION: Process $nprocess closed, parent process died\n" if ($MINIDEBUG < 3);<br />
+ warn "$nprocess QS-$VERSION: Process $nprocess closed, parent process died\n" if ($MINIDEBUG >= 3);<br />
+ exit 111;<br />
+}<br />
+$nprocess.="/$nppid" if ($MINIDEBUG >= 2);<br />
+my $sa_report='';<br />
+my ($sa_hits,$required_hits)=('0','0');<br />
+# st: Flag to delete message<br />
+my $del_message='0';<br />
+<br />
+if ($DEBUG || $MINIDEBUG ) {<br />
+ open(LOG,">>$logdir/$debuglog");<br />
+ select(LOG);$|=1;<br />
+ &debug("+++ starting debugging for process $$ (ppid=$nppid) by uid=$real_uid");<br />
+ &minidebug("+++ starting debugging for process $$ (ppid=$nppid) by uid=$real_uid");<br />
+}<br />
+<br />
+# qms: open the event log if enabled<br />
+if ($EVENTLOG ) {<br />
+ open(ELOG,">>$scandir/$eventlog");<br />
+ select(ELOG);$|=1;<br />
+ my $starttime = strftime("%F %H:%M:%S", localtime(time));<br />
+ &eventlog("------ START MSG $starttime ------");<br />
+}<br />
+<br />
+# st: if sa_alt or sa_debug are '0', sa_hdr_report_site must be 0<br />
+$sa_hdr_report_site='0' if ( !$sa_alt || !$sa_debug );<br />
+<br />
+# st: if the variable SA_ONLYDELETE_HOST is set in the tcpserver<br />
+# don't reject messages coming from those IPs, just delete them<br />
+# You should set this variable for your secondary mail server.<br />
+if (defined($ENV{'SA_ONLYDELETE_HOST'}) || defined($ENV{'SA_WHITELIST'})) {<br />
+ $sa_reject="0";<br />
+ &debug("WL: The server is a SA_ONLYDELETE_HOST, don't reject");<br />
+ &minidebug("WL: The server is a SA_ONLYDELETE_HOST, don't reject");<br />
+}<br />
+<br />
+<br />
+# st: if the variable BMC_WHITELIST is set in the tcpserver<br />
+# don't search for 'bad mime characters' in the headers of messages<br />
+# coming from those IPs.<br />
+# It would be hard to mantain this whitelist...<br />
+if (defined($ENV{'BMC_WHITELIST'})) {<br />
+ $BAD_MIME_CHECKS='0';<br />
+ &debug("WL: The server is in the BMC_WHITELIST, don't check BMC");<br />
+ &minidebug("WL: The server is in the BMC_WHITELIST, don't check BMC");<br />
+}<br />
+<br />
+<br />
+&debug("setting UID to EUID so subprocesses can access files generated by this script");<br />
+$< = $>; # set real to effective uid<br />
+$( = $); # set real to effective gid<br />
+<br />
+&debug("program name is $prog, version $VERSION");<br />
+if ($opt_z) {<br />
+ &scan_queue;<br />
+ exit 0;<br />
+}<br />
+<br />
+<br />
+&scanner_info;<br />
+<br />
+my (%headers , %virtualheader);<br />
+my ($CRYPTO_TYPE,$DOMKEYS,$altered_subject, $HEADERS, $env_returnpath, $returnpath, $QS_RELAYCLIENT);<br />
+my ($ATTACHMENT, %BOUNDARY,$BOUNDARY_REGEX,$attachment_header,$attachment_value,%attach_hdrs,%content_type);<br />
+my ($ct_attachment_filename,$cd_attachment_filename);<br />
+my ($env_recips, $recips, $trecips, $recip, $one_recip);<br />
+my ($alarm_status,$elapsed_time,$msg_size,$file_desc);<br />
+my ($description,$quarantine_description,$illegal_mime);<br />
+my $skip_text_msgs=1;<br />
+my $plain_text_msg=0;<br />
+my $indicates_attachments=0;<br />
+my $xstatus=0;<br />
+my $attachment_counter=0;<br />
+<br />
+&working_copy;<br />
+<br />
+ # st: working_copy could be high due to an slow connection<br />
+ &minidebug("w_c: message size $msg_size bytes") if ($MINIDEBUG >= 2);<br />
+ my $elapsed_1=tv_interval ($start_time, [gettimeofday]);<br />
+ &minidebug("w_c: elapsed time from start $elapsed_1 secs");<br />
+<br />
+#We will set our own value here as it allows us to unset<br />
+#it later without changing how Qmail actually interprets<br />
+#RELAYCLIENT<br />
+$QS_RELAYCLIENT=1 if (defined($ENV{'RELAYCLIENT'}));<br />
+<br />
+if ($ENV{'TCPREMOTEIP'}) {<br />
+ $remote_smtp_ip=$ENV{'TCPREMOTEIP'};<br />
+ if ($ENV{'TCPREMOTEINFO'}) {<br />
+ $remote_smtp_auth=" (".$ENV{'TCPREMOTEINFO'}."\@$remote_smtp_ip)";<br />
+ $smtp_sender="via SMTP from $remote_smtp_ip using auth $remote_smtp_auth";<br />
+ }else{<br />
+ $smtp_sender="via SMTP from $remote_smtp_ip";<br />
+ }<br />
+ $tag_score="RC:1($remote_smtp_ip):" if ($QS_RELAYCLIENT);<br />
+ &debug("incoming SMTP connection from $smtp_sender");<br />
+ &eventlog("CONNECT-SMTP:$ENV{'TCPREMOTEIP'}");<br />
+ #system("/usr/bin/printenv > /tmp/qmail-scanner.env");<br />
+ # st: do not reject mails from localhost useful for fetchmail<br />
+ $sa_reject="0" if ($remote_smtp_ip eq "127.0.0.1");<br />
+} else {<br />
+ $smtp_sender="via local process $$";<br />
+ $remote_smtp_ip='127.0.0.1';<br />
+ #Set QS_RELAYCLIENT if QS_SPAMASSASSIN isn't set<br />
+ $QS_RELAYCLIENT=1;<br />
+ $tag_score="RC:1($remote_smtp_ip):"; #Always would be relayed<br />
+ &debug("incoming pipe connection from $smtp_sender");<br />
+ &eventlog("CONNECT-PIPE:$$");<br />
+ # st: do not reject mails from localhost useful for fetchmail<br />
+ $sa_reject="0";<br />
+}<br />
+$tag_score="RC:0($remote_smtp_ip):" if ($tag_score !~ /^RC:1/);<br />
+<br />
+<br />
+#Now alarm this area so that hung networks/virus scanners don't cause <br />
+#double-delivery...<br />
+<br />
+eval {<br />
+ $SIG{ALRM} = sub { die "Maximum time exceeded. Something cannot handle this message." };<br />
+ alarm $MAXTIME;<br />
+<br />
+ &deconstruct_msg; #JLH if (!$quarantine_event);<br />
+ <br />
+ <br />
+ #Now unset env var QMAILQUEUE so any further Email's sent don't<br />
+ #go through the Qmail-Scanner again<br />
+ &debug("unsetting QMAILQUEUE env var");<br />
+ delete $ENV{'QMAILQUEUE'};<br />
+ <br />
+ #This SMTP session is incomplete until we see dem envelope headers!<br />
+ &grab_envelope_hdrs;<br />
+ &debug("from=$headers{'from'},subj=$headers{'subject'}, $qsmsgid=$headers{$qsmsgid} $smtp_sender");<br />
+ &minidebug("from='$headers{'from'}', subj='$headers{'subject'}', $smtp_sender");<br />
+ &eventlog("HEADER:$headers{'from'}:$headers{'to'}:$headers{'subject'}");<br />
+<br />
+ ##### st: variables for settings per domain<br />
+ $returnpath=tolower($returnpath);<br />
+ $domain_returnpath=$returnpath;<br />
+ $domain_returnpath=~ s/^(.*)\@(.*)$/$2/;<br />
+ #<br />
+ $one_recip=tolower($one_recip);<br />
+ $domain_one_recip=$one_recip;<br />
+ $domain_one_recip=~ s/^(.*)\@(.*)$/$2/ if ($one_recip);<br />
+ ######<br />
+<br />
+ #Add envelope details to headers array so that they can be matched within<br />
+ #perlscanner.<br />
+ #Note how they're uppercase cf the message headers which are all forced<br />
+ #lowercased. This is to ensure no-one can override them...<br />
+<br />
+ $headers{'MAILFROM'}=$returnpath;<br />
+ $headers{'RCPTTO'}=$recips;<br />
+ $headers{'REMOTEIPADDR'}=$remote_smtp_ip;<br />
+<br />
+ if ( ($BAD_MIME_CHECKS > 1 && $headers{'mime-version'} eq "") || ($headers{'mime-version'} ne "" && $headers{'content-type'} =~ /^text\/plain/i)) {<br />
+ #Hmm, doesn't look nice, but it feels better to make this a separate check for some reason<br />
+ if ($skip_text_msgs && ($indicates_attachments < 2) && !@uufile_list && !@attachment_list) {<br />
+ &debug("This is a PLAIN text message (because it's either not mime, or is text/plain), skip virus scanners - but not antispam scanners");<br />
+ &minidebug("This is a PLAIN text message, skip virus scanners - but not SA");<br />
+ &eventlog("TYPE:PLAIN");<br />
+ $plain_text_msg=1;<br />
+ }<br />
+ }<br />
+ if ($headers{'MAILFROM'} eq "" || $headers{'subject'} =~ /Returned mail:|Mail Transaction Failed/) {<br />
+ &debug("This is a bounce message - better assume there's an attachment in it");<br />
+ &eventlog("TYPE:MIXED");<br />
+ $plain_text_msg=0;<br />
+ }<br />
+<br />
+##############################################<br />
+# st: SETTINGS PER DOMAIN<br />
+##############################################<br />
+<br />
+ $quarantine_event_tmp=$quarantine_event;<br />
+<br />
+ if ($settings_pd && ( ! -f "$settings_per_domain.db")) {<br />
+ &debug("s_p_d: $settings_per_domain.db doesn't exist falling to installed scanners");<br />
+ &minidebug("s_p_d: $settings_per_domain.db doesn't exist falling to installed scanners");<br />
+ $settings_pd='0';<br />
+ }<br />
+<br />
+ if ($settings_pd) {<br />
+ &settings_p_d;<br />
+ } else {<br />
+ @scanner_array=@scanners_installed;<br />
+ &sa_defaults;<br />
+ &start_scanners($env_returnpath,$env_recips,"$scandir/$wmaildir/new/$file_id");<br />
+ }<br />
+<br />
+##############################################<br />
+<br />
+ alarm 0;<br />
+};<br />
+<br />
+$alarm_status=$@;<br />
+if ($alarm_status and $alarm_status ne "" ) { <br />
+ if ($alarm_status eq "Maximum time exceeded. Something cannot handle this message.") {<br />
+ &error_condition("ALARM: taking longer than $MAXTIME secs. Requeuing...");<br />
+ } else {<br />
+ &error_condition("Requeuing: $alarm_status");<br />
+ }<br />
+}<br />
+<br />
+<br />
+#Msg has been delivered now, so don't want hangs in this part<br />
+#to affect delivery<br />
+<br />
+&log_event;<br />
+<br />
+&cleanup;<br />
+<br />
+# st: I don't think that st-patch will reach this point, for a SPAM mail..<br />
+#<br />
+# This is commented out as I'm concerned for people running Q-S behind edge gateways.<br />
+#Those boxes would then generate a bounce (as they are not the actual spamming SMTP client)<br />
+#if ($destring =~ /SPAM/) {<br />
+# &debug("exit with permanent error as this is high-scored SPAM");<br />
+# &minidebug("SA: exit with permanent error as this is high-scored SPAM");<br />
+# &close_log;<br />
+# exit 111;<br />
+#}<br />
+<br />
+# st: just for the script log-report, add the information of policy block to the log<br />
+if ($quarantine_event =~ /^(policy|perlscan)/i && $quarantine_event !~ /gr[ae]ylist/i && $quarantine_description) {<br />
+ &debug("q_s: Policy BLOCK");<br />
+ &minidebug("q_s: Policy BLOCK");<br />
+}<br />
+<br />
+# st: write to the log the end of the process<br />
+&close_log;<br />
+&eventlog("SCANTIME:",tv_interval ($start_time, [gettimeofday]),"");<br />
+&eventlog("------ STOP MSG ---------------------------");<br />
+exit 0;<br />
+<br />
+############################################################################<br />
+# Error handling<br />
+############################################################################<br />
+<br />
+#Generate uniq identifiers<br />
+sub uniq_id {<br />
+ return "$hostname" . time . __LINE__ . $$;<br />
+}<br />
+<br />
+<br />
+sub log_event {<br />
+ if ($log_details) {<br />
+ $tag_score .= "$tag_sa_score" if ($tag_sa_score);<br />
+ $tag_score .= "$CRYPTO_TYPE:" if ($log_crypto && $CRYPTO_TYPE ne "");<br />
+ $tag_score .= "$DOMKEYS:" if ($log_crypto && $DOMKEYS ne "");<br />
+ #$virtualheader{'CRYPTODETAILS'}="$CRYPTO_TYPE:$DOMKEYS";<br />
+ $tag_score=":$tag_score" if ($tag_score ne "");<br />
+ if ($trecips =~ /\0T/) {<br />
+ for $recip (split(/\0T/,$trecips)) {<br />
+ &log_msg("qmail-scanner",($quarantine_event ne "0" ? "$quarantine_event$tag_score" : "Clear$tag_score"),$elapsed_time,$msg_size,$returnpath,$recip,$headers{'subject'},$headers{$qsmsgid},$file_desc) if ($recip ne "");<br />
+ }<br />
+ } else {<br />
+ #Only one recip<br />
+ &log_msg("qmail-scanner",($quarantine_event ne "0" ? "$quarantine_event$tag_score" : "Clear$tag_score"),$elapsed_time,$msg_size,$returnpath,$recips,$headers{'subject'},$headers{$qsmsgid},$file_desc);<br />
+ }<br />
+ }<br />
+}<br />
+<br />
+# Fail with the given message and a temporary failure code.<br />
+sub error_condition {<br />
+ my ($string,$errcode)=@_;<br />
+ $errcode=111 if (!$errcode);<br />
+ eval {<br />
+ syslog('mail|err',"$V_HEADER-$VERSION:[$file_id] $string");<br />
+ };<br />
+ if ($@) {<br />
+ setlogsock('inet');<br />
+ syslog('mail|err',"$V_HEADER-$VERSION:[$file_id] $string");<br />
+ }<br />
+ if ($log_details ne "syslog") {<br />
+ warn "$V_HEADER-$VERSION:[$file_id] $string\n";<br />
+ }<br />
+ #$nowtime = sprintf "%02d/%02d/%02d %02d:%02d:%02d", $mday, $mon+1, $year+1900, $hour, $min, $sec;<br />
+ &debug("error_condition: $V_HEADER-$VERSION: $string");<br />
+ &minidebug("error_condition: $V_HEADER-$VERSION: $string");<br />
+ &eventlog("ERROR:$V_HEADER-$VERSION:$string");<br />
+ close(ELOG);<br />
+ &cleanup;<br />
+ &close_log;<br />
+ exit $errcode;<br />
+}<br />
+<br />
+sub debug {<br />
+ my $dnowtime = strftime("%a, %d %b %Y %H:%M:%S %Z", localtime(time));<br />
+ print LOG "$dnowtime:$nprocess: ",@_,"\n" if ($DEBUG);<br />
+}<br />
+<br />
+# qms: log events to the file<br />
+sub eventlog {<br />
+ my $enowtime = sprintf "%10d", time;<br />
+ print ELOG "$enowtime:$$:",@_,"\n" if ($EVENTLOG);<br />
+}<br />
+<br />
+######## qms-monitor BLOCK BEGIN<br />
+# qms-monitor: Entry point called prior to requeueing the msg<br />
+sub qms_monitor<br />
+{<br />
+ my($msg) = @_;<br />
+ my($acct) = '';<br />
+ my($aindex) = '0';<br />
+<br />
+ foreach $acct (@qms_monitor_array)<br />
+ {<br />
+ # check the sender address first<br />
+ if ($returnpath =~ /$acct/i)<br />
+ {<br />
+ &qms_monitor_save($acct,$msg,"@qms_monitor_dest_array[$aindex]");<br />
+ $aindex += 1;<br />
+ next;<br />
+ }<br />
+<br />
+ if ($recips =~ /$acct/i)<br />
+ {<br />
+ &qms_monitor_save($acct,$msg,"@qms_monitor_dest_array[$aindex]");<br />
+ }<br />
+<br />
+ $aindex += 1;<br />
+ }<br />
+}<br />
+<br />
+# qms-monitor: save the msg to our archive location<br />
+sub qms_monitor_save<br />
+{<br />
+ my($qmsacct,$src,$dest) = @_;<br />
+ my($finaldest) = "$qms_monitor_home/$dest";<br />
+ my($fname) = &qms_monitor_get_filename($qmsacct);<br />
+<br />
+ if (!open(INMSG, "<$src"))<br />
+ {<br />
+ &eventlog("--- qms_monitor_save: unable to open src $src");<br />
+ &debug ("qms_monitor_save: unable to open src $src\n");<br />
+ return;<br />
+ }<br />
+<br />
+ if (! -d "$finaldest")<br />
+ {<br />
+ if (system("mkdir -p $finaldest"))<br />
+ {<br />
+ &eventlog("--- qms_monitor_save: unable to mkdir $finaldest");<br />
+ &debug ("qms_monitor_save: unable to mkdir $finaldest");<br />
+ return;<br />
+ }<br />
+ }<br />
+<br />
+<br />
+ if (!open(OUTMSG, ">$finaldest/$fname"))<br />
+ {<br />
+ &eventlog("--- qms_monitor_save: unable to open dest $finaldest/$fname");<br />
+ &debug ("qms_monitor_save: unable to open dest $finaldest/$fname\n");<br />
+ return;<br />
+ }<br />
+<br />
+ while (<INMSG>)<br />
+ {<br />
+ print OUTMSG;<br />
+ }<br />
+<br />
+ close(OUTMSG);<br />
+ close(INMSG);<br />
+}<br />
+<br />
+# qms-monitor: Generate meaninful file names<br />
+sub qms_monitor_get_filename<br />
+{<br />
+ my($aname) = @_;<br />
+ my($stime) = strftime("%F_%H:%M:%S", localtime(time));<br />
+<br />
+ return "$aname" . "_" . "$hostname" . "_" . "$stime" . "_" . $$;<br />
+}<br />
+<br />
+######## qms-monitor BLOCK END<br />
+<br />
+sub working_copy {<br />
+ my ($hdr,$last_hdr,$value,$num_of_headers,$last_header,$last_value,$attachment_filename);<br />
+ select(STDIN); $|=1;<br />
+ <br />
+ &debug("w_c: mkdir $ENV{'TMPDIR'}");<br />
+ mkdir("$ENV{'TMPDIR'}",0750)||&error_condition("$ENV{'TMPDIR'} exists - try again later...");<br />
+ chdir("$ENV{'TMPDIR'}")||&error_condition("cannot chdir to $ENV{'TMPDIR'}/");<br />
+ if (-f "$scandir/$wmaildir/tmp/$file_id" || -f "$scandir/$wmaildir/new/$file_id") {<br />
+ &error_condition("$file_id exists, try again later");<br />
+ }<br />
+ &debug("w_c: start dumping incoming msg into $scandir/$wmaildir/tmp/$file_id [",&deltatime,"]");<br />
+ open(TMPFILE,">$scandir/$wmaildir/tmp/$file_id")||&error_condition("cannot write to $scandir/$wmaildir/tmp/$file_id - $!");<br />
+ <br />
+ my $still_headers=1;<br />
+ my $begin_content='';<br />
+ my $still_attachment='';<br />
+ my $first_received=0;<br />
+ while (<STDIN>) {<br />
+ if ($still_headers) {<br />
+ $HEADERS .= $_;<br />
+ #Catch any naughty illegal header chars here<br />
+ if ($BAD_MIME_CHECKS && !$IGNORE_EOL_CHECK && /\r|\0/) {<br />
+ $illegal_mime=1;<br />
+ &debug("w_c: found CRL/NULL in header - invalid if this is a MIME message");<br />
+ &minidebug("w_c: found CRL/NULL in header - invalid if this is a MIME message");<br />
+ &eventlog("QMSWC:BAD_HDR_CHARS");<br />
+ }<br />
+ #Put headers into array<br />
+ if (/^\s+(.*)$/ && $last_hdr) {<br />
+ #Hmmm, a continuation...<br />
+ $headers{$last_hdr} .= $1 if (!$illegal_mime);<br />
+ } elsif (/^([^\s]+)/) {<br />
+ #This means it's not a continuation header<br />
+ if (!$quarantine_event && $BAD_MIME_CHECKS && ($headers{'mime-version'} ne "") && !/^([^\s]+):(.*)$/) {<br />
+ #Wow - a header (not header+value) that goes onto another line - not likely!<br />
+ $illegal_mime=1;<br />
+ $destring='problem';<br />
+ $quarantine_description="Disallowed breakage found in header name - not valid email";<br />
+ $quarantine_event="Policy:Bad_MIME_Break";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
+ &debug("w_c: disallowed breakage found in header name ($_) - not valid email");<br />
+ &minidebug("w_c: disallowed breakage found in header name ($_) - not valid email");<br />
+ &eventlog("QMSWC:BAD_HDR_BREAKAGE");<br />
+ #next;<br />
+ } else {<br />
+ /^([^\s]+):(.*)$/;<br />
+ $hdr=$1;<br />
+ $last_hdr=tolower($hdr);<br />
+ $value=$2;<br />
+ $value =~ s/^\s//;<br />
+ if (!$quarantine_event && $BAD_MIME_CHECKS && $headers{'mime-version'} ne "" && $hdr =~ /^[^X].*\(/i) {<br />
+ #Wow - a comment *inside* a standard header name. Only viruses are known to do that<br />
+ #Should we test for [^0-9a-z\_\-\=\+] instead?<br />
+ $illegal_mime=1;<br />
+ $destring='problem';<br />
+ $quarantine_description='Disallowed MIME comment found in header name - not valid email';<br />
+ $quarantine_event="Policy:Bad_MIME_Comment";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
+ &debug("w_c: $quarantine_description");<br />
+ &minidebug("w_c: $quarantine_description");<br />
+ &eventlog("QMSWC:BAD_HDR_MIME");<br />
+ }<br />
+ $num_of_headers++;<br />
+ }<br />
+ #Don't let this array grow without bounds...<br />
+ if ($num_of_headers < $MAX_NUM_HDRS) {<br />
+ if ($hdr =~ /^to|cc/i && $headers{tolower($hdr)}) {<br />
+ #Special-case the To: and Cc: headers.<br />
+ #Broken mailers generate messages with multiple <br />
+ #instances of these, so merge them into one...<br />
+ $headers{tolower($hdr)} .= ",$value";<br />
+ } elsif ($hdr =~ /^(from|x-mail|User-Agent|Organi|Received|Message-ID|Subject)/i && $headers{tolower($hdr)}) {<br />
+ #Make sure any multiples of these headers are remembered, so that <br />
+ #perlscanner checks can see all instances - just wrap em up<br />
+ #into one long line<br />
+ $headers{tolower($hdr)} .= " $value";<br />
+ } elsif ($hdr =~ /^received$/i && !$first_received) {<br />
+ $first_received=1;<br />
+ $value=~/\[([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\]\)$/;<br />
+ if ($1 =~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/ && !$ENV{'TCPREMOTEIP'}) {<br />
+ $ENV{'TCPREMOTEIP'}=$1;<br />
+ &debug("TCPREMOTEIP not set - configuring as $ENV{'TCPREMOTEIP'}");<br />
+ }else{<br />
+ #&debug("no need to reset TCPREMOTEIP from $value");<br />
+ }<br />
+ } elsif (!$quarantine_event && $BAD_MIME_CHECKS > 1 && (($headers{'mime-version'} ne "" && tolower($hdr) eq "mime-version") || ($headers{'content-type'} ne "" && tolower($hdr) eq "content-type") || ($headers{'content-transfer-encoding'} ne "" && tolower($hdr) eq "content-transfer-encoding") || ($headers{'content-disposition'} ne "" && tolower($hdr) eq "content-disposition"))) {<br />
+ #Why would a legit message have important MIME headers defined >1 time? It could imply someone is trying to sneak<br />
+ #something past SMTP scanners...<br />
+ #Too much parsing needs to be done to do this correctly - stuff 'em - break the sucker ;-/<br />
+ &debug("Duplicate MIME headers found [$hdr] - renaming");<br />
+ print TMPFILE "$V_HEADER-$VERSION: renamed duplicate MIME headers\n";<br />
+ $_="$V_HEADER-Renamed-$_";<br />
+ } else {<br />
+ #All other headers: the last occurance wins!<br />
+ $headers{tolower($hdr)}=$value;<br />
+ }<br />
+ }<br />
+ }<br />
+ if (/^(\r|\r\n|\n)$/) {<br />
+ #headers have finished<br />
+ $still_headers=0;<br />
+ #Normalize selected headers<br />
+ $headers{'subject'}=&normalize_string("Subject:",$headers{'subject'});<br />
+ #Try to workaround those nasty broken viruses that produce Content-Type without MIME-Version<br />
+ #to get around virus scanners<br />
+ if ($headers{'mime-version'} eq "") {<br />
+ #Make sure it's a MIME-style Content-type, Sun used to use Content-type for other purposes...<br />
+ if ($BAD_MIME_CHECKS && $headers{'content-type'} =~ /\//) {<br />
+ print TMPFILE "$V_HEADER-$VERSION: added fake MIME-Version header\nMIME-Version: 1.0\n";<br />
+ $headers{'mime-version'}="1.0";<br />
+ &debug("w_c: added fake MIME-Version header");<br />
+ }<br />
+ } elsif ($BAD_MIME_CHECKS > 1 && $headers{'content-type'} eq "") {<br />
+ #OK, now do the same for Content-Type. RFCs state "if no Content-Type present, then it's text/plain"<br />
+ #However, Outlook chooses to read the entire message and "figures out" it's mixed/multipart, etc. <br />
+ #This'll break that - as it should.<br />
+ #I wonder if I shouldn't just block these instead, the only ones I've seen are either viruses or spam...<br />
+ print TMPFILE "$V_HEADER-$VERSION: added fake Content-Type header\nContent-Type: text/plain\n";<br />
+ $headers{'content-type'}="text/plain";<br />
+ &debug("w_c: added fake Content-Type header");<br />
+ }<br />
+ if ( $headers{'mime-version'} ne "" && $headers{'content-type'} =~ /^(\s+|)([^\/\s\(]+)(\s+|)\/(\s+|)([^\/\s\(\;]+)/ ) {<br />
+ $content_type{$attachment_counter}="$2/$5";<br />
+ &debug("w_c: primary Content-Type of $content_type{$attachment_counter} found");<br />
+ if ($log_crypto) {<br />
+ $DOMKEYS="CR:DomKeys(signed)" if ($headers{'domainkey-signature'} ne "");<br />
+ if ($content_type{$attachment_counter} =~ /multipart\/signed/i) {<br />
+ $CRYPTO_TYPE="CR:SMIME(signed)" if ($CRYPTO_TYPE eq "" && $headers{'content-type'} =~ /protocol=\"application\/(x\-|)pkcs/i);<br />
+ $CRYPTO_TYPE="CR:PGP(signed)" if ($CRYPTO_TYPE eq "" && $headers{'content-type'} =~ /protocol=\"application\/(x\-|)pgp/i);<br />
+ &debug("found MIME-based crypto ($CRYPTO_TYPE)");<br />
+ } elsif ($content_type{$attachment_counter} =~ /multipart\/encrypted/i) {<br />
+ $CRYPTO_TYPE="CR:PGP(encrypted)" if ($headers{'content-type'} =~ /protocol=\"application\/(x\-|)pgp/i);<br />
+ &debug("found MIME-based crypto ($CRYPTO_TYPE)");<br />
+ }elsif ($content_type{$attachment_counter} =~ /application\/(x\-|)pkcs7/i) {<br />
+ $CRYPTO_TYPE="CR:SMIME(encrypted)" if ($headers{'content-type'} =~ /application\/(x\-|)pkcs7/i);<br />
+ &debug("found MIME-based crypto ($CRYPTO_TYPE)");<br />
+ }<br />
+ }<br />
+ } elsif ($headers{'mime-version'} ne "") {<br />
+ $destring="problem";<br />
+ $illegal_mime=1;<br />
+ $quarantine_description="Disallowed MIME Content-Type found - not valid email";<br />
+ &debug($quarantine_description);<br />
+ &minidebug("w_c: $quarantine_description");<br />
+ $quarantine_event="Policy:Bad_MIME_Type";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
+ &eventlog("QMSWC:BAD_MIME_CONTENT");<br />
+ }<br />
+ #}<br />
+ #if ( $headers{'content-type'} =~ /boundary(\s*)=(|\s+|\s*\")([^\"\;]+)($|\;|\")/i) {<br />
+ if ( $headers{'mime-version'} ne "" && $headers{'content-type'} =~ /boundary(\s*)=(|\s+|\s*\")([^\s\"\;]+)($|\;|\")/i) {<br />
+ $BOUNDARY{$attachment_counter}=$3;<br />
+ #if (!$quarantine_event && $BAD_MIME_CHECKS > 1 && ($BOUNDARY{$attachment_counter} =~ /\"|\;/ || $BOUNDARY{$attachment_counter} eq "")) {<br />
+ #&debug("w_c: RFC2046 says boundaries ($BOUNDARY{$attachment_counter}) can't contain such chars [see bcharsnospace]");<br />
+ #$destring="problem";<br />
+ #$illegal_mime=1;<br />
+ #$quarantine_description="Disallowed MIME boundary found - potential virus";<br />
+ #$quarantine_event="Policy:Bad_MIME_Boundary";<br />
+ #$description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
+ #&eventlog("QMSWC:BAD_MIME_BOUNDARY");<br />
+ #}<br />
+ if (!$quarantine_event && $headers{'mime-version'} ne "" && $BAD_MIME_CHECKS > 1 && ( length($BOUNDARY{$attachment_counter}) == 0 || length($BOUNDARY{$attachment_counter}) > 250)) {<br />
+ #RFC2046 says boundarys are 1-70 chars - making it 250 is being *real* liberal...<br />
+ $destring="problem";<br />
+ $illegal_mime=1;<br />
+ $quarantine_description="Disallowed MIME boundary length found (".length($BOUNDARY{$attachment_counter}).") - not valid email";<br />
+ &debug($quarantine_description);<br />
+ $quarantine_event="Policy:Bad_MIME_Length";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
+ &eventlog("QMSWC:BAD_MIME_BOUNDARY");<br />
+ }<br />
+ #Strip off stuff after semicolon, and escape any odd chars<br />
+ $BOUNDARY{$attachment_counter} =~ s/(\"|\;).*$//g;<br />
+ #$BOUNDARY{$attachment_counter} =~ s/([^a-z0-9=\_])/\\\1/gi;<br />
+ $BOUNDARY{$attachment_counter} =~ s/(\W)/\\$1/g;<br />
+ $BOUNDARY_REGEX=$BOUNDARY{$attachment_counter};<br />
+ &debug("w_c: found a top-level boundary definition of $BOUNDARY{$attachment_counter}"); <br />
+ }<br />
+ if ( $headers{'content-type'} =~ /name(|\s+)=(|\s+|\s*\")([^\s\"].*)/i) {<br />
+ $ATTACHMENT=$3;<br />
+ $attachment_counter++;<br />
+ #Strip off stuff after semicolon<br />
+ $ATTACHMENT =~ s/(\"|\;).*$//g;<br />
+ &debug("w_c: found a top-level file attachment definition of $ATTACHMENT");<br />
+ push(@attachment_list, $ATTACHMENT);<br />
+ }<br />
+ if ($headers{'message-id'} eq "" && !$headers{$qsmsgid}) {<br />
+ $headers{$qsmsgid}="<".time . __LINE__ . $$ . "\@$hostname>";<br />
+ print TMPFILE "${V_HEADER}-Message-ID: $headers{$qsmsgid}\n";<br />
+ } else {<br />
+ if (!$headers{$qsmsgid}) {<br />
+ $headers{$qsmsgid}=$headers{'message-id'};<br />
+ }<br />
+ }<br />
+ }<br />
+ }<br />
+ if (/^(\r|\r\n|\n)$/) {<br />
+ #&debug("w_c: attachment num=$attachment_counter");<br />
+ #&debug("w_c: last attachment header: $attachment_header:$attachment_value");<br />
+ $attach_hdrs{tolower($attachment_header)}=$attachment_value;<br />
+ if ($still_attachment ne "") {<br />
+ $still_attachment='';<br />
+ $begin_content=$attach_hdrs{'content-transfer-encoding'};<br />
+ } else {<br />
+ $begin_content='';<br />
+ }<br />
+ $attachment_header=$attachment_value='';<br />
+ #Let's see what the last MIME attachment contained<br />
+ if ($cd_attachment_filename ne "" && $ct_attachment_filename ne "" && $ct_attachment_filename ne $cd_attachment_filename) {<br />
+ if (!$quarantine_event && $BAD_MIME_CHECKS > 1) {<br />
+ &debug("w_c: Disallowed MIME filename manipulation - potential virus");<br />
+ &minidebug("w_c: Disallowed MIME filename manipulation - potential virus");<br />
+ &eventlog("QMSWC:BAD_MIME_FILENAME");<br />
+ $illegal_mime=1;<br />
+ $destring="problem";<br />
+ $quarantine_description='Disallowed MIME filename manipulation - not valid email';<br />
+ &debug($quarantine_description);<br />
+ &minidebug("w_c: $quarantine_description");<br />
+ $quarantine_event="Policy:Bad_MIME_Manipulation";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message attachment: \"$ct_attachment_filename\" != \"$cd_attachment_filename\"";<br />
+ }<br />
+ }<br />
+ #$ct_attachment_filename=$cd_attachment_filename='';<br />
+ if ($attach_hdrs{'content-type'} =~ /name(|\s+)=(|\s+|\s*\")([^\s\"].*)/i && $ATTACHMENT eq "") {<br />
+ $ATTACHMENT=$3;<br />
+ #Strip off stuff after semicolon<br />
+ $ATTACHMENT =~ s/(\"|\;).*$//g;<br />
+ $ATTACHMENT=&normalize_string("Filename:",$ATTACHMENT);<br />
+ $ATTACHMENT=tolower($ATTACHMENT);<br />
+ if (!grep(/^\Q$ATTACHMENT\E$/,@attachment_list)) {<br />
+ &debug("found C-T attachment filename \"$ATTACHMENT\"");<br />
+ push(@attachment_list, $ATTACHMENT);<br />
+ }<br />
+ $ct_attachment_filename=$ATTACHMENT;<br />
+ $ATTACHMENT='';<br />
+ #&debug("w_c: found a Content-Type attachment filename of \"$ct_attachment_filename\"");<br />
+ }<br />
+ if ($attach_hdrs{'content-disposition'} =~ /name(|\s+)=(|\s+|\s*\")([^\s\"].*)/i && $ATTACHMENT eq "") {<br />
+ $ATTACHMENT=$3;<br />
+ #Strip off stuff after semicolon<br />
+ $ATTACHMENT =~ s/(\"|\;).*$//g;<br />
+ $ATTACHMENT=&normalize_string("Filename:",$ATTACHMENT);<br />
+ $ATTACHMENT=tolower($ATTACHMENT);<br />
+ if (!grep(/^\Q$ATTACHMENT\E$/,@attachment_list)) {<br />
+ push(@attachment_list, $ATTACHMENT);<br />
+ &debug("found C-D attachment filename \"$ATTACHMENT\"");<br />
+ }<br />
+ $cd_attachment_filename=$ATTACHMENT;<br />
+ $ATTACHMENT='';<br />
+ #&debug("w_c: found a Content-Disposition attachment filename of \"$cd_attachment_filename\"");<br />
+ }<br />
+ if ($attach_hdrs{'content-type'} =~ /boundary(|\s+)=(|\s+|\s*\")([^\s\"].*)/i) {<br />
+ $BOUNDARY{$attachment_counter}=$3;<br />
+ #Strip off delimiters around boundary<br />
+ $BOUNDARY{$attachment_counter} =~ s/(\"|\;).*$//g;<br />
+ $BOUNDARY{$attachment_counter} =~ s/(\W)/\\$1/g;<br />
+ if (!$quarantine_event && $headers{'mime-version'} ne "" && $BAD_MIME_CHECKS > 1 && length($BOUNDARY{$attachment_counter}) > 250) {<br />
+ #RFC2046 says boundarys are 0-70 chars<br />
+ $destring="problem";<br />
+ $illegal_mime=1;<br />
+ $quarantine_description="Disallowed MIME boundary length found (".length($BOUNDARY{$attachment_counter}).") - not valid email";<br />
+ &debug($quarantine_description);<br />
+ &minidebug("w_c: $quarantine_description");<br />
+ $quarantine_event="Policy:Bad_MIME_Boundary";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
+ &eventlog("QMSWC:BAD_MIME_BOUNDARY");<br />
+ }<br />
+ if ( !$quarantine_event && $headers{'mime-version'} ne "" && $BAD_MIME_CHECKS > 1 && $BOUNDARY{$attachment_counter} =~ /^($BOUNDARY_REGEX)$/i) {<br />
+ &debug("w_c: hmm, a new boundary defintion that has already being set. Sounds like a trojan");<br />
+ &minidebug("w_c: hmm, a new boundary defintion that has already being set. Sounds like a trojan");<br />
+ &debug("w_c: broken attachment MIME details - block it!");<br />
+ &minidebug("w_c: broken attachment MIME details - block it!");<br />
+ $illegal_mime=1;<br />
+ $destring="problem";<br />
+ $quarantine_description='Disallowed MIME boundary found in attachment - not valid email';<br />
+ &debug($quarantine_description);<br />
+ &minidebug("w_c: $quarantine_description");<br />
+ $quarantine_event="Policy:Bad_MIME_Boundary";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
+ &eventlog("QMSWC:BAD_MIME_BOUNDARY");<br />
+ }<br />
+ if ($BOUNDARY_REGEX ne "") {<br />
+ $BOUNDARY_REGEX.="|".$BOUNDARY{$attachment_counter};<br />
+ } else {<br />
+ $BOUNDARY_REGEX=$BOUNDARY{$attachment_counter};<br />
+ }<br />
+ #&debug("w_c: BOUNDARY_REGEX=$BOUNDARY_REGEX");<br />
+ }<br />
+ if ($attach_hdrs{'content-type'} =~ /\//) {<br />
+ $attachment_filename='';<br />
+ $attachment_filename=$cd_attachment_filename ne "" ? $cd_attachment_filename : $ct_attachment_filename;<br />
+ #&debug("w_c: just parsed attachment $attach_hdrs{'content-type'}: filename=$attachment_filename");<br />
+ if ( $attach_hdrs{'content-type'} =~ /^(\s+|)([^\/\s\(]+)(\s+|)\/(\s+|)([^\/\s\(\;]+)/ ) {<br />
+ $content_type{$attachment_counter}="$2/$5";<br />
+ &debug("w_c: attachment $attachment_counter: Content-Type of $content_type{$attachment_counter} found");<br />
+ if ($attachment_filename =~ /\.(scr|pif|vbs|exe)$/i && $content_type{$attachment_counter} !~ /^(message|text|application|binary)/i) {<br />
+ $quarantine_description="Disallowed file ($attachment_filename) assosiated with unrelated MIME type ($content_type{$attachment_counter}) - forged attachments blocked";<br />
+ &debug("w_c: $quarantine_description");<br />
+ &minidebug("w_c: $quarantine_description");<br />
+ $illegal_mime=1;<br />
+ $destring='problem';<br />
+ &debug($quarantine_description);<br />
+ &minidebug("w_c: $quarantine_description");<br />
+ &eventlog("QMSWC:BAD_MIME_ASSOCIATION");<br />
+ $quarantine_event="Policy:Forged_Attachment";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in attachment $attachment_filename";<br />
+ }<br />
+ }<br />
+ $attach_hdrs{'content-type'}=$attach_hdrs{'content-disposition'}='';<br />
+ $ct_attachment_filename=$cd_attachment_filename='';<br />
+ }<br />
+ } else {<br />
+ #&debug("line=$_");<br />
+ }<br />
+ <br />
+ if ($still_attachment ne "") {<br />
+ #&debug("w_c: check those attachment headers ($_)");<br />
+ if (/^([^\s]+):(|\s+)(.*)$/) {<br />
+ $last_header=$attachment_header;<br />
+ $last_value=$attachment_value;<br />
+ $attachment_header=$1;<br />
+ $attachment_value=$3;<br />
+ $attachment_value =~ s/^\s+//;<br />
+ if ($last_header) {<br />
+ #&debug("w_c: $last_header:$last_value");<br />
+ $attach_hdrs{tolower($last_header)}=$last_value;<br />
+ }<br />
+ #&debug("w_c: beginning of $attachment_header, value=$attachment_value");<br />
+ } elsif (/^\s(.+)/) {<br />
+ #&debug("w_c: line :$_: reached");<br />
+ $attachment_value.=$1;<br />
+ } elsif (/^(\r|\r\n|\n|\s+)$/) {<br />
+ #Yeah - I should block spaces, but too many valid lists send out such junk...<br />
+ $still_attachment='';<br />
+ } else {<br />
+ #This will catch headers that are *correctly* broken over two lines.<br />
+ #No known mailer does that, but virus writers do, so we block it.<br />
+ #Note that a lot of mailing-lists (and AV systems...) shove their trailers<br />
+ #on the bottom of messages irrespective of whether they are MIME or not - so<br />
+ #we must allow such "hacks" to slip through<br />
+ if (!$quarantine_event && $BAD_MIME_CHECKS > 1 && ($BOUNDARY_REGEX ne "" && $still_attachment !~ /^\-\-($BOUNDARY_REGEX)\-\-$/) ) {<br />
+ &debug("w_c: broken attachment MIME details (still_attachment=$still_attachment, but BOUNDARY_REGEX=\"$BOUNDARY_REGEX\")- block it!");<br />
+ &minidebug("w_c: broken attachment MIME details (still_attachment=$still_attachment, but BOUNDARY_REGEX=\"$BOUNDARY_REGEX\")- block it!");<br />
+ $illegal_mime=1;<br />
+ $destring="problem";<br />
+ $quarantine_description='Disallowed content found in MIME attachment - not valid email';<br />
+ &debug($quarantine_description);<br />
+ &minidebug("w_c: $quarantine_description");<br />
+ $quarantine_event="Policy:Bad_MIME_Header";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
+ &eventlog("QMSWC:BAD_MIME_CONTENT");<br />
+ }<br />
+ }<br />
+ }<br />
+ if ($begin_content =~ /base64/i && !/^\s/) {<br />
+ #&debug("w_c: begin=\"$begin_content\",line=$_");<br />
+ $begin_content='';<br />
+ #Only looking for base64 encoded as both QP and binary appear to arrive corrupted under Outlook<br />
+ if ($_ =~ /^TV(qq|qQ|r1|pQ|pA|py|rm|rh|oF|oI|rQ|o8|ou|oA)/) {<br />
+ &debug("w_c: base64 looks like a Windows executable, filename=$attachment_filename,type=$content_type{$attachment_counter}");<br />
+ if (!$quarantine_event && $BAD_MIME_CHECKS > 1 && $content_type{$attachment_counter} !~ /^(binary|application)/i) {<br />
+ #As far as I'm aware, a Windows/DOS executable should always be of type "application/<something>"<br />
+ $illegal_mime=1;<br />
+ $destring="problem";<br />
+ $quarantine_description="Disallowed executable attachment associated with \"$content_type{$attachment_counter}\" MIME type - forged attachment";<br />
+ $quarantine_event="Policy:Forged_Attachment";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in attachment \"$attachment_filename\"";<br />
+ &debug("w_c: $quarantine_description");<br />
+ &minidebug("w_c: $quarantine_description");<br />
+ &eventlog("QMSWC:BAD_MIME_WINBLOWS");<br />
+ }<br />
+ }<br />
+ if ($_ =~ /^(UEsDB[AB]|UEswMFBL)/) {<br />
+ &debug("w_c: base64 looks like a zip file, filename=$attachment_filename,type=$content_type{$attachment_counter}");<br />
+ if (!$quarantine_event && $BAD_MIME_CHECKS > 2 && $attachment_filename !~ /\.zip$/i) {<br />
+ #This is a zip file, and yet the filename doesn't end in .zip - should quarantine it!<br />
+ $illegal_mime=1;<br />
+ $destring="problem";<br />
+ $quarantine_description="Disallowed zip attachment when not associated with a .zip filename - forged attachment";<br />
+ $quarantine_event="Policy:Forged_Attachment";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in attachment \"$attachment_filename\"";<br />
+ &debug("w_c: $quarantine_description");<br />
+ &minidebug("w_c: $quarantine_description");<br />
+ &eventlog("QMSWC:BAD_MIME_ZIP");<br />
+ }<br />
+ }<br />
+ }<br />
+ if ($BOUNDARY_REGEX ne "" && /^\-\-($BOUNDARY_REGEX)/) {<br />
+ $still_attachment=$_;<br />
+ chomp($still_attachment);<br />
+ if (/^\-\-($BOUNDARY_REGEX)\-\-.$/) {<br />
+ &debug("w_c: found end of attachment boundary, BOUNDARY_REGEX was \"$BOUNDARY_REGEX\"...");<br />
+ my ($delete_bb)=$1;<br />
+ $delete_bb =~ s/(\W)/\\$1/g;<br />
+ $BOUNDARY_REGEX =~ s/\Q$delete_bb\E//;<br />
+ $BOUNDARY_REGEX =~ s/\|\|//;<br />
+ $BOUNDARY_REGEX =~ s/(^\||\|$)//;<br />
+ &debug("w_c: now that \"$delete_bb\" has been removed, it's \"$BOUNDARY_REGEX\"...");<br />
+ }<br />
+ $attachment_counter++;<br />
+ #&debug("w_c: found :$BOUNDARY_REGEX: - must be attachment section $attachment_counter");<br />
+ }<br />
+ if ($CRYPTO_TYPE eq "" && $log_crypto) {<br />
+ <br />
+ $CRYPTO_TYPE="CR:PGP(old-signed)" if (/^(\-\-\-\-\-BEGIN PGP SIGNATURE\-\-\-\-\-|LS0tLS1CRUdJTiBQR1AgU0lHTkFUVVJFLS0tLS0)/);<br />
+ $CRYPTO_TYPE="CR:PGP(old-encrypted)" if (/^(\-\-\-\-\-BEGIN PGP MESSAGE\-\-\-\-\-|LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0t)/);<br />
+ &debug("found old PGP crypto ($CRYPTO_TYPE)") if ($CRYPTO_TYPE ne "");<br />
+ &minidebug("w_c: found old PGP crypto ($CRYPTO_TYPE)") if ($CRYPTO_TYPE ne "");<br />
+ }<br />
+ &check_and_grab_attachments;<br />
+ print TMPFILE ;<br />
+ }<br />
+ close(TMPFILE)||&error_condition("cannot close $scandir/$wmaildir/tmp/$file_id - $!");<br />
+<br />
+ #scanning message has finished<br />
+<br />
+ $HEADERS =~ s/\r|\0//g;<br />
+<br />
+ &debug("w_c: rename new msg from $scandir/$wmaildir/tmp/$file_id to $scandir/$wmaildir/new/$file_id");<br />
+ &debug("w_c: total time between DATA command and \".\" was ",&deltatime," secs");<br />
+ &debug("w_c: (this is basically the time it took the client to send the message over the network");<br />
+ &debug("w_c: resetting timer so as to measure actual Qmail-Scanner processing time");<br />
+ &minidebug("w_c: Total time between DATA command and \".\" was ",&deltatime," secs");<br />
+ $start_time=[gettimeofday];<br />
+ #Not atomic but who cares about the overhead - this is the only app using this area...<br />
+ link("$scandir/$wmaildir/tmp/$file_id","$scandir/$wmaildir/new/$file_id")||&error_condition("cannot link $scandir/$wmaildir/tmp/$file_id into $scandir/$wmaildir/new/$file_id - $!");<br />
+ unlink("$scandir/$wmaildir/tmp/$file_id")||&error_condition("cannot delete $scandir/$wmaildir/tmp/$file_id - $!");<br />
+ my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$atime,$mtime,$ctime,$blksize,$blocks);<br />
+ ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$msg_size,$atime,$mtime,$ctime,$blksize,$blocks) = stat("$scandir/$wmaildir/new/$file_id");<br />
+ if (!$headers{'date'}) {<br />
+ my (@day, @mon);<br />
+ $day[0]='Sun';$day[1]='Mon';$day[2]='Tue';$day[3]='Wed';$day[4]='Thu';$day[5]='Fri';$day[6]='Sat';<br />
+ $mon[0]='Jan';$mon[1]='Feb';$mon[2]='Mar';$mon[3]='Apr';$mon[4]='May';$mon[5]='Jun';$mon[6]='Jul';$mon[7]='Aug';$mon[8]='Sep';$mon[9]='Oct';$mon[10]='Nov';$mon[11]='Dec';<br />
+ my ($tm_sec,$tm_min,$tm_hour,$tm_mday,$tm_mon,$tm_year,$tm_wday,$tm_yday,$tm_isdst);<br />
+ ($tm_sec,$tm_min,$tm_hour,$tm_mday,$tm_mon,$tm_year,$tm_wday,$tm_yday,$tm_isdst)=localtime;<br />
+ $tm_year += 1900;<br />
+ $headers{'date'}=$day[$tm_wday].", $tm_mday ".$mon[$tm_mon]." $tm_year $tm_hour:$tm_min:$tm_sec";<br />
+ }<br />
+}<br />
+<br />
+sub grab_envelope_hdrs {<br />
+ select(STDOUT); $|=1;<br />
+ <br />
+ open(SOUT,"<&1")||&error_condition("cannot dup fd 0 - $!");<br />
+ while (<SOUT>) {<br />
+ ($env_returnpath,$env_recips) = split(/\0/,$_,2);<br />
+ if ( ($returnpath=$env_returnpath) =~ s/^F(.*)$// ) {<br />
+ $returnpath=$1;<br />
+ ($recips=$env_recips) =~ s/^T//;<br />
+ $recips =~ /^(.*)\0+$/;<br />
+ $recips=$1;<br />
+ $recips =~ s/\0+$//g;<br />
+ #Keep a note of the NULL-separated addresses<br />
+ $trecips=$recips;<br />
+ $one_recip=$trecips if ($trecips !~ /\0T/);<br />
+ $recips =~ s/\0T/\,/g;<br />
+ }<br />
+ #only meant to be one line!<br />
+ last;<br />
+ }<br />
+ close(SOUT)||&error_condition("cannot close fd 1 - $!");<br />
+ if ( ($env_returnpath eq "" && $env_recips eq "") || ($returnpath eq "" && $recips eq "") ) {<br />
+ #At the very least this is supposed to be $env_returnpath='F' - so<br />
+ #qmail-smtpd must be officially dropping the incoming message for<br />
+ #some (valid) reason (including the other end dropping the connection).<br />
+ &debug("g_e_h: no sender and no recips. Probably due to SMTP client dropping connection. Nothing we can do - cleanup and exit. This is not necessarily an error!");<br />
+ &minidebug("g_e_h: no sender and no recips, from $smtp_sender. Dropping, this isn't a QS error.");<br />
+ &eventlog("SMTP-DROP");<br />
+ warn "$$ QS-$VERSION: no sender and no recips, from $smtp_sender\n" if ($MINIDEBUG >= 3);<br />
+ warn "$V_HEADER-$VERSION: no sender and no recips, from $smtp_sender\n" if ($MINIDEBUG == 2);<br />
+ &cleanup;<br />
+ &close_log;<br />
+ exit;<br />
+ }<br />
+ &debug("g_e_h: return-path is \"$returnpath\", recips is \"$recips\"");<br />
+ &minidebug("g_e_h: return-path='$returnpath', recips='$recips'");<br />
+ &eventlog("ENV-HEADER:$local_domains_string:$returnpath:$recips");<br />
+}<br />
+<br />
+<br />
+sub deconstruct_msg {<br />
+ my ($start_decon_time) = [gettimeofday];<br />
+ my $save_filename ='';<br />
+ my ($new_filename,$MAYBETNEF,$tnef_status);<br />
+<br />
+ my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat("$scandir/$wmaildir/new/$file_id");<br />
+<br />
+ #override absurd values<br />
+ $MAX_SCAN_SIZE=10000000 if ($MAX_SCAN_SIZE < 10000000);<br />
+ if ($size > $MAX_SCAN_SIZE) {<br />
+ &debug("d_m: msg is $size bytes - too large to scan");<br />
+ &minidebug("d_m: msg is $size bytes - too large to scan");<br />
+ $SKIP_SCANNING=1;<br />
+ }<br />
+ &debug("d_m: starting $mimeunpacker_binary <$scandir/$wmaildir/new/$file_id [",&deltatime,"]");<br />
+ open(MIME,"$mimeunpacker_binary <$scandir/$wmaildir/new/$file_id 2>&1|")||&error_condition("cannot call $mimeunpacker_binary - $!");<br />
+ while (<MIME>) {<br />
+ next if (/exists/);<br />
+ &error_condition("d_m: output spotted from $mimeunpacker_binary ($_) - that shouldn't happen!");<br />
+ }<br />
+ close(MIME)||&error_condition("cannot close $mimeunpacker_binary - $!");<br />
+ my $unpacker='';<br />
+ <br />
+ opendir(DIR,"$ENV{'TMPDIR'}/")||&error_condition("cannot open dir $ENV{'TMPDIR'}/ - $!"); <br />
+ my @all_unpacked_files = grep(!/^\.+$/, readdir(DIR));<br />
+ closedir(DIR);<br />
+ &debug("d_m: finished $mimeunpacker_binary [",&deltatime,"]");<br />
+ #If you have the tnef app, you'll be able to scan broken M$ attachments<br />
+ <br />
+ if ( $tnef_binary ) {<br />
+ &debug("d_m: Checking all attachments to see if they're MS-TNEF");<br />
+ foreach $save_filename (@all_unpacked_files) {<br />
+ #Clean up $save_filename so as to keep taint happy<br />
+ $save_filename =~ /^(.*)$/; $save_filename=$1;<br />
+ ($new_filename=$save_filename) =~ s/([^a-z0-9\.\-\_\+\=\~]+)//gi;<br />
+ if ($save_filename ne $new_filename) {<br />
+ $new_filename =~ /(\.[^\.]+)$/;<br />
+ $new_filename=&uniq_id."$new_filename";<br />
+ rename($save_filename,$new_filename);<br />
+ &debug("d_m: ren $save_filename to $new_filename");<br />
+ $save_filename=$new_filename;<br />
+ }<br />
+ #Who cares if it is or isn't tnef, just scan it!<br />
+ if ($tnef_binary) {<br />
+ $MAYBETNEF=`$tnef_binary --number-backups -d $ENV{'TMPDIR'}/ -f $ENV{'TMPDIR'}/$save_filename 2>&1`;<br />
+ $tnef_status=$?;<br />
+ &debug("d_m: is $ENV{'TMPDIR'}/$save_filename is a TNEF file?: $tnef_status [",&deltatime,"]");<br />
+ }<br />
+ }<br />
+ }<br />
+<br />
+ &debug("d_m: Check for zip files...");<br />
+ #Re-initialize directory listing<br />
+ opendir(DIR,"$ENV{'TMPDIR'}/")||&error_condition("cannot open dir $ENV{'TMPDIR'}/ - $!"); <br />
+ @all_unpacked_files = grep(!/^\.+$/, readdir(DIR));<br />
+ closedir(DIR);<br />
+ foreach $save_filename (@all_unpacked_files) {<br />
+ #Clean up $save_filename so as to keep taint happy<br />
+ $save_filename =~ /^(.*)$/; $save_filename=$1;<br />
+ ($new_filename=$save_filename) =~ s/([^a-z0-9\.\-\_\+\=\~]+)//gi;<br />
+ if ($save_filename ne $new_filename) {<br />
+ $new_filename =~ /(\.[^\.]+)$/;<br />
+ $new_filename=&uniq_id."$new_filename";<br />
+ rename($save_filename,$new_filename);<br />
+ &debug("d_m: ren $save_filename to $new_filename");<br />
+ $save_filename=$new_filename;<br />
+ }<br />
+ if ( $save_filename =~ /\.(zip|exe)$/i) {<br />
+ &unzip_file($save_filename);<br />
+ }<br />
+ }<br />
+<br />
+ if (!$redundant_scanning) {<br />
+ if (-f "$ENV{'TMPDIR'}/$save_filename") {<br />
+ system $rm_binary,"-f","$ENV{'TMPDIR'}/$save_filename";<br />
+ }<br />
+ }<br />
+<br />
+ my($decon_time)=tv_interval ($start_decon_time, [gettimeofday]);<br />
+ &debug("d_m: unpacking message took $decon_time seconds");<br />
+}<br />
+<br />
+sub init_scanners {<br />
+ my($start_init_scanners_time)=[gettimeofday];<br />
+ &debug("ini_sc: start scanning");<br />
+ chdir("$ENV{'TMPDIR'}/");<br />
+ <br />
+ #Delete original zip'ped attachment as there's no point <br />
+ #in the other scanners double-scanning it - unless $redundant scanning<br />
+ #is set....<br />
+ if ($redundant_scanning) {<br />
+ link("$scandir/$wmaildir/new/$file_id","$ENV{'TMPDIR'}/orig-$file_id");<br />
+ }<br />
+ &debug("ini_sc: recursively scan the directory $ENV{'TMPDIR'}/");<br />
+<br />
+ #Run AV scanners - even if the message is already going to be quarantined<br />
+ #due to some Policy: this way you get the definitive answer as to what is<br />
+ #a virus... The exception to this is if it looks like a DoS attack - then<br />
+ #don't run the AVs over it - as they may be the ones affected by the DoS...<br />
+<br />
+ # st: JLH has changed this part... let see if I can mantain mine compatible with him.<br />
+ &scanloop if (!$quarantine_DOS && !$SKIP_SCANNING);<br />
+<br />
+ chdir("$scandir");<br />
+<br />
+ my($decon_time)=tv_interval ($start_init_scanners_time, [gettimeofday]);<br />
+ &debug("ini_sc: scanning message took $decon_time seconds");<br />
+ &minidebug("ini_sc: finished scan of \"$ENV{'TMPDIR'}\"...");<br />
+}<br />
+<br />
+<br />
+sub perlscan_scanner {<br />
+ #This is most efficient if called from within deconstruct_msg<br />
+<br />
+ my($start_perlscan_time)=[gettimeofday];<br />
+ my (%array,$var,$lfile,$filename,$section,$apptype,$save_filename);<br />
+ my ($type,$desc,$file,$filepattern,$filepath);<br />
+ my ($normalized_hdr,$ps_skipfile,$extension);<br />
+ my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks,$fsize);<br />
+ my ($attachment_list,$perlscan_time);<br />
+ &debug("p_s: starting scan of directory \"$ENV{'TMPDIR'}\"...");<br />
+ <br />
+ # use DB_File;<br />
+ <br />
+ <br />
+ tie (%array, 'DB_File', "$db_filename.db", O_RDONLY, 0600) || &error_condition("cannot open $db_filename.db - $!");<br />
+<br />
+ if (!$quarantine_event && $illegal_mime && $headers{'mime-version'} && $BAD_MIME_CHECKS) {<br />
+ $destring="problem";<br />
+ $quarantine_description="Disallowed characters found in MIME headers" if (!$quarantine_description);<br />
+ $quarantine_event="Policy:Bad_MIME";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description'\n found in message";<br />
+ &debug("p_s: something to block! ($quarantine_description)");<br />
+ &minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("PERLSCAN:BAD_MIME_HEADER");<br />
+ }<br />
+ #check out headers against DB...<br />
+ <br />
+ foreach $var (sort keys(%array)) {<br />
+ ($type,$desc)=split(/\t/,$array{$var},2);<br />
+ &debug("p_s: '$var' = '$type' = '$desc'");<br />
+ if ($type !~ /^SIZE=(\-|)[0-9]+$/) {<br />
+ &debug("p_s: type is a header!");<br />
+ $type =~ s/^Policy\-//gi;<br />
+ $var=~s/^[0-9]+://;<br />
+ if (!grep(/^$type$/,@virtualheaders_array)) {<br />
+ #only force lowercase if they are "real" headers<br />
+ $type=tolower($type);<br />
+ }else{ <br />
+ $headers{$type}=$desc if ($headers{$type} eq "");<br />
+ }<br />
+ $virtualheader{$type}=$var;<br />
+ &debug("p_s: checking for objects containing $type: $var");<br />
+ $normalized_hdr=&normalize_string("$type:",$headers{$type});<br />
+<br />
+ #Check headers against the "virtualheaders" from quarantine-events.txt<br />
+ if ($headers{$type} ne "" && ($headers{$type} =~ /^$virtualheader{$type}$/ || $normalized_hdr =~ /^$virtualheader{$type}$/i)) {<br />
+ $quarantine_description="$desc";<br />
+ ($quarantine_event=$quarantine_description) =~ s/\s/_/g;<br />
+ $quarantine_event="Perlscan:".substr($quarantine_event,0,$QE_LEN);<br />
+ $quarantine_event=~s/_$//g;<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in file $ENV{'TMPDIR'}/$file";<br />
+ &debug("p_s: something to block! ($quarantine_description)");<br />
+ &minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("PERLSCAN:BAD_HDR_DB");<br />
+ last;<br />
+ }<br />
+ } else {<br />
+ &debug("p_s: type is a size!");<br />
+ }<br />
+ }<br />
+<br />
+ #opendir(DIR,"$ENV{'TMPDIR'}/")||&error_condition("cannot open dir $ENV{'TMPDIR'}/ - $!"); <br />
+ #@allfiles = grep(!/^\.+$/, readdir(DIR));<br />
+ #closedir(DIR);<br />
+ open(DIR,"$find_binary $ENV{'TMPDIR'}/ -type f |")||&error_condition("cannot open dir $ENV{'TMPDIR'}/ - $!");<br />
+ #append any ORIGINAL uuencoded filenames to this directory array<br />
+ #so that perlscanner can match on uuencoded filenames<br />
+ my @allfiles=<DIR>;<br />
+ close(DIR);<br />
+<br />
+ #merge all crypto details<br />
+ my ($CRYPTO_DETAILS)="$CRYPTO_TYPE:$DOMKEYS";<br />
+<br />
+<br />
+ #Block if "Sensitivity:" header set and yet no sign of encryption used<br />
+ if ($headers{'sensitivity'} =~ /private|confidential/i) {<br />
+ if ($virtualheader{'ISSENSITIVEANDNOCRYPTO'} ne "" && $CRYPTO_TYPE !~ /encrypted/) {<br />
+ $quarantine_description=$headers{'ISSENSITIVEANDNOCRYPTO'};<br />
+ ($quarantine_event=$quarantine_description) =~ s/\s/_/g;<br />
+ $quarantine_event="Policy:Must_Encrypt";<br />
+ $quarantine_event=~s/_$//g;<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
+ &debug("p_s: something to block! ($quarantine_description)");<br />
+ &minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("PERLSCAN:BAD_HDR_DB");<br />
+ }<br />
+ $CRYPTO_TYPE=~s/\)$/,private\)/;<br />
+ }<br />
+<br />
+ if ($virtualheader{'CRYPTODETAILS'} ne "" && !$quarantine_event && $CRYPTO_DETAILS ne "") {<br />
+ &debug("check crypto characteristics of this message against $virtualheader{'CRYPTODETAILS'}");<br />
+ if ($CRYPTO_DETAILS =~ /$virtualheader{'CRYPTODETAILS'}/) {<br />
+ $destring='problem';<br />
+ $quarantine_description=$headers{'CRYPTODETAILS'};<br />
+ $quarantine_event="Policy:No_Crypto";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in file $ENV{'TMPDIR'}/$file";<br />
+ &debug("p_s: something to block! ($quarantine_description)");<br />
+ &minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("PERLSCAN:BAD_HDR_DB");<br />
+ return;<br />
+ }<br />
+ }<br />
+ if ($#allfiles > $MAX_NUM_UNPACKED_FILES) {<br />
+ &debug("w_c: more than $MAX_NUM_UNPACKED_FILES files found - quarantine");<br />
+ &minidebug("w_c: more than $MAX_NUM_UNPACKED_FILES files found - quarantine");<br />
+ $illegal_mime=1;<br />
+ $destring='problem';<br />
+ $quarantine_description="Too many file components found (".$#allfiles.") - potential DoS";<br />
+ $quarantine_event="Policy:Many_Files";<br />
+ $quarantine_DOS=$quarantine_event;<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in file $ENV{'TMPDIR'}/$file";<br />
+ $file_desc .= "too_many:$msg_size\t" if ($file_desc !~ /\Q$file\E:$size\t/);<br />
+ &debug("p_s: something to block! ($quarantine_description)");<br />
+ &minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("PERLSCAN:BAD_ATTACH_LENGTH");<br />
+ return;<br />
+ }<br />
+ foreach $filepath (@allfiles,@uufile_list,@zipfile_list,@attachment_list) {<br />
+ chomp($filepath);<br />
+ ($file=$filepath)=~s/^.*\///g;<br />
+ #skip files that reformime/ripmime generates.<br />
+ #This will potentially allow baddies to smuggle files through<br />
+ #by using filenames like this... Nothing can be done about that:-(<br />
+ #Reformime generates filenames of the form:<br />
+ # 967067231.24320-X.host.name (where X is a number)<br />
+ #Ripmime generates filenames of the form:<br />
+ # textfileX (where X is a number)<br />
+ if ($file =~ /^[0-9]+\.[0-9]+\-[0-9]+\.$hostname|^(orig\-|)$file_id|^textfile[0-9]+/) {<br />
+ &debug("p_s: skipping auto-generated file $file");<br />
+ $ps_skipfile=1;<br />
+ } else {<br />
+ &debug("p_s: checking $file against perlscanner database...");<br />
+ $ps_skipfile=0;<br />
+ }<br />
+<br />
+ if (!$ps_skipfile && $virtualheader{'FILELENGTHTOOLONG'} ne "" && !$quarantine_event && length($file) > 256 && $BAD_MIME_CHECKS > 1 ) {<br />
+ &debug("w_c: majorly long attachment filename found - block it");<br />
+ &minidebug("w_c: majorly long attachment filename found - block it");<br />
+ $quarantine_description=$headers{'FILELENGTHTOOLONG'};<br />
+ $illegal_mime=1;<br />
+ $destring='problem';<br />
+ $quarantine_event="Policy:Attach_Length";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in file $ENV{'TMPDIR'}/$file";<br />
+ $file_desc .= "$file:$msg_size\t" if ($file_desc !~ /\Q$file\E:$size\t/);<br />
+ &debug("p_s: something to block! ($quarantine_description)");<br />
+ &minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("QMSWC:BAD_ATTACH_FILENAME");<br />
+ return;<br />
+ }<br />
+<br />
+ #Do the patently obvious filename security checks here<br />
+ if ( !$ps_skipfile && $BAD_MIME_CHECKS > 1) {<br />
+ #Not as thorough as I'd like - but I got too many false positives doing it more generically... :-(<br />
+ #The VALID_WINDOWS_EXTENSIONS is based on double-barrel virii caught in a years worth of Qmail-Scanner<br />
+ #logs (gotta love those logs!). Notice that I expressly allow "file.exe.exe" through - as the double-extension<br />
+ #doesn't hide anything [just implies a user made a mistake]<br />
+ if ($virtualheader{'FILEDOUBLEBARRELED'} ne "" && !$quarantine_event && ($file =~ /(^.*)\.($VALID_WINDOWS_EXTENSIONS)\s*\.($SNEAKY_WINDOWS_EXTENSIONS)$/i) && $file !~ /(\.[a-z0-9]{3})\1$|\.pp.\.pp.$/i) {<br />
+ $quarantine_description=$headers{'FILEDOUBLEBARRELED'};<br />
+ $illegal_mime=1;<br />
+ $destring='problem';<br />
+ $quarantine_event="Policy:Win_Ext";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in file $ENV{'TMPDIR'}/$file";<br />
+ $file_desc .= "$file:$msg_size\t" if ($file_desc !~ /\Q$file\E:$size\t/);<br />
+ &debug("p_s: something to block! ($quarantine_description)");<br />
+ &minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("QMSWC:BAD_ATTACH_FILENAME");<br />
+ return;<br />
+ }<br />
+ if ($virtualheader{'FILECLSID'} ne "" && !$quarantine_event && $file =~ /\{[0-9a-f]{8}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{12}\}$/i) {<br />
+ $quarantine_description=$headers{'FILECLSID'};<br />
+ $destring='problem';<br />
+ $quarantine_event="Policy:Win_CLSID";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in file $ENV{'TMPDIR'}/$file";<br />
+ $file_desc .= "$file:$msg_size\t" if ($file_desc !~ /\Q$file\E:$size\t/);<br />
+ &debug("p_s: something to block! ($quarantine_description)");<br />
+ &minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("QMSWC:BAD_ATTACH_FILENAME");<br />
+ return;<br />
+ }<br />
+ }<br />
+ if ($file =~ /(^.*)(\.[^\.]+)\.?$/) {<br />
+ $extension=tolower($2);<br />
+ } else {<br />
+ $extension="";<br />
+ }<br />
+ $lfile = tolower($file);<br />
+ &debug("p_s: file $file is lowercased to $lfile and has extension $extension") if (!$ps_skipfile);<br />
+ #Stat'ing attachment names from @attachment_list will fail on filenames that reformime rewrites<br />
+ #that's OK, as they'll still be picked up via their new filename<br />
+ ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat("$filepath");<br />
+ #As you stat virtual files as well as real ones, you can't do this check against virtual files...<br />
+ if ($effective_uid ne "" && $uid ne "" && $uid != $effective_uid) {<br />
+ $DEBUG=101;<br />
+ &error_condition("owner of unpacked file \"$filepath\" (uid=$uid) doesn't match UID of Qmail-Scanner (uid=$effective_uid) - can't expect this to work. Fix whatever is creating files with uid=$uid");<br />
+ }<br />
+ if ($ino && $file_desc !~ /\Q$file\E:$size\t/) {<br />
+ #Sanity check so that the virtual attachments don't get double-counted<br />
+ $file_desc .= "$file:$size\t";<br />
+ }<br />
+ &debug("p_s: compare $lfile (size $size) against perlscanner database") if (!$ps_skipfile);<br />
+ if ( $array{$extension} && !$ps_skipfile ) {<br />
+ $destring="Disallowed attachment type";<br />
+ ($fsize,$quarantine_description) = split(/\t/,$array{$extension},2);<br />
+ $attachment_list.="$file:$size,";<br />
+ }else{<br />
+ foreach $filepattern (keys %array) {<br />
+ #&debug("p_s: does \"$filepattern\" match against $lfile?");<br />
+ if ( $lfile =~ /^${filepattern}$/i) {<br />
+ #$destring="Disallowed attachment type";<br />
+ ($fsize,$quarantine_description) = split(/\t/,$array{$filepattern},2);<br />
+ $attachment_list.="$file:$size,";<br />
+ }<br />
+ }<br />
+ }<br />
+ $fsize=~s/^SIZE=//;<br />
+ if (!$ps_skipfile && $quarantine_description && !$quarantine_event && ($size eq $fsize || $fsize =~ /^-1$/i) ) {<br />
+ ($quarantine_event=$quarantine_description) =~ s/\s/_/g;<br />
+ if ($quarantine_event=~/gr[ea]ylist/i) {<br />
+ $quarantine_event="Perlscan:Greylisted";<br />
+ }else{<br />
+ $quarantine_event="Perlscan:".substr($quarantine_event,0,$QE_LEN);<br />
+ }<br />
+ $quarantine_event=~s/_$//g;<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in file $ENV{'TMPDIR'}/$file";<br />
+ $section=$apptype=$save_filename=$filename="";<br />
+ &debug("p_s: something to block! ($quarantine_description)");<br />
+ &minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("PERLSCAN:BAD_ATTACHMENT_TYPE");<br />
+ # return;<br />
+ }<br />
+ }<br />
+ untie %array;<br />
+<br />
+<br />
+ if ($CRYPTO_TYPE=~/CR:ZIP/ && $virtualheader{'ZIPPASSWORDPROTECTED'} ne "" && !$quarantine_event) {<br />
+ $quarantine_description=$headers{'ZIPPASSWORDPROTECTED'};<br />
+ &debug("u_f: $quarantine_description");<br />
+ &minidebug("u_f: $quarantine_description");<br />
+ $destring='problem';<br />
+ $quarantine_event="Policy:Encrypted_ZIP";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in zip file";<br />
+ $file_desc .= "encrypted_zip:$msg_size\t";<br />
+ &debug("u_f: something to block! ($quarantine_description)");<br />
+ &minidebug("u_f: something to block! ($quarantine_description)");<br />
+ &eventlog("PERLSCAN:BAD_ATTACHMENT_TYPE");<br />
+ return;<br />
+ }<br />
+<br />
+ # st: cosmetic, if the messages is spam don't call it a virus.<br />
+ if ($quarantine_description =~ /spam/i) {<br />
+ $destring='problem';<br />
+ }<br />
+<br />
+ chdir("$scandir/");<br />
+ my($stop_perlscan_time)=[gettimeofday];<br />
+ $perlscan_time = tv_interval ($start_perlscan_time, $stop_perlscan_time);<br />
+ &debug("p_s: finished scan of dir \"$ENV{'TMPDIR'}\" in $perlscan_time secs");<br />
+ &minidebug("p_s: finished scan in $perlscan_time secs");<br />
+}<br />
+<br />
+<br />
+sub scanloop {<br />
+ #my($scanType)=@_;<br />
+ #&debug("scanloop($scanType): starting scan of directory \"$ENV{'TMPDIR'}\"...");<br />
+ &debug("scanloop: starting scan of directory \"$ENV{'TMPDIR'}\"...");<br />
+<br />
+ my ($scanner);<br />
+ #Remember any policy blocks that have already occurred, but reset<br />
+ #$quarantine_event so that if a virus is found, that "wins"<br />
+ #$quarantine_event_tmp=$quarantine_event; # st: done above.<br />
+ $quarantine_event='0';<br />
+ foreach $scanner (@scanner_array) {<br />
+ # st: if this recipient has spamassassin in his array we will add the X-Spam headers.<br />
+ $sa_rcpt='1' if ( $scanner =~ /spam/ );<br />
+<br />
+ # st: s_p_d, if we have multiples recipients (a lot) run each scanner just once... (except SA)<br />
+ if (exists $found_event{$scanner}) {<br />
+ ($destring,$quarantine_event,$quarantine_description,$description)=split(/\t/,$found_event{$scanner});<br />
+ $scanner =~ s/^(.*)_scanner$/$1/;<br />
+ $scanner =~ s/^perlscan$/p_s/;<br />
+<br />
+ # st: spamassassin and multiple recipients...<br />
+ if ($scanner =~ /spam/i) {<br />
+ if ($msg_size > 250000) {<br />
+ &debug("SA: message too big - skip it");<br />
+ &minidebug("SA: message too big - skip it");<br />
+ next;<br />
+ }<br />
+ if ($sa_sql) {<br />
+ # st: rerun SA, each user could have his own required_hits...<br />
+ # but we cannot run again verbose_spamassassin, then run sa_alt and add sa_report<br />
+ # It is better forget verbose_spamassassin for ever...<br />
+ if (!$sa_fast) {<br />
+ $sa_alt='1';<br />
+ $sa_debug='1';<br />
+ $sa_hdr_report='1';<br />
+ }<br />
+ $scanner = "spamassassin_alt" if ($sa_alt);<br />
+ &{$scanner} (1);<br />
+ next;<br />
+ } else {<br />
+ &check_sa_score ($sa_hits,0,1) if ($sa_hits && ($sa_hits ne "\?"));<br />
+ if ($sa_hits < $required_hits || ($sa_hits eq "\?")) {<br />
+ &debug("SA: finished scan for $one_recip - hits=$sa_hits/$required_hits");<br />
+ &minidebug("SA: finished scan for $one_recip - hits=$sa_hits/$required_hits");<br />
+ }<br />
+ }<br />
+ next;<br />
+ }<br />
+<br />
+ if ($quarantine_description ne "") {<br />
+ &debug("$scanner: $destring found $quarantine_description");<br />
+ &minidebug("$scanner: $destring found $quarantine_description");<br />
+ last;<br />
+ } else {<br />
+ &debug("$scanner: already checked and clear, skip");<br />
+ &minidebug("$scanner: already checked and clear, skip");<br />
+ next;<br />
+ }<br />
+ }<br />
+<br />
+ #Any scanner errors caused by broken zip files/etc will be ignored<br />
+ # - not sure how that should be handled...<br />
+ &debug("scanloop: scanner=$scanner,plain_text_msg=$plain_text_msg");<br />
+ <br />
+ # st: call spamassassin_alt if sa_alt is enabled<br />
+ $scanner = "spamassassin_alt" if ( $scanner =~ /spam/i && $sa_alt );<br />
+<br />
+ # st: I am not sure if this is correct<br />
+ if ($scanner =~ /perl/i) {<br />
+ $quarantine_event=$quarantine_event_tmp;<br />
+ }<br />
+<br />
+ #Just run virus scanners over mail that isn't plain text<br />
+ if ($plain_text_msg) {<br />
+ #If it's plain text - just run anti-spam checks and perl_scanner<br />
+ &{$scanner} if ($scanner =~ /spam|perl/i);<br />
+ } else {<br />
+ &{$scanner};<br />
+ }<br />
+<br />
+ $scanner = "spamassassin" if ($scanner eq "spamassassin_alt");<br />
+ if ($quarantine_event) {<br />
+ #Make sure this is set correctly<br />
+ $destring="virus" if ($quarantine_event !~ /spam/i && $scanner !~ /perl/i );<br />
+ $found_event{$scanner}="$destring\t$quarantine_event\t$quarantine_description\t$description";<br />
+ # st: mark the viruses we don't want to quarantine, but delete them<br />
+ if (($virus_to_delete ne "") && ($quarantine_description=~/($virus_to_delete)/i)) {<br />
+ $del_message='1';<br />
+ &debug("v_t_d: Virus ($quarantine_description), dropping");<br />
+ &minidebug("v_t_d: Virus ($quarantine_description), dropping");<br />
+ }<br />
+ #If one scanner finds a virus - why run the rest over it?<br />
+ last;<br />
+ }<br />
+ # st: per user settings... I have to think about...<br />
+ $found_event{$scanner}="\t\t\t";<br />
+ }<br />
+ &debug("scanloop: finished scan of \"$ENV{'TMPDIR'}\"...");<br />
+}<br />
+<br />
+sub qmail_requeue {<br />
+ my($sender,$env_recips,$msg)=@_;<br />
+ my ($temp,$findate);<br />
+<br />
+ &debug("q_r: fork off child into $qmailqueue...");<br />
+ <br />
+ #($recips=$env_recips) =~ s/^T//;<br />
+ #$recips =~ s/\0T/\,/g;<br />
+ #$recips =~ /^(.*)\0+$/;<br />
+ #$recips = $1;<br />
+ #$recips =~ s/\0+$//g;<br />
+ <br />
+ # Create a pipe through which to send the envelope addresses.<br />
+ pipe (EOUT, EIN) or &error_condition("Unable to create a pipe. - $!");<br />
+ select(EOUT);$|=1;<br />
+ select(EIN);$|=1;<br />
+ # Fork qmail-queue. The qmail-queue child will then open fd 0 as<br />
+ # $message and fd 1 as the reading end of the envelope pipe and exec<br />
+ # qmail-queue. The parent will read in the addresses and pass them <br />
+ # through the pipe and then check the exit status.<br />
+<br />
+ $elapsed_time = tv_interval ($start_time, [gettimeofday]);<br />
+ local $SIG{PIPE} = 'IGNORE';<br />
+ my $pid = fork;<br />
+<br />
+ if (not defined $pid) {<br />
+ &error_condition ("Unable to fork. (#4.3.0) - $!");<br />
+ } elsif ($pid == 0) {<br />
+ # In child. Mutilate our file handles.<br />
+ close EIN; <br />
+ <br />
+ open(STDIN,"<$msg")|| &error_condition ("Unable to reopen fd 0. (#4.3.0) - $!");<br />
+<br />
+ open (STDOUT, "<&EOUT") || &error_condition ("Unable to reopen fd 1. (#4.3.0) - $!");<br />
+ select(STDIN);$|=1;<br />
+ &debug("q_r: xstatus=$xstatus");<br />
+ open (QMQ, "|$qmailqueue")|| &error_condition ("Unable to open pipe to $qmailqueue [$xstatus] (#4.3.0) - $!");<br />
+ ($sec,$min,$hour,$mday,$mon,$year) = gmtime(time);<br />
+ $elapsed_time = tv_interval ($start_time, [gettimeofday]);<br />
+ $findate = POSIX::strftime( "%d %b ",$sec,$min,$hour,$mday,$mon,$year);<br />
+ $findate .= sprintf "%02d %02d:%02d:%02d -0000", $year+1900, $hour, $min, $sec;<br />
+ print QMQ "Received: from $remote_smtp_ip$remote_smtp_auth by $hostname (envelope-from <$returnpath>, uid $real_uid) with qmail-scanner-$VERSION \n";<br />
+ if ($scanner_array[0] ne "none") {<br />
+ print QMQ " ($SCANINFO \n Clear:$tag_score$tag_sa_score. \n";<br />
+ print QMQ " Processed in $elapsed_time secs); $findate\n";<br />
+ if ($sa_comment ne "" && $sa_rcpt) {<br />
+ print QMQ "X-Spam-Status: $sa_comment\n";<br />
+ print QMQ "X-Spam-Level: $sa_level\n" if ($sa_level ne "");<br />
+ print QMQ "X-Spam-Report: SA TESTS\n$sa_report\n" if ($sa_report && $sa_hdr_report);<br />
+ }<br />
+ #Only add these headers for Internet-incoming<br />
+ if ( $descriptive_hdrs && !$QS_RELAYCLIENT) {<br />
+ print QMQ "${V_HEADER}-Mail-From: $returnpath via $hostname\n";<br />
+ print QMQ "${V_HEADER}-Rcpt-To: $recips\n" if ($descriptive_hdrs eq "2");<br />
+ print QMQ "$V_HEADER: $VERSION (Clear:$tag_score$tag_sa_score. Processed in $elapsed_time secs Process $nprocess)\n";<br />
+ }<br />
+ }<br />
+ my $still_headers=1;<br />
+ my $seen_env=0;<br />
+ while (<STDIN>) {<br />
+ if ($still_headers && $sa_fast) {<br />
+ #break any X-Spam-Status/Level IFF we've set a SA value ourselves. Easier than removing - and it leaves<br />
+ #them around for diagnosis...<br />
+ if ($sa_comment ne "" && $sa_rcpt && /^(X-Spam-Status|X-Spam-Flag|X-Spam-Level|X-Spam-Report):/i) {<br />
+ s/^(X-Spam-Status|X-Spam-Flag|X-Spam-Level|X-Spam-Report):/${V_HEADER}-MOVED-$1:/i;<br />
+ }<br />
+ if ($sa_comment =~ /^yes/i && $sa_subject ne "" && !/^Subject: \Q$sa_subject\E/i && /^(Subject):(\s?)([^\n]+)\n/i && $sa_rcpt) {<br />
+ $altered_subject="$1: $sa_subject $3";<br />
+ if ($altered_subject !~ /^: \Q$sa_subject\E/) {<br />
+ &debug("altering subject line to $altered_subject");<br />
+ print QMQ "$altered_subject\n";<br />
+ next;<br />
+ }<br />
+ }<br />
+ $still_headers=0 if (/^(\r|\r\n|\n)$/);<br />
+ #Insert Subject: line if e-mail dosn't contain one but must be tagged<br />
+ print QMQ "Subject: $sa_subject\n" if ((!$still_headers) && ($sa_comment =~ /^yes/i) && (!$altered_subject) && $sa_subject ne "" && $sa_rcpt);<br />
+<br />
+ }<br />
+ print QMQ;<br />
+ }<br />
+ close(QMQ); #||&error_condition("Unable to close pipe to $qmailqueue (#4.3.0) - $!");<br />
+ $xstatus = ( $? >> 8 );<br />
+ if ( $xstatus > 10 && $xstatus < 41 ) {<br />
+ &error_condition("mail server permanently rejected message. (#5.3.0) - $!",$xstatus);<br />
+ } elsif ($xstatus > 0) {<br />
+ &error_condition("Unable to open pipe to $qmailqueue [$xstatus] (#4.3.0) - $!",$xstatus);<br />
+ }<br />
+ #This child is finished - exit<br />
+ exit;<br />
+ } else {<br />
+ # In parent.<br />
+ close EOUT;<br />
+ <br />
+ # Feed the envelope addresses to qmail-queue.<br />
+ print EIN "$sender\0$env_recips";<br />
+ close EIN || &error_condition ("Write error to envelope pipe. (#4.3.0) - $!");<br />
+}<br />
+<br />
+ # We should now have queued the message. Let's find out the exit status<br />
+ # of qmail-queue.<br />
+ waitpid ($pid, 0);<br />
+ $xstatus =($? >> 8);<br />
+ if ( $xstatus > 10 && $xstatus < 41 ) {<br />
+ &error_condition("mail server permanently rejected message. (#5.3.0) - $!",$xstatus);<br />
+ } elsif ($xstatus > 0) {<br />
+ &error_condition("Unable to close pipe to $qmailqueue [$xstatus] (#4.3.0) - $!",$xstatus);<br />
+ }<br />
+}<br />
+<br />
+<br />
+sub valid_virus_to_report {<br />
+ my ($virus_type)=@_;<br />
+ my ($virus)='';<br />
+ # This subroutine is used to determine if the virus found during the scan<br />
+ # is reportable. i.e. do we want to send a message to this user or not as is<br />
+ # the case with the KLEZ virus.<br />
+ #&debug("v_v_t_r: called with $virus_type");<br />
+ foreach $virus (@silent_viruses_array) {<br />
+ #&debug("v_v_t_r: does $virus_type contain $virus?");<br />
+ if ($virus_type =~ /$virus/i) {<br />
+ &debug("v_v_t_r: $virus_type contain $virus - so don't notify the sender");<br />
+ &minidebug("v_v_t_r: Description contain \"$virus\" - so don't notify the sender");<br />
+ return 0;<br />
+ }<br />
+ }<br />
+ return 1;<br />
+}<br />
+<br />
+sub automated_msg {<br />
+ if ($headers{'x-loop'} || $headers{'auto-submitted'} !~ /^(|no)$/i || $headers{'x-listname'} || $headers{'x-listmember'} || $headers{'mailing-list'} || $headers{'x-mailing-list'} || $headers{'precedence'} =~ /^(bulk|list|junk)$/i || $returnpath =~ /^$|^\#\@\[\]$|anonymous|nobody|daemon|request|bounce|mailer|postm|owner|list|words|majordom|experts|\-(return|error)/i) {<br />
+ return 1;<br />
+ } else {<br />
+ return 0;<br />
+ }<br />
+}<br />
+<br />
+sub bounce_msg {<br />
+ if ($returnpath =~ /^$|^\#\@\[\]$|(daemon|bounce|mailer|postm)/i) {<br />
+ return 1;<br />
+ } else {<br />
+ return 0;<br />
+ }<br />
+}<br />
+<br />
+sub is_unreplyable_email {<br />
+ my ($addr_type)=@_;<br />
+ my ($dom,$is_local)='';<br />
+ #This subroutine is used to see if the sender of this message<br />
+ #was a mailing-list/postmaster/etc, or the recipient is a local user. <br />
+ #If it is we don't want to send a reply.<br />
+ #&debug("i_u_e: called with $addr_type");<br />
+ <br />
+ if ($addr_type eq "recips") {<br />
+ foreach $dom (@local_domains_array) {<br />
+ #&debug("i_u_e: does $recips contain $dom?");<br />
+ if ($recips =~ /$dom$/i) {<br />
+ #&debug("i_u_e: yes it does!");<br />
+ $is_local++;<br />
+ }<br />
+ }<br />
+ } else {<br />
+ $is_local="99";<br />
+ if (&automated_msg ) {<br />
+ #&debug("i_u_e: $addr_type is a mailing-list");<br />
+ return 1;<br />
+ }<br />
+ }<br />
+ #<br />
+ #Only reply if it is a local address<br />
+ if (!$is_local) {<br />
+ #&debug("i_u_e: is_local=$is_local");<br />
+ return 1;<br />
+ } else {<br />
+ #&debug("i_u_e: is_local=$is_local");<br />
+ return 0;<br />
+ }<br />
+}<br />
+<br />
+sub email_quarantine_report {<br />
+ my($start_email_time)=[gettimeofday];<br />
+ if ($quarantine_spam) {<br />
+ # st: now spam is quarantined in a separated directory, but also it is <br />
+ # possible to set a directory per user, so I must check the directory...<br />
+ if (! -d "$scandir/quarantine/$smaildir") {<br />
+ mkdir("$scandir/quarantine/$smaildir",0750) || &error_condition("cannot create $scandir/quarantine/$smaildir - $!");<br />
+ mkdir("$scandir/quarantine/$smaildir/new",0750) || &error_condition("cannot create $scandir/quarantine/$smaildir/new - $!");<br />
+ mkdir("$scandir/quarantine/$smaildir/cur",0750) || &error_condition("cannot create $scandir/quarantine/$smaildir/cur - $!");<br />
+ mkdir("$scandir/quarantine/$smaildir/tmp",0750) || &error_condition("cannot create $scandir/quarantine/$smaildir/tmp - $!");<br />
+ }<br />
+ #Use a different maildir for SPAM<br />
+ $vmaildir=$smaildir;<br />
+ $quarantine_event=$quarantine_spam;<br />
+ }elsif ($quarantine_event =~ /^(Policy|Perlscan)/) {<br />
+ $destring="policy-violation";<br />
+ #Use a different maildir for Policy-blocks<br />
+ $vmaildir=$pmaildir;<br />
+ }<br />
+<br />
+ # st: if we have multiple recipient quarantine the file once, unless we have differents smaildir...<br />
+ return if ( -f "$scandir/quarantine/$vmaildir/new/$file_id");<br />
+<br />
+ if ($vmaildir ne "none") {<br />
+ &debug("e_v_r: quarantine msg to $scandir/quarantine/$vmaildir/new/$file_id");<br />
+ ### st: if your '$smaildir' resides in a different file system (partition) than<br />
+ ### '$wmaildir' comment the next line and uncomment the two following lines.<br />
+ link("$scandir/$wmaildir/new/$file_id","$scandir/quarantine/$vmaildir/new/$file_id")||&error_condition("cannot link $scandir/$wmaildir/new/$file_id into $scandir/quarantine/$vmaildir/new/ - $!");<br />
+ # use File::Copy;<br />
+ # copy("$scandir/$wmaildir/new/$file_id","$scandir/quarantine/$vmaildir/new/$file_id")||&error_condition("cannot copy $scandir/$wmaildir/new/$file_id into $scandir/quarantine/$vmaildir/new/ - $!");<br />
+ }<br />
+<br />
+ open(QTINE,">>$scandir/quarantine/$vmaildir/new/$file_id");<br />
+ print QTINE "\n*** Qmail-Scanner Quarantine Envelope Details Begin ***\n";<br />
+ print QTINE "${V_HEADER}-Mail-From: \"$returnpath\" via $hostname\n";<br />
+ print QTINE "${V_HEADER}-Rcpt-To: \"$recips\"\n";<br />
+ print QTINE "$V_HEADER: $VERSION ($SCANINFO $destring Found. Processed in ",tv_interval($start_time,[gettimeofday])," secs) process $nprocess \n";<br />
+ print QTINE "Quarantine-Description: $quarantine_description\n";<br />
+ if (($quarantine_description =~ /spam/i) && $sa_report) {<br />
+ print QTINE "SA_REPORT hits = $sa_hits/$required_hits\n$sa_report\n";<br />
+ }<br />
+ print QTINE "*** Qmail-Scanner Envelope Details End ***\n";<br />
+ close QTINE;<br />
+<br />
+ &email_sender("admin");<br />
+ if (!$quarantine_spam) {<br />
+ &email_sender("sender") if (&valid_virus_to_report($quarantine_description));<br />
+ if ($trecips =~ /\0T/) {<br />
+ for $recip (split(/\0T/,$trecips)) {<br />
+ &email_recips($recip);<br />
+ }<br />
+ } else {<br />
+ &email_recips($recips);<br />
+ }<br />
+ #This is almost 100% certainly SPAM - no point in notifying anyone<br />
+ }<br />
+ &write_quarantine_report;<br />
+ $elapsed_time = tv_interval ($start_time, [gettimeofday]);<br />
+ &debug("e_v_r: email_quarantine_report took ".tv_interval ($start_email_time, [gettimeofday])." seconds to execute");<br />
+}<br />
+<br />
+sub cleanup {<br />
+ closelog();<br />
+ chdir("$scandir/");<br />
+ if ($archiveit !~ /^(1|yes)$/i) {<br />
+ #This will only archive mail where the sender or recipient matches the regex that is $archiveit<br />
+ if ($headers{'MAILFROM'} !~ /$archiveit/i && $headers{'RCPTTO'} !~ /$archiveit/i) {<br />
+ $archiveit=0;<br />
+ }<br />
+ }<br />
+ if (!$archiveit) {<br />
+ &debug("cleanup: $rm_binary -rf $ENV{'TMPDIR'}/ $scandir/$wmaildir/new/$file_id") ;<br />
+ } else {<br />
+ # check if $archivedir exists<br />
+ if (!-d "$scandir/$archivedir") {<br />
+ mkdir("$scandir/$archivedir",0750) || &error_condition("cannot create $scandir/$archivedir - $!");<br />
+ mkdir("$scandir/$archivedir/new",0750) || &error_condition("cannot create $scandir/$archivedir/new - $!");<br />
+ mkdir("$scandir/$archivedir/cur",0750) || &error_condition("cannot create $scandir/$archivedir/cur - $!");<br />
+ mkdir("$scandir/$archivedir/tmp",0750) || &error_condition("cannot create $scandir/$archivedir/tmp - $!");<br />
+ }<br />
+ if ( -f "$scandir/$wmaildir/new/$file_id" ) {<br />
+ &debug("cleanup: archiving into $scandir/$archivedir/new/");<br />
+ &minidebug("cleanup: archiving into $scandir/$archivedir/new/");<br />
+ rename("$scandir/$wmaildir/new/$file_id","$scandir/$archivedir/new/$file_id");<br />
+ #This will do for now. Not pretty - but very cheap!<br />
+ #We need to append this information, otherwise how do you know who this message<br />
+ #was from or to?<br />
+ #<br />
+ open(ARCHIVE,">>$scandir/$archivedir/new/$file_id");<br />
+ print ARCHIVE "\n*** Qmail-Scanner Envelope Details Begin ***\n";<br />
+ print ARCHIVE "${V_HEADER}-Mail-From: \"$returnpath\" via $hostname\n";<br />
+ print ARCHIVE "${V_HEADER}-Rcpt-To: \"$recips\"\n";<br />
+ print ARCHIVE "$V_HEADER: $VERSION ($SCANINFO Clear:$tag_score$tag_sa_score. Processed in ",tv_interval($start_time,[gettimeofday])," secs)\n";<br />
+ if (($quarantine_description =~ /spam/i) && $sa_report) {<br />
+ print ARCHIVE "SA_REPORT hits = $sa_hits/$required_hits\n$sa_report\n";<br />
+ }<br />
+ print ARCHIVE "*** Qmail-Scanner Envelope Details End ***\n";<br />
+ close ARCHIVE;<br />
+ } <br />
+ }<br />
+ if ($DEBUG < 100 && $file_id ne "") {<br />
+ chdir("$scandir/");<br />
+ system("$rm_binary -rf $ENV{'TMPDIR'}/ $scandir/$wmaildir/new/$file_id");<br />
+ }<br />
+<br />
+}<br />
+<br />
+<br />
+sub scan_queue {<br />
+ my ($scanner,$SCANINFO,$files,$sweep_eng,$sweep_product,$sophie_eng,$dir);<br />
+ my $start_scan_time =time;<br />
+ my ($inocucmd_eng,$inocucmd_product,$spamassassin_eng);<br />
+ <br />
+ chdir($scandir);<br />
+ &debug("s_q: re-create the quarantine version file");<br />
+ &minidebug("s_q: re-create the quarantine version file");<br />
+ foreach $scanner (@scanners_installed) {<br />
+ $scanner =~ s/_scanner//;<br />
+ &debug("s_q: detecting version of $scanner");<br />
+ if ($scanner eq "uvscan") {<br />
+ open(UV,"$uvscan_binary --version|")||die "failed to call $uvscan_binary --version - $!";<br />
+ while (<UV>) {<br />
+ chomp;<br />
+ if (/^Scan engine (v[0-9\.]+) /) {<br />
+ $SCANINFO .="uvscan: $1/";<br />
+ } elsif (/^Virus data file (v[0-9\.]+) /) {<br />
+ $SCANINFO .= "$1. ";<br />
+ }<br />
+ }<br />
+ close(UV);<br />
+ } elsif ($scanner eq "csav") {<br />
+ open(CS,"$csav_binary -virno|")||die "failed to call $csav_binary -virno - $!";<br />
+ while (<CS>) {<br />
+ chomp;<br />
+ if (/Command Software AntiVirus for Linux (version [0-9\.]+)/) {<br />
+ $SCANINFO .="csav: $1/";<br />
+ } elsif (/^CSA[V]: (.*)/) {<br />
+ $SCANINFO .= "$1/";<br />
+ }<br />
+ }<br />
+ close(CS);<br />
+ } elsif ($scanner eq "trophie" ) {<br />
+ open(IS,"$trophie_binary -v 2>&1|")||die "failed to call $trophie_binary -v - $!";<br />
+ while (<IS>) {<br />
+ chomp;<br />
+ if (/VSAPI version (.*)/) {<br />
+ $SCANINFO .= "trophie: $1/";<br />
+ } elsif (/Pattern version ([0-9]+) \(pattern number ([0-9]+)\)/) {<br />
+ $SCANINFO .= "$1/$2. ";<br />
+ }<br />
+ }<br />
+ close(IS);<br />
+ } elsif ($scanner eq "iscan") {<br />
+ open(IS,"$iscan_binary -v|")||die "failed to call $iscan_binary -v - $!";<br />
+ while (<IS>) {<br />
+ chomp;<br />
+ if (/Virus Scanner (v[0-9\.]+), VSAPI (v[0-9\.\-]+)/) {<br />
+ $SCANINFO .="iscan: $1/$2/";<br />
+ } elsif (/Pattern version ([0-9\.]+)/) {<br />
+ $SCANINFO .= "$1/";<br />
+ } elsif (/Pattern number ([0-9\.]+)/) {<br />
+ $SCANINFO .= "$1. ";<br />
+ }<br />
+ }<br />
+ close(IS);<br />
+ } elsif ($scanner eq "fsecure") {<br />
+ open(FS,"$fsecure_binary --version|")||die "failed to call $fsecure_binary --version - $!";<br />
+ while (<FS>) {<br />
+ chomp;<br />
+ if (/^F-Secure.*(Release|version)\s+([0-9\.]+)\s+build\s+([0-9]+)/i) {<br />
+ $SCANINFO .="fsecure: $2/$3/";<br />
+ } elsif (/sign.def version ([0-9\.]+-[0-9\.]+-[0-9\.]+)/) {<br />
+ $SCANINFO .= "$1/";<br />
+ } elsif (/fsmacro.def version ([0-9\.]+-[0-9\.]+-[0-9\.]+)/) {<br />
+ $SCANINFO .= "$1/";<br />
+ } elsif (/sign2.def version ([0-9\.]+-[0-9\.]+-[0-9\.]+)/) {<br />
+ $SCANINFO .= "$1. ";<br />
+ } elsif (/F-PROT database version (.*)$/) {<br />
+ $SCANINFO .= "fprot($1)/";<br />
+ # Patch for version F-Secure 4.52 by Jyri<br />
+ } elsif (/AVP FPI Engine database version (.*)$/) {<br />
+ $SCANINFO .= "avp($1). ";<br />
+ } elsif (/Libra database version ([0-9\.]+-[0-9\.]+-[0-9\.]+)/) {<br />
+ $SCANINFO .= "libra database $1 / ";<br />
+ } elsif (/Orion database version ([0-9\.]+-[0-9\.]+-[0-9\.]+)/) {<br />
+ $SCANINFO .= "orion database $1 / ";<br />
+ } elsif (/AVP FPI Engine database version ([0-9\.]+-[0-9\.]+-[0-9\.]+)/) {<br />
+ $SCANINFO .= "avp fpi database $1. ";<br />
+ }<br />
+ }<br />
+ close(FS);<br />
+ $SCANINFO .= ". " if ($SCANINFO !~ /\. $/);<br />
+ } elsif ($scanner eq "fprot") { <br />
+ open(FP,"$fprot_binary \?|")||die "failed to call $fprot_binary --version - $!";<br />
+ while (<FP>) {<br />
+ chomp;<br />
+ if (/(F-PROT|Program version:) ([0-9\.]+)/) {<br />
+ $SCANINFO .="f-prot: $2/";<br />
+ } elsif (/Engine version: ([0-9\.]+)/) {<br />
+ $SCANINFO .= "$1";<br />
+ }<br />
+ }<br />
+ $SCANINFO .= ". ";<br />
+ close(FP);<br />
+ } elsif ($scanner eq "hbedv") {<br />
+ open(IS,"$hbedv_binary --version 2>&1 |")||die "failed to call $hbedv_binary --version - $!";<br />
+ while (<IS>) {<br />
+ chomp;<br />
+ if (/engine version:\s+([0-9\.]+)/) {<br />
+ $SCANINFO .= "hbedv: $1";<br />
+ } elsif (/vdf version:\s+([0-9\.]+)/) {<br />
+ $SCANINFO .= "/$1. ";<br />
+ }<br />
+ }<br />
+ close(IS);<br />
+ } elsif ($scanner eq "avp") {<br />
+ open(AVP,"$avp_binary -Y -VL 2>&1 |")||die "failed to call $avp_binary -Y -VL - $!";<br />
+ while (<AVP>) {<br />
+ chomp;<br />
+ if (/Version (([0-9\.]+)\s+build ([0-9\.]+)|([0-9\.]+))/) {<br />
+ if ($2) {<br />
+ $SCANINFO .= "avp: $1/$2. ";<br />
+ } else {<br />
+ $SCANINFO .= "avp: $1. ";<br />
+ }<br />
+ }<br />
+ }<br />
+ close(AVP);<br />
+ } elsif ($scanner eq "ravlin") {<br />
+ open(RAV,"$ravlin_binary --version 2>&1 |")||die "failed to call $ravlin_binary --version - $!";<br />
+ while (<RAV>) {<br />
+ chomp;<br />
+ if (/^Version: ([0-9\.]+)\./) {<br />
+ $SCANINFO .= "ravlin: $1. ";<br />
+ }<br />
+ }<br />
+ close(RAV);<br />
+ } elsif ($scanner eq "vexira") {<br />
+ open(VEX,"$vexira_binary --version 2>&1 |")||die "failed to call $vexira_binary --version - $!";<br />
+ while (<VEX>) {<br />
+ chomp;<br />
+ if (/^engine version:\s+([0-9\.]+)/) {<br />
+ $SCANINFO .= "vexira: $1. ";<br />
+ }<br />
+ }<br />
+ close(RAV);<br />
+ } elsif ($scanner eq "bitdefender") {<br />
+ open(BITDEF,"$bitdefender_binary --info 2>&1 |")||die "failed to call $bitdefender_binary --info - $!";<br />
+ while(<BITDEF>) {<br />
+ chomp;<br />
+ if (/^BDC\/Linux\-Console (.*) \(build ([^\)]+)\)/){<br />
+ $SCANINFO .= "bitdefender: $1/$2";<br />
+ }<br />
+ if (/^Engine signatures:\s+([0-9]+)/) {<br />
+ $SCANINFO .= "/$1. ";<br />
+ }<br />
+ }<br />
+ close(BITDEF);<br />
+ } elsif ($scanner eq "nod32") {<br />
+ open(NOD,"$nod32_binary --version 2>&1 |")||die "failed to call $nod32_binary --version - $!";<br />
+ while(<NOD>) {<br />
+ chomp;<br />
+ if (/\s(\d\S+)\s*$/){<br />
+ $SCANINFO .= "nod32: $1 ";<br />
+ }<br />
+ }<br />
+ close(NOD);<br />
+ } elsif ($scanner eq "sophie") {<br />
+ open(SOP,"$sophie_binary -v 2>&1|")||die "failed to call $sophie_binary -v - $!";<br />
+ while (<SOP>) {<br />
+ chomp;<br />
+ if (/Sophos engine version (.*)$/) {<br />
+ $sweep_eng=$1;<br />
+ } elsif (/Sophos IDE version ([0-9\.]+)/) {<br />
+ $sweep_product=$1;<br />
+ } elsif (/Sophie version\s+:\s+([0-9\.]+)/) {<br />
+ $sophie_eng=$1;<br />
+ }<br />
+ }<br />
+ $SCANINFO .= "sophie: $sophie_eng/$sweep_eng/$sweep_product. ";<br />
+ close(SOP);<br />
+ } elsif ($scanner eq "sweep") {<br />
+ open(SOP,"$sweep_binary -v|")||die "failed to call $sweep_binary -v - $!";<br />
+ while (<SOP>) {<br />
+ chomp;<br />
+ if (/Engine version\s+:\s+(.*)$/) {<br />
+ $sweep_eng=$1;<br />
+ } elsif (/Product version\s+:\s+(.*)$/) {<br />
+ $sweep_product=$1;<br />
+ }<br />
+ }<br />
+ $SCANINFO .= "sweep: $sweep_eng/$sweep_product. "; <br />
+ close(SOP);<br />
+ } elsif ($scanner eq "inocucmd") {<br />
+ open(IOP,"$inocucmd_binary -HEL|")||die "failed to call $inocucmd_binary -HEL - $!";<br />
+ while (<IOP>) {<br />
+ chomp;<br />
+ if (/Engine version:\s+(.*) ([0-9\/]+)$/) {<br />
+ $inocucmd_eng=$1;<br />
+ } elsif (/Data version:\s+(.*) ([0-9\/]+)$/) {<br />
+ $inocucmd_product=$1;<br />
+ }<br />
+ }<br />
+ $SCANINFO .= "inocucmd: $inocucmd_eng/$inocucmd_product. ";<br />
+ close(IOP);<br />
+ } elsif ($scanner eq "clamscan") {<br />
+ open(CLAMS,"$clamscan_binary --stdout -V|")||die "failed to call $clamscan_binary --stdout -V - $!";<br />
+ while (<CLAMS>) {<br />
+ chomp;<br />
+ if (/ersion ([0-9\.\-a-z]+)/i) {<br />
+ $SCANINFO .="clamscan: $1. ";<br />
+ }<br />
+ }<br />
+ close(CLAMS);<br />
+ } elsif ($scanner eq "clamdscan") {<br />
+ open(CLAMS,"$clamdscan_binary --version 2>&1|")||die "failed to call $clamdscan_binary --version - $!";<br />
+ while (<CLAMS>) {<br />
+ chomp;<br />
+ if (/ersion ([0-9\.\-a-z]+)/i) {<br />
+ $SCANINFO .="clamdscan: $1. ";<br />
+ } elsif (/^ClamAV ([^\/]+)\/([^\/]+)\//) {<br />
+ $SCANINFO .="clamdscan: $1/$2. ";<br />
+ }<br />
+ }<br />
+ close(CLAMS);<br />
+ } elsif ($scanner eq "spamassassin") {<br />
+ #X-Spam-Checker-Version: SpamAssassin 2.01<br />
+ open(SPAS,"$spamassassin_binary -V |")||die "failed to call $spamassassin_binary -V - $!";<br />
+ $spamassassin_eng="2.x";<br />
+ while (<SPAS>) {<br />
+ chomp;<br />
+ if (/^SpamAssassin version (.*)$/i) {<br />
+ $spamassassin_eng=$1;<br />
+ }<br />
+ }<br />
+ close(SPAS);<br />
+ $SCANINFO .= "spamassassin: $spamassassin_eng. ";<br />
+ } elsif ($scanner eq "perlscan") {<br />
+ $SCANINFO .="perlscan: $VERSION. ";<br />
+ } else {<br />
+ #Catch-all for other ones<br />
+ $SCANINFO .= "$scanner: ???. ";<br />
+ }<br />
+ }<br />
+ $SCANINFO =~ s/ \. / /g;<br />
+ open(VER,">$versionfile.tmp")||die "cannot write to $versionfile.tmp - $!";<br />
+ print VER $SCANINFO;<br />
+ close(VER);<br />
+ rename("$versionfile.tmp","$versionfile");<br />
+ &debug("s_q: cleaning up files older than 2 days via $find_binary $scandir/tmp -mtime +2 -exec $rm_binary -rf {} \;");<br />
+ &minidebug("s_q: cleaning up files older than 2 days via $find_binary $scandir/tmp -mtime +2 -exec $rm_binary -rf {} \;");<br />
+ my ($OLDFILES)=`$find_binary $scandir/tmp -mtime +2 -exec $rm_binary -rf {} \\; 2>/dev/null`;<br />
+ &debug("s_q: cleaning up quarantined mail older than 14 days via $find_binary $scandir/quarantine -type f -mtime +14 -exec $rm_binary -rf {} \;");<br />
+ &minidebug("s_q: cleaning up quarantined mail older than 14 days via $find_binary $scandir/quarantine -type f -mtime +14 -exec $rm_binary -rf {} \;");<br />
+ $OLDFILES=`$find_binary $scandir/quarantine/ -type f -mtime +14 -exec $rm_binary -f {} \\; 2>/dev/null`;<br />
+}<br />
+<br />
+sub write_quarantine_report {<br />
+ my ($temp,$desc,$report,$subj);<br />
+ $subj=$headers{'subject'};<br />
+ $subj =~ s/\t/ /g;<br />
+ $desc=$quarantine_description;<br />
+ $desc =~ s/\n\t/ /g;<br />
+ $nowtime = strftime("%a, %d %b %Y %H:%M:%S %Z", localtime(time));<br />
+ $report = "$nowtime\t$returnpath\t$recips\t$subj\t$desc\t$SCANINFO\n";<br />
+ open(QUARANTINELOG,">>$scandir/$quarantinelog");<br />
+ print QUARANTINELOG $report;<br />
+ close QUARANTINELOG;<br />
+ &debug("w_v_r: writing quarantine log report of: $report");<br />
+}<br />
+<br />
+sub scanner_info {<br />
+ open(SC,"<$versionfile")||&error_condition("cannot open $versionfile - did you initialise the system by running \"$prog -z\"? - $!");<br />
+ $SCANINFO = <SC>;<br />
+ $SCANINFO =~ s/\n|\r|\0/ /g;<br />
+ close(SC);<br />
+}<br />
+<br />
+sub generate_quarantine_db {<br />
+ # use DB_File;<br />
+ use vars qw( %h);<br />
+ my ($line,%array,$count,$match,$type,$descr,$entry,$descrip,$size);<br />
+ if ($opt_g) {<br />
+ print "perlscanner: generate new DB file from $db_filename.txt\n";<br />
+ unlink("$db_filename.db.tmp");<br />
+ tie (%array, 'DB_File', "$db_filename.db.tmp", O_CREAT|O_RDWR, 0640, $DB_HASH ) || &error_condition("cannot open for write $db_filename.db.tmp - $!");<br />
+ <br />
+ open(TXT,"<$db_filename.txt")||&error_condition("cannot read $db_filename.txt - $!");<br />
+<br />
+ #Remeber: all filenames are lowercased, but headers aren't...<br />
+ while (<TXT>) {<br />
+ $line++;<br />
+ next if (/^\#|^\s+$/); #ignore lines starting with hashes<br />
+ chomp;<br />
+ $count++;<br />
+ ($match,$type,$descr)=split(/\t+/,$_,3);<br />
+ if ( $match eq "" || ($type !~ /^SIZE=(\-|)[0-9]+$/ && $type !~ /^Policy-[0-9a-z\_\-]+:$/i) ) {<br />
+ print "ERROR: incorrect format on line \"$line\"\n";<br />
+ &error_condition("ERROR: incorrect format on line \"$line\"");<br />
+ } else {<br />
+ #Strip off any regex endings<br />
+ if ($type =~ /^SIZE=(|\-)[0-9]+$/) {<br />
+ #this is a filename/attachment<br />
+ if ( $match =~ /^\.dat$/i ) {<br />
+ <br />
+ print "ERROR: on line \"$line\".\nCannot block all .dat files. Will block too many normal messages.\n";<br />
+ &error_condition("ERROR: on line \"$line\".\nCannot block all .dat files. Will block too many normal messages.");<br />
+ next;<br />
+ }<br />
+ $match = tolower($match);<br />
+ } else {<br />
+ #this is for header matches<br />
+ $match =~ s/^\^|\$$//g;<br />
+ #Now make unique<br />
+ $match = "$line:$match";<br />
+ $type =~ s/:$//;<br />
+ }<br />
+ $array{"$match"}="$type\t$descr";<br />
+ }<br />
+ }<br />
+ close(TXT);<br />
+# $array->sync;<br />
+ untie %array ;<br />
+ rename("$db_filename.db.tmp","$db_filename.db");<br />
+ print "perlscanner: total of $count entries.\n";<br />
+ } else {<br />
+ print "perlscanner: reading from $db_filename.db\n";<br />
+ tie (%array, 'DB_File', "$db_filename.db", O_RDONLY, 0600) || &error_condition("cannot open $db_filename.db - $!");<br />
+ foreach $entry (keys %array) {<br />
+ $count++;<br />
+ ($type,$descrip)=split(/\t/,$array{$entry},2);<br />
+ if ( $type =~ /^SIZE=((\-|)[0-9]+)/) {<br />
+ if ($type eq "SIZE=-1") {<br />
+ $type="Any";<br />
+ } elsif ($type =~ /^SIZE=((\-|)[0-9]+)$/) {<br />
+ $type="$1 bytes";<br />
+ }<br />
+ print "File: \t$entry\n\t\t\tSize: $type\n\t\t\tDescription: $descrip\n\n";<br />
+ }<br />
+ if ($type =~ /^Policy-(.*)$/i) {<br />
+ $type=$1;<br />
+ #Strip off numeric uid...<br />
+ $entry =~ s/^[0-9]+://;<br />
+ if (grep(/^$type$/,@virtualheaders_array)) {<br />
+ print "Virtual Header: \t$type\n\t\t\tContent: ^$entry\$\n\t\t\tDescription: $descrip\n\n";<br />
+ } else {<br />
+ print "Email Header: \t$type\n\t\t\tContent: ^$entry\$\n\t\t\tDescription: $descrip\n\n";<br />
+ }<br />
+ }<br />
+ }<br />
+ untie %array;<br />
+ print "perlscanner: total of $count entries found.\n";<br />
+ }<br />
+}<br />
+<br />
+<br />
+<br />
+<br />
+sub show_version {<br />
+ my ($scanner);<br />
+ &scanner_info;<br />
+ print "<br />
+<br />
+$prog<br />
+<br />
+Version: $VERSION ($st_version)<br />
+<br />
+Perl: Summary of my perl5 (revision 5 version 8 subversion 8) configuration:\n\n";<br />
+<br />
+ if ($settings_pd && $opt_V) {<br />
+ print "Settings per domain: enabled\n\n";<br />
+ } else {<br />
+ print "Settings per domain: disabled\n\n" if ($opt_V);<br />
+ }<br />
+<br />
+ print "Scanners installed: ";<br />
+ foreach $scanner (@scanners_installed) {<br />
+ print " $scanner, ";<br />
+ }<br />
+<br />
+ if ($settings_pd && $opt_V) {<br />
+ print "\n\nScanners default: ";<br />
+ foreach $scanner (@scanners_default) {<br />
+ print " $scanner, ";<br />
+ }<br />
+ }<br />
+<br />
+ print "\n\nScanner versioning: $SCANINFO\n";<br />
+<br />
+ if ($spamc_binary =~ /spamc/ && $opt_V) {<br />
+ print "\nSpamassassin settings:\n";<br />
+ if ($sa_fast || $sa_alt) {<br />
+ print " Mode: fast_spamassassin\n";<br />
+ } else {<br />
+ print " Mode: verbose_spamassassin\n";<br />
+ }<br />
+ if ($sa_alt) {<br />
+ print " sa_alt: enabled / sa_debug = $sa_debug / sa_hdr_report_site = $sa_hdr_report_site\n";<br />
+ }<br />
+ if ($sa_forward_site) {<br />
+ print " sa_forward_site = '$sa_forward_site' / sa_fwd_verbose_site = $sa_fwd_verbose_site\n";<br />
+ }<br />
+ print " sa_subject_site = '$sa_subject_site'\n";<br />
+ print " sa_delta_site = $sa_delta_site\n";<br />
+ print " sa_quarantine_site = $sa_quarantine_site\n";<br />
+ print " sa_delete_site = $sa_delete_site / sa_reject_site = $sa_reject_site\n";<br />
+ }<br />
+<br />
+ print "<br />
+Operating System: $sysname, $release<br />
+Hardware: $machine";<br />
+ print "\n\n\n";<br />
+}<br />
+<br />
+<br />
+sub email_sender {<br />
+ #Don't e-mail bounced mail messages/etc!<br />
+ return if (&is_unreplyable_email('sender'));<br />
+ my($addr_type)=@_;<br />
+ my ($HDR,$hdr,$tmpsndrs,$tmpsubj,$polstring)='';<br />
+ my ($tmpmsgid)= &uniq_id() . "-" . $V_FROM;<br />
+ $polstring='policy' if (&notify_addr('nmlvadm'));<br />
+<br />
+ open(SM,"|$qmailinject -h -f ''")||&error_condition("cannot open $qmailinject for sending quarantine report - $!");<br />
+ print SM "From: \"$V_FROMNAME\" <$V_FROM>\n";<br />
+ if ($addr_type =~ /sender/) {<br />
+ $addr_type='psender' if ($NOTIFY_ADDRS =~ /psender/);<br />
+ if ($addr_type eq "sender") {<br />
+ if (!&is_unreplyable_email('sender') && &notify_addr('sender')) {<br />
+ &debug("e_s: sending quarantine report via: $qmailinject to sender address ($returnpath)");<br />
+ print SM "To: $returnpath\n";<br />
+ $tmpsndrs = "$returnpath";<br />
+ } else {<br />
+ &debug("e_s: don't notify sender");<br />
+ }<br />
+ } elsif ($addr_type eq "psender") {<br />
+ if (!&is_unreplyable_email('sender') && &notify_addr('sender') && ($quarantine_event =~ /^(policy|perlscan)/i && $quarantine_event !~ /(gr[ae]ylist|virus)/i)) {<br />
+ &debug("e_s: sending policy quarantine report via: $qmailinject to psender address ($returnpath)");<br />
+ &minidebug("e_s: sending policy quarantine report via: $qmailinject to psender address ($returnpath)");<br />
+ print SM "To: $returnpath\n";<br />
+ $tmpsndrs = "$returnpath";<br />
+ } else {<br />
+ &debug("e_s: don't notify psender");<br />
+ }<br />
+ } else {<br />
+ return;<br />
+ }<br />
+ } else {<br />
+ # st: if the mail is local and is set nmladm or nmlvadm,<br />
+ # always notify admin (maybe it is not good or a big site)<br />
+ if ( &notify_addr('admin') || ( &notify_addr('nmladm') && (!&is_unreplyable_email('sender') || $QS_RELAYCLIENT) ) || ( &notify_addr('nmlvadm') && (($quarantine_event =~ /^(policy|perlscan)/i && $quarantine_event !~ /(gr[ae]ylist|virus)/i && !&is_unreplyable_email('sender')) || $QS_RELAYCLIENT) ) ) {<br />
+ &debug("e_s: sending $polstring quarantine report via: $qmailinject to admin address ($QUARANTINE_CC)");<br />
+ print SM "To: $QUARANTINE_CC\n";<br />
+ $tmpsndrs .= "$QUARANTINE_CC";<br />
+ } else {<br />
+ &debug("e_s: don't notify admin");<br />
+ }<br />
+ }<br />
+ $tmpsubj="$destring found in sent message \"$headers{'subject'}\"";<br />
+ $tmpsubj =~ s/(\r|\0|\n)/ /g;<br />
+ if ($QS_RELAYCLIENT) {<br />
+ print SM "Subject: LOCAL USER - $tmpsubj\n";<br />
+ } else {<br />
+ print SM "Subject: $tmpsubj\n";<br />
+ }<br />
+ print SM "Message-ID: <".&uniq_id."\@$hostname>\n";<br />
+ print SM "X-Tnz-Problem-Type: 40\n";<br />
+ print SM "Auto-Submitted: auto-replied\n";<br />
+ if ($headers{'message-id'} ne "") {<br />
+ print SM "In-Reply-To: ",$headers{'message-id'},"\n";<br />
+ print SM "References: ",$headers{'message-id'},"\n";<br />
+ }<br />
+ print SM "MIME-Version: 1.0\n";<br />
+ print SM "Content-type: text/plain\n";<br />
+ print SM "Content-Transfer-Encoding: 8bit\n";<br />
+ #Only add these headers for Internet-incoming<br />
+ if ( $descriptive_hdrs && !$QS_RELAYCLIENT) {<br />
+ print SM "${V_HEADER}-Mail-From: $returnpath via $hostname\n";<br />
+ print SM "${V_HEADER}-Rcpt-To: $recips\n" if ($descriptive_hdrs eq "2");<br />
+ print SM "$V_HEADER: $VERSION ($SCANINFO $destring Found. \n";<br />
+ print SM " Processed in ",tv_interval($start_time,[gettimeofday])," secs)\n";<br />
+ }<br />
+ print SM "\n";<br />
+ if (&is_unreplyable_email('sender')) {<br />
+ print SM "<br />
+Attention: $V_FROMNAME.\n";<br />
+ print SM "<br />
+[This warning message is *not* being sent to the apparent originator<br />
+of the original message. This address appears to be that of a<br />
+mailing list or other automated email system.]\n";<br />
+ print SM "\n---------------------------------------\n\n";<br />
+ } else {<br />
+ print SM "<br />
+Attention: $returnpath\n";<br />
+ }<br />
+ print SM "\n<br />
+A $destring was found in an Email message you sent. <br />
+This Email scanner intercepted it and stopped the entire message<br />
+reaching its destination. <br />
+<br />
+The $destring was reported to be: <br />
+<br />
+$quarantine_description\n";<br />
+ if (($addr_type !~ /sender/) && ($quarantine_description =~ /spam/i) && $sa_report) {<br />
+ print SM "\nSA_REPORT hits = $sa_hits/$required_hits\n$sa_report\n\n";<br />
+ }<br />
+ if ($destring eq "virus") {<br />
+ print SM "\n<br />
+Please update your virus scanner or contact your IT support <br />
+personnel as soon as possible as you may have a virus on your system.\n";<br />
+ } else {<br />
+ print SM "\n<br />
+Please contact your IT support personnel with any queries regarding this <br />
+policy.\n";<br />
+ }<br />
+ print SM "\n<br />
+Your message was sent with the following envelope:<br />
+<br />
+MAIL FROM: $returnpath<br />
+RCPT TO: $recips <br />
+<br />
+... and with the following headers:\n\n";<br />
+ print SM "---\n";<br />
+ print SM "MAILFROM: $headers{'MAILFROM'}\n";<br />
+ print SM "RCPTTO: $headers{'RCPTTO'}\n";<br />
+ print SM "IP-Addr: $headers{'REMOTEIPADDR'}\n";<br />
+ print SM "$HEADERS\n";<br />
+ print SM "---\n";<br />
+ if ($addr_type !~ /sender/ ) {<br />
+ print SM "\n<br />
+<br />
+The original message is kept in:<br />
+<br />
+ $hostname:$scandir/quarantine/$vmaildir/new/$file_id<br />
+<br />
+where the $V_FROMNAME can further diagnose it.<br />
+<br />
+The Email scanner reported the following when it scanned that message:<br />
+<br />
+--- <br />
+$description<br />
+---\n";<br />
+ }<br />
+ close(SM);<br />
+ if ($log_details) {<br />
+ &log_msg("qmail-scanner","Clear:RC:1(127.0.0.1):",$elapsed_time,1100,$V_FROM,$tmpsndrs,$tmpsubj,$tmpmsgid,"quarantine-event.txt:1000");<br />
+ }<br />
+}<br />
+<br />
+sub email_recips {<br />
+ my($recip)=@_;<br />
+ return if ($recip eq "");<br />
+ #Don't notify precips if this is NOT a "Policy block"<br />
+ if (&notify_addr('precips')) {<br />
+ return if ($quarantine_event !~ /^(policy|perlscan)/i);<br />
+ } else {<br />
+ #From now on precips is the same as recips<br />
+ $NOTIFY_ADDRS=~s/precips/recips/;<br />
+ }<br />
+ return if (!&notify_addr('recips'));<br />
+ my($HDR,$hdr,$tmprecips,$tmpsubj)='';<br />
+ my($tmpmsgid)= &uniq_id() . "-" . $V_FROM;<br />
+<br />
+ open(SM,"|$qmailinject -h -f ''")||&error_condition("cannot open $qmailinject for sending quarantine report - $!");<br />
+ print SM "From: \"$V_FROMNAME\" <$V_FROM>\n";<br />
+ if (!&is_unreplyable_email('recips')) {<br />
+ &debug("e_r: sending quarantine report via: $qmailinject to recip address ($recip)");<br />
+ print SM "To: $recip\n";<br />
+ }<br />
+ $tmpsubj= "$destring found in received message \"$headers{'subject'}\"";<br />
+ $tmpsubj =~ s/(\r|\0|\n)/ /g;<br />
+ print SM "Subject: $tmpsubj\n";<br />
+ print SM "Message-ID: <".&uniq_id."\@$hostname>\n";<br />
+ print SM "X-Tnz-Problem-Type: 40\n";<br />
+ if ($headers{'message-id'} ne "") {<br />
+ print SM "In-Reply-To: ",$headers{'message-id'},"\n";<br />
+ print SM "References: ",$headers{'message-id'},"\n";<br />
+ }<br />
+ print SM "Auto-Submitted: auto-replied\n";<br />
+ print SM "MIME-Version: 1.0\n";<br />
+ print SM "Content-type: text/plain\n";<br />
+ if ( $descriptive_hdrs ) {<br />
+ print SM "${V_HEADER}-Mail-From: $returnpath via $hostname\n";<br />
+ print SM "${V_HEADER}-Rcpt-To: $recip\n" if ($descriptive_hdrs eq "2");<br />
+ print SM "$V_HEADER: $VERSION ($SCANINFO $destring Found. \n";<br />
+ print SM " Processed in ",tv_interval($start_time,[gettimeofday])," secs)\n";<br />
+ }<br />
+ print SM "\n";<br />
+ print SM "<br />
+Attention: $recip\n";<br />
+ if (!&is_unreplyable_email('recips')) {<br />
+ if (&notify_addr('sender')) {<br />
+ print SM "<br />
+[A message has been sent to the originator, stating there is a virus<br />
+in the Email they just sent to you. No further action is required on<br />
+your part.]\n";<br />
+ }<br />
+ } else {<br />
+ print SM "<br />
+<br />
+[This message was _not_ sent to the originator address, as that appears to<br />
+be a mailing-list or some other automated Email message]\n";<br />
+ }<br />
+ print SM "\nA $destring was found in an Email message sent to you. <br />
+This Email scanner intercepted it and stopped the entire message<br />
+before it reached you. No further action is required on your part.\n";<br />
+ print SM "\nThe $destring was reported to be: <br />
+<br />
+$quarantine_description<br />
+<br />
+Please contact your IT support personnel with any queries regarding this <br />
+policy.<br />
+<br />
+The message sent to you had the following envelope:<br />
+<br />
+MAIL FROM: $returnpath<br />
+RCPT TO: $recips <br />
+<br />
+... and with the following headers:\n\n";<br />
+ print SM "---\n";<br />
+ print SM "MAILFROM: $headers{'MAILFROM'}\n";<br />
+ print SM "RCPTTO: $headers{'RCPTTO'}\n";<br />
+ print SM "IP-Addr: $headers{'REMOTEIPADDR'}\n";<br />
+ print SM "$HEADERS\n";<br />
+ print SM "---\n";<br />
+ #print SM "\nLxOCALE_recips_quarantine\n";<br />
+ close(SM);<br />
+ if ($log_details) {<br />
+ &log_msg("qmail-scanner","Clear:$tag_score$tag_sa_score",$elapsed_time,1100,$V_FROM,$recip,$tmpsubj,$tmpmsgid,"quarantine-event.txt:1000");<br />
+ }<br />
+}<br />
+<br />
+sub notify_addr {<br />
+ my($addr_type)=@_;<br />
+ #&debug("n_a: notify_addr (set to $NOTIFY_ADDRS) called with $addr_type");<br />
+ if (($NOTIFY_ADDRS =~ /$addr_type/ || $NOTIFY_ADDRS =~ /all/) && ($NOTIFY_ADDRS !~ /none/)) {<br />
+ return 1;<br />
+ } else {<br />
+ return 0;<br />
+ }<br />
+}<br />
+<br />
+sub unzip_file {<br />
+ my($zipfile)=@_;<br />
+ my ($MAYBEZIP,$ztmp,$zfile,$zline,$zsize,$zip_status);<br />
+ <br />
+ &debug("u_f: potential zip archive file found ($zipfile).");<br />
+ &debug ("u_f: it is possibly a zip file, run unzip $unzip_options -t $ENV{'TMPDIR'}/$zipfile");<br />
+ $MAYBEZIP=`$unzip_binary $unzip_options -t $ENV{'TMPDIR'}/$zipfile 2>&1`;<br />
+ $zip_status=($? >> 8);<br />
+ <br />
+ if ( ($zip_status > 0) && ($zip_status !~ /^(1|2|3|51|81|82)$/) && ($MAYBEZIP !~ /skipping: /) ) {<br />
+ &debug("u_f: not a recognisable zip file ($MAYBEZIP)");<br />
+ } else {<br />
+ &debug ("u_f: it is a zip file");<br />
+ if ($MAYBEZIP =~ /skipping:.*password/) {<br />
+ &debug ("u_f: it is a password-protected zip file");<br />
+ &minidebug ("u_f: it is a password-protected zip file");<br />
+ &eventlog("UNZIP:PASSWORD_PROTECTED");<br />
+ $CRYPTO_TYPE="CR:ZIP(encrypted)";<br />
+ }<br />
+ if ($force_unzip) {<br />
+ &debug ("u_f: check size of contents before unzipping to disk");<br />
+ my $CHECK_ZIP_SIZE=`$unzip_binary $unzip_options -lv $ENV{'TMPDIR'}/$zipfile 2>&1`;<br />
+ open(ZIPPED,"$unzip_binary $unzip_options -lv $ENV{'TMPDIR'}/$zipfile 2>&1|")||&error_condition("u_f: cannot open $ENV{'TMPDIR'}/$zipfile - $!");<br />
+ my $zip_file_size=0;<br />
+ while (<ZIPPED>) {<br />
+ $zip_file_size=$1 if (/^\s+([0-9]+)\s+/);<br />
+ }<br />
+ close ZIPPED ;<br />
+ &debug("u_f: this zip file unpacks to $zip_file_size bytes of content");<br />
+ if ($max_zip_size > 0 && $max_zip_size < $zip_file_size) {<br />
+ $quarantine_description="Disallowed zip file ($zipfile) - content exceeds maximum allowed size";<br />
+ &debug("u_f: $quarantine_description");<br />
+ &minidebug("u_f: $quarantine_description");<br />
+ $destring='problem';<br />
+ $quarantine_event="Policy:Oversized_ZIP";<br />
+ $quarantine_DOS=$quarantine_event;<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in file $ENV{'TMPDIR'}/$zipfile";<br />
+ $file_desc .= "oversized_zip:$msg_size\t";<br />
+ return;<br />
+ }<br />
+ &debug("u_f: run $unzip_binary $unzip_options $ENV{'TMPDIR'}/$zipfile 2>&1");<br />
+ open(ZIPPED,"$unzip_binary $unzip_options $ENV{'TMPDIR'}/$zipfile 2>&1|")||&error_condition("u_f: cannot open $ENV{'TMPDIR'}/$zipfile - $!");<br />
+ while (<ZIPPED>) {<br />
+ if (/^\s+\w+:\s+(.*)$/) {<br />
+ ($ztmp=$1)=~s/^.*\///g;<br />
+ #Grrr, I don't know if this'll be exploited, but I have to remove the whitespace...<br />
+ #$ztmp=~s/\s+$//g;<br />
+ #if ($ztmp ne "" && !grep(/^${ztmp}$/,@zipfile_list)) {<br />
+ #&debug("u_f: adding file \"$ztmp\" to list of zipped files");<br />
+ #push(@zipfile_list, $ztmp);<br />
+ #}<br />
+ }<br />
+ if (/^\s+skipping:\s(.*)\s+(shrink|encrypted|incorrect password)/) {<br />
+ $passwd_protected_zip++ if (!/^\s+skipping:\s(.*)\s+shrink/);<br />
+ #grab these protected filenames for reports anyway.<br />
+ $zfile = $1;<br />
+ $zfile =~ s/^.*\///g;<br />
+ $zfile =~ s/(^\s+|\s+$)//g;<br />
+ #$file_desc .= "$zfile:$zsize\t";<br />
+ }<br />
+ close(ZIPPED);<br />
+ $zip_status=($? >> 8);<br />
+ if ($zip_status > 0 && ($zip_status !~ /^(1|2|3|51|81|82)$/ && !$passwd_protected_zip)) {<br />
+ &error_condition("u_f: cannot close unzip (error code: $zip_status,$passwd_protected_zip) - $!");<br />
+ }<br />
+ }<br />
+ }<br />
+ #Only delete original zip file if it happily unpacked.<br />
+ if ( $zip_status eq 0 && -f "$ENV{'TMPDIR'}/$zipfile") {<br />
+ #system $rm_binary,"-f","$ENV{'TMPDIR'}/$zipfile";<br />
+ &debug("u_f: $zip_status, and successfully unzipped");<br />
+ #It may have been deleted, but you still want to see if <br />
+ #it matches the perlscanner DB...<br />
+ #$zipfile=tolower($zipfile);<br />
+ #push(@zipfile_list, $zipfile) if (!grep(/^$zipfile$/,@zipfile_list));<br />
+ my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$zsize,$atime,$mtime,$ctime,$blksize,$blocks);<br />
+ ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$zsize,$atime,$mtime,$ctime,$blksize,$blocks) = stat("$zipfile");<br />
+ $file_desc .= "$zipfile:$zsize\t";<br />
+ } <br />
+ }<br />
+}<br />
+<br />
+sub deltatime {<br />
+ my ($delta,$current_time);<br />
+ $current_time = [gettimeofday];<br />
+ $delta = tv_interval ($last_time, $current_time);<br />
+ $last_time=$current_time;<br />
+ return $delta;<br />
+}<br />
+<br />
+sub qmail_parent_check {<br />
+ my $ppid=getppid;<br />
+ #&debug("q_s_c: PPID=$ppid");<br />
+ if ($ppid == 1) {<br />
+ &debug("q_s_c: Whoa! parent process is dead! (ppid=$ppid) Better die too...");<br />
+ &minidebug("q_s_c: Whoa! parent process is dead! (ppid=$ppid) Better die too...");<br />
+ &cleanup;<br />
+ &close_log;<br />
+ #Exit with temp error anyway - just to be real anal...<br />
+ exit 111; <br />
+ }<br />
+}<br />
+<br />
+<br />
+sub check_and_grab_attachments {<br />
+ #This subroutine find attachments (e.g., MIME/binhex,uuencode) within e-mails<br />
+<br />
+ if (/^MIME-Version:/i || ($headers{'content-type'} ne "" && $headers{'content-type'} !~ /^text\/plain/i)) {<br />
+ $indicates_attachments++;<br />
+ &debug("c_a_g: found MIME attachment") if ($indicates_attachments == 2);<br />
+ }<br />
+ #This finds MIME messages banged onto the bottom of bounces<br />
+ if (/^\-+ (Below this line|This) is a copy of the message/) {<br />
+ $indicates_attachments += 2;<br />
+ &debug("c_a_g: found hidden MIME attachment") if ($indicates_attachments == 2);<br />
+ &minidebug("c_a_g: found hidden MIME attachment") if ($indicates_attachments == 2);<br />
+ }<br />
+ #This will define any text mail that contains a URL as requiring scanning - otherwise<br />
+ #some phishing attacks will geet past<br />
+ if ($indicates_attachments < 2 && /http:\/\/|www\.|[a-z0-9\-]+\.[a-z0-9\-]+\//i) {<br />
+ $indicates_attachments += 2;<br />
+ &debug("c_a_g: found URL in message - maybe phishy - better scan it");<br />
+ &minidebug("c_a_g: found URL in message - maybe phishy - better scan it");<br />
+ }<br />
+ #This finds BinHex attachments<br />
+ if (/^\(This file must be converted with BinHex/) {<br />
+ $indicates_attachments += 2;<br />
+ &debug("c_a_g: found hidden BinHex attachment") if ($indicates_attachments == 2);<br />
+ &minidebug("c_a_g: found hidden BinHex attachment") if ($indicates_attachments == 2);<br />
+ }<br />
+ my ($begin,$perms,$uufile,$uuextension,$uulength,$uuencoded_attachments,$begin_content);<br />
+ if (/^(begin) ([0-9][0-9][0-9]) (.*)\n$/) {<br />
+ &debug("Ooohhhh, a uuencoded attachment!");<br />
+ &minidebug("Ooohhhh, a uuencoded attachment!");<br />
+ #Better reset this message back to potentially having attachments<br />
+ $plain_text_msg=0;<br />
+ $uuencoded_attachments++;<br />
+ $begin=$1;<br />
+ $perms=$2;<br />
+ $uufile=tolower($3);<br />
+ push(@uufile_list, $uufile) if(!grep(/^$uufile$/,@uufile_list));<br />
+ $uufile=~s/[^0-9a-z\_\-\.]/_/gi;<br />
+ $uufile =~ /\.([^\.]+)$/;<br />
+ $uuextension=$1;<br />
+ #Ensure the file extension isn't too long either...<br />
+ $uuextension=substr($uuextension,0,20); <br />
+ $uulength=length($uufile);<br />
+ #Ensure the filelength isn't too large!<br />
+ if ( $uulength > $MAX_FILE_LENGTH) {<br />
+ &debug("uudecode output: gah! filename is > $MAX_FILE_LENGTH (actually $uulength), chopping...");<br />
+ &minidebug("uudecode output: gah! filename is > $MAX_FILE_LENGTH (actually $uulength), chopping...");<br />
+ $uufile=substr($uufile,0,$MAX_FILE_LENGTH).".".$uuextension;<br />
+ }<br />
+ return if (!$uudecode_binary);<br />
+ if (! -f "$ENV{'TMPDIR'}/$file_id-$uuencoded_attachments-$uufile.uue") {<br />
+ open(UUIN,">$ENV{'TMPDIR'}/$file_id-$uuencoded_attachments-$uufile.uue")||&error_condition("cannot open $ENV{'TMPDIR'}/$file_id-$uuencoded_attachments-$uufile.uue - $!");<br />
+ } else {<br />
+ &error_condition("$ENV{'TMPDIR'}/$file_id-$uuencoded_attachments-$uufile.uue already exists! - $!");<br />
+ }<br />
+ print UUIN "$begin 640 $uufile\n";<br />
+ print TMPFILE;<br />
+ $begin_content = "uuencode";<br />
+ while (<STDIN>) {<br />
+ if ($begin_content eq "uuencode" && $_ =~ /^(M35JJ|M35J0|M35KU|M35H\\|M35HN)/i) {<br />
+ &debug("w_c: looks like a Windows executable, filename=$uufile");<br />
+ }<br />
+ print UUIN;<br />
+ print TMPFILE;<br />
+ if (/^end/) {<br />
+ close(UUIN)||&error_condition("cannot close $ENV{'TMPDIR'}/$file_id-$uuencoded_attachments-$uufile - $!");<br />
+ #uudecode it - toss away the error code - who cares if it's broken...<br />
+ &debug("c_a_g_u: $uudecode_binary $uudecode_pipe $ENV{'TMPDIR'}/$file_id-$uuencoded_attachments-$uufile.uue");<br />
+ if (! -f "$ENV{'TMPDIR'}/$file_id-$uuencoded_attachments-$uufile") {<br />
+ system("$uudecode_binary -o $ENV{'TMPDIR'}/$file_id-$uuencoded_attachments-$uufile $ENV{'TMPDIR'}/$file_id-$uuencoded_attachments-$uufile.uue 2>/dev/null");<br />
+ rename("$ENV{'TMPDIR'}/$file_id-$uuencoded_attachments-$uufile","$ENV{'TMPDIR'}/$uufile") if (!-f "$ENV{'TMPDIR'}/$uufile");<br />
+ } else {<br />
+ &error_condition("$ENV{'TMPDIR'}/$file_id-$uuencoded_attachments-$uufile already exists! - $!");<br />
+ }<br />
+ #open(UUOUT,"$uudecode_binary $uudecode_pipe $ENV{'TMPDIR'}/$file_id-$uuencoded_attachments-$uufile.uue|");<br />
+ #open(UUFILE,">$ENV{'TMPDIR'}/$file_id-$uuencoded_attachments-$uufile");<br />
+ #while (<UUOUT>) {<br />
+ #print UUFILE;<br />
+ #}<br />
+ #close UUOUT;<br />
+ #close UUFILE;<br />
+ &debug("deleting uuencoded file as we have a decoded version of it now");<br />
+ unlink("$ENV{'TMPDIR'}/$file_id-$uuencoded_attachments-$uufile.uue") if ($DEBUG < 100);<br />
+ last;<br />
+ }<br />
+ }<br />
+ }<br />
+}<br />
+<br />
+sub log_msg {<br />
+ my($msgtype,$status,$elapsed_time,$msgsize,$frm,$recips,$subj,$msgid,$attachs)=@_;<br />
+ my ($msg,$file);<br />
+<br />
+<br />
+ my $syslogtype='mail|info';<br />
+<br />
+ if ($log_details eq "syslog") {<br />
+<br />
+ $msgtype =~ s/\s/_/g;<br />
+ $msgtype .= "[$$]";<br />
+ $status =~ s/\s//g;<br />
+ $syslogtype='mail|warning' if ($status !~ /^Clear/);<br />
+ $elapsed_time =~ s/\s//g;<br />
+ $elapsed_time=0.0 if (!$elapsed_time);<br />
+ $elapsed_time=substr($elapsed_time,0,8);<br />
+ $frm =~ s/\s/_/g;<br />
+ $frm='<>' if (!$frm);<br />
+ $frm=substr($frm,0,100);<br />
+ $recips =~ s/\s/\|/g;<br />
+ $recips='<>' if (!$recips);<br />
+ $recips=substr($recips,0,100);<br />
+ $subj =~ s/\s/_/g;<br />
+ $subj='<>' if (!$subj);<br />
+ $subj=substr($subj,0,80);<br />
+ $msgid =~ s/\s/_/g;<br />
+ $msgid = '<>' if (!$msgid);<br />
+ $msgid=substr($msgid,0,80);<br />
+ $msgsize =~ s/\s//g;<br />
+ $attachs =~ s/\s$//g;<br />
+ #Sub any spaces for underscores then swap tabs for spaces,<br />
+ #syslog doesn't like tabs, so spaces in filenames have to go...<br />
+ $attachs =~ s/\ /_/g;<br />
+ $attachs =~ s/\t/ /g;<br />
+ if (!$attachs) {<br />
+ foreach $file (@uufile_list,@zipfile_list,@attachment_list) {<br />
+ $file =~ s/\s/_/g;<br />
+ $attachs .= "$file ";<br />
+ }<br />
+ $attachs =~ s/\s+$//g;<br />
+ }<br />
+ $attachs="$file_id-unpacked:$msg_size" if (!$attachs);<br />
+ #$attachs=substr($attachs,0,100);<br />
+ $msg = "$status $elapsed_time $msgsize $frm $recips $subj $msgid $attachs";<br />
+ #Do final santity check and remove all low-end chars - like NULL<br />
+ #I have no idea how some older syslogs would react to such things...<br />
+ $msg =~s/[\x00-\x09]//g;<br />
+ $msg =~ s/%/%%/g;<br />
+ #Now ensure syslog record isn't larger than max syslog size of 1024 chars<br />
+ $msg=substr($msg,0,1024);<br />
+ eval {<br />
+ $SIG{ALRM} = sub { die "Maximum time writing to syslog exceeded. syslog is hung/broken." };<br />
+ alarm 10;<br />
+ eval {<br />
+ syslog($syslogtype,"$msgtype: $msg");<br />
+ };<br />
+ if ($@) {<br />
+ setlogsock('inet');<br />
+ syslog('mail|info',"$msgtype: $msg");<br />
+ }<br />
+ };<br />
+ #The message is delivered - so no temp failure here - you just have to lose the log entry...<br />
+ alarm 0;<br />
+ } else {<br />
+ #No error checking - inability to write a log report shouldn't<br />
+ #stop the mail getting through!<br />
+<br />
+ $msgtype =~ s/\t/ /g;<br />
+ $status =~ s/\s//g;<br />
+ $elapsed_time =~ s/\s//g;<br />
+ $elapsed_time=0 if (!$elapsed_time);<br />
+ $frm =~ s/\t/ /g;<br />
+ $frm='<>' if (!$frm);<br />
+ $recips =~ s/\t/ /g;<br />
+ $recips='<>' if (!$recips);<br />
+ $subj =~ s/\t/ /g;<br />
+ $subj='<>' if (!$subj);<br />
+ $msgid =~ s/\t/ /g;<br />
+ $msgid = '<>' if (!$msgid);<br />
+ $msgsize =~ s/\s//g;<br />
+ $attachs =~ s/\s$//g;<br />
+ $attachs =~ s/\t/ /g;<br />
+ $attachs="$file_id-unpacked:$msg_size" if (!$attachs);<br />
+ $msg = "$status\t$elapsed_time\t$msgsize\t$frm\t$recips\t$subj\t$msgid\t$attachs";<br />
+ my $nowtime = strftime("%a, %d %b %Y %H:%M:%S %Z", localtime(time));<br />
+ open LOGMSG, ">>$log_details";<br />
+ print LOGMSG "$nowtime\t$msg\n";<br />
+ close LOGMSG;<br />
+ }<br />
+ &debug("$msgtype: $msg");<br />
+}<br />
+<br />
+<br />
+sub normalize_string {<br />
+ my($type,$raw_string)=@_;<br />
+ my($bit,$string,$nstring,$encoding,$start_normalize_time,$stop_normalize_time,$normalize_time)='';<br />
+ $start_normalize_time=[gettimeofday];<br />
+ $string=$raw_string;<br />
+ if ($raw_string =~ /^\=\?[^\?]+\?([bq])\?(.*)\?\=$/i) {<br />
+ $encoding=$1;<br />
+ $string=$2;<br />
+ #&debug("normalize_string: $type \"$string\" is an \"$encoding\" encoded - normalize");<br />
+ if ($encoding =~ /^B$/i) {<br />
+ use MIME::Base64;<br />
+ foreach $bit (split(/=\?[^\?]+\?B\?/i,$raw_string)) {<br />
+ $bit=~s/\?=$//;<br />
+ $nstring .= decode_base64($bit);<br />
+ }<br />
+ &debug("normalize_string: $type \"$string\" is decoded to \"$nstring\"");<br />
+ }elsif ($encoding =~ /^Q$/i) {<br />
+ use MIME::QuotedPrint;<br />
+ foreach $bit (split(/=\?[^\?]+\?Q\?/i,$raw_string)) {<br />
+ $bit=~s/\?=$//;<br />
+ $nstring .= decode_qp($bit);<br />
+ }<br />
+ &debug("normalize_string: $type \"$string\" is decoded to \"$nstring\"");<br />
+ }else {<br />
+ &debug("normalize_string: encoded string discovered that isn't Quoted-printable or Base64");<br />
+ &minidebug("normalize_string: encoded string discovered that isn't Quoted-printable or Base64");<br />
+ $illegal_mime=1;<br />
+ $destring='LOCALE_destring_problem';<br />
+ $quarantine_description="Disallowed MIME encoding - potential virus";<br />
+ $quarantine_event="Policy:Bogus_Encoding";<br />
+ $description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found";<br />
+ #$file_desc .= "$file:$msg_size\t" if ($file_desc !~ /\Q$file\E/);<br />
+ return $string;<br />
+ }<br />
+ }else{<br />
+ $nstring=$string;<br />
+ }<br />
+ $stop_normalize_time=[gettimeofday];<br />
+ $normalize_time = tv_interval ($start_normalize_time, $stop_normalize_time);<br />
+ &debug("normalize_string: finished normalizing in $normalize_time secs") if ($encoding ne "");<br />
+ &minidebug("normalize_string: finished normalizing in $normalize_time secs") if ($encoding ne "");<br />
+ return $nstring;<br />
+}<br />
+<br />
+###############################<br />
+##<br />
+## END of standard subroutines<br />
+## Virus-scanner specific subroutines automatically added below by setup.sh<br />
+##<br />
+###############################<br />
+<br />
+#################################################<br />
+# Subroutines added by ST<br />
+#################################################<br />
+<br />
+sub minidebug {<br />
+ my $dnowtime = strftime("%a, %d %b %Y %H:%M:%S %Z", localtime(time));<br />
+ print LOG "$dnowtime:$nprocess: ",@_,"\n" if ($MINIDEBUG && !$DEBUG);<br />
+}<br />
+<br />
+sub close_log {<br />
+ ($sec,$min,$hour,$mday,$mon,$year) = localtime(time);<br />
+<br />
+ &debug("--- all finished. Total of ",tv_interval ($start_time, [gettimeofday])," secs");<br />
+ &minidebug("------ Process $nprocess finished. Total of ",tv_interval ($start_time, [gettimeofday])," secs");<br />
+ close(LOG);<br />
+}<br />
+<br />
+sub reject_email {<br />
+ my ($exit_string,$exit_code)=@_;<br />
+ $exit_code=111 if (!$exit_code);<br />
+<br />
+ # st: tell qmail-smtpd why the message is rejected,<br />
+ # so it can be written to the qmail-smtpd log<br />
+ warn "$V_HEADER-$VERSION: $exit_string\n" if ($MINIDEBUG <= 2);<br />
+ warn "$nppid QS-$VERSION: $exit_string\n" if ($MINIDEBUG > 2);<br />
+<br />
+ &debug("r_e: $V_HEADER-$VERSION: $exit_string");<br />
+ &minidebug("r_e: $V_HEADER-$VERSION: $exit_string") if ($MINIDEBUG <= 2);<br />
+ &minidebug("r_e: QS-$VERSION: $exit_string") if ($MINIDEBUG > 2);<br />
+<br />
+ &cleanup;<br />
+<br />
+ &close_log;<br />
+ exit $exit_code;<br />
+}<br />
+<br />
+##############################################<br />
+# st: SETTINGS PER DOMAIN routines<br />
+##############################################<br />
+<br />
+sub start_scanners {<br />
+ my($e_sender,$f_recips,$msg)=@_;<br />
+ $sa_rcpt='0';<br />
+<br />
+ # Now, start the scanners!<br />
+ &init_scanners if ($scanner_array[0] ne "none");<br />
+<br />
+ # st: if the message is marked to delete skip the mailing routines<br />
+ if (!$del_message) {<br />
+ if (($quarantine_event || $quarantine_spam) && ($scanner_array[0] ne "none")) {<br />
+ &debug("unsetting TCPREMOTEIP env var");<br />
+ delete $ENV{'TCPREMOTEIP'};<br />
+ #Reset locale back to original<br />
+ $ENV{'LC_ALL'}=$orig_locale;<br />
+<br />
+ if ($sa_forward ne "" && $quarantine_event =~/spam/i && $description !~/potential virus/i) {<br />
+ if ($sa_fwd_verbose) {<br />
+ $sa_hdr_report='1' if ($sa_alt && $sa_debug && $sa_report);<br />
+ &qmail_parent_check;<br />
+ &qmail_requeue($e_sender,"T$sa_forward\0\0",$msg);<br />
+ } else {<br />
+ open (SF,"$qmailinject -f$returnpath $sa_forward < $msg|")||&error_condition("cannot run $qmailinject -f$returnpath $sa_forward < $msg - $!");<br />
+ close SF ;<br />
+ }<br />
+ # st: forward the messages just once..<br />
+ $sa_rcpt='0';<br />
+ $sa_forward='';<br />
+ }<br />
+ ## st: This code is from qs-2.00, I have to check...<br />
+ #is this a greylist event?<br />
+ if ($quarantine_event=~/gr[ae]ylist/i ) {<br />
+ #This text will only be seen by those using the "custom-error"<br />
+ #patch. Others will just get a general "qq" temp failure msg.<br />
+ &log_event;<br />
+ print STDERR "Z$quarantine_event";<br />
+ &cleanup;<br />
+ &close_log;<br />
+ exit 82;<br />
+ }else{ <br />
+ &email_quarantine_report;<br />
+ }<br />
+ ##<br />
+ } else {<br />
+ &qmail_parent_check;<br />
+ &qmail_requeue($e_sender,$f_recips,$msg); <br />
+ }<br />
+ }<br />
+}<br />
+<br />
+sub sa_defaults {<br />
+ $sa_subject=$sa_subject_site;<br />
+ $sa_quarantine=$sa_quarantine_site;<br />
+ $sa_delta=$sa_delta_site;<br />
+ $sa_delete=$sa_delete_site;<br />
+ $sa_reject=$sa_reject_site;<br />
+ $sa_forward=$sa_forward_site;<br />
+ $sa_fwd_verbose=$sa_fwd_verbose_site;<br />
+ $sa_hdr_report=$sa_hdr_report_site;<br />
+ $smaildir=$smaildir_site;<br />
+}<br />
+<br />
+sub settings_pd {<br />
+ my ($match_hdr,$match_rcpt,$domain_settings)=@_;<br />
+ my ($scanners_rcpt);<br />
+<br />
+ ($scanners_rcpt,$sa_subject,$sa_quarantine,$sa_delta,$sa_delete,$sa_reject,$sa_forward,$sa_fwd_verbose,$sa_hdr_report,$smaildir)=split(/'/,$domain_settings);<br />
+ $sa_subject="" if ($sa_subject eq "none");<br />
+ $smaildir=untaint($smaildir); # st: suggested by P-O Yliniemi <peo - bsd-guide.net><br />
+ $sa_forward=untaint($sa_forward); # st: sa_forward must be untainted too, thanks to Tomas Charvat <tc - excello.cz><br />
+<br />
+ &debug("s_p_d: $match_hdr match '$match_rcpt', settings '$sa_subject,$sa_quarantine,$sa_delta,$sa_delete,$sa_reject,$sa_forward,$sa_fwd_verbose,$sa_hdr_report,$smaildir'");<br />
+<br />
+ @scanner_array=split(/,/,$scanners_rcpt);<br />
+<br />
+ &debug("s_p_d: $match_hdr match '$match_rcpt', scanners '$scanners_rcpt'");<br />
+ &minidebug("s_p_d: $match_hdr match '$match_rcpt', scanners '$scanners_rcpt'") if ($match_hdr !~ /m_rcpt/);<br />
+}<br />
+<br />
+sub settings_p_d {<br />
+ my (%domain_settings,%seen,$scanners_array,$scanners_rcpt,$domain_settings);<br />
+<br />
+ &debug("s_p_d: reading from $settings_per_domain.db");<br />
+ tie (%domain_settings,'DB_File',"$settings_per_domain.db",O_RDONLY, 0600, $DB_HASH) || &error_condition("cannot open $settings_per_domain.db - $!");<br />
+<br />
+ # Check if we have a match within the database<br />
+ # Check order:<br />
+ # 1) return-path<br />
+ # 2) domain-return-path<br />
+ # 3) for each recipient: recipient, domain-recipient<br />
+ if ((exists $domain_settings{$returnpath}) && $QS_RELAYCLIENT) {<br />
+ &settings_pd ("return-path",$returnpath,$domain_settings{$returnpath});<br />
+ }<br />
+ elsif ((exists $domain_settings{$domain_returnpath}) && $QS_RELAYCLIENT) {<br />
+ &settings_pd ("domain-return-path",$domain_returnpath,$domain_settings{$domain_returnpath});<br />
+ }<br />
+ elsif ($one_recip && (exists $domain_settings{$one_recip})) {<br />
+ &settings_pd ("rcpt",$one_recip,$domain_settings{$one_recip});<br />
+ }<br />
+ elsif ($one_recip && (exists $domain_settings{$domain_one_recip})) {<br />
+ &settings_pd ("domain_rcpt",$domain_one_recip,$domain_settings{$domain_one_recip});<br />
+ }<br />
+ elsif (!$one_recip) {<br />
+ &debug("s_p_d: we have multiple recipient, checking each of them");<br />
+ &minidebug("s_p_d: we have multiple recipient, checking each of them");<br />
+ my @mrecips=split(',',$recips);<br />
+ my $mrcpt='';<br />
+ my $domain_mrcpt='';<br />
+ my %m_rcpt;<br />
+ foreach $mrcpt(@mrecips) {<br />
+ $mrcpt=tolower($mrcpt);<br />
+ $domain_mrcpt=$mrcpt;<br />
+ $domain_mrcpt=~ s/^(.*)\@(.*)$/$2/;<br />
+ if (exists $domain_settings{$mrcpt}) {<br />
+ &settings_pd ("m_rcpt",$mrcpt,$domain_settings{$mrcpt});<br />
+ }<br />
+ elsif (exists $domain_settings{$domain_mrcpt}) {<br />
+ &settings_pd ("domain-m_rcpt",$domain_mrcpt,$domain_settings{$domain_mrcpt});<br />
+ } else {<br />
+ @scanner_array=@scanners_default;<br />
+ &sa_defaults;<br />
+ }<br />
+ @scanner_array=&check_scanners(@scanner_array);<br />
+ $scanners_rcpt=join(',',@scanner_array);<br />
+ $domain_settings="$scanners_rcpt'$sa_subject'$sa_quarantine'$sa_delta'$sa_delete'$sa_reject'$sa_forward'$sa_fwd_verbose'$sa_hdr_report'$smaildir";<br />
+ $m_rcpt{$mrcpt}=$domain_settings;<br />
+ }<br />
+ untie %domain_settings;<br />
+ while( ($one_recip,$scanners_array)=each %m_rcpt) {<br />
+ &settings_pd ("rcpt",$one_recip,$scanners_array);<br />
+ &start_scanners($env_returnpath,"T$one_recip\0\0","$scandir/$wmaildir/new/$file_id");<br />
+ # st: maybe I had to change this if I will ever do 'sa' per user config...<br />
+ # if an user on a multiples recipients mail has a very low sa_delete... It could<br />
+ # be rare, but it could be. What to do?<br />
+ # If sa_hits doesn't exist, the mail has a virus marked to delete,<br />
+ # but if the mail was rejected this check won't be reached...<br />
+ last if ($del_message == 1);<br />
+ }<br />
+ return;<br />
+ } else {<br />
+ @scanner_array=@scanners_default;<br />
+ &sa_defaults;<br />
+ &debug("s_p_d: no match, default sa_settings '$sa_quarantine,$sa_delta,$sa_delete,$sa_reject,$sa_forward,$sa_fwd_verbose,$sa_hdr_report,$smaildir'");<br />
+ &debug("s_p_d: no match, falling to settings_default");<br />
+ &minidebug("s_p_d: no match, falling to settings_default");<br />
+ }<br />
+ # if no multiples recipients<br />
+ untie %domain_settings;<br />
+ @scanner_array=&check_scanners(@scanner_array);<br />
+ &start_scanners($env_returnpath,$env_recips,"$scandir/$wmaildir/new/$file_id");<br />
+}<br />
+<br />
+sub generate_spd {<br />
+ my ($line,$count,%domain_settings,$match_rcpt,$scanners_rcpt,@scanners_rcpt_array,%seen);<br />
+ my ($domain_settings,$sa_subject_ignore);<br />
+<br />
+ print "\n Generating $settings_per_domain.db\n\n";<br />
+<br />
+ unlink ("$settings_per_domain.db.tmp");<br />
+ tie (%domain_settings,'DB_File',"$settings_per_domain.db.tmp",O_CREAT|O_RDWR,0640,$DB_HASH) || &error_condition("cannot open for write $settings_per_domain.db.tmp - $!");<br />
+<br />
+ open(SPD, "<$settings_per_domain.txt") || &error_condition("cannot read $settings_per_domain.txt - $!");<br />
+<br />
+ while (<SPD>) {<br />
+ $line++;<br />
+ next if (/^\#|^\s.*$/); # Ignore lines starting with # or spaces<br />
+ next if (!(/:/)); # Ignore lines doesn't contain a ':'<br />
+ # if (/\;|\!/) {<br />
+ if (/\;/) {<br />
+ print "d_w: line $line contains an invalid char, SKIP\n";<br />
+ next;<br />
+ }<br />
+ chomp;<br />
+ # sa_subject could has spaces ... (from P-O Yliniemi)<br />
+ $sa_subject = (split(/'/,$_))[1];<br />
+ s/\s|\t//g;<br />
+ ($match_rcpt,$domain_settings)=split(/:/,$_,2);<br />
+ $match_rcpt=tolower("$match_rcpt");<br />
+ # $domain_settings=tolower("$domain_settings");<br />
+ ($scanners_rcpt,$sa_subject_ignore,$sa_quarantine,$sa_delta,$sa_delete,$sa_reject,$sa_forward,$sa_fwd_verbose,$sa_hdr_report,$smaildir)=split(/'/,$domain_settings);<br />
+<br />
+ if (exists $domain_settings{$match_rcpt}) {<br />
+ print " d_w: duplicated value '$match_rcpt' at line $line, SKIP \n";<br />
+ next;<br />
+ }<br />
+<br />
+ $sa_subject=$sa_subject_site if (!$sa_subject);<br />
+ $sa_quarantine=$sa_quarantine_site if (!$sa_quarantine && $sa_quarantine ne "0");<br />
+ $sa_delta=$sa_delta_site if (!$sa_delta && $sa_delta ne "0");<br />
+ $sa_delete=$sa_delete_site if (!$sa_delete && $sa_delete ne "0");<br />
+ $sa_reject=$sa_reject_site if (!$sa_reject && $sa_reject ne "0");<br />
+ $sa_forward=$sa_forward_site if (!$sa_forward);<br />
+ $sa_fwd_verbose=$sa_fwd_verbose_site if (!$sa_fwd_verbose && $sa_fwd_verbose ne "0");<br />
+ $sa_hdr_report=$sa_hdr_report_site if (!$sa_hdr_report && $sa_hdr_report ne "0");<br />
+ $smaildir=$smaildir_site if (!$smaildir);<br />
+<br />
+ # Control the values of sa_delete and sa_quarantine<br />
+ if ($sa_delete && ($sa_quarantine>$sa_delete)) {<br />
+ print " d_w: WARNING, sa_delete lower than sa_quarantine, for address '$match_rcpt' at line $line\n";<br />
+ print " resetting sa_delete to '0', spam could be quarantined, but not deleted for this address\n";<br />
+ $sa_delete='0';<br />
+ }<br />
+<br />
+ # Let check if the scanner are really installed,<br />
+ # change 'sa' and 'ps' for the correct name, and<br />
+ # add _scanner to the AVs scanners<br />
+<br />
+ @scanners_rcpt_array=split(/,/,$scanners_rcpt);<br />
+ foreach (@scanners_rcpt_array) {<br />
+ s/^sa$/spamassassin/;<br />
+ s/^ps$/perlscan/;<br />
+ s/^perlscanner$/perlscan/;<br />
+ s/^(.*)$/$1_scanner/ if((!/spamassassin/) && (!/_scanner/) && (!/^none$/));<br />
+ }<br />
+<br />
+ # Check if the scanners are installed<br />
+ @scanners_rcpt_array=&check_scanners(@scanners_rcpt_array);<br />
+<br />
+ $scanners_rcpt = join(',',@scanners_rcpt_array);<br />
+<br />
+ # Check if at least we have one valid scanner<br />
+<br />
+ if (@scanners_rcpt_array==0) {<br />
+ print " d_w: There are no valid scanners for address '$match_rcpt' at line $line, SKIP\n";<br />
+ next;<br />
+ }<br />
+ $count++;<br />
+<br />
+ $domain_settings="$scanners_rcpt'$sa_subject'$sa_quarantine'$sa_delta'$sa_delete'$sa_reject'$sa_forward'$sa_fwd_verbose'$sa_hdr_report'$smaildir";<br />
+ <br />
+ $domain_settings{$match_rcpt}=$domain_settings;<br />
+ }<br />
+ close(SPD);<br />
+ untie %domain_settings;<br />
+ rename( "$settings_per_domain.db.tmp", "$settings_per_domain.db" );<br />
+ print "\n Read $line lines, got $count entries\n\n";<br />
+ if (!$settings_pd) {<br />
+ print "\n WARNING: settings_per_domain is not enabled\n\n The database has been generated but\n";<br />
+ print " it won't be used until 'settings_per_domain' will be enabled\n\n";<br />
+ }<br />
+}<br />
+<br />
+sub read_spd {<br />
+ # st: display the database sorted by domains.<br />
+<br />
+ my ($count,%domain_settings,$scanners_rcpt,$TXT,$spd_orig);<br />
+ my (%sorted,$userpart,$domainpart,$last_domain,$fs);<br />
+ $count=0;<br />
+<br />
+ if ($opt_d) {<br />
+ $fs="\t";<br />
+ print "\n# Reading from $settings_per_domain.db\n#\n";<br />
+ $TXT="STDOUT";<br />
+ } else {<br />
+ $fs="\n#";<br />
+ $spd_orig = "$settings_per_domain.txt.";<br />
+ $spd_orig .= sprintf "%02d%02d%02d.%02d%02d%02d",$year+1900,$mon+1,$mday,$hour,$min,$sec;<br />
+ print "\n Sorting file '$settings_per_domain.txt'\n\n A copy of the current settings will be saved in:\n";<br />
+ print " $spd_orig\n\n";<br />
+ if ( (stat("$settings_per_domain.txt"))[9] > (stat("$settings_per_domain.db"))[9] ) {<br />
+ print "\n WARNING: file '$settings_per_domain.txt' is newer\n";<br />
+ print " than database '$settings_per_domain.db'\n";<br />
+ print " this could be wrong or not, anyway a copy of the current\n";<br />
+ print " 'txt file' has been saved, see above.\n\n";<br />
+ }<br />
+ rename("$settings_per_domain.txt", "$spd_orig");<br />
+ open(SPD, ">$settings_per_domain.txt") || &error_condition("cannot open for write $settings_per_domain.txt - $!");<br />
+ print SPD "#\n# File settings_per_domain.txt sorted by qmail-scanner-st\n#\n";<br />
+ $TXT="SPD";<br />
+ }<br />
+<br />
+ print $TXT "# Read the documetation at:\n";<br />
+ print $TXT "# http://toribio.apollinare.org/qmail-scanner/settings_per_domain.html\n#\n";<br />
+<br />
+ if ($opt_s) {<br />
+ print $TXT "\n######### WIDE SITE SETTINGS\n";<br />
+ print $TXT "# scanners_installed = @scanners_installed\n";<br />
+ print $TXT "# scanners_default = @scanners_default\n";<br />
+ print $TXT "# sa_subject_site = '$sa_subject_site'\n";<br />
+ print $TXT "# sa_quarantine_site = $sa_quarantine_site$fs sa_delta_site = $sa_delta_site\n";<br />
+ print $TXT "# sa_delete_site = $sa_delete_site$fs sa_reject_site = $sa_reject_site\n";<br />
+ print $TXT "# sa_forward_site = '$sa_forward_site'$fs sa_fwd_verbose_site= $sa_fwd_verbose_site\n";<br />
+ print $TXT "# sa_hdr_report_site = $sa_hdr_report_site$fs smaildir_site = $smaildir_site\n\n";<br />
+ }<br />
+<br />
+ tie (%domain_settings,'DB_File',"$settings_per_domain.db",O_RDONLY, 0600, $DB_HASH) || &error_condition("cannot open for read $settings_per_domain.db - $!");;<br />
+<br />
+ # st: let sort the match_rpt<br />
+ foreach (keys %domain_settings) {<br />
+ if ( $_ =~ /\@/) {<br />
+ ($userpart,$domainpart) = split (/\@/,$_);<br />
+ $sorted{"$domainpart.$userpart"} = $_;<br />
+ } else {<br />
+ $sorted{$_} = $_;<br />
+ }<br />
+ }<br />
+<br />
+ foreach(sort keys %sorted) {<br />
+ $count++;<br />
+ ($userpart,$domainpart) = split (/\@/,$sorted{$_});<br />
+ if ( $sorted{$_} !~ /\@/ ) {<br />
+ print $TXT "\n######### DOMAIN\t'$sorted{$_}'\n" ;<br />
+ $last_domain=$domainpart=$sorted{$_};<br />
+ }<br />
+ print $TXT "\n######### DOMAIN\t'$domainpart'\n" if ( $domainpart ne $last_domain );<br />
+ $last_domain=$domainpart;<br />
+ ($scanners_rcpt,$sa_subject,$sa_quarantine,$sa_delta,$sa_delete,$sa_reject,$sa_forward,$sa_fwd_verbose,$sa_hdr_report,$smaildir)=split(/'/,$domain_settings{$sorted{$_}});<br />
+ print $TXT "\n## $count. Settings for\t'$sorted{$_}'\n" if ($opt_d) ;<br />
+ print $TXT "$sorted{$_} : $domain_settings{$sorted{$_}}\n";<br />
+ if ($opt_d) {<br />
+ print $TXT "\n# scanners = $scanners_rcpt\n";<br />
+ print $TXT "# sa_subject = '$sa_subject'\n";<br />
+ print $TXT "# sa_quarantine = $sa_quarantine\tsa_delta = $sa_delta\n";<br />
+ print $TXT "# sa_delete = $sa_delete\tsa_reject = $sa_reject\n";<br />
+ print $TXT "# sa_forward = '$sa_forward'\tsa_fwd_verbose = $sa_fwd_verbose\n";<br />
+ print $TXT "# sa_hdr_report = $sa_hdr_report\tsmaildir = $smaildir\n\n";<br />
+ }<br />
+ }<br />
+<br />
+ print $TXT "\n######### WIDE SITE SETTINGS\n";<br />
+ print $TXT "# scanners_installed = @scanners_installed\n";<br />
+ print $TXT "# scanners_default = @scanners_default\n";<br />
+ print $TXT "# sa_subject_site = '$sa_subject_site'\n";<br />
+ print $TXT "# sa_quarantine_site = $sa_quarantine_site$fs sa_delta_site = $sa_delta_site\n";<br />
+ print $TXT "# sa_delete_site = $sa_delete_site$fs sa_reject_site = $sa_reject_site\n";<br />
+ print $TXT "# sa_forward_site = '$sa_forward_site'$fs sa_fwd_verbose_site= $sa_fwd_verbose_site\n";<br />
+ print $TXT "# sa_hdr_report_site = $sa_hdr_report_site$fs smaildir_site = $smaildir_site\n\n";<br />
+ if ($opt_d) {<br />
+ print $TXT "# Run '/var/qmail/bin/qmail-scanner-queue.pl -p' to generate the db\n";<br />
+ print $TXT "# If you have redirect the output of this command to settings_per_domain.txt\n";<br />
+ print $TXT "\n# d_w: total of $count entries found\n\n\n";<br />
+ }<br />
+ if (!$settings_pd) {<br />
+ print "\n WARNING: settings_per_domain is not enabled\n\n The database won't be used\n";<br />
+ print " until 'settings_per_domain' will be enabled\n\n";<br />
+ }<br />
+<br />
+ close(SPD) if ($opt_s);<br />
+ untie %domain_settings;<br />
+}<br />
+<br />
+<br />
+sub check_scanners {<br />
+ # Check against the installed scanners<br />
+ my @scanners_to_check=@_;<br />
+ return @scanners_to_check if ($scanners_to_check[0] eq "none");<br />
+ my %seen=();<br />
+ foreach (@scanners_installed) {<br />
+ $seen{$_}=1;<br />
+ }<br />
+<br />
+ @scanners_to_check=grep($seen{$_},@scanners_to_check);<br />
+ return @scanners_to_check;<br />
+}<br />
+<br />
+sub untaint {<br />
+ # st: suggested by P-O Yliniemi <peo - bsd-guide.net><br />
+ my($var) = @_;<br />
+ if ($var =~ /^(.*)$/) {<br />
+ $var = $1;<br />
+ }<br />
+ return $var;<br />
+}<br />
+<br />
+#################################################<br />
+# END of subroutines added by ST<br />
+#################################################<br />
+<br />
+<br />
+sub clamdscan_scanner {<br />
+ #Clamdscan scanner<br />
+ &debug("clamdscan: starting scan of directory \"$ENV{'TMPDIR'}\"...");<br />
+<br />
+ my ($start_clamdscan_time)=[gettimeofday];<br />
+ my ($DD,$clamdscan_status,$eclamdscan_status,$stop_clamdscan_time,$clamdscan_time);<br />
+ my ($clamdscan_verbose);<br />
+ $clamdscan_verbose="-v" if ($DEBUG);<br />
+<br />
+ &debug("run $clamdscan_binary $clamdscan_options $ENV{'TMPDIR'} 2>&1");<br />
+<br />
+ $DD=`$clamdscan_binary $clamdscan_options $ENV{'TMPDIR'} 2>&1`;<br />
+ $clamdscan_status=$?;<br />
+ $eclamdscan_status=($clamdscan_status >> 8);<br />
+<br />
+ &debug("--output of clamdscan was:\n$DD--");<br />
+<br />
+ if ( $eclamdscan_status > 0) {<br />
+ if ($eclamdscan_status == 1 && $DD =~ /\:\s(.*)\sFOUND$/m) {<br />
+ $quarantine_description=$+;<br />
+ &debug("There be a virus! ($quarantine_description)");<br />
+ &minidebug("clamdscan: there be a virus! ($quarantine_description)");<br />
+ &eventlog("CLAMAV:$quarantine_description");<br />
+ ($quarantine_event=$quarantine_description)=~s/\s/_/g;<br />
+ $quarantine_event="CLAMDSCAN:".substr($quarantine_event,0,$QE_LEN);<br />
+ $description .= "\n---clamdscan results ---\n$DD";<br />
+ } elsif ($eclamdscan_status == 2 && $DD =~ /module failure/) {<br />
+ #This is OK, corrupt files are let through<br />
+ } else {<br />
+ #This implies a corrupt set of DAT files or resource problems...<br />
+ &error_condition("clamdscan: corrupt or unknown clamd scanner error or memory/resource/perms problem - exit status $clamdscan_status/$eclamdscan_status");<br />
+ }<br />
+ } else {<br />
+ if ($DD =~ /Recursion limit exceeded/) {<br />
+ $quarantine_description="Resource attack - $1";<br />
+ &debug("clamdscan: $quarantine_description");<br />
+ &minidebug("clamdscan: $quarantine_description");<br />
+ $quarantine_event="CLAMDSCAN:Resource_attack";<br />
+ &eventlog("CLAMAV:$quarantine_description");<br />
+ $description .= "\n---clamdscan results ---\n$DD";<br />
+ } elsif ($clamdscan_status > 0) {<br />
+ #This implies a corrupt set of DAT files or resource problems...<br />
+ &error_condition("clamdscan: corrupt or unknown clamd scanner error or memory/resource/perms problem - exit status $clamdscan_status/$eclamdscan_status");<br />
+ }<br />
+ }<br />
+ #Bugs in clamdscan sometimes shows up as zero output. Always error on such conditions<br />
+ $DD=~s/\n//g;<br />
+ if ($DD eq "" ) {<br />
+ &error_condition("clamdscan: corrupt or unknown clamd scanner error or memory/resource/perms problem - exit status $clamdscan_status/$eclamdscan_status, but no output!");<br />
+ }<br />
+ <br />
+ $stop_clamdscan_time=[gettimeofday];<br />
+ $clamdscan_time = tv_interval ($start_clamdscan_time, $stop_clamdscan_time);<br />
+ &debug("clamdscan: finished scan of dir \"$ENV{'TMPDIR'}\" in $clamdscan_time secs");<br />
+ &minidebug("clamdscan: finished scan in $clamdscan_time secs");<br />
+}<br />
+<br />
+sub spamassassin {<br />
+ my($scanned)=@_ ;<br />
+<br />
+ $scanned='0' if ( $scanned != 1 );<br />
+<br />
+ #Only run SA if mail is from a "remote" SMTP client, or QS_SPAMASSASSIN <br />
+ #is defined via tcpserver...<br />
+ if ($QS_RELAYCLIENT && !defined($ENV{'QS_SPAMASSASSIN'})) {<br />
+ &debug("spamassassin: don't scan as RELAYCLIENT implies this was sent by a local user");<br />
+ &minidebug("SA: don't scan as RELAYCLIENT implies this was sent by a local user") if (!$scanned);<br />
+ return;<br />
+ }<br />
+ if ( $SA_SKIP_MD ne "0" && $returnpath eq "" && $headers{'from'} =~ /mailer-daemon|postmaster|bounce/i ) {<br />
+ &debug("SA: skipping message from MAILER-DAEMON");<br />
+ &minidebug("SA: skipping message from MAILER-DAEMON") if (!$scanned);<br />
+ return;<br />
+ }<br />
+<br />
+ #SpamAssassin client scanner<br />
+ #my ($spamassassin_found,$spamassassin_status);<br />
+ my ($spamassassin_status);<br />
+ my ($start_spamassassin_time)=[gettimeofday];<br />
+ my ($sa_tag,$DD,$stop_spamassassin_time,$spamassassin_time,$cmdline_recip,$spamc_options);<br />
+ my ($sa_status)=0;<br />
+ my ($sa_score)=0; my ($sa_required_hits)=0;<br />
+ ($sa_comment,$sa_level)=('','');<br />
+<br />
+ if ($msg_size > 250000) {<br />
+ &debug("spamassassin: message too big - skip it");<br />
+ &minidebug("SA: message too big ($msg_size) - skip it");<br />
+ $sa_score=$required_hits="?";<br />
+ $tag_sa_score = "SA:0($sa_score/$required_hits):";<br />
+ $sa_comment = "No, hits=$sa_score required=$required_hits";<br />
+ return;<br />
+ }<br />
+<br />
+ $spamc_options=' -c ' if ($sa_fast);<br />
+<br />
+ if ($sa_sql) {<br />
+ #Cleanup $one_recip so it's usable from the commandline...<br />
+ #any char that isn't supported to changed into an '_'<br />
+ ($cmdline_recip=$one_recip)=~s/[^0-9a-z\.\_\-\=\+\@]/_/gi;<br />
+ $cmdline_recip=~/^([0-9a-z\.\_\-\=\+\@]+)$/i;<br />
+ $cmdline_recip=tolower($1);<br />
+ $spamc_options="$spamc_options -u \"$cmdline_recip\"" if ($cmdline_recip ne "");<br />
+ }<br />
+<br />
+ &debug("SA: run $spamc_binary $spamc_options < $scandir/$wmaildir/new/$file_id");<br />
+ open(SIN,"<$scandir/$wmaildir/new/$file_id")||&error_condition("cannot open $scandir/$wmaildir/new/$file_id - $!");<br />
+ open(SOUT,"|$spamc_binary $spamc_options > $scandir/$wmaildir/new/$file_id.spamc")||&error_condition("cannot open for write $scandir/$wmaildir/new/$file_id.spamc - $!");<br />
+<br />
+ print SOUT "X-Envelope-From: $headers{'MAILFROM'}\n";<br />
+ while (<SIN>) {<br />
+ print SOUT;<br />
+ }<br />
+ close(SIN)||&error_condition("cannot close $scandir/$wmaildir/new/$file_id - $!");<br />
+ close SOUT;<br />
+ $spamassassin_status=($? >> 8);<br />
+ $sa_status=$spamassassin_status if ($sa_fast);<br />
+ open(SA,"<$scandir/$wmaildir/new/$file_id.spamc")||&error_condition("cannot open for read $scandir/$wmaildir/new/$file_id.spamc - $!");<br />
+ while (<SA>) {<br />
+ if ($sa_fast) {<br />
+ chomp;<br />
+ ($sa_score,$required_hits)=split(/\//,$_,2);<br />
+ $sa_tag++;<br />
+ last;<br />
+ } else {<br />
+ #X-Spam-Status: No, score=2.8 required=5.0<br />
+ if (/^X-Spam-Status: (Yes|No), (hits|score)=(-?[\d\.]*) required=([\d\.]*)/) {<br />
+ $sa_tag++;<br />
+ $sa_status=1 if ($1 eq "Yes");<br />
+ $sa_score=$3;$required_hits=$4;<br />
+ }<br />
+ }<br />
+ }<br />
+ close SA ;<br />
+<br />
+ if (!$sa_fast && -s "$scandir/$wmaildir/new/$file_id.spamc" && $spamassassin_status == 0) {<br />
+ &debug("SA: overwriting $scandir/$wmaildir/new/$file_id with $scandir/$wmaildir/new/$file_id.spamc");<br />
+ rename ("$scandir/$wmaildir/new/$file_id.spamc","$scandir/$wmaildir/new/$file_id");<br />
+ } else {<br />
+ unlink("$scandir/$wmaildir/new/$file_id.spamc");<br />
+ }<br />
+<br />
+ # st: new routine to avoid duplicate code, so a shorter code...<br />
+ &check_sa_score($sa_score,$start_spamassassin_time,$scanned);<br />
+}<br />
+<br />
+#################################################<br />
+# Spamassassin subroutine added by ST<br />
+#################################################<br />
+<br />
+sub spamassassin_alt {<br />
+ # st: Alternative routine for spamassassin, lighter and can logs the report...<br />
+ my($scanned)=@_ ;<br />
+<br />
+ $scanned='0' if ( $scanned != 1 );<br />
+<br />
+ #Only run SA if mail is from a "remote" SMTP client, or QS_SPAMASSASSIN <br />
+ #is defined via tcpserver...<br />
+ if ($QS_RELAYCLIENT && !defined($ENV{'QS_SPAMASSASSIN'})) {<br />
+ &debug("spamassassin: don't scan as RELAYCLIENT implies this was sent by a local user");<br />
+ &minidebug("SA: don't scan as RELAYCLIENT implies this was sent by a local user") if (!$scanned);<br />
+ return;<br />
+ }<br />
+ if ( $SA_SKIP_MD ne "0" && $returnpath eq "" && $headers{'from'} =~ /mailer-daemon|postmaster|bounce/i ) {<br />
+ &debug("SA: skipping message from MAILER-DAEMON");<br />
+ &minidebug("SA: skipping message from MAILER-DAEMON") if (!$scanned);<br />
+ return;<br />
+ }<br />
+<br />
+ #SpamAssassin client scanner<br />
+ my ($start_spamassassin_time)=[gettimeofday];<br />
+ my ($spamc_options,$sa_tag,$spamassassin_status,$sa_score,$stop_spamassassin_time,$spamassassin_time);<br />
+ my ($sa_status)=0;<br />
+ ($sa_score,$required_hits)=('0','0');<br />
+ ($sa_comment,$sa_level)=('','');<br />
+ $sa_report='';<br />
+ $sa_fast=1;<br />
+<br />
+ if ($msg_size > 250000) {<br />
+ &debug("spamassassin: message too big - skip it");<br />
+ &minidebug("SA: message too big - skip it");<br />
+ $sa_score=$required_hits="?";<br />
+ $tag_sa_score = "SA:0($sa_score/$required_hits):";<br />
+ $sa_comment = "No, hits=$sa_score required=$required_hits";<br />
+ return;<br />
+ }<br />
+<br />
+ if ( $sa_debug eq "1" ) {<br />
+ $spamc_options=" -R ";<br />
+ } else {<br />
+ $spamc_options=" -c ";<br />
+ }<br />
+<br />
+ if ($sa_sql) {<br />
+ my ($cmdline_recip);<br />
+ ($cmdline_recip=$one_recip)=~s/[^0-9a-z\.\_\-\=\+\@]/_/gi;<br />
+ $cmdline_recip=~/^([0-9a-z\.\_\-\=\+\@]+)$/i;<br />
+ $cmdline_recip=tolower($1);<br />
+ $spamc_options="$spamc_options -u \"$cmdline_recip\"" if ($cmdline_recip ne "");<br />
+ }<br />
+<br />
+ open(SA,"$spamc_binary $spamc_options < $scandir/$wmaildir/new/$file_id|")||&error_condition("cannot run $spamc_binary < $scandir/$wmaildir/new/$file_id - $!");<br />
+ while (<SA>) {<br />
+ if (!$sa_tag) {<br />
+ chomp;<br />
+ ($sa_score,$required_hits)=split(/\//,$_,2);<br />
+ # Clean some invalid returns from SA v.2.5x<br />
+ $required_hits =~ s/\r//g;<br />
+ chomp $required_hits;<br />
+ $sa_tag=1;<br />
+ next;<br />
+ }<br />
+<br />
+ if ( $sa_tag<2 ) {<br />
+ $sa_tag=2 if (/^---- ---------------------- --------------------------------------------------$/);<br />
+ next;<br />
+ }<br />
+<br />
+ $sa_report .= " $_" if ( !/^$/ || !/^\s$/ );<br />
+ }<br />
+<br />
+ # Clean some invalid returns from SA v.2.5x<br />
+ $sa_report =~ s/\r/\n/g;<br />
+ chomp $sa_report;<br />
+ $sa_report = '' if ($sa_report =~ /\n\n/ );<br />
+<br />
+ $spamassassin_status=($? >> 8);<br />
+ $sa_status=$spamassassin_status if ($sa_fast);<br />
+<br />
+ close SA ;<br />
+<br />
+ # st: new routine to avoid duplicate code, so a shorter code...<br />
+ &check_sa_score($sa_score,$start_spamassassin_time,$scanned);<br />
+}<br />
+<br />
+sub check_sa_score {<br />
+ my ($sa_score,$start_spamassassin_time,$scanned)=@_ ;<br />
+ my ($stop_spamassassin_time,$spamassassin_time);<br />
+<br />
+ # st: if the variable SA_ONLYDELETE_HOST is set in the tcpserver<br />
+ # don't reject messages coming from those IPs, just delete them<br />
+ # You should set this variable for your secondary mail server.<br />
+ if (defined($ENV{'SA_ONLYDELETE_HOST'}) || defined($ENV{'SA_WHITELIST'})) {<br />
+ $sa_reject="0";<br />
+ &debug("WL: The server is a SA_ONLYDELETE_HOST, don't reject");<br />
+ &minidebug("WL: The server is a SA_ONLYDELETE_HOST, don't reject");<br />
+ }<br />
+<br />
+ $sa_score='?' if (!$sa_score);<br />
+ $required_hits='?' if (!$required_hits);<br />
+ $sa_hits=$sa_score;<br />
+<br />
+ &debug("SA: REPORT hits = $sa_score/$required_hits\n$sa_report") if ( $sa_debug && $sa_report );<br />
+ &minidebug("SA: REPORT hits = $sa_score/$required_hits\n$sa_report") if ( $sa_debug && $sa_report && !$scanned);<br />
+ &eventlog("- - -:SCORE:REQ:QRTN:DEL:REJ");<br />
+ &eventlog("SPAM-RESULT:$sa_score:$required_hits:$sa_quarantine:$sa_delete:$sa_reject");<br />
+<br />
+ # st: what about SA sql per user, could be differents $required_hits...<br />
+ if ($required_hits > $sa_score || ($sa_score == 0) || ($sa_score eq "\?")) {<br />
+ $tag_sa_score = "SA:0($sa_score/$required_hits):";<br />
+ $sa_comment = "No, hits=$sa_score required=$required_hits";<br />
+ } else {<br />
+ $tag_sa_score = "SA:1($sa_score/$required_hits):";<br />
+ $sa_comment = "Yes, hits=$sa_score required=$required_hits" if ($sa_fast);<br />
+<br />
+ # If sa_quarantine/sa_delete are set, then compare them to the current score and<br />
+ # quarantine/delete it if necessary,<br />
+ # otherwise tag the message as spam.<br />
+<br />
+ # Control the values of sa_delete and sa_quarantine<br />
+ if ($sa_delete && ($sa_quarantine>$sa_delete)) {<br />
+ &debug("SA: WARNING, sa_delete is lower than sa_quarantine, spam could be quarantined, but not deleted");<br />
+ &minidebug("SA: WARNING, sa_delete is lower than sa_quarantine, spam could be quarantined, but not deleted");<br />
+ &eventlog("---- WARN: sa_delete < sa_quarantine => setting sa_delete = 0");<br />
+ $sa_delete='0';<br />
+ }<br />
+<br />
+ my $sa_threshold='0';<br />
+<br />
+ if ( $sa_delete && (($sa_delete+$required_hits)<$sa_score)) {<br />
+ $sa_threshold=$sa_delete+$required_hits;<br />
+ if ( $sa_reject && (($sa_delete_site+$required_hits)<$sa_score || $one_recip eq $recips )) {<br />
+ &log_sa_action($scanned,$sa_threshold,"rejected");<br />
+ &eventlog("SPAM-DETECT:REJECT");<br />
+ $stop_spamassassin_time=[gettimeofday];<br />
+ $spamassassin_time = tv_interval ($start_spamassassin_time, $stop_spamassassin_time);<br />
+ &debug("SA: finished scan of dir \"$ENV{'TMPDIR'}\" in $spamassassin_time secs");<br />
+ &minidebug("SA: finished scan in $spamassassin_time secs - hits=$sa_score/$required_hits");<br />
+ &reject_email("We have reasons to believe this mail is SPAM",31);<br />
+ } else {<br />
+ # st: mark the message to delete it, if it isn't already marked as virus to delete<br />
+ # actually it is not possible that a marke message reach this point. I think..<br />
+ $del_message='2' if ($del_message ne "1");<br />
+ # st: maybe these three lines are useful for those who wants the 'log_details'...<br />
+ # But if the message is rejected nothing remains<br />
+ $destring="SPAM";<br />
+ $quarantine_description="SPAM exceeds \"delete\" threshold - hits=$sa_score/$required_hits";<br />
+ $quarantine_event="SA:SPAM-DELETED";<br />
+ &log_sa_action($scanned,$sa_threshold,"deleted");<br />
+ &eventlog("SPAM-DETECT:DELETE");<br />
+ $description .= "\n---spamassassin results ---\n$destring '$quarantine_description'\n found in message $ENV{'TMPDIR'}";<br />
+ }<br />
+ } else {<br />
+ if ( $sa_quarantine && (($sa_quarantine+$required_hits)<$sa_score)) {<br />
+ $sa_threshold=$sa_quarantine+$required_hits;<br />
+ $destring="SPAM";<br />
+ $quarantine_description="SPAM exceeds \"quarantine\" threshold - hits=$sa_score/$required_hits";<br />
+ $quarantine_event="SA:SPAM-QUARANTINED";<br />
+ $quarantine_spam="SA:SPAM-QUARANTINED";<br />
+ &log_sa_action($scanned,$sa_threshold,"quarantined");<br />
+ &eventlog("SPAM-DETECT:QUARANTINE");<br />
+ $description .= "\n---spamassassin results ---\n$destring '$quarantine_description'\n found in message $ENV{'TMPDIR'}";<br />
+ } else {<br />
+ #st: if $spamc_subject and $sa_delta are set, add in the subject the spam-level<br />
+ if ($sa_subject ne "" && $sa_delta) {<br />
+ if ($sa_score < ($required_hits+$sa_delta)) {<br />
+ $sa_subject .= " LOW * ";<br />
+ } elsif ($sa_score > ($required_hits+(2 * $sa_delta))) {<br />
+ $sa_subject .= " HIGH * ";<br />
+ } else {<br />
+ $sa_subject .= " MEDIUM * ";<br />
+ }<br />
+ }<br />
+ &log_sa_action($scanned,$required_hits,"tagged");<br />
+ &eventlog("SPAM-DETECT:MARK");<br />
+ }<br />
+ }<br />
+ }<br />
+<br />
+ if ($sa_score > 0) {<br />
+ $sa_score=int($sa_score);<br />
+ #Keep it RFC compliant<br />
+ $sa_score=100 if ($sa_score > 100);<br />
+ my $si=0;<br />
+ $sa_level='';<br />
+ if ($sa_fast || $sa_alt) {<br />
+ while ($si < $sa_score) {<br />
+ $si++;<br />
+ $sa_level .= $sa_symbol;<br />
+ }<br />
+ }<br />
+ }<br />
+<br />
+ &debug("SA: required_hits $required_hits / sa_quarantine +$sa_quarantine / sa_delete +$sa_delete") if ($sa_quarantine || $sa_delete);<br />
+<br />
+ if ($start_spamassassin_time) {<br />
+ $stop_spamassassin_time=[gettimeofday];<br />
+ $spamassassin_time = tv_interval ($start_spamassassin_time, $stop_spamassassin_time);<br />
+<br />
+ if ($scanned) {<br />
+ &debug("SA: finished scan for $one_recip in $spamassassin_time secs - hits=$sa_hits/$required_hits");<br />
+ &minidebug("SA: finished scan for $one_recip in $spamassassin_time secs - hits=$sa_hits/$required_hits");<br />
+ } else {<br />
+ &debug("SA: finished scan of dir \"$ENV{'TMPDIR'}\" in $spamassassin_time secs - hits=$sa_hits/$required_hits");<br />
+ &minidebug("SA: finished scan in $spamassassin_time secs - hits=$sa_hits/$required_hits");<br />
+ }<br />
+ }<br />
+}<br />
+<br />
+sub log_sa_action {<br />
+ # st: maybe I will need this routine for multiples recipients<br />
+ my ($scanned,$sa_threshold,$sa_action)=@_;<br />
+ if ( $scanned && $sa_action ne "rejected" ) {<br />
+ &debug("SA: yup, this smells like SPAM - hits=$sa_hits/$required_hits/$sa_threshold - message $sa_action for $one_recip");<br />
+ &minidebug("SA: yup, this smells like SPAM - hits=$sa_hits/$required_hits/$sa_threshold - message $sa_action for $one_recip");<br />
+ } else {<br />
+ &debug("SA: yup, this smells like SPAM - hits=$sa_hits/$required_hits/$sa_threshold - message $sa_action ...");<br />
+ &minidebug("SA: yup, this smells like SPAM - hits=$sa_hits/$required_hits/$sa_threshold - message $sa_action ...");<br />
+ }<br />
+}<br />
+<br />
+#################################################<br />
+# END of Spamassassin subroutines added by ST<br />
+#################################################<br />
+<br />
+#########################<br />
+## END of scanner definitions<br />
+##<br />
+#########################<br />
diff -Naur qmail-scanner-2.01st/qmail-scanner-queue.template qmail-scanner-2.01st-qms/qmail-scanner-queue.template<br />
--- qmail-scanner-2.01st/qmail-scanner-queue.template 2007-02-04 12:55:41.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/qmail-scanner-queue.template 2007-09-09 09:28:53.000000000 +0300<br />
@@ -7,6 +7,20 @@<br />
# <br />
# Patch by: Salvatore Toribio <toribio - pusc.it><br />
#<br />
+# Patched for Event Logging by: Mark S. Teel <mteel@users.sourceforge.net><br />
+# Version: 1.22 - patched: st-qms - 20040530<br />
+#<br />
+# Patched for Account Monitoring by Mark S. Teel <mteel@users.sourceforge.net><br />
+# Version: 1.22 - patched: st-qms-monitor - 20040919<br />
+#<br />
+# Patched for Version 1.24 and merge of qms-monitor functions<br />
+# by Mark S. Teel <mteel@users.sourceforge.net><br />
+# Version: 1.24 - patched: st-qms - 20041102<br />
+#<br />
+# Patched for Version 1.25<br />
+# by Mark S. Teel <mteel@users.sourceforge.net><br />
+# Version: 1.25 - patched: st-qms - 20050618<br />
+#<br />
# See the file README-st-patch for information about the patch<br />
# This version deletes/rejects spam based in Chris Hine's patch for v1.16<br />
#<br />
@@ -112,6 +126,43 @@<br />
#deciding whether or not to send recipient alerts to<br />
my @local_domains_array=(LOCAL_DOMAINS_ARRAY);<br />
<br />
+# qms: save local domains list string<br />
+my $local_domains_string="LOCAL_DOMAINS_ARRAY";<br />
+<br />
+<br />
+######## qms-monitor: selective account monitoring/archiving<br />
+###<br />
+### Description:<br />
+### 1) qms-monitor will archive ALL email msgs SENT OR RECEIVED for<br />
+### any email address listed below<br />
+### 2) Messages are archived to $qms_monitor_home - they can be left<br />
+### there for manual examination, or a cron script can be run periodically<br />
+### to move them into a "monitor" email domain so that the mail can be<br />
+### partitioned into individual monitor domain accounts and read with<br />
+### any email client<br />
+########<br />
+<br />
+my $qms_monitor_enabled='QMS_MONITOR';<br />
+<br />
+### qms_monitor_array: add email addresses of local domains to be monitored<br />
+my @qms_monitor_array=(QMS_MON_ACCOUNTS);<br />
+<br />
+### qms_monitor_dest_array: add destination for email message copies<br />
+# Note 1: locations here will be saved underneath $qms_monitor_home;<br />
+# a cron job can later copy from that location to an alternate<br />
+# email domain used for account monitoring.<br />
+# Note 2: each entry in this array corresponds to the email address in the<br />
+# same location of the @qms_monitor_array above - i.e.,<br />
+# @qms_monitor_array[2] msgs get stored at<br />
+# @qms_monitor_dest_array[2] - thus, ORDER DOES MATTER.<br />
+# Note 3: DO NOT include a leading "/" on these paths - they will typically<br />
+# be entries that ultimately belong in /home/vpopmail/domains -<br />
+# i.e., starting with the domain name.<br />
+###<br />
+my @qms_monitor_dest_array=(QMS_MON_DESTINATIONS);<br />
+<br />
+######## qms-monitor BLOCK END<br />
+<br />
# Array of virus that we don't want to inform the sender of.<br />
my @silent_viruses_array=(SILENT_VIRUSES_ARRAY);<br />
<br />
@@ -174,6 +225,9 @@<br />
#Name of file where quarantine reports go (for long-term storage)<br />
my $quarantinelog="quarantine.log";<br />
<br />
+# qms: Name of file where usable logs for analysis are written<br />
+my $eventlog="qms-events.log";<br />
+<br />
#Generate nice random filename<br />
my ($sysname, $hostname, $release, $version, $machine) = uname();<br />
#my $hostname='FQDN'; #could get via call I suppose...<br />
@@ -191,6 +245,9 @@<br />
#turn this on<br />
my $log_crypto="LOG_CRYPTO";<br />
<br />
+# qms-monitor - the root for temporary storage<br />
+my $qms_monitor_home = "$scandir/qms-monitor";<br />
+<br />
#Max size of message allowed to be scanned - 100Mbytes by default <br />
#DO NOT SET LOWER THAN 10Mbytes!!!!!<br />
my $MAX_SCAN_SIZE=MAX_MSG_SIZE;<br />
@@ -446,12 +503,15 @@<br />
# the message size<br />
my $MINIDEBUG='MINI_DEBUG';<br />
<br />
+# qms: Want meaningful event logs? Enable this and read $scandir/qms-events.log<br />
+my $EVENTLOG='QMS_LOG'; <br />
+<br />
my @uufile_list = ();<br />
my @attachment_list = ();<br />
my @zipfile_list = ();<br />
<br />
#Want microsec times for debugging<br />
-use Time::HiRes qw( usleep ualarm gettimeofday tv_interval );<br />
+use Time::HiRes qw ( usleep ualarm gettimeofday tv_interval );<br />
use POSIX;<br />
use DB_File;<br />
<br />
@@ -534,7 +594,9 @@<br />
$mimeunpacker_binary .= " --unique_names --no-ole --paranoid -i - -d $ENV{'TMPDIR'}/";<br />
}<br />
<br />
- <br />
+#Get current timestamp for logs<br />
+my ($sec,$min,$hour,$mday,$mon,$year,$nowtime);<br />
+($sec,$min,$hour,$mday,$mon,$year) = localtime(time); <br />
my ($smtp_sender,$remote_smtp_ip,$remote_smtp_auth,$real_uid,$effective_uid);<br />
<br />
$real_uid=$<;<br />
@@ -562,9 +624,27 @@<br />
&minidebug("+++ starting debugging for process $$ (ppid=$nppid) by uid=$real_uid");<br />
}<br />
<br />
+# qms: open the event log if enabled<br />
+if ($EVENTLOG ) {<br />
+ open(ELOG,">>$scandir/$eventlog");<br />
+ select(ELOG);$|=1;<br />
+ my $starttime = strftime("%F %H:%M:%S", localtime(time));<br />
+ &eventlog("------ START MSG $starttime ------");<br />
+}<br />
+<br />
# st: if sa_alt or sa_debug are '0', sa_hdr_report_site must be 0<br />
$sa_hdr_report_site='0' if ( !$sa_alt || !$sa_debug );<br />
<br />
+# st: if the variable SA_ONLYDELETE_HOST is set in the tcpserver<br />
+# don't reject messages coming from those IPs, just delete them<br />
+# You should set this variable for your secondary mail server.<br />
+if (defined($ENV{'SA_ONLYDELETE_HOST'}) || defined($ENV{'SA_WHITELIST'})) {<br />
+ $sa_reject="0";<br />
+ &debug("WL: The server is a SA_ONLYDELETE_HOST, don't reject");<br />
+ &minidebug("WL: The server is a SA_ONLYDELETE_HOST, don't reject");<br />
+}<br />
+<br />
+<br />
# st: if the variable BMC_WHITELIST is set in the tcpserver<br />
# don't search for 'bad mime characters' in the headers of messages<br />
# coming from those IPs.<br />
@@ -624,6 +704,7 @@<br />
}<br />
$tag_score="RC:1($remote_smtp_ip):" if ($QS_RELAYCLIENT);<br />
&debug("incoming SMTP connection from $smtp_sender");<br />
+ &eventlog("CONNECT-SMTP:$ENV{'TCPREMOTEIP'}");<br />
#system("/usr/bin/printenv > /tmp/qmail-scanner.env");<br />
# st: do not reject mails from localhost useful for fetchmail<br />
$sa_reject="0" if ($remote_smtp_ip eq "127.0.0.1");<br />
@@ -634,6 +715,7 @@<br />
$QS_RELAYCLIENT=1;<br />
$tag_score="RC:1($remote_smtp_ip):"; #Always would be relayed<br />
&debug("incoming pipe connection from $smtp_sender");<br />
+ &eventlog("CONNECT-PIPE:$$");<br />
# st: do not reject mails from localhost useful for fetchmail<br />
$sa_reject="0";<br />
}<br />
@@ -659,6 +741,7 @@<br />
&grab_envelope_hdrs;<br />
&debug("from=$headers{'from'},subj=$headers{'subject'}, $qsmsgid=$headers{$qsmsgid} $smtp_sender");<br />
&minidebug("from='$headers{'from'}', subj='$headers{'subject'}', $smtp_sender");<br />
+ &eventlog("HEADER:$headers{'from'}:$headers{'to'}:$headers{'subject'}");<br />
<br />
##### st: variables for settings per domain<br />
$returnpath=tolower($returnpath);<br />
@@ -684,11 +767,13 @@<br />
if ($skip_text_msgs && ($indicates_attachments < 2) && !@uufile_list && !@attachment_list) {<br />
&debug("This is a PLAIN text message (because it's either not mime, or is text/plain), skip virus scanners - but not antispam scanners");<br />
&minidebug("This is a PLAIN text message, skip virus scanners - but not SA");<br />
+ &eventlog("TYPE:PLAIN");<br />
$plain_text_msg=1;<br />
}<br />
}<br />
if ($headers{'MAILFROM'} eq "" || $headers{'subject'} =~ /Returned mail:|Mail Transaction Failed/) {<br />
&debug("This is a bounce message - better assume there's an attachment in it");<br />
+ &eventlog("TYPE:MIXED");<br />
$plain_text_msg=0;<br />
}<br />
<br />
@@ -753,6 +838,8 @@<br />
<br />
# st: write to the log the end of the process<br />
&close_log;<br />
+&eventlog("SCANTIME:",tv_interval ($start_time, [gettimeofday]),"");<br />
+&eventlog("------ STOP MSG ---------------------------");<br />
exit 0;<br />
<br />
############################################################################<br />
@@ -800,6 +887,8 @@<br />
#$nowtime = sprintf "%02d/%02d/%02d %02d:%02d:%02d", $mday, $mon+1, $year+1900, $hour, $min, $sec;<br />
&debug("error_condition: $V_HEADER-$VERSION: $string");<br />
&minidebug("error_condition: $V_HEADER-$VERSION: $string");<br />
+ &eventlog("ERROR:$V_HEADER-$VERSION:$string");<br />
+ close(ELOG);<br />
&cleanup;<br />
&close_log;<br />
exit $errcode;<br />
@@ -810,6 +899,91 @@<br />
print LOG "$dnowtime:$nprocess: ",@_,"\n" if ($DEBUG);<br />
}<br />
<br />
+# qms: log events to the file<br />
+sub eventlog {<br />
+ my $enowtime = sprintf "%10d", time;<br />
+ print ELOG "$enowtime:$$:",@_,"\n" if ($EVENTLOG);<br />
+}<br />
+<br />
+######## qms-monitor BLOCK BEGIN<br />
+# qms-monitor: Entry point called prior to requeueing the msg<br />
+sub qms_monitor<br />
+{<br />
+ my($msg) = @_;<br />
+ my($acct) = '';<br />
+ my($aindex) = '0';<br />
+<br />
+ foreach $acct (@qms_monitor_array)<br />
+ {<br />
+ # check the sender address first<br />
+ if ($returnpath =~ /$acct/i)<br />
+ {<br />
+ &qms_monitor_save($acct,$msg,"@qms_monitor_dest_array[$aindex]");<br />
+ $aindex += 1;<br />
+ next;<br />
+ }<br />
+<br />
+ if ($recips =~ /$acct/i)<br />
+ {<br />
+ &qms_monitor_save($acct,$msg,"@qms_monitor_dest_array[$aindex]");<br />
+ }<br />
+<br />
+ $aindex += 1;<br />
+ }<br />
+}<br />
+<br />
+# qms-monitor: save the msg to our archive location<br />
+sub qms_monitor_save<br />
+{<br />
+ my($qmsacct,$src,$dest) = @_;<br />
+ my($finaldest) = "$qms_monitor_home/$dest";<br />
+ my($fname) = &qms_monitor_get_filename($qmsacct);<br />
+<br />
+ if (!open(INMSG, "<$src"))<br />
+ {<br />
+ &eventlog("--- qms_monitor_save: unable to open src $src");<br />
+ &debug ("qms_monitor_save: unable to open src $src\n");<br />
+ return;<br />
+ }<br />
+<br />
+ if (! -d "$finaldest")<br />
+ {<br />
+ if (system("mkdir -p $finaldest"))<br />
+ {<br />
+ &eventlog("--- qms_monitor_save: unable to mkdir $finaldest");<br />
+ &debug ("qms_monitor_save: unable to mkdir $finaldest");<br />
+ return;<br />
+ }<br />
+ }<br />
+<br />
+<br />
+ if (!open(OUTMSG, ">$finaldest/$fname"))<br />
+ {<br />
+ &eventlog("--- qms_monitor_save: unable to open dest $finaldest/$fname");<br />
+ &debug ("qms_monitor_save: unable to open dest $finaldest/$fname\n");<br />
+ return;<br />
+ }<br />
+<br />
+ while (<INMSG>)<br />
+ {<br />
+ print OUTMSG;<br />
+ }<br />
+<br />
+ close(OUTMSG);<br />
+ close(INMSG);<br />
+}<br />
+<br />
+# qms-monitor: Generate meaninful file names<br />
+sub qms_monitor_get_filename<br />
+{<br />
+ my($aname) = @_;<br />
+ my($stime) = strftime("%F_%H:%M:%S", localtime(time));<br />
+<br />
+ return "$aname" . "_" . "$hostname" . "_" . "$stime" . "_" . $$;<br />
+}<br />
+<br />
+######## qms-monitor BLOCK END<br />
+<br />
sub working_copy {<br />
my ($hdr,$last_hdr,$value,$num_of_headers,$last_header,$last_value,$attachment_filename);<br />
select(STDIN); $|=1;<br />
@@ -835,6 +1009,7 @@<br />
$illegal_mime=1;<br />
&debug("w_c: found CRL/NULL in header - invalid if this is a MIME message");<br />
&minidebug("w_c: found CRL/NULL in header - invalid if this is a MIME message");<br />
+ &eventlog("QMSWC:BAD_HDR_CHARS");<br />
}<br />
#Put headers into array<br />
if (/^\s+(.*)$/ && $last_hdr) {<br />
@@ -851,6 +1026,7 @@<br />
$description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
&debug("w_c: disallowed breakage found in header name ($_) - not valid email");<br />
&minidebug("w_c: disallowed breakage found in header name ($_) - not valid email");<br />
+ &eventlog("QMSWC:BAD_HDR_BREAKAGE");<br />
#next;<br />
} else {<br />
/^([^\s]+):(.*)$/;<br />
@@ -868,6 +1044,7 @@<br />
$description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
&debug("w_c: $quarantine_description");<br />
&minidebug("w_c: $quarantine_description");<br />
+ &eventlog("QMSWC:BAD_HDR_MIME");<br />
}<br />
$num_of_headers++;<br />
}<br />
@@ -953,6 +1130,7 @@<br />
&minidebug("w_c: $quarantine_description");<br />
$quarantine_event="Policy:Bad_MIME_Type";<br />
$description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
+ &eventlog("QMSWC:BAD_MIME_CONTENT");<br />
}<br />
#}<br />
#if ( $headers{'content-type'} =~ /boundary(\s*)=(|\s+|\s*\")([^\"\;]+)($|\;|\")/i) {<br />
@@ -965,6 +1143,7 @@<br />
#$quarantine_description="Disallowed MIME boundary found - potential virus";<br />
#$quarantine_event="Policy:Bad_MIME_Boundary";<br />
#$description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
+ #&eventlog("QMSWC:BAD_MIME_BOUNDARY");<br />
#}<br />
if (!$quarantine_event && $headers{'mime-version'} ne "" && $BAD_MIME_CHECKS > 1 && ( length($BOUNDARY{$attachment_counter}) == 0 || length($BOUNDARY{$attachment_counter}) > 250)) {<br />
#RFC2046 says boundarys are 1-70 chars - making it 250 is being *real* liberal...<br />
@@ -974,6 +1153,7 @@<br />
&debug($quarantine_description);<br />
$quarantine_event="Policy:Bad_MIME_Length";<br />
$description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
+ &eventlog("QMSWC:BAD_MIME_BOUNDARY");<br />
}<br />
#Strip off stuff after semicolon, and escape any odd chars<br />
$BOUNDARY{$attachment_counter} =~ s/(\"|\;).*$//g;<br />
@@ -1016,6 +1196,7 @@<br />
if (!$quarantine_event && $BAD_MIME_CHECKS > 1) {<br />
&debug("w_c: Disallowed MIME filename manipulation - potential virus");<br />
&minidebug("w_c: Disallowed MIME filename manipulation - potential virus");<br />
+ &eventlog("QMSWC:BAD_MIME_FILENAME");<br />
$illegal_mime=1;<br />
$destring="LOCALE_destring_problem";<br />
$quarantine_description='Disallowed MIME filename manipulation - not valid email';<br />
@@ -1068,6 +1249,7 @@<br />
&minidebug("w_c: $quarantine_description");<br />
$quarantine_event="Policy:Bad_MIME_Boundary";<br />
$description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
+ &eventlog("QMSWC:BAD_MIME_BOUNDARY");<br />
}<br />
if ( !$quarantine_event && $headers{'mime-version'} ne "" && $BAD_MIME_CHECKS > 1 && $BOUNDARY{$attachment_counter} =~ /^($BOUNDARY_REGEX)$/i) {<br />
&debug("w_c: hmm, a new boundary defintion that has already being set. Sounds like a trojan");<br />
@@ -1081,6 +1263,7 @@<br />
&minidebug("w_c: $quarantine_description");<br />
$quarantine_event="Policy:Bad_MIME_Boundary";<br />
$description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
+ &eventlog("QMSWC:BAD_MIME_BOUNDARY");<br />
}<br />
if ($BOUNDARY_REGEX ne "") {<br />
$BOUNDARY_REGEX.="|".$BOUNDARY{$attachment_counter};<br />
@@ -1104,6 +1287,7 @@<br />
$destring='LOCALE_destring_problem';<br />
&debug($quarantine_description);<br />
&minidebug("w_c: $quarantine_description");<br />
+ &eventlog("QMSWC:BAD_MIME_ASSOCIATION");<br />
$quarantine_event="Policy:Forged_Attachment";<br />
$description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in attachment $attachment_filename";<br />
}<br />
@@ -1150,6 +1334,7 @@<br />
&minidebug("w_c: $quarantine_description");<br />
$quarantine_event="Policy:Bad_MIME_Header";<br />
$description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
+ &eventlog("QMSWC:BAD_MIME_CONTENT");<br />
}<br />
}<br />
}<br />
@@ -1168,6 +1353,7 @@<br />
$description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in attachment \"$attachment_filename\"";<br />
&debug("w_c: $quarantine_description");<br />
&minidebug("w_c: $quarantine_description");<br />
+ &eventlog("QMSWC:BAD_MIME_WINBLOWS");<br />
}<br />
}<br />
if ($_ =~ /^(UEsDB[AB]|UEswMFBL)/) {<br />
@@ -1181,6 +1367,7 @@<br />
$description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in attachment \"$attachment_filename\"";<br />
&debug("w_c: $quarantine_description");<br />
&minidebug("w_c: $quarantine_description");<br />
+ &eventlog("QMSWC:BAD_MIME_ZIP");<br />
}<br />
}<br />
}<br />
@@ -1264,6 +1451,7 @@<br />
#some (valid) reason (including the other end dropping the connection).<br />
&debug("g_e_h: no sender and no recips. Probably due to SMTP client dropping connection. Nothing we can do - cleanup and exit. This is not necessarily an error!");<br />
&minidebug("g_e_h: no sender and no recips, from $smtp_sender. Dropping, this isn't a QS error.");<br />
+ &eventlog("SMTP-DROP");<br />
warn "$$ QS-$VERSION: no sender and no recips, from $smtp_sender\n" if ($MINIDEBUG >= 3);<br />
warn "$V_HEADER-$VERSION: no sender and no recips, from $smtp_sender\n" if ($MINIDEBUG == 2);<br />
&cleanup;<br />
@@ -1272,6 +1460,7 @@<br />
}<br />
&debug("g_e_h: return-path is \"$returnpath\", recips is \"$recips\"");<br />
&minidebug("g_e_h: return-path='$returnpath', recips='$recips'");<br />
+ &eventlog("ENV-HEADER:$local_domains_string:$returnpath:$recips");<br />
}<br />
<br />
<br />
@@ -1409,6 +1598,7 @@<br />
$description .= "\n---perlscanner results ---\n$destring '$quarantine_description'\n found in message";<br />
&debug("p_s: something to block! ($quarantine_description)");<br />
&minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("PERLSCAN:BAD_MIME_HEADER");<br />
}<br />
#check out headers against DB...<br />
<br />
@@ -1438,6 +1628,7 @@<br />
$description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in file $ENV{'TMPDIR'}/$file";<br />
&debug("p_s: something to block! ($quarantine_description)");<br />
&minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("PERLSCAN:BAD_HDR_DB");<br />
last;<br />
}<br />
} else {<br />
@@ -1468,6 +1659,7 @@<br />
$description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in message";<br />
&debug("p_s: something to block! ($quarantine_description)");<br />
&minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("PERLSCAN:BAD_HDR_DB");<br />
}<br />
$CRYPTO_TYPE=~s/\)$/,private\)/;<br />
}<br />
@@ -1481,6 +1673,7 @@<br />
$description .= "\n---perlscanner results ---\n$destring '$quarantine_description' found in file $ENV{'TMPDIR'}/$file";<br />
&debug("p_s: something to block! ($quarantine_description)");<br />
&minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("PERLSCAN:BAD_HDR_DB");<br />
return;<br />
}<br />
}<br />
@@ -1496,6 +1689,7 @@<br />
$file_desc .= "too_many:$msg_size\t" if ($file_desc !~ /\Q$file\E:$size\t/);<br />
&debug("p_s: something to block! ($quarantine_description)");<br />
&minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("PERLSCAN:BAD_ATTACH_LENGTH");<br />
return;<br />
}<br />
foreach $filepath (@allfiles,@uufile_list,@zipfile_list,@attachment_list) {<br />
@@ -1527,6 +1721,7 @@<br />
$file_desc .= "$file:$msg_size\t" if ($file_desc !~ /\Q$file\E:$size\t/);<br />
&debug("p_s: something to block! ($quarantine_description)");<br />
&minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("QMSWC:BAD_ATTACH_FILENAME");<br />
return;<br />
}<br />
<br />
@@ -1545,6 +1740,7 @@<br />
$file_desc .= "$file:$msg_size\t" if ($file_desc !~ /\Q$file\E:$size\t/);<br />
&debug("p_s: something to block! ($quarantine_description)");<br />
&minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("QMSWC:BAD_ATTACH_FILENAME");<br />
return;<br />
}<br />
if ($virtualheader{'FILECLSID'} ne "" && !$quarantine_event && $file =~ /\{[0-9a-f]{8}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{12}\}$/i) {<br />
@@ -1555,6 +1751,7 @@<br />
$file_desc .= "$file:$msg_size\t" if ($file_desc !~ /\Q$file\E:$size\t/);<br />
&debug("p_s: something to block! ($quarantine_description)");<br />
&minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("QMSWC:BAD_ATTACH_FILENAME");<br />
return;<br />
}<br />
}<br />
@@ -1605,6 +1802,7 @@<br />
$section=$apptype=$save_filename=$filename="";<br />
&debug("p_s: something to block! ($quarantine_description)");<br />
&minidebug("p_s: something to block! ($quarantine_description)");<br />
+ &eventlog("PERLSCAN:BAD_ATTACHMENT_TYPE");<br />
# return;<br />
}<br />
}<br />
@@ -1621,6 +1819,7 @@<br />
$file_desc .= "encrypted_zip:$msg_size\t";<br />
&debug("u_f: something to block! ($quarantine_description)");<br />
&minidebug("u_f: something to block! ($quarantine_description)");<br />
+ &eventlog("PERLSCAN:BAD_ATTACHMENT_TYPE");<br />
return;<br />
}<br />
<br />
@@ -2482,6 +2681,7 @@<br />
print SM "Subject: $tmpsubj\n";<br />
}<br />
print SM "Message-ID: <".&uniq_id."\@$hostname>\n";<br />
+ print SM "X-Tnz-Problem-Type: 40\n";<br />
print SM "Auto-Submitted: auto-replied\n";<br />
if ($headers{'message-id'} ne "") {<br />
print SM "In-Reply-To: ",$headers{'message-id'},"\n";<br />
@@ -2554,6 +2754,7 @@<br />
$tmpsubj =~ s/(\r|\0|\n)/ /g;<br />
print SM "Subject: $tmpsubj\n";<br />
print SM "Message-ID: <".&uniq_id."\@$hostname>\n";<br />
+ print SM "X-Tnz-Problem-Type: 40\n";<br />
if ($headers{'message-id'} ne "") {<br />
print SM "In-Reply-To: ",$headers{'message-id'},"\n";<br />
print SM "References: ",$headers{'message-id'},"\n";<br />
@@ -2617,6 +2818,7 @@<br />
if ($MAYBEZIP =~ /skipping:.*password/) {<br />
&debug ("u_f: it is a password-protected zip file");<br />
&minidebug ("u_f: it is a password-protected zip file");<br />
+ &eventlog("UNZIP:PASSWORD_PROTECTED");<br />
$CRYPTO_TYPE="CR:ZIP(encrypted)";<br />
}<br />
if ($force_unzip) {<br />
diff -Naur qmail-scanner-2.01st/qms-analog-types.txt qmail-scanner-2.01st-qms/qms-analog-types.txt<br />
--- qmail-scanner-2.01st/qms-analog-types.txt 1970-01-01 02:00:00.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/qms-analog-types.txt 2007-09-09 07:58:35.000000000 +0300<br />
@@ -0,0 +1,64 @@<br />
+qms-analog log files are of the general form:<br />
+<time (secs since epoch)>:processID:LOGTYPE:<type-specific parms>...<br />
+<br />
+<br />
+LOGTYPES and associated parameters are listed below:<br />
+<br />
+*Info*<br />
+-----------------------------------------------------------------<br />
+<br />
+-* - remark line<br />
+CONNECT-SMTP:<IP ADRS> - SMTP connect from IP<br />
+CONNECT-PIPE:$$ - SMTP connect from process $$<br />
+HEADER:<from adrs>:<to adrs>:subject - SMTP header contents<br />
+ENV-HEADER:<returnpath>:<recips> - envelope hdr contents<br />
+TYPE:PLAIN - message has no mime type or text/plain<br />
+TYPE:MIXED - message has non-text/plain mime type<br />
+SCANTIME:<time> - total time in qmail-scanner<br />
+SPAM-RESULT:<score>:<thresh>:<delete> - spamassassin score for msg<br />
+<br />
+ERROR:<VERSION>:<string> - error condition<br />
+SMTP-DROP - qmail dropping msg<br />
+<br />
+<br />
+*Flagged Msgs*<br />
+-----------------------------------------------------------------<br />
+<br />
+QMSWC: - QMS working copy detection<br />
+ BAD_HDR_CHARS - bad chars in hdr<br />
+ BAD_HDR_BREAKAGE - breakage in header name<br />
+ BAD_HDR_MIME - Disallowed mime content in hdr name<br />
+ BAD_MIME_CONTENT - Disallowed mime content type<br />
+ BAD_MIME_FILENAME - Disallowed MIME filename manipulation<br />
+ BAD_MIME_BOUNDARY - broken attachment MIME details<br />
+ BAD_MIME_ASSOCIATION - Disallowed file associated with unrelated MIME type<br />
+ BAD_MIME_WINBLOWS - Disallowed executable attachment (windows)<br />
+ BAD_ATTACH_FILENAME - Disallowed attachment filename MIME type<br />
+ BAD_MIME_ZIP - Disallowed zip attachment when not assoc with a .zip<br />
+<br />
+PERLSCAN: - PerlScan detection<br />
+ BAD_MIME_HEADER - Disallowed characters found in MIME headers<br />
+ BAD_HDR_DB - hdr type in disallowed db<br />
+ BAD_ATTACH_LENGTH - majorly long attachment filename found<br />
+ BAD_ATTACHMENT_TYPE - Disallowed attachment type<br />
+<br />
+UNZIP:PASSWORD_PROTECTED - zip file is password protected<br />
+<br />
+CLAMAV:<quarantine_description> - clamAV found a virus<br />
+AVPAV:<quarantine_description> - AVPLinux AV found a virus<br />
+CSAV:<quarantine_description> - Command scanner AV found a virus<br />
+FPROTAV:<quarantine_description> - F-prot scanner AV found a virus<br />
+FSECUREAV:<quarantine_description> - Fsecure AV found a virus<br />
+HBEDVAV:<quarantine_description> - H+BEDV scanner AV found a virus<br />
+INNOCAV:<quarantine_description> - Innoculan AV found a virus<br />
+ISCANAV:<quarantine_description> - Iscan AV found a virus<br />
+RAVLINAV:<quarantine_description> - Ravlin AV found a virus<br />
+UVSCANAV:<quarantine_description> - McAfee AV found a virus<br />
+VEXIRAV:<quarantine_description> - Vexira AV found a virus<br />
+<br />
+<br />
+SPAM-DETECT: - spamassassin spam detected<br />
+ DELETE - score > thresh + delete<br />
+ MARK - thresh < score < thresh + delete<br />
+ QUARANTINE - thresh + quarantine < score < thresh + delete<br />
+ REJECT - SMTP reject sent to sender<br />
\ No newline at end of file<br />
diff -Naur qmail-scanner-2.01st/qms-config qmail-scanner-2.01st-qms/qms-config<br />
--- qmail-scanner-2.01st/qms-config 1970-01-01 02:00:00.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/qms-config 2007-09-09 07:58:35.000000000 +0300<br />
@@ -0,0 +1,81 @@<br />
+#!/bin/sh<br />
+<br />
+## File: qms-config<br />
+##<br />
+## Purpose: Provide a file to save personal qmail-scanner configuration<br />
+## options. This file should be edited for your server and<br />
+## saved somewhere so that it survives qmail-scanner and<br />
+## qms-analog upgrades.<br />
+##<br />
+<br />
+# Was the "install" option given?<br />
+if [ "$1" != "install" ]; then<br />
+ INSTALL=<br />
+else<br />
+ INSTALL="--install"<br />
+fi<br />
+<br />
+## Definition of Options<br />
+##<br />
+## domain - your primary email domain, where your postmaster<br />
+## account is located<br />
+## admin - your postmaster username, normally "postmaster"<br />
+## local-domains - list all of your local email domains for this qmail<br />
+## server, separated by commas<br />
+## add-dscr-hdrs - enable descriptive email headers<br />
+## dscr-hdrs-text - "Header" for the header<br />
+## ignore-eol-check - ignore end of line characters in email headers<br />
+## sa-quarantine - enable/disable quarantining email identified as spam<br />
+## sa-delete - enable/disable deleting email identified as spam; <br />
+## if 0, deletion is disabled; if positive, the value <br />
+## over "required_hits" to start deletion<br />
+## sa-reject - enable/disable rejection of emails identified as spam<br />
+## sa-subject - spam-identifying test to be prepended to the subject<br />
+## header<br />
+## sa-alt - use alternative "fast" Spamassassin processing<br />
+## provided in the "st" patch<br />
+## sa-debug - turn on default qmail-scanner debugging; very verbose <br />
+## and annoying<br />
+## notify - comma-separated list parties to notify when a virus <br />
+## is quarantined; see the qmail-scanner docs for more <br />
+## details<br />
+## redundant - enable/disable allowing the scanners to scan any zip <br />
+## files and the original "raw" email file<br />
+## qms-monitor - [yes|no] enable qms-monitor Account Monitoring<br />
+## qms-monitor-accts - list of email accounts to be monitored, separated by <br />
+## commas<br />
+## Example: "acct1@dom2.com,acct2@dom1.com"<br />
+## qms-monitor-dests - list of destination paths for monitored email messages<br />
+## Note 1: locations here will be saved underneath<br />
+## .../qmailscan/qms-monitor; a cron job can later<br />
+## copy from that location to an alternate email <br />
+## domain used for account monitoring.<br />
+## Note 2: each entry in this array corresponds to the <br />
+## email address in the same location of the <br />
+## qms-monitor-accts list above - i.e., <br />
+## qms-monitor-accts[2] msgs get stored at<br />
+## qms-monitor-dests[2] - thus, ORDER DOES MATTER<br />
+## Note 3: DO NOT include a leading "/" on these paths - <br />
+## they will typically be entries that ultimately <br />
+## belong in /home/vpopmail/domains - so start with<br />
+## the domain name.<br />
+## Example: "mon.dom2.com/acct1/Maildir/new,mon.dom1.com/acct2/Maildir/new"<br />
+##<br />
+<br />
+./configure --domain yourdomain.com \<br />
+ --admin postmaster \<br />
+ --local-domains "yourdomain.com,yourotherdomain.com" \<br />
+ --add-dscr-hdrs yes \<br />
+ --dscr-hdrs-text "X-Antivirus-MYDOMAIN" \<br />
+ --ignore-eol-check yes \<br />
+ --sa-quarantine 0 \<br />
+ --sa-delete 0 \<br />
+ --sa-reject no \<br />
+ --sa-subject ":SPAM:" \<br />
+ --sa-alt yes \<br />
+ --sa-debug no \<br />
+ --notify admin \<br />
+ --redundant yes \<br />
+ --qms-monitor no \<br />
+ "$INSTALL"<br />
+<br />
diff -Naur qmail-scanner-2.01st/qms-config-cwrapper qmail-scanner-2.01st-qms/qms-config-cwrapper<br />
--- qmail-scanner-2.01st/qms-config-cwrapper 1970-01-01 02:00:00.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/qms-config-cwrapper 2007-09-09 07:58:35.000000000 +0300<br />
@@ -0,0 +1,82 @@<br />
+#!/bin/sh<br />
+<br />
+## File: qms-config-cwrapper<br />
+##<br />
+## Purpose: Provide a file to save personal qmail-scanner configuration<br />
+## options. This file should be edited for your server and <br />
+## saved somewhere so that it survives qmail-scanner and <br />
+## qms-analog upgrades.<br />
+##<br />
+<br />
+# Was the "install" option given?<br />
+if [ "$1" != "install" ]; then<br />
+ INSTALL=<br />
+else<br />
+ INSTALL="--install"<br />
+fi<br />
+<br />
+## Definition of Options<br />
+##<br />
+## domain - your primary email domain, where your postmaster<br />
+## account is located<br />
+## admin - your postmaster username, normally "postmaster"<br />
+## local-domains - list all of your local email domains for this qmail<br />
+## server, separated by commas<br />
+## add-dscr-hdrs - enable descriptive email headers<br />
+## dscr-hdrs-text - "Header" for the header<br />
+## ignore-eol-check - ignore end of line characters in email headers<br />
+## sa-quarantine - enable/disable quarantining email identified as spam<br />
+## sa-delete - enable/disable deleting email identified as spam; <br />
+## if 0, deletion is disabled; if positive, the value <br />
+## over "required_hits" to start deletion<br />
+## sa-reject - enable/disable rejection of emails identified as spam<br />
+## sa-subject - spam-identifying test to be prepended to the subject<br />
+## header<br />
+## sa-alt - use alternative "fast" Spamassassin processing<br />
+## provided in the "st" patch<br />
+## sa-debug - turn on default qmail-scanner debugging; very verbose <br />
+## and annoying<br />
+## notify - comma-separated list parties to notify when a virus <br />
+## is quarantined; see the qmail-scanner docs for more <br />
+## details<br />
+## redundant - enable/disable allowing the scanners to scan any zip <br />
+## files and the original "raw" email file<br />
+## qms-monitor - [yes|no] enable qms-monitor Account Monitoring<br />
+## qms-monitor-accts - list of email accounts to be monitored, separated by <br />
+## commas<br />
+## Example: "acct1@dom2.com,acct2@dom1.com"<br />
+## qms-monitor-dests - list of destination paths for monitored email messages<br />
+## Note 1: locations here will be saved underneath<br />
+## .../qmailscan/qms-monitor; a cron job can later<br />
+## copy from that location to an alternate email <br />
+## domain used for account monitoring.<br />
+## Note 2: each entry in this array corresponds to the <br />
+## email address in the same location of the <br />
+## qms-monitor-accts list above - i.e., <br />
+## qms-monitor-accts[2] msgs get stored at<br />
+## qms-monitor-dests[2] - thus, ORDER DOES MATTER<br />
+## Note 3: DO NOT include a leading "/" on these paths - <br />
+## they will typically be entries that ultimately <br />
+## belong in /home/vpopmail/domains - so start with<br />
+## the domain name.<br />
+## Example: "mon.dom2.com/acct1/Maildir/new,mon.dom1.com/acct2/Maildir/new"<br />
+##<br />
+<br />
+./configure --domain yourdomain.com \<br />
+ --admin postmaster \<br />
+ --local-domains "yourdomain.com,yourotherdomain.com" \<br />
+ --add-dscr-hdrs yes \<br />
+ --dscr-hdrs-text "X-Antivirus-MYDOMAIN" \<br />
+ --ignore-eol-check yes \<br />
+ --sa-quarantine 0 \<br />
+ --sa-delete 0 \<br />
+ --sa-reject no \<br />
+ --sa-subject ":SPAM:" \<br />
+ --sa-alt yes \<br />
+ --sa-debug no \<br />
+ --notify admin \<br />
+ --redundant yes \<br />
+ --skip-setuid-test \<br />
+ --qms-monitor no \<br />
+ "$INSTALL"<br />
+<br />
diff -Naur qmail-scanner-2.01st/qms-config-monitor qmail-scanner-2.01st-qms/qms-config-monitor<br />
--- qmail-scanner-2.01st/qms-config-monitor 1970-01-01 02:00:00.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/qms-config-monitor 2007-09-09 07:58:35.000000000 +0300<br />
@@ -0,0 +1,85 @@<br />
+#!/bin/sh<br />
+<br />
+## File: qms-config-monitor<br />
+##<br />
+## Purpose: Provide a file to save personal qmail-scanner configuration<br />
+## options. This file should be edited for your server and<br />
+## saved somewhere so that it survives qmail-scanner and<br />
+## qms-analog upgrades.<br />
+##<br />
+## Note: This is a special version to enable qms-monitor<br />
+##<br />
+<br />
+# Was the "install" option given?<br />
+if [ "$1" != "install" ]; then<br />
+ INSTALL=<br />
+else<br />
+ INSTALL="--install"<br />
+fi<br />
+<br />
+## Definition of Options<br />
+##<br />
+## domain - your primary email domain, where your postmaster<br />
+## account is located<br />
+## admin - your postmaster username, normally "postmaster"<br />
+## local-domains - list all of your local email domains for this qmail<br />
+## server, separated by commas<br />
+## add-dscr-hdrs - enable descriptive email headers<br />
+## dscr-hdrs-text - "Header" for the header<br />
+## ignore-eol-check - ignore end of line characters in email headers<br />
+## sa-quarantine - enable/disable quarantining email identified as spam<br />
+## sa-delete - enable/disable deleting email identified as spam; <br />
+## if 0, deletion is disabled; if positive, the value <br />
+## over "required_hits" to start deletion<br />
+## sa-reject - enable/disable rejection of emails identified as spam<br />
+## sa-subject - spam-identifying test to be prepended to the subject<br />
+## header<br />
+## sa-alt - use alternative "fast" Spamassassin processing<br />
+## provided in the "st" patch<br />
+## sa-debug - turn on default qmail-scanner debugging; very verbose <br />
+## and annoying<br />
+## notify - comma-separated list parties to notify when a virus <br />
+## is quarantined; see the qmail-scanner docs for more <br />
+## details<br />
+## redundant - enable/disable allowing the scanners to scan any zip <br />
+## files and the original "raw" email file<br />
+## qms-monitor - [yes|no] enable qms-monitor Account Monitoring<br />
+## qms-monitor-accts - list of email accounts to be monitored, separated by <br />
+## commas<br />
+## Example: "acct1@dom2.com,acct2@dom1.com"<br />
+## qms-monitor-dests - list of destination paths for monitored email messages<br />
+## Note 1: locations here will be saved underneath<br />
+## .../qmailscan/qms-monitor; a cron job can later<br />
+## copy from that location to an alternate email <br />
+## domain used for account monitoring.<br />
+## Note 2: each entry in this array corresponds to the <br />
+## email address in the same location of the <br />
+## qms-monitor-accts list above - i.e., <br />
+## qms-monitor-accts[2] msgs get stored at<br />
+## qms-monitor-dests[2] - thus, ORDER DOES MATTER<br />
+## Note 3: DO NOT include a leading "/" on these paths - <br />
+## they will typically be entries that ultimately <br />
+## belong in /home/vpopmail/domains - so start with<br />
+## the domain name.<br />
+## Example: "mon.dom2.com/acct1/Maildir/new,mon.dom1.com/acct2/Maildir/new"<br />
+##<br />
+<br />
+./configure --domain yourdomain.com \<br />
+ --admin postmaster \<br />
+ --local-domains "yourdomain.com,yourotherdomain.com" \<br />
+ --add-dscr-hdrs yes \<br />
+ --dscr-hdrs-text "X-Antivirus-MYDOMAIN" \<br />
+ --ignore-eol-check yes \<br />
+ --sa-quarantine 0 \<br />
+ --sa-delete 0 \<br />
+ --sa-reject no \<br />
+ --sa-subject ":SPAM:" \<br />
+ --sa-alt yes \<br />
+ --sa-debug no \<br />
+ --notify admin \<br />
+ --redundant yes \<br />
+ --qms-monitor yes \<br />
+ --qms-monitor-accts "acct1@dom2.com,acct2@dom1.com" \<br />
+ --qms-monitor-dests "monitor.dom2.com/acct1/Maildir/new,monitor.dom1.com/acct2/Maildir/new" \<br />
+ "$INSTALL"<br />
+<br />
diff -Naur qmail-scanner-2.01st/qms-config-monitor-cwrapper qmail-scanner-2.01st-qms/qms-config-monitor-cwrapper<br />
--- qmail-scanner-2.01st/qms-config-monitor-cwrapper 1970-01-01 02:00:00.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/qms-config-monitor-cwrapper 2007-09-09 07:58:35.000000000 +0300<br />
@@ -0,0 +1,86 @@<br />
+#!/bin/sh<br />
+<br />
+## File: qms-config-monitor-cwrapper<br />
+##<br />
+## Purpose: Provide a file to save personal qmail-scanner configuration<br />
+## options. This file should be edited for your server and <br />
+## saved somewhere so that it survives qmail-scanner and <br />
+## qms-analog upgrades.<br />
+##<br />
+## Note: This is a special version to enable qms-monitor with the<br />
+## C-wrapper<br />
+##<br />
+<br />
+# Was the "install" option given?<br />
+if [ "$1" != "install" ]; then<br />
+ INSTALL=<br />
+else<br />
+ INSTALL="--install"<br />
+fi<br />
+<br />
+## Definition of Options<br />
+##<br />
+## domain - your primary email domain, where your postmaster<br />
+## account is located<br />
+## admin - your postmaster username, normally "postmaster"<br />
+## local-domains - list all of your local email domains for this qmail<br />
+## server, separated by commas<br />
+## add-dscr-hdrs - enable descriptive email headers<br />
+## dscr-hdrs-text - "Header" for the header<br />
+## ignore-eol-check - ignore end of line characters in email headers<br />
+## sa-quarantine - enable/disable quarantining email identified as spam<br />
+## sa-delete - enable/disable deleting email identified as spam; <br />
+## if 0, deletion is disabled; if positive, the value <br />
+## over "required_hits" to start deletion<br />
+## sa-reject - enable/disable rejection of emails identified as spam<br />
+## sa-subject - spam-identifying test to be prepended to the subject<br />
+## header<br />
+## sa-alt - use alternative "fast" Spamassassin processing<br />
+## provided in the "st" patch<br />
+## sa-debug - turn on default qmail-scanner debugging; very verbose <br />
+## and annoying<br />
+## notify - comma-separated list parties to notify when a virus <br />
+## is quarantined; see the qmail-scanner docs for more <br />
+## details<br />
+## redundant - enable/disable allowing the scanners to scan any zip <br />
+## files and the original "raw" email file<br />
+## qms-monitor - [yes|no] enable qms-monitor Account Monitoring<br />
+## qms-monitor-accts - list of email accounts to be monitored, separated by <br />
+## commas<br />
+## Example: "acct1@dom2.com,acct2@dom1.com"<br />
+## qms-monitor-dests - list of destination paths for monitored email messages<br />
+## Note 1: locations here will be saved underneath<br />
+## .../qmailscan/qms-monitor; a cron job can later<br />
+## copy from that location to an alternate email <br />
+## domain used for account monitoring.<br />
+## Note 2: each entry in this array corresponds to the <br />
+## email address in the same location of the <br />
+## qms-monitor-accts list above - i.e., <br />
+## qms-monitor-accts[2] msgs get stored at<br />
+## qms-monitor-dests[2] - thus, ORDER DOES MATTER<br />
+## Note 3: DO NOT include a leading "/" on these paths - <br />
+## they will typically be entries that ultimately <br />
+## belong in /home/vpopmail/domains - so start with<br />
+## the domain name.<br />
+## Example: "mon.dom2.com/acct1/Maildir/new,mon.dom1.com/acct2/Maildir/new"<br />
+##<br />
+<br />
+./configure --domain yourdomain.com \<br />
+ --admin postmaster \<br />
+ --local-domains "yourdomain.com,yourotherdomain.com" \<br />
+ --add-dscr-hdrs yes \<br />
+ --dscr-hdrs-text "X-Antivirus-MYDOMAIN" \<br />
+ --ignore-eol-check yes \<br />
+ --sa-quarantine 0 \<br />
+ --sa-delete 0 \<br />
+ --sa-reject no \<br />
+ --sa-subject ":SPAM:" \<br />
+ --sa-alt yes \<br />
+ --sa-debug no \<br />
+ --notify admin \<br />
+ --redundant yes \<br />
+ --skip-setuid-test \<br />
+ --qms-monitor yes \<br />
+ --qms-monitor-accts "acct1@dom2.com,acct2@dom1.com" \<br />
+ --qms-monitor-dests "monitor.dom2.com/acct1/Maildir/new,monitor.dom1.com/acct2/Maildir/new" \<br />
+ "$INSTALL"<br />
diff -Naur qmail-scanner-2.01st/qms-monitor-move.sh qmail-scanner-2.01st-qms/qms-monitor-move.sh<br />
--- qmail-scanner-2.01st/qms-monitor-move.sh 1970-01-01 02:00:00.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/qms-monitor-move.sh 2007-09-09 07:58:35.000000000 +0300<br />
@@ -0,0 +1,21 @@<br />
+#!/bin/sh<br />
+<br />
+## example cron script to move qms-monitor messages to their final destination<br />
+##<br />
+## must be run from the root cron table!<br />
+##<br />
+## cron entry: 0-59/5 * * * * /var/qmail/bin/qms-monitor-move.sh >/dev/null<br />
+## will run the script every 5 minutes, moving emails to the appropriate<br />
+## monitor email domains, where they can be read as normal email<br />
+##<br />
+## Just run crontab -e (as root) and add the line above.<br />
+##<br />
+<br />
+# change ownership so we can retrieve via vpopmail<br />
+chown -R vpopmail:vchkpw /var/spool/qmailscan/qms-monitor/*<br />
+<br />
+# copy from the temp location to vpopmail home<br />
+cp -R -p /var/spool/qmailscan/qms-monitor/* /home/vpopmail/domains<br />
+<br />
+# delete the temp copies<br />
+rm -rf /var/spool/qmailscan/qms-monitor/*<br />
diff -Naur qmail-scanner-2.01st/README-qms-analog qmail-scanner-2.01st-qms/README-qms-analog<br />
--- qmail-scanner-2.01st/README-qms-analog 1970-01-01 02:00:00.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/README-qms-analog 2007-09-09 07:58:35.000000000 +0300<br />
@@ -0,0 +1,275 @@<br />
+qms-analog: Qmail-Scanner Log File Analyzer<br />
+-------------------------------------------<br />
+<br />
+Version: 0.4.0, 11/02/2004<br />
+<br />
+<br />
+Distribution Files<br />
+------------------<br />
+<br />
+COPYING - The GPL Version 2 License file<br />
+Makefile - builds the qms-analog utility<br />
+qmail-scanner-1.24-st-qms-20041102.patch<br />
+ - patch file for clean qmail-scanner-1.24 <br />
+ distro which contains the qms event logger<br />
+ and the popular "st" patch<br />
+qms-analog-types.txt - defines the event log types provided<br />
+ by the patch<br />
+qms-config - qmail-scanner config script for qms-analog<br />
+qms-config-cwrapper - qmail-scanner config script for qms-analog<br />
+ used when perl doesn't have setuid support<br />
+qms-config-monitor - qmail-scanner config script for qms-analog<br />
+ and qms-monitor<br />
+qms-config-monitor-cwrapper - qmail-scanner config script for qms-analog<br />
+ and qms-monitor used when perl doesn't have<br />
+ setuid support<br />
+README - this file<br />
+RELEASE-NOTES - version change log<br />
+src/ - source directory for qms-analog<br />
+<br />
+<br />
+<br />
+What You Get<br />
+------------<br />
+<br />
+/var/qmail/bin/qms-analog<br />
+ The utility which takes /var/spool/qmailscan/qms-events.log<br />
+ records as input from stdin and generates statistics on stdout.<br />
+ <br />
+/var/qmail/bin/qmail-scanner-queue.pl<br />
+ The patched version which generates nice logs in<br />
+ /var/spool/qmailscan/qms-events.log and optionally provides account<br />
+ monitoring if qms-monitor is enabled<br />
+<br />
+<br />
+<br />
+!!!!!!!! ATTENTION: READ THIS FIRST !!!!!!!!<br />
+--------------------------------------------<br />
+qms-analog requires a patch be applied to your qmail-scanner-1.24<br />
+distribution in order to generate a new, more legible log file. The<br />
+patch file includes the popular "st" patch which adds useful<br />
+capabilities to qmail-scanner.<br />
+<br />
+The following are minimum requirements for qms-analog to work:<br />
+1) qmail-scanner version 1.24 (unpatched, clean distro)<br />
+2) ClamAV or other qmail-scanner supported AV software.<br />
+3) Spamassassin<br />
+<br />
+If you don't have these, and are unwilling to upgrade or install<br />
+them, DO NOT USE qms-analog. I cannot be responsible for what might<br />
+happen.<br />
+<br />
+Disclaimer:<br />
+-----------<br />
+Generally speaking, it is a quite simple matter to upgrade versions<br />
+of qms-analog. Patch a clean distro of qmail-scanner-1.24, configure<br />
+it, modify qmail-scanner-queue.pl if using the C wrapper instead of<br />
+setuid, then build and install qms-analog. I have done this time and<br />
+time again with no adverse effects on my Qmail installation or any<br />
+of the ancillary utilities that were installed in the QmailRocks<br />
+procedure. Having said that, as with all open-source software, no<br />
+guarantee is expressed or implied in any way, and I am not responsible<br />
+for mistakes or abnormalities in your particular installation.<br />
+<br />
+<br />
+If you meet these requirements, let's get started...<br />
+<br />
+<br />
+<br />
+Note Concerning Where This Fits In the QmailRocks Procedure<br />
+-----------------------------------------------------------<br />
+<br />
+qms-analog is now part of the QmailRocks procedure. See<br />
+http://qmailrocks.org for details.<br />
+<br />
+<br />
+<br />
+A. Patching the qmail-scanner-1.24 Distribution<br />
+-----------------------------------------------<br />
+<br />
+1) Obtain the unpatched source distribution qmail-scanner-1.24.tgz.<br />
+<br />
+2) Extract it to the location of your choice.<br />
+<br />
+3) Make a backup copy of the qmail-scanner-1.24 directory before<br />
+ patching it:<br />
+ cp -R qmail-scanner-1.24 qmail-scanner-1.24-orig<br />
+<br />
+4) Copy qmail-scanner-1.24-st-qms-20041102.patch from the qms-analog<br />
+ distro to the qmail-scanner-1.24 directory where the tarball was<br />
+ extracted.<br />
+ cp qmail-scanner-1.24-st-qms-20041102.patch <path_qm-scanner-1.24><br />
+<br />
+5) Change directory to the qmail-scanner-1.24 distribution:<br />
+ cd <path_qm-scanner-1.24><br />
+<br />
+6) Patch qmail-scanner-1.24:<br />
+ patch -p1 < qmail-scanner-1.24-st-qms-20041102.patch<br />
+<br />
+7) Configure qmail-scanner-1.24:<br />
+ <br />
+ To configure qms-monitor support: CONFFILE = qms-config-monitor<br />
+ To disable qms-monitor support: CONFFILE = qms-config<br />
+ <br />
+ Substitute the appropriate config file name above for the place holder <br />
+ CONFFILE in the following directions.<br />
+ <br />
+ <br />
+ a) Edit CONFFILE to insert your domain name, postmaster account name, <br />
+ and local domain list. Also modify other settings of interest including<br />
+ qms-monitor accounts, etc.<br />
+ <br />
+ b) Execute:<br />
+ ./CONFFILE<br />
+<br />
+ c) if the test configure looks good, install it:<br />
+ ./CONFFILE install<br />
+ <br />
+ Proceed to step 8. <br />
+<br />
+ d) if the script complains about setuid, execute:<br />
+ ./CONFFILE-cwrapper<br />
+<br />
+ e) if that works, execute:<br />
+ ./CONFFILE-cwrapper install<br />
+ to install it and follow the "C Wrapper" instructions<br />
+<br />
+ <br />
+ This sets up qmail-scanner in a qms-analog friendly way.<br />
+<br />
+ Note: I changed debug to default to disabled in the patch. You can add<br />
+ "--debug=1" as an option to configure to enable it. It gets very<br />
+ large and is of no real use anyway to users. The st --minidebug<br />
+ together with --sa_alt and --sa_debug produce much better debug<br />
+ output anyway.<br />
+<br />
+8) After successful configuration , if you are using the C-wrapper instead<br />
+ of perl's setuid, follow the directions in the<br />
+ qmail-scanner-1.24/contrib/qmail-scanner-queue.c file - to modify the<br />
+ permissions of qmail-scanner-queue.pl and the perl tag at the top of<br />
+ that file (delete the "-T").<br />
+<br />
+9) Copy the qmailstats script from the qms-analog distro directory to <br />
+ /var/qmail/bin:<br />
+ cp <qms-analog directory>/qmailstats /var/qmail/bin<br />
+ chmod 0755 /var/qmail/bin/qmailstats<br />
+ <br />
+10) The following log files will need to be rotated or otherwise monitored<br />
+ so they do not grow too large:<br />
+<br />
+ /var/spool/qmailscan/qmail-queue.log<br />
+ /var/spool/qmailscan/qms-events.log<br />
+<br />
+<br />
+<br />
+B. Building qms-analog and installing it with a new qmailstats script<br />
+---------------------------------------------------------------------<br />
+<br />
+1) Become root<br />
+<br />
+2) cd to the qms-analog directory (wherever you extracted it)<br />
+<br />
+3) make all<br />
+<br />
+<br />
+<br />
+C. Testing<br />
+----------<br />
+<br />
+1) Allow several logs to accumulate in /var/spool/qmailscan/qms-events.log.<br />
+<br />
+2) Execute:<br />
+ cat /var/spool/qmailscan/qms-events.log | /var/qmail/bin/qms-analog 0<br />
+<br />
+ This should dump the qms-analog results to stdout (the shell you ran it<br />
+ from).<br />
+<br />
+3) If that looks good, execute:<br />
+ /var/qmail/bin/qmailstats<br />
+<br />
+ This should generate the nightly email to the postmaster including the<br />
+ qms-analog stats at the bottom.<br />
+<br />
+4) If those two tests pass, you are done!<br />
+<br />
+<br />
+<br />
+D. Using qms-analog<br />
+-------------------<br />
+<br />
+1) qms-analog reads the log records from stdin. Thus you can pipe the<br />
+ output of "cat /var/spool/qmailscan/qms-events.log" into qms-analog.<br />
+<br />
+2) qms-analog writes its results to stdout. This can be redirected to<br />
+ a file or viewed on the controlling console.<br />
+<br />
+3) qms-analog requires the hours-of-history argument which specifies the<br />
+ number of hours of historical stats to compile.<br />
+ You can also pass a second argument, sort-key. This specifies the order<br />
+ of the account based statistics.<br />
+<br />
+ usage: qms-analog hours-of-history <sort-key><br />
+<br />
+ hours-of-history (0 - n) hours of history to collect<br />
+ 0 => all records<br />
+ sort-key (optional) sort key for account statistics<br />
+ msgbw (default) msg bandwidth - successful msgs<br />
+ alpha alphanumeric by account name<br />
+ virus number of viruses received<br />
+ saavg Spamassassin avg score<br />
+ sadet Spamassassin msgs detected<br />
+<br />
+ Some examples:<br />
+ "qms-analog 24" - use only records within the last 24 hours,<br />
+ sort by msg bandwidth<br />
+ "qms-analog 168" - use only records within the last 7 days,<br />
+ sort by msg bandwidth<br />
+ "qms-analog 0" - use all records, sort by msg bandwidth<br />
+ "qms-analog 0 alpha" - use all records, sort alphabetically<br />
+ "qms-analog 0 saavg" - use all records, sort by Spam average score<br />
+<br />
+4) Although qms-analog is installed as part of the "qmailstats" script,<br />
+ it could easily be invoked from a custom script which could be run<br />
+ from a shell at any time, or as part of the cron daemon's tasks. See<br />
+ "qmailstats" for example usage.<br />
+<br />
+5) Notes on Statistical Output<br />
+ The headings for the account statistics are described below:<br />
+ <br />
+ MsgRx - messages successfully received (not virus, not deleted or <br />
+ quarantined spam)<br />
+ MsgTx - messages successfully transmitted (not virus)<br />
+ %Total - what percent of total successful messages for the mail server <br />
+ (MsgRx + MsgTx) comprises<br />
+ ScanTime - total time in secs that qmail-scanner took to process the <br />
+ messages<br />
+ VirusRx - messages received that were intercepted as containing a virus<br />
+ VirusTx - messages transmited that were intercepted as containing a virus<br />
+ SA-AVG - average Spamassassin score for all messages for this account <br />
+ run through Spamassassin<br />
+ SA-MRK - number of messages for this account marked and delivered by <br />
+ qmail-scanner based on the Spamassassin score<br />
+ SA-DEL - number of messages for this account deleted by qmail-scanner <br />
+ based on the Spamassassin score<br />
+ SA-REJ - number of messages for this account rejected by qmail-scanner <br />
+ based on the Spamassassin score<br />
+ SA-QUA - number of messages for this account quarantined by qmail-scanner<br />
+ based on the Spamassassin score<br />
+<br />
+ <br />
+E. Notes<br />
+--------<br />
+<br />
+If you have any problems, first re-read the directions and make sure you did<br />
+everything as prescribed, and if you are still having a problem, just restore<br />
+the original qmail-scanner-1.24 distribution (we backed it up, right?) and<br />
+configure it as normal. Also, please report problems or suggestions to the<br />
+Sourceforge mailing list or to the appropriate Sourceforge forum at:<br />
+http://sourceforge.net/projects/qms-analog/<br />
+<br />
+I try to be very responsive.<br />
+<br />
+<br />
+Mark Teel<br />
+mteel@users.sourceforge.net<br />
+<br />
diff -Naur qmail-scanner-2.01st/README-qms-monitor qmail-scanner-2.01st-qms/README-qms-monitor<br />
--- qmail-scanner-2.01st/README-qms-monitor 1970-01-01 02:00:00.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/README-qms-monitor 2007-09-09 07:58:35.000000000 +0300<br />
@@ -0,0 +1,146 @@<br />
+qms-monitor: Local Account Email Activity Monitoring for qmail-scanner<br />
+----------------------------------------------------------------------<br />
+<br />
+<br />
+What Is It?<br />
+-----------<br />
+<br />
+A patch to the qmail-scanner distro which provides per account email <br />
+monitoring, incoming and outgoing. For accounts specified in the <br />
+qmail-scanner configure script, there will be a corresponding destination<br />
+specified for the monitor copies of all email into or out of that account.<br />
+The destination is a path that will be placed under <br />
+/var/spool/qmailscan/qms-monitor. A cron script is provided to periodically <br />
+move messages from this location to alternate vpopmail account locations, <br />
+if you want to use a normal email client to retrieve and manage the monitored<br />
+mail in unique monitor accounts/domains, or to one unique account/domain. <br />
+Otherwise it will collect in that location until you archive it or delete it.<br />
+<br />
+<br />
+<br />
+Purpose:<br />
+--------<br />
+<br />
+Provide a mechanism to specify email addresses and corresponding archive<br />
+locations for local accounts so that ALL incoming and outgoing SMTP mail from<br />
+those accounts is archived for later review.<br />
+<br />
+<br />
+<br />
+Setup (all done as root):<br />
+-------------------------<br />
+<br />
+1) Edit the qms-monitor-config (or qms-monitor-config-cwrapper) script:<br />
+<br />
+ NOTE: Before you can accurately set up destinations for your monitored<br />
+ email, you must decide on a monitor strategy (see #6 below).<br />
+<br />
+ Pay particular attention to the following in the script:<br />
+<br />
+ domain - your primary email domain, where your postmaster <br />
+ account is located<br />
+ admin - your postmaster username, normally "postmaster"<br />
+ local-domains - list all of your local email domains for this qmail <br />
+ server, separated by commas<br />
+ qms-monitor - [yes|no] enable qms-monitor Account Monitoring<br />
+ qms-monitor-accts - list of email accounts to be monitored, separated by <br />
+ commas<br />
+ Example: "acct1@dom2.com,acct2@dom1.com"<br />
+ qms-monitor-dests - list of destination paths for monitored email messages<br />
+ Note 1: locations here will be saved underneath<br />
+ .../qmailscan/qms-monitor; a cron job can later<br />
+ copy from that location to an alternate email <br />
+ domain used for account monitoring.<br />
+ Note 2: each entry in this array corresponds to the <br />
+ email address in the same location of the <br />
+ qms-monitor-accts list above - i.e., <br />
+ qms-monitor-accts[2] msgs get stored at<br />
+ qms-monitor-dests[2] - thus, ORDER DOES MATTER<br />
+ Note 3: DO NOT include a leading "/" on these paths - <br />
+ they will typically be entries that ultimately <br />
+ belong in /home/vpopmail/domains - so start with<br />
+ the domain name.<br />
+ Example: "mon.dom2.com/acct1/Maildir/new,mon.dom1.com/acct2/Maildir/new"<br />
+<br />
+ The example destination paths in the config scripts provided indicate the<br />
+ proper paths for vpopmail Maildir accounts<br />
+ (<domain>/<account name>/Maildir/new). The account name here should be the<br />
+ monitor account and the domain can be the monitor domain if you are using<br />
+ one, otherwise the existing domain you will create the monitor accounts in.<br />
+<br />
+2) Configure qmail-scanner:<br />
+<br />
+ For use with setuid:<br />
+ ./qms-config-monitor<br />
+<br />
+ For use with the qmail-scanner-queue C-wrapper and no setuid:<br />
+ ./qms-config-monitor-cwrapper<br />
+<br />
+3) If that does not produce errors, install the new perl script:<br />
+<br />
+ For use with setuid:<br />
+ ./qms-config-monitor install<br />
+<br />
+ For use with the qmail-scanner-queue C-wrapper and no setuid:<br />
+ ./qms-config-monitor-cwrapper install<br />
+<br />
+4) Setup version and database (and C-wrapper):<br />
+<br />
+ For use with setuid:<br />
+ setuidgid qscand /var/qmail/bin/qmail-scanner-queue.pl -z<br />
+ setuidgid qscand /var/qmail/bin/qmail-scanner-queue.pl -g<br />
+<br />
+ For use with the qmail-scanner-queue C-wrapper and no setuid:<br />
+ (Unset the setuid bit on /var/qmail/bin/qmail-scanner-queue.pl)<br />
+ chmod 0755 /var/qmail/bin/qmail-scanner-queue.pl<br />
+<br />
+ (Remove the "-T" from the perl signature in<br />
+ /var/qmail/bin/qmail-scanner-queue.pl (first line of the file))<br />
+ vi /var/qmail/bin/qmail-scanner-queue.pl<br />
+<br />
+ /var/qmail/bin/qmail-scanner-queue -z<br />
+ /var/qmail/bin/qmail-scanner-queue -g<br />
+<br />
+<br />
+*****************************************************************************<br />
+That's it to start archiving all incoming and outgoing email for the accounts<br />
+specified in the config script. But if you want to be able to read/manage the<br />
+email with any email client, a cron job and associated script are required as<br />
+well as the creation of a new email domain(s) and/or accounts to<br />
+store/retrieve/manage the monitored mail. Those optional instructions follow...<br />
+*****************************************************************************<br />
+<br />
+5) Create Monitor Email Domain(s) and/or Account(s):<br />
+<br />
+ I suggest adopting a convention like creating a shadow domain for every<br />
+ real email domain, for example if you have domain domain.com, your<br />
+ shadow domain could be monitor.domain.com, if you can control or add<br />
+ domains to your DNS server of record. If not, you can just shadow at<br />
+ the account level in your existing domain(s). In this case, if the account<br />
+ of interest is shady@domain.com, you could create an account called<br />
+ monitor.shady@domain.com, and monitor the account from that account.<br />
+ These are just suggestions, bottom line is that you decide on a strategy<br />
+ BEFORE setting up the monitoring domains and/or accounts. If you adopt<br />
+ the convention of providing the destinations in the qms-config-monitor<br />
+ script as starting with the email domain name (no leading '/'), then<br />
+ the cron script below will work right out of the box if your vpopmail<br />
+ is located in /home/vpopmail, otherwise some simple editing of the<br />
+ script is required to get email placed into the proper monitor locations.<br />
+<br />
+ I will leave it to the QMR guide to describe how new domains and<br />
+ accounts are created...<br />
+<br />
+6) Copy the cron script to /var/qmail/bin:<br />
+<br />
+ cp ./qms-monitor-move.sh /var/qmail/bin<br />
+ chmod 700 /var/qmail/bin/qms-monitor-move.sh<br />
+<br />
+7) Add an entry to the root's cron table so this script will be run (and<br />
+ the monitored mail moved to the proper vpopmail location:<br />
+<br />
+ crontab -e<br />
+<br />
+ (Add a line such as:<br />
+ 0-59/5 * * * * /var/qmail/bin/qms-monitor-move.sh >/dev/null<br />
+ to the root's cron table. Save it and it will start running every<br />
+ 5 minutes.)<br />
diff -Naur qmail-scanner-2.01st/sub-avp.pl qmail-scanner-2.01st-qms/sub-avp.pl<br />
--- qmail-scanner-2.01st/sub-avp.pl 2006-02-26 12:34:40.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/sub-avp.pl 2007-09-09 09:11:32.000000000 +0300<br />
@@ -27,6 +27,7 @@<br />
}<br />
&debug("There be a $destring! ($quarantine_description)");<br />
&minidebug("kasp: there be a virus! ($quarantine_description)");<br />
+ &eventlog("AVPAV:$quarantine_description");<br />
($quarantine_event=$quarantine_description)=~s/\s/_/g;<br />
$quarantine_event="AVP:".substr($quarantine_event,0,$QE_LEN);<br />
} else {<br />
diff -Naur qmail-scanner-2.01st/sub-clamdscan.pl qmail-scanner-2.01st-qms/sub-clamdscan.pl<br />
--- qmail-scanner-2.01st/sub-clamdscan.pl 2006-02-26 17:20:25.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/sub-clamdscan.pl 2007-09-09 09:15:18.000000000 +0300<br />
@@ -21,6 +21,7 @@<br />
$quarantine_description=$+;<br />
&debug("There be a virus! ($quarantine_description)");<br />
&minidebug("clamdscan: there be a virus! ($quarantine_description)");<br />
+ &eventlog("CLAMAV:$quarantine_description");<br />
($quarantine_event=$quarantine_description)=~s/\s/_/g;<br />
$quarantine_event="CLAMDSCAN:".substr($quarantine_event,0,$QE_LEN);<br />
$description .= "\n---clamdscan results ---\n$DD";<br />
@@ -36,6 +37,7 @@<br />
&debug("clamdscan: $quarantine_description");<br />
&minidebug("clamdscan: $quarantine_description");<br />
$quarantine_event="CLAMDSCAN:Resource_attack";<br />
+ &eventlog("CLAMAV:$quarantine_description");<br />
$description .= "\n---clamdscan results ---\n$DD";<br />
} elsif ($clamdscan_status > 0) {<br />
#This implies a corrupt set of DAT files or resource problems...<br />
diff -Naur qmail-scanner-2.01st/sub-clamscan.pl qmail-scanner-2.01st-qms/sub-clamscan.pl<br />
--- qmail-scanner-2.01st/sub-clamscan.pl 2006-02-26 17:24:39.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/sub-clamscan.pl 2007-09-09 09:15:54.000000000 +0300<br />
@@ -20,6 +20,7 @@<br />
$quarantine_description=$+;<br />
&debug("There be a virus! ($quarantine_description)");<br />
&minidebug("clamscan: there be a virus! ($quarantine_description)");<br />
+ &eventlog("CLAMAV:$quarantine_description");<br />
($quarantine_event=$quarantine_description)=~s/\s/_/g;<br />
$quarantine_event="CLAMSCAN:".substr($quarantine_event,0,$QE_LEN);<br />
$description .= "\n---clamscan results ---\n$DD";<br />
@@ -32,6 +33,7 @@<br />
$quarantine_description="Resource attack - $1";<br />
&debug("clamscan: $quarantine_description");<br />
&minidebug("clamscan: $quarantine_description");<br />
+ &eventlog("CLAMAV:$quarantine_description");<br />
$quarantine_event="CLAMSCAN:Resource_attack";<br />
$description .= "\n---clamscan results ---\n$DD";<br />
} elsif ($clamscan_status > 0) {<br />
diff -Naur qmail-scanner-2.01st/sub-csav.pl qmail-scanner-2.01st-qms/sub-csav.pl<br />
--- qmail-scanner-2.01st/sub-csav.pl 2006-02-26 12:37:50.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/sub-csav.pl 2007-09-09 09:16:24.000000000 +0300<br />
@@ -18,6 +18,7 @@<br />
$quarantine_description=$1;<br />
&debug("There be a virus! ($quarantine_description)");<br />
&minidebug("csav_scanner: there be a virus! ($quarantine_description)");<br />
+ &eventlog("CSAV:$quarantine_description");<br />
($quarantine_event=$quarantine_description)=~s/\s/_/g;<br />
$quarantine_event="CSAV:".substr($quarantine_event,0,$QE_LEN);<br />
} <br />
diff -Naur qmail-scanner-2.01st/sub-fprot.pl qmail-scanner-2.01st-qms/sub-fprot.pl<br />
--- qmail-scanner-2.01st/sub-fprot.pl 2006-02-26 17:21:15.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/sub-fprot.pl 2007-09-09 09:17:23.000000000 +0300<br />
@@ -21,6 +21,7 @@<br />
$quarantine_description=~s/^\s+//g;<br />
&debug("There be a virus! ($quarantine_description)");<br />
&minidebug("fprot: there be a virus! ($quarantine_description)");<br />
+ &eventlog("FPROTAV:$quarantine_description");<br />
($quarantine_event=$quarantine_description)=~s/\s/_/g;<br />
$quarantine_event="FPROT:".substr($quarantine_event,0,$QE_LEN);<br />
$description .= "\n---fprot results ---\n$DD";<br />
diff -Naur qmail-scanner-2.01st/sub-fsecure.pl qmail-scanner-2.01st-qms/sub-fsecure.pl<br />
--- qmail-scanner-2.01st/sub-fsecure.pl 2006-02-26 17:21:39.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/sub-fsecure.pl 2007-09-09 09:17:38.000000000 +0300<br />
@@ -24,6 +24,7 @@<br />
$quarantine_description=~s/^\s+//g;<br />
&debug("There be a virus! ($quarantine_description)");<br />
&minidebug("fsecure: there be a virus! ($quarantine_description)");<br />
+ &eventlog("FSECUREAV:$quarantine_description");<br />
($quarantine_event=$quarantine_description)=~s/\s/_/g;<br />
$quarantine_event="FSEC:".substr($quarantine_event,0,$QE_LEN);<br />
$description .= "\n---fsecure results ---\n$DD";<br />
diff -Naur qmail-scanner-2.01st/sub-hbedv.pl qmail-scanner-2.01st-qms/sub-hbedv.pl<br />
--- qmail-scanner-2.01st/sub-hbedv.pl 2006-02-26 17:22:11.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/sub-hbedv.pl 2007-09-09 09:17:48.000000000 +0300<br />
@@ -17,6 +17,7 @@<br />
$quarantine_description=$1;<br />
&debug("There be a virus! ($quarantine_description)");<br />
&minidebug("hbedv: there be a virus! ($quarantine_description)");<br />
+ &eventlog("HBEDVAV:$quarantine_description");<br />
($quarantine_event=$quarantine_description)=~s/\s/_/g;<br />
$quarantine_event="HBEDV:".substr($quarantine_event,0,$QE_LEN);<br />
$description .= "\n---hbedv results ---\n$DD";<br />
diff -Naur qmail-scanner-2.01st/sub-inocucmd.pl qmail-scanner-2.01st-qms/sub-inocucmd.pl<br />
--- qmail-scanner-2.01st/sub-inocucmd.pl 2006-02-26 17:22:35.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/sub-inocucmd.pl 2007-09-09 09:18:02.000000000 +0300<br />
@@ -15,6 +15,7 @@<br />
$quarantine_description=$1;<br />
&debug("There be a virus! ($quarantine_description)");<br />
&minidebug("inocucmd: there be a virus! ($quarantine_description)");<br />
+ &eventlog("INNOCAV:$quarantine_description");<br />
($quarantine_event=$quarantine_description)=~s/\s/_/g;<br />
$quarantine_event="INOC:".substr($quarantine_event,0,$QE_LEN);<br />
$description .= "\n$DD\n";<br />
diff -Naur qmail-scanner-2.01st/sub-iscan.pl qmail-scanner-2.01st-qms/sub-iscan.pl<br />
--- qmail-scanner-2.01st/sub-iscan.pl 2006-02-26 17:22:59.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/sub-iscan.pl 2007-09-09 09:18:13.000000000 +0300<br />
@@ -16,6 +16,7 @@<br />
$quarantine_description=$1;<br />
&debug("There be a virus! ($quarantine_description)");<br />
&minidebug("iscan: there be a virus! ($quarantine_description)");<br />
+ &eventlog("ISCANAV:$quarantine_description");<br />
($quarantine_event=$quarantine_description)=~s/\s/_/g;<br />
$quarantine_event="ISCAN:".substr($quarantine_event,0,$QE_LEN);<br />
$description .= "\n---iscan results ---\n$DD";<br />
diff -Naur qmail-scanner-2.01st/sub-ravlin.pl qmail-scanner-2.01st-qms/sub-ravlin.pl<br />
--- qmail-scanner-2.01st/sub-ravlin.pl 2006-02-26 17:18:35.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/sub-ravlin.pl 2007-09-09 09:19:23.000000000 +0300<br />
@@ -22,6 +22,7 @@<br />
$quarantine_description=$1;<br />
&debug("ravlin_scanner: There be a virus! ($quarantine_description)");<br />
&minidebug("ravlin_scanner: there be a virus! ($quarantine_description)");<br />
+ &eventlog("RAVLINAV:$quarantine_description");<br />
($quarantine_event=$quarantine_description)=~s/\s/_/g;<br />
$quarantine_event="RAV:".substr($quarantine_event,0,$QE_LEN);<br />
$description .= "\n---ravlin results ---\n$DD";<br />
diff -Naur qmail-scanner-2.01st/sub-spamassassin.pl qmail-scanner-2.01st-qms/sub-spamassassin.pl<br />
--- qmail-scanner-2.01st/sub-spamassassin.pl 2006-12-23 14:00:20.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/sub-spamassassin.pl 2007-09-09 09:22:54.000000000 +0300<br />
@@ -195,6 +195,8 @@<br />
<br />
&debug("SA: REPORT hits = $sa_score/$required_hits\n$sa_report") if ( $sa_debug && $sa_report );<br />
&minidebug("SA: REPORT hits = $sa_score/$required_hits\n$sa_report") if ( $sa_debug && $sa_report && !$scanned);<br />
+ &eventlog("- - -:SCORE:REQ:QRTN:DEL:REJ");<br />
+ &eventlog("SPAM-RESULT:$sa_score:$required_hits:$sa_quarantine:$sa_delete:$sa_reject");<br />
<br />
# st: what about SA sql per user, could be differents $required_hits...<br />
if ($required_hits > $sa_score || ($sa_score == 0) || ($sa_score eq "\?")) {<br />
@@ -212,6 +214,7 @@<br />
if ($sa_delete && ($sa_quarantine>$sa_delete)) {<br />
&debug("SA: WARNING, sa_delete is lower than sa_quarantine, spam could be quarantined, but not deleted");<br />
&minidebug("SA: WARNING, sa_delete is lower than sa_quarantine, spam could be quarantined, but not deleted");<br />
+ &eventlog("---- WARN: sa_delete < sa_quarantine => setting sa_delete = 0");<br />
$sa_delete='0';<br />
}<br />
<br />
@@ -221,6 +224,7 @@<br />
$sa_threshold=$sa_delete+$required_hits;<br />
if ( $sa_reject && (($sa_delete_site+$required_hits)<$sa_score || $one_recip eq $recips )) {<br />
&log_sa_action($scanned,$sa_threshold,"rejected");<br />
+ &eventlog("SPAM-DETECT:REJECT");<br />
$stop_spamassassin_time=[gettimeofday];<br />
$spamassassin_time = tv_interval ($start_spamassassin_time, $stop_spamassassin_time);<br />
&debug("SA: finished scan of dir \"$ENV{'TMPDIR'}\" in $spamassassin_time secs");<br />
@@ -236,6 +240,7 @@<br />
$quarantine_description="SPAM exceeds \"delete\" threshold - hits=$sa_score/$required_hits";<br />
$quarantine_event="SA:SPAM-DELETED";<br />
&log_sa_action($scanned,$sa_threshold,"deleted");<br />
+ &eventlog("SPAM-DETECT:DELETE");<br />
$description .= "\n---spamassassin results ---\n$destring '$quarantine_description'\n found in message $ENV{'TMPDIR'}";<br />
}<br />
} else {<br />
@@ -246,6 +251,7 @@<br />
$quarantine_event="SA:SPAM-QUARANTINED";<br />
$quarantine_spam="SA:SPAM-QUARANTINED";<br />
&log_sa_action($scanned,$sa_threshold,"quarantined");<br />
+ &eventlog("SPAM-DETECT:QUARANTINE");<br />
$description .= "\n---spamassassin results ---\n$destring '$quarantine_description'\n found in message $ENV{'TMPDIR'}";<br />
} else {<br />
#st: if $spamc_subject and $sa_delta are set, add in the subject the spam-level<br />
@@ -259,6 +265,7 @@<br />
}<br />
}<br />
&log_sa_action($scanned,$required_hits,"tagged");<br />
+ &eventlog("SPAM-DETECT:MARK");<br />
}<br />
}<br />
}<br />
diff -Naur qmail-scanner-2.01st/sub-uvscan.pl qmail-scanner-2.01st-qms/sub-uvscan.pl<br />
--- qmail-scanner-2.01st/sub-uvscan.pl 2006-02-26 12:55:43.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/sub-uvscan.pl 2007-09-09 09:23:24.000000000 +0300<br />
@@ -16,6 +16,7 @@<br />
$quarantine_description=$1;<br />
&debug("There be a virus! ($quarantine_description)");<br />
&minidebug("uvscan: there be a virus! ($quarantine_description)");<br />
+ &eventlog("UVSCANAV:$quarantine_description");<br />
($quarantine_event=$quarantine_description)=~s/\s/_/g;<br />
$quarantine_event="UVSCAN:".substr($quarantine_event,0,$QE_LEN);<br />
$description .= "\n---uvscan results ---\n$DD";<br />
diff -Naur qmail-scanner-2.01st/sub-vexira.pl qmail-scanner-2.01st-qms/sub-vexira.pl<br />
--- qmail-scanner-2.01st/sub-vexira.pl 2006-02-26 17:19:03.000000000 +0200<br />
+++ qmail-scanner-2.01st-qms/sub-vexira.pl 2007-09-09 09:23:41.000000000 +0300<br />
@@ -18,6 +18,7 @@<br />
$quarantine_description=$1;<br />
&debug("vexira_scanner: There be a virus! ($quarantine_description)");<br />
&minidebug("vexira_scanner: there be a virus! ($quarantine_description)");<br />
+ &eventlog("VEXIRAV:$quarantine_description");<br />
($quarantine_event=$quarantine_description)=~s/\s/_/g;<br />
$quarantine_event="VEX:".substr($quarantine_event,0,$QE_LEN);<br />
$description .= "\n---vexira results ---\n$DD"; <br />
@@ -30,6 +31,7 @@<br />
if ($DD =~ /WARNING: archive not completely scanned: (contents exceed \d+ (levels of recursion|bytes))/) {<br />
$quarantine_description="Resource attack - $1";<br />
&debug("vexira_scanner: $quarantine_description");<br />
+ &eventlog("VEXIRAV:$quarantine_description");<br />
$quarantine_event="VEX:Resource_attack";<br />
$description .= "\n---vexira results ---\n$DD";<br />
} elsif ($vexira_status > 0) {<br />
<br />
'''STOP'''<br />
<br />
<br />
tar xzf q-s-2.01st-20070204.tgz<br />
cd qmail-scanner-2.01st<br />
patch -p1 < ../qmail-scanner-2.01-st-qms.patch<br />
<br />
'''Add qscand new group and user'''<br />
<br />
groupadd qscand<br />
useradd -c "Qmail-Scanner Account" -g qscand -s /bin/false qscand<br />
<br />
'''Execute the config file'''<br />
<br />
./configure<br />
<br />
'''You shouldn't get any errors, but I have a machine who is complaining about some variables (like opt_d opt_p) it is safe to ignore'''<br />
<br />
'''Now run configure with --install option'''<br />
<br />
./configure --install<br />
<br />
'''You can edit /var/qmail/bin/qmail-scanner-queue.pl to suit your needs'''<br />
'''You will hawe to replace default queue(simscan) with qmail-scanner'''<br />
'''Relace in /etc/tcprules.d/tcp.smtp <br />
''' QMAILQUEUE="/var/qmail/bin/simscan"<br />
'''With'''<br />
QMAILQUEUE="/var/qmail/bin/qmail-scanner-queue.pl"<br />
<br />
'''Rebuild cdb'''<br />
<br />
qmailctl cdb<br />
<br />
'''Stop qmail'''<br />
<br />
qmailctl stop<br />
<br />
'''Edit clamd to run as qscand in file /var/qmail/supervise/clamd/run'''<br />
<br />
'''Replace'''<br />
exec /usr/bin/setuidgid clamav /usr/sbin/clamd 2>&1<br />
'''With'''<br />
exec /usr/bin/setuidgid qscand /usr/sbin/clamd 2>&1<br />
<br />
'''On some systems it is working only with root user: exec /usr/bin/setuidgid root /usr/sbin/clamd 2>&1<br />
'''<br />
<br />
'''Begin testing..<br />
send you some mails and analize /var/log/maillog, /var/spool/qscan/qms-events.log, qmail-queue.log, quarantine.log<br />
the exectue qmailstats and wait for a nicely log !<br />
'''</div>Ebroch