249 lines
7.9 KiB
Perl
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);
|