nginx pop imap and ldap

Øyvind Kolbu oyvind.kolbu at usit.uio.no
Mon Aug 4 11:18:28 MSD 2008


On 2008-07-24 at 00:37, Leveau Stanislas wrote:
> Maybe that someone has already done it? ;)) a script for ldap??

Hi

Sorry for the late answer, but I've attached the perl auth daemon we use.

You probably want to change IMAPserver to mailHost, and look up the port as
well, but the changes should be quite straight forward.

In the mail section, add "auth_http  localhost:9000/cgi-bin/auth;"

-- 
Øyvind Kolbu
Postmaster
Universitetet i Oslo
-------------- next part --------------
#!/local/bin/perl -w
# $Header: /usit/cvs/cvsroot/gt/postmaster/mail_config/proxy/site/bin/proxy_auth,v 1.9 2008/02/24 13:02:15 kolbu Exp $
use strict;
use Socket;
use POSIX;
use Getopt::Long;
use Net::LDAP;
use Net::hostent;
use Data::Dumper;

my $hostname     = `hostname`;
chomp $hostname;
my $ldap_server  = "ldap.uio.no";
my $target_dir   = "/var/log/proxy_auth";
my $port         = 9000;
my $uid          = "nobody";
my $daemon       = 1;

GetOptions("hostname=s"    => \$hostname,
	   "port=s"        => \$port,
	   "uid=s"         => \$uid,
	   "targetdir=s"   => \$target_dir,
	   "ldap=s"        => \$ldap_server,
	   "daemon!"       => \$daemon);

if( $port !~ /^\d+/ ) { $port = getservbyname($port,"tcp"); }
if( $uid  !~ /^\d+/ ) { $uid  = getpwnam($uid);             }
$| = 1;
socket(SERVER, PF_INET, SOCK_STREAM,getprotobyname('tcp')) or
    die "socket failed $!,";
setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, pack("l",1)) or
    die "setsockopt $!,";
bind(SERVER,sockaddr_in($port,INADDR_ANY)) or
    die "bind $!,";
listen(SERVER,SOMAXCONN) or 
    die "listen $!,";

chdir $target_dir or die "chdir $target_dir failed,";
$> = $uid;
warn "UID $uid != $>," if $uid != $>;

if($daemon) {
    my $pid = fork();
    if($pid) {
	exit(0);
    }
    close(STDIN);
    close(STDOUT);
    close(STDERR);
}


while(my $paddr = accept(CLIENT,SERVER)) {
    my $pid = fork();
    die "fork," unless defined($pid);
    if($pid == 0) {
	close(SERVER);
	autoflush(*CLIENT);
	my ($port,$iaddr) = sockaddr_in($paddr);
	my $remote        = sprintf("%s:%d",inet_ntoa($iaddr),$port);
	my $messageid;
	my %request = ();
	while(<CLIENT>) {
	    s/\r//g;
	    last if /^\s*$/;
	    if(my ($key,$value) = /(\S+):\s(.+)/) {
		$request{$key} = $value;
                if ($key eq "Auth-Pass") {
                    $request{'Auth-Pass'} =~ s/\%([A-Fa-f0-9]{2})/pack("C",hex($1))/seg;
                    next;
                }
	    }
	}
	my $imapserver;
	my $remote_port;
	my $user;
	if($request{'Auth-User'} =~ /^[\w_-]+$/) {
	    my $uid = $request{'Auth-User'};
	    my $pwd = $request{'Auth-Pass'};
	    my @ret = ldap( base   => "cn=targets,cn=mail,dc=uio,dc=no",
			    filter => "(&(target=$uid)(targetType=user))" );
	    for my $i (@ret) {
		my ($k,$v) = @$i;
		#print "$k: $v\n";
		if($k eq "IMAPserver") {
		    $imapserver = inet_ntoa(gethost($v)->addr);
		} elsif($k eq "dn") {
		    $user = auth($v,$pwd);
		}
	    }
	}
	if($request{'Auth-Protocol'} eq "imap") {
	    $remote_port = 143;
	}
	if($request{'Auth-Protocol'} eq "pop3") {
	    $remote_port = 110;
	}
	if($imapserver and $remote_port and $user) {
	    l("main","ok",$request{'Auth-User'},$request{'Auth-Protocol'});
	    print CLIENT <<EOF
HTTP/1.0 200 OK
Auth-Status: OK
Auth-Server: $imapserver
Auth-Port: $remote_port

EOF
;
	} elsif($imapserver and $remote_port) {
	    l("main","invalid password",
	      $request{'Auth-User'},$request{'Auth-Protocol'});
	    print CLIENT <<EOF
HTTP/1.0 200 OK
Auth-Status: Invalid password. 
Auth-Wait: 3

EOF
;
	} else {
	    l("main","invalid login",
	      $request{'Auth-User'},$request{'Auth-Protocol'});
	    print CLIENT <<EOF
HTTP/1.0 200 OK
Auth-Status: Invalid login. 
Auth-Wait: 5

EOF
;
	}
	exit(0);
    }
    close(CLIENT);
    1 while waitpid(-1,POSIX::WNOHANG) > 0;
}

sub autoflush {
    my $fh = shift;
    my $old = select($fh);
    $| = 1;
    select($old);
}

sub auth {
    my $dn       = shift;
    my $password = shift;
    my $uio = Net::LDAP->new($ldap_server)
	or die "LDAP failed,";
    $uio->start_tls();
    my $m   = $uio->bind( $dn,
			  password => $password );    
    return $m && ! $m->code();
}

sub ldap {
    no strict 'vars';
    no warnings 'once';
    my %params = @_;
    *uio = *LDAP::ldap;
    *m   = *LDAP::message;
    my $errors = 0;
    do {
	eval {
	    if(not $uio) {
		$uio = Net::LDAP->new ($ldap_server) 
		    or die "LDAP->new $!,";
		$m    = $uio->bind() or die "bind,$!,";
	    }
	    $m    = $uio->search (%params) or die "search $!,";
	    if($m->code) {
		die "Search error: " . $m->code . ",";
	    }
	};
	if($@) {
	    $uio = undef;
            &l("error","LDAP",%params,"error: $@"); 
	    select(undef,undef,undef,0.25);
	    if($errors++ > 10) {
		die "This is not working. $@,";
	    }
	}
    } while($@);

    return () unless ( defined( $m->entry));
	
    my @ret = ( [ "dn", $m->entry->dn() ] );
    for my $entry ($m->entries) {
	for my $attr ( $entry->attributes ) {
	    for my $value (@{$entry->get_value($attr, asref => 1)}) {
		push(@ret,[ $attr , $value]);
	    }
	}
    }
    return @ret;
}

sub l {
    my $pre     = shift;
    my @args    = @_;
    my $now     = localtime();
    my $timestr = POSIX::strftime("%F", localtime() );
    open O,">>","$pre.log.$timestr" or die "Cannot open log '$pre.$timestr',";
    if(not @args) {
	carp("\@args not defined,");
    } else {
	chomp @args;
    }
    local $" = "] [";
    print O "$now: [@args]\n";
    close(O);
}
-------------- next part --------------
#!/bin/bash
# $Header: /usit/cvs/cvsroot/gt/postmaster/mail_config/proxy/etc/rc.d/init.d/proxy_auth,v 1.2 2007/12/20 13:01:43 kolbu Exp $
# proxy_auth    This shell script takes care of starting and stopping proxy_auth
#
# chkconfig: 2345 70 30
# description: proxy_auth nginx authentication helper. 
# processname: proxy_auth
# config: 
# pidfile: /var/run/proxy_auth.pid

# Source function library.
. /etc/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0

[ -f /site/bin/proxy_auth ] || exit 0

start() {
        echo -n $"Starting proxy_auth: "
	mkdir -p /var/log/proxy_auth
        chown nobody.nobody /var/log/proxy_auth
        cd /var/log/proxy_auth || exit
	daemon /site/bin/proxy_auth
        RETVAL1=$?
        echo
        [ $RETVAL1 = 0 ] && touch /var/lock/subsys/proxy_auth
}

stop() {
        # Stop daemons.
        echo -n $"Shutting down proxy_auth: "
        killproc proxy_auth
	RETVAL1=$?
        echo
        [ $RETVAL1 = 0 ] && rm -f /var/lock/subsys/proxy_auth
}

restart() {
	stop
	start
}

# See how we were called.
case "$1" in
  start)
	start
	;;
  stop)
	stop
	;;
  restart)
	restart
	;;
  status)
	status proxy_auth
	;;
  *)
	echo $"Usage: $0 {start|stop|restart|status}"
	exit 1
esac

exit $RETVAL

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
URL: <http://nginx.org/pipermail/nginx/attachments/20080804/b00c2c1a/attachment.pgp>


More information about the nginx mailing list