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

Pàgina inicial
Delete this message
Reply to this message
Autor: Kirill Miazine
Data:  
A: exim-users
Assumpte: Re: [Exim] SMTP Auth against /etc/master.passwd on FreeBSD
Jez Hancock wrote:
> Hi all,
>
> This is a summary of one solution to the subject problem which was put
> forward by Kirill Miazine and hacked at to do MD5 authentication
> against the system password file /etc/master.passwd on FreeBSD by.
>
> The following perl code uses the Net::Server module to fork a
> specified number of server processes (similar in manner to the
> mechanism employed by apache webserver), each process listening for
> incoming authentication traffic on a unix domain socket.
>
> Upon receiving an authentication request on a listening socket, the
> server does some minimal data validation checking on the submitted
> user/password pair.
>
> The server then retrieves the pwd hash from /etc/master.passwd based
> on the 'username' key submitted and then hashes the submitted
> 'password' string using the salt obtained from the pwd hash. If the
> resulting hash matches the pwd hash, the user is authenticated.
>
> The script has to be suid root with suidperl unfortunately since it
> has to read /etc/master.passwd. However this entails that the domain


This is not true. You just start that script as root and it will have
the neccessary permissions.

> sockets created by the server are not readable by the exim user
> (unless you like running exim as root:) It's conceivable to have the


This is not true either ;). Just say umask(0000) before you say
__PACKAGE__->run() the socket file is created and the socket will be
created in such way that everybody will be able to speak to it.

> server not suid and instead have it call a suid root helper that makes
> the lookup on the db, but to be honest I'm happy now I've got pwcheck


Huh?

> back and won't go to the effort.
>
> The code is here anyway in case anyone in future is interested:


I've some comments, please read on.

> -----------------------------------------------------------------------------
> #!/usr/bin/perl
>
> package EximAuth;
>
> use strict;
> use vars qw(@ISA);
> use Crypt::PasswdMD5;
> use Net::Server::PreFork;
> @ISA = qw(Net::Server::PreFork);
>
> sub process_request {
>     my $self = shift;
>     my $sock = $self->{'server'}->{'client'};
>     chomp(my $username = $sock->getline());
>     chomp(my $password = $sock->getline());

>
>     # some minimal data validation:
>     !$username ||
>     !$password ||
>     length($username) >16 ||
>     length($password) >255 ||
>     $username=~/[^0-9A-Za-z]/ ||
>     $password=~/[^0-9A-Za-z]/ &&


Weak passwords, weak passwords... I like to use some funny characters in
passwords myself...

>     $sock->print("no");

    ^^^^^^^^^^^^^^^^^^


The above line really should be

    return $sock->print("no");


To be honest, your data validation routine sucks a lot. Sorry, but it
does that. It does not do what you think it does. "no" will be output if
and only if $password =~ /[^0-9A-Za-z]/. Please read "man perop" - that
will help. Hint: you'll see how much better your "validator" works if
you replace "&&" with "and".

>     # get the line from the pwd db based on $username:
>     my (undef,$sys_password) = getpwnam($username);

>
>     # get the salt:
>     my ($salt) = $sys_password =~ /\$.*\$(.*)\$/;

>
>     # get our hash:
>     my $hash=unix_md5_crypt($password, $salt);

>
>     $sock->print($hash eq $sys_password ? 'yes' : 'no');
>     # for debug output:
>     # $sock->print("username: $username submitted password: "
>     #    ."$password salt: $salt myhash: $hash syshash: $sys_password\n");
> }

>
> __PACKAGE__->run(
>     proto => 'unix',
>     port => '/var/spool/exim/auth/auth.sock',
>     min_servers => 5,
>     min_spare_servers => 5,
>     max_spare_servers => 10,
>     max_servers => 15,
>     max_requests => 1000,
>     log_level => 4,


You don't need such a high log_level. Set it to 0.

> );


--
Kirill Miazine, Stud. Jur.
Faculty of Law, University of Oslo