smeserver-ldap/root/etc/e-smith/events/actions/ldap-update-simple

249 lines
7.9 KiB
Perl

#!/usr/bin/perl -w
package esmith;
use strict;
use Errno;
use esmith::ConfigDB;
use esmith::AccountsDB;
use esmith::util;
use Net::LDAP;
use Date::Parse;
$ENV{'LANG'} = 'C';
$ENV{'TZ'} = '';
my $c = esmith::ConfigDB->open_ro;
my $a = esmith::AccountsDB->open_ro;
my $l = $c->get('ldap');
my $status = $l->prop('status') || "disabled";
unless ($status eq "enabled" )
{
warn "Not running action script $0, LDAP service not enabled!\n";
exit(0);
}
exit(0) if ($c->get('ldap')->prop('Authentication') || 'disabled') eq 'enabled';
my $domain = $c->get('DomainName')
|| die("Couldn't determine domain name");
$domain = $domain->value;
my $schema = '/etc/openldap/schema/samba.schema';
my $event = shift || die "Event name must be specified";
my @name = @ARGV;
die "Account name argument missing." unless scalar (@name) >= 1;
#------------------------------------------------------------
# Update LDAP database entry.
#------------------------------------------------------------
my $base = esmith::util::ldapBase ($domain);
my $pw = esmith::util::LdapPassword();
my $ldap = Net::LDAP->new('localhost')
or die "$@";
$ldap->bind(
dn => "cn=root,$base",
password => $pw
);
my @accounts;
my $account;
foreach my $name (@name)
{
$account = $a->get($name);
die "Account $name not found.\n" unless defined $account;
my $type = $account->prop('type') || "unknown";
die "Account $name is not a user, group, ibay, machine account; update LDAP entry failed.\n"
unless ($type =~ m{^(?:user|group|ibay|machine)$} or $name eq 'admin');
push @accounts, $account;
}
#------------------------------------------------------------
# Read all samba groups (can't do individual lookups)
#------------------------------------------------------------
my $groupmap = ();
# Only do if schema is found
if ( -f "$schema" and -x '/usr/bin/net' )
{
foreach (`/usr/bin/net groupmap list 2> /dev/null`){
chomp;
next if m{\(S-1-5-32-\d+\)};
$groupmap->{$3} = { name => "$1", sid => "$2" } if (/^(.*) \((S-.*-\d+)\) -> (.*)$/);
}
}
#------------------------------------------------------------
# Create a list of updates that need to happen
#------------------------------------------------------------
my $updates;
foreach my $acct (@accounts)
{
my $key = $acct->key;
my $type = $acct->prop('type');
my $desc = undef;
my $dn;
if ($type =~ m{^(?:user|group|ibay|machine)$} or $key eq 'admin')
{
#------------------------------------------------------------
# Do the user portion
#------------------------------------------------------------
if ($type eq 'machine')
{
$dn = "uid=$key,ou=Computers,$base";
}
else
{
$dn = "uid=$key,ou=Users,$base";
}
utf8::upgrade($dn);
# Read information from getent passwd
@{$updates->{$dn}}{'uid','userPassword'} = getpwnam($key);
unless ($updates->{$dn}->{uid})
{
delete $updates->{$dn};
next;
}
$updates->{$dn}->{userPassword} = "!*" if $updates->{$dn}->{userPassword} eq '!!';
$updates->{$dn}->{userPassword} =~ s/^/{CRYPT}/ unless $updates->{$dn}->{userPassword} =~ m/^{/;
# Samba parameters if we find the samba.schema
if ( -f "$schema" and -x '/usr/bin/pdbedit' )
{
my $line = `/usr/bin/pdbedit -wu '$key' 2> /dev/null`;
chomp($line);
if ($line)
{
@{$updates->{$dn}}{'junk','junk','sambaLMPassword','sambaNTPassword'} = split(/:/,$line);
foreach $line (`/usr/bin/pdbedit -vu '$key' 2> /dev/null`)
{
chomp($line);
$updates->{$dn}->{sambaSID} = $1 if $line =~ m{User SID:\s+(S-.*)$};
$updates->{$dn}->{displayName} = $1 if $line =~ m{Full Name:\s+(.*)$};
$updates->{$dn}->{sambaPrimaryGroupSID} = $1 if $line =~ m{Primary Group SID:\s+(S-.*)$};
$updates->{$dn}->{sambaAcctFlags} = $1 if $line =~ m{Account Flags:\s+(.*)$};
$updates->{$dn}->{sambaPwdLastSet} = str2time($1) if $line =~ m{Password last set:\s+(.*)$};
}
push @{$updates->{$dn}->{objectClass}}, 'sambaSamAccount';
}
else
{
$updates->{$dn}->{sambaLMPassword} = [];
$updates->{$dn}->{sambaNTPassword} = [];
$updates->{$dn}->{sambaSID} = [];
$updates->{$dn}->{displayName} = [];
$updates->{$dn}->{sambaPrimaryGroupSID} = [];
$updates->{$dn}->{sambaAcctFlags} = [];
$updates->{$dn}->{sambaPwdLastSet} = [];
}
}
}
}
endpwent();
#------------------------------------------------------------
# Do the group portion (only if we have samba)
#------------------------------------------------------------
if ( -f "$schema" )
{
foreach my $group ( (map { $_->key } $a->users), (map { $_->key } $a->groups), qw/admin nobody shared/ ){
my $dn = "cn=$group,ou=Groups,$base";
utf8::upgrade($dn);
if ( exists $groupmap->{$group} )
{
push @{$updates->{$dn}->{objectClass}}, 'sambaGroupMapping';
$updates->{$dn}->{displayName} = $groupmap->{$group}->{name};
$updates->{$dn}->{sambaSID} = $groupmap->{$group}->{sid};
$updates->{$dn}->{sambaGroupType} = '2';
}
else
{
$updates->{$dn}->{displayName} = [];
$updates->{$dn}->{sambaSID} = [];
$updates->{$dn}->{sambaGroupType} = [];
}
}
}
#------------------------------------------------------------
# Update LDAP database entry.
#------------------------------------------------------------
foreach my $dn (keys %$updates)
{
# Try and find record
my $result = $ldap->search( base => $dn, filter => '(objectClass=*)', scope => 'base' );
warn "failed looking up entry $dn: ", $result->error if $result->code && $result->code != 32;
my $code = $result->code;
my @objectClass = $code == 32 ? () : $result->entry(0)->get_value('objectClass');
# Clean up attributes and convert to utf8
delete $updates->{$dn}->{'junk'};
foreach my $attr ( keys %{$updates->{$dn}} )
{
if ( ref($updates->{$dn}->{$attr}) eq 'ARRAY' )
{
if ( $code == 32 and scalar(@{$updates->{$dn}->{$attr}}) == 0 )
{
delete $updates->{$dn}->{$attr};
}
else
{
for (my $c = 0; $c < scalar(@{$updates->{$dn}->{$attr}}); $c++)
{
utf8::upgrade($updates->{$dn}->{$attr}[$c]);
}
}
}
else
{
if ($updates->{$dn}->{$attr} !~ /^\s*$/)
{
utf8::upgrade($updates->{$dn}->{$attr});
}
elsif ( $code == 32 )
{
delete $updates->{$dn}->{$attr};
}
else
{
$updates->{$dn}->{$attr} = [];
}
}
}
# Perform insert or update
if ( $code == 32 )
{
$result = $ldap->add( $dn, attrs => [ %{$updates->{$dn}} ] );
$result->code && warn "failed to add entry $dn: ", $result->error;
}
else
{
# Don't overwrite objectClass (just update if necessary)
my $seen = ();
# Remove samba objectClasses if removing samba attributes
@{$seen}{'sambaSamAccount','sambaGroupMapping'} = (1,1) if ref($updates->{$dn}->{sambaSID}) eq 'ARRAY';
@{$updates->{$dn}->{objectClass}} = grep { ! $seen->{$_}++ } (@{$updates->{$dn}->{objectClass}}, @objectClass );
$result = $ldap->modify( $dn, replace => $updates->{$dn});
$result->code && warn "failed to modify entry $dn: ", $result->error;
}
}
$ldap->unbind;
exit (0);