Re: [Exim] SMTP Auth against /etc/master.passwd on FreeBSD

Top Page
Delete this message
Reply to this message
Author: Jez Hancock
Date:  
To: Exim Users List
Subject: Re: [Exim] SMTP Auth against /etc/master.passwd on FreeBSD
Hi,

Ok thanks for the repsonses so far - especially from William Thompson who was kind enough
to provide some code for authenticating against a linux shadow password file.

Unfortunately I'm no C coder and so porting this to freebsd is out. Yes I know I should learn
C, but I'm short on time as always :)

Anyway, I've come up with the following perl script which I'm including into exim as follows:

perl_startup = do '/usr/local/etc/exim/exim.pl'

'/usr/local/etc/exim/exim.pl' is as follows:
------------------------------------------------------------------------------
#!/usr/bin/perl
use strict;
use Crypt::PasswdMD5;

=comment
    Note this perl script should be SUID 0 and be placed in your exim config dir.


    It should be included into exim via the exim configure file with a line like:


    perl_startup = do '/usr/local/etc/exim/exim.pl'


    The relevant subroutines can then be called from the exim configure file
    using:


    ${perl{foo}}


    where 'foo' is a subroutine defined within this script.
=cut


my($user, $pass, $salt, $hash)=(undef,undef,undef,undef);
my $err=undef;

my $progname = $0;
$progname =~ s,.*/,,; # use basename only
$progname =~ s/\.\w*$//; # strip extension, if any

my $VERSION=0.1;
# &MD5_auth(@ARGV); # For testing in a shell

sub MD5_auth(){
=comment
    #
    # Not needed in exim mode
    #


    # Get options:
    &Getopts();


    # data validation:
    if(!$user || !$pass || $user=~/[^0-9A-Za-z]/ || $pass=~/[^0-9A-Za-z]/){ &usage(); }
=cut
    $user=shift;
    $pass=shift;


    # get the line from the pwd db based on $user:
    my (undef,$sys_pass) = getpwnam($user);


    # get the salt:
    ($salt) = $sys_pass =~ /\$.*\$(.*)\$/;


    # get our hash:
    $hash=unix_md5_crypt($pass, $salt);


    #die("user: $user submitted pass: $pass salt: $salt myhash: $hash syshash: $sys_pass\n"); # for exim debug output to mainlog


    # if hash!=syspass:
    if($hash ne $sys_pass) { die("Bad user/pass pair\n"); }


    return 0;
}


sub usage{
    $err && (print $err,"\n");
    die<<"~USAGE~";
Usage: $progname -u user -p pass [-h]
       -h                     Display this help.


       -u user                User to search the /etc/master.passwd file for.


       -p pass            user's pass to authenticate against the entry
                              in /etc/master.passwd


Version $VERSION
~USAGE~
}

sub Getopts(){
    # Get opts:
    ARG: while (@ARGV && $ARGV[0] =~ s/-(?=.)//){
        OPT: for (shift @ARGV){
            s/h//        && do { usage(); exit; };
            s/u//        && do { $user = shift @ARGV; next ARG; };
            s/p//        && do { $pass = shift @ARGV; next ARG; };
            usage("Unknown option: $_");
        }
    }
}


__END__
------------------------------------------------------------------------------

This perl script works ok in a shell - for example on a dummy account I setup for
testing the output looks something like this:

[11:41:18] root@users /usr/local/etc/exim# ./exim.pl dummy dummy
user: dummy submitted pass: dummy salt: koz3aLbT myhash: $1$koz3aLbT$j9Srfw60S7U6MnjGN2Met1 syshash: $1$koz3aLbT$j9Srfw60S7U6MnjGN2Met1

which corresponds to the entry for 'dummy' in /etc/master.passwd:

[11:41:53] root@users /usr/local/etc/exim# grep ^dummy: /etc/master.passwd
dummy:$1$koz3aLbT$j9Srfw60S7U6MnjGN2Met1:1124:1124::0:0:User &:/home/dummy:/sbin/nologin

Now my authenticator in /usr/local/etc/exim/configure looks like this (this is the problem I think!):

------------------------------------------------------------------------------
begin authenticators

plain:
  driver = plaintext
  public_name = PLAIN
  server_condition = ${perl{MD5_auth}{$1}{$2}}
#  server_condition = "${if and {{!eq{$2}{}}{!eq{$3}{}} \
#              {crypteq{$3}{${extract{1}{:} \
#{${lookup{$2}lsearch{/etc/master.passwd}{$value}{*:*}}}}}}}{1}{0}}"
#  server_set_id = $2


login:
  driver = plaintext
  public_name = LOGIN
  server_prompts = "Username:: : Password::"
  server_condition = ${perl{MD5_auth}{$2}{$3}}
#  server_condition = "${if and {{!eq{$1}{}}{!eq{$2}{}} \
#              {crypteq{$2}{${extract{1}{:} \
#{${lookup{$1}lsearch{/etc/master.passwd}{$value}{*:*}}}}}}}{1}{0}}"
#  server_set_id = $1
------------------------------------------------------------------------------


Which is yielding nothing but 'Bad user/pass pair' in my exim mainlog.

Can anyone shed some light on how my authenticator should look. Also how can I debug this
better. Currently I'm doing this:

[11:55:09] root@users /usr/local/etc/exim# ./encode.pl '\0dummy\0dummy'
AGR1bW15AGR1bW15
[11:55:11] root@users /usr/local/etc/exim# exim -d+auth -bh 127.0.0.1
Exim version 4.14 uid=0 gid=0 pid=17877 D=fbb95cfd
Probably Berkeley DB version 1.8x (native mode)
Support for: IPv6 PAM Perl OpenSSL
Authenticators: cram_md5 plaintext
Routers: accept dnslookup ipliteral manualroute queryprogram redirect
Transports: appendfile/maildir/mailstore/mbx autoreply lmtp pipe smtp
changed uid/gid: forcing real = effective
uid=0 gid=0 pid=17877
auxiliary group list: 0
configuration file is /usr/local/etc/exim/configure
log selector = 020d99d8
trusted user
admin user
changed uid/gid: privilege not needed
uid=26 gid=6 pid=17877
auxiliary group list: 6
originator: uid=0 gid=0 login=root name=Charlie Root
sender address = root@???
sender_fullhost = [127.0.0.1]
sender_rcvhost = [127.0.0.1]

**** SMTP testing session as if from host 127.0.0.1
**** but without any ident (RFC 1413) callback.
**** This is not for real!

host in host_lookup? yes (matched "*")
looking up host name for 127.0.0.1
IP address lookup yielded localhost
gethostbyname2 returned 4 (NO_DATA)
gethostbyname2 looked up these IP addresses:
name=localhost address=127.0.0.1
checking addresses for localhost
127.0.0.1
sender_fullhost = localhost [127.0.0.1]
sender_rcvhost = localhost ([127.0.0.1])
set_process_info: 17877 handling incoming connection from localhost [127.0.0.1]
host in host_reject_connection? no (option unset)
host in sender_unqualified_hosts? no (option unset)
host in recipient_unqualified_hosts? no (option unset)
host in helo_verify_hosts? no (option unset)
host in helo_try_verify_hosts? no (option unset)
host in helo_accept_junk_hosts? no (option unset)
LOG: smtp_connection MAIN
SMTP connection from localhost [127.0.0.1]
SMTP>> 220 mail.munk.nu ESMTP Exim 4.14 Tue, 22 Apr 2003 11:55:18 +0100

220 mail.munk.nu ESMTP Exim 4.14 Tue, 22 Apr 2003 11:55:18 +0100
smtp_setup_msg entered
ehlo localhost
SMTP<< ehlo localhost
sender_fullhost = localhost [127.0.0.1]
sender_rcvhost = localhost ([127.0.0.1])
set_process_info: 17877 handling incoming connection from localhost [127.0.0.1]
host in pipelining_advertise_hosts? yes (matched "*")
host in auth_advertise_hosts? yes (matched "*")
host in tls_advertise_hosts? no (option unset)
250-mail.munk.nu Hello localhost [127.0.0.1]
250-SIZE 52428800
250-PIPELINING
250-AUTH PLAIN LOGIN
250 HELP
SMTP>> 250-mail.munk.nu Hello localhost [127.0.0.1]

250-SIZE 52428800
250-PIPELINING
250-AUTH PLAIN LOGIN
250 HELP
AUTH LOGIN
SMTP<< AUTH LOGIN
SMTP>> 334 VXNlcm5hbWU6

334 VXNlcm5hbWU6
AGR1bW15AGR1bW15
Starting Perl interpreter
login authenticator:
$1 =
$2 = dummy
$3 = dummy
expansion failed: error in perl_startup code: user: submitted pass: salt: myhash: $1$$qRPK7m23GJusamGpoGLby/ syshash:


SMTP>> 435 Unable to authenticate at present

435 Unable to authenticate at present
LOG: MAIN REJECT
login authenticator failed for localhost [127.0.0.1]: 435 Unable to authenticate at present: error in perl_startup code: user: submitted pass: salt: myhash: $1$$qRPK7m23GJusamGpoGLby/ syshash:


quit
SMTP<< quit
SMTP>> 221 mail.munk.nu closing connection

221 mail.munk.nu closing connection
LOG: smtp_connection MAIN
SMTP connection from localhost [127.0.0.1] closed by QUIT
search_tidyup called
>>>>>>>>>>>>>>>> Exim pid=17877 terminating with rc=0 >>>>>>>>>>>>>>>>



Sorry if this is too much information!

Thanks in advance,

Jez