File: //lib64/squid/basic_msnt_multi_domain_auth
#!/usr/bin/perl
use strict;
use Pod::Usage;
use Getopt::Long;
=pod
=head1 NAME
basic_msnt_multi_domain_auth
=head1 SYNOPSIS
basic_msnt_multi_domain_auth [options]
=head1 DESCRIPTION
B<basic_msnt_multi_domain_auth> is a Squid authenticator to check
user credentials against multiple NT domains using B<nmblookup>.
The user is expected to enter his/her credentials as domain\username
or domain/username (in analogy to what MS-Proxy does).
Requires Authen::SMB from CPAN and Samba if you need to perform NETBIOS
queries.
=head1 OPTIONS
=over 12
=item B<--debug>
Write debug info to stderr.
=item B<--wins-server>
Use the named WINS server.
Default: broadcast will be attempted.
=item B<--no-fqdn>
Some servers don't like to be called by their fully qualified name.
Define this if you wish to call them ONLY by their hostname.
=item B<--no-rdns>
Some servers really really want to be called by address.
=back
=head1 AUTHOR
This program was written by I<Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>>
This manual was written by I<Amos Jeffries <squid3@treenet.co.nz>>
=head1 COPYRIGHT
* Copyright (C) 1996-2016 The Squid Software Foundation and contributors
*
* Squid software is distributed under GPLv2+ license and includes
* contributions from numerous individuals and organizations.
* Please see the COPYING and CONTRIBUTORS files for details.
=head1 QUESTIONS
Questions on the usage of this program can be sent to the I<Squid Users mailing list <squid-users@squid-cache.org>>
=head1 REPORTING BUGS
Bug reports need to be made in English.
See http://wiki.squid-cache.org/SquidFaq/BugReporting for details of what you need to include with your bug report.
Report bugs or bug fixes using http://bugs.squid-cache.org/
Report serious security bugs to I<Squid Bugs <squid-bugs@squid-cache.org>>
Report ideas for new improvements to the I<Squid Developers mailing list <squid-dev@squid-cache.org>>
=head1 SEE ALSO
squid (8), GPL (7),
The Squid FAQ wiki http://wiki.squid-cache.org/SquidFaq
The Squid Configuration Manual http://www.squid-cache.org/Doc/config/
=cut
#to force using some DC for some domains, fill in this hash.
#the key is a regexp matched against the domain name
# the value is an array ref with PDC and BDC.
# the order the names are matched in is UNDEFINED.
#i.e.:
# %controllers = ( "domain" => ["pdc","bdc"]);
#%controllers = ( ".*" => ["pdcname","bdcname"]);
#no more user-serviceable parts
use Authen::Smb;
#variables:
# %pdc used to cache the domain -> pdc_ip values. IT NEVER EXPIRES!
my $debug = undef;
my $wins_server = undef;
my $no_rdns = undef;
my $no_fqdn = undef;
GetOptions(
'debug' => \$debug,
'wins-server=s' => $wins_server,
'no-fqdn' => $no_fqdn,
'no-rdns' => $no_rdns
);
$|=1;
while (<>) {
chomp;
if (! m;^(\S+)(/|%5c)(\S+)\s(\S+)$; ) { #parse the line
print "ERR\n";
next;
}
$domain=$1;
$user=$3;
$pass=$4;
$domain =~ s/%([0-9a-f][0-9a-f])/pack("H2",$1)/gie;
$user =~ s/%([0-9a-f][0-9a-f])/pack("H2",$1)/gie;
$pass =~ s/%([0-9a-f][0-9a-f])/pack("H2",$1)/gie;
print STDERR "domain: $domain, user: $user, pass=$pass\n"
if (defined ($debug));
# check out that we know the PDC address
if (!$pdc{$domain}) {
($pdc,$bdc)=&discover_dc($domain);
if ($pdc) {
$pdc{$domain}=$pdc;
$bdc{$domain}=$bdc;
}
}
$pdc=$pdc{$domain};
$bdc=$bdc{$domain};
if (!$pdc) {
#a pdc was not found
print "ERR\n";
print STDERR "No PDC found\n" if (defined($debug));
next;
}
print STDERR "querying '$pdc' and '$bdc' for user '$domain\\$user', ".
"pass $pass\n" if (defined($debug));
$result=Authen::Smb::authen($user,$pass,$pdc,$bdc,$domain);
print STDERR "result is: $nt_results{$result} ($result)\n"
if (defined($debug));
if ($result == NTV_NO_ERROR) {
print STDERR ("OK for user '$domain\\$user'\n") if (defined($debug));
print ("OK\n");
} else {
print STDERR "Could not authenticate user '$domain\\$user'\n";
print ("ERR\n");
}
}
#why do Microsoft servers have to be so damn picky and convoluted?
sub discover_dc {
my $domain = shift @_;
my ($pdc, $bdc, $lookupstring, $datum);
foreach (keys %controllers) {
if ($domain =~ /$_/) {
print STDERR "DCs forced by user: $_ => ".
join(',',@{$controllers{$_}}).
"\n" if (defined($debug));
return @{$controllers{$_}};
}
}
$lookupstring="nmblookup";
$lookupstring.=" -R -U $wins_server" if (defined($wins_server));
$lookupstring.=" -T" unless (defined($no_rdns));
$lookupstring.=" '$domain#1c'";
print STDERR "Discovering PDC: $lookupstring\n"
if (defined($debug));
#discover the PDC address
open(PDC,"$lookupstring|");
while (<PDC>) {
print STDERR "response line: $_" if (defined($debug));
if (m|(.*), (\d+\.\d+\.\d+\.\d+)|) {
$datum=$1;
print STDERR "matched $datum\n" if (defined($debug));
if (defined($no_fqdn) && $datum =~ /^([^.]+)\..*/) {
$datum=$1;
print STDERR "stripped domain name: $datum\n" if (defined($debug));
}
} elsif (m|^(\d+\.\d+\.\d+\.\d+)|) {
$datum=$1;
} else {
#no data here, go to next line
next;
}
if ($datum) {
if ($pdc) {
$bdc=$datum;
print STDERR "BDC is $datum\n" if (defined($debug));
last;
} else {
$pdc=$datum;
print STDERR "PDC is $datum\n" if (defined($debug));
}
last;
}
}
close(PDC);
return ($pdc,$bdc) if ($pdc);
return 0;
}