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; }