#!/usr/bin/perl
#smtpauth
#called by exim to verify if an smtp user is allowed to
#send email through the server
#possible success:
# user is in /etc/virtual/domain.com/passwd and password matches
# user is in /etc/passwd and password matches in /etc/shadow
sub smtpauth
{
$username = Exim::expand_string('$1');
$password = Exim::expand_string('$2');
$domain = "";
$unixuser = 1;
if ($username =~ /\@/)
{
$unixuser = 0;
($username,$domain) = split(/\@/, $username);
if ($domain eq "") { return "no"; }
}
if ($unixuser == 1)
{
#the username passed doesn't have a domain, so its a system account
$homepath = (getpwnam($username))[7];
if ($homepath eq "") { return 0; }
open(PASSFILE, "< $homepath/.shadow") || return "no";
$crypted_pass = <PASSFILE>;
close PASSFILE;
#+MOD: Is User Domain Allowed to use SMTP
$domain = get_user_domain($username);
if (not is_smtp_allowed($domain)) { return "no"; }
#-MOD: Is User Domain Allowed to use SMTP
if ($crypted_pass eq crypt($password, $crypted_pass)) { return "yes"; }
else { return "no"; }
}
else
{
#+MOD: Is User Domain Allowed to use SMTP
if (not is_smtp_allowed($domain)) { return "no"; }
#-MOD: Is User Domain Allowed to use SMTP
#the username contain a domain, which is now in $domain.
#this is a pure virtual pop account.
open(PASSFILE, "< /etc/virtual/$domain/passwd") || return "no";
while (<PASSFILE>)
{
($test_user,$test_pass) = split(/:/,$_);
$test_pass =~ s/\n//g; #snip out the newline at the end
if ($test_user eq $username)
{
if ($test_pass eq crypt($password, $test_pass))
{
close PASSFILE;
return "yes";
}
}
}
close PASSFILE;
return "no";
}
return "no";
}
#+MOD: Is User Domain Allowed to use SMTP
sub is_smtp_allowed
{
my ($domain) = @_;
open(DOMAINS,"/etc/virtual/domains_without_smtp");
while (<DOMAINS>)
{
$_ =~ s/\n//;
if ($domain eq $_)
{
return 0;
}
}
close(DOMAINS);
return 1;
}
sub get_user_domain
{
my ($username) = @_;
my $domain="";
open(DOMAINOWNERS,"/etc/virtual/domainowners");
while (<DOMAINOWNERS>)
{
$_ =~ s/\n//;
my ($dmn,$usr) = split(/: /, $_);
if ($usr eq $username)
{
return $dmn;
}
}
close(DOMAINOWNERS);
return -1;
}
#-MOD: Is User Domain Allowed to use SMTP
sub find_uid_apache
{
my ($work_path) = @_;
my @pw;
# $pwd will probably look like '/home/username/domains/domain.com/public_html'
# it may or may not use /home though. others are /usr/home, but it's ultimately
# specified in the /etc/passwd file. We *could* parse through it, but for efficiency
# reasons, we'll only check /home and /usr/home .. if they change it, they can
# manually adjust if needed.
@dirs = split(/\//, $work_path);
foreach $dir (@dirs)
{
# check the dir name for a valid user
# get the home dir for that user
# compare it with the first part of the work_path
if ( (@pw = getpwnam($dir)) )
{
if ($work_path =~/^$pw[7]/)
{
return $pw[2];
}
}
}
return -1;
}
sub get_domain_owner
{
my ($domain) = @_;
my $username="";
open(DOMAINOWNERS,"/etc/virtual/domainowners");
while (<DOMAINOWNERS>)
{
$_ =~ s/\n//;
my ($dmn,$usr) = split(/: /, $_);
if ($dmn eq $domain)
{
return $usr;
}
}
close(DOMAINOWNERS);
return -1;
}
sub find_uid_auth_id
{
# this will be passwed either
# 'username' or '[email protected]'
my ($auth_id) = @_;
my $unixuser = 1;
my $domain = "";
my $user = "";
my $username = $auth_id;
my @pw;
if ($auth_id =~ /\@/)
{
$unixuser = 0;
($user,$domain) = split(/\@/, $auth_id);
if ($domain eq "") { return "-1"; }
}
if (!$unixuser)
{
# we need to take $domain and get the user from /etc/virtual/domainowners
# once we find it, set $username
my $u = get_domain_owner($domain);;
if ($u != -1)
{
$username = $u;
}
}
#log_str("username found from $auth_id: $username:\n");
if ( (@pw = getpwnam($username)) )
{
return $pw[2];
}
return -1;
}
sub find_uid_sender
{
my $sender_address = Exim::expand_string('$sender_address');
my ($user,$domain) = split(/\@/, $sender_address);
my $username = get_domain_owner($domain);
if ( (@pw = getpwnam($username)) )
{
return $pw[2];
}
return -1;
}
sub find_uid
{
my $uid = Exim::expand_string('$originator_uid');
my $username = getpwuid($uid);
my $auth_id = Exim::expand_string('$authenticated_id');
my $work_path = $ENV{'PWD'};
if ($username eq "apache" || $username eq "nobody")
{
$uid = find_uid_apache($work_path);
if ($uid != -1) { return $uid; }
}
$uid = find_uid_auth_id($auth_id);
if ($uid != -1) { return $uid; }
# we don't want to rely on this, but it's all thats left.
return find_uid_sender;
}
sub uid_exempt
{
my ($uid) = @_;
if ($uid == 0) { return 1; }
my $name = getpwuid($uid);
if ($name eq "root") { return 1; }
if ($name eq "diradmin") { return 1; }
return 0;
}
#check_limits
#used to enforce limits for the number of emails sent
#by a user. It also logs the bandwidth of the data
#for received mail.
sub check_limits
{
my $count = 0;
open (LIMIT, "/etc/virtual/limit");
my $email_limit = int(<LIMIT>);
close(LIMIT);
#find the curent user
$uid = find_uid();
#log_str("Found uid: $uid\n");
if (uid_exempt($uid)) { return; }
my $name="";
if ($email_limit > 0)
{
#check this users limit
if (($name = getpwuid($uid)))
{
$count = (stat("/etc/virtual/usage/$name"))[7];
if ($count > $email_limit)
{
die("You ($name) have reach your daily email limit of $email_limit emails\n");
}
}
}
open(USAGE, ">>/etc/virtual/usage/$name");
print USAGE "1";
close(USAGE);
chmod (0660, "/etc/virtual/usage/$name");
log_bandwidth($uid);
return "yes"
}
sub log_bandwidth
{
my ($uid) = @_;
my $name = getpwuid($uid);
if (uid_exempt($uid)) { return; }
if ($name eq "") { return; }
my $bytes = Exim::expand_string('$message_size');
if ($bytes == -1) { return; }
open (BYTES, ">>/etc/virtual/usage/$name.bytes");
print BYTES "$bytes\n";
close(BYTES);
chmod (0660, "/etc/virtual/usage/$name.bytes");
}
sub log_str
{
my ($str) = @_;
open (LOG, ">> /tmp/test.txt");
print LOG $str;
close(LOG);
}