Mailing List Archive

Another Alternative checkpassword
Well I finally converted :) It was a major chore, but I'm very happy with
the results of qmail compared to what we were getting with sendmail.

We were running an HP9000/735 99MHz with 80Megs RAM using sendmail 8.8.x.
We are delivering about 60-80k messages per day, and I had to do some MAJOR
throttling back to get it to handle that load. I had average delays of
4 to 6 hours during peak hours. I also had the "shutdown" level set to
a load average of 30, and it was hitting that about 1/2 of all messages
between 5pm and midnight. By midnight I ususally had a queue of 6-10k
messages that would take until about 3am to deliver.

Now I switched to qmail on a P200 with 96Megs RAM. I'm not "throttling"
anything, all messages are being delivered immediatly. Our users are MUCH
happier :) The load average on the server never goes over 5.0 and is usually
closer to .8 to 1.0. This is handeling around 18,000 email accounts including
POP3 only access for all accounts.

I have set it up using the qmail-pop3d server as it seemed simpler then
qpopper (although I'm having a few minor problems. I'm still searching
the archives for answers.). I like using the Maildir format, and I'm
starting to get used to it.

I also like that qmail-pop3d uses checkpassword which I wanted to hackup
to use our database eventually. For now, we did re-write it to use
a seperate dbm hash table, which has made it MUCH faster. It is in perl,
but we will re-write it in C when we learn how the C dbm libraries work :)

If anyone can see improvments or problems with these please let me know.
We stayed up until 2:30 am writing these, as the new qmail server was
crashing trying to read the password info from flat files.


Dan Thibadeau
CyberHighway Inc.

------------------------------------sh_update----------------------------------
#!/bin/sh

########################
#
# Name: sh_update
# Author: Dan Thibadeau
# Email: dragon@cyberhighway.net
#
# Description: This program generates a hash table of info needed for the
# checkpassword.pl program. It creates the information from
# the /etc/passwd and /etc/shadow files and uses the
# "makemap" utility that comes with the Berkley dbm package
# to create the hash table as /etc/shadow.db
#
########################

PWFILE=/etc/passwd # original password file to use
SHFILE=/etc/shadow # original shadow file to use
MAKEMAP=/usr/sbin/makemap # dbm utility to create db file

awk 'BEGIN {
FS = ":"
### Read the shadow info into an assoc. array
while ( (getline < "'$SHFILE'") > 0) { shadow[$1] = $2 }
if (ERRNO) { exit(1) }
}
{
if(shadow[$1])
printf("%s %s:%s:%s:%s:%s\n",$1,shadow[$1],$3,$4,$6,$7);
else
printf("%s *:%s:%s:%s:%s\n",$1,$3,$4,$6,$7);
}
' $PWFILE | $MAKEMAP hash $SHFILE.tmp

mv $SHFILE.db $SHFILE.db.old
mv $SHFILE.tmp.db $SHFILE.db

---------------------------------checkpassword---------------------------------
#!/usr/bin/perl
########################
#
# Name: checkpassword.pl
# Author: Owen Jones
# Email: owen@cyberhighway.net
#
# Description: This replaces the C version of checkpassword and uses perl's
# built in DBM support to get password info instead of using
# getpwnam.
#
########################

use DB_File;
use Fcntl;

$0 = "checkpassword";

open(INPUT,"<&3");
$Input = <INPUT>;
close(INPUT);


($User,$ClearPasswd) = split(/\000/,$Input);

$0 = "checkpassword $User";

tie (%PasswdFile , DB_File, "/etc/shadow.db", O_RDONLY, 0444) || exit(111);
($PwEntry) = $PasswdFile{$User};
untie(%PasswdFile);

($RealPasswd,$UID,$GID,$Home,$Shell) = split(/:/,$PwEntry);

$CryptPasswd = crypt($ClearPasswd,substr($RealPasswd,0,2));
if($CryptPasswd ne $RealPasswd)
{
exit(1);
}
else
{
$ENV{"USER"} = $User;
$ENV{"HOME"} = $Home;
$ENV{"SHELL"} = $Shell;

# Change to the User's home directory
#------------------------------------
if(!chdir($Home))
{
exit(111);
}

# Change the Process' GID to the User's GID
#------------------------------------------
$( = $GID;
$) = $GID;
if(((split(/ /,$)))[0] ne $GID) ||
((split(/ /,$())[0] ne $GID))
{
exit(1);
}

# Change the Process' UID to the User's GID
#------------------------------------------
$> = $UID;
$< = $UID;
if(($> ne $UID) ||
($< ne $UID))
{
exit(1);
}
exec(@ARGV);
}