>From 0b45b3d488471cd6b55c425271154c6f49830dd8 Mon Sep 17 00:00:00 2001 From: Nathan Kinder Date: Wed, 28 Oct 2009 18:18:49 -0700 Subject: [PATCH] Bug 529258 - Make upgrade remove obsolete schema from 99user.ldif Due to a previously fixed bug (bz 474254), standard schema may have been duplicated in 99user.ldif. When running an upgrade, we need to check the 99user.ldif file to see if any obsolete standard schema is defined there and remove it. This patch makes upgrade backup the original 99user.ldif, and scans it to see if any of the obsolete attributeTypes or objectClasses attributes that we are removing from the standard schema exist in 99user.ldif. We trim the obsolete definitions and write out a new 99user.ldif with the proper permissions. --- ldap/admin/src/scripts/60upgradeschemafiles.pl | 137 +++++++++++++++++++++++- ldap/admin/src/scripts/setup-ds.res.in | 2 + 2 files changed, 138 insertions(+), 1 deletions(-) diff --git a/ldap/admin/src/scripts/60upgradeschemafiles.pl b/ldap/admin/src/scripts/60upgradeschemafiles.pl index c1b1bb7..0cf4a98 100644 --- a/ldap/admin/src/scripts/60upgradeschemafiles.pl +++ b/ldap/admin/src/scripts/60upgradeschemafiles.pl @@ -1,4 +1,5 @@ +use Mozilla::LDAP::LDIF; use DSCreate qw(installSchema); sub runinst { @@ -12,6 +13,14 @@ sub runinst { # them with newer versions my @toremove = qw(00core.ldif 01core389.ldif 01common.ldif 02common.ldif 05rfc2247.ldif 10presence.ldif 28pilot.ldif 30ns-common.ldif 50ns-directory.ldif 60mozilla.ldif); + # these hashes will be used to check for obsolete schema + # in 99user.ldif + my %attrsbyname; + my %attrsbyoid; + my %objclassesbyname; + my %objclassesbyoid; + my $userschemaentry; + # make a backup directory to store the deleted schema, then # don't really delete it, just move it to that directory my $mode = (stat($inf->{slapd}->{schema_dir}))[2]; @@ -36,7 +45,126 @@ sub runinst { } } - if (@errs) { # errors backing up schema + # Remove obsolete schema from 99user.ldif. Compare by name and OID. + if (!open( OLDUSERSCHEMA, $inf->{slapd}->{schema_dir} . "/99user.ldif")) { + push @errs, ["error_reading_schema_file", $inf->{slapd}->{schema_dir} . "/99user.ldif", $!]; + } else { + my $olduserschema = new Mozilla::LDAP::LDIF(*OLDUSERSCHEMA); + + # Find the cn=schema entry. + while ($userschemaentry = readOneEntry $olduserschema) { + my $dn = $userschemaentry->getDN(); + # The only entry should be cn=schema, but best to play it safe. + next if ($dn ne "cn=schema"); + + # create the attributeTypes hashes (name->value, oid->value) + my @attrtypes = $userschemaentry->getValues("attributeTypes"); + foreach my $attrtype (@attrtypes) { + # parse out the attribute name and oid + if ($attrtype =~ /^\(\s*([\d\.]+)\s+NAME\s+'(\w+)'/) { + # normalize the attribute name + $attrsbyname{lc "$2"} = "$attrtype"; + $attrsbyoid{"$1"} = "$attrtype"; + } + } + + # create the objectClasses hashes (name->value, oid->value) + my @objclasses = $userschemaentry->getValues("objectClasses"); + foreach my $objclass (@objclasses) { + # parse out the objectclass name and oid + if ($objclass =~ /^\(\s*([\d\.]+)\s+NAME\s+'(\w+)'/) { + # normalize the objectclass name + $objclassesbyname{lc "$2"} = "$objclass"; + $objclassesbyoid{"$1"} = "$objclass"; + } + } + + # We found the cn=schema entry, so there's no need + # to look for more entries. + last; + } + + close OLDUSERSCHEMA; + } + + for my $file (@toremove) { + my $fullname = "$bakdir/$file"; + + next if (! -f $fullname); # does not exist - skip - already (re)moved + + if (!open( OBSOLETESCHEMA, "$fullname")) { + push @errs, ["error_reading_schema_file", $fullname, $!]; + } else { + my $obsoleteschema = new Mozilla::LDAP::LDIF(*OBSOLETESCHEMA); + + # Find the cn=schema entry. + while (my $entry = readOneEntry $obsoleteschema) { + my $dn = $entry->getDN(); + # The only entry should be cn=schema, but best to play it safe. + next if ($dn ne "cn=schema"); + + # Check if any of the attributeTypes in this file + # are defined in 99user.ldif and remove them if so. + my @attrtypes = $entry->getValues("attributeTypes"); + foreach $attrtype (@attrtypes) { + # parse out the attribute name and oid + if ($attrtype =~ /^\(\s*([\d\.]+)\s+NAME\s+'(\w+)'/) { + # normalize the attribute name + if ($attrsbyname{lc "$2"}) { + $userschemaentry->removeValue("attributeTypes", $attrsbyname{lc "$2"}); + } elsif ($attrsbyoid{"$1"}) { + $userschemaentry->removeValue("attributeTypes", $attrsbyoid{"$1"}); + } + } + } + + # Check if any of the objectClasses in this file + # are defined in 99user.ldif and remove them if so. + my @objclasses = $entry->getValues("objectClasses"); + foreach $objclass (@objclasses) { + # parse out the objectclass name and oid + if ($objclass =~ /^\(\s*([\d\.]+)\s+NAME\s+'(\w+)'/) { + # normalize the objectclass name + if ($objclassesbyname{lc "$2"}) { + $userschemaentry->removeValue("objectClasses", $objclassesbyname{lc "$2"}); + } elsif ($objclassesbyoid{"$1"}) { + $userschemaentry->removeValue("objectClasses", $objclassesbyoid{"$1"}); + } + } + } + } + + close OBSOLETESCHEMA; + } + } + + # Backup the original 99user.ldif + $! = 0; # clear + rename $inf->{slapd}->{schema_dir} . "/99user.ldif", "$bakdir/99user.ldif"; + if ($!) { + push @errs, ["error_renaming_schema", $inf->{slapd}->{schema_dir} . "/99user.ldif", "$bakdir/99user.ldif", $!]; + } + + # Write the new 99user.ldif + if (!open ( NEWUSERSCHEMA, ">" . $inf->{slapd}->{schema_dir} . "/99user.ldif")) { + push @errs, ["error_writing_schema_file", $inf->{slapd}->{schema_dir} . "/99user.ldif", $!]; + } else { + my $newuserschema = new Mozilla::LDAP::LDIF(*NEWUSERSCHEMA); + writeOneEntry $newuserschema $userschemaentry; + close NEWUSERSCHEMA; + + # Set permissions based off of the original 99user.ldif. + my @stat = stat("$bakdir/99user.ldif"); + my $mode = $stat[2]; + my $uid = $stat[4]; + my $gid = $stat[5]; + chmod $mode, $inf->{slapd}->{schema_dir} . "/99user.ldif"; + chown $uid, $gid, $inf->{slapd}->{schema_dir} . "/99user.ldif"; + } + + # If we've encountered any errors up to this point, restore + # the original schema. + if (@errs) { # restore the original schema files for my $file (@toremove) { my $oldname = "$bakdir/$file"; @@ -45,6 +173,13 @@ sub runinst { next if (-f $newname); # not removed rename $oldname, $newname; } + + # Restore 99user.ldif. We overwrite whatever is there since + # it is possible that we have modifed it. + if (-f "$bakdir/99user.ldif") { + rename "$bakdir/99user.ldif", $inf->{slapd}->{schema_dir} . "/99user.ldif"; + } + return @errs; } diff --git a/ldap/admin/src/scripts/setup-ds.res.in b/ldap/admin/src/scripts/setup-ds.res.in index 57e7654..af9080d 100644 --- a/ldap/admin/src/scripts/setup-ds.res.in +++ b/ldap/admin/src/scripts/setup-ds.res.in @@ -176,7 +176,9 @@ update_admin_dialog = Please specify the authentication data for '%s'\n\n update_admin_id_prompt = Full DN of administrative user update_admin_pwd_prompt = Password for this user error_renaming_schema = Could not rename schema file '%s' tp '%s'. Error: %s\n +error_reading_schema_file = Schema file '%s' does not exist or is not readable. Error: %s\n error_reading_schema_dir = Schema directory '%s' does not exist or is not readable\n +error_writing_schema_file = Schema file '%s' could not be opened for writing. Error: %s\n error_online_update = Could not open a connection to the server at %s port %s as '%s'.\ Please make sure the server is up and running before using online mode,\ or use offline mode.\n\n -- 1.6.2.5