summaryrefslogtreecommitdiffstats
path: root/ldap/admin/src/scripts
diff options
context:
space:
mode:
authorcvsadm <cvsadm>2005-01-21 00:44:34 +0000
committercvsadm <cvsadm>2005-01-21 00:44:34 +0000
commitb2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch)
treecf58939393a9032182c4fbc4441164a9456e82f8 /ldap/admin/src/scripts
downloadds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.gz
ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.xz
ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.zip
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'ldap/admin/src/scripts')
-rw-r--r--ldap/admin/src/scripts/template-bak2db.pl89
-rwxr-xr-xldap/admin/src/scripts/template-cl-dump.pl307
-rw-r--r--ldap/admin/src/scripts/template-db2bak.pl89
-rw-r--r--ldap/admin/src/scripts/template-db2index.pl195
-rw-r--r--ldap/admin/src/scripts/template-db2ldif.pl215
-rw-r--r--ldap/admin/src/scripts/template-dsml-activate.pl198
-rw-r--r--ldap/admin/src/scripts/template-ldif2db.pl193
-rw-r--r--ldap/admin/src/scripts/template-migrate50to512778
-rw-r--r--ldap/admin/src/scripts/template-migrate5to63043
-rw-r--r--ldap/admin/src/scripts/template-migrate5to73043
-rw-r--r--ldap/admin/src/scripts/template-migrate6to73049
-rw-r--r--ldap/admin/src/scripts/template-migrateInstance5518
-rw-r--r--ldap/admin/src/scripts/template-migrateInstance6550
-rw-r--r--ldap/admin/src/scripts/template-migrateInstance7559
-rwxr-xr-xldap/admin/src/scripts/template-migrateTo53094
-rw-r--r--ldap/admin/src/scripts/template-migrateTo63268
-rw-r--r--ldap/admin/src/scripts/template-migrateTo73268
-rw-r--r--ldap/admin/src/scripts/template-ns-accountstatus.pl813
-rw-r--r--ldap/admin/src/scripts/template-ns-activate.pl813
-rw-r--r--ldap/admin/src/scripts/template-ns-inactivate.pl813
-rwxr-xr-xldap/admin/src/scripts/template-ns-newpwpolicy.pl241
-rwxr-xr-xldap/admin/src/scripts/template-repl-monitor-cgi.pl40
-rwxr-xr-xldap/admin/src/scripts/template-repl-monitor.pl956
-rw-r--r--ldap/admin/src/scripts/template-verify-db.pl196
24 files changed, 28328 insertions, 0 deletions
diff --git a/ldap/admin/src/scripts/template-bak2db.pl b/ldap/admin/src/scripts/template-bak2db.pl
new file mode 100644
index 00000000..10cb99bc
--- /dev/null
+++ b/ldap/admin/src/scripts/template-bak2db.pl
@@ -0,0 +1,89 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+sub usage {
+ print(STDERR "Usage: $0 [-v] -D rootdn { -w password | -w - | -j filename } \n");
+ print(STDERR " : -a dirname [-t dbtype]\n");
+ print(STDERR " Opts: -D rootdn - Directory Manager\n");
+ print(STDERR " : -w password - Directory Manager's password\n");
+ print(STDERR " : -w - - Prompt for Directory Manager's password\n");
+ print(STDERR " : -j filename - Read Directory Manager's password from file\n");
+ print(STDERR " : -a dirname - backup directory\n");
+ print(STDERR " : -t dbtype - database type (default: ldbm database)\n");
+ print(STDERR " : -v - verbose\n");
+}
+$taskname = "";
+$archivedir = "";
+$dbtype = "ldbm database";
+$dsroot = "{{DS-ROOT}}";
+$mydsroot = "{{MY-DS-ROOT}}";
+$verbose = 0;
+$rootdn = "";
+$passwd = "";
+$passwdfile = "";
+$i = 0;
+while ($i <= $#ARGV) {
+ if ("$ARGV[$i]" eq "-a") { # backup directory
+ $i++; $archivedir = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-D") { # Directory Manager
+ $i++; $rootdn = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-w") { # Directory Manager's password
+ $i++; $passwd = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-j") { # Read Directory Manager's password from a file
+ $i++; $passwdfile = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-t") { # database type
+ $i++; $dbtype = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-v") { # verbose
+ $verbose = 1;
+ } else {
+ &usage; exit(1);
+ }
+ $i++;
+}
+if ($passwdfile ne ""){
+# Open file and get the password
+ unless (open (RPASS, $passwdfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $passwd = <RPASS>;
+ chomp($passwd);
+ close(RPASS);
+} elsif ($passwd eq "-"){
+# Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $passwd = ReadLine(0);
+# chomp($passwd);
+# ReadMode('normal');
+}
+if ( $rootdn eq "" || $passwd eq "") { &usage; exit(1); }
+($s, $m, $h, $dy, $mn, $yr, $wdy, $ydy, $r) = localtime(time);
+$mn++; $yr += 1900;
+$taskname = "restore_${yr}_${mn}_${dy}_${h}_${m}_${s}";
+if ($archivedir eq "") {
+ &usage; exit(1);
+}
+$dn = "dn: cn=$taskname, cn=restore, cn=tasks, cn=config\n";
+$misc = "changetype: add\nobjectclass: top\nobjectclass: extensibleObject\n";
+$cn = "cn: $taskname\n";
+$nsarchivedir = "nsArchiveDir: $archivedir\n";
+$nsdbtype = "nsDatabaseType: $dbtype\n";
+$entry = "${dn}${misc}${cn}${nsarchivedir}${nsdbtype}";
+$vstr = "";
+if ($verbose != 0) { $vstr = "-v"; }
+chdir("$dsroot{{SEP}}shared{{SEP}}bin");
+open(FOO, "| $dsroot{{SEP}}shared{{SEP}}bin{{SEP}}ldapmodify $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
+print(FOO "$entry");
+close(FOO);
diff --git a/ldap/admin/src/scripts/template-cl-dump.pl b/ldap/admin/src/scripts/template-cl-dump.pl
new file mode 100755
index 00000000..fe89de2a
--- /dev/null
+++ b/ldap/admin/src/scripts/template-cl-dump.pl
@@ -0,0 +1,307 @@
+#{{PERL-EXEC}}
+
+################################################################################
+#
+# Copyright (C) 2002-2004 Netscape Communications Corporation.
+# All rights reserved.
+#
+# FILE: cl-dump.pl
+#
+# SYNOPSIS:
+#
+# cl-dump.pl [-h host] [-p port] [-D bind-dn] -w bind-password | -P bind-cert\
+# [-r replica-roots] [-o output-file] [-c] [-v]\n";
+#
+# cl-dump.pl -i changelog-ldif-file-with-base64encoding [-o output-file] [-c]\n";
+#
+# DESCRIPTION:
+# Dump and decode Netscape Directory Server replication change log
+#
+# OPTIONS:
+#
+# -c Dump and interpret CSN only. This option can be used with or
+# without -i option.
+#
+# -D bind-dn
+# Directory server's bind DN. Default to "cn=Directory Manager" if
+# the option is omitted.
+#
+# -h host
+# Directory server's host. Default to the server where the script
+# is running.
+#
+# -i changelog-ldif-file-with-base64encoding
+# If you already have a ldif-like changelog, but the changes
+# in that file are encoded, you may use this option to
+# decode that ldif-like changelog.
+#
+# -o output-file
+# Path name for the final result. Default to STDOUT if omitted.
+#
+# -p port
+# Directory server's port. Default to 389.
+#
+# -P bind-cert
+# Pathname of binding certificate DB
+#
+# -r replica-roots
+# Specify replica roots whose changelog you want to dump. The replica
+# roots may be seperated by comma. All the replica roots would be
+# dumped if the option is omitted.
+#
+# -v Print the version of this script.
+#
+# -w bind-password
+# Password for the bind DN
+#
+# RESTRICTION:
+# If you are not using -i option, the script should be run when the server
+# is running, and from where the server's changelog directory is accessible.
+#
+# DIAGNOSIS:
+# For environment variable issues, see script template-repl-monitor.pl under
+# DSHOME/bin/slapd/admin/scripts
+#
+################################################################################
+$usage="Usage: $0 [-h host] [-p port] [-D bind-dn] [-w bind-password | -P bind-cert] [-r replica-roots] [-o output-file] [-c] [-v]\n\n $0 -i changelog-ldif-file-with-base64encoding [-o output-file] [-c]";
+
+use Getopt::Std; # Parse command line arguments
+use Mozilla::LDAP::Conn; # LDAP module for Perl
+use Mozilla::LDAP::Utils; # LULU, utilities.
+use Mozilla::LDAP::API; # Used to parse LDAP URL
+use MIME::Base64; # Decode
+
+# Global variables
+
+$version = "Netscape Directory Server Changelog Dump - Version 1.0";
+
+#main
+{
+ # Turn off buffered I/O
+ $| = 1;
+
+ # Check for legal options
+ if (!getopts('h:p:D:w:P:r:o:cvi:')) {
+ print $usage;
+ exit -1;
+ }
+
+ exit -1 if &validateArgs;
+
+ if ($opt_v) {
+ print OUTPUT "$version\n";
+ exit;
+ }
+
+ if (!$opt_i) {
+ &cl_dump_and_decode;
+ }
+ elsif ($opt_c) {
+ &grep_csn ($opt_i);
+ }
+ else {
+ &cl_decode ($opt_i);
+ }
+
+ close (OUTPUT);
+}
+
+# Validate the parameters
+sub validateArgs
+{
+ my ($rc) = 0;
+
+ %ld = Mozilla::LDAP::Utils::ldapArgs();
+ chop ($ld{host} = `hostname`) if !$opt_h;
+ $ld{bind} = "cn=Directory Manager" if !$opt_D;
+ @allreplicas = ($opt_r) if ($opt_r);
+ if ($opt_o && ! open (OUTPUT, ">$opt_o")) {
+ print "Can't create output file $opt_o\n";
+ $rc = -1;
+ }
+ # Open STDOUT if option -o is missing
+ open (OUTPUT, ">-") if !$opt_o;
+
+ return $rc;
+}
+
+# Dump and decode changelog
+# OUTPUT should have been opened before this call
+sub cl_dump_and_decode
+{
+ # Open the connection
+ my ($conn) = new Mozilla::LDAP::Conn (\%ld);
+ if (!$conn) {
+ print OUTPUT qq/Can't connect to $ld{host}:$ld{port} as "$ld{bind}"\n/;
+ return -1;
+ }
+
+ # Get the changelog dir
+ my ($changelogdir);
+ my ($entry) = $conn->search ("cn=changelog5,cn=config", "sub", "(objectClass=*)");
+ while ($entry) {
+ $changelogdir = $entry->{"nsslapd-changelogdir"}[0];
+ last if $changelogdir;
+ $entry = $conn->nextEntry ();
+ }
+
+ # Get all the replicas on the server if -r option is not specified
+ if (!$opt_r) {
+ $entry = $conn->search ("cn=mapping tree,cn=config", "sub",
+ "(objectClass=nsDS5Replica)");
+ while ($entry) {
+ push (@allreplicas, "$entry->{nsDS5ReplicaRoot}[0]");
+ $entry = $conn->nextEntry ();
+ }
+ }
+
+ # Dump the changelog for the replica
+ my (@ldifs);
+ my ($replica);
+ my ($gotldif);
+ my ($ldif);
+ foreach (@allreplicas) {
+ # Reset the script's start time
+ $^T = time;
+
+ $replica = $_;
+ $gotldif = 0;
+
+ # Can't move this line before entering the loop:
+ # no ldif file generated other than for the first
+ # replica.
+ $entry = $conn->newEntry();
+ $entry->setDN ("cn=replica,cn=\"$_\",cn=mapping tree,cn=config");
+ $entry->setValues('nsDS5Task', 'CL2LDIF');
+ $conn->update ($entry);
+
+ #Decode the dumped changelog
+ @ldifs = <$changelogdir/*.ldif>;
+ foreach (@ldifs) {
+ # Skip older ldif files
+ next if ($#ldifs > 0 && (-M $_ > 0));
+ $ldif = $_;
+ $gotldif = 1;
+ &print_header ($replica, 0);
+ if ($opt_c) {
+ &grep_csn ($_);
+ }
+ else {
+ &cl_decode ($_);
+ }
+ # Test op -M doesn't work well so we use rename
+ # here to avoid reading the same ldif file more
+ # than once.
+ rename ($ldif, "$ldif.done");
+ }
+ &print_header ($replica, "Not Found") if !$gotldif;
+ }
+ $conn->close;
+}
+
+sub print_header
+{
+ my ($replica, $ldif) = @_;
+ print OUTPUT "\n# Replica Root: $replica" if $replica;
+ print OUTPUT "\n# LDIF File : $ldif\n" if $ldif;
+}
+
+# Grep and interpret CSNs
+# OUTPUT should have been opened before this call
+sub grep_csn
+{
+ open (INPUT, "@_") || return;
+ &print_header (0, @_);
+
+ my ($csn, $maxcsn, $modts);
+ while (<INPUT>) {
+ next if ($_ !~ /(csn:)|(ruv:)/i);
+ if (/ruv:\s*{.+}\s+(\w+)\s+(\w+)\s+(\w*)/i) {
+ #
+ # RUV with two CSNs and an optional lastModifiedTime
+ #
+ $csn = &csn_to_string($1);
+ $maxcsn = &csn_to_string($2);
+ $modts = $3;
+ if ( $modts =~ /^0+$/ ) {
+ $modts = "";
+ }
+ else {
+ $modts = &csn_to_string($modts);
+ }
+ }
+ elsif (/csn:\s*(\w+)\s+/i || /ruv:\s*{.+}\s+(\w+)\s+/i) {
+ #
+ # Single CSN
+ #
+ $csn = &csn_to_string($1);
+ $maxcsn = "";
+ $modts = "";
+ }
+ else {
+ printf OUTPUT;
+ next;
+ }
+ chop;
+ printf OUTPUT "$_ ($csn";
+ printf OUTPUT "; $maxcsn" if $maxcsn;
+ printf OUTPUT "; $modts" if $modts;
+ printf OUTPUT ")\n";
+ }
+}
+
+sub csn_to_string
+{
+ my ($csn, $tm, $seq, $masterid, $subseq);
+ my ($sec, $min, $hour, $mday, $mon, $year);
+
+ $csn = "@_";
+ return $csn if !$csn;
+
+ ($tm, $seq, $masterid, $subseq) = unpack("a8 a4 a4 a4", $csn);
+ $tm = hex($tm);
+ $seq = hex($seq);
+ $masterid = hex($masterid);
+ $subseq = hex($subseq);
+ ($sec, $min, $hour, $mday, $mon, $year) = localtime ($tm);
+ $mon++;
+ $year += 1900;
+ foreach ($sec, $min, $hour, $mday, $mon) {
+ $_ = "0".$_ if ($_ < 10);
+ }
+ $csn = "$mon/$mday/$year $hour:$min:$sec";
+ $csn .= " $seq $subseq" if ( $seq != 0 || $subseq != 0 );
+
+ return $csn;
+}
+
+# Decode the changelog
+# OUTPUT should have been opened before this call
+sub cl_decode
+{
+ open (INPUT, "@_") || return;
+ &print_header (0, @_);
+
+ my ($encoded);
+ undef $encoded;
+ while (<INPUT>) {
+ # Try to accomodate "changes" in 4.X and "change" in 6.X
+ if (/^changes?::\s*(\S*)/i) {
+ print OUTPUT "change::\n";
+ $encoded = $1;
+ next;
+ }
+ if (!defined ($encoded)) {
+ print OUTPUT;
+ next;
+ }
+ if ($_ eq "\n") {
+ print OUTPUT MIME::Base64::decode($encoded);
+ print OUTPUT "\n";
+ undef $encoded;
+ next;
+ }
+ /^\s*(\S+)\s*\n/;
+ $encoded .= $1;
+ }
+}
diff --git a/ldap/admin/src/scripts/template-db2bak.pl b/ldap/admin/src/scripts/template-db2bak.pl
new file mode 100644
index 00000000..f9514997
--- /dev/null
+++ b/ldap/admin/src/scripts/template-db2bak.pl
@@ -0,0 +1,89 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+sub usage {
+ print(STDERR "Usage: $0 [-v] -D rootdn { -w password | -w - | -j filename } \n");
+ print(STDERR " [-a dirname] [-t dbtype]\n");
+ print(STDERR " Opts: -D rootdn - Directory Manager\n");
+ print(STDERR " : -w password - Directory Manager's password\n");
+ print(STDERR " : -w - - Prompt for Directory Manager's password\n");
+ print(STDERR " : -j filename - Read Directory Manager's password from file\n");
+ print(STDERR " : -a dirname - backup directory\n");
+ print(STDERR " : -t dbtype - database type (default: ldbm database)\n");
+ print(STDERR " : -v - verbose\n");
+}
+$taskname = "";
+$archivedir = "";
+$dbtype = "ldbm database";
+$dsroot = "{{DS-ROOT}}";
+$mydsroot = "{{MY-DS-ROOT}}";
+$verbose = 0;
+$rootdn = "";
+$passwd = "";
+$passwdfile = "";
+$i = 0;
+while ($i <= $#ARGV) {
+ if ("$ARGV[$i]" eq "-a") { # backup directory
+ $i++; $archivedir = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-D") { # Directory Manager
+ $i++; $rootdn = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-w") { # Directory Manager's password
+ $i++; $passwd = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-j") { # Read Directory Manager's password from a file
+ $i++; $passwdfile = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-t") { # database type
+ $i++; $dbtype = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-v") { # verbose
+ $verbose = 1;
+ } else {
+ &usage; exit(1);
+ }
+ $i++;
+}
+if ($passwdfile ne ""){
+# Open file and get the password
+ unless (open (RPASS, $passwdfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $passwd = <RPASS>;
+ chomp($passwd);
+ close(RPASS);
+} elsif ($passwd eq "-"){
+# Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $passwd = ReadLine(0);
+# chomp($passwd);
+# ReadMode('normal');
+}
+if ( $rootdn eq "" || $passwd eq "") { &usage; exit(1); }
+($s, $m, $h, $dy, $mn, $yr, $wdy, $ydy, $r) = localtime(time);
+$mn++; $yr += 1900;
+$taskname = "backup_${yr}_${mn}_${dy}_${h}_${m}_${s}";
+if ($archivedir eq "") {
+ $archivedir = "${mydsroot}{{SEP}}bak{{SEP}}${yr}_${mn}_${dy}_${h}_${m}_${s}";
+}
+$dn = "dn: cn=$taskname, cn=backup, cn=tasks, cn=config\n";
+$misc = "changetype: add\nobjectclass: top\nobjectclass: extensibleObject\n";
+$cn = "cn: $taskname\n";
+$nsarchivedir = "nsArchiveDir: $archivedir\n";
+$nsdbtype = "nsDatabaseType: $dbtype\n";
+$entry = "${dn}${misc}${cn}${nsarchivedir}${nsdbtype}";
+$vstr = "";
+if ($verbose != 0) { $vstr = "-v"; }
+chdir("$dsroot{{SEP}}shared{{SEP}}bin");
+open(FOO, "| $dsroot{{SEP}}shared{{SEP}}bin{{SEP}}ldapmodify $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
+print(FOO "$entry");
+close(FOO);
diff --git a/ldap/admin/src/scripts/template-db2index.pl b/ldap/admin/src/scripts/template-db2index.pl
new file mode 100644
index 00000000..237cf952
--- /dev/null
+++ b/ldap/admin/src/scripts/template-db2index.pl
@@ -0,0 +1,195 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+sub usage {
+ print(STDERR "Usage: $0 [-v] -D rootdn { -w password | -w - | -j filename } \n");
+ print(STDERR " -n instance [-t attributeName[:indextypes[:matchingrules]]]\n");
+ print(STDERR " Opts: -D rootdn - Directory Manager\n");
+ print(STDERR " : -w password - Directory Manager's password\n");
+ print(STDERR " : -w - - Prompt for Directory Manager's password\n");
+ print(STDERR " : -j filename - Read Directory Manager's password from file\n");
+ print(STDERR " : -n instance - instance to be indexed\n");
+ print(STDERR " : -t attributeName[:indextypes[:matchingrules]]\n");
+ print(STDERR " - attribute: name of the attribute to be indexed\n");
+ print(STDERR " If omitted, all the indexes defined \n");
+ print(STDERR " for that instance are generated.\n");
+ print(STDERR " - indextypes: comma separated index types\n");
+ print(STDERR " - matchingrules: comma separated matrules\n");
+ print(STDERR " Example: -t foo:eq,pres\n");
+ print(STDERR " : -v - version\n");
+}
+
+$instance = "";
+$rootdn = "";
+$passwd = "";
+$passwdfile = "";
+$attribute_arg = "";
+$vlvattribute_arg = "";
+$verbose = 0;
+
+$dsroot = "{{DS-ROOT}}";
+$mydsroot = "{{MY-DS-ROOT}}";
+
+$i = 0;
+while ($i <= $#ARGV)
+{
+ if ("$ARGV[$i]" eq "-n")
+ {
+ # instance
+ $i++; $instance = $ARGV[$i];
+ }
+ elsif ("$ARGV[$i]" eq "-D")
+ {
+ # Directory Manager
+ $i++; $rootdn = $ARGV[$i];
+ }
+ elsif ("$ARGV[$i]" eq "-w")
+ {
+ # Directory Manager's password
+ $i++; $passwd = $ARGV[$i];
+ }
+ elsif ("$ARGV[$i]" eq "-j")
+ {
+ # Read Directory Manager's password from a file
+ $i++; $passwdfile = $ARGV[$i];
+ }
+ elsif ("$ARGV[$i]" eq "-t")
+ {
+ # Attribute to index
+ $i++; $attribute_arg = $ARGV[$i];
+ }
+ elsif ("$ARGV[$i]" eq "-T")
+ {
+ # Vlvattribute to index
+ $i++; $vlvattribute_arg = $ARGV[$i];
+ }
+ elsif ("$ARGV[$i]" eq "-v")
+ {
+ # verbose
+ $verbose = 1;
+ }
+ else
+ {
+ &usage; exit(1);
+ }
+ $i++;
+}
+
+if ($passwdfile ne ""){
+# Open file and get the password
+ unless (open (RPASS, $passwdfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $passwd = <RPASS>;
+ chomp($passwd);
+ close(RPASS);
+} elsif ($passwd eq "-"){
+# Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $passwd = ReadLine(0);
+# chomp($passwd);
+# ReadMode('normal');
+}
+
+if ( $rootdn eq "" || $passwd eq "" )
+{
+ &usage;
+ exit(1);
+}
+
+$vstr = "";
+if ($verbose != 0)
+{
+ $vstr = "-v";
+}
+
+($s, $m, $h, $dy, $mn, $yr, $wdy, $ydy, $r) = localtime(time);
+$mn++; $yr += 1900;
+$taskname = "db2index_${yr}_${mn}_${dy}_${h}_${m}_${s}";
+
+if ( $instance eq "" )
+{
+ &usage;
+ exit(1);
+}
+else
+{
+ # No attribute name has been specified: let's get them from the configuration
+ $attribute="";
+ $indexes_list="";
+ $vlvattribute="";
+ $vlvindexes_list="";
+ if ( $attribute_arg eq "" && $vlvattribute_arg eq "" )
+ {
+ # Get the list of indexes from the entry
+ $indexes_list="$dsroot{{SEP}}shared{{SEP}}bin{{SEP}}ldapsearch $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -s one " .
+ "-b \"cn=index,cn=\"$instance\", cn=ldbm database,cn=plugins,cn=config\" \"(&(objectclass=*)(nsSystemIndex=false))\" cn";
+
+ # build the values of the attribute nsIndexAttribute
+ open(LDAP1, "$indexes_list |");
+ while (<LDAP1>) {
+ s/\n //g;
+ if (/^cn: (.*)\n/) {
+ $IndexAttribute="nsIndexAttribute";
+ $attribute="$attribute$IndexAttribute: $1\n";
+ }
+ }
+ close(LDAP1);
+ if ( $attribute eq "" )
+ {
+ # No attribute to index, just exit
+ exit(0);
+ }
+
+ # Get the list of indexes from the entry
+ $vlvindexes_list="$dsroot{{SEP}}shared{{SEP}}bin{{SEP}}ldapsearch $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -s sub -b \"cn=\"$instance\", cn=ldbm database,cn=plugins,cn=config\" \"objectclass=vlvIndex\" cn";
+
+ # build the values of the attribute nsIndexVlvAttribute
+ open(LDAP1, "$vlvindexes_list |");
+ while (<LDAP1>) {
+ s/\n //g;
+ if (/^cn: (.*)\n/) {
+ $vlvIndexAttribute="nsIndexVlvAttribute";
+ $vlvattribute="$vlvattribute$vlvIndexAttribute: $1\n";
+ }
+ }
+ close(LDAP1);
+ }
+ else
+ {
+ if ( $attribute_arg ne "" )
+ {
+ $attribute="nsIndexAttribute: $attribute_arg\n";
+ }
+ if ( $vlvattribute_arg ne "" )
+ {
+ $vlvattribute="nsIndexVlvAttribute: $vlvattribute_arg\n";
+ }
+ }
+
+ # Build the task entry to add
+
+ $dn = "dn: cn=$taskname, cn=index, cn=tasks, cn=config\n";
+ $misc = "changetype: add\nobjectclass: top\nobjectclass: extensibleObject\n";
+ $cn = "cn: $taskname\n";
+ $nsinstance = "nsInstance: ${instance}\n";
+
+ $entry = "${dn}${misc}${cn}${nsinstance}${attribute}${vlvattribute}";
+}
+chdir("$dsroot{{SEP}}shared{{SEP}}bin");
+open(FOO, "| $dsroot{{SEP}}shared{{SEP}}bin{{SEP}}ldapmodify $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
+print(FOO "$entry");
+close(FOO);
diff --git a/ldap/admin/src/scripts/template-db2ldif.pl b/ldap/admin/src/scripts/template-db2ldif.pl
new file mode 100644
index 00000000..cd5b6065
--- /dev/null
+++ b/ldap/admin/src/scripts/template-db2ldif.pl
@@ -0,0 +1,215 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+sub usage {
+ print(STDERR "Usage: $0 [-v] -D rootdn { -w password | -w - | -j filename } \n");
+ print(STDERR " {-n instance}* | {-s include}* [{-x exclude}*] \n");
+ print(STDERR " [-m] [-M] [-u] [-C] [-N] [-U] [-a filename]\n");
+ print(STDERR " Opts: -D rootdn - Directory Manager\n");
+ print(STDERR " : -w password - Directory Manager's password\n");
+ print(STDERR " : -w - - Prompt for Directory Manager's password\n");
+ print(STDERR " : -j filename - Read Directory Manager's password from file\n");
+ print(STDERR " : -n instance - instance to be exported\n");
+ print(STDERR " : -a filename - output ldif file\n");
+ print(STDERR " : -s include - included suffix(es)\n");
+ print(STDERR " : -x exclude - excluded suffix(es)\n");
+ print(STDERR " : -m - minimal base64 encoding\n");
+ print(STDERR " : -M - output ldif is stored in multiple files\n");
+ print(STDERR " these files are named : <instance>_<filename>\n");
+ print(STDERR " by default, all instances are stored in <filename>\n");
+ print(STDERR " : -r - export replica\n");
+ print(STDERR " : -u - do not export unique id\n");
+ print(STDERR " : -C - use main db file only\n");
+ print(STDERR " : -N - suppress printing sequential number\n");
+ print(STDERR " : -U - output ldif is not folded\n");
+ print(STDERR " : -E - Decrypt encrypted data when exporting\n");
+ print(STDERR " : -1 - do not print version line\n");
+ print(STDERR " : -v - verbose\n");
+}
+
+@instances = (
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ ""
+);
+@included = (
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ ""
+);
+@excluded = (
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ ""
+);
+$maxidx = 50;
+$nowrap = 0;
+$nobase64 = 0;
+$noversion = 0;
+$nouniqueid = 0;
+$useid2entry = 0;
+$onefile = 1;
+$printkey = 1;
+$taskname = "";
+$ldiffile = "";
+$doreplica = 0;
+$dsroot = "{{DS-ROOT}}";
+$mydsroot = "{{MY-DS-ROOT}}";
+$verbose = 0;
+$rootdn = "";
+$passwd = "";
+$passwdfile = "";
+$i = 0;
+$insti = 0;
+$incli = 0;
+$excli = 0;
+$decrypt_on_export = 0;
+while ($i <= $#ARGV) {
+ if ( "$ARGV[$i]" eq "-n" ) { # instances
+ $i++;
+ if ($insti < $maxidx) {
+ $instances[$insti] = $ARGV[$i]; $insti++;
+ } else {
+ &usage; exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-s") { # included suffix
+ $i++;
+ if ($incli < $maxidx) {
+ $included[$incli] = $ARGV[$i]; $incli++;
+ } else {
+ &usage; exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-x") { # excluded suffix
+ $i++;
+ if ($excli < $maxidx) {
+ $excluded[$excli] = $ARGV[$i]; $excli++;
+ } else {
+ &usage; exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-a") { # ldif file
+ $i++; $ldiffile = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-D") { # Directory Manager
+ $i++; $rootdn = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-w") { # Directory Manager's password
+ $i++; $passwd = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-j") { # Read Directory Manager's password from a file
+ $i++; $passwdfile = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-M") { # multiple ldif file
+ $onefile = 0;
+ } elsif ("$ARGV[$i]" eq "-o") { # one ldif file
+ $onefile = 1;
+ } elsif ("$ARGV[$i]" eq "-u") { # no dump unique id
+ $nouniqueid = 1;
+ } elsif ("$ARGV[$i]" eq "-C") { # use id2entry
+ $useid2entry = 1;
+ } elsif ("$ARGV[$i]" eq "-N") { # does not print key
+ $printkey = 0;
+ } elsif ("$ARGV[$i]" eq "-r") { # export replica
+ $doreplica = 1;
+ } elsif ("$ARGV[$i]" eq "-m") { # no base64
+ $nobase64 = 1;
+ } elsif ("$ARGV[$i]" eq "-U") { # no wrap
+ $nowrap = 1;
+ } elsif ("$ARGV[$i]" eq "-1") { # no version line
+ $noversion = 1;
+ } elsif ("$ARGV[$i]" eq "-E") { # decrypt
+ $decrypt_on_export = 1;
+ } elsif ("$ARGV[$i]" eq "-v") { # verbose
+ $verbose = 1;
+ } else {
+ &usage; exit(1);
+ }
+ $i++;
+}
+if ($passwdfile ne ""){
+# Open file and get the password
+ unless (open (RPASS, $passwdfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $passwd = <RPASS>;
+ chomp($passwd);
+ close(RPASS);
+} elsif ($passwd eq "-"){
+# Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $passwd = ReadLine(0);
+# chomp($passwd);
+# ReadMode('normal');
+}
+if (($instances[0] eq "" && $included[0] eq "") || $rootdn eq "" || $passwd eq "") { &usage; exit(1); }
+($s, $m, $h, $dy, $mn, $yr, $wdy, $ydy, $r) = localtime(time);
+$mn++; $yr += 1900;
+$taskname = "export_${yr}_${mn}_${dy}_${h}_${m}_${s}";
+if ($ldiffile eq "") {
+ $ldiffile = "${mydsroot}{{SEP}}ldif{{SEP}}${yr}_${mn}_${dy}_${h}_${m}_${s}.ldif";
+}
+$dn = "dn: cn=$taskname, cn=export, cn=tasks, cn=config\n";
+$misc = "changetype: add\nobjectclass: top\nobjectclass: extensibleObject\n";
+$cn = "cn: $taskname\n";
+$i = 0;
+$nsinstance = "";
+while ("" ne "$instances[$i]") {
+ $nsinstance = "${nsinstance}nsInstance: $instances[$i]\n";
+ $i++;
+}
+$i = 0;
+$nsincluded = "";
+while ("" ne "$included[$i]") {
+ $nsincluded = "${nsincluded}nsIncludeSuffix: $included[$i]\n";
+ $i++;
+}
+$i = 0;
+$nsexcluded = "";
+while ("" ne "$excluded[$i]") {
+ $nsexcluded = "${nsexcluded}nsExcludeSuffix: $excluded[$i]\n";
+ $i++;
+}
+$nsreplica = "";
+if ($doreplica != 0) { $nsreplica = "nsExportReplica: true\n"; }
+$nsnobase64 = "";
+if ($nobase64 != 0) { $nsnobase64 = "nsMinimalEncoding: true\n"; }
+$nsnowrap = "";
+if ($nowrap != 0) { $nsnowrap = "nsNoWrap: true\n"; }
+$nsnoversion = "";
+if ($noversion != 0) { $nsnoversion = "nsNoVersionLine: true\n"; }
+$nsnouniqueid = "";
+if ($nouniqueid != 0) { $nsnouniqueid = "nsDumpUniqId: false\n"; }
+$nsuseid2entry = "";
+if ($useid2entry != 0) { $nsuseid2entry = "nsUseId2Entry: true\n"; }
+$nsonefile = "";
+if ($onefile != 0) { $nsonefile = "nsUseOneFile: true\n"; }
+if ($onefile == 0) { $nsonefile = "nsUseOneFile: false\n"; }
+$nsexportdecrypt = "";
+if ($decrypt_on_export != 0) { $nsexportdecrypt = "nsExportDecrypt: true\n"; }
+$nsprintkey = "";
+if ($printkey == 0) { $nsprintkey = "nsPrintKey: false\n"; }
+$nsldiffile = "nsFilename: ${ldiffile}\n";
+$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsreplica}${nsnobase64}${nsnowrap}${nsnoversion}${nsnouniqueid}${nsuseid2entry}${nsonefile}${nsexportdecrypt}${nsprintkey}${nsldiffile}";
+$vstr = "";
+if ($verbose != 0) { $vstr = "-v"; }
+chdir("$dsroot{{SEP}}shared{{SEP}}bin");
+open(FOO, "| $dsroot{{SEP}}shared{{SEP}}bin{{SEP}}ldapmodify $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
+print(FOO "$entry");
+close(FOO);
diff --git a/ldap/admin/src/scripts/template-dsml-activate.pl b/ldap/admin/src/scripts/template-dsml-activate.pl
new file mode 100644
index 00000000..392e164f
--- /dev/null
+++ b/ldap/admin/src/scripts/template-dsml-activate.pl
@@ -0,0 +1,198 @@
+#{{PERL-EXEC}}
+
+use Getopt::Std;
+use File::Copy "cp";
+use warnings;
+#use strict;
+
+sub usage {
+ print (STDERR "Arguments:\n");
+ print (STDERR " -i - install\n");
+ print (STDERR " -u - uninstall\n");
+ print (STDERR " -p - optional dsml port, defaults to 8080\n\n");
+
+ exit 100;
+}
+
+# Process the command line arguments
+{
+ usage() if (!getopts('uip:'));
+
+ $DSMLPORT=8080;
+ $DSMLPORT=$opt_p if ($opt_p);
+ my $SERVERNAME = "{{SERVER-NAME}}";
+ my $SERVERROOT = "{{DS-ROOT}}";
+ my $PATH="{{SEP}}admin-serv{{SEP}}config{{SEP}}";
+ my @FILES= ( "server.xml", "web-apps.xml", "obj.conf", "jvm12.conf" );
+
+ die "-i or -u required" if (!($opt_i || $opt_u));
+ die "-i OR -u required" if ($opt_i && $opt_u);
+
+ if ($opt_i) {
+ if (-e "$SERVERROOT{{SEP}}clients{{SEP}}dsmlgw{{SEP}}dsmlgw.cfg" ) {
+ print STDERR "leaving existing dsmlgw.cfg untouched.\n";
+ } else {
+ open DSMLCFG, ">$SERVERROOT{{SEP}}clients{{SEP}}dsmlgw{{SEP}}dsmlgw.cfg";
+ select DSMLCFG;
+ print "\#properties file for the Netscape DSMLGW\n\nServerHost=${SERVERNAME}\nServerPort={{SERVER-PORT}}\nBindDN=\nBindPW=\n\n";
+ print "MinLoginPool=1\nMaxLoginPool=2\nMinPool=3\nMaxPool=15\n";
+ close DSMLCFG;
+ }
+
+ open WEB, ">$SERVERROOT{{SEP}}clients{{SEP}}dsmlgw{{SEP}}WEB-INF{{SEP}}web.xml";
+ select WEB;
+ print <<EOF;
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!DOCTYPE web-app SYSTEM "../web-app_2_3.dtd">
+
+<web-app>
+ <display-name>Apache-Axis</display-name>
+
+ <listener>
+ <listener-class>org.apache.axis.transport.http.AxisHTTPSessionListener</listener-class>
+ </listener>
+
+ <servlet>
+ <servlet-name>AxisServlet</servlet-name>
+ <display-name>Apache-Axis Servlet</display-name>
+ <servlet-class>
+ org.apache.axis.transport.http.AxisServlet
+ </servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>AxisServlet</servlet-name>
+ <url-pattern>/services/*</url-pattern>
+ </servlet-mapping>
+
+ <session-config>
+ <!-- Default to 5 minute session timeouts -->
+ <session-timeout>5</session-timeout>
+ </session-config>
+
+ <mime-mapping>
+ <extension>wsdl</extension>
+ <mime-type>text/xml</mime-type>
+ </mime-mapping>
+
+
+ <mime-mapping>
+ <extension>xsd</extension>
+ <mime-type>text/xml</mime-type>
+ </mime-mapping>
+
+ <welcome-file-list>
+ <welcome-file>index.html</welcome-file>
+ <welcome-file>index.jsp</welcome-file>
+ <welcome-file>index.jws</welcome-file>
+ </welcome-file-list>
+
+</web-app>
+
+EOF
+
+
+ close WEB;
+ }
+
+ foreach $file (@FILES) {
+
+ if ($opt_u) {
+ # restore from backups
+ print STDOUT "${file}.bak -> ${file}\n";
+ rename("${SERVERROOT}${PATH}${file}.bak","${SERVERROOT}${PATH}${file}");
+ }
+ if ($opt_i) {
+ # make backups
+ print STDOUT "${file} -> ${file}.bak\n";
+ cp("${SERVERROOT}${PATH}${file}","${SERVERROOT}${PATH}${file}.bak");
+
+ if ( $file eq "server.xml") {
+ open SERVER, "${SERVERROOT}${PATH}${file}" || die("Could not open file!");
+ @raw_data=<SERVER>;
+ close SERVER;
+
+ $i=0;
+
+ while ($line = $raw_data[$i++]) {
+ #if ($line =~ /CONNECTIONGROUP.*servername=\"([\w.?]+)\"/ ){
+ #$SERVERNAME = $1;
+ #}
+
+ if ($line =~ /\<\/LS/ ) {
+ splice @raw_data, $i++,0,
+ (" <LS id=\"dsml-listener\" ip=\"0.0.0.0\" port=\"${DSMLPORT}\" security=\"off\" acceptorthreads=\"1\" blocking=\"no\">\n",
+ " <CONNECTIONGROUP id=\"dsml_default\" matchingip=\"default\" servername=\"${SERVERNAME}\" defaultvs=\"dsml-serv\"/></LS>\n" );
+ $i+=2;
+ }
+
+ if ($line =~ /\<\/VSCLASS/ ) {
+ splice @raw_data, $i, 0,
+ (" <VSCLASS id=\"dsml\" objectfile=\"obj.conf\" rootobject=\"dsmlgw\" acceptlanguage=\"off\">\n" .
+ "<VARS nice=\"\" docroot=\"${SERVERROOT}{{SEP}}clients{{SEP}}dsmlgw\" webapps_file=\"web-apps.xml\" webapps_enable=\"on\" />\n" .
+ " <VS id=\"dsml-serv\" state=\"on\" connections=\"dsml_default\" urlhosts=\"${SERVERNAME}\" mime=\"mime1\" aclids=\"acl1\">\n" .
+ " <USERDB id=\"default\" database=\"default\"/>\n </VS>\n </VSCLASS>\n");
+ $i++;
+ }
+
+
+ }
+ open SERVER, "> ${SERVERROOT}${PATH}${file}" || die("Could not open file!");
+ select SERVER;
+ print @raw_data;
+ close SERVER;
+ }
+
+ if ( $file eq "web-apps.xml" ) {
+ open WEBAPPS, "> ${SERVERROOT}${PATH}${file}";
+ select WEBAPPS;
+ print STDERR "adding necessary entry to $file.\n";
+ print <<EOF;
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE vs PUBLIC "-//Netscape Communications Corp.; Netscape//DTD Virtual Server Web Applications 6.1//EN" "http://developer.netscape.com/products/servers/enterprise/dtds/nes-webapps_6_1.dtd">
+<vs>
+ <web-app uri="/axis" dir="${SERVERROOT}{{SEP}}clients{{SEP}}dsmlgw" enable="true"/>
+</vs>
+
+EOF
+
+ close WEBAPPS;
+
+ }
+
+ if ( $file eq "obj.conf" ) {
+ open OBJ, ">> ${SERVERROOT}${PATH}${file}";
+ select OBJ;
+ print STDERR "adding necessary entry to $file.\n";
+ print <<EOF;
+<Object name="dsmlgw">
+ObjectType fn=type-by-extension
+ObjectType fn=force-type type=text/plain
+Service fn="NSServletService" type="magnus-internal/servlet"
+Service method=(GET|HEAD|POST) type=*~magnus-internal/* fn=send-file
+Error fn="admin-error" reason="server error"
+AddLog fn="admin40_flex_log" name="access"
+NameTrans fn="NSServletNameTrans" name="servlet"
+PathCheck fn=find-pathinfo
+PathCheck fn=find-index index-names="index.html,home.html"
+Service type="magnus-internal/jsp" fn="NSServletService"
+</Object>
+
+EOF
+
+ close OBJ;
+
+
+ }
+
+ if ( $file eq "jvm12.conf" ) {
+ open JVM, ">> ${SERVERROOT}${PATH}${file}";
+ select JVM;
+ print STDERR "adding necessary entry to $file.\n";
+ print "jvm.option=-Duser.home=${SERVERROOT}{{SEP}}clients{{SEP}}dsmlgw";
+ close JVM;
+ }
+ }
+ }
+}
diff --git a/ldap/admin/src/scripts/template-ldif2db.pl b/ldap/admin/src/scripts/template-ldif2db.pl
new file mode 100644
index 00000000..c552af69
--- /dev/null
+++ b/ldap/admin/src/scripts/template-ldif2db.pl
@@ -0,0 +1,193 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+sub usage {
+ print(STDERR "Usage: $0 [-v] -D rootdn { -w password | -w - | -j filename } \n");
+ print(STDERR " -n instance | {-s include}* [{-x exclude}*] [-O] [-c]\n");
+ print(STDERR " [-g [string]] [-G namespace_id] {-i filename}*\n");
+ print(STDERR " Opts: -D rootdn - Directory Manager\n");
+ print(STDERR " : -w password - Directory Manager's password\n");
+ print(STDERR " : -w - - Prompt for Directory Manager's password\n");
+ print(STDERR " : -j filename - Read Directory Manager's password from file\n");
+ print(STDERR " : -n instance - instance to be imported to\n");
+ print(STDERR " : -i filename - input ldif file(s)\n");
+ print(STDERR " : -s include - included suffix\n");
+ print(STDERR " : -x exclude - excluded suffix(es)\n");
+ print(STDERR " : -O - only create core db, no attr indexes\n");
+ print(STDERR " : -c size - merge chunk size\n");
+ print(STDERR " : -g [string] - string is \"none\" or \"deterministic\"\n");
+ print(STDERR " : none - unique id is not generated\n");
+ print(STDERR " : deterministic - generate name based unique id (-G name)\n");
+ print(STDERR " : by default - generate time based unique id\n");
+ print(STDERR " : -G name - namespace id for name based uniqueid (-g deterministic)\n");
+ print(STDERR " : -E - Encrypt data when importing\n");
+ print(STDERR " : -v - verbose\n");
+}
+
+@ldiffiles = (
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ ""
+);
+@included = (
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ ""
+);
+@excluded = (
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ ""
+);
+$maxidx = 50;
+$instance = "";
+$noattrindexes = 0;
+$mergechunksiz = 0;
+$genuniqid = "time";
+$uniqidname = "";
+$taskname = "";
+$dsroot = "{{DS-ROOT}}";
+$mydsroot = "{{MY-DS-ROOT}}";
+$verbose = 0;
+$rootdn = "";
+$passwd = "";
+$passwdfile = "";
+$i = 0;
+$ldifi = 0;
+$incli = 0;
+$excli = 0;
+$encrypt_on_import = 0;
+while ($i <= $#ARGV) {
+ if ( "$ARGV[$i]" eq "-i" ) { # ldiffiles
+ $i++;
+ if ($ldifi < $maxidx) {
+ $ldiffiles[$ldifi] = $ARGV[$i]; $ldifi++;
+ } else {
+ &usage; exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-s") { # included suffix
+ $i++;
+ if ($incli < $maxidx) {
+ $included[$incli] = $ARGV[$i]; $incli++;
+ } else {
+ &usage; exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-x") { # excluded suffix
+ $i++;
+ if ($excli < $maxidx) {
+ $excluded[$excli] = $ARGV[$i]; $excli++;
+ } else {
+ &usage; exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-n") { # instance
+ $i++; $instance = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-D") { # Directory Manager
+ $i++; $rootdn = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-w") { # Directory Manager's password
+ $i++; $passwd = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-j") { # Read Directory Manager's password from a file
+ $i++; $passwdfile = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-O") { # no attr indexes
+ $noattrindexes = 1;
+ } elsif ("$ARGV[$i]" eq "-c") { # merge chunk size
+ $i++; $mergechunksiz = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-g") { # generate uniqueid
+ if (("$ARGV[$i+1]" ne "") && !("$ARGV[$i+1]" =~ /^-/)) {
+ $i++;
+ if ("$ARGV[$i]" eq "none") {
+ $genuniqid = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "deterministic") {
+ $genuniqid = $ARGV[$i];
+ }
+ }
+ } elsif ("$ARGV[$i]" eq "-G") { # namespace id
+ $i++; $uniqidname = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-v") { # verbose
+ $verbose = 1;
+ } elsif ("$ARGV[$i]" eq "-E") { # encrypt on import
+ $encrypt_on_import = 1;
+ } else {
+ &usage; exit(1);
+ }
+ $i++;
+}
+if ($passwdfile ne ""){
+# Open file and get the password
+ unless (open (RPASS, $passwdfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $passwd = <RPASS>;
+ chomp($passwd);
+ close(RPASS);
+} elsif ($passwd eq "-"){
+# Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $passwd = ReadLine(0);
+# chomp($passwd);
+# ReadMode('normal');
+}
+if (($instance eq "" && $included[0] eq "") || $ldiffiles[0] eq "" || $rootdn eq "" || $passwd eq "") { &usage; exit(1); }
+($s, $m, $h, $dy, $mn, $yr, $wdy, $ydy, $r) = localtime(time);
+$mn++; $yr += 1900;
+$taskname = "import_${yr}_${mn}_${dy}_${h}_${m}_${s}";
+$dn = "dn: cn=$taskname, cn=import, cn=tasks, cn=config\n";
+$misc = "changetype: add\nobjectclass: top\nobjectclass: extensibleObject\n";
+$cn = "cn: $taskname\n";
+if ($instance ne "") {
+ $nsinstance = "nsInstance: ${instance}\n";
+}
+$i = 0;
+$nsldiffiles = "";
+while ("" ne "$ldiffiles[$i]") {
+ $nsldiffiles = "${nsldiffiles}nsFilename: $ldiffiles[$i]\n";
+ $i++;
+}
+$i = 0;
+$nsincluded = "";
+while ("" ne "$included[$i]") {
+ $nsincluded = "${nsincluded}nsIncludeSuffix: $included[$i]\n";
+ $i++;
+}
+$i = 0;
+$nsexcluded = "";
+while ("" ne "$excluded[$i]") {
+ $nsexcluded = "${nsexcluded}nsExcludeSuffix: $excluded[$i]\n";
+ $i++;
+}
+$nsnoattrindexes = "";
+if ($noattrindexes != 0) { $nsnoattrindexes = "nsImportIndexAttrs: false\n"; }
+$nsimportencrypt = "";
+if ($encrypt_on_import != 0) { $nsimportencrypt = "nsImportEncrypt: true\n"; }
+$nsmergechunksiz = "nsImportChunkSize: ${mergechunksiz}\n";
+$nsgenuniqid = "nsUniqueIdGenerator: ${genuniqid}\n";
+$nsuniqidname = "";
+if ($uniqidname ne "") { $nsuniqidname = "nsUniqueIdGeneratorNamespace: ${uniqidname}\n"; }
+$entry = "${dn}${misc}${cn}${nsinstance}${nsincluded}${nsexcluded}${nsldiffiles}${nsnoattrindexes}${nsimportencrypt}${nsmergechunksiz}${nsgenuniqid}${nsuniqidname}";
+$vstr = "";
+if ($verbose != 0) { $vstr = "-v"; }
+chdir("$dsroot{{SEP}}shared{{SEP}}bin");
+open(FOO, "| $dsroot{{SEP}}shared{{SEP}}bin{{SEP}}ldapmodify $vstr -h {{SERVER-NAME}} -p {{SERVER-PORT}} -D \"$rootdn\" -w \"$passwd\" -a" );
+print(FOO "$entry");
+close(FOO);
diff --git a/ldap/admin/src/scripts/template-migrate50to51 b/ldap/admin/src/scripts/template-migrate50to51
new file mode 100644
index 00000000..c9c32276
--- /dev/null
+++ b/ldap/admin/src/scripts/template-migrate50to51
@@ -0,0 +1,2778 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# Migrate a 5.0 directory server to a 5.1 directory server
+
+#######################################################################################################
+# enable the use of Perldap functions
+require DynaLoader;
+
+use Getopt::Std;
+use Mozilla::LDAP::Conn;
+use Mozilla::LDAP::Entry;
+use Mozilla::LDAP::LDIF;
+use Mozilla::LDAP::Utils qw(:all);
+use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API
+use Time::localtime;
+use File::Basename;
+use Class::Struct ;
+
+#######################################################################################################
+
+sub usage {
+ print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n");
+ print(STDERR " -o oldInstancePath -n newInstancePath [-t tracelevel] [-L logfile]\n");
+ print(STDERR "************** parameters in brackets are optionals, others are required **************\n");
+ print(STDERR " Opts: -D rootdn - new 5.x Directory Manager\n");
+ print(STDERR " : -w password - new 5.x Directory Manager's password\n");
+ print(STDERR " : -w - - Prompt for new 5.x Directory Manager's password\n");
+ print(STDERR " : -j filename - Read new 5.x Directory Manager's password from file\n");
+ print(STDERR " : -p port - new 5.x Directory Server port\n");
+ print(STDERR " : -o oldInstancePath - Path of the old instance to migrate \n");
+ print(STDERR " : -n newInstancePath - Path of the new 5.x instance\n");
+ print(STDERR " : [-t tracelevel] - specify the level of trace (0..3)\n");
+ print(STDERR " : [-L logfile] - specify the file to log the migration report \n");
+ }
+########################################################################################################
+
+BEGIN {
+
+ require 'uname.lib' ;
+ $isNT = -d '\\';
+ $PATHSEP = $isNT ? "\\" : "/";
+ ${SEP} = $isNT ? ";" : ":" ;
+ @INC = ( '.', '../../../admin/admin/bin');
+ grep { s@/@\\@g } @INC if $isNT;
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ # NT needs quotes around some things unix doesn't
+ $quote = $isNT ? "\"" : "";
+
+ # If this variable is set, all file/directory creation will make sure the mode
+ # and ownership of the destination is the same as the source
+ $PRESERVE = 1 if (!$isNT);
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ if ($isNT) {
+ $os = "WINNT";
+ } else {
+ $os = &uname("-s");
+ }
+ if ($isNT) {
+ # we have to pass batch files directly to the NT command interpreter
+ $com_spec = $ENV{ComSpec};
+ if (!$com_spec) {
+ $com_spec = $ENV{COMSPEC};
+ }
+ if (!$com_spec || ! -f $com_spec) {
+ # find the first available command interpreter
+ foreach $drive (c..z) {
+ $com_spec = "$drive:\\winnt\\system32\\cmd.exe";
+ last if (-f $com_spec);
+ $com_spec = undef;
+ }
+ if (! $com_spec) {
+ # punt and pray
+ $com_spec = 'c:\winnt\system32\cmd.exe';
+ }
+ }
+ }
+ if ( $os eq "AIX" ) {
+ $dll_suffix = "_shr.a";
+ }
+ elsif ( $os eq "HP-UX" ) {
+ $dll_suffix = ".sl";
+ }
+ elsif ( $os eq "WINNT" ) {
+ $dll_suffix = ".dll";
+ }
+ else {
+ $dll_suffix = ".so";
+ }
+ $slapdExecName = $isNT ? 'slapd.exe' : 'ns-slapd';
+ select STDERR;
+ $| = 1;
+ select STDOUT;
+ $| = 1;
+}
+
+SWITCH: {
+ if ($os eq "AIX") {
+ $LIB_PATH = "LIBPATH" ;
+ last SWITCH ;
+ }
+ if ($os eq "HP-UX") {
+ $LIB_PATH = "SHLIB_PATH" ;
+ last SWITCH ;
+ }
+ if ($isNT) {
+ $LIB_PATH = "PATH" ;
+ last SWITCH ;
+ }
+ else {
+ $LIB_PATH = "LD_LIBRARY_PATH" ;
+ last SWITCH ;
+ }
+ }
+
+ # old parameters
+ ${oldDir} = "" ;
+ ${oldname} = "" ;
+ ${oldHome} = "" ;
+ ${oldConfDir} = "" ;
+ ${oldlocaluser} ;
+ ${olduid} ;
+ ${oldgid} ;
+
+ # new parameters
+ ${root} = "{{DS-ROOT}}" ;
+ ${type} = "" ;
+ ${newname} = "" ;
+ ${newport} = "" ;
+ ${rootDN} = "" ;
+ ${rootpwd} = "" ;
+ ${localhost} = "" ;
+ ${LogFileReport} = "" ;
+ ${newuid} ;
+ ${localuser} ;
+ ${newgid} ;
+ $NO_INPUT_USER = 0 ; # by default user can give inputs during the migration process
+ ${curdir} = getCwd();
+ ${slapdExecDir} = "${root}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+ # in 5.1 the replica Id is setup to a static value
+ $replicaIdvalue = 65535;
+
+ # specify the level of trace
+ $TRACELEVEL=1;
+
+ $LDAP_SERVER_UNREACHABLE = 81;
+
+ # get input users
+ &getParameters() ;
+ ${oldDir} = &normalizeDir("${oldDir}");
+ ${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ;
+ ${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ;
+ ${oldSchemaDir} = "${oldConfDir}schema${PATHSEP}";
+ ${oldDSEldif} = "${oldConfDir}dse.ldif";
+ ${serverHome} = "${root}${PATHSEP}$type-$newname" ;
+ ${schemaDir} = "$serverHome${PATHSEP}config${PATHSEP}schema${PATHSEP}";
+ ${DSEldif} = "$serverHome${PATHSEP}config${PATHSEP}dse.ldif";
+ ${ldif_rep} = "${oldConfDir}${PATHSEP}ldif${PATHSEP}" ;
+ ${oldSlapdExecDir} = "${oldDir}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+
+ open(LOGFILE, ">> $LogFileReport");
+
+ printTrace("\noldDir: $oldDir, oldHome: $oldHome, \noldConfDir: $oldConfDir, \nldif_rep: $ldif_rep, \nrootDN: $rootDN, \nPort: $newport, \nNewname: $newname\n",3);
+ printTrace("\nLIB_PATH: $LIB_PATH",4);
+
+ if (!(-d $serverHome)) {
+ printMsg("\n$serverHome doesn't exist\n");
+ exit(1);
+ }
+ if (!(-d $oldHome)) {
+ printMsg("\n$oldHome doesn't exist\n");
+ exit(1);
+ }
+
+
+%HashParametersName = ();
+
+# The following hash displays only general server parameters to migrate under cn=config
+%GeneralSrvParamToMigrate = (
+ 'nsslapd-accesscontrol'=> '\n',
+ 'nsslapd-errorlog-logging-enabled'=> '\n',
+ 'nsslapd-accesslog-logging-enabled'=> '\n',
+ 'nsslapd-auditlog-logging-enabled'=> '\n',
+ 'nsslapd-accesslog-level'=> '\n',
+ 'nsslapd-accesslog-logbuffering'=> '\n',
+ 'nsslapd-accesslog-logexpirationtime'=> '\n',
+ 'nsslapd-accesslog-logexpirationtimeunit'=> '\n',
+ 'nsslapd-accesslog-logmaxdiskspace'=> '\n',
+ 'nsslapd-accesslog-logminfreediskspace'=> '\n',
+ 'nsslapd-accesslog-logrotationtime'=> '\n',
+ 'nsslapd-accesslog-logrotationtimeunit'=> '\n',
+ 'nsslapd-accesslog-maxlogsize'=> '\n',
+ 'nsslapd-accesslog-maxLogsPerDir'=> '\n',
+ 'nsslapd-attribute-name-exceptions'=> '\n',
+ 'nsslapd-auditlog-logexpirationtime'=> '\n',
+ 'nsslapd-auditlog-logexpirationtimeunit'=> '\n',
+ 'nsslapd-auditlog-logmaxdiskspace'=> '\n',
+ 'nsslapd-auditlog-logminfreediskspace'=> '\n',
+ 'nsslapd-auditlog-logrotationtime'=> '\n',
+ 'nsslapd-auditlog-logrotationtimeunit'=> '\n',
+ 'nsslapd-auditlog-maxlogsize'=> '\n',
+ 'nsslapd-auditlog-maxLogsPerDir'=> '\n',
+ 'nsslapd-certmap-basedn'=> '\n',
+ 'nsslapd-ds4-compatible-schema'=> '\n',
+ 'nsslapd-enquote-sup-oc'=> '\n',
+ 'nsslapd-errorlog-level'=> '\n',
+ 'nsslapd-errorlog-logexpirationtime'=> '\n',
+ 'nsslapd-errorlog-logexpirationtimeunit'=> '\n',
+ 'nsslapd-errorlog-logmaxdiskspace'=> '\n',
+ 'nsslapd-errorlog-logminfreediskspace'=> '\n',
+ 'nsslapd-errorlog-logrotationtime'=> '\n',
+ 'nsslapd-errorlog-logrotationtimeunit'=> '\n',
+ 'nsslapd-errorlog-maxlogsize'=> '\n',
+ 'nsslapd-errorlog-maxlogsperdir'=> '\n',
+ 'nsslapd-groupevalnestlevel'=> '\n',
+ 'nsslapd-idletimeout'=> '\n',
+ 'nsslapd-ioblocktimeout'=> '\n',
+ 'nsslapd-lastmod'=> '\n',
+ 'nsslapd-listenhost'=> '\n',
+ 'nsslapd-maxdescriptors'=> '\n',
+ 'nsslapd-nagle'=> '\n',
+ 'nsslapd-readonly'=> '\n',
+ 'nsslapd-referralmode'=> '\n',
+ 'nsslapd-plugin-depends-on-name'=> '\n',
+ 'nsslapd-plugin-depends-on-type'=> '\n',
+ 'nsslapd-referral'=> '\n',
+ 'nsslapd-reservedescriptors'=> '\n',
+ 'nsslapd-rootpwstoragescheme'=> '\n',
+ 'nsslapd-schemacheck'=> '\n',
+ 'nsslapd-secureport'=> '\n',
+ 'nsslapd-security'=> '\n',
+ 'nsslapd-sizelimit'=> '\n',
+ 'nsslapd-ssl3ciphers'=> '\n',
+ 'nsslapd-timelimit'=> '\n',
+ 'passwordchange'=> '\n',
+ 'passwordchecksyntax'=> '\n',
+ 'passwordexp'=> '\n',
+ 'passwordhistory'=> '\n',
+ 'passwordinhistory'=> '\n',
+ 'passwordlockout'=> '\n',
+ 'passwordlockoutduration'=> '\n',
+ 'passwordmaxage'=> '\n',
+ 'passwordmaxfailure'=> '\n',
+ 'passwordminage'=> '\n',
+ 'passwordminlength'=> '\n',
+ 'passwordmustchange'=> '\n',
+ 'passwordresetfailurecount' => '\n',
+ 'passwordstoragescheme' => '\n',
+ 'passwordunlock' => '\n',
+ 'passwordwarning' => '\n'
+);
+
+# the following hash displays global parameters related to database stored under cn=config,cn=ldbm database,cn=plugins,cn=config
+%GlobalConfigLDBMparamToMigrate = (
+ 'nsslapd-allidsthreshold' => '\n',
+ 'nsslapd-lookthroughlimit' => '\n',
+ 'nsslapd-mode' => '\n',
+ 'nsslapd-dbcachesize' => '\n',
+ 'nsslapd-cache-autosize' => '\n',
+ 'nsslapd-cache-autosize-split' => '\n',
+ 'nsslapd-db-transaction-logging' => '\n',
+ 'nsslapd-import-cachesize' => '\n'
+);
+
+# the following hash displays specific parameters to each backends and stored under cn=DBname,cn=ldbm database,cn=plugins,cn=config
+%LDBMparamToMigrate = (
+ 'nsslapd-cachesize' => '\n',
+ 'nsslapd-cachememsize' => '\n',
+ 'nsslapd-readonly' => '\n',
+ 'nsslapd-require-index' => '\n'
+);
+
+
+%ChainingConfigParams = (
+ 'nsactivechainingcomponents' => '\n',
+ 'nstransmittedcontrols' => '\n'
+ );
+
+%ChainingDefaultInstanceConfigParams = (
+ 'nsabandonedsearchcheckinterval' => '\n',
+ 'nsbindconnectionslimit' => '\n',
+ 'nsbindtimeout' => '\n',
+ 'nsbindretrylimit' => '\n',
+ 'nshoplimit' => '\n',
+ 'nsmaxresponsedelay' => '\n',
+ 'nsmaxtestresponsedelay' => '\n',
+ 'nschecklocalaci' => '\n',
+ 'nsconcurrentbindlimit' => '\n',
+ 'nsconcurrentoperationslimit' => '\n',
+ 'nsconnectionlife' => '\n',
+ 'nsoperationconnectionslimit' => '\n',
+ 'nsproxiedauthorization' => '\n',
+ 'nsreferralonscopedsearch' => '\n',
+ 'nsslapd-sizelimit' => '\n',
+ 'nsslapd-timelimit' => '\n'
+);
+
+%changelog5params = (
+ 'nsslapd-changelogmaxage' => '\n',
+ 'nsslapd-changelogmaxentries' => '\n'
+ );
+
+@SNMPparams = (
+ 'nssnmpenabled',
+ 'nssnmporganization',
+ 'nssnmplocation',
+ 'nssnmpcontact',
+ 'nssnmpdescription',
+ 'nssnmpmasterhost',
+ 'nssnmpmasterport',
+ 'nssnmpenabled',
+ 'aci'
+ );
+
+%stdIncludes = (
+ "." => "\n",
+ ".." => "\n",
+ "30ns-common.ldif " => "\n",
+ "50ns-mail.ldif " => "\n",
+ "50ns-news.ldif" => "\n",
+ "50iplanet-servicemgt.ldif"=> "\n",
+ "50ns-mcd-browser.ldif" => "\n",
+ "50ns-proxy.ldif" => "\n",
+ "00core.ldif" => "\n",
+ "50ns-admin.ldif" => "\n",
+ "50ns-mcd-config.ldif " => "\n",
+ "50ns-value.ldif" => "\n",
+ "05rfc2247.ldif" => "\n",
+ "50ns-calendar.ldif" => "\n",
+ "50ns-mcd-li.ldif" => "\n",
+ "50ns-wcal.ldif" => "\n",
+ "05rfc2927.ldif" => "\n",
+ "50ns-certificate.ldif" => "\n",
+ "50ns-mcd-mail.ldif" => "\n",
+ "50ns-web.ldif" => "\n",
+ "10rfc2307.ldif" => "\n",
+ "50ns-compass.ldif" => "\n",
+ "50ns-media.ldif" => "\n",
+ "20subscriber.ldif" => "\n",
+ "50ns-delegated-admin.ldif"=> "\n",
+ "50ns-mlm.ldif" => "\n",
+ "25java-object.ldif" => "\n",
+ "50ns-directory.ldif" => "\n",
+ "50ns-msg.ldif" => "\n",
+ "28pilot.ldif" => "\n",
+ "50ns-legacy.ldif" => "\n",
+ "50ns-netshare.ldif" => "\n"
+);
+
+
+# Backends migrated (Backend CN attribute value)
+@BACKENDS = () ;
+# All pairs of suffix-backend are registered in this hashtable
+%oldBackends = () ;
+
+#store the backend instances to migrate
+@LDBM_backend_instances = ();
+
+#store the mapping tree
+@Mapping_tree_entries = ();
+
+#store the suffix and the associated chaining backend
+%oldChainingBackends = ();
+
+#store the multiplexor bind entries to migrate
+%MultiplexorBindDNEntriesToMigrate = ();
+
+#store the Replica bind DN entries to migrate
+%ReplicaBindDNEntriesToMigrate = ();
+
+# list of standard plugin's in version 4
+%stdPlugins = (
+ "7-bit check" => "\n",
+ "acl plugin" => "\n",
+ "acl preoperation" => "\n",
+ "binary syntax" => "\n",
+ "case exact string syntax" => "\n",
+ "case ignore string syntax" => "\n",
+ "chaining database" => "\n",
+ "class of service" => "\n",
+ "country string syntax" => "\n",
+ "distinguished name syntax" => "\n",
+ "generalized time syntax" => "\n",
+ "integer syntax" => "\n",
+ "internationalization plugin" => "\n",
+ "ldbm database" => "\n",
+ "legacy replication plugin" => "\n",
+ "multimaster replication plugin" => "\n",
+ "octet string syntax" => "\n",
+ "clear" => "\n",
+ "crypt" => "\n",
+ "ns-mta-md5" => "\n",
+ "sha" => "\n",
+ "ssha" => "\n",
+ "postal address syntax" => "\n",
+ "referential integrity postoperation" => "\n",
+ "retro changelog plugin" => "\n",
+ "roles plugin" => "\n",
+ "telephone syntax" => "\n",
+ "uid uniqueness" => "\n",
+ "uri syntax" => "\n"
+ );
+
+# list of indexes that have disappeared from the 5.1 schema compared to 5.0
+%deniedIndexes = (
+ 'dncomp' => "\n"
+);
+
+@default_indexes = ();
+@indexes = ();
+
+# list of user added Plugin's. In 5.x, they 'll need to be recompiled
+@badPlugins = () ;
+
+@pluginAttrs = (
+ "objectclass",
+ "cn",
+ "nsslapd-pluginpath",
+ "nsslapd-plugininitfunc",
+ "nsslapd-plugintype",
+ "nsslapd-pluginenabled",
+ "nsslapd-plugin-depends-on-type",
+ "nsslapd-pluginid",
+ "nsslapd-pluginversion",
+ "nsslapd-pluginvendor"
+ );
+
+@nsds5replicaAttrs = (
+ 'objectclass',
+ 'nsDS5ReplicaRoot',
+ 'nsDS5ReplicaType',
+ 'nsDS5ReplicaLegacyConsumer',
+ 'nsDS5flags',
+ 'nsDS5ReplicaId',
+ 'nsDS5ReplicaPurgeDelay',
+ 'nsDS5ReplicaBinddn',
+ 'cn',
+ 'nsDS5ReplicaReferral'
+ );
+
+# array of replicas to migrate
+@new51replicas = ();
+
+# array of replication agreements to migrate
+@replicationAgreements = ();
+
+# Shutdown the legacy Directory instance
+printTrace("\nShutdown the legacy Directory Server instance: ${oldHome}",0);
+&stopServer($oldDir, 'slapd-'.$oldname);
+
+# compare LDIF standard config files with standard ones
+CompareStdConfigFiles() ;
+die "\n\n The version of product you want to migrate is not a 5.x iPlanet Directory Server\n" unless ($oldVersion == 5) ;
+
+# get the hostname of the new LDAP server
+my $LDAPservername = &getLDAPservername();
+
+# get the uid and gid of the 5.1 slapd user
+($localuser, $newuid, $newgid) = getuid_gid();
+# get the uid and gid of the 5.0 slapd user
+($oldlocaluser, $olduid, $oldgid) = getolduid_gid();
+printTrace("\n5.1 localuser: $localuser, uid: $newuid, gid: $newgid",2);
+printTrace("\n5.0 localuser: $oldlocaluser, uid: $olduid, gid: $oldgid",2);
+
+# backup 5.1 configuration files in <root_server51>/slapd-instancename/config
+printTrace("\nBackup $serverHome${PATHSEP}config on $serverHome${PATHSEP}config_backup ...",0);
+&backupConfigFiles();
+
+# migrate the schema (need to stop and start the 5.1 server)
+printTrace("\nMigrate the schema...",0);
+MigrateSchema();
+
+# start the server unless it is already started
+&startServer() unless (isDirectoryAlive());
+
+############### Connect to the 5.1 LDAP Directory Server ######################
+$ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"} ;
+
+die "\n Migration aborted. Check your 5.0 and 5.1 iPlanet Directory Server are installed on the same machine \n" if ( $LDAPservername == -1 );
+$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+
+# Cconnection to 5.1 LDAP server is successful !
+printTrace("\nConnected to $Version.$Minor LDAP server",0) ;
+
+# Parse the main configuration file: dse.ldif
+printTrace("\n\nParse the old DSE ldif file: $oldDSEldif *****",0, 1);
+printTrace("\nThis may take a while ...\n",0);
+&MigrateDSEldif();
+
+#migrate LDBM backend instances
+printTrace("\n\nMigrate LDBM backend instances...",0,1);
+&migrateLDBM_backend_instances();
+
+#migrate mapping tree entries
+printTrace("\n\nMigrate mapping tree...",0,1);
+&migrateMappingTree();
+
+#migrate default indexes
+printTrace("\n\nMigrate default indexes...",0,1);
+migrateDefaultIndexes();
+
+#migrate indexes
+printTrace("\n\nMigrate indexes...",0,1);
+migrateIndexes();
+
+#migrate replicas
+printTrace("\n\nMigrate replicas...",0,1);
+&MigrateNSDS5_replica();
+
+#migrate replication agreements
+printTrace("\n\nMigrate replication agreements...",0,1);
+&MigrateNSDS_replication_agreement();
+
+#migrate key/cert databases
+printTrace("\n\nMigrate key/cert databases...",0,1);
+&MigrateSSL();
+
+# migrate certmap.conf
+printTrace("\n\nMigrate Certmap.conf...",0,1);
+&MigrateCertmap() ;
+
+################## Close the connection to 5.1 LDAP Server #####################
+printTrace("\n\n***** Close the LDAP connection to the 5.1 Directory Server instance ***** ",0);
+$conn->close;
+
+
+################## stop the 5.x instance and Export/Import the data, restart the server ##################
+if (@BACKENDS) {
+ &stopServer($root,'slapd-'.$newname);
+ printTrace("\nData processing...\n",0,1) ;
+ # migrate data for each backend: 5.0 -> LDIF files
+ &manydb2Ldif($ldif_rep);
+
+ # migrate LDIF data to the 5.1 database: LDIF -> 5.1
+ &manyLdif2db($ldif_rep);
+ printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1);
+ &importReplicaBindDNEntries();
+ printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1);
+ &importMultiplexorBindDNEntries();
+ &startServer() unless (isDirectoryAlive());
+}
+else {
+ printTrace("\nINFORMATION - There are no 5.0 non-standard or non-already existing suffixes to migrate\n",0);
+ printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1);
+ &importReplicaBindDNEntries();
+ printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1);
+ &importMultiplexorBindDNEntries();
+}
+
+printMsg("\n\n ****** End of migration ******\n\n");
+
+close(LOGFILE);
+
+
+###########################################################################################
+# get input users
+sub getParameters {
+ my $exit = 0 ;
+ my $i = 0;
+ my $pwdfile= "";
+
+ while ($i <= $#ARGV) {
+ if ( "$ARGV[$i]" eq "-D" ) { # directory manager
+ if (! $rootDN) {
+ $rootDN = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-w") { # password
+ if (! $rootpwd) {
+ $rootpwd = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-j") { # password file
+ if (! $pwdfile) {
+ $pwdfile = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-o") { # 4.x instance path
+ if (! $oldHome ) {
+ $oldHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $oldHome if $isNT ;
+ if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; }
+ if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) {
+ $oldDir = $1 ;
+ $type = $2 ;
+ $oldname = $3 ;
+ if ($isNT) {
+ $oldDir = lc($oldDir) ;
+ $type = lc($type) ;
+ $oldname = lc($oldname) ;
+ $oldHome = lc($oldHome) ;
+ grep { s@/@\\@g } $oldDir ;
+ grep { s@/@\\@g } $oldHome ;
+ }
+ }
+ else {
+ print("\nThe old instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-n") { # 5.x instance path
+ if (! $serverHome ) {
+ $serverHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $root if $isNT ;
+ grep { s@\\@/@g } $serverHome if $isNT ;
+ if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; }
+ if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) {
+ $root = $1 if ($1);
+ $type = $2 ;
+ $newname = $3 ;
+ if ($isNT) {
+ $root = lc($root) ;
+ $type = lc($type) ;
+ $newname = lc($newname) ;
+ $serverHome = lc($serverHome) ;
+ grep { s@/@\\@g } $root ;
+ grep { s@/@\\@g } $serverHome ;
+ }
+ }
+ else {
+ print("\nThe 5.x instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-p") { # 5.x DS port
+ if (! $newport ) {
+ $newport = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL
+ my $value = $ARGV[++$i] ;
+ if ($value =~ /[0-3]/) {
+ $TRACELEVEL = $value ;
+ }
+ else {
+ print("\nThe tracelevel must belong to 0..3 interval");
+ &usage();
+ exit();
+ }
+ } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing
+ $NO_INPUT_USER = 1 ;
+ } elsif ("$ARGV[$i]" eq "-L") { # migration logfile
+ $LogFileReport = $ARGV[++$i] ;
+ }
+ else {
+ print("\nThe option $ARGV[$i] is not recognized");
+ &usage() ;
+ exit(1);
+ }
+ $i++;
+ }
+ if (! $rootDN) {
+ print("\nThe rootDN is missing");
+ $exit = 1;
+ }
+ if ($pwdfile ne "") {
+ # Open file and get the password
+ unless (open (RPASS, $pwfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $rootpwd = <RPASS>;
+ chomp($rootpwd);
+ close(RPASS);
+ } elsif ($rootpwd eq "-"){
+ # Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+ # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $rootpwd = ReadLine(0);
+# chomp($rootpwd);
+# ReadMode('normal');
+ }
+ if (! $rootpwd) {
+ print("\nThe rootpwd is missing");
+ $exit = 1 ;
+ }
+ if (! $newport) {
+ print("\nThe port is missing");
+ $exit = 1;
+ }
+ if (! $serverHome) {
+ print("\nThe new instance path is missing");
+ $exit = 1;
+ }
+ if (! $oldHome) {
+ print("\nThe old instance path is missing");
+ $exit = 1;
+ }
+ if ((! $LogFileReport) && $serverHome) {
+ ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime();
+ $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log";
+ }
+ if ($exit) {
+ &usage() ;
+ exit(1);
+ }
+
+}
+
+###################################################################################################
+
+sub MigrateSchema{
+ my $FilesChanged = "";
+ my $AllDiffs = "";
+ my $NoChanges = "" ;
+ my $lineToBegin = 0 ;
+ opendir(SCHEMADIR, $oldSchemaDir) or
+ die "Error: could not open migrated config dir $oldSchemaDir: $!";
+
+ foreach $file (readdir(SCHEMADIR)) {
+ if (! exists($stdIncludes{lc($file)})) {
+ my $new51file = $schemaDir . $file;
+ if (-f $new51file ) {
+ # The ldif file already exists. Make a diff and warn the user if different.
+ if (diff($new51file, $oldSchemaDir.$file)) {
+ &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive());
+ $AllDiffs .= "\n$file";
+ copyBinFile("$oldSchemaDir$file", $new51file);
+ }
+ }
+ else {
+ &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive());
+ $AllDiffs .= "\n$file";
+ copyBinFile("$oldSchemaDir$file", $new51file);
+ }
+ }
+ }
+ closedir(SCHEMADIR);
+ if ($AllDiffs) {
+ printMsg("\n\n***********************************************************************");
+ printMsg("\nThe following LDIF files have been migrated:");
+ printMsg("$AllDiffs");
+ printMsg("\n*************************************************************************\n\n");
+ }
+ &startServer() if (! isDirectoryAlive());
+}
+
+
+###################################################################################################
+# This subroutine is used to parse the dse.ldif file and call specific routines to act with entries
+sub MigrateDSEldif {
+ printTrace("\nMigrate DSE entries...",1);
+ my $tempoAlreadyDone = 0;
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ $typeOfEntry = getTypeOfEntry($entry);
+ SWITCH: {
+ if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){
+ parseLDBM_backend_instance($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "MAPPING_TREE"){
+ parseMapping_tree($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "DEFAULT_INDEX"){
+ parseDefaultIndex($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "INDEX"){
+ parseIndex($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "STANDARD_PLUGIN"){
+ migrateStdPlugin($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CONFIG_NODE"){
+ migrateConfig_Node($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CONFIG_LDBM_DATABASE"){
+ migrateConfig_LDBM_database($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CHAINING_BACKEND_CONFIG"){
+ migrateChainingBE_config($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CHAINING_BACKEND_INSTANCE"){
+ migrateChainingBE_instance($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "NSDS5_REPLICA"){
+ parseNSDS5_replica($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "NSDS_REPLICATION_AGREEMENT"){
+ parseNSDS_replication_agreement($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CHANGELOG5"){
+ migrateChangelog5($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "REPLICATION"){
+ migrateReplication($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "SECURITY"){
+ migrateSecurity($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "SNMP"){
+ migrateSNMP($entry);
+ last SWITCH;
+ }
+ }
+
+ }
+ close(DSELDIF);
+}
+
+#############################################################################
+# returns the "type of an entry". If the entry is not to be migrated its type is "NOT_MIGRATED_TYPE"
+
+sub getTypeOfEntry{
+ my $entry = shift;
+ my $DN = $entry->getDN(1) ; # 1 is to normalize the returned DN
+ if (($DN =~ /cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) {
+ return "LDBM_BACKEND_INSTANCE";
+ }
+ if (($DN =~ /cn=mapping tree,cn=config$/i) && (isObjectclass($entry,"nsMappingTree"))) {
+ return "MAPPING_TREE";
+ }
+ if (($DN =~ /cn=default indexes,cn=config,cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsIndex"))) {
+ return "DEFAULT_INDEX";
+ }
+ if (isObjectclass($entry,"nsIndex")) {
+ return "INDEX";
+ }
+ if ((isObjectclass($entry,"nsSlapdPlugin")) && (isStdPlugin($entry))) {
+ return "STANDARD_PLUGIN";
+ }
+ if ($DN =~ /^cn=config$/i) {
+ return "CONFIG_NODE";
+ }
+ if ($DN =~ /^cn=config,cn=ldbm database,cn=plugins,cn=config$/i) {
+ return "CONFIG_LDBM_DATABASE";
+ }
+ if (($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i) || ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i)){
+ return "CHAINING_BACKEND_CONFIG";
+ }
+ if (($DN =~ /cn=chaining database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) {
+ return "CHAINING_BACKEND_INSTANCE";
+ }
+ if (isObjectclass($entry,"nsDS5Replica")) {
+ return "NSDS5_REPLICA";
+ }
+ if (isObjectclass($entry,"nsDS5ReplicationAgreement")) {
+ return "NSDS_REPLICATION_AGREEMENT";
+ }
+ if ($DN =~ /^cn=changelog5,cn=config$/i) {
+ return "CHANGELOG5";
+ }
+ if (($DN =~ /cn=replication,cn=config$/i) && ($DN !~ /^cn=replication,cn=config$/i)) {
+ return "REPLICATION";
+ }
+ if ($DN =~ /cn=encryption,cn=config$/i) {
+ return "SECURITY";
+ }
+ if ($DN =~ /^cn=SNMP,cn=config$/i) {
+ return "SNMP";
+ }
+ return "NOT_MIGRATED_TYPE";
+}
+
+#############################################################################
+
+
+
+#############################################################################
+# returns 1 if the objectclass given in parameter is present in the objectclasses values of the entry
+# given in parameter, 0 else
+
+sub isObjectclass {
+ my $entry = shift;
+ my $objectclass = shift;
+ return ($entry->hasValue("objectclass",$objectclass,1));
+}
+
+#############################################################################
+
+sub isStdPlugin {
+ my $entry = shift;
+ my $CN = $entry->{cn}[0];
+ if (isObjectclass($entry,"nsSlapdPlugin")) {
+ return 1 if ($stdPlugins{lc($CN)});
+ }
+ return 0;
+}
+
+
+#############################################################################
+
+sub alreadyExistsIn51{
+ my $entry = shift;
+ my $mustExist = shift;
+ my $DN = $entry->getDN(1); # 1 to normalize the DN
+ return searchEntry($DN, $mustExist);
+}
+
+#############################################################################
+sub searchEntry {
+ my $DN = shift;
+ my $mustExist = shift;
+ my $res = $conn->search($DN, "base", "objectclass=*");
+ my $cpt = 5;
+ if ($res) {
+ return $res;
+ }
+ else {
+ my $errorCode = $conn->getErrorCode();
+ while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) {
+ printMsg("\ntry to reconnect to search $DN");
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ $res = $conn->search($DN, "base", "objectclass=*");
+ $errorCode = $conn->getErrorCode();
+ $cpt--;
+ }
+ if ($res){
+ return $res ;
+ }
+ elsif (($errorCode eq $LDAP_SERVER_UNREACHABLE) || ($mustExist)) {
+ my $msg = $conn->getErrorString();
+ printMsg("\n\n*** Failed to search: $DN");
+ printMsg("\n*** Error Msg: $msg, Error code: $errorCode");
+ }
+ return 0;
+ }
+}
+
+
+#############################################################################
+
+sub addEntryTo51{
+ my $entry = shift;
+ my $typeOfEntry = shift;
+ my $trace = shift;
+ my $res = $conn->add($entry);
+ my $DN = $entry->getDN(1);
+ my $cpt = 5;
+ if ($res) {
+ printTrace("\n$typeOfEntry - Add successfull: $DN",$trace);
+ return 1;
+ }
+ else {
+ my $errorCode = $conn->getErrorCode();
+ while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) {
+ printMsg("\ntry to reconnect to add $DN");
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ $res = $conn->add($entry);
+ $errorCode = $conn->getErrorCode();
+ $cpt--;
+ }
+ if ($res){
+ printTrace("\n$typeOfEntry - Add successfull: $DN",$trace);
+ return 1;
+ }
+ else {
+ my $msg = $conn->getErrorString();
+ printMsg("\n\n*** $typeOfEntry: Add Failed: $DN");
+ printMsg("\n*** Error Msg: $msg, Error code: $errorCode");
+ return 0;
+ }
+ }
+}
+
+#############################################################################
+
+sub updateEntry{
+ my $entry = shift;
+ my $typeOfEntry = shift;
+ my $CHECK = shift;
+ my $trace = shift;
+ my $cpt = 5;
+ if ($CHECK) {
+ if (! hasChanged($entry, $typeOfEntry)) {
+ return 1;
+ }
+ }
+ my $res = $conn->update($entry);
+ my $DN = $entry->getDN(1);
+ if ($res) {
+ printTrace("\n$typeOfEntry - Update successfull: $DN",$trace);
+ return 1 ;
+ }
+ else {
+ my $errorCode = $conn->getErrorCode();
+ while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) {
+ printMsg("\ntry to reconnect to update $DN");
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ $res = $conn->update($entry);
+ $errorCode = $conn->getErrorCode();
+ $cpt--;
+ }
+ if ($res){
+ printTrace("\n$typeOfEntry - Update successfull: $DN",$trace);
+ return 1;
+ }
+ else {
+ my $msg = $conn->getErrorString();
+ printMsg("\n\n*** $typeOfEntry - Update Failed: $DN");
+ printMsg("\n*** Error Msg: $msg, Error code: $errorCode");
+ return 0;
+ }
+ }
+}
+
+
+#############################################################################
+# returns 1 if the entry to migrate and the current entry are different one another
+
+sub hasChanged {
+ my $entry = shift;
+ my $typeOfEntry = shift;
+ my $DN = $entry->getDN(1);
+ my $new51entry = searchEntry($DN,1);
+ return 1 if (! $new51entry); # we shoudn't be in that case ...
+ # do the stuff to check wether the entry has changed or not given its type
+ if (($typeOfEntry eq "DEFAULT_INDEX") || ($typeOfEntry eq "INDEX")){
+ my @indexTypes = $entry->getValues("nsIndexType");
+ my @new51indexTypes = $new51entry->getValues("nsIndexType");
+ my @nsmatchingrules = $entry->getValues("nsmatchingrule");
+ my @new51nsmatchingrules = $new51entry->getValues("nsmatchingrule");
+ return 1 if (Diffs(\@indexTypes, \@new51indexTypes));
+ return 1 if (Diffs(\@nsmatchingrules,\@new51nsmatchingrules));
+ return 0;
+ }
+ if ($typeOfEntry eq "CHANGELOG5"){
+ printTrace("\nCheck wether changelog has changed or not",3);
+ my @params = keys(%changelog5params);
+ foreach $param (@params){
+ my @values = $entry->getValues($param);
+ my @new51values = $new51entry->getValues($param);
+ return 1 if (Diffs(\@values,\@new51values));
+ }
+ return 0;
+ }
+ if ($typeOfEntry eq "SNMP"){
+ foreach $param (@SNMPparams){
+ my @values = $entry->getValues($param);
+ my @new51values = $new51entry->getValues($param);
+ return 1 if (Diffs(\@values,\@new51values));
+ }
+ return 0;
+ }
+ # we don't know how to compare such type of entry => just return 1
+ return 1 ;
+}
+
+sub isAsystemIndex {
+ my $index = shift;
+ return ($index->hasValue("nsSystemIndex","true",1));
+}
+
+
+sub updatePathInPluginArgs {
+ my $plugin = shift;
+ my $argNum = 0;
+ my $argPrefix = "nsslapd-pluginarg";
+ my $cont = 1;
+ my $Unix_oldDir = ${oldDir} ;
+ my $Unix_root = ${root} ;
+ grep { s@\\@/@g } $Unix_oldDir if $isNT;
+ grep { s@\\@/@g } $Unix_root if $isNT;
+ while ($cont) {
+ my $arg = $argPrefix . $argNum ;
+ if ($plugin->exists($arg)) {
+ $_ = $plugin->{$arg}[0] ;
+ s@$Unix_oldDir@$Unix_root@ig ;
+ s/$type-$oldname/$type-$newname/ig ;
+ $plugin->setValues($arg, $_) ;
+ }
+ else {
+ $cont = 0 ;
+ }
+ $argNum++;
+ }
+ return $plugin;
+}
+
+
+sub Diffs {
+ my $valuesToMigrate = shift;
+ my $currentValues = shift;
+ return 1 if (getDiff(\@{$valuesToMigrate},\@{$currentValues}));
+ return 1 if (getDiff(\@{$currentValues},\@{$valuesToMigrate}));
+ return 0 ;
+}
+
+sub getDiff {
+ # we get references to arrays
+ my $elements = shift ;
+ my $existing_elements = shift ;
+ my %count = () ;
+ my %countEE = () ;
+ @diff = () ;
+ foreach $e (@{$elements}, @{$existing_elements}) { $count{$e}++ ;}
+ foreach $e (@{existing_elements}) { $countEE{$e}++ ;}
+ foreach $e (@{$elements}) {
+ # if $e is only present in @$elements, we push it to the diff array
+ if (($count{$e} == 1) && ($countEE{$e} == 0)) {
+ push @diff, $e ;
+ }
+ }
+ return @diff ;
+}
+
+sub registerSuffix_Backend {
+ my $ldbmDatabase = shift;
+ my $CN = $ldbmDatabase->{cn}[0];
+ my $suffixArg = "nsslapd-suffix";
+ my $suffix = $ldbmDatabase->{$suffixArg}[0];
+ $oldBackends{$suffix} = $CN;
+}
+
+
+#############################################################################
+# #
+# #
+# #
+#############################################################################
+sub migrateLDBM_backend_instances {
+ foreach $entry (@LDBM_backend_instances) {
+ my $DN = $entry->getDN(1); # 1 is to normalize the DN
+ my $CN = $entry->{cn}[0];
+ if ($DN =~/cn=netscaperoot,cn=ldbm database/i){
+ printTrace("\n\n*** INFORMATION - NetscapeRoot is NOT migrated",0);
+ }
+ else {
+ if(alreadyExistsIn51($entry)){
+ printMsg("\n\n*** LDBM_BACKEND_INSTANCE - $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ printTrace("\nWe should add the backend instance $DN",3);
+ my $suffixarg = "nsslapd-suffix" ;
+ my $suffixname= $entry->{$suffixarg}[0] ;
+ my $new51entry = $conn->newEntry() ;
+ $new51entry->setDN($DN);
+ $new51entry->setValues("objectclass", "top", "extensibleObject", "nsBackendInstance" );
+ $new51entry->setValues("cn", $CN );
+ $new51entry->setValues($suffixarg, $suffixname);
+ my @params = keys(%LDBMparamToMigrate);
+ foreach $param (@params) {
+ my @values = $entry->getValues($param);
+ $new51entry->setValues($param, @values) if (@values);
+ }
+ if (addEntryTo51($new51entry, "LDBM_BACKEND_INSTANCE",1)) {
+ push @BACKENDS, $CN;
+ }
+ }
+ }
+ }
+}
+
+sub parseLDBM_backend_instance {
+ my $entry = shift;
+ &registerSuffix_Backend($entry);
+ push @LDBM_backend_instances, $entry;
+}
+
+#############################################################################
+sub migrateMappingTree {
+ foreach $entry (@Mapping_tree_entries) {
+ my $DN = $entry->getDN(1); # 1 si to normalize the DN
+ if ($DN =~/cn=\"o=netscaperoot\",cn=mapping tree,cn=config/i){
+ # DO NOTHING
+ }
+ else {
+ if(alreadyExistsIn51($entry)){
+ printMsg("\n\n*** MAPPING_TREE - $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ addEntryTo51($entry, "MAPPING_TREE",1);
+ }
+ }
+ }
+}
+
+
+sub parseMapping_tree{
+ my $entry = shift;
+ push @Mapping_tree_entries, $entry;
+}
+
+#############################################################################
+sub migrateDefaultIndexes {
+ foreach $index (@default_indexes) {
+ my $CN = $index->{cn}[0];
+ my $new51index ;
+ if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)})) {
+ if ($new51index = alreadyExistsIn51($index)) {
+ if (! isAsystemIndex($new51index)) {
+ updateEntry($index, "DEFAULT_INDEX", 1, 2);
+ }
+ }
+ else {
+ addEntryTo51($index, "DEFAULT_INDEX", 2);
+ }
+ }
+ }
+}
+
+
+sub parseDefaultIndex{
+ my $index = shift;
+ push @default_indexes, $index;
+}
+
+#############################################################################
+
+sub migrateIndexes {
+ foreach $index (@indexes) {
+ my $CN = $index->{cn}[0];
+ my $new51index;
+ if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)}) && (DN !~ /cn=netscaperoot,cn=index/i)){
+ if ($new51index = alreadyExistsIn51($index)) {
+ if (! isAsystemIndex($new51index)) {
+ updateEntry($index, "INDEX", 1, 2);
+ }
+ }
+ else {
+ addEntryTo51($index, "INDEX", 2);
+ }
+ }
+ }
+}
+
+sub parseIndex{
+ my $index = shift;
+ push @indexes, $index;
+}
+
+#############################################################################
+
+sub newLDIFplugin {
+ my $current51plugin = shift;
+ my $DN = $current51plugin->getDN(1);
+ my $new51plugin = $conn->newEntry() ;
+ $new51plugin->setDN($DN);
+ foreach $Attr (@pluginAttrs) {
+ my @values = $current51plugin->getValues($Attr);
+ $new51plugin->setValues($Attr, @values) if (@values);
+ }
+ return $new51plugin;
+}
+
+sub migrateStdPlugin{
+ my $plugin = shift;
+ my $DN = $plugin->getDN(1);
+ my $pluginEnable = "nsslapd-pluginEnabled";
+ my $argNum = 0;
+ my $argPrefix = "nsslapd-pluginarg";
+ my $current51plugin ;
+ if ($current51plugin = alreadyExistsIn51($plugin, 1)) {
+ $plugin = updatePathInPluginArgs($plugin);
+ my $pluginEnableValue = $plugin->{$pluginEnable}[0];
+ my $cont = 1;
+ my $pluginHasChanged = 0;
+ my $new51plugin = &newLDIFplugin($current51plugin);
+ if (! $current51plugin->hasValue($pluginEnable,$pluginEnableValue,1)){
+ $new51plugin->setValues($pluginEnable, $pluginEnableValue);
+ $pluginHasChanged = 1 unless ($pluginHasChanged);
+ }
+ while($cont){
+ my $arg = $argPrefix . $argNum ;
+ if ($plugin->exists($arg)) {
+ my @values = $plugin->getValues($arg);
+ my $value = $values[0] ;
+ $new51plugin->setValues($arg, $value) if (@values);
+ if ($current51plugin->exists($arg)) {
+ if (! $current51plugin->hasValue($arg,$value,1)) {
+ $pluginHasChanged = 1 unless ($pluginHasChanged);
+ }
+ }
+ else {
+ $pluginHasChanged = 1 unless ($pluginHasChanged);
+ }
+ }
+ else {
+ if ($current51plugin->exists($arg)) {
+ # Just Warn the user. Do nothing.
+ printTrace("\nCompared to 5.0, the current 5.1 plugin $DN belongs this attribute: $arg",2);
+ }
+ else {
+ $cont = 0 ;
+ }
+ }
+ $argNum++;
+ }
+ updateEntry($new51plugin, "STANDARD_PLUGIN", 0, 1) if ($pluginHasChanged);
+ }
+}
+
+#############################################################################
+
+sub migrateConfig_Node{
+ my $config_node = shift;
+ my @params = keys(%GeneralSrvParamToMigrate);
+ my $hasChanged = 0;
+ my $new51config_node;
+ if ($new51config_node = alreadyExistsIn51($config_node, 1)){
+ foreach $param (@params) {
+ if ($config_node->exists($param)){
+ my @valuesToMigrate = $config_node->getValues($param);
+ if (@valuesToMigrate){
+ if ($new51config_node->exists($param)){
+ my @currentValues = $new51config_node->getValues($param);
+ if (Diffs(\@valuesToMigrate, \@currentValues)) {
+ $new51config_node->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ printTrace("\nParam to update: $param with value @valuesToMigrate",3);
+ }
+ }
+ else {
+ $new51config_node->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ printTrace("\nParam to update: $param with value @valuesToMigrate",3);
+ }
+ }
+ }
+ }
+ updateEntry($new51config_node, "CONFIG_NODE", 0, 1) if ($hasChanged);
+ }
+}
+
+#############################################################################
+
+sub migrateConfig_LDBM_database{
+ my $config_ldbm = shift;
+ my @params = keys(%GlobalConfigLDBMparamToMigrate);
+ my $hasChanged = 0;
+ my $new51config_ldbm ;
+ if ($new51config_ldbm = alreadyExistsIn51($config_ldbm, 1)) {
+ foreach $param (@params) {
+ if ($config_ldbm->exists($param)){
+ my @valuesToMigrate = $config_ldbm->getValues($param);
+ if (@valuesToMigrate){
+ if ($new51config_ldbm->exists($param)){
+ my @currentValues = $new51config_ldbm->getValues($param);
+ if (Diffs(\@valuesToMigrate, \@currentValues)) {
+ $new51config_ldbm->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ else {
+ $new51config_ldbm->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ }
+ }
+ updateEntry($new51config_ldbm, "CONFIG_LDBM_DATABASE", 0, 1) if ($hasChanged);
+ }
+}
+
+#############################################################################
+
+sub migrateChainingBE_config{
+ my $chaining_config = shift;
+ my $DN = $chaining_config->getDN(1);
+ my @params = ();
+ my $hasChanged = 0;
+ my $new51chaining_config;
+ if ($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i){
+ $new51chaining_config = searchEntry("cn=config,cn=chaining database,cn=plugins,cn=config");
+ @params = keys(%ChainingConfigParams);
+ }
+ if ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i){
+ $new51chaining_config = searchEntry("cn=default instance config,cn=chaining database,cn=plugins,cn=config");
+ @params = keys(%ChainingDefaultInstanceConfigParams);
+ }
+ foreach $param (@params) {
+ if ($chaining_config->exists($param)){
+ my @valuesToMigrate = $chaining_config->getValues($param);
+ if (@valuesToMigrate){
+ printTrace("\nParam: $param values To migrate: @valuesToMigrate",3);
+ if ($new51chaining_config->exists($param)){
+ my @currentValues = $new51chaining_config->getValues($param);
+ printTrace("\nParam: $param 51 current values: @currentValues",3);
+ if (Diffs(\@valuesToMigrate, \@currentValues)) {
+ $new51chaining_config->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ else {
+ $new51chaining_config->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ }
+ }
+ updateEntry($new51chaining_config, "CHAINING_BACKEND_CONFIG", 0, 1) if ($hasChanged);
+}
+
+#############################################################################
+
+sub registerSuffix_ChainingBE {
+ my $ldbmDatabase = shift;
+ my $CN = $ldbmDatabase->{cn}[0];
+ my $suffixArg = "nsslapd-suffix";
+ my $suffix = $ldbmDatabase->{$suffixArg}[0];
+ $oldChainingBackends{$suffix} = $CN;
+}
+
+sub storeMultiplexorBindDN {
+ my $chaining_instance = shift;
+ my $DN = $chaining_instance->getDN(1);
+ if ($chaining_instance->exists("nsMultiplexorBindDN")){
+ my $bindDN = $chaining_instance->{nsMultiplexorBindDN}[0];
+ my $new51bindDN = searchEntry($bindDN);
+ if (! $new51bindDN){
+ # the bindDN entry doesn't yet exist in 5.1 => it will have to be migrated
+ $MultiplexorBindDNEntriesToMigrate{$bindDN}="\n" ;
+ printTrace("\nThe bindDN: $bindDN need to be migrated",3);
+ }
+ else {
+ # do nothing as the entry already exists in 5.1
+ }
+ }
+
+}
+
+sub importMultiplexorBindDNEntries {
+ # import all entries present in @MultiplexorBindDNEntriesToMigrate in 5.1
+ my @MultiplexorBindDNs = keys (%MultiplexorBindDNEntriesToMigrate);
+ my $ldif_dir = $ldif_rep;
+ foreach $bindDN (@MultiplexorBindDNs) {
+ printTrace("\nimportMultiplexorBindDNEntries: bindDN to migrate: $bindDN",3);
+ # get the backend in which is stored the bind DN entry
+ my $backendtoExportFrom = getBackendtoExportFrom($bindDN);
+ printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3);
+ # check wether the backend has been imported in 5.1 or not
+ if (! alreadyMigrated($backendtoExportFrom)) {
+ if ($backendtoExportFrom ne $NULL) {
+ # if not imported => we need to import the binf DN entry
+ &startServer() unless (isDirectoryAlive());
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir);
+ }
+ else {
+ # do nothing
+ }
+ }
+ }
+ # remove the empty ldif directory
+ rmdir($ldif_dir) if (-d $ldif_dir);
+ # close the LDAP connection to 5.1
+ $conn->close if ($conn);
+}
+
+sub migrateChainingBE_instance{
+ my $chaining_instance = shift;
+ my $DN = $chaining_instance->getDN(1);
+ &registerSuffix_ChainingBE($chaining_instance);
+ if (alreadyExistsIn51($chaining_instance)) {
+ # already exists
+ printMsg("\n\n*** CHAINING_BACKEND_INSTANCE - $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ &migrate_credential($chaining_instance, "nsmultiplexorcredentials");
+ addEntryTo51($chaining_instance, "CHAINING_BACKEND_INSTANCE", 1);
+ storeMultiplexorBindDN($chaining_instance);
+ }
+}
+
+#############################################################################
+
+# create a new LDIF representation of a 5.1 replica consumer
+sub newLDIFreplica {
+ my $replica = shift;
+ my $DN = $replica->getDN(1);
+ my $new51replica = $conn->newEntry() ;
+ my $MASTER_OR_MULTIMASTER = "3" ;
+ $new51replica->setDN($DN);
+ foreach $Attr (@nsds5replicaAttrs) {
+ my @values = $replica->getValues($Attr);
+ $new51replica->setValues($Attr, @values) if (@values);
+ }
+ my $replicaType = $replica->{nsDS5ReplicaType}[0];
+ if ($replicaType eq $MASTER_OR_MULTIMASTER) {
+ my @nsState = $replica->getValues("nsState");
+ $new51replica->setValues("nsState", @nsState);
+ }
+ else {
+ $new51replica->setValues("nsDS5ReplicaId", $replicaIdvalue);
+ }
+ return $new51replica;
+}
+
+sub MigrateNSDS5_replica{
+ foreach $replica (@new51replicas) {
+ my $DN = $replica->getDN(1);
+ my $new51replica;
+ if (alreadyExistsIn51($replica)) {
+ # replica already exists
+ printMsg("\n\n*** NSDS5_REPLICA - $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ $new51replica = &newLDIFreplica($replica);
+ addEntryTo51($new51replica, "NSDS5_REPLICA", 1);
+ storeReplicaBindDN($replica);
+ }
+ }
+}
+
+sub parseNSDS5_replica{
+ my $replica = shift;
+ push @new51replicas, $replica;
+}
+
+sub storeReplicaBindDN {
+ my $replica = shift;
+ my $DN = $replica->getDN(1);
+ if ($replica->exists("nsDS5ReplicaBindDN")){
+ my $bindDN = $replica->{nsDS5ReplicaBindDN}[0];
+ my $new51bindDN = searchEntry($bindDN);
+ if (! $new51bindDN){
+ # the bindDN entry doesn't yet exist in 5.1 => it will have to be migrated
+ $ReplicaBindDNEntriesToMigrate{$bindDN}="\n" ;
+ printTrace("\nThe bindDN: $bindDN need to be migrated",3);
+ }
+ else {
+ # do nothing as the entry already exists in 5.1
+ }
+ }
+}
+
+
+sub importReplicaBindDNEntries {
+ # import all entries present in @ReplicaBindDNEntriesToMigrate in 5.1
+ my @ReplicaBindDNs = keys (%ReplicaBindDNEntriesToMigrate);
+ my $ldif_dir = $ldif_rep;
+ foreach $bindDN (@ReplicaBindDNs) {
+ printTrace("\nimportReplicaBindDNEntries: bindDN to migrate: $bindDN",3);
+ # get the backend in which is stored the bind DN entry
+ my $backendtoExportFrom = getBackendtoExportFrom($bindDN);
+ printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3);
+ # check wether the backend has been imported in 5.1 or not
+ if (! alreadyMigrated($backendtoExportFrom)) {
+ if ($backendtoExportFrom ne $NULL) {
+ # if not imported => we need to import the binf DN entry
+ &startServer() unless (isDirectoryAlive());
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir);
+ }
+ else {
+ # do nothing
+ }
+ }
+ }
+ # remove the empty ldif directory
+ rmdir($ldif_dir) if (-d $ldif_dir);
+ # close the LDAP connection to 5.1
+ $conn->close if ($conn);
+}
+
+sub alreadyMigrated {
+ my $backendToCheck = shift;
+ foreach $backend (@BACKENDS) {
+ return 1 if ($backend eq $backendToCheck);
+ }
+ return 0 ;
+}
+
+sub belongsSuffix {
+ my $suffix = shift;
+ my $bindDN = shift;
+ return ($bindDN =~ /$suffix\s*$/i);
+}
+
+sub length {
+ my $suffix = shift;
+ my $count = 0;
+ while ($suffix =~ /./g) {
+ $count++;
+ }
+ return $count ;
+}
+
+sub getBackendtoExportFrom {
+ my $bindDN = shift ;
+ my $sizeOfSuffix = 0 ;
+ my $NULL = "";
+ my @oldSuffixes = keys(%oldBackends);
+ my @oldChainingSuffixes = keys(%oldChainingBackends);
+ my $bindDN_backend = $NULL;
+ foreach $suffix (@oldSuffixes){
+ printTrace("\ngetBackendtoExportFrom: suffix to compare with is: $suffix",3);
+ if ((belongsSuffix($suffix,$bindDN)) && (length($suffix) > $sizeOfSuffix)) {
+ $sizeOfSuffix = length($suffix);
+ $bindDN_backend = $oldBackends{$suffix};
+ printTrace("\ngetBackendtoExportFrom: bindDN_backend: $bindDN_backend, sizeOfSuffix: $sizeOfSuffix",3);
+ }
+ }
+ foreach $suffix (@oldChainingSuffixes){
+ printTrace("\ngetBackendtoExportFrom: suffix to compare with is a chained suffix: $suffix",3);
+ if ((belongsSuffix($suffix,$bindDN)) && (length($suffix) > $sizeOfSuffix)) {
+ printMsg("\n\n*** Entry stored on a remote backend - $bindDN");
+ printMsg("\n*** We don't migrate it");
+ return $NULL;
+ }
+ }
+ return $bindDN_backend ;
+}
+
+
+sub getBackendtoImportTo {
+ my $bindDN = shift;
+ my $sizeOfSuffix = 0;
+ my $NULL = "";
+ my $suffixArg = "nsslapd-suffix";
+ my $bindDN_backend = $NULL;
+ open( DSELDIF, "< $DSEldif" ) || die "Can't open $DSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ $typeOfEntry = getTypeOfEntry($entry);
+ if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){
+ my $suffix = $entry->{$suffixArg}[0];
+ if ((belongsSuffix($suffix,$bindDN)) && (length($suffix) > $sizeOfSuffix)) {
+ $sizeOfSuffix = length($suffix);
+ $bindDN_backend = $entry->{cn}[0];
+ }
+ }
+ }
+ close(DSELDIF);
+ return $bindDN_backend ;
+}
+
+
+sub ExportAndAddEntry {
+ my $DN = shift;
+ my $backendtoExportFrom = shift;
+ my $ldif_dir = shift;
+ my $ldif = "$ldif_dir${PATHSEP}$backendtoExportFrom.ldif" ;
+ # first: export entry pointed out by the $DN to $ldif file
+ $ENV{"$LIB_PATH"}="$oldDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ if (! $ldif_dir) { $ldif_dir = $ldif_rep ;}
+ if (!(-d $ldif_dir)) {
+ mkdir($ldif_dir,0777) or die "\ncan't create $ldif_dir to store temporary ldif files\n";
+ }
+ chdir($oldSlapdExecDir) or die "\nCould not change directory to $oldSlapdExecDir: $!\n";
+ &db2Ldif($ldif, $backendtoExportFrom, $DN);
+ chdir($curdir) or die "\nCould not change directory to $curdir: $!\n";
+
+ # then: Add it to 5.1
+ if (! $conn) {
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ }
+ open( BINDDNLDIF, "< $ldif" ) || die "\nCan't open $ldif: $!: \n";
+ my $in = new Mozilla::LDAP::LDIF(*BINDDNLDIF) ;
+ while ($entry = readOneEntry $in) {
+ my $entryDN = $entry->getDN(1);
+ if ($DN eq $entryDN) {
+ addEntryTo51($entry, "nsds5ReplicaBindDN", 0);
+ }
+ }
+ close(BINDDNLDIF);
+ # remove the ldif file after the import
+ unlink($ldif) ;
+}
+
+#############################################################################
+sub MigrateNSDS_replication_agreement {
+ foreach $replicationAgreement (@replicationAgreements) {
+ my $DN = $replicationAgreement->getDN(1);
+ if (alreadyExistsIn51($replicationAgreement)){
+ # replication agreement already exists
+ printMsg("\n\n*** NSDS_REPLICATION_AGREEMENT - $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ &migrate_credential($replicationAgreement, "nsDS5ReplicaCredentials");
+ addEntryTo51($replicationAgreement, "NSDS_REPLICATION_AGREEMENT", 1);
+ }
+ }
+}
+
+
+sub parseNSDS_replication_agreement{
+ my $replicationAgreement = shift;
+ push @replicationAgreements, $replicationAgreement ;
+}
+
+#############################################################################
+
+sub migrateChangelog5{
+ my $changelog = shift;
+ my $DN = $changelog->getDN(1);
+ my $changelogdir = "nsslapd-changelogdir";
+ if (alreadyExistsIn51($changelog)){
+ # cn=changelog5,cn=config already exists in 5.1
+ my $new51changelog = searchEntry($DN);
+ my @new51changelodir = $new51changelog->getValues($changelogdir);
+ $changelog->setValues($changelogdir, @new51changelogdir);
+ updateEntry($changelog, "CHANGELOG5", 0, 1);
+ }
+ else {
+ # cn=changelog5,cn=config need to be created in 5.1.
+ # the changelogdir value must be setup to <root_server51>/slapd-instance/changelogdb
+ $changelog->setValues($changelogdir,"${serverHome}${PATHSEP}changelogdb");
+ addEntryTo51($changelog, "CHANGELOG5", 1);
+ }
+}
+
+#############################################################################
+
+sub migrateReplication{
+ my $replication = shift;
+ my $DN = $replication->getDN(1);
+ if (alreadyExistsIn51($replication)){
+ # replication agreement already exists
+ printMsg("\n\n*** $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ addEntryTo51($replication, "REPLICATION", 1);
+ }
+}
+
+#############################################################################
+
+sub migrateSecurity{
+ my $security = shift;
+ if (alreadyExistsIn51($security)){
+ # already exists in 5.1
+ updateEntry($security, "SECURITY", 0, 1);
+ }
+ else {
+ addEntryTo51($security, "SECURITY", 1);
+ }
+}
+
+#############################################################################
+
+sub migrateSNMP{
+ my $snmp = shift;
+ if (alreadyExistsIn51($snmp)){
+ # already exists in 5.1
+ updateEntry($snmp, "SNMP", 0, 1);
+ }
+ else {
+ addEntryTo51($snmp, "SNMP", 1);
+ }
+}
+
+#############################################################################
+# printMsg print message to the user standard output.
+
+sub printMsg {
+
+ my $TypeMsg = shift ;
+ my $Msg = shift ;
+ my $LineNb = shift ;
+ if ($LineNb) {
+ printTrace("Line: $LineNb, $TypeMsg, $Msg");
+ }
+ else {
+ printTrace("$TypeMsg $Msg");
+ }
+}
+
+#############################################################################
+# print message error to the user standard output.
+
+sub printTrace {
+
+ my $Msg = shift ;
+ my $level = shift ;
+ my $sep = shift ;
+
+ if ($sep) {
+ print "\n-------------------------------------------------------------------------";
+ print LOGFILE "\n-------------------------------------------------------------------------";
+ }
+
+ if ($level <= $TRACELEVEL) {
+ print($Msg);
+ print LOGFILE $Msg ;
+ }
+}
+
+#############################################################################
+# this subroutine implements a very stupid version of diff
+
+sub diff {
+ my $f1 = shift;
+ my $f2 = shift;
+ my $lineToBeginWith = shift;
+ my $NULL = "" ;
+ my $diff_f1 = $NULL ;
+ my $diff_f2 = $NULL ;
+ my $retval = $NULL ;
+ my $ret;
+ open(F1, "$f1") or die "Could not open file $f1";
+ open(F2, "$f2") or close(F1), die "Could not open file $f2";
+
+ while (defined($l1 = <F1>)) {
+ if ($lineToBeginWith){
+ $lineToBeginWith -- ;
+ next ;
+ }
+ next if ($l1 =~ /^\#/);
+ $ret = defined($l2 = <F2>);
+ if ($ret) {
+ $ret = defined($l2 = <F2>) while ($ret && ($l2 =~ /^\#/)) ;
+ if ($ret) {
+ if (!($l1 eq $l2)) {
+
+ # ignore whitespace
+ $l1_clean = $l1 ;
+ $l2_clean = $l2 ;
+ $l1_clean =~ s/\s//g;
+ $l2_clean =~ s/\s//g;
+
+ if (!($l1_clean eq $l2_clean)) {
+ $diff_f1 .= "${l1}" unless ($l1_clean eq $NULL);
+ $diff_f2 .= "${l2}" unless ($l2_clean eq $NULL);
+ }
+ }
+ }
+ else {
+ next if ($l1 =~ /^\s*$/) ;
+ $diff_f1 .= "${l1}";
+ }
+ }
+ else {
+ next if ($l1 =~ /^\s*$/) ;
+ $diff_f1 .= "${l1}";
+ }
+ }
+
+ while (defined($l2 = <F2>)) {
+ if (($l2 =~ /^\#/) || ($l2 =~ /^\s*$/)) {
+ next ;
+ }
+ else {
+ $diff_f2 .= "${l2}" ;
+ }
+ }
+
+ close(F1);
+ close(F2);
+
+ $retval .= "- differences present in your config file but not in standard file:\n\n". "$diff_f1\n" if ($diff_f1) ;
+ $retval .= "- differences present in standard file but not in your config file:\n\n" . "$diff_f2" if ($diff_f2) ;
+ return $retval ;
+}
+
+sub CompareStdConfigFiles {
+ # Compare each configuration file against its default version. If it has changed,
+ # notify the user that the file has changed and will need to be checked by the
+ # user. This should be safe to do because there should be no path information
+ # stored in these conf files, which are just schema stuff.
+ # printTrace("\nCheck if standard configuration files have changed",3);
+
+ # get the version of the DS to migrate
+ ($oldVersion, $oldMinor) = &getVersion($oldDir);
+ # get the version of the new DS
+ ($Version, $Minor) = &getVersion($root);
+
+ my $origFilePath = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}install${PATHSEP}schema${PATHSEP}" ;
+ my $FilesChanged = "";
+ my $AllDiffs = "***********************************************************************";
+ my $NoChanges = "" ;
+ my $lineToBegin = 0 ;
+ opendir(CONFDIR, $oldSchemaDir) or
+ die "Error: could not open migrated config dir $oldConfDir: $!";
+
+ foreach $file (readdir(CONFDIR)) {
+ $origFile = $origFilePath . $file ;
+ $configFile = $oldSchemaDir . $file ;
+ if (( exists($stdIncludes{lc($file)})) && (-f $origFile)) {
+ $diffs = &diff($configFile, $origFile, $lineToBegin);
+ $lineToBegin = 0 if $lineToBegin ;
+ if ($diffs) {
+ $FilesChanged .= "\n$configFile";
+ $AllDiffs .= "\n$configFile is different than the standard configuration file" ;
+ $AllDiffs .= "\nYou will need to check this file and make sure its changes are compatible ";
+ $AllDiffs .= "with the new directory server\nHere are the differences:\n";
+ $AllDiffs .= "$diffs \n\n";
+ $AllDiffs .= "***********************************************************************";
+ }
+ else {
+ $NoChanges .= "\n$configFile";
+ }
+ }
+ }
+ closedir(CONFDIR);
+
+if ($FilesChanged) {
+ printTrace("\nNo changes to old configuration files:$NoChanges",3) ;
+ printTrace("\n***********************************************************************",3) ;
+ printMsg("\nThe following standard files have been modified: $FilesChanged");
+ if ($NO_INPUT_USER) {
+ # do nothing
+ }
+ else {
+ printMsg("\nDo you want to see the differences Yes/No [No] ?") ;
+ my $answer = <STDIN> ;
+ if ($answer =~ /y|yes/i) {
+ printMsg("$AllDiffs");
+ }
+ printMsg("\nDo you want to continue the migration Yes/No [No] ?");
+ $answer = <STDIN> ;
+ if (! ($answer =~ /y|yes/i)) {
+ exit(1);
+ }
+ }
+ }
+}
+
+
+
+#############################################################################
+
+# this is used to run the system() call, capture exit and signal codes,
+# and die() upon badness; the first argument is a directory to change
+# dir to, if any, and the rest are passed to system()
+sub mySystem {
+ my $rc = &mySystemNoDie(@_);
+ my ($dir, @args) = @_;
+ if ($rc == 0) {
+# success
+ } elsif ($rc == 0xff00) {
+ die "Error executing @args: error code $rc: $!";
+ } elsif ($rc > 0x80) {
+ $rc >>= 8;
+ die "Error executing @args: error code $rc: $!";
+ } else {
+ if ($rc & 0x80) {
+ $rc &= ~0x80;
+ }
+ die "Error executing @args: received signal $rc: $!";
+ }
+
+ # usually won't get return value
+ return $rc;
+}
+
+# This version does not die but just returns the error code
+sub mySystemNoDie {
+ my ($dir, @args) = @_;
+ if ($dir && ($dir ne "")) {
+ chdir($dir) or die "Could not change directory to $dir: $!";
+ }
+ my $cmd = $args[0];
+ # the system {$cmd} avoids some NT shell quoting problems if the $cmd
+ # needs to be quoted e.g. contains spaces; the map puts double quotes
+ # around the arguments on NT which are stripped by the command
+ # interpreter cmd.exe; but don't quote things which are already quoted
+ my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args;
+ my $rc = 0;
+ if ($cmd =~ /[.](bat|cmd)$/) {
+ # we have to pass batch files directly to the NT command interpreter
+ $cmd = $com_spec;
+# print "system $cmd /c \"@fixargs\"\n";
+ $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\"";
+ } else {
+# print "system $cmd @fixargs\n";
+ $rc = 0xffff & system {$cmd} @fixargs;
+ }
+ chdir(${curdir}) or die "Could not change directory to $curdir: $!";
+ return $rc;
+}
+
+###########################################################################################
+# #
+# Export/Import of the backends in @BACKENDS #
+# #
+###########################################################################################
+
+sub manydb2Ldif {
+ my $ldif_dir = shift;
+ $ENV{"$LIB_PATH"}="$oldDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ if (! $ldif_dir) { $ldif_dir = $ldif_rep ;}
+ if (!(-d $ldif_dir)) {
+ mkdir($ldif_dir,0777) or die "can't create $ldif_dir to store temporary ldif files";
+ }
+ chdir($oldSlapdExecDir) or die "Could not change directory to $oldSlapdExecDir: $!";
+ foreach $backend (@BACKENDS) {
+ my $ldif = "${ldif_dir}$backend.ldif" ;
+ &db2Ldif($ldif, $backend);
+ }
+ print " Done.\n";
+ chdir($curdir) or die "Could not change directory to $curdir: $!";
+}
+
+sub db2Ldif {
+ my $ldif = shift ;
+ my $backend = shift ;
+ my $include_suffix = shift ;
+ my $db2ldif_param ;
+ if ($include_suffix) {
+ $db2ldif_param = "db2ldif -D $oldHome -n $backend -a $ldif -s \"$include_suffix\"";
+ }
+ else {
+ $db2ldif_param = "db2ldif -D $oldHome -n $backend -a $ldif";
+ }
+ open(DB2LDIF, "${quote}${quote}$slapdExecName${quote} $db2ldif_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n";
+ sleep(1); # allow some data to accumulate in the pipe
+ my $ii = 0;
+ while (<DB2LDIF>) {
+ ++$ii;
+ if (($ii % 250) == 0) {
+ printMsg(" Processing...\n");
+ }
+ printMsg($_);
+ }
+ close(DB2LDIF);
+ # set the ownership of the ldif file; should be the same as the 5.x slapd user id
+ if ((! $isNt) && ($oldlocaluser ne $localuser)) {
+ if (-f $ldif) {
+ chown( $newuid, $newgid, $ldif) or printMsg("\nUnable to change the ownership of $ldif to $localuser") ;
+ }
+ }
+}
+
+sub manyLdif2db {
+ my $ldif_dir = shift;
+ $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ chdir($slapdExecDir) or die "Could not change directory to $slapdExecDir: $!";
+ foreach $backend (@BACKENDS) {
+ my $ldif = "${ldif_dir}$backend.ldif" ;
+ &Ldif2db($ldif, $backend);
+ }
+ # remove the empty ldif directory
+ rmdir($ldif_dir);
+ chdir($curdir) or die "Could not change directory to $curdir: $!";
+}
+
+
+sub Ldif2db {
+ my $ldif = shift ;
+ my $backend = shift ;
+ my $ldif2db_param = "ldif2db -D $serverHome -n $backend -i $ldif";
+ open(LDIF2DB, "${quote}${quote}$slapdExecName${quote} $ldif2db_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n";
+ sleep(1); # allow some data to accumulate in the pipe
+ while (<LDIF2DB>) {
+ printMsg($_);
+ }
+ close(LDIF2DB);
+ # remove the ldif file after the import
+ unlink($ldif) ;
+}
+
+
+###########################################################################################
+# #
+# Running/Stopping the Server #
+# #
+###########################################################################################
+
+
+
+sub isDirectoryAlive {
+ die "\n Migration aborted. Check your 5.0 and 5.1 iPlanet Directory Server are installed on the same machine \n" if ( $LDAPservername == -1 );
+ my $test_conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd);
+ if ($test_conn) {
+ $test_conn->close();
+ return 1;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+
+sub startServer {
+ my $instanceDir = ${serverHome} ;
+ my $errLog = $instanceDir . $PATHSEP . 'logs' . $PATHSEP . 'errors';
+ # emulate tail -f
+ # if the last line we see does not contain "slapd started", try again
+ my $done = 0;
+ my $started = 0;
+ my $code = 0;
+ my $lastLine = "";
+ my $timeout = time + 240; # 4 minutes
+ $ENV{"$LIB_PATH"}="${root}${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+
+ my $startCmd = $instanceDir . $PATHSEP . 'start' . $script_suffix;
+ if (! -f $startCmd) {
+ $startCmd = $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix;
+ }
+ $code = &mySystem($instanceDir,$startCmd);
+ open(IN, $errLog) or die "Could not open error log $errLog: $!";
+ my $pos = tell(IN);
+ while (($done == 0) && (time < $timeout)) {
+ for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) {
+ $lastLine = $_;
+ # print;
+ # the server has already been started and shutdown once . . .
+ if (/slapd started\./) {
+ $started++;
+ if ($started == 2) {
+ $done = 1;
+ }
+ # sometimes the server will fail to come up; in that case, restart it
+ } elsif (/Initialization Failed/) {
+ # print "Server failed to start: $_";
+ $code = &mySystem($instanceDir, $startCmd);
+ # sometimes the server will fail to come up; in that case, restart it
+ } elsif (/exiting\./) {
+ # print "Server failed to start: $_";
+ #$code = &mySystem($startCmd);
+ $code = &mySystem($instanceDir, $startCmd);
+ }
+ }
+ if ($lastLine =~ /PR_Bind/) {
+ # server port conflicts with another one, just report and punt
+ print $lastLine;
+ print "This server cannot be started until the other server on this\n";
+ print "port is shutdown.\n";
+ $done = 1;
+ }
+ if ($done == 0) {
+ # rest a bit, then . . .
+ sleep(2);
+ # . . . reset the EOF status of the file desc
+ seek(IN, $pos, 0);
+ }
+ }
+ close(IN);
+
+ sleep(5);
+ die "\nUnable to start the $Version.$Minor iPlanet Directory Server\n" unless (isDirectoryAlive());
+
+ return 0;
+}
+
+sub stopServer {
+ my $root = shift;
+ my $name = shift;
+ $maxStopIterations = 5;
+ print "\nShutting down server $name . . .\n";
+ $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop' . $script_suffix . $quote;
+ if (! -f $stopCmd) {
+ $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop-slapd' . $script_suffix . $quote;
+ }
+
+ if (! -f $stopCmd) {
+ # no stop command, probably a 1.X system; for NT, we'll try net stop
+ # for unix, we'll get the pid and kill it
+ if ($isNT) {
+ $stopCmd = 'net stop ' . $name;
+ } else {
+ # see if there is a pid file
+ $pidfile = $root . $PATHSEP . $name . $PATHSEP . 'logs' .
+ $PATHSEP . 'pid';
+ if (open(PIDFILE, $pidfile)) {
+ chomp($pid = <PIDFILE>);
+ close(PIDFILE);
+ while ($maxStopIterations-- && !$exitCode) {
+ $exitCode = kill(15, $pid);
+ }
+ $stopCmd = undef;
+ }
+ }
+ }
+
+ # keep looping until the stop cmd returns an error code, which usually
+ # means that what ever we want to stop is stopped, or some other error
+ # occurred e.g. permission, or no such service
+ $exitCode = &runAndIgnoreOutput($stopCmd);
+# print "stopServer: exitCode=$exitCode\n";
+ while ($stopCmd && $maxStopIterations-- && $exitCode) {
+ $exitCode = &runAndIgnoreOutput($stopCmd);
+# print "stopServer: exitCode=$exitCode\n";
+ }
+
+ if (!$maxStopIterations) {
+ print "Warning: could not shutdown the server: $!\n";
+ }
+ sleep(10) ;
+ $exitCode = 0;
+}
+
+
+sub runAndIgnoreOutput {
+ my $cmd = shift;
+ printMsg(".");
+ open(RUNCMD, "${quote}$cmd${quote} 2>&1 |") or die "Error: could not run $cmd: $!";
+ printMsg(".");
+ sleep(1); # allow pipe to fill with data
+ printMsg(".");
+ while (<RUNCMD>) {
+# print;
+ }
+ my $code = close(RUNCMD);
+# print "runAndIgnore: code=$code status=$?\n";
+ return $?;
+}
+
+#############################################################################
+# migrate SSL info
+
+sub MigrateSSL {
+ my $secPwd = 'bidon' ;
+ # copy the SSL directory
+ &copyDir("$oldHome${PATHSEP}ssl","$serverHome${PATHSEP}ssl") if (-d "$oldHome${PATHSEP}ssl");
+ # copy the cert db and key files
+ if ( -d "$oldDir${PATHSEP}alias") {
+ $aliasDir = "$root${PATHSEP}alias";
+ if (! -d $aliasDir) {
+ mkdir($aliasDir, 0750);
+ }
+ my $keydb = "$aliasDir${PATHSEP}slapd-$newname-key3.db" ;
+ my $certdb = "$aliasDir${PATHSEP}slapd-$newname-cert7.db" ;
+ my $old_keydb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-key3.db" ;
+ my $old_certdb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-cert7.db";
+ my $keydb_backup = "$aliasDir${PATHSEP}slapd-$newname-key3.db_backup" ;
+ my $certdb_backup = "$aliasDir${PATHSEP}slapd-$newname-cert7.db_backup" ;
+ if (-f $old_keydb) {
+ if (-f $keydb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$keydb already exists. backup in $keydb_backup ...");
+ &copyBinFile($keydb,$keydb_backup);
+ &copyBinFile($old_keydb,$keydb);
+ }
+ else {
+ print("\n\n$keydb already exists. Do you want to overwrite it ? [no]: ");
+ my $answer = <STDIN> ;
+ if ($answer =~ /^y|yes$/i) {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ if (-f $old_certdb) {
+ if (-f $certdb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$certdb already exists. backup in $certdb_backup ...");
+ &copyBinFile($certdb,$certdb_backup);
+ &copyBinFile($old_certdb,$certdb);
+ }
+ else {
+ print("\n\n$certdb already exists. Do you want to overwrite it ? [no]: ");
+ my $answer = <STDIN> ;
+ if ($answer =~ /^y|yes$/i) {
+ &copyBinFile($old_certdb,$certdb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_certdb,$certdb);
+ }
+ }
+ # copy the old password file
+ if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") {
+ &copyBinFile(
+ "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt",
+ "$aliasDir${PATHSEP}$type-$newname-pin.txt"
+ );
+ }
+ }
+
+}
+
+sub DisableSSL {
+ my $entry = $conn->search("cn=config","base","objectclass=*");
+ my $LDAPparam = "nsslapd-security" ;
+ my $Value = "off" ;
+ if ($entry->{$LDAPparam}[0] ne $Value) {
+ printTrace("\nDisable SSL...",1);
+ $entry->setValues($LDAPparam, $Value);
+ }
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nSSL disabled",2);
+ }
+ else {
+ printMsg("\nCan't disabled SSL. The server may have problems to start");
+ }
+}
+
+# enable the migration of client authentication informations
+sub MigrateCertmap {
+ # backup the old certmap.conf and replace it with the new one
+ my $oldCertmap = "$oldDir${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf";
+ my $newCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf" ;
+ my $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ;
+ if (-f $oldCertmap) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$newCertmap has been backup in $backupCertmap");
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($oldCertmap,$newCertmap);
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\n\nWhere do you want to back up the file $newCertmap [$backupCertmap] ?") ;
+ my $Answer = <STDIN> ;
+ $backupCertmap = $Answer if ($Answer ne "\n");
+ chomp($backupCertmap);
+ printTrace("\nDest: .$backupCertmap.",4);
+ if (-e $backupCertmap) {
+ printMsg("\n\n$backupCertmap already exists. Do you want to overwrite it Yes/No [No] ?") ;
+ if (<STDIN> =~ /yes|y/i) {
+ $Ask = 0 ;
+ }
+ else {
+ $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ;
+ }
+ }
+ else {
+ $Ask = 0 ;
+ }
+ }
+ printTrace("\nBackup file: $newCertmap in $backupCertmap",4);
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($oldCertmap,$newCertmap);
+ }
+ }
+ else {
+ }
+}
+
+sub hasChangedoldCertmap {
+ my $certmapfile = shift ;
+ my @reference = ("certmap default default",
+ "default:DNComps",
+ "default:FilterComps e") ;
+ my $cpt = 0 ;
+ printTrace("\nhasChangedoldCertmap",3);
+ open(CERTMAP,"< $certmapfile");
+ while (<CERTMAP>) {
+ if ((! /^\s*#/) && (! /^\s*$/)) {
+ my $ref = $reference[$cpt] ;
+ printTrace("\nValue: $_, ref: $ref",4);
+ if (! /^\s*$ref\s*$/) {
+ return 1 ;
+ }
+ else {
+ $cpt++ ;
+ }
+ }
+ }
+ close (CERTMAP);
+ printTrace("\ncpt: $cpt",4);
+ if ($cpt < $#reference) {
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+
+###########################################################################################
+# #
+# Copy directory and files functions #
+# #
+###########################################################################################
+
+
+sub copyDir {
+ my $src = shift;
+ my $dest = shift;
+ my $exclude = shift;
+
+ opendir( SRC, $src ) or die "Can't open directory $src: $!: ";
+ my $mode;
+ my $uid;
+ my $gid;
+ mkdir ( $dest , 0755 ) or die "\nCan't create directory $dest. \nPlease check you have enough rights to create it and/or check that your parent directory exists.\n" if !( -e $dest );
+ if ($PRESERVE) {
+ $mode = (stat($src))[2];
+ ($uid, $gid) = (stat(_))[4..5];
+ # Make sure files owned by the old user are owned by the
+ # new user
+ if ($uid == $olduid) {
+ $uid = $newuid;
+ $gid = $newgid;
+ }
+ chown $uid, $gid, $dest;
+ chmod $mode, $dest;
+ }
+ local ( @files ) = readdir ( SRC );
+ closedir( SRC );
+ for ( @files ) {
+ if ( $_ eq "." || $_ eq ".." ) {
+ next;
+ } elsif ( $exclude && /$exclude/ ) {
+ next;
+ } elsif( -d "$src${PATHSEP}$_") {
+ &copyDir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" );
+ } else {
+ &copyBinFile ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_");
+ }
+ }
+}
+
+sub copyBinFile {
+ my $src = shift;
+ my $dest = shift;
+ my $buf = "";
+ my $bufsize = 8192;
+
+ open( SRC, $src ) || die "Can't open $src: $!\n";
+ # if we are given a directory destination instead of a file, extract the
+ # filename portion of the source to use as the destination filename
+ if (-d $dest) {
+ $dest = $dest . $PATHSEP . &basename($src);
+ }
+ open( DEST, ">$dest" ) || die "Can't create $dest: $!\n";
+ binmode SRC;
+ binmode DEST;
+ if ($PRESERVE) {
+ $mode = (stat($src))[2];
+ ($uid, $gid) = (stat(_))[4..5];
+ # Make sure files owned by the old user are owned by the
+ # new user
+ if ($uid == $olduid) {
+ $uid = $newuid;
+ $gid = $newgid;
+ }
+ chown $uid, $gid, $dest;
+ chmod $mode, $dest;
+ }
+ while (read(SRC, $buf, $bufsize)) {
+ print DEST $buf;
+ }
+ close( SRC );
+ close( DEST );
+}
+
+#############################################################################################################
+# backup 5.x configuration files #
+# backup the directory <root_server5>/slapd-instance/config dans <root_server5>/slapd-instance/BackupConfig # #
+# #
+#############################################################################################################
+
+
+sub backupConfigFiles {
+ # backup the 5.x config files
+ my $src = "$serverHome${PATHSEP}config" ;
+ my $dest = "$serverHome${PATHSEP}config_backup" ;
+ if ($NO_INPUT_USER) {
+ printMsg("\n$src has been backup in $dest");
+ &copyDir($src,$dest);
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\n\nWhere do you want to back up your configuration directory [$dest] ?") ;
+ my $Answer = <STDIN> ;
+ $dest = $Answer if ($Answer ne "\n");
+ chomp($dest);
+ printTrace("\nDest: .$dest.",4);
+ if (-e $dest) {
+ printMsg("\n\n$dest already exists. Do you want to overwrite it Yes/No [No] ?") ;
+ if (<STDIN> =~ /yes|y/i) {
+ $Ask = 0 ;
+ }
+ else {
+ $dest = "$serverHome${PATHSEP}config_backup" ;
+ }
+ }
+ else {
+ $Ask = 0 ;
+ }
+ }
+ printTrace("\nBackup Directory: $src in $dest",4);
+ &copyDir($src,$dest);
+ }
+}
+#############################################################################
+
+sub getLDAPservername {
+ my $oldLDAPservername;
+ my $LDAPservername;
+ my $localhost = "nsslapd-localhost";
+ open(OLDDSELDIF, "< $oldDSEldif") or die "\nError: could not open old config file $oldDSEldif \n";
+ my $in = new Mozilla::LDAP::LDIF(*OLDDSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ my $DN = $entry->getDN(1) ;
+ if ($DN =~ /^cn=config$/i) {
+ my @values = $entry->getValues($localhost);
+ if ($entry->size($localhost)) {
+ $oldLDAPservername = $values[0];
+ printTrace("\nName of the old LDAP server: $oldLDAPservername",3);
+ }
+ break;
+ }
+ }
+ close(OLDSELDIF);
+
+ open( DSELDIF, "< $DSEldif" ) || die "\nCan't open $DSEldif \n";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ my $DN = $entry->getDN(1) ;
+ if ($DN =~ /^cn=config$/i) {
+ my @values = $entry->getValues($localhost);
+ if ($entry->size($localhost)) {
+ $LDAPservername = $values[0];
+ printTrace("\nName of the new LDAP server: $LDAPservername",3);
+ }
+ break;
+ }
+ }
+ close(DSELDIF);
+ # check ol and new Directory Instance are installed on the same physical machine.
+ if (lc($oldLDAPservername) ne lc($LDAPservername)) {
+ # warn the user he tries to migrate a 4.x server installed on a different machine from the 5.x one
+ printMsg("\n\nYour old instance is on $oldLDAPservername, whereas your new instance is on $LDAPservername. Migration on different machines is not supported. Do you want to continue ? Yes/No [No]:") ;
+ if (! (<STDIN> =~ /yes|y/i)) {
+ return -1;
+ }
+ }
+ return $LDAPservername ;
+}
+
+#############################################################################
+
+sub getVersion {
+ my $dir = shift;
+ my $version = 0;
+ my $minor = 0;
+ my $buildNumber = 0;
+ my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+ my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}";
+
+ # find the slapd executable
+ $prog = $dir . $progDir . $slapdExecName;
+ if (! -f $prog) {
+ $prog = $dir . $progDir2 . $slapdExecName;
+ if (-f $prog && $isNT) {
+ # if slapd is in bin/slapd and we're on NT, just assume version 1;
+ # apparently, slapd.exe doesn't like the -v argument . . .
+ return ( '1', $minor );
+ }
+ else{
+ die "Could not run slapd program $prog: $!";
+ }
+ }
+ else {
+ chdir($dir . $progDir) or die "Could not change directory to $dir$progDir: $!";;
+ }
+ $ENV{"$LIB_PATH"}="$dir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ # read the old version from the old slapd program
+
+ open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or
+ die "Could not run slapd program $prog: $!";
+ sleep(1); # allow some data to accumulate in the pipe
+# print "Output from $prog -v:\n";
+ while (<F>) {
+ #print;
+ if (/^Netscape-Directory\/(\d+)\.(\d+)\s+(\S+)/) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ last;
+ }
+ elsif (/^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ...
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ last;
+ }
+ elsif (/^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ last;
+ }
+ }
+ $code = close(F);
+# print "$prog returned code=$code status=$?\n";
+ $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+
+ if ($version == 0) {
+ die "\nCould not determine version of the directory server in $dir: \n";
+ }
+
+ # distinguish the 4.1 and the 4.11 thanks to the buildNumber
+ if (($version == 4) && ($minor == 1)){
+ if (! ($buildNumber =~ /^B99\.16/)) {
+ # it's not a 4.1 Netscape Directory Server => it's a 4.11
+ $minor = 11 ;
+ }
+ }
+ chdir($curdir) or die "Could not change directory to $curdir: $!" ;
+ return ( $version, $minor );
+}
+
+
+###############################################################################################
+sub normalizeDir {
+ my $dir = shift ;
+ my $dir_prec = "" ;
+ while ($dir_prec ne $dir) {
+ $dir_prec = $dir ;
+ if ($isNT) {
+ grep { s@\\\\@\\@g } $dir ;
+ }
+ else {
+ grep { s@//@/@g } $dir ;
+ }
+ }
+ return $dir ;
+}
+
+
+###############################################################################################
+
+sub GetTime {
+ my $tm = localtime;
+ (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900);
+ $sec = "0$sec" unless $sec > 9 ;
+ $min = "0$min" unless $min > 9 ;
+ $hour = "0$hour" unless $hour > 9 ;
+ $dd = "0$dd" unless $dd > 9 ;
+ $mm = "0$mm" unless $mm > 9 ;
+ return ($sec, $min, $hour, $dd, $mm, $yy);
+}
+
+###############################################################################################
+# get uid and group id of the 5.x slapd server.
+# The uid is done through the nsslapd-localuser attribute
+
+sub getuid_gid {
+ my $newuid ;
+ my $newgid ;
+ my $localuser ;
+ my $localuser_attr = "nsslapd-localuser" ;
+ if (! $isNT) {
+ &startServer() unless (isDirectoryAlive());
+ my $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ my $entry = $conn->search("cn=config ", "base","objectclass=*", 0, ($localuser_attr)) ;
+ # Tests wether we succeed to get the entry cn=config
+ die "\nCan't get the entry cn=config \n" unless ($entry);
+ my @values = $entry->getValues($localuser_attr);
+ $conn->close();
+ if ($#values == -1 || ($values[0] eq "") ) { # tests wether the nsslapd-localuser attribute has a value
+ printMsg("\nNo localuser has been found in the configuration of the directory. ");
+ if ($NO_INPUT_USER) {
+ printMsg("\nWe considered nobody as the localuser");
+ $localuser = "nobody" ;
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\nUnder what user does your $Version.$Minor directory server run [nobody] ? ") ;
+ $localuser = <STDIN> ;
+ chomp($localuser);
+ $localuser = "nobody" if ($localuser eq "");
+ ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ;
+ if ($newuid) {
+ $Ask = 0 ;
+ }
+ else {
+ printMsg("\nError: $localuser is unknown from the system ");
+ }
+ }
+ }
+ }
+ else {
+ $localuser = $values[0]; # returns the first value (we should only have one localuser)
+ my $size = $#values ;
+ }
+ ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ;
+ return ($localuser, $newuid, $newgid) ;
+ }
+ else {
+ return () ;
+ }
+}
+
+sub getolduid_gid {
+ my $oldlocaluser ;
+ my $localuserAttr = "nsslapd-localuser";
+ my $entry ;
+ if (! $isNT) {
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ $typeOfEntry = getTypeOfEntry($entry);
+ if ($typeOfEntry eq "CONFIG_NODE") {
+ $oldlocaluser = $entry->{$localuserAttr}[0] if ($entry->exists($localuserAttr));
+ break ;
+ }
+ }
+ close(DSE);
+ ($olduid, $oldgid) = (getpwnam("$oldlocaluser"))[2..3] ;
+ return ($oldlocaluser, $olduid, $oldgid) ;
+ }
+ else {
+ return ();
+ }
+}
+###############################################################################################
+# get current directory
+
+sub getCwd {
+ my $command = $isNT ? "cd" : "/bin/pwd";
+ open(PWDCMD, "$command 2>&1 |") or
+ die "Error: could not execute $command: $!";
+ # without the following sleep, reading from the pipe will
+ # return nothing; I guess it gives the pwd command time
+ # to get some data to read . . .
+ sleep(1);
+ my $currentdir;
+ while (<PWDCMD>) {
+ if (!$currentdir) {
+ chomp($currentdir = $_);
+ }
+ }
+ my $code = close(PWDCMD);
+# if ($code || $?) {
+# print "$command returned code=$code status=$? dir=$curdir\n";
+# }
+# print "getCwd curdir=\[$curdir\]\n";
+ return $currentdir;
+}
+
+################################
+# Need to migrate the credential.
+# If the credential can not be migrated, leave it at it is
+################################
+sub migrate_credential{
+ my $entry_to_modify = shift;
+ my $credentials_attr = shift;
+ my @old_value = $entry_to_modify->getValues($credentials_attr);
+ my $migratecredExecName = 'migratecred';
+
+ my @new_cred = `${quote}${quote}$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}admin${PATHSEP}bin${PATHSEP}$migratecredExecName${quote} -o $oldHome -n $serverHome -c @old_value`;
+
+ if ( $? == 0 )
+ {
+ $entry_to_modify->setValues($credentials_attr, @new_cred);
+ }
+}
+
diff --git a/ldap/admin/src/scripts/template-migrate5to6 b/ldap/admin/src/scripts/template-migrate5to6
new file mode 100644
index 00000000..3cc5bd58
--- /dev/null
+++ b/ldap/admin/src/scripts/template-migrate5to6
@@ -0,0 +1,3043 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# Migrate a 5.x directory server to a 6.2 directory server
+
+#######################################################################################################
+# enable the use of Perldap functions
+require DynaLoader;
+
+use Getopt::Std;
+use Mozilla::LDAP::Conn;
+use Mozilla::LDAP::Entry;
+use Mozilla::LDAP::LDIF;
+use Mozilla::LDAP::Utils qw(:all);
+use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API
+use Time::localtime;
+use File::Basename;
+use Class::Struct ;
+
+#######################################################################################################
+
+sub usage {
+ print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n");
+ print(STDERR " -o oldInstancePath -n newInstancePath [-t tracelevel] [-L logfile]\n");
+ print(STDERR "************** parameters in brackets are optionals, others are required **************\n");
+ print(STDERR " Opts: -D rootdn - new 6.2 Directory Manager\n");
+ print(STDERR " : -w password - new 6.2 Directory Manager's password\n");
+ print(STDERR " : -w - - Prompt for new 6.2 Directory Manager's password\n");
+ print(STDERR " : -j filename - Read new 6.2 Directory Manager's password from file\n");
+ print(STDERR " : -p port - new 6.2 Directory Server port\n");
+ print(STDERR " : -o oldInstancePath - Path of the old instance to migrate \n");
+ print(STDERR " : -n newInstancePath - Path of the new 6.2 instance\n");
+ print(STDERR " : [-d dataPath] - Path to directory containing data files to import into new instance\n");
+ print(STDERR " : [-v oldVersion] - Version of old instance (obtained by running $slapdExecName -v\n");
+ print(STDERR " : [-t tracelevel] - (optional) specify the level of trace (0..3)\n");
+ print(STDERR " : [-L logfile] - (optional) specify the file to log the migration report \n");
+ }
+########################################################################################################
+
+BEGIN {
+
+ require 'uname.lib' ;
+ $isNT = -d '\\';
+ $PATHSEP = $isNT ? "\\" : "/";
+ ${SEP} = $isNT ? ";" : ":" ;
+ @INC = ( '.', '../../../admin/admin/bin');
+ grep { s@/@\\@g } @INC if $isNT;
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ # NT needs quotes around some things unix doesn't
+ $quote = $isNT ? "\"" : "";
+
+ # If this variable is set, all file/directory creation will make sure the mode
+ # and ownership of the destination is the same as the source
+ $PRESERVE = 1 if (!$isNT);
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ if ($isNT) {
+ $os = "WINNT";
+ } else {
+ $os = &uname("-s");
+ }
+ if ($isNT) {
+ # we have to pass batch files directly to the NT command interpreter
+ $com_spec = $ENV{ComSpec};
+ if (!$com_spec) {
+ $com_spec = $ENV{COMSPEC};
+ }
+ if (!$com_spec || ! -f $com_spec) {
+ # find the first available command interpreter
+ foreach $drive (c..z) {
+ $com_spec = "$drive:\\winnt\\system32\\cmd.exe";
+ last if (-f $com_spec);
+ $com_spec = undef;
+ }
+ if (! $com_spec) {
+ # punt and pray
+ $com_spec = 'c:\winnt\system32\cmd.exe';
+ }
+ }
+ }
+ if ( $os eq "AIX" ) {
+ $dll_suffix = "_shr.a";
+ }
+ elsif ( $os eq "HP-UX" ) {
+ $dll_suffix = ".sl";
+ }
+ elsif ( $os eq "WINNT" ) {
+ $dll_suffix = ".dll";
+ }
+ else {
+ $dll_suffix = ".so";
+ }
+ $slapdExecName = $isNT ? 'slapd.exe' : './ns-slapd';
+ select STDERR;
+ $| = 1;
+ select STDOUT;
+ $| = 1;
+}
+
+SWITCH: {
+ if ($os eq "AIX") {
+ $LIB_PATH = "LIBPATH" ;
+ last SWITCH ;
+ }
+ if ($os eq "HP-UX") {
+ $LIB_PATH = "SHLIB_PATH" ;
+ last SWITCH ;
+ }
+ if ($isNT) {
+ $LIB_PATH = "PATH" ;
+ last SWITCH ;
+ }
+ else {
+ $LIB_PATH = "LD_LIBRARY_PATH" ;
+ last SWITCH ;
+ }
+ }
+
+ # old parameters
+ ${oldDir} = "" ;
+ ${oldname} = "" ;
+ ${oldHome} = "" ;
+ ${oldConfDir} = "" ;
+ ${oldlocaluser} ;
+ ${olduid} ;
+ ${oldgid} ;
+
+ # new parameters
+ ${root} = "{{DS-ROOT}}" ;
+ ${type} = "" ;
+ ${newname} = "" ;
+ ${newport} = "" ;
+ ${rootDN} = "" ;
+ ${rootpwd} = "" ;
+ ${localhost} = "" ;
+ ${LogFileReport} = "" ;
+ ${newuid} ;
+ ${localuser} ;
+ ${newgid} ;
+ $NO_INPUT_USER = 0 ; # by default user can give inputs during the migration process
+ ${curdir} = getCwd();
+ ${slapdExecDir} = "${root}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+ # in 6.2 the replica Id is setup to a static value
+ $replicaIdvalue = 65535;
+
+ # specify the level of trace
+ $TRACELEVEL=1;
+
+ $LDAP_SERVER_UNREACHABLE = 81;
+
+ # get input users
+ &getParameters() ;
+ ${oldDir} = &normalizeDir("${oldDir}");
+ ${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ;
+ ${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ;
+ ${oldSchemaDir} = "${oldConfDir}schema${PATHSEP}";
+ ${oldDSEldif} = "${oldConfDir}dse.ldif";
+ ${serverHome} = "${root}${PATHSEP}$type-$newname" ;
+ ${schemaDir} = "$serverHome${PATHSEP}config${PATHSEP}schema${PATHSEP}";
+ ${DSEldif} = "$serverHome${PATHSEP}config${PATHSEP}dse.ldif";
+ ${ldif_rep} = "${oldConfDir}ldif${PATHSEP}" ;
+ ${oldSlapdExecDir} = "${oldDir}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+
+ open(LOGFILE, ">> $LogFileReport");
+
+ printTrace("\noldDir: $oldDir, oldHome: $oldHome, \noldConfDir: $oldConfDir, \nldif_rep: $ldif_rep, \nrootDN: $rootDN, \nPort: $newport, \nNewname: $newname\n",3);
+ printTrace("\nLIB_PATH: $LIB_PATH",4);
+
+ if (!(-d $serverHome)) {
+ printMsg("\n$serverHome doesn't exist\n");
+ exit(1);
+ }
+ if (!(-d $oldHome)) {
+ printMsg("\n$oldHome doesn't exist\n");
+ exit(1);
+ }
+
+ if ($olddatadir && !(-d $olddatadir)) {
+ print("\n$olddatadir doesn't exist\n");
+ exit(1);
+ }
+
+
+%HashParametersName = ();
+
+# The following hash displays only general server parameters to migrate under cn=config
+%GeneralSrvParamToMigrate = (
+ 'nsslapd-accesscontrol'=> '\n',
+ 'nsslapd-errorlog-logging-enabled'=> '\n',
+ 'nsslapd-accesslog-logging-enabled'=> '\n',
+ 'nsslapd-auditlog-logging-enabled'=> '\n',
+ 'nsslapd-accesslog-level'=> '\n',
+ 'nsslapd-accesslog-logbuffering'=> '\n',
+ 'nsslapd-accesslog-logexpirationtime'=> '\n',
+ 'nsslapd-accesslog-logexpirationtimeunit'=> '\n',
+ 'nsslapd-accesslog-logmaxdiskspace'=> '\n',
+ 'nsslapd-accesslog-logminfreediskspace'=> '\n',
+ 'nsslapd-accesslog-logrotationtime'=> '\n',
+ 'nsslapd-accesslog-logrotationtimeunit'=> '\n',
+ 'nsslapd-accesslog-maxlogsize'=> '\n',
+ 'nsslapd-accesslog-maxLogsPerDir'=> '\n',
+ 'nsslapd-attribute-name-exceptions'=> '\n',
+ 'nsslapd-auditlog-logexpirationtime'=> '\n',
+ 'nsslapd-auditlog-logexpirationtimeunit'=> '\n',
+ 'nsslapd-auditlog-logmaxdiskspace'=> '\n',
+ 'nsslapd-auditlog-logminfreediskspace'=> '\n',
+ 'nsslapd-auditlog-logrotationtime'=> '\n',
+ 'nsslapd-auditlog-logrotationtimeunit'=> '\n',
+ 'nsslapd-auditlog-maxlogsize'=> '\n',
+ 'nsslapd-auditlog-maxLogsPerDir'=> '\n',
+ 'nsslapd-certmap-basedn'=> '\n',
+ 'nsslapd-ds4-compatible-schema'=> '\n',
+ 'nsslapd-enquote-sup-oc'=> '\n',
+ 'nsslapd-errorlog-level'=> '\n',
+ 'nsslapd-errorlog-logexpirationtime'=> '\n',
+ 'nsslapd-errorlog-logexpirationtimeunit'=> '\n',
+ 'nsslapd-errorlog-logmaxdiskspace'=> '\n',
+ 'nsslapd-errorlog-logminfreediskspace'=> '\n',
+ 'nsslapd-errorlog-logrotationtime'=> '\n',
+ 'nsslapd-errorlog-logrotationtimeunit'=> '\n',
+ 'nsslapd-errorlog-maxlogsize'=> '\n',
+ 'nsslapd-errorlog-maxlogsperdir'=> '\n',
+ 'nsslapd-groupevalnestlevel'=> '\n',
+ 'nsslapd-idletimeout'=> '\n',
+ 'nsslapd-ioblocktimeout'=> '\n',
+ 'nsslapd-lastmod'=> '\n',
+ 'nsslapd-listenhost'=> '\n',
+ 'nsslapd-maxdescriptors'=> '\n',
+ 'nsslapd-nagle'=> '\n',
+ 'nsslapd-readonly'=> '\n',
+ 'nsslapd-referralmode'=> '\n',
+ 'nsslapd-plugin-depends-on-name'=> '\n',
+ 'nsslapd-plugin-depends-on-type'=> '\n',
+ 'nsslapd-referral'=> '\n',
+ 'nsslapd-reservedescriptors'=> '\n',
+ 'nsslapd-rootpwstoragescheme'=> '\n',
+ 'nsslapd-schemacheck'=> '\n',
+ 'nsslapd-secureport'=> '\n',
+ 'nsslapd-security'=> '\n',
+ 'nsslapd-sizelimit'=> '\n',
+ 'nsslapd-ssl3ciphers'=> '\n',
+ 'nsslapd-timelimit'=> '\n',
+ 'passwordchange'=> '\n',
+ 'passwordchecksyntax'=> '\n',
+ 'passwordexp'=> '\n',
+ 'passwordhistory'=> '\n',
+ 'passwordinhistory'=> '\n',
+ 'passwordlockout'=> '\n',
+ 'passwordlockoutduration'=> '\n',
+ 'passwordmaxage'=> '\n',
+ 'passwordmaxfailure'=> '\n',
+ 'passwordminage'=> '\n',
+ 'passwordminlength'=> '\n',
+ 'passwordmustchange'=> '\n',
+ 'passwordresetfailurecount' => '\n',
+ 'passwordstoragescheme' => '\n',
+ 'passwordunlock' => '\n',
+ 'passwordwarning' => '\n'
+);
+
+# the following hash displays global parameters related to database stored under cn=config,cn=ldbm database,cn=plugins,cn=config
+%GlobalConfigLDBMparamToMigrate = (
+ 'nsslapd-allidsthreshold' => '\n',
+ 'nsslapd-lookthroughlimit' => '\n',
+ 'nsslapd-mode' => '\n',
+ 'nsslapd-dbcachesize' => '\n',
+ 'nsslapd-cache-autosize' => '\n',
+ 'nsslapd-cache-autosize-split' => '\n',
+ 'nsslapd-db-transaction-logging' => '\n',
+ 'nsslapd-import-cachesize' => '\n'
+);
+
+# the following hash displays specific parameters to each backends and stored under cn=DBname,cn=ldbm database,cn=plugins,cn=config
+%LDBMparamToMigrate = (
+ 'nsslapd-cachesize' => '\n',
+ 'nsslapd-cachememsize' => '\n',
+ 'nsslapd-readonly' => '\n',
+ 'nsslapd-require-index' => '\n'
+);
+
+
+%ChainingConfigParams = (
+ 'nsactivechainingcomponents' => '\n',
+ 'nstransmittedcontrols' => '\n'
+ );
+
+%ChainingDefaultInstanceConfigParams = (
+ 'nsabandonedsearchcheckinterval' => '\n',
+ 'nsbindconnectionslimit' => '\n',
+ 'nsbindtimeout' => '\n',
+ 'nsbindretrylimit' => '\n',
+ 'nshoplimit' => '\n',
+ 'nsmaxresponsedelay' => '\n',
+ 'nsmaxtestresponsedelay' => '\n',
+ 'nschecklocalaci' => '\n',
+ 'nsconcurrentbindlimit' => '\n',
+ 'nsconcurrentoperationslimit' => '\n',
+ 'nsconnectionlife' => '\n',
+ 'nsoperationconnectionslimit' => '\n',
+ 'nsproxiedauthorization' => '\n',
+ 'nsreferralonscopedsearch' => '\n',
+ 'nsslapd-sizelimit' => '\n',
+ 'nsslapd-timelimit' => '\n'
+);
+
+%changelog5params = (
+ 'nsslapd-changelogmaxage' => '\n',
+ 'nsslapd-changelogmaxentries' => '\n'
+ );
+
+@SNMPparams = (
+ 'nssnmpenabled',
+ 'nssnmporganization',
+ 'nssnmplocation',
+ 'nssnmpcontact',
+ 'nssnmpdescription',
+ 'nssnmpmasterhost',
+ 'nssnmpmasterport',
+ 'nssnmpenabled',
+ 'aci'
+ );
+
+%stdIncludes = (
+ "." => "\n",
+ ".." => "\n",
+ "30ns-common.ldif " => "\n",
+ "50ns-mail.ldif " => "\n",
+ "50ns-news.ldif" => "\n",
+ "50iplanet-servicemgt.ldif"=> "\n",
+ "50netscape-servicemgt.ldif"=> "\n",
+ "50ns-mcd-browser.ldif" => "\n",
+ "50ns-proxy.ldif" => "\n",
+ "00core.ldif" => "\n",
+ "50ns-admin.ldif" => "\n",
+ "50ns-mcd-config.ldif " => "\n",
+ "50ns-value.ldif" => "\n",
+ "05rfc2247.ldif" => "\n",
+ "50ns-calendar.ldif" => "\n",
+ "50ns-mcd-li.ldif" => "\n",
+ "50ns-wcal.ldif" => "\n",
+ "05rfc2927.ldif" => "\n",
+ "50ns-certificate.ldif" => "\n",
+ "50ns-mcd-mail.ldif" => "\n",
+ "50ns-web.ldif" => "\n",
+ "10rfc2307.ldif" => "\n",
+ "50ns-compass.ldif" => "\n",
+ "50ns-media.ldif" => "\n",
+ "20subscriber.ldif" => "\n",
+ "50ns-delegated-admin.ldif"=> "\n",
+ "50ns-mlm.ldif" => "\n",
+ "25java-object.ldif" => "\n",
+ "50ns-directory.ldif" => "\n",
+ "50ns-msg.ldif" => "\n",
+ "28pilot.ldif" => "\n",
+ "50ns-legacy.ldif" => "\n",
+ "50ns-netshare.ldif" => "\n"
+);
+
+
+# Backends migrated (Backend CN attribute value)
+@BACKENDS = () ;
+# All pairs of suffix-backend are registered in this hashtable
+%oldBackends = () ;
+
+#store the backend instances to migrate
+@LDBM_backend_instances = ();
+
+#store the mapping tree
+@Mapping_tree_entries = ();
+
+#store the suffix and the associated chaining backend
+%oldChainingBackends = ();
+
+#store the multiplexor bind entries to migrate
+%MultiplexorBindDNEntriesToMigrate = ();
+
+#store the Replica bind DN entries to migrate
+%ReplicaBindDNEntriesToMigrate = ();
+
+# list of standard plugins
+%stdPlugins = (
+ "7-bit check" => "\n",
+ "acl plugin" => "\n",
+ "acl preoperation" => "\n",
+ "binary syntax" => "\n",
+ "case exact string syntax" => "\n",
+ "case ignore string syntax" => "\n",
+ "chaining database" => "\n",
+ "class of service" => "\n",
+ "country string syntax" => "\n",
+ "distinguished name syntax" => "\n",
+ "generalized time syntax" => "\n",
+ "integer syntax" => "\n",
+ "internationalization plugin" => "\n",
+ "ldbm database" => "\n",
+ "legacy replication plugin" => "\n",
+ "multimaster replication plugin" => "\n",
+ "octet string syntax" => "\n",
+ "clear" => "\n",
+ "crypt" => "\n",
+ "ns-mta-md5" => "\n",
+ "sha" => "\n",
+ "ssha" => "\n",
+ "postal address syntax" => "\n",
+ "referential integrity postoperation" => "\n",
+ "retro changelog plugin" => "\n",
+ "roles plugin" => "\n",
+ "telephone syntax" => "\n",
+ "uid uniqueness" => "\n",
+ "uri syntax" => "\n"
+ );
+
+# list of indexes that have disappeared from the new schema compared to 5.0
+%deniedIndexes = (
+ 'dncomp' => "\n"
+);
+
+@default_indexes = ();
+@indexes = ();
+
+# list of user added Plugin's. In 6.2, they 'll need to be recompiled
+@badPlugins = () ;
+
+@pluginAttrs = (
+ "objectclass",
+ "cn",
+ "nsslapd-pluginpath",
+ "nsslapd-plugininitfunc",
+ "nsslapd-plugintype",
+ "nsslapd-pluginenabled",
+ "nsslapd-plugin-depends-on-type",
+ "nsslapd-pluginid",
+ "nsslapd-pluginversion",
+ "nsslapd-pluginvendor"
+ );
+
+@nsds5replicaAttrs = (
+ 'objectclass',
+ 'nsDS5ReplicaRoot',
+ 'nsDS5ReplicaType',
+ 'nsDS5ReplicaLegacyConsumer',
+ 'nsDS5flags',
+ 'nsDS5ReplicaId',
+ 'nsDS5ReplicaPurgeDelay',
+ 'nsDS5ReplicaBinddn',
+ 'cn',
+ 'nsDS5ReplicaReferral'
+ );
+
+# array of replicas to migrate
+@new6replicas = ();
+
+# array of replication agreements to migrate
+@replicationAgreements = ();
+
+# compare LDIF standard config files with standard ones
+CompareStdConfigFiles() ;
+die "\n\n The version of product you want to migrate is not a 5.x Directory Server\n" unless ($oldVersion == 5) ;
+
+# Shutdown the legacy Directory instance
+printTrace("\nShutdown the legacy Directory Server instance: ${oldHome}",0);
+&stopServer($oldDir, 'slapd-'.$oldname);
+
+# get the hostname of the new LDAP server
+my $LDAPservername = &getLDAPservername();
+
+# get the uid and gid of the 6.2 slapd user
+($localuser, $newuid, $newgid) = getuid_gid();
+# get the uid and gid of the 5.x slapd user
+($oldlocaluser, $olduid, $oldgid) = getolduid_gid();
+printTrace("\n6.2 localuser: $localuser, uid: $newuid, gid: $newgid",2);
+printTrace("\n5.x localuser: $oldlocaluser, uid: $olduid, gid: $oldgid",2);
+
+# backup 6.2 configuration files in <6server_root>/slapd-instancename/config
+printTrace("\nBackup $serverHome${PATHSEP}config on $serverHome${PATHSEP}config_backup ...",0);
+&backupConfigFiles();
+
+# migrate the schema (need to stop and start the 6.2 server)
+printTrace("\nMigrate the schema...",0);
+MigrateSchema();
+
+# start the server unless it is already started
+&startServer() unless (isDirectoryAlive());
+
+############### Connect to the 6.2 LDAP Directory Server ######################
+$ENV{"$LIB_PATH"} = $new_libpath;
+
+die "\n Migration aborted. Make sure your old and new Directory Server are installed on the same machine \n" if ( $LDAPservername == -1 );
+$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+
+# Cconnection to 6.2 LDAP server is successful !
+printTrace("\nConnected to $Version.$Minor LDAP server",0) ;
+
+# Parse the main configuration file: dse.ldif
+printTrace("\n\nParse the old DSE ldif file: $oldDSEldif *****",0, 1);
+printTrace("\nThis may take a while ...\n",0);
+&MigrateDSEldif();
+
+#migrate LDBM backend instances
+printTrace("\n\nMigrate LDBM backend instances...",0,1);
+&migrateLDBM_backend_instances();
+
+#migrate mapping tree entries
+printTrace("\n\nMigrate mapping tree...",0,1);
+&migrateMappingTree();
+
+#migrate default indexes
+printTrace("\n\nMigrate default indexes...",0,1);
+migrateDefaultIndexes();
+
+#migrate indexes
+printTrace("\n\nMigrate indexes...",0,1);
+migrateIndexes();
+
+#migrate replicas
+printTrace("\n\nMigrate replicas...",0,1);
+&MigrateNSDS5_replica();
+
+#migrate replication agreements
+printTrace("\n\nMigrate replication agreements...",0,1);
+&MigrateNSDS_replication_agreement();
+
+#migrate key/cert databases
+printTrace("\n\nMigrate key/cert databases...",0,1);
+&MigrateSSL();
+
+# migrate certmap.conf
+printTrace("\n\nMigrate Certmap.conf...",0,1);
+&MigrateCertmap() ;
+
+################## Close the connection to 6.2 LDAP Server #####################
+printTrace("\n\n***** Close the LDAP connection to the new Directory Server instance ***** ",0);
+$conn->close;
+
+
+################## stop the new instance and Export/Import the data, restart the server ##################
+if (@BACKENDS) {
+ &stopServer($root,'slapd-'.$newname);
+ if ($olddatadir) {
+ printTrace("\nData already contained in $olddatadir...\n",0,1) ;
+ $ldif_rep = "$olddatadir${PATHSEP}";
+ } else {
+ printTrace("\nData processing...\n",0,1) ;
+ # migrate data for each backend: 5.x -> LDIF files
+ &manydb2Ldif($ldif_rep);
+ }
+
+ # migrate LDIF data to the new database: LDIF -> New
+ &manyLdif2db($ldif_rep);
+ &migrateChangelog();
+ printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1);
+ &importReplicaBindDNEntries();
+ printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1);
+ &importMultiplexorBindDNEntries();
+ &startServer() unless (isDirectoryAlive());
+}
+else {
+ printTrace("\nINFORMATION - There are no non-standard or non-already existing suffixes to migrate\n",0);
+ &migrateChangelog();
+ printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1);
+ &importReplicaBindDNEntries();
+ printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1);
+ &importMultiplexorBindDNEntries();
+}
+
+printMsg("\n\n ****** End of migration ******\n\n");
+
+close(LOGFILE);
+
+
+###########################################################################################
+# get input users
+sub getParameters {
+ my $exit = 0 ;
+ my $i = 0;
+ my $pwdfile= "";
+
+ while ($i <= $#ARGV) {
+ if ( "$ARGV[$i]" eq "-D" ) { # directory manager
+ if (! $rootDN) {
+ $rootDN = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-w") { # password
+ if (! $rootpwd) {
+ $rootpwd = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-j") { # password file
+ if (! $pwdfile) {
+ $pwdfile = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-o") { # old instance path
+ if (! $oldHome ) {
+ $oldHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $oldHome if $isNT ;
+ if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; }
+ if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) {
+ $oldDir = $1 ;
+ $type = $2 ;
+ $oldname = $3 ;
+ if ($isNT) {
+ $oldDir = lc($oldDir) ;
+ $type = lc($type) ;
+ $oldname = lc($oldname) ;
+ $oldHome = lc($oldHome) ;
+ grep { s@/@\\@g } $oldDir ;
+ grep { s@/@\\@g } $oldHome ;
+ }
+ }
+ else {
+ print("\nThe old instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-n") { # new instance path
+ if (! $serverHome ) {
+ $serverHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $root if $isNT ;
+ grep { s@\\@/@g } $serverHome if $isNT ;
+ if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; }
+ if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) {
+ $root = $1 if ($1);
+ $type = $2 ;
+ $newname = $3 ;
+ if ($isNT) {
+ $root = lc($root) ;
+ $type = lc($type) ;
+ $newname = lc($newname) ;
+ $serverHome = lc($serverHome) ;
+ grep { s@/@\\@g } $root ;
+ grep { s@/@\\@g } $serverHome ;
+ }
+ }
+ else {
+ print("\nThe new instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-p") { # new DS port
+ if (! $newport ) {
+ $newport = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-d") { # old instance LDIF data dir
+ if (! $olddatadir ) {
+ $olddatadir = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-v") { # old version
+ if (! $oldversionstr ) {
+ $oldversionstr = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL
+ my $value = $ARGV[++$i] ;
+ if ($value =~ /[0-3]/) {
+ $TRACELEVEL = $value ;
+ }
+ else {
+ print("\nThe tracelevel must belong to 0..3 interval");
+ &usage();
+ exit();
+ }
+ } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing
+ $NO_INPUT_USER = 1 ;
+ } elsif ("$ARGV[$i]" eq "-L") { # migration logfile
+ $LogFileReport = $ARGV[++$i] ;
+ }
+ else {
+ print("\nThe option $ARGV[$i] is not recognized");
+ &usage() ;
+ exit(1);
+ }
+ $i++;
+ }
+ if (! $rootDN) {
+ print("\nThe rootDN is missing");
+ $exit = 1;
+ }
+ if ($pwdfile ne "") {
+ # Open file and get the password
+ unless (open (RPASS, $pwfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $rootpwd = <RPASS>;
+ chomp($rootpwd);
+ close(RPASS);
+ } elsif ($rootpwd eq "-"){
+ # Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+ # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $rootpwd = ReadLine(0);
+# chomp($rootpwd);
+# ReadMode('normal');
+ }
+ if (! $rootpwd) {
+ print("\nThe rootpwd is missing");
+ $exit = 1 ;
+ }
+ if (! $newport) {
+ print("\nThe port is missing");
+ $exit = 1;
+ }
+ if (! $serverHome) {
+ print("\nThe new instance path is missing");
+ $exit = 1;
+ }
+ if (! $oldHome) {
+ print("\nThe old instance path is missing");
+ $exit = 1;
+ }
+ if ((! $LogFileReport) && $serverHome) {
+ ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime();
+ $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log";
+ }
+ if ($exit) {
+ &usage() ;
+ exit(1);
+ }
+
+}
+
+###################################################################################################
+
+sub MigrateSchema{
+ my $FilesChanged = "";
+ my $AllDiffs = "";
+ my $NoChanges = "" ;
+ my $lineToBegin = 0 ;
+ opendir(SCHEMADIR, $oldSchemaDir) or
+ die "Error: could not open migrated config dir $oldSchemaDir: $!";
+
+ foreach $file (readdir(SCHEMADIR)) {
+ if (! exists($stdIncludes{lc($file)})) {
+ my $newSchemaFile = $schemaDir . $file;
+ if (-f $newSchemaFile ) {
+ # The ldif file already exists. Make a diff and warn the user if different.
+ if (diff($newSchemaFile, $oldSchemaDir.$file)) {
+ &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive());
+ $AllDiffs .= "\n$file";
+ copyBinFile("$oldSchemaDir$file", $newSchemaFile);
+ }
+ }
+ else {
+ &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive());
+ $AllDiffs .= "\n$file";
+ copyBinFile("$oldSchemaDir$file", $newSchemaFile);
+ }
+ }
+ }
+ closedir(SCHEMADIR);
+ if ($AllDiffs) {
+ printMsg("\n\n***********************************************************************");
+ printMsg("\nThe following LDIF files have been migrated:");
+ printMsg("$AllDiffs");
+ printMsg("\n*************************************************************************\n\n");
+ }
+ &startServer() if (! isDirectoryAlive());
+}
+
+
+###################################################################################################
+# This subroutine is used to parse the dse.ldif file and call specific routines to act with entries
+sub MigrateDSEldif {
+ printTrace("\nMigrate DSE entries...",1);
+ my $tempoAlreadyDone = 0;
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ $typeOfEntry = getTypeOfEntry($entry);
+ SWITCH: {
+ if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){
+ parseLDBM_backend_instance($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "MAPPING_TREE"){
+ parseMapping_tree($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "DEFAULT_INDEX"){
+ parseDefaultIndex($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "INDEX"){
+ parseIndex($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "STANDARD_PLUGIN"){
+ migrateStdPlugin($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CONFIG_NODE"){
+ migrateConfig_Node($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CONFIG_LDBM_DATABASE"){
+ migrateConfig_LDBM_database($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CHAINING_BACKEND_CONFIG"){
+ migrateChainingBE_config($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CHAINING_BACKEND_INSTANCE"){
+ migrateChainingBE_instance($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "NSDS5_REPLICA"){
+ parseNSDS5_replica($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "NSDS_REPLICATION_AGREEMENT"){
+ parseNSDS_replication_agreement($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CHANGELOG5"){
+ migrateChangelog5($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "REPLICATION"){
+ migrateReplication($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "SECURITY"){
+ migrateSecurity($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "SNMP"){
+ migrateSNMP($entry);
+ last SWITCH;
+ }
+ }
+
+ }
+ close(DSELDIF);
+}
+
+#############################################################################
+# returns the "type of an entry". If the entry is not to be migrated its type is "NOT_MIGRATED_TYPE"
+
+sub getTypeOfEntry{
+ my $entry = shift;
+ my $DN = $entry->getDN(1) ; # 1 is to normalize the returned DN
+ if (($DN =~ /cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) {
+ return "LDBM_BACKEND_INSTANCE";
+ }
+ if (($DN =~ /cn=mapping tree,cn=config$/i) && (isObjectclass($entry,"nsMappingTree"))) {
+ return "MAPPING_TREE";
+ }
+ if (($DN =~ /cn=default indexes,cn=config,cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsIndex"))) {
+ return "DEFAULT_INDEX";
+ }
+ if (isObjectclass($entry,"nsIndex")) {
+ return "INDEX";
+ }
+ if ((isObjectclass($entry,"nsSlapdPlugin")) && (isStdPlugin($entry))) {
+ return "STANDARD_PLUGIN";
+ }
+ if ($DN =~ /^cn=config$/i) {
+ return "CONFIG_NODE";
+ }
+ if ($DN =~ /^cn=config,cn=ldbm database,cn=plugins,cn=config$/i) {
+ return "CONFIG_LDBM_DATABASE";
+ }
+ if (($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i) || ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i)){
+ return "CHAINING_BACKEND_CONFIG";
+ }
+ if (($DN =~ /cn=chaining database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) {
+ return "CHAINING_BACKEND_INSTANCE";
+ }
+ if (isObjectclass($entry,"nsDS5Replica")) {
+ return "NSDS5_REPLICA";
+ }
+ if (isObjectclass($entry,"nsDS5ReplicationAgreement")) {
+ return "NSDS_REPLICATION_AGREEMENT";
+ }
+ if ($DN =~ /^cn=changelog5,cn=config$/i) {
+ return "CHANGELOG5";
+ }
+ if (($DN =~ /cn=replication,cn=config$/i) && ($DN !~ /^cn=replication,cn=config$/i)) {
+ return "REPLICATION";
+ }
+ if ($DN =~ /cn=encryption,cn=config$/i) {
+ return "SECURITY";
+ }
+ if ($DN =~ /^cn=SNMP,cn=config$/i) {
+ return "SNMP";
+ }
+ return "NOT_MIGRATED_TYPE";
+}
+
+#############################################################################
+
+
+
+#############################################################################
+# returns 1 if the objectclass given in parameter is present in the objectclasses values of the entry
+# given in parameter, 0 else
+
+sub isObjectclass {
+ my $entry = shift;
+ my $objectclass = shift;
+ return ($entry->hasValue("objectclass",$objectclass,1));
+}
+
+#############################################################################
+
+sub isStdPlugin {
+ my $entry = shift;
+ my $CN = $entry->{cn}[0];
+ if (isObjectclass($entry,"nsSlapdPlugin")) {
+ return 1 if ($stdPlugins{lc($CN)});
+ }
+ return 0;
+}
+
+
+#############################################################################
+
+sub alreadyExistsInNew{
+ my $entry = shift;
+ my $mustExist = shift;
+ my $DN = $entry->getDN(1); # 1 to normalize the DN
+ # We have a name change of "uid uniqueness" plugin in DS6.x
+ # to "attribute uniqueness"
+ $DN =~ s/uid\ uniqueness/attribute\ uniqueness/ if ($DN =~ /uid\ uniqueness/);
+ return searchEntry($DN, $mustExist);
+}
+
+#############################################################################
+sub searchEntry {
+ my $DN = shift;
+ my $mustExist = shift;
+ my $res = $conn->search($DN, "base", "objectclass=*");
+ my $cpt = 5;
+ if ($res) {
+ return $res;
+ }
+ else {
+ my $errorCode = $conn->getErrorCode();
+ while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) {
+ printMsg("\ntry to reconnect to search $DN");
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ $res = $conn->search($DN, "base", "objectclass=*");
+ $errorCode = $conn->getErrorCode();
+ $cpt--;
+ }
+ if ($res){
+ return $res ;
+ }
+ elsif (($errorCode eq $LDAP_SERVER_UNREACHABLE) || ($mustExist)) {
+ my $msg = $conn->getErrorString();
+ printMsg("\n\n*** Failed to search: $DN");
+ printMsg("\n*** Error Msg: $msg, Error code: $errorCode");
+ }
+ return 0;
+ }
+}
+
+
+#############################################################################
+
+sub addEntryToNew{
+ my $entry = shift;
+ my $typeOfEntry = shift;
+ my $trace = shift;
+ my $res = $conn->add($entry);
+ my $DN = $entry->getDN(1);
+ my $cpt = 5;
+ if ($res) {
+ printTrace("\n$typeOfEntry - Add successfull: $DN",$trace);
+ return 1;
+ }
+ else {
+ my $errorCode = $conn->getErrorCode();
+ while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) {
+ printMsg("\ntry to reconnect to add $DN");
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ $res = $conn->add($entry);
+ $errorCode = $conn->getErrorCode();
+ $cpt--;
+ }
+ if ($res){
+ printTrace("\n$typeOfEntry - Add successfull: $DN",$trace);
+ return 1;
+ }
+ else {
+ my $msg = $conn->getErrorString();
+ printMsg("\n\n*** $typeOfEntry: Add Failed: $DN");
+ printMsg("\n*** Error Msg: $msg, Error code: $errorCode");
+ return 0;
+ }
+ }
+}
+
+#############################################################################
+
+sub updateEntry{
+ my $entry = shift;
+ my $typeOfEntry = shift;
+ my $CHECK = shift;
+ my $trace = shift;
+ my $cpt = 5;
+ if ($CHECK) {
+ if (! hasChanged($entry, $typeOfEntry)) {
+ return 1;
+ }
+ }
+ my $res = $conn->update($entry);
+ my $DN = $entry->getDN(1);
+ if ($res) {
+ printTrace("\n$typeOfEntry - Update successfull: $DN",$trace);
+ return 1 ;
+ }
+ else {
+ my $errorCode = $conn->getErrorCode();
+ while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) {
+ printMsg("\ntry to reconnect to update $DN");
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ $res = $conn->update($entry);
+ $errorCode = $conn->getErrorCode();
+ $cpt--;
+ }
+ if ($res){
+ printTrace("\n$typeOfEntry - Update successfull: $DN",$trace);
+ return 1;
+ }
+ else {
+ my $msg = $conn->getErrorString();
+ printMsg("\n\n*** $typeOfEntry - Update Failed: $DN");
+ printMsg("\n*** Error Msg: $msg, Error code: $errorCode");
+ return 0;
+ }
+ }
+}
+
+
+#############################################################################
+# returns 1 if the entry to migrate and the current entry are different one another
+
+sub hasChanged {
+ my $entry = shift;
+ my $typeOfEntry = shift;
+ my $DN = $entry->getDN(1);
+ my $newEntry = searchEntry($DN,1);
+ return 1 if (! $newEntry); # we shoudn't be in that case ...
+ # do the stuff to check wether the entry has changed or not given its type
+ if (($typeOfEntry eq "DEFAULT_INDEX") || ($typeOfEntry eq "INDEX")){
+ my @indexTypes = $entry->getValues("nsIndexType");
+ my @newIndexTypes = $newEntry->getValues("nsIndexType");
+ my @nsmatchingrules = $entry->getValues("nsmatchingrule");
+ my @newMatchingRules = $newEntry->getValues("nsmatchingrule");
+ return 1 if (Diffs(\@indexTypes, \@newIndexTypes));
+ return 1 if (Diffs(\@nsmatchingrules,\@newMatchingRules));
+ return 0;
+ }
+ if ($typeOfEntry eq "CHANGELOG5"){
+ printTrace("\nCheck wether changelog has changed or not",3);
+ my @params = keys(%changelog5params);
+ foreach $param (@params){
+ my @values = $entry->getValues($param);
+ my @newValues = $newEntry->getValues($param);
+ return 1 if (Diffs(\@values,\@newValues));
+ }
+ return 0;
+ }
+ if ($typeOfEntry eq "SNMP"){
+ foreach $param (@SNMPparams){
+ my @values = $entry->getValues($param);
+ my @newValues = $newEntry->getValues($param);
+ return 1 if (Diffs(\@values,\@newValues));
+ }
+ return 0;
+ }
+ # we don't know how to compare such type of entry => just return 1
+ return 1 ;
+}
+
+sub isAsystemIndex {
+ my $index = shift;
+ return ($index->hasValue("nsSystemIndex","true",1));
+}
+
+
+sub updatePathInPluginArgs {
+ my $plugin = shift;
+ my $argNum = 0;
+ my $argPrefix = "nsslapd-pluginarg";
+ my $cont = 1;
+ my $Unix_oldDir = ${oldDir} ;
+ my $Unix_root = ${root} ;
+ grep { s@\\@/@g } $Unix_oldDir if $isNT;
+ grep { s@\\@/@g } $Unix_root if $isNT;
+ while ($cont) {
+ my $arg = $argPrefix . $argNum ;
+ if ($plugin->exists($arg)) {
+ $_ = $plugin->{$arg}[0] ;
+ s@$Unix_oldDir@$Unix_root@ig ;
+ s/$type-$oldname/$type-$newname/ig ;
+ $plugin->setValues($arg, $_) ;
+ }
+ else {
+ $cont = 0 ;
+ }
+ $argNum++;
+ }
+ return $plugin;
+}
+
+
+sub Diffs {
+ my $valuesToMigrate = shift;
+ my $currentValues = shift;
+ return 1 if (getDiff(\@{$valuesToMigrate},\@{$currentValues}));
+ return 1 if (getDiff(\@{$currentValues},\@{$valuesToMigrate}));
+ return 0 ;
+}
+
+sub getDiff {
+ # we get references to arrays
+ my $elements = shift ;
+ my $existing_elements = shift ;
+ my %count = () ;
+ my %countEE = () ;
+ @diff = () ;
+ foreach $e (@{$elements}, @{$existing_elements}) { $count{$e}++ ;}
+ foreach $e (@{existing_elements}) { $countEE{$e}++ ;}
+ foreach $e (@{$elements}) {
+ # if $e is only present in @$elements, we push it to the diff array
+ if (($count{$e} == 1) && ($countEE{$e} == 0)) {
+ push @diff, $e ;
+ }
+ }
+ return @diff ;
+}
+
+sub registerSuffix_Backend {
+ my $ldbmDatabase = shift;
+ my $CN = $ldbmDatabase->{cn}[0];
+ my $suffixArg = "nsslapd-suffix";
+ my $suffix = $ldbmDatabase->{$suffixArg}[0];
+ $oldBackends{$suffix} = $CN;
+}
+
+
+#############################################################################
+# #
+# #
+# #
+#############################################################################
+sub migrateLDBM_backend_instances {
+ foreach $entry (@LDBM_backend_instances) {
+ my $DN = $entry->getDN(1); # 1 is to normalize the DN
+ my $CN = $entry->{cn}[0];
+ my $expLdif;
+ my $confirm = "No";
+ my $dest = "$serverHome${PATHSEP}db_backup" ;
+ my $newSlapdExecDir = "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server";
+
+ if ($DN =~/cn=netscaperoot,cn=ldbm database/i){
+ printTrace("\n\n*** INFORMATION - NetscapeRoot is NOT migrated",0);
+ }
+ else {
+ if(alreadyExistsInNew($entry)){
+ printMsg("\n\n*** LDBM_BACKEND_INSTANCE - $DN already exists");
+ printMsg("\n*** Migration will overwrite existing database");
+ printMsg("\nDo you want to continue Yes/No [No] ?") ;
+ my $answer = <STDIN> ;
+ if ($answer =~ /y|yes/i) {
+ printMsg("Do you want to export the existing data Yes/No [Yes] ?");
+ my $answer = <STDIN> ;
+ if (!($answer =~ /n|no/i)) {
+ mkdir $dest, 0700 unless (-d $dest);
+ $expLdif = "$dest${PATHSEP}$CN.ldif";
+ while (!($confirm =~ /y|yes/i)) {
+ printMsg("\nEnter the full pathname of the file [$expLdif]:") ;
+ $answer = <STDIN> ;
+ chomp($expLdif = $answer) unless ($answer eq "\n");
+ printMsg("\nExisting data will be exported under $expLdif");
+ printMsg("\nContinue Yes/No [No] ?");
+ $confirm = <STDIN>;
+ }
+ $ENV{"$LIB_PATH"}=$new_libpath;
+ chdir($newSlapdExecDir) or die "\nCould not change directory to $newSlapdExecDir: $!\n";
+ printTrace("\nNow backing up database $CN in $expLdif\n",0);
+ &stopServer($root,'slapd-'.$newname);
+ &db2Ldif($expLdif, $CN, $serverHome);
+ &startServer() unless (isDirectoryAlive());
+ }
+ push @BACKENDS, $CN;
+ } else {
+ printMsg("\n*** Migration will not update it");
+ break;
+ }
+ } else {
+ printTrace("\nWe should add the backend instance $DN",3);
+ my $suffixarg = "nsslapd-suffix" ;
+ my $suffixname= $entry->{$suffixarg}[0] ;
+ my $newEntry = $conn->newEntry() ;
+ $newEntry->setDN($DN);
+ $newEntry->setValues("objectclass", "top", "extensibleObject", "nsBackendInstance" );
+ $newEntry->setValues("cn", $CN );
+ $newEntry->setValues($suffixarg, $suffixname);
+ my @params = keys(%LDBMparamToMigrate);
+ foreach $param (@params) {
+ my @values = $entry->getValues($param);
+ $newEntry->setValues($param, @values) if (@values);
+ }
+ if (addEntryToNew($newEntry, "LDBM_BACKEND_INSTANCE",1)) {
+ push @BACKENDS, $CN;
+ }
+ }
+ }
+ }
+}
+
+sub parseLDBM_backend_instance {
+ my $entry = shift;
+ &registerSuffix_Backend($entry);
+ push @LDBM_backend_instances, $entry;
+}
+
+#############################################################################
+sub migrateMappingTree {
+ foreach $entry (@Mapping_tree_entries) {
+ my $DN = $entry->getDN(1); # 1 si to normalize the DN
+ if ($DN =~/cn=\"o=netscaperoot\",cn=mapping tree,cn=config/i){
+ # DO NOTHING
+ }
+ else {
+ if(alreadyExistsInNew($entry)){
+ printMsg("\n\n*** MAPPING_TREE - $DN already exists");
+ printMsg("\n*** Migration will not add the suffix");
+ }
+ else {
+ addEntryToNew($entry, "MAPPING_TREE",1);
+ }
+ }
+ }
+}
+
+
+sub parseMapping_tree{
+ my $entry = shift;
+ push @Mapping_tree_entries, $entry;
+}
+
+#############################################################################
+sub migrateDefaultIndexes {
+ foreach $index (@default_indexes) {
+ my $CN = $index->{cn}[0];
+ my $newIndex ;
+ if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)})) {
+ if ($newIndex = alreadyExistsInNew($index)) {
+ if (! isAsystemIndex($newIndex)) {
+ updateEntry($index, "DEFAULT_INDEX", 1, 2);
+ }
+ }
+ else {
+ addEntryToNew($index, "DEFAULT_INDEX", 2);
+ }
+ }
+ }
+}
+
+
+sub parseDefaultIndex{
+ my $index = shift;
+ push @default_indexes, $index;
+}
+
+#############################################################################
+
+sub migrateIndexes {
+ foreach $index (@indexes) {
+ my $CN = $index->{cn}[0];
+ my $newIndex;
+ if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)}) && (DN !~ /cn=netscaperoot,cn=index/i)){
+ if ($newIndex = alreadyExistsInNew($index)) {
+ if (! isAsystemIndex($newIndex)) {
+ updateEntry($index, "INDEX", 1, 2);
+ }
+ }
+ else {
+ addEntryToNew($index, "INDEX", 2);
+ }
+ }
+ }
+}
+
+sub parseIndex{
+ my $index = shift;
+ push @indexes, $index;
+}
+
+#############################################################################
+
+sub newLDIFplugin {
+ my $currentPlugin = shift;
+ my $DN = $currentPlugin->getDN(1);
+ my $newPlugin = $conn->newEntry() ;
+ $newPlugin->setDN($DN);
+ foreach $Attr (@pluginAttrs) {
+ my @values = $currentPlugin->getValues($Attr);
+ $newPlugin->setValues($Attr, @values) if (@values);
+ }
+ return $newPlugin;
+}
+
+sub migrateStdPlugin{
+ my $plugin = shift;
+ my $DN = $plugin->getDN(1);
+ my $pluginEnable = "nsslapd-pluginEnabled";
+ my $argNum = 0;
+ my $argPrefix = "nsslapd-pluginarg";
+ my $currentPlugin ;
+ if ($currentPlugin = alreadyExistsInNew($plugin, 1)) {
+ $plugin = updatePathInPluginArgs($plugin);
+ my $pluginEnableValue = $plugin->{$pluginEnable}[0];
+ my $cont = 1;
+ my $pluginHasChanged = 0;
+ my $newPlugin = &newLDIFplugin($currentPlugin);
+ if (! $currentPlugin->hasValue($pluginEnable,$pluginEnableValue,1)){
+ $newPlugin->setValues($pluginEnable, $pluginEnableValue);
+ $pluginHasChanged = 1 unless ($pluginHasChanged);
+ }
+ while($cont){
+ my $arg = $argPrefix . $argNum ;
+ if ($plugin->exists($arg)) {
+ my @values = $plugin->getValues($arg);
+ my $value = $values[0] ;
+ $newPlugin->setValues($arg, $value) if (@values);
+ if ($currentPlugin->exists($arg)) {
+ if (! $currentPlugin->hasValue($arg,$value,1)) {
+ $pluginHasChanged = 1 unless ($pluginHasChanged);
+ }
+ }
+ else {
+ $pluginHasChanged = 1 unless ($pluginHasChanged);
+ }
+ }
+ else {
+ if ($currentPlugin->exists($arg)) {
+ # Just Warn the user. Do nothing.
+ printTrace("\nCompared to the old instance, the current new plugin $DN belongs this attribute: $arg",2);
+ }
+ else {
+ $cont = 0 ;
+ }
+ }
+ $argNum++;
+ }
+ updateEntry($newPlugin, "STANDARD_PLUGIN", 0, 1) if ($pluginHasChanged);
+ }
+}
+
+#############################################################################
+
+sub migrateConfig_Node{
+ my $config_node = shift;
+ my @params = keys(%GeneralSrvParamToMigrate);
+ my $hasChanged = 0;
+ my $newConfigNode;
+ if ($newConfigNode = alreadyExistsInNew($config_node, 1)){
+ foreach $param (@params) {
+ if ($config_node->exists($param)){
+ my @valuesToMigrate = $config_node->getValues($param);
+ if (@valuesToMigrate){
+ if ($newConfigNode->exists($param)){
+ my @currentValues = $newConfigNode->getValues($param);
+ if (Diffs(\@valuesToMigrate, \@currentValues)) {
+ $newConfigNode->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ printTrace("\nParam to update: $param with value @valuesToMigrate",3);
+ }
+ }
+ else {
+ $newConfigNode->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ printTrace("\nParam to update: $param with value @valuesToMigrate",3);
+ }
+ }
+ }
+ }
+ updateEntry($newConfigNode, "CONFIG_NODE", 0, 1) if ($hasChanged);
+ }
+}
+
+#############################################################################
+
+sub migrateConfig_LDBM_database{
+ my $config_ldbm = shift;
+ my @params = keys(%GlobalConfigLDBMparamToMigrate);
+ my $hasChanged = 0;
+ my $newConfigLdbm ;
+ if ($newConfigLdbm = alreadyExistsInNew($config_ldbm, 1)) {
+ foreach $param (@params) {
+ if ($config_ldbm->exists($param)){
+ my @valuesToMigrate = $config_ldbm->getValues($param);
+ if (@valuesToMigrate){
+ if ($newConfigLdbm->exists($param)){
+ my @currentValues = $newConfigLdbm->getValues($param);
+ if (Diffs(\@valuesToMigrate, \@currentValues)) {
+ $newConfigLdbm->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ else {
+ $newConfigLdbm->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ }
+ }
+ updateEntry($newConfigLdbm, "CONFIG_LDBM_DATABASE", 0, 1) if ($hasChanged);
+ }
+}
+
+#############################################################################
+
+sub migrateChainingBE_config{
+ my $chaining_config = shift;
+ my $DN = $chaining_config->getDN(1);
+ my @params = ();
+ my $hasChanged = 0;
+ my $newChainingConfig;
+ if ($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i){
+ $newChainingConfig = searchEntry("cn=config,cn=chaining database,cn=plugins,cn=config");
+ @params = keys(%ChainingConfigParams);
+ }
+ if ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i){
+ $newChainingConfig = searchEntry("cn=default instance config,cn=chaining database,cn=plugins,cn=config");
+ @params = keys(%ChainingDefaultInstanceConfigParams);
+ }
+ foreach $param (@params) {
+ if ($chaining_config->exists($param)){
+ my @valuesToMigrate = $chaining_config->getValues($param);
+ if (@valuesToMigrate){
+ printTrace("\nParam: $param values To migrate: @valuesToMigrate",3);
+ if ($newChainingConfig->exists($param)){
+ my @currentValues = $newChainingConfig->getValues($param);
+ printTrace("\nParam: $param new current values: @currentValues",3);
+ if (Diffs(\@valuesToMigrate, \@currentValues)) {
+ $newChainingConfig->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ else {
+ $newChainingConfig->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ }
+ }
+ updateEntry($newChainingConfig, "CHAINING_BACKEND_CONFIG", 0, 1) if ($hasChanged);
+}
+
+#############################################################################
+
+sub registerSuffix_ChainingBE {
+ my $ldbmDatabase = shift;
+ my $CN = $ldbmDatabase->{cn}[0];
+ my $suffixArg = "nsslapd-suffix";
+ my $suffix = $ldbmDatabase->{$suffixArg}[0];
+ $oldChainingBackends{$suffix} = $CN;
+}
+
+sub storeMultiplexorBindDN {
+ my $chaining_instance = shift;
+ my $DN = $chaining_instance->getDN(1);
+ if ($chaining_instance->exists("nsMultiplexorBindDN")){
+ my $bindDN = $chaining_instance->{nsMultiplexorBindDN}[0];
+ my $newBindDN = searchEntry($bindDN);
+ if (! $newBindDN){
+ # the bindDN entry doesn't yet exist in new => it will have to be migrated
+ $MultiplexorBindDNEntriesToMigrate{$bindDN}="\n" ;
+ printTrace("\nThe bindDN: $bindDN need to be migrated",3);
+ }
+ else {
+ # do nothing as the entry already exists in new
+ }
+ }
+
+}
+
+sub importMultiplexorBindDNEntries {
+ # import all entries present in @MultiplexorBindDNEntriesToMigrate in new
+ my @MultiplexorBindDNs = keys (%MultiplexorBindDNEntriesToMigrate);
+ my $ldif_dir = $ldif_rep;
+ foreach $bindDN (@MultiplexorBindDNs) {
+ printTrace("\nimportMultiplexorBindDNEntries: bindDN to migrate: $bindDN",3);
+ # get the backend in which is stored the bind DN entry
+ my $backendtoExportFrom = getBackendtoExportFrom($bindDN);
+ printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3);
+ # check wether the backend has been imported in new or not
+ if (! alreadyMigrated($backendtoExportFrom)) {
+ if ($backendtoExportFrom ne $NULL) {
+ # if not imported => we need to import the binf DN entry
+ &startServer() unless (isDirectoryAlive());
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir);
+ }
+ else {
+ # do nothing
+ }
+ }
+ }
+ # remove the empty ldif directory
+ rmdir($ldif_dir) if (-d $ldif_dir);
+ # close the LDAP connection to new
+ $conn->close if ($conn);
+}
+
+sub migrateChainingBE_instance{
+ my $chaining_instance = shift;
+ my $DN = $chaining_instance->getDN(1);
+ &registerSuffix_ChainingBE($chaining_instance);
+ if (alreadyExistsInNew($chaining_instance)) {
+ # already exists
+ printMsg("\n\n*** CHAINING_BACKEND_INSTANCE - $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ &migrate_credential($chaining_instance, "nsmultiplexorcredentials");
+ addEntryToNew($chaining_instance, "CHAINING_BACKEND_INSTANCE", 1);
+ storeMultiplexorBindDN($chaining_instance);
+ }
+}
+
+#############################################################################
+
+# create a new LDIF representation of a new replica consumer
+sub newLDIFreplica {
+ my $replica = shift;
+ my $DN = $replica->getDN(1);
+ my $newReplica = $conn->newEntry() ;
+ my $MASTER_OR_MULTIMASTER = "3" ;
+ $newReplica->setDN($DN);
+ foreach $Attr (@nsds5replicaAttrs) {
+ my @values = $replica->getValues($Attr);
+ $newReplica->setValues($Attr, @values) if (@values);
+ }
+ my $replicaType = $replica->{nsDS5ReplicaType}[0];
+ if ($replicaType eq $MASTER_OR_MULTIMASTER) {
+ my @nsState = $replica->getValues("nsState");
+ $newReplica->setValues("nsState", @nsState);
+ }
+ else {
+ $newReplica->setValues("nsDS5ReplicaId", $replicaIdvalue);
+ }
+ return $newReplica;
+}
+
+sub MigrateNSDS5_replica{
+ foreach $replica (@new6replicas) {
+ my $DN = $replica->getDN(1);
+ my $newReplica;
+ my @removeAttrs = qw(nsstate nsds5replicaname nsds5replicachangecount);
+ for (@removeAttrs) {
+ $replica->remove($_);
+ }
+ if (alreadyExistsInNew($replica)) {
+ # replica already exists
+ printMsg("\n\n*** NSDS5_REPLICA - $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ $newReplica = &newLDIFreplica($replica);
+ addEntryToNew($newReplica, "NSDS5_REPLICA", 1);
+ }
+ storeReplicaBindDN($replica);
+ }
+}
+
+sub parseNSDS5_replica{
+ my $replica = shift;
+ push @new6replicas, $replica;
+}
+
+sub storeReplicaBindDN {
+ my $replica = shift;
+ my $DN = $replica->getDN(1);
+ if ($replica->exists("nsDS5ReplicaBindDN")){
+ my $bindDN = $replica->{nsDS5ReplicaBindDN}[0];
+ my $newBindDN = searchEntry($bindDN);
+ if (! $newBindDN){
+ # the bindDN entry doesn't yet exist in new => it will have to be migrated
+ $ReplicaBindDNEntriesToMigrate{$bindDN}="\n" ;
+ printTrace("\nThe bindDN: $bindDN need to be migrated",3);
+ }
+ else {
+ # do nothing as the entry already exists in new
+ }
+ }
+}
+
+
+sub importReplicaBindDNEntries {
+ # import all entries present in @ReplicaBindDNEntriesToMigrate in new
+ my @ReplicaBindDNs = keys (%ReplicaBindDNEntriesToMigrate);
+ my $ldif_dir = $ldif_rep;
+ my $replBind_entry = "";
+ my @bindDN_elements = "";
+ my $bindDN_parent = "";
+ my $parentBind_entry = "";
+ foreach $bindDN (@ReplicaBindDNs) {
+ printTrace("\nimportReplicaBindDNEntries: bindDN to migrate: $bindDN",3);
+ # get the backend in which is stored the bind DN entry
+ my $backendtoExportFrom = getBackendtoExportFrom($bindDN);
+ printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3);
+ # If backend is from config, read the entry from dse.ldif and add to new - NGK
+ if ($backendtoExportFrom eq "cn=config") {
+ my $norm_bindDN = normalizeDN($bindDN);
+ @bindDN_elements = ldap_explode_dn($norm_bindDN, 0);
+# @bindDN_elements = split(/,/,$norm_bindDN);
+ my $junk = shift(@bindDN_elements);
+ if ($#bindDN_elements >= 1) {
+ $bindDN_parent = normalizeDN(join(",", @bindDN_elements));
+ }
+ printTrace("\nOpening DSE.ldif",3);
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF);
+ while ($entry = readOneEntry $in) {
+ my $DN = $entry->getDN(1);
+ if ($DN eq $norm_bindDN) {
+ $replBind_entry = $entry;
+ }
+ if ($bindDN_parent ne "") {
+ if ($DN eq $bindDN_parent) {
+ $parentBind_entry = $entry;
+ }
+ }
+ }
+ close(DSELDIF);
+ &startServer() unless (isDirectoryAlive());
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ if ($bindDN_parent ne "") {
+ addEntryToNew($parentBind_entry, BINDDN_PARENT, 0);
+ }
+ printTrace("\nAdding BindDN with addEntryToNew",3);
+ addEntryToNew($replBind_entry, BINDDN, 0);
+ } else {
+ # check wether the backend has been imported in new or not
+ if (! alreadyMigrated($backendtoExportFrom)) {
+ if ($backendtoExportFrom ne $NULL) {
+ # if not imported => we need to import the bind DN entry
+ &startServer() unless (isDirectoryAlive());
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir);
+ }
+ else {
+ # do nothing
+ }
+ }
+ }
+ }
+ # remove the empty ldif directory
+ rmdir($ldif_dir) if (-d $ldif_dir);
+ # close the LDAP connection to new
+ $conn->close if ($conn);
+}
+
+sub alreadyMigrated {
+ my $backendToCheck = shift;
+ foreach $backend (@BACKENDS) {
+ return 1 if ($backend eq $backendToCheck);
+ }
+ return 0 ;
+}
+
+sub belongsSuffix {
+ my $suffix = shift;
+ my $bindDN = shift;
+ return ($bindDN =~ /$suffix\s*$/i);
+}
+
+sub length {
+ my $suffix = shift;
+ my $count = 0;
+ while ($suffix =~ /./g) {
+ $count++;
+ }
+ return $count ;
+}
+
+sub getBackendtoExportFrom {
+ my $bindDN = shift ;
+ my $sizeOfSuffix = 0 ;
+ my $NULL = "";
+ my @oldSuffixes = keys(%oldBackends);
+ my @oldChainingSuffixes = keys(%oldChainingBackends);
+ my $bindDN_backend = $NULL;
+ my $config = "cn=config";
+
+ my $norm_bindDN = normalizeDN($bindDN);
+ # Check if bindDN exists in cn=config - NGK
+ if (belongsSuffix($config,$norm_bindDN)) {
+ $bindDN_backend = $config;
+ printTrace("\ngetBackendtoExportFrom: bindDN_backend: $bindDN_backend",3);
+ } else {
+ foreach $suffix (@oldSuffixes){
+ printTrace("\ngetBackendtoExportFrom: suffix to compare with is: $suffix",3);
+ if ((belongsSuffix($suffix,$norm_bindDN)) && (length($suffix) > $sizeOfSuffix)) {
+ $sizeOfSuffix = length($suffix);
+ $bindDN_backend = $oldBackends{$suffix};
+ printTrace("\ngetBackendtoExportFrom: bindDN_backend: $bindDN_backend, sizeOfSuffix: $sizeOfSuffix",3);
+ }
+ }
+ foreach $suffix (@oldChainingSuffixes){
+ printTrace("\ngetBackendtoExportFrom: suffix to compare with is a chained suffix: $suffix",3);
+ if ((belongsSuffix($suffix,$norm_bindDN)) && (length($suffix) > $sizeOfSuffix)) {
+ printMsg("\n\n*** Entry stored on a remote backend - $norm_bindDN");
+ printMsg("\n*** We don't migrate it");
+ return $NULL;
+ }
+ }
+ }
+ return $bindDN_backend;
+}
+
+
+sub getBackendtoImportTo {
+ my $bindDN = shift;
+ my $sizeOfSuffix = 0;
+ my $NULL = "";
+ my $suffixArg = "nsslapd-suffix";
+ my $bindDN_backend = $NULL;
+ open( DSELDIF, "< $DSEldif" ) || die "Can't open $DSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ $typeOfEntry = getTypeOfEntry($entry);
+ if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){
+ my $suffix = $entry->{$suffixArg}[0];
+ if ((belongsSuffix($suffix,$bindDN)) && (length($suffix) > $sizeOfSuffix)) {
+ $sizeOfSuffix = length($suffix);
+ $bindDN_backend = $entry->{cn}[0];
+ }
+ }
+ }
+ close(DSELDIF);
+ return $bindDN_backend ;
+}
+
+
+sub ExportAndAddEntry {
+ my $DN = shift;
+ my $backendtoExportFrom = shift;
+ my $ldif_dir = shift;
+ my $ldif = "$ldif_dir${PATHSEP}$backendtoExportFrom.ldif" ;
+ # first: export entry pointed out by the $DN to $ldif file
+ $ENV{"$LIB_PATH"}=$old_libpath;
+ if (! $ldif_dir) { $ldif_dir = $ldif_rep ;}
+ if (!(-d $ldif_dir)) {
+ mkdir($ldif_dir,0777) or die "\ncan't create $ldif_dir to store temporary ldif files\n";
+ }
+ chdir($oldSlapdExecDir) or die "\nCould not change directory to $oldSlapdExecDir: $!\n";
+ &db2Ldif($ldif, $backendtoExportFrom, $oldHome, $DN);
+ chdir($curdir) or die "\nCould not change directory to $curdir: $!\n";
+
+ # then: Add it to new
+ if (! $conn) {
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ }
+ open( BINDDNLDIF, "< $ldif" ) || die "\nCan't open $ldif: $!: \n";
+ my $in = new Mozilla::LDAP::LDIF(*BINDDNLDIF) ;
+ while ($entry = readOneEntry $in) {
+ my $entryDN = $entry->getDN(1);
+ if ($DN eq $entryDN) {
+ addEntryToNew($entry, "nsds5ReplicaBindDN", 0);
+ }
+ }
+ close(BINDDNLDIF);
+ # remove the ldif file after the import
+ unlink($ldif) ;
+}
+
+#############################################################################
+sub MigrateNSDS_replication_agreement {
+ foreach $replicationAgreement (@replicationAgreements) {
+ my $DN = $replicationAgreement->getDN(1);
+ if (alreadyExistsInNew($replicationAgreement)){
+ # replication agreement already exists
+ printMsg("\n\n*** NSDS_REPLICATION_AGREEMENT - $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ &migrate_credential($replicationAgreement, "nsDS5ReplicaCredentials");
+ addEntryToNew($replicationAgreement, "NSDS_REPLICATION_AGREEMENT", 1);
+ }
+ }
+}
+
+
+sub parseNSDS_replication_agreement{
+ my $replicationAgreement = shift;
+ push @replicationAgreements, $replicationAgreement ;
+}
+
+#############################################################################
+
+sub migrateChangelog5{
+ my $changelog = shift;
+ my $DN = $changelog->getDN(1);
+ my $changelogdir = "nsslapd-changelogdir";
+ if (alreadyExistsInNew($changelog)){
+ # cn=changelog5,cn=config already exists in new
+ my $newChangelog = searchEntry($DN);
+ my @newChangelogdir = $newChangelog->getValues($changelogdir);
+ $changelog->setValues($changelogdir, @newChangelogdir);
+ updateEntry($changelog, "CHANGELOG5", 0, 1);
+ }
+ else {
+ # cn=changelog5,cn=config need to be created in new.
+ # the changelogdir value must be setup to <new_root_server>/slapd-instance/changelogdb
+ $changelog->setValues($changelogdir,"${serverHome}${PATHSEP}changelogdb");
+ addEntryToNew($changelog, "CHANGELOG5", 1);
+ }
+}
+
+
+sub migrateChangelog {
+ my $oldchangelogdir = "";
+ my $newchangelogdir = "";
+ my $changelogdir = "nsslapd-changelogdir";
+ my $CL5DN = "cn=changelog5,cn=config";
+ printTrace("\n\n***** Migrate Changelog...",0,1);
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF);
+ while ($entry = readOneEntry $in) {
+ $typeOfEntry = getTypeOfEntry($entry);
+ if ($typeOfEntry eq "CHANGELOG5"){
+ $oldchangelogdir = ($entry->getValues($changelogdir))[0];
+ }
+ }
+ close(DSELDIF);
+ if ($oldchangelogdir) {
+ # If using olddatadir to migrate from, the path of the changelogdb
+ # from the dse.ldif may not match the path where the old server
+ # root was archived. We may need to modify oldchangelogdir so the
+ # copy of the changelog files succeeds.
+ unless(-e $oldchangelogdir) {
+ if($olddatadir) {
+ my @cldbpath = split(/\//,$oldchangelogdir);
+ until($cldbpath[0] =~/^slapd-/) {
+ shift(@cldbpath);
+ }
+ my $tmpcldbpath = join(${PATHSEP}, @cldbpath);
+ $oldchangelogdir = "$oldDir${PATHSEP}$tmpcldbpath";
+ }
+ # If oldchangelogdir still looks to be wrong, prompt for the
+ # location instead of just failing on the copydir operation
+ # and bombing out of the migration.
+ unless(-e $oldchangelogdir) {
+ print("\n\nThe old changelog directory \"$oldchangelogdir\" doesn't exist. Please enter the correct path: ");
+ $oldchangelogdir = <STDIN>;
+ }
+ }
+ &startServer() unless (isDirectoryAlive());
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ my $newChangelog = searchEntry($CL5DN);
+ $newchangelogdir = ($newChangelog->getValues($changelogdir))[0];
+ stopServer($root,'slapd-'.$newname);
+ printTrace("\ncopying $oldchangelogdir${PATHSEP}* to $newchangelogdir",3);
+ copyDir("$oldchangelogdir","$newchangelogdir");
+
+ # We need to modify the DBVERSION file for a new verision of the db
+ open(DBVERSION,">$newchangelogdir${PATHSEP}DBVERSION") || die "Can't overwrite $newchangelogdir${PATHSEP}DBVERSION: $! ";
+ print DBVERSION "Changelog5/NSMMReplicationPlugin/3.0";
+ close(DBVERSION);
+
+ &startServer() unless (isDirectoryAlive());
+ }
+}
+
+#############################################################################
+
+sub migrateReplication{
+ my $replication = shift;
+ my $DN = $replication->getDN(1);
+ if (alreadyExistsInNew($replication)){
+ # replication agreement already exists
+ printMsg("\n\n*** $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ addEntryToNew($replication, "REPLICATION", 1);
+ }
+}
+
+#############################################################################
+
+sub migrateSecurity{
+ my $security = shift;
+ if ($entry->hasValue("objectClass", "nsEncryptionConfig")) {
+ my $certfile = "alias/slapd-" . $newname . "-cert8.db";
+ my $keyfile = "alias/slapd-" . $newname. "-key3.db";
+ $entry->setValues("nsCertfile",$certfile) if ! $entry->hasValue("nsCertfile",$certfile);
+ $entry->setValues("nsKeyfile",$keyfile) if ! $entry->hasValue("nsKeyfile",$keyfile);
+ }
+ if (alreadyExistsInNew($security)){
+ # already exists in new
+ updateEntry($security, "SECURITY", 0, 1);
+ }
+ else {
+ addEntryToNew($security, "SECURITY", 1);
+ }
+}
+
+#############################################################################
+
+sub migrateSNMP{
+ my $snmp = shift;
+ if (alreadyExistsInNew($snmp)){
+ # already exists in new
+ updateEntry($snmp, "SNMP", 0, 1);
+ }
+ else {
+ addEntryToNew($snmp, "SNMP", 1);
+ }
+}
+
+#############################################################################
+# printMsg print message to the user standard output.
+
+sub printMsg {
+
+ my $TypeMsg = shift ;
+ my $Msg = shift ;
+ my $LineNb = shift ;
+ if ($LineNb) {
+ printTrace("Line: $LineNb, $TypeMsg, $Msg");
+ }
+ else {
+ printTrace("$TypeMsg $Msg");
+ }
+}
+
+#############################################################################
+# print message error to the user standard output.
+
+sub printTrace {
+
+ my $Msg = shift ;
+ my $level = shift ;
+ my $sep = shift ;
+
+ if ($sep) {
+ print "\n-------------------------------------------------------------------------";
+ print LOGFILE "\n-------------------------------------------------------------------------";
+ }
+
+ if ($level <= $TRACELEVEL) {
+ print($Msg);
+ print LOGFILE $Msg ;
+ }
+}
+
+#############################################################################
+# this subroutine implements a very stupid version of diff
+
+sub diff {
+ my $f1 = shift;
+ my $f2 = shift;
+ my $lineToBeginWith = shift;
+ my $NULL = "" ;
+ my $diff_f1 = $NULL ;
+ my $diff_f2 = $NULL ;
+ my $retval = $NULL ;
+ my $ret;
+ open(F1, "$f1") or die "Could not open file $f1";
+ open(F2, "$f2") or close(F1), die "Could not open file $f2";
+
+ while (defined($l1 = <F1>)) {
+ if ($lineToBeginWith){
+ $lineToBeginWith -- ;
+ next ;
+ }
+ next if ($l1 =~ /^\#/);
+ $ret = defined($l2 = <F2>);
+ if ($ret) {
+ $ret = defined($l2 = <F2>) while ($ret && ($l2 =~ /^\#/)) ;
+ if ($ret) {
+ if (!($l1 eq $l2)) {
+
+ # ignore whitespace
+ $l1_clean = $l1 ;
+ $l2_clean = $l2 ;
+ $l1_clean =~ s/\s//g;
+ $l2_clean =~ s/\s//g;
+
+ if (!($l1_clean eq $l2_clean)) {
+ $diff_f1 .= "${l1}" unless ($l1_clean eq $NULL);
+ $diff_f2 .= "${l2}" unless ($l2_clean eq $NULL);
+ }
+ }
+ }
+ else {
+ next if ($l1 =~ /^\s*$/) ;
+ $diff_f1 .= "${l1}";
+ }
+ }
+ else {
+ next if ($l1 =~ /^\s*$/) ;
+ $diff_f1 .= "${l1}";
+ }
+ }
+
+ while (defined($l2 = <F2>)) {
+ if (($l2 =~ /^\#/) || ($l2 =~ /^\s*$/)) {
+ next ;
+ }
+ else {
+ $diff_f2 .= "${l2}" ;
+ }
+ }
+
+ close(F1);
+ close(F2);
+
+ $retval .= "- differences present in your config file but not in standard file:\n\n". "$diff_f1\n" if ($diff_f1) ;
+ $retval .= "- differences present in standard file but not in your config file:\n\n" . "$diff_f2" if ($diff_f2) ;
+ return $retval ;
+}
+
+sub CompareStdConfigFiles {
+ # Compare each configuration file against its default version. If it has changed,
+ # notify the user that the file has changed and will need to be checked by the
+ # user. This should be safe to do because there should be no path information
+ # stored in these conf files, which are just schema stuff.
+ # printTrace("\nCheck if standard configuration files have changed",3);
+
+ # get the version of the DS to migrate
+ ($oldVersion, $oldMinor) = &getVersion($oldDir, $oldversionstr);
+ # get the version of the new DS
+ ($Version, $Minor) = &getVersion($root);
+
+ # get old LIB_PATH
+ $old_libpath = &getLibPath($oldDir, $oldVersion, $oldMinor);
+ # get new LIB_PATH
+ $new_libpath = &getLibPath($root, $Version, $Minor);
+
+ my $origFilePath = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}install${PATHSEP}schema${PATHSEP}" ;
+ my $FilesChanged = "";
+ my $AllDiffs = "***********************************************************************";
+ my $NoChanges = "" ;
+ my $lineToBegin = 0 ;
+ opendir(CONFDIR, $oldSchemaDir) or
+ die "Error: could not open migrated config dir $oldConfDir: $!";
+
+ foreach $file (readdir(CONFDIR)) {
+ $origFile = $origFilePath . $file ;
+ $configFile = $oldSchemaDir . $file ;
+ if (( exists($stdIncludes{lc($file)})) && (-f $origFile)) {
+ $diffs = &diff($configFile, $origFile, $lineToBegin);
+ $lineToBegin = 0 if $lineToBegin ;
+ if ($diffs) {
+ $FilesChanged .= "\n$configFile";
+ $AllDiffs .= "\n$configFile is different than the standard configuration file" ;
+ $AllDiffs .= "\nYou will need to check this file and make sure its changes are compatible ";
+ $AllDiffs .= "with the new directory server\nHere are the differences:\n";
+ $AllDiffs .= "$diffs \n\n";
+ $AllDiffs .= "***********************************************************************";
+ }
+ else {
+ $NoChanges .= "\n$configFile";
+ }
+ }
+ }
+ closedir(CONFDIR);
+
+if ($FilesChanged) {
+ printTrace("\nNo changes to old configuration files:$NoChanges",3) ;
+ printTrace("\n***********************************************************************",3) ;
+ printMsg("\nThe following standard files have been modified: $FilesChanged");
+ if ($NO_INPUT_USER) {
+ # do nothing
+ }
+ else {
+ printMsg("\nDo you want to see the differences Yes/No [No] ?") ;
+ my $answer = <STDIN> ;
+ if ($answer =~ /y|yes/i) {
+ printMsg("$AllDiffs");
+ }
+ printMsg("\nDo you want to continue the migration Yes/No [No] ?");
+ $answer = <STDIN> ;
+ if (! ($answer =~ /y|yes/i)) {
+ exit(1);
+ }
+ }
+ }
+}
+
+
+
+#############################################################################
+
+# this is used to run the system() call, capture exit and signal codes,
+# and die() upon badness; the first argument is a directory to change
+# dir to, if any, and the rest are passed to system()
+sub mySystem {
+ my $rc = &mySystemNoDie(@_);
+ my ($dir, @args) = @_;
+ if ($rc == 0) {
+# success
+ } elsif ($rc == 0xff00) {
+ die "Error executing @args: error code $rc: $!";
+ } elsif ($rc > 0x80) {
+ $rc >>= 8;
+ die "Error executing @args: error code $rc: $!";
+ } else {
+ if ($rc & 0x80) {
+ $rc &= ~0x80;
+ }
+ die "Error executing @args: received signal $rc: $!";
+ }
+
+ # usually won't get return value
+ return $rc;
+}
+
+# This version does not die but just returns the error code
+sub mySystemNoDie {
+ my ($dir, @args) = @_;
+ if ($dir && ($dir ne "")) {
+ chdir($dir) or die "Could not change directory to $dir: $!";
+ }
+ my $cmd = $args[0];
+ # the system {$cmd} avoids some NT shell quoting problems if the $cmd
+ # needs to be quoted e.g. contains spaces; the map puts double quotes
+ # around the arguments on NT which are stripped by the command
+ # interpreter cmd.exe; but don't quote things which are already quoted
+ my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args;
+ my $rc = 0;
+ if ($cmd =~ /[.](bat|cmd)$/) {
+ # we have to pass batch files directly to the NT command interpreter
+ $cmd = $com_spec;
+# print "system $cmd /c \"@fixargs\"\n";
+ $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\"";
+ } else {
+# print "system $cmd @fixargs\n";
+ $rc = 0xffff & system {$cmd} @fixargs;
+ }
+ chdir(${curdir}) or die "Could not change directory to $curdir: $!";
+ return $rc;
+}
+
+###########################################################################################
+# #
+# Export/Import of the backends in @BACKENDS #
+# #
+###########################################################################################
+
+sub manydb2Ldif {
+ my $ldif_dir = shift;
+ $ENV{"$LIB_PATH"}=$old_libpath;
+ if (! $ldif_dir) { $ldif_dir = $ldif_rep ;}
+ if (!(-d $ldif_dir)) {
+ mkdir($ldif_dir,0777) or die "can't create $ldif_dir to store temporary ldif files";
+ }
+ chdir($oldSlapdExecDir) or die "Could not change directory to $oldSlapdExecDir: $!";
+ foreach $backend (@BACKENDS) {
+ my $ldif = "${ldif_dir}$backend.ldif" ;
+ &db2Ldif($ldif, $backend, $oldHome);
+ }
+ print " Done.\n";
+ chdir($curdir) or die "Could not change directory to $curdir: $!";
+}
+
+sub db2Ldif {
+ my $ldif = shift ;
+ my $backend = shift ;
+ my $home = shift ;
+ my $include_suffix = shift ;
+ my $db2ldif_param ;
+ if ($include_suffix) {
+ $db2ldif_param = "db2ldif -r -D $home -n $backend -a $ldif -s \"$include_suffix\"";
+ }
+ else {
+ $db2ldif_param = "db2ldif -r -D $home -n $backend -a $ldif";
+ }
+ open(DB2LDIF, "${quote}${quote}$slapdExecName${quote} $db2ldif_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n";
+ sleep(1); # allow some data to accumulate in the pipe
+ my $ii = 0;
+ while (<DB2LDIF>) {
+ ++$ii;
+ if (($ii % 250) == 0) {
+ printMsg(" Processing...\n");
+ }
+ printMsg($_);
+ }
+ close(DB2LDIF);
+ # set the ownership of the ldif file; should be the same as the 5.x slapd user id
+ if ((! $isNt) && ($oldlocaluser ne $localuser)) {
+ if (-f $ldif) {
+ chown( $newuid, $newgid, $ldif) or printMsg("\nUnable to change the ownership of $ldif to $localuser") ;
+ }
+ }
+}
+
+sub manyLdif2db {
+ my $ldif_dir = shift;
+ $ENV{"$LIB_PATH"}=$new_libpath;
+ chdir($slapdExecDir) or die "Could not change directory to $slapdExecDir: $!";
+ foreach $backend (@BACKENDS) {
+ my $ldif = "${ldif_dir}$backend.ldif" ;
+ &Ldif2db($ldif, $backend);
+ }
+ # remove the empty ldif directory
+ # but not if using the data dir
+ if (!$olddatadir) {
+ rmdir($ldif_dir);
+ }
+ chdir($curdir) or die "Could not change directory to $curdir: $!";
+}
+
+
+sub Ldif2db {
+ my $ldif = shift ;
+ my $backend = shift ;
+ my $ldif2db_param = "ldif2db -D $serverHome -n $backend -i $ldif";
+ open(LDIF2DB, "${quote}${quote}$slapdExecName${quote} $ldif2db_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n";
+ sleep(1); # allow some data to accumulate in the pipe
+ while (<LDIF2DB>) {
+ printMsg($_);
+ }
+ close(LDIF2DB);
+ # remove the ldif file after the import
+ # but not if using the data dir
+ if (!$olddatadir) {
+ unlink($ldif) ;
+ }
+}
+
+
+###########################################################################################
+# #
+# Running/Stopping the Server #
+# #
+###########################################################################################
+
+
+
+sub isDirectoryAlive {
+ die "\n Migration aborted. Make sure your old and new Directory Servers are installed on the same machine \n" if ( $LDAPservername == -1 );
+ my $test_conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd);
+ if ($test_conn) {
+ $test_conn->close();
+ return 1;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+
+sub startServer {
+ my $instanceDir = ${serverHome} ;
+ my $errLog = $instanceDir . $PATHSEP . 'logs' . $PATHSEP . 'errors';
+ # emulate tail -f
+ # if the last line we see does not contain "slapd started", try again
+ my $done = 0;
+ my $started = 0;
+ my $code = 0;
+ my $lastLine = "";
+ my $timeout = time + 240; # 4 minutes
+ $ENV{"$LIB_PATH"}=$new_libpath;
+
+ my $startCmd = $instanceDir . $PATHSEP . 'start' . $script_suffix;
+ if (! -f $startCmd) {
+ $startCmd = $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix;
+ }
+ $code = &mySystem($instanceDir,$startCmd);
+ open(IN, $errLog) or die "Could not open error log $errLog: $!";
+ my $pos = tell(IN);
+ while (($done == 0) && (time < $timeout)) {
+ for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) {
+ $lastLine = $_;
+ # print;
+ # the server has already been started and shutdown once . . .
+ if (/slapd started\./) {
+ $started++;
+ if ($started == 2) {
+ $done = 1;
+ }
+ # sometimes the server will fail to come up; in that case, restart it
+ } elsif (/Initialization Failed/) {
+ # print "Server failed to start: $_";
+ $code = &mySystem($instanceDir, $startCmd);
+ # sometimes the server will fail to come up; in that case, restart it
+ } elsif (/exiting\./) {
+ # print "Server failed to start: $_";
+ #$code = &mySystem($startCmd);
+ $code = &mySystem($instanceDir, $startCmd);
+ }
+ }
+ if ($lastLine =~ /PR_Bind/) {
+ # server port conflicts with another one, just report and punt
+ print $lastLine;
+ print "This server cannot be started until the other server on this\n";
+ print "port is shutdown.\n";
+ $done = 1;
+ }
+ if ($done == 0) {
+ # rest a bit, then . . .
+ sleep(2);
+ # . . . reset the EOF status of the file desc
+ seek(IN, $pos, 0);
+ }
+ }
+ close(IN);
+
+ sleep(5);
+ die "\nUnable to start the $Version.$Minor Directory Server\n" unless (isDirectoryAlive());
+
+ return 0;
+}
+
+sub stopServer {
+ my $root = shift;
+ my $name = shift;
+ $maxStopIterations = 5;
+ print "\nShutting down server $name . . .\n";
+ $ENV{"$LIB_PATH"}=$new_libpath;
+ $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop' . $script_suffix . $quote;
+ if (! -f $stopCmd) {
+ $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop-slapd' . $script_suffix . $quote;
+ }
+
+ if (! -f $stopCmd) {
+ # no stop command, probably a 1.X system; for NT, we'll try net stop
+ # for unix, we'll get the pid and kill it
+ if ($isNT) {
+ $stopCmd = 'net stop ' . $name;
+ } else {
+ # see if there is a pid file
+ $pidfile = $root . $PATHSEP . $name . $PATHSEP . 'logs' .
+ $PATHSEP . 'pid';
+ if (open(PIDFILE, $pidfile)) {
+ chomp($pid = <PIDFILE>);
+ close(PIDFILE);
+ while ($maxStopIterations-- && !$exitCode) {
+ $exitCode = kill(15, $pid);
+ }
+ $stopCmd = undef;
+ }
+ }
+ }
+
+ # keep looping until the stop cmd returns an error code, which usually
+ # means that what ever we want to stop is stopped, or some other error
+ # occurred e.g. permission, or no such service
+ $exitCode = &runAndIgnoreOutput($stopCmd);
+# print "stopServer: exitCode=$exitCode\n";
+ while ($stopCmd && $maxStopIterations-- && $exitCode) {
+ $exitCode = &runAndIgnoreOutput($stopCmd);
+# print "stopServer: exitCode=$exitCode\n";
+ }
+
+ if (!$maxStopIterations) {
+ print "Warning: could not shutdown the server: $!\n";
+ }
+ sleep(10) ;
+ $exitCode = 0;
+}
+
+
+sub runAndIgnoreOutput {
+ my $cmd = shift;
+ printMsg(".");
+ open(RUNCMD, "${quote}$cmd${quote} 2>&1 |") or die "Error: could not run $cmd: $!";
+ printMsg(".");
+ sleep(1); # allow pipe to fill with data
+ printMsg(".");
+ while (<RUNCMD>) {
+# print;
+ }
+ my $code = close(RUNCMD);
+# print "runAndIgnore: code=$code status=$?\n";
+ return $?;
+}
+
+#############################################################################
+# migrate SSL info
+
+sub MigrateSSL {
+ my $secPwd = 'bidon' ;
+ # copy the SSL directory
+ &copyDir("$oldHome${PATHSEP}ssl","$serverHome${PATHSEP}ssl") if (-d "$oldHome${PATHSEP}ssl");
+ # copy the cert db and key files
+ if ( -d "$oldDir${PATHSEP}alias") {
+ $aliasDir = "$root${PATHSEP}alias";
+ if (! -d $aliasDir) {
+ mkdir($aliasDir, 0750);
+ }
+ &stopServer($root,'slapd-'.$newname);
+ my $keydb = "$aliasDir${PATHSEP}slapd-$newname-key3.db" ;
+ my $certdb = "$aliasDir${PATHSEP}slapd-$newname-cert8.db" ;
+ my $certdb7 = "$aliasDir${PATHSEP}slapd-$newname-cert7.db" ;
+ my $old_keydb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-key3.db" ;
+ my $old_certdb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-cert7.db";
+ my $keydb_backup = "$aliasDir${PATHSEP}slapd-$newname-key3.db_backup" ;
+ my $certdb_backup = "$aliasDir${PATHSEP}slapd-$newname-cert7.db_backup" ;
+ if (-f $old_keydb) {
+ if (-f $keydb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$keydb already exists. backup in $keydb_backup ...");
+ &copyBinFile($keydb,$keydb_backup);
+ &copyBinFile($old_keydb,$keydb);
+ }
+ else {
+ print("\n\n$keydb already exists. Do you want to overwrite it ? [no]: ");
+ my $answer = <STDIN> ;
+ if ($answer =~ /^y|yes$/i) {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ if (-f $old_certdb) {
+ $mode = (stat($old_certdb))[2] if $PRESERVE;
+ if (-f $certdb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$certdb already exists. backup in $certdb_backup ...");
+ &copyBinFile($certdb,$certdb_backup);
+ unlink($certdb) || print "Couldn't delete $certdb : $!\n";
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ else {
+ print("\n\n$certdb already exists. Do you want to overwrite it ? [no]: ");
+ my $answer = <STDIN> ;
+ if ($answer =~ /^y|yes$/i) {
+ unlink($certdb) || print "Couldn't delete $certdb : $!\n";
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ # copy the old password file
+ if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") {
+ &copyBinFile(
+ "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt",
+ "$aliasDir${PATHSEP}$type-$newname-pin.txt"
+ );
+ }
+ &startServer();
+ if ($PRESERVE) {
+ chown($newuid,$newgid,$certdb) || print "Failed to set uid $newuid gid $newgid on $certdb : $!\n";
+ chmod($mode,$certdb) || print "Failed to set mode $mode on $certdb : $!\n";
+ }
+ }
+
+}
+
+sub DisableSSL {
+ my $entry = $conn->search("cn=config","base","objectclass=*");
+ my $LDAPparam = "nsslapd-security" ;
+ my $Value = "off" ;
+ if ($entry->{$LDAPparam}[0] ne $Value) {
+ printTrace("\nDisable SSL...",1);
+ $entry->setValues($LDAPparam, $Value);
+ }
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nSSL disabled",2);
+ }
+ else {
+ printMsg("\nCan't disabled SSL. The server may have problems to start");
+ }
+}
+
+# enable the migration of client authentication informations
+sub MigrateCertmap {
+ # backup the old certmap.conf and replace it with the new one
+ my $oldCertmap = "$oldDir${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf";
+ my $newCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf" ;
+ my $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ;
+ if (-f $oldCertmap) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$newCertmap has been backup in $backupCertmap");
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($oldCertmap,$newCertmap);
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\n\nWhere do you want to back up the file $newCertmap [$backupCertmap] ?") ;
+ my $Answer = <STDIN> ;
+ $backupCertmap = $Answer if ($Answer ne "\n");
+ chomp($backupCertmap);
+ printTrace("\nDest: .$backupCertmap.",4);
+ if (-e $backupCertmap) {
+ printMsg("\n\n$backupCertmap already exists. Do you want to overwrite it Yes/No [No] ?") ;
+ if (<STDIN> =~ /yes|y/i) {
+ $Ask = 0 ;
+ }
+ else {
+ $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ;
+ }
+ }
+ else {
+ $Ask = 0 ;
+ }
+ }
+ printTrace("\nBackup file: $newCertmap in $backupCertmap",4);
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($oldCertmap,$newCertmap);
+ }
+ }
+ else {
+ }
+}
+
+sub hasChangedoldCertmap {
+ my $certmapfile = shift ;
+ my @reference = ("certmap default default",
+ "default:DNComps",
+ "default:FilterComps e") ;
+ my $cpt = 0 ;
+ printTrace("\nhasChangedoldCertmap",3);
+ open(CERTMAP,"< $certmapfile");
+ while (<CERTMAP>) {
+ if ((! /^\s*#/) && (! /^\s*$/)) {
+ my $ref = $reference[$cpt] ;
+ printTrace("\nValue: $_, ref: $ref",4);
+ if (! /^\s*$ref\s*$/) {
+ return 1 ;
+ }
+ else {
+ $cpt++ ;
+ }
+ }
+ }
+ close (CERTMAP);
+ printTrace("\ncpt: $cpt",4);
+ if ($cpt < $#reference) {
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+
+###########################################################################################
+# #
+# Copy directory and files functions #
+# #
+###########################################################################################
+
+
+sub copyDir {
+ my $src = shift;
+ my $dest = shift;
+ my $exclude = shift;
+
+ opendir( SRC, $src ) or die "Can't open directory $src: $!: ";
+ my $mode;
+ my $uid;
+ my $gid;
+ mkdir ( $dest , 0755 ) or die "\nCan't create directory $dest. \nPlease check you have enough rights to create it and/or check that your parent directory exists.\n" if !( -e $dest );
+ if ($PRESERVE) {
+ $mode = (stat($src))[2];
+ ($uid, $gid) = (stat(_))[4..5];
+ # Make sure files owned by the old user are owned by the
+ # new user
+ if ($uid == $olduid) {
+ $uid = $newuid;
+ $gid = $newgid;
+ }
+ chown $uid, $gid, $dest;
+ chmod $mode, $dest;
+ }
+ local ( @files ) = readdir ( SRC );
+ closedir( SRC );
+ for ( @files ) {
+ if ( $_ eq "." || $_ eq ".." ) {
+ next;
+ } elsif ( $exclude && /$exclude/ ) {
+ next;
+ } elsif( -d "$src${PATHSEP}$_") {
+ &copyDir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" );
+ } else {
+ &copyBinFile ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_");
+ }
+ }
+}
+
+sub copyBinFile {
+ my $src = shift;
+ my $dest = shift;
+ my $buf = "";
+ my $bufsize = 8192;
+
+ open( SRC, $src ) || die "Can't open $src: $!\n";
+ # if we are given a directory destination instead of a file, extract the
+ # filename portion of the source to use as the destination filename
+ if (-d $dest) {
+ $dest = $dest . $PATHSEP . &basename($src);
+ }
+ open( DEST, ">$dest" ) || die "Can't create $dest: $!\n";
+ binmode SRC;
+ binmode DEST;
+ if ($PRESERVE) {
+ $mode = (stat($src))[2];
+ ($uid, $gid) = (stat(_))[4..5];
+ # Make sure files owned by the old user are owned by the
+ # new user
+ if ($uid == $olduid) {
+ $uid = $newuid;
+ $gid = $newgid;
+ }
+ chown $uid, $gid, $dest;
+ chmod $mode, $dest;
+ }
+ while (read(SRC, $buf, $bufsize)) {
+ print DEST $buf;
+ }
+ close( SRC );
+ close( DEST );
+}
+
+#############################################################################################################
+# backup 5.x configuration files #
+# backup the directory <root_server5>/slapd-instance/config dans <root_server5>/slapd-instance/BackupConfig # #
+# #
+#############################################################################################################
+
+
+sub backupConfigFiles {
+ # backup the 5.x config files
+ my $src = "$serverHome${PATHSEP}config" ;
+ my $dest = "$serverHome${PATHSEP}config_backup" ;
+ if ($NO_INPUT_USER) {
+ printMsg("\n$src has been backup in $dest");
+ &copyDir($src,$dest);
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\n\nWhere do you want to back up your configuration directory [$dest] ?") ;
+ my $Answer = <STDIN> ;
+ $dest = $Answer if ($Answer ne "\n");
+ chomp($dest);
+ printTrace("\nDest: .$dest.",4);
+ if (-e $dest) {
+ printMsg("\n\n$dest already exists. Do you want to overwrite it Yes/No [No] ?") ;
+ if (<STDIN> =~ /yes|y/i) {
+ $Ask = 0 ;
+ }
+ else {
+ $dest = "$serverHome${PATHSEP}config_backup" ;
+ }
+ }
+ else {
+ $Ask = 0 ;
+ }
+ }
+ printTrace("\nBackup Directory: $src in $dest",4);
+ &copyDir($src,$dest);
+ }
+}
+#############################################################################
+
+sub getLDAPservername {
+ my $oldLDAPservername;
+ my $LDAPservername;
+ my $localhost = "nsslapd-localhost";
+ open(OLDDSELDIF, "< $oldDSEldif") or die "\nError: could not open old config file $oldDSEldif \n";
+ my $in = new Mozilla::LDAP::LDIF(*OLDDSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ my $DN = $entry->getDN(1) ;
+ if ($DN =~ /^cn=config$/i) {
+ my @values = $entry->getValues($localhost);
+ if ($entry->size($localhost)) {
+ $oldLDAPservername = $values[0];
+ printTrace("\nName of the old LDAP server: $oldLDAPservername",3);
+ }
+ break;
+ }
+ }
+ close(OLDSELDIF);
+
+ open( DSELDIF, "< $DSEldif" ) || die "\nCan't open $DSEldif \n";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ my $DN = $entry->getDN(1) ;
+ if ($DN =~ /^cn=config$/i) {
+ my @values = $entry->getValues($localhost);
+ if ($entry->size($localhost)) {
+ $LDAPservername = $values[0];
+ printTrace("\nName of the new LDAP server: $LDAPservername",3);
+ }
+ break;
+ }
+ }
+ close(DSELDIF);
+ # check ol and new Directory Instance are installed on the same physical machine.
+ if (lc($oldLDAPservername) ne lc($LDAPservername)) {
+ # warn the user he tries to migrate a 4.x server installed on a different machine from the 5.x one
+ printMsg("\n\nYour old instance is on $oldLDAPservername, whereas your new instance is on $LDAPservername. Migration on different machines is not supported. Do you want to continue ? Yes/No [No]:") ;
+ if (! (<STDIN> =~ /yes|y/i)) {
+ return -1;
+ }
+ }
+ return $LDAPservername ;
+}
+
+#############################################################################
+
+sub getLibPath {
+ my $myDir = shift;
+ my $myVersion = shift;
+ my $myMinor = shift;
+
+ if ($isNT) {
+ return $ENV{"$LIB_PATH"};
+ }
+ if (($myVersion >= 6) && ($myMinor >= 2)) {
+ return
+ "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}".
+ "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}".
+ $ENV{"$LIB_PATH"};
+ } else {
+ return "$myDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ }
+}
+
+#############################################################################
+
+sub getVersion {
+ my $dir = shift;
+ my $versionstr = shift;
+ my $version = 0;
+ my $minor = 0;
+ my $buildNumber = 0;
+ my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+ my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}";
+
+ # find the slapd executable
+ if (!$versionstr) { # version not specified on cmd line - find it
+ $prog = $dir . $progDir . $slapdExecName;
+ if (! -f $prog) {
+ $prog = $dir . $progDir2 . $slapdExecName;
+ if (-f $prog && $isNT) {
+ # if slapd is in bin/slapd and we're on NT, just assume version 1;
+ # apparently, slapd.exe doesn't like the -v argument . . .
+ return ( '1', $minor );
+ }
+ else{
+ die "Could not run slapd program $prog: $!";
+ }
+ }
+ else {
+ chdir($dir . $progDir);
+ }
+ $cur_libpath=$ENV{"$LIB_PATH"};
+ $ENV{"$LIB_PATH"}=
+ "$dir${PATHSEP}lib${SEP}".
+ "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}".
+ "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}".
+ $ENV{"$LIB_PATH"};
+ # read the old version from the old slapd program
+
+ open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or
+ die "Could not run slapd program $prog: $!";
+ sleep(1); # allow some data to accumulate in the pipe
+# print "Output from $prog -v:\n";
+ while (<F>) {
+ if (/^Netscape-Directory/ || /^iPlanet-Directory/i) {
+ $versionstr = $_;
+ last;
+ }
+ }
+ $code = close(F);
+ # print "$prog returned code=$code status=$?\n";
+ $ENV{"$LIB_PATH"}=$cur_libpath;
+ }
+
+ if ($versionstr =~ /^Netscape-Directory\/(\d+)\.(\d+)(?:b\d)*\s+(\S+)/) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ }
+ elsif ($versionstr =~ /^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ...
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ }
+ elsif ($versionstr =~ /^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ } elsif ($versionstr =~ /(\d+)\.(\d+)/) {
+ $version = $1;
+ $minor = $2;
+ }
+
+ if ($version == 0) {
+ die "\nCould not determine version of the directory server in $dir: \n";
+ }
+
+ # distinguish the 4.1 and the 4.11 thanks to the buildNumber
+ if (($version == 4) && ($minor == 1)){
+ if (! ($buildNumber =~ /^B99\.16/)) {
+ # it's not a 4.1 Netscape Directory Server => it's a 4.11
+ $minor = 11 ;
+ }
+ }
+ chdir($curdir) or die "Could not change directory to $curdir: $!" ;
+ return ( $version, $minor );
+}
+
+###############################################################################################
+sub normalizeDir {
+ my $dir = shift ;
+ my $dir_prec = "" ;
+ while ($dir_prec ne $dir) {
+ $dir_prec = $dir ;
+ if ($isNT) {
+ grep { s@\\\\@\\@g } $dir ;
+ }
+ else {
+ grep { s@//@/@g } $dir ;
+ }
+ }
+ return $dir ;
+}
+
+
+###############################################################################################
+
+sub GetTime {
+ my $tm = localtime;
+ (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900);
+ $sec = "0$sec" unless $sec > 9 ;
+ $min = "0$min" unless $min > 9 ;
+ $hour = "0$hour" unless $hour > 9 ;
+ $dd = "0$dd" unless $dd > 9 ;
+ $mm = "0$mm" unless $mm > 9 ;
+ return ($sec, $min, $hour, $dd, $mm, $yy);
+}
+
+###############################################################################################
+# get uid and group id of the 5.x slapd server.
+# The uid is done through the nsslapd-localuser attribute
+
+sub getuid_gid {
+ my $newuid ;
+ my $newgid ;
+ my $localuser ;
+ my $localuser_attr = "nsslapd-localuser" ;
+ if (! $isNT) {
+ &startServer() unless (isDirectoryAlive());
+ my $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ my $entry = $conn->search("cn=config ", "base","objectclass=*", 0, ($localuser_attr)) ;
+ # Tests wether we succeed to get the entry cn=config
+ die "\nCan't get the entry cn=config \n" unless ($entry);
+ my @values = $entry->getValues($localuser_attr);
+ $conn->close();
+ if ($#values == -1 || ($values[0] eq "") ) { # tests wether the nsslapd-localuser attribute has a value
+ printMsg("\nNo localuser has been found in the configuration of the directory. ");
+ if ($NO_INPUT_USER) {
+ printMsg("\nWe considered nobody as the localuser");
+ $localuser = "nobody" ;
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\nUnder what user does your $Version.$Minor directory server run [nobody] ? ") ;
+ $localuser = <STDIN> ;
+ chomp($localuser);
+ $localuser = "nobody" if ($localuser eq "");
+ ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ;
+ if ($newuid) {
+ $Ask = 0 ;
+ }
+ else {
+ printMsg("\nError: $localuser is unknown from the system ");
+ }
+ }
+ }
+ }
+ else {
+ $localuser = $values[0]; # returns the first value (we should only have one localuser)
+ my $size = $#values ;
+ }
+ ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ;
+ return ($localuser, $newuid, $newgid) ;
+ }
+ else {
+ return () ;
+ }
+}
+
+sub getolduid_gid {
+ my $oldlocaluser ;
+ my $localuserAttr = "nsslapd-localuser";
+ my $entry ;
+ if (! $isNT) {
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ $typeOfEntry = getTypeOfEntry($entry);
+ if ($typeOfEntry eq "CONFIG_NODE") {
+ $oldlocaluser = $entry->{$localuserAttr}[0] if ($entry->exists($localuserAttr));
+ break ;
+ }
+ }
+ close(DSE);
+ ($olduid, $oldgid) = (getpwnam("$oldlocaluser"))[2..3] ;
+ return ($oldlocaluser, $olduid, $oldgid) ;
+ }
+ else {
+ return ();
+ }
+}
+###############################################################################################
+# get current directory
+
+sub getCwd {
+ my $command = $isNT ? "cd" : "/bin/pwd";
+ open(PWDCMD, "$command 2>&1 |") or
+ die "Error: could not execute $command: $!";
+ # without the following sleep, reading from the pipe will
+ # return nothing; I guess it gives the pwd command time
+ # to get some data to read . . .
+ sleep(1);
+ my $currentdir;
+ while (<PWDCMD>) {
+ if (!$currentdir) {
+ chomp($currentdir = $_);
+ }
+ }
+ my $code = close(PWDCMD);
+# if ($code || $?) {
+# print "$command returned code=$code status=$? dir=$curdir\n";
+# }
+# print "getCwd curdir=\[$curdir\]\n";
+ return $currentdir;
+}
+
+################################
+# Need to migrate the credential.
+# If the credential can not be migrated, leave it at it is
+################################
+sub migrate_credential{
+ my $entry_to_modify = shift;
+ my $credentials_attr = shift;
+ my @old_value = $entry_to_modify->getValues($credentials_attr);
+ my $migratecredExecName = 'migratecred';
+ my $credOldHome = $oldHome;
+ my $credServerHome = $serverHome;
+
+ if ($isNT) {
+ # oldHome may be pointing to the archived copy of the
+ # instance dir which may be different than the path that
+ # the instance was originally installed as on Windows. If
+ # this path is not the original install path, then the
+ # credential will not be migrated correctly. We should
+ # prompt the user on Windows for the correct path.
+
+ print "\n\nThe old instance path must be the same as where it was";
+ print "\ninitially installed, not where it was archived in order";
+ print "\nfor this step to succeed. Please verify that the path";
+ print "\nis correct. Note that case sensitivity is important here.";
+ print "\n\nOld Instance Directory: $credOldHome";
+ print "\nIs this correct? (y/n): ";
+ chomp(my $answer = <STDIN>);
+ if (!($answer =~ /y|yes/i)) {
+ print "\nPlease enter the correct path for the old instance directory: ";
+ chomp($credOldHome = <STDIN>);
+ }
+
+ print "\n\nThe new instance path must also be correct for this step";
+ print "\nto succeed. Please verify that the path is correct. Note";
+ print "\nthat case sensitivity is important here.";
+ print "\n\nNew Instance Directory: $credServerHome";
+ print "\nIs this correct? (y/n): ";
+ chomp(my $answer = <STDIN>);
+ if (!($answer =~ /y|yes/i)) {
+ print "\nPlease enter the correct path for the new instance directory: ";
+ chomp($credServerHome = <STDIN>);
+ }
+ }
+# print "\nMigratecred command is: ${quote}$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}$migratecredExecName${quote} -o $credOldHome -n $credServerHome -c @old_value\n";
+
+ my @new_cred = `${quote}$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}$migratecredExecName${quote} -o $credOldHome -n $credServerHome -c @old_value`;
+
+ if ( $? == 0 )
+ {
+ $entry_to_modify->setValues($credentials_attr, @new_cred);
+ }
+}
+
diff --git a/ldap/admin/src/scripts/template-migrate5to7 b/ldap/admin/src/scripts/template-migrate5to7
new file mode 100644
index 00000000..50aead79
--- /dev/null
+++ b/ldap/admin/src/scripts/template-migrate5to7
@@ -0,0 +1,3043 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# Migrate a 5.x directory server to a 7.0 directory server
+
+#######################################################################################################
+# enable the use of Perldap functions
+require DynaLoader;
+
+use Getopt::Std;
+use Mozilla::LDAP::Conn;
+use Mozilla::LDAP::Entry;
+use Mozilla::LDAP::LDIF;
+use Mozilla::LDAP::Utils qw(:all);
+use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API
+use Time::localtime;
+use File::Basename;
+use Class::Struct ;
+
+#######################################################################################################
+
+sub usage {
+ print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n");
+ print(STDERR " -o oldInstancePath -n newInstancePath [-t tracelevel] [-L logfile]\n");
+ print(STDERR "************** parameters in brackets are optionals, others are required **************\n");
+ print(STDERR " Opts: -D rootdn - new 7.0 Directory Manager\n");
+ print(STDERR " : -w password - new 7.0 Directory Manager's password\n");
+ print(STDERR " : -w - - Prompt for new 7.0 Directory Manager's password\n");
+ print(STDERR " : -j filename - Read new 7.0 Directory Manager's password from file\n");
+ print(STDERR " : -p port - new 7.0 Directory Server port\n");
+ print(STDERR " : -o oldInstancePath - Path of the old instance to migrate \n");
+ print(STDERR " : -n newInstancePath - Path of the new 7.0 instance\n");
+ print(STDERR " : [-d dataPath] - Path to directory containing data files to import into new instance\n");
+ print(STDERR " : [-v oldVersion] - Version of old instance (obtained by running $slapdExecName -v\n");
+ print(STDERR " : [-t tracelevel] - (optional) specify the level of trace (0..3)\n");
+ print(STDERR " : [-L logfile] - (optional) specify the file to log the migration report \n");
+ }
+########################################################################################################
+
+BEGIN {
+
+ require 'uname.lib' ;
+ $isNT = -d '\\';
+ $PATHSEP = $isNT ? "\\" : "/";
+ ${SEP} = $isNT ? ";" : ":" ;
+ @INC = ( '.', '../../../admin/admin/bin');
+ grep { s@/@\\@g } @INC if $isNT;
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ # NT needs quotes around some things unix doesn't
+ $quote = $isNT ? "\"" : "";
+
+ # If this variable is set, all file/directory creation will make sure the mode
+ # and ownership of the destination is the same as the source
+ $PRESERVE = 1 if (!$isNT);
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ if ($isNT) {
+ $os = "WINNT";
+ } else {
+ $os = &uname("-s");
+ }
+ if ($isNT) {
+ # we have to pass batch files directly to the NT command interpreter
+ $com_spec = $ENV{ComSpec};
+ if (!$com_spec) {
+ $com_spec = $ENV{COMSPEC};
+ }
+ if (!$com_spec || ! -f $com_spec) {
+ # find the first available command interpreter
+ foreach $drive (c..z) {
+ $com_spec = "$drive:\\winnt\\system32\\cmd.exe";
+ last if (-f $com_spec);
+ $com_spec = undef;
+ }
+ if (! $com_spec) {
+ # punt and pray
+ $com_spec = 'c:\winnt\system32\cmd.exe';
+ }
+ }
+ }
+ if ( $os eq "AIX" ) {
+ $dll_suffix = "_shr.a";
+ }
+ elsif ( $os eq "HP-UX" ) {
+ $dll_suffix = ".sl";
+ }
+ elsif ( $os eq "WINNT" ) {
+ $dll_suffix = ".dll";
+ }
+ else {
+ $dll_suffix = ".so";
+ }
+ $slapdExecName = $isNT ? 'slapd.exe' : './ns-slapd';
+ select STDERR;
+ $| = 1;
+ select STDOUT;
+ $| = 1;
+}
+
+SWITCH: {
+ if ($os eq "AIX") {
+ $LIB_PATH = "LIBPATH" ;
+ last SWITCH ;
+ }
+ if ($os eq "HP-UX") {
+ $LIB_PATH = "SHLIB_PATH" ;
+ last SWITCH ;
+ }
+ if ($isNT) {
+ $LIB_PATH = "PATH" ;
+ last SWITCH ;
+ }
+ else {
+ $LIB_PATH = "LD_LIBRARY_PATH" ;
+ last SWITCH ;
+ }
+ }
+
+ # old parameters
+ ${oldDir} = "" ;
+ ${oldname} = "" ;
+ ${oldHome} = "" ;
+ ${oldConfDir} = "" ;
+ ${oldlocaluser} ;
+ ${olduid} ;
+ ${oldgid} ;
+
+ # new parameters
+ ${root} = "{{DS-ROOT}}" ;
+ ${type} = "" ;
+ ${newname} = "" ;
+ ${newport} = "" ;
+ ${rootDN} = "" ;
+ ${rootpwd} = "" ;
+ ${localhost} = "" ;
+ ${LogFileReport} = "" ;
+ ${newuid} ;
+ ${localuser} ;
+ ${newgid} ;
+ $NO_INPUT_USER = 0 ; # by default user can give inputs during the migration process
+ ${curdir} = getCwd();
+ ${slapdExecDir} = "${root}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+ # in 7.0 the replica Id is setup to a static value
+ $replicaIdvalue = 65535;
+
+ # specify the level of trace
+ $TRACELEVEL=1;
+
+ $LDAP_SERVER_UNREACHABLE = 81;
+
+ # get input users
+ &getParameters() ;
+ ${oldDir} = &normalizeDir("${oldDir}");
+ ${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ;
+ ${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ;
+ ${oldSchemaDir} = "${oldConfDir}schema${PATHSEP}";
+ ${oldDSEldif} = "${oldConfDir}dse.ldif";
+ ${serverHome} = "${root}${PATHSEP}$type-$newname" ;
+ ${schemaDir} = "$serverHome${PATHSEP}config${PATHSEP}schema${PATHSEP}";
+ ${DSEldif} = "$serverHome${PATHSEP}config${PATHSEP}dse.ldif";
+ ${ldif_rep} = "${oldConfDir}ldif${PATHSEP}" ;
+ ${oldSlapdExecDir} = "${oldDir}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+
+ open(LOGFILE, ">> $LogFileReport");
+
+ printTrace("\noldDir: $oldDir, oldHome: $oldHome, \noldConfDir: $oldConfDir, \nldif_rep: $ldif_rep, \nrootDN: $rootDN, \nPort: $newport, \nNewname: $newname\n",3);
+ printTrace("\nLIB_PATH: $LIB_PATH",4);
+
+ if (!(-d $serverHome)) {
+ printMsg("\n$serverHome doesn't exist\n");
+ exit(1);
+ }
+ if (!(-d $oldHome)) {
+ printMsg("\n$oldHome doesn't exist\n");
+ exit(1);
+ }
+
+ if ($olddatadir && !(-d $olddatadir)) {
+ print("\n$olddatadir doesn't exist\n");
+ exit(1);
+ }
+
+
+%HashParametersName = ();
+
+# The following hash displays only general server parameters to migrate under cn=config
+%GeneralSrvParamToMigrate = (
+ 'nsslapd-accesscontrol'=> '\n',
+ 'nsslapd-errorlog-logging-enabled'=> '\n',
+ 'nsslapd-accesslog-logging-enabled'=> '\n',
+ 'nsslapd-auditlog-logging-enabled'=> '\n',
+ 'nsslapd-accesslog-level'=> '\n',
+ 'nsslapd-accesslog-logbuffering'=> '\n',
+ 'nsslapd-accesslog-logexpirationtime'=> '\n',
+ 'nsslapd-accesslog-logexpirationtimeunit'=> '\n',
+ 'nsslapd-accesslog-logmaxdiskspace'=> '\n',
+ 'nsslapd-accesslog-logminfreediskspace'=> '\n',
+ 'nsslapd-accesslog-logrotationtime'=> '\n',
+ 'nsslapd-accesslog-logrotationtimeunit'=> '\n',
+ 'nsslapd-accesslog-maxlogsize'=> '\n',
+ 'nsslapd-accesslog-maxLogsPerDir'=> '\n',
+ 'nsslapd-attribute-name-exceptions'=> '\n',
+ 'nsslapd-auditlog-logexpirationtime'=> '\n',
+ 'nsslapd-auditlog-logexpirationtimeunit'=> '\n',
+ 'nsslapd-auditlog-logmaxdiskspace'=> '\n',
+ 'nsslapd-auditlog-logminfreediskspace'=> '\n',
+ 'nsslapd-auditlog-logrotationtime'=> '\n',
+ 'nsslapd-auditlog-logrotationtimeunit'=> '\n',
+ 'nsslapd-auditlog-maxlogsize'=> '\n',
+ 'nsslapd-auditlog-maxLogsPerDir'=> '\n',
+ 'nsslapd-certmap-basedn'=> '\n',
+ 'nsslapd-ds4-compatible-schema'=> '\n',
+ 'nsslapd-enquote-sup-oc'=> '\n',
+ 'nsslapd-errorlog-level'=> '\n',
+ 'nsslapd-errorlog-logexpirationtime'=> '\n',
+ 'nsslapd-errorlog-logexpirationtimeunit'=> '\n',
+ 'nsslapd-errorlog-logmaxdiskspace'=> '\n',
+ 'nsslapd-errorlog-logminfreediskspace'=> '\n',
+ 'nsslapd-errorlog-logrotationtime'=> '\n',
+ 'nsslapd-errorlog-logrotationtimeunit'=> '\n',
+ 'nsslapd-errorlog-maxlogsize'=> '\n',
+ 'nsslapd-errorlog-maxlogsperdir'=> '\n',
+ 'nsslapd-groupevalnestlevel'=> '\n',
+ 'nsslapd-idletimeout'=> '\n',
+ 'nsslapd-ioblocktimeout'=> '\n',
+ 'nsslapd-lastmod'=> '\n',
+ 'nsslapd-listenhost'=> '\n',
+ 'nsslapd-maxdescriptors'=> '\n',
+ 'nsslapd-nagle'=> '\n',
+ 'nsslapd-readonly'=> '\n',
+ 'nsslapd-referralmode'=> '\n',
+ 'nsslapd-plugin-depends-on-name'=> '\n',
+ 'nsslapd-plugin-depends-on-type'=> '\n',
+ 'nsslapd-referral'=> '\n',
+ 'nsslapd-reservedescriptors'=> '\n',
+ 'nsslapd-rootpwstoragescheme'=> '\n',
+ 'nsslapd-schemacheck'=> '\n',
+ 'nsslapd-secureport'=> '\n',
+ 'nsslapd-security'=> '\n',
+ 'nsslapd-sizelimit'=> '\n',
+ 'nsslapd-ssl3ciphers'=> '\n',
+ 'nsslapd-timelimit'=> '\n',
+ 'passwordchange'=> '\n',
+ 'passwordchecksyntax'=> '\n',
+ 'passwordexp'=> '\n',
+ 'passwordhistory'=> '\n',
+ 'passwordinhistory'=> '\n',
+ 'passwordlockout'=> '\n',
+ 'passwordlockoutduration'=> '\n',
+ 'passwordmaxage'=> '\n',
+ 'passwordmaxfailure'=> '\n',
+ 'passwordminage'=> '\n',
+ 'passwordminlength'=> '\n',
+ 'passwordmustchange'=> '\n',
+ 'passwordresetfailurecount' => '\n',
+ 'passwordstoragescheme' => '\n',
+ 'passwordunlock' => '\n',
+ 'passwordwarning' => '\n'
+);
+
+# the following hash displays global parameters related to database stored under cn=config,cn=ldbm database,cn=plugins,cn=config
+%GlobalConfigLDBMparamToMigrate = (
+ 'nsslapd-allidsthreshold' => '\n',
+ 'nsslapd-lookthroughlimit' => '\n',
+ 'nsslapd-mode' => '\n',
+ 'nsslapd-dbcachesize' => '\n',
+ 'nsslapd-cache-autosize' => '\n',
+ 'nsslapd-cache-autosize-split' => '\n',
+ 'nsslapd-db-transaction-logging' => '\n',
+ 'nsslapd-import-cachesize' => '\n'
+);
+
+# the following hash displays specific parameters to each backends and stored under cn=DBname,cn=ldbm database,cn=plugins,cn=config
+%LDBMparamToMigrate = (
+ 'nsslapd-cachesize' => '\n',
+ 'nsslapd-cachememsize' => '\n',
+ 'nsslapd-readonly' => '\n',
+ 'nsslapd-require-index' => '\n'
+);
+
+
+%ChainingConfigParams = (
+ 'nsactivechainingcomponents' => '\n',
+ 'nstransmittedcontrols' => '\n'
+ );
+
+%ChainingDefaultInstanceConfigParams = (
+ 'nsabandonedsearchcheckinterval' => '\n',
+ 'nsbindconnectionslimit' => '\n',
+ 'nsbindtimeout' => '\n',
+ 'nsbindretrylimit' => '\n',
+ 'nshoplimit' => '\n',
+ 'nsmaxresponsedelay' => '\n',
+ 'nsmaxtestresponsedelay' => '\n',
+ 'nschecklocalaci' => '\n',
+ 'nsconcurrentbindlimit' => '\n',
+ 'nsconcurrentoperationslimit' => '\n',
+ 'nsconnectionlife' => '\n',
+ 'nsoperationconnectionslimit' => '\n',
+ 'nsproxiedauthorization' => '\n',
+ 'nsreferralonscopedsearch' => '\n',
+ 'nsslapd-sizelimit' => '\n',
+ 'nsslapd-timelimit' => '\n'
+);
+
+%changelog5params = (
+ 'nsslapd-changelogmaxage' => '\n',
+ 'nsslapd-changelogmaxentries' => '\n'
+ );
+
+@SNMPparams = (
+ 'nssnmpenabled',
+ 'nssnmporganization',
+ 'nssnmplocation',
+ 'nssnmpcontact',
+ 'nssnmpdescription',
+ 'nssnmpmasterhost',
+ 'nssnmpmasterport',
+ 'nssnmpenabled',
+ 'aci'
+ );
+
+%stdIncludes = (
+ "." => "\n",
+ ".." => "\n",
+ "30ns-common.ldif " => "\n",
+ "50ns-mail.ldif " => "\n",
+ "50ns-news.ldif" => "\n",
+ "50iplanet-servicemgt.ldif"=> "\n",
+ "50netscape-servicemgt.ldif"=> "\n",
+ "50ns-mcd-browser.ldif" => "\n",
+ "50ns-proxy.ldif" => "\n",
+ "00core.ldif" => "\n",
+ "50ns-admin.ldif" => "\n",
+ "50ns-mcd-config.ldif " => "\n",
+ "50ns-value.ldif" => "\n",
+ "05rfc2247.ldif" => "\n",
+ "50ns-calendar.ldif" => "\n",
+ "50ns-mcd-li.ldif" => "\n",
+ "50ns-wcal.ldif" => "\n",
+ "05rfc2927.ldif" => "\n",
+ "50ns-certificate.ldif" => "\n",
+ "50ns-mcd-mail.ldif" => "\n",
+ "50ns-web.ldif" => "\n",
+ "10rfc2307.ldif" => "\n",
+ "50ns-compass.ldif" => "\n",
+ "50ns-media.ldif" => "\n",
+ "20subscriber.ldif" => "\n",
+ "50ns-delegated-admin.ldif"=> "\n",
+ "50ns-mlm.ldif" => "\n",
+ "25java-object.ldif" => "\n",
+ "50ns-directory.ldif" => "\n",
+ "50ns-msg.ldif" => "\n",
+ "28pilot.ldif" => "\n",
+ "50ns-legacy.ldif" => "\n",
+ "50ns-netshare.ldif" => "\n"
+);
+
+
+# Backends migrated (Backend CN attribute value)
+@BACKENDS = () ;
+# All pairs of suffix-backend are registered in this hashtable
+%oldBackends = () ;
+
+#store the backend instances to migrate
+@LDBM_backend_instances = ();
+
+#store the mapping tree
+@Mapping_tree_entries = ();
+
+#store the suffix and the associated chaining backend
+%oldChainingBackends = ();
+
+#store the multiplexor bind entries to migrate
+%MultiplexorBindDNEntriesToMigrate = ();
+
+#store the Replica bind DN entries to migrate
+%ReplicaBindDNEntriesToMigrate = ();
+
+# list of standard plugins
+%stdPlugins = (
+ "7-bit check" => "\n",
+ "acl plugin" => "\n",
+ "acl preoperation" => "\n",
+ "binary syntax" => "\n",
+ "case exact string syntax" => "\n",
+ "case ignore string syntax" => "\n",
+ "chaining database" => "\n",
+ "class of service" => "\n",
+ "country string syntax" => "\n",
+ "distinguished name syntax" => "\n",
+ "generalized time syntax" => "\n",
+ "integer syntax" => "\n",
+ "internationalization plugin" => "\n",
+ "ldbm database" => "\n",
+ "legacy replication plugin" => "\n",
+ "multimaster replication plugin" => "\n",
+ "octet string syntax" => "\n",
+ "clear" => "\n",
+ "crypt" => "\n",
+ "ns-mta-md5" => "\n",
+ "sha" => "\n",
+ "ssha" => "\n",
+ "postal address syntax" => "\n",
+ "referential integrity postoperation" => "\n",
+ "retro changelog plugin" => "\n",
+ "roles plugin" => "\n",
+ "telephone syntax" => "\n",
+ "uid uniqueness" => "\n",
+ "uri syntax" => "\n"
+ );
+
+# list of indexes that have disappeared from the new schema compared to 5.0
+%deniedIndexes = (
+ 'dncomp' => "\n"
+);
+
+@default_indexes = ();
+@indexes = ();
+
+# list of user added Plugin's. In 7.0, they 'll need to be recompiled
+@badPlugins = () ;
+
+@pluginAttrs = (
+ "objectclass",
+ "cn",
+ "nsslapd-pluginpath",
+ "nsslapd-plugininitfunc",
+ "nsslapd-plugintype",
+ "nsslapd-pluginenabled",
+ "nsslapd-plugin-depends-on-type",
+ "nsslapd-pluginid",
+ "nsslapd-pluginversion",
+ "nsslapd-pluginvendor"
+ );
+
+@nsds5replicaAttrs = (
+ 'objectclass',
+ 'nsDS5ReplicaRoot',
+ 'nsDS5ReplicaType',
+ 'nsDS5ReplicaLegacyConsumer',
+ 'nsDS5flags',
+ 'nsDS5ReplicaId',
+ 'nsDS5ReplicaPurgeDelay',
+ 'nsDS5ReplicaBinddn',
+ 'cn',
+ 'nsDS5ReplicaReferral'
+ );
+
+# array of replicas to migrate
+@new6replicas = ();
+
+# array of replication agreements to migrate
+@replicationAgreements = ();
+
+# compare LDIF standard config files with standard ones
+CompareStdConfigFiles() ;
+die "\n\n The version of product you want to migrate is not a 5.x Directory Server\n" unless ($oldVersion == 5) ;
+
+# Shutdown the legacy Directory instance
+printTrace("\nShutdown the legacy Directory Server instance: ${oldHome}",0);
+&stopServer($oldDir, 'slapd-'.$oldname);
+
+# get the hostname of the new LDAP server
+my $LDAPservername = &getLDAPservername();
+
+# get the uid and gid of the 7.0 slapd user
+($localuser, $newuid, $newgid) = getuid_gid();
+# get the uid and gid of the 5.x slapd user
+($oldlocaluser, $olduid, $oldgid) = getolduid_gid();
+printTrace("\n7.0 localuser: $localuser, uid: $newuid, gid: $newgid",2);
+printTrace("\n5.x localuser: $oldlocaluser, uid: $olduid, gid: $oldgid",2);
+
+# backup 7.0 configuration files in <6server_root>/slapd-instancename/config
+printTrace("\nBackup $serverHome${PATHSEP}config on $serverHome${PATHSEP}config_backup ...",0);
+&backupConfigFiles();
+
+# migrate the schema (need to stop and start the 7.0 server)
+printTrace("\nMigrate the schema...",0);
+MigrateSchema();
+
+# start the server unless it is already started
+&startServer() unless (isDirectoryAlive());
+
+############### Connect to the 7.0 LDAP Directory Server ######################
+$ENV{"$LIB_PATH"} = $new_libpath;
+
+die "\n Migration aborted. Make sure your old and new Directory Server are installed on the same machine \n" if ( $LDAPservername == -1 );
+$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+
+# Cconnection to 7.0 LDAP server is successful !
+printTrace("\nConnected to $Version.$Minor LDAP server",0) ;
+
+# Parse the main configuration file: dse.ldif
+printTrace("\n\nParse the old DSE ldif file: $oldDSEldif *****",0, 1);
+printTrace("\nThis may take a while ...\n",0);
+&MigrateDSEldif();
+
+#migrate LDBM backend instances
+printTrace("\n\nMigrate LDBM backend instances...",0,1);
+&migrateLDBM_backend_instances();
+
+#migrate mapping tree entries
+printTrace("\n\nMigrate mapping tree...",0,1);
+&migrateMappingTree();
+
+#migrate default indexes
+printTrace("\n\nMigrate default indexes...",0,1);
+migrateDefaultIndexes();
+
+#migrate indexes
+printTrace("\n\nMigrate indexes...",0,1);
+migrateIndexes();
+
+#migrate replicas
+printTrace("\n\nMigrate replicas...",0,1);
+&MigrateNSDS5_replica();
+
+#migrate replication agreements
+printTrace("\n\nMigrate replication agreements...",0,1);
+&MigrateNSDS_replication_agreement();
+
+#migrate key/cert databases
+printTrace("\n\nMigrate key/cert databases...",0,1);
+&MigrateSSL();
+
+# migrate certmap.conf
+printTrace("\n\nMigrate Certmap.conf...",0,1);
+&MigrateCertmap() ;
+
+################## Close the connection to 7.0 LDAP Server #####################
+printTrace("\n\n***** Close the LDAP connection to the new Directory Server instance ***** ",0);
+$conn->close;
+
+
+################## stop the new instance and Export/Import the data, restart the server ##################
+if (@BACKENDS) {
+ &stopServer($root,'slapd-'.$newname);
+ if ($olddatadir) {
+ printTrace("\nData already contained in $olddatadir...\n",0,1) ;
+ $ldif_rep = "$olddatadir${PATHSEP}";
+ } else {
+ printTrace("\nData processing...\n",0,1) ;
+ # migrate data for each backend: 5.x -> LDIF files
+ &manydb2Ldif($ldif_rep);
+ }
+
+ # migrate LDIF data to the new database: LDIF -> New
+ &manyLdif2db($ldif_rep);
+ &migrateChangelog();
+ printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1);
+ &importReplicaBindDNEntries();
+ printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1);
+ &importMultiplexorBindDNEntries();
+ &startServer() unless (isDirectoryAlive());
+}
+else {
+ printTrace("\nINFORMATION - There are no non-standard or non-already existing suffixes to migrate\n",0);
+ &migrateChangelog();
+ printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1);
+ &importReplicaBindDNEntries();
+ printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1);
+ &importMultiplexorBindDNEntries();
+}
+
+printMsg("\n\n ****** End of migration ******\n\n");
+
+close(LOGFILE);
+
+
+###########################################################################################
+# get input users
+sub getParameters {
+ my $exit = 0 ;
+ my $i = 0;
+ my $pwdfile= "";
+
+ while ($i <= $#ARGV) {
+ if ( "$ARGV[$i]" eq "-D" ) { # directory manager
+ if (! $rootDN) {
+ $rootDN = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-w") { # password
+ if (! $rootpwd) {
+ $rootpwd = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-j") { # password file
+ if (! $pwdfile) {
+ $pwdfile = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-o") { # old instance path
+ if (! $oldHome ) {
+ $oldHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $oldHome if $isNT ;
+ if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; }
+ if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) {
+ $oldDir = $1 ;
+ $type = $2 ;
+ $oldname = $3 ;
+ if ($isNT) {
+ $oldDir = lc($oldDir) ;
+ $type = lc($type) ;
+ $oldname = lc($oldname) ;
+ $oldHome = lc($oldHome) ;
+ grep { s@/@\\@g } $oldDir ;
+ grep { s@/@\\@g } $oldHome ;
+ }
+ }
+ else {
+ print("\nThe old instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-n") { # new instance path
+ if (! $serverHome ) {
+ $serverHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $root if $isNT ;
+ grep { s@\\@/@g } $serverHome if $isNT ;
+ if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; }
+ if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) {
+ $root = $1 if ($1);
+ $type = $2 ;
+ $newname = $3 ;
+ if ($isNT) {
+ $root = lc($root) ;
+ $type = lc($type) ;
+ $newname = lc($newname) ;
+ $serverHome = lc($serverHome) ;
+ grep { s@/@\\@g } $root ;
+ grep { s@/@\\@g } $serverHome ;
+ }
+ }
+ else {
+ print("\nThe new instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-p") { # new DS port
+ if (! $newport ) {
+ $newport = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-d") { # old instance LDIF data dir
+ if (! $olddatadir ) {
+ $olddatadir = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-v") { # old version
+ if (! $oldversionstr ) {
+ $oldversionstr = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL
+ my $value = $ARGV[++$i] ;
+ if ($value =~ /[0-3]/) {
+ $TRACELEVEL = $value ;
+ }
+ else {
+ print("\nThe tracelevel must belong to 0..3 interval");
+ &usage();
+ exit();
+ }
+ } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing
+ $NO_INPUT_USER = 1 ;
+ } elsif ("$ARGV[$i]" eq "-L") { # migration logfile
+ $LogFileReport = $ARGV[++$i] ;
+ }
+ else {
+ print("\nThe option $ARGV[$i] is not recognized");
+ &usage() ;
+ exit(1);
+ }
+ $i++;
+ }
+ if (! $rootDN) {
+ print("\nThe rootDN is missing");
+ $exit = 1;
+ }
+ if ($pwdfile ne "") {
+ # Open file and get the password
+ unless (open (RPASS, $pwfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $rootpwd = <RPASS>;
+ chomp($rootpwd);
+ close(RPASS);
+ } elsif ($rootpwd eq "-"){
+ # Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+ # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $rootpwd = ReadLine(0);
+# chomp($rootpwd);
+# ReadMode('normal');
+ }
+ if (! $rootpwd) {
+ print("\nThe rootpwd is missing");
+ $exit = 1 ;
+ }
+ if (! $newport) {
+ print("\nThe port is missing");
+ $exit = 1;
+ }
+ if (! $serverHome) {
+ print("\nThe new instance path is missing");
+ $exit = 1;
+ }
+ if (! $oldHome) {
+ print("\nThe old instance path is missing");
+ $exit = 1;
+ }
+ if ((! $LogFileReport) && $serverHome) {
+ ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime();
+ $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log";
+ }
+ if ($exit) {
+ &usage() ;
+ exit(1);
+ }
+
+}
+
+###################################################################################################
+
+sub MigrateSchema{
+ my $FilesChanged = "";
+ my $AllDiffs = "";
+ my $NoChanges = "" ;
+ my $lineToBegin = 0 ;
+ opendir(SCHEMADIR, $oldSchemaDir) or
+ die "Error: could not open migrated config dir $oldSchemaDir: $!";
+
+ foreach $file (readdir(SCHEMADIR)) {
+ if (! exists($stdIncludes{lc($file)})) {
+ my $newSchemaFile = $schemaDir . $file;
+ if (-f $newSchemaFile ) {
+ # The ldif file already exists. Make a diff and warn the user if different.
+ if (diff($newSchemaFile, $oldSchemaDir.$file)) {
+ &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive());
+ $AllDiffs .= "\n$file";
+ copyBinFile("$oldSchemaDir$file", $newSchemaFile);
+ }
+ }
+ else {
+ &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive());
+ $AllDiffs .= "\n$file";
+ copyBinFile("$oldSchemaDir$file", $newSchemaFile);
+ }
+ }
+ }
+ closedir(SCHEMADIR);
+ if ($AllDiffs) {
+ printMsg("\n\n***********************************************************************");
+ printMsg("\nThe following LDIF files have been migrated:");
+ printMsg("$AllDiffs");
+ printMsg("\n*************************************************************************\n\n");
+ }
+ &startServer() if (! isDirectoryAlive());
+}
+
+
+###################################################################################################
+# This subroutine is used to parse the dse.ldif file and call specific routines to act with entries
+sub MigrateDSEldif {
+ printTrace("\nMigrate DSE entries...",1);
+ my $tempoAlreadyDone = 0;
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ $typeOfEntry = getTypeOfEntry($entry);
+ SWITCH: {
+ if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){
+ parseLDBM_backend_instance($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "MAPPING_TREE"){
+ parseMapping_tree($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "DEFAULT_INDEX"){
+ parseDefaultIndex($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "INDEX"){
+ parseIndex($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "STANDARD_PLUGIN"){
+ migrateStdPlugin($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CONFIG_NODE"){
+ migrateConfig_Node($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CONFIG_LDBM_DATABASE"){
+ migrateConfig_LDBM_database($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CHAINING_BACKEND_CONFIG"){
+ migrateChainingBE_config($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CHAINING_BACKEND_INSTANCE"){
+ migrateChainingBE_instance($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "NSDS5_REPLICA"){
+ parseNSDS5_replica($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "NSDS_REPLICATION_AGREEMENT"){
+ parseNSDS_replication_agreement($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CHANGELOG5"){
+ migrateChangelog5($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "REPLICATION"){
+ migrateReplication($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "SECURITY"){
+ migrateSecurity($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "SNMP"){
+ migrateSNMP($entry);
+ last SWITCH;
+ }
+ }
+
+ }
+ close(DSELDIF);
+}
+
+#############################################################################
+# returns the "type of an entry". If the entry is not to be migrated its type is "NOT_MIGRATED_TYPE"
+
+sub getTypeOfEntry{
+ my $entry = shift;
+ my $DN = $entry->getDN(1) ; # 1 is to normalize the returned DN
+ if (($DN =~ /cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) {
+ return "LDBM_BACKEND_INSTANCE";
+ }
+ if (($DN =~ /cn=mapping tree,cn=config$/i) && (isObjectclass($entry,"nsMappingTree"))) {
+ return "MAPPING_TREE";
+ }
+ if (($DN =~ /cn=default indexes,cn=config,cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsIndex"))) {
+ return "DEFAULT_INDEX";
+ }
+ if (isObjectclass($entry,"nsIndex")) {
+ return "INDEX";
+ }
+ if ((isObjectclass($entry,"nsSlapdPlugin")) && (isStdPlugin($entry))) {
+ return "STANDARD_PLUGIN";
+ }
+ if ($DN =~ /^cn=config$/i) {
+ return "CONFIG_NODE";
+ }
+ if ($DN =~ /^cn=config,cn=ldbm database,cn=plugins,cn=config$/i) {
+ return "CONFIG_LDBM_DATABASE";
+ }
+ if (($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i) || ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i)){
+ return "CHAINING_BACKEND_CONFIG";
+ }
+ if (($DN =~ /cn=chaining database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) {
+ return "CHAINING_BACKEND_INSTANCE";
+ }
+ if (isObjectclass($entry,"nsDS5Replica")) {
+ return "NSDS5_REPLICA";
+ }
+ if (isObjectclass($entry,"nsDS5ReplicationAgreement")) {
+ return "NSDS_REPLICATION_AGREEMENT";
+ }
+ if ($DN =~ /^cn=changelog5,cn=config$/i) {
+ return "CHANGELOG5";
+ }
+ if (($DN =~ /cn=replication,cn=config$/i) && ($DN !~ /^cn=replication,cn=config$/i)) {
+ return "REPLICATION";
+ }
+ if ($DN =~ /cn=encryption,cn=config$/i) {
+ return "SECURITY";
+ }
+ if ($DN =~ /^cn=SNMP,cn=config$/i) {
+ return "SNMP";
+ }
+ return "NOT_MIGRATED_TYPE";
+}
+
+#############################################################################
+
+
+
+#############################################################################
+# returns 1 if the objectclass given in parameter is present in the objectclasses values of the entry
+# given in parameter, 0 else
+
+sub isObjectclass {
+ my $entry = shift;
+ my $objectclass = shift;
+ return ($entry->hasValue("objectclass",$objectclass,1));
+}
+
+#############################################################################
+
+sub isStdPlugin {
+ my $entry = shift;
+ my $CN = $entry->{cn}[0];
+ if (isObjectclass($entry,"nsSlapdPlugin")) {
+ return 1 if ($stdPlugins{lc($CN)});
+ }
+ return 0;
+}
+
+
+#############################################################################
+
+sub alreadyExistsInNew{
+ my $entry = shift;
+ my $mustExist = shift;
+ my $DN = $entry->getDN(1); # 1 to normalize the DN
+ # We have a name change of "uid uniqueness" plugin in DS6.x
+ # to "attribute uniqueness"
+ $DN =~ s/uid\ uniqueness/attribute\ uniqueness/ if ($DN =~ /uid\ uniqueness/);
+ return searchEntry($DN, $mustExist);
+}
+
+#############################################################################
+sub searchEntry {
+ my $DN = shift;
+ my $mustExist = shift;
+ my $res = $conn->search($DN, "base", "objectclass=*");
+ my $cpt = 5;
+ if ($res) {
+ return $res;
+ }
+ else {
+ my $errorCode = $conn->getErrorCode();
+ while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) {
+ printMsg("\ntry to reconnect to search $DN");
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ $res = $conn->search($DN, "base", "objectclass=*");
+ $errorCode = $conn->getErrorCode();
+ $cpt--;
+ }
+ if ($res){
+ return $res ;
+ }
+ elsif (($errorCode eq $LDAP_SERVER_UNREACHABLE) || ($mustExist)) {
+ my $msg = $conn->getErrorString();
+ printMsg("\n\n*** Failed to search: $DN");
+ printMsg("\n*** Error Msg: $msg, Error code: $errorCode");
+ }
+ return 0;
+ }
+}
+
+
+#############################################################################
+
+sub addEntryToNew{
+ my $entry = shift;
+ my $typeOfEntry = shift;
+ my $trace = shift;
+ my $res = $conn->add($entry);
+ my $DN = $entry->getDN(1);
+ my $cpt = 5;
+ if ($res) {
+ printTrace("\n$typeOfEntry - Add successfull: $DN",$trace);
+ return 1;
+ }
+ else {
+ my $errorCode = $conn->getErrorCode();
+ while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) {
+ printMsg("\ntry to reconnect to add $DN");
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ $res = $conn->add($entry);
+ $errorCode = $conn->getErrorCode();
+ $cpt--;
+ }
+ if ($res){
+ printTrace("\n$typeOfEntry - Add successfull: $DN",$trace);
+ return 1;
+ }
+ else {
+ my $msg = $conn->getErrorString();
+ printMsg("\n\n*** $typeOfEntry: Add Failed: $DN");
+ printMsg("\n*** Error Msg: $msg, Error code: $errorCode");
+ return 0;
+ }
+ }
+}
+
+#############################################################################
+
+sub updateEntry{
+ my $entry = shift;
+ my $typeOfEntry = shift;
+ my $CHECK = shift;
+ my $trace = shift;
+ my $cpt = 5;
+ if ($CHECK) {
+ if (! hasChanged($entry, $typeOfEntry)) {
+ return 1;
+ }
+ }
+ my $res = $conn->update($entry);
+ my $DN = $entry->getDN(1);
+ if ($res) {
+ printTrace("\n$typeOfEntry - Update successfull: $DN",$trace);
+ return 1 ;
+ }
+ else {
+ my $errorCode = $conn->getErrorCode();
+ while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) {
+ printMsg("\ntry to reconnect to update $DN");
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ $res = $conn->update($entry);
+ $errorCode = $conn->getErrorCode();
+ $cpt--;
+ }
+ if ($res){
+ printTrace("\n$typeOfEntry - Update successfull: $DN",$trace);
+ return 1;
+ }
+ else {
+ my $msg = $conn->getErrorString();
+ printMsg("\n\n*** $typeOfEntry - Update Failed: $DN");
+ printMsg("\n*** Error Msg: $msg, Error code: $errorCode");
+ return 0;
+ }
+ }
+}
+
+
+#############################################################################
+# returns 1 if the entry to migrate and the current entry are different one another
+
+sub hasChanged {
+ my $entry = shift;
+ my $typeOfEntry = shift;
+ my $DN = $entry->getDN(1);
+ my $newEntry = searchEntry($DN,1);
+ return 1 if (! $newEntry); # we shoudn't be in that case ...
+ # do the stuff to check wether the entry has changed or not given its type
+ if (($typeOfEntry eq "DEFAULT_INDEX") || ($typeOfEntry eq "INDEX")){
+ my @indexTypes = $entry->getValues("nsIndexType");
+ my @newIndexTypes = $newEntry->getValues("nsIndexType");
+ my @nsmatchingrules = $entry->getValues("nsmatchingrule");
+ my @newMatchingRules = $newEntry->getValues("nsmatchingrule");
+ return 1 if (Diffs(\@indexTypes, \@newIndexTypes));
+ return 1 if (Diffs(\@nsmatchingrules,\@newMatchingRules));
+ return 0;
+ }
+ if ($typeOfEntry eq "CHANGELOG5"){
+ printTrace("\nCheck wether changelog has changed or not",3);
+ my @params = keys(%changelog5params);
+ foreach $param (@params){
+ my @values = $entry->getValues($param);
+ my @newValues = $newEntry->getValues($param);
+ return 1 if (Diffs(\@values,\@newValues));
+ }
+ return 0;
+ }
+ if ($typeOfEntry eq "SNMP"){
+ foreach $param (@SNMPparams){
+ my @values = $entry->getValues($param);
+ my @newValues = $newEntry->getValues($param);
+ return 1 if (Diffs(\@values,\@newValues));
+ }
+ return 0;
+ }
+ # we don't know how to compare such type of entry => just return 1
+ return 1 ;
+}
+
+sub isAsystemIndex {
+ my $index = shift;
+ return ($index->hasValue("nsSystemIndex","true",1));
+}
+
+
+sub updatePathInPluginArgs {
+ my $plugin = shift;
+ my $argNum = 0;
+ my $argPrefix = "nsslapd-pluginarg";
+ my $cont = 1;
+ my $Unix_oldDir = ${oldDir} ;
+ my $Unix_root = ${root} ;
+ grep { s@\\@/@g } $Unix_oldDir if $isNT;
+ grep { s@\\@/@g } $Unix_root if $isNT;
+ while ($cont) {
+ my $arg = $argPrefix . $argNum ;
+ if ($plugin->exists($arg)) {
+ $_ = $plugin->{$arg}[0] ;
+ s@$Unix_oldDir@$Unix_root@ig ;
+ s/$type-$oldname/$type-$newname/ig ;
+ $plugin->setValues($arg, $_) ;
+ }
+ else {
+ $cont = 0 ;
+ }
+ $argNum++;
+ }
+ return $plugin;
+}
+
+
+sub Diffs {
+ my $valuesToMigrate = shift;
+ my $currentValues = shift;
+ return 1 if (getDiff(\@{$valuesToMigrate},\@{$currentValues}));
+ return 1 if (getDiff(\@{$currentValues},\@{$valuesToMigrate}));
+ return 0 ;
+}
+
+sub getDiff {
+ # we get references to arrays
+ my $elements = shift ;
+ my $existing_elements = shift ;
+ my %count = () ;
+ my %countEE = () ;
+ @diff = () ;
+ foreach $e (@{$elements}, @{$existing_elements}) { $count{$e}++ ;}
+ foreach $e (@{existing_elements}) { $countEE{$e}++ ;}
+ foreach $e (@{$elements}) {
+ # if $e is only present in @$elements, we push it to the diff array
+ if (($count{$e} == 1) && ($countEE{$e} == 0)) {
+ push @diff, $e ;
+ }
+ }
+ return @diff ;
+}
+
+sub registerSuffix_Backend {
+ my $ldbmDatabase = shift;
+ my $CN = $ldbmDatabase->{cn}[0];
+ my $suffixArg = "nsslapd-suffix";
+ my $suffix = $ldbmDatabase->{$suffixArg}[0];
+ $oldBackends{$suffix} = $CN;
+}
+
+
+#############################################################################
+# #
+# #
+# #
+#############################################################################
+sub migrateLDBM_backend_instances {
+ foreach $entry (@LDBM_backend_instances) {
+ my $DN = $entry->getDN(1); # 1 is to normalize the DN
+ my $CN = $entry->{cn}[0];
+ my $expLdif;
+ my $confirm = "No";
+ my $dest = "$serverHome${PATHSEP}db_backup" ;
+ my $newSlapdExecDir = "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server";
+
+ if ($DN =~/cn=netscaperoot,cn=ldbm database/i){
+ printTrace("\n\n*** INFORMATION - NetscapeRoot is NOT migrated",0);
+ }
+ else {
+ if(alreadyExistsInNew($entry)){
+ printMsg("\n\n*** LDBM_BACKEND_INSTANCE - $DN already exists");
+ printMsg("\n*** Migration will overwrite existing database");
+ printMsg("\nDo you want to continue Yes/No [No] ?") ;
+ my $answer = <STDIN> ;
+ if ($answer =~ /y|yes/i) {
+ printMsg("Do you want to export the existing data Yes/No [Yes] ?");
+ my $answer = <STDIN> ;
+ if (!($answer =~ /n|no/i)) {
+ mkdir $dest, 0700 unless (-d $dest);
+ $expLdif = "$dest${PATHSEP}$CN.ldif";
+ while (!($confirm =~ /y|yes/i)) {
+ printMsg("\nEnter the full pathname of the file [$expLdif]:") ;
+ $answer = <STDIN> ;
+ chomp($expLdif = $answer) unless ($answer eq "\n");
+ printMsg("\nExisting data will be exported under $expLdif");
+ printMsg("\nContinue Yes/No [No] ?");
+ $confirm = <STDIN>;
+ }
+ $ENV{"$LIB_PATH"}=$new_libpath;
+ chdir($newSlapdExecDir) or die "\nCould not change directory to $newSlapdExecDir: $!\n";
+ printTrace("\nNow backing up database $CN in $expLdif\n",0);
+ &stopServer($root,'slapd-'.$newname);
+ &db2Ldif($expLdif, $CN, $serverHome);
+ &startServer() unless (isDirectoryAlive());
+ }
+ push @BACKENDS, $CN;
+ } else {
+ printMsg("\n*** Migration will not update it");
+ break;
+ }
+ } else {
+ printTrace("\nWe should add the backend instance $DN",3);
+ my $suffixarg = "nsslapd-suffix" ;
+ my $suffixname= $entry->{$suffixarg}[0] ;
+ my $newEntry = $conn->newEntry() ;
+ $newEntry->setDN($DN);
+ $newEntry->setValues("objectclass", "top", "extensibleObject", "nsBackendInstance" );
+ $newEntry->setValues("cn", $CN );
+ $newEntry->setValues($suffixarg, $suffixname);
+ my @params = keys(%LDBMparamToMigrate);
+ foreach $param (@params) {
+ my @values = $entry->getValues($param);
+ $newEntry->setValues($param, @values) if (@values);
+ }
+ if (addEntryToNew($newEntry, "LDBM_BACKEND_INSTANCE",1)) {
+ push @BACKENDS, $CN;
+ }
+ }
+ }
+ }
+}
+
+sub parseLDBM_backend_instance {
+ my $entry = shift;
+ &registerSuffix_Backend($entry);
+ push @LDBM_backend_instances, $entry;
+}
+
+#############################################################################
+sub migrateMappingTree {
+ foreach $entry (@Mapping_tree_entries) {
+ my $DN = $entry->getDN(1); # 1 si to normalize the DN
+ if ($DN =~/cn=\"o=netscaperoot\",cn=mapping tree,cn=config/i){
+ # DO NOTHING
+ }
+ else {
+ if(alreadyExistsInNew($entry)){
+ printMsg("\n\n*** MAPPING_TREE - $DN already exists");
+ printMsg("\n*** Migration will not add the suffix");
+ }
+ else {
+ addEntryToNew($entry, "MAPPING_TREE",1);
+ }
+ }
+ }
+}
+
+
+sub parseMapping_tree{
+ my $entry = shift;
+ push @Mapping_tree_entries, $entry;
+}
+
+#############################################################################
+sub migrateDefaultIndexes {
+ foreach $index (@default_indexes) {
+ my $CN = $index->{cn}[0];
+ my $newIndex ;
+ if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)})) {
+ if ($newIndex = alreadyExistsInNew($index)) {
+ if (! isAsystemIndex($newIndex)) {
+ updateEntry($index, "DEFAULT_INDEX", 1, 2);
+ }
+ }
+ else {
+ addEntryToNew($index, "DEFAULT_INDEX", 2);
+ }
+ }
+ }
+}
+
+
+sub parseDefaultIndex{
+ my $index = shift;
+ push @default_indexes, $index;
+}
+
+#############################################################################
+
+sub migrateIndexes {
+ foreach $index (@indexes) {
+ my $CN = $index->{cn}[0];
+ my $newIndex;
+ if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)}) && (DN !~ /cn=netscaperoot,cn=index/i)){
+ if ($newIndex = alreadyExistsInNew($index)) {
+ if (! isAsystemIndex($newIndex)) {
+ updateEntry($index, "INDEX", 1, 2);
+ }
+ }
+ else {
+ addEntryToNew($index, "INDEX", 2);
+ }
+ }
+ }
+}
+
+sub parseIndex{
+ my $index = shift;
+ push @indexes, $index;
+}
+
+#############################################################################
+
+sub newLDIFplugin {
+ my $currentPlugin = shift;
+ my $DN = $currentPlugin->getDN(1);
+ my $newPlugin = $conn->newEntry() ;
+ $newPlugin->setDN($DN);
+ foreach $Attr (@pluginAttrs) {
+ my @values = $currentPlugin->getValues($Attr);
+ $newPlugin->setValues($Attr, @values) if (@values);
+ }
+ return $newPlugin;
+}
+
+sub migrateStdPlugin{
+ my $plugin = shift;
+ my $DN = $plugin->getDN(1);
+ my $pluginEnable = "nsslapd-pluginEnabled";
+ my $argNum = 0;
+ my $argPrefix = "nsslapd-pluginarg";
+ my $currentPlugin ;
+ if ($currentPlugin = alreadyExistsInNew($plugin, 1)) {
+ $plugin = updatePathInPluginArgs($plugin);
+ my $pluginEnableValue = $plugin->{$pluginEnable}[0];
+ my $cont = 1;
+ my $pluginHasChanged = 0;
+ my $newPlugin = &newLDIFplugin($currentPlugin);
+ if (! $currentPlugin->hasValue($pluginEnable,$pluginEnableValue,1)){
+ $newPlugin->setValues($pluginEnable, $pluginEnableValue);
+ $pluginHasChanged = 1 unless ($pluginHasChanged);
+ }
+ while($cont){
+ my $arg = $argPrefix . $argNum ;
+ if ($plugin->exists($arg)) {
+ my @values = $plugin->getValues($arg);
+ my $value = $values[0] ;
+ $newPlugin->setValues($arg, $value) if (@values);
+ if ($currentPlugin->exists($arg)) {
+ if (! $currentPlugin->hasValue($arg,$value,1)) {
+ $pluginHasChanged = 1 unless ($pluginHasChanged);
+ }
+ }
+ else {
+ $pluginHasChanged = 1 unless ($pluginHasChanged);
+ }
+ }
+ else {
+ if ($currentPlugin->exists($arg)) {
+ # Just Warn the user. Do nothing.
+ printTrace("\nCompared to the old instance, the current new plugin $DN belongs this attribute: $arg",2);
+ }
+ else {
+ $cont = 0 ;
+ }
+ }
+ $argNum++;
+ }
+ updateEntry($newPlugin, "STANDARD_PLUGIN", 0, 1) if ($pluginHasChanged);
+ }
+}
+
+#############################################################################
+
+sub migrateConfig_Node{
+ my $config_node = shift;
+ my @params = keys(%GeneralSrvParamToMigrate);
+ my $hasChanged = 0;
+ my $newConfigNode;
+ if ($newConfigNode = alreadyExistsInNew($config_node, 1)){
+ foreach $param (@params) {
+ if ($config_node->exists($param)){
+ my @valuesToMigrate = $config_node->getValues($param);
+ if (@valuesToMigrate){
+ if ($newConfigNode->exists($param)){
+ my @currentValues = $newConfigNode->getValues($param);
+ if (Diffs(\@valuesToMigrate, \@currentValues)) {
+ $newConfigNode->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ printTrace("\nParam to update: $param with value @valuesToMigrate",3);
+ }
+ }
+ else {
+ $newConfigNode->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ printTrace("\nParam to update: $param with value @valuesToMigrate",3);
+ }
+ }
+ }
+ }
+ updateEntry($newConfigNode, "CONFIG_NODE", 0, 1) if ($hasChanged);
+ }
+}
+
+#############################################################################
+
+sub migrateConfig_LDBM_database{
+ my $config_ldbm = shift;
+ my @params = keys(%GlobalConfigLDBMparamToMigrate);
+ my $hasChanged = 0;
+ my $newConfigLdbm ;
+ if ($newConfigLdbm = alreadyExistsInNew($config_ldbm, 1)) {
+ foreach $param (@params) {
+ if ($config_ldbm->exists($param)){
+ my @valuesToMigrate = $config_ldbm->getValues($param);
+ if (@valuesToMigrate){
+ if ($newConfigLdbm->exists($param)){
+ my @currentValues = $newConfigLdbm->getValues($param);
+ if (Diffs(\@valuesToMigrate, \@currentValues)) {
+ $newConfigLdbm->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ else {
+ $newConfigLdbm->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ }
+ }
+ updateEntry($newConfigLdbm, "CONFIG_LDBM_DATABASE", 0, 1) if ($hasChanged);
+ }
+}
+
+#############################################################################
+
+sub migrateChainingBE_config{
+ my $chaining_config = shift;
+ my $DN = $chaining_config->getDN(1);
+ my @params = ();
+ my $hasChanged = 0;
+ my $newChainingConfig;
+ if ($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i){
+ $newChainingConfig = searchEntry("cn=config,cn=chaining database,cn=plugins,cn=config");
+ @params = keys(%ChainingConfigParams);
+ }
+ if ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i){
+ $newChainingConfig = searchEntry("cn=default instance config,cn=chaining database,cn=plugins,cn=config");
+ @params = keys(%ChainingDefaultInstanceConfigParams);
+ }
+ foreach $param (@params) {
+ if ($chaining_config->exists($param)){
+ my @valuesToMigrate = $chaining_config->getValues($param);
+ if (@valuesToMigrate){
+ printTrace("\nParam: $param values To migrate: @valuesToMigrate",3);
+ if ($newChainingConfig->exists($param)){
+ my @currentValues = $newChainingConfig->getValues($param);
+ printTrace("\nParam: $param new current values: @currentValues",3);
+ if (Diffs(\@valuesToMigrate, \@currentValues)) {
+ $newChainingConfig->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ else {
+ $newChainingConfig->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ }
+ }
+ updateEntry($newChainingConfig, "CHAINING_BACKEND_CONFIG", 0, 1) if ($hasChanged);
+}
+
+#############################################################################
+
+sub registerSuffix_ChainingBE {
+ my $ldbmDatabase = shift;
+ my $CN = $ldbmDatabase->{cn}[0];
+ my $suffixArg = "nsslapd-suffix";
+ my $suffix = $ldbmDatabase->{$suffixArg}[0];
+ $oldChainingBackends{$suffix} = $CN;
+}
+
+sub storeMultiplexorBindDN {
+ my $chaining_instance = shift;
+ my $DN = $chaining_instance->getDN(1);
+ if ($chaining_instance->exists("nsMultiplexorBindDN")){
+ my $bindDN = $chaining_instance->{nsMultiplexorBindDN}[0];
+ my $newBindDN = searchEntry($bindDN);
+ if (! $newBindDN){
+ # the bindDN entry doesn't yet exist in new => it will have to be migrated
+ $MultiplexorBindDNEntriesToMigrate{$bindDN}="\n" ;
+ printTrace("\nThe bindDN: $bindDN need to be migrated",3);
+ }
+ else {
+ # do nothing as the entry already exists in new
+ }
+ }
+
+}
+
+sub importMultiplexorBindDNEntries {
+ # import all entries present in @MultiplexorBindDNEntriesToMigrate in new
+ my @MultiplexorBindDNs = keys (%MultiplexorBindDNEntriesToMigrate);
+ my $ldif_dir = $ldif_rep;
+ foreach $bindDN (@MultiplexorBindDNs) {
+ printTrace("\nimportMultiplexorBindDNEntries: bindDN to migrate: $bindDN",3);
+ # get the backend in which is stored the bind DN entry
+ my $backendtoExportFrom = getBackendtoExportFrom($bindDN);
+ printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3);
+ # check wether the backend has been imported in new or not
+ if (! alreadyMigrated($backendtoExportFrom)) {
+ if ($backendtoExportFrom ne $NULL) {
+ # if not imported => we need to import the binf DN entry
+ &startServer() unless (isDirectoryAlive());
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir);
+ }
+ else {
+ # do nothing
+ }
+ }
+ }
+ # remove the empty ldif directory
+ rmdir($ldif_dir) if (-d $ldif_dir);
+ # close the LDAP connection to new
+ $conn->close if ($conn);
+}
+
+sub migrateChainingBE_instance{
+ my $chaining_instance = shift;
+ my $DN = $chaining_instance->getDN(1);
+ &registerSuffix_ChainingBE($chaining_instance);
+ if (alreadyExistsInNew($chaining_instance)) {
+ # already exists
+ printMsg("\n\n*** CHAINING_BACKEND_INSTANCE - $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ &migrate_credential($chaining_instance, "nsmultiplexorcredentials");
+ addEntryToNew($chaining_instance, "CHAINING_BACKEND_INSTANCE", 1);
+ storeMultiplexorBindDN($chaining_instance);
+ }
+}
+
+#############################################################################
+
+# create a new LDIF representation of a new replica consumer
+sub newLDIFreplica {
+ my $replica = shift;
+ my $DN = $replica->getDN(1);
+ my $newReplica = $conn->newEntry() ;
+ my $MASTER_OR_MULTIMASTER = "3" ;
+ $newReplica->setDN($DN);
+ foreach $Attr (@nsds5replicaAttrs) {
+ my @values = $replica->getValues($Attr);
+ $newReplica->setValues($Attr, @values) if (@values);
+ }
+ my $replicaType = $replica->{nsDS5ReplicaType}[0];
+ if ($replicaType eq $MASTER_OR_MULTIMASTER) {
+ my @nsState = $replica->getValues("nsState");
+ $newReplica->setValues("nsState", @nsState);
+ }
+ else {
+ $newReplica->setValues("nsDS5ReplicaId", $replicaIdvalue);
+ }
+ return $newReplica;
+}
+
+sub MigrateNSDS5_replica{
+ foreach $replica (@new6replicas) {
+ my $DN = $replica->getDN(1);
+ my $newReplica;
+ my @removeAttrs = qw(nsstate nsds5replicaname nsds5replicachangecount);
+ for (@removeAttrs) {
+ $replica->remove($_);
+ }
+ if (alreadyExistsInNew($replica)) {
+ # replica already exists
+ printMsg("\n\n*** NSDS5_REPLICA - $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ $newReplica = &newLDIFreplica($replica);
+ addEntryToNew($newReplica, "NSDS5_REPLICA", 1);
+ }
+ storeReplicaBindDN($replica);
+ }
+}
+
+sub parseNSDS5_replica{
+ my $replica = shift;
+ push @new6replicas, $replica;
+}
+
+sub storeReplicaBindDN {
+ my $replica = shift;
+ my $DN = $replica->getDN(1);
+ if ($replica->exists("nsDS5ReplicaBindDN")){
+ my $bindDN = $replica->{nsDS5ReplicaBindDN}[0];
+ my $newBindDN = searchEntry($bindDN);
+ if (! $newBindDN){
+ # the bindDN entry doesn't yet exist in new => it will have to be migrated
+ $ReplicaBindDNEntriesToMigrate{$bindDN}="\n" ;
+ printTrace("\nThe bindDN: $bindDN need to be migrated",3);
+ }
+ else {
+ # do nothing as the entry already exists in new
+ }
+ }
+}
+
+
+sub importReplicaBindDNEntries {
+ # import all entries present in @ReplicaBindDNEntriesToMigrate in new
+ my @ReplicaBindDNs = keys (%ReplicaBindDNEntriesToMigrate);
+ my $ldif_dir = $ldif_rep;
+ my $replBind_entry = "";
+ my @bindDN_elements = "";
+ my $bindDN_parent = "";
+ my $parentBind_entry = "";
+ foreach $bindDN (@ReplicaBindDNs) {
+ printTrace("\nimportReplicaBindDNEntries: bindDN to migrate: $bindDN",3);
+ # get the backend in which is stored the bind DN entry
+ my $backendtoExportFrom = getBackendtoExportFrom($bindDN);
+ printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3);
+ # If backend is from config, read the entry from dse.ldif and add to new - NGK
+ if ($backendtoExportFrom eq "cn=config") {
+ my $norm_bindDN = normalizeDN($bindDN);
+ @bindDN_elements = ldap_explode_dn($norm_bindDN, 0);
+# @bindDN_elements = split(/,/,$norm_bindDN);
+ my $junk = shift(@bindDN_elements);
+ if ($#bindDN_elements >= 1) {
+ $bindDN_parent = normalizeDN(join(",", @bindDN_elements));
+ }
+ printTrace("\nOpening DSE.ldif",3);
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF);
+ while ($entry = readOneEntry $in) {
+ my $DN = $entry->getDN(1);
+ if ($DN eq $norm_bindDN) {
+ $replBind_entry = $entry;
+ }
+ if ($bindDN_parent ne "") {
+ if ($DN eq $bindDN_parent) {
+ $parentBind_entry = $entry;
+ }
+ }
+ }
+ close(DSELDIF);
+ &startServer() unless (isDirectoryAlive());
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ if ($bindDN_parent ne "") {
+ addEntryToNew($parentBind_entry, BINDDN_PARENT, 0);
+ }
+ printTrace("\nAdding BindDN with addEntryToNew",3);
+ addEntryToNew($replBind_entry, BINDDN, 0);
+ } else {
+ # check wether the backend has been imported in new or not
+ if (! alreadyMigrated($backendtoExportFrom)) {
+ if ($backendtoExportFrom ne $NULL) {
+ # if not imported => we need to import the bind DN entry
+ &startServer() unless (isDirectoryAlive());
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir);
+ }
+ else {
+ # do nothing
+ }
+ }
+ }
+ }
+ # remove the empty ldif directory
+ rmdir($ldif_dir) if (-d $ldif_dir);
+ # close the LDAP connection to new
+ $conn->close if ($conn);
+}
+
+sub alreadyMigrated {
+ my $backendToCheck = shift;
+ foreach $backend (@BACKENDS) {
+ return 1 if ($backend eq $backendToCheck);
+ }
+ return 0 ;
+}
+
+sub belongsSuffix {
+ my $suffix = shift;
+ my $bindDN = shift;
+ return ($bindDN =~ /$suffix\s*$/i);
+}
+
+sub length {
+ my $suffix = shift;
+ my $count = 0;
+ while ($suffix =~ /./g) {
+ $count++;
+ }
+ return $count ;
+}
+
+sub getBackendtoExportFrom {
+ my $bindDN = shift ;
+ my $sizeOfSuffix = 0 ;
+ my $NULL = "";
+ my @oldSuffixes = keys(%oldBackends);
+ my @oldChainingSuffixes = keys(%oldChainingBackends);
+ my $bindDN_backend = $NULL;
+ my $config = "cn=config";
+
+ my $norm_bindDN = normalizeDN($bindDN);
+ # Check if bindDN exists in cn=config - NGK
+ if (belongsSuffix($config,$norm_bindDN)) {
+ $bindDN_backend = $config;
+ printTrace("\ngetBackendtoExportFrom: bindDN_backend: $bindDN_backend",3);
+ } else {
+ foreach $suffix (@oldSuffixes){
+ printTrace("\ngetBackendtoExportFrom: suffix to compare with is: $suffix",3);
+ if ((belongsSuffix($suffix,$norm_bindDN)) && (length($suffix) > $sizeOfSuffix)) {
+ $sizeOfSuffix = length($suffix);
+ $bindDN_backend = $oldBackends{$suffix};
+ printTrace("\ngetBackendtoExportFrom: bindDN_backend: $bindDN_backend, sizeOfSuffix: $sizeOfSuffix",3);
+ }
+ }
+ foreach $suffix (@oldChainingSuffixes){
+ printTrace("\ngetBackendtoExportFrom: suffix to compare with is a chained suffix: $suffix",3);
+ if ((belongsSuffix($suffix,$norm_bindDN)) && (length($suffix) > $sizeOfSuffix)) {
+ printMsg("\n\n*** Entry stored on a remote backend - $norm_bindDN");
+ printMsg("\n*** We don't migrate it");
+ return $NULL;
+ }
+ }
+ }
+ return $bindDN_backend;
+}
+
+
+sub getBackendtoImportTo {
+ my $bindDN = shift;
+ my $sizeOfSuffix = 0;
+ my $NULL = "";
+ my $suffixArg = "nsslapd-suffix";
+ my $bindDN_backend = $NULL;
+ open( DSELDIF, "< $DSEldif" ) || die "Can't open $DSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ $typeOfEntry = getTypeOfEntry($entry);
+ if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){
+ my $suffix = $entry->{$suffixArg}[0];
+ if ((belongsSuffix($suffix,$bindDN)) && (length($suffix) > $sizeOfSuffix)) {
+ $sizeOfSuffix = length($suffix);
+ $bindDN_backend = $entry->{cn}[0];
+ }
+ }
+ }
+ close(DSELDIF);
+ return $bindDN_backend ;
+}
+
+
+sub ExportAndAddEntry {
+ my $DN = shift;
+ my $backendtoExportFrom = shift;
+ my $ldif_dir = shift;
+ my $ldif = "$ldif_dir${PATHSEP}$backendtoExportFrom.ldif" ;
+ # first: export entry pointed out by the $DN to $ldif file
+ $ENV{"$LIB_PATH"}=$old_libpath;
+ if (! $ldif_dir) { $ldif_dir = $ldif_rep ;}
+ if (!(-d $ldif_dir)) {
+ mkdir($ldif_dir,0777) or die "\ncan't create $ldif_dir to store temporary ldif files\n";
+ }
+ chdir($oldSlapdExecDir) or die "\nCould not change directory to $oldSlapdExecDir: $!\n";
+ &db2Ldif($ldif, $backendtoExportFrom, $oldHome, $DN);
+ chdir($curdir) or die "\nCould not change directory to $curdir: $!\n";
+
+ # then: Add it to new
+ if (! $conn) {
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ }
+ open( BINDDNLDIF, "< $ldif" ) || die "\nCan't open $ldif: $!: \n";
+ my $in = new Mozilla::LDAP::LDIF(*BINDDNLDIF) ;
+ while ($entry = readOneEntry $in) {
+ my $entryDN = $entry->getDN(1);
+ if ($DN eq $entryDN) {
+ addEntryToNew($entry, "nsds5ReplicaBindDN", 0);
+ }
+ }
+ close(BINDDNLDIF);
+ # remove the ldif file after the import
+ unlink($ldif) ;
+}
+
+#############################################################################
+sub MigrateNSDS_replication_agreement {
+ foreach $replicationAgreement (@replicationAgreements) {
+ my $DN = $replicationAgreement->getDN(1);
+ if (alreadyExistsInNew($replicationAgreement)){
+ # replication agreement already exists
+ printMsg("\n\n*** NSDS_REPLICATION_AGREEMENT - $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ &migrate_credential($replicationAgreement, "nsDS5ReplicaCredentials");
+ addEntryToNew($replicationAgreement, "NSDS_REPLICATION_AGREEMENT", 1);
+ }
+ }
+}
+
+
+sub parseNSDS_replication_agreement{
+ my $replicationAgreement = shift;
+ push @replicationAgreements, $replicationAgreement ;
+}
+
+#############################################################################
+
+sub migrateChangelog5{
+ my $changelog = shift;
+ my $DN = $changelog->getDN(1);
+ my $changelogdir = "nsslapd-changelogdir";
+ if (alreadyExistsInNew($changelog)){
+ # cn=changelog5,cn=config already exists in new
+ my $newChangelog = searchEntry($DN);
+ my @newChangelogdir = $newChangelog->getValues($changelogdir);
+ $changelog->setValues($changelogdir, @newChangelogdir);
+ updateEntry($changelog, "CHANGELOG5", 0, 1);
+ }
+ else {
+ # cn=changelog5,cn=config need to be created in new.
+ # the changelogdir value must be setup to <new_root_server>/slapd-instance/changelogdb
+ $changelog->setValues($changelogdir,"${serverHome}${PATHSEP}changelogdb");
+ addEntryToNew($changelog, "CHANGELOG5", 1);
+ }
+}
+
+
+sub migrateChangelog {
+ my $oldchangelogdir = "";
+ my $newchangelogdir = "";
+ my $changelogdir = "nsslapd-changelogdir";
+ my $CL5DN = "cn=changelog5,cn=config";
+ printTrace("\n\n***** Migrate Changelog...",0,1);
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF);
+ while ($entry = readOneEntry $in) {
+ $typeOfEntry = getTypeOfEntry($entry);
+ if ($typeOfEntry eq "CHANGELOG5"){
+ $oldchangelogdir = ($entry->getValues($changelogdir))[0];
+ }
+ }
+ close(DSELDIF);
+ if ($oldchangelogdir) {
+ # If using olddatadir to migrate from, the path of the changelogdb
+ # from the dse.ldif may not match the path where the old server
+ # root was archived. We may need to modify oldchangelogdir so the
+ # copy of the changelog files succeeds.
+ unless(-e $oldchangelogdir) {
+ if($olddatadir) {
+ my @cldbpath = split(/\//,$oldchangelogdir);
+ until($cldbpath[0] =~/^slapd-/) {
+ shift(@cldbpath);
+ }
+ my $tmpcldbpath = join(${PATHSEP}, @cldbpath);
+ $oldchangelogdir = "$oldDir${PATHSEP}$tmpcldbpath";
+ }
+ # If oldchangelogdir still looks to be wrong, prompt for the
+ # location instead of just failing on the copydir operation
+ # and bombing out of the migration.
+ unless(-e $oldchangelogdir) {
+ print("\n\nThe old changelog directory \"$oldchangelogdir\" doesn't exist. Please enter the correct path: ");
+ $oldchangelogdir = <STDIN>;
+ }
+ }
+ &startServer() unless (isDirectoryAlive());
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ my $newChangelog = searchEntry($CL5DN);
+ $newchangelogdir = ($newChangelog->getValues($changelogdir))[0];
+ stopServer($root,'slapd-'.$newname);
+ printTrace("\ncopying $oldchangelogdir${PATHSEP}* to $newchangelogdir",3);
+ copyDir("$oldchangelogdir","$newchangelogdir");
+
+ # We need to modify the DBVERSION file for a new verision of the db
+ open(DBVERSION,">$newchangelogdir${PATHSEP}DBVERSION") || die "Can't overwrite $newchangelogdir${PATHSEP}DBVERSION: $! ";
+ print DBVERSION "Changelog5/NSMMReplicationPlugin/3.0";
+ close(DBVERSION);
+
+ &startServer() unless (isDirectoryAlive());
+ }
+}
+
+#############################################################################
+
+sub migrateReplication{
+ my $replication = shift;
+ my $DN = $replication->getDN(1);
+ if (alreadyExistsInNew($replication)){
+ # replication agreement already exists
+ printMsg("\n\n*** $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ addEntryToNew($replication, "REPLICATION", 1);
+ }
+}
+
+#############################################################################
+
+sub migrateSecurity{
+ my $security = shift;
+ if ($entry->hasValue("objectClass", "nsEncryptionConfig")) {
+ my $certfile = "alias/slapd-" . $newname . "-cert8.db";
+ my $keyfile = "alias/slapd-" . $newname. "-key3.db";
+ $entry->setValues("nsCertfile",$certfile) if ! $entry->hasValue("nsCertfile",$certfile);
+ $entry->setValues("nsKeyfile",$keyfile) if ! $entry->hasValue("nsKeyfile",$keyfile);
+ }
+ if (alreadyExistsInNew($security)){
+ # already exists in new
+ updateEntry($security, "SECURITY", 0, 1);
+ }
+ else {
+ addEntryToNew($security, "SECURITY", 1);
+ }
+}
+
+#############################################################################
+
+sub migrateSNMP{
+ my $snmp = shift;
+ if (alreadyExistsInNew($snmp)){
+ # already exists in new
+ updateEntry($snmp, "SNMP", 0, 1);
+ }
+ else {
+ addEntryToNew($snmp, "SNMP", 1);
+ }
+}
+
+#############################################################################
+# printMsg print message to the user standard output.
+
+sub printMsg {
+
+ my $TypeMsg = shift ;
+ my $Msg = shift ;
+ my $LineNb = shift ;
+ if ($LineNb) {
+ printTrace("Line: $LineNb, $TypeMsg, $Msg");
+ }
+ else {
+ printTrace("$TypeMsg $Msg");
+ }
+}
+
+#############################################################################
+# print message error to the user standard output.
+
+sub printTrace {
+
+ my $Msg = shift ;
+ my $level = shift ;
+ my $sep = shift ;
+
+ if ($sep) {
+ print "\n-------------------------------------------------------------------------";
+ print LOGFILE "\n-------------------------------------------------------------------------";
+ }
+
+ if ($level <= $TRACELEVEL) {
+ print($Msg);
+ print LOGFILE $Msg ;
+ }
+}
+
+#############################################################################
+# this subroutine implements a very stupid version of diff
+
+sub diff {
+ my $f1 = shift;
+ my $f2 = shift;
+ my $lineToBeginWith = shift;
+ my $NULL = "" ;
+ my $diff_f1 = $NULL ;
+ my $diff_f2 = $NULL ;
+ my $retval = $NULL ;
+ my $ret;
+ open(F1, "$f1") or die "Could not open file $f1";
+ open(F2, "$f2") or close(F1), die "Could not open file $f2";
+
+ while (defined($l1 = <F1>)) {
+ if ($lineToBeginWith){
+ $lineToBeginWith -- ;
+ next ;
+ }
+ next if ($l1 =~ /^\#/);
+ $ret = defined($l2 = <F2>);
+ if ($ret) {
+ $ret = defined($l2 = <F2>) while ($ret && ($l2 =~ /^\#/)) ;
+ if ($ret) {
+ if (!($l1 eq $l2)) {
+
+ # ignore whitespace
+ $l1_clean = $l1 ;
+ $l2_clean = $l2 ;
+ $l1_clean =~ s/\s//g;
+ $l2_clean =~ s/\s//g;
+
+ if (!($l1_clean eq $l2_clean)) {
+ $diff_f1 .= "${l1}" unless ($l1_clean eq $NULL);
+ $diff_f2 .= "${l2}" unless ($l2_clean eq $NULL);
+ }
+ }
+ }
+ else {
+ next if ($l1 =~ /^\s*$/) ;
+ $diff_f1 .= "${l1}";
+ }
+ }
+ else {
+ next if ($l1 =~ /^\s*$/) ;
+ $diff_f1 .= "${l1}";
+ }
+ }
+
+ while (defined($l2 = <F2>)) {
+ if (($l2 =~ /^\#/) || ($l2 =~ /^\s*$/)) {
+ next ;
+ }
+ else {
+ $diff_f2 .= "${l2}" ;
+ }
+ }
+
+ close(F1);
+ close(F2);
+
+ $retval .= "- differences present in your config file but not in standard file:\n\n". "$diff_f1\n" if ($diff_f1) ;
+ $retval .= "- differences present in standard file but not in your config file:\n\n" . "$diff_f2" if ($diff_f2) ;
+ return $retval ;
+}
+
+sub CompareStdConfigFiles {
+ # Compare each configuration file against its default version. If it has changed,
+ # notify the user that the file has changed and will need to be checked by the
+ # user. This should be safe to do because there should be no path information
+ # stored in these conf files, which are just schema stuff.
+ # printTrace("\nCheck if standard configuration files have changed",3);
+
+ # get the version of the DS to migrate
+ ($oldVersion, $oldMinor) = &getVersion($oldDir, $oldversionstr);
+ # get the version of the new DS
+ ($Version, $Minor) = &getVersion($root);
+
+ # get old LIB_PATH
+ $old_libpath = &getLibPath($oldDir, $oldVersion, $oldMinor);
+ # get new LIB_PATH
+ $new_libpath = &getLibPath($root, $Version, $Minor);
+
+ my $origFilePath = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}install${PATHSEP}schema${PATHSEP}" ;
+ my $FilesChanged = "";
+ my $AllDiffs = "***********************************************************************";
+ my $NoChanges = "" ;
+ my $lineToBegin = 0 ;
+ opendir(CONFDIR, $oldSchemaDir) or
+ die "Error: could not open migrated config dir $oldConfDir: $!";
+
+ foreach $file (readdir(CONFDIR)) {
+ $origFile = $origFilePath . $file ;
+ $configFile = $oldSchemaDir . $file ;
+ if (( exists($stdIncludes{lc($file)})) && (-f $origFile)) {
+ $diffs = &diff($configFile, $origFile, $lineToBegin);
+ $lineToBegin = 0 if $lineToBegin ;
+ if ($diffs) {
+ $FilesChanged .= "\n$configFile";
+ $AllDiffs .= "\n$configFile is different than the standard configuration file" ;
+ $AllDiffs .= "\nYou will need to check this file and make sure its changes are compatible ";
+ $AllDiffs .= "with the new directory server\nHere are the differences:\n";
+ $AllDiffs .= "$diffs \n\n";
+ $AllDiffs .= "***********************************************************************";
+ }
+ else {
+ $NoChanges .= "\n$configFile";
+ }
+ }
+ }
+ closedir(CONFDIR);
+
+if ($FilesChanged) {
+ printTrace("\nNo changes to old configuration files:$NoChanges",3) ;
+ printTrace("\n***********************************************************************",3) ;
+ printMsg("\nThe following standard files have been modified: $FilesChanged");
+ if ($NO_INPUT_USER) {
+ # do nothing
+ }
+ else {
+ printMsg("\nDo you want to see the differences Yes/No [No] ?") ;
+ my $answer = <STDIN> ;
+ if ($answer =~ /y|yes/i) {
+ printMsg("$AllDiffs");
+ }
+ printMsg("\nDo you want to continue the migration Yes/No [No] ?");
+ $answer = <STDIN> ;
+ if (! ($answer =~ /y|yes/i)) {
+ exit(1);
+ }
+ }
+ }
+}
+
+
+
+#############################################################################
+
+# this is used to run the system() call, capture exit and signal codes,
+# and die() upon badness; the first argument is a directory to change
+# dir to, if any, and the rest are passed to system()
+sub mySystem {
+ my $rc = &mySystemNoDie(@_);
+ my ($dir, @args) = @_;
+ if ($rc == 0) {
+# success
+ } elsif ($rc == 0xff00) {
+ die "Error executing @args: error code $rc: $!";
+ } elsif ($rc > 0x80) {
+ $rc >>= 8;
+ die "Error executing @args: error code $rc: $!";
+ } else {
+ if ($rc & 0x80) {
+ $rc &= ~0x80;
+ }
+ die "Error executing @args: received signal $rc: $!";
+ }
+
+ # usually won't get return value
+ return $rc;
+}
+
+# This version does not die but just returns the error code
+sub mySystemNoDie {
+ my ($dir, @args) = @_;
+ if ($dir && ($dir ne "")) {
+ chdir($dir) or die "Could not change directory to $dir: $!";
+ }
+ my $cmd = $args[0];
+ # the system {$cmd} avoids some NT shell quoting problems if the $cmd
+ # needs to be quoted e.g. contains spaces; the map puts double quotes
+ # around the arguments on NT which are stripped by the command
+ # interpreter cmd.exe; but don't quote things which are already quoted
+ my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args;
+ my $rc = 0;
+ if ($cmd =~ /[.](bat|cmd)$/) {
+ # we have to pass batch files directly to the NT command interpreter
+ $cmd = $com_spec;
+# print "system $cmd /c \"@fixargs\"\n";
+ $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\"";
+ } else {
+# print "system $cmd @fixargs\n";
+ $rc = 0xffff & system {$cmd} @fixargs;
+ }
+ chdir(${curdir}) or die "Could not change directory to $curdir: $!";
+ return $rc;
+}
+
+###########################################################################################
+# #
+# Export/Import of the backends in @BACKENDS #
+# #
+###########################################################################################
+
+sub manydb2Ldif {
+ my $ldif_dir = shift;
+ $ENV{"$LIB_PATH"}=$old_libpath;
+ if (! $ldif_dir) { $ldif_dir = $ldif_rep ;}
+ if (!(-d $ldif_dir)) {
+ mkdir($ldif_dir,0777) or die "can't create $ldif_dir to store temporary ldif files";
+ }
+ chdir($oldSlapdExecDir) or die "Could not change directory to $oldSlapdExecDir: $!";
+ foreach $backend (@BACKENDS) {
+ my $ldif = "${ldif_dir}$backend.ldif" ;
+ &db2Ldif($ldif, $backend, $oldHome);
+ }
+ print " Done.\n";
+ chdir($curdir) or die "Could not change directory to $curdir: $!";
+}
+
+sub db2Ldif {
+ my $ldif = shift ;
+ my $backend = shift ;
+ my $home = shift ;
+ my $include_suffix = shift ;
+ my $db2ldif_param ;
+ if ($include_suffix) {
+ $db2ldif_param = "db2ldif -r -D $home -n $backend -a $ldif -s \"$include_suffix\"";
+ }
+ else {
+ $db2ldif_param = "db2ldif -r -D $home -n $backend -a $ldif";
+ }
+ open(DB2LDIF, "${quote}${quote}$slapdExecName${quote} $db2ldif_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n";
+ sleep(1); # allow some data to accumulate in the pipe
+ my $ii = 0;
+ while (<DB2LDIF>) {
+ ++$ii;
+ if (($ii % 250) == 0) {
+ printMsg(" Processing...\n");
+ }
+ printMsg($_);
+ }
+ close(DB2LDIF);
+ # set the ownership of the ldif file; should be the same as the 5.x slapd user id
+ if ((! $isNt) && ($oldlocaluser ne $localuser)) {
+ if (-f $ldif) {
+ chown( $newuid, $newgid, $ldif) or printMsg("\nUnable to change the ownership of $ldif to $localuser") ;
+ }
+ }
+}
+
+sub manyLdif2db {
+ my $ldif_dir = shift;
+ $ENV{"$LIB_PATH"}=$new_libpath;
+ chdir($slapdExecDir) or die "Could not change directory to $slapdExecDir: $!";
+ foreach $backend (@BACKENDS) {
+ my $ldif = "${ldif_dir}$backend.ldif" ;
+ &Ldif2db($ldif, $backend);
+ }
+ # remove the empty ldif directory
+ # but not if using the data dir
+ if (!$olddatadir) {
+ rmdir($ldif_dir);
+ }
+ chdir($curdir) or die "Could not change directory to $curdir: $!";
+}
+
+
+sub Ldif2db {
+ my $ldif = shift ;
+ my $backend = shift ;
+ my $ldif2db_param = "ldif2db -D $serverHome -n $backend -i $ldif";
+ open(LDIF2DB, "${quote}${quote}$slapdExecName${quote} $ldif2db_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n";
+ sleep(1); # allow some data to accumulate in the pipe
+ while (<LDIF2DB>) {
+ printMsg($_);
+ }
+ close(LDIF2DB);
+ # remove the ldif file after the import
+ # but not if using the data dir
+ if (!$olddatadir) {
+ unlink($ldif) ;
+ }
+}
+
+
+###########################################################################################
+# #
+# Running/Stopping the Server #
+# #
+###########################################################################################
+
+
+
+sub isDirectoryAlive {
+ die "\n Migration aborted. Make sure your old and new Directory Servers are installed on the same machine \n" if ( $LDAPservername == -1 );
+ my $test_conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd);
+ if ($test_conn) {
+ $test_conn->close();
+ return 1;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+
+sub startServer {
+ my $instanceDir = ${serverHome} ;
+ my $errLog = $instanceDir . $PATHSEP . 'logs' . $PATHSEP . 'errors';
+ # emulate tail -f
+ # if the last line we see does not contain "slapd started", try again
+ my $done = 0;
+ my $started = 0;
+ my $code = 0;
+ my $lastLine = "";
+ my $timeout = time + 240; # 4 minutes
+ $ENV{"$LIB_PATH"}=$new_libpath;
+
+ my $startCmd = $instanceDir . $PATHSEP . 'start' . $script_suffix;
+ if (! -f $startCmd) {
+ $startCmd = $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix;
+ }
+ $code = &mySystem($instanceDir,$startCmd);
+ open(IN, $errLog) or die "Could not open error log $errLog: $!";
+ my $pos = tell(IN);
+ while (($done == 0) && (time < $timeout)) {
+ for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) {
+ $lastLine = $_;
+ # print;
+ # the server has already been started and shutdown once . . .
+ if (/slapd started\./) {
+ $started++;
+ if ($started == 2) {
+ $done = 1;
+ }
+ # sometimes the server will fail to come up; in that case, restart it
+ } elsif (/Initialization Failed/) {
+ # print "Server failed to start: $_";
+ $code = &mySystem($instanceDir, $startCmd);
+ # sometimes the server will fail to come up; in that case, restart it
+ } elsif (/exiting\./) {
+ # print "Server failed to start: $_";
+ #$code = &mySystem($startCmd);
+ $code = &mySystem($instanceDir, $startCmd);
+ }
+ }
+ if ($lastLine =~ /PR_Bind/) {
+ # server port conflicts with another one, just report and punt
+ print $lastLine;
+ print "This server cannot be started until the other server on this\n";
+ print "port is shutdown.\n";
+ $done = 1;
+ }
+ if ($done == 0) {
+ # rest a bit, then . . .
+ sleep(2);
+ # . . . reset the EOF status of the file desc
+ seek(IN, $pos, 0);
+ }
+ }
+ close(IN);
+
+ sleep(5);
+ die "\nUnable to start the $Version.$Minor Directory Server\n" unless (isDirectoryAlive());
+
+ return 0;
+}
+
+sub stopServer {
+ my $root = shift;
+ my $name = shift;
+ $maxStopIterations = 5;
+ print "\nShutting down server $name . . .\n";
+ $ENV{"$LIB_PATH"}=$new_libpath;
+ $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop' . $script_suffix . $quote;
+ if (! -f $stopCmd) {
+ $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop-slapd' . $script_suffix . $quote;
+ }
+
+ if (! -f $stopCmd) {
+ # no stop command, probably a 1.X system; for NT, we'll try net stop
+ # for unix, we'll get the pid and kill it
+ if ($isNT) {
+ $stopCmd = 'net stop ' . $name;
+ } else {
+ # see if there is a pid file
+ $pidfile = $root . $PATHSEP . $name . $PATHSEP . 'logs' .
+ $PATHSEP . 'pid';
+ if (open(PIDFILE, $pidfile)) {
+ chomp($pid = <PIDFILE>);
+ close(PIDFILE);
+ while ($maxStopIterations-- && !$exitCode) {
+ $exitCode = kill(15, $pid);
+ }
+ $stopCmd = undef;
+ }
+ }
+ }
+
+ # keep looping until the stop cmd returns an error code, which usually
+ # means that what ever we want to stop is stopped, or some other error
+ # occurred e.g. permission, or no such service
+ $exitCode = &runAndIgnoreOutput($stopCmd);
+# print "stopServer: exitCode=$exitCode\n";
+ while ($stopCmd && $maxStopIterations-- && $exitCode) {
+ $exitCode = &runAndIgnoreOutput($stopCmd);
+# print "stopServer: exitCode=$exitCode\n";
+ }
+
+ if (!$maxStopIterations) {
+ print "Warning: could not shutdown the server: $!\n";
+ }
+ sleep(10) ;
+ $exitCode = 0;
+}
+
+
+sub runAndIgnoreOutput {
+ my $cmd = shift;
+ printMsg(".");
+ open(RUNCMD, "${quote}$cmd${quote} 2>&1 |") or die "Error: could not run $cmd: $!";
+ printMsg(".");
+ sleep(1); # allow pipe to fill with data
+ printMsg(".");
+ while (<RUNCMD>) {
+# print;
+ }
+ my $code = close(RUNCMD);
+# print "runAndIgnore: code=$code status=$?\n";
+ return $?;
+}
+
+#############################################################################
+# migrate SSL info
+
+sub MigrateSSL {
+ my $secPwd = 'bidon' ;
+ # copy the SSL directory
+ &copyDir("$oldHome${PATHSEP}ssl","$serverHome${PATHSEP}ssl") if (-d "$oldHome${PATHSEP}ssl");
+ # copy the cert db and key files
+ if ( -d "$oldDir${PATHSEP}alias") {
+ $aliasDir = "$root${PATHSEP}alias";
+ if (! -d $aliasDir) {
+ mkdir($aliasDir, 0750);
+ }
+ &stopServer($root,'slapd-'.$newname);
+ my $keydb = "$aliasDir${PATHSEP}slapd-$newname-key3.db" ;
+ my $certdb = "$aliasDir${PATHSEP}slapd-$newname-cert8.db" ;
+ my $certdb7 = "$aliasDir${PATHSEP}slapd-$newname-cert7.db" ;
+ my $old_keydb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-key3.db" ;
+ my $old_certdb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-cert7.db";
+ my $keydb_backup = "$aliasDir${PATHSEP}slapd-$newname-key3.db_backup" ;
+ my $certdb_backup = "$aliasDir${PATHSEP}slapd-$newname-cert7.db_backup" ;
+ if (-f $old_keydb) {
+ if (-f $keydb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$keydb already exists. backup in $keydb_backup ...");
+ &copyBinFile($keydb,$keydb_backup);
+ &copyBinFile($old_keydb,$keydb);
+ }
+ else {
+ print("\n\n$keydb already exists. Do you want to overwrite it ? [no]: ");
+ my $answer = <STDIN> ;
+ if ($answer =~ /^y|yes$/i) {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ if (-f $old_certdb) {
+ $mode = (stat($old_certdb))[2] if $PRESERVE;
+ if (-f $certdb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$certdb already exists. backup in $certdb_backup ...");
+ &copyBinFile($certdb,$certdb_backup);
+ unlink($certdb) || print "Couldn't delete $certdb : $!\n";
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ else {
+ print("\n\n$certdb already exists. Do you want to overwrite it ? [no]: ");
+ my $answer = <STDIN> ;
+ if ($answer =~ /^y|yes$/i) {
+ unlink($certdb) || print "Couldn't delete $certdb : $!\n";
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ # copy the old password file
+ if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") {
+ &copyBinFile(
+ "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt",
+ "$aliasDir${PATHSEP}$type-$newname-pin.txt"
+ );
+ }
+ &startServer();
+ if ($PRESERVE) {
+ chown($newuid,$newgid,$certdb) || print "Failed to set uid $newuid gid $newgid on $certdb : $!\n";
+ chmod($mode,$certdb) || print "Failed to set mode $mode on $certdb : $!\n";
+ }
+ }
+
+}
+
+sub DisableSSL {
+ my $entry = $conn->search("cn=config","base","objectclass=*");
+ my $LDAPparam = "nsslapd-security" ;
+ my $Value = "off" ;
+ if ($entry->{$LDAPparam}[0] ne $Value) {
+ printTrace("\nDisable SSL...",1);
+ $entry->setValues($LDAPparam, $Value);
+ }
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nSSL disabled",2);
+ }
+ else {
+ printMsg("\nCan't disabled SSL. The server may have problems to start");
+ }
+}
+
+# enable the migration of client authentication informations
+sub MigrateCertmap {
+ # backup the old certmap.conf and replace it with the new one
+ my $oldCertmap = "$oldDir${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf";
+ my $newCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf" ;
+ my $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ;
+ if (-f $oldCertmap) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$newCertmap has been backup in $backupCertmap");
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($oldCertmap,$newCertmap);
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\n\nWhere do you want to back up the file $newCertmap [$backupCertmap] ?") ;
+ my $Answer = <STDIN> ;
+ $backupCertmap = $Answer if ($Answer ne "\n");
+ chomp($backupCertmap);
+ printTrace("\nDest: .$backupCertmap.",4);
+ if (-e $backupCertmap) {
+ printMsg("\n\n$backupCertmap already exists. Do you want to overwrite it Yes/No [No] ?") ;
+ if (<STDIN> =~ /yes|y/i) {
+ $Ask = 0 ;
+ }
+ else {
+ $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ;
+ }
+ }
+ else {
+ $Ask = 0 ;
+ }
+ }
+ printTrace("\nBackup file: $newCertmap in $backupCertmap",4);
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($oldCertmap,$newCertmap);
+ }
+ }
+ else {
+ }
+}
+
+sub hasChangedoldCertmap {
+ my $certmapfile = shift ;
+ my @reference = ("certmap default default",
+ "default:DNComps",
+ "default:FilterComps e") ;
+ my $cpt = 0 ;
+ printTrace("\nhasChangedoldCertmap",3);
+ open(CERTMAP,"< $certmapfile");
+ while (<CERTMAP>) {
+ if ((! /^\s*#/) && (! /^\s*$/)) {
+ my $ref = $reference[$cpt] ;
+ printTrace("\nValue: $_, ref: $ref",4);
+ if (! /^\s*$ref\s*$/) {
+ return 1 ;
+ }
+ else {
+ $cpt++ ;
+ }
+ }
+ }
+ close (CERTMAP);
+ printTrace("\ncpt: $cpt",4);
+ if ($cpt < $#reference) {
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+
+###########################################################################################
+# #
+# Copy directory and files functions #
+# #
+###########################################################################################
+
+
+sub copyDir {
+ my $src = shift;
+ my $dest = shift;
+ my $exclude = shift;
+
+ opendir( SRC, $src ) or die "Can't open directory $src: $!: ";
+ my $mode;
+ my $uid;
+ my $gid;
+ mkdir ( $dest , 0755 ) or die "\nCan't create directory $dest. \nPlease check you have enough rights to create it and/or check that your parent directory exists.\n" if !( -e $dest );
+ if ($PRESERVE) {
+ $mode = (stat($src))[2];
+ ($uid, $gid) = (stat(_))[4..5];
+ # Make sure files owned by the old user are owned by the
+ # new user
+ if ($uid == $olduid) {
+ $uid = $newuid;
+ $gid = $newgid;
+ }
+ chown $uid, $gid, $dest;
+ chmod $mode, $dest;
+ }
+ local ( @files ) = readdir ( SRC );
+ closedir( SRC );
+ for ( @files ) {
+ if ( $_ eq "." || $_ eq ".." ) {
+ next;
+ } elsif ( $exclude && /$exclude/ ) {
+ next;
+ } elsif( -d "$src${PATHSEP}$_") {
+ &copyDir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" );
+ } else {
+ &copyBinFile ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_");
+ }
+ }
+}
+
+sub copyBinFile {
+ my $src = shift;
+ my $dest = shift;
+ my $buf = "";
+ my $bufsize = 8192;
+
+ open( SRC, $src ) || die "Can't open $src: $!\n";
+ # if we are given a directory destination instead of a file, extract the
+ # filename portion of the source to use as the destination filename
+ if (-d $dest) {
+ $dest = $dest . $PATHSEP . &basename($src);
+ }
+ open( DEST, ">$dest" ) || die "Can't create $dest: $!\n";
+ binmode SRC;
+ binmode DEST;
+ if ($PRESERVE) {
+ $mode = (stat($src))[2];
+ ($uid, $gid) = (stat(_))[4..5];
+ # Make sure files owned by the old user are owned by the
+ # new user
+ if ($uid == $olduid) {
+ $uid = $newuid;
+ $gid = $newgid;
+ }
+ chown $uid, $gid, $dest;
+ chmod $mode, $dest;
+ }
+ while (read(SRC, $buf, $bufsize)) {
+ print DEST $buf;
+ }
+ close( SRC );
+ close( DEST );
+}
+
+#############################################################################################################
+# backup 5.x configuration files #
+# backup the directory <root_server5>/slapd-instance/config dans <root_server5>/slapd-instance/BackupConfig # #
+# #
+#############################################################################################################
+
+
+sub backupConfigFiles {
+ # backup the 5.x config files
+ my $src = "$serverHome${PATHSEP}config" ;
+ my $dest = "$serverHome${PATHSEP}config_backup" ;
+ if ($NO_INPUT_USER) {
+ printMsg("\n$src has been backup in $dest");
+ &copyDir($src,$dest);
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\n\nWhere do you want to back up your configuration directory [$dest] ?") ;
+ my $Answer = <STDIN> ;
+ $dest = $Answer if ($Answer ne "\n");
+ chomp($dest);
+ printTrace("\nDest: .$dest.",4);
+ if (-e $dest) {
+ printMsg("\n\n$dest already exists. Do you want to overwrite it Yes/No [No] ?") ;
+ if (<STDIN> =~ /yes|y/i) {
+ $Ask = 0 ;
+ }
+ else {
+ $dest = "$serverHome${PATHSEP}config_backup" ;
+ }
+ }
+ else {
+ $Ask = 0 ;
+ }
+ }
+ printTrace("\nBackup Directory: $src in $dest",4);
+ &copyDir($src,$dest);
+ }
+}
+#############################################################################
+
+sub getLDAPservername {
+ my $oldLDAPservername;
+ my $LDAPservername;
+ my $localhost = "nsslapd-localhost";
+ open(OLDDSELDIF, "< $oldDSEldif") or die "\nError: could not open old config file $oldDSEldif \n";
+ my $in = new Mozilla::LDAP::LDIF(*OLDDSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ my $DN = $entry->getDN(1) ;
+ if ($DN =~ /^cn=config$/i) {
+ my @values = $entry->getValues($localhost);
+ if ($entry->size($localhost)) {
+ $oldLDAPservername = $values[0];
+ printTrace("\nName of the old LDAP server: $oldLDAPservername",3);
+ }
+ break;
+ }
+ }
+ close(OLDSELDIF);
+
+ open( DSELDIF, "< $DSEldif" ) || die "\nCan't open $DSEldif \n";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ my $DN = $entry->getDN(1) ;
+ if ($DN =~ /^cn=config$/i) {
+ my @values = $entry->getValues($localhost);
+ if ($entry->size($localhost)) {
+ $LDAPservername = $values[0];
+ printTrace("\nName of the new LDAP server: $LDAPservername",3);
+ }
+ break;
+ }
+ }
+ close(DSELDIF);
+ # check ol and new Directory Instance are installed on the same physical machine.
+ if (lc($oldLDAPservername) ne lc($LDAPservername)) {
+ # warn the user he tries to migrate a 4.x server installed on a different machine from the 5.x one
+ printMsg("\n\nYour old instance is on $oldLDAPservername, whereas your new instance is on $LDAPservername. Migration on different machines is not supported. Do you want to continue ? Yes/No [No]:") ;
+ if (! (<STDIN> =~ /yes|y/i)) {
+ return -1;
+ }
+ }
+ return $LDAPservername ;
+}
+
+#############################################################################
+
+sub getLibPath {
+ my $myDir = shift;
+ my $myVersion = shift;
+ my $myMinor = shift;
+
+ if ($isNT) {
+ return $ENV{"$LIB_PATH"};
+ }
+ if (($myVersion >= 6) && ($myMinor >= 2)) {
+ return
+ "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}".
+ "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}".
+ $ENV{"$LIB_PATH"};
+ } else {
+ return "$myDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ }
+}
+
+#############################################################################
+
+sub getVersion {
+ my $dir = shift;
+ my $versionstr = shift;
+ my $version = 0;
+ my $minor = 0;
+ my $buildNumber = 0;
+ my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+ my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}";
+
+ # find the slapd executable
+ if (!$versionstr) { # version not specified on cmd line - find it
+ $prog = $dir . $progDir . $slapdExecName;
+ if (! -f $prog) {
+ $prog = $dir . $progDir2 . $slapdExecName;
+ if (-f $prog && $isNT) {
+ # if slapd is in bin/slapd and we're on NT, just assume version 1;
+ # apparently, slapd.exe doesn't like the -v argument . . .
+ return ( '1', $minor );
+ }
+ else{
+ die "Could not run slapd program $prog: $!";
+ }
+ }
+ else {
+ chdir($dir . $progDir);
+ }
+ $cur_libpath=$ENV{"$LIB_PATH"};
+ $ENV{"$LIB_PATH"}=
+ "$dir${PATHSEP}lib${SEP}".
+ "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}".
+ "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}".
+ $ENV{"$LIB_PATH"};
+ # read the old version from the old slapd program
+
+ open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or
+ die "Could not run slapd program $prog: $!";
+ sleep(1); # allow some data to accumulate in the pipe
+# print "Output from $prog -v:\n";
+ while (<F>) {
+ if (/^Netscape-Directory/ || /^iPlanet-Directory/i) {
+ $versionstr = $_;
+ last;
+ }
+ }
+ $code = close(F);
+ # print "$prog returned code=$code status=$?\n";
+ $ENV{"$LIB_PATH"}=$cur_libpath;
+ }
+
+ if ($versionstr =~ /^Netscape-Directory\/(\d+)\.(\d+)(?:b\d)*\s+(\S+)/) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ }
+ elsif ($versionstr =~ /^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ...
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ }
+ elsif ($versionstr =~ /^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ } elsif ($versionstr =~ /(\d+)\.(\d+)/) {
+ $version = $1;
+ $minor = $2;
+ }
+
+ if ($version == 0) {
+ die "\nCould not determine version of the directory server in $dir: \n";
+ }
+
+ # distinguish the 4.1 and the 4.11 thanks to the buildNumber
+ if (($version == 4) && ($minor == 1)){
+ if (! ($buildNumber =~ /^B99\.16/)) {
+ # it's not a 4.1 Netscape Directory Server => it's a 4.11
+ $minor = 11 ;
+ }
+ }
+ chdir($curdir) or die "Could not change directory to $curdir: $!" ;
+ return ( $version, $minor );
+}
+
+###############################################################################################
+sub normalizeDir {
+ my $dir = shift ;
+ my $dir_prec = "" ;
+ while ($dir_prec ne $dir) {
+ $dir_prec = $dir ;
+ if ($isNT) {
+ grep { s@\\\\@\\@g } $dir ;
+ }
+ else {
+ grep { s@//@/@g } $dir ;
+ }
+ }
+ return $dir ;
+}
+
+
+###############################################################################################
+
+sub GetTime {
+ my $tm = localtime;
+ (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900);
+ $sec = "0$sec" unless $sec > 9 ;
+ $min = "0$min" unless $min > 9 ;
+ $hour = "0$hour" unless $hour > 9 ;
+ $dd = "0$dd" unless $dd > 9 ;
+ $mm = "0$mm" unless $mm > 9 ;
+ return ($sec, $min, $hour, $dd, $mm, $yy);
+}
+
+###############################################################################################
+# get uid and group id of the 5.x slapd server.
+# The uid is done through the nsslapd-localuser attribute
+
+sub getuid_gid {
+ my $newuid ;
+ my $newgid ;
+ my $localuser ;
+ my $localuser_attr = "nsslapd-localuser" ;
+ if (! $isNT) {
+ &startServer() unless (isDirectoryAlive());
+ my $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ my $entry = $conn->search("cn=config ", "base","objectclass=*", 0, ($localuser_attr)) ;
+ # Tests wether we succeed to get the entry cn=config
+ die "\nCan't get the entry cn=config \n" unless ($entry);
+ my @values = $entry->getValues($localuser_attr);
+ $conn->close();
+ if ($#values == -1 || ($values[0] eq "") ) { # tests wether the nsslapd-localuser attribute has a value
+ printMsg("\nNo localuser has been found in the configuration of the directory. ");
+ if ($NO_INPUT_USER) {
+ printMsg("\nWe considered nobody as the localuser");
+ $localuser = "nobody" ;
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\nUnder what user does your $Version.$Minor directory server run [nobody] ? ") ;
+ $localuser = <STDIN> ;
+ chomp($localuser);
+ $localuser = "nobody" if ($localuser eq "");
+ ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ;
+ if ($newuid) {
+ $Ask = 0 ;
+ }
+ else {
+ printMsg("\nError: $localuser is unknown from the system ");
+ }
+ }
+ }
+ }
+ else {
+ $localuser = $values[0]; # returns the first value (we should only have one localuser)
+ my $size = $#values ;
+ }
+ ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ;
+ return ($localuser, $newuid, $newgid) ;
+ }
+ else {
+ return () ;
+ }
+}
+
+sub getolduid_gid {
+ my $oldlocaluser ;
+ my $localuserAttr = "nsslapd-localuser";
+ my $entry ;
+ if (! $isNT) {
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ $typeOfEntry = getTypeOfEntry($entry);
+ if ($typeOfEntry eq "CONFIG_NODE") {
+ $oldlocaluser = $entry->{$localuserAttr}[0] if ($entry->exists($localuserAttr));
+ break ;
+ }
+ }
+ close(DSE);
+ ($olduid, $oldgid) = (getpwnam("$oldlocaluser"))[2..3] ;
+ return ($oldlocaluser, $olduid, $oldgid) ;
+ }
+ else {
+ return ();
+ }
+}
+###############################################################################################
+# get current directory
+
+sub getCwd {
+ my $command = $isNT ? "cd" : "/bin/pwd";
+ open(PWDCMD, "$command 2>&1 |") or
+ die "Error: could not execute $command: $!";
+ # without the following sleep, reading from the pipe will
+ # return nothing; I guess it gives the pwd command time
+ # to get some data to read . . .
+ sleep(1);
+ my $currentdir;
+ while (<PWDCMD>) {
+ if (!$currentdir) {
+ chomp($currentdir = $_);
+ }
+ }
+ my $code = close(PWDCMD);
+# if ($code || $?) {
+# print "$command returned code=$code status=$? dir=$curdir\n";
+# }
+# print "getCwd curdir=\[$curdir\]\n";
+ return $currentdir;
+}
+
+################################
+# Need to migrate the credential.
+# If the credential can not be migrated, leave it at it is
+################################
+sub migrate_credential{
+ my $entry_to_modify = shift;
+ my $credentials_attr = shift;
+ my @old_value = $entry_to_modify->getValues($credentials_attr);
+ my $migratecredExecName = 'migratecred';
+ my $credOldHome = $oldHome;
+ my $credServerHome = $serverHome;
+
+ if ($isNT) {
+ # oldHome may be pointing to the archived copy of the
+ # instance dir which may be different than the path that
+ # the instance was originally installed as on Windows. If
+ # this path is not the original install path, then the
+ # credential will not be migrated correctly. We should
+ # prompt the user on Windows for the correct path.
+
+ print "\n\nThe old instance path must be the same as where it was";
+ print "\ninitially installed, not where it was archived in order";
+ print "\nfor this step to succeed. Please verify that the path";
+ print "\nis correct. Note that case sensitivity is important here.";
+ print "\n\nOld Instance Directory: $credOldHome";
+ print "\nIs this correct? (y/n): ";
+ chomp(my $answer = <STDIN>);
+ if (!($answer =~ /y|yes/i)) {
+ print "\nPlease enter the correct path for the old instance directory: ";
+ chomp($credOldHome = <STDIN>);
+ }
+
+ print "\n\nThe new instance path must also be correct for this step";
+ print "\nto succeed. Please verify that the path is correct. Note";
+ print "\nthat case sensitivity is important here.";
+ print "\n\nNew Instance Directory: $credServerHome";
+ print "\nIs this correct? (y/n): ";
+ chomp(my $answer = <STDIN>);
+ if (!($answer =~ /y|yes/i)) {
+ print "\nPlease enter the correct path for the new instance directory: ";
+ chomp($credServerHome = <STDIN>);
+ }
+ }
+# print "\nMigratecred command is: ${quote}$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}$migratecredExecName${quote} -o $credOldHome -n $credServerHome -c @old_value\n";
+
+ my @new_cred = `${quote}$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}$migratecredExecName${quote} -o $credOldHome -n $credServerHome -c @old_value`;
+
+ if ( $? == 0 )
+ {
+ $entry_to_modify->setValues($credentials_attr, @new_cred);
+ }
+}
+
diff --git a/ldap/admin/src/scripts/template-migrate6to7 b/ldap/admin/src/scripts/template-migrate6to7
new file mode 100644
index 00000000..26f117b6
--- /dev/null
+++ b/ldap/admin/src/scripts/template-migrate6to7
@@ -0,0 +1,3049 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# Migrate a 6.x directory server to a 7.0 directory server
+
+#######################################################################################################
+# enable the use of Perldap functions
+require DynaLoader;
+
+use Getopt::Std;
+use Mozilla::LDAP::Conn;
+use Mozilla::LDAP::Entry;
+use Mozilla::LDAP::LDIF;
+use Mozilla::LDAP::Utils qw(:all);
+use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API
+use Time::localtime;
+use File::Basename;
+use Class::Struct ;
+
+#######################################################################################################
+
+sub usage {
+ print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n");
+ print(STDERR " -o oldInstancePath -n newInstancePath [-t tracelevel] [-L logfile]\n");
+ print(STDERR "************** parameters in brackets are optionals, others are required **************\n");
+ print(STDERR " Opts: -D rootdn - new 7.0 Directory Manager\n");
+ print(STDERR " : -w password - new 7.0 Directory Manager's password\n");
+ print(STDERR " : -w - - Prompt for new 7.0 Directory Manager's password\n");
+ print(STDERR " : -j filename - Read new 7.0 Directory Manager's password from file\n");
+ print(STDERR " : -p port - new 7.0 Directory Server port\n");
+ print(STDERR " : -o oldInstancePath - Path of the old instance to migrate \n");
+ print(STDERR " : -n newInstancePath - Path of the new 7.0 instance\n");
+ print(STDERR " : [-d dataPath] - Path to directory containing data files to import into new instance\n");
+ print(STDERR " : [-v oldVersion] - Version of old instance (obtained by running $slapdExecName -v\n");
+ print(STDERR " : [-t tracelevel] - (optional) specify the level of trace (0..3)\n");
+ print(STDERR " : [-L logfile] - (optional) specify the file to log the migration report \n");
+ }
+########################################################################################################
+
+BEGIN {
+
+ require 'uname.lib' ;
+ $isNT = -d '\\';
+ $PATHSEP = $isNT ? "\\" : "/";
+ ${SEP} = $isNT ? ";" : ":" ;
+ @INC = ( '.', '../../../admin/admin/bin');
+ grep { s@/@\\@g } @INC if $isNT;
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ # NT needs quotes around some things unix doesn't
+ $quote = $isNT ? "\"" : "";
+
+ # If this variable is set, all file/directory creation will make sure the mode
+ # and ownership of the destination is the same as the source
+ $PRESERVE = 1 if (!$isNT);
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ if ($isNT) {
+ $os = "WINNT";
+ } else {
+ $os = &uname("-s");
+ }
+ if ($isNT) {
+ # we have to pass batch files directly to the NT command interpreter
+ $com_spec = $ENV{ComSpec};
+ if (!$com_spec) {
+ $com_spec = $ENV{COMSPEC};
+ }
+ if (!$com_spec || ! -f $com_spec) {
+ # find the first available command interpreter
+ foreach $drive (c..z) {
+ $com_spec = "$drive:\\winnt\\system32\\cmd.exe";
+ last if (-f $com_spec);
+ $com_spec = undef;
+ }
+ if (! $com_spec) {
+ # punt and pray
+ $com_spec = 'c:\winnt\system32\cmd.exe';
+ }
+ }
+ }
+ if ( $os eq "AIX" ) {
+ $dll_suffix = "_shr.a";
+ }
+ elsif ( $os eq "HP-UX" ) {
+ $dll_suffix = ".sl";
+ }
+ elsif ( $os eq "WINNT" ) {
+ $dll_suffix = ".dll";
+ }
+ else {
+ $dll_suffix = ".so";
+ }
+ $slapdExecName = $isNT ? 'slapd.exe' : './ns-slapd';
+ select STDERR;
+ $| = 1;
+ select STDOUT;
+ $| = 1;
+}
+
+SWITCH: {
+ if ($os eq "AIX") {
+ $LIB_PATH = "LIBPATH" ;
+ last SWITCH ;
+ }
+ if ($os eq "HP-UX") {
+ $LIB_PATH = "SHLIB_PATH" ;
+ last SWITCH ;
+ }
+ if ($isNT) {
+ $LIB_PATH = "PATH" ;
+ last SWITCH ;
+ }
+ else {
+ $LIB_PATH = "LD_LIBRARY_PATH" ;
+ last SWITCH ;
+ }
+ }
+
+ # old parameters
+ ${oldDir} = "" ;
+ ${oldname} = "" ;
+ ${oldHome} = "" ;
+ ${oldConfDir} = "" ;
+ ${oldlocaluser} ;
+ ${olduid} ;
+ ${oldgid} ;
+
+ # new parameters
+ ${root} = "{{DS-ROOT}}" ;
+ ${type} = "" ;
+ ${newname} = "" ;
+ ${newport} = "" ;
+ ${rootDN} = "" ;
+ ${rootpwd} = "" ;
+ ${localhost} = "" ;
+ ${LogFileReport} = "" ;
+ ${newuid} ;
+ ${localuser} ;
+ ${newgid} ;
+ $NO_INPUT_USER = 0 ; # by default user can give inputs during the migration process
+ ${curdir} = getCwd();
+ ${slapdExecDir} = "${root}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+ # in 7.0 the replica Id is setup to a static value
+ $replicaIdvalue = 65535;
+
+ # specify the level of trace
+ $TRACELEVEL=1;
+
+ $LDAP_SERVER_UNREACHABLE = 81;
+
+ # get input users
+ &getParameters() ;
+ ${oldDir} = &normalizeDir("${oldDir}");
+ ${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ;
+ ${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ;
+ ${oldSchemaDir} = "${oldConfDir}schema${PATHSEP}";
+ ${oldDSEldif} = "${oldConfDir}dse.ldif";
+ ${serverHome} = "${root}${PATHSEP}$type-$newname" ;
+ ${schemaDir} = "$serverHome${PATHSEP}config${PATHSEP}schema${PATHSEP}";
+ ${DSEldif} = "$serverHome${PATHSEP}config${PATHSEP}dse.ldif";
+ ${ldif_rep} = "${oldConfDir}ldif${PATHSEP}" ;
+ ${oldSlapdExecDir} = "${oldDir}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+
+ open(LOGFILE, ">> $LogFileReport");
+
+ printTrace("\noldDir: $oldDir, oldHome: $oldHome, \noldConfDir: $oldConfDir, \nldif_rep: $ldif_rep, \nrootDN: $rootDN, \nPort: $newport, \nNewname: $newname\n",3);
+ printTrace("\nLIB_PATH: $LIB_PATH",4);
+
+ if (!(-d $serverHome)) {
+ printMsg("\n$serverHome doesn't exist\n");
+ exit(1);
+ }
+ if (!(-d $oldHome)) {
+ printMsg("\n$oldHome doesn't exist\n");
+ exit(1);
+ }
+
+ if ($olddatadir && !(-d $olddatadir)) {
+ print("\n$olddatadir doesn't exist\n");
+ exit(1);
+ }
+
+
+%HashParametersName = ();
+
+# The following hash displays only general server parameters to migrate under cn=config
+%GeneralSrvParamToMigrate = (
+ 'nsslapd-accesscontrol'=> '\n',
+ 'nsslapd-errorlog-logging-enabled'=> '\n',
+ 'nsslapd-accesslog-logging-enabled'=> '\n',
+ 'nsslapd-auditlog-logging-enabled'=> '\n',
+ 'nsslapd-accesslog-level'=> '\n',
+ 'nsslapd-accesslog-logbuffering'=> '\n',
+ 'nsslapd-accesslog-logexpirationtime'=> '\n',
+ 'nsslapd-accesslog-logexpirationtimeunit'=> '\n',
+ 'nsslapd-accesslog-logmaxdiskspace'=> '\n',
+ 'nsslapd-accesslog-logminfreediskspace'=> '\n',
+ 'nsslapd-accesslog-logrotationtime'=> '\n',
+ 'nsslapd-accesslog-logrotationtimeunit'=> '\n',
+ 'nsslapd-accesslog-maxlogsize'=> '\n',
+ 'nsslapd-accesslog-maxLogsPerDir'=> '\n',
+ 'nsslapd-attribute-name-exceptions'=> '\n',
+ 'nsslapd-auditlog-logexpirationtime'=> '\n',
+ 'nsslapd-auditlog-logexpirationtimeunit'=> '\n',
+ 'nsslapd-auditlog-logmaxdiskspace'=> '\n',
+ 'nsslapd-auditlog-logminfreediskspace'=> '\n',
+ 'nsslapd-auditlog-logrotationtime'=> '\n',
+ 'nsslapd-auditlog-logrotationtimeunit'=> '\n',
+ 'nsslapd-auditlog-maxlogsize'=> '\n',
+ 'nsslapd-auditlog-maxLogsPerDir'=> '\n',
+ 'nsslapd-certmap-basedn'=> '\n',
+ 'nsslapd-ds4-compatible-schema'=> '\n',
+ 'nsslapd-enquote-sup-oc'=> '\n',
+ 'nsslapd-errorlog-level'=> '\n',
+ 'nsslapd-errorlog-logexpirationtime'=> '\n',
+ 'nsslapd-errorlog-logexpirationtimeunit'=> '\n',
+ 'nsslapd-errorlog-logmaxdiskspace'=> '\n',
+ 'nsslapd-errorlog-logminfreediskspace'=> '\n',
+ 'nsslapd-errorlog-logrotationtime'=> '\n',
+ 'nsslapd-errorlog-logrotationtimeunit'=> '\n',
+ 'nsslapd-errorlog-maxlogsize'=> '\n',
+ 'nsslapd-errorlog-maxlogsperdir'=> '\n',
+ 'nsslapd-groupevalnestlevel'=> '\n',
+ 'nsslapd-idletimeout'=> '\n',
+ 'nsslapd-ioblocktimeout'=> '\n',
+ 'nsslapd-lastmod'=> '\n',
+ 'nsslapd-listenhost'=> '\n',
+ 'nsslapd-maxdescriptors'=> '\n',
+ 'nsslapd-nagle'=> '\n',
+ 'nsslapd-readonly'=> '\n',
+ 'nsslapd-referralmode'=> '\n',
+ 'nsslapd-plugin-depends-on-name'=> '\n',
+ 'nsslapd-plugin-depends-on-type'=> '\n',
+ 'nsslapd-referral'=> '\n',
+ 'nsslapd-reservedescriptors'=> '\n',
+ 'nsslapd-rootpwstoragescheme'=> '\n',
+ 'nsslapd-schemacheck'=> '\n',
+ 'nsslapd-secureport'=> '\n',
+ 'nsslapd-security'=> '\n',
+ 'nsslapd-sizelimit'=> '\n',
+ 'nsslapd-ssl3ciphers'=> '\n',
+ 'nsslapd-timelimit'=> '\n',
+ 'passwordchange'=> '\n',
+ 'passwordchecksyntax'=> '\n',
+ 'passwordexp'=> '\n',
+ 'passwordhistory'=> '\n',
+ 'passwordinhistory'=> '\n',
+ 'passwordlockout'=> '\n',
+ 'passwordlockoutduration'=> '\n',
+ 'passwordmaxage'=> '\n',
+ 'passwordmaxfailure'=> '\n',
+ 'passwordminage'=> '\n',
+ 'passwordminlength'=> '\n',
+ 'passwordmustchange'=> '\n',
+ 'passwordresetfailurecount' => '\n',
+ 'passwordstoragescheme' => '\n',
+ 'passwordunlock' => '\n',
+ 'passwordwarning' => '\n'
+);
+
+# the following hash displays global parameters related to database stored under cn=config,cn=ldbm database,cn=plugins,cn=config
+%GlobalConfigLDBMparamToMigrate = (
+ 'nsslapd-allidsthreshold' => '\n',
+ 'nsslapd-lookthroughlimit' => '\n',
+ 'nsslapd-mode' => '\n',
+ 'nsslapd-dbcachesize' => '\n',
+ 'nsslapd-cache-autosize' => '\n',
+ 'nsslapd-cache-autosize-split' => '\n',
+ 'nsslapd-db-transaction-logging' => '\n',
+ 'nsslapd-import-cachesize' => '\n'
+);
+
+# the following hash displays specific parameters to each backends and stored under cn=DBname,cn=ldbm database,cn=plugins,cn=config
+%LDBMparamToMigrate = (
+ 'nsslapd-cachesize' => '\n',
+ 'nsslapd-cachememsize' => '\n',
+ 'nsslapd-readonly' => '\n',
+ 'nsslapd-require-index' => '\n'
+);
+
+
+%ChainingConfigParams = (
+ 'nsactivechainingcomponents' => '\n',
+ 'nstransmittedcontrols' => '\n'
+ );
+
+%ChainingDefaultInstanceConfigParams = (
+ 'nsabandonedsearchcheckinterval' => '\n',
+ 'nsbindconnectionslimit' => '\n',
+ 'nsbindtimeout' => '\n',
+ 'nsbindretrylimit' => '\n',
+ 'nshoplimit' => '\n',
+ 'nsmaxresponsedelay' => '\n',
+ 'nsmaxtestresponsedelay' => '\n',
+ 'nschecklocalaci' => '\n',
+ 'nsconcurrentbindlimit' => '\n',
+ 'nsconcurrentoperationslimit' => '\n',
+ 'nsconnectionlife' => '\n',
+ 'nsoperationconnectionslimit' => '\n',
+ 'nsproxiedauthorization' => '\n',
+ 'nsreferralonscopedsearch' => '\n',
+ 'nsslapd-sizelimit' => '\n',
+ 'nsslapd-timelimit' => '\n'
+);
+
+%changelog5params = (
+ 'nsslapd-changelogmaxage' => '\n',
+ 'nsslapd-changelogmaxentries' => '\n'
+ );
+
+@SNMPparams = (
+ 'nssnmpenabled',
+ 'nssnmporganization',
+ 'nssnmplocation',
+ 'nssnmpcontact',
+ 'nssnmpdescription',
+ 'nssnmpmasterhost',
+ 'nssnmpmasterport',
+ 'nssnmpenabled',
+ 'aci'
+ );
+
+%stdIncludes = (
+ "." => "\n",
+ ".." => "\n",
+ "30ns-common.ldif " => "\n",
+ "50ns-mail.ldif " => "\n",
+ "50ns-news.ldif" => "\n",
+ "50iplanet-servicemgt.ldif"=> "\n",
+ "50netscape-servicemgt.ldif"=> "\n",
+ "50ns-mcd-browser.ldif" => "\n",
+ "50ns-proxy.ldif" => "\n",
+ "00core.ldif" => "\n",
+ "50ns-admin.ldif" => "\n",
+ "50ns-mcd-config.ldif " => "\n",
+ "50ns-value.ldif" => "\n",
+ "05rfc2247.ldif" => "\n",
+ "50ns-calendar.ldif" => "\n",
+ "50ns-mcd-li.ldif" => "\n",
+ "50ns-wcal.ldif" => "\n",
+ "05rfc2927.ldif" => "\n",
+ "50ns-certificate.ldif" => "\n",
+ "50ns-mcd-mail.ldif" => "\n",
+ "50ns-web.ldif" => "\n",
+ "10rfc2307.ldif" => "\n",
+ "50ns-compass.ldif" => "\n",
+ "50ns-media.ldif" => "\n",
+ "20subscriber.ldif" => "\n",
+ "50ns-delegated-admin.ldif"=> "\n",
+ "50ns-mlm.ldif" => "\n",
+ "25java-object.ldif" => "\n",
+ "50ns-directory.ldif" => "\n",
+ "50ns-msg.ldif" => "\n",
+ "28pilot.ldif" => "\n",
+ "50ns-legacy.ldif" => "\n",
+ "50ns-netshare.ldif" => "\n"
+);
+
+
+# Backends migrated (Backend CN attribute value)
+@BACKENDS = () ;
+# All pairs of suffix-backend are registered in this hashtable
+%oldBackends = () ;
+
+#store the backend instances to migrate
+@LDBM_backend_instances = ();
+
+#store the mapping tree
+@Mapping_tree_entries = ();
+
+#store the suffix and the associated chaining backend
+%oldChainingBackends = ();
+
+#store the multiplexor bind entries to migrate
+%MultiplexorBindDNEntriesToMigrate = ();
+
+#store the Replica bind DN entries to migrate
+%ReplicaBindDNEntriesToMigrate = ();
+
+# list of standard plugins
+%stdPlugins = (
+ "7-bit check" => "\n",
+ "acl plugin" => "\n",
+ "acl preoperation" => "\n",
+ "binary syntax" => "\n",
+ "case exact string syntax" => "\n",
+ "case ignore string syntax" => "\n",
+ "chaining database" => "\n",
+ "class of service" => "\n",
+ "country string syntax" => "\n",
+ "distinguished name syntax" => "\n",
+ "generalized time syntax" => "\n",
+ "integer syntax" => "\n",
+ "internationalization plugin" => "\n",
+ "ldbm database" => "\n",
+ "legacy replication plugin" => "\n",
+ "multimaster replication plugin" => "\n",
+ "octet string syntax" => "\n",
+ "clear" => "\n",
+ "crypt" => "\n",
+ "ns-mta-md5" => "\n",
+ "sha" => "\n",
+ "ssha" => "\n",
+ "postal address syntax" => "\n",
+ "referential integrity postoperation" => "\n",
+ "retro changelog plugin" => "\n",
+ "roles plugin" => "\n",
+ "telephone syntax" => "\n",
+ "uid uniqueness" => "\n",
+ "uri syntax" => "\n"
+ );
+
+# list of indexes that have disappeared from the new schema compared to 6.x
+%deniedIndexes = (
+ 'dncomp' => "\n"
+);
+
+@default_indexes = ();
+@indexes = ();
+
+# list of user added Plugin's. In 7.0, they 'll need to be recompiled
+@badPlugins = () ;
+
+@pluginAttrs = (
+ "objectclass",
+ "cn",
+ "nsslapd-pluginpath",
+ "nsslapd-plugininitfunc",
+ "nsslapd-plugintype",
+ "nsslapd-pluginenabled",
+ "nsslapd-plugin-depends-on-type",
+ "nsslapd-pluginid",
+ "nsslapd-pluginversion",
+ "nsslapd-pluginvendor"
+ );
+
+@nsds5replicaAttrs = (
+ 'objectclass',
+ 'nsDS5ReplicaRoot',
+ 'nsDS5ReplicaType',
+ 'nsDS5ReplicaLegacyConsumer',
+ 'nsDS5flags',
+ 'nsDS5ReplicaId',
+ 'nsDS5ReplicaPurgeDelay',
+ 'nsDS5ReplicaBinddn',
+ 'cn',
+ 'nsDS5ReplicaReferral'
+ );
+
+# array of replicas to migrate
+@new6replicas = ();
+
+# array of replication agreements to migrate
+@replicationAgreements = ();
+
+# compare LDIF standard config files with standard ones
+CompareStdConfigFiles() ;
+die "\n\n The version of product you want to migrate is not a 6.x Directory Server\n" unless ($oldVersion == 6) ;
+
+# Shutdown the legacy Directory instance
+printTrace("\nShutdown the legacy Directory Server instance: ${oldHome}",0);
+&stopServer($oldDir, 'slapd-'.$oldname);
+
+# get the hostname of the new LDAP server
+my $LDAPservername = &getLDAPservername();
+
+# get the uid and gid of the 7.0 slapd user
+($localuser, $newuid, $newgid) = getuid_gid();
+# get the uid and gid of the 6.x slapd user
+($oldlocaluser, $olduid, $oldgid) = getolduid_gid();
+printTrace("\n7.0 localuser: $localuser, uid: $newuid, gid: $newgid",2);
+printTrace("\n6.x localuser: $oldlocaluser, uid: $olduid, gid: $oldgid",2);
+
+# backup 7.0 configuration files in <6server_root>/slapd-instancename/config
+printTrace("\nBackup $serverHome${PATHSEP}config on $serverHome${PATHSEP}config_backup ...",0);
+&backupConfigFiles();
+
+# migrate the schema (need to stop and start the 7.0 server)
+printTrace("\nMigrate the schema...",0);
+MigrateSchema();
+
+# start the server unless it is already started
+&startServer() unless (isDirectoryAlive());
+
+############### Connect to the 7.0 LDAP Directory Server ######################
+$ENV{"$LIB_PATH"} = $new_libpath;
+
+die "\n Migration aborted. Make sure your old and new Directory Server are installed on the same machine \n" if ( $LDAPservername == -1 );
+$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+
+# Cconnection to 7.0 LDAP server is successful !
+printTrace("\nConnected to $Version.$Minor LDAP server",0) ;
+
+# Parse the main configuration file: dse.ldif
+printTrace("\n\nParse the old DSE ldif file: $oldDSEldif *****",0, 1);
+printTrace("\nThis may take a while ...\n",0);
+&MigrateDSEldif();
+
+#migrate LDBM backend instances
+printTrace("\n\nMigrate LDBM backend instances...",0,1);
+&migrateLDBM_backend_instances();
+
+#migrate mapping tree entries
+printTrace("\n\nMigrate mapping tree...",0,1);
+&migrateMappingTree();
+
+#migrate default indexes
+printTrace("\n\nMigrate default indexes...",0,1);
+migrateDefaultIndexes();
+
+#migrate indexes
+printTrace("\n\nMigrate indexes...",0,1);
+migrateIndexes();
+
+#migrate replicas
+printTrace("\n\nMigrate replicas...",0,1);
+&MigrateNSDS5_replica();
+
+#migrate replication agreements
+printTrace("\n\nMigrate replication agreements...",0,1);
+&MigrateNSDS_replication_agreement();
+
+#migrate key/cert databases
+printTrace("\n\nMigrate key/cert databases...",0,1);
+&MigrateSSL();
+
+# migrate certmap.conf
+printTrace("\n\nMigrate Certmap.conf...",0,1);
+&MigrateCertmap() ;
+
+################## Close the connection to 7.0 LDAP Server #####################
+printTrace("\n\n***** Close the LDAP connection to the new Directory Server instance ***** ",0);
+$conn->close;
+
+
+################## stop the new instance and Export/Import the data, restart the server ##################
+if (@BACKENDS) {
+ &stopServer($root,'slapd-'.$newname);
+ if ($olddatadir) {
+ printTrace("\nData already contained in $olddatadir...\n",0,1) ;
+ $ldif_rep = "$olddatadir${PATHSEP}";
+ } else {
+ printTrace("\nData processing...\n",0,1) ;
+ # migrate data for each backend: 6.x -> LDIF files
+ &manydb2Ldif($ldif_rep);
+ }
+
+ # migrate LDIF data to the new database: LDIF -> New
+ &manyLdif2db($ldif_rep);
+ &migrateChangelog();
+ printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1);
+ &importReplicaBindDNEntries();
+ printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1);
+ &importMultiplexorBindDNEntries();
+ &startServer() unless (isDirectoryAlive());
+}
+else {
+ printTrace("\nINFORMATION - There are no non-standard or non-already existing suffixes to migrate\n",0);
+ &migrateChangelog();
+ printTrace("\n***** Migrate ReplicaBindDN entries...\n",0,1);
+ &importReplicaBindDNEntries();
+ printTrace("\n***** Migrate MultiplexorBindDN entries...\n",0,1);
+ &importMultiplexorBindDNEntries();
+}
+
+printMsg("\n\n ****** End of migration ******\n\n");
+
+close(LOGFILE);
+
+
+###########################################################################################
+# get input users
+sub getParameters {
+ my $exit = 0 ;
+ my $i = 0;
+ my $pwdfile= "";
+
+ while ($i <= $#ARGV) {
+ if ( "$ARGV[$i]" eq "-D" ) { # directory manager
+ if (! $rootDN) {
+ $rootDN = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-w") { # password
+ if (! $rootpwd) {
+ $rootpwd = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-j") { # password file
+ if (! $pwdfile) {
+ $pwdfile = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-o") { # old instance path
+ if (! $oldHome ) {
+ $oldHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $oldHome if $isNT ;
+ if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; }
+ if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) {
+ $oldDir = $1 ;
+ $type = $2 ;
+ $oldname = $3 ;
+ if ($isNT) {
+ $oldDir = lc($oldDir) ;
+ $type = lc($type) ;
+ $oldname = lc($oldname) ;
+ $oldHome = lc($oldHome) ;
+ grep { s@/@\\@g } $oldDir ;
+ grep { s@/@\\@g } $oldHome ;
+ }
+ }
+ else {
+ print("\nThe old instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-n") { # new instance path
+ if (! $serverHome ) {
+ $serverHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $root if $isNT ;
+ grep { s@\\@/@g } $serverHome if $isNT ;
+ if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; }
+ if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) {
+ $root = $1 if ($1);
+ $type = $2 ;
+ $newname = $3 ;
+ if ($isNT) {
+ $root = lc($root) ;
+ $type = lc($type) ;
+ $newname = lc($newname) ;
+ $serverHome = lc($serverHome) ;
+ grep { s@/@\\@g } $root ;
+ grep { s@/@\\@g } $serverHome ;
+ }
+ }
+ else {
+ print("\nThe new instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-p") { # new DS port
+ if (! $newport ) {
+ $newport = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-d") { # old instance LDIF data dir
+ if (! $olddatadir ) {
+ $olddatadir = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-v") { # old version
+ if (! $oldversionstr ) {
+ $oldversionstr = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL
+ my $value = $ARGV[++$i] ;
+ if ($value =~ /[0-3]/) {
+ $TRACELEVEL = $value ;
+ }
+ else {
+ print("\nThe tracelevel must belong to 0..3 interval");
+ &usage();
+ exit();
+ }
+ } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing
+ $NO_INPUT_USER = 1 ;
+ } elsif ("$ARGV[$i]" eq "-L") { # migration logfile
+ $LogFileReport = $ARGV[++$i] ;
+ }
+ else {
+ print("\nThe option $ARGV[$i] is not recognized");
+ &usage() ;
+ exit(1);
+ }
+ $i++;
+ }
+ if (! $rootDN) {
+ print("\nThe rootDN is missing");
+ $exit = 1;
+ }
+ if ($pwdfile ne "") {
+ # Open file and get the password
+ unless (open (RPASS, $pwfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $rootpwd = <RPASS>;
+ chomp($rootpwd);
+ close(RPASS);
+ } elsif ($rootpwd eq "-"){
+ # Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+ # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $rootpwd = ReadLine(0);
+# chomp($rootpwd);
+# ReadMode('normal');
+ }
+ if (! $rootpwd) {
+ print("\nThe rootpwd is missing");
+ $exit = 1 ;
+ }
+ if (! $newport) {
+ print("\nThe port is missing");
+ $exit = 1;
+ }
+ if (! $serverHome) {
+ print("\nThe new instance path is missing");
+ $exit = 1;
+ }
+ if (! $oldHome) {
+ print("\nThe old instance path is missing");
+ $exit = 1;
+ }
+ if ((! $LogFileReport) && $serverHome) {
+ ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime();
+ $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log";
+ }
+ if ($exit) {
+ &usage() ;
+ exit(1);
+ }
+
+}
+
+###################################################################################################
+
+sub MigrateSchema{
+ my $FilesChanged = "";
+ my $AllDiffs = "";
+ my $NoChanges = "" ;
+ my $lineToBegin = 0 ;
+ opendir(SCHEMADIR, $oldSchemaDir) or
+ die "Error: could not open migrated config dir $oldSchemaDir: $!";
+
+ foreach $file (readdir(SCHEMADIR)) {
+ if (! exists($stdIncludes{lc($file)})) {
+ my $newSchemaFile = $schemaDir . $file;
+ if (-f $newSchemaFile ) {
+ # The ldif file already exists. Make a diff and warn the user if different.
+ if (diff($newSchemaFile, $oldSchemaDir.$file)) {
+ &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive());
+ $AllDiffs .= "\n$file";
+ copyBinFile("$oldSchemaDir$file", $newSchemaFile);
+ }
+ }
+ else {
+ &stopServer($root,'slapd-'.$newname) if (isDirectoryAlive());
+ $AllDiffs .= "\n$file";
+ copyBinFile("$oldSchemaDir$file", $newSchemaFile);
+ }
+ }
+ }
+ closedir(SCHEMADIR);
+ if ($AllDiffs) {
+ printMsg("\n\n***********************************************************************");
+ printMsg("\nThe following LDIF files have been migrated:");
+ printMsg("$AllDiffs");
+ printMsg("\n*************************************************************************\n\n");
+ }
+ &startServer() if (! isDirectoryAlive());
+}
+
+
+###################################################################################################
+# This subroutine is used to parse the dse.ldif file and call specific routines to act with entries
+sub MigrateDSEldif {
+ printTrace("\nMigrate DSE entries...",1);
+ my $tempoAlreadyDone = 0;
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ $typeOfEntry = getTypeOfEntry($entry);
+ SWITCH: {
+ if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){
+ parseLDBM_backend_instance($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "MAPPING_TREE"){
+ parseMapping_tree($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "DEFAULT_INDEX"){
+ parseDefaultIndex($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "INDEX"){
+ parseIndex($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "STANDARD_PLUGIN"){
+ migrateStdPlugin($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CONFIG_NODE"){
+ migrateConfig_Node($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CONFIG_LDBM_DATABASE"){
+ migrateConfig_LDBM_database($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CHAINING_BACKEND_CONFIG"){
+ migrateChainingBE_config($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CHAINING_BACKEND_INSTANCE"){
+ migrateChainingBE_instance($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "NSDS5_REPLICA"){
+ parseNSDS5_replica($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "NSDS_REPLICATION_AGREEMENT"){
+ parseNSDS_replication_agreement($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "CHANGELOG5"){
+ migrateChangelog5($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "REPLICATION"){
+ migrateReplication($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "SECURITY"){
+ migrateSecurity($entry);
+ last SWITCH;
+ }
+ if ($typeOfEntry eq "SNMP"){
+ migrateSNMP($entry);
+ last SWITCH;
+ }
+ }
+
+ }
+ close(DSELDIF);
+}
+
+#############################################################################
+# returns the "type of an entry". If the entry is not to be migrated its type is "NOT_MIGRATED_TYPE"
+
+sub getTypeOfEntry{
+ my $entry = shift;
+ my $DN = $entry->getDN(1) ; # 1 is to normalize the returned DN
+ if (($DN =~ /cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) {
+ return "LDBM_BACKEND_INSTANCE";
+ }
+ if (($DN =~ /cn=mapping tree,cn=config$/i) && (isObjectclass($entry,"nsMappingTree"))) {
+ return "MAPPING_TREE";
+ }
+ if (($DN =~ /cn=default indexes,cn=config,cn=ldbm database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsIndex"))) {
+ return "DEFAULT_INDEX";
+ }
+ if (isObjectclass($entry,"nsIndex")) {
+ return "INDEX";
+ }
+ if ((isObjectclass($entry,"nsSlapdPlugin")) && (isStdPlugin($entry))) {
+ return "STANDARD_PLUGIN";
+ }
+ if ($DN =~ /^cn=config$/i) {
+ return "CONFIG_NODE";
+ }
+ if ($DN =~ /^cn=config,cn=ldbm database,cn=plugins,cn=config$/i) {
+ return "CONFIG_LDBM_DATABASE";
+ }
+ if (($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i) || ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i)){
+ return "CHAINING_BACKEND_CONFIG";
+ }
+ if (($DN =~ /cn=chaining database,cn=plugins,cn=config$/i) && (isObjectclass($entry,"nsBackendInstance"))) {
+ return "CHAINING_BACKEND_INSTANCE";
+ }
+ if (isObjectclass($entry,"nsDS5Replica")) {
+ return "NSDS5_REPLICA";
+ }
+ if (isObjectclass($entry,"nsDS5ReplicationAgreement")) {
+ return "NSDS_REPLICATION_AGREEMENT";
+ }
+ if ($DN =~ /^cn=changelog5,cn=config$/i) {
+ return "CHANGELOG5";
+ }
+ if (($DN =~ /cn=replication,cn=config$/i) && ($DN !~ /^cn=replication,cn=config$/i)) {
+ return "REPLICATION";
+ }
+ if ($DN =~ /cn=encryption,cn=config$/i) {
+ return "SECURITY";
+ }
+ if ($DN =~ /^cn=SNMP,cn=config$/i) {
+ return "SNMP";
+ }
+ return "NOT_MIGRATED_TYPE";
+}
+
+#############################################################################
+
+
+
+#############################################################################
+# returns 1 if the objectclass given in parameter is present in the objectclasses values of the entry
+# given in parameter, 0 else
+
+sub isObjectclass {
+ my $entry = shift;
+ my $objectclass = shift;
+ return ($entry->hasValue("objectclass",$objectclass,1));
+}
+
+#############################################################################
+
+sub isStdPlugin {
+ my $entry = shift;
+ my $CN = $entry->{cn}[0];
+ if (isObjectclass($entry,"nsSlapdPlugin")) {
+ return 1 if ($stdPlugins{lc($CN)});
+ }
+ return 0;
+}
+
+
+#############################################################################
+
+sub alreadyExistsInNew{
+ my $entry = shift;
+ my $mustExist = shift;
+ my $DN = $entry->getDN(1); # 1 to normalize the DN
+ # We have a name change of "uid uniqueness" plugin in DS6.x
+ # to "attribute uniqueness"
+ $DN =~ s/uid\ uniqueness/attribute\ uniqueness/ if ($DN =~ /uid\ uniqueness/);
+ return searchEntry($DN, $mustExist);
+}
+
+#############################################################################
+sub searchEntry {
+ my $DN = shift;
+ my $mustExist = shift;
+ my $res = $conn->search($DN, "base", "objectclass=*");
+ my $cpt = 5;
+ if ($res) {
+ return $res;
+ }
+ else {
+ my $errorCode = $conn->getErrorCode();
+ while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) {
+ printMsg("\ntry to reconnect to search $DN");
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ $res = $conn->search($DN, "base", "objectclass=*");
+ $errorCode = $conn->getErrorCode();
+ $cpt--;
+ }
+ if ($res){
+ return $res ;
+ }
+ elsif (($errorCode eq $LDAP_SERVER_UNREACHABLE) || ($mustExist)) {
+ my $msg = $conn->getErrorString();
+ printMsg("\n\n*** Failed to search: $DN");
+ printMsg("\n*** Error Msg: $msg, Error code: $errorCode");
+ }
+ return 0;
+ }
+}
+
+
+#############################################################################
+
+sub addEntryToNew{
+ my $entry = shift;
+ my $typeOfEntry = shift;
+ my $trace = shift;
+ my $res = $conn->add($entry);
+ my $DN = $entry->getDN(1);
+ my $cpt = 5;
+ if ($res) {
+ printTrace("\n$typeOfEntry - Add successfull: $DN",$trace);
+ return 1;
+ }
+ else {
+ my $errorCode = $conn->getErrorCode();
+ while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) {
+ printMsg("\ntry to reconnect to add $DN");
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ $res = $conn->add($entry);
+ $errorCode = $conn->getErrorCode();
+ $cpt--;
+ }
+ if ($res){
+ printTrace("\n$typeOfEntry - Add successfull: $DN",$trace);
+ return 1;
+ }
+ else {
+ my $msg = $conn->getErrorString();
+ printMsg("\n\n*** $typeOfEntry: Add Failed: $DN");
+ printMsg("\n*** Error Msg: $msg, Error code: $errorCode");
+ return 0;
+ }
+ }
+}
+
+#############################################################################
+
+sub updateEntry{
+ my $entry = shift;
+ my $typeOfEntry = shift;
+ my $CHECK = shift;
+ my $trace = shift;
+ my $cpt = 5;
+ if ($CHECK) {
+ if (! hasChanged($entry, $typeOfEntry)) {
+ return 1;
+ }
+ }
+ my $res = $conn->update($entry);
+ my $DN = $entry->getDN(1);
+ if ($res) {
+ printTrace("\n$typeOfEntry - Update successfull: $DN",$trace);
+ return 1 ;
+ }
+ else {
+ my $errorCode = $conn->getErrorCode();
+ while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && cpt && (! $res)) {
+ printMsg("\ntry to reconnect to update $DN");
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ $res = $conn->update($entry);
+ $errorCode = $conn->getErrorCode();
+ $cpt--;
+ }
+ if ($res){
+ printTrace("\n$typeOfEntry - Update successfull: $DN",$trace);
+ return 1;
+ }
+ else {
+ my $msg = $conn->getErrorString();
+ printMsg("\n\n*** $typeOfEntry - Update Failed: $DN");
+ printMsg("\n*** Error Msg: $msg, Error code: $errorCode");
+ return 0;
+ }
+ }
+}
+
+
+#############################################################################
+# returns 1 if the entry to migrate and the current entry are different one another
+
+sub hasChanged {
+ my $entry = shift;
+ my $typeOfEntry = shift;
+ my $DN = $entry->getDN(1);
+ my $newEntry = searchEntry($DN,1);
+ return 1 if (! $newEntry); # we shoudn't be in that case ...
+ # do the stuff to check wether the entry has changed or not given its type
+ if (($typeOfEntry eq "DEFAULT_INDEX") || ($typeOfEntry eq "INDEX")){
+ my @indexTypes = $entry->getValues("nsIndexType");
+ my @newIndexTypes = $newEntry->getValues("nsIndexType");
+ my @nsmatchingrules = $entry->getValues("nsmatchingrule");
+ my @newMatchingRules = $newEntry->getValues("nsmatchingrule");
+ return 1 if (Diffs(\@indexTypes, \@newIndexTypes));
+ return 1 if (Diffs(\@nsmatchingrules,\@newMatchingRules));
+ return 0;
+ }
+ if ($typeOfEntry eq "CHANGELOG5"){
+ printTrace("\nCheck wether changelog has changed or not",3);
+ my @params = keys(%changelog5params);
+ foreach $param (@params){
+ my @values = $entry->getValues($param);
+ my @newValues = $newEntry->getValues($param);
+ return 1 if (Diffs(\@values,\@newValues));
+ }
+ return 0;
+ }
+ if ($typeOfEntry eq "SNMP"){
+ foreach $param (@SNMPparams){
+ my @values = $entry->getValues($param);
+ my @newValues = $newEntry->getValues($param);
+ return 1 if (Diffs(\@values,\@newValues));
+ }
+ return 0;
+ }
+ # we don't know how to compare such type of entry => just return 1
+ return 1 ;
+}
+
+sub isAsystemIndex {
+ my $index = shift;
+ return ($index->hasValue("nsSystemIndex","true",1));
+}
+
+
+sub updatePathInPluginArgs {
+ my $plugin = shift;
+ my $argNum = 0;
+ my $argPrefix = "nsslapd-pluginarg";
+ my $cont = 1;
+ my $Unix_oldDir = ${oldDir} ;
+ my $Unix_root = ${root} ;
+ grep { s@\\@/@g } $Unix_oldDir if $isNT;
+ grep { s@\\@/@g } $Unix_root if $isNT;
+ while ($cont) {
+ my $arg = $argPrefix . $argNum ;
+ if ($plugin->exists($arg)) {
+ $_ = $plugin->{$arg}[0] ;
+ s@$Unix_oldDir@$Unix_root@ig ;
+ s/$type-$oldname/$type-$newname/ig ;
+ $plugin->setValues($arg, $_) ;
+ }
+ else {
+ $cont = 0 ;
+ }
+ $argNum++;
+ }
+ return $plugin;
+}
+
+
+sub Diffs {
+ my $valuesToMigrate = shift;
+ my $currentValues = shift;
+ return 1 if (getDiff(\@{$valuesToMigrate},\@{$currentValues}));
+ return 1 if (getDiff(\@{$currentValues},\@{$valuesToMigrate}));
+ return 0 ;
+}
+
+sub getDiff {
+ # we get references to arrays
+ my $elements = shift ;
+ my $existing_elements = shift ;
+ my %count = () ;
+ my %countEE = () ;
+ @diff = () ;
+ foreach $e (@{$elements}, @{$existing_elements}) { $count{$e}++ ;}
+ foreach $e (@{existing_elements}) { $countEE{$e}++ ;}
+ foreach $e (@{$elements}) {
+ # if $e is only present in @$elements, we push it to the diff array
+ if (($count{$e} == 1) && ($countEE{$e} == 0)) {
+ push @diff, $e ;
+ }
+ }
+ return @diff ;
+}
+
+sub registerSuffix_Backend {
+ my $ldbmDatabase = shift;
+ my $CN = $ldbmDatabase->{cn}[0];
+ my $suffixArg = "nsslapd-suffix";
+ my $suffix = $ldbmDatabase->{$suffixArg}[0];
+ $oldBackends{$suffix} = $CN;
+}
+
+
+#############################################################################
+# #
+# #
+# #
+#############################################################################
+sub migrateLDBM_backend_instances {
+ foreach $entry (@LDBM_backend_instances) {
+ my $DN = $entry->getDN(1); # 1 is to normalize the DN
+ my $CN = $entry->{cn}[0];
+ my $expLdif;
+ my $confirm = "No";
+ my $dest = "$serverHome${PATHSEP}db_backup" ;
+ my $newSlapdExecDir = "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server";
+
+ if ($DN =~/cn=netscaperoot,cn=ldbm database/i){
+ printTrace("\n\n*** INFORMATION - NetscapeRoot is NOT migrated",0);
+ }
+ else {
+ if(alreadyExistsInNew($entry)){
+ printMsg("\n\n*** LDBM_BACKEND_INSTANCE - $DN already exists");
+ printMsg("\n*** Migration will overwrite existing database");
+ printMsg("\nDo you want to continue Yes/No [No] ?") ;
+ my $answer = <STDIN> ;
+ if ($answer =~ /y|yes/i) {
+ printMsg("Do you want to export the existing data Yes/No [Yes] ?");
+ my $answer = <STDIN> ;
+ if (!($answer =~ /n|no/i)) {
+ mkdir $dest, 0700 unless (-d $dest);
+ $expLdif = "$dest${PATHSEP}$CN.ldif";
+ while (!($confirm =~ /y|yes/i)) {
+ printMsg("\nEnter the full pathname of the file [$expLdif]:") ;
+ $answer = <STDIN> ;
+ chomp($expLdif = $answer) unless ($answer eq "\n");
+ printMsg("\nExisting data will be exported under $expLdif");
+ printMsg("\nContinue Yes/No [No] ?");
+ $confirm = <STDIN>;
+ }
+ $ENV{"$LIB_PATH"}=$new_libpath;
+ chdir($newSlapdExecDir) or die "\nCould not change directory to $newSlapdExecDir: $!\n";
+ printTrace("\nNow backing up database $CN in $expLdif\n",0);
+ &stopServer($root,'slapd-'.$newname);
+ &db2Ldif($expLdif, $CN, $serverHome);
+ &startServer() unless (isDirectoryAlive());
+ }
+ push @BACKENDS, $CN;
+ } else {
+ printMsg("\n*** Migration will not update it");
+ break;
+ }
+ } else {
+ printTrace("\nWe should add the backend instance $DN",3);
+ my $suffixarg = "nsslapd-suffix" ;
+ my $suffixname= $entry->{$suffixarg}[0] ;
+ my $newEntry = $conn->newEntry() ;
+ $newEntry->setDN($DN);
+ $newEntry->setValues("objectclass", "top", "extensibleObject", "nsBackendInstance" );
+ $newEntry->setValues("cn", $CN );
+ $newEntry->setValues($suffixarg, $suffixname);
+ my @params = keys(%LDBMparamToMigrate);
+ foreach $param (@params) {
+ my @values = $entry->getValues($param);
+ $newEntry->setValues($param, @values) if (@values);
+ }
+ if (addEntryToNew($newEntry, "LDBM_BACKEND_INSTANCE",1)) {
+ push @BACKENDS, $CN;
+ }
+ }
+ }
+ }
+}
+
+sub parseLDBM_backend_instance {
+ my $entry = shift;
+ &registerSuffix_Backend($entry);
+ push @LDBM_backend_instances, $entry;
+}
+
+#############################################################################
+sub migrateMappingTree {
+ foreach $entry (@Mapping_tree_entries) {
+ my $DN = $entry->getDN(1); # 1 si to normalize the DN
+ if ($DN =~/cn=\"o=netscaperoot\",cn=mapping tree,cn=config/i){
+ # DO NOTHING
+ }
+ else {
+ if(alreadyExistsInNew($entry)){
+ printMsg("\n\n*** MAPPING_TREE - $DN already exists");
+ printMsg("\n*** Migration will not add the suffix");
+ }
+ else {
+ addEntryToNew($entry, "MAPPING_TREE",1);
+ }
+ }
+ }
+}
+
+
+sub parseMapping_tree{
+ my $entry = shift;
+ push @Mapping_tree_entries, $entry;
+}
+
+#############################################################################
+sub migrateDefaultIndexes {
+ foreach $index (@default_indexes) {
+ my $CN = $index->{cn}[0];
+ my $newIndex ;
+ if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)})) {
+ if ($newIndex = alreadyExistsInNew($index)) {
+ if (! isAsystemIndex($newIndex)) {
+ updateEntry($index, "DEFAULT_INDEX", 1, 2);
+ }
+ }
+ else {
+ addEntryToNew($index, "DEFAULT_INDEX", 2);
+ }
+ }
+ }
+}
+
+
+sub parseDefaultIndex{
+ my $index = shift;
+ push @default_indexes, $index;
+}
+
+#############################################################################
+
+sub migrateIndexes {
+ foreach $index (@indexes) {
+ my $CN = $index->{cn}[0];
+ my $newIndex;
+ if ((! isAsystemIndex($index)) && (! $deniedIndexes{lc($CN)}) && (DN !~ /cn=netscaperoot,cn=index/i)){
+ if ($newIndex = alreadyExistsInNew($index)) {
+ if (! isAsystemIndex($newIndex)) {
+ updateEntry($index, "INDEX", 1, 2);
+ }
+ }
+ else {
+ addEntryToNew($index, "INDEX", 2);
+ }
+ }
+ }
+}
+
+sub parseIndex{
+ my $index = shift;
+ push @indexes, $index;
+}
+
+#############################################################################
+
+sub newLDIFplugin {
+ my $currentPlugin = shift;
+ my $DN = $currentPlugin->getDN(1);
+ my $newPlugin = $conn->newEntry() ;
+ $newPlugin->setDN($DN);
+ foreach $Attr (@pluginAttrs) {
+ my @values = $currentPlugin->getValues($Attr);
+ $newPlugin->setValues($Attr, @values) if (@values);
+ }
+ return $newPlugin;
+}
+
+sub migrateStdPlugin{
+ my $plugin = shift;
+ my $DN = $plugin->getDN(1);
+ my $pluginEnable = "nsslapd-pluginEnabled";
+ my $argNum = 0;
+ my $argPrefix = "nsslapd-pluginarg";
+ my $currentPlugin ;
+ if ($currentPlugin = alreadyExistsInNew($plugin, 1)) {
+ $plugin = updatePathInPluginArgs($plugin);
+ my $pluginEnableValue = $plugin->{$pluginEnable}[0];
+ my $cont = 1;
+ my $pluginHasChanged = 0;
+ my $newPlugin = &newLDIFplugin($currentPlugin);
+ if (! $currentPlugin->hasValue($pluginEnable,$pluginEnableValue,1)){
+ $newPlugin->setValues($pluginEnable, $pluginEnableValue);
+ $pluginHasChanged = 1 unless ($pluginHasChanged);
+ }
+ while($cont){
+ my $arg = $argPrefix . $argNum ;
+ if ($plugin->exists($arg)) {
+ my @values = $plugin->getValues($arg);
+ my $value = $values[0] ;
+ $newPlugin->setValues($arg, $value) if (@values);
+ if ($currentPlugin->exists($arg)) {
+ if (! $currentPlugin->hasValue($arg,$value,1)) {
+ $pluginHasChanged = 1 unless ($pluginHasChanged);
+ }
+ }
+ else {
+ $pluginHasChanged = 1 unless ($pluginHasChanged);
+ }
+ }
+ else {
+ if ($currentPlugin->exists($arg)) {
+ # Just Warn the user. Do nothing.
+ printTrace("\nCompared to the old instance, the current new plugin $DN belongs this attribute: $arg",2);
+ }
+ else {
+ $cont = 0 ;
+ }
+ }
+ $argNum++;
+ }
+ updateEntry($newPlugin, "STANDARD_PLUGIN", 0, 1) if ($pluginHasChanged);
+ }
+}
+
+#############################################################################
+
+sub migrateConfig_Node{
+ my $config_node = shift;
+ my @params = keys(%GeneralSrvParamToMigrate);
+ my $hasChanged = 0;
+ my $newConfigNode;
+ if ($newConfigNode = alreadyExistsInNew($config_node, 1)){
+ foreach $param (@params) {
+ if ($config_node->exists($param)){
+ my @valuesToMigrate = $config_node->getValues($param);
+ if (@valuesToMigrate){
+ if ($newConfigNode->exists($param)){
+ my @currentValues = $newConfigNode->getValues($param);
+ if (Diffs(\@valuesToMigrate, \@currentValues)) {
+ $newConfigNode->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ printTrace("\nParam to update: $param with value @valuesToMigrate",3);
+ }
+ }
+ else {
+ $newConfigNode->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ printTrace("\nParam to update: $param with value @valuesToMigrate",3);
+ }
+ }
+ }
+ }
+ updateEntry($newConfigNode, "CONFIG_NODE", 0, 1) if ($hasChanged);
+ }
+}
+
+#############################################################################
+
+sub migrateConfig_LDBM_database{
+ my $config_ldbm = shift;
+ my @params = keys(%GlobalConfigLDBMparamToMigrate);
+ my $hasChanged = 0;
+ my $newConfigLdbm ;
+ if ($newConfigLdbm = alreadyExistsInNew($config_ldbm, 1)) {
+ foreach $param (@params) {
+ if ($config_ldbm->exists($param)){
+ my @valuesToMigrate = $config_ldbm->getValues($param);
+ if (@valuesToMigrate){
+ if ($newConfigLdbm->exists($param)){
+ my @currentValues = $newConfigLdbm->getValues($param);
+ if (Diffs(\@valuesToMigrate, \@currentValues)) {
+ $newConfigLdbm->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ else {
+ $newConfigLdbm->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ }
+ }
+ updateEntry($newConfigLdbm, "CONFIG_LDBM_DATABASE", 0, 1) if ($hasChanged);
+ }
+}
+
+#############################################################################
+
+sub migrateChainingBE_config{
+ my $chaining_config = shift;
+ my $DN = $chaining_config->getDN(1);
+ my @params = ();
+ my $hasChanged = 0;
+ my $newChainingConfig;
+ if ($DN =~ /^cn=config,cn=chaining database,cn=plugins,cn=config$/i){
+ $newChainingConfig = searchEntry("cn=config,cn=chaining database,cn=plugins,cn=config");
+ @params = keys(%ChainingConfigParams);
+ }
+ if ($DN =~ /^cn=default instance config,cn=chaining database,cn=plugins,cn=config$/i){
+ $newChainingConfig = searchEntry("cn=default instance config,cn=chaining database,cn=plugins,cn=config");
+ @params = keys(%ChainingDefaultInstanceConfigParams);
+ }
+ foreach $param (@params) {
+ if ($chaining_config->exists($param)){
+ my @valuesToMigrate = $chaining_config->getValues($param);
+ if (@valuesToMigrate){
+ printTrace("\nParam: $param values To migrate: @valuesToMigrate",3);
+ if ($newChainingConfig->exists($param)){
+ my @currentValues = $newChainingConfig->getValues($param);
+ printTrace("\nParam: $param new current values: @currentValues",3);
+ if (Diffs(\@valuesToMigrate, \@currentValues)) {
+ $newChainingConfig->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ else {
+ $newChainingConfig->setValues($param, @valuesToMigrate);
+ $hasChanged = 1 unless ($hasChanged);
+ }
+ }
+ }
+ }
+ updateEntry($newChainingConfig, "CHAINING_BACKEND_CONFIG", 0, 1) if ($hasChanged);
+}
+
+#############################################################################
+
+sub registerSuffix_ChainingBE {
+ my $ldbmDatabase = shift;
+ my $CN = $ldbmDatabase->{cn}[0];
+ my $suffixArg = "nsslapd-suffix";
+ my $suffix = $ldbmDatabase->{$suffixArg}[0];
+ $oldChainingBackends{$suffix} = $CN;
+}
+
+sub storeMultiplexorBindDN {
+ my $chaining_instance = shift;
+ my $DN = $chaining_instance->getDN(1);
+ if ($chaining_instance->exists("nsMultiplexorBindDN")){
+ my $bindDN = $chaining_instance->{nsMultiplexorBindDN}[0];
+ my $newBindDN = searchEntry($bindDN);
+ if (! $newBindDN){
+ # the bindDN entry doesn't yet exist in new => it will have to be migrated
+ $MultiplexorBindDNEntriesToMigrate{$bindDN}="\n" ;
+ printTrace("\nThe bindDN: $bindDN need to be migrated",3);
+ }
+ else {
+ # do nothing as the entry already exists in new
+ }
+ }
+
+}
+
+sub importMultiplexorBindDNEntries {
+ # import all entries present in @MultiplexorBindDNEntriesToMigrate in new
+ my @MultiplexorBindDNs = keys (%MultiplexorBindDNEntriesToMigrate);
+ my $ldif_dir = $ldif_rep;
+ foreach $bindDN (@MultiplexorBindDNs) {
+ printTrace("\nimportMultiplexorBindDNEntries: bindDN to migrate: $bindDN",3);
+ # get the backend in which is stored the bind DN entry
+ my $backendtoExportFrom = getBackendtoExportFrom($bindDN);
+ printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3);
+ # check wether the backend has been imported in new or not
+ if (! alreadyMigrated($backendtoExportFrom)) {
+ if ($backendtoExportFrom ne $NULL) {
+ # if not imported => we need to import the binf DN entry
+ &startServer() unless (isDirectoryAlive());
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir);
+ }
+ else {
+ # do nothing
+ }
+ }
+ }
+ # remove the empty ldif directory
+ rmdir($ldif_dir) if (-d $ldif_dir);
+ # close the LDAP connection to new
+ $conn->close if ($conn);
+}
+
+sub migrateChainingBE_instance{
+ my $chaining_instance = shift;
+ my $DN = $chaining_instance->getDN(1);
+ &registerSuffix_ChainingBE($chaining_instance);
+ if (alreadyExistsInNew($chaining_instance)) {
+ # already exists
+ printMsg("\n\n*** CHAINING_BACKEND_INSTANCE - $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ &migrate_credential($chaining_instance, "nsmultiplexorcredentials");
+ addEntryToNew($chaining_instance, "CHAINING_BACKEND_INSTANCE", 1);
+ storeMultiplexorBindDN($chaining_instance);
+ }
+}
+
+#############################################################################
+
+# create a new LDIF representation of a new replica consumer
+sub newLDIFreplica {
+ my $replica = shift;
+ my $DN = $replica->getDN(1);
+ my $newReplica = $conn->newEntry() ;
+ my $MASTER_OR_MULTIMASTER = "3" ;
+ $newReplica->setDN($DN);
+ foreach $Attr (@nsds5replicaAttrs) {
+ my @values = $replica->getValues($Attr);
+ $newReplica->setValues($Attr, @values) if (@values);
+ }
+ my $replicaType = $replica->{nsDS5ReplicaType}[0];
+ if ($replicaType eq $MASTER_OR_MULTIMASTER) {
+ my @nsState = $replica->getValues("nsState");
+ # nsState omitted because it is incomatible between 32 and 64 bit
+ # servers. Bug 624441
+ # $newReplica->setValues("nsState", @nsState);
+ }
+ else {
+ $newReplica->setValues("nsDS5ReplicaId", $replicaIdvalue);
+ }
+ return $newReplica;
+}
+
+sub MigrateNSDS5_replica{
+ foreach $replica (@new6replicas) {
+ my $DN = $replica->getDN(1);
+ my $newReplica;
+ my @removeAttrs = qw(nsstate nsds5replicaname nsds5replicachangecount);
+ for (@removeAttrs) {
+ $replica->remove($_);
+ }
+ if (alreadyExistsInNew($replica)) {
+ # replica already exists
+ printMsg("\n\n*** NSDS5_REPLICA - $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ $newReplica = &newLDIFreplica($replica);
+ addEntryToNew($newReplica, "NSDS5_REPLICA", 1);
+ }
+ storeReplicaBindDN($replica);
+ }
+}
+
+sub parseNSDS5_replica{
+ my $replica = shift;
+ push @new6replicas, $replica;
+}
+
+sub storeReplicaBindDN {
+ my $replica = shift;
+ my $DN = $replica->getDN(1);
+ if ($replica->exists("nsDS5ReplicaBindDN")){
+ my $bindDN = $replica->{nsDS5ReplicaBindDN}[0];
+ my $newBindDN = searchEntry($bindDN);
+ if (! $newBindDN){
+ # the bindDN entry doesn't yet exist in new => it will have to be migrated
+ $ReplicaBindDNEntriesToMigrate{$bindDN}="\n" ;
+ printTrace("\nThe bindDN: $bindDN need to be migrated",3);
+ }
+ else {
+ # do nothing as the entry already exists in new
+ }
+ }
+}
+
+
+sub importReplicaBindDNEntries {
+ # import all entries present in @ReplicaBindDNEntriesToMigrate in new
+ my @ReplicaBindDNs = keys (%ReplicaBindDNEntriesToMigrate);
+ my $ldif_dir = $ldif_rep;
+ my $replBind_entry = "";
+ my @bindDN_elements = "";
+ my $bindDN_parent = "";
+ my $parentBind_entry = "";
+ foreach $bindDN (@ReplicaBindDNs) {
+ printTrace("\nimportReplicaBindDNEntries: bindDN to migrate: $bindDN",3);
+ # get the backend in which is stored the bind DN entry
+ my $backendtoExportFrom = getBackendtoExportFrom($bindDN);
+ printTrace("\nbackendtoExportFrom is: $backendtoExportFrom",3);
+ # If backend is from config, read the entry from dse.ldif and add to new - NGK
+ if ($backendtoExportFrom eq "cn=config") {
+ my $norm_bindDN = normalizeDN($bindDN);
+ @bindDN_elements = ldap_explode_dn($norm_bindDN, 0);
+# @bindDN_elements = split(/,/,$norm_bindDN);
+ my $junk = shift(@bindDN_elements);
+ if ($#bindDN_elements >= 1) {
+ $bindDN_parent = normalizeDN(join(",", @bindDN_elements));
+ }
+ printTrace("\nOpening DSE.ldif",3);
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF);
+ while ($entry = readOneEntry $in) {
+ my $DN = $entry->getDN(1);
+ if ($DN eq $norm_bindDN) {
+ $replBind_entry = $entry;
+ }
+ if ($bindDN_parent ne "") {
+ if ($DN eq $bindDN_parent) {
+ $parentBind_entry = $entry;
+ }
+ }
+ }
+ close(DSELDIF);
+ &startServer() unless (isDirectoryAlive());
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ if ($bindDN_parent ne "") {
+ addEntryToNew($parentBind_entry, BINDDN_PARENT, 0);
+ }
+ printTrace("\nAdding BindDN with addEntryToNew",3);
+ addEntryToNew($replBind_entry, BINDDN, 0);
+ } else {
+ # check wether the backend has been imported in new or not
+ if (! alreadyMigrated($backendtoExportFrom)) {
+ if ($backendtoExportFrom ne $NULL) {
+ # if not imported => we need to import the bind DN entry
+ &startServer() unless (isDirectoryAlive());
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ &ExportAndAddEntry($bindDN, $backendtoExportFrom, $ldif_dir);
+ }
+ else {
+ # do nothing
+ }
+ }
+ }
+ }
+ # remove the empty ldif directory
+ rmdir($ldif_dir) if (-d $ldif_dir);
+ # close the LDAP connection to new
+ $conn->close if ($conn);
+}
+
+sub alreadyMigrated {
+ my $backendToCheck = shift;
+ foreach $backend (@BACKENDS) {
+ return 1 if ($backend eq $backendToCheck);
+ }
+ return 0 ;
+}
+
+sub belongsSuffix {
+ my $suffix = shift;
+ my $bindDN = shift;
+ return ($bindDN =~ /$suffix\s*$/i);
+}
+
+sub length {
+ my $suffix = shift;
+ my $count = 0;
+ while ($suffix =~ /./g) {
+ $count++;
+ }
+ return $count ;
+}
+
+sub getBackendtoExportFrom {
+ my $bindDN = shift ;
+ my $sizeOfSuffix = 0 ;
+ my $NULL = "";
+ my @oldSuffixes = keys(%oldBackends);
+ my @oldChainingSuffixes = keys(%oldChainingBackends);
+ my $bindDN_backend = $NULL;
+ my $config = "cn=config";
+
+ my $norm_bindDN = normalizeDN($bindDN);
+ # Check if bindDN exists in cn=config - NGK
+ if (belongsSuffix($config,$norm_bindDN)) {
+ $bindDN_backend = $config;
+ printTrace("\ngetBackendtoExportFrom: bindDN_backend: $bindDN_backend",3);
+ } else {
+ foreach $suffix (@oldSuffixes){
+ printTrace("\ngetBackendtoExportFrom: suffix to compare with is: $suffix",3);
+ if ((belongsSuffix($suffix,$norm_bindDN)) && (length($suffix) > $sizeOfSuffix)) {
+ $sizeOfSuffix = length($suffix);
+ $bindDN_backend = $oldBackends{$suffix};
+ printTrace("\ngetBackendtoExportFrom: bindDN_backend: $bindDN_backend, sizeOfSuffix: $sizeOfSuffix",3);
+ }
+ }
+ foreach $suffix (@oldChainingSuffixes){
+ printTrace("\ngetBackendtoExportFrom: suffix to compare with is a chained suffix: $suffix",3);
+ if ((belongsSuffix($suffix,$norm_bindDN)) && (length($suffix) > $sizeOfSuffix)) {
+ printMsg("\n\n*** Entry stored on a remote backend - $norm_bindDN");
+ printMsg("\n*** We don't migrate it");
+ return $NULL;
+ }
+ }
+ }
+ return $bindDN_backend;
+}
+
+
+sub getBackendtoImportTo {
+ my $bindDN = shift;
+ my $sizeOfSuffix = 0;
+ my $NULL = "";
+ my $suffixArg = "nsslapd-suffix";
+ my $bindDN_backend = $NULL;
+ open( DSELDIF, "< $DSEldif" ) || die "Can't open $DSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ $typeOfEntry = getTypeOfEntry($entry);
+ if ($typeOfEntry eq "LDBM_BACKEND_INSTANCE"){
+ my $suffix = $entry->{$suffixArg}[0];
+ if ((belongsSuffix($suffix,$bindDN)) && (length($suffix) > $sizeOfSuffix)) {
+ $sizeOfSuffix = length($suffix);
+ $bindDN_backend = $entry->{cn}[0];
+ }
+ }
+ }
+ close(DSELDIF);
+ return $bindDN_backend ;
+}
+
+
+sub ExportAndAddEntry {
+ my $DN = shift;
+ my $backendtoExportFrom = shift;
+ my $ldif_dir = shift;
+ my $ldif = "$ldif_dir${PATHSEP}$backendtoExportFrom.ldif" ;
+ # first: export entry pointed out by the $DN to $ldif file
+ $ENV{"$LIB_PATH"}=$old_libpath;
+ if (! $ldif_dir) { $ldif_dir = $ldif_rep ;}
+ if (!(-d $ldif_dir)) {
+ mkdir($ldif_dir,0777) or die "\ncan't create $ldif_dir to store temporary ldif files\n";
+ }
+ chdir($oldSlapdExecDir) or die "\nCould not change directory to $oldSlapdExecDir: $!\n";
+ &db2Ldif($ldif, $backendtoExportFrom, $oldHome, $DN);
+ chdir($curdir) or die "\nCould not change directory to $curdir: $!\n";
+
+ # then: Add it to new
+ if (! $conn) {
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ }
+ open( BINDDNLDIF, "< $ldif" ) || die "\nCan't open $ldif: $!: \n";
+ my $in = new Mozilla::LDAP::LDIF(*BINDDNLDIF) ;
+ while ($entry = readOneEntry $in) {
+ my $entryDN = $entry->getDN(1);
+ if ($DN eq $entryDN) {
+ addEntryToNew($entry, "nsds5ReplicaBindDN", 0);
+ }
+ }
+ close(BINDDNLDIF);
+ # remove the ldif file after the import
+ unlink($ldif) ;
+}
+
+#############################################################################
+sub MigrateNSDS_replication_agreement {
+ foreach $replicationAgreement (@replicationAgreements) {
+ my $DN = $replicationAgreement->getDN(1);
+ if (alreadyExistsInNew($replicationAgreement)){
+ # replication agreement already exists
+ printMsg("\n\n*** NSDS_REPLICATION_AGREEMENT - $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ &migrate_credential($replicationAgreement, "nsDS5ReplicaCredentials");
+ addEntryToNew($replicationAgreement, "NSDS_REPLICATION_AGREEMENT", 1);
+ }
+ }
+}
+
+
+sub parseNSDS_replication_agreement{
+ my $replicationAgreement = shift;
+ push @replicationAgreements, $replicationAgreement ;
+}
+
+#############################################################################
+
+sub migrateChangelog5{
+ my $changelog = shift;
+ my $DN = $changelog->getDN(1);
+ my $changelogdir = "nsslapd-changelogdir";
+ if (alreadyExistsInNew($changelog)){
+ # cn=changelog5,cn=config already exists in new
+ my $newChangelog = searchEntry($DN);
+ my @newChangelogdir = $newChangelog->getValues($changelogdir);
+ $changelog->setValues($changelogdir, @newChangelogdir);
+ updateEntry($changelog, "CHANGELOG5", 0, 1);
+ }
+ else {
+ # cn=changelog5,cn=config need to be created in new.
+ # the changelogdir value must be setup to <new_root_server>/slapd-instance/changelogdb
+ $changelog->setValues($changelogdir,"${serverHome}${PATHSEP}changelogdb");
+ addEntryToNew($changelog, "CHANGELOG5", 1);
+ }
+}
+
+
+sub migrateChangelog {
+ my $oldchangelogdir = "";
+ my $newchangelogdir = "";
+ my $changelogdir = "nsslapd-changelogdir";
+ my $CL5DN = "cn=changelog5,cn=config";
+ printTrace("\n\n***** Migrate Changelog...",0,1);
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF);
+ while ($entry = readOneEntry $in) {
+ $typeOfEntry = getTypeOfEntry($entry);
+ if ($typeOfEntry eq "CHANGELOG5"){
+ $oldchangelogdir = ($entry->getValues($changelogdir))[0];
+ }
+ }
+ close(DSELDIF);
+ if ($oldchangelogdir) {
+ # If using olddatadir to migrate from, the path of the changelogdb
+ # from the dse.ldif may not match the path where the old server
+ # root was archived. We may need to modify oldchangelogdir so the
+ # copy of the changelog files succeeds.
+ unless(-e $oldchangelogdir) {
+ if($olddatadir) {
+ my @cldbpath = split(/\//,$oldchangelogdir);
+ until($cldbpath[0] =~/^slapd-/) {
+ shift(@cldbpath);
+ }
+ my $tmpcldbpath = join(${PATHSEP}, @cldbpath);
+ $oldchangelogdir = "$oldDir${PATHSEP}$tmpcldbpath";
+ }
+ # If oldchangelogdir still looks to be wrong, prompt for the
+ # location instead of just failing on the copydir operation
+ # and bombing out of the migration.
+ unless(-e $oldchangelogdir) {
+ print("\n\nThe old changelog directory \"$oldchangelogdir\" doesn't exist. Please enter the correct path: ");
+ $oldchangelogdir = <STDIN>;
+ }
+ }
+ &startServer() unless (isDirectoryAlive());
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ my $newChangelog = searchEntry($CL5DN);
+ $newchangelogdir = ($newChangelog->getValues($changelogdir))[0];
+ stopServer($root,'slapd-'.$newname);
+ printTrace("\ncopying $oldchangelogdir${PATHSEP}* to $newchangelogdir",3);
+ copyDir("$oldchangelogdir","$newchangelogdir");
+
+ # We need to modify the DBVERSION file for a new verision of the db
+ open(DBVERSION,">$newchangelogdir${PATHSEP}DBVERSION") || die "Can't overwrite $newchangelogdir${PATHSEP}DBVERSION: $! ";
+ print DBVERSION "Changelog5/NSMMReplicationPlugin/3.0";
+ close(DBVERSION);
+
+ &startServer() unless (isDirectoryAlive());
+ }
+}
+
+#############################################################################
+
+sub migrateReplication{
+ my $replication = shift;
+ my $DN = $replication->getDN(1);
+ if (alreadyExistsInNew($replication)){
+ # replication agreement already exists
+ printMsg("\n\n*** $DN already exists");
+ printMsg("\n*** Migration will not update it");
+ }
+ else {
+ addEntryToNew($replication, "REPLICATION", 1);
+ }
+}
+
+#############################################################################
+
+sub migrateSecurity{
+ my $security = shift;
+ if ($entry->hasValue("objectClass", "nsEncryptionConfig")) {
+ my $certfile = "alias/slapd-" . $newname . "-cert8.db";
+ my $keyfile = "alias/slapd-" . $newname. "-key3.db";
+ $entry->setValues("nsCertfile",$certfile) if ! $entry->hasValue("nsCertfile",$certfile);
+ $entry->setValues("nsKeyfile",$keyfile) if ! $entry->hasValue("nsKeyfile",$keyfile);
+ }
+ if (alreadyExistsInNew($security)){
+ # already exists in new
+ updateEntry($security, "SECURITY", 0, 1);
+ }
+ else {
+ addEntryToNew($security, "SECURITY", 1);
+ }
+}
+
+#############################################################################
+
+sub migrateSNMP{
+ my $snmp = shift;
+ if (alreadyExistsInNew($snmp)){
+ # already exists in new
+ updateEntry($snmp, "SNMP", 0, 1);
+ }
+ else {
+ addEntryToNew($snmp, "SNMP", 1);
+ }
+}
+
+#############################################################################
+# printMsg print message to the user standard output.
+
+sub printMsg {
+
+ my $TypeMsg = shift ;
+ my $Msg = shift ;
+ my $LineNb = shift ;
+ if ($LineNb) {
+ printTrace("Line: $LineNb, $TypeMsg, $Msg");
+ }
+ else {
+ printTrace("$TypeMsg $Msg");
+ }
+}
+
+#############################################################################
+# print message error to the user standard output.
+
+sub printTrace {
+
+ my $Msg = shift ;
+ my $level = shift ;
+ my $sep = shift ;
+
+ if ($sep) {
+ print "\n-------------------------------------------------------------------------";
+ print LOGFILE "\n-------------------------------------------------------------------------";
+ }
+
+ if ($level <= $TRACELEVEL) {
+ print($Msg);
+ print LOGFILE $Msg ;
+ }
+}
+
+#############################################################################
+# this subroutine implements a very stupid version of diff
+
+sub diff {
+ my $f1 = shift;
+ my $f2 = shift;
+ my $lineToBeginWith = shift;
+ my $NULL = "" ;
+ my $diff_f1 = $NULL ;
+ my $diff_f2 = $NULL ;
+ my $retval = $NULL ;
+ my $ret;
+ open(F1, "$f1") or die "Could not open file $f1";
+ open(F2, "$f2") or close(F1), die "Could not open file $f2";
+
+ while (defined($l1 = <F1>)) {
+ if ($lineToBeginWith){
+ $lineToBeginWith -- ;
+ next ;
+ }
+ next if ($l1 =~ /^\#/);
+ $ret = defined($l2 = <F2>);
+ if ($ret) {
+ $ret = defined($l2 = <F2>) while ($ret && ($l2 =~ /^\#/)) ;
+ if ($ret) {
+ if (!($l1 eq $l2)) {
+
+ # ignore whitespace
+ $l1_clean = $l1 ;
+ $l2_clean = $l2 ;
+ $l1_clean =~ s/\s//g;
+ $l2_clean =~ s/\s//g;
+
+ if (!($l1_clean eq $l2_clean)) {
+ $diff_f1 .= "${l1}" unless ($l1_clean eq $NULL);
+ $diff_f2 .= "${l2}" unless ($l2_clean eq $NULL);
+ }
+ }
+ }
+ else {
+ next if ($l1 =~ /^\s*$/) ;
+ $diff_f1 .= "${l1}";
+ }
+ }
+ else {
+ next if ($l1 =~ /^\s*$/) ;
+ $diff_f1 .= "${l1}";
+ }
+ }
+
+ while (defined($l2 = <F2>)) {
+ if (($l2 =~ /^\#/) || ($l2 =~ /^\s*$/)) {
+ next ;
+ }
+ else {
+ $diff_f2 .= "${l2}" ;
+ }
+ }
+
+ close(F1);
+ close(F2);
+
+ $retval .= "- differences present in your config file but not in standard file:\n\n". "$diff_f1\n" if ($diff_f1) ;
+ $retval .= "- differences present in standard file but not in your config file:\n\n" . "$diff_f2" if ($diff_f2) ;
+ return $retval ;
+}
+
+sub CompareStdConfigFiles {
+ # Compare each configuration file against its default version. If it has changed,
+ # notify the user that the file has changed and will need to be checked by the
+ # user. This should be safe to do because there should be no path information
+ # stored in these conf files, which are just schema stuff.
+ # printTrace("\nCheck if standard configuration files have changed",3);
+
+ # get the version of the DS to migrate
+ ($oldVersion, $oldMinor) = &getVersion($oldDir, $oldversionstr);
+ # get the version of the new DS
+ ($Version, $Minor) = &getVersion($root);
+
+ # get old LIB_PATH
+ $old_libpath = &getLibPath($oldDir, $oldVersion, $oldMinor);
+ # get new LIB_PATH
+ $new_libpath = &getLibPath($root, $Version, $Minor);
+
+ my $origFilePath = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}install${PATHSEP}schema${PATHSEP}" ;
+ my $FilesChanged = "";
+ my $AllDiffs = "***********************************************************************";
+ my $NoChanges = "" ;
+ my $lineToBegin = 0 ;
+ opendir(CONFDIR, $oldSchemaDir) or
+ die "Error: could not open migrated config dir $oldConfDir: $!";
+
+ foreach $file (readdir(CONFDIR)) {
+ $origFile = $origFilePath . $file ;
+ $configFile = $oldSchemaDir . $file ;
+ if (( exists($stdIncludes{lc($file)})) && (-f $origFile)) {
+ $diffs = &diff($configFile, $origFile, $lineToBegin);
+ $lineToBegin = 0 if $lineToBegin ;
+ if ($diffs) {
+ $FilesChanged .= "\n$configFile";
+ $AllDiffs .= "\n$configFile is different than the standard configuration file" ;
+ $AllDiffs .= "\nYou will need to check this file and make sure its changes are compatible ";
+ $AllDiffs .= "with the new directory server\nHere are the differences:\n";
+ $AllDiffs .= "$diffs \n\n";
+ $AllDiffs .= "***********************************************************************";
+ }
+ else {
+ $NoChanges .= "\n$configFile";
+ }
+ }
+ }
+ closedir(CONFDIR);
+
+if ($FilesChanged) {
+ printTrace("\nNo changes to old configuration files:$NoChanges",3) ;
+ printTrace("\n***********************************************************************",3) ;
+ printMsg("\nThe following standard files have been modified: $FilesChanged");
+ if ($NO_INPUT_USER) {
+ # do nothing
+ }
+ else {
+ printMsg("\nDo you want to see the differences Yes/No [No] ?") ;
+ my $answer = <STDIN> ;
+ if ($answer =~ /y|yes/i) {
+ printMsg("$AllDiffs");
+ }
+ printMsg("\nDo you want to continue the migration Yes/No [No] ?");
+ $answer = <STDIN> ;
+ if (! ($answer =~ /y|yes/i)) {
+ exit(1);
+ }
+ }
+ }
+}
+
+
+
+#############################################################################
+
+# this is used to run the system() call, capture exit and signal codes,
+# and die() upon badness; the first argument is a directory to change
+# dir to, if any, and the rest are passed to system()
+sub mySystem {
+ my $rc = &mySystemNoDie(@_);
+ my ($dir, @args) = @_;
+ if ($rc == 0) {
+# success
+ } elsif ($rc == 0xff00) {
+ die "Error executing @args: error code $rc: $!";
+ } elsif ($rc > 0x80) {
+ $rc >>= 8;
+ die "Error executing @args: error code $rc: $!";
+ } else {
+ if ($rc & 0x80) {
+ $rc &= ~0x80;
+ }
+ die "Error executing @args: received signal $rc: $!";
+ }
+
+ # usually won't get return value
+ return $rc;
+}
+
+# This version does not die but just returns the error code
+sub mySystemNoDie {
+ my ($dir, @args) = @_;
+ if ($dir && ($dir ne "")) {
+ chdir($dir) or die "Could not change directory to $dir: $!";
+ }
+ my $cmd = $args[0];
+ # the system {$cmd} avoids some NT shell quoting problems if the $cmd
+ # needs to be quoted e.g. contains spaces; the map puts double quotes
+ # around the arguments on NT which are stripped by the command
+ # interpreter cmd.exe; but don't quote things which are already quoted
+ my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args;
+ my $rc = 0;
+ if ($cmd =~ /[.](bat|cmd)$/) {
+ # we have to pass batch files directly to the NT command interpreter
+ $cmd = $com_spec;
+# print "system $cmd /c \"@fixargs\"\n";
+ $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\"";
+ } else {
+# print "system $cmd @fixargs\n";
+ $rc = 0xffff & system {$cmd} @fixargs;
+ }
+ chdir(${curdir}) or die "Could not change directory to $curdir: $!";
+ return $rc;
+}
+
+###########################################################################################
+# #
+# Export/Import of the backends in @BACKENDS #
+# #
+###########################################################################################
+
+sub manydb2Ldif {
+ my $ldif_dir = shift;
+ $ENV{"$LIB_PATH"}=$old_libpath;
+ if (! $ldif_dir) { $ldif_dir = $ldif_rep ;}
+ if (!(-d $ldif_dir)) {
+ mkdir($ldif_dir,0777) or die "can't create $ldif_dir to store temporary ldif files";
+ }
+ chdir($oldSlapdExecDir) or die "Could not change directory to $oldSlapdExecDir: $!";
+ foreach $backend (@BACKENDS) {
+ my $ldif = "${ldif_dir}$backend.ldif" ;
+ &db2Ldif($ldif, $backend, $oldHome);
+ }
+ print " Done.\n";
+ chdir($curdir) or die "Could not change directory to $curdir: $!";
+}
+
+sub db2Ldif {
+ my $ldif = shift ;
+ my $backend = shift ;
+ my $home = shift ;
+ my $include_suffix = shift ;
+ my $db2ldif_param ;
+ if ($include_suffix) {
+ $db2ldif_param = "db2ldif -r -D $home -n $backend -a $ldif -s \"$include_suffix\"";
+ }
+ else {
+ $db2ldif_param = "db2ldif -r -D $home -n $backend -a $ldif";
+ }
+ open(DB2LDIF, "${quote}${quote}$slapdExecName${quote} $db2ldif_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n";
+ sleep(1); # allow some data to accumulate in the pipe
+ my $ii = 0;
+ while (<DB2LDIF>) {
+ ++$ii;
+ if (($ii % 250) == 0) {
+ printMsg(" Processing...\n");
+ }
+ printMsg($_);
+ }
+ close(DB2LDIF);
+ # set the ownership of the ldif file; should be the same as the 6.x slapd user id
+ if ((! $isNt) && ($oldlocaluser ne $localuser)) {
+ if (-f $ldif) {
+ chown( $newuid, $newgid, $ldif) or printMsg("\nUnable to change the ownership of $ldif to $localuser") ;
+ }
+ }
+}
+
+sub manyLdif2db {
+ my $ldif_dir = shift;
+ $ENV{"$LIB_PATH"}=$new_libpath;
+ chdir($slapdExecDir) or die "Could not change directory to $slapdExecDir: $!";
+ foreach $backend (@BACKENDS) {
+ my $ldif = "${ldif_dir}$backend.ldif" ;
+ &Ldif2db($ldif, $backend);
+ }
+ # remove the empty ldif directory
+ # but not if using the data dir
+ if (!$olddatadir) {
+ rmdir($ldif_dir);
+ }
+ chdir($curdir) or die "Could not change directory to $curdir: $!";
+}
+
+
+sub Ldif2db {
+ my $ldif = shift ;
+ my $backend = shift ;
+ my $ldif2db_param = "ldif2db -D $serverHome -n $backend -i $ldif";
+ open(LDIF2DB, "${quote}${quote}$slapdExecName${quote} $ldif2db_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n";
+ sleep(1); # allow some data to accumulate in the pipe
+ while (<LDIF2DB>) {
+ printMsg($_);
+ }
+ close(LDIF2DB);
+ # remove the ldif file after the import
+ # but not if using the data dir
+ if (!$olddatadir) {
+ unlink($ldif) ;
+ }
+}
+
+
+###########################################################################################
+# #
+# Running/Stopping the Server #
+# #
+###########################################################################################
+
+
+
+sub isDirectoryAlive {
+ die "\n Migration aborted. Make sure your old and new Directory Servers are installed on the same machine \n" if ( $LDAPservername == -1 );
+ my $test_conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd);
+ if ($test_conn) {
+ $test_conn->close();
+ return 1;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+
+sub startServer {
+ my $instanceDir = ${serverHome} ;
+ my $errLog = $instanceDir . $PATHSEP . 'logs' . $PATHSEP . 'errors';
+ # emulate tail -f
+ # if the last line we see does not contain "slapd started", try again
+ my $done = 0;
+ my $started = 0;
+ my $code = 0;
+ my $lastLine = "";
+ my $timeout = time + 240; # 4 minutes
+ $ENV{"$LIB_PATH"}=$new_libpath;
+
+ my $startCmd = $instanceDir . $PATHSEP . 'start' . $script_suffix;
+ if (! -f $startCmd) {
+ $startCmd = $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix;
+ }
+ $code = &mySystem($instanceDir,$startCmd);
+ open(IN, $errLog) or die "Could not open error log $errLog: $!";
+ my $pos = tell(IN);
+ while (($done == 0) && (time < $timeout)) {
+ for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) {
+ $lastLine = $_;
+ # print;
+ # the server has already been started and shutdown once . . .
+ if (/slapd started\./) {
+ $started++;
+ if ($started == 2) {
+ $done = 1;
+ }
+ # sometimes the server will fail to come up; in that case, restart it
+ } elsif (/Initialization Failed/) {
+ # print "Server failed to start: $_";
+ $code = &mySystem($instanceDir, $startCmd);
+ # sometimes the server will fail to come up; in that case, restart it
+ } elsif (/exiting\./) {
+ # print "Server failed to start: $_";
+ #$code = &mySystem($startCmd);
+ $code = &mySystem($instanceDir, $startCmd);
+ }
+ }
+ if ($lastLine =~ /PR_Bind/) {
+ # server port conflicts with another one, just report and punt
+ print $lastLine;
+ print "This server cannot be started until the other server on this\n";
+ print "port is shutdown.\n";
+ $done = 1;
+ }
+ if ($done == 0) {
+ # rest a bit, then . . .
+ sleep(2);
+ # . . . reset the EOF status of the file desc
+ seek(IN, $pos, 0);
+ }
+ }
+ close(IN);
+
+ sleep(5);
+ die "\nUnable to start the $Version.$Minor Directory Server\n" unless (isDirectoryAlive());
+
+ return 0;
+}
+
+sub stopServer {
+ my $root = shift;
+ my $name = shift;
+ $maxStopIterations = 5;
+ print "\nShutting down server $name . . .\n";
+ $ENV{"$LIB_PATH"}=$new_libpath;
+ $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop' . $script_suffix . $quote;
+ if (! -f $stopCmd) {
+ $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop-slapd' . $script_suffix . $quote;
+ }
+
+ if (! -f $stopCmd) {
+ # no stop command, probably a 1.X system; for NT, we'll try net stop
+ # for unix, we'll get the pid and kill it
+ if ($isNT) {
+ $stopCmd = 'net stop ' . $name;
+ } else {
+ # see if there is a pid file
+ $pidfile = $root . $PATHSEP . $name . $PATHSEP . 'logs' .
+ $PATHSEP . 'pid';
+ if (open(PIDFILE, $pidfile)) {
+ chomp($pid = <PIDFILE>);
+ close(PIDFILE);
+ while ($maxStopIterations-- && !$exitCode) {
+ $exitCode = kill(15, $pid);
+ }
+ $stopCmd = undef;
+ }
+ }
+ }
+
+ # keep looping until the stop cmd returns an error code, which usually
+ # means that what ever we want to stop is stopped, or some other error
+ # occurred e.g. permission, or no such service
+ $exitCode = &runAndIgnoreOutput($stopCmd);
+# print "stopServer: exitCode=$exitCode\n";
+ while ($stopCmd && $maxStopIterations-- && $exitCode) {
+ $exitCode = &runAndIgnoreOutput($stopCmd);
+# print "stopServer: exitCode=$exitCode\n";
+ }
+
+ if (!$maxStopIterations) {
+ print "Warning: could not shutdown the server: $!\n";
+ }
+ sleep(10) ;
+ $exitCode = 0;
+}
+
+
+sub runAndIgnoreOutput {
+ my $cmd = shift;
+ printMsg(".");
+ open(RUNCMD, "${quote}$cmd${quote} 2>&1 |") or die "Error: could not run $cmd: $!";
+ printMsg(".");
+ sleep(1); # allow pipe to fill with data
+ printMsg(".");
+ while (<RUNCMD>) {
+# print;
+ }
+ my $code = close(RUNCMD);
+# print "runAndIgnore: code=$code status=$?\n";
+ return $?;
+}
+
+#############################################################################
+# migrate SSL info
+
+sub MigrateSSL {
+ my $secPwd = 'bidon' ;
+ # copy the SSL directory
+ &copyDir("$oldHome${PATHSEP}ssl","$serverHome${PATHSEP}ssl") if (-d "$oldHome${PATHSEP}ssl");
+ # copy the cert db and key files
+ if ( -d "$oldDir${PATHSEP}alias") {
+ $aliasDir = "$root${PATHSEP}alias";
+ if (! -d $aliasDir) {
+ mkdir($aliasDir, 0750);
+ }
+ &stopServer($root,'slapd-'.$newname);
+ my $keydb = "$aliasDir${PATHSEP}slapd-$newname-key3.db" ;
+ my $certdb = "$aliasDir${PATHSEP}slapd-$newname-cert8.db" ;
+ my $certdb7 = "$aliasDir${PATHSEP}slapd-$newname-cert7.db" ;
+ my $old_keydb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-key3.db" ;
+ my $old_certdb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-cert7.db";
+ my $keydb_backup = "$aliasDir${PATHSEP}slapd-$newname-key3.db_backup" ;
+ my $certdb_backup = "$aliasDir${PATHSEP}slapd-$newname-cert7.db_backup" ;
+ if (-f $old_keydb) {
+ if (-f $keydb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$keydb already exists. backup in $keydb_backup ...");
+ &copyBinFile($keydb,$keydb_backup);
+ &copyBinFile($old_keydb,$keydb);
+ }
+ else {
+ print("\n\n$keydb already exists. Do you want to overwrite it ? [no]: ");
+ my $answer = <STDIN> ;
+ if ($answer =~ /^y|yes$/i) {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ if (-f $old_certdb) {
+ $mode = (stat($old_certdb))[2] if $PRESERVE;
+ if (-f $certdb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$certdb already exists. backup in $certdb_backup ...");
+ &copyBinFile($certdb,$certdb_backup);
+ unlink($certdb) || print "Couldn't delete $certdb : $!\n";
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ else {
+ print("\n\n$certdb already exists. Do you want to overwrite it ? [no]: ");
+ my $answer = <STDIN> ;
+ if ($answer =~ /^y|yes$/i) {
+ unlink($certdb) || print "Couldn't delete $certdb : $!\n";
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ # copy the old password file
+ if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") {
+ &copyBinFile(
+ "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt",
+ "$aliasDir${PATHSEP}$type-$newname-pin.txt"
+ );
+ }
+ &startServer();
+ if ($PRESERVE) {
+ chown($newuid,$newgid,$certdb) || print "Failed to set uid $newuid gid $newgid on $certdb : $!\n";
+ chmod($mode,$certdb) || print "Failed to set mode $mode on $certdb : $!\n";
+ }
+ }
+
+}
+
+sub DisableSSL {
+ my $entry = $conn->search("cn=config","base","objectclass=*");
+ my $LDAPparam = "nsslapd-security" ;
+ my $Value = "off" ;
+ if ($entry->{$LDAPparam}[0] ne $Value) {
+ printTrace("\nDisable SSL...",1);
+ $entry->setValues($LDAPparam, $Value);
+ }
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nSSL disabled",2);
+ }
+ else {
+ printMsg("\nCan't disabled SSL. The server may have problems to start");
+ }
+}
+
+# enable the migration of client authentication informations
+sub MigrateCertmap {
+ # backup the old certmap.conf and replace it with the new one
+ my $oldCertmap = "$oldDir${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf";
+ my $newCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf" ;
+ my $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ;
+ if (-f $oldCertmap) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$newCertmap has been backup in $backupCertmap");
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($oldCertmap,$newCertmap);
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\n\nWhere do you want to back up the file $newCertmap [$backupCertmap] ?") ;
+ my $Answer = <STDIN> ;
+ $backupCertmap = $Answer if ($Answer ne "\n");
+ chomp($backupCertmap);
+ printTrace("\nDest: .$backupCertmap.",4);
+ if (-e $backupCertmap) {
+ printMsg("\n\n$backupCertmap already exists. Do you want to overwrite it Yes/No [No] ?") ;
+ if (<STDIN> =~ /yes|y/i) {
+ $Ask = 0 ;
+ }
+ else {
+ $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ;
+ }
+ }
+ else {
+ $Ask = 0 ;
+ }
+ }
+ printTrace("\nBackup file: $newCertmap in $backupCertmap",4);
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($oldCertmap,$newCertmap);
+ }
+ }
+ else {
+ }
+}
+
+sub hasChangedoldCertmap {
+ my $certmapfile = shift ;
+ my @reference = ("certmap default default",
+ "default:DNComps",
+ "default:FilterComps e") ;
+ my $cpt = 0 ;
+ printTrace("\nhasChangedoldCertmap",3);
+ open(CERTMAP,"< $certmapfile");
+ while (<CERTMAP>) {
+ if ((! /^\s*#/) && (! /^\s*$/)) {
+ my $ref = $reference[$cpt] ;
+ printTrace("\nValue: $_, ref: $ref",4);
+ if (! /^\s*$ref\s*$/) {
+ return 1 ;
+ }
+ else {
+ $cpt++ ;
+ }
+ }
+ }
+ close (CERTMAP);
+ printTrace("\ncpt: $cpt",4);
+ if ($cpt < $#reference) {
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+
+###########################################################################################
+# #
+# Copy directory and files functions #
+# #
+###########################################################################################
+
+
+sub copyDir {
+ my $src = shift;
+ my $dest = shift;
+ my $exclude = shift;
+
+ opendir( SRC, $src ) or die "Can't open directory $src: $!: ";
+ my $mode;
+ my $uid;
+ my $gid;
+ mkdir ( $dest , 0755 ) or die "\nCan't create directory $dest. \nPlease check you have enough rights to create it and/or check that your parent directory exists.\n" if !( -e $dest );
+ if ($PRESERVE) {
+ $mode = (stat($src))[2];
+ ($uid, $gid) = (stat(_))[4..5];
+ # Make sure files owned by the old user are owned by the
+ # new user
+ if ($uid == $olduid) {
+ $uid = $newuid;
+ $gid = $newgid;
+ }
+ chown $uid, $gid, $dest;
+ chmod $mode, $dest;
+ }
+ local ( @files ) = readdir ( SRC );
+ closedir( SRC );
+ for ( @files ) {
+ if ( $_ eq "." || $_ eq ".." ) {
+ next;
+ } elsif ( $exclude && /$exclude/ ) {
+ next;
+ } elsif ( $_ =~ /^__/ ) {
+ # region files are incompatible between 32
+ # and 64 bit servers
+ next;
+ } elsif( -d "$src${PATHSEP}$_") {
+ &copyDir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" );
+ } else {
+ &copyBinFile ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_");
+ }
+ }
+}
+
+sub copyBinFile {
+ my $src = shift;
+ my $dest = shift;
+ my $buf = "";
+ my $bufsize = 8192;
+
+ open( SRC, $src ) || die "Can't open $src: $!\n";
+ # if we are given a directory destination instead of a file, extract the
+ # filename portion of the source to use as the destination filename
+ if (-d $dest) {
+ $dest = $dest . $PATHSEP . &basename($src);
+ }
+ open( DEST, ">$dest" ) || die "Can't create $dest: $!\n";
+ binmode SRC;
+ binmode DEST;
+ if ($PRESERVE) {
+ $mode = (stat($src))[2];
+ ($uid, $gid) = (stat(_))[4..5];
+ # Make sure files owned by the old user are owned by the
+ # new user
+ if ($uid == $olduid) {
+ $uid = $newuid;
+ $gid = $newgid;
+ }
+ chown $uid, $gid, $dest;
+ chmod $mode, $dest;
+ }
+ while (read(SRC, $buf, $bufsize)) {
+ print DEST $buf;
+ }
+ close( SRC );
+ close( DEST );
+}
+
+#############################################################################################################
+# backup 6.x configuration files #
+# backup the directory <root_server5>/slapd-instance/config dans <root_server5>/slapd-instance/BackupConfig # #
+# #
+#############################################################################################################
+
+
+sub backupConfigFiles {
+ # backup the 6.x config files
+ my $src = "$serverHome${PATHSEP}config" ;
+ my $dest = "$serverHome${PATHSEP}config_backup" ;
+ if ($NO_INPUT_USER) {
+ printMsg("\n$src has been backup in $dest");
+ &copyDir($src,$dest);
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\n\nWhere do you want to back up your configuration directory [$dest] ?") ;
+ my $Answer = <STDIN> ;
+ $dest = $Answer if ($Answer ne "\n");
+ chomp($dest);
+ printTrace("\nDest: .$dest.",4);
+ if (-e $dest) {
+ printMsg("\n\n$dest already exists. Do you want to overwrite it Yes/No [No] ?") ;
+ if (<STDIN> =~ /yes|y/i) {
+ $Ask = 0 ;
+ }
+ else {
+ $dest = "$serverHome${PATHSEP}config_backup" ;
+ }
+ }
+ else {
+ $Ask = 0 ;
+ }
+ }
+ printTrace("\nBackup Directory: $src in $dest",4);
+ &copyDir($src,$dest);
+ }
+}
+#############################################################################
+
+sub getLDAPservername {
+ my $oldLDAPservername;
+ my $LDAPservername;
+ my $localhost = "nsslapd-localhost";
+ open(OLDDSELDIF, "< $oldDSEldif") or die "\nError: could not open old config file $oldDSEldif \n";
+ my $in = new Mozilla::LDAP::LDIF(*OLDDSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ my $DN = $entry->getDN(1) ;
+ if ($DN =~ /^cn=config$/i) {
+ my @values = $entry->getValues($localhost);
+ if ($entry->size($localhost)) {
+ $oldLDAPservername = $values[0];
+ printTrace("\nName of the old LDAP server: $oldLDAPservername",3);
+ }
+ break;
+ }
+ }
+ close(OLDSELDIF);
+
+ open( DSELDIF, "< $DSEldif" ) || die "\nCan't open $DSEldif \n";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ my $DN = $entry->getDN(1) ;
+ if ($DN =~ /^cn=config$/i) {
+ my @values = $entry->getValues($localhost);
+ if ($entry->size($localhost)) {
+ $LDAPservername = $values[0];
+ printTrace("\nName of the new LDAP server: $LDAPservername",3);
+ }
+ break;
+ }
+ }
+ close(DSELDIF);
+ # check ol and new Directory Instance are installed on the same physical machine.
+ if (lc($oldLDAPservername) ne lc($LDAPservername)) {
+ # warn the user he tries to migrate a 4.x server installed on a different machine from the 6.x one
+ printMsg("\n\nYour old instance is on $oldLDAPservername, whereas your new instance is on $LDAPservername. Migration on different machines is not supported. Do you want to continue ? Yes/No [No]:") ;
+ if (! (<STDIN> =~ /yes|y/i)) {
+ return -1;
+ }
+ }
+ return $LDAPservername ;
+}
+
+#############################################################################
+
+sub getLibPath {
+ my $myDir = shift;
+ my $myVersion = shift;
+ my $myMinor = shift;
+
+ if ($isNT) {
+ return $ENV{"$LIB_PATH"};
+ }
+ if (($myVersion >= 6) && ($myMinor >= 2)) {
+ return
+ "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}".
+ "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}".
+ $ENV{"$LIB_PATH"};
+ } else {
+ return "$myDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ }
+}
+
+#############################################################################
+
+sub getVersion {
+ my $dir = shift;
+ my $versionstr = shift;
+ my $version = 0;
+ my $minor = 0;
+ my $buildNumber = 0;
+ my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+ my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}";
+
+ # find the slapd executable
+ if (!$versionstr) { # version not specified on cmd line - find it
+ $prog = $dir . $progDir . $slapdExecName;
+ if (! -f $prog) {
+ $prog = $dir . $progDir2 . $slapdExecName;
+ if (-f $prog && $isNT) {
+ # if slapd is in bin/slapd and we're on NT, just assume version 1;
+ # apparently, slapd.exe doesn't like the -v argument . . .
+ return ( '1', $minor );
+ }
+ else{
+ die "Could not run slapd program $prog: $!";
+ }
+ }
+ else {
+ chdir($dir . $progDir);
+ }
+ $cur_libpath=$ENV{"$LIB_PATH"};
+ $ENV{"$LIB_PATH"}=
+ "$dir${PATHSEP}lib${SEP}".
+ "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}".
+ "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}".
+ $ENV{"$LIB_PATH"};
+ # read the old version from the old slapd program
+
+ open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or
+ die "Could not run slapd program $prog: $!";
+ sleep(1); # allow some data to accumulate in the pipe
+# print "Output from $prog -v:\n";
+ while (<F>) {
+ if (/^Netscape-Directory/ || /^iPlanet-Directory/i) {
+ $versionstr = $_;
+ last;
+ }
+ }
+ $code = close(F);
+ # print "$prog returned code=$code status=$?\n";
+ $ENV{"$LIB_PATH"}=$cur_libpath;
+ }
+
+ if ($versionstr =~ /^Netscape-Directory\/(\d+)\.(\d+)(?:b\d)*\s+(\S+)/) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ }
+ elsif ($versionstr =~ /^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ...
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ }
+ elsif ($versionstr =~ /^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ } elsif ($versionstr =~ /(\d+)\.(\d+)/) {
+ $version = $1;
+ $minor = $2;
+ }
+
+ if ($version == 0) {
+ die "\nCould not determine version of the directory server in $dir: \n";
+ }
+
+ # distinguish the 4.1 and the 4.11 thanks to the buildNumber
+ if (($version == 4) && ($minor == 1)){
+ if (! ($buildNumber =~ /^B99\.16/)) {
+ # it's not a 4.1 Netscape Directory Server => it's a 4.11
+ $minor = 11 ;
+ }
+ }
+ chdir($curdir) or die "Could not change directory to $curdir: $!" ;
+ return ( $version, $minor );
+}
+
+###############################################################################################
+sub normalizeDir {
+ my $dir = shift ;
+ my $dir_prec = "" ;
+ while ($dir_prec ne $dir) {
+ $dir_prec = $dir ;
+ if ($isNT) {
+ grep { s@\\\\@\\@g } $dir ;
+ }
+ else {
+ grep { s@//@/@g } $dir ;
+ }
+ }
+ return $dir ;
+}
+
+
+###############################################################################################
+
+sub GetTime {
+ my $tm = localtime;
+ (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900);
+ $sec = "0$sec" unless $sec > 9 ;
+ $min = "0$min" unless $min > 9 ;
+ $hour = "0$hour" unless $hour > 9 ;
+ $dd = "0$dd" unless $dd > 9 ;
+ $mm = "0$mm" unless $mm > 9 ;
+ return ($sec, $min, $hour, $dd, $mm, $yy);
+}
+
+###############################################################################################
+# get uid and group id of the 6.x slapd server.
+# The uid is done through the nsslapd-localuser attribute
+
+sub getuid_gid {
+ my $newuid ;
+ my $newgid ;
+ my $localuser ;
+ my $localuser_attr = "nsslapd-localuser" ;
+ if (! $isNT) {
+ &startServer() unless (isDirectoryAlive());
+ my $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ my $entry = $conn->search("cn=config ", "base","objectclass=*", 0, ($localuser_attr)) ;
+ # Tests wether we succeed to get the entry cn=config
+ die "\nCan't get the entry cn=config \n" unless ($entry);
+ my @values = $entry->getValues($localuser_attr);
+ $conn->close();
+ if ($#values == -1 || ($values[0] eq "") ) { # tests wether the nsslapd-localuser attribute has a value
+ printMsg("\nNo localuser has been found in the configuration of the directory. ");
+ if ($NO_INPUT_USER) {
+ printMsg("\nWe considered nobody as the localuser");
+ $localuser = "nobody" ;
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\nUnder what user does your $Version.$Minor directory server run [nobody] ? ") ;
+ $localuser = <STDIN> ;
+ chomp($localuser);
+ $localuser = "nobody" if ($localuser eq "");
+ ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ;
+ if ($newuid) {
+ $Ask = 0 ;
+ }
+ else {
+ printMsg("\nError: $localuser is unknown from the system ");
+ }
+ }
+ }
+ }
+ else {
+ $localuser = $values[0]; # returns the first value (we should only have one localuser)
+ my $size = $#values ;
+ }
+ ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ;
+ return ($localuser, $newuid, $newgid) ;
+ }
+ else {
+ return () ;
+ }
+}
+
+sub getolduid_gid {
+ my $oldlocaluser ;
+ my $localuserAttr = "nsslapd-localuser";
+ my $entry ;
+ if (! $isNT) {
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ $typeOfEntry = getTypeOfEntry($entry);
+ if ($typeOfEntry eq "CONFIG_NODE") {
+ $oldlocaluser = $entry->{$localuserAttr}[0] if ($entry->exists($localuserAttr));
+ break ;
+ }
+ }
+ close(DSE);
+ ($olduid, $oldgid) = (getpwnam("$oldlocaluser"))[2..3] ;
+ return ($oldlocaluser, $olduid, $oldgid) ;
+ }
+ else {
+ return ();
+ }
+}
+###############################################################################################
+# get current directory
+
+sub getCwd {
+ my $command = $isNT ? "cd" : "/bin/pwd";
+ open(PWDCMD, "$command 2>&1 |") or
+ die "Error: could not execute $command: $!";
+ # without the following sleep, reading from the pipe will
+ # return nothing; I guess it gives the pwd command time
+ # to get some data to read . . .
+ sleep(1);
+ my $currentdir;
+ while (<PWDCMD>) {
+ if (!$currentdir) {
+ chomp($currentdir = $_);
+ }
+ }
+ my $code = close(PWDCMD);
+# if ($code || $?) {
+# print "$command returned code=$code status=$? dir=$curdir\n";
+# }
+# print "getCwd curdir=\[$curdir\]\n";
+ return $currentdir;
+}
+
+################################
+# Need to migrate the credential.
+# If the credential can not be migrated, leave it at it is
+################################
+sub migrate_credential{
+ my $entry_to_modify = shift;
+ my $credentials_attr = shift;
+ my @old_value = $entry_to_modify->getValues($credentials_attr);
+ my $migratecredExecName = 'migratecred';
+ my $credOldHome = $oldHome;
+ my $credServerHome = $serverHome;
+
+ if ($isNT) {
+ # oldHome may be pointing to the archived copy of the
+ # instance dir which may be different than the path that
+ # the instance was originally installed as on Windows. If
+ # this path is not the original install path, then the
+ # credential will not be migrated correctly. We should
+ # prompt the user on Windows for the correct path.
+
+ print "\n\nThe old instance path must be the same as where it was";
+ print "\ninitially installed, not where it was archived in order";
+ print "\nfor this step to succeed. Please verify that the path";
+ print "\nis correct. Note that case sensitivity is important here.";
+ print "\n\nOld Instance Directory: $credOldHome";
+ print "\nIs this correct? (y/n): ";
+ chomp(my $answer = <STDIN>);
+ if (!($answer =~ /y|yes/i)) {
+ print "\nPlease enter the correct path for the old instance directory: ";
+ chomp($credOldHome = <STDIN>);
+ }
+
+ print "\n\nThe new instance path must also be correct for this step";
+ print "\nto succeed. Please verify that the path is correct. Note";
+ print "\nthat case sensitivity is important here.";
+ print "\n\nNew Instance Directory: $credServerHome";
+ print "\nIs this correct? (y/n): ";
+ chomp(my $answer = <STDIN>);
+ if (!($answer =~ /y|yes/i)) {
+ print "\nPlease enter the correct path for the new instance directory: ";
+ chomp($credServerHome = <STDIN>);
+ }
+ }
+# print "\nMigratecred command is: ${quote}$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}$migratecredExecName${quote} -o $credOldHome -n $credServerHome -c @old_value\n";
+
+ my @new_cred = `${quote}$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}$migratecredExecName${quote} -o $credOldHome -n $credServerHome -c @old_value`;
+
+ if ( $? == 0 )
+ {
+ $entry_to_modify->setValues($credentials_attr, @new_cred);
+ }
+}
+
diff --git a/ldap/admin/src/scripts/template-migrateInstance5 b/ldap/admin/src/scripts/template-migrateInstance5
new file mode 100644
index 00000000..3d3396c2
--- /dev/null
+++ b/ldap/admin/src/scripts/template-migrateInstance5
@@ -0,0 +1,518 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+use Time::localtime;
+
+BEGIN {
+ require 'uname.lib';
+ $| = 1;
+ $isNT = -d '\\';
+ $PATHSEP = $isNT ? "\\" : "/";
+ $SEP = $isNT ? ";" : ":" ;
+ $exitCode = 0;
+ @INC = ( '.', '../../../admin/admin/bin');
+ grep { s@/@\\@g } @INC if $isNT;
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ # NT needs quotes around some things unix doesn't
+ $quote = $isNT ? "\"" : "";
+ if ($isNT) {
+ # we have to pass batch files directly to the NT command interpreter
+ $com_spec = $ENV{ComSpec};
+ if (!$com_spec) {
+ $com_spec = $ENV{COMSPEC};
+ }
+ if (!$com_spec || ! -f $com_spec) {
+ # find the first available command interpreter
+ foreach $drive (c..z) {
+ $com_spec = "$drive:\\winnt\\system32\\cmd.exe";
+ last if (-f $com_spec);
+ $com_spec = undef;
+ }
+ if (! $com_spec) {
+ # punt and pray
+ $com_spec = 'c:\winnt\system32\cmd.exe';
+ }
+ }
+ $os = "WINNT";
+ } else {
+ $os = &uname("-s");
+ if ($os eq "SunOS") {
+ $isSolaris9 = ( &uname("-r") eq "5.9" );
+ }
+ }
+
+ if ( ($os eq "AIX") || ($os eq "HP-UX") ) {
+ $sigChildHandler = 'sigChildHandler';
+ }
+ SWITCH: {
+ if ($os eq "AIX") {
+ $LIB_PATH = "LIBPATH" ;
+ last SWITCH ;
+ }
+ if ($os eq "HP-UX") {
+ $LIB_PATH = "SHLIB_PATH" ;
+ last SWITCH ;
+ }
+ if ($isNT) {
+ $LIB_PATH = "PATH" ;
+ last SWITCH ;
+ }
+ else {
+ $LIB_PATH = "LD_LIBRARY_PATH" ;
+ last SWITCH ;
+ }
+ }
+ $slapdExecName = $isNT ? 'slapd.exe' : 'ns-slapd';
+ select STDERR;
+ $| = 1;
+ select STDOUT;
+ $| = 1;
+}
+
+
+
+$TRACELEVEL = 0;
+${root} = "{{DS-ROOT}}" ;
+${type} = "" ;
+${newname} = "" ;
+${newport} = "" ;
+${rootDN} = "" ;
+${rootpwd} = "" ;
+${localhost} = "" ;
+${LogFileReport} = "" ;
+
+# get input users
+&getParameters() ;
+
+
+${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ;
+${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ;
+${oldSlapdConf} = "${oldConfDir}slapd.conf" ;
+${serverHome} = "${root}${PATHSEP}$type-$newname" ;
+${ldif_rep} = "${oldConfDir}${PATHSEP}ldif${PATHSEP}" ;
+${curdir} = getCwd();
+
+
+if (!(-d $serverHome)) {
+ print("\n$serverHome doesn't exist\n");
+ exit(1);
+ }
+ if (!(-d $oldHome)) {
+ print("\n$oldHome doesn't exist\n");
+ exit(1);
+ }
+$ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"} ;
+if ($isSolaris9) {
+ $ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.005_03${PATHSEP}lib${PATHSEP}sun4-solaris${PATHSEP}CORE${SEP}".$ENV{"$LIB_PATH"} ;
+}
+
+if ($isNT) {
+ $ENV{"PERL5LIB"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.005_03${PATHSEP}site${PATHSEP}lib${SEP}".$ENV{"PERL5LIB"} ;
+}
+else {
+ $ENV{"PERL5LIB"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.005_03${PATHSEP}lib${PATHSEP}site${SEP}".$ENV{"PERL5LIB"} ;
+}
+
+# get the version of the DS to migrate
+($oldVersion, $oldMinor) = &getVersion($oldDir);
+# get the version of the new DS
+($Version, $Minor) = &getVersion($root);
+
+if ($Version >= 5) {
+ if ($oldVersion == 4) {
+ $myscript = "migrateTo5" ;
+ printMsg("\n******* Migration from $oldVersion.$oldMinor Netscape Directory Server to $Version.$Minor iPlanet Directory Server *********\n");
+ }
+ elsif ($oldVersion == 5 ) {
+ printMsg("\nWarning. You may experiment some problems considering the version of directory server you want to migrate is not a 5.0") if ($oldMinor != 0);
+ if ($oldMinor > $Minor) {
+ die "The migration from a version to an oldest one is not supported\nMigration aborted\n";
+ }
+ $myscript = "migrate50to51" ;
+ printMsg("\n******* Migration from $oldVersion.$oldMinor to $Version.$Minor iPlanet Directory Server *********\n");
+ }
+ else {
+ die "We don't support the version of directory server you want to migrate";
+ }
+}
+else {
+ die "\n\nThe version of directory you want to upgrade is not a 5.x product\nMigration aborted\n";
+}
+
+
+
+my $start_time = gmtime ;
+@args = ($, $myscript, @ARGV, '-L', $LogFileReport);
+$exitCode = &mySystem(@args);
+#die "Error: @args: $!" if ($exitCode != 0);
+
+open(LOGFILE,">> $LogFileReport") or die "\nCan't write to $LogFileReport\n$!\n";
+if (! $exitCode) {
+ my $end_time = gmtime ;
+ printMsg("-> Migration started at $start_time\n");
+ printMsg("-> Migration ended at $end_time\n\n");
+}
+printMsg("***********************************************\n\n");
+print("-> The migration report file is available at: $LogFileReport\n\n");
+
+close(LOGFILE);
+
+#######################################################################################################################
+sub usage {
+ print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n");
+ print(STDERR " -o oldInstancePath -n newInstancePath [-t tracelevel] \n");
+ print(STDERR " [-L logfile] [-noinput]\n");
+ print(STDERR "************** parameters in brackets are optionals, others are required **************\n");
+ print(STDERR " Opts: -D rootdn - new 5.x Directory Manager\n");
+ print(STDERR " : -w password - new 5.x Directory Manager's password\n");
+ print(STDERR " : -w - - Prompt for new 5.x Directory Manager's password\n");
+ print(STDERR " : -j filename - Read new 5.x Directory Manager's password from file\n");
+ print(STDERR " : -p port - new 5.x Directory Server port\n");
+ print(STDERR " : -o oldInstancePath - Path of the old instance to migrate \n");
+ print(STDERR " : -n newInstancePath - Path of the new 5.x instance\n");
+ print(STDERR " : [-t tracelevel] - specify the level of trace (0..3) by default setup to 1\n");
+ print(STDERR " : [-L logfile] - specify the file to log the migration report \n");
+ print(STDERR " : [-noinput] - no user interventions during migration processing to solve conflicts\n");
+
+ }
+
+
+#######################################################################################################################
+# get input users
+
+sub getParameters {
+ my $exit = 0 ;
+ my $i = 0;
+ my $pwdfile= "";
+
+ while ($i <= $#ARGV) {
+ if ( "$ARGV[$i]" eq "-D" ) { # directory manager
+ if (! $rootDN) {
+ $rootDN = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-w") { # password
+ if (! $rootpwd) {
+ $rootpwd = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-j") { # password file
+ if (! $pwdfile) {
+ $pwdfile = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-o") { # old instance path
+ if (! $oldHome ) {
+ $oldHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $oldHome if $isNT ;
+ if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; }
+ if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) {
+ $oldDir = $1 ;
+ $type = $2 ;
+ $oldname = $3 ;
+ if ($isNT) {
+ $oldDir = lc($oldDir) ;
+ $type = lc($type) ;
+ $oldname = lc($oldname) ;
+ $oldHome = lc($oldHome) ;
+ grep { s@/@\\@g } $oldDir ;
+ grep { s@/@\\@g } $oldHome ;
+ }
+ }
+ else {
+ print("\nThe old instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-n") { # 5.x instance path
+ if (! $serverHome ) {
+ $serverHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $root if $isNT ;
+ grep { s@\\@/@g } $serverHome if $isNT ;
+ if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; }
+ if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) {
+ $root = $1 if ($1);
+ $type = $2 ;
+ $newname = $3 ;
+ if ($isNT) {
+ $root = lc($root) ;
+ $type = lc($type) ;
+ $newname = lc($newname) ;
+ $serverHome = lc($serverHome) ;
+ grep { s@/@\\@g } $root ;
+ grep { s@/@\\@g } $serverHome ;
+ }
+ }
+ else {
+ print("\nThe 5.x instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-p") { # 5.x DS port
+ if (! $newport ) {
+ $newport = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL
+ my $value = $ARGV[++$i] ;
+ if ($value =~ /[0-3]/) {
+ $TRACELEVEL = $value ;
+ }
+ else {
+ print("\nThe tracelevel must belong to 0..3 interval");
+ &usage();
+ exit();
+ }
+ } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing
+ } elsif ("$ARGV[$i]" eq "-L") { # user defined logfile for the migration
+ $LogFileReport = $ARGV[++$i];
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ $i++;
+ }
+
+ if (! $rootDN) {
+ print("\nThe rootDN is missing");
+ $exit = 1;
+ }
+ if ($pwdfile ne "") {
+ # Open file and get the password
+ unless (open (RPASS, $pwfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $rootpwd = <RPASS>;
+ chomp($rootpwd);
+ close(RPASS);
+ } elsif ($rootpwd eq "-"){
+ # Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+ # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $rootpwd = ReadLine(0);
+# chomp($rootpwd);
+# ReadMode('normal');
+ }
+ if (! $rootpwd) {
+ print("\nThe rootpwd is missing");
+ $exit = 1 ;
+ }
+ if (! $newport) {
+ print("\nThe port is missing");
+ $exit = 1;
+ }
+ if (! $serverHome) {
+ print("\nThe new instance path is missing");
+ $exit = 1;
+ }
+ if (! $oldHome) {
+ print("\nThe old instance path is missing");
+ $exit = 1;
+ }
+ if ((! $LogFileReport) && $serverHome) {
+ ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime();
+ $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log";
+ }
+ if ($exit) {
+ &usage() ;
+ exit(1);
+ }
+
+}
+
+#############################################################################
+# printMsg print message to the user standard output.
+
+sub printMsg {
+
+ my $TypeMsg = shift ;
+ my $Msg = shift ;
+ my $LineNb = shift ;
+ if ($LineNb) {
+ printTrace("Line: $LineNb, $TypeMsg, $Msg");
+ }
+ else {
+ printTrace("$TypeMsg $Msg");
+ }
+}
+
+#############################################################################
+# print message error to the user standard output.
+
+sub printTrace {
+
+ my $Msg = shift ;
+ my $level = shift ;
+ if ($level <= $TRACELEVEL) {
+ print($Msg);
+ print LOGFILE $Msg;
+ }
+
+}
+
+#############################################################################
+sub mySystem {
+ my $cmd = $_[0];
+ # the system {$cmd} avoids some NT shell quoting problems if the $cmd
+ # needs to be quoted e.g. contains spaces; the map puts double quotes
+ # around the arguments on NT which are stripped by the command
+ # interpreter cmd.exe; but don't quote things which are already quoted
+ my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @_;
+ my $rc = 0;
+ if ($cmd =~ /[.](bat|cmd)$/) {
+ # we have to pass batch files directly to the NT command interpreter
+ $cmd = $com_spec;
+# print "system $cmd /c \"@fixargs\"\n";
+ $rc = system {$cmd} '/c', "\"@fixargs\"";
+ } else {
+# print "system $cmd \"@fixargs\"\n";
+ $rc = system {$cmd} @fixargs;
+ }
+
+ return $rc;
+}
+
+#############################################################################
+
+sub GetTime {
+ my $tm = localtime;
+ (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900);
+ $sec = "0$sec" unless $sec > 9 ;
+ $min = "0$min" unless $min > 9 ;
+ $hour = "0$hour" unless $hour > 9 ;
+ $dd = "0$dd" unless $dd > 9 ;
+ $mm = "0$mm" unless $mm > 9 ;
+ return ($sec, $min, $hour, $dd, $mm, $yy);
+}
+
+#############################################################################
+
+sub getVersion {
+ my $dir = shift;
+ my $version = 0;
+ my $minor = 0;
+ my $buildNumber = 0;
+ my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+ my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}";
+
+ # find the slapd executable
+ $prog = $dir . $progDir . $slapdExecName;
+ if (! -f $prog) {
+ $prog = $dir . $progDir2 . $slapdExecName;
+ if (-f $prog && $isNT) {
+ # if slapd is in bin/slapd and we're on NT, just assume version 1;
+ # apparently, slapd.exe doesn't like the -v argument . . .
+ return ( '1', $minor );
+ }
+ else{
+ die "Could not run slapd program $prog: $!";
+ }
+ }
+ else {
+ chdir($dir . $progDir);
+ }
+ $ENV{"$LIB_PATH"}="$dir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ # read the old version from the old slapd program
+
+ open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or
+ die "Could not run slapd program $prog: $!";
+ sleep(1); # allow some data to accumulate in the pipe
+# print "Output from $prog -v:\n";
+ while (<F>) {
+ if (/^Netscape-Directory\/(\d+)\.(\d+)\s+(\S+)/) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ last;
+ }
+ elsif (/^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ...
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ last;
+ }
+ elsif (/^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ last;
+ }
+ }
+ $code = close(F);
+# print "$prog returned code=$code status=$?\n";
+ $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+
+ if ($version == 0) {
+ die "\nCould not determine version of the directory server in $dir: \n";
+ }
+
+ # distinguish the 4.1 and the 4.11 thanks to the buildNumber
+ if (($version == 4) && ($minor == 1)){
+ if (! ($buildNumber =~ /^B99\.16/)) {
+ # it's not a 4.1 Netscape Directory Server => it's a 4.11
+ $minor = 11 ;
+ }
+ }
+ chdir($curdir) or die "Could not change directory to $curdir: $!" ;
+ return ( $version, $minor );
+}
+
+###############################################################################################
+# get current directory
+
+sub getCwd {
+ my $command = $isNT ? "cd" : "/bin/pwd";
+ open(PWDCMD, "$command 2>&1 |") or
+ die "Error: could not execute $command: $!";
+ # without the following sleep, reading from the pipe will
+ # return nothing; I guess it gives the pwd command time
+ # to get some data to read . . .
+ sleep(1);
+ my $currentdir;
+ while (<PWDCMD>) {
+ if (!$currentdir) {
+ chomp($currentdir = $_);
+ }
+ }
+ my $code = close(PWDCMD);
+# if ($code || $?) {
+# print "$command returned code=$code status=$? dir=$curdir\n";
+# }
+# print "getCwd curdir=\[$curdir\]\n";
+ return $currentdir;
+}
diff --git a/ldap/admin/src/scripts/template-migrateInstance6 b/ldap/admin/src/scripts/template-migrateInstance6
new file mode 100644
index 00000000..faaf6363
--- /dev/null
+++ b/ldap/admin/src/scripts/template-migrateInstance6
@@ -0,0 +1,550 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+use Time::localtime;
+
+BEGIN {
+ require 'uname.lib';
+ $| = 1;
+ $isNT = -d '\\';
+ $PATHSEP = $isNT ? "\\" : "/";
+ $SEP = $isNT ? ";" : ":" ;
+ $exitCode = 0;
+ @INC = ( '.', '../../../admin/admin/bin');
+ grep { s@/@\\@g } @INC if $isNT;
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ # NT needs quotes around some things unix doesn't
+ $quote = $isNT ? "\"" : "";
+ if ($isNT) {
+ # we have to pass batch files directly to the NT command interpreter
+ $com_spec = $ENV{ComSpec};
+ if (!$com_spec) {
+ $com_spec = $ENV{COMSPEC};
+ }
+ if (!$com_spec || ! -f $com_spec) {
+ # find the first available command interpreter
+ foreach $drive (c..z) {
+ $com_spec = "$drive:\\winnt\\system32\\cmd.exe";
+ last if (-f $com_spec);
+ $com_spec = undef;
+ }
+ if (! $com_spec) {
+ # punt and pray
+ $com_spec = 'c:\winnt\system32\cmd.exe';
+ }
+ }
+ $os = "WINNT";
+ } else {
+ $os = &uname("-s");
+ if ($os eq "SunOS") {
+ $isSolaris9 = ( &uname("-r") eq "5.9" );
+ }
+ }
+
+ if ( ($os eq "AIX") || ($os eq "HP-UX") ) {
+ $sigChildHandler = 'sigChildHandler';
+ }
+ SWITCH: {
+ if ($os eq "AIX") {
+ $LIB_PATH = "LIBPATH" ;
+ last SWITCH ;
+ }
+ if ($os eq "HP-UX") {
+ $LIB_PATH = "SHLIB_PATH" ;
+ last SWITCH ;
+ }
+ if ($isNT) {
+ $LIB_PATH = "PATH" ;
+ last SWITCH ;
+ }
+ else {
+ $LIB_PATH = "LD_LIBRARY_PATH" ;
+ last SWITCH ;
+ }
+ }
+ $slapdExecName = $isNT ? 'slapd.exe' : 'ns-slapd';
+ select STDERR;
+ $| = 1;
+ select STDOUT;
+ $| = 1;
+}
+
+
+
+$TRACELEVEL = 0;
+${root} = "{{DS-ROOT}}" ;
+${type} = "" ;
+${newname} = "" ;
+${newport} = "" ;
+${rootDN} = "" ;
+${rootpwd} = "" ;
+${localhost} = "" ;
+${LogFileReport} = "" ;
+
+# get input users
+&getParameters() ;
+
+
+${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ;
+${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ;
+${oldSlapdConf} = "${oldConfDir}slapd.conf" ;
+${serverHome} = "${root}${PATHSEP}$type-$newname" ;
+${ldif_rep} = "${oldConfDir}ldif${PATHSEP}" ;
+${curdir} = getCwd();
+
+
+if (!(-d $serverHome)) {
+ print("\n$serverHome doesn't exist\n");
+ exit(1);
+ }
+ if (!(-d $oldHome)) {
+ print("\n$oldHome doesn't exist\n");
+ exit(1);
+ }
+if ($olddatadir && !(-d $olddatadir)) {
+ print("\n$olddatadir doesn't exist\n");
+ exit(1);
+ }
+$ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"} ;
+if ($isSolaris9) {
+ $ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.6.1${PATHSEP}lib${PATHSEP}sun4-solaris${PATHSEP}CORE${SEP}".$ENV{"$LIB_PATH"} ;
+}
+
+if ($isNT) {
+ $ENV{"PERL5LIB"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.6.1${PATHSEP}site${PATHSEP}lib${SEP}".$ENV{"PERL5LIB"} ;
+}
+else {
+ $ENV{"PERL5LIB"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.6.1${PATHSEP}lib${PATHSEP}site${SEP}".$ENV{"PERL5LIB"} ;
+}
+
+# get the version of the DS to migrate
+($oldVersion, $oldMinor) = &getVersion($oldDir, $oldversionstr);
+# get the version of the new DS
+($Version, $Minor) = &getVersion($root);
+
+if ($Version >= 6) {
+ if ($oldVersion == 4) {
+ $myscript = "migrateTo6" ;
+ printMsg("\n******* Migration from $oldVersion.$oldMinor to $Version.$Minor Directory Server *********\n");
+ }
+ elsif ($oldVersion == 5 ) {
+ printMsg("\nWarning. You may experience some problems if the version of directory server you want to migrate is not a 5.0 or 5.1") if ($oldMinor > 1);
+ $myscript = "migrate5to6" ;
+ printMsg("\n******* Migration from $oldVersion.$oldMinor to $Version.$Minor Directory Server *********\n");
+ } else {
+ die "We don't support the version of directory server you want to migrate";
+ }
+}
+else {
+ die "\n\nThe version of directory you want to upgrade is not a 6.x product\nMigration aborted\n";
+}
+
+my $start_time = gmtime ;
+@args = ($^X, $myscript, @ARGV, '-L', $LogFileReport);
+$exitCode = &mySystem(@args);
+#die "Error: @args: $!" if ($exitCode != 0);
+
+open(LOGFILE,">> $LogFileReport") or die "\nCan't write to $LogFileReport\n$!\n";
+if (! $exitCode) {
+ my $end_time = gmtime ;
+ printMsg("-> Migration started at $start_time\n");
+ printMsg("-> Migration ended at $end_time\n\n");
+}
+printMsg("***********************************************\n\n");
+print("-> The migration report file is available at: $LogFileReport\n\n");
+
+close(LOGFILE);
+
+#######################################################################################################################
+sub usage {
+ print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n");
+ print(STDERR " -o oldInstancePath -n newInstancePath [-t tracelevel] \n");
+ print(STDERR " [-L logfile] [-noinput]\n");
+ print(STDERR "************** parameters in brackets are optionals, others are required **************\n");
+ print(STDERR " Opts: -D rootdn - new Directory Manager\n");
+ print(STDERR " : -w password - new Directory Manager's password\n");
+ print(STDERR " : -w - - Prompt for new Directory Manager's password\n");
+ print(STDERR " : -j filename - Read new Directory Manager's password from file\n");
+ print(STDERR " : -p port - new Directory Server port\n");
+ print(STDERR " : -o oldInstancePath - Path of the old instance to migrate \n");
+ print(STDERR " : -n newInstancePath - Path of the new instance\n");
+ print(STDERR " : [-d dataPath] - Path to directory containing data files to import into new instance\n");
+ print(STDERR " : [-v oldVersion] - Version of old instance (obtained by running $slapdExecName -v\n");
+ print(STDERR " : [-t tracelevel] - specify the level of trace (0..3) by default setup to 1\n");
+ print(STDERR " : [-L logfile] - specify the file to log the migration report \n");
+ print(STDERR " : [-noinput] - no user interventions during migration processing to solve conflicts\n");
+
+ }
+
+
+#######################################################################################################################
+# get input users
+
+sub getParameters {
+ my $exit = 0 ;
+ my $i = 0;
+ my $pwdfile= "";
+
+ while ($i <= $#ARGV) {
+ if ( "$ARGV[$i]" eq "-D" ) { # directory manager
+ if (! $rootDN) {
+ $rootDN = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-w") { # password
+ if (! $rootpwd) {
+ $rootpwd = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-j") { # password file
+ if (! $pwdfile) {
+ $pwdfile = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-o") { # old instance path
+ if (! $oldHome ) {
+ $oldHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $oldHome if $isNT ;
+ if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; }
+ if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) {
+ $oldDir = $1 ;
+ $type = $2 ;
+ $oldname = $3 ;
+ if ($isNT) {
+ $oldDir = lc($oldDir) ;
+ $type = lc($type) ;
+ $oldname = lc($oldname) ;
+ $oldHome = lc($oldHome) ;
+ grep { s@/@\\@g } $oldDir ;
+ grep { s@/@\\@g } $oldHome ;
+ }
+ }
+ else {
+ print("\nThe old instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-n") { # 5.x instance path
+ if (! $serverHome ) {
+ $serverHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $root if $isNT ;
+ grep { s@\\@/@g } $serverHome if $isNT ;
+ if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; }
+ if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) {
+ $root = $1 if ($1);
+ $type = $2 ;
+ $newname = $3 ;
+ if ($isNT) {
+ $root = lc($root) ;
+ $type = lc($type) ;
+ $newname = lc($newname) ;
+ $serverHome = lc($serverHome) ;
+ grep { s@/@\\@g } $root ;
+ grep { s@/@\\@g } $serverHome ;
+ }
+ }
+ else {
+ print("\nThe new instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-p") { # 5.x DS port
+ if (! $newport ) {
+ $newport = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-d") { # old instance LDIF data dir
+ if (! $olddatadir ) {
+ $olddatadir = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-v") { # old version
+ if (! $oldversionstr ) {
+ $oldversionstr = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL
+ my $value = $ARGV[++$i] ;
+ if ($value =~ /[0-3]/) {
+ $TRACELEVEL = $value ;
+ }
+ else {
+ print("\nThe tracelevel must belong to 0..3 interval");
+ &usage();
+ exit();
+ }
+ } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing
+ } elsif ("$ARGV[$i]" eq "-L") { # user defined logfile for the migration
+ $LogFileReport = $ARGV[++$i];
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ $i++;
+ }
+
+ if (! $rootDN) {
+ print("\nThe rootDN is missing");
+ $exit = 1;
+ }
+ if ($pwdfile ne "") {
+ # Open file and get the password
+ unless (open (RPASS, $pwfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $rootpwd = <RPASS>;
+ chomp($rootpwd);
+ close(RPASS);
+ } elsif ($rootpwd eq "-"){
+ # Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+ # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $rootpwd = ReadLine(0);
+# chomp($rootpwd);
+# ReadMode('normal');
+ }
+ if (! $rootpwd) {
+ print("\nThe rootpwd is missing");
+ $exit = 1 ;
+ }
+ if (! $newport) {
+ print("\nThe port is missing");
+ $exit = 1;
+ }
+ if (! $serverHome) {
+ print("\nThe new instance path is missing");
+ $exit = 1;
+ }
+ if (! $oldHome) {
+ print("\nThe old instance path is missing");
+ $exit = 1;
+ }
+ if ((! $LogFileReport) && $serverHome) {
+ ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime();
+ $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log";
+ }
+ if ($exit) {
+ &usage() ;
+ exit(1);
+ }
+
+}
+
+#############################################################################
+# printMsg print message to the user standard output.
+
+sub printMsg {
+
+ my $TypeMsg = shift ;
+ my $Msg = shift ;
+ my $LineNb = shift ;
+ if ($LineNb) {
+ printTrace("Line: $LineNb, $TypeMsg, $Msg");
+ }
+ else {
+ printTrace("$TypeMsg $Msg");
+ }
+}
+
+#############################################################################
+# print message error to the user standard output.
+
+sub printTrace {
+
+ my $Msg = shift ;
+ my $level = shift ;
+ if ($level <= $TRACELEVEL) {
+ print($Msg);
+ print LOGFILE $Msg;
+ }
+
+}
+
+#############################################################################
+sub mySystem {
+ my $cmd = $_[0];
+ # the system {$cmd} avoids some NT shell quoting problems if the $cmd
+ # needs to be quoted e.g. contains spaces; the map puts double quotes
+ # around the arguments on NT which are stripped by the command
+ # interpreter cmd.exe; but don't quote things which are already quoted
+ my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @_;
+ my $rc = 0;
+ if ($cmd =~ /[.](bat|cmd)$/) {
+ # we have to pass batch files directly to the NT command interpreter
+ $cmd = $com_spec;
+# print "system $cmd /c \"@fixargs\"\n";
+ $rc = system {$cmd} '/c', "\"@fixargs\"";
+ } else {
+# print "system $cmd \"@fixargs\"\n";
+ if($isNT) {
+ $rc = system "\"@fixargs\"";
+ } else {
+ $rc = system @fixargs;
+ }
+ }
+
+ return $rc;
+}
+
+#############################################################################
+
+sub GetTime {
+ my $tm = localtime;
+ (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900);
+ $sec = "0$sec" unless $sec > 9 ;
+ $min = "0$min" unless $min > 9 ;
+ $hour = "0$hour" unless $hour > 9 ;
+ $dd = "0$dd" unless $dd > 9 ;
+ $mm = "0$mm" unless $mm > 9 ;
+ return ($sec, $min, $hour, $dd, $mm, $yy);
+}
+
+#############################################################################
+
+sub getVersion {
+ my $dir = shift;
+ my $versionstr = shift;
+ my $version = 0;
+ my $minor = 0;
+ my $buildNumber = 0;
+ my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+ my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}";
+
+ # find the slapd executable
+ if (!$versionstr) { # version not specified on cmd line - find it
+ $prog = $dir . $progDir . $slapdExecName;
+ if (! -f $prog) {
+ $prog = $dir . $progDir2 . $slapdExecName;
+ if (-f $prog && $isNT) {
+ # if slapd is in bin/slapd and we're on NT, just assume version 1;
+ # apparently, slapd.exe doesn't like the -v argument . . .
+ return ( '1', $minor );
+ }
+ else{
+ die "Could not run slapd program $prog: $!";
+ }
+ }
+ else {
+ chdir($dir . $progDir);
+ }
+ $ENV{"$LIB_PATH"}=
+ "$dir${PATHSEP}lib${SEP}".
+ "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}".
+ "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}".
+ $ENV{"$LIB_PATH"};
+ # read the old version from the old slapd program
+
+ open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or
+ die "Could not run slapd program $prog: $!";
+ sleep(1); # allow some data to accumulate in the pipe
+# print "Output from $prog -v:\n";
+ while (<F>) {
+ if (/^Netscape-Directory/ || /^iPlanet-Directory/i) {
+ $versionstr = $_;
+ last;
+ }
+ }
+ $code = close(F);
+ # print "$prog returned code=$code status=$?\n";
+ $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ }
+
+ if ($versionstr =~ /^Netscape-Directory\/(\d+)\.(\d+)(?:b\d)*\s+(\S+)/) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ }
+ elsif ($versionstr =~ /^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ...
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ }
+ elsif ($versionstr =~ /^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ } elsif ($versionstr =~ /(\d+)\.(\d+)/) {
+ $version = $1;
+ $minor = $2;
+ }
+
+ if ($version == 0) {
+ die "\nCould not determine version of the directory server in $dir: \n";
+ }
+
+ # distinguish the 4.1 and the 4.11 thanks to the buildNumber
+ if (($version == 4) && ($minor == 1)){
+ if (! ($buildNumber =~ /^B99\.16/)) {
+ # it's not a 4.1 Netscape Directory Server => it's a 4.11
+ $minor = 11 ;
+ }
+ }
+ chdir($curdir) or die "Could not change directory to $curdir: $!" ;
+ return ( $version, $minor );
+}
+
+###############################################################################################
+# get current directory
+
+sub getCwd {
+ my $command = $isNT ? "cd" : "/bin/pwd";
+ open(PWDCMD, "$command 2>&1 |") or
+ die "Error: could not execute $command: $!";
+ # without the following sleep, reading from the pipe will
+ # return nothing; I guess it gives the pwd command time
+ # to get some data to read . . .
+ sleep(1);
+ my $currentdir;
+ while (<PWDCMD>) {
+ if (!$currentdir) {
+ chomp($currentdir = $_);
+ }
+ }
+ my $code = close(PWDCMD);
+# if ($code || $?) {
+# print "$command returned code=$code status=$? dir=$curdir\n";
+# }
+# print "getCwd curdir=\[$curdir\]\n";
+ return $currentdir;
+}
diff --git a/ldap/admin/src/scripts/template-migrateInstance7 b/ldap/admin/src/scripts/template-migrateInstance7
new file mode 100644
index 00000000..2a754b10
--- /dev/null
+++ b/ldap/admin/src/scripts/template-migrateInstance7
@@ -0,0 +1,559 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+use Time::localtime;
+
+BEGIN {
+ require 'uname.lib';
+ $| = 1;
+ $isNT = -d '\\';
+ $PATHSEP = $isNT ? "\\" : "/";
+ $SEP = $isNT ? ";" : ":" ;
+ $exitCode = 0;
+ @INC = ( '.', '../../../admin/admin/bin');
+ grep { s@/@\\@g } @INC if $isNT;
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ # NT needs quotes around some things unix doesn't
+ $quote = $isNT ? "\"" : "";
+ if ($isNT) {
+ # we have to pass batch files directly to the NT command interpreter
+ $com_spec = $ENV{ComSpec};
+ if (!$com_spec) {
+ $com_spec = $ENV{COMSPEC};
+ }
+ if (!$com_spec || ! -f $com_spec) {
+ # find the first available command interpreter
+ foreach $drive (c..z) {
+ $com_spec = "$drive:\\winnt\\system32\\cmd.exe";
+ last if (-f $com_spec);
+ $com_spec = undef;
+ }
+ if (! $com_spec) {
+ # punt and pray
+ $com_spec = 'c:\winnt\system32\cmd.exe';
+ }
+ }
+ $os = "WINNT";
+ } else {
+ $os = &uname("-s");
+ if ($os eq "SunOS") {
+ $isSolaris9 = ( &uname("-r") eq "5.9" );
+ }
+ }
+
+ if ( ($os eq "AIX") || ($os eq "HP-UX") ) {
+ $sigChildHandler = 'sigChildHandler';
+ }
+ SWITCH: {
+ if ($os eq "AIX") {
+ $LIB_PATH = "LIBPATH" ;
+ last SWITCH ;
+ }
+ if ($os eq "HP-UX") {
+ $LIB_PATH = "SHLIB_PATH" ;
+ last SWITCH ;
+ }
+ if ($isNT) {
+ $LIB_PATH = "PATH" ;
+ last SWITCH ;
+ }
+ else {
+ $LIB_PATH = "LD_LIBRARY_PATH" ;
+ last SWITCH ;
+ }
+ }
+ $slapdExecName = $isNT ? 'slapd.exe' : 'ns-slapd';
+ select STDERR;
+ $| = 1;
+ select STDOUT;
+ $| = 1;
+}
+
+
+
+$TRACELEVEL = 0;
+${root} = "{{DS-ROOT}}" ;
+${type} = "" ;
+${newname} = "" ;
+${newport} = "" ;
+${rootDN} = "" ;
+${rootpwd} = "" ;
+${localhost} = "" ;
+${LogFileReport} = "" ;
+
+# get input users
+&getParameters() ;
+
+
+${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ;
+${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ;
+${oldSlapdConf} = "${oldConfDir}slapd.conf" ;
+${serverHome} = "${root}${PATHSEP}$type-$newname" ;
+${ldif_rep} = "${oldConfDir}ldif${PATHSEP}" ;
+${curdir} = getCwd();
+
+
+if (!(-d $serverHome)) {
+ print("\n$serverHome doesn't exist\n");
+ exit(1);
+ }
+ if (!(-d $oldHome)) {
+ print("\n$oldHome doesn't exist\n");
+ exit(1);
+ }
+if ($olddatadir && !(-d $olddatadir)) {
+ print("\n$olddatadir doesn't exist\n");
+ exit(1);
+ }
+$ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"} ;
+if ($isSolaris9) {
+ $ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.6.1${PATHSEP}lib${PATHSEP}sun4-solaris${PATHSEP}CORE${SEP}".$ENV{"$LIB_PATH"} ;
+}
+
+if ($isNT) {
+ $ENV{"PERL5LIB"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.6.1${PATHSEP}site${PATHSEP}lib${SEP}".$ENV{"PERL5LIB"} ;
+}
+else {
+ $ENV{"PERL5LIB"} = "$root${PATHSEP}lib${PATHSEP}nsPerl5.6.1${PATHSEP}lib${PATHSEP}site${SEP}".$ENV{"PERL5LIB"} ;
+}
+
+# get the version of the DS to migrate
+($oldVersion, $oldMinor) = &getVersion($oldDir, $oldversionstr);
+# get the version of the new DS
+($Version, $Minor) = &getVersion($root);
+
+if ($Version >= 7) {
+ if ($oldVersion == 4) {
+ $myscript = "migrateTo7" ;
+ printMsg("\n******* Migration from $oldVersion.$oldMinor to $Version.$Minor Directory Server *********\n");
+ }
+ elsif ($oldVersion == 5 ) {
+ printMsg("\nWarning. You may experience some problems if the version of directory server you want to migrate is not a 5.0 or 5.1") if ($oldMinor > 1);
+ $myscript = "migrate5to7" ;
+ printMsg("\n******* Migration from $oldVersion.$oldMinor to $Version.$Minor Directory Server *********\n");
+ }
+ elsif ($oldVersion == 6 ) {
+ $myscript = "migrate6to7" ;
+ printMsg("\n******* Migration from $oldVersion.$oldMinor to $Version.$Minor Directory Server *********\n");
+ }
+ else {
+
+ die "We don't support the version of directory server you want to migrate";
+ }
+}
+else {
+ die "\n\nThe version of directory you want to upgrade is not a 7.x product\nMigration aborted\n";
+}
+
+my $start_time = gmtime ;
+@args = ($^X, $myscript, @ARGV, '-L', $LogFileReport);
+$exitCode = &mySystem(@args);
+#die "Error: @args: $!" if ($exitCode != 0);
+
+open(LOGFILE,">> $LogFileReport") or die "\nCan't write to $LogFileReport\n$!\n";
+if (! $exitCode) {
+ my $end_time = gmtime ;
+ printMsg("-> Migration started at $start_time\n");
+ printMsg("-> Migration ended at $end_time\n\n");
+}
+printMsg("***********************************************\n\n");
+print("-> The migration report file is available at: $LogFileReport\n\n");
+
+close(LOGFILE);
+
+#######################################################################################################################
+sub usage {
+ print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n");
+ print(STDERR " -o oldInstancePath -n newInstancePath [-t tracelevel] \n");
+ print(STDERR " [-L logfile] [-noinput]\n");
+ print(STDERR "************** parameters in brackets are optionals, others are required **************\n");
+ print(STDERR " Opts: -D rootdn - new Directory Manager\n");
+ print(STDERR " : -w password - new Directory Manager's password\n");
+ print(STDERR " : -w - - Prompt for new Directory Manager's password\n");
+ print(STDERR " : -j filename - Read new Directory Manager's password from file\n");
+ print(STDERR " : -p port - new Directory Server port\n");
+ print(STDERR " : -o oldInstancePath - Path of the old instance to migrate \n");
+ print(STDERR " : -n newInstancePath - Path of the new instance\n");
+ print(STDERR " : [-d dataPath] - Path to directory containing data files to import into new instance\n");
+ print(STDERR " : [-v oldVersion] - Version of old instance (obtained by running $slapdExecName -v\n");
+ print(STDERR " : [-t tracelevel] - specify the level of trace (0..3) by default setup to 1\n");
+ print(STDERR " : [-L logfile] - specify the file to log the migration report \n");
+ print(STDERR " : [-noinput] - no user interventions during migration processing to solve conflicts\n");
+
+ }
+
+
+#######################################################################################################################
+# get input users
+
+sub getParameters {
+ my $exit = 0 ;
+ my $i = 0;
+ my $pwdfile= "";
+
+ while ($i <= $#ARGV) {
+ if ( "$ARGV[$i]" eq "-D" ) { # directory manager
+ if (! $rootDN) {
+ $rootDN = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-w") { # password
+ if (! $rootpwd) {
+ $rootpwd = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-j") { # password file
+ if (! $pwdfile) {
+ $pwdfile = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-o") { # old instance path
+ if (! $oldHome ) {
+ $oldHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $oldHome if $isNT ;
+ if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; }
+ if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) {
+ $oldDir = $1 ;
+ $type = $2 ;
+ $oldname = $3 ;
+ if ($isNT) {
+ $oldDir = lc($oldDir) ;
+ $type = lc($type) ;
+ $oldname = lc($oldname) ;
+ $oldHome = lc($oldHome) ;
+ grep { s@/@\\@g } $oldDir ;
+ grep { s@/@\\@g } $oldHome ;
+ }
+ }
+ else {
+ print("\nThe old instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-n") { # 5.x instance path
+ if (! $serverHome ) {
+ $serverHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $root if $isNT ;
+ grep { s@\\@/@g } $serverHome if $isNT ;
+ if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; }
+ if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) {
+ $root = $1 if ($1);
+ $type = $2 ;
+ $newname = $3 ;
+ if ($isNT) {
+ $root = lc($root) ;
+ $type = lc($type) ;
+ $newname = lc($newname) ;
+ $serverHome = lc($serverHome) ;
+ grep { s@/@\\@g } $root ;
+ grep { s@/@\\@g } $serverHome ;
+ }
+ }
+ else {
+ print("\nThe new instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-p") { # 5.x DS port
+ if (! $newport ) {
+ $newport = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-d") { # old instance LDIF data dir
+ if (! $olddatadir ) {
+ $olddatadir = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-v") { # old version
+ if (! $oldversionstr ) {
+ $oldversionstr = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL
+ my $value = $ARGV[++$i] ;
+ if ($value =~ /[0-3]/) {
+ $TRACELEVEL = $value ;
+ }
+ else {
+ print("\nThe tracelevel must belong to 0..3 interval");
+ &usage();
+ exit();
+ }
+ } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing
+ } elsif ("$ARGV[$i]" eq "-L") { # user defined logfile for the migration
+ $LogFileReport = $ARGV[++$i];
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ $i++;
+ }
+
+ if (! $rootDN) {
+ print("\nThe rootDN is missing");
+ $exit = 1;
+ }
+ if ($pwdfile ne "") {
+ # Open file and get the password
+ unless (open (RPASS, $pwfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $rootpwd = <RPASS>;
+ chomp($rootpwd);
+ close(RPASS);
+ } elsif ($rootpwd eq "-"){
+ # Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+ # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $rootpwd = ReadLine(0);
+# chomp($rootpwd);
+# ReadMode('normal');
+ }
+ if (! $rootpwd) {
+ print("\nThe rootpwd is missing");
+ $exit = 1 ;
+ }
+ if (! $newport) {
+ print("\nThe port is missing");
+ $exit = 1;
+ }
+ if (! $serverHome) {
+ print("\nThe new instance path is missing");
+ $exit = 1;
+ }
+ if (! $oldHome) {
+ print("\nThe old instance path is missing");
+ $exit = 1;
+ }
+ if ((! $LogFileReport) && $serverHome) {
+ ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime();
+ $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log";
+ }
+ if ($exit) {
+ &usage() ;
+ exit(1);
+ }
+
+}
+
+#############################################################################
+# printMsg print message to the user standard output.
+
+sub printMsg {
+
+ my $TypeMsg = shift ;
+ my $Msg = shift ;
+ my $LineNb = shift ;
+ if ($LineNb) {
+ printTrace("Line: $LineNb, $TypeMsg, $Msg");
+ }
+ else {
+ printTrace("$TypeMsg $Msg");
+ }
+}
+
+#############################################################################
+# print message error to the user standard output.
+
+sub printTrace {
+
+ my $Msg = shift ;
+ my $level = shift ;
+ if ($level <= $TRACELEVEL) {
+ print($Msg);
+ print LOGFILE $Msg;
+ }
+
+}
+
+#############################################################################
+sub mySystem {
+ my $cmd = $_[0];
+ # the system {$cmd} avoids some NT shell quoting problems if the $cmd
+ # needs to be quoted e.g. contains spaces; the map puts double quotes
+ # around the arguments on NT which are stripped by the command
+ # interpreter cmd.exe; but don't quote things which are already quoted
+ my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @_;
+ my $rc = 0;
+ if ($cmd =~ /[.](bat|cmd)$/) {
+ # we have to pass batch files directly to the NT command interpreter
+ $cmd = $com_spec;
+# print "system $cmd /c \"@fixargs\"\n";
+ $rc = system {$cmd} '/c', "\"@fixargs\"";
+ } else {
+# print "system $cmd \"@fixargs\"\n";
+ if($isNT) {
+ $rc = system "\"@fixargs\"";
+ } else {
+ $rc = system @fixargs;
+ }
+ }
+
+ return $rc;
+}
+
+#############################################################################
+
+sub GetTime {
+ my $tm = localtime;
+ (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900);
+ $sec = "0$sec" unless $sec > 9 ;
+ $min = "0$min" unless $min > 9 ;
+ $hour = "0$hour" unless $hour > 9 ;
+ $dd = "0$dd" unless $dd > 9 ;
+ $mm = "0$mm" unless $mm > 9 ;
+ return ($sec, $min, $hour, $dd, $mm, $yy);
+}
+
+#############################################################################
+
+sub getVersion {
+ my $dir = shift;
+ my $versionstr = shift;
+ my $version = 0;
+ my $minor = 0;
+ my $buildNumber = 0;
+ my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+ my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}";
+
+ # find the slapd executable
+ if (!$versionstr) { # version not specified on cmd line - find it
+ $prog = $dir . $progDir . $slapdExecName;
+ if (! -f $prog) {
+ $prog = $dir . $progDir2 . $slapdExecName;
+ if (-f $prog && $isNT) {
+ # if slapd is in bin/slapd and we're on NT, just assume version 1;
+ # apparently, slapd.exe doesn't like the -v argument . . .
+ return ( '1', $minor );
+ }
+ else{
+ die "Could not run slapd program $prog: $!";
+ }
+ }
+ else {
+ chdir($dir . $progDir);
+ }
+ $preserve_lib_path = $ENV{"$LIB_PATH"};
+ $ENV{"$LIB_PATH"}=
+ "$dir${PATHSEP}lib${SEP}".
+ "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}".
+ "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}".
+ $ENV{"$LIB_PATH"};
+ # read the old version from the old slapd program
+
+ open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or
+ die "Could not run slapd program $prog: $!";
+ sleep(1); # allow some data to accumulate in the pipe
+# print "Output from $prog -v:\n";
+ while (<F>) {
+ if (/^Netscape-Directory/ || /^iPlanet-Directory/i) {
+ $versionstr = $_;
+ last;
+ }
+ }
+ $code = close(F);
+ # print "$prog returned code=$code status=$?\n";
+ $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ }
+
+ if ($versionstr =~ /^Netscape-Directory\/(\d+)\.(\d+)(?:b\d)*\s+(\S+)/) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ }
+ elsif ($versionstr =~ /^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ...
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ }
+ elsif ($versionstr =~ /^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ } elsif ($versionstr =~ /(\d+)\.(\d+)/) {
+ $version = $1;
+ $minor = $2;
+ }
+
+ if ($version == 0) {
+ die "\nCould not determine version of the directory server in $dir: \n";
+ }
+
+ # distinguish the 4.1 and the 4.11 thanks to the buildNumber
+ if (($version == 4) && ($minor == 1)){
+ if (! ($buildNumber =~ /^B99\.16/)) {
+ # it's not a 4.1 Netscape Directory Server => it's a 4.11
+ $minor = 11 ;
+ }
+ }
+ # Restore the original library path
+ $ENV{"$LIB_PATH"} = $preserve_lib_path;
+ chdir($curdir) or die "Could not change directory to $curdir: $!" ;
+ return ( $version, $minor );
+}
+
+###############################################################################################
+# get current directory
+
+sub getCwd {
+ my $command = $isNT ? "cd" : "/bin/pwd";
+ open(PWDCMD, "$command 2>&1 |") or
+ die "Error: could not execute $command: $!";
+ # without the following sleep, reading from the pipe will
+ # return nothing; I guess it gives the pwd command time
+ # to get some data to read . . .
+ sleep(1);
+ my $currentdir;
+ while (<PWDCMD>) {
+ if (!$currentdir) {
+ chomp($currentdir = $_);
+ }
+ }
+ my $code = close(PWDCMD);
+# if ($code || $?) {
+# print "$command returned code=$code status=$? dir=$curdir\n";
+# }
+# print "getCwd curdir=\[$curdir\]\n";
+ return $currentdir;
+}
diff --git a/ldap/admin/src/scripts/template-migrateTo5 b/ldap/admin/src/scripts/template-migrateTo5
new file mode 100755
index 00000000..f02a6279
--- /dev/null
+++ b/ldap/admin/src/scripts/template-migrateTo5
@@ -0,0 +1,3094 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# Migrate a 4.0 directory server to a 5.x directory server
+
+########################################################################################################
+# enable the use of Perldap functions
+require DynaLoader;
+
+use Getopt::Std;
+use Mozilla::LDAP::Conn;
+use Mozilla::LDAP::Entry;
+use Mozilla::LDAP::LDIF;
+use Mozilla::LDAP::Utils qw(:all);
+use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API
+use Time::localtime;
+
+########################################################################################################
+use Class::Struct ; # load struct-building module
+
+struct S_index => {
+ names => '@' ,
+ types => '@' ,
+ oids => '@' ,
+ specific => '$'
+ };
+
+
+struct S_plugin => {
+ name => '$' ,
+ type => '$' ,
+ enable => '$' ,
+ args => '@'
+ };
+#####################################################################################################
+
+sub usage {
+ print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n");
+ print(STDERR " -o 4.xInstancePath -n 5.xInstancePath [-t tracelevel] [-L logfile]\n");
+ print(STDERR "************** parameters in brackets are optionals, others are required **************\n");
+ print(STDERR " Opts: -D rootdn - 5.x Directory Manager\n");
+ print(STDERR " : -w password - 5.x Directory Manager's password\n");
+ print(STDERR " : -w - - Prompt for 5.x Directory Manager's password\n");
+ print(STDERR " : -j filename - Read 5.x Directory Manager's password from file\n");
+ print(STDERR " : -p port - 5.x Directory Server port\n");
+ print(STDERR " : -o 4.xInstancePath - Path of the 4.x instance to migrate \n");
+ print(STDERR " : -n 5.xInstancePath - Path of the new 5.x instance\n");
+ print(STDERR " : [-t tracelevel] - specify the level of trace (0..3)\n");
+ print(STDERR " : [-L logfile] - specify the file to log the migration report \n");
+
+
+ }
+
+
+
+#############
+BEGIN {
+
+ require 'uname.lib' ;
+ $isNT = -d '\\';
+ $PATHSEP = $isNT ? "\\" : "/";
+ ${SEP} = $isNT ? ";" : ":" ;
+ @INC = ( '.', '../../../admin/admin/bin');
+ grep { s@/@\\@g } @INC if $isNT;
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ # NT needs quotes around some things unix doesn't
+ $quote = $isNT ? "\"" : "";
+
+ # If this variable is set, all file/directory creation will make sure the mode
+ # and ownership of the destination is the same as the source
+ $PRESERVE = 1 if (!$isNT);
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ if ($isNT) {
+ $os = "WINNT";
+ } else {
+ $os = &uname("-s");
+ }
+ if ($isNT) {
+ # we have to pass batch files directly to the NT command interpreter
+ $com_spec = $ENV{ComSpec};
+ if (!$com_spec) {
+ $com_spec = $ENV{COMSPEC};
+ }
+ if (!$com_spec || ! -f $com_spec) {
+ # find the first available command interpreter
+ foreach $drive (c..z) {
+ $com_spec = "$drive:\\winnt\\system32\\cmd.exe";
+ last if (-f $com_spec);
+ $com_spec = undef;
+ }
+ if (! $com_spec) {
+ # punt and pray
+ $com_spec = 'c:\winnt\system32\cmd.exe';
+ }
+ }
+ }
+ if ( $os eq "AIX" ) {
+ $dll_suffix = "_shr.a";
+ }
+ elsif ( $os eq "HP-UX" ) {
+ $dll_suffix = ".sl";
+ }
+ elsif ( $os eq "WINNT" ) {
+ $dll_suffix = ".dll";
+ }
+ else {
+ $dll_suffix = ".so";
+ }
+ $slapdExecName = $isNT ? 'slapd.exe' : 'ns-slapd';
+ # if this flag is set, we will migrate the 4.x database
+ # by doing a db2ldif -> ldif2db;
+ $convertToLDIF = 1;
+ select STDERR;
+ $| = 1;
+ select STDOUT;
+ $| = 1;
+ # if the old value for dbcachesize is less than this, make it this
+ $MIN_DBCACHESIZE = '500000';
+}
+
+SWITCH: {
+ if ($os eq "AIX") {
+ $LIB_PATH = "LIBPATH" ;
+ last SWITCH ;
+ }
+ if ($os eq "HP-UX") {
+ $LIB_PATH = "SHLIB_PATH" ;
+ last SWITCH ;
+ }
+ if ($isNT) {
+ $LIB_PATH = "PATH" ;
+ last SWITCH ;
+ }
+ else {
+ $LIB_PATH = "LD_LIBRARY_PATH" ;
+ last SWITCH ;
+ }
+ }
+
+ # 4.x parameters
+ ${oldDir} = "" ;
+ ${oldname} = "" ;
+ ${oldHome} = "" ;
+ ${oldConfDir} = "" ;
+ ${oldlocaluser} ;
+ ${olduid} ;
+ ${oldgid} ;
+
+ # 5.x parameters
+ ${root} = "{{DS-ROOT}}" ;
+ ${type} = "" ;
+ ${newname} = "" ;
+ ${newport} = "" ;
+ ${rootDN} = "" ;
+ ${rootpwd} = "" ;
+ ${localhost} = "" ;
+ ${LogFileReport} = "" ;
+ ${newuid} ;
+ ${localuser} ;
+ ${newgid} ;
+ $NO_INPUT_USER = 0 ; # by default user can give inputs during the migration process
+ ${curdir} = getCwd();
+ ${slapdExecDir} = "${root}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+
+ # specify the level of trace
+ $TRACELEVEL=1;
+
+ # get input users
+ &getParameters() ;
+ ${oldDir} = &normalizeDir("${oldDir}");
+ ${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ;
+ ${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ;
+ ${oldSlapdConf} = "${oldConfDir}slapd.conf" ;
+ ${oldDSEldif} = "${oldConfDir}dse.ldif" ;
+ ${serverHome} = "${root}${PATHSEP}$type-$newname" ;
+ ${DSEldif} = "$serverHome${PATHSEP}config${PATHSEP}dse.ldif";
+ ${ldif_rep} = "${oldConfDir}${PATHSEP}ldif${PATHSEP}" ;
+ ${oldSlapdExecDir} = "${oldDir}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+
+
+
+
+ open(LOGFILE, ">> $LogFileReport");
+
+ printTrace("\noldDir: $oldDir, oldHome: $oldHome, \noldConfDir: $oldConfDir, \noldSlapdConf: $oldSlapdConf, \nldif_rep: $ldif_rep, \nrootDN: $rootDN, \nPwd: ******, \nPort: $newport, \nNewname: $newname\n",3);
+ printTrace("\nLIB_PATH: $LIB_PATH",4);
+
+ if (!(-d $serverHome)) {
+ printMsg("\n$serverHome doesn't exist\n");
+ exit(1);
+ }
+ if (!(-d $oldHome)) {
+ printMsg("\n$oldHome doesn't exist\n");
+ exit(1);
+ }
+
+#define CONFIG_DATABASE_DIRECTIVE "database"
+#define CONFIG_DATABASE_ATTRIBUTE "nsslapd-database"
+#define CONFIG_PLUGIN_DIRECTIVE "plugin"
+#define CONFIG_PLUGIN_ATTRIBUTE "nsslapd-plugin"
+#define CONFIG_SIZELIMIT_DIRECTIVE "sizelimit"
+#define CONFIG_SIZELIMIT_ATTRIBUTE "nsslapd-sizelimit"
+#define CONFIG_ORCAUTO_DIRECTIVE "orcauto"
+#define CONFIG_ORCAUTO_ATTRIBUTE "nsslapd-orcauto"
+#define CONFIG_TIMELIMIT_DIRECTIVE "timelimit"
+#define CONFIG_TIMELIMIT_ATTRIBUTE "nsslapd-timelimit"
+#define CONFIG_SUFFIX_DIRECTIVE "suffix"
+#define CONFIG_SUFFIX_ATTRIBUTE "nsslapd-suffix"
+#define CONFIG_READONLY_DIRECTIVE "readonly"
+#define CONFIG_READONLY_ATTRIBUTE "nsslapd-readonly"
+#define CONFIG_REFERRAL_DIRECTIVE "referral"
+#define CONFIG_REFERRAL_ATTRIBUTE "nsslapd-referral"
+#define CONFIG_OBJECTCLASS_DIRECTIVE "objectclass"
+#define CONFIG_OBJECTCLASS_ATTRIBUTE "nsslapd-objectclass"
+#define CONFIG_ATTRIBUTE_DIRECTIVE "attribute"
+#define CONFIG_ATTRIBUTE_ATTRIBUTE "nsslapd-attribute"
+#define CONFIG_SCHEMACHECK_DIRECTIVE "schemacheck"
+#define CONFIG_SCHEMACHECK_ATTRIBUTE "nsslapd-schemacheck"
+#define CONFIG_LOGLEVEL_DIRECTIVE "loglevel"
+#define CONFIG_LOGLEVEL_ATTRIBUTE "nsslapd-errorlog-level"
+#define CONFIG_ACCESSLOGLEVEL_DIRECTIVE "accessloglevel"
+#define CONFIG_ACCESSLOGLEVEL_ATTRIBUTE "nsslapd-accesslog-level"
+#define CONFIG_ACCESSLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "accesslog-maxNumOfLogsPerDir"
+#define CONFIG_ACCESSLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-accesslog-maxlogsperdir"
+#define CONFIG_ERRORLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "errorlog-maxNumOfLogsPerDir"
+#define CONFIG_ERRORLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-errorlog-maxlogsperdir"
+#define CONFIG_AUDITLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "auditlog-maxNumOfLogsPerDir"
+#define CONFIG_AUDITLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-auditlog-maxlogsperdir"
+#define CONFIG_ACCESSLOG_MAXLOGSIZE_DIRECTIVE "accesslog-maxlogsize"
+#define CONFIG_ACCESSLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-accesslog-maxlogsize"
+#define CONFIG_ERRORLOG_MAXLOGSIZE_DIRECTIVE "errorlog-maxlogsize"
+#define CONFIG_ERRORLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-errorlog-maxlogsize"
+#define CONFIG_AUDITLOG_MAXLOGSIZE_DIRECTIVE "auditlog-maxlogsize"
+#define CONFIG_AUDITLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-auditlog-maxlogsize"
+#define CONFIG_ACCESSLOG_LOGROTATIONTIME_DIRECTIVE "accesslog-logrotationtime"
+#define CONFIG_ACCESSLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-accesslog-logrotationtime"
+#define CONFIG_ERRORLOG_LOGROTATIONTIME_DIRECTIVE "errorlog-logrotationtime"
+#define CONFIG_ERRORLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-errorlog-logrotationtime"
+#define CONFIG_AUDITLOG_LOGROTATIONTIME_DIRECTIVE "auditlog-logrotationtime"
+#define CONFIG_AUDITLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-auditlog-logrotationtime"
+#define CONFIG_ACCESSLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "accesslog-logrotationtimeunit"
+#define CONFIG_ACCESSLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-accesslog-logrotationtimeunit"
+#define CONFIG_ERRORLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "errorlog-logrotationtimeunit"
+#define CONFIG_ERRORLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-errorlog-logrotationtimeunit"
+#define CONFIG_AUDITLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "auditlog-logrotationtimeunit"
+#define CONFIG_AUDITLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-auditlog-logrotationtimeunit"
+#define CONFIG_ACCESSLOG_MAXLOGDISKSPACE_DIRECTIVE "accesslog-maxlogdiskspace"
+#define CONFIG_ACCESSLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-accesslog-logmaxdiskspace"
+#define CONFIG_ERRORLOG_MAXLOGDISKSPACE_DIRECTIVE "errorlog-maxlogdiskspace"
+#define CONFIG_ERRORLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-errorlog-logmaxdiskspace"
+#define CONFIG_AUDITLOG_MAXLOGDISKSPACE_DIRECTIVE "auditlog-maxlogdiskspace"
+#define CONFIG_AUDITLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-auditlog-logmaxdiskspace"
+#define CONFIG_ACCESSLOG_MINFREEDISKSPACE_DIRECTIVE "accesslog-minfreediskspace"
+#define CONFIG_ACCESSLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-accesslog-logminfreediskspace"
+#define CONFIG_ERRORLOG_MINFREEDISKSPACE_DIRECTIVE "errorlog-minfreediskspace"
+#define CONFIG_ERRORLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-errorlog-logminfreediskspace"
+#define CONFIG_AUDITLOG_MINFREEDISKSPACE_DIRECTIVE "auditlog-minfreediskspace"
+#define CONFIG_AUDITLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-auditlog-logminfreediskspace"
+#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIME_DIRECTIVE "accesslog-logexpirationtime"
+#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-accesslog-logexpirationtime"
+#define CONFIG_ERRORLOG_LOGEXPIRATIONTIME_DIRECTIVE "errorlog-logexpirationtime"
+#define CONFIG_ERRORLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-errorlog-logexpirationtime"
+#define CONFIG_AUDITLOG_LOGEXPIRATIONTIME_DIRECTIVE "auditlog-logexpirationtime"
+#define CONFIG_AUDITLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-auditlog-logexpirationtime"
+#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "accesslog-logexpirationtimeunit"
+#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-accesslog-logexpirationtimeunit"
+#define CONFIG_ERRORLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "errorlog-logexpirationtimeunit"
+#define CONFIG_ERRORLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-errorlog-logexpirationtimeunit"
+#define CONFIG_AUDITLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "auditlog-logexpirationtimeunit"
+#define CONFIG_AUDITLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-auditlog-logexpirationtimeunit"
+#define CONFIG_ACCESSLOG_LOGGING_ENABLED_DIRECTIVE "accesslog-logging-enabled"
+#define CONFIG_ACCESSLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-accesslog-logging-enabled"
+#define CONFIG_ERRORLOG_LOGGING_ENABLED_DIRECTIVE "errorlog-logging-enabled"
+#define CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-errorlog-logging-enabled"
+#define CONFIG_AUDITLOG_LOGGING_ENABLED_DIRECTIVE "auditlog-logging-enabled"
+#define CONFIG_AUDITLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-auditlog-logging-enabled"
+#define CONFIG_ROOTDN_DIRECTIVE "rootdn"
+#define CONFIG_ROOTDN_ATTRIBUTE "nsslapd-rootdn"
+#define CONFIG_ROOTPW_DIRECTIVE "rootpw"
+#define CONFIG_ROOTPW_ATTRIBUTE "nsslapd-rootpw"
+#define CONFIG_ROOTPWSTORAGESCHEME_DIRECTIVE "rootpwstoragescheme"
+#define CONFIG_ROOTPWSTORAGESCHEME_ATTRIBUTE "nsslapd-rootpwstoragescheme"
+#define CONFIG_UPDATEDN_DIRECTIVE "updatedn"
+#define CONFIG_UPDATEDN_ATTRIBUTE "nsslapd-updatedn"
+#define CONFIG_UPDATEPW_DIRECTIVE "updatepw"
+#define CONFIG_UPDATEPW_ATTRIBUTE "nsslapd-updatepw"
+#define CONFIG_UPDATESSLCLIENT_DIRECTIVE "updateSSLclient"
+#define CONFIG_UPDATESSLCLIENT_ATTRIBUTE "nsslapd-updateSSLclient"
+#define CONFIG_AUDITFILE_DIRECTIVE "auditfile"
+#define CONFIG_AUDITFILE_ATTRIBUTE "nsslapd-auditlog"
+#define CONFIG_LASTMOD_DIRECTIVE "lastmod"
+#define CONFIG_LASTMOD_ATTRIBUTE "nsslapd-lastmod"
+#define CONFIG_INCLUDE_DIRECTIVE "include"
+#define CONFIG_INCLUDE_ATTRIBUTE "nsslapd-include"
+#define CONFIG_DYNAMICCONF_DIRECTIVE "dynamicconf"
+#define CONFIG_DYNAMICCONF_ATTRIBUTE "nsslapd-dynamicconf"
+#define CONFIG_USEROC_DIRECTIVE "useroc"
+#define CONFIG_USEROC_ATTRIBUTE "nsslapd-useroc"
+#define CONFIG_USERAT_DIRECTIVE "userat"
+#define CONFIG_USERAT_ATTRIBUTE "nsslapd-userat"
+#define CONFIG_SVRTAB_DIRECTIVE "svrtab"
+#define CONFIG_SVRTAB_ATTRIBUTE "nsslapd-svrtab"
+#ifndef _WIN32
+#define CONFIG_LOCALUSER_DIRECTIVE "localuser"
+#define CONFIG_LOCALUSER_ATTRIBUTE "nsslapd-localuser"
+#endif /* !_WIN32 */
+#define CONFIG_LOCALHOST_DIRECTIVE "localhost"
+#define CONFIG_LOCALHOST_ATTRIBUTE "nsslapd-localhost"
+#define CONFIG_PORT_DIRECTIVE "port"
+#define CONFIG_PORT_ATTRIBUTE "nsslapd-port"
+#define CONFIG_LISTENHOST_DIRECTIVE "listenhost"
+#define CONFIG_LISTENHOST_ATTRIBUTE "nsslapd-listenhost"
+#define CONFIG_SECURITY_DIRECTIVE "security"
+#define CONFIG_SECURITY_ATTRIBUTE "nsslapd-security"
+#define CONFIG_SSL3CIPHERS_DIRECTIVE "SSL3ciphers"
+#define CONFIG_SSL3CIPHERS_ATTRIBUTE "nsslapd-SSL3ciphers"
+#define CONFIG_ACCESSLOG_DIRECTIVE "accesslog"
+#define CONFIG_ACCESSLOG_ATTRIBUTE "nsslapd-accesslog"
+#define CONFIG_ERRORLOG_DIRECTIVE "errorlog"
+#define CONFIG_ERRORLOG_ATTRIBUTE "nsslapd-errorlog"
+#define CONFIG_INSTANCEDIR_DIRECTIVE "instancedir"
+#define CONFIG_INSTANCEDIR_ATTRIBUTE "nsslapd-instancedir"
+#define CONFIG_SECUREPORT_DIRECTIVE "secure-port"
+#define CONFIG_SECUREPORT_ATTRIBUTE "nsslapd-securePort"
+#define CONFIG_SECURELISTENHOST_DIRECTIVE "secure-listenhost"
+#define CONFIG_SECURELISTENHOST_ATTRIBUTE "nsslapd-securelistenhost"
+#define CONFIG_THREADNUMBER_DIRECTIVE "threadnumber"
+#define CONFIG_THREADNUMBER_ATTRIBUTE "nsslapd-threadnumber"
+#define CONFIG_MAXTHREADSPERCONN_DIRECTIVE "maxthreadsperconn"
+#define CONFIG_MAXTHREADSPERCONN_ATTRIBUTE "nsslapd-maxthreadsperconn"
+#if !defined(_WIN32) && !defined(AIX)
+#define CONFIG_MAXDESCRIPTORS_DIRECTIVE "maxdescriptors"
+#define CONFIG_MAXDESCRIPTORS_ATTRIBUTE "nsslapd-maxdescriptors"
+#endif /* !_WIN32 && ! AIX */
+#define CONFIG_RESERVEDESCRIPTORS_DIRECTIVE "reservedescriptors"
+#define CONFIG_RESERVEDESCRIPTORS_ATTRIBUTE "nsslapd-reservedescriptors"
+#define CONFIG_IDLETIMEOUT_DIRECTIVE "idletimeout"
+#define CONFIG_IDLETIMEOUT_ATTRIBUTE "nsslapd-idletimeout"
+#define CONFIG_IOBLOCKTIMEOUT_DIRECTIVE "ioblocktimeout"
+#define CONFIG_IOBLOCKTIMEOUT_ATTRIBUTE "nsslapd-ioblocktimeout"
+#define CONFIG_NTSYNCH_DIRECTIVE "ntsynch"
+#define CONFIG_NTSYNCH_ATTRIBUTE "nsslapd-NTSynch"
+#define CONFIG_NTSYNCHUSESSL_DIRECTIVE "ntsynchusessl"
+#define CONFIG_NTSYNCHUSESSL_ATTRIBUTE "nsslapd-NTSynch-SSL"
+#define CONFIG_NTSYNCHPORT_DIRECTIVE "ntsynch-port"
+#define CONFIG_NTSYNCHPORT_ATTRIBUTE "nsslapd-NTSynch-port"
+#define CONFIG_ACCESSCONTROL_DIRECTIVE "accesscontrol"
+#define CONFIG_ACCESSCONTROL_ATTRIBUTE "nsslapd-accesscontrol"
+#define CONFIG_GROUPEVALNESTLEVEL_DIRECTIVE "groupevalnestlevel"
+#define CONFIG_GROUPEVALNESTLEVEL_ATTRIBUTE "nsslapd-groupevalnestlevel"
+#define CONFIG_NAGLE_DIRECTIVE "nagle"
+#define CONFIG_NAGLE_ATTRIBUTE "nsslapd-nagle"
+#define CONFIG_PW_CHANGE_DIRECTIVE "pw_change"
+#define CONFIG_PW_CHANGE_ATTRIBUTE "passwordChange"
+#define CONFIG_PW_MUSTCHANGE_DIRECTIVE "pw_must_change"
+#define CONFIG_PW_MUSTCHANGE_ATTRIBUTE "passwordMustChange"
+#define CONFIG_PW_SYNTAX_DIRECTIVE "pw_syntax"
+#define CONFIG_PW_SYNTAX_ATTRIBUTE "passwordCheckSyntax"
+#define CONFIG_PW_MINLENGTH_DIRECTIVE "pw_minlength"
+#define CONFIG_PW_MINLENGTH_ATTRIBUTE "passwordMinLength"
+#define CONFIG_PW_EXP_DIRECTIVE "pw_exp"
+#define CONFIG_PW_EXP_ATTRIBUTE "passwordExp"
+#define CONFIG_PW_MAXAGE_DIRECTIVE "pw_maxage"
+#define CONFIG_PW_MAXAGE_ATTRIBUTE "passwordMaxAge"
+#define CONFIG_PW_MINAGE_DIRECTIVE "pw_minage"
+#define CONFIG_PW_MINAGE_ATTRIBUTE "passwordMinAge"
+#define CONFIG_PW_WARNING_DIRECTIVE "pw_warning"
+#define CONFIG_PW_WARNING_ATTRIBUTE "passwordWarning"
+#define CONFIG_PW_HISTORY_DIRECTIVE "pw_history"
+#define CONFIG_PW_HISTORY_ATTRIBUTE "passwordHistory"
+#define CONFIG_PW_INHISTORY_DIRECTIVE "pw_inhistory"
+#define CONFIG_PW_INHISTORY_ATTRIBUTE "passwordInHistory"
+#define CONFIG_PW_LOCKOUT_DIRECTIVE "pw_lockout"
+#define CONFIG_PW_LOCKOUT_ATTRIBUTE "passwordLockout"
+#define CONFIG_PW_STORAGESCHEME_DIRECTIVE "pw_storagescheme"
+#define CONFIG_PW_STORAGESCHEME_ATTRIBUTE "passwordStorageScheme"
+#define CONFIG_PW_MAXFAILURE_DIRECTIVE "pw_maxfailure"
+#define CONFIG_PW_MAXFAILURE_ATTRIBUTE "passwordMaxFailure"
+#define CONFIG_PW_UNLOCK_DIRECTIVE "pw_unlock"
+#define CONFIG_PW_UNLOCK_ATTRIBUTE "passwordUnlock"
+#define CONFIG_PW_LOCKDURATION_DIRECTIVE "pw_lockduration"
+#define CONFIG_PW_LOCKDURATION_ATTRIBUTE "passwordLockoutDuration"
+#define CONFIG_PW_RESETFAILURECOUNT_DIRECTIVE "pw_resetfailurecount"
+#define CONFIG_PW_RESETFAILURECOUNT_ATTRIBUTE "passwordResetFailureCount"
+#define CONFIG_ACCESSLOG_BUFFERING_DIRECTIVE "logbuffering"
+#define CONFIG_ACCESSLOG_BUFFERING_ATTRIBUTE "nsslapd-accesslog-logbuffering"
+#define CONFIG_CHANGELOG_DIR_DIRECTIVE "changelogdir"
+#define CONFIG_CHANGELOG_DIR_ATTRIBUTE "nsslapd-changelogdir"
+#define CONFIG_CHANGELOG_SUFFIX_DIRECTIVE "changelogsuffix"
+#define CONFIG_CHANGELOG_SUFFIX_ATTRIBUTE "nsslapd-changelogsuffix"
+#define CONFIG_CHANGELOG_MAXENTRIES_DIRECTIVE "changelogmaxextries"
+#define CONFIG_CHANGELOG_MAXENTRIES_ATTRIBUTE "nsslapd-changelogmaxentries"
+#define CONFIG_CHANGELOG_MAXAGE_DIRECTIVE "changelogmaxage"
+#define CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE "nsslapd-changelogmaxage"
+#define CONFIG_RETURN_EXACT_CASE_DIRECTIVE "return_exact_case"
+#define CONFIG_RESULT_TWEAK_DIRECTIVE "result_tweak"
+#define CONFIG_REFERRAL_MODE_DIRECTIVE "referralmode"
+#define CONFIG_ATTRIBUTE_NAME_EXCEPTION_DIRECTIVE "attribute_name_exceptions"
+#define CONFIG_MAXBERSIZE_DIRECTIVE "maxbersize"
+#define CONFIG_VERSIONSTRING_DIRECTIVE "versionstring"
+#define CONFIG_ENQUOTE_SUP_OC_DIRECTIVE "enquote_sup_oc"
+#define CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE "nsslapd-enquote_sup_oc"
+#define CONFIG_BASEDN_DIRECTIVE "certmap-basedn"
+#define CONFIG_BASEDN_ATTRIBUTE "nsslapd-certmap-basedn"
+
+%HashParametersName = ();
+
+# The following hash displays only general server parameters to migrate under cn=config
+%GeneralSrvParamToMigrate = (
+ 'accesscontrol' => 'nsslapd-accesscontrol',
+ 'errorlog-logging-enabled' => 'nsslapd-errorlog-logging-enabled',
+ 'accesslog-logging-enabled' => 'nsslapd-accesslog-logging-enabled',
+ 'auditlog-logging-enabled' => 'nsslapd-auditlog-logging-enabled',
+ 'logbuffering' => 'nsslapd-accesslog-logbuffering',
+ 'accesslog-logexpirationtime' => 'nsslapd-accesslog-logexpirationtime',
+ 'accesslog-logexpirationtimeunit' => 'nsslapd-accesslog-logexpirationtimeunit',
+ 'accesslog-maxlogdiskspace' => 'nsslapd-accesslog-logmaxdiskspace',
+ 'accesslog-minfreediskspace' => 'nsslapd-accesslog-logminfreediskspace',
+ 'accesslog-logrotationtime' => 'nsslapd-accesslog-logrotationtime',
+ 'accesslog-logrotationtimeunit' => 'nsslapd-accesslog-logrotationtimeunit',
+ 'accesslog-maxlogsize' => 'nsslapd-accesslog-maxlogsize',
+ 'accesslog-maxnumoflogsperdir' => 'nsslapd-accesslog-maxLogsPerDir',
+ 'auditlog-logexpirationtime' => 'nsslapd-auditlog-logexpirationtime',
+ 'auditlog-logexpirationtimeunit' => 'nsslapd-auditlog-logexpirationtimeunit',
+ 'auditlog-maxlogdiskspace' => 'nsslapd-auditlog-logmaxdiskspace',
+ 'auditlog-minfreediskspace' => 'nsslapd-auditlog-logminfreediskspace',
+ 'auditlog-logrotationtime' => 'nsslapd-auditlog-logrotationtime',
+ 'auditlog-logrotationtimeunit' => 'nsslapd-auditlog-logrotationtimeunit',
+ 'auditlog-maxlogsize' => 'nsslapd-auditlog-maxlogsize',
+ 'auditlog-maxnumoflogsperdir' => 'nsslapd-auditlog-maxLogsPerDir',
+ 'certmap-basedn' => 'nsslapd-certmap-basedn',
+ 'enquote_sup_oc' => 'nsslapd-enquote-sup-oc',
+ 'loglevel' => 'nsslapd-errorlog-level',
+ 'errorlog-logexpirationtime' => 'nsslapd-errorlog-logexpirationtime',
+ 'errorlog-logexpirationtimeunit' => 'nsslapd-errorlog-logexpirationtimeunit',
+ 'errorlog-maxlogdiskspace' => 'nsslapd-errorlog-logmaxdiskspace',
+ 'errorlog-minfreediskspace' => 'nsslapd-errorlog-logminfreediskspace',
+ 'errorlog-logrotationtime' => 'nsslapd-errorlog-logrotationtime',
+ 'errorlog-logrotationtimeunit' => 'nsslapd-errorlog-logrotationtimeunit',
+ 'errorlog-maxlogsize' => 'nsslapd-errorlog-maxlogsize',
+ 'errorlog-maxnumoflogsperdir' => 'nsslapd-errorlog-maxlogsperdir',
+ 'idletimeout' => 'nsslapd-idletimeout',
+ 'ioblocktimeout' => 'nsslapd-ioblocktimeout',
+ 'lastmod' => 'nsslapd-lastmod',
+ 'listenhost' => 'nsslapd-listenhost',
+ 'maxdescriptors' => 'nsslapd-maxdescriptors',
+ 'referral' => 'nsslapd-referral',
+ 'reservedescriptors' => 'nsslapd-reservedescriptors',
+ 'rootpwstoragescheme' => 'nsslapd-rootpwstoragescheme',
+ 'schemacheck' => 'nsslapd-schemacheck',
+ 'secure-port' => 'nsslapd-securePort',
+ 'security' => 'nsslapd-security',
+ 'sizelimit' => 'nsslapd-sizelimit',
+ 'SSL3ciphers' => 'nsslapd-SSL3ciphers',
+ 'timelimit' => 'nsslapd-timelimit',
+ 'pw_change' => 'passwordChange',
+ 'pw_syntax' => 'passwordCheckSyntax',
+ 'pw_exp' => 'passwordExp',
+ 'pw_history' => 'passwordHistory',
+ 'pw_inhistory' => 'passwordInHistory',
+ 'pw_lockout' => 'passwordLockout',
+ 'pw_lockduration' => 'passwordLockoutDuration',
+ 'pw_maxage' => 'passwordMaxAge',
+ 'pw_maxfailure' => 'passwordMaxFailure',
+ 'pw_minage' => 'passwordMinAge',
+ 'pw_minlength' => 'passwordMinLength',
+ 'pw_must_change' => 'passwordMustChange',
+ 'pw_resetfailurecount' => 'passwordResetFailureCount',
+ 'pw_storagescheme' => 'passwordStorageScheme',
+ 'pw_unlock' => 'passwordUnlock',
+ 'pw_warning' => 'passwordWarning'
+);
+
+# the following hash displays global parameters related to database stored under cn=config,cn=ldbm database,cn=plugins,cn=config
+%GlobalConfigLDBMparamToMigrate = (
+ 'allidsthreshold' => 'nsslapd-allidsthreshold',
+ 'lookthroughlimit' => 'nsslapd-lookthroughlimit',
+ 'mode' => 'nsslapd-mode',
+ 'dbcachesize' => 'nsslapd-dbcachesize'
+);
+
+# the following hash displays specific parameters to each backends and stored under cn=DBname,cn=ldbm database,cn=plugins,cn=config
+%LDBMparamToMigrate = (
+ 'cachesize' => 'nsslapd-cachesize',
+ 'readonly' => 'nsslapd-readonly'
+);
+
+%stdIncludes = (
+ "${oldConfDir}slapd.at.conf", "\n",
+ "${oldConfDir}slapd.oc.conf", "\n",
+ "${oldConfDir}java-object-schema.conf", "\n",
+ "${oldConfDir}ns-admin-schema.conf", "\n",
+ "${oldConfDir}ns-calendar-schema.conf", "\n",
+ "${oldConfDir}ns-certificate-schema.conf", "\n",
+ "${oldConfDir}ns-common-schema.conf", "\n",
+ "${oldConfDir}ns-compass-schema.conf", "\n",
+ "${oldConfDir}ns-delegated-admin-schema.conf", "\n",
+ "${oldConfDir}ns-directory-schema.conf", "\n",
+ "${oldConfDir}ns-legacy-schema.conf", "\n",
+ "${oldConfDir}ns-mail-schema.conf", "\n",
+ "${oldConfDir}ns-mcd-browser-schema.conf", "\n",
+ "${oldConfDir}ns-mcd-config-schema.conf", "\n",
+ "${oldConfDir}ns-mcd-li-schema.conf", "\n",
+ "${oldConfDir}ns-mcd-mail-schema.conf", "\n",
+ "${oldConfDir}ns-media-schema.conf", "\n",
+ "${oldConfDir}ns-mlm-schema.conf", "\n",
+ "${oldConfDir}ns-msg-schema.conf", "\n",
+ "${oldConfDir}ns-netshare-schema.conf", "\n",
+ "${oldConfDir}ns-news-schema.conf", "\n",
+ "${oldConfDir}ns-proxy-schema.conf", "\n",
+ "${oldConfDir}ns-value-schema.conf", "\n",
+ "${oldConfDir}ns-wcal-schema.conf", "\n",
+ "${oldConfDir}ns-cos-schema.conf", "\n",
+ "${oldConfDir}ns-web-schema.conf", "\n"
+);
+
+%userDefinedConfigFiles = (
+ "slapd.conf", "\n",
+ "slapd.ldbm.conf", "\n",
+ "slapd.user_at.conf", "\n",
+ "slapd.user_oc.conf", "\n",
+ "ns-schema.conf", "\n"
+ );
+
+$CIS_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.15" ;
+$TELEPHONE_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.50" ;
+$DN_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.12" ;
+$CES_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.26" ;
+$INT_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.27" ;
+$BIN_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.5" ;
+
+%allowedPlugins = (
+ "cis", $CIS_SYNTAX_OID,
+ "tel", $TELEPHONE_SYNTAX_OID,
+ "dn", $DN_SYNTAX_OID,
+ "ces", $CES_SYNTAX_OID,
+ "int", $INT_SYNTAX_OID,
+ "bin", $BIN_SYNTAX_OID
+ );
+
+%allowedModifiers = (
+ "single", "SINGLE-VALUE"
+ );
+# "override" is not supported anymore and "operational" cannot be used in user defined attribute.
+
+@oldSuffixes = () ; # array of 4.x suffixes (with "o=netscaperoot" if presents)
+
+# link beetwen the name of the suffix and its associated DBname
+%DBNAMES = () ;
+%DBDirectory = () ;
+
+%oldhash = () ;
+
+# list of standard plugin's in version 4
+%stdPlugins = (
+ "7-bit check" => "\n",
+ "binary syntax" => "\n",
+ "case exact string syntax" => "\n",
+ "case ignore string syntax" => "\n",
+ "distinguished name syntax" => "\n",
+ "integer syntax" => "\n",
+ "internationalization plugin" => "\n",
+ "referential integrity postoperation" => "\n",
+ "telephone syntax" => "\n",
+ "uid uniqueness" => "\n"
+
+ );
+
+# list of standard indexes configured out of the box in version 4
+%stdIndex = (
+ 'aci', "\n",
+ 'changenumber', "\n",
+ 'copiedfrom', "\n",
+ 'dncomp', "\n",
+ 'entrydn', "\n",
+ 'numsubordinates', "\n",
+ 'objectclass', "\n",
+ 'parentid', "\n"
+);
+
+# list of user added Plugin's. In 5.x, they 'll need to be recompiled
+@badPlugins = () ;
+
+%newIndex = () ;
+
+%User_oc = () ;
+# push objectnames as they are encountered in config files.
+@User_oc_names = () ;
+
+%User_at = () ;
+
+
+
+#Usage parameters
+$USER_OC_FILE_MODIFIED = 0 ; # 0 if user don't want to modify LDIF objectclasses before processing, 1 else
+$USER_AT_FILE_MODIFIED = 0 ;
+$INDEX_FILE_MODIFIED = 0 ;
+
+# Shutdown the legacy Directory instance
+printTrace("\nShutdown the legacy Directory Server instance: ${oldHome}",0);
+&stopServer($oldDir, 'slapd-'.$oldname);
+
+# compare configuration files with the standard ones
+CompareStdConfigFiles() ;
+die "\n\n The version of the product you want to migrate is not a 4.x Netscape Directory Server\n" unless ($oldVersion == 4) ;
+
+FillHashParametersName() ;
+
+############### Connect to the 5.x LDAP Directory Server ######################
+$ENV{"$LIB_PATH"} = "$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"} ;
+my $LDAPservername = &getLDAPservername();
+die "\n Migration aborted. Check your 4.x and 5.x Netscape Directory Server are installed on the same machine \n" if ( $LDAPservername == -1 );
+$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n";
+
+# continue if the connection to 5.x LDAP server is successful !
+printTrace("\nConnected to $Version.$Minor LDAP server\n",0) ;
+
+# get the uid and gid of the 5.x slapd user
+($localuser, $newuid, $newgid) = getuid_gid();
+# get the uid and gid of the 4.x slapd user
+($oldlocaluser, $olduid, $oldgid) = getolduid_gid();
+
+# backup 5.x configuration files in <root_server5>/slapd-instancename/config
+printTrace("\nBackup $serverHome${PATHSEP}config on $serverHome${PATHSEP}config_backup ...",0);
+&backupConfigFiles();
+
+# Parse the main configuration file: slapd.conf
+printTrace("\nParse the configuration file: $oldSlapdConf...",0);
+ParseSlapdConf("< ${oldSlapdConf}");
+
+#migrate key/cert databases
+printTrace("\nMigrate key/cert databases...",0);
+&MigrateSSL();
+
+# Update parameters : general server parameters, global LDBM parameter, specific backend parameters
+printTrace("\nUpdate general server parameters...",0);
+AddGeneralParameters();
+printTrace("\nUpdate global LDBM parameters...",0);
+AddGeneralLDBMParameters();
+printTrace("\nUpdate specific backend parameters...",0);
+AddSpecificLDBMParameters();
+
+##### FOR TESTING PURPOSE ONLY ########
+#
+#testIndexUpdating();
+#
+#######################################
+
+# Migrate some entries contained in the old dse.ldif, and migrate certmap.conf
+&MigrateDSE() ;
+&MigrateCertmap() ;
+
+# update 5.x attribute definitions
+LDAPmodify_User_at();
+
+# update 5.x object classes definitions
+LDAPmodify_User_oc();
+
+# add new indexes to each backends
+LDAPmodify_Indexes();
+
+# migrate Plug'ins parameters (enable attribute, and arguments)
+LDAPmodify_stdPlugin();
+
+################## Close the connection to 5.x LDAP Server #####################
+$conn->close;
+
+
+################## stop the 5.x instance and Export/Import the data, restart the server ##################
+if (%DBNAMES) {
+ &stopServer($root,'slapd-'.$newname);
+ printTrace("\ndata processing...",0) ;
+ # migrate data for each suffix: 4.x -> LDIF files
+ &db2ldif($oldSlapdConf);
+
+ # migrate LDIF data to the 5.x database: LDIF -> 5.x
+ &manyLdif2db();
+ &startServer();
+}
+else {
+ printTrace("\nThere no 4.x non-standard suffixes to migrate",0);
+}
+
+printMsg("\n\n ****** End of migration ******\n\n");
+
+close(LOGFILE);
+
+
+###########################################################################################
+# get input users
+sub getParameters {
+ my $exit = 0 ;
+ my $i = 0;
+ my $pwdfile= "";
+ while ($i <= $#ARGV) {
+ if ( "$ARGV[$i]" eq "-D" ) { # directory manager
+ if (! $rootDN) {
+ $rootDN = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-w") { # password
+ if (! $rootpwd) {
+ $rootpwd = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-j") { # password file
+ if (! $pwdfile) {
+ $pwdfile = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-o") { # 4.x instance path
+ if (! $oldHome ) {
+ $oldHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $oldHome if $isNT ;
+ if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; }
+ if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) {
+ $oldDir = $1 ;
+ $type = $2 ;
+ $oldname = $3 ;
+ if ($isNT) {
+ $oldDir = lc($oldDir) ;
+ $type = lc($type) ;
+ $oldname = lc($oldname) ;
+ $oldHome = lc($oldHome) ;
+ grep { s@/@\\@g } $oldDir ;
+ grep { s@/@\\@g } $oldHome ;
+ }
+ }
+ else {
+ print("\nThe 4.x instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-n") { # 5.x instance path
+ if (! $serverHome ) {
+ $serverHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $root if $isNT ;
+ grep { s@\\@/@g } $serverHome if $isNT ;
+ if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; }
+ if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) {
+ $root = $1 if ($1);
+ $type = $2 ;
+ $newname = $3 ;
+ if ($isNT) {
+ $root = lc($root) ;
+ $type = lc($type) ;
+ $newname = lc($newname) ;
+ $serverHome = lc($serverHome) ;
+ grep { s@/@\\@g } $root ;
+ grep { s@/@\\@g } $serverHome ;
+ }
+ }
+ else {
+ print("\nThe 5.x instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-p") { # 5.x DS port
+ if (! $newport ) {
+ $newport = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL
+ my $value = $ARGV[++$i] ;
+ if ($value =~ /[0-3]/) {
+ $TRACELEVEL = $value ;
+ }
+ else {
+ print("\nThe tracelevel must belong to 0..3 interval");
+ &usage();
+ exit();
+ }
+ } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing
+ $NO_INPUT_USER = 1 ;
+ } elsif ("$ARGV[$i]" eq "-L") { # migration logfile
+ $LogFileReport = $ARGV[++$i] ;
+ }
+ else {
+ print("\nThe option $ARGV[$i] is not recognized");
+ &usage() ;
+ exit(1);
+ }
+ $i++;
+ }
+ if (! $rootDN) {
+ print("\nThe rootDN is missing");
+ $exit = 1;
+ }
+ if ($pwdfile ne "") {
+ # Open file and get the password
+ unless (open (RPASS, $pwfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $rootpwd = <RPASS>;
+ chomp($rootpwd);
+ close(RPASS);
+ } elsif ($rootpwd eq "-"){
+ # Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+ # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $rootpwd = ReadLine(0);
+# chomp($rootpwd);
+# ReadMode('normal');
+ }
+ if (! $rootpwd) {
+ print("\nThe rootpwd is missing");
+ $exit = 1 ;
+ }
+ if (! $newport) {
+ print("\nThe port is missing");
+ $exit = 1;
+ }
+ if (! $serverHome) {
+ print("\nThe 5.x instance path is missing");
+ $exit = 1;
+ }
+ if (! $oldHome) {
+ print("\nThe 4.x instance path is missing");
+ $exit = 1;
+ }
+ if ((! $LogFileReport) && $serverHome) {
+ ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime();
+ $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log";
+ }
+
+ if ($exit) {
+ &usage() ;
+ exit(1);
+ }
+
+}
+
+
+###############################################################################
+# This subroutine is used to parse the slapd.conf configuration file and migrate specific parameters contained in it
+
+
+sub ParseSlapdConf {
+ my $oldsrc = shift;
+ my $NumLine = 0 ;
+ # read the old conf file into a hash table
+ open( OLDSRC, $oldsrc ) || die "Can't open $oldsrc: $!: ";
+ LINE: while ( <OLDSRC> ) {
+ $NumLine++ ;
+ printTrace("\nLine: $_",4) ;
+ if (/^\s*\#/) { # skip comments
+ printTrace("\n# ",4) ;
+ next LINE;
+ }
+ if (/^\s*$/) { # skip blank lines
+ printTrace("\nBLANK LINE",4);
+ next LINE;
+ } elsif (/^suffix\s+/i) {
+ chomp($_) ;
+ CheckSuffix($_);
+ } elsif (/^plugin/i) {
+ printTrace("\nPLUGIN",4);
+ chomp($_);
+ if (! &isAStandardPlugin($_)) {
+ push @badPlugins, $_;
+ }
+ else {
+ my $Plugin = $_ ;
+ if (! &ParsePlugin($_,$NumLine)) {
+ printMsg("\nLine $NumLine, syntax error of the plugin:\n$Plugin");
+ }
+ }
+ } elsif (/^include\s+[\"]?(.*?)[\"]?\s*$/i) {
+ # strip leading and trailing "
+ my $include_file = $1 ;
+ grep { s@/@\\@g } $include_file if $isNT;
+ if (! &isAStandardInclude($include_file)) {
+ printTrace("\nFILE: $1 NOT STANDARD",4) ;
+ &ParseConfigurationFile($include_file);
+ printTrace("\nEXIT ParseConfigurationFile: $include_file",4) ;
+ }
+ } elsif (/^userat\s+[\"]?(.*?)[\"]?\s*$/i) {
+ printTrace("\nuserat: $1",4);
+ my $at_file = $1 ;
+ grep { s@/@\\@g } $at_file if $isNT;
+ # Parse user defined attributes
+ &ParseAttributesFile($at_file);
+ } elsif (/^useroc\s+[\"]?(.*?)[\"]?\s*$/i) {
+ printTrace("\nuseroc: $1",4);
+ my $oc_file = $1 ;
+ grep { s@/@\\@g } $oc_file if $isNT;
+ # Parse user defined object classes
+ &ParseObjectClassesFile($oc_file);
+ } elsif (/^dynamicconf\s+[\"]?(.*?)[\"]?\s*$/i){
+ printTrace("\ndynamicconf: $1",4);
+ my $dynamiconf_file = $1 ;
+ grep { s@/@\\@g } $dynamiconf_file if $isNT;
+ # Parse dynamic configuration file (e-g slapd.ldbm.conf)
+ &ParseConfigurationFile($dynamiconf_file);
+ } elsif (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/) {
+ printTrace("\nParseParameters: $1",4);
+ # Parse parameters and record the associated value in %oldhash
+ &ParseParameters($1,$2,$NumLine);
+ } else {
+ printTrace("\nUnknown format of configuration data: $_",0); }
+ }
+ close(OLDSRC);
+
+ }
+
+
+
+#############################################################################
+# return 1 if the suffix already exists, 0 else
+sub existSuffix {
+ my $suffixname = shift ;
+ my $entry = $conn->search("cn=\"$suffixname\",cn=mapping tree,cn=config ", "base","objectclass=*") ;
+ return 1 if ($entry) ;
+ return 0 ;
+}
+
+# return the name of the backend if it has been successfully created, 0 else
+sub createBackend {
+ my $suffixname = shift ;
+ my $backend = "MigratedDB_0" ;
+ my $NbRetry = 1 ;
+ my $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ;
+ while ($entry) {
+ # try to find another name for the backend
+ $backend = "MigratedDB_$NbRetry" ;
+ $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ;
+ $NbRetry++;
+ }
+ # normally I should have a unique name for the backend
+ my $suffixarg = "nsslapd-suffix" ;
+ $entry = $conn->newEntry() ;
+ $entry->setDN("cn=$backend,cn=ldbm database,cn=plugins,cn=config");
+ $entry->setValues("objectclass", "top", "extensibleObject", "nsBackendInstance" );
+ $entry->setValues("cn", $backend );
+ $entry->setValues($suffixarg, $suffixname );
+ my $res = $conn->add($entry) ;
+ if ($res) {
+ return $backend ;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+# return 1, if add the new entry in the mapping tree, else 0
+sub AddEntryInMappingTree {
+ my $backend = shift ;
+ my $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ;
+ if ($entry) {
+ printTrace("\nAddEntry in progress ...",4) ;
+ my $suffixarg = "nsslapd-suffix" ;
+ my $statearg = "nsslapd-state" ;
+ my $backendarg= "nsslapd-backend";
+ my $suffixname = $entry->{$suffixarg}[0];
+ $entry = $conn->newEntry() ;
+ $entry->setDN("cn=\"$suffixname\",cn=mapping tree,cn=config") ;
+ $entry->setValues("objectclass", "top", "extensibleObject", "nsMappingTree" );
+ $entry->setValues("cn", "\"$suffixname\"");
+ $entry->setValues($statearg, "backend");
+ $entry->setValues($backendarg, $backend);
+ return $conn->add($entry);
+ }
+ else {
+ printTrace("\nNo AddEntry processed for $backend",4);
+ return 0 ;
+ }
+}
+
+
+# Treat the case where the suffix is "o=NetscapeRoot"
+sub CheckSuffix {
+ my $suffix = shift ;
+ my $suffixname ;
+ if (!(/^suffix\s+\"?(.*?)\"?\s*$/i)) {
+ printMsg("Syntax error of the suffix: $suffix");
+ return 0 ;
+ }
+ else {
+ $suffixname = $1 ;
+ }
+ if (/^suffix\s+\"?\s*o=netscaperoot\s*\"?\s*$/i) {
+ printTrace("\nFor the suffix o=NetscapeRoot, we do nothing",1);
+ # treat the case where the suffix is "o=NetscapeRoot"
+ }
+ else {
+ push @oldSuffixes, $_;
+ # check if the suffix already exists in the 5.x DS target
+ if (! existSuffix($suffixname)) {
+ printTrace("\nSuffix $suffixname doesn't exist",1) ;
+ # create a new backend with the name of the suffix preceded by MigratedDB_
+ my $backend = createBackend($suffixname) ;
+ if ($backend) {
+ printTrace("\nBackend: $backend has been created !!!",1);
+ # if the creation of the backend is ok, we add a new entry in the mapping tree
+ if (AddEntryInMappingTree($backend)) {
+ # We add the association dbname->suffix in the hash %DBNAMES
+ $DBNAMES{$suffixname} = $backend ;
+ # get the db filename
+ $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ;
+ my $dirarg = "nsslapd-directory";
+ $DBDirectory{$backend} = $entry->{$dirarg}[0];
+ printTrace("\nThe relation $backend->$suffixname has been added to the mapping tree",2);
+ }
+ else {
+ printMsg("\nCOULD NOT ADD ENTRY: $backend->$suffixname IN MAPPINGTREE");
+ }
+ }
+ else {
+ printMsg("\nCOULD NOT CREATE BACKEND: $backend");
+ }
+ }
+ else {
+ printTrace("\nSuffix: $suffixname already exists",1);
+ # the suffix already exists in the 5.x DS
+ }
+ }
+ return 1 ;
+}
+
+#############################################################################
+# Usefull to know the standard configuration
+sub isAStandardPlugin {
+ my $line = shift;
+ chomp($line);
+ printTrace("\nStdPlugin?: $line",4);
+ if ($line =~ /^plugin\s+(database|extendop|preoperation|postoperation|matchingrule|syntax)\s+(on|off)\s+\"(.*?)\"\s+\"(.*?)\"\s+(\S+)(.*)$/i) {
+ # $1 = <type>, $2 = <on|off>, $3 = <name>, $4 = <pathname>, $5 = <init_function>, $6 = [<arg>]*
+ printTrace("\nName: $3, pathname: $4, init_function: $5",4);
+
+ my $LC_line = lc($3);
+ my $Value = $stdPlugins{$LC_line} ;
+ if ($Value) {
+ printTrace("\nIS A STANDARD PLUGIN",4);
+ }
+ else {
+ printTrace("\nNOT A STANDARD PLUGIN",4);
+ }
+ return $stdPlugins{$LC_line} ;
+ }
+ else {
+ printTrace("\nSYNTAX ERROR PLUGIN",4);
+ return 0 ;
+ }
+}
+
+sub isAStandardIndex {
+ my $line = shift ;
+ chomp($line);
+ if ($line =~ /^index\s+(\S+).*/i) {
+ my $LC_line = lc($1);
+ my $Value = $stdIndex{$LC_line} ;
+ printTrace("\nInclude: $LC_line \nValue: $Value", 4);
+ return $stdIndex{$LC_line};
+ }
+ else {
+ return 0 ;
+ }
+}
+
+
+sub isAStandardInclude {
+ my $line = shift;
+
+ chomp($line);
+ if ($isNT){
+ return $stdIncludes{lc($line)};
+ }
+ else {
+ return $stdIncludes{$line} ;
+ }
+}
+
+#############################################################################
+#
+# Execute a Perldap command to update plugins definition in the 5.x schema
+
+sub LDAPmodify_stdPlugin {
+ my $Filename = shift ;
+ my @pluginames = keys(%stdPlugins);
+ if (! $STDPLUGINS_FILE_MODIFIED) {
+ printTrace("\nLDAPmodify_plugin",4);
+ printTrace("\nMigrate plugin's...",1);
+ foreach $pluginame ( @pluginames ) {
+ my $update_plugin = 0 ;
+ my $ref_plugin = $stdPlugins{$pluginame};
+ if ($ref_plugin ne "\n") {
+ my $name = $ref_plugin->name ;
+ my $entry = $conn->search("cn=$name,cn=plugins,cn=config", "base","objectclass=nsSlapdPlugin") ;
+ if ($entry) {
+ my $pluginenabled="nsslapd-pluginenabled" ;
+ if (($entry->{$pluginenabled}[0]) ne $ref_plugin->enable) {
+ $update_plugin = 1 ;
+ my $enable = $ref_plugin->enable ;
+ printTrace("\n$pluginame, plugin-enable: $enable",3) ;
+ $entry->setValues($pluginenabled, $enable );
+ }
+ my $ArgNum = 0 ;
+ foreach $ArgValue (@{$ref_plugin->args}) {
+ my $Arg="nsslapd-pluginarg$ArgNum";
+ printTrace("\n$Arg: $ArgValue",3) ;
+ if ($entry->{$Arg}[0] ne $ArgValue) {
+ printTrace("\n$pluginame, $Arg: $ArgValue",3) ;
+ $update_plugin = 1 ;
+ $entry->setValues($Arg, $ArgValue) ;
+ }
+ $ArgNum++ ;
+ }
+ if ($update_plugin) {
+ printTrace("\n$pluginame is being updated...",2);
+ my $res = $conn->update($entry) ;
+ if ($res) {
+ printTrace("\nupdated !",2);
+ }
+ else {
+ printMsg("\nError during update of plugin: $pluginame") ;
+ $MigrationErrors .= "\nError during update of plugin: $pluginame";
+ }
+ }
+ else {
+ printTrace("\n$pluginame has not changed",4);
+ }
+ }
+ else {
+ printMsg("\ncan't access the plugin: cn=$name,cn=plugins,cn=config");
+ }
+ }
+ else {
+ printTrace("\nPLUGIN NOT RECORDED: $pluginame",4) ;
+ }
+ }
+ }
+ else {
+ # treat the case where the user wants to look at these plugins before processing
+ }
+}
+
+#############################################################################
+# Execute Perldap command to add new indexes to the migrated instances
+
+sub LDAPmodify_Indexes {
+ my $Filename = shift ;
+ my @indexnames = keys(%newIndex);
+ my @suffixnames = keys(%DBNAMES);
+ if ((! $INDEX_FILE_MODIFIED) && (%DBNAMES)) {
+ # we update indexes only if there is at least one backend to migrate
+ printTrace("\nLDAPmodify_indexes",4);
+ printTrace("\nMigrate indexes...",1);
+ foreach $indexname ( @indexnames ) {
+ printTrace("\nIndexName: $indexname",4);
+ printTrace("\nIndexTypes: .@{$newIndex{$indexname}->types}.", 4) ;
+ printTrace("\nIndexOIDS: .@{$newIndex{$indexname}->oids}.", 4) ;
+ foreach $suffixname ( @suffixnames ) {
+ # check if the index already exists !
+ printTrace("\nsearch for cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...", 3);
+ my $entry = $conn->search("cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex");
+ if (! $entry) {
+ # create a new index
+ printTrace("index $indexname is being created under cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...",2);
+ my $entry = $conn->newEntry();
+ $entry->setDN("cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config");
+ $entry->setValues("objectclass", "top", "nsIndex" ) ;
+ $entry->setValues("cn", $indexname) ;
+ $entry->setValues("nssystemindex", "false") ;
+ my @types = @{$newIndex{$indexname}->types} ;
+ my @oids = @{$newIndex{$indexname}->oids} ;
+ $entry->setValues("nsindextype", @types) if (@types) ;
+ $entry->setValues("nsmatchingrule", @oids ) if (@oids);
+ my $res = $conn->add($entry) ;
+ if ($res) {
+ printTrace("\nAdd index successfully: $indexname for backend: $DBNAMES{$suffixname}",2);
+ }
+ else {
+ printMsg("\n Failed to add the index: $indexname to backend: $DBNAMES{$suffixname}");
+ $MigrationErrors .= "\n Failed to add the index: $indexname to backend: $DBNAMES{$suffixname}" ;
+ }
+ }
+ elsif ($entry->{nssystemindex}[0] eq "false") {
+ # if the index is not a system index, we update it
+ printTrace("\nindex $indexname is being processed under cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...",2);
+ my @types = @{$newIndex{$indexname}->types} ; printTrace("\ntypes: .@types.",2) ;
+ my @oids = @{$newIndex{$indexname}->oids} ; printTrace("\noids: .@oids.",2) ;
+ my @existing_types = $entry->getValues("nsindextype");
+ my @existing_oids = $entry->getValues("nsmatchingrule");
+ # get the elements present in @types and not present in @existing_types
+ my @typesToAdd = &getDiff(\@types, \@existing_types);
+ # same for matchingrules
+ my @oidsToAdd = &getDiff(\@oids, \@existing_oids);
+ foreach $newtype (@typesToAdd) {
+ $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2);
+ }
+ foreach $newoid (@oidsToAdd) {
+ $entry->addValue("nsmatchingrule", $newoid);
+ }
+ if (@typesToAdd || @oidsToAdd) {
+ my $res = $conn->update($entry) ;
+ if ($res) {
+ printTrace("\nUpdate index successfully: $indexname for backend: $DBNAMES{$suffixname}",2);
+ }
+ else {
+ printMsg("\n Failed to update the index: $indexname to backend: $DBNAMES{$suffixname}");
+ $MigrationErrors .= "\n Failed to update the index: $indexname to backend: $DBNAMES{$suffixname}" ;
+ }
+ }
+ else {
+ printTrace("\nNothing to update",2);
+ }
+ }
+ else {
+ printTrace("\nThe index: $indexname is a system index. It can't be updated",2);
+ }
+ }
+ }
+
+ }
+ else {
+ # treat the case where the user wants to look at these indexes before processing
+ }
+
+}
+
+#############################################################################
+#
+# Execute a Perldap command to add all user defined object classes in the 5.x schema
+
+sub LDAPmodify_User_oc {
+ my $Filename = shift ;
+ if (! $USER_OC_FILE_MODIFIED) {
+ printTrace("\nLDAPmodify_User_oc",4);
+ printTrace("\nMigrate objectclasses...",1);
+ foreach $objectname ( @User_oc_names ) {
+ my $entry = $conn->search("cn=schema", "base","objectclass=*") ;
+ die "\ncan't connect to object: cn=schema\n" unless ($entry);
+ printTrace("\nObjectName: $objectname\nValue: $User_oc{$objectname}",3);
+ next if ($entry->hasValue("objectclasses",$User_oc{$objectname},1)) ;
+ $entry->addValue("objectclasses",$User_oc{$objectname},"1") ;
+ my $res = $conn->update($entry) ;
+ if (! $res) {
+ printMsg("\nCan\'t add objectclass to the schema: $User_oc{$objectname}");
+ my $msg = $conn->getErrorString();
+ printMsg("\nMsg: $msg");
+ $MigrationErrors .= "\nCan\'t add objectclass to the schema: $User_oc{$objectname}" ;
+ }
+ else {
+ printTrace("\nobjectclass: $User_oc{$objectname} added",2);
+ }
+ }
+ }
+ else {
+ # treat the case where the user wants to look at these objectclasses before processing
+ }
+}
+
+#############################################################################
+#
+# Execute a Perldap command to add all user defined attributes in the 5.x schema
+
+sub LDAPmodify_User_at {
+ my $Filename = shift ;
+ my @attributenames = keys(%User_at);
+ if (! $USER_AT_FILE_MODIFIED) {
+
+ printTrace("\nLDAPmodify_User_at",4);
+ printTrace("\nMigrate attributes...",1);
+ foreach $attributename ( @attributenames ) {
+ my $entry = $conn->search("cn=schema", "base","objectclass=*") ;
+ printTrace("\nAtributeName: $attributename, Value: $User_at{$attributename}",3);
+ die "\nentry not found cn=schema\n" unless $entry ;
+ next if ($entry->hasValue("attributetypes",$User_at{$attributename},1) ) ;
+ my $res = $entry->addValue("attributetypes",$User_at{$attributename},"1") ;
+ if (! $res) {
+ printMsg("\nCan\'t add attribute to the schema: $User_at{$attributename}");
+ $MigrationErrors .= "\nCan\'t add attribute to the schema: $User_at{$attributename}" ;
+ }
+ my $res = $conn->update($entry) ;
+ if ($res) {
+ printTrace("\nattribute: $attributename added",2);
+ }
+ else {
+ printMsg("\nCan\'t add attribute to the schema: $User_at{$attributename}");
+ my $msg = $conn->getErrorString();
+ printMsg("\nMsg: $msg");
+ $MigrationErrors .= "\nCan\'t add attribute to the schema: $User_at{$attributename}" ;
+ }
+ }
+ }
+ else {
+ # treat the case where the user wants to look at these attributes before processing
+ }
+}
+
+#############################################################################
+# Add an object class to the user_oc hash and reset the object !!!
+sub AddObjectClass {
+ my $ObjectClass = shift ;
+ my $ObjectName = $ObjectClass->{'ObjectName'} ;
+ my $Object_oid = $ObjectClass->{'Object_oid'} ;
+ my $Object_superior = $ObjectClass->{'Object_superior'} ;
+ my $Object_requires = $ObjectClass->{'Object_requires'} ;
+ my $Object_allows = $ObjectClass->{'Object_allows'} ;
+ my $ObjectClassDef = "( $Object_oid NAME \'$ObjectName\' DESC \'\' SUP $Object_superior STRUCTURAL MUST ($Object_requires) MAY ($Object_allows) X-ORIGIN \'user defined\' )";
+ if ( (!($ObjectName =~ /^top$/i)) && ( ! $User_oc{$ObjectName} )) {
+ $User_oc{$ObjectName} = $ObjectClassDef ;
+ push @User_oc_names, $ObjectName ;
+ printTrace("ObjectName: $ObjectName \nObject_oid: $Object_oid \nObject_superior:$Object_superior \nObject_requires: $Object_requires \nObject_allows: $Object_allows \nObjectClassDefinition: $User_oc{$ObjectName}\n",4);
+ }
+ elsif ( ($User_oc{$ObjectName}) && ($User_oc{$ObjectName} ne $ObjectClassDef) ) {
+ printMsg("\nAttempt to redifine the objectclass: $ObjectName previously defined in your configuration file. Operation not allowed ");
+ }
+ else {
+ printMsg("\nAttempt to redifine the objectclass: top. Operation not allowed");
+ }
+ resetObjectClass($ObjectClass);
+}
+
+#############################################################################
+# Build an LDIF attribute and add it to the user_at hash
+sub AddAttribute {
+ my $Attr = shift ;
+ my $AttributeName = $Attr->{'AttributeName'};
+ my $Attribute_oid = $Attr->{'Attribute_oid'};
+ my $Attribute_aliases = $Attr->{'Attribute_aliases'};
+ my $Attribute_syntax = $Attr->{'Attribute_syntax'};
+ my $Attribute_single = $Attr->{'Attribute_single'};
+ my $AttributeDef = "( $Attribute_oid NAME ( \'$AttributeName\' $Attribute_aliases) DESC \'User Defined Attribute\' SYNTAX $Attribute_syntax $Attribute_single X-ORIGIN 'user defined' )" ;
+ printTrace("\nAttributeDef: $AttributeDef",4);
+ $User_at{$AttributeName} = $AttributeDef ;
+}
+#############################################################################
+# add the index structure to the newIndex hash
+sub AddIndex {
+ my $ref_index = shift ;
+ my $state = shift ;
+ printTrace("\nAddIndex, last state: $state",4) ;
+ if ($state == 1) {
+ $ref_index->specific("ALL") ;
+ return 1 ;
+ }
+ elsif ($state == 6) {
+ $ref_index->specific("NONE") ;
+ return 1 ;
+ }
+ if (($state == 1) || ($state == 3) || ($state == 5) || ($state == 6)) {
+ foreach $name (@{$ref_index->names}) {
+ $newIndex{$name} = $ref_index ; # record the ref to the index struct in the newIndex hash
+ }
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+#############################################################################
+# add the plugin structure to the stdPlugin hash
+
+sub AddPlugin {
+ my $ref_plugin = shift ;
+ printTrace("\nAddPlugin",4) ;
+ $stdPlugins{lc($ref_plugin->name)} = $ref_plugin ;
+ my $name = $ref_plugin->name ;
+ my $type = $ref_plugin->type ;
+ my $enable = $ref_plugin->enable ;
+
+ printTrace("\nPluginName: $name",4);
+ printTrace("\nPluginType: $type",4);
+ printTrace("\nPluginEnable: $enable",4);
+ printTrace("\nPluginArgs: @{$ref_plugin->args}",4);
+ return 1 ;
+}
+
+
+#############################################################################
+# parse a plugin definition and call the addindex
+
+sub ParsePlugin {
+ my $Plugin = shift ;
+ my $NumLine = shift ;
+ my $state = 0 ;
+ my $ErrorMsg = "Syntax error of a plugin definition. \n line parsed:";
+ my $ref_plugin = S_plugin->new();
+ printTrace("\nParsePlugin: $_",4);
+ if (/^plugin\s+(database|extendop|preoperation|postoperation|matchingrule|syntax)\s+(on|off)\s+\"(.*?)\"\s+\"(.*?)\"\s+(\S+)(.*)$/i) {
+ # $1 = <type>, $2 = <on|off>, $3 = <name>, $4 = <pathname>, $5 = <init_function>, $6 = [<arg>]*
+ $ref_plugin->name($3);
+ $ref_plugin->type($1);
+ $ref_plugin->enable($2);
+ $_ = $6 ;
+ my $ArgNb = 0 ;
+ my $prec ;
+ my $arg ;
+ my $Unix_oldDir = $oldDir ;
+ my $Unix_root = $root ;
+ grep { s@\\@/@g } $Unix_oldDir if $isNT;
+ grep { s@\\@/@g } $Unix_root if $isNT;
+ while (!(/^\s*$/)) {
+ if (/^\s*\".*?\"/) {
+ s/^\s*\"(.*?)\"(.*)/$2/i ;
+ $arg = $1 ;
+ }
+ elsif (/^\s*[^\"\s]+/) {
+ s/^\s*([^\"\s]+)(.*)/$2/i ;
+ $arg = $1 ;
+ }
+ $prec = $_ ;
+ $_ = $arg ;
+
+ s@$Unix_oldDir@$Unix_root@ig ;
+ s/$type-$oldname/$type-$newname/ig ;
+ @{$ref_plugin->args}[$ArgNb++] = $_ ;
+ $_ = $prec ;
+ }
+ if (/^\s*$/) {
+ return AddPlugin($ref_plugin);
+ }
+ else {
+ return 0 ;
+ }
+ }
+ return 0 ;
+}
+
+#############################################################################
+# parse an index definition and call the addindex
+
+sub ParseIndex {
+ my $index = shift ;
+ my $NumLine = shift ;
+ my $ref_index = S_index->new() ;
+ my $Value ;
+ my $state = 0 ;
+ my $ErrorMsg = "Syntax error of an index definition.\nline parsed:";
+ printTrace("\nParseIndex: $_",4) ;
+ s/,/, /g ;
+ s/\s+,/,/g ;
+ s/^index\s+//i ; # substitute the token index
+ while (!(/^\s*$/)) {
+ s/^\s*(\S+)(.*)$/$2/ ;
+ $Value = $1 ;
+ printTrace("\nValue: $Value",4);
+ printTrace("\nState: $state",4) ;
+ SWITCH: {
+ if ($state == 0) {
+ if ($Value =~ /[^\.]/) {
+ if ($Value =~ /(\S+),$/) {
+ push @{$ref_index->names}, $1 ;
+ }
+ else {
+ $state = 1 ;
+ push @{$ref_index->names}, $Value ;
+ }
+ }
+ else {
+ return 0 ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 1) {
+ if ($Value =~ /^none$/i) {
+ $state = 6 ; # end of the index definition
+ }
+ elsif ($Value =~ /^\"\"$/) {
+ $state = 4 ; # we expect to have at least one OID
+ }
+ elsif ($Value =~ /(\S+),$/) {
+ $state = 2 ;
+ push @{$ref_index->types}, $1 ;
+ }
+ else {
+ $state = 3 ;
+ push @{$ref_index->types}, $Value ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 2) {
+ if ($Value =~ /(\S+),$/) {
+ push @{$ref_index->types}, $1 ;
+ }
+ else {
+ $state = 3 ;
+ push @{$ref_index->types}, $Value ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 3) {
+ if ($Value =~ /(\S+),$/) {
+ $state = 4 ;
+ push @{$ref_index->oids}, $1 ;
+ }
+ else {
+ $state = 5 ;
+ push @{$ref_index->oids}, $Value ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 4) {
+ if ($Value =~ /(\S+),$/) {
+ push @{$ref_index->oids}, $1 ;
+ }
+ else {
+ $state = 5 ;
+ push @{$ref_index->oids}, $Value ;
+ }
+ last SWITCH ;
+ }
+ }
+ }
+return AddIndex($ref_index,$state) ;
+
+}
+
+#############################################################################
+
+sub ParseAttribute {
+
+
+ my $Attr = shift ;
+ my $NumLine = shift ;
+ my $state = 1 ;
+ my $ErrorMsg = "Syntax error of an attribute definition.\nline parsed:";
+ my %Attribute = (
+ 'AttributeName' => "",
+ 'Attribute_oid' => "",
+ 'Attribute_aliases' => "",
+ 'Attribute_syntax' => "",
+ 'Attribute_single' => ""
+ );
+ my $AttributeName = " ";
+ printTrace("\nParseAttribute",4);
+ while (!(/^\s*$/)) {
+ s/^(.*?)(\S+)\s*$/$1/ ;
+ printTrace("\nValue: $2",4);
+ printTrace("\nState: $state",4) ;
+ my $Value = $2 ;
+ SWITCH: {
+ if ($state == 1) {
+ if (isAllowedModifier($Value)) {
+ $state = 1 ;
+ $modifier = lc($Value);
+ $AttrVar = 'Attribute_' . $modifier ;
+ $Attribute{$AttrVar} = &getModifierValue($Value) ;
+ }
+ elsif (&isAllowedPlugin($Value)) {
+ $state = 2 ;
+ $Attribute{'Attribute_syntax'} = &getSyntaxOid($Value) ;
+ }
+ else {
+ return 0 ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 2) {
+ if ($Value =~ /[\.]|-oid$/) {
+ $Attribute{'Attribute_oid'} = "$Value" ;
+ printTrace("\nAttribute-oid: $Attribute{'Attribute_oid'}",3);
+ $state = 3 ;
+ }
+ elsif ($Value =~ /[^\.]/) {
+ $AttributeName = $Attribute{'AttributeName'} ;
+ if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;}
+ $Attribute{'AttributeName'} = $Value ;
+ $state = 4 ;
+ }
+ else {
+ return 0 ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 3) {
+ if ($Value =~ /[^\.]/) {
+ $AttributeName = $Attribute{'AttributeName'} ;
+ if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;}
+ $Attribute{'AttributeName'} = $Value ;
+ $state = 4 ; }
+ else {
+ return 0 ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 4) {
+ if ($Value =~/^attribute$/i){
+ $state = 5;
+ }
+ elsif ($Value =~/[^\.]/i) {
+ $AttributeName = $Attribute{'AttributeName'} ;
+ if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;}
+ $Attribute{'AttributeName'} = $Value ;
+ }
+ else {
+ return 0 ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 5) {
+ return 0 ;
+ last SWITCH ;
+ }
+ }
+ }
+ $Attribute{'Attribute_oid'} = $Attribute{'AttributeName'} . '-oid' unless ($Attribute{'Attribute_oid'}) ;
+ return AddAttribute(\%Attribute) ;
+}
+
+
+#############################################################################
+# fill in the hash HashParametersName
+
+sub FillHashParametersName {
+ my @paramnames = ( keys(%GeneralSrvParamToMigrate), keys(%GlobalConfigLDBMparamToMigrate), keys(%LDBMparamToMigrate));
+ foreach $param (@paramnames) {
+ $HashParametersName{$param} = '\n';
+ }
+}
+
+
+# Parse parameters
+sub ParseParameters {
+ my $param = shift ;
+ my $value = shift ;
+ my $NumLine = shift ;
+ my $ErrorMsg = "parameter unknown, or not to be migrated: ";
+ if ($HashParametersName{lc($param)} && ($value !~ /^\s*$/)) {
+ $HashParametersName{lc($param)} = $value ;
+ printTrace("\nParam: $param is present",4);
+ }
+ else {
+ printTrace("\n$NumLine, $ErrorMsg,$param",4);
+ }
+
+}
+
+# add general server parameters
+sub AddGeneralParameters {
+ my @paramnames = keys(%GeneralSrvParamToMigrate);
+ my $entry = $conn->search("cn=config","base","objectclass=*");
+ die "\ncan't access to object: cn=config. \nMigration stopped\n" unless ($entry);
+ printTrace("\nAddGeneralParameters",4);
+ foreach $param (@paramnames) {
+ my $LDAPparam = $GeneralSrvParamToMigrate{$param} ;
+ my $Value = $HashParametersName{$param} ;
+ if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) {
+ printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4);
+ $entry->setValues($LDAPparam, $Value);
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nUpdate successfully $LDAPparam ",0);
+ }
+ else {
+ printMsg("\nCan't update parameter: $LDAPparam");
+ }
+ }
+ }
+}
+
+
+# add general LDBM parameters
+sub AddGeneralLDBMParameters {
+ my @paramnames = keys(%GlobalConfigLDBMparamToMigrate);
+ my $entry = $conn->search("cn=config,cn=ldbm database,cn=plugins,cn=config","base","objectclass=*");
+ die "\ncan't access to object: cn=config,cn=ldbm database,cn=plugins,cn=config. \nMigration stopped\n" unless ($entry);
+ printTrace("\nAddGeneralLDBMParameters",4);
+ foreach $param (@paramnames) {
+ my $LDAPparam = $GlobalConfigLDBMparamToMigrate{$param} ;
+ my $Value = $HashParametersName{$param} ;
+ if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) {
+ printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4);
+ $entry->setValues($LDAPparam, $Value);
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nUpdate successfully $LDAPparam ",0);
+ }
+ else {
+ printMsg("\nCan't update parameter: $LDAPparam");
+ }
+ }
+ }
+}
+
+# add specific LDBM parameters
+sub AddSpecificLDBMParameters {
+ my @paramnames = keys(%LDBMparamToMigrate);
+ my %REV_DBNAMES = reverse %DBNAMES ;
+ my @dbnames = keys(%REV_DBNAMES);
+ printTrace("\nAddSpecificLDBMParameters",4);
+ foreach $dbname (@dbnames) {
+ my $entry = $conn->search("cn=$dbname,cn=ldbm database,cn=plugins,cn=config","base","objectclass=*");
+ die "\ncan't access to object: cn=$dbname,cn=ldbm database,cn=plugins,cn=config. \nMigration stopped\n" unless ($entry);
+ foreach $param (@paramnames) {
+ my $LDAPparam = $LDBMparamToMigrate{$param} ;
+ my $Value = $HashParametersName{$param} ;
+ if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) {
+ printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4);
+ $entry->setValues($LDAPparam, $Value);
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nUpdate successfully $LDAPparam",2);
+ }
+ else {
+ printMsg("\nCan't update parameter: $LDAPparam");
+ }
+ }
+ }
+ }
+}
+
+#############################################################################
+# Parse a configuration file potentialy tuned by the user (different from slapd.user_oc.conf and slapd.user_at.conf)
+
+sub ParseConfigurationFile {
+
+ my $FileToParse = shift;
+ my $NumLine = 0;
+ my $PARSE_OBJECTCLASSES = 0 ; # 1 if there are objectclass definitions in the file
+ printTrace("\nParseConfigurationFile: $FileToParse",4) ;
+ printTrace("\nParse $FileToParse",2);
+ # read each line of the configuration file
+ my $CONFIGFILE = "CONFIGFILE.$FileToParse" ;
+ open( $CONFIGFILE, $FileToParse ) || die "Can't open $FileToParsec: $!: ";
+ LINE: while ( <$CONFIGFILE> ) {
+ $NumLine++ ;
+ if (/^\s*\#/) { # skip comments
+ next LINE;
+ }
+ if (/^\s*$/) { # skip blank lines
+ next LINE;
+ } elsif (/^suffix\s+/i) {
+ chomp($_) ;
+ CheckSuffix($_) ;
+ } elsif (/^plugin/i) {
+ chomp($_);
+ if (! &isAStandardPlugin($_)) {
+ push @badPlugins, $_;
+ }
+ else {
+ my $Plugin = $_ ;
+ if (! &ParsePlugin($_,$NumLine)) {
+ printMsg("\nLine $NumLine, syntax error of the plugin:\n$Plugin");
+ }
+ }
+ } elsif (/^index/i) {
+ chomp($_);
+ if (! &isAStandardIndex($_)) {
+ my $Index = $_ ;
+ if (! &ParseIndex($_,$NumLine)) {
+ printMsg("\nLine $NumLine, syntax error of index:\n$Index");
+ }
+ }
+ } elsif (/^include\s+[\"]?(.*?)[\"]?\s*$/i) {
+ # strip leading and trailing "
+ my $include_file = $1 ;
+ grep { s@/@\\@g } $include_file if $isNT;
+ if (! &isAStandardInclude($include_file)) {
+ &ParseConfigurationFile($include_file);
+ }
+ } elsif (/^attribute\s+\S+/i) {
+ chomp($_);
+ my $Attrib = $_ ;
+ if (! &ParseAttribute($_,$NumLine)) {
+ printMsg("\nLine $NumLine, syntax error of attribute:\n$Attrib");
+ }
+ } elsif (/^objectclass\s+(\S+)\s*$/i) {
+ # At least one objectclass is present in the file
+ $PARSE_OBJECTCLASSES = 1;
+ } elsif (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/) {
+ # Parse parameters and record the associated value in %Oldhash
+ &ParseParameters($1,$2,$NumLine);
+ }
+ }
+ close($CONFIGFILE);
+ ParseObjectClassesFile($FileToParse) if ($PARSE_OBJECTCLASSES); # parse objectclass definition
+
+}
+
+#############################################################################
+# Parse the file specified in the userat attribute
+
+sub ParseAttributesFile {
+ my $userat_file=shift ;
+ my $NumLine = 0;
+ printTrace("\nParseAttributesFile: $userat_file",4);
+ printTrace("\nParse user defined attributes file: $userat_file",2);
+ # read each line of the configuration file
+ open( ATTRFILE, $userat_file ) || die "Can't open $FileToParsec: $!: ";
+ LINE: while ( <ATTRFILE> ) {
+ $NumLine++ ;
+ if (/^\s*\#/) { # skip comments
+ next LINE;
+ }
+ if (/^\s*$/) { # skip blank lines
+ next LINE;
+ } elsif (/^attribute\s+\S+/i) {
+ chomp($_);
+ my $Attrib = $_ ;
+ if (! &ParseAttribute($_, $NumLine)) {
+ printMsg("\nLine $NumLine, syntax error of attribute:\n$Attrib");
+ }
+ }
+ }
+ close(ATTRFILE);
+}
+
+#############################################################################
+# Parse the file specified in the useroc token
+
+sub ParseObjectClassesFile {
+ my $useroc_file = shift ;
+ my %ObjectClass = (
+ 'ObjectName' => " ",
+ 'Object_oid' => " ",
+ 'Object_superior' => "top",
+ 'Object_requires' => " ",
+ 'Object_allows' => " "
+ );
+
+ my $state = 0;
+ my $ErrorMsg = "Syntax error of an object class definition.\nline parsed:";
+ my $LineNb = 0 ; # Number of the current line parsed in the file
+ printTrace("ParseObjectClassesFile: $useroc_file\n",4) ;
+ # read each line of the configuration file
+ open( OBJCLASSFILE, $useroc_file ) || die "Can't open $FileToParsec: $!: ";
+ printTrace("Begin the parsing of the file: $useroc_file",4);
+ LINE: while ( <OBJCLASSFILE> ) {
+ printTrace("Current Line: $_",4);
+ $LineNb++ ;
+ if (/^\s*\#/) { # skip comments
+ next LINE;
+ }
+ if (/^\s*$/) { # skip blank lines
+ next LINE;
+ }
+ SWITCH: {
+ if ($state == 0) { resetObjectClass(\%ObjectClass);
+ if (/^objectclass\s+(\S+)\s*$/i) {
+ $ObjectClass{'ObjectName'} = $1;
+ $state = 1 ;}
+ else {} # printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 1) {if (/^\s+oid\s+(\S+)\s*$/i) {
+ $ObjectClass{'Object_oid'} = $1;
+ $state = 2 ;}
+ elsif (/^\s+superior\s+(\S+)\s*$/i) {
+ $ObjectClass{'Object_superior'} = $1;
+ $state = 3 ;
+ }
+ elsif (/^\s+requires\s*$/i) {
+ $state = 4;
+ }
+ elsif (/^\s+allows\s*$/i) {
+ $state = 5;
+ }
+ else {$state=0; printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 2) {if (/^\s+superior\s+(\S+)\s*$/i) {
+ $ObjectClass{'Object_superior'} = $1;
+ $state = 3 ;}
+ elsif (/^\s+requires\s*$/i) {
+ $state = 4;
+ }
+ elsif (/^\s+allows\s*$/i) {
+ $state = 5;
+ }
+ else { $state=0; printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 3) {if (/^\s+requires\s*$/i)
+ { $state = 4; }
+ elsif (/^objectclass\s+(\S+)\s*$/i) {
+ # run an ldap add before to continue
+ &AddObjectClass(\%ObjectClass);
+ $ObjectClass{'ObjectName'} = $1;
+ $state = 1 ;}
+ elsif (/^\s+allows\s*$/i)
+ { $state = 5; }
+ else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 4) {if (/^\s+([^,\s]+),\s*$/i) {
+ $ObjectClass{'Object_requires'}.=$1." \$ "; }
+ elsif (/^\s+([^,\s]+)\s*$/i) {
+ $ObjectClass{'Object_requires'}.=$1." ";
+ $state = 6; }
+ else {$state = 0;printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 5) {if (/^\s+([^,\s]+),\s*$/i) {
+ $ObjectClass{'Object_allows'}.=$1." \$ "; }
+ elsif (/^\s+([^,\s]+)\s*$/i) {
+ $ObjectClass{'Object_allows'}.=$1." ";
+ # run an ldap add before to continue
+ &AddObjectClass(\%ObjectClass);
+ $state = 0; }
+ else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 6) {if (/^objectclass\s+(\S+)\s*$/i) {
+ # run an ldap add before to continue
+ &AddObjectClass(\%ObjectClass);
+ $ObjectClass{'ObjectName'} = $1;
+ $state = 1 ;}
+ elsif (/^\s+allows\s*$/i) {
+ $state = 5;}
+ else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ }
+ }
+ close(OBJCLASSFILE);
+ if (($state == 3) || ($state == 4) || ($state == 5) || ($state == 6)) {
+ &AddObjectClass(\%ObjectClass);
+ }
+ printTrace("state: $state",4);
+}
+
+#############################################################################
+# printMsg print message to the user standard output.
+
+sub printMsg {
+
+ my $TypeMsg = shift ;
+ my $Msg = shift ;
+ my $LineNb = shift ;
+ if ($LineNb) {
+ printTrace("Line: $LineNb, $TypeMsg, $Msg");
+ }
+ else {
+ printTrace("$TypeMsg $Msg");
+ }
+}
+
+#############################################################################
+# print message error to the user standard output.
+
+sub printTrace {
+
+ my $Msg = shift ;
+ my $level = shift ;
+ if ($level <= $TRACELEVEL) {
+ print($Msg);
+ print LOGFILE $Msg ;
+ }
+}
+
+#############################################################################
+# reset an objectclass structure
+
+sub resetObjectClass {
+ my $ObjectClass = shift;
+ $ObjectClass->{'ObjectName'} = " " ;
+ $ObjectClass->{'Object_oid'} = " " ;
+ $ObjectClass->{'Object_superior'} = "top" ;
+ $ObjectClass->{'Object_requires'} = " " ;
+ $ObjectClass->{'Object_allows'} = " " ;
+}
+
+#############################################################################
+# this subroutine implements a very stupid version of diff
+
+sub diff {
+ my $f1 = shift;
+ my $f2 = shift;
+ my $lineToBeginWith = shift;
+ my $NULL = "" ;
+ my $diff_f1 = $NULL ;
+ my $diff_f2 = $NULL ;
+ my $retval = $NULL ;
+ my $ret;
+ open(F1, "$f1") or die "Could not open file $f1";
+ open(F2, "$f2") or close(F1), die "Could not open file $f2";
+
+ while (defined($l1 = <F1>)) {
+ if ($lineToBeginWith){
+ $lineToBeginWith -- ;
+ next ;
+ }
+ next if ($l1 =~ /^\#/);
+ $ret = defined($l2 = <F2>);
+ if ($ret) {
+ $ret = defined($l2 = <F2>) while ($ret && ($l2 =~ /^\#/)) ;
+ if ($ret) {
+ if (!($l1 eq $l2)) {
+
+ # ignore whitespace
+ $l1_clean = $l1 ;
+ $l2_clean = $l2 ;
+ $l1_clean =~ s/\s//g;
+ $l2_clean =~ s/\s//g;
+
+ if (!($l1_clean eq $l2_clean)) {
+ $diff_f1 .= "${l1}" unless ($l1_clean eq $NULL);
+ $diff_f2 .= "${l2}" unless ($l2_clean eq $NULL);
+ }
+ }
+ }
+ else {
+ next if ($l1 =~ /^\s*$/) ;
+ $diff_f1 .= "${l1}";
+ }
+ }
+ else {
+ next if ($l1 =~ /^\s*$/) ;
+ $diff_f1 .= "${l1}";
+ }
+ }
+
+ while (defined($l2 = <F2>)) {
+ if (($l2 =~ /^\#/) || ($l2 =~ /^\s*$/)) {
+ next ;
+ }
+ else {
+ $diff_f2 .= "${l2}" ;
+ }
+ }
+
+ close(F1);
+ close(F2);
+
+ $retval .= "- differences present in your config file but not in standard file:\n\n". "$diff_f1\n" if ($diff_f1) ;
+ $retval .= "- differences present in standard file but not in your config file:\n\n" . "$diff_f2" if ($diff_f2) ;
+ return $retval ;
+}
+
+sub CompareStdConfigFiles {
+ # Compare each configuration file against its default version. If it has changed,
+ # notify the user that the file has changed and will need to be checked by the
+ # user. This should be safe to do because there should be no path information
+ # stored in these conf files, which are just schema stuff.
+ # printTrace("\nCheck if standard configuration files have changed",3);
+
+ # get the version of the DS to migrate
+ ($oldVersion, $oldMinor) = &getVersion($oldDir);
+ # get the version of the new DS
+ ($Version, $Minor) = &getVersion($root);
+
+ my $origFilePath = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}install${PATHSEP}config${PATHSEP}" ;
+ my $FilesChanged = "";
+ my $AllDiffs = "***********************************************************************";
+ my $NoChanges = "" ;
+ my $lineToBegin = 0 ;
+ printTrace("\nVersion of the old directory server: $oldVersion.$oldMinor",0);
+ opendir(CONFDIR, $oldConfDir) or
+ die "Error: could not open migrated config dir $oldConfDir: $!";
+
+ foreach $file (readdir(CONFDIR)) {
+ $origFile = $origFilePath . $file ;
+ $configFile = $oldConfDir . $file ;
+ if ((! exists($userDefinedConfigFiles{lc($file)})) && (-f $origFile)) {
+ my $lineToBegin = 1 if (lc($file) eq "slapd-collations.conf"); # we ignore the first line of slapd-collations
+ $diffs = &diff($configFile, $origFile, $lineToBegin);
+ $lineToBegin = 0 if $lineToBegin ;
+ if ($diffs) {
+ $FilesChanged .= "\n$configFile";
+ $AllDiffs .= "\n$configFile is different than the standard configuration file" ;
+ $AllDiffs .= "\nYou will need to check this file and make sure its changes are compatible ";
+ $AllDiffs .= "with the new directory server\nHere are the differences:\n";
+ $AllDiffs .= "$diffs \n\n";
+ $AllDiffs .= "***********************************************************************";
+ }
+ else {
+ $NoChanges .= "\n$configFile";
+ }
+ }
+ }
+ closedir(CONFDIR);
+
+if ($FilesChanged) {
+ printTrace("\nNo changes to old configuration files:$NoChanges",3) ;
+ printTrace("\n***********************************************************************",3) ;
+ printMsg("\nThe following standard files have been modified: $FilesChanged");
+ if ($NO_INPUT_USER) {
+ # do nothing
+ }
+ else {
+ printMsg("\nDo you want to see the differences Yes/No [No] ?") ;
+ my $answer = <STDIN> ;
+ if ($answer =~ /y|yes/i) {
+ printMsg("$AllDiffs");
+ }
+ printMsg("\nDo you want to continue the migration Yes/No [No] ?");
+ $answer = <STDIN> ;
+ if (! ($answer =~ /y|yes/i)) {
+ exit(1);
+ }
+ }
+ }
+}
+
+
+#############################################################################
+
+sub db2ldif {
+ my ($conf, $ldif_dir) = @_;
+ $ENV{"$LIB_PATH"}="$oldDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ if (!$conf) {
+ $conf = "$oldHome${PATHSEP}config${PATHSEP}slapd.conf";
+ }
+ if (! $ldif_dir) { $ldif_dir = $ldif_rep ;}
+ if (!(-d $ldif_dir)) {
+ mkdir($ldif_dir,0777) or die "can't create $ldif_rep to store temporary ldif files";
+ }
+ my $dir = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server";
+ chdir($dir) or
+ die "Error: could not change directory to $dir: $!";
+ my @suffixnames = keys(%DBNAMES) ;
+ foreach $suffixname (@suffixnames) {
+ my $ldif_file = $ldif_dir.$DBNAMES{$suffixname}.".ldif" ;
+ # If we are on NT, ${quote} is setup to "\"", else it's setup to ""
+ # As the suffix can contain some space characters, I write the suffix parameter: "\"$suffixname\"" rather than "${quote}$suffixname${quote}"
+ my @cmd =
+ ( "${quote}$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" .
+ "${PATHSEP}$slapdExecName${quote}", "db2ldif", '-n', '-f',
+ "${quote}$conf${quote}", '-a', "${quote}$ldif_file${quote}",
+ '-d', '1','-s',"\"$suffixname\"" );
+ open(DB2LDIF, "${quote}@cmd${quote} 2>&1|") or
+ die "Error: could not execute @cmd: $!";
+ sleep(1); # allow pipe to fill with data
+ $ii = 0; # counter
+ while (<DB2LDIF>) {
+ ++$ii;
+ if (($ii % 250) == 0) {
+ printMsg(" Processing...\n");
+ }
+ }
+ close(DB2LDIF);
+ # set the ownership of the ldif file; should be the same as the 5.x slapd user id
+ if ((! $isNt) && ($oldlocaluser ne $localuser)) {
+ if (-f $ldif_file) {
+ chown( $newuid, $newgid, $ldif_file) or printMsg("\nUnable to change the ownership of $ldif_file to $localuser") ;
+ }
+ }
+ }
+ print " Done.\n";
+ chdir($curdir) or die "Could not change directory to $curdir: $!";
+}
+
+#############################################################################
+
+# this is used to run the system() call, capture exit and signal codes,
+# and die() upon badness; the first argument is a directory to change
+# dir to, if any, and the rest are passed to system()
+sub mySystem {
+ my $rc = &mySystemNoDie(@_);
+ my ($dir, @args) = @_;
+ if ($rc == 0) {
+# success
+ } elsif ($rc == 0xff00) {
+ die "Error executing @args: error code $rc: $!";
+ } elsif ($rc > 0x80) {
+ $rc >>= 8;
+ die "Error executing @args: error code $rc: $!";
+ } else {
+ if ($rc & 0x80) {
+ $rc &= ~0x80;
+ }
+ die "Error executing @args: received signal $rc: $!";
+ }
+
+ # usually won't get return value
+ return $rc;
+}
+
+# This version does not die but just returns the error code
+sub mySystemNoDie {
+ my ($dir, @args) = @_;
+ if ($dir && ($dir ne "")) {
+ chdir($dir) or die "Could not change directory to $dir: $!";
+ }
+ my $cmd = $args[0];
+ # the system {$cmd} avoids some NT shell quoting problems if the $cmd
+ # needs to be quoted e.g. contains spaces; the map puts double quotes
+ # around the arguments on NT which are stripped by the command
+ # interpreter cmd.exe; but don't quote things which are already quoted
+ my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args;
+ my $rc = 0;
+ if ($cmd =~ /[.](bat|cmd)$/) {
+ # we have to pass batch files directly to the NT command interpreter
+ $cmd = $com_spec;
+# print "system $cmd /c \"@fixargs\"\n";
+ $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\"";
+ } else {
+# print "system $cmd @fixargs\n";
+ $rc = 0xffff & system {$cmd} @fixargs;
+ }
+ chdir(${curdir}) or die "Could not change directory to $curdir: $!";
+ return $rc;
+}
+
+#############################################################################
+sub manyLdif2db {
+ my %rev_dbnames = reverse(%DBNAMES);
+ @backends = keys(%rev_dbnames);
+ $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ chdir($slapdExecDir) or die "Could not change directory to $slapdExecDir: $!";
+ foreach $backend (@backends) {
+ my $ldif = "${ldif_rep}$backend.ldif" ;
+ &Ldif2db($ldif, $backend);
+ }
+ # remove the empty ldif directory
+ rmdir($ldif_rep);
+ chdir($curdir) or die "Could not change directory to $curdir: $!";
+}
+
+
+sub Ldif2db {
+ my $ldif = shift ;
+ my $backend = shift ;
+ my $ldif2db_param = "ldif2db -D $serverHome -n $backend -i $ldif";
+ open(LDIF2DB, "${quote}${quote}$slapdExecName${quote} $ldif2db_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n";
+ sleep(1); # allow some data to accumulate in the pipe
+ while (<LDIF2DB>) {
+ printMsg($_);
+ }
+ close(LDIF2DB);
+ # remove the ldif file after the import
+ unlink($ldif) ;
+}
+
+#############################################################################
+
+#sub copyBak {
+# opendir( OLDBAK, "$oldHome${PATHSEP}bak" ) ||
+# die "Can't open directory $oldHome${PATHSEP}bak: $!: ";
+# local ( @dirs ) = readdir( OLDBAK );
+# closedir ( OLDBAK );
+# for ( @dirs ) {
+# if ( $_ eq "." || $_ eq ".." ) {
+# next;
+# } elsif ( -d "$oldHome${PATHSEP}bak${PATHSEP}$_" ) {
+# $srcDir = "$oldHome${PATHSEP}bak${PATHSEP}$_";
+# $destDir = "$serverHome${PATHSEP}bak${PATHSEP}$_";
+# $srcLDIF = "$oldHome${PATHSEP}ldif${PATHSEP}bak.ldif";
+# $destLDIF = "$serverHome${PATHSEP}ldif${PATHSEP}bak.ldif";
+# mkdir( $destDir , 0755 ) if !( -e $destDir);
+# # Converting database
+# if ( !$isNT && $newuser ) {
+# chown($newuid, $newgid,
+# "$serverHome${PATHSEP}bak", $destDir);
+# }
+# &other_db2ldif($srcDir, $srcLDIF);
+# if ($needAclUpg) {
+# &mySystem("$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server",
+# "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" .
+# "${PATHSEP}aclupg$exe_suffix", '-d', '-i',
+# $srcLDIF, '-o', $destLDIF);
+# } else {
+# &copyBinFile($srcLDIF, $destLDIF);
+# }
+# &other_ldif2db($destLDIF, $destDir);
+# }
+# }
+#}
+#############################################################################
+
+sub startServer {
+ my $instanceDir = ${serverHome} ;
+ my $errLog = $instanceDir . $PATHSEP . 'logs' . $PATHSEP . 'errors';
+ # emulate tail -f
+ # if the last line we see does not contain "slapd started", try again
+ my $done = 0;
+ my $started = 0;
+ my $code = 0;
+ my $lastLine = "";
+ my $timeout = time + 240; # 4 minutes
+ $ENV{"$LIB_PATH"}="${root}${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+
+ my $startCmd = $instanceDir . $PATHSEP . 'start' . $script_suffix;
+ if (! -f $startCmd) {
+ $startCmd = $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix;
+ }
+ printTrace("\nInstanceDir: $instanceDir\n",4);
+ $code = &mySystem($instanceDir,$startCmd);
+ open(IN, $errLog) or die "Could not open error log $errLog: $!";
+ my $pos = tell(IN);
+ while (($done == 0) && (time < $timeout)) {
+ for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) {
+ $lastLine = $_;
+ # print;
+ # the server has already been started and shutdown once . . .
+ if (/slapd started\./) {
+ $started++;
+ if ($started == 2) {
+ $done = 1;
+ }
+ # sometimes the server will fail to come up; in that case, restart it
+ } elsif (/Initialization Failed/) {
+ # print "Server failed to start: $_";
+ $code = &mySystem($instanceDir, $startCmd);
+ # sometimes the server will fail to come up; in that case, restart it
+ } elsif (/exiting\./) {
+ # print "Server failed to start: $_";
+ #$code = &mySystem($startCmd);
+
+ $code = &mySystem($instanceDir, $startCmd);
+ }
+ }
+ if ($lastLine =~ /PR_Bind/) {
+ # server port conflicts with another one, just report and punt
+ print $lastLine;
+ print "This server cannot be started until the other server on this\n";
+ print "port is shutdown.\n";
+ $done = 1;
+ }
+ if ($done == 0) {
+ # rest a bit, then . . .
+ sleep(2);
+ # . . . reset the EOF status of the file desc
+ seek(IN, $pos, 0);
+ }
+ }
+ close(IN);
+
+ if ($started < 2) {
+ $! = $code;
+ # $now = time;
+ # if ($now > $timeout) {
+ # print "Possible timeout: timeout=$timeout now=$now\n";
+ # }
+ die "Error: could not start server: $!";
+ }
+
+ return 0;
+}
+
+sub stopServer {
+ my $root = shift;
+ my $name = shift;
+ $maxStopIterations = 5;
+ print "\nShutting down server $name . . .\n";
+
+ $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop' . $script_suffix . $quote;
+ if (! -f $stopCmd) {
+ $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop-slapd' . $script_suffix . $quote;
+ }
+
+ if (! -f $stopCmd) {
+ # no stop command, probably a 1.X system; for NT, we'll try net stop
+ # for unix, we'll get the pid and kill it
+ if ($isNT) {
+ $stopCmd = 'net stop ' . $name;
+ } else {
+ # see if there is a pid file
+ $pidfile = $root . $PATHSEP . $name . $PATHSEP . 'logs' .
+ $PATHSEP . 'pid';
+ if (open(PIDFILE, $pidfile)) {
+ chomp($pid = <PIDFILE>);
+ close(PIDFILE);
+ while ($maxStopIterations-- && !$exitCode) {
+ $exitCode = kill(15, $pid);
+ }
+ $stopCmd = undef;
+ }
+ }
+ }
+
+ # keep looping until the stop cmd returns an error code, which usually
+ # means that what ever we want to stop is stopped, or some other error
+ # occurred e.g. permission, or no such service
+ $exitCode = &runAndIgnoreOutput($stopCmd);
+# print "stopServer: exitCode=$exitCode\n";
+ while ($stopCmd && $maxStopIterations-- && $exitCode) {
+ $exitCode = &runAndIgnoreOutput($stopCmd);
+# print "stopServer: exitCode=$exitCode\n";
+ }
+
+ if (!$maxStopIterations) {
+ print "Warning: could not shutdown the server: $!\n";
+ }
+
+ sleep(10) ;
+
+ $exitCode = 0;
+
+}
+
+
+sub runAndIgnoreOutput {
+ my $cmd = shift;
+ printMsg(".");
+ open(RUNCMD, "${quote}$cmd${quote} 2>&1 |") or die "Error: could not run $cmd: $!";
+ printMsg(".");
+ sleep(1); # allow pipe to fill with data
+ printMsg(".");
+ while (<RUNCMD>) {
+# print;
+ }
+ my $code = close(RUNCMD);
+# print "runAndIgnore: code=$code status=$?\n";
+ return $?;
+}
+#############################################################################
+# migrate some of entries present in the old DSE.ldif like
+# cn=snmp,cn=config
+# cn=encryption,cn=config
+# all the aci's
+
+sub MigrateDSE {
+ printTrace("\nMigrate DSE entries...",1);
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($old_entry = readOneEntry $in) {
+ my $DN = $old_entry->getDN() ;
+ SWITCH: {
+ # migrate the entrie: cn=snmp,cn=config
+ if ($DN =~ /^cn=SNMP,cn=config$/i) {
+ my $entry = $conn->search("$DN","base","objectclass=nsSNMP");
+ if ($entry) {
+ my $res = $conn->update($old_entry);
+ if ($res) {
+ printTrace("\n$DN updated !",2);
+ }
+ else {
+ printMsg("\nFailed to update $DN");
+ }
+ }
+ else {
+ printMsg("\nUnable to get info under $DN");
+ }
+ last SWITCH;
+ }
+ # migrate the entrie: cn=encryption,cn=config
+ if ($DN =~ /cn=encryption,cn=config$/i) {
+ if ($conn->search("$DN","base","objectclass=*")) {
+ my $res = $conn->update($old_entry);
+ if ($res) {
+ printTrace("\n$DN updated !",2);
+ }
+ else {
+ printMsg("\nFailed to update $DN");
+ }
+ }
+ else {
+ my $res = $conn->add($old_entry);
+ if ($res) {
+ printTrace("\n$DN added !",2);
+ }
+ else {
+ printMsg("\nFailed to add $DN");
+ }
+ }
+ last SWITCH;
+ }
+ if (@{$old_entry->{aci}} && (! ($DN =~ /^cn=monitor$/i)) && (! ($DN =~ /^cn=schema$/i))) {
+ # migrate aci's
+ my $entry = $conn->search("$DN","base","objectclass=*");
+ if ($entry) {
+ my $res = $conn->update($old_entry);
+ if ($res) {
+ printTrace("\n$DN updated !",2);
+ }
+ else {
+ printMsg("\nFailed to update $DN");
+ }
+ }
+ else {
+ my $res = $conn->add($old_entry);
+ if ($res) {
+ printTrace("\n$DN added !",2);
+ }
+ else {
+ printMsg("\nFailed to add $DN");
+ }
+ }
+ last SWITCH;
+ }
+ }
+ }
+ close(DSELDIF);
+}
+#############################################################################
+# migrate SSL info
+
+sub MigrateSSL {
+ my $secPwd = 'bidon' ;
+ # copy the SSL directory
+ &copyDir("$oldHome${PATHSEP}ssl","$serverHome${PATHSEP}ssl");
+ # copy the cert db and key files
+ if ( -d "$oldDir${PATHSEP}alias") {
+ $aliasDir = "$root${PATHSEP}alias";
+ if (! -d $aliasDir) {
+ mkdir($aliasDir, 0750);
+ }
+ my $keydb = "$aliasDir${PATHSEP}slapd-$newname-key3.db" ;
+ my $certdb = "$aliasDir${PATHSEP}slapd-$newname-cert7.db" ;
+ my $old_keydb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-key3.db" ;
+ my $old_certdb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-cert7.db";
+ my $keydb_backup = "$aliasDir${PATHSEP}slapd-$newname-key3.db_backup" ;
+ my $certdb_backup = "$aliasDir${PATHSEP}slapd-$newname-cert7.db_backup" ;
+ if (-f $old_keydb) {
+ if (-f $keydb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$keydb already exists. backup in $keydb_backup ...");
+ &copyBinFile($keydb,$keydb_backup);
+ &copyBinFile($old_keydb,$keydb);
+ }
+ else {
+ print("\n\n$keydb already exists. Do you want to overwrite it ? [no]: ");
+ my $answer = <STDIN> ;
+ if ($answer =~ /^y|yes$/i) {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ if (-f $old_certdb) {
+ if (-f $certdb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$certdb already exists. backup in $certdb_backup ...");
+ &copyBinFile($certdb,$certdb_backup);
+ &copyBinFile($old_certdb,$certdb);
+ }
+ else {
+ print("\n\n$certdb already exists. Do you want to overwrite it ? [no]: ");
+ my $answer = <STDIN> ;
+ if ($answer =~ /^y|yes$/i) {
+ &copyBinFile($old_certdb,$certdb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_certdb,$certdb);
+ }
+ }
+ # copy the old password file
+ if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") {
+ &copyBinFile(
+ "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt",
+ "$aliasDir${PATHSEP}$type-$newname-pin.txt"
+ );
+ }
+ }
+
+}
+
+sub DisableSSL {
+ my $entry = $conn->search("cn=config","base","objectclass=*");
+ my $LDAPparam = "nsslapd-security" ;
+ my $Value = "off" ;
+ if ($entry->{$LDAPparam}[0] ne $Value) {
+ printTrace("\nDisable SSL...",1);
+ $entry->setValues($LDAPparam, $Value);
+ }
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nSSL disabled",2);
+ }
+ else {
+ printMsg("\nCan't disabled SSL. The server may have problems to start");
+ }
+}
+
+# enable the migration of client authentication informations
+sub MigrateCertmap {
+ # backup the old 5.x certmap.conf and replace it with the 4.x certmap.conf file
+ my $oldCertmap = "$oldDir${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf";
+ my $newCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf" ;
+ my $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ;
+ if (&hasChangedoldCertmap($oldCertmap)) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$newCertmap has been backup in $backupCertmap");
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($oldCertmap,$newCertmap);
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\n\nWhere do you want to back up the file $newCertmap [$backupCertmap] ?") ;
+ my $Answer = <STDIN> ;
+ $backupCertmap = $Answer if ($Answer ne "\n");
+ chomp($backupCertmap);
+ printTrace("\nDest: .$backupCertmap.",4);
+ if (-e $backupCertmap) {
+ printMsg("\n\n$backupCertmap already exists. Do you want to overwrite it Yes/No [No] ?") ;
+ if (<STDIN> =~ /yes|y/i) {
+ $Ask = 0 ;
+ }
+ else {
+ $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ;
+ }
+ }
+ else {
+ $Ask = 0 ;
+ }
+ }
+ printTrace("\nBackup file: $newCertmap in $backupCertmap",4);
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($oldCertmap,$newCertmap);
+ }
+ }
+ else {
+ }
+}
+
+sub hasChangedoldCertmap {
+ my $certmapfile = shift ;
+ my @reference = ("certmap default default",
+ "default:DNComps",
+ "default:FilterComps e") ;
+ my $cpt = 0 ;
+ printTrace("\nhasChangedoldCertmap",3);
+ open(CERTMAP,"< $certmapfile");
+ while (<CERTMAP>) {
+ if ((! /^\s*#/) && (! /^\s*$/)) {
+ my $ref = $reference[$cpt] ;
+ printTrace("\nValue: $_, ref: $ref",4);
+ if (! /^\s*$ref\s*$/) {
+ return 1 ;
+ }
+ else {
+ $cpt++ ;
+ }
+ }
+ }
+ close (CERTMAP);
+ printTrace("\ncpt: $cpt",4);
+ if ($cpt < $#reference) {
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+}
+#############################################################################
+# copy a directory to another
+
+sub copyDir {
+ my $src = shift;
+ my $dest = shift;
+ my $exclude = shift;
+
+ opendir( SRC, $src ) or die "Can't open directory $src: $!: ";
+ my $mode;
+ my $uid;
+ my $gid;
+ mkdir ( $dest , 0755 ) or die "\nCan't create directory $dest. \nPlease check you have enough rights to create it and/or check that your parent directory exists.\n" if !( -e $dest );
+ if ($PRESERVE) {
+ $mode = (stat($src))[2];
+ ($uid, $gid) = (stat(_))[4..5];
+ # Make sure files owned by the old user are owned by the
+ # new user
+ if ($uid == $olduid) {
+ $uid = $newuid;
+ $gid = $newgid;
+ }
+ chown $uid, $gid, $dest;
+ chmod $mode, $dest;
+ }
+ local ( @files ) = readdir ( SRC );
+ closedir( SRC );
+ for ( @files ) {
+ if ( $_ eq "." || $_ eq ".." ) {
+ next;
+ } elsif ( $exclude && /$exclude/ ) {
+ next;
+ } elsif( -d "$src${PATHSEP}$_") {
+ &copyDir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" );
+ } else {
+ &copyBinFile ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_");
+ }
+ }
+}
+
+sub copyBinFile {
+ my $src = shift;
+ my $dest = shift;
+ my $buf = "";
+ my $bufsize = 8192;
+
+ open( SRC, $src ) || die "Can't open $src: $!\n";
+ # if we are given a directory destination instead of a file, extract the
+ # filename portion of the source to use as the destination filename
+ if (-d $dest) {
+ $dest = $dest . $PATHSEP . &basename($src);
+ }
+ open( DEST, ">$dest" ) || die "Can't create $dest: $!\n";
+ binmode SRC;
+ binmode DEST;
+ if ($PRESERVE) {
+ $mode = (stat($src))[2];
+ ($uid, $gid) = (stat(_))[4..5];
+ # Make sure files owned by the old user are owned by the
+ # new user
+ if ($uid == $olduid) {
+ $uid = $newuid;
+ $gid = $newgid;
+ }
+ chown $uid, $gid, $dest;
+ chmod $mode, $dest;
+ }
+ while (read(SRC, $buf, $bufsize)) {
+ print DEST $buf;
+ }
+ close( SRC );
+ close( DEST );
+}
+#############################################################################
+# backup 5.x configuration files
+# backup the directory <root_server5>/slapd-instance/config dans <root_server5>/slapd-instance/BackupConfig
+
+sub backupConfigFiles {
+ # backup the 5.x config files
+ my $src = "$serverHome${PATHSEP}config" ;
+ my $dest = "$serverHome${PATHSEP}config_backup" ;
+ if ($NO_INPUT_USER) {
+ printMsg("\n$src has been backup in $dest");
+ &copyDir($src,$dest);
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\n\nWhere do you want to back up your configuration directory [$dest] ?") ;
+ my $Answer = <STDIN> ;
+ $dest = $Answer if ($Answer ne "\n");
+ chomp($dest);
+ printTrace("\nDest: .$dest.",4);
+ if (-e $dest) {
+ printMsg("\n\n$dest already exists. Do you want to overwrite it Yes/No [No] ?") ;
+ if (<STDIN> =~ /yes|y/i) {
+ $Ask = 0 ;
+ }
+ else {
+ $dest = "$serverHome${PATHSEP}config_backup" ;
+ }
+ }
+ else {
+ $Ask = 0 ;
+ }
+ }
+ printTrace("\nBackup Directory: $src in $dest",4);
+ &copyDir($src,$dest);
+ }
+}
+#############################################################################
+
+sub getLDAPservername {
+ my $oldLDAPservername;
+ my $LDAPservername;
+ open(OLDSLAPDCONF, $oldSlapdConf) or
+ die "\nError: could not open old config file $oldSlapdConf \n";
+ while(<OLDSLAPDCONF>) {
+ chop;
+ if (/^localhost\s+/i) {
+ ($oldLDAPservername = $') =~ s/^[\"]//;;
+ $oldLDAPservername =~ s/[\"]$//;
+ printTrace("\nName of the old LDAP server: $oldLDAPservername",3);
+ }
+ }
+ close(OLDSLAPDCONF);
+
+ open( DSELDIF, "< $DSEldif" ) || die "\nCan't open $DSEldif \n";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ my $DN = $entry->getDN() ;
+ if ($DN =~ /^cn=config$/i) {
+ my $localhost = "nsslapd-localhost";
+ my @values = $entry->getValues($localhost);
+ if ($#values != -1) {
+ $LDAPservername = $values[0];
+ }
+ break;
+ }
+ }
+ close(DSELDIF);
+ # check 4.x and 5.x are installed on the same physical machine.
+ if (lc($oldLDAPservername) ne lc($LDAPservername)) {
+ # warn the user he tries to migrate a 4.x server installed on a different machine from the 5.x one
+ printMsg("\n\nYour 4.x server is on $oldLDAPservername, and your 5.x server is on $LDAPservername. We don't support migration on different machines. Do you want to continue ? Yes/No [No]:") ;
+ if (! (<STDIN> =~ /yes|y/i)) {
+ return -1;
+ }
+ }
+ return $LDAPservername ;
+}
+
+#############################################################################
+
+sub getVersion {
+ my $dir = shift;
+ my $version = 0;
+ my $minor = 0;
+ my $buildNumber = 0;
+ my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+ my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}";
+
+ # find the slapd executable
+ $prog = $dir . $progDir . $slapdExecName;
+ if (! -f $prog) {
+ $prog = $dir . $progDir2 . $slapdExecName;
+ if (-f $prog && $isNT) {
+ # if slapd is in bin/slapd and we're on NT, just assume version 1;
+ # apparently, slapd.exe doesn't like the -v argument . . .
+ return ( '1', $minor );
+ }
+ else{
+ die "Could not run slapd program $prog: $!";
+ }
+ }
+ else {
+ chdir($dir . $progDir);
+ }
+ $ENV{"$LIB_PATH"}="$dir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ # read the old version from the old slapd program
+
+ open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or
+ die "Could not run slapd program $prog: $!";
+ sleep(1); # allow some data to accumulate in the pipe
+# print "Output from $prog -v:\n";
+ while (<F>) {
+ print;
+ if (/^Netscape-Directory\/(\d+)\.(\d+)\s+(\S+)/) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ last;
+ }
+ elsif (/^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ...
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ last;
+ }
+ elsif (/^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ last;
+ }
+ }
+ $code = close(F);
+# print "$prog returned code=$code status=$?\n";
+ $ENV{"$LIB_PATH"}="$root${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+
+ if ($version == 0) {
+ printMsg("\nCould not determine version of the directory server in $dir: ");
+ printMsg("\nBe careful, this script is designed to migrate only from 4.x Netscape Directory Server to 5.x. Do you want to continue ? [no]: ");
+ my $answer = <STDIN> ;
+ if (! ($answer =~ /y|yes/i)) {
+ exit(1);
+ }
+ $version = 4 ; # setup to 4 and pray ...
+ }
+
+ # distinguish the 4.1 and the 4.11 thanks to the buildNumber
+ if (($version == 4) && ($minor == 1)){
+ if (! ($buildNumber =~ /^B99\.16/)) {
+ # it's not a 4.1 Netscape Directory Server => it's a 4.11
+ $minor = 11 ;
+ }
+ }
+ return ( $version, $minor );
+}
+
+#############################################################################
+
+sub getDiff {
+ # we get references to arrays
+ my $elements = shift ;
+ my $existing_elements = shift ;
+ my %count = () ;
+ my %countEE = () ;
+ @diff = () ;
+ foreach $e (@{$elements}, @{$existing_elements}) { $count{$e}++ ;}
+ foreach $e (@{existing_elements}) { $countEE{$e}++ ;}
+ foreach $e (@{$elements}) {
+ # if $e is only present in @$elements, we push it to the diff array
+ if (($count{$e} == 1) && ($countEE{$e} == 0)) {
+ push @diff, $e ;
+ }
+ }
+ return @diff ;
+}
+
+###############################################################################################
+sub testIndexUpdating {
+ #my $entry = $conn->newEntry();
+ #$entry->setDN("cn=djeattribute,cn=index,cn=MigratedDB_5,cn=ldbm database,cn=plugins,cn=config");
+ my $entry = $conn->search("cn=mail,cn=index,cn=MigratedDB_2,cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex");
+ my @types = ("pres", "sub", "eq") ;
+ my @existing_types = $entry->getValues("nsindextype");
+ my @typesToAdd = &getDiff(\@types, \@existing_types);
+ foreach $newtype (@typesToAdd) {
+ $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2);
+ }
+ my $res = $conn->update($entry) ;
+ if ($res) {print("\nUpdate index mail\n");}
+ else { print("\ncan't update index mail");}
+
+ $entry = $conn->search("cn=givenName,cn=index,cn=MigratedDB_2,cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex");
+ @types = ("pres", "sub", "eq") ;
+ @existing_types = $entry->getValues("nsindextype"); print("\ngivenName, existing_types: @existing_types");
+ @typesToAdd = &getDiff(\@types, \@existing_types); print("\nTypesToAdd: @typesToAdd");
+ foreach $newtype (@typesToAdd) {
+ $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2);
+ }
+ my $res = $conn->update($entry) ;
+ if ($res) {print("\nUpdate index givenName\n");}
+ else { print("\ncan't update index givenName");}
+ }
+
+
+###############################################################################################
+sub normalizeDir {
+ my $dir = shift ;
+ my $dir_prec = "" ;
+ while ($dir_prec ne $dir) {
+ $dir_prec = $dir ;
+ if ($isNT) {
+ grep { s@\\\\@\\@g } $dir ;
+ }
+ else {
+ grep { s@//@/@g } $dir ;
+ }
+ }
+ return $dir ;
+}
+
+
+###############################################################################################
+# return 1 if the value parameters is
+sub isAllowedPlugin {
+ my $Value = lc(shift) ;
+ if ($allowedPlugins{$Value}) {
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+
+}
+
+
+sub getSyntaxOid {
+ my $Value = lc(shift) ;
+ return $allowedPlugins{$Value} ;
+}
+
+###############################################################################################
+# return 1 if the value given in parameters is an allowed modifier
+sub isAllowedModifier {
+ my $Value = lc(shift) ;
+ if ($allowedModifiers{$Value}) {
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+sub getModifierValue {
+ my $Value = lc(shift) ;
+ return $allowedModifiers{$Value} ;
+}
+
+###############################################################################################
+
+sub GetTime {
+ my $tm = localtime;
+ (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900);
+ $sec = "0$sec" unless $sec > 9 ;
+ $min = "0$min" unless $min > 9 ;
+ $hour = "0$hour" unless $hour > 9 ;
+ $dd = "0$dd" unless $dd > 9 ;
+ $mm = "0$mm" unless $mm > 9 ;
+ return ($sec, $min, $hour, $dd, $mm, $yy);
+}
+
+###############################################################################################
+# get uid and group id of the 5.x slapd server.
+# The uid is done through the nsslapd-localuser attribute
+
+sub getuid_gid {
+ my $newuid ;
+ my $newgid ;
+ my $localuser ;
+ my $localuser_attr = "nsslapd-localuser" ;
+ if (! $isNT) {
+ my $entry = $conn->search("cn=config ", "base","objectclass=*", 0, ($localuser_attr)) ;
+ # Tests wether we succeed to get the entry cn=config
+ die "\nCan't get the entry cn=config \n" unless ($entry);
+ my @values = $entry->getValues($localuser_attr);
+ if ($#values == -1 || ($values[0] eq "") ) { # tests wether the nsslapd-localuser attribute has a value
+ printMsg("\nNo localuser has been found in the configuration of the directory. ");
+ if ($NO_INPUT_USER) {
+ printMsg("\nWe considered nobody as the localuser");
+ $localuser = "nobody" ;
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\nUnder what user does your $Version.$Minor directory server run [nobody] ? ") ;
+ $localuser = <STDIN> ;
+ chomp($localuser);
+ $localuser = "nobody" if ($localuser eq "");
+ ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ;
+ if ($newuid) {
+ $Ask = 0 ;
+ }
+ else {
+ printMsg("\nError: $localuser is unknown from the system ");
+ }
+ }
+ }
+ }
+ else {
+ $localuser = $values[0]; # returns the first value (we should only have one localuser)
+ my $size = $#values ;
+ }
+ ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ;
+ return ($localuser, $newuid, $newgid) ;
+ }
+ else {
+ return () ;
+ }
+}
+
+
+###############################################################################################
+# get uid and group id of the 4.x slapd server.
+
+sub getolduid_gid {
+ my $oldlocaluser ;
+ if (! $isNT) {
+ open(CONF, $oldSlapdConf) or die "\nError: cannot open $oldSlapdConf: $!\n";
+ while (<CONF>) {
+ if (/^localuser\s+/i) {
+ chomp($oldlocaluser = $');
+ last;
+ }
+ }
+ close(CONF);
+ ($olduid, $oldgid) = (getpwnam("$oldlocaluser"))[2..3] ;
+ return ($oldlocaluser, $olduid, $oldgid) ;
+ }
+ else {
+ return ();
+ }
+}
+
+###############################################################################################
+# get current directory
+
+sub getCwd {
+ my $command = $isNT ? "cd" : "/bin/pwd";
+ open(PWDCMD, "$command 2>&1 |") or
+ die "Error: could not execute $command: $!";
+ # without the following sleep, reading from the pipe will
+ # return nothing; I guess it gives the pwd command time
+ # to get some data to read . . .
+ sleep(1);
+ my $currentdir;
+ while (<PWDCMD>) {
+ if (!$currentdir) {
+ chomp($currentdir = $_);
+ }
+ }
+ my $code = close(PWDCMD);
+# if ($code || $?) {
+# print "$command returned code=$code status=$? dir=$curdir\n";
+# }
+# print "getCwd curdir=\[$curdir\]\n";
+ return $currentdir;
+}
diff --git a/ldap/admin/src/scripts/template-migrateTo6 b/ldap/admin/src/scripts/template-migrateTo6
new file mode 100644
index 00000000..91174b41
--- /dev/null
+++ b/ldap/admin/src/scripts/template-migrateTo6
@@ -0,0 +1,3268 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# Migrate a old directory server to a 6.2 directory server
+
+########################################################################################################
+# enable the use of Perldap functions
+require DynaLoader;
+
+use Getopt::Std;
+use Mozilla::LDAP::Conn;
+use Mozilla::LDAP::Entry;
+use Mozilla::LDAP::LDIF;
+use Mozilla::LDAP::Utils qw(:all);
+use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API
+use Time::localtime;
+
+########################################################################################################
+use Class::Struct ; # load struct-building module
+
+struct S_index => {
+ names => '@' ,
+ types => '@' ,
+ oids => '@' ,
+ specific => '$'
+ };
+
+
+struct S_plugin => {
+ name => '$' ,
+ type => '$' ,
+ enable => '$' ,
+ args => '@'
+ };
+#####################################################################################################
+
+sub usage {
+ print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n");
+ print(STDERR " -o OldInstancePath -n NewInstancePath [-t tracelevel] [-L logfile]\n");
+ print(STDERR "************** parameters in brackets are optionals, others are required **************\n");
+ print(STDERR " Opts: -D rootdn - New Directory Manager\n");
+ print(STDERR " : -w password - New Directory Manager's password\n");
+ print(STDERR " : -w - - Prompt for New Directory Manager's password\n");
+ print(STDERR " : -j filename - Read New Directory Manager's password from file\n");
+ print(STDERR " : -p port - New Directory Server port\n");
+ print(STDERR " : -o OldInstancePath - Path of the Old instance to migrate \n");
+ print(STDERR " : -n NewInstancePath - Path of the new instance\n");
+ print(STDERR " : [-d dataPath] - Path to directory containing data files to import into new instance\n");
+ print(STDERR " : [-v oldVersion] - Old version (obtained by running $slapdExecName -v\n");
+ print(STDERR " : [-t tracelevel] - specify the level of trace (0..3)\n");
+ print(STDERR " : [-L logfile] - specify the file to log the migration report \n");
+
+
+ }
+
+
+
+#############
+BEGIN {
+
+ require 'uname.lib' ;
+ $isNT = -d '\\';
+ $PATHSEP = $isNT ? "\\" : "/";
+ ${SEP} = $isNT ? ";" : ":" ;
+ @INC = ( '.', '../../../admin/admin/bin');
+ grep { s@/@\\@g } @INC if $isNT;
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ # NT needs quotes around some things unix doesn't
+ $quote = $isNT ? "\"" : "";
+
+ # If this variable is set, all file/directory creation will make sure the mode
+ # and ownership of the destination is the same as the source
+ $PRESERVE = 1 if (!$isNT);
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ if ($isNT) {
+ $os = "WINNT";
+ } else {
+ $os = &uname("-s");
+ }
+ if ($isNT) {
+ # we have to pass batch files directly to the NT command interpreter
+ $com_spec = $ENV{ComSpec};
+ if (!$com_spec) {
+ $com_spec = $ENV{COMSPEC};
+ }
+ if (!$com_spec || ! -f $com_spec) {
+ # find the first available command interpreter
+ foreach $drive (c..z) {
+ $com_spec = "$drive:\\winnt\\system32\\cmd.exe";
+ last if (-f $com_spec);
+ $com_spec = undef;
+ }
+ if (! $com_spec) {
+ # punt and pray
+ $com_spec = 'c:\winnt\system32\cmd.exe';
+ }
+ }
+ }
+ if ( $os eq "AIX" ) {
+ $dll_suffix = "_shr.a";
+ }
+ elsif ( $os eq "HP-UX" ) {
+ $dll_suffix = ".sl";
+ }
+ elsif ( $os eq "WINNT" ) {
+ $dll_suffix = ".dll";
+ }
+ else {
+ $dll_suffix = ".so";
+ }
+ $slapdExecName = $isNT ? 'slapd.exe' : './ns-slapd';
+ # if this flag is set, we will migrate the old database
+ # by doing a db2ldif -> ldif2db;
+ $convertToLDIF = 1;
+ select STDERR;
+ $| = 1;
+ select STDOUT;
+ $| = 1;
+ # if the old value for dbcachesize is less than this, make it this
+ $MIN_DBCACHESIZE = '500000';
+}
+
+SWITCH: {
+ if ($os eq "AIX") {
+ $LIB_PATH = "LIBPATH" ;
+ last SWITCH ;
+ }
+ if ($os eq "HP-UX") {
+ $LIB_PATH = "SHLIB_PATH" ;
+ last SWITCH ;
+ }
+ if ($isNT) {
+ $LIB_PATH = "PATH" ;
+ last SWITCH ;
+ }
+ else {
+ $LIB_PATH = "LD_LIBRARY_PATH" ;
+ last SWITCH ;
+ }
+ }
+
+ # Old parameters
+ ${oldDir} = "" ;
+ ${oldname} = "" ;
+ ${oldHome} = "" ;
+ ${oldConfDir} = "" ;
+ ${oldlocaluser} ;
+ ${olduid} ;
+ ${oldgid} ;
+
+ # New parameters
+ ${root} = "{{DS-ROOT}}" ;
+ ${type} = "" ;
+ ${newname} = "" ;
+ ${newport} = "" ;
+ ${rootDN} = "" ;
+ ${rootpwd} = "" ;
+ ${localhost} = "" ;
+ ${LogFileReport} = "" ;
+ ${newuid} ;
+ ${localuser} ;
+ ${newgid} ;
+ $NO_INPUT_USER = 0 ; # by default user can give inputs during the migration process
+ ${curdir} = getCwd();
+ ${slapdExecDir} = "${root}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+
+ # specify the level of trace
+ $TRACELEVEL=1;
+
+ $LDAP_SERVER_UNREACHABLE = 81;
+
+ # get input users
+ &getParameters() ;
+ ${oldDir} = &normalizeDir("${oldDir}");
+ ${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ;
+ ${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ;
+ ${oldSlapdConf} = "${oldConfDir}slapd.conf" ;
+ ${oldDSEldif} = "${oldConfDir}dse.ldif" ;
+ ${serverHome} = "${root}${PATHSEP}$type-$newname" ;
+ ${DSEldif} = "$serverHome${PATHSEP}config${PATHSEP}dse.ldif";
+ ${ldif_rep} = "${oldConfDir}${PATHSEP}ldif${PATHSEP}" ;
+ ${oldSlapdExecDir} = "${oldDir}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+
+
+
+
+ open(LOGFILE, ">> $LogFileReport");
+
+ printTrace("\noldDir: $oldDir, oldHome: $oldHome, \noldConfDir: $oldConfDir, \noldSlapdConf: $oldSlapdConf, \nldif_rep: $ldif_rep, \nrootDN: $rootDN, \nPwd: ******, \nPort: $newport, \nNewname: $newname\n",3);
+ printTrace("\nLIB_PATH: $LIB_PATH",4);
+
+ if (!(-d $serverHome)) {
+ printMsg("\n$serverHome doesn't exist\n");
+ exit(1);
+ }
+ if (!(-d $oldHome)) {
+ printMsg("\n$oldHome doesn't exist\n");
+ exit(1);
+ }
+
+ if ($olddatadir && !(-d $olddatadir)) {
+ print("\n$olddatadir doesn't exist\n");
+ exit(1);
+ }
+
+#define CONFIG_DATABASE_DIRECTIVE "database"
+#define CONFIG_DATABASE_ATTRIBUTE "nsslapd-database"
+#define CONFIG_PLUGIN_DIRECTIVE "plugin"
+#define CONFIG_PLUGIN_ATTRIBUTE "nsslapd-plugin"
+#define CONFIG_SIZELIMIT_DIRECTIVE "sizelimit"
+#define CONFIG_SIZELIMIT_ATTRIBUTE "nsslapd-sizelimit"
+#define CONFIG_ORCAUTO_DIRECTIVE "orcauto"
+#define CONFIG_ORCAUTO_ATTRIBUTE "nsslapd-orcauto"
+#define CONFIG_TIMELIMIT_DIRECTIVE "timelimit"
+#define CONFIG_TIMELIMIT_ATTRIBUTE "nsslapd-timelimit"
+#define CONFIG_SUFFIX_DIRECTIVE "suffix"
+#define CONFIG_SUFFIX_ATTRIBUTE "nsslapd-suffix"
+#define CONFIG_READONLY_DIRECTIVE "readonly"
+#define CONFIG_READONLY_ATTRIBUTE "nsslapd-readonly"
+#define CONFIG_REFERRAL_DIRECTIVE "referral"
+#define CONFIG_REFERRAL_ATTRIBUTE "nsslapd-referral"
+#define CONFIG_OBJECTCLASS_DIRECTIVE "objectclass"
+#define CONFIG_OBJECTCLASS_ATTRIBUTE "nsslapd-objectclass"
+#define CONFIG_ATTRIBUTE_DIRECTIVE "attribute"
+#define CONFIG_ATTRIBUTE_ATTRIBUTE "nsslapd-attribute"
+#define CONFIG_SCHEMACHECK_DIRECTIVE "schemacheck"
+#define CONFIG_SCHEMACHECK_ATTRIBUTE "nsslapd-schemacheck"
+#define CONFIG_LOGLEVEL_DIRECTIVE "loglevel"
+#define CONFIG_LOGLEVEL_ATTRIBUTE "nsslapd-errorlog-level"
+#define CONFIG_ACCESSLOGLEVEL_DIRECTIVE "accessloglevel"
+#define CONFIG_ACCESSLOGLEVEL_ATTRIBUTE "nsslapd-accesslog-level"
+#define CONFIG_ACCESSLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "accesslog-maxNumOfLogsPerDir"
+#define CONFIG_ACCESSLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-accesslog-maxlogsperdir"
+#define CONFIG_ERRORLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "errorlog-maxNumOfLogsPerDir"
+#define CONFIG_ERRORLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-errorlog-maxlogsperdir"
+#define CONFIG_AUDITLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "auditlog-maxNumOfLogsPerDir"
+#define CONFIG_AUDITLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-auditlog-maxlogsperdir"
+#define CONFIG_ACCESSLOG_MAXLOGSIZE_DIRECTIVE "accesslog-maxlogsize"
+#define CONFIG_ACCESSLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-accesslog-maxlogsize"
+#define CONFIG_ERRORLOG_MAXLOGSIZE_DIRECTIVE "errorlog-maxlogsize"
+#define CONFIG_ERRORLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-errorlog-maxlogsize"
+#define CONFIG_AUDITLOG_MAXLOGSIZE_DIRECTIVE "auditlog-maxlogsize"
+#define CONFIG_AUDITLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-auditlog-maxlogsize"
+#define CONFIG_ACCESSLOG_LOGROTATIONTIME_DIRECTIVE "accesslog-logrotationtime"
+#define CONFIG_ACCESSLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-accesslog-logrotationtime"
+#define CONFIG_ERRORLOG_LOGROTATIONTIME_DIRECTIVE "errorlog-logrotationtime"
+#define CONFIG_ERRORLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-errorlog-logrotationtime"
+#define CONFIG_AUDITLOG_LOGROTATIONTIME_DIRECTIVE "auditlog-logrotationtime"
+#define CONFIG_AUDITLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-auditlog-logrotationtime"
+#define CONFIG_ACCESSLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "accesslog-logrotationtimeunit"
+#define CONFIG_ACCESSLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-accesslog-logrotationtimeunit"
+#define CONFIG_ERRORLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "errorlog-logrotationtimeunit"
+#define CONFIG_ERRORLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-errorlog-logrotationtimeunit"
+#define CONFIG_AUDITLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "auditlog-logrotationtimeunit"
+#define CONFIG_AUDITLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-auditlog-logrotationtimeunit"
+#define CONFIG_ACCESSLOG_MAXLOGDISKSPACE_DIRECTIVE "accesslog-maxlogdiskspace"
+#define CONFIG_ACCESSLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-accesslog-logmaxdiskspace"
+#define CONFIG_ERRORLOG_MAXLOGDISKSPACE_DIRECTIVE "errorlog-maxlogdiskspace"
+#define CONFIG_ERRORLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-errorlog-logmaxdiskspace"
+#define CONFIG_AUDITLOG_MAXLOGDISKSPACE_DIRECTIVE "auditlog-maxlogdiskspace"
+#define CONFIG_AUDITLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-auditlog-logmaxdiskspace"
+#define CONFIG_ACCESSLOG_MINFREEDISKSPACE_DIRECTIVE "accesslog-minfreediskspace"
+#define CONFIG_ACCESSLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-accesslog-logminfreediskspace"
+#define CONFIG_ERRORLOG_MINFREEDISKSPACE_DIRECTIVE "errorlog-minfreediskspace"
+#define CONFIG_ERRORLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-errorlog-logminfreediskspace"
+#define CONFIG_AUDITLOG_MINFREEDISKSPACE_DIRECTIVE "auditlog-minfreediskspace"
+#define CONFIG_AUDITLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-auditlog-logminfreediskspace"
+#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIME_DIRECTIVE "accesslog-logexpirationtime"
+#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-accesslog-logexpirationtime"
+#define CONFIG_ERRORLOG_LOGEXPIRATIONTIME_DIRECTIVE "errorlog-logexpirationtime"
+#define CONFIG_ERRORLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-errorlog-logexpirationtime"
+#define CONFIG_AUDITLOG_LOGEXPIRATIONTIME_DIRECTIVE "auditlog-logexpirationtime"
+#define CONFIG_AUDITLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-auditlog-logexpirationtime"
+#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "accesslog-logexpirationtimeunit"
+#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-accesslog-logexpirationtimeunit"
+#define CONFIG_ERRORLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "errorlog-logexpirationtimeunit"
+#define CONFIG_ERRORLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-errorlog-logexpirationtimeunit"
+#define CONFIG_AUDITLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "auditlog-logexpirationtimeunit"
+#define CONFIG_AUDITLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-auditlog-logexpirationtimeunit"
+#define CONFIG_ACCESSLOG_LOGGING_ENABLED_DIRECTIVE "accesslog-logging-enabled"
+#define CONFIG_ACCESSLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-accesslog-logging-enabled"
+#define CONFIG_ERRORLOG_LOGGING_ENABLED_DIRECTIVE "errorlog-logging-enabled"
+#define CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-errorlog-logging-enabled"
+#define CONFIG_AUDITLOG_LOGGING_ENABLED_DIRECTIVE "auditlog-logging-enabled"
+#define CONFIG_AUDITLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-auditlog-logging-enabled"
+#define CONFIG_ROOTDN_DIRECTIVE "rootdn"
+#define CONFIG_ROOTDN_ATTRIBUTE "nsslapd-rootdn"
+#define CONFIG_ROOTPW_DIRECTIVE "rootpw"
+#define CONFIG_ROOTPW_ATTRIBUTE "nsslapd-rootpw"
+#define CONFIG_ROOTPWSTORAGESCHEME_DIRECTIVE "rootpwstoragescheme"
+#define CONFIG_ROOTPWSTORAGESCHEME_ATTRIBUTE "nsslapd-rootpwstoragescheme"
+#define CONFIG_UPDATEDN_DIRECTIVE "updatedn"
+#define CONFIG_UPDATEDN_ATTRIBUTE "nsslapd-updatedn"
+#define CONFIG_UPDATEPW_DIRECTIVE "updatepw"
+#define CONFIG_UPDATEPW_ATTRIBUTE "nsslapd-updatepw"
+#define CONFIG_UPDATESSLCLIENT_DIRECTIVE "updateSSLclient"
+#define CONFIG_UPDATESSLCLIENT_ATTRIBUTE "nsslapd-updateSSLclient"
+#define CONFIG_AUDITFILE_DIRECTIVE "auditfile"
+#define CONFIG_AUDITFILE_ATTRIBUTE "nsslapd-auditlog"
+#define CONFIG_LASTMOD_DIRECTIVE "lastmod"
+#define CONFIG_LASTMOD_ATTRIBUTE "nsslapd-lastmod"
+#define CONFIG_INCLUDE_DIRECTIVE "include"
+#define CONFIG_INCLUDE_ATTRIBUTE "nsslapd-include"
+#define CONFIG_DYNAMICCONF_DIRECTIVE "dynamicconf"
+#define CONFIG_DYNAMICCONF_ATTRIBUTE "nsslapd-dynamicconf"
+#define CONFIG_USEROC_DIRECTIVE "useroc"
+#define CONFIG_USEROC_ATTRIBUTE "nsslapd-useroc"
+#define CONFIG_USERAT_DIRECTIVE "userat"
+#define CONFIG_USERAT_ATTRIBUTE "nsslapd-userat"
+#define CONFIG_SVRTAB_DIRECTIVE "svrtab"
+#define CONFIG_SVRTAB_ATTRIBUTE "nsslapd-svrtab"
+#ifndef _WIN32
+#define CONFIG_LOCALUSER_DIRECTIVE "localuser"
+#define CONFIG_LOCALUSER_ATTRIBUTE "nsslapd-localuser"
+#endif /* !_WIN32 */
+#define CONFIG_LOCALHOST_DIRECTIVE "localhost"
+#define CONFIG_LOCALHOST_ATTRIBUTE "nsslapd-localhost"
+#define CONFIG_PORT_DIRECTIVE "port"
+#define CONFIG_PORT_ATTRIBUTE "nsslapd-port"
+#define CONFIG_LISTENHOST_DIRECTIVE "listenhost"
+#define CONFIG_LISTENHOST_ATTRIBUTE "nsslapd-listenhost"
+#define CONFIG_SECURITY_DIRECTIVE "security"
+#define CONFIG_SECURITY_ATTRIBUTE "nsslapd-security"
+#define CONFIG_SSL3CIPHERS_DIRECTIVE "SSL3ciphers"
+#define CONFIG_SSL3CIPHERS_ATTRIBUTE "nsslapd-SSL3ciphers"
+#define CONFIG_ACCESSLOG_DIRECTIVE "accesslog"
+#define CONFIG_ACCESSLOG_ATTRIBUTE "nsslapd-accesslog"
+#define CONFIG_ERRORLOG_DIRECTIVE "errorlog"
+#define CONFIG_ERRORLOG_ATTRIBUTE "nsslapd-errorlog"
+#define CONFIG_INSTANCEDIR_DIRECTIVE "instancedir"
+#define CONFIG_INSTANCEDIR_ATTRIBUTE "nsslapd-instancedir"
+#define CONFIG_SECUREPORT_DIRECTIVE "secure-port"
+#define CONFIG_SECUREPORT_ATTRIBUTE "nsslapd-securePort"
+#define CONFIG_SECURELISTENHOST_DIRECTIVE "secure-listenhost"
+#define CONFIG_SECURELISTENHOST_ATTRIBUTE "nsslapd-securelistenhost"
+#define CONFIG_THREADNUMBER_DIRECTIVE "threadnumber"
+#define CONFIG_THREADNUMBER_ATTRIBUTE "nsslapd-threadnumber"
+#define CONFIG_MAXTHREADSPERCONN_DIRECTIVE "maxthreadsperconn"
+#define CONFIG_MAXTHREADSPERCONN_ATTRIBUTE "nsslapd-maxthreadsperconn"
+#if !defined(_WIN32) && !defined(AIX)
+#define CONFIG_MAXDESCRIPTORS_DIRECTIVE "maxdescriptors"
+#define CONFIG_MAXDESCRIPTORS_ATTRIBUTE "nsslapd-maxdescriptors"
+#endif /* !_WIN32 && ! AIX */
+#define CONFIG_RESERVEDESCRIPTORS_DIRECTIVE "reservedescriptors"
+#define CONFIG_RESERVEDESCRIPTORS_ATTRIBUTE "nsslapd-reservedescriptors"
+#define CONFIG_IDLETIMEOUT_DIRECTIVE "idletimeout"
+#define CONFIG_IDLETIMEOUT_ATTRIBUTE "nsslapd-idletimeout"
+#define CONFIG_IOBLOCKTIMEOUT_DIRECTIVE "ioblocktimeout"
+#define CONFIG_IOBLOCKTIMEOUT_ATTRIBUTE "nsslapd-ioblocktimeout"
+#define CONFIG_NTSYNCH_DIRECTIVE "ntsynch"
+#define CONFIG_NTSYNCH_ATTRIBUTE "nsslapd-NTSynch"
+#define CONFIG_NTSYNCHUSESSL_DIRECTIVE "ntsynchusessl"
+#define CONFIG_NTSYNCHUSESSL_ATTRIBUTE "nsslapd-NTSynch-SSL"
+#define CONFIG_NTSYNCHPORT_DIRECTIVE "ntsynch-port"
+#define CONFIG_NTSYNCHPORT_ATTRIBUTE "nsslapd-NTSynch-port"
+#define CONFIG_ACCESSCONTROL_DIRECTIVE "accesscontrol"
+#define CONFIG_ACCESSCONTROL_ATTRIBUTE "nsslapd-accesscontrol"
+#define CONFIG_GROUPEVALNESTLEVEL_DIRECTIVE "groupevalnestlevel"
+#define CONFIG_GROUPEVALNESTLEVEL_ATTRIBUTE "nsslapd-groupevalnestlevel"
+#define CONFIG_NAGLE_DIRECTIVE "nagle"
+#define CONFIG_NAGLE_ATTRIBUTE "nsslapd-nagle"
+#define CONFIG_PW_CHANGE_DIRECTIVE "pw_change"
+#define CONFIG_PW_CHANGE_ATTRIBUTE "passwordChange"
+#define CONFIG_PW_MUSTCHANGE_DIRECTIVE "pw_must_change"
+#define CONFIG_PW_MUSTCHANGE_ATTRIBUTE "passwordMustChange"
+#define CONFIG_PW_SYNTAX_DIRECTIVE "pw_syntax"
+#define CONFIG_PW_SYNTAX_ATTRIBUTE "passwordCheckSyntax"
+#define CONFIG_PW_MINLENGTH_DIRECTIVE "pw_minlength"
+#define CONFIG_PW_MINLENGTH_ATTRIBUTE "passwordMinLength"
+#define CONFIG_PW_EXP_DIRECTIVE "pw_exp"
+#define CONFIG_PW_EXP_ATTRIBUTE "passwordExp"
+#define CONFIG_PW_MAXAGE_DIRECTIVE "pw_maxage"
+#define CONFIG_PW_MAXAGE_ATTRIBUTE "passwordMaxAge"
+#define CONFIG_PW_MINAGE_DIRECTIVE "pw_minage"
+#define CONFIG_PW_MINAGE_ATTRIBUTE "passwordMinAge"
+#define CONFIG_PW_WARNING_DIRECTIVE "pw_warning"
+#define CONFIG_PW_WARNING_ATTRIBUTE "passwordWarning"
+#define CONFIG_PW_HISTORY_DIRECTIVE "pw_history"
+#define CONFIG_PW_HISTORY_ATTRIBUTE "passwordHistory"
+#define CONFIG_PW_INHISTORY_DIRECTIVE "pw_inhistory"
+#define CONFIG_PW_INHISTORY_ATTRIBUTE "passwordInHistory"
+#define CONFIG_PW_LOCKOUT_DIRECTIVE "pw_lockout"
+#define CONFIG_PW_LOCKOUT_ATTRIBUTE "passwordLockout"
+#define CONFIG_PW_STORAGESCHEME_DIRECTIVE "pw_storagescheme"
+#define CONFIG_PW_STORAGESCHEME_ATTRIBUTE "passwordStorageScheme"
+#define CONFIG_PW_MAXFAILURE_DIRECTIVE "pw_maxfailure"
+#define CONFIG_PW_MAXFAILURE_ATTRIBUTE "passwordMaxFailure"
+#define CONFIG_PW_UNLOCK_DIRECTIVE "pw_unlock"
+#define CONFIG_PW_UNLOCK_ATTRIBUTE "passwordUnlock"
+#define CONFIG_PW_LOCKDURATION_DIRECTIVE "pw_lockduration"
+#define CONFIG_PW_LOCKDURATION_ATTRIBUTE "passwordLockoutDuration"
+#define CONFIG_PW_RESETFAILURECOUNT_DIRECTIVE "pw_resetfailurecount"
+#define CONFIG_PW_RESETFAILURECOUNT_ATTRIBUTE "passwordResetFailureCount"
+#define CONFIG_ACCESSLOG_BUFFERING_DIRECTIVE "logbuffering"
+#define CONFIG_ACCESSLOG_BUFFERING_ATTRIBUTE "nsslapd-accesslog-logbuffering"
+#define CONFIG_CHANGELOG_DIR_DIRECTIVE "changelogdir"
+#define CONFIG_CHANGELOG_DIR_ATTRIBUTE "nsslapd-changelogdir"
+#define CONFIG_CHANGELOG_SUFFIX_DIRECTIVE "changelogsuffix"
+#define CONFIG_CHANGELOG_SUFFIX_ATTRIBUTE "nsslapd-changelogsuffix"
+#define CONFIG_CHANGELOG_MAXENTRIES_DIRECTIVE "changelogmaxextries"
+#define CONFIG_CHANGELOG_MAXENTRIES_ATTRIBUTE "nsslapd-changelogmaxentries"
+#define CONFIG_CHANGELOG_MAXAGE_DIRECTIVE "changelogmaxage"
+#define CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE "nsslapd-changelogmaxage"
+#define CONFIG_RETURN_EXACT_CASE_DIRECTIVE "return_exact_case"
+#define CONFIG_RESULT_TWEAK_DIRECTIVE "result_tweak"
+#define CONFIG_REFERRAL_MODE_DIRECTIVE "referralmode"
+#define CONFIG_ATTRIBUTE_NAME_EXCEPTION_DIRECTIVE "attribute_name_exceptions"
+#define CONFIG_MAXBERSIZE_DIRECTIVE "maxbersize"
+#define CONFIG_VERSIONSTRING_DIRECTIVE "versionstring"
+#define CONFIG_ENQUOTE_SUP_OC_DIRECTIVE "enquote_sup_oc"
+#define CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE "nsslapd-enquote_sup_oc"
+#define CONFIG_BASEDN_DIRECTIVE "certmap-basedn"
+#define CONFIG_BASEDN_ATTRIBUTE "nsslapd-certmap-basedn"
+
+%HashParametersName = ();
+
+# The following hash displays only general server parameters to migrate under cn=config
+%GeneralSrvParamToMigrate = (
+ 'accesscontrol' => 'nsslapd-accesscontrol',
+ 'errorlog-logging-enabled' => 'nsslapd-errorlog-logging-enabled',
+ 'accesslog-logging-enabled' => 'nsslapd-accesslog-logging-enabled',
+ 'auditlog-logging-enabled' => 'nsslapd-auditlog-logging-enabled',
+ 'logbuffering' => 'nsslapd-accesslog-logbuffering',
+ 'accesslog-logexpirationtime' => 'nsslapd-accesslog-logexpirationtime',
+ 'accesslog-logexpirationtimeunit' => 'nsslapd-accesslog-logexpirationtimeunit',
+ 'accesslog-maxlogdiskspace' => 'nsslapd-accesslog-logmaxdiskspace',
+ 'accesslog-minfreediskspace' => 'nsslapd-accesslog-logminfreediskspace',
+ 'accesslog-logrotationtime' => 'nsslapd-accesslog-logrotationtime',
+ 'accesslog-logrotationtimeunit' => 'nsslapd-accesslog-logrotationtimeunit',
+ 'accesslog-maxlogsize' => 'nsslapd-accesslog-maxlogsize',
+ 'accesslog-maxnumoflogsperdir' => 'nsslapd-accesslog-maxLogsPerDir',
+ 'auditlog-logexpirationtime' => 'nsslapd-auditlog-logexpirationtime',
+ 'auditlog-logexpirationtimeunit' => 'nsslapd-auditlog-logexpirationtimeunit',
+ 'auditlog-maxlogdiskspace' => 'nsslapd-auditlog-logmaxdiskspace',
+ 'auditlog-minfreediskspace' => 'nsslapd-auditlog-logminfreediskspace',
+ 'auditlog-logrotationtime' => 'nsslapd-auditlog-logrotationtime',
+ 'auditlog-logrotationtimeunit' => 'nsslapd-auditlog-logrotationtimeunit',
+ 'auditlog-maxlogsize' => 'nsslapd-auditlog-maxlogsize',
+ 'auditlog-maxnumoflogsperdir' => 'nsslapd-auditlog-maxLogsPerDir',
+ 'certmap-basedn' => 'nsslapd-certmap-basedn',
+ 'enquote_sup_oc' => 'nsslapd-enquote-sup-oc',
+ 'loglevel' => 'nsslapd-errorlog-level',
+ 'errorlog-logexpirationtime' => 'nsslapd-errorlog-logexpirationtime',
+ 'errorlog-logexpirationtimeunit' => 'nsslapd-errorlog-logexpirationtimeunit',
+ 'errorlog-maxlogdiskspace' => 'nsslapd-errorlog-logmaxdiskspace',
+ 'errorlog-minfreediskspace' => 'nsslapd-errorlog-logminfreediskspace',
+ 'errorlog-logrotationtime' => 'nsslapd-errorlog-logrotationtime',
+ 'errorlog-logrotationtimeunit' => 'nsslapd-errorlog-logrotationtimeunit',
+ 'errorlog-maxlogsize' => 'nsslapd-errorlog-maxlogsize',
+ 'errorlog-maxnumoflogsperdir' => 'nsslapd-errorlog-maxlogsperdir',
+ 'idletimeout' => 'nsslapd-idletimeout',
+ 'ioblocktimeout' => 'nsslapd-ioblocktimeout',
+ 'lastmod' => 'nsslapd-lastmod',
+ 'listenhost' => 'nsslapd-listenhost',
+ 'maxdescriptors' => 'nsslapd-maxdescriptors',
+ 'referral' => 'nsslapd-referral',
+ 'reservedescriptors' => 'nsslapd-reservedescriptors',
+ 'rootpwstoragescheme' => 'nsslapd-rootpwstoragescheme',
+ 'schemacheck' => 'nsslapd-schemacheck',
+ 'secure-port' => 'nsslapd-securePort',
+ 'security' => 'nsslapd-security',
+ 'sizelimit' => 'nsslapd-sizelimit',
+ 'SSL3ciphers' => 'nsslapd-SSL3ciphers',
+ 'timelimit' => 'nsslapd-timelimit',
+ 'pw_change' => 'passwordChange',
+ 'pw_syntax' => 'passwordCheckSyntax',
+ 'pw_exp' => 'passwordExp',
+ 'pw_history' => 'passwordHistory',
+ 'pw_inhistory' => 'passwordInHistory',
+ 'pw_lockout' => 'passwordLockout',
+ 'pw_lockduration' => 'passwordLockoutDuration',
+ 'pw_maxage' => 'passwordMaxAge',
+ 'pw_maxfailure' => 'passwordMaxFailure',
+ 'pw_minage' => 'passwordMinAge',
+ 'pw_minlength' => 'passwordMinLength',
+ 'pw_must_change' => 'passwordMustChange',
+ 'pw_resetfailurecount' => 'passwordResetFailureCount',
+ 'pw_storagescheme' => 'passwordStorageScheme',
+ 'pw_unlock' => 'passwordUnlock',
+ 'pw_warning' => 'passwordWarning'
+);
+
+# the following hash displays global parameters related to database stored under cn=config,cn=ldbm database,cn=plugins,cn=config
+%GlobalConfigLDBMparamToMigrate = (
+ 'allidsthreshold' => 'nsslapd-allidsthreshold',
+ 'lookthroughlimit' => 'nsslapd-lookthroughlimit',
+ 'mode' => 'nsslapd-mode',
+ 'dbcachesize' => 'nsslapd-dbcachesize'
+);
+
+# the following hash displays specific parameters to each backends and stored under cn=DBname,cn=ldbm database,cn=plugins,cn=config
+%LDBMparamToMigrate = (
+ 'cachesize' => 'nsslapd-cachesize',
+ 'readonly' => 'nsslapd-readonly'
+);
+
+%stdIncludes = (
+ "${oldConfDir}slapd.at.conf", "\n",
+ "${oldConfDir}slapd.oc.conf", "\n",
+ "${oldConfDir}java-object-schema.conf", "\n",
+ "${oldConfDir}ns-admin-schema.conf", "\n",
+ "${oldConfDir}ns-calendar-schema.conf", "\n",
+ "${oldConfDir}ns-certificate-schema.conf", "\n",
+ "${oldConfDir}ns-common-schema.conf", "\n",
+ "${oldConfDir}ns-compass-schema.conf", "\n",
+ "${oldConfDir}ns-delegated-admin-schema.conf", "\n",
+ "${oldConfDir}ns-directory-schema.conf", "\n",
+ "${oldConfDir}ns-legacy-schema.conf", "\n",
+ "${oldConfDir}ns-mail-schema.conf", "\n",
+ "${oldConfDir}ns-mcd-browser-schema.conf", "\n",
+ "${oldConfDir}ns-mcd-config-schema.conf", "\n",
+ "${oldConfDir}ns-mcd-li-schema.conf", "\n",
+ "${oldConfDir}ns-mcd-mail-schema.conf", "\n",
+ "${oldConfDir}ns-media-schema.conf", "\n",
+ "${oldConfDir}ns-mlm-schema.conf", "\n",
+ "${oldConfDir}ns-msg-schema.conf", "\n",
+ "${oldConfDir}ns-netshare-schema.conf", "\n",
+ "${oldConfDir}ns-news-schema.conf", "\n",
+ "${oldConfDir}ns-proxy-schema.conf", "\n",
+ "${oldConfDir}ns-value-schema.conf", "\n",
+ "${oldConfDir}ns-wcal-schema.conf", "\n",
+ "${oldConfDir}ns-cos-schema.conf", "\n",
+ "${oldConfDir}ns-web-schema.conf", "\n"
+);
+
+%userDefinedConfigFiles = (
+ "slapd.conf", "\n",
+ "slapd.ldbm.conf", "\n",
+ "slapd.user_at.conf", "\n",
+ "slapd.user_oc.conf", "\n",
+ "ns-schema.conf", "\n"
+ );
+
+$CIS_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.15" ;
+$TELEPHONE_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.50" ;
+$DN_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.12" ;
+$CES_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.26" ;
+$INT_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.27" ;
+$BIN_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.5" ;
+
+%allowedPlugins = (
+ "cis", $CIS_SYNTAX_OID,
+ "tel", $TELEPHONE_SYNTAX_OID,
+ "dn", $DN_SYNTAX_OID,
+ "ces", $CES_SYNTAX_OID,
+ "int", $INT_SYNTAX_OID,
+ "bin", $BIN_SYNTAX_OID
+ );
+
+%allowedModifiers = (
+ "single", "SINGLE-VALUE"
+ );
+# "override" is not supported anymore and "operational" cannot be used in user defined attribute.
+
+@oldSuffixes = () ; # array of old suffixes (with "o=netscaperoot" if presents)
+
+# link beetwen the name of the suffix and its associated DBname
+%DBNAMES = () ;
+%DBDirectory = () ;
+
+%oldhash = () ;
+
+# list of standard plugin's in version 4
+%stdPlugins = (
+ "7-bit check" => "\n",
+ "binary syntax" => "\n",
+ "case exact string syntax" => "\n",
+ "case ignore string syntax" => "\n",
+ "distinguished name syntax" => "\n",
+ "integer syntax" => "\n",
+ "internationalization plugin" => "\n",
+ "referential integrity postoperation" => "\n",
+ "telephone syntax" => "\n",
+ "uid uniqueness" => "\n"
+
+ );
+
+# list of standard indexes configured out of the box in version 4
+%stdIndex = (
+ 'aci', "\n",
+ 'changenumber', "\n",
+ 'copiedfrom', "\n",
+ 'dncomp', "\n",
+ 'entrydn', "\n",
+ 'numsubordinates', "\n",
+ 'objectclass', "\n",
+ 'parentid', "\n"
+);
+
+# list of user added Plugin's. In the new version, they 'll need to be recompiled
+@badPlugins = () ;
+
+%newIndex = () ;
+
+%User_oc = () ;
+# push objectnames as they are encountered in config files.
+@User_oc_names = () ;
+
+%User_at = () ;
+
+
+
+#Usage parameters
+$USER_OC_FILE_MODIFIED = 0 ; # 0 if user don't want to modify LDIF objectclasses before processing, 1 else
+$USER_AT_FILE_MODIFIED = 0 ;
+$INDEX_FILE_MODIFIED = 0 ;
+
+# get the version of the DS to migrate
+($oldVersion, $oldMinor) = &getVersion($oldDir, $oldversionstr);
+# get the version of the new DS
+($Version, $Minor) = &getVersion($root);
+
+# get old LIB_PATH
+$old_libpath = &getLibPath($oldDir, $oldVersion, $oldMinor);
+# get new LIB_PATH
+$new_libpath = &getLibPath($root, $Version, $Minor);
+
+# Shutdown the legacy Directory instance
+printTrace("\nShutdown the legacy Directory Server instance: ${oldHome}",0);
+&stopServer($oldDir, 'slapd-'.$oldname);
+
+# compare configuration files with the standard ones
+CompareStdConfigFiles() ;
+die "\n\n The version of the product you want to migrate is not a 4.x Netscape Directory Server\n" unless ($oldVersion == 4) ;
+
+FillHashParametersName() ;
+
+############### Connect to the New LDAP Directory Server ######################
+$ENV{"$LIB_PATH"} = $new_libpath;
+my $LDAPservername = &getLDAPservername();
+die "\n Migration aborted. Make sure your Old and New Directory Servers are installed on the same machine \n" if ( $LDAPservername == -1 );
+$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n";
+
+# continue if the connection to new LDAP server is successful !
+printTrace("\nConnected to $Version.$Minor LDAP server\n",0) ;
+
+# get the uid and gid of the new slapd user
+($localuser, $newuid, $newgid) = getuid_gid();
+# get the uid and gid of the old slapd user
+($oldlocaluser, $olduid, $oldgid) = getolduid_gid();
+
+# backup new configuration files in <new_root_server>/slapd-instancename/config
+printTrace("\nBackup $serverHome${PATHSEP}config on $serverHome${PATHSEP}config_backup ...",0);
+&backupConfigFiles();
+
+# Parse the main configuration file: slapd.conf
+printTrace("\nParse the configuration file: $oldSlapdConf...",0);
+ParseSlapdConf("< ${oldSlapdConf}");
+
+#migrate key/cert databases
+printTrace("\nMigrate key/cert databases...",0);
+&MigrateSSL();
+
+# Update parameters : general server parameters, global LDBM parameter, specific backend parameters
+printTrace("\nUpdate general server parameters...",0);
+$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n";
+AddGeneralParameters();
+printTrace("\nUpdate global LDBM parameters...",0);
+AddGeneralLDBMParameters();
+printTrace("\nUpdate specific backend parameters...",0);
+AddSpecificLDBMParameters();
+
+##### FOR TESTING PURPOSE ONLY ########
+#
+#testIndexUpdating();
+#
+#######################################
+
+# Migrate some entries contained in the old dse.ldif, and migrate certmap.conf
+&MigrateDSE() ;
+&MigrateCertmap() ;
+
+# update new attribute definitions
+LDAPmodify_User_at();
+
+# update new object classes definitions
+LDAPmodify_User_oc();
+
+# add new indexes to each backends
+LDAPmodify_Indexes();
+
+# migrate Plug'ins parameters (enable attribute, and arguments)
+LDAPmodify_stdPlugin();
+
+################## Close the connection to new LDAP Server #####################
+$conn->close;
+
+
+################## stop the new instance and Export/Import the data, restart the server ##################
+if (%DBNAMES) {
+ &stopServer($root,'slapd-'.$newname);
+ if ($olddatadir) {
+ printTrace("\nold data directory $olddatadir...",0) ;
+ $ldif_rep = "$olddatadir${PATHSEP}";
+ } else {
+ printTrace("\ndata processing...",0) ;
+ # migrate data for each suffix: old -> LDIF files
+ &db2ldif($oldSlapdConf);
+ }
+
+ # migrate LDIF data to the new database: LDIF -> new
+ &manyLdif2db();
+ &startServer();
+}
+else {
+ printTrace("\nThere no old non-standard suffixes to migrate",0);
+}
+
+printMsg("\n\n ****** End of migration ******\n\n");
+
+close(LOGFILE);
+
+
+###########################################################################################
+# get input users
+sub getParameters {
+ my $exit = 0 ;
+ my $i = 0;
+ my $pwdfile= "";
+ while ($i <= $#ARGV) {
+ if ( "$ARGV[$i]" eq "-D" ) { # directory manager
+ if (! $rootDN) {
+ $rootDN = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-w") { # password
+ if (! $rootpwd) {
+ $rootpwd = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-j") { # password file
+ if (! $pwdfile) {
+ $pwdfile = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-o") { # old instance path
+ if (! $oldHome ) {
+ $oldHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $oldHome if $isNT ;
+ if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; }
+ if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) {
+ $oldDir = $1 ;
+ $type = $2 ;
+ $oldname = $3 ;
+ if ($isNT) {
+ $oldDir = lc($oldDir) ;
+ $type = lc($type) ;
+ $oldname = lc($oldname) ;
+ $oldHome = lc($oldHome) ;
+ grep { s@/@\\@g } $oldDir ;
+ grep { s@/@\\@g } $oldHome ;
+ }
+ }
+ else {
+ print("\nThe old instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-n") { # new instance path
+ if (! $serverHome ) {
+ $serverHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $root if $isNT ;
+ grep { s@\\@/@g } $serverHome if $isNT ;
+ if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; }
+ if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) {
+ $root = $1 if ($1);
+ $type = $2 ;
+ $newname = $3 ;
+ if ($isNT) {
+ $root = lc($root) ;
+ $type = lc($type) ;
+ $newname = lc($newname) ;
+ $serverHome = lc($serverHome) ;
+ grep { s@/@\\@g } $root ;
+ grep { s@/@\\@g } $serverHome ;
+ }
+ }
+ else {
+ print("\nThe new instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-p") { # new DS port
+ if (! $newport ) {
+ $newport = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-d") { # old instance LDIF data dir
+ if (! $olddatadir ) {
+ $olddatadir = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-v") { # old version
+ if (! $oldversionstr ) {
+ $oldversionstr = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL
+ my $value = $ARGV[++$i] ;
+ if ($value =~ /[0-3]/) {
+ $TRACELEVEL = $value ;
+ }
+ else {
+ print("\nThe tracelevel must belong to 0..3 interval");
+ &usage();
+ exit();
+ }
+ } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing
+ $NO_INPUT_USER = 1 ;
+ } elsif ("$ARGV[$i]" eq "-L") { # migration logfile
+ $LogFileReport = $ARGV[++$i] ;
+ }
+ else {
+ print("\nThe option $ARGV[$i] is not recognized");
+ &usage() ;
+ exit(1);
+ }
+ $i++;
+ }
+ if (! $rootDN) {
+ print("\nThe rootDN is missing");
+ $exit = 1;
+ }
+ if ($pwdfile ne "") {
+ # Open file and get the password
+ unless (open (RPASS, $pwfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $rootpwd = <RPASS>;
+ chomp($rootpwd);
+ close(RPASS);
+ } elsif ($rootpwd eq "-"){
+ # Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+ # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $rootpwd = ReadLine(0);
+# chomp($rootpwd);
+# ReadMode('normal');
+ }
+ if (! $rootpwd) {
+ print("\nThe rootpwd is missing");
+ $exit = 1 ;
+ }
+ if (! $newport) {
+ print("\nThe port is missing");
+ $exit = 1;
+ }
+ if (! $serverHome) {
+ print("\nThe new instance path is missing");
+ $exit = 1;
+ }
+ if (! $oldHome) {
+ print("\nThe old instance path is missing");
+ $exit = 1;
+ }
+ if ((! $LogFileReport) && $serverHome) {
+ ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime();
+ $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log";
+ }
+
+ if ($exit) {
+ &usage() ;
+ exit(1);
+ }
+
+}
+
+
+###############################################################################
+# This subroutine is used to parse the slapd.conf configuration file and migrate specific parameters contained in it
+
+
+sub ParseSlapdConf {
+ my $oldsrc = shift;
+ my $NumLine = 0 ;
+ # read the old conf file into a hash table
+ open( OLDSRC, $oldsrc ) || die "Can't open $oldsrc: $!: ";
+ LINE: while ( <OLDSRC> ) {
+ $NumLine++ ;
+ printTrace("\nLine: $_",4) ;
+ if (/^\s*\#/) { # skip comments
+ printTrace("\n# ",4) ;
+ next LINE;
+ }
+ if (/^\s*$/) { # skip blank lines
+ printTrace("\nBLANK LINE",4);
+ next LINE;
+ } elsif (/^suffix\s+/i) {
+ chomp($_) ;
+ CheckSuffix($_);
+ } elsif (/^plugin/i) {
+ printTrace("\nPLUGIN",4);
+ chomp($_);
+ if (! &isAStandardPlugin($_)) {
+ push @badPlugins, $_;
+ }
+ else {
+ my $Plugin = $_ ;
+ if (! &ParsePlugin($_,$NumLine)) {
+ printMsg("\nLine $NumLine, syntax error of the plugin:\n$Plugin");
+ }
+ }
+ } elsif (/^include\s+[\"]?(.*?)[\"]?\s*$/i) {
+ # strip leading and trailing "
+ my $include_file = $1 ;
+ grep { s@/@\\@g } $include_file if $isNT;
+ if (! &isAStandardInclude($include_file)) {
+ printTrace("\nFILE: $1 NOT STANDARD",4) ;
+ &ParseConfigurationFile($include_file);
+ printTrace("\nEXIT ParseConfigurationFile: $include_file",4) ;
+ }
+ } elsif (/^userat\s+[\"]?(.*?)[\"]?\s*$/i) {
+ printTrace("\nuserat: $1",4);
+ my $at_file = $1 ;
+ grep { s@/@\\@g } $at_file if $isNT;
+ # Parse user defined attributes
+ &ParseAttributesFile($at_file);
+ } elsif (/^useroc\s+[\"]?(.*?)[\"]?\s*$/i) {
+ printTrace("\nuseroc: $1",4);
+ my $oc_file = $1 ;
+ grep { s@/@\\@g } $oc_file if $isNT;
+ # Parse user defined object classes
+ &ParseObjectClassesFile($oc_file);
+ } elsif (/^dynamicconf\s+[\"]?(.*?)[\"]?\s*$/i){
+ printTrace("\ndynamicconf: $1",4);
+ my $dynamiconf_file = $1 ;
+ grep { s@/@\\@g } $dynamiconf_file if $isNT;
+ # Parse dynamic configuration file (e-g slapd.ldbm.conf)
+ &ParseConfigurationFile($dynamiconf_file);
+ } elsif (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/) {
+ printTrace("\nParseParameters: $1",4);
+ # Parse parameters and record the associated value in %oldhash
+ &ParseParameters($1,$2,$NumLine);
+ } else {
+ printTrace("\nUnknown format of configuration data: $_",0); }
+ }
+ close(OLDSRC);
+
+ }
+
+
+
+#############################################################################
+# return 1 if the suffix already exists, 0 else
+sub existSuffix {
+ my $suffixname = shift ;
+ my $nsuffix = normalizeDN($suffixname);
+ my $entry = $conn->search("cn=mapping tree,cn=config", "one", "(|(cn=\"$suffixname\")(cn=\"$nsuffix\"))");
+ return 1 if ($entry) ;
+ my $cpt = 5;
+ my $errorCode = $conn->getErrorCode();
+ while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && $cpt && (! $entry)) {
+ printTrace("\ntry to reconnect to search cn=\"$suffixname\",cn=mapping tree,cn=config", 1);
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ $entry = $conn->search("cn=mapping tree,cn=config", "one", "(|(cn=\"$suffixname\")(cn=\"$nsuffix\"))");
+ $errorCode = $conn->getErrorCode();
+ $cpt--;
+ }
+ return 1 if ($entry) ;
+ return 0 ;
+}
+
+# return the name of the backend if it has been successfully created, 0 else
+sub createBackend {
+ my $suffixname = shift ;
+ my $backend = "MigratedDB_0" ;
+ my $NbRetry = 1 ;
+ my $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ;
+ while ($entry) {
+ # try to find another name for the backend
+ $backend = "MigratedDB_$NbRetry" ;
+ $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ;
+ $NbRetry++;
+ }
+ # normally I should have a unique name for the backend
+ my $suffixarg = "nsslapd-suffix" ;
+ $entry = $conn->newEntry() ;
+ $entry->setDN("cn=$backend,cn=ldbm database,cn=plugins,cn=config");
+ $entry->setValues("objectclass", "top", "extensibleObject", "nsBackendInstance" );
+ $entry->setValues("cn", $backend );
+ $entry->setValues($suffixarg, $suffixname );
+ my $res = $conn->add($entry) ;
+ if ($res) {
+ return $backend ;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+# return 1, if add the new entry in the mapping tree, else 0
+sub AddEntryInMappingTree {
+ my $backend = shift ;
+ my $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ;
+ if ($entry) {
+ printTrace("\nAddEntry in progress ...",4) ;
+ my $suffixarg = "nsslapd-suffix" ;
+ my $statearg = "nsslapd-state" ;
+ my $backendarg= "nsslapd-backend";
+ my $suffixname = $entry->{$suffixarg}[0];
+ $entry = $conn->newEntry() ;
+ $entry->setDN("cn=\"$suffixname\",cn=mapping tree,cn=config") ;
+ $entry->setValues("objectclass", "top", "extensibleObject", "nsMappingTree" );
+ $entry->setValues("cn", "\"$suffixname\"");
+ $entry->setValues($statearg, "backend");
+ $entry->setValues($backendarg, $backend);
+ return $conn->add($entry);
+ }
+ else {
+ printTrace("\nNo AddEntry processed for $backend",4);
+ return 0 ;
+ }
+}
+
+
+# Treat the case where the suffix is "o=NetscapeRoot"
+sub CheckSuffix {
+ my $suffix = shift ;
+ my $suffixname ;
+ my $expLdif;
+ my $confirm = "No";
+ my $dest = "$serverHome${PATHSEP}db_backup" ;
+ my $newSlapdExecDir = "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server";
+
+ if (!(/^suffix\s+\"?(.*?)\"?\s*$/i)) {
+ printMsg("Syntax error of the suffix: $suffix");
+ return 0 ;
+ }
+ else {
+ $suffixname = $1 ;
+ }
+ if (/^suffix\s+\"?\s*o=netscaperoot\s*\"?\s*$/i) {
+ printTrace("\nFor the suffix o=NetscapeRoot, we do nothing",1);
+ # treat the case where the suffix is "o=NetscapeRoot"
+ }
+ else {
+ push @oldSuffixes, $_;
+ # check if the suffix already exists in the new DS target
+ if (! existSuffix($suffixname)) {
+ printTrace("\n\nSuffix $suffixname doesn't exist",1) ;
+ # create a new backend with the name of the suffix preceded by MigratedDB_
+ my $backend = createBackend($suffixname) ;
+ if ($backend) {
+ printTrace("\nBackend: $backend has been created !!!",1);
+ # if the creation of the backend is ok, we add a new entry in the mapping tree
+ if (AddEntryInMappingTree($backend)) {
+ # We add the association dbname->suffix in the hash %DBNAMES
+ $DBNAMES{$suffixname} = $backend ;
+ # get the db filename
+ $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ;
+ my $dirarg = "nsslapd-directory";
+ $DBDirectory{$backend} = $entry->{$dirarg}[0];
+ printTrace("\nThe relation $backend->$suffixname has been added to the mapping tree",2);
+ }
+ else {
+ printMsg("\nCOULD NOT ADD ENTRY: $backend->$suffixname IN MAPPINGTREE");
+ }
+ }
+ else {
+ printMsg("\nCOULD NOT CREATE BACKEND: $backend");
+ }
+ }
+ else {
+ printMsg("\n\nSuffix: $suffixname already exists");
+ # the suffix already exists in the new DS
+ printMsg("\nMigration will overwrite existing database");
+ printMsg("\nDo you want to continue Yes/No [No] ?") ;
+ my $answer = <STDIN> ;
+ if ($answer =~ /y|yes/i) {
+ my $nsuffix = normalizeDN($suffixname);
+ my $my_entry = $conn->search("cn=mapping tree,cn=config", "one", "(|(cn=\"$suffixname\")(cn=\"$nsuffix\"))");
+ my $backend = $my_entry->{"nsslapd-backend"}[0];
+ my $backend_entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ;
+ printMsg("Do you want to export the existing data Yes/No [Yes] ?");
+ my $answer = <STDIN> ;
+ if (!($answer =~ /n|no/i)) {
+ mkdir $dest, 0700 unless (-d $dest);
+ $expLdif = "$dest${PATHSEP}$backend.ldif";
+ while (!($confirm =~ /y|yes/i)) {
+ printMsg("\nEnter the full pathname of the file [$expLdif]:") ;
+ $answer = <STDIN> ;
+ chomp($expLdif = $answer) unless ($answer eq "\n");
+ printMsg("\nExisting data will be exported under $expLdif");
+ printMsg("\nContinue Yes/No [No] ?");
+ $confirm = <STDIN>;
+ }
+ $ENV{"$LIB_PATH"}=$new_libpath;
+ chdir($newSlapdExecDir) or die "\nCould not change directory to $newSlapdExecDir: $!\n";
+ printTrace("\nNow backing up database $CN in $expLdif\n",0);
+ &stopServer($root,'slapd-'.$newname);
+ &newinst_db2ldif($expLdif, $suffixname, $serverHome);
+ &startServer();
+ }
+ # We add the association dbname->suffix in the hash %DBNAMES
+ $DBNAMES{$suffixname} = $backend ;
+ my $dirarg = "nsslapd-directory";
+ $DBDirectory{$backend} = $backend_entry->{$dirarg}[0];
+ printTrace("\nThe relation $backend->$suffixname has been added to the mapping tree",2);
+ }
+ }
+ return 1 ;
+}
+}
+
+#############################################################################
+# Usefull to know the standard configuration
+sub isAStandardPlugin {
+ my $line = shift;
+ chomp($line);
+ printTrace("\nStdPlugin?: $line",4);
+ if ($line =~ /^plugin\s+(database|extendop|preoperation|postoperation|matchingrule|syntax)\s+(on|off)\s+\"(.*?)\"\s+\"(.*?)\"\s+(\S+)(.*)$/i) {
+ # $1 = <type>, $2 = <on|off>, $3 = <name>, $4 = <pathname>, $5 = <init_function>, $6 = [<arg>]*
+ printTrace("\nName: $3, pathname: $4, init_function: $5",4);
+
+ my $LC_line = lc($3);
+ my $Value = $stdPlugins{$LC_line} ;
+ if ($Value) {
+ printTrace("\nIS A STANDARD PLUGIN",4);
+ }
+ else {
+ printTrace("\nNOT A STANDARD PLUGIN",4);
+ }
+ return $stdPlugins{$LC_line} ;
+ }
+ else {
+ printTrace("\nSYNTAX ERROR PLUGIN",4);
+ return 0 ;
+ }
+}
+
+sub isAStandardIndex {
+ my $line = shift ;
+ chomp($line);
+ if ($line =~ /^index\s+(\S+).*/i) {
+ my $LC_line = lc($1);
+ my $Value = $stdIndex{$LC_line} ;
+ printTrace("\nInclude: $LC_line \nValue: $Value", 4);
+ return $stdIndex{$LC_line};
+ }
+ else {
+ return 0 ;
+ }
+}
+
+
+sub isAStandardInclude {
+ my $line = shift;
+
+ chomp($line);
+ if ($isNT){
+ return $stdIncludes{lc($line)};
+ }
+ else {
+ return $stdIncludes{$line} ;
+ }
+}
+
+#############################################################################
+#
+# Execute a Perldap command to update plugins definition in the new schema
+
+sub LDAPmodify_stdPlugin {
+ my $Filename = shift ;
+ my @pluginames = keys(%stdPlugins);
+ if (! $STDPLUGINS_FILE_MODIFIED) {
+ printTrace("\nLDAPmodify_plugin",4);
+ printTrace("\nMigrate plugin's...",1);
+ foreach $pluginame ( @pluginames ) {
+ my $update_plugin = 0 ;
+ my $ref_plugin = $stdPlugins{$pluginame};
+ if ($ref_plugin ne "\n") {
+ my $name = $ref_plugin->name ;
+ # We have a name change of "uid uniqueness plugin" in DS6.x
+ # to "attribute uniqueness"
+ $name = "attribute uniqueness" if ($name eq "uid uniqueness");
+ my $entry = $conn->search("cn=$name,cn=plugins,cn=config", "base","objectclass=nsSlapdPlugin") ;
+ if ($entry) {
+ my $pluginenabled="nsslapd-pluginenabled" ;
+ if (($entry->{$pluginenabled}[0]) ne $ref_plugin->enable) {
+ $update_plugin = 1 ;
+ my $enable = $ref_plugin->enable ;
+ printTrace("\n$pluginame, plugin-enable: $enable",3) ;
+ $entry->setValues($pluginenabled, $enable );
+ }
+ my $ArgNum = 0 ;
+ foreach $ArgValue (@{$ref_plugin->args}) {
+ my $Arg="nsslapd-pluginarg$ArgNum";
+ printTrace("\n$Arg: $ArgValue",3) ;
+ if ($entry->{$Arg}[0] ne $ArgValue) {
+ printTrace("\n$pluginame, $Arg: $ArgValue",3) ;
+ $update_plugin = 1 ;
+ $entry->setValues($Arg, $ArgValue) ;
+ }
+ $ArgNum++ ;
+ }
+ if ($update_plugin) {
+ printTrace("\n$pluginame is being updated...",2);
+ my $res = $conn->update($entry) ;
+ if ($res) {
+ printTrace("\nupdated !",2);
+ }
+ else {
+ printMsg("\nError during update of plugin: $pluginame") ;
+ $MigrationErrors .= "\nError during update of plugin: $pluginame";
+ }
+ }
+ else {
+ printTrace("\n$pluginame has not changed",4);
+ }
+ }
+ else {
+ printMsg("\ncan't access the plugin: cn=$name,cn=plugins,cn=config");
+ }
+ }
+ else {
+ printTrace("\nPLUGIN NOT RECORDED: $pluginame",4) ;
+ }
+ }
+ }
+ else {
+ # treat the case where the user wants to look at these plugins before processing
+ }
+}
+
+#############################################################################
+# Execute Perldap command to add new indexes to the migrated instances
+
+sub LDAPmodify_Indexes {
+ my $Filename = shift ;
+ my @indexnames = keys(%newIndex);
+ my @suffixnames = keys(%DBNAMES);
+ if ((! $INDEX_FILE_MODIFIED) && (%DBNAMES)) {
+ # we update indexes only if there is at least one backend to migrate
+ printTrace("\nLDAPmodify_indexes",4);
+ printTrace("\nMigrate indexes...",1);
+ foreach $indexname ( @indexnames ) {
+ printTrace("\nIndexName: $indexname",4);
+ printTrace("\nIndexTypes: .@{$newIndex{$indexname}->types}.", 4) ;
+ printTrace("\nIndexOIDS: .@{$newIndex{$indexname}->oids}.", 4) ;
+ foreach $suffixname ( @suffixnames ) {
+ # check if the index already exists !
+ printTrace("\nsearch for cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...", 3);
+ my $entry = $conn->search("cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex");
+ if (! $entry) {
+ # create a new index
+ printTrace("index $indexname is being created under cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...",2);
+ my $entry = $conn->newEntry();
+ $entry->setDN("cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config");
+ $entry->setValues("objectclass", "top", "nsIndex" ) ;
+ $entry->setValues("cn", $indexname) ;
+ $entry->setValues("nssystemindex", "false") ;
+ my @types = @{$newIndex{$indexname}->types} ;
+ my @oids = @{$newIndex{$indexname}->oids} ;
+ $entry->setValues("nsindextype", @types) if (@types) ;
+ $entry->setValues("nsmatchingrule", @oids ) if (@oids);
+ my $res = $conn->add($entry) ;
+ if ($res) {
+ printTrace("\nAdd index successfully: $indexname for backend: $DBNAMES{$suffixname}",2);
+ }
+ else {
+ printMsg("\n Failed to add the index: $indexname to backend: $DBNAMES{$suffixname}");
+ $MigrationErrors .= "\n Failed to add the index: $indexname to backend: $DBNAMES{$suffixname}" ;
+ }
+ }
+ elsif ($entry->{nssystemindex}[0] eq "false") {
+ # if the index is not a system index, we update it
+ printTrace("\nindex $indexname is being processed under cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...",2);
+ my @types = @{$newIndex{$indexname}->types} ; printTrace("\ntypes: .@types.",2) ;
+ my @oids = @{$newIndex{$indexname}->oids} ; printTrace("\noids: .@oids.",2) ;
+ my @existing_types = $entry->getValues("nsindextype");
+ my @existing_oids = $entry->getValues("nsmatchingrule");
+ # get the elements present in @types and not present in @existing_types
+ my @typesToAdd = &getDiff(\@types, \@existing_types);
+ # same for matchingrules
+ my @oidsToAdd = &getDiff(\@oids, \@existing_oids);
+ foreach $newtype (@typesToAdd) {
+ $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2);
+ }
+ foreach $newoid (@oidsToAdd) {
+ $entry->addValue("nsmatchingrule", $newoid);
+ }
+ if (@typesToAdd || @oidsToAdd) {
+ my $res = $conn->update($entry) ;
+ if ($res) {
+ printTrace("\nUpdate index successfully: $indexname for backend: $DBNAMES{$suffixname}",2);
+ }
+ else {
+ printMsg("\n Failed to update the index: $indexname to backend: $DBNAMES{$suffixname}");
+ $MigrationErrors .= "\n Failed to update the index: $indexname to backend: $DBNAMES{$suffixname}" ;
+ }
+ }
+ else {
+ printTrace("\nNothing to update",2);
+ }
+ }
+ else {
+ printTrace("\nThe index: $indexname is a system index. It can't be updated",2);
+ }
+ }
+ }
+
+ }
+ else {
+ # treat the case where the user wants to look at these indexes before processing
+ }
+
+}
+
+#############################################################################
+#
+# Execute a Perldap command to add all user defined object classes in the new schema
+
+sub LDAPmodify_User_oc {
+ my $Filename = shift ;
+ if (! $USER_OC_FILE_MODIFIED) {
+ printTrace("\nLDAPmodify_User_oc",4);
+ printTrace("\nMigrate objectclasses...",1);
+ foreach $objectname ( @User_oc_names ) {
+ my $entry = $conn->search("cn=schema", "base","objectclass=*") ;
+ die "\ncan't connect to object: cn=schema\n" unless ($entry);
+ printTrace("\nObjectName: $objectname\nValue: $User_oc{$objectname}",3);
+ next if ($entry->hasValue("objectclasses",$User_oc{$objectname},1)) ;
+ $entry->addValue("objectclasses",$User_oc{$objectname},"1") ;
+ my $res = $conn->update($entry) ;
+ my $err = $conn->getErrorCode();
+ if ($res) {
+ printTrace("\nobjectclass: $User_oc{$objectname} added",2);
+ } elsif ($err == 20) { # already exists
+ printTrace("\nobjectclass: $User_oc{$objectname} already exists",1);
+ } else {
+ printMsg("\nCan\'t add objectclass to the schema: $User_oc{$objectname}");
+ my $msg = $conn->getErrorString();
+ printMsg("\nMsg: $msg");
+ $MigrationErrors .= "\nCan\'t add objectclass to the schema: $User_oc{$objectname}" ;
+ }
+ }
+ }
+ else {
+ # treat the case where the user wants to look at these objectclasses before processing
+ }
+}
+
+#############################################################################
+#
+# Execute a Perldap command to add all user defined attributes in the new schema
+
+sub LDAPmodify_User_at {
+ my $Filename = shift ;
+ my @attributenames = keys(%User_at);
+ if (! $USER_AT_FILE_MODIFIED) {
+
+ printTrace("\nLDAPmodify_User_at",4);
+ printTrace("\nMigrate attributes...",1);
+ foreach $attributename ( @attributenames ) {
+ my $entry = $conn->search("cn=schema", "base","objectclass=*") ;
+ printTrace("\nAtributeName: $attributename, Value: $User_at{$attributename}",3);
+ die "\nentry not found cn=schema\n" unless $entry ;
+ next if ($entry->hasValue("attributetypes",$User_at{$attributename},1) ) ;
+ my $res = $entry->addValue("attributetypes",$User_at{$attributename},"1") ;
+ if (! $res) {
+ printMsg("\nCan\'t add attribute to the schema: $User_at{$attributename}");
+ $MigrationErrors .= "\nCan\'t add attribute to the schema: $User_at{$attributename}" ;
+ }
+ my $res = $conn->update($entry) ;
+ my $err = $conn->getErrorCode();
+ if ($res) {
+ printTrace("\nattribute: $attributename added",2);
+ } elsif ($err == 20) { # already exists
+ printTrace("\nattribute: $attributename already exists",1);
+ }
+ else {
+ printMsg("\nCan\'t add attribute to the schema: $User_at{$attributename}");
+ my $msg = $conn->getErrorString();
+ printMsg("\nMsg: $msg");
+ $MigrationErrors .= "\nCan\'t add attribute to the schema: $User_at{$attributename}" ;
+ }
+ }
+ }
+ else {
+ # treat the case where the user wants to look at these attributes before processing
+ }
+}
+
+#############################################################################
+# Add an object class to the user_oc hash and reset the object !!!
+sub AddObjectClass {
+ my $ObjectClass = shift ;
+ my $ObjectName = $ObjectClass->{'ObjectName'} ;
+ my $Object_oid = $ObjectClass->{'Object_oid'} ;
+ my $Object_superior = $ObjectClass->{'Object_superior'} ;
+ my $Object_requires = $ObjectClass->{'Object_requires'} ;
+ my $Object_allows = $ObjectClass->{'Object_allows'} ;
+ my $ObjectClassDef = "( $Object_oid NAME \'$ObjectName\' DESC \'\' SUP $Object_superior STRUCTURAL MUST ($Object_requires) MAY ($Object_allows) X-ORIGIN \'user defined\' )";
+ if ( (!($ObjectName =~ /^top$/i)) && ( ! $User_oc{$ObjectName} )) {
+ $User_oc{$ObjectName} = $ObjectClassDef ;
+ push @User_oc_names, $ObjectName ;
+ printTrace("ObjectName: $ObjectName \nObject_oid: $Object_oid \nObject_superior:$Object_superior \nObject_requires: $Object_requires \nObject_allows: $Object_allows \nObjectClassDefinition: $User_oc{$ObjectName}\n",4);
+ }
+ elsif ( ($User_oc{$ObjectName}) && ($User_oc{$ObjectName} ne $ObjectClassDef) ) {
+ printMsg("\nAttempt to redifine the objectclass: $ObjectName previously defined in your configuration file. Operation not allowed ");
+ }
+ else {
+ printMsg("\nAttempt to redifine the objectclass: top. Operation not allowed");
+ }
+ resetObjectClass($ObjectClass);
+}
+
+#############################################################################
+# Build an LDIF attribute and add it to the user_at hash
+sub AddAttribute {
+ my $Attr = shift ;
+ my $AttributeName = $Attr->{'AttributeName'};
+ my $Attribute_oid = $Attr->{'Attribute_oid'};
+ my $Attribute_aliases = $Attr->{'Attribute_aliases'};
+ my $Attribute_syntax = $Attr->{'Attribute_syntax'};
+ my $Attribute_single = $Attr->{'Attribute_single'};
+ my $AttributeDef = "( $Attribute_oid NAME ( \'$AttributeName\' $Attribute_aliases) DESC \'User Defined Attribute\' SYNTAX $Attribute_syntax $Attribute_single X-ORIGIN 'user defined' )" ;
+ printTrace("\nAttributeDef: $AttributeDef",4);
+ $User_at{$AttributeName} = $AttributeDef ;
+}
+#############################################################################
+# add the index structure to the newIndex hash
+sub AddIndex {
+ my $ref_index = shift ;
+ my $state = shift ;
+ printTrace("\nAddIndex, last state: $state",4) ;
+ if ($state == 1) {
+ $ref_index->specific("ALL") ;
+ return 1 ;
+ }
+ elsif ($state == 6) {
+ $ref_index->specific("NONE") ;
+ return 1 ;
+ }
+ if (($state == 1) || ($state == 3) || ($state == 5) || ($state == 6)) {
+ foreach $name (@{$ref_index->names}) {
+ $newIndex{$name} = $ref_index ; # record the ref to the index struct in the newIndex hash
+ }
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+#############################################################################
+# add the plugin structure to the stdPlugin hash
+
+sub AddPlugin {
+ my $ref_plugin = shift ;
+ printTrace("\nAddPlugin",4) ;
+ $stdPlugins{lc($ref_plugin->name)} = $ref_plugin ;
+ my $name = $ref_plugin->name ;
+ my $type = $ref_plugin->type ;
+ my $enable = $ref_plugin->enable ;
+
+ printTrace("\nPluginName: $name",4);
+ printTrace("\nPluginType: $type",4);
+ printTrace("\nPluginEnable: $enable",4);
+ printTrace("\nPluginArgs: @{$ref_plugin->args}",4);
+ return 1 ;
+}
+
+
+#############################################################################
+# parse a plugin definition and call the addindex
+
+sub ParsePlugin {
+ my $Plugin = shift ;
+ my $NumLine = shift ;
+ my $state = 0 ;
+ my $ErrorMsg = "Syntax error of a plugin definition. \n line parsed:";
+ my $ref_plugin = S_plugin->new();
+ printTrace("\nParsePlugin: $_",4);
+ if (/^plugin\s+(database|extendop|preoperation|postoperation|matchingrule|syntax)\s+(on|off)\s+\"(.*?)\"\s+\"(.*?)\"\s+(\S+)(.*)$/i) {
+ # $1 = <type>, $2 = <on|off>, $3 = <name>, $4 = <pathname>, $5 = <init_function>, $6 = [<arg>]*
+ $ref_plugin->name($3);
+ $ref_plugin->type($1);
+ $ref_plugin->enable($2);
+ $_ = $6 ;
+ my $ArgNb = 0 ;
+ my $prec ;
+ my $arg ;
+ my $Unix_oldDir = $oldDir ;
+ my $Unix_root = $root ;
+ grep { s@\\@/@g } $Unix_oldDir if $isNT;
+ grep { s@\\@/@g } $Unix_root if $isNT;
+ while (!(/^\s*$/)) {
+ if (/^\s*\".*?\"/) {
+ s/^\s*\"(.*?)\"(.*)/$2/i ;
+ $arg = $1 ;
+ }
+ elsif (/^\s*[^\"\s]+/) {
+ s/^\s*([^\"\s]+)(.*)/$2/i ;
+ $arg = $1 ;
+ }
+ $prec = $_ ;
+ $_ = $arg ;
+
+ s@$Unix_oldDir@$Unix_root@ig ;
+ s/$type-$oldname/$type-$newname/ig ;
+ @{$ref_plugin->args}[$ArgNb++] = $_ ;
+ $_ = $prec ;
+ }
+ if (/^\s*$/) {
+ return AddPlugin($ref_plugin);
+ }
+ else {
+ return 0 ;
+ }
+ }
+ return 0 ;
+}
+
+#############################################################################
+# parse an index definition and call the addindex
+
+sub ParseIndex {
+ my $index = shift ;
+ my $NumLine = shift ;
+ my $ref_index = S_index->new() ;
+ my $Value ;
+ my $state = 0 ;
+ my $ErrorMsg = "Syntax error of an index definition.\nline parsed:";
+ printTrace("\nParseIndex: $_",4) ;
+ s/,/, /g ;
+ s/\s+,/,/g ;
+ s/^index\s+//i ; # substitute the token index
+ while (!(/^\s*$/)) {
+ s/^\s*(\S+)(.*)$/$2/ ;
+ $Value = $1 ;
+ printTrace("\nValue: $Value",4);
+ printTrace("\nState: $state",4) ;
+ SWITCH: {
+ if ($state == 0) {
+ if ($Value =~ /[^\.]/) {
+ if ($Value =~ /(\S+),$/) {
+ push @{$ref_index->names}, $1 ;
+ }
+ else {
+ $state = 1 ;
+ push @{$ref_index->names}, $Value ;
+ }
+ }
+ else {
+ return 0 ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 1) {
+ if ($Value =~ /^none$/i) {
+ $state = 6 ; # end of the index definition
+ }
+ elsif ($Value =~ /^\"\"$/) {
+ $state = 4 ; # we expect to have at least one OID
+ }
+ elsif ($Value =~ /(\S+),$/) {
+ $state = 2 ;
+ push @{$ref_index->types}, $1 ;
+ }
+ else {
+ $state = 3 ;
+ push @{$ref_index->types}, $Value ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 2) {
+ if ($Value =~ /(\S+),$/) {
+ push @{$ref_index->types}, $1 ;
+ }
+ else {
+ $state = 3 ;
+ push @{$ref_index->types}, $Value ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 3) {
+ if ($Value =~ /(\S+),$/) {
+ $state = 4 ;
+ push @{$ref_index->oids}, $1 ;
+ }
+ else {
+ $state = 5 ;
+ push @{$ref_index->oids}, $Value ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 4) {
+ if ($Value =~ /(\S+),$/) {
+ push @{$ref_index->oids}, $1 ;
+ }
+ else {
+ $state = 5 ;
+ push @{$ref_index->oids}, $Value ;
+ }
+ last SWITCH ;
+ }
+ }
+ }
+return AddIndex($ref_index,$state) ;
+
+}
+
+#############################################################################
+
+sub ParseAttribute {
+
+
+ my $Attr = shift ;
+ my $NumLine = shift ;
+ my $state = 1 ;
+ my $ErrorMsg = "Syntax error of an attribute definition.\nline parsed:";
+ my %Attribute = (
+ 'AttributeName' => "",
+ 'Attribute_oid' => "",
+ 'Attribute_aliases' => "",
+ 'Attribute_syntax' => "",
+ 'Attribute_single' => ""
+ );
+ my $AttributeName = " ";
+ printTrace("\nParseAttribute",4);
+ while (!(/^\s*$/)) {
+ s/^(.*?)(\S+)\s*$/$1/ ;
+ printTrace("\nValue: $2",4);
+ printTrace("\nState: $state",4) ;
+ my $Value = $2 ;
+ SWITCH: {
+ if ($state == 1) {
+ if (isAllowedModifier($Value)) {
+ $state = 1 ;
+ $modifier = lc($Value);
+ $AttrVar = 'Attribute_' . $modifier ;
+ $Attribute{$AttrVar} = &getModifierValue($Value) ;
+ }
+ elsif (&isAllowedPlugin($Value)) {
+ $state = 2 ;
+ $Attribute{'Attribute_syntax'} = &getSyntaxOid($Value) ;
+ }
+ else {
+ return 0 ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 2) {
+ if ($Value =~ /[\.]|-oid$/) {
+ $Attribute{'Attribute_oid'} = "$Value" ;
+ printTrace("\nAttribute-oid: $Attribute{'Attribute_oid'}",3);
+ $state = 3 ;
+ }
+ elsif ($Value =~ /[^\.]/) {
+ $AttributeName = $Attribute{'AttributeName'} ;
+ if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;}
+ $Attribute{'AttributeName'} = $Value ;
+ $state = 4 ;
+ }
+ else {
+ return 0 ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 3) {
+ if ($Value =~ /[^\.]/) {
+ $AttributeName = $Attribute{'AttributeName'} ;
+ if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;}
+ $Attribute{'AttributeName'} = $Value ;
+ $state = 4 ; }
+ else {
+ return 0 ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 4) {
+ if ($Value =~/^attribute$/i){
+ $state = 5;
+ }
+ elsif ($Value =~/[^\.]/i) {
+ $AttributeName = $Attribute{'AttributeName'} ;
+ if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;}
+ $Attribute{'AttributeName'} = $Value ;
+ }
+ else {
+ return 0 ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 5) {
+ return 0 ;
+ last SWITCH ;
+ }
+ }
+ }
+ $Attribute{'Attribute_oid'} = $Attribute{'AttributeName'} . '-oid' unless ($Attribute{'Attribute_oid'}) ;
+ return AddAttribute(\%Attribute) ;
+}
+
+
+#############################################################################
+# fill in the hash HashParametersName
+
+sub FillHashParametersName {
+ my @paramnames = ( keys(%GeneralSrvParamToMigrate), keys(%GlobalConfigLDBMparamToMigrate), keys(%LDBMparamToMigrate));
+ foreach $param (@paramnames) {
+ $HashParametersName{$param} = '\n';
+ }
+}
+
+
+# Parse parameters
+sub ParseParameters {
+ my $param = shift ;
+ my $value = shift ;
+ my $NumLine = shift ;
+ my $ErrorMsg = "parameter unknown, or not to be migrated: ";
+ if ($HashParametersName{lc($param)} && ($value !~ /^\s*$/)) {
+ $HashParametersName{lc($param)} = $value ;
+ printTrace("\nParam: $param is present",4);
+ }
+ else {
+ printTrace("\n$NumLine, $ErrorMsg,$param",4);
+ }
+
+}
+
+# add general server parameters
+sub AddGeneralParameters {
+ my @paramnames = keys(%GeneralSrvParamToMigrate);
+ my $entry = $conn->search("cn=config","base","objectclass=*");
+ die "\ncan't access to object: cn=config. \nMigration stopped\n" unless ($entry);
+ printTrace("\nAddGeneralParameters",4);
+ foreach $param (@paramnames) {
+ my $LDAPparam = $GeneralSrvParamToMigrate{$param} ;
+ my $Value = $HashParametersName{$param} ;
+ if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) {
+ printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4);
+ $entry->setValues($LDAPparam, $Value);
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nUpdate successfully $LDAPparam ",0);
+ }
+ else {
+ printMsg("\nCan't update parameter: $LDAPparam");
+ }
+ }
+ }
+}
+
+
+# add general LDBM parameters
+sub AddGeneralLDBMParameters {
+ my @paramnames = keys(%GlobalConfigLDBMparamToMigrate);
+ my $entry = $conn->search("cn=config,cn=ldbm database,cn=plugins,cn=config","base","objectclass=*");
+ die "\ncan't access to object: cn=config,cn=ldbm database,cn=plugins,cn=config. \nMigration stopped\n" unless ($entry);
+ printTrace("\nAddGeneralLDBMParameters",4);
+ foreach $param (@paramnames) {
+ my $LDAPparam = $GlobalConfigLDBMparamToMigrate{$param} ;
+ my $Value = $HashParametersName{$param} ;
+ if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) {
+ printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4);
+ $entry->setValues($LDAPparam, $Value);
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nUpdate successfully $LDAPparam ",0);
+ }
+ else {
+ printMsg("\nCan't update parameter: $LDAPparam");
+ }
+ }
+ }
+}
+
+# add specific LDBM parameters
+sub AddSpecificLDBMParameters {
+ my @paramnames = keys(%LDBMparamToMigrate);
+ my %REV_DBNAMES = reverse %DBNAMES ;
+ my @dbnames = keys(%REV_DBNAMES);
+ printTrace("\nAddSpecificLDBMParameters",4);
+ foreach $dbname (@dbnames) {
+ my $entry = $conn->search("cn=$dbname,cn=ldbm database,cn=plugins,cn=config","base","objectclass=*");
+ die "\ncan't access to object: cn=$dbname,cn=ldbm database,cn=plugins,cn=config. \nMigration stopped\n" unless ($entry);
+ foreach $param (@paramnames) {
+ my $LDAPparam = $LDBMparamToMigrate{$param} ;
+ my $Value = $HashParametersName{$param} ;
+ if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) {
+ printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4);
+ $entry->setValues($LDAPparam, $Value);
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nUpdate successfully $LDAPparam",2);
+ }
+ else {
+ printMsg("\nCan't update parameter: $LDAPparam");
+ }
+ }
+ }
+ }
+}
+
+#############################################################################
+# Parse a configuration file potentialy tuned by the user (different from slapd.user_oc.conf and slapd.user_at.conf)
+
+sub ParseConfigurationFile {
+
+ my $FileToParse = shift;
+ my $NumLine = 0;
+ my $PARSE_OBJECTCLASSES = 0 ; # 1 if there are objectclass definitions in the file
+ printTrace("\nParseConfigurationFile: $FileToParse",4) ;
+ printTrace("\nParse $FileToParse",2);
+ # read each line of the configuration file
+ my $CONFIGFILE = "CONFIGFILE.$FileToParse" ;
+ open( $CONFIGFILE, $FileToParse ) || die "Can't open $FileToParsec: $!: ";
+ LINE: while ( <$CONFIGFILE> ) {
+ $NumLine++ ;
+ if (/^\s*\#/) { # skip comments
+ next LINE;
+ }
+ if (/^\s*$/) { # skip blank lines
+ next LINE;
+ } elsif (/^suffix\s+/i) {
+ chomp($_) ;
+ CheckSuffix($_) ;
+ } elsif (/^plugin/i) {
+ chomp($_);
+ if (! &isAStandardPlugin($_)) {
+ push @badPlugins, $_;
+ }
+ else {
+ my $Plugin = $_ ;
+ if (! &ParsePlugin($_,$NumLine)) {
+ printMsg("\nLine $NumLine, syntax error of the plugin:\n$Plugin");
+ }
+ }
+ } elsif (/^index/i) {
+ chomp($_);
+ if (! &isAStandardIndex($_)) {
+ my $Index = $_ ;
+ if (! &ParseIndex($_,$NumLine)) {
+ printMsg("\nLine $NumLine, syntax error of index:\n$Index");
+ }
+ }
+ } elsif (/^include\s+[\"]?(.*?)[\"]?\s*$/i) {
+ # strip leading and trailing "
+ my $include_file = $1 ;
+ grep { s@/@\\@g } $include_file if $isNT;
+ if (! &isAStandardInclude($include_file)) {
+ &ParseConfigurationFile($include_file);
+ }
+ } elsif (/^attribute\s+\S+/i) {
+ chomp($_);
+ my $Attrib = $_ ;
+ if (! &ParseAttribute($_,$NumLine)) {
+ printMsg("\nLine $NumLine, syntax error of attribute:\n$Attrib");
+ }
+ } elsif (/^objectclass\s+(\S+)\s*$/i) {
+ # At least one objectclass is present in the file
+ $PARSE_OBJECTCLASSES = 1;
+ } elsif (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/) {
+ # Parse parameters and record the associated value in %Oldhash
+ &ParseParameters($1,$2,$NumLine);
+ }
+ }
+ close($CONFIGFILE);
+ ParseObjectClassesFile($FileToParse) if ($PARSE_OBJECTCLASSES); # parse objectclass definition
+
+}
+
+#############################################################################
+# Parse the file specified in the userat attribute
+
+sub ParseAttributesFile {
+ my $userat_file=shift ;
+ my $NumLine = 0;
+ printTrace("\nParseAttributesFile: $userat_file",4);
+ printTrace("\nParse user defined attributes file: $userat_file",2);
+ # read each line of the configuration file
+ open( ATTRFILE, $userat_file ) || die "Can't open $FileToParsec: $!: ";
+ LINE: while ( <ATTRFILE> ) {
+ $NumLine++ ;
+ if (/^\s*\#/) { # skip comments
+ next LINE;
+ }
+ if (/^\s*$/) { # skip blank lines
+ next LINE;
+ } elsif (/^attribute\s+\S+/i) {
+ chomp($_);
+ my $Attrib = $_ ;
+ if (! &ParseAttribute($_, $NumLine)) {
+ printMsg("\nLine $NumLine, syntax error of attribute:\n$Attrib");
+ }
+ }
+ }
+ close(ATTRFILE);
+}
+
+#############################################################################
+# Parse the file specified in the useroc token
+
+sub ParseObjectClassesFile {
+ my $useroc_file = shift ;
+ my %ObjectClass = (
+ 'ObjectName' => " ",
+ 'Object_oid' => " ",
+ 'Object_superior' => "top",
+ 'Object_requires' => " ",
+ 'Object_allows' => " "
+ );
+
+ my $state = 0;
+ my $ErrorMsg = "Syntax error of an object class definition.\nline parsed:";
+ my $LineNb = 0 ; # Number of the current line parsed in the file
+ printTrace("ParseObjectClassesFile: $useroc_file\n",4) ;
+ # read each line of the configuration file
+ open( OBJCLASSFILE, $useroc_file ) || die "Can't open $FileToParsec: $!: ";
+ printTrace("Begin the parsing of the file: $useroc_file",4);
+ LINE: while ( <OBJCLASSFILE> ) {
+ printTrace("Current Line: $_",4);
+ $LineNb++ ;
+ if (/^\s*\#/) { # skip comments
+ next LINE;
+ }
+ if (/^\s*$/) { # skip blank lines
+ next LINE;
+ }
+ SWITCH: {
+ if ($state == 0) { resetObjectClass(\%ObjectClass);
+ if (/^objectclass\s+(\S+)\s*$/i) {
+ $ObjectClass{'ObjectName'} = $1;
+ $state = 1 ;}
+ else {} # printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 1) {if (/^\s+oid\s+(\S+)\s*$/i) {
+ $ObjectClass{'Object_oid'} = $1;
+ $state = 2 ;}
+ elsif (/^\s+superior\s+(\S+)\s*$/i) {
+ $ObjectClass{'Object_superior'} = $1;
+ $state = 3 ;
+ }
+ elsif (/^\s+requires\s*$/i) {
+ $state = 4;
+ }
+ elsif (/^\s+allows\s*$/i) {
+ $state = 5;
+ }
+ else {$state=0; printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 2) {if (/^\s+superior\s+(\S+)\s*$/i) {
+ $ObjectClass{'Object_superior'} = $1;
+ $state = 3 ;}
+ elsif (/^\s+requires\s*$/i) {
+ $state = 4;
+ }
+ elsif (/^\s+allows\s*$/i) {
+ $state = 5;
+ }
+ else { $state=0; printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 3) {if (/^\s+requires\s*$/i)
+ { $state = 4; }
+ elsif (/^objectclass\s+(\S+)\s*$/i) {
+ # run an ldap add before to continue
+ &AddObjectClass(\%ObjectClass);
+ $ObjectClass{'ObjectName'} = $1;
+ $state = 1 ;}
+ elsif (/^\s+allows\s*$/i)
+ { $state = 5; }
+ else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 4) {if (/^\s+([^,\s]+),\s*$/i) {
+ $ObjectClass{'Object_requires'}.=$1." \$ "; }
+ elsif (/^\s+([^,\s]+)\s*$/i) {
+ $ObjectClass{'Object_requires'}.=$1." ";
+ $state = 6; }
+ else {$state = 0;printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 5) {if (/^\s+([^,\s]+),\s*$/i) {
+ $ObjectClass{'Object_allows'}.=$1." \$ "; }
+ elsif (/^\s+([^,\s]+)\s*$/i) {
+ $ObjectClass{'Object_allows'}.=$1." ";
+ # run an ldap add before to continue
+ &AddObjectClass(\%ObjectClass);
+ $state = 0; }
+ else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 6) {if (/^objectclass\s+(\S+)\s*$/i) {
+ # run an ldap add before to continue
+ &AddObjectClass(\%ObjectClass);
+ $ObjectClass{'ObjectName'} = $1;
+ $state = 1 ;}
+ elsif (/^\s+allows\s*$/i) {
+ $state = 5;}
+ else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ }
+ }
+ close(OBJCLASSFILE);
+ if (($state == 3) || ($state == 4) || ($state == 5) || ($state == 6)) {
+ &AddObjectClass(\%ObjectClass);
+ }
+ printTrace("state: $state",4);
+}
+
+#############################################################################
+# printMsg print message to the user standard output.
+
+sub printMsg {
+
+ my $TypeMsg = shift ;
+ my $Msg = shift ;
+ my $LineNb = shift ;
+ if ($LineNb) {
+ printTrace("Line: $LineNb, $TypeMsg, $Msg");
+ }
+ else {
+ printTrace("$TypeMsg $Msg");
+ }
+}
+
+#############################################################################
+# print message error to the user standard output.
+
+sub printTrace {
+
+ my $Msg = shift ;
+ my $level = shift ;
+ if ($level <= $TRACELEVEL) {
+ print($Msg);
+ print LOGFILE $Msg ;
+ }
+}
+
+#############################################################################
+# reset an objectclass structure
+
+sub resetObjectClass {
+ my $ObjectClass = shift;
+ $ObjectClass->{'ObjectName'} = " " ;
+ $ObjectClass->{'Object_oid'} = " " ;
+ $ObjectClass->{'Object_superior'} = "top" ;
+ $ObjectClass->{'Object_requires'} = " " ;
+ $ObjectClass->{'Object_allows'} = " " ;
+}
+
+#############################################################################
+# this subroutine implements a very stupid version of diff
+
+sub diff {
+ my $f1 = shift;
+ my $f2 = shift;
+ my $lineToBeginWith = shift;
+ my $NULL = "" ;
+ my $diff_f1 = $NULL ;
+ my $diff_f2 = $NULL ;
+ my $retval = $NULL ;
+ my $ret;
+ open(F1, "$f1") or die "Could not open file $f1";
+ open(F2, "$f2") or close(F1), die "Could not open file $f2";
+
+ while (defined($l1 = <F1>)) {
+ if ($lineToBeginWith){
+ $lineToBeginWith -- ;
+ next ;
+ }
+ next if ($l1 =~ /^\#/);
+ $ret = defined($l2 = <F2>);
+ if ($ret) {
+ $ret = defined($l2 = <F2>) while ($ret && ($l2 =~ /^\#/)) ;
+ if ($ret) {
+ if (!($l1 eq $l2)) {
+
+ # ignore whitespace
+ $l1_clean = $l1 ;
+ $l2_clean = $l2 ;
+ $l1_clean =~ s/\s//g;
+ $l2_clean =~ s/\s//g;
+
+ if (!($l1_clean eq $l2_clean)) {
+ $diff_f1 .= "${l1}" unless ($l1_clean eq $NULL);
+ $diff_f2 .= "${l2}" unless ($l2_clean eq $NULL);
+ }
+ }
+ }
+ else {
+ next if ($l1 =~ /^\s*$/) ;
+ $diff_f1 .= "${l1}";
+ }
+ }
+ else {
+ next if ($l1 =~ /^\s*$/) ;
+ $diff_f1 .= "${l1}";
+ }
+ }
+
+ while (defined($l2 = <F2>)) {
+ if (($l2 =~ /^\#/) || ($l2 =~ /^\s*$/)) {
+ next ;
+ }
+ else {
+ $diff_f2 .= "${l2}" ;
+ }
+ }
+
+ close(F1);
+ close(F2);
+
+ $retval .= "- differences present in your config file but not in standard file:\n\n". "$diff_f1\n" if ($diff_f1) ;
+ $retval .= "- differences present in standard file but not in your config file:\n\n" . "$diff_f2" if ($diff_f2) ;
+ return $retval ;
+}
+
+sub CompareStdConfigFiles {
+ # Compare each configuration file against its default version. If it has changed,
+ # notify the user that the file has changed and will need to be checked by the
+ # user. This should be safe to do because there should be no path information
+ # stored in these conf files, which are just schema stuff.
+ # printTrace("\nCheck if standard configuration files have changed",3);
+
+ my $origFilePath = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}install${PATHSEP}config${PATHSEP}" ;
+ my $FilesChanged = "";
+ my $AllDiffs = "***********************************************************************";
+ my $NoChanges = "" ;
+ my $lineToBegin = 0 ;
+ printTrace("\nVersion of the old directory server: $oldVersion.$oldMinor",0);
+ opendir(CONFDIR, $oldConfDir) or
+ die "Error: could not open migrated config dir $oldConfDir: $!";
+
+ foreach $file (readdir(CONFDIR)) {
+ $origFile = $origFilePath . $file ;
+ $configFile = $oldConfDir . $file ;
+ if ((! exists($userDefinedConfigFiles{lc($file)})) && (-f $origFile)) {
+ my $lineToBegin = 1 if (lc($file) eq "slapd-collations.conf"); # we ignore the first line of slapd-collations
+ $diffs = &diff($configFile, $origFile, $lineToBegin);
+ $lineToBegin = 0 if $lineToBegin ;
+ if ($diffs) {
+ $FilesChanged .= "\n$configFile";
+ $AllDiffs .= "\n$configFile is different than the standard configuration file" ;
+ $AllDiffs .= "\nYou will need to check this file and make sure its changes are compatible ";
+ $AllDiffs .= "with the new directory server\nHere are the differences:\n";
+ $AllDiffs .= "$diffs \n\n";
+ $AllDiffs .= "***********************************************************************";
+ }
+ else {
+ $NoChanges .= "\n$configFile";
+ }
+ }
+ }
+ closedir(CONFDIR);
+
+if ($FilesChanged) {
+ printTrace("\nNo changes to old configuration files:$NoChanges",3) ;
+ printTrace("\n***********************************************************************",3) ;
+ printMsg("\nThe following standard files have been modified: $FilesChanged");
+ if ($NO_INPUT_USER) {
+ # do nothing
+ }
+ else {
+ printMsg("\nDo you want to see the differences Yes/No [No] ?") ;
+ my $answer = <STDIN> ;
+ if ($answer =~ /y|yes/i) {
+ printMsg("$AllDiffs");
+ }
+ printMsg("\nDo you want to continue the migration Yes/No [No] ?");
+ $answer = <STDIN> ;
+ if (! ($answer =~ /y|yes/i)) {
+ exit(1);
+ }
+ }
+ }
+}
+
+
+#############################################################################
+
+sub db2ldif {
+ my ($conf, $ldif_dir) = @_;
+ $ENV{"$LIB_PATH"}=$old_libpath;
+ if (!$conf) {
+ $conf = "$oldHome${PATHSEP}config${PATHSEP}slapd.conf";
+ }
+ if (! $ldif_dir) { $ldif_dir = $ldif_rep ;}
+ if (!(-d $ldif_dir)) {
+ mkdir($ldif_dir,0777) or die "can't create $ldif_rep to store temporary ldif files";
+ }
+ my $dir = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server";
+ chdir($dir) or
+ die "Error: could not change directory to $dir: $!";
+ my @suffixnames = keys(%DBNAMES) ;
+ foreach $suffixname (@suffixnames) {
+ my $ldif_file = $ldif_dir.$DBNAMES{$suffixname}.".ldif" ;
+ # If we are on NT, ${quote} is setup to "\"", else it's setup to ""
+ # As the suffix can contain some space characters, I write the suffix parameter: "\"$suffixname\"" rather than "${quote}$suffixname${quote}"
+ my @cmd =
+ ( "${quote}$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" .
+ "${PATHSEP}$slapdExecName${quote}", "db2ldif", '-n', '-f',
+ "${quote}$conf${quote}", '-a', "${quote}$ldif_file${quote}",
+ '-d', '1','-s',"\"$suffixname\"" );
+ open(DB2LDIF, "${quote}@cmd${quote} 2>&1|") or
+ die "Error: could not execute @cmd: $!";
+ sleep(1); # allow pipe to fill with data
+ $ii = 0; # counter
+ while (<DB2LDIF>) {
+ ++$ii;
+ if (($ii % 250) == 0) {
+ printMsg(" Processing...\n");
+ }
+ }
+ close(DB2LDIF);
+ # set the ownership of the ldif file; should be the same as the new slapd user id
+ if ((! $isNt) && ($oldlocaluser ne $localuser)) {
+ if (-f $ldif_file) {
+ chown( $newuid, $newgid, $ldif_file) or printMsg("\nUnable to change the ownership of $ldif_file to $localuser") ;
+ }
+ }
+ }
+ print " Done.\n";
+ chdir($curdir) or die "Could not change directory to $curdir: $!";
+}
+
+#############################################################################
+# This db2ldif is used to export database of the new instance
+
+sub newinst_db2ldif {
+ my $ldif = shift ;
+ my $include_suffix = shift ;
+ my $home = shift ;
+ my $db2ldif_param = "db2ldif -r -D $home -a $ldif -s \"$include_suffix\"";
+
+ open(DB2LDIF, "${quote}${quote}$slapdExecName${quote} $db2ldif_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n";
+ sleep(1); # allow some data to accumulate in the pipe
+ my $ii = 0;
+ while (<DB2LDIF>) {
+ ++$ii;
+ if (($ii % 250) == 0) {
+ printMsg(" Processing...\n");
+ }
+ printMsg($_);
+ }
+ close(DB2LDIF);
+ # set the ownership of the ldif file; should be the same as the 5.x slapd user id
+ if ((! $isNt) && ($oldlocaluser ne $localuser)) {
+ if (-f $ldif) {
+ chown( $newuid, $newgid, $ldif) or printMsg("\nUnable to change the ownership of $ldif to $localuser") ;
+ }
+ }
+}
+
+#############################################################################
+
+# this is used to run the system() call, capture exit and signal codes,
+# and die() upon badness; the first argument is a directory to change
+# dir to, if any, and the rest are passed to system()
+sub mySystem {
+ my $rc = &mySystemNoDie(@_);
+ my ($dir, @args) = @_;
+ if ($rc == 0) {
+# success
+ } elsif ($rc == 0xff00) {
+ die "Error executing @args: error code $rc: $!";
+ } elsif ($rc > 0x80) {
+ $rc >>= 8;
+ die "Error executing @args: error code $rc: $!";
+ } else {
+ if ($rc & 0x80) {
+ $rc &= ~0x80;
+ }
+ die "Error executing @args: received signal $rc: $!";
+ }
+
+ # usually won't get return value
+ return $rc;
+}
+
+# This version does not die but just returns the error code
+sub mySystemNoDie {
+ my ($dir, @args) = @_;
+ if ($dir && ($dir ne "")) {
+ chdir($dir) or die "Could not change directory to $dir: $!";
+ }
+ my $cmd = $args[0];
+ # the system {$cmd} avoids some NT shell quoting problems if the $cmd
+ # needs to be quoted e.g. contains spaces; the map puts double quotes
+ # around the arguments on NT which are stripped by the command
+ # interpreter cmd.exe; but don't quote things which are already quoted
+ my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args;
+ my $rc = 0;
+ if ($cmd =~ /[.](bat|cmd)$/) {
+ # we have to pass batch files directly to the NT command interpreter
+ $cmd = $com_spec;
+# print "system $cmd /c \"@fixargs\"\n";
+ $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\"";
+ } else {
+# print "system $cmd @fixargs\n";
+ $rc = 0xffff & system {$cmd} @fixargs;
+ }
+ chdir(${curdir}) or die "Could not change directory to $curdir: $!";
+ return $rc;
+}
+
+#############################################################################
+sub manyLdif2db {
+ my %rev_dbnames = reverse(%DBNAMES);
+ @backends = keys(%rev_dbnames);
+ $ENV{"$LIB_PATH"}=$new_libpath;
+ chdir($slapdExecDir) or die "Could not change directory to $slapdExecDir: $!";
+ foreach $backend (@backends) {
+ my $ldif = "${ldif_rep}$backend.ldif" ;
+ if (! -f $ldif) {
+ $ldif = ${ldif_rep}."data.ldif";
+ }
+ &Ldif2db($ldif, $backend);
+ }
+ # remove the empty ldif directory
+ # but not if using the data dir
+ if (!$olddatadir) {
+ rmdir($ldif_rep);
+ }
+ chdir($curdir) or die "Could not change directory to $curdir: $!";
+}
+
+
+sub Ldif2db {
+ my $ldif = shift ;
+ my $backend = shift ;
+ my $ldif2db_param = "ldif2db -D $serverHome -n $backend -i $ldif";
+ open(LDIF2DB, "${quote}${quote}$slapdExecName${quote} $ldif2db_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n";
+ sleep(1); # allow some data to accumulate in the pipe
+ while (<LDIF2DB>) {
+ printMsg($_);
+ }
+ close(LDIF2DB);
+ # remove the ldif file after the import
+ # but not if using the data dir
+ if (!$olddatadir) {
+ unlink($ldif) ;
+ }
+}
+
+#############################################################################
+
+#sub copyBak {
+# opendir( OLDBAK, "$oldHome${PATHSEP}bak" ) ||
+# die "Can't open directory $oldHome${PATHSEP}bak: $!: ";
+# local ( @dirs ) = readdir( OLDBAK );
+# closedir ( OLDBAK );
+# for ( @dirs ) {
+# if ( $_ eq "." || $_ eq ".." ) {
+# next;
+# } elsif ( -d "$oldHome${PATHSEP}bak${PATHSEP}$_" ) {
+# $srcDir = "$oldHome${PATHSEP}bak${PATHSEP}$_";
+# $destDir = "$serverHome${PATHSEP}bak${PATHSEP}$_";
+# $srcLDIF = "$oldHome${PATHSEP}ldif${PATHSEP}bak.ldif";
+# $destLDIF = "$serverHome${PATHSEP}ldif${PATHSEP}bak.ldif";
+# mkdir( $destDir , 0755 ) if !( -e $destDir);
+# # Converting database
+# if ( !$isNT && $newuser ) {
+# chown($newuid, $newgid,
+# "$serverHome${PATHSEP}bak", $destDir);
+# }
+# &other_db2ldif($srcDir, $srcLDIF);
+# if ($needAclUpg) {
+# &mySystem("$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server",
+# "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" .
+# "${PATHSEP}aclupg$exe_suffix", '-d', '-i',
+# $srcLDIF, '-o', $destLDIF);
+# } else {
+# &copyBinFile($srcLDIF, $destLDIF);
+# }
+# &other_ldif2db($destLDIF, $destDir);
+# }
+# }
+#}
+#############################################################################
+
+sub startServer {
+ my $instanceDir = ${serverHome} ;
+ my $errLog = $instanceDir . $PATHSEP . 'logs' . $PATHSEP . 'errors';
+ # emulate tail -f
+ # if the last line we see does not contain "slapd started", try again
+ my $done = 0;
+ my $started = 0;
+ my $code = 0;
+ my $lastLine = "";
+ my $timeout = time + 240; # 4 minutes
+ $ENV{"$LIB_PATH"}=$new_libpath;
+
+ my $startCmd = $instanceDir . $PATHSEP . 'start' . $script_suffix;
+ if (! -f $startCmd) {
+ $startCmd = $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix;
+ }
+ printTrace("\nInstanceDir: $instanceDir\n",4);
+ $code = &mySystem($instanceDir,$startCmd);
+ open(IN, $errLog) or die "Could not open error log $errLog: $!";
+ my $pos = tell(IN);
+ while (($done == 0) && (time < $timeout)) {
+ for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) {
+ $lastLine = $_;
+ # print;
+ # the server has already been started and shutdown once . . .
+ if (/slapd started\./) {
+ $started++;
+ if ($started == 2) {
+ $done = 1;
+ }
+ # sometimes the server will fail to come up; in that case, restart it
+ } elsif (/Initialization Failed/) {
+ # print "Server failed to start: $_";
+ $code = &mySystem($instanceDir, $startCmd);
+ # sometimes the server will fail to come up; in that case, restart it
+ } elsif (/exiting\./) {
+ # print "Server failed to start: $_";
+ #$code = &mySystem($startCmd);
+
+ $code = &mySystem($instanceDir, $startCmd);
+ }
+ }
+ if ($lastLine =~ /PR_Bind/) {
+ # server port conflicts with another one, just report and punt
+ print $lastLine;
+ print "This server cannot be started until the other server on this\n";
+ print "port is shutdown.\n";
+ $done = 1;
+ }
+ if ($done == 0) {
+ # rest a bit, then . . .
+ sleep(2);
+ # . . . reset the EOF status of the file desc
+ seek(IN, $pos, 0);
+ }
+ }
+ close(IN);
+
+ if ($started < 2) {
+ $! = $code;
+ # $now = time;
+ # if ($now > $timeout) {
+ # print "Possible timeout: timeout=$timeout now=$now\n";
+ # }
+ die "Error: could not start server: $!";
+ }
+
+ return 0;
+}
+
+sub stopServer {
+ my $root = shift;
+ my $name = shift;
+ $maxStopIterations = 5;
+ print "\nShutting down server $name . . .\n";
+
+ $ENV{"$LIB_PATH"}=$new_libpath;
+ $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop' . $script_suffix . $quote;
+ if (! -f $stopCmd) {
+ $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop-slapd' . $script_suffix . $quote;
+ }
+
+ if (! -f $stopCmd) {
+ # no stop command, probably a 1.X system; for NT, we'll try net stop
+ # for unix, we'll get the pid and kill it
+ if ($isNT) {
+ $stopCmd = 'net stop ' . $name;
+ } else {
+ # see if there is a pid file
+ $pidfile = $root . $PATHSEP . $name . $PATHSEP . 'logs' .
+ $PATHSEP . 'pid';
+ if (open(PIDFILE, $pidfile)) {
+ chomp($pid = <PIDFILE>);
+ close(PIDFILE);
+ while ($maxStopIterations-- && !$exitCode) {
+ $exitCode = kill(15, $pid);
+ }
+ $stopCmd = undef;
+ }
+ }
+ }
+
+ # keep looping until the stop cmd returns an error code, which usually
+ # means that what ever we want to stop is stopped, or some other error
+ # occurred e.g. permission, or no such service
+ $exitCode = &runAndIgnoreOutput($stopCmd);
+# print "stopServer: exitCode=$exitCode\n";
+ while ($stopCmd && $maxStopIterations-- && $exitCode) {
+ $exitCode = &runAndIgnoreOutput($stopCmd);
+# print "stopServer: exitCode=$exitCode\n";
+ }
+
+ if (!$maxStopIterations) {
+ print "Warning: could not shutdown the server: $!\n";
+ }
+
+ sleep(10) ;
+
+ $exitCode = 0;
+
+}
+
+
+sub runAndIgnoreOutput {
+ my $cmd = shift;
+ printMsg(".");
+ open(RUNCMD, "${quote}$cmd${quote} 2>&1 |") or die "Error: could not run $cmd: $!";
+ printMsg(".");
+ sleep(1); # allow pipe to fill with data
+ printMsg(".");
+ while (<RUNCMD>) {
+# print;
+ }
+ my $code = close(RUNCMD);
+# print "runAndIgnore: code=$code status=$?\n";
+ return $?;
+}
+#############################################################################
+# migrate some of entries present in the old DSE.ldif like
+# cn=snmp,cn=config
+# cn=encryption,cn=config
+# all the aci's
+
+sub MigrateDSE {
+ printTrace("\nMigrate DSE entries...",1);
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($old_entry = readOneEntry $in) {
+ my $DN = $old_entry->getDN() ;
+ SWITCH: {
+ # migrate the entrie: cn=snmp,cn=config
+ if ($DN =~ /^cn=SNMP,cn=config$/i) {
+ my $entry = $conn->search("$DN","base","objectclass=nsSNMP");
+ if ($entry) {
+ my $res = $conn->update($old_entry);
+ if ($res) {
+ printTrace("\n$DN updated !",2);
+ }
+ else {
+ printMsg("\nFailed to update $DN");
+ }
+ }
+ else {
+ printMsg("\nUnable to get info under $DN");
+ }
+ last SWITCH;
+ }
+ # migrate the entrie: cn=encryption,cn=config
+ if ($DN =~ /cn=encryption,cn=config$/i) {
+ if ($conn->search("$DN","base","objectclass=*")) {
+ if ($old_entry->hasValue("objectClass", "nsEncryptionConfig")) {
+ my $certfile = "alias/slapd-" . $newname . "-cert8.db";
+ my $keyfile = "alias/slapd-" . $newname. "-key3.db";
+ $old_entry->setValues("nsCertfile",$certfile) if ! $old_entry->hasValue("nsCertfile",$certfile);
+ $old_entry->setValues("nsKeyfile",$keyfile) if ! $old_entry->hasValue("nsKeyfile",$keyfile);
+ }
+ my $res = $conn->update($old_entry);
+ if ($res) {
+ printTrace("\n$DN updated !",2);
+ }
+ else {
+ printMsg("\nFailed to update $DN");
+ }
+ }
+ else {
+ my $res = $conn->add($old_entry);
+ if ($res) {
+ printTrace("\n$DN added !",2);
+ }
+ else {
+ printMsg("\nFailed to add $DN");
+ }
+ }
+ last SWITCH;
+ }
+ if (@{$old_entry->{aci}} && (! ($DN =~ /^cn=monitor$/i)) && (! ($DN =~ /^cn=schema$/i))) {
+ # migrate aci's
+ my $entry = $conn->search("$DN","base","objectclass=*");
+ if ($entry) {
+ my $res = $conn->update($old_entry);
+ if ($res) {
+ printTrace("\n$DN updated !",2);
+ }
+ else {
+ printMsg("\nFailed to update $DN");
+ }
+ }
+ else {
+ my $res = $conn->add($old_entry);
+ if ($res) {
+ printTrace("\n$DN added !",2);
+ }
+ else {
+ printMsg("\nFailed to add $DN");
+ }
+ }
+ last SWITCH;
+ }
+ }
+ }
+ close(DSELDIF);
+}
+#############################################################################
+# migrate SSL info
+
+sub MigrateSSL {
+ my $secPwd = 'bidon' ;
+ # copy the SSL directory
+ &copyDir("$oldHome${PATHSEP}ssl","$serverHome${PATHSEP}ssl");
+ # copy the cert db and key files
+ if ( -d "$oldDir${PATHSEP}alias") {
+ $aliasDir = "$root${PATHSEP}alias";
+ if (! -d $aliasDir) {
+ mkdir($aliasDir, 0750);
+ }
+ &stopServer($root,'slapd-'.$newname);
+ my $keydb = "$aliasDir${PATHSEP}slapd-$newname-key3.db" ;
+ my $certdb = "$aliasDir${PATHSEP}slapd-$newname-cert8.db" ;
+ my $certdb7 = "$aliasDir${PATHSEP}slapd-$newname-cert7.db" ;
+ my $old_keydb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-key3.db" ;
+ my $old_certdb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-cert7.db";
+ my $keydb_backup = "$aliasDir${PATHSEP}slapd-$newname-key3.db_backup" ;
+ my $certdb_backup = "$aliasDir${PATHSEP}slapd-$newname-cert7.db_backup" ;
+ if (-f $old_keydb) {
+ if (-f $keydb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$keydb already exists. backup in $keydb_backup ...");
+ &copyBinFile($keydb,$keydb_backup);
+ &copyBinFile($old_keydb,$keydb);
+ }
+ else {
+ print("\n\n$keydb already exists. Do you want to overwrite it ? [no]: ");
+ my $answer = <STDIN> ;
+ if ($answer =~ /^y|yes$/i) {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ if (-f $old_certdb) {
+ $mode = (stat($old_certdb))[2] if $PRESERVE;
+ if (-f $certdb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$certdb already exists. backup in $certdb_backup ...");
+ &copyBinFile($certdb,$certdb_backup);
+ unlink($certdb) || print "Couldn't delete $certdb : $!\n";
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ else {
+ print("\n\n$certdb already exists. Do you want to overwrite it ? [no]: ");
+ my $answer = <STDIN> ;
+ if ($answer =~ /^y|yes$/i) {
+ unlink($certdb) || print "Couldn't delete $certdb : $!\n";
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ # copy the old password file
+ if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") {
+ &copyBinFile(
+ "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt",
+ "$aliasDir${PATHSEP}$type-$newname-pin.txt"
+ );
+ }
+ &startServer();
+ if ($PRESERVE) {
+ chown($newuid,$newgid,$certdb) || print "Failed to set uid $newuid gid $newgid on $certdb : $!\n";
+ chmod($mode,$certdb) || print "Failed to set mode $mode on $certdb : $!\n";
+ }
+ }
+
+}
+
+sub DisableSSL {
+ my $entry = $conn->search("cn=config","base","objectclass=*");
+ my $LDAPparam = "nsslapd-security" ;
+ my $Value = "off" ;
+ if ($entry->{$LDAPparam}[0] ne $Value) {
+ printTrace("\nDisable SSL...",1);
+ $entry->setValues($LDAPparam, $Value);
+ }
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nSSL disabled",2);
+ }
+ else {
+ printMsg("\nCan't disable SSL, the server may have problems starting");
+ }
+}
+
+# enable the migration of client authentication informations
+sub MigrateCertmap {
+ # backup the old new certmap.conf and replace it with the old certmap.conf file
+ my $oldCertmap = "$oldDir${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf";
+ my $newCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf" ;
+ my $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ;
+ if (&hasChangedoldCertmap($oldCertmap)) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$newCertmap has been backup in $backupCertmap");
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($oldCertmap,$newCertmap);
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\n\nWhere do you want to back up the file $newCertmap [$backupCertmap] ?") ;
+ my $Answer = <STDIN> ;
+ $backupCertmap = $Answer if ($Answer ne "\n");
+ chomp($backupCertmap);
+ printTrace("\nDest: .$backupCertmap.",4);
+ if (-e $backupCertmap) {
+ printMsg("\n\n$backupCertmap already exists. Do you want to overwrite it Yes/No [No] ?") ;
+ if (<STDIN> =~ /yes|y/i) {
+ $Ask = 0 ;
+ }
+ else {
+ $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ;
+ }
+ }
+ else {
+ $Ask = 0 ;
+ }
+ }
+ printTrace("\nBackup file: $newCertmap in $backupCertmap",4);
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($oldCertmap,$newCertmap);
+ }
+ }
+ else {
+ }
+}
+
+sub hasChangedoldCertmap {
+ my $certmapfile = shift ;
+ my @reference = ("certmap default default",
+ "default:DNComps",
+ "default:FilterComps e") ;
+ my $cpt = 0 ;
+ printTrace("\nhasChangedoldCertmap",3);
+ open(CERTMAP,"< $certmapfile");
+ while (<CERTMAP>) {
+ if ((! /^\s*#/) && (! /^\s*$/)) {
+ my $ref = $reference[$cpt] ;
+ printTrace("\nValue: $_, ref: $ref",4);
+ if (! /^\s*$ref\s*$/) {
+ return 1 ;
+ }
+ else {
+ $cpt++ ;
+ }
+ }
+ }
+ close (CERTMAP);
+ printTrace("\ncpt: $cpt",4);
+ if ($cpt < $#reference) {
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+}
+#############################################################################
+# copy a directory to another
+
+sub copyDir {
+ my $src = shift;
+ my $dest = shift;
+ my $exclude = shift;
+
+ opendir( SRC, $src ) or die "Can't open directory $src: $!: ";
+ my $mode;
+ my $uid;
+ my $gid;
+ mkdir ( $dest , 0755 ) or die "\nCan't create directory $dest. \nPlease check you have enough rights to create it and/or check that your parent directory exists.\n" if !( -e $dest );
+ if ($PRESERVE) {
+ $mode = (stat($src))[2];
+ ($uid, $gid) = (stat(_))[4..5];
+ # Make sure files owned by the old user are owned by the
+ # new user
+ if ($uid == $olduid) {
+ $uid = $newuid;
+ $gid = $newgid;
+ }
+ chown $uid, $gid, $dest;
+ chmod $mode, $dest;
+ }
+ local ( @files ) = readdir ( SRC );
+ closedir( SRC );
+ for ( @files ) {
+ if ( $_ eq "." || $_ eq ".." ) {
+ next;
+ } elsif ( $exclude && /$exclude/ ) {
+ next;
+ } elsif( -d "$src${PATHSEP}$_") {
+ &copyDir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" );
+ } else {
+ &copyBinFile ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_");
+ }
+ }
+}
+
+sub copyBinFile {
+ my $src = shift;
+ my $dest = shift;
+ my $buf = "";
+ my $bufsize = 8192;
+
+ open( SRC, $src ) || die "Can't open $src: $!\n";
+ # if we are given a directory destination instead of a file, extract the
+ # filename portion of the source to use as the destination filename
+ if (-d $dest) {
+ $dest = $dest . $PATHSEP . &basename($src);
+ }
+ open( DEST, ">$dest" ) || die "Can't create $dest: $!\n";
+ binmode SRC;
+ binmode DEST;
+ if ($PRESERVE) {
+ $mode = (stat($src))[2];
+ ($uid, $gid) = (stat(_))[4..5];
+ # Make sure files owned by the old user are owned by the
+ # new user
+ if ($uid == $olduid) {
+ $uid = $newuid;
+ $gid = $newgid;
+ }
+ chown $uid, $gid, $dest;
+ chmod $mode, $dest;
+ }
+ while (read(SRC, $buf, $bufsize)) {
+ print DEST $buf;
+ }
+ close( SRC );
+ close( DEST );
+}
+#############################################################################
+# backup new configuration files
+# backup the directory <new_root_server>/slapd-instance/config in <new_root_server>/slapd-instance/BackupConfig
+
+sub backupConfigFiles {
+ # backup the new config files
+ my $src = "$serverHome${PATHSEP}config" ;
+ my $dest = "$serverHome${PATHSEP}config_backup" ;
+ if ($NO_INPUT_USER) {
+ printMsg("\n$src has been backup in $dest");
+ &copyDir($src,$dest);
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\n\nWhere do you want to back up your configuration directory [$dest] ?") ;
+ my $Answer = <STDIN> ;
+ $dest = $Answer if ($Answer ne "\n");
+ chomp($dest);
+ printTrace("\nDest: .$dest.",4);
+ if (-e $dest) {
+ printMsg("\n\n$dest already exists. Do you want to overwrite it Yes/No [No] ?") ;
+ if (<STDIN> =~ /yes|y/i) {
+ $Ask = 0 ;
+ }
+ else {
+ $dest = "$serverHome${PATHSEP}config_backup" ;
+ }
+ }
+ else {
+ $Ask = 0 ;
+ }
+ }
+ printTrace("\nBackup Directory: $src in $dest",4);
+ &copyDir($src,$dest);
+ }
+}
+#############################################################################
+
+sub getLDAPservername {
+ my $oldLDAPservername;
+ my $LDAPservername;
+ open(OLDSLAPDCONF, $oldSlapdConf) or
+ die "\nError: could not open old config file $oldSlapdConf \n";
+ while(<OLDSLAPDCONF>) {
+ chop;
+ if (/^localhost\s+/i) {
+ ($oldLDAPservername = $') =~ s/^[\"]//;;
+ $oldLDAPservername =~ s/[\"]$//;
+ printTrace("\nName of the old LDAP server: $oldLDAPservername",3);
+ }
+ }
+ close(OLDSLAPDCONF);
+
+ open( DSELDIF, "< $DSEldif" ) || die "\nCan't open $DSEldif \n";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ my $DN = $entry->getDN() ;
+ if ($DN =~ /^cn=config$/i) {
+ my $localhost = "nsslapd-localhost";
+ my @values = $entry->getValues($localhost);
+ if ($#values != -1) {
+ $LDAPservername = $values[0];
+ }
+ break;
+ }
+ }
+ close(DSELDIF);
+ # check old and new are installed on the same physical machine.
+ if (lc($oldLDAPservername) ne lc($LDAPservername)) {
+ # warn the user he tries to migrate a old server installed on a different machine from the new one
+ printMsg("\n\nYour old server is on $oldLDAPservername, and your new server is on $LDAPservername. We don't support migration on different machines. Do you want to continue ? Yes/No [No]:") ;
+ if (! (<STDIN> =~ /yes|y/i)) {
+ return -1;
+ }
+ }
+ return $LDAPservername ;
+}
+
+#############################################################################
+
+sub getLibPath {
+ my $myDir = shift;
+ my $myVersion = shift;
+ my $myMinor = shift;
+
+ if ($isNT) {
+ return $ENV{"$LIB_PATH"};
+ }
+ if (($myVersion >= 6) && ($myMinor >= 2)) {
+ return
+ "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}".
+ "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}".
+ $ENV{"$LIB_PATH"};
+ } else {
+ return "$myDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ }
+}
+
+#############################################################################
+
+sub getVersion {
+ my $dir = shift;
+ my $versionstr = shift;
+ my $version = 0;
+ my $minor = 0;
+ my $buildNumber = 0;
+ my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+ my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}";
+
+ # find the slapd executable
+ if (!$versionstr) { # version not specified on cmd line - find it
+ $prog = $dir . $progDir . $slapdExecName;
+ if (! -f $prog) {
+ $prog = $dir . $progDir2 . $slapdExecName;
+ if (-f $prog && $isNT) {
+ # if slapd is in bin/slapd and we're on NT, just assume version 1;
+ # apparently, slapd.exe doesn't like the -v argument . . .
+ return ( '1', $minor );
+ }
+ else{
+ die "Could not run slapd program $prog: $!";
+ }
+ }
+ else {
+ chdir($dir . $progDir);
+ }
+ $cur_libpath=$ENV{"$LIB_PATH"};
+ $ENV{"$LIB_PATH"}=
+ "$dir${PATHSEP}lib${SEP}".
+ "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}".
+ "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}".
+ $ENV{"$LIB_PATH"};
+ # read the old version from the old slapd program
+
+ open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or
+ die "Could not run slapd program $prog: $!";
+ sleep(1); # allow some data to accumulate in the pipe
+# print "Output from $prog -v:\n";
+ while (<F>) {
+ if (/^Netscape-Directory/ || /^iPlanet-Directory/i) {
+ $versionstr = $_;
+ last;
+ }
+ }
+ $code = close(F);
+ # print "$prog returned code=$code status=$?\n";
+ $ENV{"$LIB_PATH"}=$cur_libpath;
+ }
+
+ if ($versionstr =~ /^Netscape-Directory\/(\d+)\.(\d+)(?:b\d)*\s+(\S+)/) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ }
+ elsif ($versionstr =~ /^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ...
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ }
+ elsif ($versionstr =~ /^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ } elsif ($versionstr =~ /(\d+)\.(\d+)/) {
+ $version = $1;
+ $minor = $2;
+ }
+
+ if ($version == 0) {
+ die "\nCould not determine version of the directory server in $dir: \n";
+ }
+
+ # distinguish the 4.1 and the 4.11 thanks to the buildNumber
+ if (($version == 4) && ($minor == 1)){
+ if (! ($buildNumber =~ /^B99\.16/)) {
+ # it's not a 4.1 Netscape Directory Server => it's a 4.11
+ $minor = 11 ;
+ }
+ }
+ chdir($curdir) or die "Could not change directory to $curdir: $!" ;
+ return ( $version, $minor );
+}
+
+#############################################################################
+
+sub getDiff {
+ # we get references to arrays
+ my $elements = shift ;
+ my $existing_elements = shift ;
+ my %count = () ;
+ my %countEE = () ;
+ @diff = () ;
+ foreach $e (@{$elements}, @{$existing_elements}) { $count{$e}++ ;}
+ foreach $e (@{existing_elements}) { $countEE{$e}++ ;}
+ foreach $e (@{$elements}) {
+ # if $e is only present in @$elements, we push it to the diff array
+ if (($count{$e} == 1) && ($countEE{$e} == 0)) {
+ push @diff, $e ;
+ }
+ }
+ return @diff ;
+}
+
+###############################################################################################
+sub testIndexUpdating {
+ #my $entry = $conn->newEntry();
+ #$entry->setDN("cn=djeattribute,cn=index,cn=MigratedDB_5,cn=ldbm database,cn=plugins,cn=config");
+ my $entry = $conn->search("cn=mail,cn=index,cn=MigratedDB_2,cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex");
+ my @types = ("pres", "sub", "eq") ;
+ my @existing_types = $entry->getValues("nsindextype");
+ my @typesToAdd = &getDiff(\@types, \@existing_types);
+ foreach $newtype (@typesToAdd) {
+ $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2);
+ }
+ my $res = $conn->update($entry) ;
+ if ($res) {print("\nUpdate index mail\n");}
+ else { print("\ncan't update index mail");}
+
+ $entry = $conn->search("cn=givenName,cn=index,cn=MigratedDB_2,cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex");
+ @types = ("pres", "sub", "eq") ;
+ @existing_types = $entry->getValues("nsindextype"); print("\ngivenName, existing_types: @existing_types");
+ @typesToAdd = &getDiff(\@types, \@existing_types); print("\nTypesToAdd: @typesToAdd");
+ foreach $newtype (@typesToAdd) {
+ $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2);
+ }
+ my $res = $conn->update($entry) ;
+ if ($res) {print("\nUpdate index givenName\n");}
+ else { print("\ncan't update index givenName");}
+ }
+
+
+###############################################################################################
+sub normalizeDir {
+ my $dir = shift ;
+ my $dir_prec = "" ;
+ while ($dir_prec ne $dir) {
+ $dir_prec = $dir ;
+ if ($isNT) {
+ grep { s@\\\\@\\@g } $dir ;
+ }
+ else {
+ grep { s@//@/@g } $dir ;
+ }
+ }
+ return $dir ;
+}
+
+
+###############################################################################################
+# return 1 if the value parameters is
+sub isAllowedPlugin {
+ my $Value = lc(shift) ;
+ if ($allowedPlugins{$Value}) {
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+
+}
+
+
+sub getSyntaxOid {
+ my $Value = lc(shift) ;
+ return $allowedPlugins{$Value} ;
+}
+
+###############################################################################################
+# return 1 if the value given in parameters is an allowed modifier
+sub isAllowedModifier {
+ my $Value = lc(shift) ;
+ if ($allowedModifiers{$Value}) {
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+sub getModifierValue {
+ my $Value = lc(shift) ;
+ return $allowedModifiers{$Value} ;
+}
+
+###############################################################################################
+
+sub GetTime {
+ my $tm = localtime;
+ (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900);
+ $sec = "0$sec" unless $sec > 9 ;
+ $min = "0$min" unless $min > 9 ;
+ $hour = "0$hour" unless $hour > 9 ;
+ $dd = "0$dd" unless $dd > 9 ;
+ $mm = "0$mm" unless $mm > 9 ;
+ return ($sec, $min, $hour, $dd, $mm, $yy);
+}
+
+###############################################################################################
+# get uid and group id of the new slapd server.
+# The uid is done through the nsslapd-localuser attribute
+
+sub getuid_gid {
+ my $newuid ;
+ my $newgid ;
+ my $localuser ;
+ my $localuser_attr = "nsslapd-localuser" ;
+ if (! $isNT) {
+ my $entry = $conn->search("cn=config ", "base","objectclass=*", 0, ($localuser_attr)) ;
+ # Tests wether we succeed to get the entry cn=config
+ die "\nCan't get the entry cn=config \n" unless ($entry);
+ my @values = $entry->getValues($localuser_attr);
+ if ($#values == -1 || ($values[0] eq "") ) { # tests wether the nsslapd-localuser attribute has a value
+ printMsg("\nNo localuser has been found in the configuration of the directory. ");
+ if ($NO_INPUT_USER) {
+ printMsg("\nWe considered nobody as the localuser");
+ $localuser = "nobody" ;
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\nUnder what user does your $Version.$Minor directory server run [nobody] ? ") ;
+ $localuser = <STDIN> ;
+ chomp($localuser);
+ $localuser = "nobody" if ($localuser eq "");
+ ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ;
+ if ($newuid) {
+ $Ask = 0 ;
+ }
+ else {
+ printMsg("\nError: $localuser is unknown from the system ");
+ }
+ }
+ }
+ }
+ else {
+ $localuser = $values[0]; # returns the first value (we should only have one localuser)
+ my $size = $#values ;
+ }
+ ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ;
+ return ($localuser, $newuid, $newgid) ;
+ }
+ else {
+ return () ;
+ }
+}
+
+
+###############################################################################################
+# get uid and group id of the old slapd server.
+
+sub getolduid_gid {
+ my $oldlocaluser ;
+ if (! $isNT) {
+ open(CONF, $oldSlapdConf) or die "\nError: cannot open $oldSlapdConf: $!\n";
+ while (<CONF>) {
+ if (/^localuser\s+/i) {
+ chomp($oldlocaluser = $');
+ last;
+ }
+ }
+ close(CONF);
+ ($olduid, $oldgid) = (getpwnam("$oldlocaluser"))[2..3] ;
+ return ($oldlocaluser, $olduid, $oldgid) ;
+ }
+ else {
+ return ();
+ }
+}
+
+###############################################################################################
+# get current directory
+
+sub getCwd {
+ my $command = $isNT ? "cd" : "/bin/pwd";
+ open(PWDCMD, "$command 2>&1 |") or
+ die "Error: could not execute $command: $!";
+ # without the following sleep, reading from the pipe will
+ # return nothing; I guess it gives the pwd command time
+ # to get some data to read . . .
+ sleep(1);
+ my $currentdir;
+ while (<PWDCMD>) {
+ if (!$currentdir) {
+ chomp($currentdir = $_);
+ }
+ }
+ my $code = close(PWDCMD);
+# if ($code || $?) {
+# print "$command returned code=$code status=$? dir=$curdir\n";
+# }
+# print "getCwd curdir=\[$curdir\]\n";
+ return $currentdir;
+}
diff --git a/ldap/admin/src/scripts/template-migrateTo7 b/ldap/admin/src/scripts/template-migrateTo7
new file mode 100644
index 00000000..73f71ab9
--- /dev/null
+++ b/ldap/admin/src/scripts/template-migrateTo7
@@ -0,0 +1,3268 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# Migrate a old directory server to a 7.0 directory server
+
+########################################################################################################
+# enable the use of Perldap functions
+require DynaLoader;
+
+use Getopt::Std;
+use Mozilla::LDAP::Conn;
+use Mozilla::LDAP::Entry;
+use Mozilla::LDAP::LDIF;
+use Mozilla::LDAP::Utils qw(:all);
+use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API
+use Time::localtime;
+
+########################################################################################################
+use Class::Struct ; # load struct-building module
+
+struct S_index => {
+ names => '@' ,
+ types => '@' ,
+ oids => '@' ,
+ specific => '$'
+ };
+
+
+struct S_plugin => {
+ name => '$' ,
+ type => '$' ,
+ enable => '$' ,
+ args => '@'
+ };
+#####################################################################################################
+
+sub usage {
+ print(STDERR "\nUsage: $0 -D rootdn { -w password | -w - | -j filename } -p port \n");
+ print(STDERR " -o OldInstancePath -n NewInstancePath [-t tracelevel] [-L logfile]\n");
+ print(STDERR "************** parameters in brackets are optionals, others are required **************\n");
+ print(STDERR " Opts: -D rootdn - New Directory Manager\n");
+ print(STDERR " : -w password - New Directory Manager's password\n");
+ print(STDERR " : -w - - Prompt for New Directory Manager's password\n");
+ print(STDERR " : -j filename - Read New Directory Manager's password from file\n");
+ print(STDERR " : -p port - New Directory Server port\n");
+ print(STDERR " : -o OldInstancePath - Path of the Old instance to migrate \n");
+ print(STDERR " : -n NewInstancePath - Path of the new instance\n");
+ print(STDERR " : [-d dataPath] - Path to directory containing data files to import into new instance\n");
+ print(STDERR " : [-v oldVersion] - Old version (obtained by running $slapdExecName -v\n");
+ print(STDERR " : [-t tracelevel] - specify the level of trace (0..3)\n");
+ print(STDERR " : [-L logfile] - specify the file to log the migration report \n");
+
+
+ }
+
+
+
+#############
+BEGIN {
+
+ require 'uname.lib' ;
+ $isNT = -d '\\';
+ $PATHSEP = $isNT ? "\\" : "/";
+ ${SEP} = $isNT ? ";" : ":" ;
+ @INC = ( '.', '../../../admin/admin/bin');
+ grep { s@/@\\@g } @INC if $isNT;
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ # NT needs quotes around some things unix doesn't
+ $quote = $isNT ? "\"" : "";
+
+ # If this variable is set, all file/directory creation will make sure the mode
+ # and ownership of the destination is the same as the source
+ $PRESERVE = 1 if (!$isNT);
+ $script_suffix = $isNT ? ".bat" : "";
+ $exe_suffix = $isNT ? ".exe" : "";
+ if ($isNT) {
+ $os = "WINNT";
+ } else {
+ $os = &uname("-s");
+ }
+ if ($isNT) {
+ # we have to pass batch files directly to the NT command interpreter
+ $com_spec = $ENV{ComSpec};
+ if (!$com_spec) {
+ $com_spec = $ENV{COMSPEC};
+ }
+ if (!$com_spec || ! -f $com_spec) {
+ # find the first available command interpreter
+ foreach $drive (c..z) {
+ $com_spec = "$drive:\\winnt\\system32\\cmd.exe";
+ last if (-f $com_spec);
+ $com_spec = undef;
+ }
+ if (! $com_spec) {
+ # punt and pray
+ $com_spec = 'c:\winnt\system32\cmd.exe';
+ }
+ }
+ }
+ if ( $os eq "AIX" ) {
+ $dll_suffix = "_shr.a";
+ }
+ elsif ( $os eq "HP-UX" ) {
+ $dll_suffix = ".sl";
+ }
+ elsif ( $os eq "WINNT" ) {
+ $dll_suffix = ".dll";
+ }
+ else {
+ $dll_suffix = ".so";
+ }
+ $slapdExecName = $isNT ? 'slapd.exe' : './ns-slapd';
+ # if this flag is set, we will migrate the old database
+ # by doing a db2ldif -> ldif2db;
+ $convertToLDIF = 1;
+ select STDERR;
+ $| = 1;
+ select STDOUT;
+ $| = 1;
+ # if the old value for dbcachesize is less than this, make it this
+ $MIN_DBCACHESIZE = '500000';
+}
+
+SWITCH: {
+ if ($os eq "AIX") {
+ $LIB_PATH = "LIBPATH" ;
+ last SWITCH ;
+ }
+ if ($os eq "HP-UX") {
+ $LIB_PATH = "SHLIB_PATH" ;
+ last SWITCH ;
+ }
+ if ($isNT) {
+ $LIB_PATH = "PATH" ;
+ last SWITCH ;
+ }
+ else {
+ $LIB_PATH = "LD_LIBRARY_PATH" ;
+ last SWITCH ;
+ }
+ }
+
+ # Old parameters
+ ${oldDir} = "" ;
+ ${oldname} = "" ;
+ ${oldHome} = "" ;
+ ${oldConfDir} = "" ;
+ ${oldlocaluser} ;
+ ${olduid} ;
+ ${oldgid} ;
+
+ # New parameters
+ ${root} = "{{DS-ROOT}}" ;
+ ${type} = "" ;
+ ${newname} = "" ;
+ ${newport} = "" ;
+ ${rootDN} = "" ;
+ ${rootpwd} = "" ;
+ ${localhost} = "" ;
+ ${LogFileReport} = "" ;
+ ${newuid} ;
+ ${localuser} ;
+ ${newgid} ;
+ $NO_INPUT_USER = 0 ; # by default user can give inputs during the migration process
+ ${curdir} = getCwd();
+ ${slapdExecDir} = "${root}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+
+ # specify the level of trace
+ $TRACELEVEL=1;
+
+ $LDAP_SERVER_UNREACHABLE = 81;
+
+ # get input users
+ &getParameters() ;
+ ${oldDir} = &normalizeDir("${oldDir}");
+ ${oldHome} = "${oldDir}${PATHSEP}$type-$oldname" ;
+ ${oldConfDir} = "${oldHome}${PATHSEP}config${PATHSEP}" ;
+ ${oldSlapdConf} = "${oldConfDir}slapd.conf" ;
+ ${oldDSEldif} = "${oldConfDir}dse.ldif" ;
+ ${serverHome} = "${root}${PATHSEP}$type-$newname" ;
+ ${DSEldif} = "$serverHome${PATHSEP}config${PATHSEP}dse.ldif";
+ ${ldif_rep} = "${oldConfDir}${PATHSEP}ldif${PATHSEP}" ;
+ ${oldSlapdExecDir} = "${oldDir}${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+
+
+
+
+ open(LOGFILE, ">> $LogFileReport");
+
+ printTrace("\noldDir: $oldDir, oldHome: $oldHome, \noldConfDir: $oldConfDir, \noldSlapdConf: $oldSlapdConf, \nldif_rep: $ldif_rep, \nrootDN: $rootDN, \nPwd: ******, \nPort: $newport, \nNewname: $newname\n",3);
+ printTrace("\nLIB_PATH: $LIB_PATH",4);
+
+ if (!(-d $serverHome)) {
+ printMsg("\n$serverHome doesn't exist\n");
+ exit(1);
+ }
+ if (!(-d $oldHome)) {
+ printMsg("\n$oldHome doesn't exist\n");
+ exit(1);
+ }
+
+ if ($olddatadir && !(-d $olddatadir)) {
+ print("\n$olddatadir doesn't exist\n");
+ exit(1);
+ }
+
+#define CONFIG_DATABASE_DIRECTIVE "database"
+#define CONFIG_DATABASE_ATTRIBUTE "nsslapd-database"
+#define CONFIG_PLUGIN_DIRECTIVE "plugin"
+#define CONFIG_PLUGIN_ATTRIBUTE "nsslapd-plugin"
+#define CONFIG_SIZELIMIT_DIRECTIVE "sizelimit"
+#define CONFIG_SIZELIMIT_ATTRIBUTE "nsslapd-sizelimit"
+#define CONFIG_ORCAUTO_DIRECTIVE "orcauto"
+#define CONFIG_ORCAUTO_ATTRIBUTE "nsslapd-orcauto"
+#define CONFIG_TIMELIMIT_DIRECTIVE "timelimit"
+#define CONFIG_TIMELIMIT_ATTRIBUTE "nsslapd-timelimit"
+#define CONFIG_SUFFIX_DIRECTIVE "suffix"
+#define CONFIG_SUFFIX_ATTRIBUTE "nsslapd-suffix"
+#define CONFIG_READONLY_DIRECTIVE "readonly"
+#define CONFIG_READONLY_ATTRIBUTE "nsslapd-readonly"
+#define CONFIG_REFERRAL_DIRECTIVE "referral"
+#define CONFIG_REFERRAL_ATTRIBUTE "nsslapd-referral"
+#define CONFIG_OBJECTCLASS_DIRECTIVE "objectclass"
+#define CONFIG_OBJECTCLASS_ATTRIBUTE "nsslapd-objectclass"
+#define CONFIG_ATTRIBUTE_DIRECTIVE "attribute"
+#define CONFIG_ATTRIBUTE_ATTRIBUTE "nsslapd-attribute"
+#define CONFIG_SCHEMACHECK_DIRECTIVE "schemacheck"
+#define CONFIG_SCHEMACHECK_ATTRIBUTE "nsslapd-schemacheck"
+#define CONFIG_LOGLEVEL_DIRECTIVE "loglevel"
+#define CONFIG_LOGLEVEL_ATTRIBUTE "nsslapd-errorlog-level"
+#define CONFIG_ACCESSLOGLEVEL_DIRECTIVE "accessloglevel"
+#define CONFIG_ACCESSLOGLEVEL_ATTRIBUTE "nsslapd-accesslog-level"
+#define CONFIG_ACCESSLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "accesslog-maxNumOfLogsPerDir"
+#define CONFIG_ACCESSLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-accesslog-maxlogsperdir"
+#define CONFIG_ERRORLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "errorlog-maxNumOfLogsPerDir"
+#define CONFIG_ERRORLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-errorlog-maxlogsperdir"
+#define CONFIG_AUDITLOG_MAXNUMOFLOGSPERDIR_DIRECTIVE "auditlog-maxNumOfLogsPerDir"
+#define CONFIG_AUDITLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-auditlog-maxlogsperdir"
+#define CONFIG_ACCESSLOG_MAXLOGSIZE_DIRECTIVE "accesslog-maxlogsize"
+#define CONFIG_ACCESSLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-accesslog-maxlogsize"
+#define CONFIG_ERRORLOG_MAXLOGSIZE_DIRECTIVE "errorlog-maxlogsize"
+#define CONFIG_ERRORLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-errorlog-maxlogsize"
+#define CONFIG_AUDITLOG_MAXLOGSIZE_DIRECTIVE "auditlog-maxlogsize"
+#define CONFIG_AUDITLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-auditlog-maxlogsize"
+#define CONFIG_ACCESSLOG_LOGROTATIONTIME_DIRECTIVE "accesslog-logrotationtime"
+#define CONFIG_ACCESSLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-accesslog-logrotationtime"
+#define CONFIG_ERRORLOG_LOGROTATIONTIME_DIRECTIVE "errorlog-logrotationtime"
+#define CONFIG_ERRORLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-errorlog-logrotationtime"
+#define CONFIG_AUDITLOG_LOGROTATIONTIME_DIRECTIVE "auditlog-logrotationtime"
+#define CONFIG_AUDITLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-auditlog-logrotationtime"
+#define CONFIG_ACCESSLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "accesslog-logrotationtimeunit"
+#define CONFIG_ACCESSLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-accesslog-logrotationtimeunit"
+#define CONFIG_ERRORLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "errorlog-logrotationtimeunit"
+#define CONFIG_ERRORLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-errorlog-logrotationtimeunit"
+#define CONFIG_AUDITLOG_LOGROTATIONTIMEUNIT_DIRECTIVE "auditlog-logrotationtimeunit"
+#define CONFIG_AUDITLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-auditlog-logrotationtimeunit"
+#define CONFIG_ACCESSLOG_MAXLOGDISKSPACE_DIRECTIVE "accesslog-maxlogdiskspace"
+#define CONFIG_ACCESSLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-accesslog-logmaxdiskspace"
+#define CONFIG_ERRORLOG_MAXLOGDISKSPACE_DIRECTIVE "errorlog-maxlogdiskspace"
+#define CONFIG_ERRORLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-errorlog-logmaxdiskspace"
+#define CONFIG_AUDITLOG_MAXLOGDISKSPACE_DIRECTIVE "auditlog-maxlogdiskspace"
+#define CONFIG_AUDITLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-auditlog-logmaxdiskspace"
+#define CONFIG_ACCESSLOG_MINFREEDISKSPACE_DIRECTIVE "accesslog-minfreediskspace"
+#define CONFIG_ACCESSLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-accesslog-logminfreediskspace"
+#define CONFIG_ERRORLOG_MINFREEDISKSPACE_DIRECTIVE "errorlog-minfreediskspace"
+#define CONFIG_ERRORLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-errorlog-logminfreediskspace"
+#define CONFIG_AUDITLOG_MINFREEDISKSPACE_DIRECTIVE "auditlog-minfreediskspace"
+#define CONFIG_AUDITLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-auditlog-logminfreediskspace"
+#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIME_DIRECTIVE "accesslog-logexpirationtime"
+#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-accesslog-logexpirationtime"
+#define CONFIG_ERRORLOG_LOGEXPIRATIONTIME_DIRECTIVE "errorlog-logexpirationtime"
+#define CONFIG_ERRORLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-errorlog-logexpirationtime"
+#define CONFIG_AUDITLOG_LOGEXPIRATIONTIME_DIRECTIVE "auditlog-logexpirationtime"
+#define CONFIG_AUDITLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-auditlog-logexpirationtime"
+#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "accesslog-logexpirationtimeunit"
+#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-accesslog-logexpirationtimeunit"
+#define CONFIG_ERRORLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "errorlog-logexpirationtimeunit"
+#define CONFIG_ERRORLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-errorlog-logexpirationtimeunit"
+#define CONFIG_AUDITLOG_LOGEXPIRATIONTIMEUNIT_DIRECTIVE "auditlog-logexpirationtimeunit"
+#define CONFIG_AUDITLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-auditlog-logexpirationtimeunit"
+#define CONFIG_ACCESSLOG_LOGGING_ENABLED_DIRECTIVE "accesslog-logging-enabled"
+#define CONFIG_ACCESSLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-accesslog-logging-enabled"
+#define CONFIG_ERRORLOG_LOGGING_ENABLED_DIRECTIVE "errorlog-logging-enabled"
+#define CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-errorlog-logging-enabled"
+#define CONFIG_AUDITLOG_LOGGING_ENABLED_DIRECTIVE "auditlog-logging-enabled"
+#define CONFIG_AUDITLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-auditlog-logging-enabled"
+#define CONFIG_ROOTDN_DIRECTIVE "rootdn"
+#define CONFIG_ROOTDN_ATTRIBUTE "nsslapd-rootdn"
+#define CONFIG_ROOTPW_DIRECTIVE "rootpw"
+#define CONFIG_ROOTPW_ATTRIBUTE "nsslapd-rootpw"
+#define CONFIG_ROOTPWSTORAGESCHEME_DIRECTIVE "rootpwstoragescheme"
+#define CONFIG_ROOTPWSTORAGESCHEME_ATTRIBUTE "nsslapd-rootpwstoragescheme"
+#define CONFIG_UPDATEDN_DIRECTIVE "updatedn"
+#define CONFIG_UPDATEDN_ATTRIBUTE "nsslapd-updatedn"
+#define CONFIG_UPDATEPW_DIRECTIVE "updatepw"
+#define CONFIG_UPDATEPW_ATTRIBUTE "nsslapd-updatepw"
+#define CONFIG_UPDATESSLCLIENT_DIRECTIVE "updateSSLclient"
+#define CONFIG_UPDATESSLCLIENT_ATTRIBUTE "nsslapd-updateSSLclient"
+#define CONFIG_AUDITFILE_DIRECTIVE "auditfile"
+#define CONFIG_AUDITFILE_ATTRIBUTE "nsslapd-auditlog"
+#define CONFIG_LASTMOD_DIRECTIVE "lastmod"
+#define CONFIG_LASTMOD_ATTRIBUTE "nsslapd-lastmod"
+#define CONFIG_INCLUDE_DIRECTIVE "include"
+#define CONFIG_INCLUDE_ATTRIBUTE "nsslapd-include"
+#define CONFIG_DYNAMICCONF_DIRECTIVE "dynamicconf"
+#define CONFIG_DYNAMICCONF_ATTRIBUTE "nsslapd-dynamicconf"
+#define CONFIG_USEROC_DIRECTIVE "useroc"
+#define CONFIG_USEROC_ATTRIBUTE "nsslapd-useroc"
+#define CONFIG_USERAT_DIRECTIVE "userat"
+#define CONFIG_USERAT_ATTRIBUTE "nsslapd-userat"
+#define CONFIG_SVRTAB_DIRECTIVE "svrtab"
+#define CONFIG_SVRTAB_ATTRIBUTE "nsslapd-svrtab"
+#ifndef _WIN32
+#define CONFIG_LOCALUSER_DIRECTIVE "localuser"
+#define CONFIG_LOCALUSER_ATTRIBUTE "nsslapd-localuser"
+#endif /* !_WIN32 */
+#define CONFIG_LOCALHOST_DIRECTIVE "localhost"
+#define CONFIG_LOCALHOST_ATTRIBUTE "nsslapd-localhost"
+#define CONFIG_PORT_DIRECTIVE "port"
+#define CONFIG_PORT_ATTRIBUTE "nsslapd-port"
+#define CONFIG_LISTENHOST_DIRECTIVE "listenhost"
+#define CONFIG_LISTENHOST_ATTRIBUTE "nsslapd-listenhost"
+#define CONFIG_SECURITY_DIRECTIVE "security"
+#define CONFIG_SECURITY_ATTRIBUTE "nsslapd-security"
+#define CONFIG_SSL3CIPHERS_DIRECTIVE "SSL3ciphers"
+#define CONFIG_SSL3CIPHERS_ATTRIBUTE "nsslapd-SSL3ciphers"
+#define CONFIG_ACCESSLOG_DIRECTIVE "accesslog"
+#define CONFIG_ACCESSLOG_ATTRIBUTE "nsslapd-accesslog"
+#define CONFIG_ERRORLOG_DIRECTIVE "errorlog"
+#define CONFIG_ERRORLOG_ATTRIBUTE "nsslapd-errorlog"
+#define CONFIG_INSTANCEDIR_DIRECTIVE "instancedir"
+#define CONFIG_INSTANCEDIR_ATTRIBUTE "nsslapd-instancedir"
+#define CONFIG_SECUREPORT_DIRECTIVE "secure-port"
+#define CONFIG_SECUREPORT_ATTRIBUTE "nsslapd-securePort"
+#define CONFIG_SECURELISTENHOST_DIRECTIVE "secure-listenhost"
+#define CONFIG_SECURELISTENHOST_ATTRIBUTE "nsslapd-securelistenhost"
+#define CONFIG_THREADNUMBER_DIRECTIVE "threadnumber"
+#define CONFIG_THREADNUMBER_ATTRIBUTE "nsslapd-threadnumber"
+#define CONFIG_MAXTHREADSPERCONN_DIRECTIVE "maxthreadsperconn"
+#define CONFIG_MAXTHREADSPERCONN_ATTRIBUTE "nsslapd-maxthreadsperconn"
+#if !defined(_WIN32) && !defined(AIX)
+#define CONFIG_MAXDESCRIPTORS_DIRECTIVE "maxdescriptors"
+#define CONFIG_MAXDESCRIPTORS_ATTRIBUTE "nsslapd-maxdescriptors"
+#endif /* !_WIN32 && ! AIX */
+#define CONFIG_RESERVEDESCRIPTORS_DIRECTIVE "reservedescriptors"
+#define CONFIG_RESERVEDESCRIPTORS_ATTRIBUTE "nsslapd-reservedescriptors"
+#define CONFIG_IDLETIMEOUT_DIRECTIVE "idletimeout"
+#define CONFIG_IDLETIMEOUT_ATTRIBUTE "nsslapd-idletimeout"
+#define CONFIG_IOBLOCKTIMEOUT_DIRECTIVE "ioblocktimeout"
+#define CONFIG_IOBLOCKTIMEOUT_ATTRIBUTE "nsslapd-ioblocktimeout"
+#define CONFIG_NTSYNCH_DIRECTIVE "ntsynch"
+#define CONFIG_NTSYNCH_ATTRIBUTE "nsslapd-NTSynch"
+#define CONFIG_NTSYNCHUSESSL_DIRECTIVE "ntsynchusessl"
+#define CONFIG_NTSYNCHUSESSL_ATTRIBUTE "nsslapd-NTSynch-SSL"
+#define CONFIG_NTSYNCHPORT_DIRECTIVE "ntsynch-port"
+#define CONFIG_NTSYNCHPORT_ATTRIBUTE "nsslapd-NTSynch-port"
+#define CONFIG_ACCESSCONTROL_DIRECTIVE "accesscontrol"
+#define CONFIG_ACCESSCONTROL_ATTRIBUTE "nsslapd-accesscontrol"
+#define CONFIG_GROUPEVALNESTLEVEL_DIRECTIVE "groupevalnestlevel"
+#define CONFIG_GROUPEVALNESTLEVEL_ATTRIBUTE "nsslapd-groupevalnestlevel"
+#define CONFIG_NAGLE_DIRECTIVE "nagle"
+#define CONFIG_NAGLE_ATTRIBUTE "nsslapd-nagle"
+#define CONFIG_PW_CHANGE_DIRECTIVE "pw_change"
+#define CONFIG_PW_CHANGE_ATTRIBUTE "passwordChange"
+#define CONFIG_PW_MUSTCHANGE_DIRECTIVE "pw_must_change"
+#define CONFIG_PW_MUSTCHANGE_ATTRIBUTE "passwordMustChange"
+#define CONFIG_PW_SYNTAX_DIRECTIVE "pw_syntax"
+#define CONFIG_PW_SYNTAX_ATTRIBUTE "passwordCheckSyntax"
+#define CONFIG_PW_MINLENGTH_DIRECTIVE "pw_minlength"
+#define CONFIG_PW_MINLENGTH_ATTRIBUTE "passwordMinLength"
+#define CONFIG_PW_EXP_DIRECTIVE "pw_exp"
+#define CONFIG_PW_EXP_ATTRIBUTE "passwordExp"
+#define CONFIG_PW_MAXAGE_DIRECTIVE "pw_maxage"
+#define CONFIG_PW_MAXAGE_ATTRIBUTE "passwordMaxAge"
+#define CONFIG_PW_MINAGE_DIRECTIVE "pw_minage"
+#define CONFIG_PW_MINAGE_ATTRIBUTE "passwordMinAge"
+#define CONFIG_PW_WARNING_DIRECTIVE "pw_warning"
+#define CONFIG_PW_WARNING_ATTRIBUTE "passwordWarning"
+#define CONFIG_PW_HISTORY_DIRECTIVE "pw_history"
+#define CONFIG_PW_HISTORY_ATTRIBUTE "passwordHistory"
+#define CONFIG_PW_INHISTORY_DIRECTIVE "pw_inhistory"
+#define CONFIG_PW_INHISTORY_ATTRIBUTE "passwordInHistory"
+#define CONFIG_PW_LOCKOUT_DIRECTIVE "pw_lockout"
+#define CONFIG_PW_LOCKOUT_ATTRIBUTE "passwordLockout"
+#define CONFIG_PW_STORAGESCHEME_DIRECTIVE "pw_storagescheme"
+#define CONFIG_PW_STORAGESCHEME_ATTRIBUTE "passwordStorageScheme"
+#define CONFIG_PW_MAXFAILURE_DIRECTIVE "pw_maxfailure"
+#define CONFIG_PW_MAXFAILURE_ATTRIBUTE "passwordMaxFailure"
+#define CONFIG_PW_UNLOCK_DIRECTIVE "pw_unlock"
+#define CONFIG_PW_UNLOCK_ATTRIBUTE "passwordUnlock"
+#define CONFIG_PW_LOCKDURATION_DIRECTIVE "pw_lockduration"
+#define CONFIG_PW_LOCKDURATION_ATTRIBUTE "passwordLockoutDuration"
+#define CONFIG_PW_RESETFAILURECOUNT_DIRECTIVE "pw_resetfailurecount"
+#define CONFIG_PW_RESETFAILURECOUNT_ATTRIBUTE "passwordResetFailureCount"
+#define CONFIG_ACCESSLOG_BUFFERING_DIRECTIVE "logbuffering"
+#define CONFIG_ACCESSLOG_BUFFERING_ATTRIBUTE "nsslapd-accesslog-logbuffering"
+#define CONFIG_CHANGELOG_DIR_DIRECTIVE "changelogdir"
+#define CONFIG_CHANGELOG_DIR_ATTRIBUTE "nsslapd-changelogdir"
+#define CONFIG_CHANGELOG_SUFFIX_DIRECTIVE "changelogsuffix"
+#define CONFIG_CHANGELOG_SUFFIX_ATTRIBUTE "nsslapd-changelogsuffix"
+#define CONFIG_CHANGELOG_MAXENTRIES_DIRECTIVE "changelogmaxextries"
+#define CONFIG_CHANGELOG_MAXENTRIES_ATTRIBUTE "nsslapd-changelogmaxentries"
+#define CONFIG_CHANGELOG_MAXAGE_DIRECTIVE "changelogmaxage"
+#define CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE "nsslapd-changelogmaxage"
+#define CONFIG_RETURN_EXACT_CASE_DIRECTIVE "return_exact_case"
+#define CONFIG_RESULT_TWEAK_DIRECTIVE "result_tweak"
+#define CONFIG_REFERRAL_MODE_DIRECTIVE "referralmode"
+#define CONFIG_ATTRIBUTE_NAME_EXCEPTION_DIRECTIVE "attribute_name_exceptions"
+#define CONFIG_MAXBERSIZE_DIRECTIVE "maxbersize"
+#define CONFIG_VERSIONSTRING_DIRECTIVE "versionstring"
+#define CONFIG_ENQUOTE_SUP_OC_DIRECTIVE "enquote_sup_oc"
+#define CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE "nsslapd-enquote_sup_oc"
+#define CONFIG_BASEDN_DIRECTIVE "certmap-basedn"
+#define CONFIG_BASEDN_ATTRIBUTE "nsslapd-certmap-basedn"
+
+%HashParametersName = ();
+
+# The following hash displays only general server parameters to migrate under cn=config
+%GeneralSrvParamToMigrate = (
+ 'accesscontrol' => 'nsslapd-accesscontrol',
+ 'errorlog-logging-enabled' => 'nsslapd-errorlog-logging-enabled',
+ 'accesslog-logging-enabled' => 'nsslapd-accesslog-logging-enabled',
+ 'auditlog-logging-enabled' => 'nsslapd-auditlog-logging-enabled',
+ 'logbuffering' => 'nsslapd-accesslog-logbuffering',
+ 'accesslog-logexpirationtime' => 'nsslapd-accesslog-logexpirationtime',
+ 'accesslog-logexpirationtimeunit' => 'nsslapd-accesslog-logexpirationtimeunit',
+ 'accesslog-maxlogdiskspace' => 'nsslapd-accesslog-logmaxdiskspace',
+ 'accesslog-minfreediskspace' => 'nsslapd-accesslog-logminfreediskspace',
+ 'accesslog-logrotationtime' => 'nsslapd-accesslog-logrotationtime',
+ 'accesslog-logrotationtimeunit' => 'nsslapd-accesslog-logrotationtimeunit',
+ 'accesslog-maxlogsize' => 'nsslapd-accesslog-maxlogsize',
+ 'accesslog-maxnumoflogsperdir' => 'nsslapd-accesslog-maxLogsPerDir',
+ 'auditlog-logexpirationtime' => 'nsslapd-auditlog-logexpirationtime',
+ 'auditlog-logexpirationtimeunit' => 'nsslapd-auditlog-logexpirationtimeunit',
+ 'auditlog-maxlogdiskspace' => 'nsslapd-auditlog-logmaxdiskspace',
+ 'auditlog-minfreediskspace' => 'nsslapd-auditlog-logminfreediskspace',
+ 'auditlog-logrotationtime' => 'nsslapd-auditlog-logrotationtime',
+ 'auditlog-logrotationtimeunit' => 'nsslapd-auditlog-logrotationtimeunit',
+ 'auditlog-maxlogsize' => 'nsslapd-auditlog-maxlogsize',
+ 'auditlog-maxnumoflogsperdir' => 'nsslapd-auditlog-maxLogsPerDir',
+ 'certmap-basedn' => 'nsslapd-certmap-basedn',
+ 'enquote_sup_oc' => 'nsslapd-enquote-sup-oc',
+ 'loglevel' => 'nsslapd-errorlog-level',
+ 'errorlog-logexpirationtime' => 'nsslapd-errorlog-logexpirationtime',
+ 'errorlog-logexpirationtimeunit' => 'nsslapd-errorlog-logexpirationtimeunit',
+ 'errorlog-maxlogdiskspace' => 'nsslapd-errorlog-logmaxdiskspace',
+ 'errorlog-minfreediskspace' => 'nsslapd-errorlog-logminfreediskspace',
+ 'errorlog-logrotationtime' => 'nsslapd-errorlog-logrotationtime',
+ 'errorlog-logrotationtimeunit' => 'nsslapd-errorlog-logrotationtimeunit',
+ 'errorlog-maxlogsize' => 'nsslapd-errorlog-maxlogsize',
+ 'errorlog-maxnumoflogsperdir' => 'nsslapd-errorlog-maxlogsperdir',
+ 'idletimeout' => 'nsslapd-idletimeout',
+ 'ioblocktimeout' => 'nsslapd-ioblocktimeout',
+ 'lastmod' => 'nsslapd-lastmod',
+ 'listenhost' => 'nsslapd-listenhost',
+ 'maxdescriptors' => 'nsslapd-maxdescriptors',
+ 'referral' => 'nsslapd-referral',
+ 'reservedescriptors' => 'nsslapd-reservedescriptors',
+ 'rootpwstoragescheme' => 'nsslapd-rootpwstoragescheme',
+ 'schemacheck' => 'nsslapd-schemacheck',
+ 'secure-port' => 'nsslapd-securePort',
+ 'security' => 'nsslapd-security',
+ 'sizelimit' => 'nsslapd-sizelimit',
+ 'SSL3ciphers' => 'nsslapd-SSL3ciphers',
+ 'timelimit' => 'nsslapd-timelimit',
+ 'pw_change' => 'passwordChange',
+ 'pw_syntax' => 'passwordCheckSyntax',
+ 'pw_exp' => 'passwordExp',
+ 'pw_history' => 'passwordHistory',
+ 'pw_inhistory' => 'passwordInHistory',
+ 'pw_lockout' => 'passwordLockout',
+ 'pw_lockduration' => 'passwordLockoutDuration',
+ 'pw_maxage' => 'passwordMaxAge',
+ 'pw_maxfailure' => 'passwordMaxFailure',
+ 'pw_minage' => 'passwordMinAge',
+ 'pw_minlength' => 'passwordMinLength',
+ 'pw_must_change' => 'passwordMustChange',
+ 'pw_resetfailurecount' => 'passwordResetFailureCount',
+ 'pw_storagescheme' => 'passwordStorageScheme',
+ 'pw_unlock' => 'passwordUnlock',
+ 'pw_warning' => 'passwordWarning'
+);
+
+# the following hash displays global parameters related to database stored under cn=config,cn=ldbm database,cn=plugins,cn=config
+%GlobalConfigLDBMparamToMigrate = (
+ 'allidsthreshold' => 'nsslapd-allidsthreshold',
+ 'lookthroughlimit' => 'nsslapd-lookthroughlimit',
+ 'mode' => 'nsslapd-mode',
+ 'dbcachesize' => 'nsslapd-dbcachesize'
+);
+
+# the following hash displays specific parameters to each backends and stored under cn=DBname,cn=ldbm database,cn=plugins,cn=config
+%LDBMparamToMigrate = (
+ 'cachesize' => 'nsslapd-cachesize',
+ 'readonly' => 'nsslapd-readonly'
+);
+
+%stdIncludes = (
+ "${oldConfDir}slapd.at.conf", "\n",
+ "${oldConfDir}slapd.oc.conf", "\n",
+ "${oldConfDir}java-object-schema.conf", "\n",
+ "${oldConfDir}ns-admin-schema.conf", "\n",
+ "${oldConfDir}ns-calendar-schema.conf", "\n",
+ "${oldConfDir}ns-certificate-schema.conf", "\n",
+ "${oldConfDir}ns-common-schema.conf", "\n",
+ "${oldConfDir}ns-compass-schema.conf", "\n",
+ "${oldConfDir}ns-delegated-admin-schema.conf", "\n",
+ "${oldConfDir}ns-directory-schema.conf", "\n",
+ "${oldConfDir}ns-legacy-schema.conf", "\n",
+ "${oldConfDir}ns-mail-schema.conf", "\n",
+ "${oldConfDir}ns-mcd-browser-schema.conf", "\n",
+ "${oldConfDir}ns-mcd-config-schema.conf", "\n",
+ "${oldConfDir}ns-mcd-li-schema.conf", "\n",
+ "${oldConfDir}ns-mcd-mail-schema.conf", "\n",
+ "${oldConfDir}ns-media-schema.conf", "\n",
+ "${oldConfDir}ns-mlm-schema.conf", "\n",
+ "${oldConfDir}ns-msg-schema.conf", "\n",
+ "${oldConfDir}ns-netshare-schema.conf", "\n",
+ "${oldConfDir}ns-news-schema.conf", "\n",
+ "${oldConfDir}ns-proxy-schema.conf", "\n",
+ "${oldConfDir}ns-value-schema.conf", "\n",
+ "${oldConfDir}ns-wcal-schema.conf", "\n",
+ "${oldConfDir}ns-cos-schema.conf", "\n",
+ "${oldConfDir}ns-web-schema.conf", "\n"
+);
+
+%userDefinedConfigFiles = (
+ "slapd.conf", "\n",
+ "slapd.ldbm.conf", "\n",
+ "slapd.user_at.conf", "\n",
+ "slapd.user_oc.conf", "\n",
+ "ns-schema.conf", "\n"
+ );
+
+$CIS_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.15" ;
+$TELEPHONE_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.50" ;
+$DN_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.12" ;
+$CES_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.26" ;
+$INT_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.27" ;
+$BIN_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.5" ;
+
+%allowedPlugins = (
+ "cis", $CIS_SYNTAX_OID,
+ "tel", $TELEPHONE_SYNTAX_OID,
+ "dn", $DN_SYNTAX_OID,
+ "ces", $CES_SYNTAX_OID,
+ "int", $INT_SYNTAX_OID,
+ "bin", $BIN_SYNTAX_OID
+ );
+
+%allowedModifiers = (
+ "single", "SINGLE-VALUE"
+ );
+# "override" is not supported anymore and "operational" cannot be used in user defined attribute.
+
+@oldSuffixes = () ; # array of old suffixes (with "o=netscaperoot" if presents)
+
+# link beetwen the name of the suffix and its associated DBname
+%DBNAMES = () ;
+%DBDirectory = () ;
+
+%oldhash = () ;
+
+# list of standard plugin's in version 4
+%stdPlugins = (
+ "7-bit check" => "\n",
+ "binary syntax" => "\n",
+ "case exact string syntax" => "\n",
+ "case ignore string syntax" => "\n",
+ "distinguished name syntax" => "\n",
+ "integer syntax" => "\n",
+ "internationalization plugin" => "\n",
+ "referential integrity postoperation" => "\n",
+ "telephone syntax" => "\n",
+ "uid uniqueness" => "\n"
+
+ );
+
+# list of standard indexes configured out of the box in version 4
+%stdIndex = (
+ 'aci', "\n",
+ 'changenumber', "\n",
+ 'copiedfrom', "\n",
+ 'dncomp', "\n",
+ 'entrydn', "\n",
+ 'numsubordinates', "\n",
+ 'objectclass', "\n",
+ 'parentid', "\n"
+);
+
+# list of user added Plugin's. In the new version, they 'll need to be recompiled
+@badPlugins = () ;
+
+%newIndex = () ;
+
+%User_oc = () ;
+# push objectnames as they are encountered in config files.
+@User_oc_names = () ;
+
+%User_at = () ;
+
+
+
+#Usage parameters
+$USER_OC_FILE_MODIFIED = 0 ; # 0 if user don't want to modify LDIF objectclasses before processing, 1 else
+$USER_AT_FILE_MODIFIED = 0 ;
+$INDEX_FILE_MODIFIED = 0 ;
+
+# get the version of the DS to migrate
+($oldVersion, $oldMinor) = &getVersion($oldDir, $oldversionstr);
+# get the version of the new DS
+($Version, $Minor) = &getVersion($root);
+
+# get old LIB_PATH
+$old_libpath = &getLibPath($oldDir, $oldVersion, $oldMinor);
+# get new LIB_PATH
+$new_libpath = &getLibPath($root, $Version, $Minor);
+
+# Shutdown the legacy Directory instance
+printTrace("\nShutdown the legacy Directory Server instance: ${oldHome}",0);
+&stopServer($oldDir, 'slapd-'.$oldname);
+
+# compare configuration files with the standard ones
+CompareStdConfigFiles() ;
+die "\n\n The version of the product you want to migrate is not a 4.x Netscape Directory Server\n" unless ($oldVersion == 4) ;
+
+FillHashParametersName() ;
+
+############### Connect to the New LDAP Directory Server ######################
+$ENV{"$LIB_PATH"} = $new_libpath;
+my $LDAPservername = &getLDAPservername();
+die "\n Migration aborted. Make sure your Old and New Directory Servers are installed on the same machine \n" if ( $LDAPservername == -1 );
+$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n";
+
+# continue if the connection to new LDAP server is successful !
+printTrace("\nConnected to $Version.$Minor LDAP server\n",0) ;
+
+# get the uid and gid of the new slapd user
+($localuser, $newuid, $newgid) = getuid_gid();
+# get the uid and gid of the old slapd user
+($oldlocaluser, $olduid, $oldgid) = getolduid_gid();
+
+# backup new configuration files in <new_root_server>/slapd-instancename/config
+printTrace("\nBackup $serverHome${PATHSEP}config on $serverHome${PATHSEP}config_backup ...",0);
+&backupConfigFiles();
+
+# Parse the main configuration file: slapd.conf
+printTrace("\nParse the configuration file: $oldSlapdConf...",0);
+ParseSlapdConf("< ${oldSlapdConf}");
+
+#migrate key/cert databases
+printTrace("\nMigrate key/cert databases...",0);
+&MigrateSSL();
+
+# Update parameters : general server parameters, global LDBM parameter, specific backend parameters
+printTrace("\nUpdate general server parameters...",0);
+$conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Can't contact the $Version.$Minor LDAP server: $LDAPservername\n";
+AddGeneralParameters();
+printTrace("\nUpdate global LDBM parameters...",0);
+AddGeneralLDBMParameters();
+printTrace("\nUpdate specific backend parameters...",0);
+AddSpecificLDBMParameters();
+
+##### FOR TESTING PURPOSE ONLY ########
+#
+#testIndexUpdating();
+#
+#######################################
+
+# Migrate some entries contained in the old dse.ldif, and migrate certmap.conf
+&MigrateDSE() ;
+&MigrateCertmap() ;
+
+# update new attribute definitions
+LDAPmodify_User_at();
+
+# update new object classes definitions
+LDAPmodify_User_oc();
+
+# add new indexes to each backends
+LDAPmodify_Indexes();
+
+# migrate Plug'ins parameters (enable attribute, and arguments)
+LDAPmodify_stdPlugin();
+
+################## Close the connection to new LDAP Server #####################
+$conn->close;
+
+
+################## stop the new instance and Export/Import the data, restart the server ##################
+if (%DBNAMES) {
+ &stopServer($root,'slapd-'.$newname);
+ if ($olddatadir) {
+ printTrace("\nold data directory $olddatadir...",0) ;
+ $ldif_rep = "$olddatadir${PATHSEP}";
+ } else {
+ printTrace("\ndata processing...",0) ;
+ # migrate data for each suffix: old -> LDIF files
+ &db2ldif($oldSlapdConf);
+ }
+
+ # migrate LDIF data to the new database: LDIF -> new
+ &manyLdif2db();
+ &startServer();
+}
+else {
+ printTrace("\nThere no old non-standard suffixes to migrate",0);
+}
+
+printMsg("\n\n ****** End of migration ******\n\n");
+
+close(LOGFILE);
+
+
+###########################################################################################
+# get input users
+sub getParameters {
+ my $exit = 0 ;
+ my $i = 0;
+ my $pwdfile= "";
+ while ($i <= $#ARGV) {
+ if ( "$ARGV[$i]" eq "-D" ) { # directory manager
+ if (! $rootDN) {
+ $rootDN = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-w") { # password
+ if (! $rootpwd) {
+ $rootpwd = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-j") { # password file
+ if (! $pwdfile) {
+ $pwdfile = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-o") { # old instance path
+ if (! $oldHome ) {
+ $oldHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $oldHome if $isNT ;
+ if ($oldHome =~ /[\"]?(.*)?[\"]?/) { $oldHome = $1 ; }
+ if ($oldHome =~ m@^(.*)/([^-/]*)-([^/]*)[/]?$@) {
+ $oldDir = $1 ;
+ $type = $2 ;
+ $oldname = $3 ;
+ if ($isNT) {
+ $oldDir = lc($oldDir) ;
+ $type = lc($type) ;
+ $oldname = lc($oldname) ;
+ $oldHome = lc($oldHome) ;
+ grep { s@/@\\@g } $oldDir ;
+ grep { s@/@\\@g } $oldHome ;
+ }
+ }
+ else {
+ print("\nThe old instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-n") { # new instance path
+ if (! $serverHome ) {
+ $serverHome = $ARGV[++$i] ;
+ grep { s@\\@/@g } $root if $isNT ;
+ grep { s@\\@/@g } $serverHome if $isNT ;
+ if ($serverHome =~ /[\"]?(.*)?[\"]?/) { $serverHome = $1 ; }
+ if ($serverHome =~ m@^(.*?)/?([^/-]*)-([^/]*)[/]?$@) {
+ $root = $1 if ($1);
+ $type = $2 ;
+ $newname = $3 ;
+ if ($isNT) {
+ $root = lc($root) ;
+ $type = lc($type) ;
+ $newname = lc($newname) ;
+ $serverHome = lc($serverHome) ;
+ grep { s@/@\\@g } $root ;
+ grep { s@/@\\@g } $serverHome ;
+ }
+ }
+ else {
+ print("\nThe new instance path is not correct. It must be like slapd-instancename");
+ &usage();
+ exit(1);
+ }
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-p") { # new DS port
+ if (! $newport ) {
+ $newport = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-d") { # old instance LDIF data dir
+ if (! $olddatadir ) {
+ $olddatadir = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-v") { # old version
+ if (! $oldversionstr ) {
+ $oldversionstr = $ARGV[++$i] ;
+ }
+ else {
+ &usage() ;
+ exit(1);
+ }
+ } elsif ("$ARGV[$i]" eq "-t") { # TRACELEVEL
+ my $value = $ARGV[++$i] ;
+ if ($value =~ /[0-3]/) {
+ $TRACELEVEL = $value ;
+ }
+ else {
+ print("\nThe tracelevel must belong to 0..3 interval");
+ &usage();
+ exit();
+ }
+ } elsif ("$ARGV[$i]" eq "-noinput") { # no user interventions during processing
+ $NO_INPUT_USER = 1 ;
+ } elsif ("$ARGV[$i]" eq "-L") { # migration logfile
+ $LogFileReport = $ARGV[++$i] ;
+ }
+ else {
+ print("\nThe option $ARGV[$i] is not recognized");
+ &usage() ;
+ exit(1);
+ }
+ $i++;
+ }
+ if (! $rootDN) {
+ print("\nThe rootDN is missing");
+ $exit = 1;
+ }
+ if ($pwdfile ne "") {
+ # Open file and get the password
+ unless (open (RPASS, $pwfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $rootpwd = <RPASS>;
+ chomp($rootpwd);
+ close(RPASS);
+ } elsif ($rootpwd eq "-"){
+ # Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+ # Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $rootpwd = ReadLine(0);
+# chomp($rootpwd);
+# ReadMode('normal');
+ }
+ if (! $rootpwd) {
+ print("\nThe rootpwd is missing");
+ $exit = 1 ;
+ }
+ if (! $newport) {
+ print("\nThe port is missing");
+ $exit = 1;
+ }
+ if (! $serverHome) {
+ print("\nThe new instance path is missing");
+ $exit = 1;
+ }
+ if (! $oldHome) {
+ print("\nThe old instance path is missing");
+ $exit = 1;
+ }
+ if ((! $LogFileReport) && $serverHome) {
+ ($sec, $min, $hour, $dd, $mm, $yy) = &GetTime();
+ $LogFileReport = "${serverHome}${PATHSEP}logs${PATHSEP}Migration_${dd}${mm}${yy}_${hour}${min}${sec}.log";
+ }
+
+ if ($exit) {
+ &usage() ;
+ exit(1);
+ }
+
+}
+
+
+###############################################################################
+# This subroutine is used to parse the slapd.conf configuration file and migrate specific parameters contained in it
+
+
+sub ParseSlapdConf {
+ my $oldsrc = shift;
+ my $NumLine = 0 ;
+ # read the old conf file into a hash table
+ open( OLDSRC, $oldsrc ) || die "Can't open $oldsrc: $!: ";
+ LINE: while ( <OLDSRC> ) {
+ $NumLine++ ;
+ printTrace("\nLine: $_",4) ;
+ if (/^\s*\#/) { # skip comments
+ printTrace("\n# ",4) ;
+ next LINE;
+ }
+ if (/^\s*$/) { # skip blank lines
+ printTrace("\nBLANK LINE",4);
+ next LINE;
+ } elsif (/^suffix\s+/i) {
+ chomp($_) ;
+ CheckSuffix($_);
+ } elsif (/^plugin/i) {
+ printTrace("\nPLUGIN",4);
+ chomp($_);
+ if (! &isAStandardPlugin($_)) {
+ push @badPlugins, $_;
+ }
+ else {
+ my $Plugin = $_ ;
+ if (! &ParsePlugin($_,$NumLine)) {
+ printMsg("\nLine $NumLine, syntax error of the plugin:\n$Plugin");
+ }
+ }
+ } elsif (/^include\s+[\"]?(.*?)[\"]?\s*$/i) {
+ # strip leading and trailing "
+ my $include_file = $1 ;
+ grep { s@/@\\@g } $include_file if $isNT;
+ if (! &isAStandardInclude($include_file)) {
+ printTrace("\nFILE: $1 NOT STANDARD",4) ;
+ &ParseConfigurationFile($include_file);
+ printTrace("\nEXIT ParseConfigurationFile: $include_file",4) ;
+ }
+ } elsif (/^userat\s+[\"]?(.*?)[\"]?\s*$/i) {
+ printTrace("\nuserat: $1",4);
+ my $at_file = $1 ;
+ grep { s@/@\\@g } $at_file if $isNT;
+ # Parse user defined attributes
+ &ParseAttributesFile($at_file);
+ } elsif (/^useroc\s+[\"]?(.*?)[\"]?\s*$/i) {
+ printTrace("\nuseroc: $1",4);
+ my $oc_file = $1 ;
+ grep { s@/@\\@g } $oc_file if $isNT;
+ # Parse user defined object classes
+ &ParseObjectClassesFile($oc_file);
+ } elsif (/^dynamicconf\s+[\"]?(.*?)[\"]?\s*$/i){
+ printTrace("\ndynamicconf: $1",4);
+ my $dynamiconf_file = $1 ;
+ grep { s@/@\\@g } $dynamiconf_file if $isNT;
+ # Parse dynamic configuration file (e-g slapd.ldbm.conf)
+ &ParseConfigurationFile($dynamiconf_file);
+ } elsif (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/) {
+ printTrace("\nParseParameters: $1",4);
+ # Parse parameters and record the associated value in %oldhash
+ &ParseParameters($1,$2,$NumLine);
+ } else {
+ printTrace("\nUnknown format of configuration data: $_",0); }
+ }
+ close(OLDSRC);
+
+ }
+
+
+
+#############################################################################
+# return 1 if the suffix already exists, 0 else
+sub existSuffix {
+ my $suffixname = shift ;
+ my $nsuffix = normalizeDN($suffixname);
+ my $entry = $conn->search("cn=mapping tree,cn=config", "one", "(|(cn=\"$suffixname\")(cn=\"$nsuffix\"))");
+ return 1 if ($entry) ;
+ my $cpt = 5;
+ my $errorCode = $conn->getErrorCode();
+ while (($errorCode eq $LDAP_SERVER_UNREACHABLE) && $cpt && (! $entry)) {
+ printTrace("\ntry to reconnect to search cn=\"$suffixname\",cn=mapping tree,cn=config", 1);
+ $conn = new Mozilla::LDAP::Conn($LDAPservername,$newport,$rootDN,$rootpwd) or die "\n Unable to contact the $Version.$Minor LDAP server: $LDAPservername\n";
+ $entry = $conn->search("cn=mapping tree,cn=config", "one", "(|(cn=\"$suffixname\")(cn=\"$nsuffix\"))");
+ $errorCode = $conn->getErrorCode();
+ $cpt--;
+ }
+ return 1 if ($entry) ;
+ return 0 ;
+}
+
+# return the name of the backend if it has been successfully created, 0 else
+sub createBackend {
+ my $suffixname = shift ;
+ my $backend = "MigratedDB_0" ;
+ my $NbRetry = 1 ;
+ my $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ;
+ while ($entry) {
+ # try to find another name for the backend
+ $backend = "MigratedDB_$NbRetry" ;
+ $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ;
+ $NbRetry++;
+ }
+ # normally I should have a unique name for the backend
+ my $suffixarg = "nsslapd-suffix" ;
+ $entry = $conn->newEntry() ;
+ $entry->setDN("cn=$backend,cn=ldbm database,cn=plugins,cn=config");
+ $entry->setValues("objectclass", "top", "extensibleObject", "nsBackendInstance" );
+ $entry->setValues("cn", $backend );
+ $entry->setValues($suffixarg, $suffixname );
+ my $res = $conn->add($entry) ;
+ if ($res) {
+ return $backend ;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+# return 1, if add the new entry in the mapping tree, else 0
+sub AddEntryInMappingTree {
+ my $backend = shift ;
+ my $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ;
+ if ($entry) {
+ printTrace("\nAddEntry in progress ...",4) ;
+ my $suffixarg = "nsslapd-suffix" ;
+ my $statearg = "nsslapd-state" ;
+ my $backendarg= "nsslapd-backend";
+ my $suffixname = $entry->{$suffixarg}[0];
+ $entry = $conn->newEntry() ;
+ $entry->setDN("cn=\"$suffixname\",cn=mapping tree,cn=config") ;
+ $entry->setValues("objectclass", "top", "extensibleObject", "nsMappingTree" );
+ $entry->setValues("cn", "\"$suffixname\"");
+ $entry->setValues($statearg, "backend");
+ $entry->setValues($backendarg, $backend);
+ return $conn->add($entry);
+ }
+ else {
+ printTrace("\nNo AddEntry processed for $backend",4);
+ return 0 ;
+ }
+}
+
+
+# Treat the case where the suffix is "o=NetscapeRoot"
+sub CheckSuffix {
+ my $suffix = shift ;
+ my $suffixname ;
+ my $expLdif;
+ my $confirm = "No";
+ my $dest = "$serverHome${PATHSEP}db_backup" ;
+ my $newSlapdExecDir = "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server";
+
+ if (!(/^suffix\s+\"?(.*?)\"?\s*$/i)) {
+ printMsg("Syntax error of the suffix: $suffix");
+ return 0 ;
+ }
+ else {
+ $suffixname = $1 ;
+ }
+ if (/^suffix\s+\"?\s*o=netscaperoot\s*\"?\s*$/i) {
+ printTrace("\nFor the suffix o=NetscapeRoot, we do nothing",1);
+ # treat the case where the suffix is "o=NetscapeRoot"
+ }
+ else {
+ push @oldSuffixes, $_;
+ # check if the suffix already exists in the new DS target
+ if (! existSuffix($suffixname)) {
+ printTrace("\n\nSuffix $suffixname doesn't exist",1) ;
+ # create a new backend with the name of the suffix preceded by MigratedDB_
+ my $backend = createBackend($suffixname) ;
+ if ($backend) {
+ printTrace("\nBackend: $backend has been created !!!",1);
+ # if the creation of the backend is ok, we add a new entry in the mapping tree
+ if (AddEntryInMappingTree($backend)) {
+ # We add the association dbname->suffix in the hash %DBNAMES
+ $DBNAMES{$suffixname} = $backend ;
+ # get the db filename
+ $entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ;
+ my $dirarg = "nsslapd-directory";
+ $DBDirectory{$backend} = $entry->{$dirarg}[0];
+ printTrace("\nThe relation $backend->$suffixname has been added to the mapping tree",2);
+ }
+ else {
+ printMsg("\nCOULD NOT ADD ENTRY: $backend->$suffixname IN MAPPINGTREE");
+ }
+ }
+ else {
+ printMsg("\nCOULD NOT CREATE BACKEND: $backend");
+ }
+ }
+ else {
+ printMsg("\n\nSuffix: $suffixname already exists");
+ # the suffix already exists in the new DS
+ printMsg("\nMigration will overwrite existing database");
+ printMsg("\nDo you want to continue Yes/No [No] ?") ;
+ my $answer = <STDIN> ;
+ if ($answer =~ /y|yes/i) {
+ my $nsuffix = normalizeDN($suffixname);
+ my $my_entry = $conn->search("cn=mapping tree,cn=config", "one", "(|(cn=\"$suffixname\")(cn=\"$nsuffix\"))");
+ my $backend = $my_entry->{"nsslapd-backend"}[0];
+ my $backend_entry = $conn->search("cn=$backend,cn=ldbm database,cn=plugins,cn=config ", "base","objectclass=*") ;
+ printMsg("Do you want to export the existing data Yes/No [Yes] ?");
+ my $answer = <STDIN> ;
+ if (!($answer =~ /n|no/i)) {
+ mkdir $dest, 0700 unless (-d $dest);
+ $expLdif = "$dest${PATHSEP}$backend.ldif";
+ while (!($confirm =~ /y|yes/i)) {
+ printMsg("\nEnter the full pathname of the file [$expLdif]:") ;
+ $answer = <STDIN> ;
+ chomp($expLdif = $answer) unless ($answer eq "\n");
+ printMsg("\nExisting data will be exported under $expLdif");
+ printMsg("\nContinue Yes/No [No] ?");
+ $confirm = <STDIN>;
+ }
+ $ENV{"$LIB_PATH"}=$new_libpath;
+ chdir($newSlapdExecDir) or die "\nCould not change directory to $newSlapdExecDir: $!\n";
+ printTrace("\nNow backing up database $CN in $expLdif\n",0);
+ &stopServer($root,'slapd-'.$newname);
+ &newinst_db2ldif($expLdif, $suffixname, $serverHome);
+ &startServer();
+ }
+ # We add the association dbname->suffix in the hash %DBNAMES
+ $DBNAMES{$suffixname} = $backend ;
+ my $dirarg = "nsslapd-directory";
+ $DBDirectory{$backend} = $backend_entry->{$dirarg}[0];
+ printTrace("\nThe relation $backend->$suffixname has been added to the mapping tree",2);
+ }
+ }
+ return 1 ;
+}
+}
+
+#############################################################################
+# Usefull to know the standard configuration
+sub isAStandardPlugin {
+ my $line = shift;
+ chomp($line);
+ printTrace("\nStdPlugin?: $line",4);
+ if ($line =~ /^plugin\s+(database|extendop|preoperation|postoperation|matchingrule|syntax)\s+(on|off)\s+\"(.*?)\"\s+\"(.*?)\"\s+(\S+)(.*)$/i) {
+ # $1 = <type>, $2 = <on|off>, $3 = <name>, $4 = <pathname>, $5 = <init_function>, $6 = [<arg>]*
+ printTrace("\nName: $3, pathname: $4, init_function: $5",4);
+
+ my $LC_line = lc($3);
+ my $Value = $stdPlugins{$LC_line} ;
+ if ($Value) {
+ printTrace("\nIS A STANDARD PLUGIN",4);
+ }
+ else {
+ printTrace("\nNOT A STANDARD PLUGIN",4);
+ }
+ return $stdPlugins{$LC_line} ;
+ }
+ else {
+ printTrace("\nSYNTAX ERROR PLUGIN",4);
+ return 0 ;
+ }
+}
+
+sub isAStandardIndex {
+ my $line = shift ;
+ chomp($line);
+ if ($line =~ /^index\s+(\S+).*/i) {
+ my $LC_line = lc($1);
+ my $Value = $stdIndex{$LC_line} ;
+ printTrace("\nInclude: $LC_line \nValue: $Value", 4);
+ return $stdIndex{$LC_line};
+ }
+ else {
+ return 0 ;
+ }
+}
+
+
+sub isAStandardInclude {
+ my $line = shift;
+
+ chomp($line);
+ if ($isNT){
+ return $stdIncludes{lc($line)};
+ }
+ else {
+ return $stdIncludes{$line} ;
+ }
+}
+
+#############################################################################
+#
+# Execute a Perldap command to update plugins definition in the new schema
+
+sub LDAPmodify_stdPlugin {
+ my $Filename = shift ;
+ my @pluginames = keys(%stdPlugins);
+ if (! $STDPLUGINS_FILE_MODIFIED) {
+ printTrace("\nLDAPmodify_plugin",4);
+ printTrace("\nMigrate plugin's...",1);
+ foreach $pluginame ( @pluginames ) {
+ my $update_plugin = 0 ;
+ my $ref_plugin = $stdPlugins{$pluginame};
+ if ($ref_plugin ne "\n") {
+ my $name = $ref_plugin->name ;
+ # We have a name change of "uid uniqueness plugin" in DS7.0
+ # to "attribute uniqueness"
+ $name = "attribute uniqueness" if ($name eq "uid uniqueness");
+ my $entry = $conn->search("cn=$name,cn=plugins,cn=config", "base","objectclass=nsSlapdPlugin") ;
+ if ($entry) {
+ my $pluginenabled="nsslapd-pluginenabled" ;
+ if (($entry->{$pluginenabled}[0]) ne $ref_plugin->enable) {
+ $update_plugin = 1 ;
+ my $enable = $ref_plugin->enable ;
+ printTrace("\n$pluginame, plugin-enable: $enable",3) ;
+ $entry->setValues($pluginenabled, $enable );
+ }
+ my $ArgNum = 0 ;
+ foreach $ArgValue (@{$ref_plugin->args}) {
+ my $Arg="nsslapd-pluginarg$ArgNum";
+ printTrace("\n$Arg: $ArgValue",3) ;
+ if ($entry->{$Arg}[0] ne $ArgValue) {
+ printTrace("\n$pluginame, $Arg: $ArgValue",3) ;
+ $update_plugin = 1 ;
+ $entry->setValues($Arg, $ArgValue) ;
+ }
+ $ArgNum++ ;
+ }
+ if ($update_plugin) {
+ printTrace("\n$pluginame is being updated...",2);
+ my $res = $conn->update($entry) ;
+ if ($res) {
+ printTrace("\nupdated !",2);
+ }
+ else {
+ printMsg("\nError during update of plugin: $pluginame") ;
+ $MigrationErrors .= "\nError during update of plugin: $pluginame";
+ }
+ }
+ else {
+ printTrace("\n$pluginame has not changed",4);
+ }
+ }
+ else {
+ printMsg("\ncan't access the plugin: cn=$name,cn=plugins,cn=config");
+ }
+ }
+ else {
+ printTrace("\nPLUGIN NOT RECORDED: $pluginame",4) ;
+ }
+ }
+ }
+ else {
+ # treat the case where the user wants to look at these plugins before processing
+ }
+}
+
+#############################################################################
+# Execute Perldap command to add new indexes to the migrated instances
+
+sub LDAPmodify_Indexes {
+ my $Filename = shift ;
+ my @indexnames = keys(%newIndex);
+ my @suffixnames = keys(%DBNAMES);
+ if ((! $INDEX_FILE_MODIFIED) && (%DBNAMES)) {
+ # we update indexes only if there is at least one backend to migrate
+ printTrace("\nLDAPmodify_indexes",4);
+ printTrace("\nMigrate indexes...",1);
+ foreach $indexname ( @indexnames ) {
+ printTrace("\nIndexName: $indexname",4);
+ printTrace("\nIndexTypes: .@{$newIndex{$indexname}->types}.", 4) ;
+ printTrace("\nIndexOIDS: .@{$newIndex{$indexname}->oids}.", 4) ;
+ foreach $suffixname ( @suffixnames ) {
+ # check if the index already exists !
+ printTrace("\nsearch for cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...", 3);
+ my $entry = $conn->search("cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex");
+ if (! $entry) {
+ # create a new index
+ printTrace("index $indexname is being created under cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...",2);
+ my $entry = $conn->newEntry();
+ $entry->setDN("cn=$indexname,cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config");
+ $entry->setValues("objectclass", "top", "nsIndex" ) ;
+ $entry->setValues("cn", $indexname) ;
+ $entry->setValues("nssystemindex", "false") ;
+ my @types = @{$newIndex{$indexname}->types} ;
+ my @oids = @{$newIndex{$indexname}->oids} ;
+ $entry->setValues("nsindextype", @types) if (@types) ;
+ $entry->setValues("nsmatchingrule", @oids ) if (@oids);
+ my $res = $conn->add($entry) ;
+ if ($res) {
+ printTrace("\nAdd index successfully: $indexname for backend: $DBNAMES{$suffixname}",2);
+ }
+ else {
+ printMsg("\n Failed to add the index: $indexname to backend: $DBNAMES{$suffixname}");
+ $MigrationErrors .= "\n Failed to add the index: $indexname to backend: $DBNAMES{$suffixname}" ;
+ }
+ }
+ elsif ($entry->{nssystemindex}[0] eq "false") {
+ # if the index is not a system index, we update it
+ printTrace("\nindex $indexname is being processed under cn=index,cn=$DBNAMES{$suffixname},cn=ldbm database,cn=plugins,cn=config...",2);
+ my @types = @{$newIndex{$indexname}->types} ; printTrace("\ntypes: .@types.",2) ;
+ my @oids = @{$newIndex{$indexname}->oids} ; printTrace("\noids: .@oids.",2) ;
+ my @existing_types = $entry->getValues("nsindextype");
+ my @existing_oids = $entry->getValues("nsmatchingrule");
+ # get the elements present in @types and not present in @existing_types
+ my @typesToAdd = &getDiff(\@types, \@existing_types);
+ # same for matchingrules
+ my @oidsToAdd = &getDiff(\@oids, \@existing_oids);
+ foreach $newtype (@typesToAdd) {
+ $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2);
+ }
+ foreach $newoid (@oidsToAdd) {
+ $entry->addValue("nsmatchingrule", $newoid);
+ }
+ if (@typesToAdd || @oidsToAdd) {
+ my $res = $conn->update($entry) ;
+ if ($res) {
+ printTrace("\nUpdate index successfully: $indexname for backend: $DBNAMES{$suffixname}",2);
+ }
+ else {
+ printMsg("\n Failed to update the index: $indexname to backend: $DBNAMES{$suffixname}");
+ $MigrationErrors .= "\n Failed to update the index: $indexname to backend: $DBNAMES{$suffixname}" ;
+ }
+ }
+ else {
+ printTrace("\nNothing to update",2);
+ }
+ }
+ else {
+ printTrace("\nThe index: $indexname is a system index. It can't be updated",2);
+ }
+ }
+ }
+
+ }
+ else {
+ # treat the case where the user wants to look at these indexes before processing
+ }
+
+}
+
+#############################################################################
+#
+# Execute a Perldap command to add all user defined object classes in the new schema
+
+sub LDAPmodify_User_oc {
+ my $Filename = shift ;
+ if (! $USER_OC_FILE_MODIFIED) {
+ printTrace("\nLDAPmodify_User_oc",4);
+ printTrace("\nMigrate objectclasses...",1);
+ foreach $objectname ( @User_oc_names ) {
+ my $entry = $conn->search("cn=schema", "base","objectclass=*") ;
+ die "\ncan't connect to object: cn=schema\n" unless ($entry);
+ printTrace("\nObjectName: $objectname\nValue: $User_oc{$objectname}",3);
+ next if ($entry->hasValue("objectclasses",$User_oc{$objectname},1)) ;
+ $entry->addValue("objectclasses",$User_oc{$objectname},"1") ;
+ my $res = $conn->update($entry) ;
+ my $err = $conn->getErrorCode();
+ if ($res) {
+ printTrace("\nobjectclass: $User_oc{$objectname} added",2);
+ } elsif ($err == 20) { # already exists
+ printTrace("\nobjectclass: $User_oc{$objectname} already exists",1);
+ } else {
+ printMsg("\nCan\'t add objectclass to the schema: $User_oc{$objectname}");
+ my $msg = $conn->getErrorString();
+ printMsg("\nMsg: $msg");
+ $MigrationErrors .= "\nCan\'t add objectclass to the schema: $User_oc{$objectname}" ;
+ }
+ }
+ }
+ else {
+ # treat the case where the user wants to look at these objectclasses before processing
+ }
+}
+
+#############################################################################
+#
+# Execute a Perldap command to add all user defined attributes in the new schema
+
+sub LDAPmodify_User_at {
+ my $Filename = shift ;
+ my @attributenames = keys(%User_at);
+ if (! $USER_AT_FILE_MODIFIED) {
+
+ printTrace("\nLDAPmodify_User_at",4);
+ printTrace("\nMigrate attributes...",1);
+ foreach $attributename ( @attributenames ) {
+ my $entry = $conn->search("cn=schema", "base","objectclass=*") ;
+ printTrace("\nAtributeName: $attributename, Value: $User_at{$attributename}",3);
+ die "\nentry not found cn=schema\n" unless $entry ;
+ next if ($entry->hasValue("attributetypes",$User_at{$attributename},1) ) ;
+ my $res = $entry->addValue("attributetypes",$User_at{$attributename},"1") ;
+ if (! $res) {
+ printMsg("\nCan\'t add attribute to the schema: $User_at{$attributename}");
+ $MigrationErrors .= "\nCan\'t add attribute to the schema: $User_at{$attributename}" ;
+ }
+ my $res = $conn->update($entry) ;
+ my $err = $conn->getErrorCode();
+ if ($res) {
+ printTrace("\nattribute: $attributename added",2);
+ } elsif ($err == 20) { # already exists
+ printTrace("\nattribute: $attributename already exists",1);
+ }
+ else {
+ printMsg("\nCan\'t add attribute to the schema: $User_at{$attributename}");
+ my $msg = $conn->getErrorString();
+ printMsg("\nMsg: $msg");
+ $MigrationErrors .= "\nCan\'t add attribute to the schema: $User_at{$attributename}" ;
+ }
+ }
+ }
+ else {
+ # treat the case where the user wants to look at these attributes before processing
+ }
+}
+
+#############################################################################
+# Add an object class to the user_oc hash and reset the object !!!
+sub AddObjectClass {
+ my $ObjectClass = shift ;
+ my $ObjectName = $ObjectClass->{'ObjectName'} ;
+ my $Object_oid = $ObjectClass->{'Object_oid'} ;
+ my $Object_superior = $ObjectClass->{'Object_superior'} ;
+ my $Object_requires = $ObjectClass->{'Object_requires'} ;
+ my $Object_allows = $ObjectClass->{'Object_allows'} ;
+ my $ObjectClassDef = "( $Object_oid NAME \'$ObjectName\' DESC \'\' SUP $Object_superior STRUCTURAL MUST ($Object_requires) MAY ($Object_allows) X-ORIGIN \'user defined\' )";
+ if ( (!($ObjectName =~ /^top$/i)) && ( ! $User_oc{$ObjectName} )) {
+ $User_oc{$ObjectName} = $ObjectClassDef ;
+ push @User_oc_names, $ObjectName ;
+ printTrace("ObjectName: $ObjectName \nObject_oid: $Object_oid \nObject_superior:$Object_superior \nObject_requires: $Object_requires \nObject_allows: $Object_allows \nObjectClassDefinition: $User_oc{$ObjectName}\n",4);
+ }
+ elsif ( ($User_oc{$ObjectName}) && ($User_oc{$ObjectName} ne $ObjectClassDef) ) {
+ printMsg("\nAttempt to redifine the objectclass: $ObjectName previously defined in your configuration file. Operation not allowed ");
+ }
+ else {
+ printMsg("\nAttempt to redifine the objectclass: top. Operation not allowed");
+ }
+ resetObjectClass($ObjectClass);
+}
+
+#############################################################################
+# Build an LDIF attribute and add it to the user_at hash
+sub AddAttribute {
+ my $Attr = shift ;
+ my $AttributeName = $Attr->{'AttributeName'};
+ my $Attribute_oid = $Attr->{'Attribute_oid'};
+ my $Attribute_aliases = $Attr->{'Attribute_aliases'};
+ my $Attribute_syntax = $Attr->{'Attribute_syntax'};
+ my $Attribute_single = $Attr->{'Attribute_single'};
+ my $AttributeDef = "( $Attribute_oid NAME ( \'$AttributeName\' $Attribute_aliases) DESC \'User Defined Attribute\' SYNTAX $Attribute_syntax $Attribute_single X-ORIGIN 'user defined' )" ;
+ printTrace("\nAttributeDef: $AttributeDef",4);
+ $User_at{$AttributeName} = $AttributeDef ;
+}
+#############################################################################
+# add the index structure to the newIndex hash
+sub AddIndex {
+ my $ref_index = shift ;
+ my $state = shift ;
+ printTrace("\nAddIndex, last state: $state",4) ;
+ if ($state == 1) {
+ $ref_index->specific("ALL") ;
+ return 1 ;
+ }
+ elsif ($state == 6) {
+ $ref_index->specific("NONE") ;
+ return 1 ;
+ }
+ if (($state == 1) || ($state == 3) || ($state == 5) || ($state == 6)) {
+ foreach $name (@{$ref_index->names}) {
+ $newIndex{$name} = $ref_index ; # record the ref to the index struct in the newIndex hash
+ }
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+#############################################################################
+# add the plugin structure to the stdPlugin hash
+
+sub AddPlugin {
+ my $ref_plugin = shift ;
+ printTrace("\nAddPlugin",4) ;
+ $stdPlugins{lc($ref_plugin->name)} = $ref_plugin ;
+ my $name = $ref_plugin->name ;
+ my $type = $ref_plugin->type ;
+ my $enable = $ref_plugin->enable ;
+
+ printTrace("\nPluginName: $name",4);
+ printTrace("\nPluginType: $type",4);
+ printTrace("\nPluginEnable: $enable",4);
+ printTrace("\nPluginArgs: @{$ref_plugin->args}",4);
+ return 1 ;
+}
+
+
+#############################################################################
+# parse a plugin definition and call the addindex
+
+sub ParsePlugin {
+ my $Plugin = shift ;
+ my $NumLine = shift ;
+ my $state = 0 ;
+ my $ErrorMsg = "Syntax error of a plugin definition. \n line parsed:";
+ my $ref_plugin = S_plugin->new();
+ printTrace("\nParsePlugin: $_",4);
+ if (/^plugin\s+(database|extendop|preoperation|postoperation|matchingrule|syntax)\s+(on|off)\s+\"(.*?)\"\s+\"(.*?)\"\s+(\S+)(.*)$/i) {
+ # $1 = <type>, $2 = <on|off>, $3 = <name>, $4 = <pathname>, $5 = <init_function>, $6 = [<arg>]*
+ $ref_plugin->name($3);
+ $ref_plugin->type($1);
+ $ref_plugin->enable($2);
+ $_ = $6 ;
+ my $ArgNb = 0 ;
+ my $prec ;
+ my $arg ;
+ my $Unix_oldDir = $oldDir ;
+ my $Unix_root = $root ;
+ grep { s@\\@/@g } $Unix_oldDir if $isNT;
+ grep { s@\\@/@g } $Unix_root if $isNT;
+ while (!(/^\s*$/)) {
+ if (/^\s*\".*?\"/) {
+ s/^\s*\"(.*?)\"(.*)/$2/i ;
+ $arg = $1 ;
+ }
+ elsif (/^\s*[^\"\s]+/) {
+ s/^\s*([^\"\s]+)(.*)/$2/i ;
+ $arg = $1 ;
+ }
+ $prec = $_ ;
+ $_ = $arg ;
+
+ s@$Unix_oldDir@$Unix_root@ig ;
+ s/$type-$oldname/$type-$newname/ig ;
+ @{$ref_plugin->args}[$ArgNb++] = $_ ;
+ $_ = $prec ;
+ }
+ if (/^\s*$/) {
+ return AddPlugin($ref_plugin);
+ }
+ else {
+ return 0 ;
+ }
+ }
+ return 0 ;
+}
+
+#############################################################################
+# parse an index definition and call the addindex
+
+sub ParseIndex {
+ my $index = shift ;
+ my $NumLine = shift ;
+ my $ref_index = S_index->new() ;
+ my $Value ;
+ my $state = 0 ;
+ my $ErrorMsg = "Syntax error of an index definition.\nline parsed:";
+ printTrace("\nParseIndex: $_",4) ;
+ s/,/, /g ;
+ s/\s+,/,/g ;
+ s/^index\s+//i ; # substitute the token index
+ while (!(/^\s*$/)) {
+ s/^\s*(\S+)(.*)$/$2/ ;
+ $Value = $1 ;
+ printTrace("\nValue: $Value",4);
+ printTrace("\nState: $state",4) ;
+ SWITCH: {
+ if ($state == 0) {
+ if ($Value =~ /[^\.]/) {
+ if ($Value =~ /(\S+),$/) {
+ push @{$ref_index->names}, $1 ;
+ }
+ else {
+ $state = 1 ;
+ push @{$ref_index->names}, $Value ;
+ }
+ }
+ else {
+ return 0 ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 1) {
+ if ($Value =~ /^none$/i) {
+ $state = 6 ; # end of the index definition
+ }
+ elsif ($Value =~ /^\"\"$/) {
+ $state = 4 ; # we expect to have at least one OID
+ }
+ elsif ($Value =~ /(\S+),$/) {
+ $state = 2 ;
+ push @{$ref_index->types}, $1 ;
+ }
+ else {
+ $state = 3 ;
+ push @{$ref_index->types}, $Value ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 2) {
+ if ($Value =~ /(\S+),$/) {
+ push @{$ref_index->types}, $1 ;
+ }
+ else {
+ $state = 3 ;
+ push @{$ref_index->types}, $Value ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 3) {
+ if ($Value =~ /(\S+),$/) {
+ $state = 4 ;
+ push @{$ref_index->oids}, $1 ;
+ }
+ else {
+ $state = 5 ;
+ push @{$ref_index->oids}, $Value ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 4) {
+ if ($Value =~ /(\S+),$/) {
+ push @{$ref_index->oids}, $1 ;
+ }
+ else {
+ $state = 5 ;
+ push @{$ref_index->oids}, $Value ;
+ }
+ last SWITCH ;
+ }
+ }
+ }
+return AddIndex($ref_index,$state) ;
+
+}
+
+#############################################################################
+
+sub ParseAttribute {
+
+
+ my $Attr = shift ;
+ my $NumLine = shift ;
+ my $state = 1 ;
+ my $ErrorMsg = "Syntax error of an attribute definition.\nline parsed:";
+ my %Attribute = (
+ 'AttributeName' => "",
+ 'Attribute_oid' => "",
+ 'Attribute_aliases' => "",
+ 'Attribute_syntax' => "",
+ 'Attribute_single' => ""
+ );
+ my $AttributeName = " ";
+ printTrace("\nParseAttribute",4);
+ while (!(/^\s*$/)) {
+ s/^(.*?)(\S+)\s*$/$1/ ;
+ printTrace("\nValue: $2",4);
+ printTrace("\nState: $state",4) ;
+ my $Value = $2 ;
+ SWITCH: {
+ if ($state == 1) {
+ if (isAllowedModifier($Value)) {
+ $state = 1 ;
+ $modifier = lc($Value);
+ $AttrVar = 'Attribute_' . $modifier ;
+ $Attribute{$AttrVar} = &getModifierValue($Value) ;
+ }
+ elsif (&isAllowedPlugin($Value)) {
+ $state = 2 ;
+ $Attribute{'Attribute_syntax'} = &getSyntaxOid($Value) ;
+ }
+ else {
+ return 0 ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 2) {
+ if ($Value =~ /[\.]|-oid$/) {
+ $Attribute{'Attribute_oid'} = "$Value" ;
+ printTrace("\nAttribute-oid: $Attribute{'Attribute_oid'}",3);
+ $state = 3 ;
+ }
+ elsif ($Value =~ /[^\.]/) {
+ $AttributeName = $Attribute{'AttributeName'} ;
+ if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;}
+ $Attribute{'AttributeName'} = $Value ;
+ $state = 4 ;
+ }
+ else {
+ return 0 ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 3) {
+ if ($Value =~ /[^\.]/) {
+ $AttributeName = $Attribute{'AttributeName'} ;
+ if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;}
+ $Attribute{'AttributeName'} = $Value ;
+ $state = 4 ; }
+ else {
+ return 0 ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 4) {
+ if ($Value =~/^attribute$/i){
+ $state = 5;
+ }
+ elsif ($Value =~/[^\.]/i) {
+ $AttributeName = $Attribute{'AttributeName'} ;
+ if ($AttributeName) { $Attribute{'Attribute_aliases'} .= "\'$AttributeName\' " ;}
+ $Attribute{'AttributeName'} = $Value ;
+ }
+ else {
+ return 0 ;
+ }
+ last SWITCH ;
+ }
+ if ($state == 5) {
+ return 0 ;
+ last SWITCH ;
+ }
+ }
+ }
+ $Attribute{'Attribute_oid'} = $Attribute{'AttributeName'} . '-oid' unless ($Attribute{'Attribute_oid'}) ;
+ return AddAttribute(\%Attribute) ;
+}
+
+
+#############################################################################
+# fill in the hash HashParametersName
+
+sub FillHashParametersName {
+ my @paramnames = ( keys(%GeneralSrvParamToMigrate), keys(%GlobalConfigLDBMparamToMigrate), keys(%LDBMparamToMigrate));
+ foreach $param (@paramnames) {
+ $HashParametersName{$param} = '\n';
+ }
+}
+
+
+# Parse parameters
+sub ParseParameters {
+ my $param = shift ;
+ my $value = shift ;
+ my $NumLine = shift ;
+ my $ErrorMsg = "parameter unknown, or not to be migrated: ";
+ if ($HashParametersName{lc($param)} && ($value !~ /^\s*$/)) {
+ $HashParametersName{lc($param)} = $value ;
+ printTrace("\nParam: $param is present",4);
+ }
+ else {
+ printTrace("\n$NumLine, $ErrorMsg,$param",4);
+ }
+
+}
+
+# add general server parameters
+sub AddGeneralParameters {
+ my @paramnames = keys(%GeneralSrvParamToMigrate);
+ my $entry = $conn->search("cn=config","base","objectclass=*");
+ die "\ncan't access to object: cn=config. \nMigration stopped\n" unless ($entry);
+ printTrace("\nAddGeneralParameters",4);
+ foreach $param (@paramnames) {
+ my $LDAPparam = $GeneralSrvParamToMigrate{$param} ;
+ my $Value = $HashParametersName{$param} ;
+ if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) {
+ printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4);
+ $entry->setValues($LDAPparam, $Value);
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nUpdate successfully $LDAPparam ",0);
+ }
+ else {
+ printMsg("\nCan't update parameter: $LDAPparam");
+ }
+ }
+ }
+}
+
+
+# add general LDBM parameters
+sub AddGeneralLDBMParameters {
+ my @paramnames = keys(%GlobalConfigLDBMparamToMigrate);
+ my $entry = $conn->search("cn=config,cn=ldbm database,cn=plugins,cn=config","base","objectclass=*");
+ die "\ncan't access to object: cn=config,cn=ldbm database,cn=plugins,cn=config. \nMigration stopped\n" unless ($entry);
+ printTrace("\nAddGeneralLDBMParameters",4);
+ foreach $param (@paramnames) {
+ my $LDAPparam = $GlobalConfigLDBMparamToMigrate{$param} ;
+ my $Value = $HashParametersName{$param} ;
+ if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) {
+ printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4);
+ $entry->setValues($LDAPparam, $Value);
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nUpdate successfully $LDAPparam ",0);
+ }
+ else {
+ printMsg("\nCan't update parameter: $LDAPparam");
+ }
+ }
+ }
+}
+
+# add specific LDBM parameters
+sub AddSpecificLDBMParameters {
+ my @paramnames = keys(%LDBMparamToMigrate);
+ my %REV_DBNAMES = reverse %DBNAMES ;
+ my @dbnames = keys(%REV_DBNAMES);
+ printTrace("\nAddSpecificLDBMParameters",4);
+ foreach $dbname (@dbnames) {
+ my $entry = $conn->search("cn=$dbname,cn=ldbm database,cn=plugins,cn=config","base","objectclass=*");
+ die "\ncan't access to object: cn=$dbname,cn=ldbm database,cn=plugins,cn=config. \nMigration stopped\n" unless ($entry);
+ foreach $param (@paramnames) {
+ my $LDAPparam = $LDBMparamToMigrate{$param} ;
+ my $Value = $HashParametersName{$param} ;
+ if (($Value ne '\n') && ($entry->{$LDAPparam}[0] ne $Value)) {
+ printTrace("\nLDAPparam: $LDAPparam, Value: $Value",4);
+ $entry->setValues($LDAPparam, $Value);
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nUpdate successfully $LDAPparam",2);
+ }
+ else {
+ printMsg("\nCan't update parameter: $LDAPparam");
+ }
+ }
+ }
+ }
+}
+
+#############################################################################
+# Parse a configuration file potentialy tuned by the user (different from slapd.user_oc.conf and slapd.user_at.conf)
+
+sub ParseConfigurationFile {
+
+ my $FileToParse = shift;
+ my $NumLine = 0;
+ my $PARSE_OBJECTCLASSES = 0 ; # 1 if there are objectclass definitions in the file
+ printTrace("\nParseConfigurationFile: $FileToParse",4) ;
+ printTrace("\nParse $FileToParse",2);
+ # read each line of the configuration file
+ my $CONFIGFILE = "CONFIGFILE.$FileToParse" ;
+ open( $CONFIGFILE, $FileToParse ) || die "Can't open $FileToParsec: $!: ";
+ LINE: while ( <$CONFIGFILE> ) {
+ $NumLine++ ;
+ if (/^\s*\#/) { # skip comments
+ next LINE;
+ }
+ if (/^\s*$/) { # skip blank lines
+ next LINE;
+ } elsif (/^suffix\s+/i) {
+ chomp($_) ;
+ CheckSuffix($_) ;
+ } elsif (/^plugin/i) {
+ chomp($_);
+ if (! &isAStandardPlugin($_)) {
+ push @badPlugins, $_;
+ }
+ else {
+ my $Plugin = $_ ;
+ if (! &ParsePlugin($_,$NumLine)) {
+ printMsg("\nLine $NumLine, syntax error of the plugin:\n$Plugin");
+ }
+ }
+ } elsif (/^index/i) {
+ chomp($_);
+ if (! &isAStandardIndex($_)) {
+ my $Index = $_ ;
+ if (! &ParseIndex($_,$NumLine)) {
+ printMsg("\nLine $NumLine, syntax error of index:\n$Index");
+ }
+ }
+ } elsif (/^include\s+[\"]?(.*?)[\"]?\s*$/i) {
+ # strip leading and trailing "
+ my $include_file = $1 ;
+ grep { s@/@\\@g } $include_file if $isNT;
+ if (! &isAStandardInclude($include_file)) {
+ &ParseConfigurationFile($include_file);
+ }
+ } elsif (/^attribute\s+\S+/i) {
+ chomp($_);
+ my $Attrib = $_ ;
+ if (! &ParseAttribute($_,$NumLine)) {
+ printMsg("\nLine $NumLine, syntax error of attribute:\n$Attrib");
+ }
+ } elsif (/^objectclass\s+(\S+)\s*$/i) {
+ # At least one objectclass is present in the file
+ $PARSE_OBJECTCLASSES = 1;
+ } elsif (/^\s*(\S+)\s+[\"]?(.*?)[\"]?\s*$/) {
+ # Parse parameters and record the associated value in %Oldhash
+ &ParseParameters($1,$2,$NumLine);
+ }
+ }
+ close($CONFIGFILE);
+ ParseObjectClassesFile($FileToParse) if ($PARSE_OBJECTCLASSES); # parse objectclass definition
+
+}
+
+#############################################################################
+# Parse the file specified in the userat attribute
+
+sub ParseAttributesFile {
+ my $userat_file=shift ;
+ my $NumLine = 0;
+ printTrace("\nParseAttributesFile: $userat_file",4);
+ printTrace("\nParse user defined attributes file: $userat_file",2);
+ # read each line of the configuration file
+ open( ATTRFILE, $userat_file ) || die "Can't open $FileToParsec: $!: ";
+ LINE: while ( <ATTRFILE> ) {
+ $NumLine++ ;
+ if (/^\s*\#/) { # skip comments
+ next LINE;
+ }
+ if (/^\s*$/) { # skip blank lines
+ next LINE;
+ } elsif (/^attribute\s+\S+/i) {
+ chomp($_);
+ my $Attrib = $_ ;
+ if (! &ParseAttribute($_, $NumLine)) {
+ printMsg("\nLine $NumLine, syntax error of attribute:\n$Attrib");
+ }
+ }
+ }
+ close(ATTRFILE);
+}
+
+#############################################################################
+# Parse the file specified in the useroc token
+
+sub ParseObjectClassesFile {
+ my $useroc_file = shift ;
+ my %ObjectClass = (
+ 'ObjectName' => " ",
+ 'Object_oid' => " ",
+ 'Object_superior' => "top",
+ 'Object_requires' => " ",
+ 'Object_allows' => " "
+ );
+
+ my $state = 0;
+ my $ErrorMsg = "Syntax error of an object class definition.\nline parsed:";
+ my $LineNb = 0 ; # Number of the current line parsed in the file
+ printTrace("ParseObjectClassesFile: $useroc_file\n",4) ;
+ # read each line of the configuration file
+ open( OBJCLASSFILE, $useroc_file ) || die "Can't open $FileToParsec: $!: ";
+ printTrace("Begin the parsing of the file: $useroc_file",4);
+ LINE: while ( <OBJCLASSFILE> ) {
+ printTrace("Current Line: $_",4);
+ $LineNb++ ;
+ if (/^\s*\#/) { # skip comments
+ next LINE;
+ }
+ if (/^\s*$/) { # skip blank lines
+ next LINE;
+ }
+ SWITCH: {
+ if ($state == 0) { resetObjectClass(\%ObjectClass);
+ if (/^objectclass\s+(\S+)\s*$/i) {
+ $ObjectClass{'ObjectName'} = $1;
+ $state = 1 ;}
+ else {} # printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 1) {if (/^\s+oid\s+(\S+)\s*$/i) {
+ $ObjectClass{'Object_oid'} = $1;
+ $state = 2 ;}
+ elsif (/^\s+superior\s+(\S+)\s*$/i) {
+ $ObjectClass{'Object_superior'} = $1;
+ $state = 3 ;
+ }
+ elsif (/^\s+requires\s*$/i) {
+ $state = 4;
+ }
+ elsif (/^\s+allows\s*$/i) {
+ $state = 5;
+ }
+ else {$state=0; printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 2) {if (/^\s+superior\s+(\S+)\s*$/i) {
+ $ObjectClass{'Object_superior'} = $1;
+ $state = 3 ;}
+ elsif (/^\s+requires\s*$/i) {
+ $state = 4;
+ }
+ elsif (/^\s+allows\s*$/i) {
+ $state = 5;
+ }
+ else { $state=0; printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 3) {if (/^\s+requires\s*$/i)
+ { $state = 4; }
+ elsif (/^objectclass\s+(\S+)\s*$/i) {
+ # run an ldap add before to continue
+ &AddObjectClass(\%ObjectClass);
+ $ObjectClass{'ObjectName'} = $1;
+ $state = 1 ;}
+ elsif (/^\s+allows\s*$/i)
+ { $state = 5; }
+ else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 4) {if (/^\s+([^,\s]+),\s*$/i) {
+ $ObjectClass{'Object_requires'}.=$1." \$ "; }
+ elsif (/^\s+([^,\s]+)\s*$/i) {
+ $ObjectClass{'Object_requires'}.=$1." ";
+ $state = 6; }
+ else {$state = 0;printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 5) {if (/^\s+([^,\s]+),\s*$/i) {
+ $ObjectClass{'Object_allows'}.=$1." \$ "; }
+ elsif (/^\s+([^,\s]+)\s*$/i) {
+ $ObjectClass{'Object_allows'}.=$1." ";
+ # run an ldap add before to continue
+ &AddObjectClass(\%ObjectClass);
+ $state = 0; }
+ else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ if ($state == 6) {if (/^objectclass\s+(\S+)\s*$/i) {
+ # run an ldap add before to continue
+ &AddObjectClass(\%ObjectClass);
+ $ObjectClass{'ObjectName'} = $1;
+ $state = 1 ;}
+ elsif (/^\s+allows\s*$/i) {
+ $state = 5;}
+ else {$state = 0; printMsg($ErrorMsg,$_,$LineNb);}
+ last SWITCH;}
+ }
+ }
+ close(OBJCLASSFILE);
+ if (($state == 3) || ($state == 4) || ($state == 5) || ($state == 6)) {
+ &AddObjectClass(\%ObjectClass);
+ }
+ printTrace("state: $state",4);
+}
+
+#############################################################################
+# printMsg print message to the user standard output.
+
+sub printMsg {
+
+ my $TypeMsg = shift ;
+ my $Msg = shift ;
+ my $LineNb = shift ;
+ if ($LineNb) {
+ printTrace("Line: $LineNb, $TypeMsg, $Msg");
+ }
+ else {
+ printTrace("$TypeMsg $Msg");
+ }
+}
+
+#############################################################################
+# print message error to the user standard output.
+
+sub printTrace {
+
+ my $Msg = shift ;
+ my $level = shift ;
+ if ($level <= $TRACELEVEL) {
+ print($Msg);
+ print LOGFILE $Msg ;
+ }
+}
+
+#############################################################################
+# reset an objectclass structure
+
+sub resetObjectClass {
+ my $ObjectClass = shift;
+ $ObjectClass->{'ObjectName'} = " " ;
+ $ObjectClass->{'Object_oid'} = " " ;
+ $ObjectClass->{'Object_superior'} = "top" ;
+ $ObjectClass->{'Object_requires'} = " " ;
+ $ObjectClass->{'Object_allows'} = " " ;
+}
+
+#############################################################################
+# this subroutine implements a very stupid version of diff
+
+sub diff {
+ my $f1 = shift;
+ my $f2 = shift;
+ my $lineToBeginWith = shift;
+ my $NULL = "" ;
+ my $diff_f1 = $NULL ;
+ my $diff_f2 = $NULL ;
+ my $retval = $NULL ;
+ my $ret;
+ open(F1, "$f1") or die "Could not open file $f1";
+ open(F2, "$f2") or close(F1), die "Could not open file $f2";
+
+ while (defined($l1 = <F1>)) {
+ if ($lineToBeginWith){
+ $lineToBeginWith -- ;
+ next ;
+ }
+ next if ($l1 =~ /^\#/);
+ $ret = defined($l2 = <F2>);
+ if ($ret) {
+ $ret = defined($l2 = <F2>) while ($ret && ($l2 =~ /^\#/)) ;
+ if ($ret) {
+ if (!($l1 eq $l2)) {
+
+ # ignore whitespace
+ $l1_clean = $l1 ;
+ $l2_clean = $l2 ;
+ $l1_clean =~ s/\s//g;
+ $l2_clean =~ s/\s//g;
+
+ if (!($l1_clean eq $l2_clean)) {
+ $diff_f1 .= "${l1}" unless ($l1_clean eq $NULL);
+ $diff_f2 .= "${l2}" unless ($l2_clean eq $NULL);
+ }
+ }
+ }
+ else {
+ next if ($l1 =~ /^\s*$/) ;
+ $diff_f1 .= "${l1}";
+ }
+ }
+ else {
+ next if ($l1 =~ /^\s*$/) ;
+ $diff_f1 .= "${l1}";
+ }
+ }
+
+ while (defined($l2 = <F2>)) {
+ if (($l2 =~ /^\#/) || ($l2 =~ /^\s*$/)) {
+ next ;
+ }
+ else {
+ $diff_f2 .= "${l2}" ;
+ }
+ }
+
+ close(F1);
+ close(F2);
+
+ $retval .= "- differences present in your config file but not in standard file:\n\n". "$diff_f1\n" if ($diff_f1) ;
+ $retval .= "- differences present in standard file but not in your config file:\n\n" . "$diff_f2" if ($diff_f2) ;
+ return $retval ;
+}
+
+sub CompareStdConfigFiles {
+ # Compare each configuration file against its default version. If it has changed,
+ # notify the user that the file has changed and will need to be checked by the
+ # user. This should be safe to do because there should be no path information
+ # stored in these conf files, which are just schema stuff.
+ # printTrace("\nCheck if standard configuration files have changed",3);
+
+ my $origFilePath = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}install${PATHSEP}config${PATHSEP}" ;
+ my $FilesChanged = "";
+ my $AllDiffs = "***********************************************************************";
+ my $NoChanges = "" ;
+ my $lineToBegin = 0 ;
+ printTrace("\nVersion of the old directory server: $oldVersion.$oldMinor",0);
+ opendir(CONFDIR, $oldConfDir) or
+ die "Error: could not open migrated config dir $oldConfDir: $!";
+
+ foreach $file (readdir(CONFDIR)) {
+ $origFile = $origFilePath . $file ;
+ $configFile = $oldConfDir . $file ;
+ if ((! exists($userDefinedConfigFiles{lc($file)})) && (-f $origFile)) {
+ my $lineToBegin = 1 if (lc($file) eq "slapd-collations.conf"); # we ignore the first line of slapd-collations
+ $diffs = &diff($configFile, $origFile, $lineToBegin);
+ $lineToBegin = 0 if $lineToBegin ;
+ if ($diffs) {
+ $FilesChanged .= "\n$configFile";
+ $AllDiffs .= "\n$configFile is different than the standard configuration file" ;
+ $AllDiffs .= "\nYou will need to check this file and make sure its changes are compatible ";
+ $AllDiffs .= "with the new directory server\nHere are the differences:\n";
+ $AllDiffs .= "$diffs \n\n";
+ $AllDiffs .= "***********************************************************************";
+ }
+ else {
+ $NoChanges .= "\n$configFile";
+ }
+ }
+ }
+ closedir(CONFDIR);
+
+if ($FilesChanged) {
+ printTrace("\nNo changes to old configuration files:$NoChanges",3) ;
+ printTrace("\n***********************************************************************",3) ;
+ printMsg("\nThe following standard files have been modified: $FilesChanged");
+ if ($NO_INPUT_USER) {
+ # do nothing
+ }
+ else {
+ printMsg("\nDo you want to see the differences Yes/No [No] ?") ;
+ my $answer = <STDIN> ;
+ if ($answer =~ /y|yes/i) {
+ printMsg("$AllDiffs");
+ }
+ printMsg("\nDo you want to continue the migration Yes/No [No] ?");
+ $answer = <STDIN> ;
+ if (! ($answer =~ /y|yes/i)) {
+ exit(1);
+ }
+ }
+ }
+}
+
+
+#############################################################################
+
+sub db2ldif {
+ my ($conf, $ldif_dir) = @_;
+ $ENV{"$LIB_PATH"}=$old_libpath;
+ if (!$conf) {
+ $conf = "$oldHome${PATHSEP}config${PATHSEP}slapd.conf";
+ }
+ if (! $ldif_dir) { $ldif_dir = $ldif_rep ;}
+ if (!(-d $ldif_dir)) {
+ mkdir($ldif_dir,0777) or die "can't create $ldif_rep to store temporary ldif files";
+ }
+ my $dir = "$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server";
+ chdir($dir) or
+ die "Error: could not change directory to $dir: $!";
+ my @suffixnames = keys(%DBNAMES) ;
+ foreach $suffixname (@suffixnames) {
+ my $ldif_file = $ldif_dir.$DBNAMES{$suffixname}.".ldif" ;
+ # If we are on NT, ${quote} is setup to "\"", else it's setup to ""
+ # As the suffix can contain some space characters, I write the suffix parameter: "\"$suffixname\"" rather than "${quote}$suffixname${quote}"
+ my @cmd =
+ ( "${quote}$oldDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" .
+ "${PATHSEP}$slapdExecName${quote}", "db2ldif", '-n', '-f',
+ "${quote}$conf${quote}", '-a', "${quote}$ldif_file${quote}",
+ '-d', '1','-s',"\"$suffixname\"" );
+ open(DB2LDIF, "${quote}@cmd${quote} 2>&1|") or
+ die "Error: could not execute @cmd: $!";
+ sleep(1); # allow pipe to fill with data
+ $ii = 0; # counter
+ while (<DB2LDIF>) {
+ ++$ii;
+ if (($ii % 250) == 0) {
+ printMsg(" Processing...\n");
+ }
+ }
+ close(DB2LDIF);
+ # set the ownership of the ldif file; should be the same as the new slapd user id
+ if ((! $isNt) && ($oldlocaluser ne $localuser)) {
+ if (-f $ldif_file) {
+ chown( $newuid, $newgid, $ldif_file) or printMsg("\nUnable to change the ownership of $ldif_file to $localuser") ;
+ }
+ }
+ }
+ print " Done.\n";
+ chdir($curdir) or die "Could not change directory to $curdir: $!";
+}
+
+#############################################################################
+# This db2ldif is used to export database of the new instance
+
+sub newinst_db2ldif {
+ my $ldif = shift ;
+ my $include_suffix = shift ;
+ my $home = shift ;
+ my $db2ldif_param = "db2ldif -r -D $home -a $ldif -s \"$include_suffix\"";
+
+ open(DB2LDIF, "${quote}${quote}$slapdExecName${quote} $db2ldif_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n";
+ sleep(1); # allow some data to accumulate in the pipe
+ my $ii = 0;
+ while (<DB2LDIF>) {
+ ++$ii;
+ if (($ii % 250) == 0) {
+ printMsg(" Processing...\n");
+ }
+ printMsg($_);
+ }
+ close(DB2LDIF);
+ # set the ownership of the ldif file; should be the same as the 5.x slapd user id
+ if ((! $isNt) && ($oldlocaluser ne $localuser)) {
+ if (-f $ldif) {
+ chown( $newuid, $newgid, $ldif) or printMsg("\nUnable to change the ownership of $ldif to $localuser") ;
+ }
+ }
+}
+
+#############################################################################
+
+# this is used to run the system() call, capture exit and signal codes,
+# and die() upon badness; the first argument is a directory to change
+# dir to, if any, and the rest are passed to system()
+sub mySystem {
+ my $rc = &mySystemNoDie(@_);
+ my ($dir, @args) = @_;
+ if ($rc == 0) {
+# success
+ } elsif ($rc == 0xff00) {
+ die "Error executing @args: error code $rc: $!";
+ } elsif ($rc > 0x80) {
+ $rc >>= 8;
+ die "Error executing @args: error code $rc: $!";
+ } else {
+ if ($rc & 0x80) {
+ $rc &= ~0x80;
+ }
+ die "Error executing @args: received signal $rc: $!";
+ }
+
+ # usually won't get return value
+ return $rc;
+}
+
+# This version does not die but just returns the error code
+sub mySystemNoDie {
+ my ($dir, @args) = @_;
+ if ($dir && ($dir ne "")) {
+ chdir($dir) or die "Could not change directory to $dir: $!";
+ }
+ my $cmd = $args[0];
+ # the system {$cmd} avoids some NT shell quoting problems if the $cmd
+ # needs to be quoted e.g. contains spaces; the map puts double quotes
+ # around the arguments on NT which are stripped by the command
+ # interpreter cmd.exe; but don't quote things which are already quoted
+ my @fixargs = map { /^[\"].*[\"]$/ ? $_ : $quote . $_ . $quote } @args;
+ my $rc = 0;
+ if ($cmd =~ /[.](bat|cmd)$/) {
+ # we have to pass batch files directly to the NT command interpreter
+ $cmd = $com_spec;
+# print "system $cmd /c \"@fixargs\"\n";
+ $rc = 0xffff & system {$cmd} '/c', "\"@fixargs\"";
+ } else {
+# print "system $cmd @fixargs\n";
+ $rc = 0xffff & system {$cmd} @fixargs;
+ }
+ chdir(${curdir}) or die "Could not change directory to $curdir: $!";
+ return $rc;
+}
+
+#############################################################################
+sub manyLdif2db {
+ my %rev_dbnames = reverse(%DBNAMES);
+ @backends = keys(%rev_dbnames);
+ $ENV{"$LIB_PATH"}=$new_libpath;
+ chdir($slapdExecDir) or die "Could not change directory to $slapdExecDir: $!";
+ foreach $backend (@backends) {
+ my $ldif = "${ldif_rep}$backend.ldif" ;
+ if (! -f $ldif) {
+ $ldif = ${ldif_rep}."data.ldif";
+ }
+ &Ldif2db($ldif, $backend);
+ }
+ # remove the empty ldif directory
+ # but not if using the data dir
+ if (!$olddatadir) {
+ rmdir($ldif_rep);
+ }
+ chdir($curdir) or die "Could not change directory to $curdir: $!";
+}
+
+
+sub Ldif2db {
+ my $ldif = shift ;
+ my $backend = shift ;
+ my $ldif2db_param = "ldif2db -D $serverHome -n $backend -i $ldif";
+ open(LDIF2DB, "${quote}${quote}$slapdExecName${quote} $ldif2db_param${quote} 2>&1 |") or die "Could not run ns-slapd program $ldif2db_exe\n";
+ sleep(1); # allow some data to accumulate in the pipe
+ while (<LDIF2DB>) {
+ printMsg($_);
+ }
+ close(LDIF2DB);
+ # remove the ldif file after the import
+ # but not if using the data dir
+ if (!$olddatadir) {
+ unlink($ldif) ;
+ }
+}
+
+#############################################################################
+
+#sub copyBak {
+# opendir( OLDBAK, "$oldHome${PATHSEP}bak" ) ||
+# die "Can't open directory $oldHome${PATHSEP}bak: $!: ";
+# local ( @dirs ) = readdir( OLDBAK );
+# closedir ( OLDBAK );
+# for ( @dirs ) {
+# if ( $_ eq "." || $_ eq ".." ) {
+# next;
+# } elsif ( -d "$oldHome${PATHSEP}bak${PATHSEP}$_" ) {
+# $srcDir = "$oldHome${PATHSEP}bak${PATHSEP}$_";
+# $destDir = "$serverHome${PATHSEP}bak${PATHSEP}$_";
+# $srcLDIF = "$oldHome${PATHSEP}ldif${PATHSEP}bak.ldif";
+# $destLDIF = "$serverHome${PATHSEP}ldif${PATHSEP}bak.ldif";
+# mkdir( $destDir , 0755 ) if !( -e $destDir);
+# # Converting database
+# if ( !$isNT && $newuser ) {
+# chown($newuid, $newgid,
+# "$serverHome${PATHSEP}bak", $destDir);
+# }
+# &other_db2ldif($srcDir, $srcLDIF);
+# if ($needAclUpg) {
+# &mySystem("$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server",
+# "$root${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server" .
+# "${PATHSEP}aclupg$exe_suffix", '-d', '-i',
+# $srcLDIF, '-o', $destLDIF);
+# } else {
+# &copyBinFile($srcLDIF, $destLDIF);
+# }
+# &other_ldif2db($destLDIF, $destDir);
+# }
+# }
+#}
+#############################################################################
+
+sub startServer {
+ my $instanceDir = ${serverHome} ;
+ my $errLog = $instanceDir . $PATHSEP . 'logs' . $PATHSEP . 'errors';
+ # emulate tail -f
+ # if the last line we see does not contain "slapd started", try again
+ my $done = 0;
+ my $started = 0;
+ my $code = 0;
+ my $lastLine = "";
+ my $timeout = time + 240; # 4 minutes
+ $ENV{"$LIB_PATH"}=$new_libpath;
+
+ my $startCmd = $instanceDir . $PATHSEP . 'start' . $script_suffix;
+ if (! -f $startCmd) {
+ $startCmd = $instanceDir . $PATHSEP . 'start-slapd' . $script_suffix;
+ }
+ printTrace("\nInstanceDir: $instanceDir\n",4);
+ $code = &mySystem($instanceDir,$startCmd);
+ open(IN, $errLog) or die "Could not open error log $errLog: $!";
+ my $pos = tell(IN);
+ while (($done == 0) && (time < $timeout)) {
+ for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) {
+ $lastLine = $_;
+ # print;
+ # the server has already been started and shutdown once . . .
+ if (/slapd started\./) {
+ $started++;
+ if ($started == 2) {
+ $done = 1;
+ }
+ # sometimes the server will fail to come up; in that case, restart it
+ } elsif (/Initialization Failed/) {
+ # print "Server failed to start: $_";
+ $code = &mySystem($instanceDir, $startCmd);
+ # sometimes the server will fail to come up; in that case, restart it
+ } elsif (/exiting\./) {
+ # print "Server failed to start: $_";
+ #$code = &mySystem($startCmd);
+
+ $code = &mySystem($instanceDir, $startCmd);
+ }
+ }
+ if ($lastLine =~ /PR_Bind/) {
+ # server port conflicts with another one, just report and punt
+ print $lastLine;
+ print "This server cannot be started until the other server on this\n";
+ print "port is shutdown.\n";
+ $done = 1;
+ }
+ if ($done == 0) {
+ # rest a bit, then . . .
+ sleep(2);
+ # . . . reset the EOF status of the file desc
+ seek(IN, $pos, 0);
+ }
+ }
+ close(IN);
+
+ if ($started < 2) {
+ $! = $code;
+ # $now = time;
+ # if ($now > $timeout) {
+ # print "Possible timeout: timeout=$timeout now=$now\n";
+ # }
+ die "Error: could not start server: $!";
+ }
+
+ return 0;
+}
+
+sub stopServer {
+ my $root = shift;
+ my $name = shift;
+ $maxStopIterations = 5;
+ print "\nShutting down server $name . . .\n";
+
+ $ENV{"$LIB_PATH"}=$new_libpath;
+ $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop' . $script_suffix . $quote;
+ if (! -f $stopCmd) {
+ $stopCmd = $quote . $root . $PATHSEP . $name . $PATHSEP . 'stop-slapd' . $script_suffix . $quote;
+ }
+
+ if (! -f $stopCmd) {
+ # no stop command, probably a 1.X system; for NT, we'll try net stop
+ # for unix, we'll get the pid and kill it
+ if ($isNT) {
+ $stopCmd = 'net stop ' . $name;
+ } else {
+ # see if there is a pid file
+ $pidfile = $root . $PATHSEP . $name . $PATHSEP . 'logs' .
+ $PATHSEP . 'pid';
+ if (open(PIDFILE, $pidfile)) {
+ chomp($pid = <PIDFILE>);
+ close(PIDFILE);
+ while ($maxStopIterations-- && !$exitCode) {
+ $exitCode = kill(15, $pid);
+ }
+ $stopCmd = undef;
+ }
+ }
+ }
+
+ # keep looping until the stop cmd returns an error code, which usually
+ # means that what ever we want to stop is stopped, or some other error
+ # occurred e.g. permission, or no such service
+ $exitCode = &runAndIgnoreOutput($stopCmd);
+# print "stopServer: exitCode=$exitCode\n";
+ while ($stopCmd && $maxStopIterations-- && $exitCode) {
+ $exitCode = &runAndIgnoreOutput($stopCmd);
+# print "stopServer: exitCode=$exitCode\n";
+ }
+
+ if (!$maxStopIterations) {
+ print "Warning: could not shutdown the server: $!\n";
+ }
+
+ sleep(10) ;
+
+ $exitCode = 0;
+
+}
+
+
+sub runAndIgnoreOutput {
+ my $cmd = shift;
+ printMsg(".");
+ open(RUNCMD, "${quote}$cmd${quote} 2>&1 |") or die "Error: could not run $cmd: $!";
+ printMsg(".");
+ sleep(1); # allow pipe to fill with data
+ printMsg(".");
+ while (<RUNCMD>) {
+# print;
+ }
+ my $code = close(RUNCMD);
+# print "runAndIgnore: code=$code status=$?\n";
+ return $?;
+}
+#############################################################################
+# migrate some of entries present in the old DSE.ldif like
+# cn=snmp,cn=config
+# cn=encryption,cn=config
+# all the aci's
+
+sub MigrateDSE {
+ printTrace("\nMigrate DSE entries...",1);
+ open( DSELDIF, "< $oldDSEldif" ) || die "Can't open $oldDSEldif: $!: ";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($old_entry = readOneEntry $in) {
+ my $DN = $old_entry->getDN() ;
+ SWITCH: {
+ # migrate the entrie: cn=snmp,cn=config
+ if ($DN =~ /^cn=SNMP,cn=config$/i) {
+ my $entry = $conn->search("$DN","base","objectclass=nsSNMP");
+ if ($entry) {
+ my $res = $conn->update($old_entry);
+ if ($res) {
+ printTrace("\n$DN updated !",2);
+ }
+ else {
+ printMsg("\nFailed to update $DN");
+ }
+ }
+ else {
+ printMsg("\nUnable to get info under $DN");
+ }
+ last SWITCH;
+ }
+ # migrate the entrie: cn=encryption,cn=config
+ if ($DN =~ /cn=encryption,cn=config$/i) {
+ if ($conn->search("$DN","base","objectclass=*")) {
+ if ($old_entry->hasValue("objectClass", "nsEncryptionConfig")) {
+ my $certfile = "alias/slapd-" . $newname . "-cert8.db";
+ my $keyfile = "alias/slapd-" . $newname. "-key3.db";
+ $old_entry->setValues("nsCertfile",$certfile) if ! $old_entry->hasValue("nsCertfile",$certfile);
+ $old_entry->setValues("nsKeyfile",$keyfile) if ! $old_entry->hasValue("nsKeyfile",$keyfile);
+ }
+ my $res = $conn->update($old_entry);
+ if ($res) {
+ printTrace("\n$DN updated !",2);
+ }
+ else {
+ printMsg("\nFailed to update $DN");
+ }
+ }
+ else {
+ my $res = $conn->add($old_entry);
+ if ($res) {
+ printTrace("\n$DN added !",2);
+ }
+ else {
+ printMsg("\nFailed to add $DN");
+ }
+ }
+ last SWITCH;
+ }
+ if (@{$old_entry->{aci}} && (! ($DN =~ /^cn=monitor$/i)) && (! ($DN =~ /^cn=schema$/i))) {
+ # migrate aci's
+ my $entry = $conn->search("$DN","base","objectclass=*");
+ if ($entry) {
+ my $res = $conn->update($old_entry);
+ if ($res) {
+ printTrace("\n$DN updated !",2);
+ }
+ else {
+ printMsg("\nFailed to update $DN");
+ }
+ }
+ else {
+ my $res = $conn->add($old_entry);
+ if ($res) {
+ printTrace("\n$DN added !",2);
+ }
+ else {
+ printMsg("\nFailed to add $DN");
+ }
+ }
+ last SWITCH;
+ }
+ }
+ }
+ close(DSELDIF);
+}
+#############################################################################
+# migrate SSL info
+
+sub MigrateSSL {
+ my $secPwd = 'bidon' ;
+ # copy the SSL directory
+ &copyDir("$oldHome${PATHSEP}ssl","$serverHome${PATHSEP}ssl");
+ # copy the cert db and key files
+ if ( -d "$oldDir${PATHSEP}alias") {
+ $aliasDir = "$root${PATHSEP}alias";
+ if (! -d $aliasDir) {
+ mkdir($aliasDir, 0750);
+ }
+ &stopServer($root,'slapd-'.$newname);
+ my $keydb = "$aliasDir${PATHSEP}slapd-$newname-key3.db" ;
+ my $certdb = "$aliasDir${PATHSEP}slapd-$newname-cert8.db" ;
+ my $certdb7 = "$aliasDir${PATHSEP}slapd-$newname-cert7.db" ;
+ my $old_keydb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-key3.db" ;
+ my $old_certdb = "$oldDir${PATHSEP}alias${PATHSEP}slapd-$oldname-cert7.db";
+ my $keydb_backup = "$aliasDir${PATHSEP}slapd-$newname-key3.db_backup" ;
+ my $certdb_backup = "$aliasDir${PATHSEP}slapd-$newname-cert7.db_backup" ;
+ if (-f $old_keydb) {
+ if (-f $keydb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$keydb already exists. backup in $keydb_backup ...");
+ &copyBinFile($keydb,$keydb_backup);
+ &copyBinFile($old_keydb,$keydb);
+ }
+ else {
+ print("\n\n$keydb already exists. Do you want to overwrite it ? [no]: ");
+ my $answer = <STDIN> ;
+ if ($answer =~ /^y|yes$/i) {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ if (-f $old_certdb) {
+ $mode = (stat($old_certdb))[2] if $PRESERVE;
+ if (-f $certdb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$certdb already exists. backup in $certdb_backup ...");
+ &copyBinFile($certdb,$certdb_backup);
+ unlink($certdb) || print "Couldn't delete $certdb : $!\n";
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ else {
+ print("\n\n$certdb already exists. Do you want to overwrite it ? [no]: ");
+ my $answer = <STDIN> ;
+ if ($answer =~ /^y|yes$/i) {
+ unlink($certdb) || print "Couldn't delete $certdb : $!\n";
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ # copy the old password file
+ if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") {
+ &copyBinFile(
+ "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt",
+ "$aliasDir${PATHSEP}$type-$newname-pin.txt"
+ );
+ }
+ &startServer();
+ if ($PRESERVE) {
+ chown($newuid,$newgid,$certdb) || print "Failed to set uid $newuid gid $newgid on $certdb : $!\n";
+ chmod($mode,$certdb) || print "Failed to set mode $mode on $certdb : $!\n";
+ }
+ }
+
+}
+
+sub DisableSSL {
+ my $entry = $conn->search("cn=config","base","objectclass=*");
+ my $LDAPparam = "nsslapd-security" ;
+ my $Value = "off" ;
+ if ($entry->{$LDAPparam}[0] ne $Value) {
+ printTrace("\nDisable SSL...",1);
+ $entry->setValues($LDAPparam, $Value);
+ }
+ my $res = $conn->update($entry);
+ if ($res) {
+ printTrace("\nSSL disabled",2);
+ }
+ else {
+ printMsg("\nCan't disable SSL, the server may have problems starting");
+ }
+}
+
+# enable the migration of client authentication informations
+sub MigrateCertmap {
+ # backup the old new certmap.conf and replace it with the old certmap.conf file
+ my $oldCertmap = "$oldDir${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf";
+ my $newCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf" ;
+ my $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ;
+ if (&hasChangedoldCertmap($oldCertmap)) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$newCertmap has been backup in $backupCertmap");
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($oldCertmap,$newCertmap);
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\n\nWhere do you want to back up the file $newCertmap [$backupCertmap] ?") ;
+ my $Answer = <STDIN> ;
+ $backupCertmap = $Answer if ($Answer ne "\n");
+ chomp($backupCertmap);
+ printTrace("\nDest: .$backupCertmap.",4);
+ if (-e $backupCertmap) {
+ printMsg("\n\n$backupCertmap already exists. Do you want to overwrite it Yes/No [No] ?") ;
+ if (<STDIN> =~ /yes|y/i) {
+ $Ask = 0 ;
+ }
+ else {
+ $backupCertmap = "$root${PATHSEP}shared${PATHSEP}config${PATHSEP}certmap.conf_backup" ;
+ }
+ }
+ else {
+ $Ask = 0 ;
+ }
+ }
+ printTrace("\nBackup file: $newCertmap in $backupCertmap",4);
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($oldCertmap,$newCertmap);
+ }
+ }
+ else {
+ }
+}
+
+sub hasChangedoldCertmap {
+ my $certmapfile = shift ;
+ my @reference = ("certmap default default",
+ "default:DNComps",
+ "default:FilterComps e") ;
+ my $cpt = 0 ;
+ printTrace("\nhasChangedoldCertmap",3);
+ open(CERTMAP,"< $certmapfile");
+ while (<CERTMAP>) {
+ if ((! /^\s*#/) && (! /^\s*$/)) {
+ my $ref = $reference[$cpt] ;
+ printTrace("\nValue: $_, ref: $ref",4);
+ if (! /^\s*$ref\s*$/) {
+ return 1 ;
+ }
+ else {
+ $cpt++ ;
+ }
+ }
+ }
+ close (CERTMAP);
+ printTrace("\ncpt: $cpt",4);
+ if ($cpt < $#reference) {
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+}
+#############################################################################
+# copy a directory to another
+
+sub copyDir {
+ my $src = shift;
+ my $dest = shift;
+ my $exclude = shift;
+
+ opendir( SRC, $src ) or die "Can't open directory $src: $!: ";
+ my $mode;
+ my $uid;
+ my $gid;
+ mkdir ( $dest , 0755 ) or die "\nCan't create directory $dest. \nPlease check you have enough rights to create it and/or check that your parent directory exists.\n" if !( -e $dest );
+ if ($PRESERVE) {
+ $mode = (stat($src))[2];
+ ($uid, $gid) = (stat(_))[4..5];
+ # Make sure files owned by the old user are owned by the
+ # new user
+ if ($uid == $olduid) {
+ $uid = $newuid;
+ $gid = $newgid;
+ }
+ chown $uid, $gid, $dest;
+ chmod $mode, $dest;
+ }
+ local ( @files ) = readdir ( SRC );
+ closedir( SRC );
+ for ( @files ) {
+ if ( $_ eq "." || $_ eq ".." ) {
+ next;
+ } elsif ( $exclude && /$exclude/ ) {
+ next;
+ } elsif( -d "$src${PATHSEP}$_") {
+ &copyDir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" );
+ } else {
+ &copyBinFile ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_");
+ }
+ }
+}
+
+sub copyBinFile {
+ my $src = shift;
+ my $dest = shift;
+ my $buf = "";
+ my $bufsize = 8192;
+
+ open( SRC, $src ) || die "Can't open $src: $!\n";
+ # if we are given a directory destination instead of a file, extract the
+ # filename portion of the source to use as the destination filename
+ if (-d $dest) {
+ $dest = $dest . $PATHSEP . &basename($src);
+ }
+ open( DEST, ">$dest" ) || die "Can't create $dest: $!\n";
+ binmode SRC;
+ binmode DEST;
+ if ($PRESERVE) {
+ $mode = (stat($src))[2];
+ ($uid, $gid) = (stat(_))[4..5];
+ # Make sure files owned by the old user are owned by the
+ # new user
+ if ($uid == $olduid) {
+ $uid = $newuid;
+ $gid = $newgid;
+ }
+ chown $uid, $gid, $dest;
+ chmod $mode, $dest;
+ }
+ while (read(SRC, $buf, $bufsize)) {
+ print DEST $buf;
+ }
+ close( SRC );
+ close( DEST );
+}
+#############################################################################
+# backup new configuration files
+# backup the directory <new_root_server>/slapd-instance/config in <new_root_server>/slapd-instance/BackupConfig
+
+sub backupConfigFiles {
+ # backup the new config files
+ my $src = "$serverHome${PATHSEP}config" ;
+ my $dest = "$serverHome${PATHSEP}config_backup" ;
+ if ($NO_INPUT_USER) {
+ printMsg("\n$src has been backup in $dest");
+ &copyDir($src,$dest);
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\n\nWhere do you want to back up your configuration directory [$dest] ?") ;
+ my $Answer = <STDIN> ;
+ $dest = $Answer if ($Answer ne "\n");
+ chomp($dest);
+ printTrace("\nDest: .$dest.",4);
+ if (-e $dest) {
+ printMsg("\n\n$dest already exists. Do you want to overwrite it Yes/No [No] ?") ;
+ if (<STDIN> =~ /yes|y/i) {
+ $Ask = 0 ;
+ }
+ else {
+ $dest = "$serverHome${PATHSEP}config_backup" ;
+ }
+ }
+ else {
+ $Ask = 0 ;
+ }
+ }
+ printTrace("\nBackup Directory: $src in $dest",4);
+ &copyDir($src,$dest);
+ }
+}
+#############################################################################
+
+sub getLDAPservername {
+ my $oldLDAPservername;
+ my $LDAPservername;
+ open(OLDSLAPDCONF, $oldSlapdConf) or
+ die "\nError: could not open old config file $oldSlapdConf \n";
+ while(<OLDSLAPDCONF>) {
+ chop;
+ if (/^localhost\s+/i) {
+ ($oldLDAPservername = $') =~ s/^[\"]//;;
+ $oldLDAPservername =~ s/[\"]$//;
+ printTrace("\nName of the old LDAP server: $oldLDAPservername",3);
+ }
+ }
+ close(OLDSLAPDCONF);
+
+ open( DSELDIF, "< $DSEldif" ) || die "\nCan't open $DSEldif \n";
+ my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ;
+ while ($entry = readOneEntry $in) {
+ my $DN = $entry->getDN() ;
+ if ($DN =~ /^cn=config$/i) {
+ my $localhost = "nsslapd-localhost";
+ my @values = $entry->getValues($localhost);
+ if ($#values != -1) {
+ $LDAPservername = $values[0];
+ }
+ break;
+ }
+ }
+ close(DSELDIF);
+ # check old and new are installed on the same physical machine.
+ if (lc($oldLDAPservername) ne lc($LDAPservername)) {
+ # warn the user he tries to migrate a old server installed on a different machine from the new one
+ printMsg("\n\nYour old server is on $oldLDAPservername, and your new server is on $LDAPservername. We don't support migration on different machines. Do you want to continue ? Yes/No [No]:") ;
+ if (! (<STDIN> =~ /yes|y/i)) {
+ return -1;
+ }
+ }
+ return $LDAPservername ;
+}
+
+#############################################################################
+
+sub getLibPath {
+ my $myDir = shift;
+ my $myVersion = shift;
+ my $myMinor = shift;
+
+ if ($isNT) {
+ return $ENV{"$LIB_PATH"};
+ }
+ if (($myVersion >= 6) && ($myMinor >= 2)) {
+ return
+ "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}".
+ "$myDir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}".
+ $ENV{"$LIB_PATH"};
+ } else {
+ return "$myDir${PATHSEP}lib${SEP}".$ENV{"$LIB_PATH"};
+ }
+}
+
+#############################################################################
+
+sub getVersion {
+ my $dir = shift;
+ my $versionstr = shift;
+ my $version = 0;
+ my $minor = 0;
+ my $buildNumber = 0;
+ my $progDir = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${PATHSEP}";
+ my $progDir2 = "${PATHSEP}bin${PATHSEP}slapd${PATHSEP}";
+
+ # find the slapd executable
+ if (!$versionstr) { # version not specified on cmd line - find it
+ $prog = $dir . $progDir . $slapdExecName;
+ if (! -f $prog) {
+ $prog = $dir . $progDir2 . $slapdExecName;
+ if (-f $prog && $isNT) {
+ # if slapd is in bin/slapd and we're on NT, just assume version 1;
+ # apparently, slapd.exe doesn't like the -v argument . . .
+ return ( '1', $minor );
+ }
+ else{
+ die "Could not run slapd program $prog: $!";
+ }
+ }
+ else {
+ chdir($dir . $progDir);
+ }
+ $cur_libpath=$ENV{"$LIB_PATH"};
+ $ENV{"$LIB_PATH"}=
+ "$dir${PATHSEP}lib${SEP}".
+ "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}lib${SEP}".
+ "$dir${PATHSEP}bin${PATHSEP}slapd${PATHSEP}server${SEP}".
+ $ENV{"$LIB_PATH"};
+ # read the old version from the old slapd program
+
+ open(F, "${quote}${quote}$prog${quote} -v${quote} 2>&1 |") or
+ die "Could not run slapd program $prog: $!";
+ sleep(1); # allow some data to accumulate in the pipe
+# print "Output from $prog -v:\n";
+ while (<F>) {
+ if (/^Netscape-Directory/ || /^iPlanet-Directory/i) {
+ $versionstr = $_;
+ last;
+ }
+ }
+ $code = close(F);
+ # print "$prog returned code=$code status=$?\n";
+ $ENV{"$LIB_PATH"}=$cur_libpath;
+ }
+
+ if ($versionstr =~ /^Netscape-Directory\/(\d+)\.(\d+)(?:b\d)*\s+(\S+)/) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ }
+ elsif ($versionstr =~ /^Netscape-Directory\(restrict?ed-mode\)\/(\d+)\.(\d+)\s+(\S+)/) { # we can have restricted-mode or restriced-mode ...
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ }
+ elsif ($versionstr =~ /^iPlanet-Directory\/(\d+)\.(\d+)\s+(\S+)/i) {
+ $version = $1;
+ $minor = $2;
+ $buildNumber = $3;
+ } elsif ($versionstr =~ /(\d+)\.(\d+)/) {
+ $version = $1;
+ $minor = $2;
+ }
+
+ if ($version == 0) {
+ die "\nCould not determine version of the directory server in $dir: \n";
+ }
+
+ # distinguish the 4.1 and the 4.11 thanks to the buildNumber
+ if (($version == 4) && ($minor == 1)){
+ if (! ($buildNumber =~ /^B99\.16/)) {
+ # it's not a 4.1 Netscape Directory Server => it's a 4.11
+ $minor = 11 ;
+ }
+ }
+ chdir($curdir) or die "Could not change directory to $curdir: $!" ;
+ return ( $version, $minor );
+}
+
+#############################################################################
+
+sub getDiff {
+ # we get references to arrays
+ my $elements = shift ;
+ my $existing_elements = shift ;
+ my %count = () ;
+ my %countEE = () ;
+ @diff = () ;
+ foreach $e (@{$elements}, @{$existing_elements}) { $count{$e}++ ;}
+ foreach $e (@{existing_elements}) { $countEE{$e}++ ;}
+ foreach $e (@{$elements}) {
+ # if $e is only present in @$elements, we push it to the diff array
+ if (($count{$e} == 1) && ($countEE{$e} == 0)) {
+ push @diff, $e ;
+ }
+ }
+ return @diff ;
+}
+
+###############################################################################################
+sub testIndexUpdating {
+ #my $entry = $conn->newEntry();
+ #$entry->setDN("cn=djeattribute,cn=index,cn=MigratedDB_5,cn=ldbm database,cn=plugins,cn=config");
+ my $entry = $conn->search("cn=mail,cn=index,cn=MigratedDB_2,cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex");
+ my @types = ("pres", "sub", "eq") ;
+ my @existing_types = $entry->getValues("nsindextype");
+ my @typesToAdd = &getDiff(\@types, \@existing_types);
+ foreach $newtype (@typesToAdd) {
+ $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2);
+ }
+ my $res = $conn->update($entry) ;
+ if ($res) {print("\nUpdate index mail\n");}
+ else { print("\ncan't update index mail");}
+
+ $entry = $conn->search("cn=givenName,cn=index,cn=MigratedDB_2,cn=ldbm database,cn=plugins,cn=config","base","objectclass=nsIndex");
+ @types = ("pres", "sub", "eq") ;
+ @existing_types = $entry->getValues("nsindextype"); print("\ngivenName, existing_types: @existing_types");
+ @typesToAdd = &getDiff(\@types, \@existing_types); print("\nTypesToAdd: @typesToAdd");
+ foreach $newtype (@typesToAdd) {
+ $entry->addValue("nsindextype", $newtype); printTrace("\nnewtype: $newtype",2);
+ }
+ my $res = $conn->update($entry) ;
+ if ($res) {print("\nUpdate index givenName\n");}
+ else { print("\ncan't update index givenName");}
+ }
+
+
+###############################################################################################
+sub normalizeDir {
+ my $dir = shift ;
+ my $dir_prec = "" ;
+ while ($dir_prec ne $dir) {
+ $dir_prec = $dir ;
+ if ($isNT) {
+ grep { s@\\\\@\\@g } $dir ;
+ }
+ else {
+ grep { s@//@/@g } $dir ;
+ }
+ }
+ return $dir ;
+}
+
+
+###############################################################################################
+# return 1 if the value parameters is
+sub isAllowedPlugin {
+ my $Value = lc(shift) ;
+ if ($allowedPlugins{$Value}) {
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+
+}
+
+
+sub getSyntaxOid {
+ my $Value = lc(shift) ;
+ return $allowedPlugins{$Value} ;
+}
+
+###############################################################################################
+# return 1 if the value given in parameters is an allowed modifier
+sub isAllowedModifier {
+ my $Value = lc(shift) ;
+ if ($allowedModifiers{$Value}) {
+ return 1 ;
+ }
+ else {
+ return 0 ;
+ }
+}
+
+sub getModifierValue {
+ my $Value = lc(shift) ;
+ return $allowedModifiers{$Value} ;
+}
+
+###############################################################################################
+
+sub GetTime {
+ my $tm = localtime;
+ (my $sec, my $min, my $hour, my $dd, my $mm, my $yy) = ($tm->sec, $tm->min, $tm->hour, $tm->mday, ($tm->mon)+1, ($tm->year)+1900);
+ $sec = "0$sec" unless $sec > 9 ;
+ $min = "0$min" unless $min > 9 ;
+ $hour = "0$hour" unless $hour > 9 ;
+ $dd = "0$dd" unless $dd > 9 ;
+ $mm = "0$mm" unless $mm > 9 ;
+ return ($sec, $min, $hour, $dd, $mm, $yy);
+}
+
+###############################################################################################
+# get uid and group id of the new slapd server.
+# The uid is done through the nsslapd-localuser attribute
+
+sub getuid_gid {
+ my $newuid ;
+ my $newgid ;
+ my $localuser ;
+ my $localuser_attr = "nsslapd-localuser" ;
+ if (! $isNT) {
+ my $entry = $conn->search("cn=config ", "base","objectclass=*", 0, ($localuser_attr)) ;
+ # Tests wether we succeed to get the entry cn=config
+ die "\nCan't get the entry cn=config \n" unless ($entry);
+ my @values = $entry->getValues($localuser_attr);
+ if ($#values == -1 || ($values[0] eq "") ) { # tests wether the nsslapd-localuser attribute has a value
+ printMsg("\nNo localuser has been found in the configuration of the directory. ");
+ if ($NO_INPUT_USER) {
+ printMsg("\nWe considered nobody as the localuser");
+ $localuser = "nobody" ;
+ }
+ else {
+ my $Ask = 1 ;
+ while ($Ask) {
+ printMsg("\nUnder what user does your $Version.$Minor directory server run [nobody] ? ") ;
+ $localuser = <STDIN> ;
+ chomp($localuser);
+ $localuser = "nobody" if ($localuser eq "");
+ ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ;
+ if ($newuid) {
+ $Ask = 0 ;
+ }
+ else {
+ printMsg("\nError: $localuser is unknown from the system ");
+ }
+ }
+ }
+ }
+ else {
+ $localuser = $values[0]; # returns the first value (we should only have one localuser)
+ my $size = $#values ;
+ }
+ ($newuid, $newgid) = (getpwnam("$localuser"))[2..3] ;
+ return ($localuser, $newuid, $newgid) ;
+ }
+ else {
+ return () ;
+ }
+}
+
+
+###############################################################################################
+# get uid and group id of the old slapd server.
+
+sub getolduid_gid {
+ my $oldlocaluser ;
+ if (! $isNT) {
+ open(CONF, $oldSlapdConf) or die "\nError: cannot open $oldSlapdConf: $!\n";
+ while (<CONF>) {
+ if (/^localuser\s+/i) {
+ chomp($oldlocaluser = $');
+ last;
+ }
+ }
+ close(CONF);
+ ($olduid, $oldgid) = (getpwnam("$oldlocaluser"))[2..3] ;
+ return ($oldlocaluser, $olduid, $oldgid) ;
+ }
+ else {
+ return ();
+ }
+}
+
+###############################################################################################
+# get current directory
+
+sub getCwd {
+ my $command = $isNT ? "cd" : "/bin/pwd";
+ open(PWDCMD, "$command 2>&1 |") or
+ die "Error: could not execute $command: $!";
+ # without the following sleep, reading from the pipe will
+ # return nothing; I guess it gives the pwd command time
+ # to get some data to read . . .
+ sleep(1);
+ my $currentdir;
+ while (<PWDCMD>) {
+ if (!$currentdir) {
+ chomp($currentdir = $_);
+ }
+ }
+ my $code = close(PWDCMD);
+# if ($code || $?) {
+# print "$command returned code=$code status=$? dir=$curdir\n";
+# }
+# print "getCwd curdir=\[$curdir\]\n";
+ return $currentdir;
+}
diff --git a/ldap/admin/src/scripts/template-ns-accountstatus.pl b/ldap/admin/src/scripts/template-ns-accountstatus.pl
new file mode 100644
index 00000000..5913f7ad
--- /dev/null
+++ b/ldap/admin/src/scripts/template-ns-accountstatus.pl
@@ -0,0 +1,813 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+###############################
+# SUB-ROUTINES
+###############################
+
+sub usage_and_exit
+{
+ print (STDERR "$cmd [-D rootdn] { -w password | -w - | -j filename } \n");
+ print (STDERR " [-p port] [-h host] -I DN-to-$operation\n\n");
+ print (STDERR "May be used to $operation a user or a domain of users\n\n");
+ print (STDERR "Arguments:\n");
+ print (STDERR " -? - help\n");
+ print (STDERR " -D rootdn - Provide a Directory Manager DN. Default= '$defrootdn'\n");
+ print (STDERR " -w password - Provide a password for the Directory Manager DN\n");
+ print (STDERR " -w - - Prompt for the Directory Manager's password\n");
+ print (STDERR " -j filename - Read the Directory Manager's password from file\n");
+ print (STDERR " -p port - Provide a port. Default= '$defport'\n");
+ print (STDERR " -h host - Provide a host name. Default= '$defhost'\n");
+ print (STDERR " -I DN-to-$operation - Single entry DN or role DN to $operation\n");
+ exit 100;
+}
+
+sub debug
+{
+# print " ==> @_";
+}
+
+sub out
+{
+ print "@_";
+}
+
+# --------------------------
+# Check if the entry is part of a locked role:
+# i.e.: for each role member (nsroledn) of nsdisabledrole, check if
+# * it is the same as the entry
+# * the entry is member of role (==has nsroledn attributes), compare each of
+# them with the nsroledn of nsdisabledrole
+# * if nsroledn of nsdisabledrole are complex, go through each of them
+# argv[0] is the local file handler
+# argv[1] is the entry (may be a single entry DN or a role DN)
+# argv[2] is the base for the search
+# --------------------------
+
+$throughRole="";
+
+sub indirectLock
+{
+ # For recursivity, file handler must be local
+ my $L_filehandle=$_[0];
+ $L_filehandle++;
+
+ my $L_entry=$_[1];
+ # Remove useless space
+ my @L_intern=split /([,])/,$L_entry;
+ my $L_result="";
+ foreach $L_part (@L_intern)
+ {
+ $L_part=~s/^ +//;
+ $L_part=~ tr/A-Z/a-z/;
+ $L_result="$L_result$L_part";
+ }
+ $L_entry=$L_result;
+
+ my $L_base=$_[2];
+
+ my $L_search;
+ my $L_currentrole;
+ my $L_retCode;
+
+ my $L_local;
+
+`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsroledn >> {{DEV-NULL}} 2>&1 `;
+$retCode=$?;
+if ( $retCode != 0 )
+{
+ $retCode=$?>>8;
+ return 1;
+}
+
+ # Check if the role is a nested role
+ @L_Nested="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=nsNestedRoleDefinition)(objectclass=ldapsubentry))\" ";
+ # L_isNested == 1 means that we are going through a nested role, so for each member of that
+ # nested role, check that the member is below the scope of the nested
+ $L_isNested=@L_Nested;
+
+ # Not Direct Lock, Go through roles if any
+ $L_search="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsroledn ";
+
+ debug("\t-->indirectLock: check if $L_entry is part of a locked role from base $L_base\n\n");
+
+ unless (open ($L_filehandle, "$L_search |"))
+ {
+ out("Can't open file $L_filehandle\n");
+ exit;
+ }
+ while (<$L_filehandle>) {
+
+ s/\n //g;
+ if (/^nsroledn: (.*)\n/) {
+ $L_currentrole = $1;
+
+ # Remove useless space
+ my @L_intern=split /([,])/,$L_currentrole;
+ my $L_result="";
+ foreach $L_part (@L_intern)
+ {
+ $L_part=~s/^ +//;
+ $L_part=~ tr/A-Z/a-z/;
+ $L_result="$L_result$L_part";
+ }
+ $L_currentrole=$L_result;
+
+ debug("\t-- indirectLock loop: current nsroledn $L_currentrole of base $L_base\n");
+ if ( $L_isNested == 1 )
+ {
+ if ( checkScope($L_currentrole, $L_base) == 0 )
+ {
+ # Scope problem probably a bad conf, skip the currentrole
+ next;
+ }
+ }
+
+ if ( $L_currentrole eq $L_entry )
+ {
+ # the entry is a role that is directly locked
+ # i.e, nsroledn of nsdisabledrole contains the entry
+ $throughRole=$L_base;
+ $throughRole=~ tr/A-Z/a-z/;
+
+ # skipDisabled means that we've just found that the entry (which is a role)
+ # is locked directly (==its DN is part of nsroledn attributes)
+ # we just want to know now, if it is locked through another role
+ # at least, one
+ if ( $skipDisabled == 1 )
+ {
+ # direct inactivation
+ $directLocked=1;
+ # just go through that test once
+ $skipDisabled=0;
+ next;
+ }
+ debug("\t-- 1 indirectLock: $L_currentrole locked throughRole == $throughRole\n");
+ return 0;
+ }
+
+ $L_retCode=memberOf($L_currentrole, $L_entry);
+ if ( $L_retCode == 0 && $single == 1 )
+ {
+ $throughRole=$L_currentrole;
+ $throughRole=~ tr/A-Z/a-z/;
+ if ( $skipManaged == 1 )
+ {
+ if ( $L_currentrole eq $nsManagedDisabledRole)
+ {
+ # Try next nsroledn
+ $directLocked=1;
+ $skipManaged=0;
+ next;
+ }
+ }
+ debug("\t-- 2 indirectLock: $L_currentrole locked throughRole == $throughRole\n");
+ return 0;
+ }
+
+ # Only for the first iteration
+ # the first iteration is with nsdisabledrole as base, other
+ # loops are deeper
+ $L_local=$skipDisabled;
+ $skipDisabled=0;
+
+ # the current nsroledn may be a complex role, just go through
+ # its won nsroledn
+ $L_retCode=indirectLock($L_filehandle,$L_entry, $L_currentrole);
+
+ # Because of recursivity, to keep the initial value for the first level
+ $skipDisabled=$L_local;
+
+ if ( $L_retCode == 0 )
+ {
+ $throughRole=$L_currentrole;
+ $throughRole=~ tr/A-Z/a-z/;
+ debug("\t-- 3 indirectLock: $L_entry locked throughRole == $throughRole\n");
+ return 0;
+ }
+ }
+ }
+
+ close($L_filehandle);
+
+ debug("\t<--indirectLock: no more nsroledn to process\n");
+ return 1;
+}
+
+# --------------------------
+# Check if nsroledn is part of the entry attributes
+# argv[0] is a role DN (nsroledn attribute)
+# argv[1] is the entry
+# --------------------------
+sub memberOf
+{
+ my $L_nsroledn=$_[0];
+ $L_nsroledn=~ tr/A-Z/a-z/;
+
+ my $L_entry=$_[1];
+
+ my $L_search;
+ my $L_currentrole;
+
+ $L_search="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_entry\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsrole";
+
+ debug("\t\t-->memberOf: $L_search: check if $L_entry has $L_nsroledn as nsroledn attribute\n");
+
+ open (LDAP2, "$L_search |");
+ while (<LDAP2>) {
+ s/\n //g;
+ if (/^nsrole: (.*)\n/) {
+ $L_currentrole = $1;
+ $L_currentrole=~ tr/A-Z/a-z/;
+ if ( $L_currentrole eq $L_nsroledn )
+ {
+ # the parm is part of the $L_entry nsroledn
+ debug("\t\t<--memberOf: $L_entry locked through $L_nsroledn\n");
+ return 0;
+ }
+ }
+ }
+ close(LDAP2);
+
+ # the parm is not part of the $L_entry nsroledn
+ debug("\t\t<--memberOf: $L_entry not locked through $L_nsroledn\n");
+ return 1;
+}
+
+
+# --------------------------
+# Remove the rdn of a DN
+# argv[0] is a DN
+# --------------------------
+sub removeRdn
+{
+ $L_entry=$_[0];
+
+ @L_entryToTest=split /([,])/,$L_entry;
+ debug("removeRdn: entry to split: $L_entry**@L_entryToTest\n");
+
+ $newDN="";
+ $removeRDN=1;
+ foreach $part (@L_entryToTest)
+ {
+ $part=~ s/^ +//;
+ $part=~ tr/A-Z/a-z/;
+ if ( $removeRDN <= 2 )
+ {
+ $removeRDN=$removeRDN+1;
+ }
+ else
+ {
+ $newDN="$newDN$part";
+ }
+ }
+
+ debug("removeRdn: new DN **$newDN**\n");
+}
+
+# --------------------------
+# Check if L_current is below the scope of
+# L_nestedRole
+# argv[0] is a role
+# argv[1] is the nested role
+# --------------------------
+sub checkScope
+{
+ $L_current=$_[0];
+ $L_nestedRole=$_[1];
+
+ debug("checkScope: check if $L_current is below $L_nestedRole\n");
+
+ removeRdn($L_nestedRole);
+ $L_nestedRoleSuffix=$newDN;
+ debug("checkScope: nested role based: $L_nestedRoleSuffix\n");
+
+ $cont=1;
+ while ( ($cont == 1) && ($L_current ne "") )
+ {
+ removeRdn($L_current);
+ $currentDn=$newDN;
+ debug("checkScope: current DN to check: $currentDn\n");
+
+ if ( $currentDn eq $L_nestedRoleSuffix )
+ {
+ debug("checkScope: DN match!!!\n");
+ $cont = 0;
+ }
+ else
+ {
+ $L_current=$currentDn;
+ }
+ }
+
+ if ( $cont == 1 )
+ {
+ debug("checkScope: $_[0] and $_[1] are not compatible\n");
+ return 0;
+ }
+ else
+ {
+ debug("checkScope: $_[0] and $_[1] are compatible\n");
+ return 1;
+ }
+}
+
+
+###############################
+# MAIN ROUTINE
+###############################
+
+# Generated variable
+$dsroot="{{DS-ROOT}}";
+
+# Determine which command we are running
+if ( $0 =~ /ns-inactivate(.pl)?$/ )
+{
+ $cmd="ns-inactivate.pl";
+ $operation="inactivate";
+ $state="inactivated";
+ $modrole="add";
+ $already="already";
+}
+elsif ( $0 =~ /ns-activate(.pl)?$/ )
+{
+ $cmd="ns-activate.pl";
+ $operation="activate";
+ $state="activated";
+ $modrole="delete";
+ $already="already";
+}
+elsif ( $0 =~ /ns-accountstatus(.pl)?$/ )
+{
+ $cmd="ns-accountstatus.pl";
+ $operation="get status of";
+ $state="activated";
+ # no need for $modrole as no operation is performed
+ $already="";
+
+}
+else
+{
+ out("$0: unknown command\n");
+ exit 100;
+}
+
+debug("Running ** $cmd ** $operation\n");
+
+$dsbinroot="$dsroot{{SEP}}shared{{SEP}}bin";
+$ldapsearch="$dsbinroot{{SEP}}ldapsearch -1";
+$ldapmodify="$dsbinroot{{SEP}}ldapmodify";
+
+# Default values
+$defrootdn= "{{ROOT-DN}}";
+$defhost= "{{SERVER-NAME}}";
+$defport= "{{SERVER-PORT}}";
+
+# User values
+$rootdn= "{{ROOT-DN}}";
+$rootpw= "";
+$pwfile= "";
+$host= "{{SERVER-NAME}}";
+$port= "{{SERVER-PORT}}";
+$entry= "";
+
+$single=0;
+$role=0;
+
+chdir("$dsbinroot");
+
+# Process the command line arguments
+while( $arg = shift)
+{
+ if($arg eq "-?")
+ {
+ usage_and_exit();
+ }
+ elsif($arg eq "-D")
+ {
+ $rootdn= shift @ARGV;
+ }
+ elsif($arg eq "-w")
+ {
+ $rootpw= shift @ARGV;
+ }
+ elsif($arg eq "-j")
+ {
+ $pwfile= shift @ARGV;
+ }
+ elsif($arg eq "-p")
+ {
+ $port= shift @ARGV;
+ }
+ elsif($arg eq "-h")
+ {
+ $host= shift @ARGV;
+ }
+ elsif($arg eq "-I")
+ {
+ $entry= shift @ARGV;
+ }
+ else
+ {
+ print "$arg: Unknown command line argument.\n";
+ usage_and_exit();
+ }
+}
+
+if ($pwfile ne ""){
+# Open file and get the password
+ unless (open (RPASS, $pwfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $rootpw = <RPASS>;
+ chomp($rootpw);
+ close(RPASS);
+} elsif ($rootpw eq "-"){
+# Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $rootpw = ReadLine(0);
+# chomp($rootpw);
+# ReadMode('normal');
+}
+
+if( $rootpw eq "" )
+{
+ usage_and_exit();
+}
+
+if( $entry eq "" )
+{
+ usage_and_exit();
+}
+
+#
+# Check the actual existence of the entry to inactivate/activate
+# and at the same time, validate the various parm: port, host, rootdn, rootpw
+#
+@exist=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(objectclass=*)\" dn`;
+$retCode1=$?;
+if ( $retCode1 != 0 )
+{
+ $retCode1=$?>>8;
+ exit $retCode1;
+}
+
+@isRole=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(&(objectclass=LDAPsubentry)(objectclass=nsRoleDefinition))\" dn`;
+$nbLineRole=@isRole;
+$retCode2=$?;
+if ( $retCode2 != 0 )
+{
+ $retCode2=$?>>8;
+ exit $retCode2;
+}
+
+if ( $nbLineRole == 1 )
+{
+ debug("Groups of users\n");
+ $role=1;
+}
+else
+{
+ debug("Single user\n");
+ $single=1;
+}
+
+#
+# First of all, check the existence of the nsaccountlock attribute in the entry
+#
+$isLocked=0;
+if ( $single == 1 )
+{
+ $searchAccountLock="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(objectclass=*)\" nsaccountlock";
+ open (LDAP1, "$searchAccountLock |");
+ while (<LDAP1>) {
+ s/\n //g;
+ if (/^nsaccountlock: (.*)\n/) {
+ $L_currentvalue = $1;
+ $L_currentvalue=~ tr/A-Z/a-z/;
+ if ( $L_currentvalue eq "true")
+ {
+ $isLocked=1;
+ }
+ elsif ( $L_currentvalue eq "false" )
+ {
+ $isLocked=0;
+ }
+ }
+ }
+ close(LDAP1);
+}
+debug("Is the entry already locked? ==> $isLocked\n");
+
+#
+# Get the suffix name of that entry
+#
+
+# Remove the space at the beginning (just in case...)
+# -I "uid=jvedder , ou=People , o=sun.com"
+@suffix=split /([,])/,$entry;
+$result="";
+foreach $part (@suffix)
+{
+ $part=~s/^ +//;
+ $part=~ tr/A-Z/a-z/;
+ $result="$result$part";
+}
+@suffixN=$result;
+
+debug("Entry to $operation: #@suffix#\n");
+debug("Entry to $operation: #@suffixN#\n");
+
+# Get the suffix
+$cont=0;
+while ($cont == 0)
+{
+ # Look if suffix is the suffix of the entry
+ # ldapsearch -s one -b "cn=mapping tree,cn=config" "cn=\"uid=jvedder,ou=People,o=sun.com\""
+ #
+ debug("\tSuffix from the entry: #@suffixN#\n");
+ @mapping=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s one -b \"cn=mapping tree, cn=config\" \"cn=\\"@suffixN\\"\" cn `;
+
+ $retCode=$?;
+ if ( $retCode != 0 )
+ {
+ $retCode=$?>>8;
+ exit $retCode;
+ }
+
+ # If we get a result, remove the dn:
+ # dn: cn="o=sun.com",cn=mapping tree,cn=config
+ # cn: "o=sun.com"
+ #
+ shift @mapping;
+
+ foreach $res (@mapping)
+ {
+ # Break the string cn: "o=sun.com" into pieces
+ @cn= split(/ /,$res);
+
+ # And remove the cn: part
+ shift @cn;
+
+ # Now compare the suffix we extract from the mapping tree
+ # with the suffix derived from the entry
+ debug("\tSuffix from mapping tree: #@cn#\n");
+ if ( @cn eq @suffixN ) {
+ debug("Found matching suffix\n");
+ $cont=1;
+ }
+ }
+
+ if ( $cont == 0 )
+ {
+ # Remove the current rdn to try another suffix
+ shift @suffix;
+
+ $result="";
+ foreach $part (@suffix)
+ {
+ $part=~ s/^ +//;
+ $part=~ tr/A-Z/a-z/;
+ $result="$result$part";
+ }
+ @suffixN=$result;
+
+ debug("\t\tNothing found => go up one level in rdn #@suffix#\n");
+ $len=@suffix;
+ if ( $len == 0 )
+ {
+ debug("Can not find suffix. Problem\n");
+ $cont=2;
+ }
+ }
+}
+if ( $cont == 2)
+{
+ out("Can not find suffix for entry $entry\n");
+ exit 100;
+}
+
+if ( $operation eq "inactivate" )
+{
+ #
+ # Now that we have the suffix and we know if we deal with a single entry or
+ # a role, just try to create the COS and roles associated.
+ #
+ @base=(
+ "cn=nsManagedDisabledRole,@suffixN",
+ "cn=nsDisabledRole,@suffixN",
+ "cn=nsAccountInactivationTmp,@suffixN",
+ "\'cn=\"cn=nsDisabledRole,@suffixN\",cn=nsAccountInactivationTmp,@suffixN\'",
+ "cn=nsAccountInactivation_cos,@suffixN" );
+
+ $addrolescos="$ldapmodify -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -c -a >> {{DEV-NULL}} 2>&1 ";
+ @role1=(
+ "dn: cn=nsManagedDisabledRole,@suffixN\n",
+ "objectclass: LDAPsubentry\n",
+ "objectclass: nsRoleDefinition\n",
+ "objectclass: nsSimpleRoleDefinition\n",
+ "objectclass: nsManagedRoleDefinition\n",
+ "cn: nsManagedDisabledRole\n\n" );
+ @role2=(
+ "dn: cn=nsDisabledRole,@suffixN\n",
+ "objectclass: top\n",
+ "objectclass: LDAPsubentry\n",
+ "objectclass: nsRoleDefinition\n",
+ "objectclass: nsComplexRoleDefinition\n",
+ "objectclass: nsNestedRoleDefinition\n",
+ "nsRoleDN: cn=nsManagedDisabledRole,@suffixN\n",
+ "cn: nsDisabledRole\n\n" );
+ @cos1=(
+ "dn: cn=nsAccountInactivationTmp,@suffixN\n",
+ "objectclass: top\n",
+ "objectclass: nsContainer\n\n" );
+ @cos2=(
+ "dn: cn=\"cn=nsDisabledRole,@suffixN\",cn=nsAccountInactivationTmp,@suffixN\n",
+ "objectclass: top\n",
+ "objectclass: extensibleObject\n",
+ "objectclass: costemplate\n",
+ "objectclass: ldapsubentry\n",
+ "cosPriority: 1\n",
+ "nsAccountLock: true\n\n" );
+ @cos3=(
+ "dn: cn=nsAccountInactivation_cos,@suffixN\n",
+ "objectclass: top\n",
+ "objectclass: LDAPsubentry\n",
+ "objectclass: cosSuperDefinition\n",
+ "objectclass: cosClassicDefinition\n",
+ "cosTemplateDn: cn=nsAccountInactivationTmp,@suffixN\n",
+ "cosSpecifier: nsRole\n",
+ "cosAttribute: nsAccountLock operational\n\n" );
+
+ @all=(\@role1, \@role2, \@cos1, \@cos2, \@cos3);
+
+ $i=0;
+
+ foreach $current (@base)
+ {
+ debug("Creating $current ??\n");
+ open(FD,"| $addrolescos ");
+ print FD @{$all[$i]};
+ close(FD);
+ if ( $? != 0 )
+ {
+ $retCode=$?>>8;
+ if ( $retCode == 68 )
+ {
+ debug("Entry $current already exists, ignore error\n");
+ }
+ else
+ {
+ # Probably a more serious problem.
+ # Exit with LDAP error
+ exit $retCode;
+ }
+ }
+ else
+ {
+ debug("Entry $current created\n");
+ }
+ $i=$i+1;
+ }
+}
+
+$skipManaged=0;
+$skipDisabled=0;
+$directLocked=0;
+
+$nsDisabledRole="cn=nsDisabledRole,@suffixN";
+$nsDisabledRole=~ tr/A-Z/a-z/;
+
+$nsManagedDisabledRole="cn=nsManagedDisabledRole,@suffixN";
+$nsManagedDisabledRole=~ tr/A-Z/a-z/;
+
+if ( $operation eq "inactivate" )
+{
+ # Go through all the roles part of nsdisabledrole to check if the entry
+ # is a member of one of those roles
+ $ret=indirectLock("LDAP00", $entry, $nsDisabledRole);
+ if ( $ret == 0 )
+ {
+ if ( $throughRole ne $nsDisabledRole && $throughRole ne $nsManagedDisabledRole )
+ {
+ # indirect lock
+ out("$entry already $state through $throughRole.\n");
+ }
+ else
+ {
+ # direct lock
+ out("$entry already $state.\n");
+ }
+ exit 100;
+ }
+ elsif ( $isLocked == 1 )
+ {
+ # the entry is not locked through a role, may be nsaccountlock is "hardcoded" ?
+ out("$entry already $state (probably directly).\n");
+ exit 103;
+ }
+}
+elsif ( $operation eq "activate" || $operation eq "get status of" )
+{
+ $skipManaged=$single;
+ $skipDisabled=$role;
+
+ $ret=indirectLock("LDAP00",$entry, $nsDisabledRole);
+
+ if ( $ret == 0 )
+ {
+ # undirectly locked
+ if ( $throughRole ne $nsDisabledRole && $throughRole ne $nsManagedDisabledRole )
+ {
+ if ( $operation eq "activate" )
+ {
+ out("$entry inactivated through $throughRole. Can not activate it individually.\n");
+ exit 100;
+ }
+ else
+ {
+ out("$entry inactivated through $throughRole.\n");
+ exit 104;
+ }
+ }
+ debug("$entry locked individually\n");
+
+ if ( $operation ne "activate" )
+ {
+ out("$entry inactivated.\n");
+ exit 103;
+ }
+ }
+ elsif ( $directLocked == 0 )
+ {
+ if ( $operation eq "activate" && $isLocked != 1 )
+ {
+ out("$entry $already $state.\n");
+ exit 100;
+ }
+ elsif ( $isLocked != 1 )
+ {
+ out("$entry $already $state.\n");
+ exit 102;
+ }
+ else
+ {
+ # not locked using our schema, but nsaccountlock is probably present
+ out("$entry inactivated (probably directly).\n");
+ exit 103;
+ }
+ }
+ elsif ( $operation ne "activate" )
+ {
+ out("$entry inactivated.\n");
+ exit 103;
+ }
+ # else Locked directly, juste unlock it!
+ debug("$entry locked individually\n");
+}
+
+#
+# Inactivate/activate the entry
+#
+$action="$ldapmodify -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -c >> {{DEV-NULL}} 2>&1";
+if ( $single == 1 )
+{
+ @record=(
+ "dn: $entry\n",
+ "changetype: modify\n",
+ "$modrole: nsRoleDN\n",
+ "nsRoleDN: cn=nsManagedDisabledRole,@suffixN\n\n" );
+}
+else
+{
+ @record=(
+ "dn: cn=nsDisabledRole,@suffixN\n",
+ "changetype: modify\n",
+ "$modrole: nsRoleDN\n",
+ "nsRoleDN: $entry\n\n" );
+}
+open(FD,"| $action ");
+print FD @record;
+close(FD);
+if ( $? != 0 )
+{
+debug("$modrole, $entry\n");
+ $retCode=$?>>8;
+ exit $retCode;
+}
+
+out("$entry $state.\n");
+exit 0;
diff --git a/ldap/admin/src/scripts/template-ns-activate.pl b/ldap/admin/src/scripts/template-ns-activate.pl
new file mode 100644
index 00000000..5913f7ad
--- /dev/null
+++ b/ldap/admin/src/scripts/template-ns-activate.pl
@@ -0,0 +1,813 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+###############################
+# SUB-ROUTINES
+###############################
+
+sub usage_and_exit
+{
+ print (STDERR "$cmd [-D rootdn] { -w password | -w - | -j filename } \n");
+ print (STDERR " [-p port] [-h host] -I DN-to-$operation\n\n");
+ print (STDERR "May be used to $operation a user or a domain of users\n\n");
+ print (STDERR "Arguments:\n");
+ print (STDERR " -? - help\n");
+ print (STDERR " -D rootdn - Provide a Directory Manager DN. Default= '$defrootdn'\n");
+ print (STDERR " -w password - Provide a password for the Directory Manager DN\n");
+ print (STDERR " -w - - Prompt for the Directory Manager's password\n");
+ print (STDERR " -j filename - Read the Directory Manager's password from file\n");
+ print (STDERR " -p port - Provide a port. Default= '$defport'\n");
+ print (STDERR " -h host - Provide a host name. Default= '$defhost'\n");
+ print (STDERR " -I DN-to-$operation - Single entry DN or role DN to $operation\n");
+ exit 100;
+}
+
+sub debug
+{
+# print " ==> @_";
+}
+
+sub out
+{
+ print "@_";
+}
+
+# --------------------------
+# Check if the entry is part of a locked role:
+# i.e.: for each role member (nsroledn) of nsdisabledrole, check if
+# * it is the same as the entry
+# * the entry is member of role (==has nsroledn attributes), compare each of
+# them with the nsroledn of nsdisabledrole
+# * if nsroledn of nsdisabledrole are complex, go through each of them
+# argv[0] is the local file handler
+# argv[1] is the entry (may be a single entry DN or a role DN)
+# argv[2] is the base for the search
+# --------------------------
+
+$throughRole="";
+
+sub indirectLock
+{
+ # For recursivity, file handler must be local
+ my $L_filehandle=$_[0];
+ $L_filehandle++;
+
+ my $L_entry=$_[1];
+ # Remove useless space
+ my @L_intern=split /([,])/,$L_entry;
+ my $L_result="";
+ foreach $L_part (@L_intern)
+ {
+ $L_part=~s/^ +//;
+ $L_part=~ tr/A-Z/a-z/;
+ $L_result="$L_result$L_part";
+ }
+ $L_entry=$L_result;
+
+ my $L_base=$_[2];
+
+ my $L_search;
+ my $L_currentrole;
+ my $L_retCode;
+
+ my $L_local;
+
+`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsroledn >> {{DEV-NULL}} 2>&1 `;
+$retCode=$?;
+if ( $retCode != 0 )
+{
+ $retCode=$?>>8;
+ return 1;
+}
+
+ # Check if the role is a nested role
+ @L_Nested="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=nsNestedRoleDefinition)(objectclass=ldapsubentry))\" ";
+ # L_isNested == 1 means that we are going through a nested role, so for each member of that
+ # nested role, check that the member is below the scope of the nested
+ $L_isNested=@L_Nested;
+
+ # Not Direct Lock, Go through roles if any
+ $L_search="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsroledn ";
+
+ debug("\t-->indirectLock: check if $L_entry is part of a locked role from base $L_base\n\n");
+
+ unless (open ($L_filehandle, "$L_search |"))
+ {
+ out("Can't open file $L_filehandle\n");
+ exit;
+ }
+ while (<$L_filehandle>) {
+
+ s/\n //g;
+ if (/^nsroledn: (.*)\n/) {
+ $L_currentrole = $1;
+
+ # Remove useless space
+ my @L_intern=split /([,])/,$L_currentrole;
+ my $L_result="";
+ foreach $L_part (@L_intern)
+ {
+ $L_part=~s/^ +//;
+ $L_part=~ tr/A-Z/a-z/;
+ $L_result="$L_result$L_part";
+ }
+ $L_currentrole=$L_result;
+
+ debug("\t-- indirectLock loop: current nsroledn $L_currentrole of base $L_base\n");
+ if ( $L_isNested == 1 )
+ {
+ if ( checkScope($L_currentrole, $L_base) == 0 )
+ {
+ # Scope problem probably a bad conf, skip the currentrole
+ next;
+ }
+ }
+
+ if ( $L_currentrole eq $L_entry )
+ {
+ # the entry is a role that is directly locked
+ # i.e, nsroledn of nsdisabledrole contains the entry
+ $throughRole=$L_base;
+ $throughRole=~ tr/A-Z/a-z/;
+
+ # skipDisabled means that we've just found that the entry (which is a role)
+ # is locked directly (==its DN is part of nsroledn attributes)
+ # we just want to know now, if it is locked through another role
+ # at least, one
+ if ( $skipDisabled == 1 )
+ {
+ # direct inactivation
+ $directLocked=1;
+ # just go through that test once
+ $skipDisabled=0;
+ next;
+ }
+ debug("\t-- 1 indirectLock: $L_currentrole locked throughRole == $throughRole\n");
+ return 0;
+ }
+
+ $L_retCode=memberOf($L_currentrole, $L_entry);
+ if ( $L_retCode == 0 && $single == 1 )
+ {
+ $throughRole=$L_currentrole;
+ $throughRole=~ tr/A-Z/a-z/;
+ if ( $skipManaged == 1 )
+ {
+ if ( $L_currentrole eq $nsManagedDisabledRole)
+ {
+ # Try next nsroledn
+ $directLocked=1;
+ $skipManaged=0;
+ next;
+ }
+ }
+ debug("\t-- 2 indirectLock: $L_currentrole locked throughRole == $throughRole\n");
+ return 0;
+ }
+
+ # Only for the first iteration
+ # the first iteration is with nsdisabledrole as base, other
+ # loops are deeper
+ $L_local=$skipDisabled;
+ $skipDisabled=0;
+
+ # the current nsroledn may be a complex role, just go through
+ # its won nsroledn
+ $L_retCode=indirectLock($L_filehandle,$L_entry, $L_currentrole);
+
+ # Because of recursivity, to keep the initial value for the first level
+ $skipDisabled=$L_local;
+
+ if ( $L_retCode == 0 )
+ {
+ $throughRole=$L_currentrole;
+ $throughRole=~ tr/A-Z/a-z/;
+ debug("\t-- 3 indirectLock: $L_entry locked throughRole == $throughRole\n");
+ return 0;
+ }
+ }
+ }
+
+ close($L_filehandle);
+
+ debug("\t<--indirectLock: no more nsroledn to process\n");
+ return 1;
+}
+
+# --------------------------
+# Check if nsroledn is part of the entry attributes
+# argv[0] is a role DN (nsroledn attribute)
+# argv[1] is the entry
+# --------------------------
+sub memberOf
+{
+ my $L_nsroledn=$_[0];
+ $L_nsroledn=~ tr/A-Z/a-z/;
+
+ my $L_entry=$_[1];
+
+ my $L_search;
+ my $L_currentrole;
+
+ $L_search="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_entry\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsrole";
+
+ debug("\t\t-->memberOf: $L_search: check if $L_entry has $L_nsroledn as nsroledn attribute\n");
+
+ open (LDAP2, "$L_search |");
+ while (<LDAP2>) {
+ s/\n //g;
+ if (/^nsrole: (.*)\n/) {
+ $L_currentrole = $1;
+ $L_currentrole=~ tr/A-Z/a-z/;
+ if ( $L_currentrole eq $L_nsroledn )
+ {
+ # the parm is part of the $L_entry nsroledn
+ debug("\t\t<--memberOf: $L_entry locked through $L_nsroledn\n");
+ return 0;
+ }
+ }
+ }
+ close(LDAP2);
+
+ # the parm is not part of the $L_entry nsroledn
+ debug("\t\t<--memberOf: $L_entry not locked through $L_nsroledn\n");
+ return 1;
+}
+
+
+# --------------------------
+# Remove the rdn of a DN
+# argv[0] is a DN
+# --------------------------
+sub removeRdn
+{
+ $L_entry=$_[0];
+
+ @L_entryToTest=split /([,])/,$L_entry;
+ debug("removeRdn: entry to split: $L_entry**@L_entryToTest\n");
+
+ $newDN="";
+ $removeRDN=1;
+ foreach $part (@L_entryToTest)
+ {
+ $part=~ s/^ +//;
+ $part=~ tr/A-Z/a-z/;
+ if ( $removeRDN <= 2 )
+ {
+ $removeRDN=$removeRDN+1;
+ }
+ else
+ {
+ $newDN="$newDN$part";
+ }
+ }
+
+ debug("removeRdn: new DN **$newDN**\n");
+}
+
+# --------------------------
+# Check if L_current is below the scope of
+# L_nestedRole
+# argv[0] is a role
+# argv[1] is the nested role
+# --------------------------
+sub checkScope
+{
+ $L_current=$_[0];
+ $L_nestedRole=$_[1];
+
+ debug("checkScope: check if $L_current is below $L_nestedRole\n");
+
+ removeRdn($L_nestedRole);
+ $L_nestedRoleSuffix=$newDN;
+ debug("checkScope: nested role based: $L_nestedRoleSuffix\n");
+
+ $cont=1;
+ while ( ($cont == 1) && ($L_current ne "") )
+ {
+ removeRdn($L_current);
+ $currentDn=$newDN;
+ debug("checkScope: current DN to check: $currentDn\n");
+
+ if ( $currentDn eq $L_nestedRoleSuffix )
+ {
+ debug("checkScope: DN match!!!\n");
+ $cont = 0;
+ }
+ else
+ {
+ $L_current=$currentDn;
+ }
+ }
+
+ if ( $cont == 1 )
+ {
+ debug("checkScope: $_[0] and $_[1] are not compatible\n");
+ return 0;
+ }
+ else
+ {
+ debug("checkScope: $_[0] and $_[1] are compatible\n");
+ return 1;
+ }
+}
+
+
+###############################
+# MAIN ROUTINE
+###############################
+
+# Generated variable
+$dsroot="{{DS-ROOT}}";
+
+# Determine which command we are running
+if ( $0 =~ /ns-inactivate(.pl)?$/ )
+{
+ $cmd="ns-inactivate.pl";
+ $operation="inactivate";
+ $state="inactivated";
+ $modrole="add";
+ $already="already";
+}
+elsif ( $0 =~ /ns-activate(.pl)?$/ )
+{
+ $cmd="ns-activate.pl";
+ $operation="activate";
+ $state="activated";
+ $modrole="delete";
+ $already="already";
+}
+elsif ( $0 =~ /ns-accountstatus(.pl)?$/ )
+{
+ $cmd="ns-accountstatus.pl";
+ $operation="get status of";
+ $state="activated";
+ # no need for $modrole as no operation is performed
+ $already="";
+
+}
+else
+{
+ out("$0: unknown command\n");
+ exit 100;
+}
+
+debug("Running ** $cmd ** $operation\n");
+
+$dsbinroot="$dsroot{{SEP}}shared{{SEP}}bin";
+$ldapsearch="$dsbinroot{{SEP}}ldapsearch -1";
+$ldapmodify="$dsbinroot{{SEP}}ldapmodify";
+
+# Default values
+$defrootdn= "{{ROOT-DN}}";
+$defhost= "{{SERVER-NAME}}";
+$defport= "{{SERVER-PORT}}";
+
+# User values
+$rootdn= "{{ROOT-DN}}";
+$rootpw= "";
+$pwfile= "";
+$host= "{{SERVER-NAME}}";
+$port= "{{SERVER-PORT}}";
+$entry= "";
+
+$single=0;
+$role=0;
+
+chdir("$dsbinroot");
+
+# Process the command line arguments
+while( $arg = shift)
+{
+ if($arg eq "-?")
+ {
+ usage_and_exit();
+ }
+ elsif($arg eq "-D")
+ {
+ $rootdn= shift @ARGV;
+ }
+ elsif($arg eq "-w")
+ {
+ $rootpw= shift @ARGV;
+ }
+ elsif($arg eq "-j")
+ {
+ $pwfile= shift @ARGV;
+ }
+ elsif($arg eq "-p")
+ {
+ $port= shift @ARGV;
+ }
+ elsif($arg eq "-h")
+ {
+ $host= shift @ARGV;
+ }
+ elsif($arg eq "-I")
+ {
+ $entry= shift @ARGV;
+ }
+ else
+ {
+ print "$arg: Unknown command line argument.\n";
+ usage_and_exit();
+ }
+}
+
+if ($pwfile ne ""){
+# Open file and get the password
+ unless (open (RPASS, $pwfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $rootpw = <RPASS>;
+ chomp($rootpw);
+ close(RPASS);
+} elsif ($rootpw eq "-"){
+# Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $rootpw = ReadLine(0);
+# chomp($rootpw);
+# ReadMode('normal');
+}
+
+if( $rootpw eq "" )
+{
+ usage_and_exit();
+}
+
+if( $entry eq "" )
+{
+ usage_and_exit();
+}
+
+#
+# Check the actual existence of the entry to inactivate/activate
+# and at the same time, validate the various parm: port, host, rootdn, rootpw
+#
+@exist=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(objectclass=*)\" dn`;
+$retCode1=$?;
+if ( $retCode1 != 0 )
+{
+ $retCode1=$?>>8;
+ exit $retCode1;
+}
+
+@isRole=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(&(objectclass=LDAPsubentry)(objectclass=nsRoleDefinition))\" dn`;
+$nbLineRole=@isRole;
+$retCode2=$?;
+if ( $retCode2 != 0 )
+{
+ $retCode2=$?>>8;
+ exit $retCode2;
+}
+
+if ( $nbLineRole == 1 )
+{
+ debug("Groups of users\n");
+ $role=1;
+}
+else
+{
+ debug("Single user\n");
+ $single=1;
+}
+
+#
+# First of all, check the existence of the nsaccountlock attribute in the entry
+#
+$isLocked=0;
+if ( $single == 1 )
+{
+ $searchAccountLock="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(objectclass=*)\" nsaccountlock";
+ open (LDAP1, "$searchAccountLock |");
+ while (<LDAP1>) {
+ s/\n //g;
+ if (/^nsaccountlock: (.*)\n/) {
+ $L_currentvalue = $1;
+ $L_currentvalue=~ tr/A-Z/a-z/;
+ if ( $L_currentvalue eq "true")
+ {
+ $isLocked=1;
+ }
+ elsif ( $L_currentvalue eq "false" )
+ {
+ $isLocked=0;
+ }
+ }
+ }
+ close(LDAP1);
+}
+debug("Is the entry already locked? ==> $isLocked\n");
+
+#
+# Get the suffix name of that entry
+#
+
+# Remove the space at the beginning (just in case...)
+# -I "uid=jvedder , ou=People , o=sun.com"
+@suffix=split /([,])/,$entry;
+$result="";
+foreach $part (@suffix)
+{
+ $part=~s/^ +//;
+ $part=~ tr/A-Z/a-z/;
+ $result="$result$part";
+}
+@suffixN=$result;
+
+debug("Entry to $operation: #@suffix#\n");
+debug("Entry to $operation: #@suffixN#\n");
+
+# Get the suffix
+$cont=0;
+while ($cont == 0)
+{
+ # Look if suffix is the suffix of the entry
+ # ldapsearch -s one -b "cn=mapping tree,cn=config" "cn=\"uid=jvedder,ou=People,o=sun.com\""
+ #
+ debug("\tSuffix from the entry: #@suffixN#\n");
+ @mapping=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s one -b \"cn=mapping tree, cn=config\" \"cn=\\"@suffixN\\"\" cn `;
+
+ $retCode=$?;
+ if ( $retCode != 0 )
+ {
+ $retCode=$?>>8;
+ exit $retCode;
+ }
+
+ # If we get a result, remove the dn:
+ # dn: cn="o=sun.com",cn=mapping tree,cn=config
+ # cn: "o=sun.com"
+ #
+ shift @mapping;
+
+ foreach $res (@mapping)
+ {
+ # Break the string cn: "o=sun.com" into pieces
+ @cn= split(/ /,$res);
+
+ # And remove the cn: part
+ shift @cn;
+
+ # Now compare the suffix we extract from the mapping tree
+ # with the suffix derived from the entry
+ debug("\tSuffix from mapping tree: #@cn#\n");
+ if ( @cn eq @suffixN ) {
+ debug("Found matching suffix\n");
+ $cont=1;
+ }
+ }
+
+ if ( $cont == 0 )
+ {
+ # Remove the current rdn to try another suffix
+ shift @suffix;
+
+ $result="";
+ foreach $part (@suffix)
+ {
+ $part=~ s/^ +//;
+ $part=~ tr/A-Z/a-z/;
+ $result="$result$part";
+ }
+ @suffixN=$result;
+
+ debug("\t\tNothing found => go up one level in rdn #@suffix#\n");
+ $len=@suffix;
+ if ( $len == 0 )
+ {
+ debug("Can not find suffix. Problem\n");
+ $cont=2;
+ }
+ }
+}
+if ( $cont == 2)
+{
+ out("Can not find suffix for entry $entry\n");
+ exit 100;
+}
+
+if ( $operation eq "inactivate" )
+{
+ #
+ # Now that we have the suffix and we know if we deal with a single entry or
+ # a role, just try to create the COS and roles associated.
+ #
+ @base=(
+ "cn=nsManagedDisabledRole,@suffixN",
+ "cn=nsDisabledRole,@suffixN",
+ "cn=nsAccountInactivationTmp,@suffixN",
+ "\'cn=\"cn=nsDisabledRole,@suffixN\",cn=nsAccountInactivationTmp,@suffixN\'",
+ "cn=nsAccountInactivation_cos,@suffixN" );
+
+ $addrolescos="$ldapmodify -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -c -a >> {{DEV-NULL}} 2>&1 ";
+ @role1=(
+ "dn: cn=nsManagedDisabledRole,@suffixN\n",
+ "objectclass: LDAPsubentry\n",
+ "objectclass: nsRoleDefinition\n",
+ "objectclass: nsSimpleRoleDefinition\n",
+ "objectclass: nsManagedRoleDefinition\n",
+ "cn: nsManagedDisabledRole\n\n" );
+ @role2=(
+ "dn: cn=nsDisabledRole,@suffixN\n",
+ "objectclass: top\n",
+ "objectclass: LDAPsubentry\n",
+ "objectclass: nsRoleDefinition\n",
+ "objectclass: nsComplexRoleDefinition\n",
+ "objectclass: nsNestedRoleDefinition\n",
+ "nsRoleDN: cn=nsManagedDisabledRole,@suffixN\n",
+ "cn: nsDisabledRole\n\n" );
+ @cos1=(
+ "dn: cn=nsAccountInactivationTmp,@suffixN\n",
+ "objectclass: top\n",
+ "objectclass: nsContainer\n\n" );
+ @cos2=(
+ "dn: cn=\"cn=nsDisabledRole,@suffixN\",cn=nsAccountInactivationTmp,@suffixN\n",
+ "objectclass: top\n",
+ "objectclass: extensibleObject\n",
+ "objectclass: costemplate\n",
+ "objectclass: ldapsubentry\n",
+ "cosPriority: 1\n",
+ "nsAccountLock: true\n\n" );
+ @cos3=(
+ "dn: cn=nsAccountInactivation_cos,@suffixN\n",
+ "objectclass: top\n",
+ "objectclass: LDAPsubentry\n",
+ "objectclass: cosSuperDefinition\n",
+ "objectclass: cosClassicDefinition\n",
+ "cosTemplateDn: cn=nsAccountInactivationTmp,@suffixN\n",
+ "cosSpecifier: nsRole\n",
+ "cosAttribute: nsAccountLock operational\n\n" );
+
+ @all=(\@role1, \@role2, \@cos1, \@cos2, \@cos3);
+
+ $i=0;
+
+ foreach $current (@base)
+ {
+ debug("Creating $current ??\n");
+ open(FD,"| $addrolescos ");
+ print FD @{$all[$i]};
+ close(FD);
+ if ( $? != 0 )
+ {
+ $retCode=$?>>8;
+ if ( $retCode == 68 )
+ {
+ debug("Entry $current already exists, ignore error\n");
+ }
+ else
+ {
+ # Probably a more serious problem.
+ # Exit with LDAP error
+ exit $retCode;
+ }
+ }
+ else
+ {
+ debug("Entry $current created\n");
+ }
+ $i=$i+1;
+ }
+}
+
+$skipManaged=0;
+$skipDisabled=0;
+$directLocked=0;
+
+$nsDisabledRole="cn=nsDisabledRole,@suffixN";
+$nsDisabledRole=~ tr/A-Z/a-z/;
+
+$nsManagedDisabledRole="cn=nsManagedDisabledRole,@suffixN";
+$nsManagedDisabledRole=~ tr/A-Z/a-z/;
+
+if ( $operation eq "inactivate" )
+{
+ # Go through all the roles part of nsdisabledrole to check if the entry
+ # is a member of one of those roles
+ $ret=indirectLock("LDAP00", $entry, $nsDisabledRole);
+ if ( $ret == 0 )
+ {
+ if ( $throughRole ne $nsDisabledRole && $throughRole ne $nsManagedDisabledRole )
+ {
+ # indirect lock
+ out("$entry already $state through $throughRole.\n");
+ }
+ else
+ {
+ # direct lock
+ out("$entry already $state.\n");
+ }
+ exit 100;
+ }
+ elsif ( $isLocked == 1 )
+ {
+ # the entry is not locked through a role, may be nsaccountlock is "hardcoded" ?
+ out("$entry already $state (probably directly).\n");
+ exit 103;
+ }
+}
+elsif ( $operation eq "activate" || $operation eq "get status of" )
+{
+ $skipManaged=$single;
+ $skipDisabled=$role;
+
+ $ret=indirectLock("LDAP00",$entry, $nsDisabledRole);
+
+ if ( $ret == 0 )
+ {
+ # undirectly locked
+ if ( $throughRole ne $nsDisabledRole && $throughRole ne $nsManagedDisabledRole )
+ {
+ if ( $operation eq "activate" )
+ {
+ out("$entry inactivated through $throughRole. Can not activate it individually.\n");
+ exit 100;
+ }
+ else
+ {
+ out("$entry inactivated through $throughRole.\n");
+ exit 104;
+ }
+ }
+ debug("$entry locked individually\n");
+
+ if ( $operation ne "activate" )
+ {
+ out("$entry inactivated.\n");
+ exit 103;
+ }
+ }
+ elsif ( $directLocked == 0 )
+ {
+ if ( $operation eq "activate" && $isLocked != 1 )
+ {
+ out("$entry $already $state.\n");
+ exit 100;
+ }
+ elsif ( $isLocked != 1 )
+ {
+ out("$entry $already $state.\n");
+ exit 102;
+ }
+ else
+ {
+ # not locked using our schema, but nsaccountlock is probably present
+ out("$entry inactivated (probably directly).\n");
+ exit 103;
+ }
+ }
+ elsif ( $operation ne "activate" )
+ {
+ out("$entry inactivated.\n");
+ exit 103;
+ }
+ # else Locked directly, juste unlock it!
+ debug("$entry locked individually\n");
+}
+
+#
+# Inactivate/activate the entry
+#
+$action="$ldapmodify -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -c >> {{DEV-NULL}} 2>&1";
+if ( $single == 1 )
+{
+ @record=(
+ "dn: $entry\n",
+ "changetype: modify\n",
+ "$modrole: nsRoleDN\n",
+ "nsRoleDN: cn=nsManagedDisabledRole,@suffixN\n\n" );
+}
+else
+{
+ @record=(
+ "dn: cn=nsDisabledRole,@suffixN\n",
+ "changetype: modify\n",
+ "$modrole: nsRoleDN\n",
+ "nsRoleDN: $entry\n\n" );
+}
+open(FD,"| $action ");
+print FD @record;
+close(FD);
+if ( $? != 0 )
+{
+debug("$modrole, $entry\n");
+ $retCode=$?>>8;
+ exit $retCode;
+}
+
+out("$entry $state.\n");
+exit 0;
diff --git a/ldap/admin/src/scripts/template-ns-inactivate.pl b/ldap/admin/src/scripts/template-ns-inactivate.pl
new file mode 100644
index 00000000..5913f7ad
--- /dev/null
+++ b/ldap/admin/src/scripts/template-ns-inactivate.pl
@@ -0,0 +1,813 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+###############################
+# SUB-ROUTINES
+###############################
+
+sub usage_and_exit
+{
+ print (STDERR "$cmd [-D rootdn] { -w password | -w - | -j filename } \n");
+ print (STDERR " [-p port] [-h host] -I DN-to-$operation\n\n");
+ print (STDERR "May be used to $operation a user or a domain of users\n\n");
+ print (STDERR "Arguments:\n");
+ print (STDERR " -? - help\n");
+ print (STDERR " -D rootdn - Provide a Directory Manager DN. Default= '$defrootdn'\n");
+ print (STDERR " -w password - Provide a password for the Directory Manager DN\n");
+ print (STDERR " -w - - Prompt for the Directory Manager's password\n");
+ print (STDERR " -j filename - Read the Directory Manager's password from file\n");
+ print (STDERR " -p port - Provide a port. Default= '$defport'\n");
+ print (STDERR " -h host - Provide a host name. Default= '$defhost'\n");
+ print (STDERR " -I DN-to-$operation - Single entry DN or role DN to $operation\n");
+ exit 100;
+}
+
+sub debug
+{
+# print " ==> @_";
+}
+
+sub out
+{
+ print "@_";
+}
+
+# --------------------------
+# Check if the entry is part of a locked role:
+# i.e.: for each role member (nsroledn) of nsdisabledrole, check if
+# * it is the same as the entry
+# * the entry is member of role (==has nsroledn attributes), compare each of
+# them with the nsroledn of nsdisabledrole
+# * if nsroledn of nsdisabledrole are complex, go through each of them
+# argv[0] is the local file handler
+# argv[1] is the entry (may be a single entry DN or a role DN)
+# argv[2] is the base for the search
+# --------------------------
+
+$throughRole="";
+
+sub indirectLock
+{
+ # For recursivity, file handler must be local
+ my $L_filehandle=$_[0];
+ $L_filehandle++;
+
+ my $L_entry=$_[1];
+ # Remove useless space
+ my @L_intern=split /([,])/,$L_entry;
+ my $L_result="";
+ foreach $L_part (@L_intern)
+ {
+ $L_part=~s/^ +//;
+ $L_part=~ tr/A-Z/a-z/;
+ $L_result="$L_result$L_part";
+ }
+ $L_entry=$L_result;
+
+ my $L_base=$_[2];
+
+ my $L_search;
+ my $L_currentrole;
+ my $L_retCode;
+
+ my $L_local;
+
+`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsroledn >> {{DEV-NULL}} 2>&1 `;
+$retCode=$?;
+if ( $retCode != 0 )
+{
+ $retCode=$?>>8;
+ return 1;
+}
+
+ # Check if the role is a nested role
+ @L_Nested="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=nsNestedRoleDefinition)(objectclass=ldapsubentry))\" ";
+ # L_isNested == 1 means that we are going through a nested role, so for each member of that
+ # nested role, check that the member is below the scope of the nested
+ $L_isNested=@L_Nested;
+
+ # Not Direct Lock, Go through roles if any
+ $L_search="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_base\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsroledn ";
+
+ debug("\t-->indirectLock: check if $L_entry is part of a locked role from base $L_base\n\n");
+
+ unless (open ($L_filehandle, "$L_search |"))
+ {
+ out("Can't open file $L_filehandle\n");
+ exit;
+ }
+ while (<$L_filehandle>) {
+
+ s/\n //g;
+ if (/^nsroledn: (.*)\n/) {
+ $L_currentrole = $1;
+
+ # Remove useless space
+ my @L_intern=split /([,])/,$L_currentrole;
+ my $L_result="";
+ foreach $L_part (@L_intern)
+ {
+ $L_part=~s/^ +//;
+ $L_part=~ tr/A-Z/a-z/;
+ $L_result="$L_result$L_part";
+ }
+ $L_currentrole=$L_result;
+
+ debug("\t-- indirectLock loop: current nsroledn $L_currentrole of base $L_base\n");
+ if ( $L_isNested == 1 )
+ {
+ if ( checkScope($L_currentrole, $L_base) == 0 )
+ {
+ # Scope problem probably a bad conf, skip the currentrole
+ next;
+ }
+ }
+
+ if ( $L_currentrole eq $L_entry )
+ {
+ # the entry is a role that is directly locked
+ # i.e, nsroledn of nsdisabledrole contains the entry
+ $throughRole=$L_base;
+ $throughRole=~ tr/A-Z/a-z/;
+
+ # skipDisabled means that we've just found that the entry (which is a role)
+ # is locked directly (==its DN is part of nsroledn attributes)
+ # we just want to know now, if it is locked through another role
+ # at least, one
+ if ( $skipDisabled == 1 )
+ {
+ # direct inactivation
+ $directLocked=1;
+ # just go through that test once
+ $skipDisabled=0;
+ next;
+ }
+ debug("\t-- 1 indirectLock: $L_currentrole locked throughRole == $throughRole\n");
+ return 0;
+ }
+
+ $L_retCode=memberOf($L_currentrole, $L_entry);
+ if ( $L_retCode == 0 && $single == 1 )
+ {
+ $throughRole=$L_currentrole;
+ $throughRole=~ tr/A-Z/a-z/;
+ if ( $skipManaged == 1 )
+ {
+ if ( $L_currentrole eq $nsManagedDisabledRole)
+ {
+ # Try next nsroledn
+ $directLocked=1;
+ $skipManaged=0;
+ next;
+ }
+ }
+ debug("\t-- 2 indirectLock: $L_currentrole locked throughRole == $throughRole\n");
+ return 0;
+ }
+
+ # Only for the first iteration
+ # the first iteration is with nsdisabledrole as base, other
+ # loops are deeper
+ $L_local=$skipDisabled;
+ $skipDisabled=0;
+
+ # the current nsroledn may be a complex role, just go through
+ # its won nsroledn
+ $L_retCode=indirectLock($L_filehandle,$L_entry, $L_currentrole);
+
+ # Because of recursivity, to keep the initial value for the first level
+ $skipDisabled=$L_local;
+
+ if ( $L_retCode == 0 )
+ {
+ $throughRole=$L_currentrole;
+ $throughRole=~ tr/A-Z/a-z/;
+ debug("\t-- 3 indirectLock: $L_entry locked throughRole == $throughRole\n");
+ return 0;
+ }
+ }
+ }
+
+ close($L_filehandle);
+
+ debug("\t<--indirectLock: no more nsroledn to process\n");
+ return 1;
+}
+
+# --------------------------
+# Check if nsroledn is part of the entry attributes
+# argv[0] is a role DN (nsroledn attribute)
+# argv[1] is the entry
+# --------------------------
+sub memberOf
+{
+ my $L_nsroledn=$_[0];
+ $L_nsroledn=~ tr/A-Z/a-z/;
+
+ my $L_entry=$_[1];
+
+ my $L_search;
+ my $L_currentrole;
+
+ $L_search="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$L_entry\" \"(|(objectclass=*)(objectclass=ldapsubentry))\" nsrole";
+
+ debug("\t\t-->memberOf: $L_search: check if $L_entry has $L_nsroledn as nsroledn attribute\n");
+
+ open (LDAP2, "$L_search |");
+ while (<LDAP2>) {
+ s/\n //g;
+ if (/^nsrole: (.*)\n/) {
+ $L_currentrole = $1;
+ $L_currentrole=~ tr/A-Z/a-z/;
+ if ( $L_currentrole eq $L_nsroledn )
+ {
+ # the parm is part of the $L_entry nsroledn
+ debug("\t\t<--memberOf: $L_entry locked through $L_nsroledn\n");
+ return 0;
+ }
+ }
+ }
+ close(LDAP2);
+
+ # the parm is not part of the $L_entry nsroledn
+ debug("\t\t<--memberOf: $L_entry not locked through $L_nsroledn\n");
+ return 1;
+}
+
+
+# --------------------------
+# Remove the rdn of a DN
+# argv[0] is a DN
+# --------------------------
+sub removeRdn
+{
+ $L_entry=$_[0];
+
+ @L_entryToTest=split /([,])/,$L_entry;
+ debug("removeRdn: entry to split: $L_entry**@L_entryToTest\n");
+
+ $newDN="";
+ $removeRDN=1;
+ foreach $part (@L_entryToTest)
+ {
+ $part=~ s/^ +//;
+ $part=~ tr/A-Z/a-z/;
+ if ( $removeRDN <= 2 )
+ {
+ $removeRDN=$removeRDN+1;
+ }
+ else
+ {
+ $newDN="$newDN$part";
+ }
+ }
+
+ debug("removeRdn: new DN **$newDN**\n");
+}
+
+# --------------------------
+# Check if L_current is below the scope of
+# L_nestedRole
+# argv[0] is a role
+# argv[1] is the nested role
+# --------------------------
+sub checkScope
+{
+ $L_current=$_[0];
+ $L_nestedRole=$_[1];
+
+ debug("checkScope: check if $L_current is below $L_nestedRole\n");
+
+ removeRdn($L_nestedRole);
+ $L_nestedRoleSuffix=$newDN;
+ debug("checkScope: nested role based: $L_nestedRoleSuffix\n");
+
+ $cont=1;
+ while ( ($cont == 1) && ($L_current ne "") )
+ {
+ removeRdn($L_current);
+ $currentDn=$newDN;
+ debug("checkScope: current DN to check: $currentDn\n");
+
+ if ( $currentDn eq $L_nestedRoleSuffix )
+ {
+ debug("checkScope: DN match!!!\n");
+ $cont = 0;
+ }
+ else
+ {
+ $L_current=$currentDn;
+ }
+ }
+
+ if ( $cont == 1 )
+ {
+ debug("checkScope: $_[0] and $_[1] are not compatible\n");
+ return 0;
+ }
+ else
+ {
+ debug("checkScope: $_[0] and $_[1] are compatible\n");
+ return 1;
+ }
+}
+
+
+###############################
+# MAIN ROUTINE
+###############################
+
+# Generated variable
+$dsroot="{{DS-ROOT}}";
+
+# Determine which command we are running
+if ( $0 =~ /ns-inactivate(.pl)?$/ )
+{
+ $cmd="ns-inactivate.pl";
+ $operation="inactivate";
+ $state="inactivated";
+ $modrole="add";
+ $already="already";
+}
+elsif ( $0 =~ /ns-activate(.pl)?$/ )
+{
+ $cmd="ns-activate.pl";
+ $operation="activate";
+ $state="activated";
+ $modrole="delete";
+ $already="already";
+}
+elsif ( $0 =~ /ns-accountstatus(.pl)?$/ )
+{
+ $cmd="ns-accountstatus.pl";
+ $operation="get status of";
+ $state="activated";
+ # no need for $modrole as no operation is performed
+ $already="";
+
+}
+else
+{
+ out("$0: unknown command\n");
+ exit 100;
+}
+
+debug("Running ** $cmd ** $operation\n");
+
+$dsbinroot="$dsroot{{SEP}}shared{{SEP}}bin";
+$ldapsearch="$dsbinroot{{SEP}}ldapsearch -1";
+$ldapmodify="$dsbinroot{{SEP}}ldapmodify";
+
+# Default values
+$defrootdn= "{{ROOT-DN}}";
+$defhost= "{{SERVER-NAME}}";
+$defport= "{{SERVER-PORT}}";
+
+# User values
+$rootdn= "{{ROOT-DN}}";
+$rootpw= "";
+$pwfile= "";
+$host= "{{SERVER-NAME}}";
+$port= "{{SERVER-PORT}}";
+$entry= "";
+
+$single=0;
+$role=0;
+
+chdir("$dsbinroot");
+
+# Process the command line arguments
+while( $arg = shift)
+{
+ if($arg eq "-?")
+ {
+ usage_and_exit();
+ }
+ elsif($arg eq "-D")
+ {
+ $rootdn= shift @ARGV;
+ }
+ elsif($arg eq "-w")
+ {
+ $rootpw= shift @ARGV;
+ }
+ elsif($arg eq "-j")
+ {
+ $pwfile= shift @ARGV;
+ }
+ elsif($arg eq "-p")
+ {
+ $port= shift @ARGV;
+ }
+ elsif($arg eq "-h")
+ {
+ $host= shift @ARGV;
+ }
+ elsif($arg eq "-I")
+ {
+ $entry= shift @ARGV;
+ }
+ else
+ {
+ print "$arg: Unknown command line argument.\n";
+ usage_and_exit();
+ }
+}
+
+if ($pwfile ne ""){
+# Open file and get the password
+ unless (open (RPASS, $pwfile)) {
+ die "Error, cannot open password file $passwdfile\n";
+ }
+ $rootpw = <RPASS>;
+ chomp($rootpw);
+ close(RPASS);
+} elsif ($rootpw eq "-"){
+# Read the password from terminal
+ die "The '-w -' option requires an extension library (Term::ReadKey) which is not\n",
+ "part of the standard perl distribution. If you want to use it, you must\n",
+ "download and install the module. You can find it at\n",
+ "http://www.perl.com/CPAN/CPAN.html\n";
+# Remove the previous line and uncomment the following 6 lines once you have installed Term::ReadKey module.
+# use Term::ReadKey;
+# print "Bind Password: ";
+# ReadMode('noecho');
+# $rootpw = ReadLine(0);
+# chomp($rootpw);
+# ReadMode('normal');
+}
+
+if( $rootpw eq "" )
+{
+ usage_and_exit();
+}
+
+if( $entry eq "" )
+{
+ usage_and_exit();
+}
+
+#
+# Check the actual existence of the entry to inactivate/activate
+# and at the same time, validate the various parm: port, host, rootdn, rootpw
+#
+@exist=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(objectclass=*)\" dn`;
+$retCode1=$?;
+if ( $retCode1 != 0 )
+{
+ $retCode1=$?>>8;
+ exit $retCode1;
+}
+
+@isRole=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(&(objectclass=LDAPsubentry)(objectclass=nsRoleDefinition))\" dn`;
+$nbLineRole=@isRole;
+$retCode2=$?;
+if ( $retCode2 != 0 )
+{
+ $retCode2=$?>>8;
+ exit $retCode2;
+}
+
+if ( $nbLineRole == 1 )
+{
+ debug("Groups of users\n");
+ $role=1;
+}
+else
+{
+ debug("Single user\n");
+ $single=1;
+}
+
+#
+# First of all, check the existence of the nsaccountlock attribute in the entry
+#
+$isLocked=0;
+if ( $single == 1 )
+{
+ $searchAccountLock="$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s base -b \"$entry\" \"(objectclass=*)\" nsaccountlock";
+ open (LDAP1, "$searchAccountLock |");
+ while (<LDAP1>) {
+ s/\n //g;
+ if (/^nsaccountlock: (.*)\n/) {
+ $L_currentvalue = $1;
+ $L_currentvalue=~ tr/A-Z/a-z/;
+ if ( $L_currentvalue eq "true")
+ {
+ $isLocked=1;
+ }
+ elsif ( $L_currentvalue eq "false" )
+ {
+ $isLocked=0;
+ }
+ }
+ }
+ close(LDAP1);
+}
+debug("Is the entry already locked? ==> $isLocked\n");
+
+#
+# Get the suffix name of that entry
+#
+
+# Remove the space at the beginning (just in case...)
+# -I "uid=jvedder , ou=People , o=sun.com"
+@suffix=split /([,])/,$entry;
+$result="";
+foreach $part (@suffix)
+{
+ $part=~s/^ +//;
+ $part=~ tr/A-Z/a-z/;
+ $result="$result$part";
+}
+@suffixN=$result;
+
+debug("Entry to $operation: #@suffix#\n");
+debug("Entry to $operation: #@suffixN#\n");
+
+# Get the suffix
+$cont=0;
+while ($cont == 0)
+{
+ # Look if suffix is the suffix of the entry
+ # ldapsearch -s one -b "cn=mapping tree,cn=config" "cn=\"uid=jvedder,ou=People,o=sun.com\""
+ #
+ debug("\tSuffix from the entry: #@suffixN#\n");
+ @mapping=`$ldapsearch -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -s one -b \"cn=mapping tree, cn=config\" \"cn=\\"@suffixN\\"\" cn `;
+
+ $retCode=$?;
+ if ( $retCode != 0 )
+ {
+ $retCode=$?>>8;
+ exit $retCode;
+ }
+
+ # If we get a result, remove the dn:
+ # dn: cn="o=sun.com",cn=mapping tree,cn=config
+ # cn: "o=sun.com"
+ #
+ shift @mapping;
+
+ foreach $res (@mapping)
+ {
+ # Break the string cn: "o=sun.com" into pieces
+ @cn= split(/ /,$res);
+
+ # And remove the cn: part
+ shift @cn;
+
+ # Now compare the suffix we extract from the mapping tree
+ # with the suffix derived from the entry
+ debug("\tSuffix from mapping tree: #@cn#\n");
+ if ( @cn eq @suffixN ) {
+ debug("Found matching suffix\n");
+ $cont=1;
+ }
+ }
+
+ if ( $cont == 0 )
+ {
+ # Remove the current rdn to try another suffix
+ shift @suffix;
+
+ $result="";
+ foreach $part (@suffix)
+ {
+ $part=~ s/^ +//;
+ $part=~ tr/A-Z/a-z/;
+ $result="$result$part";
+ }
+ @suffixN=$result;
+
+ debug("\t\tNothing found => go up one level in rdn #@suffix#\n");
+ $len=@suffix;
+ if ( $len == 0 )
+ {
+ debug("Can not find suffix. Problem\n");
+ $cont=2;
+ }
+ }
+}
+if ( $cont == 2)
+{
+ out("Can not find suffix for entry $entry\n");
+ exit 100;
+}
+
+if ( $operation eq "inactivate" )
+{
+ #
+ # Now that we have the suffix and we know if we deal with a single entry or
+ # a role, just try to create the COS and roles associated.
+ #
+ @base=(
+ "cn=nsManagedDisabledRole,@suffixN",
+ "cn=nsDisabledRole,@suffixN",
+ "cn=nsAccountInactivationTmp,@suffixN",
+ "\'cn=\"cn=nsDisabledRole,@suffixN\",cn=nsAccountInactivationTmp,@suffixN\'",
+ "cn=nsAccountInactivation_cos,@suffixN" );
+
+ $addrolescos="$ldapmodify -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -c -a >> {{DEV-NULL}} 2>&1 ";
+ @role1=(
+ "dn: cn=nsManagedDisabledRole,@suffixN\n",
+ "objectclass: LDAPsubentry\n",
+ "objectclass: nsRoleDefinition\n",
+ "objectclass: nsSimpleRoleDefinition\n",
+ "objectclass: nsManagedRoleDefinition\n",
+ "cn: nsManagedDisabledRole\n\n" );
+ @role2=(
+ "dn: cn=nsDisabledRole,@suffixN\n",
+ "objectclass: top\n",
+ "objectclass: LDAPsubentry\n",
+ "objectclass: nsRoleDefinition\n",
+ "objectclass: nsComplexRoleDefinition\n",
+ "objectclass: nsNestedRoleDefinition\n",
+ "nsRoleDN: cn=nsManagedDisabledRole,@suffixN\n",
+ "cn: nsDisabledRole\n\n" );
+ @cos1=(
+ "dn: cn=nsAccountInactivationTmp,@suffixN\n",
+ "objectclass: top\n",
+ "objectclass: nsContainer\n\n" );
+ @cos2=(
+ "dn: cn=\"cn=nsDisabledRole,@suffixN\",cn=nsAccountInactivationTmp,@suffixN\n",
+ "objectclass: top\n",
+ "objectclass: extensibleObject\n",
+ "objectclass: costemplate\n",
+ "objectclass: ldapsubentry\n",
+ "cosPriority: 1\n",
+ "nsAccountLock: true\n\n" );
+ @cos3=(
+ "dn: cn=nsAccountInactivation_cos,@suffixN\n",
+ "objectclass: top\n",
+ "objectclass: LDAPsubentry\n",
+ "objectclass: cosSuperDefinition\n",
+ "objectclass: cosClassicDefinition\n",
+ "cosTemplateDn: cn=nsAccountInactivationTmp,@suffixN\n",
+ "cosSpecifier: nsRole\n",
+ "cosAttribute: nsAccountLock operational\n\n" );
+
+ @all=(\@role1, \@role2, \@cos1, \@cos2, \@cos3);
+
+ $i=0;
+
+ foreach $current (@base)
+ {
+ debug("Creating $current ??\n");
+ open(FD,"| $addrolescos ");
+ print FD @{$all[$i]};
+ close(FD);
+ if ( $? != 0 )
+ {
+ $retCode=$?>>8;
+ if ( $retCode == 68 )
+ {
+ debug("Entry $current already exists, ignore error\n");
+ }
+ else
+ {
+ # Probably a more serious problem.
+ # Exit with LDAP error
+ exit $retCode;
+ }
+ }
+ else
+ {
+ debug("Entry $current created\n");
+ }
+ $i=$i+1;
+ }
+}
+
+$skipManaged=0;
+$skipDisabled=0;
+$directLocked=0;
+
+$nsDisabledRole="cn=nsDisabledRole,@suffixN";
+$nsDisabledRole=~ tr/A-Z/a-z/;
+
+$nsManagedDisabledRole="cn=nsManagedDisabledRole,@suffixN";
+$nsManagedDisabledRole=~ tr/A-Z/a-z/;
+
+if ( $operation eq "inactivate" )
+{
+ # Go through all the roles part of nsdisabledrole to check if the entry
+ # is a member of one of those roles
+ $ret=indirectLock("LDAP00", $entry, $nsDisabledRole);
+ if ( $ret == 0 )
+ {
+ if ( $throughRole ne $nsDisabledRole && $throughRole ne $nsManagedDisabledRole )
+ {
+ # indirect lock
+ out("$entry already $state through $throughRole.\n");
+ }
+ else
+ {
+ # direct lock
+ out("$entry already $state.\n");
+ }
+ exit 100;
+ }
+ elsif ( $isLocked == 1 )
+ {
+ # the entry is not locked through a role, may be nsaccountlock is "hardcoded" ?
+ out("$entry already $state (probably directly).\n");
+ exit 103;
+ }
+}
+elsif ( $operation eq "activate" || $operation eq "get status of" )
+{
+ $skipManaged=$single;
+ $skipDisabled=$role;
+
+ $ret=indirectLock("LDAP00",$entry, $nsDisabledRole);
+
+ if ( $ret == 0 )
+ {
+ # undirectly locked
+ if ( $throughRole ne $nsDisabledRole && $throughRole ne $nsManagedDisabledRole )
+ {
+ if ( $operation eq "activate" )
+ {
+ out("$entry inactivated through $throughRole. Can not activate it individually.\n");
+ exit 100;
+ }
+ else
+ {
+ out("$entry inactivated through $throughRole.\n");
+ exit 104;
+ }
+ }
+ debug("$entry locked individually\n");
+
+ if ( $operation ne "activate" )
+ {
+ out("$entry inactivated.\n");
+ exit 103;
+ }
+ }
+ elsif ( $directLocked == 0 )
+ {
+ if ( $operation eq "activate" && $isLocked != 1 )
+ {
+ out("$entry $already $state.\n");
+ exit 100;
+ }
+ elsif ( $isLocked != 1 )
+ {
+ out("$entry $already $state.\n");
+ exit 102;
+ }
+ else
+ {
+ # not locked using our schema, but nsaccountlock is probably present
+ out("$entry inactivated (probably directly).\n");
+ exit 103;
+ }
+ }
+ elsif ( $operation ne "activate" )
+ {
+ out("$entry inactivated.\n");
+ exit 103;
+ }
+ # else Locked directly, juste unlock it!
+ debug("$entry locked individually\n");
+}
+
+#
+# Inactivate/activate the entry
+#
+$action="$ldapmodify -p $port -h $host -D \"$rootdn\" -w \"$rootpw\" -c >> {{DEV-NULL}} 2>&1";
+if ( $single == 1 )
+{
+ @record=(
+ "dn: $entry\n",
+ "changetype: modify\n",
+ "$modrole: nsRoleDN\n",
+ "nsRoleDN: cn=nsManagedDisabledRole,@suffixN\n\n" );
+}
+else
+{
+ @record=(
+ "dn: cn=nsDisabledRole,@suffixN\n",
+ "changetype: modify\n",
+ "$modrole: nsRoleDN\n",
+ "nsRoleDN: $entry\n\n" );
+}
+open(FD,"| $action ");
+print FD @record;
+close(FD);
+if ( $? != 0 )
+{
+debug("$modrole, $entry\n");
+ $retCode=$?>>8;
+ exit $retCode;
+}
+
+out("$entry $state.\n");
+exit 0;
diff --git a/ldap/admin/src/scripts/template-ns-newpwpolicy.pl b/ldap/admin/src/scripts/template-ns-newpwpolicy.pl
new file mode 100755
index 00000000..dd57c944
--- /dev/null
+++ b/ldap/admin/src/scripts/template-ns-newpwpolicy.pl
@@ -0,0 +1,241 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# Add new password policy specific entries
+
+#############################################################################
+# enable the use of Perldap functions
+require DynaLoader;
+
+use Getopt::Std;
+use Mozilla::LDAP::Conn;
+use Mozilla::LDAP::Utils qw(:all);
+use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API
+
+#############################################################################
+# Default values of the variables
+
+$opt_D = "{{ROOT-DN}}";
+$opt_p = "{{SERVER-PORT}}";
+$opt_h = "{{SERVER-NAME}}";
+$opt_v = 0;
+
+# Variables
+$ldapsearch="{{DS-ROOT}}{{SEP}}shared{{SEP}}bin{{SEP}}ldapsearch";
+$ldapmodify="{{DS-ROOT}}{{SEP}}shared{{SEP}}bin{{SEP}}ldapmodify";
+
+chdir("{{DS-ROOT}}{{SEP}}shared{{SEP}}bin");
+
+#############################################################################
+
+sub usage {
+ print (STDERR "ns-newpwpolicy.pl [-v] [-D rootdn] { -w password | -j filename } \n");
+ print (STDERR " [-p port] [-h host] -U UserDN -S SuffixDN\n\n");
+
+ print (STDERR "Arguments:\n");
+ print (STDERR " -? - help\n");
+ print (STDERR " -v - verbose output\n");
+ print (STDERR " -D rootdn - Directory Manager DN. Default= '$opt_D'\n");
+ print (STDERR " -w rootpw - password for the Directory Manager DN\n");
+ print (STDERR " -j filename - Read the Directory Manager's password from file\n");
+ print (STDERR " -p port - port. Default= $opt_p\n");
+ print (STDERR " -h host - host name. Default= '$opt_h'\n");
+ print (STDERR " -U userDN - User entry DN\n");
+ print (STDERR " -S suffixDN - Suffix entry DN\n");
+ exit 100;
+}
+
+# Process the command line arguments
+{
+ usage() if (!getopts('vD:w:j:p:h:U:S:'));
+
+ if ($opt_j ne ""){
+ die "Error, cannot open password file $opt_j\n" unless (open (RPASS, $opt_j));
+ $opt_w = <RPASS>;
+ chomp($opt_w);
+ close(RPASS);
+ }
+
+ usage() if( $opt_w eq "" );
+ if ($opt_U eq "" && $opt_S eq "") {
+ print (STDERR "Please provide at least -S or -U option.\n\n");
+ }
+
+ # Now, check if the user/group exists
+
+ if ($opt_S) {
+ print (STDERR "host = $opt_h, port = $opt_p, suffixDN = \"$opt_S\"\n\n") if $opt_v;
+ @base=(
+ "cn=nsPwPolicyContainer,$opt_S",
+ "cn=\"cn=nsPwPolicyEntry,$opt_S\",cn=nsPwPolicyContainer,$opt_S",
+ "cn=\"cn=nsPwTemplateEntry,$opt_S\",cn=nsPwPolicyContainer,$opt_S",
+ "cn=nsPwPolicy_cos,$opt_S"
+ );
+
+ $ldapadd="$ldapmodify -p $opt_p -h $opt_h -D \"$opt_D\" -w \"$opt_w\" -c -a 2>&1";
+ $modifyCfg="$ldapmodify -p $opt_p -h $opt_h -D \"$opt_D\" -w \"$opt_w\" -c 2>&1";
+
+ @container=(
+ "dn: cn=nsPwPolicyContainer,$opt_S\n",
+ "objectclass: top\n",
+ "objectclass: nsContainer\n\n" );
+ @pwpolicy=(
+ "dn: cn=\"cn=nsPwPolicyEntry,$opt_S\",cn=nsPwPolicyContainer,$opt_S\n",
+ "objectclass: top\n",
+ "objectclass: ldapsubentry\n",
+ "objectclass: passwordpolicy\n\n" );
+ @template=(
+ "dn: cn=\"cn=nsPwTemplateEntry,$opt_S\",cn=nsPwPolicyContainer,$opt_S\n",
+ "objectclass: top\n",
+ "objectclass: extensibleObject\n",
+ "objectclass: costemplate\n",
+ "objectclass: ldapsubentry\n",
+ "cosPriority: 1\n",
+ "pwdpolicysubentry: cn=\"cn=nsPwPolicyEntry,$opt_S\",cn=nsPwPolicyContainer,$opt_S\n\n" );
+ @cos=(
+ "dn: cn=nsPwPolicy_cos,$opt_S\n",
+ "objectclass: top\n",
+ "objectclass: LDAPsubentry\n",
+ "objectclass: cosSuperDefinition\n",
+ "objectclass: cosPointerDefinition\n",
+ "cosTemplateDn: cn=\"cn=nsPwTemplateEntry,$opt_S\",cn=nsPwPolicyContainer,$opt_S\n",
+ "cosAttribute: pwdpolicysubentry default operational-default\n\n" );
+
+ @all=(\@container, \@pwpolicy, \@template, \@cos);
+
+ $i=0;
+
+ foreach $current (@base)
+ {
+ open(FD,"| $ldapadd");
+ print FD @{$all[$i]};
+ close(FD);
+ if ( $? != 0 ) {
+ $retCode=$?>>8;
+ if ( $retCode == 68 ) {
+ print( STDERR "Entry \"$current\" already exists. Please ignore the error\n\n");
+ }
+ else {
+ # Probably a more serious problem.
+ # Exit with LDAP error
+ print(STDERR "Error $retcode while adding \"$current\". Exiting.\n");
+ exit $retCode;
+ }
+ }
+ else {
+ print( STDERR "Entry \"$current\" created\n\n") if $opt_v;
+ }
+ $i=$i+1;
+ }
+
+ $modConfig = "dn:cn=config\nchangetype: modify\nreplace:nsslapd-pwpolicy-local\nnsslapd-pwpolicy-local: on\n\n";
+ open(FD,"| $modifyCfg ");
+ print(FD $modConfig);
+ close(FD);
+ $retcode = $?;
+ if ( $retcode != 0 ) {
+ print( STDERR "Error $retcode while modifing \"cn=config\". Exiting.\n" );
+ exit ($retcode);
+ }
+ else {
+ print( STDERR "Entry \"cn=config\" modified\n\n") if $opt_v;
+ }
+ } # end of $opt_S
+
+ if ($opt_U) {
+ my $norm_opt_U = normalizeDN($opt_U);
+ print (STDERR "host = $opt_h, port = $opt_p, userDN = \"$norm_opt_U\"\n\n") if $opt_v;
+ $retcode = `$ldapsearch -h $opt_h -p $opt_p -b \"$norm_opt_U\" -s base \"\"`;
+ if ($retcode != 0 ) {
+ print( STDERR "the user entry $norm_opt_U does not exist. Exiting.\n");
+ exit ($retcode);
+ }
+
+ print( STDERR "the user entry $norm_opt_U found..\n\n") if $opt_v;
+
+ # Now, get the parentDN
+ @rdns = ldap_explode_dn($norm_opt_U, 0);
+ shift @rdns;
+ $parentDN = join(',', @rdns);
+
+ print (STDERR "parentDN is $parentDN\n\n") if $opt_v;
+
+ @base=(
+ "cn=nsPwPolicyContainer,$parentDN",
+ "cn=\"cn=nsPwPolicyEntry,$norm_opt_U\",cn=nsPwPolicyContainer,$parentDN"
+ );
+
+ $ldapadd="$ldapmodify -p $opt_p -h $opt_h -D \"$opt_D\" -w \"$opt_w\" -c -a 2>&1";
+ $modifyCfg="$ldapmodify -p $opt_p -h $opt_h -D \"$opt_D\" -w \"$opt_w\" -c 2>&1";
+
+ @container=(
+ "dn: cn=nsPwPolicyContainer,$parentDN\n",
+ "objectclass: top\n",
+ "objectclass: nsContainer\n\n" );
+ @pwpolicy=(
+ "dn: cn=\"cn=nsPwPolicyEntry,$norm_opt_U\",cn=nsPwPolicyContainer,$parentDN\n",
+ "objectclass: top\n",
+ "objectclass: ldapsubentry\n",
+ "objectclass: passwordpolicy\n\n" );
+
+ @all=(\@container, \@pwpolicy);
+
+ $i=0;
+
+ foreach $current (@base)
+ {
+ open(FD,"| $ldapadd ");
+ print FD @{$all[$i]};
+ close(FD);
+ if ( $? != 0 ) {
+ $retCode=$?>>8;
+ if ( $retCode == 68 ) {
+ print( STDERR "Entry $current already exists. Please ignore the error\n\n");
+ }
+ else {
+ # Probably a more serious problem.
+ # Exit with LDAP error
+ print(STDERR "Error $retcode while adding \"$current\". Exiting.\n");
+ exit $retCode;
+ }
+ }
+ else {
+ print( STDERR "Entry $current created\n\n") if $opt_v;
+ }
+ $i=$i+1;
+ }
+
+ $target = "cn=\"cn=nsPwPolicyEntry,$norm_opt_U\",cn=nsPwPolicyContainer,$parentDN";
+ $modConfig = "dn: $norm_opt_U\nchangetype: modify\nreplace:pwdpolicysubentry\npwdpolicysubentry: $target\n\n";
+ open(FD,"| $modifyCfg ");
+ print(FD $modConfig);
+ close(FD);
+ $retcode = $?;
+ if ( $retcode != 0 ) {
+ print( STDERR "Error $retcode while modifing $norm_opt_U. Exiting.\n" );
+ exit ($retcode);
+ }
+ else {
+ print( STDERR "Entry \"$norm_opt_U\" modified\n\n") if $opt_v;
+ }
+
+ $modConfig = "dn:cn=config\nchangetype: modify\nreplace:nsslapd-pwpolicy-local\nnsslapd-pwpolicy-local: on\n\n";
+ open(FD,"| $modifyCfg ");
+ print(FD $modConfig);
+ close(FD);
+ $retcode = $?;
+ if ( $retcode != 0 ) {
+ print( STDERR "Error $retcode while modifing \"cn=config\". Exiting.\n" );
+ exit ($retcode);
+ }
+ else {
+ print( STDERR "Entry \"cn=config\" modified\n\n") if $opt_v;
+ }
+ } # end of $opt_U
+}
diff --git a/ldap/admin/src/scripts/template-repl-monitor-cgi.pl b/ldap/admin/src/scripts/template-repl-monitor-cgi.pl
new file mode 100755
index 00000000..b9494d0d
--- /dev/null
+++ b/ldap/admin/src/scripts/template-repl-monitor-cgi.pl
@@ -0,0 +1,40 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright (C) 2002-2004 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+use Cgi;
+
+$params = "";
+$params .= " -h $cgiVars{'servhost'}" if $cgiVars{'servhost'};
+$params .= " -p $cgiVars{'servport'}" if $cgiVars{'servport'};
+$params .= " -f $cgiVars{'configfile'}" if $cgiVars{'configfile'};
+$params .= " -t $cgiVars{'refreshinterval'}" if $cgiVars{'refreshinterval'};
+if ($cgiVars{'admurl'}) {
+ $admurl = "$cgiVars{'admurl'}";
+ if ( $ENV{'QUERY_STRING'} ) {
+ $admurl .= "?$ENV{'QUERY_STRING'}";
+ }
+ elsif ( $ENV{'CONTENT_LENGTH'} ) {
+ $admurl .= "?$Cgi::CONTENT";
+ }
+ $params .= " -u \"$admurl\"";
+}
+$siteroot = $cgiVars{'siteroot'};
+$perl = "$siteroot/bin/slapd/admin/bin/perl";
+$ENV{'LD_LIBRARY_PATH'} = "$siteroot/lib:$siteroot/lib/nsPerl5.005_03/lib";
+
+# Save user-specified parameters as cookies in monreplication.properties.
+# Sync up with the property file so that monreplication2 is interval, and
+# monreplication3 the config file pathname.
+$propertyfile = "$siteroot/bin/admin/admin/bin/property/monreplication.properties";
+$edit1 = "s#monreplication2=.*#monreplication2=$cgiVars{'refreshinterval'}#;";
+$edit2 = "s#^monreplication3=.*#monreplication3=$cgiVars{'configfile'}#;";
+system("$perl -p -i.bak -e \"$edit1\" -e \"$edit2\" $propertyfile");
+
+# Now the real work
+$replmon = "$siteroot/bin/slapd/admin/scripts/template-repl-monitor.pl";
+system("$perl $replmon $params");
diff --git a/ldap/admin/src/scripts/template-repl-monitor.pl b/ldap/admin/src/scripts/template-repl-monitor.pl
new file mode 100755
index 00000000..78e3aa85
--- /dev/null
+++ b/ldap/admin/src/scripts/template-repl-monitor.pl
@@ -0,0 +1,956 @@
+#{{PERL-EXEC}}
+
+##############################################################################
+#
+# Copyright (C) 2002-2004 Netscape Communications Corporation.
+# All Rights Reserved.
+#
+# FILE: repl-monitor.pl
+#
+# SYNOPSIS:
+# repl-monitor.pl -f configuration-file [-h host] [-p port] [-r] \
+# [-u refresh-url] [-t refresh-interval]
+#
+# repl-monitor.pl -v
+#
+# DESCRIPTION:
+# Given an LDAP replication "supplier" server, crawl over all the ldap
+# servers via direct or indirect replication agreements.
+# For each master replica discovered, display the maxcsn of the master
+# and the replication status of all its lower level replicas.
+# All output is in HTML.
+#
+# OPTIONS:
+#
+# -f configuration-file
+# The configuration file contains the sections for the connection
+# parameters, the server alias, and the thresholds for different colors
+# when display the time lags between consumers and master.
+# If the Admin Server is running on Windows, the configuration-file
+# name may have format "D:/Netscape/replmon.conf".
+#
+# The connection parameter section consists of the section name
+# followed by one of more connection parameter entries:
+#
+# [connection]
+# host:port:binddn:bindpwd:bindcert
+# host:port=shadowport:binddn:bindpwd:bindcert
+# ...
+#
+# where host:port default (*:*) to that in a replication agreement,
+# binddn default (*) to "cn=Directory Manager", and bindcert is the
+# pathname of cert db if you want the script to connect to the server
+# via SSL. If bindcert is omitted, the connection will be simple
+# bind.
+# "port=shadowport" means to use shadowport instead of port if port
+# is specified in the replication agreement. This is useful when
+# for example, ssl port is specified in a replication agreement,
+# but you can't access the cert db from the machine where this
+# script is running. So you could let the script to map the ssl
+# port to a non-ssl port and use the simple bind.
+#
+# A server may have a dedicated or a share entry in the connection
+# section. The script will find out the most matched entry for a given
+# server. For example, if all the ldap servers except host1 share the
+# same binddn and bindpassword, the connection section then just need
+# two entries:
+#
+# [connection]
+# *:*:binddn:bindpassword:
+# host1:*:binddn:bindpassword:
+#
+# If a host:port is assigned an alias, then the alias instead of
+# host:port will be displayed in The output file. Each host:port
+# can have only one alias. But each alias may be used by more than
+# one host:port.
+#
+# [alias]
+# alias = host:port
+# ...
+#
+# CSN time lags between masters and consumers might be displayed in
+# different colors based on their range. The thresholds for different
+# colors may be specified in color section:
+#
+# [color]
+# lowmark (in minutes) = color
+# ...
+# If the color section or color entry is missing, the default color
+# set is: green for [0-5) minutes lag, yellow [5-60), and red 60 and more.
+#
+# -h host
+# Initial replication supplier's host. Default to the current host.
+#
+# -p port
+# Initial replication supplier's port. Default to 389.
+#
+# -r If specified, -r causes the routine to be entered without printing
+# HTML header information. This is suitable when making multiple calls
+# to this routine (e.g. when specifying multiple, different, "unrelated"
+# supplier servers) and expecting a single HTML output.
+#
+# -t refresh-interval
+# Specify the refresh interval in seconds. This option has to be
+# jointly used with option -u.
+#
+# -u refresh-url
+# The output HTML file may invoke a CGI program periodically. If
+# this CGI program in turn calls this script, the effect is that
+# the output HTML file would automatically refresh itself. This
+# is useful for continuing monitoring. See also option -t.
+#
+# -v Print out the version of this script
+#
+# DIAGNOSTICS:
+# There are several ways to invoke this script if you got error
+# "Can't locate Mozilla/LDAP/Conn.pm in @INC", or
+# "usage: Undefined variable":
+#
+# 1. Set the first line of the script to #!<DSHOME>/bin/slapd/admin/bin/perl
+# and run this script directly.
+#
+# 2. Run
+# <DSHOME>/bin/slapd/admin/bin/perl repl-monitor.pl
+#
+# 3. Set environment variable PERL5LIB to your Perl lib dirs where
+# Mozilla::LDAP module can be located.
+#
+# 4. Invoke the script as follows if <MYPERLDIR>/lib/site contains
+# Mozilla/LDAP:
+# <MYPERLDIR>/bin/perl -I <MYPERLDIR>/lib/site repl-monitor.pl
+#
+# If you get error "Can't load ...", try to set environment variable
+# for library path to <DSHOME>/lib:<DSHOME>/lib/nsPerl5.005_03/lib
+#
+#############################################################################
+$usage = "\nusage: $0 -f configuration-file [-h host] [-p port] [-r] [-u refresh-url] [-t refresh-interval]\n\nor : $0 -v\n";
+
+use Getopt::Std; # parse command line arguments
+use Mozilla::LDAP::Conn; # LDAP module for Perl
+use Mozilla::LDAP::Utils qw(normalizeDN); # LULU, utilities.
+use Mozilla::LDAP::API qw(:api :ssl :apiv3 :constant); # Direct access to C API
+use Time::Local; # to convert GMT Z strings to localtime
+
+#
+# Global variables
+#
+$product = "Netscape Directory Server Replication Monitor";
+$version = "Version 1.0";
+#
+# ldap servers given or discovered from the replication agreements:
+# @servers = (host:port=shadowport:binddn:password:cert_db)
+#
+# entries read from the connection section of the configuration file:
+# @allconnections = (host:port=shadowport:binddn:password:cert_db)
+#
+# aliases of ldap servers read from the configuration file:
+# %allaliases{$host:$port}= (alias)
+#
+# replicas discovered on all ldap servers
+# @allreplicas = (server#:replicaroot:replicatype:serverid:replicadn)
+#
+# ruvs retrieved from all replicas
+# @allruvs{replica#:masterid} = (rawcsn:decimalcsn;mon/day/year hh:mi:ss)
+#
+# agreements discovered on all ldap supplier servers:
+# @allagreements = (supplier_replica#:consumer#:conntype:schedule:status)
+# the array may take another format after the consumer replicas are located:
+# @allagreements = (supplier_replica#:consumer_replica#:conntype:schedule:status)
+#
+
+#main
+{
+ # turn off buffered I/O
+ $| = 1;
+
+ # Check for legal options
+ if (!getopts('h:p:f:ru:t:v')) {
+ print $usage;
+ exit -1;
+ }
+
+ if ($opt_v) {
+ print "$product - $version\n";
+ exit;
+ }
+
+ $interval = $opt_t;
+ $interval = 300 if ( !$interval || $interval <= 0 );
+
+ # Get current date/time
+ $nowraw = localtime();
+ ($wday, $mm, $dd, $tt, $yy) = split(/ /, $nowraw);
+ $now = "$wday $mm $dd $yy $tt";
+
+ # if no -r (Reenter and skip html header), print html header
+ if (!$opt_r) {
+ # print the HTML header
+ &print_html_header;
+ } else {
+ # print separator for new replication set
+ print "<hr width=90% size=3><br>\n";
+ }
+
+ exit -1 if &validateArgs < 0;
+ exit if &read_cfg_file ($opt_f) < 0;
+
+ # Start with the given host and port
+ # The index names in %ld are defined in Mozilla::LDAP::Utils::ldapArgs()
+ &add_server ("$ld{host}:$ld{port}:$ld{bind}:$ld{pswd}:$ld{cert}");
+
+ $serveridx = 0;
+ while ($serveridx <= $#servers) {
+ if (&get_replicas ($serveridx) != 0 && $serveridx == 0) {
+ my ($host, $port, $binddn) = split (/:/, $servers[0]);
+ print("Login to $host:$port as \"$binddn\" failed\n");
+ exit;
+ }
+ $serveridx++;
+ }
+
+ &find_consumer_replicas;
+ &process_suppliers;
+
+ # All done! - well, for the current invokation only
+ # print "</body></html>\n";
+ exit;
+}
+
+sub validateArgs
+{
+ my ($rc) = 0;
+
+ %ld = Mozilla::LDAP::Utils::ldapArgs();
+
+ if (!$opt_v && !$opt_f) {
+ print "<p>Error: Missing configuration file.\n";
+ print "<p>If you need help on the configuration file, Please go back and click the Help button.\n";
+ #print $usage; # Don't show usage in CGI
+ $rc = -1;
+ }
+ elsif (!$opt_h) {
+ chop ($ld{"host"} = `hostname`);
+ }
+
+ return $rc;
+}
+
+sub read_cfg_file
+{
+ my ($fn) = @_;
+ unless (open(CFGFILEHANDLE, $fn)) {
+ print "<p>Error: Can't open \"$fn\": $!.\n";
+ print "<p>If you need help on the configuration file, Please go back and click the Help button.\n";
+ return -1;
+ }
+ $section = 0;
+ while (<CFGFILEHANDLE>) {
+ next if (/^\s*\#/ || /^\s*$/);
+ chop ($_);
+ if (m/^\[(.*)\]/) {
+ $section = $1;
+ }
+ else {
+ if ( $section =~ /conn/i ) {
+ push (@allconnections, $_);
+ }
+ elsif ( $section =~ /alias/i ) {
+ m/^\s*(\S.*)\s*=\s*(\S+)/;
+ $allaliases {$2} = $1;
+ }
+ elsif ( $section =~ /color/i ) {
+ m/^\s*(-?\d+)\s*=\s*(\S+)/;
+ $allcolors {$1} = $2;
+ }
+ }
+ }
+ if ( ! keys (%allcolors) ) {
+ $allcolors {0} = "#ccffcc"; #apple green
+ $allcolors {5} = "#ffffcc"; #cream yellow
+ $allcolors {60} = "#ffcccc"; #pale pink
+ }
+ @colorkeys = sort (keys (%allcolors));
+ close (CFGFILEHANDLE);
+ return 0;
+}
+
+sub get_replicas
+{
+ my ($serveridx) = @_;
+ my ($conn, $host, $port, $shadowport, $binddn, $bindpwd, $bindcert);
+ my ($others);
+ my ($replica, $replicadn);
+ my ($ruv, $replicaroot, $replicatype, $serverid, $masterid, $maxcsn);
+ my ($type, $flag, $i);
+ my ($myridx, $ridx, $cidx);
+
+ #
+ # Bind to the server
+ #
+ ($host, $port, $binddn, $bindpwd, $bindcert) = split (/:/, "$servers[$serveridx]", 5);
+
+ ($port, $shadowport) = split (/=/, $port);
+ $shadowport = $port if !$shadowport;
+
+ $conn = new Mozilla::LDAP::Conn ($host, $shadowport, "$binddn", $bindpwd, $bindcert);
+
+ return -1 if (!$conn);
+
+ #
+ # Get all the replica on the server
+ #
+ $myridx = $#allreplicas + 1;
+ $replica = $conn->search ("cn=mapping tree,cn=config",
+ "sub",
+ "(objectClass=nsDS5Replica)", 0,
+ qw(nsDS5ReplicaRoot nsDS5ReplicaType nsDS5Flags nsDS5ReplicaId));
+ while ($replica) {
+ $replicadn = $replica->getDN;
+ $replicaroot = normalizeDN ($replica->{nsDS5ReplicaRoot}[0]);
+ $type = $replica->{nsDS5ReplicaType}[0];
+ $flag = $replica->{nsDS5Flags}[0];
+ $serverid = $replica->{nsDS5ReplicaId}[0];
+
+ # flag = 0: change log is not created
+ # type = 2: read only replica
+ # type = 3: updatable replica
+ $replicatype = $flag == 0 ? "consumer" : ($type == 2 ? "hub" : "master");
+
+ push (@allreplicas, "$serveridx:$replicaroot:$replicatype:$serverid:$replicadn");
+
+ $replica = $conn->nextEntry ();
+ }
+
+ #
+ # Get ruv for each replica
+ #
+ for ($ridx = $myridx; $ridx <= $#allreplicas; $ridx++) {
+
+ $replicaroot = $1 if ($allreplicas[$ridx] =~ /^\d+:([^:]*)/);
+ # do a one level search with nsuniqueid in the filter - this will force the use of the
+ # nsuniqueid index instead of the entry dn index, which seems to be unreliable in
+ # heavily loaded servers
+ $ruv = $conn->search($replicaroot, "one",
+ "(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectClass=nsTombstone))",
+ 0, qw(nsds50ruv nsruvReplicaLastModified));
+ next if !$ruv; # this should be an error case . . .
+
+ for ($ruv->getValues('nsds50ruv')) {
+ if (m/\{replica\s+(\d+).+?\}\s*\S+\s*(\S+)/i) {
+ $masterid = $1;
+ $maxcsn = &to_decimal_csn ($2);
+ $allruvs {"$ridx:$masterid"} = "$2:$maxcsn";
+ }
+ }
+
+ for ($ruv->getValues('nsruvReplicaLastModified')) {
+ if (m/\{replica\s+(\d+).+?\}\s*(\S+)/i) {
+ $masterid = $1;
+ $lastmodifiedat = hex($2);
+ my ($sec, $min, $hour, $mday, $mon, $year) = localtime ($lastmodifiedat);
+ $mon++;
+ $year += 1900;
+ $hour = "0".$hour if ($hour < 10);
+ $min = "0".$min if ($min < 10);
+ $sec = "0".$sec if ($sec < 10);
+ $allruvs {"$ridx:$masterid"} .= ";$mon/$mday/$year $hour:$min:$sec";
+ }
+ }
+ }
+
+ #
+ # Get all agreements for each supplier replica
+ #
+ for ($ridx = $myridx; $ridx <= $#allreplicas; $ridx++) {
+ $_ = $allreplicas[$ridx];
+
+ # Skip consumers
+ next if m/:consumer:/i;
+
+ m/:([^:]*)$/;
+ $replicadn = $1;
+ my @attrlist = qw(cn nsds5BeginReplicaRefresh nsds5replicaUpdateInProgress
+ nsds5ReplicaLastInitStatus nsds5ReplicaLastInitStart
+ nsds5ReplicaLastInitEnd nsds5replicaReapActive
+ nsds5replicaLastUpdateStart nsds5replicaLastUpdateEnd
+ nsds5replicaChangesSentSinceStartup nsds5replicaLastUpdateStatus
+ nsds5ReplicaHost
+ nsds5ReplicaPort nsDS5ReplicaBindMethod nsds5ReplicaUpdateSchedule);
+ $agreement = $conn->search("$replicadn", "sub", "(objectClass=nsDS5ReplicationAgreement)",
+ 0, @attrlist);
+ while ($agreement) {
+
+ my %agmt = ();
+ # Push consumer to server stack if we have not already
+ $host = ($agreement->getValues('nsDS5ReplicaHost'))[0];
+ $port = ($agreement->getValues('nsDS5ReplicaPort'))[0];
+ $cidx = &add_server ("$host:$port");
+
+ for (@attrlist) {
+ $agmt{$_} = ($agreement->getValues($_))[0];
+ }
+ if ($agmt{nsDS5ReplicaBindMethod} =~ /simple/i) {
+ $agmt{nsDS5ReplicaBindMethod} = 'n';
+ }
+ if (!$agmt{nsds5ReplicaUpdateSchedule} ||
+ ($agmt{nsds5ReplicaUpdateSchedule} eq '0000-2359 0123456') ||
+ ($agmt{nsds5ReplicaUpdateSchedule} eq '*') ||
+ ($agmt{nsds5ReplicaUpdateSchedule} eq '* *')) {
+ $agmt{nsds5ReplicaUpdateSchedule} = 'always in sync';
+ }
+
+ $agmt{ridx} = $ridx;
+ $agmt{cidx} = $cidx;
+ push @allagreements, \%agmt;
+
+ $agreement = $conn->nextEntry ();
+ }
+ }
+
+ $conn->close;
+}
+
+#
+# Initially, the agreements have consumer host:port info instead of
+# replica info. This routine will find the consumer replica info
+#
+sub find_consumer_replicas
+{
+ my ($m_ridx); # index of master's replica
+ my ($s_ridx); # index of supplier's replica
+ my ($c_ridx); # index of consumer's replica
+ my ($c_sidx); # index of consumer server
+ my ($remainder); #
+ my ($s_replicaroot); # supplier replica root
+ my ($c_replicaroot); # consumer replica root
+ my ($j, $val);
+
+ #
+ # Loop through every agreement defined on the current supplier replica
+ #
+ foreach (@allagreements) {
+ $s_ridx = $_->{ridx};
+ $c_sidx = $_->{cidx};
+ $s_replicaroot = $1 if ($allreplicas[$s_ridx] =~ /^\d+:([^:]*)/);
+ $c_replicaroot = "";
+
+ # $c_ridx will be assigned to -$c_sidx
+ # if the condumer is not accessible
+ # $c_sidx will not be zero since it's
+ # not the first server.
+ $c_ridx = -$c_sidx; # $c_sidx will not be zero
+
+ # Loop through consumer's replicas and find
+ # the counter part for the current supplier
+ # replica
+ for ($j = 0; $j <= $#allreplicas; $j++) {
+
+ # Get a replica on consumer
+ # I'm not sure what's going on here, but possibly could be made
+ # much simpler with normalizeDN and/or ldap_explode_dn
+ if ($allreplicas[$j] =~ /^$c_sidx:([^:]*)/) {
+ $val = $1;
+
+ # We need to find out the consumer
+ # replica that matches the supplier
+ # replicaroot most.
+ if ($s_replicaroot =~ /^.*$val$/i &&
+ length ($val) >= length ($c_replicaroot)) {
+ $c_ridx = $j;
+
+ # Avoid case-sensitive comparison
+ last if (length($s_replicaroot) == length($val));
+ $c_replicaroot = $val;
+ }
+ }
+ }
+ $_->{ridx} = $s_ridx;
+ $_->{cidx} = $c_ridx;
+ }
+}
+
+sub process_suppliers
+{
+ my ($ridx, $mid, $maxcsn);
+
+ $mid = "";
+
+ $last_sidx = -1; # global variable for print html page
+
+ for ($ridx = 0; $ridx <= $#allreplicas; $ridx++) {
+
+ # Skip consumers and hubs
+ next if $allreplicas[$ridx] !~ /:master:(\d+):/i;
+ $mid = $1;
+
+ # Skip replicas without agreements defined yet
+ next if (! grep {$_->{ridx} == $ridx} @allagreements);
+
+ $maxcsn = &print_master_header ($ridx, $mid);
+ if ( "$maxcsn" != "none" ) {
+ &print_consumer_header ();
+ &print_consumers ($ridx, $mid);
+ }
+ &print_supplier_end;
+ }
+
+ if ($mid eq "") {
+ print "<p>The server is not a master or it has no replication agreement\n";
+ }
+}
+
+sub print_master_header
+{
+ my ($ridx, $mid) = @_;
+ my ($myruv) = $allruvs {"$ridx:$mid"};
+ my ($maxcsnval) = split ( /;/, "$myruv" );
+ my ($maxcsn) = &to_string_csn ($maxcsnval);
+ my ($sidx, $replicaroot, $replicatype, $serverid) = split (/:/, $allreplicas[$ridx]);
+
+ # Print the master name
+ if ( $last_sidx != $sidx ) {
+ my ($ldapurl) = &get_ldap_url ($sidx, $sidx);
+ &print_legend if ( $last_sidx < 0);
+ print "<p><p><hr><p>\n";
+ print "\n<p><center class=page-subtitle><font color=#0099cc>\n";
+ print "Master:&nbsp $ldapurl</center>\n";
+ $last_sidx = $sidx;
+ }
+
+ # Print the current replica info onthe master
+ print "\n<p><table border=0 cellspacing=1 cellpadding=6 cols=10 width=100% class=bgColor9>\n";
+
+ print "\n<tr><td colspan=10><center>\n";
+ print "<font class=areatitle>Replica ID:&nbsp;</font>";
+ print "<font class=text28>$serverid</font>\n";
+
+ print "<font class=areatitle>Replica Root:&nbsp;</font>";
+ print "<font class=text28>$replicaroot</font>\n";
+
+ print "<font class=areatitle>Max CSN:&nbsp;</font>";
+ print "<font class=text28>$maxcsn</font>\n";
+
+ return $maxcsn;
+}
+
+sub print_consumer_header
+{
+ #Print the header of consumer
+ print "\n<tr class=bgColor16>\n";
+ print "<th nowrap>Receiver</th>\n";
+ print "<th nowrap>Time Lag</th>\n";
+ print "<th nowrap>Max CSN</th>\n";
+ print "<th nowrap>Last Modify Time</th>\n";
+ print "<th nowrap>Supplier</th>\n";
+ print "<th nowrap>Sent/Skipped</th>\n";
+ print "<th nowrap>Update Status</th>\n";
+ print "<th nowrap>Update Started</th>\n";
+ print "<th nowrap>Update Ended</th>\n";
+ print "<th nowrap colspan=2>Schedule</th>\n";
+ print "<th nowrap>SSL?</th>\n";
+ print "</tr>\n";
+}
+
+sub print_consumers
+{
+ my ($m_ridx, $mid) = @_;
+ my ($ignore, $m_replicaroot) = split (/:/, $allreplicas[$m_ridx]);
+ my (@consumers, @ouragreements, @myagreements);
+ my ($s_ridx, $c_ridx, $conntype, $schedule, $status);
+ my ($c_maxcsn_str, $lag, $markcolor);
+ my ($c_replicaroot, $c_replicatype);
+ my ($first_entry);
+ my ($nrows);
+ my ($found);
+
+ undef @ouragreements;
+
+ # Collect all the consumer replicas for the current master replica
+ push (@consumers, $m_ridx);
+ foreach (@consumers) {
+ $s_ridx = $_;
+ for (@allagreements) {
+ next if ($_->{ridx} != $s_ridx);
+ $c_ridx = $_->{cidx};
+ next if $c_ridx == $m_ridx;
+ push @ouragreements, $_;
+ $found = 0;
+ foreach (@consumers) {
+ if ($_ == $c_ridx) {
+ $found = 1;
+ last;
+ }
+ }
+ push (@consumers, $c_ridx) if !$found;
+ }
+ }
+
+ # Print each consumer replica
+ my ($myruv) = $allruvs {"$m_ridx:$mid"};
+ my ($m_maxcsn) = split ( /;/, "$myruv" );
+ foreach (@consumers) {
+ $c_ridx = $_;
+ next if $c_ridx == $m_ridx;
+
+ if ($c_ridx >= 0) {
+ $myruv = $allruvs {"$c_ridx:$mid"};
+ ($c_maxcsn, $c_lastmodified) = split ( /;/, "$myruv" );
+ ($c_maxcsn_str, $lag, $markcolor) = &cacl_time_lag ($m_maxcsn, $c_maxcsn);
+ $c_maxcsn_str =~ s/ /\<br\>/;
+ ($c_sidx, $c_replicaroot, $c_replicatype) = split (/:/, $allreplicas[$c_ridx]);
+ $c_replicaroot = "same as master" if $m_replicaroot eq $c_replicaroot;
+ }
+ else {
+ # $c_ridx is actually -$c_sidx when c is not available
+ $c_sidx = -$c_ridx;
+ $c_maxcsn_str = "_";
+ $lag = "n/a";
+ $markcolor = red;
+ $c_replicaroot = "_";
+ $c_replicatype = "_";
+ }
+
+ $nrows = 0;
+ foreach (@ouragreements) {
+ next if ($_->{cidx} != $c_ridx);
+ $nrows++;
+ }
+
+ $first_entry = 1;
+ foreach (@ouragreements) {
+ next if ($_->{cidx} != $c_ridx);
+ $s_ridx = $_->{ridx};
+ $conntype = $_->{nsDS5ReplicaBindMethod};
+ $status = $_->{nsds5replicaLastUpdateStatus};
+ $schedule = $_->{nsds5ReplicaUpdateSchedule};
+ $s_sidx = $1 if $allreplicas [$s_ridx] =~ /^(\d+):/;
+ $s_ldapurl = &get_ldap_url ($s_sidx, "n/a");
+
+ # Print out the consumer's replica and ruvs
+ print "\n<tr class=bgColor13>\n";
+ if ($first_entry) {
+ $first_entry = 0;
+ $c_ldapurl = &get_ldap_url ($c_sidx, $conntype);
+ print "<td rowspan=$nrows width=5% class=bgColor5>$c_ldapurl<BR>Type: $c_replicatype</td>\n";
+ print "<td rowspan=$nrows width=5% nowrap bgcolor=$markcolor><center>$lag</center></td>\n";
+ print "<td rowspan=$nrows width=15% nowrap>$c_maxcsn_str</td>\n";
+ print "<td rowspan=$nrows width=15% nowrap>$c_lastmodified</td>\n";
+ }
+ print "<td width=5% nowrap><center>$s_ldapurl</center></td>\n";
+ my $changecount = $_->{nsds5replicaChangesSentSinceStartup};
+ if ( $changecount =~ /^$mid:(\d+)\/(\d+) / || $changecount =~ / $mid:(\d+)\/(\d+) / ) {
+ $changecount = "$1 / $2";
+ }
+ elsif ( $changecount =~ /^(\d+)$/ ) {
+ $changecount = $changecount . " / " . "$_->{nsds5replicaChangesSkippedSinceStartup}";
+ }
+ else {
+ $changecount = "0 / 0";
+ }
+ print "<td width=3% nowrap>$changecount</td>\n";
+ my $redfontstart = "";
+ my $redfontend = "";
+ if ($status =~ /error/i) {
+ $redfontstart = "<font color='red'>";
+ $redfontend = "</font>";
+ }
+ elsif ($status =~ /^(\d+) /) {
+ if ( $1 != 0 ) {
+ # warning
+ $redfontstart = "<font color='#FF7777'>";
+ $redfontend = "</font>";
+ }
+ }
+ print "<td width=20% nowrap>$redfontstart$status$redfontend</td>\n";
+ print "<td nowrap>", &format_z_time($_->{nsds5replicaLastUpdateStart}), "</td>\n";
+ print "<td nowrap>", &format_z_time($_->{nsds5replicaLastUpdateEnd}), "</td>\n";
+ if ( $schedule =~ /always/i ) {
+ print "<td colspan=2 width=10% nowrap>$schedule</td>\n";
+ }
+ else {
+ my ($ndays, @days);
+ $schedule =~ /(\d\d)(\d\d)-(\d\d)(\d\d) (\d+)/;
+ print "<td width=10% nowrap>$1:$2-$3:$4</td>\n";
+ $ndays = $5;
+ $ndays =~ s/(\d)/$1,/g;
+ @days = (Sun,Mon,Tue,Wed,Thu,Fri,Sat)[eval $ndays];
+ print "<td width=10% nowrap>@days</td>\n";
+ }
+ print "<td width=3% nowrap class=bgColor5>$conntype</td>\n";
+ }
+ }
+}
+
+sub cacl_time_lag
+{
+ my ($s_maxcsn, $c_maxcsn) = @_;
+ my ($markcolor);
+ my ($csn_str);
+ my ($s_tm, $c_tm, $lag_tm, $lag_str, $hours, $minute);
+
+ $csn_str = &to_string_csn ($c_maxcsn);
+
+ if ($s_maxcsn && !$c_maxcsn) {
+ $lag_str = "- ?:??:??";
+ $markcolor = &get_color (36000); # assume consumer has big latency
+ }
+ elsif (!$s_maxcsn && $c_maxcsn) {
+ $lag_str = "+ ?:??:??";
+ $markcolor = &get_color (1); # consumer is ahead of supplier
+ }
+ elsif ($s_maxcsn le $c_maxcsn) {
+ $lag_str = "0:00:00";
+ $markcolor = &get_color (0);
+ }
+ else {
+ my ($rawcsn, $decimalcsn) = split (/:/, $s_maxcsn);
+ ($s_tm) = split(/ /, $decimalcsn);
+
+ ($rawcsn, $decimalcsn) = split (/:/, $c_maxcsn);
+ ($c_tm) = split(/ /, $decimalcsn);
+ if ($s_tm > $c_tm) {
+ $lag_tm = $s_tm - $c_tm;
+ $lag_str = "- ";
+ $markcolor = &get_color ($lag_tm);
+ }
+ else {
+ $lag_tm = $c_tm - $s_tm;
+ $lag_str = "+ ";
+ $markcolor = $allcolors{ $colorkeys[0] }; # no delay
+ }
+ $hours = int ($lag_tm / 3600);
+ $lag_str .= "$hours:";
+
+ $lag_tm = $lag_tm % 3600;
+ $minutes = int ($lag_tm / 60);
+ $minutes = "0".$minutes if ($minutes < 10);
+ $lag_str .= "$minutes:";
+
+ $lag_tm = $lag_tm % 60;
+ $lag_tm = "0".$lag_tm if ($lag_tm < 10);
+ $lag_str .= "$lag_tm";
+ }
+ return ($csn_str, $lag_str, $markcolor);
+}
+
+#
+# The subroutine would append a new entry to the end of
+# @servers if the host and port are new to @servers.
+#
+sub add_server
+{
+ my ($host, $port, $binddn, $bindpwd, $bindcert) = split (/:/, "@_");
+ my ($shadowport) = $port;
+ my ($domainpattern) = '\.[^:]+';
+ my ($i);
+
+ # Remove the domain name from the host name
+ my ($hostnode) = $host;
+ $hostnode = $1 if $host =~ /^(\w+)\./;
+
+ # new host:port
+ if ($binddn eq "" || $bindpwd eq "" && $bindcert eq "") {
+ #
+ # Look up connection parameter in the order of
+ # host:port
+ # host:*
+ # *:port
+ # *:*
+ #
+ my (@myconfig, $h, $p, $d, $w, $c);
+ (@myconfig = grep (/^$hostnode($domainpattern)*:$port\D/i, @allconnections)) ||
+ (@myconfig = grep (/^$hostnode($domainpattern)*:\*:/i, @allconnections)) ||
+ (@myconfig = grep (/^\*:$port\D/, @allconnections)) ||
+ (@myconfig = grep (/^\*:\*\D/, @allconnections));
+ if ($#myconfig >= 0) {
+ ($h, $p, $d, $w, $c) = split (/:/, $myconfig[0]);
+ ($p, $shadowport) = split (/=/, $p);
+ $p = "" if $p eq "*";
+ $c = "" if $c eq "*";
+ }
+ if ($binddn eq "" || $binddn eq "*") {
+ if ($d eq "" || $d eq "*") {
+ $binddn = "cn=Directory Manager";
+ }
+ else {
+ $binddn = $d;
+ }
+ }
+ $bindpwd = $w if ($bindpwd eq "" || $bindpwd eq "*");
+ $bindcert = $c if ($bindcert eq "" || $bindcert eq "*");
+ }
+
+ for ($i = 0; $i <= $#servers; $i++) {
+ return $i if ($servers[$i] =~ /$hostnode($domainpattern)*:\d*=$shadowport\D/i);
+ }
+
+ push (@servers, "$host:$port=$shadowport:$binddn:$bindpwd:$bindcert");
+ return $i;
+}
+
+sub get_ldap_url
+{
+ my ($sidx, $conntype) = @_;
+ my ($host, $port) = split(/:/, $servers[$sidx]);
+ my ($shadowport);
+ ($port, $shadowport) = split (/=/, $port);
+ my ($protocol, $ldapurl);
+
+ if ($port eq 636 && $conntype eq "0" || $conntype =~ /SSL/i) {
+ $protocol = ldaps;
+ }
+ else {
+ $protocol = ldap;
+ }
+ my ($instance) = $allaliases { "$host:$port" };
+ $instance = "$host:$port" if !$instance;
+ if ($conntype eq "n/a") {
+ $ldapurl = $instance;
+ }
+ else {
+ $ldapurl = "<a href=\"$protocol://$host:$port/\">$instance</a>";
+ }
+ return $ldapurl;
+}
+
+sub to_decimal_csn
+{
+ my ($maxcsn) = @_;
+ if (!$maxcsn || $maxcsn eq "") {
+ return "none";
+ }
+
+ my ($tm, $seq, $masterid, $subseq) = unpack("a8 a4 a4 a4", $maxcsn);
+
+ $tm = hex($tm);
+ $seq = hex($seq);
+ $masterid = hex($masterid);
+ $subseq = hex($subseq);
+
+ return "$tm $seq $masterid $subseq";
+}
+
+sub to_string_csn
+{
+ my ($rawcsn, $decimalcsn) = split(/:/, "@_");
+ if (!$rawcsn || $rawcsn eq "") {
+ return "none";
+ }
+ my ($tm, $seq, $masterid, $subseq) = split(/ /, $decimalcsn);
+ my ($sec, $min, $hour, $mday, $mon, $year) = localtime($tm);
+ $mon++;
+ $year += 1900;
+ foreach ($sec, $min, $hour, $mday, $mon) {
+ $_ = "0".$_ if ($_ < 10);
+ }
+ my ($csnstr) = "$mon/$mday/$year $hour:$min:$sec";
+ $csnstr .= " $seq $subseq" if ( $seq != 0 || $subseq != 0 );
+ return "$rawcsn ($csnstr)";
+}
+
+sub get_color
+{
+ my ($lag_minute) = @_;
+ $lag_minute /= 60;
+ my ($color) = $allcolors { $colorkeys[0] };
+ foreach (@colorkeys) {
+ last if ($lag_minute < $_);
+ $color = $allcolors {$_};
+ }
+ return $color;
+}
+
+# subroutine to remove escaped encoding
+
+sub unescape
+{
+ #my ($_) = @_;
+ tr/+/ /;
+ s/%(..)/pack("c",hex($1))/ge;
+ $_;
+}
+
+sub print_html_header
+{
+ # print the HTML header
+
+ print "Content-type: text/html\n\n";
+ print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\"><html>\n";
+ print "<head><title>Replication Status</title>\n";
+ # print "<link type=text/css rel=stylesheet href=\"master-style.css\">\n";
+ print "<style text/css>\n";
+ print "Body, p, table, td, ul, li {color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 12px;}\n";
+ print "A {color:blue; text-decoration: none;}\n";
+ print "BODY {font-family: arial, helvetica, sans-serif}\n";
+ print "P {font-family: arial, helvetica, sans-serif}\n";
+ print "TH {font-weight: bold; font-family: arial, helvetica, sans-serif}\n";
+ print "TD {font-family: arial, helvetica, sans-serif}\n";
+ print ".bgColor1 {background-color: #003366;}\n";
+ print ".bgColor4 {background-color: #cccccc;}\n";
+ print ".bgColor5 {background-color: #999999;}\n";
+ print ".bgColor9 {background-color: #336699;}\n";
+ print ".bgColor13 {background-color: #ffffff;}\n";
+ print ".bgColor16 {background-color: #6699cc;}\n";
+ print ".text8 {color: #0099cc; font-size: 11px; font-weight: bold;}\n";
+ print ".text28 {color: #ffcc33; font-size: 12px; font-weight: bold;}\n";
+ print ".areatitle {font-weight: bold; color: #ffffff; font-family: arial, helvetica, sans-serif}\n";
+ print ".page-title {font-weight: bold; font-size: larger; font-family: arial, helvetica, sans-serif}\n";
+ print ".page-subtitle {font-weight: bold; font-family: arial, helvetica, sans-serif}\n";
+
+ print "</style></head>\n<body class=bgColor4>\n";
+
+ if ($opt_u) {
+ print "<meta http-equiv=refresh content=$interval; URL=$opt_u>\n";
+ }
+
+ print "<table border=0 cellspacing=0 cellpadding=10 width=100% class=bgColor1>\n";
+ print "<tr><td><font class=text8>$now</font></td>\n";
+ print "<td align=center class=page-title><font color=#0099CC>";
+ print "Netscape Directory Server Replication Status</font>\n";
+
+ if ($opt_u) {
+ print "<br><font class=text8>(This page updates every $interval seconds)</font>\n";
+ }
+
+ print "</td><td align=right valign=center width=25%><font class=text8>$version";
+ print "</font></td></table>\n";
+}
+
+sub print_legend
+{
+ my ($nlegends) = $#colorkeys + 1;
+ print "\n<center><p><font class=page-subtitle color=#0099cc>Time Lag Legend:</font><p>\n";
+ print "<table cellpadding=6 cols=$nlegends width=40%>\n<tr>\n";
+ my ($i, $j);
+ for ($i = 0; $i < $nlegends - 1; $i++) {
+ $j = $colorkeys[$i];
+ print "\n<td bgcolor=$allcolors{$j}><center>within $colorkeys[$i+1] min</center></td>\n";
+ }
+ $j = $colorkeys[$i];
+ print "\n<td bgcolor=$allcolors{$j}><center>over $colorkeys[$i] min</center></td>\n";
+ print "\n<td bgcolor=red><center>server n/a</center></td>\n";
+ print "</table></center>\n";
+}
+
+sub print_supplier_end
+{
+ print "</table>\n";
+}
+
+# given a string in generalized time format, convert to ascii time
+sub format_z_time
+{
+ my $zstr = shift;
+ return "n/a" if (! $zstr);
+ my ($year, $mon, $day, $hour, $min, $sec) =
+ ($zstr =~ /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/);
+ my $time = timegm($sec, $min, $hour, $day, ($mon-1), $year);
+ ($sec, $min, $hour, $day, $mon, $year) = localtime($time);
+ $mon++;
+ $year += 1900;
+ foreach ($sec, $min, $hour, $day, $mon) {
+ $_ = "0".$_ if ($_ < 10);
+ }
+
+ return "$mon/$day/$year $hour:$min:$sec";
+}
diff --git a/ldap/admin/src/scripts/template-verify-db.pl b/ldap/admin/src/scripts/template-verify-db.pl
new file mode 100644
index 00000000..a6cd98ca
--- /dev/null
+++ b/ldap/admin/src/scripts/template-verify-db.pl
@@ -0,0 +1,196 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright (C) 2003-2004 AOL, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+sub getDbDir
+{
+ (my $here) = @_;
+ my @dbdirs = ();
+
+ opendir(DIR, $here) or die "can't opendir $here : $!";
+ while (defined($dir = readdir(DIR)))
+ {
+ my $thisdir;
+ if ("$here" eq ".")
+ {
+ $thisdir = $dir;
+ }
+ else
+ {
+ $thisdir = $here . "{{SEP}}" . $dir;
+ }
+ if (-d $thisdir)
+ {
+ if (!($thisdir =~ /\./))
+ {
+ opendir(SUBDIR, "$thisdir") or die "can't opendir $thisdir : $!";
+ while (defined($file = readdir(SUBDIR)))
+ {
+ if ($file eq "DBVERSION")
+ {
+ $#dbdirs++;
+ $dbdirs[$#dbdirs] = $thisdir;
+ }
+ }
+ closedir(SUBDIR);
+ }
+ }
+ }
+ closedir(DIR);
+
+ return \@dbdirs;
+}
+
+sub getLastLogfile
+{
+ (my $here) = @_;
+ my $logfile = "";
+
+ opendir(DIR, $here) or die "can't opendir $here : $!";
+ while (defined($file = readdir(DIR)))
+ {
+ if ($file =~ /log./)
+ {
+ $logfile = $file;
+ }
+ }
+ closedir(DIR);
+
+ return \$logfile;
+}
+
+print("*****************************************************************\n");
+print("verify-db: This tool should only be run if recovery start fails\n" .
+ "and the server is down. If you run this tool while the server is\n" .
+ "running, you may get false reports of corrupted files or other\n" .
+ "false errors.\n");
+print("*****************************************************************\n");
+
+# get dirs having DBVERSION
+my $dbdirs = getDbDir(".");
+
+for (my $i = 0; $i < @$dbdirs; $i++)
+{
+ # run ../bin/slapd/server/db_printlog -h <dbdir> for each <dbdir>
+ print "Verify log files in $$dbdirs[$i] ... ";
+ open(PRINTLOG, "..{{SEP}}bin{{SEP}}slapd{{SEP}}server{{SEP}}db_printlog -h $$dbdirs[$i] 2>&1 1> nul |");
+ sleep 1;
+ my $haserr = 0;
+ while ($l = <PRINTLOG>)
+ {
+ if ("$l" ne "")
+ {
+ if ($haserr == 0)
+ {
+ print "\n";
+ }
+ print "LOG ERROR: $l";
+ $haserr++;
+ }
+ }
+ close(PRINTLOG);
+ if ($haserr == 0 && $? == 0)
+ {
+ print "Good\n";
+ }
+ else
+ {
+ my $logfile = getLastLogfile($$dbdirs[$i]);
+ print "Log file(s) in $$dbdirs[$i] could be corrupted.\n";
+ print "Please delete a log file $$logfile, and try restarting the server.\n";
+ }
+}
+
+for (my $i = 0; $i < @$dbdirs; $i++)
+{
+ # changelog
+ opendir(DB, $$dbdirs[$i]) or die "can't opendir $$dbdirs[$i] : $!";
+ while (defined($db = readdir(DB)))
+ {
+ if ($db =~ /\.db/)
+ {
+ my $thisdb = $$dbdirs[$i] . "{{SEP}}" . $db;
+ print "Verify $thisdb ... ";
+ open(DBVERIFY, "..{{SEP}}bin{{SEP}}slapd{{SEP}}server{{SEP}}db_verify $thisdb 2>&1 1> nul |");
+ sleep 1;
+ my $haserr = 0;
+ while ($l = <DBVERIFY>)
+ {
+ if ($haserr == 0)
+ {
+ print "\n";
+ }
+ if ("$l" ne "")
+ {
+ $haserr++;
+ print "DB ERROR: $l";
+ }
+ }
+ close(DBVERIFY);
+ if ($haserr == 0 && $? == 0)
+ {
+ print "Good\n";
+ }
+ else
+ {
+ print "changelog file $db in $$dbdirs[$i] is corrupted.\n";
+ print "Please restore your backup and recover the database.\n";
+ }
+ }
+ }
+ closedir(DB);
+
+ # backend: get instance dirs under <dbdir>
+ my $instdirs = getDbDir($$dbdirs[$i]);
+
+ for (my $j = 0; $j < @$instdirs; $j++)
+ {
+ opendir(DIR, $$instdirs[$j]) or die "can't opendir $here : $!";
+ while (defined($db = readdir(DIR)))
+ {
+ if ($db =~ /\.db/)
+ {
+ my $thisdb = $$instdirs[$j] . "{{SEP}}" . $db;
+ print "Verify $thisdb ... ";
+ open(DBVERIFY, "..{{SEP}}bin{{SEP}}slapd{{SEP}}server{{SEP}}db_verify $thisdb 2>&1 1> null |");
+ sleep 1;
+ my $haserr = 0;
+ while ($l = <DBVERIFY>)
+ {
+ if ($haserr == 0)
+ {
+ print "\n";
+ }
+ if ("$l" ne "")
+ {
+ $haserr++;
+ print "DB ERROR: $l";
+ }
+ }
+ close(DBVERIFY);
+ if ($haserr == 0 && $? == 0)
+ {
+ print "Good\n";
+ }
+ else
+ {
+ if ("$db" =~ /id2entry.db/)
+ {
+ print "Primary db file $db in $$instdirs[$j] is corrupted.\n";
+ print "Please restore your backup and recover the database.\n";
+ }
+ else
+ {
+ print "Secondary index file $db in $$instdirs[$j] is corrupted.\n";
+ print "Please run db2index(.pl) for reindexing.\n";
+ }
+ }
+ }
+ }
+ closedir(DIR);
+ }
+}