use strict;
package smbldap_tools;
use smbldap_conf;
use Net::LDAP;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
use Exporter;
$VERSION = 1.00;
@ISA = qw(Exporter);
@EXPORT = qw(
get_user_dn
get_group_dn
is_samba_user
is_user_valid
get_dn_from_line
add_posix_machine
add_samba_machine
add_samba_machine_mkntpwd
group_add_user
add_grouplist_user
disable_user
delete_user
group_add
get_homedir
read_user
read_group
find_groups_of
parse_group
group_remove_member
group_get_members
do_ldapadd
do_ldapmodify
get_user_dn2
);
sub get_user_dn
{
my $user = shift;
my $dn='';
my $ldap = Net::LDAP->new($slaveLDAP) or die "erreur LDAP";
$ldap->bind ;
my $mesg = $ldap->search ( base => $suffix,
scope => $scope,
filter => "(&(objectclass=posixAccount)(uid=$user))"
);
$mesg->code && die $mesg->error;
foreach my $entry ($mesg->all_entries) {
$dn= $entry->dn;}
$ldap->unbind;
chomp($dn);
if ($dn eq '') {
return undef;
}
$dn="dn: ".$dn;
return $dn;
}
sub get_user_dn2 {
my $user = shift;
my $dn='';
my $ldap = Net::LDAP->new($slaveLDAP) or die "erreur LDAP";
$ldap->bind ;
my $mesg = $ldap->search ( base => $suffix,
scope => $scope,
filter => "(&(objectclass=posixAccount)(uid=$user))"
);
if ($mesg->code)
{
print("Code erreur : ",$mesg->code,"\n");
print("Message d'erreur : ",$mesg->error,"\n");
return (0,undef);
}
foreach my $entry ($mesg->all_entries) {
$dn= $entry->dn;
}
$ldap->unbind;
chomp($dn);
if ($dn eq '') {
return (1,undef);
}
$dn="dn: ".$dn;
return (1,$dn);
}
sub get_group_dn
{
my $group = shift;
my $dn='';
my $ldap = Net::LDAP->new($slaveLDAP) or die "erreur LDAP";
$ldap->bind ;
my $mesg = $ldap->search ( base => $groupsdn,
scope => $scope,
filter => "(&(objectclass=posixGroup)(|(cn=$group)(gidNumber=$group)))"
);
$mesg->code && die $mesg->error;
foreach my $entry ($mesg->all_entries) {
$dn= $entry->dn;}
$ldap->unbind;
chomp($dn);
if ($dn eq '') {
return undef;
}
$dn="dn: ".$dn;
return $dn;
}
sub is_samba_user
{
my $user = shift;
my $ldap = Net::LDAP->new($slaveLDAP) or die "erreur LDAP";
$ldap->bind ;
my $mesg = $ldap->search ( base => $suffix,
scope => $scope,
filter => "(&(objectClass=sambaSamAccount)(uid=$user))"
);
$mesg->code && die $mesg->error;
$ldap->unbind;
return ($mesg->count ne 0);
}
sub is_user_valid
{
my ($user, $dn, $pass) = @_;
my $ldap = Net::LDAP->new($slaveLDAP) or die "erreur LDAP";
my $mesg= $ldap->bind (dn => $dn, password => $pass );
if ($mesg->code eq 0)
{
$ldap->unbind;
return 1;
}
else
{
if($ldap->bind()) {
$ldap->unbind;
return 0;
} else {
print ("Le serveur LDAP est indisponible.\nVérifier le serveur, les câblages, ...");
$ldap->unbind;
return 0;
} die "Problème : Contacter votre administrateur";
}
}
sub get_dn_from_line
{
my $dn = shift;
$dn =~ s/^dn: //;
return $dn;
}
sub add_posix_machine
{
my ($user, $uid, $gid) = @_;
my $tmpldif =
"dn: uid=$user,$computersdn
objectclass: inetOrgPerson
objectclass: posixAccount
sn: $user
cn: $user
uid: $user
uidNumber: $uid
gidNumber: $gid
homeDirectory: /dev/null
loginShell: /bin/false
description: Computer
";
die "$0: error while adding posix account to machine $user\n"
unless (do_ldapadd($tmpldif) == 0);
undef $tmpldif;
return 1;
}
sub add_samba_machine
{
my $user = shift;
system "smbpasswd -a -m $user";
return 1;
}
sub add_samba_machine_mkntpwd
{
my ($user, $uid) = @_;
my $sambaSID = 2 * $uid + 1000;
my $name = $user;
$name =~ s/.$//s;
if ($mk_ntpasswd eq '') {
print "Either set \$with_smbpasswd = 1 or specify \$mk_ntpasswd\n";
return 0;
}
my $ntpwd = `$mk_ntpasswd '$name'`;
chomp(my $lmpassword = substr($ntpwd, 0, index($ntpwd, ':')));
chomp(my $ntpassword = substr($ntpwd, index($ntpwd, ':')+1));
my $tmpldif =
"dn: uid=$user,$computersdn
changetype: modify
objectclass: inetOrgPerson
objectclass: posixAccount
objectClass: sambaSamAccount
sambaPwdLastSet: 0
sambaLogonTime: 0
sambaLogoffTime: 2147483647
sambaKickoffTime: 2147483647
sambaPwdCanChange: 0
sambaPwdMustChange: 2147483647
sambaAcctFlags: [W ]
sambaLMPassword: $lmpassword
sambaNTPassword: $ntpassword
sambaSID: $smbldap_conf::SID-$sambaSID
sambaPrimaryGroupSID: $smbldap_conf::SID-0
";
die "$0: error while adding samba account to $user\n"
unless (do_ldapmodify($tmpldif) == 0);
undef $tmpldif;
return 1;
}
sub group_add_user
{
my ($group, $userid) = @_;
my $members='';
my $dn_line = get_group_dn($group);
if (!defined($dn_line)) {
return 1;
}
my $dn = get_dn_from_line($dn_line);
my $ldap = Net::LDAP->new($slaveLDAP) or die "erreur LDAP";
$ldap->bind ;
my $mesg = $ldap->search ( base =>$dn, scope => "base", filter => "(objectClass=*)" );
$mesg->code && die $mesg->error;
foreach my $entry ($mesg->all_entries){
foreach my $attr ($entry->attributes)
{
if ($attr=~/\bmemberUid\b/){
foreach my $ent($entry->get_value($attr)) { $members.= $attr.": ".$ent."\n"; }
}
}
}
$ldap->unbind;
chomp($members);
if ($members =~ m/^memberUid: $userid/) {
return 2;
}
my $mods = "";
if ($members ne '') {
$mods="$dn_line
changetype: modify
replace: memberUid
$members
memberUid: $userid
";
} else {
$mods="$dn_line
changetype: modify
add: memberUid
memberUid: $userid
";
}
my $tmpldif =
"$mods
";
die "$0: error while modifying group $group\n"
unless (do_ldapmodify($tmpldif) == 0);
undef $tmpldif;
return 0;
}
sub add_grouplist_user
{
my ($grouplist, $user) = @_;
my @array = split(/,/, $grouplist);
foreach my $group (@array) {
group_add_user($group, $user);
}
}
sub disable_user
{
my $user = shift;
my $dn_line;
if (!defined($dn_line = get_user_dn($user))) {
print "$0: user $user doesn't exist\n";
exit (10);
}
my $tmpldif =
"dn: $dn_line
changetype: modify
replace: userPassword
userPassword: {crypt}!x
";
die "$0: error while modifying user $user\n"
unless (do_ldapmodify($tmpldif) == 0);
undef $tmpldif;
if (is_samba_user($user)) {
my $tmpldif =
"dn: $dn_line
changetype: modify
replace: sambaAcctFlags
sambaAcctFlags: [D ]
";
die "$0: error while modifying user $user\n"
unless (do_ldapmodify($tmpldif) == 0);
undef $tmpldif;
}
}
sub delete_user
{
my $user = shift;
my $dn_line;
if (!defined($dn_line = get_user_dn($user))) {
print "$0: user $user doesn't exist\n";
exit (10);
}
my $dn = get_dn_from_line($dn_line);
system "$ldapdelete $dn >/dev/null";
}
sub group_add
{
my ($gname, $gid, $force) = @_;
my $nscd_status = system "/etc/init.d/nscd status >/dev/null 2>&1";
if ($nscd_status == 0) {
system "/etc/init.d/nscd stop > /dev/null 2>&1";
}
if (!defined($gid)) {
while (defined(getgrgid($GID_START))) {
$GID_START++;
}
$gid = $GID_START;
} else {
if (!defined($force)) {
if (defined(getgrgid($gid))) {
return 0;
}
}
}
if ($nscd_status == 0) {
system "/etc/init.d/nscd start > /dev/null 2>&1";
}
my $tmpldif =
"dn: cn=$gname,$groupsdn
objectclass: posixGroup
cn: $gname
gidNumber: $gid
";
die "$0: error while adding posix group $gname\n"
unless (do_ldapadd($tmpldif) == 0);
undef $tmpldif;
return 1;
}
sub get_homedir
{
my $user = shift;
my $homeDir='';
my $ldap = Net::LDAP->new($slaveLDAP) or die "erreur LDAP";
$ldap->bind ;
my $mesg = $ldap->search ( base =>$suffix, scope => $scope, filter => "(&(objectclass=posixAccount)(uid=$user))" );
$mesg->code && die $mesg->error;
foreach my $entry ($mesg->all_entries){
foreach my $attr ($entry->attributes)
{
if ($attr=~/\bhomeDirectory\b/){
foreach my $ent($entry->get_value($attr)) {
$homeDir.= $attr.": ".$ent."\n";
}
}
}
}
$ldap->unbind;
chomp $homeDir;
if ($homeDir eq '') {
return undef;
}
$homeDir =~ s/^homeDirectory: //;
return $homeDir;
}
sub read_user
{
my $user = shift;
my $lines ='';
my $ldap = Net::LDAP->new($slaveLDAP) or die "erreur LDAP";
$ldap->bind ;
my $mesg = $ldap->search ( base => $suffix,
scope => $scope,
filter => "(&(objectclass=posixAccount)(uid=$user))"
);
$mesg->code && die $mesg->error;
foreach my $entry ($mesg->all_entries) {
$lines.= "dn: " . $entry->dn."\n";
foreach my $attr ($entry->attributes) {
{
$lines.= $attr.": ".join(',', $entry->get_value($attr))."\n";
}
}
}
$ldap->unbind; chomp $lines;
if ($lines eq '') {
return undef;
}
return $lines;
}
sub read_group
{
my $user = shift;
my $lines ='';
my $ldap = Net::LDAP->new($slaveLDAP) or die "erreur LDAP";
$ldap->bind ;
my $mesg = $ldap->search ( base => $groupsdn,
scope => $scope,
filter => "(&(objectclass=posixGroup)(cn=$user))"
);
$mesg->code && die $mesg->error;
foreach my $entry ($mesg->all_entries) {
$lines.= "dn: " . $entry->dn."\n";
foreach my $attr ($entry->attributes) {
{
$lines.= $attr.": ".join(',', $entry->get_value($attr))."\n";
}
}
}
$ldap->unbind; chomp $lines;
if ($lines eq '') {
return undef;
}
return $lines;
}
sub find_groups_of
{
my $user = shift;
my $lines ='';
my $ldap = Net::LDAP->new($slaveLDAP) or die "erreur LDAP";
$ldap->bind ;
my $mesg = $ldap->search ( base => $groupsdn,
scope => $scope,
filter => "(&(objectclass=posixGroup)(memberuid=$user))"
);
$mesg->code && die $mesg->error;
foreach my $entry ($mesg->all_entries) {
$lines.= "dn: ".$entry->dn."\n";
}
$ldap->unbind;
chomp($lines);
if ($lines eq '') {return undef; }
return $lines;
}
sub parse_group
{
my $userGidNumber = shift;
if ($userGidNumber =~ /[^\d]/ ) {
my $gname = $userGidNumber;
my $gidnum = getgrnam($gname);
if ($gidnum !~ /\d+/) {
return -1;
} else {
$userGidNumber = $gidnum;
}
} elsif (!defined(getgrgid($userGidNumber))) {
return -2;
}
return $userGidNumber;
}
sub group_remove_member
{
my ($group, $user) = @_;
my $members='';
my $grp_line = get_group_dn($group);
if (!defined($grp_line)) {
return 0;
}
my $ldap = Net::LDAP->new($slaveLDAP) or die "erreur LDAP";
$ldap->bind ;
my $mesg = $ldap->search ( base => $groupsdn,
scope => $scope,
filter => "(&(objectclass=posixgroup)(cn=$group))"
);
$mesg->code && die $mesg->error;
foreach my $entry ($mesg->all_entries){
foreach my $attr ($entry->attributes)
{
if ($attr=~/\bmemberUid\b/){
foreach my $ent($entry->get_value($attr)) {
$members.= $attr.": ".$ent."\n";
}
}
}
}
$ldap->unbind;
$members =~ s/memberUid: $user\n//;
chomp($members);
my $header;
if ($members eq '') {
$header = "changetype: modify\n";
$header .= "delete: memberUid";
} else {
$header = "changetype: modify\n";
$header .= "replace: memberUid";
}
my $tmpldif =
"$grp_line
$header
$members
";
die "$0: error while modifying group $group\n"
unless (do_ldapmodify($tmpldif) == 0);
undef $tmpldif;
$ldap->unbind;
return 1;
}
sub group_get_members
{
my ($group) = @_;
my $members;
my @resultat;
my $grp_line = get_group_dn($group);
if (!defined($grp_line)) { return 0; }
my $ldap = Net::LDAP->new($slaveLDAP) or die "erreur LDAP";
$ldap->bind ;
my $mesg = $ldap->search ( base => $groupsdn,
scope => $scope,
filter => "(&(objectclass=posixgroup)(cn=$group))"
);
$mesg->code && die $mesg->error;
foreach my $entry ($mesg->all_entries){
foreach my $attr ($entry->attributes){
if ($attr=~/\bmemberUid\b/){
foreach my $ent($entry->get_value($attr)) { push (@resultat,$ent); }
}
}
}
return @resultat;
}
sub file_write {
my ($filename, $filecontent) = @_;
local *FILE;
open (FILE, "> $filename") ||
die "Cannot open $filename for writing: $!\n";
print FILE $filecontent;
close FILE;
}
sub do_ldapadd2
{
my $ldif = shift;
my $tempfile = "/tmp/smbldapadd.$$";
file_write($tempfile, $ldif);
my $rc = system "$ldapadd < $tempfile >/dev/null";
unlink($tempfile);
return $rc;
}
sub do_ldapadd
{
my $ldif = shift;
my $FILE = "|$ldapadd >/dev/null";
open (FILE, $FILE) || die "$!\n";
print FILE <<EOF;
$ldif
EOF
;
close FILE;
my $rc = $?;
return $rc;
}
sub do_ldapmodify2
{
my $ldif = shift;
my $tempfile = "/tmp/smbldapmod.$$";
file_write($tempfile, $ldif);
my $rc = system "$ldapmodify -r < $tempfile >/dev/null";
unlink($tempfile);
return $rc;
}
sub do_ldapmodify
{
my $ldif = shift;
my $FILE = "|$ldapmodify -r >/dev/null";
open (FILE, $FILE) || die "$!\n";
print FILE <<EOF;
$ldif
EOF
;
close FILE;
my $rc = $?;
return $rc;
}
1;