ldap_auth.pl0100644000076500007650000001173310200172577013561 0ustar tedfinestedfines#!/usr/local/bin/perl
use Net::LDAP;
use IO::Handle;
use warnings;
# ldap_auth.pl by Ted Fines, Jan. 2005. version 0.1
# Contact info: http://www.apecity.com
# Search for 'Net::LDAP' on http://www.cpan.org for more info/options on
# perl-ldap.
#
# Put your LDAP server name here
#
my $ldap_server='ldap.macalester.edu';
#
# Put your LDAP port number here. 389 is the default (insecure) port.
#
my $ldap_port = 389;
#
# Put your LDAP base here
# for our organization, o=mac is correct. If you only wanted to
# authenticate for users in the O=Company,ou=Marketing, then you'd set
# the $base variable to 'o=company,ou=marketing'
#
my $base = 'o=mac';
#
# Put your scope here
# sub means search sub-branches of the LDAP directory tree
# Other options are 'one' and 'base'
#
my $scope = 'sub';
#
# Set PROTOCOL_LEN to the max amount of input this program is
# willing to accept. Considering it is only taking as input a
# username and password, it should be pretty short. Default for
# checkpassword is 512, so I set it to the same though that seems
# ridiculously large
#
my $PROTOCOL_LEN = 512;
#
# Set LOG_YES to 1 and info on how logins are going will be written to
# the qmail-smtpd log file (assuming a Life with qmail install, this will
# be /var/log/qmail/smtpd/current). You probably only want this on when
# initially setting it up, or when troubleshooting.
#
my $LOG_YES = 1;
#
# You probably won't need to change anything past this point.
# Well, one exception to that. Check out line 143, which reads:
# filter => "(cn=$username)"
# Our unique identifier is the common name. Yours may not be, so
# so you might need to change that.
#
##
my $rawinput;
my @authdata;
my $authresult;
#
# I know checkpassword takes 3 params, the third being a timestamp.
# But on descriptor 3, I am only receiving 2 params (user/pass).
# I don't know why checkpassword gets that other one and I don't.
#
my $num_params = 2;
#
# Input comes in on descriptor 3. That's just how it's setup. If
# you want to write back to the client on the SMTP session (which you
# probably don't want to do for any production system) write to fileno(STDOUT)
#
my $input_descriptor = 3;
#
# These codes from DJB's checkpassword page.
#
my ($resp_ok,$resp_unacceptable,$resp_misused,$resp_tempfailure) = (0,1,2,111);
#
# messages that get written to the qmail-smtpd log file.
#
my ($msg_ok, $msg_unacceptable, $msg_misused,$msg_tempfailure,
$msg_badldap,$msg_ldapgeneral) =
("LDAP_AUTH_INFO: Authentication Success\n",
"LDAP_AUTH_INFO: Authentication Failure\n",
"LDAP_AUTH_INFO: Received incorrect number of parameters.\n",
"LDAP_AUTH_ERROR: CRITICAL Something is wrong. Check LDAP server connectivity.\n",
"LDAP_LDAP_ERROR: CRITICAL Could not connect to LDAP Server.\n",
"LDAP_LDAP_ERROR: CRITICAL Message=");
#
my $fhin = new IO::Handle;
my $fherr = new IO::Handle;
$fhin->fdopen($input_descriptor,"r");
$fherr->fdopen(fileno(STDERR),"w");
if (($fhin->opened) && ($fherr->opened)) {
$fhin->read($rawinput,$PROTOCOL_LEN);
@authdata = split(/\0/,$rawinput);
if (scalar(@authdata) != $num_params) {
$LOG_YES && $fherr->print($msg_misused);
exit $resp_misused;
}
#
# This section is the 'bottom line' so to speak,
# where the yea or nay is given.
#
$authresult = &ldap_auth(@authdata);
if ($authresult == $resp_ok) {
$LOG_YES && $fherr->print($msg_ok);
} elsif ($authresult == $resp_unacceptable) {
$LOG_YES && $fherr->print($msg_unacceptable);
}
exit $authresult;
}
$fherr->print($msg_tempfailure);
exit $resp_tempfailure;
sub ldap_auth {
my ($username, $password) = @_;
my $dn = &ldap_search($username);
if ($dn ne '') {
$ldap = Net::LDAP->new($ldap_server) or &mydie();
$mesg = $ldap->bind( $dn, password => $password );
$ldap->unbind; # take down session
if ( $mesg->code ) {
# FAILURE (bad password)
return $resp_unacceptable;
} else {
# SUCCESS
return $resp_ok;
}
} else {
# FAILURE (username doesn't exist)
return $resp_unacceptable;
}
}
sub ldap_search {
($username) = @_;
$ldap = Net::LDAP->new(
$ldap_server,
port => $ldap_port
) or &mydie();
$mesg = $ldap->bind ;
if ( $mesg->code ) {
&mydie($mesg->code);
}
$mesg = $ldap->search (
base => $base,
scope => $scope,
filter => "(cn=$username)"
);
$mesg->code && &mydie($mesg->error);
my $numfound = $mesg->count ;
my $dn="" ;
if ($numfound) {
my $entry = $mesg->entry(0);
$dn = $entry->dn ;
}
$ldap->unbind; # take down session
return $dn ;
}
sub mydie {
if (scalar(@_) > 0) {
$fherr->print($msg_ldapgeneral . $_[0] . "\n");
} else {
$fherr->print($msg_badldap);
}
exit $resp_tempfailure;
}