#!/usr/bin/perl
#
# Authenticate users for INN against a MySQL database.
# Written by Daniel Marsh.
# Covered under the same license as INN in general.

# You really shouldn't need to edit this file.
# To test via tcsh:
#   (echo 'ClientAuthname: test' ; echo 'ClientPassword: monkey') | ./authmysql

use strict;
use warnings;

use DBI;

# Get STDIN and return it as a HASH.
my %stdin = get_stdin();

# Edit this path to wherever you want your config to reside.
# Read our config.
my %conf = readconf('/usr/local/news/etc/authmysql.config');

# Create our dbi string for the connection.
$conf{'database'} = "dbi:mysql:database=$conf{'DB'};host=$conf{'HOST'};";

# Open the database connection.
my $dbh = db_open(%conf);

# Create the query we're going to pass through.
my $query
  = "SELECT $conf{'passcol'} FROM $conf{'TABLE'}"
  . " WHERE $conf{'usercol'}='$stdin{'ClientAuthname'}'";

# Get our statement handler... not really a result.
my $result = $dbh->prepare($query);
$result->execute;
# The database needs to store this encrypted.
my $cryptedpw = $result->fetchrow_array();

# Encrypt the client password we were given.
$stdin{'ClientPassword'} = crypt($stdin{'ClientPassword'}, $cryptedpw);

# This query is to return a count of 1.  There should either be one
# match of the encrypted password/username or none.
$query
  = "SELECT COUNT(*) FROM $conf{'TABLE'} WHERE"
  . " $conf{'usercol'}='$stdin{'ClientAuthname'}' and"
  . " $conf{'passcol'}='$stdin{'ClientPassword'}'";

$result = $dbh->prepare($query);
$result->execute;
my $query_result = $result->fetchrow_array();    # This should be 1 or 0,
                                                 # 1 on success.
$result->finish;

# Need to get the return shit working now so it will reply proper
# information to news clients.
if ($query_result) {    # The user authenticated fine.
    print "user:$stdin{'ClientAuthname'}\n";    # Return based on nnrpd
                                                # auth specs.
    exit(0);                                    # Exit with no error.
} else {
    exit(502);    # Exit with error: username/password incorrect.
}

# Subs below.
sub readconf {
    my ($file) = @_;

    my %config;

    open(CONF, "$file");
    while (<CONF>) {
        chomp;
        next if $_ =~ /^#.*$/;
        next if $_ =~ /\s+/;
        $_ =~ s/#.*$//g;

        if ($_ ne "") {
            my ($key, $value_unused) = split(/:/, $_, 2);
            $config{$key} = $_;
        }
    }
    close(CONF);

    return (%config);
}

sub db_open {
    my (%config) = @_;
    my ($err, $dbhandle);

    if (
        $dbhandle = DBI->connect(
            $config{'database'},
            $config{'User'},
            $config{'Pass'},
        )
    ) {
        return ($dbhandle);
    } else {
        $err = "Failure opening database " . $DBI::errstr;
        # Log the error?
        # The script currently just exits with a non-zero status.
    }

    return (undef);
}

sub get_stdin {
    my %retstdin;
    while (<STDIN>) {
        chomp;
        next if $_ =~ /^#.*$/;
        next if $_ =~ /\s+/;
        $_ =~ s/#.*$//g;
        $_ =~ s/\s+//g;

        if ($_ ne "") {
            my ($key, $value) = split(/:/, $_, 2);
            $retstdin{$key} = $value;
        }
    }
    return (%retstdin);
}
