summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNoriko Hosoi <nhosoi@redhat.com>2006-10-25 20:36:46 +0000
committerNoriko Hosoi <nhosoi@redhat.com>2006-10-25 20:36:46 +0000
commit1c02a56cfc3185d4db4a336f6a2be11bc55c1c8f (patch)
treedfc204ae9969e272f3deff8e0f87dd67ac7a13cd
parent603b79151aa03f9150216fba4b8b4faa1e63a755 (diff)
downloadds-1c02a56cfc3185d4db4a336f6a2be11bc55c1c8f.tar.gz
ds-1c02a56cfc3185d4db4a336f6a2be11bc55c1c8f.tar.xz
ds-1c02a56cfc3185d4db4a336f6a2be11bc55c1c8f.zip
Resolves: #212098
Summary: Use autoconf to generate task perl script templates Changes: 1) added template files to AC_CONFIG_FILES list 2) added db_bindir and ldapsdk_bindir to pass their tools path to the template files. The paths are hardcoded for now.
-rw-r--r--configure.ac17
-rw-r--r--ldap/admin/src/scripts/template-bak2db.pl.in134
-rwxr-xr-xldap/admin/src/scripts/template-cl-dump.pl2
-rwxr-xr-xldap/admin/src/scripts/template-cl-dump.pl.in348
-rw-r--r--ldap/admin/src/scripts/template-db2bak.pl.in123
-rw-r--r--ldap/admin/src/scripts/template-db2index.pl.in227
-rw-r--r--ldap/admin/src/scripts/template-db2ldif.pl.in250
-rw-r--r--ldap/admin/src/scripts/template-ldif2db.pl.in226
-rw-r--r--ldap/admin/src/scripts/template-ns-accountstatus.pl.in846
-rw-r--r--ldap/admin/src/scripts/template-ns-activate.pl.in846
-rw-r--r--ldap/admin/src/scripts/template-ns-inactivate.pl.in846
-rwxr-xr-xldap/admin/src/scripts/template-ns-newpwpolicy.pl8
-rwxr-xr-xldap/admin/src/scripts/template-ns-newpwpolicy.pl.in279
-rwxr-xr-xldap/admin/src/scripts/template-repl-monitor-cgi.pl2
-rwxr-xr-xldap/admin/src/scripts/template-repl-monitor-cgi.pl.in75
-rwxr-xr-xldap/admin/src/scripts/template-repl-monitor.pl.in996
-rw-r--r--ldap/admin/src/scripts/template-verify-db.pl2
-rw-r--r--ldap/admin/src/scripts/template-verify-db.pl.in241
-rw-r--r--m4/db.m42
-rw-r--r--m4/mozldap.m43
20 files changed, 5467 insertions, 6 deletions
diff --git a/configure.ac b/configure.ac
index 1e63e72f..46643b31 100644
--- a/configure.ac
+++ b/configure.ac
@@ -104,10 +104,12 @@ AC_SUBST(nss_libdir)
AC_SUBST(ldapsdk_inc)
AC_SUBST(ldapsdk_lib)
AC_SUBST(ldapsdk_libdir)
+AC_SUBST(ldapsdk_bindir)
AC_SUBST(db_inc)
AC_SUBST(db_incdir)
AC_SUBST(db_lib)
AC_SUBST(db_libdir)
+AC_SUBST(db_bindir)
AC_SUBST(sasl_inc)
AC_SUBST(sasl_lib)
AC_SUBST(sasl_libdir)
@@ -153,4 +155,19 @@ AC_CONFIG_FILES([wrappers/migratecred])
AC_CONFIG_FILES([wrappers/mmldif])
AC_CONFIG_FILES([wrappers/pwdhash])
AC_CONFIG_FILES([wrappers/rsearch])
+
+AC_CONFIG_FILES([ldap/admin/src/scripts/template-bak2db.pl])
+AC_CONFIG_FILES([ldap/admin/src/scripts/template-cl-dump.pl])
+AC_CONFIG_FILES([ldap/admin/src/scripts/template-db2bak.pl])
+AC_CONFIG_FILES([ldap/admin/src/scripts/template-db2index.pl])
+AC_CONFIG_FILES([ldap/admin/src/scripts/template-db2ldif.pl])
+AC_CONFIG_FILES([ldap/admin/src/scripts/template-ldif2db.pl])
+AC_CONFIG_FILES([ldap/admin/src/scripts/template-ns-accountstatus.pl])
+AC_CONFIG_FILES([ldap/admin/src/scripts/template-ns-activate.pl])
+AC_CONFIG_FILES([ldap/admin/src/scripts/template-ns-inactivate.pl])
+AC_CONFIG_FILES([ldap/admin/src/scripts/template-ns-newpwpolicy.pl])
+AC_CONFIG_FILES([ldap/admin/src/scripts/template-repl-monitor-cgi.pl])
+AC_CONFIG_FILES([ldap/admin/src/scripts/template-repl-monitor.pl])
+AC_CONFIG_FILES([ldap/admin/src/scripts/template-verify-db.pl])
+
AC_OUTPUT
diff --git a/ldap/admin/src/scripts/template-bak2db.pl.in b/ldap/admin/src/scripts/template-bak2db.pl.in
new file mode 100644
index 00000000..efebee2e
--- /dev/null
+++ b/ldap/admin/src/scripts/template-bak2db.pl.in
@@ -0,0 +1,134 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2005 Red Hat, Inc.
+# 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 " : -n backend - name of backend instance to restore\n");
+ print(STDERR " : -v - verbose\n");
+}
+$taskname = "";
+$archivedir = "";
+$dbtype = "ldbm database";
+$instance = "";
+$prefix = "{{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 "-n") { # backend instance name
+ $i++; $instance = $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);
+}
+use File::Spec;
+$isabs = File::Spec->file_name_is_absolute( $archivedir );
+if (!$isabs) {
+ $archivedir = File::Spec->rel2abs( $archivedir );
+}
+$dn = "dn: cn=$taskname, cn=restore, cn=tasks, cn=config\n";
+$misc = "changetype: add\nobjectclass: top\nobjectclass: extensibleObject\n";
+$cn = "cn: $taskname\n";
+if ($instance ne "") {
+ $nsinstance = "nsInstance: ${instance}\n";
+}
+$nsarchivedir = "nsArchiveDir: $archivedir\n";
+$nsdbtype = "nsDatabaseType: $dbtype\n";
+$entry = "${dn}${misc}${cn}${nsinstance}${nsarchivedir}${nsdbtype}";
+$vstr = "";
+if ($verbose != 0) { $vstr = "-v"; }
+$ENV{'PATH'} = '$prefix@ldapsdk_bindir@:$prefix/usr/lib:@ldapsdk_bindir@:/usr/lib';
+$ENV{'LD_LIBRARY_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+$ENV{'SHLIB_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+open(FOO, "| 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
index ae611a9e..7320b1fc 100755
--- a/ldap/admin/src/scripts/template-cl-dump.pl
+++ b/ldap/admin/src/scripts/template-cl-dump.pl
@@ -99,6 +99,8 @@
# enable the use of our bundled perldap with our bundled ldapsdk libraries
# all of this nonsense can be omitted if the mozldapsdk and perldap are
# installed in the operating system locations (e.g. /usr/lib /usr/lib/perl5)
+$prefix = "{{DS-ROOT}}";
+
$ENV{'LD_LIBRARY_PATH'} = '$prefix/usr/lib/dirsec:$prefix/usr/lib:/usr/lib/dirsec:/usr/lib';
$ENV{'SHLIB_PATH'} = '$prefix/usr/lib/dirsec:$prefix/usr/lib:/usr/lib/dirsec:/usr/lib';
diff --git a/ldap/admin/src/scripts/template-cl-dump.pl.in b/ldap/admin/src/scripts/template-cl-dump.pl.in
new file mode 100755
index 00000000..c3583667
--- /dev/null
+++ b/ldap/admin/src/scripts/template-cl-dump.pl.in
@@ -0,0 +1,348 @@
+#{{PERL-EXEC}}
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2005 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+###################################################################################
+#
+# 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 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
+#
+################################################################################
+# enable the use of our bundled perldap with our bundled ldapsdk libraries
+# all of this nonsense can be omitted if the mozldapsdk and perldap are
+# installed in the operating system locations (e.g. /usr/lib /usr/lib/perl5)
+$prefix = "{{DS-ROOT}}";
+
+$ENV{'LD_LIBRARY_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+$ENV{'SHLIB_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+
+$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 = "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.in b/ldap/admin/src/scripts/template-db2bak.pl.in
new file mode 100644
index 00000000..abc42978
--- /dev/null
+++ b/ldap/admin/src/scripts/template-db2bak.pl.in
@@ -0,0 +1,123 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2005 Red Hat, Inc.
+# 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";
+$prefix = "{{DS-ROOT}}";
+$mybakdir = "{{BAK-DIR}}";
+$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 = "${bakdir}{{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"; }
+$ENV{'PATH'} = '$prefix@ldapsdk_bindir@:$prefix/usr/lib:@ldapsdk_bindir@:/usr/lib';
+$ENV{'LD_LIBRARY_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+$ENV{'SHLIB_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+open(FOO, "| 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.in b/ldap/admin/src/scripts/template-db2index.pl.in
new file mode 100644
index 00000000..7c527552
--- /dev/null
+++ b/ldap/admin/src/scripts/template-db2index.pl.in
@@ -0,0 +1,227 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2005 Red Hat, Inc.
+# 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 - verbose\n");
+}
+
+$instance = "";
+$rootdn = "";
+$passwd = "";
+$passwdfile = "";
+$attribute_arg = "";
+$vlvattribute_arg = "";
+$verbose = 0;
+
+$prefix = "{{DS-ROOT}}";
+
+$ENV{'PATH'} = '$prefix@ldapsdk_bindir@:$prefix/usr/lib:@ldapsdk_bindir@:/usr/lib';
+$ENV{'LD_LIBRARY_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+$ENV{'SHLIB_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+
+$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);
+}
+
+# No attribute name has been specified: let's get them from the configuration
+$attribute="";
+$indexes_list="";
+$vlvattribute="";
+$vlvindexes_list="";
+chdir("$prefix{{SEP}}usr{{SEP}}bin");
+if ( $attribute_arg eq "" && $vlvattribute_arg eq "" )
+{
+ # Get the list of indexes from the entry
+ $indexes_list="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="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}";
+open(FOO, "| 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.in b/ldap/admin/src/scripts/template-db2ldif.pl.in
new file mode 100644
index 00000000..3043821f
--- /dev/null
+++ b/ldap/admin/src/scripts/template-db2ldif.pl.in
@@ -0,0 +1,250 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2005 Red Hat, Inc.
+# 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;
+$prefix = "{{DS-ROOT}}";
+$ldifdir = "{{LDIF-DIR}}";
+$servid = "{{SERV-ID}}";
+$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 = "${ldifdir}{{SEP}}${servid}-${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"; }
+$ENV{'PATH'} = '$prefix@ldapsdk_bindir@:$prefix/usr/lib:@ldapsdk_bindir@:/usr/lib';
+$ENV{'LD_LIBRARY_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+$ENV{'SHLIB_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+open(FOO, "| 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-ldif2db.pl.in b/ldap/admin/src/scripts/template-ldif2db.pl.in
new file mode 100644
index 00000000..ed936a88
--- /dev/null
+++ b/ldap/admin/src/scripts/template-ldif2db.pl.in
@@ -0,0 +1,226 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2005 Red Hat, Inc.
+# 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 = "";
+$prefix = "{{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"; }
+$ENV{'PATH'} = '$prefix@ldapsdk_bindir@:$prefix/usr/lib:@ldapsdk_bindir@:/usr/lib';
+$ENV{'LD_LIBRARY_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+$ENV{'SHLIB_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+open(FOO, "| 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-ns-accountstatus.pl.in b/ldap/admin/src/scripts/template-ns-accountstatus.pl.in
new file mode 100644
index 00000000..384f5f6c
--- /dev/null
+++ b/ldap/admin/src/scripts/template-ns-accountstatus.pl.in
@@ -0,0 +1,846 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2005 Red Hat, Inc.
+# 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
+$prefix="{{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");
+
+$ENV{'PATH'} = '$prefix@ldapsdk_bindir@:$prefix/usr/lib:@ldapsdk_bindir@:/usr/lib';
+$ENV{'LD_LIBRARY_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+$ENV{'SHLIB_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+
+$ldapsearch="ldapsearch -1";
+$ldapmodify="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;
+
+# 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.in b/ldap/admin/src/scripts/template-ns-activate.pl.in
new file mode 100644
index 00000000..384f5f6c
--- /dev/null
+++ b/ldap/admin/src/scripts/template-ns-activate.pl.in
@@ -0,0 +1,846 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2005 Red Hat, Inc.
+# 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
+$prefix="{{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");
+
+$ENV{'PATH'} = '$prefix@ldapsdk_bindir@:$prefix/usr/lib:@ldapsdk_bindir@:/usr/lib';
+$ENV{'LD_LIBRARY_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+$ENV{'SHLIB_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+
+$ldapsearch="ldapsearch -1";
+$ldapmodify="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;
+
+# 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.in b/ldap/admin/src/scripts/template-ns-inactivate.pl.in
new file mode 100644
index 00000000..384f5f6c
--- /dev/null
+++ b/ldap/admin/src/scripts/template-ns-inactivate.pl.in
@@ -0,0 +1,846 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2005 Red Hat, Inc.
+# 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
+$prefix="{{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");
+
+$ENV{'PATH'} = '$prefix@ldapsdk_bindir@:$prefix/usr/lib:@ldapsdk_bindir@:/usr/lib';
+$ENV{'LD_LIBRARY_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+$ENV{'SHLIB_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+
+$ldapsearch="ldapsearch -1";
+$ldapmodify="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;
+
+# 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
index d0f93773..6a8ba72c 100755
--- a/ldap/admin/src/scripts/template-ns-newpwpolicy.pl
+++ b/ldap/admin/src/scripts/template-ns-newpwpolicy.pl
@@ -42,6 +42,8 @@
# enable the use of our bundled perldap with our bundled ldapsdk libraries
# all of this nonsense can be omitted if the mozldapsdk and perldap are
# installed in the operating system locations (e.g. /usr/lib /usr/lib/perl5)
+$prefix = "{{DS-ROOT}}";
+
$ENV{'PATH'} = '$prefix/usr/lib/mozldap6:$prefix/usr/lib:/usr/lib/mozldap6:/usr/lib';
$ENV{'LD_LIBRARY_PATH'} = '$prefix/usr/lib/dirsec:$prefix/usr/lib:/usr/lib/dirsec:/usr/lib';
$ENV{'SHLIB_PATH'} = '$prefix/usr/lib/dirsec:$prefix/usr/lib:/usr/lib/dirsec:/usr/lib';
@@ -64,12 +66,6 @@ $opt_p = "{{SERVER-PORT}}";
$opt_h = "{{SERVER-NAME}}";
$opt_v = 0;
-$ENV{'PATH'} = '$prefix{{SEP}}usr{{SEP}}lib:{{SEP}}usr{{SEP}}lib{{SEP}}mozldap';
-$ENV{'LD_LIBRARY_PATH'} .= ":";
-$ENV{'LD_LIBRARY_PATH'} .= "$prefix{{SEP}}usr{{SEP}}lib:{{SEP}}usr{{SEP}}lib{{SEP}}mozldap";
-$ENV{'SHLIB_PATH'} .= ":";
-$ENV{'SHLIB_PATH'} .= "$prefix{{SEP}}usr{{SEP}}lib:{{SEP}}usr{{SEP}}lib{{SEP}}mozldap";
-
# Variables
$ldapsearch="ldapsearch -1";
$ldapmodify="ldapmodify";
diff --git a/ldap/admin/src/scripts/template-ns-newpwpolicy.pl.in b/ldap/admin/src/scripts/template-ns-newpwpolicy.pl.in
new file mode 100755
index 00000000..56d20956
--- /dev/null
+++ b/ldap/admin/src/scripts/template-ns-newpwpolicy.pl.in
@@ -0,0 +1,279 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2005 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# enable the use of our bundled perldap with our bundled ldapsdk libraries
+# all of this nonsense can be omitted if the mozldapsdk and perldap are
+# installed in the operating system locations (e.g. /usr/lib /usr/lib/perl5)
+$prefix = "{{DS-ROOT}}";
+
+$ENV{'PATH'} = '$prefix@ldapsdk_bindir@:$prefix/usr/lib:@ldapsdk_bindir@:/usr/lib';
+$ENV{'LD_LIBRARY_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+$ENV{'SHLIB_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+# 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="ldapsearch -1";
+$ldapmodify="ldapmodify";
+
+#############################################################################
+
+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
index b2342bf4..d365672a 100755
--- a/ldap/admin/src/scripts/template-repl-monitor-cgi.pl
+++ b/ldap/admin/src/scripts/template-repl-monitor-cgi.pl
@@ -56,6 +56,8 @@ if ($cgiVars{'admurl'}) {
$params .= " -u \"$admurl\"";
}
$siteroot = $cgiVars{'siteroot'};
+$prefix = "{{DS-ROOT}}";
+
$ENV{'PATH'} = '$prefix/usr/lib/mozldap6:$prefix/usr/lib:/usr/lib/mozldap6:/usr/lib';
$ENV{'LD_LIBRARY_PATH'} = '$prefix/usr/lib/dirsec:$prefix/usr/lib:/usr/lib/dirsec:/usr/lib';
$ENV{'SHLIB_PATH'} = '$prefix/usr/lib/dirsec:$prefix/usr/lib:/usr/lib/dirsec:/usr/lib';
diff --git a/ldap/admin/src/scripts/template-repl-monitor-cgi.pl.in b/ldap/admin/src/scripts/template-repl-monitor-cgi.pl.in
new file mode 100755
index 00000000..ad52ce4d
--- /dev/null
+++ b/ldap/admin/src/scripts/template-repl-monitor-cgi.pl.in
@@ -0,0 +1,75 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2005 Red Hat, Inc.
+# 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'};
+$prefix = "{{DS-ROOT}}";
+
+$ENV{'PATH'} = '$prefix@ldapsdk_bindir@:$prefix/usr/lib:@ldapsdk_bindir@:/usr/lib';
+$ENV{'LD_LIBRARY_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/lib';
+$ENV{'SHLIB_PATH'} = '$prefix@nss_libdir@:$prefix/usr/lib:@nss_libdir@:/usr/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 -I$siteroot/lib/perl/arch -I$siteroot/lib/perl $replmon $params");
diff --git a/ldap/admin/src/scripts/template-repl-monitor.pl.in b/ldap/admin/src/scripts/template-repl-monitor.pl.in
new file mode 100755
index 00000000..d1ec4bb6
--- /dev/null
+++ b/ldap/admin/src/scripts/template-repl-monitor.pl.in
@@ -0,0 +1,996 @@
+#{{PERL-EXEC}}
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
+# Copyright (C) 2005 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+##############################################################################
+#
+# 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:/opt/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. This should be under serverroot/lib/perl
+# e.g. PERL5LIB="serverroot/lib/perl/arch:serverroot/lib/perl"
+#
+# 4. Set LD_LIBRARY_PATH (or SHLIB_PATH) to point to the location of our
+# bundled shared libraries e.g. LD_LIBRARY_PATH="serverroot/lib"
+#
+# 5. Invoke the script as follows if <MYPERLDIR> (serverroot/lib/perl) contains
+# Mozilla/LDAP:
+# <MYPERLDIR>/bin/perl -I <MYPERLDIR>/arch -I <MYPERLDIR> repl-monitor.pl
+#
+#############################################################################
+# enable the use of our bundled perldap with our bundled ldapsdk libraries
+# all of this nonsense can be omitted if the mozldapsdk and perldap are
+# installed in the operating system locations (e.g. /usr/lib /usr/lib/perl5)
+# this script is always invoked by repl-monitor-cgi.pl, which sets all of these
+# If using this script standalone, be sure to set the shared lib path and
+# the path to the perldap modules.
+$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 = "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 "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
index 91d37975..38758562 100644
--- a/ldap/admin/src/scripts/template-verify-db.pl
+++ b/ldap/admin/src/scripts/template-verify-db.pl
@@ -112,6 +112,8 @@ print("*****************************************************************\n");
# get dirs having DBVERSION
my $dbdirs = getDbDir(".");
my $brand_ds = {{DS-BRAND}};
+my $prefix = "{{DS-ROOT}}";
+
$ENV{'PATH'} = '$prefix/usr/bin:$prefix/usr/lib:/usr/bin:/usr/lib';
$ENV{'LD_LIBRARY_PATH'} = ':/usr/lib';
$ENV{'SHLIB_PATH'} = ':/usr/lib';
diff --git a/ldap/admin/src/scripts/template-verify-db.pl.in b/ldap/admin/src/scripts/template-verify-db.pl.in
new file mode 100644
index 00000000..8cf45afa
--- /dev/null
+++ b/ldap/admin/src/scripts/template-verify-db.pl.in
@@ -0,0 +1,241 @@
+#{{PERL-EXEC}}
+#
+# BEGIN COPYRIGHT BLOCK
+# This Program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This Program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# In addition, as a special exception, Red Hat, Inc. gives You the additional
+# right to link the code of this Program with code not covered under the GNU
+# General Public License ("Non-GPL Code") and to distribute linked combinations
+# including the two, subject to the limitations in this paragraph. Non-GPL Code
+# permitted under this exception must only link to the code of this Program
+# through those well defined interfaces identified in the file named EXCEPTION
+# found in the source code files (the "Approved Interfaces"). The files of
+# Non-GPL Code may instantiate templates or use macros or inline functions from
+# the Approved Interfaces without causing the resulting work to be covered by
+# the GNU General Public License. Only Red Hat, Inc. may make changes or
+# additions to the list of Approved Interfaces. You must obey the GNU General
+# Public License in all respects for all of the Program code and other code used
+# in conjunction with the Program except the Non-GPL Code covered by this
+# exception. If you modify this file, you may extend this exception to your
+# version of the file, but you are not obligated to do so. If you do not wish to
+# provide this exception without modification, you must delete this exception
+# statement from your version and license this file solely under the GPL without
+# exception.
+#
+#
+# Copyright (C) 2005 Red Hat, 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;
+}
+
+$isWin = -d '\\';
+if ($isWin) {
+ $NULL = "nul";
+} else {
+ $NULL = "/dev/null";
+}
+
+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(".");
+my $brand_ds = {{DS-BRAND}};
+my $prefix = "{{DS-ROOT}}";
+
+$ENV{'PATH'} = '$prefix@db_bindir@:$prefix/usr/lib:@db_bindir@:/usr/lib';
+$ENV{'LD_LIBRARY_PATH'} = '@db_libdir@:/usr/lib';
+$ENV{'SHLIB_PATH'} = '@db_libdir@:/usr/lib';
+
+for (my $i = 0; $i < @$dbdirs; $i++)
+{
+ # run db_printlog -h <dbdir> for each <dbdir>
+ print "Verify log files in $$dbdirs[$i] ... ";
+ open(PRINTLOG, "db_printlog -h $$dbdirs[$i] 2>&1 1> $NULL |");
+ 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, "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
+ {
+ 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, "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);
+ }
+}
diff --git a/m4/db.m4 b/m4/db.m4
index 8d520c54..e463ed7f 100644
--- a/m4/db.m4
+++ b/m4/db.m4
@@ -50,6 +50,8 @@ AC_ARG_WITH(db, [ --with-db=PATH Berkeley DB directory],
fi
],
AC_MSG_RESULT(no))
+dnl default path for the db tools (see [210947] for more details)
+db_bindir=/usr/bin
dnl - check in system locations
if test -z "$db_inc"; then
diff --git a/m4/mozldap.m4 b/m4/mozldap.m4
index 8007ad27..6db01ea0 100644
--- a/m4/mozldap.m4
+++ b/m4/mozldap.m4
@@ -89,6 +89,9 @@ fi
if test -z "$ldapsdk_inc" -o -z "$ldapsdk_lib"; then
AC_MSG_ERROR([LDAPSDK not found, specify with --with-ldapsdk[-inc|-lib].])
fi
+dnl default path for the ldap c sdk tools (see [210947] for more details)
+ldapsdk_bindir=/usr/lib/mozldap6
+
dnl make sure the ldap sdk version is 6 or greater - we do not support
dnl the old 5.x or prior versions - the ldap server code expects the new
dnl ber types and other code used with version 6