diff options
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:  $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: </font>"; + print "<font class=text28>$serverid</font>\n"; + + print "<font class=areatitle>Replica Root: </font>"; + print "<font class=text28>$replicaroot</font>\n"; + + print "<font class=areatitle>Max CSN: </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); + } +} @@ -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 |