#!/usr/bin/perl -w # LDAP to unix password sync script for samba # This code is derivated from smbldap-passwd.pl developped by IDEALX (http://IDEALX.org/) and # contributors (their names can be found in the CONTRIBUTORS file). # # Copyright (C) 2001-2002 IDEALX # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, # USA. # Purpose : # ldap-unix passwd sync for samba to use if samba # use ITDS e AIX 5.x RFC2307AIX objectclass and you want # SSO use strict; use diagnostics; use Net::LDAP qw(:all); use Net::LDAP::Util qw(ldap_error_name ldap_error_text) ; use POSIX; use Sys::Syslog qw(:DEFAULT setlogsock); my %config_bind_conf; my %config_conf; my $smbldap_bind_conf; my $smbldap_conf; my $ldap_user; my $ldap; my $result_ldap; my $progname = $0; $progname =~ s,.*/,,; sub CreateCryptSalt { my $salt; my $md5salt = shift; my @valid = split(//, "./0123456789abcdefghilmnopqrstuvwxyzABCDEFGHILMNOPQRSTUVWXYZ") ; my $cryptsaltlen = ($md5salt ? 8 : 2); open(F, "< /dev/urandom") || die "No /dev/urandom found!"; foreach (1..$cryptsaltlen) { my $in; read(F, $in, 1); $salt .= $valid[ord($in) % ($#valid + 1)]; } close F; return ($md5salt ? "\$1\$$salt\$" : $salt ); } ############################ # LogDie ############################ sub LogDie() { my $facility="authpriv"; my $priority="err"; my $debug=0; my ($msg,$code)=@_; my $message=$msg; $message="$msg"." $code" if defined($code); closelog; openlog "$progname", 'ndelay,pid', $facility or die "$0: openlog: $!\n"; syslog $priority, "%s", $message unless $debug; die "$progname $facility/$priority $message\n" if $debug; } ########################### # LogInfo ########################### sub LogInfo() { my $facility="authpriv"; my $priority="info"; my $debug=0; my ($msg,$code)=@_; my $message=$msg; $message="$msg"." $code" if defined($code); closelog; openlog "$progname", 'ndelay,pid', $facility or die "$0: openlog: $!\n"; syslog $priority, "%s", $msg unless $debug; warn "$progname $facility/$priority $msg\n" if $debug; } $ldap_user = shift @ARGV; usage() if (! $ldap_user ); if ($< != 0) { print STDERR "You must be root to modify an user\n"; exit (1); } setlogsock('unix') if grep /^ $^O $/xo, ("linux", "openbsd", "freebsd", "netbsd"); if (-e "/etc/smbldap-tools/smbldap_bind.conf") { $smbldap_bind_conf="/etc/smbldap-tools/smbldap_bind.conf"; } else { &LogDie("Unable to open /etc/smbldap-tools/smbldap_bind.conf for reading !\n"); }; if (-e "/etc/smbldap-tools/smbldap.conf") { $smbldap_conf="/etc/smbldap-tools/smbldap.conf"; } else { &LogDie("Unable to open /etc/smbldap-tools/smbldap.conf for reading !\n") ; }; open (CONFIGFILE, "$smbldap_bind_conf") || &LogDie("Unable to open $smbldap_bind_conf for reading !\n"); while () { chomp($_); ## eat leading whitespace $_=~s/^\s*//; ## eat trailing whitespace $_=~s/\s*$//; ## throw away comments next if (($_=~/^#/) || ($_=~/^;/)); ## check for a param = value if ($_=~/=/) { #my ($param, $value) = split (/=/, $_); my ($param, $value) = ($_=~/([^=]*)=(.*)/i); $param=~s/./\l$&/g; $param=~s/\s+//g; $value=~s/^\s+//; $value=~s/"//g; $config_bind_conf{$param} = $value; next; } } close (CONFIGFILE); open (CONFIGFILE, "$smbldap_conf") || &LogDie("Unable to open $smbldap_conf for reading !\n"); while () { chomp($_); ## eat leading whitespace $_=~s/^\s*//; ## eat trailing whitespace $_=~s/\s*$//; ## throw away comments next if (($_=~/^#/) || ($_=~/^;/)); ## check for a param = value if ($_=~/=/) { #my ($param, $value) = split (/=/, $_); my ($param, $value) = ($_=~/([^=]*)=(.*)/i); $param=~s/./\l$&/g; $param=~s/\s+//g; $value=~s/^\s+//; $value=~s/"//g; $config_conf{$param} = $value; next; } } close (CONFIGFILE); my $masterdn = $config_bind_conf{'masterdn'}; my $masterpw = $config_bind_conf{'masterpw'}; my $masterldap = $config_conf{'masterldap'}; my $masterport = $config_conf{'masterport'}; my $slaveldap = $config_conf{'slaveldap'}; my $usersdn = $config_conf{'usersdn'}; my $computersdn = $config_conf{'computersdn'}; my $suffix = $config_conf{'suffix'}; my $scope = $config_conf{'scope'}; my $ldap_server_timeout=3 ; &LogDie("Unable to read smbldap configuration paramaters") unless $masterdn && $masterpw && $masterldap && $masterport && $usersdn && $slaveldap; # Build Rdn my $target_userdn; $ldap = Net::LDAP -> new($masterldap,port=>$masterport,timeout=>$ldap_server_timeout,version=>3) ; if ( ! $ldap ) { $ldap = Net::LDAP -> new($slaveldap,port=>$masterport,timeout=>$ldap_server_timeout,version=>3) or &LogDie("Unable to open $slaveldap: $@\n"); $result_ldap = $ldap->bind ($masterdn, password => $masterpw); $result_ldap->code && &LogDie("Failed to bind to $slaveldap $result_ldap->error"); } else { $result_ldap = $ldap->bind ($masterdn, password => $masterpw); $result_ldap->code && &LogDie("Failed to bind to $masterldap $result_ldap->error"); } # Find users dn my $mesg = $ldap->search ( # perform a search base => $suffix, scope => $scope, filter => "(&(objectclass=posixAccount)(uid=$ldap_user))" ); $mesg->code && &LogDie("$mesg->error"); foreach my $entry ($mesg->all_entries) { $target_userdn= $entry->dn; } unless ($target_userdn ) { &LogDie("Error: the user $ldap_user doesn't exists\n") ;} print "Changing password for user $ldap_user\n"; # prompt for new password my $pass; my $pass2; system "/bin/stty -echo"; print "New UNIX password for user $ldap_user: "; chomp($pass=); print "\n"; system "/bin/stty echo"; system "/bin/stty -echo"; print "Retype new UNIX password for user $ldap_user: "; chomp($pass2=); print "\n"; system "/bin/stty echo"; if ($pass ne $pass2) { print "Sorry, passwords do not match\n"; exit (10); } # change unix password my $hash_password = "{crypt}".crypt($pass, CreateCryptSalt(0)) ; chomp($hash_password); my $shadowlastchange=POSIX::ceil(time()/(24*3600)); my @whatToChange; my @ReplaceArray; my @DeleteArray; my @AddArray; my @NullArray; push (@ReplaceArray, 'userPassword', $hash_password); push (@ReplaceArray, 'shadowLastChange', $shadowlastchange); ################################## # Delete ADMCHG from RFC2307 aix ################################## push (@ReplaceArray, 'passwordflags',\@NullArray); if ( @ReplaceArray ) { push @whatToChange, 'replace', \@ReplaceArray; } if ( @DeleteArray ) { push ( @whatToChange, 'delete', \@DeleteArray); } if ( @AddArray ) { push ( @whatToChange, 'add', \@AddArray) ; } if ( @whatToChange ) { $result_ldap=$ldap->modify ( $target_userdn, changes => [ @whatToChange ] ); $result_ldap->code && &LogDie("Failed to update of $target_userdn ldap_error_name($result_ldap->code)"); } $ldap->unbind; print "passwd: all authentication tokens updated successfully.\n"; &LogInfo("Updated $target_userdn password successfully.\n"); exit 0; ######### sub usage { print STDERR <