[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: (ITS#6915) memberof+accesslog duplicate reqStart



This is a multi-part message in MIME format.
--------------050703040907090602090901
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

I figured I would share a workaround that I'm currently using for this 
issue which may be of help to others. I've disabled the memberOf overlay 
in slapd, and use an external script to populate memberOf on the master 
server, which then replicates to the consumer servers. I currently run 
this every 5 minutes from cron as follows:

memberof.pl --ldap

Regards,

	-Kartik

--------------050703040907090602090901
Content-Type: application/x-perl;
 name="memberof.pl"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="memberof.pl"

#! /usr/bin/perl

# Implements memberOf reverse mapping attributes -- workaround for when
# memberOf overlay isn't available

use Net::LDAP;
use Net::LDAP::LDIF;
use Authen::SASL;
use Fcntl qw(LOCK_EX LOCK_NB);
use Getopt::Long;

use strict;

my $basedn = "dc=example,dc=com";

my @attrs = qw(member manager);
# Note -- this filter properly excludes dynamic groupOfURLs groups
my $attrfilter = '(|' . join("", map { "($_=*)" } @attrs) . ')';
my %revattrs = (member => 'memberOf', manager => 'directReports');
my %fwattrs = reverse %revattrs;
my $revattrfilter = '(|' . join("", map { "($_=*)" } values %revattrs) . ')';
my (%entries, %reventries);

# Prevent multiple instances from running at the same time
open(LOCKFH, $0); flock(LOCKFH, LOCK_EX|LOCK_NB) or exit 1;

my ($generate_ldif, $update_ldap);
GetOptions('ldif' => \$generate_ldif, 'ldap' => \$update_ldap);

my $ldifout = Net::LDAP::LDIF->new('-', 'w');
$ldifout->{change} = 1;
my $ldap = Net::LDAP->new('ldapi://') or die "ldapi: $@\n";
my $sasl = Authen::SASL->new(mechanism => 'EXTERNAL');
my $sasl_client = $sasl->client_new('ldap', 'localhost');
$ldap->bind(undef, sasl => $sasl_client);

# Build %entries and %reventries maps
my $mesg = $ldap->search(base => $basedn,
						 filter => $attrfilter,
						 attrs => \@attrs);
$mesg->code && die($mesg->error . "\n");
foreach my $entry ($mesg->all_entries) {$entries{lc $entry->dn} = $entry }

$mesg = $ldap->search(base => $basedn,
						 filter => $revattrfilter,
						 attrs => [values %revattrs]);
$mesg->code && die($mesg->error . "\n");
foreach my $entry ($mesg->all_entries) { $reventries{lc $entry->dn} = $entry }

# Go through and generate updates for the reverse mapping attributes
my ($dn, $entry);
while (($dn, $entry) = each %entries) {
	foreach my $attr (@attrs) {
		my $revattr = $revattrs{$attr};
		foreach my $val ($entry->get_value($attr)) {
			$val = lc $val;
			if (!$reventries{$val}) {
				$reventries{$val} = Net::LDAP::Entry->new;
				$reventries{$val}->dn($val);
				$reventries{$val}->changetype('modify');
			}
			$reventries{$val}->add($revattr => $entry->dn)
				unless grep({ lc $_ eq $dn } 
							$reventries{$val}->get_value($revattr));
		}
	}
}
while (($dn, $entry) = each %reventries) {
	foreach my $revattr (values %revattrs) {
		foreach my $val ($entry->get_value($revattr)) {
			$val = lc $val;
			$reventries{$dn}->delete($revattr => $val)
				if !exists($entries{$val})
				|| !grep({ lc $_ eq $dn }
						 $entries{$val}->get_value($fwattrs{$revattr}));

		}
	}
	if ($entry->changes) {
		$ldifout->write_entry($entry) if $generate_ldif;
		if ($update_ldap) {
			my $modmesg = $entry->update($ldap);
			$modmesg->code && die("LDAP: " .$modmesg->error .  "\n");
		}
	}
}

--------------050703040907090602090901--