Package: slapd
Version: 2.2.23-0.pre5
Severity: wishlist
Tags: patch


-- System Information:
Debian Release: 3.1
  APT prefers unstable
  APT policy: (500, 'unstable'), (1, 'experimental')
Architecture: i386 (i686)
Kernel: Linux 2.6.9-timotheus
Locale: LANG=C, [EMAIL PROTECTED]

Versions of packages slapd depends on:
ii  coreutils [fileutils]      5.2.1-2       The GNU core utilities
ii  debconf                    1.4.38        Debian configuration management sy
ii  fileutils                  5.2.1-2       The GNU file management utilities 
ii  libc6                      2.3.2.ds1-17  GNU C Library: Shared libraries an
ii  libdb4.3                   4.3.27-2      Berkeley v4.3 Database Libraries [
ii  libiodbc2                  3.52.2-3      iODBC Driver Manager
ii  libldap-2.2-7              2.2.23-0.pre5 OpenLDAP libraries
ii  libltdl3                   1.5.6-2       A system independent dlopen wrappe
ii  libperl5.8                 5.8.4-2.3     Shared Perl library
ii  libsasl2                   2.1.19-1.3    Authentication abstraction library
ii  libslp1                    1.0.11-7      OpenSLP libraries
ii  libssl0.9.7                0.9.7d-5      SSL shared libraries
ii  libwrap0                   7.6.dbs-6     Wietse Venema's TCP wrappers libra
ii  perl [libmime-base64-perl] 5.8.4-2.3     Larry Wall's Practical Extraction 
ii  psmisc                     21.5-1        Utilities that use the proc filesy

-- debconf information:
  slapd/fix_directory: true
* shared/organization: schuldei.com
  slapd/upgrade_slapcat_failure:
  slapd/backend: BDB
* slapd/allow_ldap_v2: false
  slapd/no_configuration: false
  slapd/move_old_database: true
  slapd/suffix_change: false
  slapd/slave_databases_require_updateref:
  slapd/autoconf_modules: true
* slapd/domain: schuldei.com
  slapd/password_mismatch:
  slapd/invalid_config: true
* slapd/upgrade_slapadd_failure:
  slapd/purge_database: false
  slapd/admin:




--- /usr/share/slapd/fix_ldif   2004-07-27 08:07:49.000000000 +0200
+++ fix_ldif.orig.pl    2004-08-18 22:43:57.000000000 +0200
@@ -2,6 +2,9 @@
 # Copyright (c) Dave Horsfall.
 # All rights reserved.
 # 
+# extended and rewritten by Andreas Schuldei
+# for debian(-edu)
+# 
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
 # are met:
@@ -113,9 +116,22 @@
 use Data::Dumper;
 use Getopt::Long;
 use MIME::Base64;
+use strict;
+use diagnostics;
 
 my $origDN = '.origDN';        # Attribute stores original DN
 
+# the command line options
+
+my ($opt_dump, $opt_fix, $opt_inheritance, $opt_suffix, $opt_write,
+    $opt_no_auth, $opt_org);
+
+# some big hashes
+my (%entries, %schema, @single);
+
+my $suffix;
+
+
 &parse_options;
 $opt_write = 1 if $opt_fix;
 
@@ -128,6 +144,7 @@
     my $dn = shift @_;
     # Check if base64 encoded
     next if ! $dn =~ /^dn::? /i;
+    my $encoded;
     if($dn =~ /^dn:: /i) {
       $dn =~ s/dn:: (.*)/$1/;
       $dn = decode_base64($dn);
@@ -155,16 +172,15 @@
     # Extract the first component (the RDN)
     # for later tests.
     #
-    ($rdn, undef) = split(/,/, $cdn);
-    ($rdnattr, $rdnval) = split(/=/, $rdn);
+    my ( $rdn, undef ) = split ( /,/, $cdn );
+    my ( $rdnattr, $rdnval ) = split ( /=/, $rdn );
 
     #
     # Get the attributes/values.
     # Attributes are low-cased.
     #
-    for (@_)
-    {
-       ($attr, $val) = split(/\s/, $_, 2);     # In case of "::"
+    for (@_) {
+        my ( $attr, $val ) = split ( /\s/, $_, 2 );    # In case of "::"
        $attr =~ s/://;
        if ($attr =~ /:/)                       # Must be binary (base-64)
        {
@@ -248,46 +264,150 @@
     }
 
     #
-    # Check the objectclass inheritance.
+    # Check the objectclass inheritance and hirarcy.
     #
     if ($opt_inheritance)      # Will soon be mandatory
     {
-       foreach my $i (@{$entries{$cdn}{"objectclass"}})
-       {
+       my $obj_ref = objlist2hash( $entries{$cdn}{'objectclass'} );
+       $obj_ref->{top} = 1 # it might be that top is not there yet. 
+           unless $obj_ref->{alias};
+
+       # remove unknown object classes
+       foreach my $i ( keys %$obj_ref ) {
            next if $i eq "top";        # top is topless :-)
-           if (!defined $sup{$i})
-           {
+            unless ( $schema{objectclass}{$i} ) {
+               # check if objectclass is known in the first place
                print STDERR "dn: $dn\nUnknown objectclass: \"$i\"";
                if ($opt_fix)
                {
                    print STDERR "; ignored";
-                   &remove($i, [EMAIL PROTECTED]"objectclass"}});
+                    delete $obj_ref->{$i};
                }
                print STDERR "\n\n";
            }
-           if (defined $sup{$i} &&
-               !&present($sup{$i}, [EMAIL PROTECTED]"objectclass"}}))
-           {
-               print STDERR "dn: $dn\nNo sup for \"$i\": \"$sup{$i}\"";
-               if ($opt_fix)
-               {
+       }
+       
+       #
+        # check if we have one and only one structural 
+       # object class and remove superfluous object classes.
+       #
+       my %structural_objectclasses;
+       foreach my $i ( keys %$obj_ref ) {      
+           next if $i eq "top";    # top is topless :-)
+           
+           if ( $schema{objectclass}{$i}{structural} ) {
+               $structural_objectclasses{$i}=1;
+           }
+       }
+       if  (1 < scalar keys %structural_objectclasses ) {
+           print STDERR "dn: $dn\nMore then one structural objectclass:";
+           for my $structural_objectclass ( keys %structural_objectclasses ) {
+               print STDERR " \"$structural_objectclass\"";
+           }
+           print STDERR ".";
+           my $removable_objectclasses_ref = 
+               resolve_structural_clash ( \%structural_objectclasses, 
$entries{$cdn} );
+           if ($opt_fix) {
+               print STDERR " Removing ";
+               for my $obj_class ( @$removable_objectclasses_ref ) {
+                   print STDERR " \"$obj_class\"";
+                   delete $obj_ref->{$obj_class};
+               }
+               print STDERR ".\n\n";
+           }
+       }
+       #
+       # Now we find and add missing superior objectclasses
+       #
+       foreach my $i ( keys %$obj_ref ) {      
+           next if $i eq "top";    # top is topless :-)
+           for my $sup ( @{ $schema{objectclass}{$i}{sup} } ) {
+               unless ( $obj_ref->{$sup} ) {
+                   print STDERR "dn: $dn\nNo sup for \"$i\"";
+                   if ($opt_fix) {
                    print STDERR "; inserted";
-                   push @{$entries{$cdn}{"objectclass"}}, $sup{$i};
+                       $obj_ref->{$sup} = 1;
                }
                print STDERR "\n\n";
            }
-       } # each objectclass
-    } # inheritance
+           }    
+       } 
 
     #
-    # Check required attributes.
-    # Can't do in above loop, because the keys
-    # may have changed from inserting new classes.
+       # see if all mandatory attributes are there
     #
-    foreach my $i (@{$entries{$cdn}{"objectclass"}})
-    {
-       &checkattrs($cdn, $i);
+       my %must;
+       for my $i ( keys %$obj_ref ) {  
+           next if $i eq "top";    # top is topless :-)
+           
+           for my $attrib_must ( @{ $schema{objectclass}{$i}{must} } ) {
+               $must{ $attrib_must } = 1;
+           }
+       }
+       my %must_missing;
+      MUST:
+       for my $i ( keys %must ) {
+           next if ($i eq "cn"            or # there is no schema entry for cn!
+                    $i eq "objectclass");    # or for objectclass
+           for my $name ( @{ $schema{attributetype}{$i}{names} } ) {
+               next MUST if $entries{$cdn}{$name};
+           }
+           $must_missing{$i} = 1;
+       }
+       for my $i ( keys %must_missing ) {
+           print STDERR "dn: $dn\nAttribut \"$i\": mandatory but missing";
+           if ($opt_fix) {
+               print STDERR "; inserted";
+               $entries{$cdn}{$i} = [ "" ]; # FIXME: figure out proper syntax
+           }
+           print STDERR "\n\n";
+       }
+
+       # see if any attributes are orphans
+       # everything is allowed with extensibleobject. skip this case
+       unless ( $obj_ref->{extensibleobject} ) { 
+
+           my %attrib_all = %must;
+           foreach my $i ( keys %$obj_ref ) {
+               
+               next if $i eq "top";    # top is topless :-)
+               
+               for my $attrib_may ( @{ $schema{objectclass}{$i}{may} } ) {
+                   $attrib_all{ $attrib_may } = 1;
+               }
+           }
+           my %attrib_orphan;
+           for my $attrib ( keys %{ $entries{$cdn} } ) {
+               next if ".origDN"     eq $attrib or
+                   "encoded"         eq $attrib or
+                   "objectclass"     eq $attrib or
+                   "creatorsname"    eq $attrib or
+                   "createtimestamp" eq $attrib or
+                   "modifiersname"   eq $attrib or
+                   "modifytimestamp" eq $attrib or
+                   "cdn"             eq $attrib or
+                   "dn"              eq $attrib;
+               unless ( $attrib_all{ $attrib } ) {
+                   $attrib_orphan{ $attrib } = 1;
+               }
+           }
+           for my $i ( keys %attrib_orphan ) {
+               print STDERR "dn: $dn\nAttribut \"$i\": is not part of 
objectclasses";
+               for my $objclss ( keys %$obj_ref) {
+                   print STDERR  " \"$objclss\""; 
+               }
+               if ($opt_fix) {
+                   print STDERR "; removed";
+                   delete $entries{$cdn}{$i}; 
     }
+               print STDERR "\n\n";
+           }
+       } # extensibleobject.
+       # at this point we should have an entry with all needed sups, nicely 
cleand up 
+       objhash2list( $entries{$cdn}{objectclass} , $obj_ref ); # back to the 
old format
+    } # inheritance
+
+    
 } # main loop
 
 #
@@ -312,11 +432,16 @@
 
     # Fix up the suffix dn if it's our mess, adding a structural objectclass.
     if ($thisdn eq &canon($suffix)) {
-       if (@{$entries{$thisdn}{'objectclass'}} == 1
-           && lc $entries{$thisdn}{'objectclass'}[0] eq 'dcobject')
-       {
-               if (defined($opt_org))
+       my $obj_ref = objlist2hash( $entries{$thisdn}{'objectclass'} );
+       if ( ( 1 == keys %$obj_ref  
+              and $obj_ref->{dcobject} )
+            or 
+            ( 2 == keys %$obj_ref  
+              and $obj_ref->{dcobject} 
+              and $obj_ref->{top} )
+            )
                {
+            if ( defined($opt_org) ) {
                        push(@{$entries{$thisdn}{'objectclass'}}, 
'organization');
                        push(@{$entries{$thisdn}{'o'}}, $opt_org);
                } else {
@@ -361,34 +486,6 @@
 }
 
 #
-# Check required attributes.
-#
-sub checkattrs
-{
-    (my $dn, $class) = @_;
-    foreach my $attr (@{$reqd{lc $class}})
-    {
-       if (!defined @{$entries{$dn}{lc $attr}})
-       {
-           my $odn = $entries{$dn}{$origDN};
-           print STDERR "dn: $odn\nMissing reqd \"$class\" attr \"$attr\"";
-           if ($opt_fix)
-           {
-               # Quick hack for CI
-               my $fix = "UNKNOWN";
-               if ($attr eq "cn" && $fix ne "")
-               {
-                   $fix = $entries{$dn}{"givenname"}[0];
-               }
-               push @{$entries{$dn}{$attr}}, $fix;
-               print STDERR "; inserted \"$fix\"";
-           }
-           print STDERR "\n\n";
-       }
-    }
-}
-
-#
 # Write an entry to standard output.
 #
 # Ought to wrap at 78 cols as well.
@@ -398,110 +495,35 @@
     my ($dn) = @_;
     my $odn = $entries{$dn}{$origDN};
     if ($entries{$dn}{"encoded"} == 1) {
-      $encoded = encode_base64($odn,"");
+      my $encoded = encode_base64( $odn, "" );
       print "dn:: $encoded\n";
     } else {
       print "dn: $odn\n";
     }
-    foreach my $attr (keys %{$entries{$dn}})
-    {
-       next if $attr eq $origDN;
-       foreach my $value (@{$entries{$dn}{$attr}})
-       {
+    foreach my $attr ( keys %{ $entries{$dn} } ) {
+        next if $attr eq $origDN or $attr eq "encoded" ;
+        foreach my $value ( @{ $entries{$dn}{$attr} } ) {
            print "$attr:";
-           if ($attr =~ /userpassword/i
-               || $value =~ /(^[ :]|[\x00-\x1f\x7f-\xff])/)
+
+            if ( defined $value and ( $attr =~ /userpassword/i
+                || $value =~ /(^[ :]|[\x00-\x1f\x7f-\xff])/ )  )
            {
                print ": ", &enmime($value, "");
            }
-           else
-           {
+            elsif ( defined $value and "" ne $value) { 
                print " $value";
            }
            print "\n";
-       }
-    }
-    print "\n";
-}
 
-#
-# Test for presence of element in list.
-#
-sub present
-{
-    my ($element, $list) = @_;
-    my $found = 0;
-
-    foreach my $i (@$list)
-    {
-        if ($i eq $element)
-        {
-            $found = 1;
-            last;
-        }
-    }
-    return $found;
-}
-
-#
-# Remove specified element from list.
-# It's a unique element, but multiple
-# occurances will be removed.  It will
-# change the order of the list.
-#
-sub remove
-{
-    my ($element, $list) = @_;
-
-    for (my $i = 0; $i < @$list; $i++)
-    {
-        if ($element eq @$list[$i])
-        {
-           @$list[$i] = @$list[$#$list];
-            pop @$list;
         }
     }
+    print "\n";
 }
 
-#
-# Initialise some stuff (automatically called).
-#
-sub INIT
-{
-    #
-    # Initialise the superior objectclasses.
-    # Ought to get this from the schema.
-    #
-    $sup{"dcObject"} = "top";
-    $sup{"inetOrgPerson"} = "organizationalPerson";
-    $sup{"organizationalPerson"} = "person";
-    $sup{"organizationalRole"} = "top";
-    $sup{"organizationalUnit"} = "top";
-    $sup{"person"} = "top";
-    $sup{"posixAccount"} = "top";
-    $sup{"room"} = "top";
-    $sup{"simpleSecurityObject"} = "top";
+sub INIT {
 
-    #
-    # These are incomplete/wrong/WIP.
-    #
-    $sup{"ciAdministrator"} = "top";
-    $sup{"ciApplication"} = "top";
-    $sup{"ciEmployee"} = "inetOrgPerson";
-    $sup{"ciLdapConfig"} = "top";
-    $sup{"ciPrinter"} = "top";
-    $sup{"ciServer"} = "top";
-
-    #
-    # Required attributes.
-    #
-    $reqd{"person"} = [ "sn", "cn" ];  # Special - can be autofixed
-    $reqd{"ciadministrator"} = [ "uid", "userPassword" ];
-    $reqd{"ciapplication"} = [ "ciApp", "ciAppType", "ciHost", "ciStatus", 
"ciPortNum" ];
-    $reqd{"ciemployee"} = [ "employeeNumber", "sn" ];
-    $reqd{"cildapconfig"} = [ "ciHost" ];
-    $reqd{"ciprinter"} = [ "ciPrinterName" ];
-    $reqd{"ciserver"} = [ "name" ];
+    my $schema_ref = parse_schemas();
+    %schema = %$schema_ref;
 
     #
     # Single-value attributes.
@@ -624,3 +646,299 @@
     }
     return $res;
 }
+
+sub read_config {
+    my ($file) = @_;
+    
+    open CONFIG,   "<  $file"  or die "can't open $file: $!";
+
+    my %config;
+    while ( <CONFIG> ) {
+       chomp;
+       s/\#.*//;
+       s/^\s+//;
+       s/\s+$//;
+       next unless length;
+       my ($var, $value) = split(/\s*=\s*/, $_, 2);
+       $config{$var} = $value;
+    }
+    
+    close CONFIG;
+    
+    return \%config;
+}
+
+sub read_slapd_config {
+    my ($file) = @_;
+    
+    open CONFIG,   "<  $file"  or die "can't open $file: $!";
+
+    my $seperator = $/; # save the seperator since it is non-standard
+    undef $/;
+    my $whole_file =  <CONFIG>; # sluuuurp
+    $whole_file =~ s/\n(?!\n)\s+/ /g; # merge logical line as the ldap config 
parser does
+    $/= $seperator; # restore the original line seperator;
+
+    my @whole_file = split (/\n/, $whole_file);
+
+
+    my %config;
+    while ( @whole_file ) {
+       $_ = pop @whole_file;
+       chomp;
+       s/\#.*//;
+       s/^\s+//;
+       s/\s+$//;
+       next unless length;
+       my ($var, $value) = split(/\s+/, $_, 2);
+       push @{ $config{$var} }, $value; 
+
+       # this does not keep the order of the configuration easily
+       # accessable, which is bad for things like databases and
+       # suffixes but does not matter for the include lines of the
+       # schemas. With some efford one could pirce together the order
+       # by getting it from the order in the anonymous arrays.
+
+    }
+    
+    close CONFIG;
+    
+    return \%config;
+}
+
+sub extract_system_schemas {
+    my ($core_schema, $schema_raw_ref) = @_;
+
+    while ( $core_schema ) {
+       $core_schema =~ s/^.*?\n\# system schema\n\#(.*?\))(\n\n.*)$/$2/s;
+       last unless $1;
+       my $core_def = $1;
+       $core_def =~ s/\n(?!\n)\#\s+/ /g;
+       chomp $core_def;
+       $core_def =~s/^\s+//;
+       $core_def =~s/\s+$//;
+       next unless length $core_def;
+       push @$schema_raw_ref, "$core_def\n"; 
+    }
+}
+
+sub read_schema {
+    my ($file) = @_;
+    
+    open SCHEMA,   "<  $file"  or die "can't open $file: $!";
+
+    my $seperator = $/; # save the seperator since it is non-standard
+    undef $/;
+    my $whole_file =  <SCHEMA>; # sluuuurp
+
+    my @schema_raw;    
+    if ($file eq "/etc/ldap/schema/core.schema") {
+       # There are some system schema entries which are hard coded
+       # into openLdap.  They are marked "system schema" in the
+       # core.schema. we try to detect them and remove the comments
+       # in front of those.
+       extract_system_schemas( $whole_file, [EMAIL PROTECTED]);
+       
+    }
+
+    $whole_file =~ s/\n(?!\n)\s+/ /g; 
+    # this is dubious, since we should watch not lines starting with 
+    # whitespaces but balance the parantecies. but this works well.
+    $/= $seperator; # restore the original line seperator;
+
+    
+    my @whole_file = split (/\n/, $whole_file);
+
+    
+    while ( @whole_file ) {
+       $_ = pop @whole_file;
+       chomp;
+       s/\#.*//;
+       s/^\s+//;
+       s/\s+$//;
+       next unless length;
+       push @schema_raw, "$_\n"; 
+    }
+    
+    close SCHEMA;
+    return [EMAIL PROTECTED];
+}
+
+
+sub find_slapd_config {
+
+    my $defaults = "/etc/default/slapd";
+    my $slapd_defaults_ref;
+    
+    if ( -f $defaults ) {
+       $slapd_defaults_ref = read_config( $defaults ); 
+    }
+
+    unless ( $slapd_defaults_ref->{SLAPD_CONF} and 
+        -f $slapd_defaults_ref->{SLAPD_CONF} ) 
+    {
+       $slapd_defaults_ref->{SLAPD_CONF} = "/etc/ldap/slapd.conf";
+    }
+       
+    return $slapd_defaults_ref->{SLAPD_CONF};
+
+}
+
+sub parse_slapd_config {
+    
+    my ($slapd_config_file) = @_;
+    
+    my $slapd_config_href = read_slapd_config( $slapd_config_file );
+    
+    return $slapd_config_href;
+}
+
+sub find_active_schemas {
+    my ($slapd_config_href) = @_;
+
+    return [EMAIL PROTECTED] $slapd_config_href->{include} }; 
+}
+sub preprocess_schemas {
+    my ( $schemas_list_ref ) = @_;
+    
+    my @schemas_raw;
+    
+    for my $file ( @{$schemas_list_ref} ) {
+       push @schemas_raw, @{ read_schema( $file ) }; 
+    }
+    return [EMAIL PROTECTED];
+}
+
+sub get_used_schemas {
+
+    my $slapd_config_path = find_slapd_config();
+    my $slapd_config_href = parse_slapd_config( $slapd_config_path );
+    my $schemas_list_aref = find_active_schemas( $slapd_config_href );
+    my $schemas_raw_aref = preprocess_schemas( $schemas_list_aref );
+    return $schemas_raw_aref;
+}
+
+sub parse_schemas {
+
+    my $schemas_raw_aref = get_used_schemas();
+    
+    my %schema;
+    while ( @$schemas_raw_aref ) {
+       $_= pop @$schemas_raw_aref;
+       chomp;
+
+       #poor man`s parser
+
+       my ( $type ) =
+           /^(\w+)\s/;
+       
+       my ( $structural ) = 
+           /^.*\s(STRUCTURAL)\s.*$/;
+       
+       my ( $auxiliary ) =     
+           /^.*\s(AUXILIARY)\s.*$/;
+       
+       my ( $description ) = 
+           /^.*\s+DESC\s+\'([^\']+)\'.*$/;
+
+       my ( $syntax ) =        
+           /^.*\s+SYNTAX\s+([\d\.\{\}]+).*$/;
+
+
+       my @names;
+       if ( /^.*\s+NAME\s+\(\s*\'([\w\s\']+)\'\s*\).*$/  ) {
+            @names = split(/\'\s+\'/, lc $1);
+       }
+       elsif ( /^.*\s+NAME\s+\'(\w+)\'\s.*$/ ) {
+           push @names, lc $1;
+       }
+       
+       my @sup;
+       if ( /^.*\s+SUP\s+\(\s*([^\)]+?)\s*\).*$/ ) {
+           @sup = split(/\s*\$\s*/, lc $1);
+       }
+       elsif ( /^.*\s+SUP\s+(\w+)\s.*$/ ) {
+           push @sup, lc $1;
+       }
+       
+       my @must;
+       if ( /^.*\s+MUST\s+\(\s*([^\)]+?)\s*\).*$/ ) {
+           @must = split(/\s*\$\s*/, lc $1);
+       }
+       elsif ( /^.*\s+MUST\s+(\w+)\s.*$/ ) {
+           push @must, lc $1 ;
+       }
+       
+       my @may;
+       if ( /^.*\s+MAY\s+\(\s*([^\)]+?)\s*\).*$/ ) {
+           @may = split(/\s*\$\s*/, lc $1);
+       }
+       elsif ( /^.*\s+MAY\s+(\w+)\s.*$/ ) {
+           push @may, lc $1 ;
+       }
+
+       unless ($type eq "attributetype" or 
+               $type eq "objectclass"   or 
+               @names ) 
+       {
+           print STDERR "$_\n"; 
+       }
+       else {
+           for my $name ( @names ) {
+               $name = lc $name;
+
+               $schema{$type}{$name}{names}       = [EMAIL PROTECTED];
+               $schema{$type}{$name}{description}= $description 
+                   if $description;
+               $schema{$type}{$name}{syntax}     = $syntax
+                   if $syntax;
+               $schema{$type}{$name}{structural} = 1
+                   if $structural;
+               $schema{$type}{$name}{auxiliary}  = 1
+                   if $auxiliary;
+               $schema{$type}{$name}{must}       = [EMAIL PROTECTED] 
+                   if @must;
+               $schema{$type}{$name}{may}        = [EMAIL PROTECTED]
+                   if @may;
+               $schema{$type}{$name}{sup}        = [EMAIL PROTECTED] 
+                   if @sup;
+           }
+       }
+    }
+    return \%schema;
+}
+
+sub objlist2hash {
+    my ($list_ref) = @_;
+    
+    my %objectclass;
+    for my $objclass ( @$list_ref ) {
+       $objclass = lc $objclass;
+       $objectclass{$objclass } = 1;
+    }
+    
+    return \%objectclass;
+}
+
+sub objhash2list {
+    my ($array_ref , $obj_hash_ref ) = @_;
+    
+    @$array_ref = keys %$obj_hash_ref;
+}
+
+sub resolve_structural_clash {
+    my ( $structural_objectclasses_ref, $entry_ref ) = @_;
+
+    my @removable_objectclasses;
+
+    # remove automountmap
+    # i dont know good heuristics to decide which one i 
+    # should remove, so this is hard coded.
+    # what other common cases are there?
+    if ($structural_objectclasses_ref->{automountmap}       and
+       $structural_objectclasses_ref->{organizationalunit} and 
+       2 == keys %$structural_objectclasses_ref ) {
+       push @removable_objectclasses, "automountmap";
+    }
+    return [EMAIL PROTECTED];
+}


-- 
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to