Hi guys,
I'm migrating a Qmail + Vpopmail mail server to a Qmail-ldap installation.
Before I completely migrate all the domains to qmail-ldap, the two different qmailservers
will coexist in the same machine.
In order to deal with the POP3 users, i wrote the perl script bellow and I'd like you to comment it.
See you, bruno negr�o.
#!/usr/bin/perl -w
#
# /bin/pop3switch - switches the authorization/popup of POP3 users between two
# different qmail-pop3d servers running in the same machine
#
# SYNOPSIS
# /bin/pop3switch --server1-exec "COMMANDLINE1" --server1-user "USERNAME1" \
# --server1-domainslistfile "PATH_TO_FILE" \
# --server2-exec "COMMANDLINE2" --server2-user "USERNAME2"
#
# DESCRIPTION
# This program is designed to help in the situation when a given host
# has two different Qmail servers running, we gonna call them "server1"
# and "server2". For example, server1 could be a qmail-ldap
# server, and server2 could be an installation of Qmail + Vpopmail.
# pop3switch provides a means for authenticating and getting messages
# of the POP3 users from both servers.
# Also, it will execute COMMANDLINEX under the UserID and GroupID of
# the user specified by the --serverX-user option.
#
# HOW DOES IT DISTINGUISH WHICH SERVER OWNS EACH ACCOUNT
# When the mail server receives a pop3 client connecting on port 110, tcpserver
# will be listening on this port, then it will invoke qmail-popup which, in turn,
# will interact with the client and catch the user/password information.
# qmail-popup will call pop3switch and pass this information to it.
# Finally, to discover if this POP3 user pertains to server1 or server2,
# pop3switch will check if the user's domain is listed in the file set
# with the --server1-domainslistfile option.
# If the user's domain is not listed in this file, pop2switch assume this
# user pertains to server2.
# When it decides which server to use, pop3switch gonna exec the program specified
# by --serverX-exec option.
#
# HOW TO USE IT
# Call this program from the /service/qmail-pop3d/run file, in substitution of
# the authorization program you're using there. Bellow, see an example of
# "tcpserver" calling pop3switch to switch between a Qmail-ldap pop3d and
# a Qmail + Vpopmail pop3d:
#
# tcpserver -u 0 -g 0 0 110 \
# /var/qmail/bin/qmail-popup $DOMAINNAME \
# /bin/pop3switch \
# --server1-exec "/var/qmldap/bin/auth_pop /var/qmldap/bin/qmail-pop3d Maildir" \
# --server1-user "qmldapv" \
# --server1-domainslistfile "/var/qmldap/control/ldapdomains" \
# --server2-exec "/var/vpopmail/bin/vchkpw /var/qmail/bin/qmail-pop3d Maildir" \
# --server2-user "vpopmail"
#
# ERROR MESSAGES
# This program prints its error messages to a file called /tmp/pop3switch_error. It can't
# just print them to standard out since it will be connected to the network when this program
# is executed.
#
# KNOWN LIMITATIONS
# - pop3switch expects to receive an email in the format: "[EMAIL PROTECTED]". It won't
# work with e-mails in different formats.
# - To increase performance, pop3switch won't check the validity of the arguments
# it receives. Check them yourself carefully.
#
# SECURITY LIMITATIONS
# - pop3switch must be run as root.
# - When it passes the username/password to the pop3 server executable, this information
# can be seen with the "ps -ef" command.
#
# DEPENDENCIES
# DJ Bernstein's Daemontools package is required for the use of 'setuidgid' executable
#
# AUTHOR
# Bruno Negr�o - vpopmail at engepel.com.br
#
# LAST MODIFIED
# 10/05/2004
##########################################################################################
use strict;
# subroutine prototypes
sub my_die($); # prints the error message in /tmp/pop3switch_error file and dies.
# setuidgid's path my $SETUIDGID = "/usr/local/bin/setuidgid";
# check for its existence
my_die "$0: ERROR: cannot find $SETUIDGID. If you don't have daemontools installed in your" .
" system, install it. If it's installed in a path different than '/usr/local/bin'," .
" then edit the pop3switch's '\$SETUIDGID' variable to reflect the right path.\n"
if (! -x $SETUIDGID);
# getting the arguments my %ARG = @ARGV;
# Option Variables
my $SERVER1_EXEC = $ARG{"--server1-exec"};
my $SERVER2_EXEC = $ARG{"--server2-exec"};
my $SERVER1_USER = $ARG{"--server1-user"};
my $SERVER2_USER = $ARG{"--server2-user"};
my $SERVER1_DOMAINSLISTFILE = $ARG{"--server1-domainslistfile"};# check for the passed arguments validity
if ( (my $error = checkAllArguments()) ) {
my_die "$error";
}# 1 - We read the user/password input from qmail-popup in the
# descriptor 3 and store it in a variable
my $qmail_popup_input; # input read from qmail-popup
open(FH, "<&=3") or my_die "$0: ERROR: I couldn't open descriptor 3 for reading.\n";
binmode (FH);
$qmail_popup_input = <FH>;
close FH;
# 2 - Now we parse this input, breaking it in user, password and # timestamp (these fields are separated by NUL characters) my ($user, $pwd, $time) = ( split(/\x00/, $qmail_popup_input) );
# 3 - Now we extract the domain name from the username my $domain = (split(/\@/, $user))[1];
# 4 - Check if this domain is in server1's database. If it is,
# sets the variable $IS_DOMAIN_IN_SERVER1 to 1. For doing this, we gonna
# search for this domain in the $SERVER1_DOMAINSLISTFILE
my $IS_DOMAIN_IN_SERVER1 = 0; # says if $domain is in the LDAP database
open (LDF, "<$SERVER1_DOMAINSLISTFILE") or my_die "$0: ERROR: I couldn't open the file ".
"$SERVER1_DOMAINSLISTFILE for reading.\n";
while (<LDF>) {
chomp; # no newline
s/#.*//; # no comments
s/^\s+//; # no leading white
s/\s+$//; # no trailing white
next unless length;
if ( /^$domain$/ ) {
$IS_DOMAIN_IN_SERVER1 = 1;
last;
}
}
# 5 - Escaping the <, >, and \0 caracters:
$time =~ s/([<>])/\\$1/g; # escaping $time
# escaping qmail-popup input to feed shell:
my $qmail_popup_input_escaped = $user . '\\\\000' . $pwd . '\\\\000' . $time . '\\\\000';
# 6 - Choose the apropriate command line to execute my $CMD_LINE = "$SETUIDGID "; $CMD_LINE .= ($IS_DOMAIN_IN_SERVER1 ? "$SERVER1_USER $SERVER1_EXEC" : "$SERVER2_USER $SERVER2_EXEC");
# 7 - exec the AUTH program, taking care to maintain the descriptors 0 and 1
# connected to the network and to read the user/pwd info from descriptor 3
exec (qq(exec 4<&0; echo -ne $qmail_popup_input_escaped | $CMD_LINE 3<&0 0<&4 4<&-));
sub my_die($) {
my $msg = shift;
my $error_file = "/tmp/pop3switch_error";
open (ERROR, "> $error_file");
print ERROR $msg;
die "\n";
}sub checkAllArguments {
sub error {
my $opt = shift;
return "$0: ERROR: The option $opt is not correctly set up.\n";
}
unless ( $SERVER1_EXEC ) {
return error("--server1-exec");
}
unless ( $SERVER2_EXEC ) {
return error("--server2-exec");
}
unless ( $SERVER1_USER ) {
return error("--server1-user");
}
unless ( $SERVER2_USER ) {
return error("--server2-user");
}
unless ( $SERVER1_DOMAINSLISTFILE ) {
return error("--server1-domainslistfile");
}
return "";
}
