Skip to content

Instantly share code, notes, and snippets.

@rpetti
Last active December 27, 2015 12:19
Show Gist options
  • Save rpetti/7325408 to your computer and use it in GitHub Desktop.
Save rpetti/7325408 to your computer and use it in GitHub Desktop.
/etc/p4passwd contains plain text passwords (for administrator override). When a user changes their password, a shadow password entry is added to /etc/p4shadow, which is used for authentication from then-on. If the user isn't in the p4passwd or p4shadow file, it will use ldap authentication.
#!/usr/bin/perl
# p4 trigger: updateLocalPw auth-set auth "%serverroot%/triggers/auth-set.pl %user% %serverroot%/triggers/ldap-check-auth.pl"
$login = shift(ARGV);
$authCmd = shift(ARGV);
open(LCL_PASSWD_FILE,"</etc/p4shadow") or die "Can't open local shadow password file.";
@PASSWD = <LCL_PASSWD_FILE>;
close(LCL_PASSWD_FILE);
chomp(@PASSWD);
@PASSWD = grep(!/^$login\:\:/, @PASSWD);
chomp(my @passwd = <STDIN>);
s/\r$// for(@passwd);
open(AUTH, "| $authCmd $login") or die "Can't authenticate password.";
print AUTH "$passwd[0]\n";
close(AUTH);
die "Authentication failed." if $?;
my @salt = ( '.', '/', 0 .. 9, 'A' .. 'Z', 'a' .. 'z' );
# this takes password as argument: good for simple example, bad for
# security (perldoc -q password)
my $encrypted;
# generate traditional (weak!) DES password, and more modern md5
$encrypted = crypt( $passwd[1], gensalt(2) );
push(@PASSWD,"$login\:\:$encrypted");
open(LCL_PASSWD_FILE,">/etc/p4shadow");
foreach (@PASSWD) {
print LCL_PASSWD_FILE "$_\n";
}
close(LCL_PASSWD_FILE);
# uses global @salt to construct salt string of requested length
sub gensalt {
my $count = shift;
my $salt;
for (1..$count) {
$salt .= (@salt)[rand @salt];
}
return $salt;
}
#!/usr/bin/perl
#
# Script called by the perforce via the auth-check trigger
# p4 trigger: 'ldap auth-check auth "%serverroot%/triggers/ldap-check-auth.pl %user%"'
use Net::LDAP;
# Read in login name and password
my $login = shift(ARGV);
my $ldapServer = "ldap-hostname";
my $ldapServerBackup = "ldap-hostname-2";
open(STDERR, ">&STDOUT") or die "Can't dup stdout";
##
## read the password from <stdin< and truncate the newline
##
chomp (my $passwd = <STDIN>);
$passwd =~ s/\r$//;
#
# Check /etc/p4shadow to see if the login account this there. If it is, do authentication there.
#
open(LCL_PASSWD_FILE,"</etc/p4shadow") or die "Can't open local shadow password file.";
while (<LCL_PASSWD_FILE>) {
# next if ( /^\#/ );
if ( /^$login\:\:/ ) {
chomp;
($testpasswd = $_) =~ s/^$login\:\://;
if ( crypt($passwd, $testpasswd) ne $testpasswd ) {
open("DEBUGFILE", '>>/tmp/debugP4Login');
$mesg = "Local Authentication of $login failed with bad shadow password - " . `date` ."";
print DEBUGFILE $mesg;
close DEBUGFILE;
sendError("relops", "LocalShadowAuth", $mesg);
exit 1;
}
# Was able to authenticate via local p4passwd file, exist success
exit 0;
}
}
close LCL_PASSWD_FILE;
#
# Check /etc/p4passwd to see if the login account this there. If it is, do authentication there.
#
open(LCL_PASSWD_FILE,"</etc/p4passwd") or die "Can't open local password file.";
while (<LCL_PASSWD_FILE>) {
# next if ( /^\#/ );
if ( /^$login\:\:/ ) {
chomp;
($testpasswd = $_) =~ s/^$login\:\://;
if ( $testpasswd ne $passwd ) {
open("DEBUGFILE", '>>/tmp/debugP4Login');
$mesg = "Local Authentication of $login failed with bad password - " . `date` ."";
print DEBUGFILE $mesg;
close DEBUGFILE;
sendError("relops", "LocalAuth", $mesg);
exit 1;
}
# Was able to authenticate via local p4passwd file, exist success
exit 0;
}
}
close LCL_PASSWD_FILE;
$ldap = Net::LDAP->new ( $ldapServer ) or sendError("relops", "Connection", "");
$mesg = $ldap->bind ( version => 3 ); # use for searches
$mesg = $ldap->bind ( "$login\@somedomain.com",
password => "$passwd",
version => 3 );
#
# It applears that "52e" means bad password and 525 is invalid login
#
if ( $mesg->code ) {
open("DEBUGFILE", '>>/tmp/debugP4Login');
print DEBUGFILE $mesg->error;
print DEBUGFILE " - $login " . `date` . "";
#print DEBUGFILE "LDAP Authentication Error.\n";
if ( $mesg->error =~ /52e/ )
{
$ldapErrorMsg="LDAP returned data 52e which means bad password Full LDAP message\n";
}
elsif ( $mesg->error =~ /525/ )
{
$ldapErrorMsg="LDAP returned data 525 which means unknown login Full LDAP message\n";
}
$ldapErrorMsg = $ldapErrorMsg . $mesg->error;
$ldapErrorMsg=~s/[^0-9a-zA-Z ]//g;
sendError("relops", "LDAP", $ldapErrorMsg);
exit $mesg->code;
}
exit 0;
sub sendError
{
my ($emailUser, $error, $msg) = @_;
$msg = `date` . $msg;
$msg=~s/[:,]//g;
if ($error=~/Connection/)
{
`echo "$login is having Connection Problem on $ldapServer" | mail -s "IMPORTANT: Respond immediately!! ldap connection problem on $ldapServer" $emailUser\@somedomain.com`;
`echo "Perforce is having problem communicating with LDAP Server $ldapServer. Please let releng know ASAP." | mail -s "Perforce LDAP communication problem" -c relops\@interwoven.com $login\@somedomain.com`;
die "LDAP failed";
exit 1;
}
if ($error=~/LDAP/)
{
`echo "$msg" | mail -s "LDAP authentication failed for $login on $ldapServer" $emailUser\@somedomain.com`;
}
if ($error=~/LocalAuth/)
{
`echo "$msg" | mail -s "Local authentication failed for $login" $emailUser\@somedomain.com`;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment