From 8c13153e739afa9d7f2480d1b488ec7c76036802 Mon Sep 17 00:00:00 2001
From: Rich Megginson <rmeggins@redhat.com>
Date: Wed, 9 Sep 2009 17:01:49 -0600
Subject: [PATCH] Add update code - make setup-ds.pl -u do updates
 Updates are implemented in:
 perl - code that plugs in to setup - scriptlets that are imported into
 the setup perl interpreter and executed in process, giving access to all
 of the packages and context provided by setup
 ldif - applied to instances, in the same manner as ConfigFile directives
 to setup
 other - any executable file, shell script, etc. can be invoked, with a limited
 amount of context from the setup process
 An update directory is added to the package - /usr/share/dirsrv/update - this
 directory contains the update files - the update filenames begin with two digits
 and are executed in numeric order (00 first, then 01, etc. up to 99) which
 should provide enough flexibility
 In addition, there are 5 stages of update:
 pre - invoked before any instance specific code
 preinst, runinst, postinst - invoked for each instance
 post - invoked after any instance specific code
 Example files are provided which demonstrate how to get the context.
 There are two different modes of operation for update:
 online - must supply a bind dn and password for each instance - servers must
 be up and running
 offline - operates directly on the dse.ldif - servers must be shutdown first
 A new section is added to the .inf file that can be passed in

[slapd-instancename]
RootDN = binddn
RootDNPwd = bindpw

The RootDN is optional - if not supplied, it will get the nsslapd-rootdn attribute from the dse.ldif for the instance.
I also fixed some problems with error messages.
The pam pta plugin entry was giving object class violations, so I added the
missing attributes - note that these are replaced by the plugin code when
the plugin is loaded - they are only needed during setup.

Fixed usage of $_ - $_ behaves like a dynamically scoped variable - which
means if you use it in an outer context, you cannot use it in an inner
context, even if it is used in a different function.  Rather than attempting
to figure out how to use $_ safely in lower level functions, I just removed
the use of it altogether, which also makes the code easier to read.
---
 Makefile.am                                        |   51 ++-
 Makefile.in                                        |  131 +++++-
 configure                                          |   28 +-
 configure.ac                                       |    7 +-
 .../src/scripts/50addchainingsaslpwroles.ldif      |    6 +
 .../admin/src/scripts/50bitstringsyntaxplugin.ldif |   14 +
 .../src/scripts/50deliverymethodsyntaxplugin.ldif  |   14 +
 ldap/admin/src/scripts/50derefplugin.ldif          |   16 +
 .../src/scripts/50disableurisyntaxplugin.ldif      |    9 +
 .../src/scripts/50enhancedguidesyntaxplugin.ldif   |   14 +
 ldap/admin/src/scripts/50entryusnindex.ldif        |    7 +
 .../admin/src/scripts/50faxnumbersyntaxplugin.ldif |   14 +
 ldap/admin/src/scripts/50faxsyntaxplugin.ldif      |   14 +
 ldap/admin/src/scripts/50guidesyntaxplugin.ldif    |   14 +
 ldap/admin/src/scripts/50linkedattrsplugin.ldif    |   16 +
 ldap/admin/src/scripts/50memberofindex.ldif        |    6 +
 ldap/admin/src/scripts/50memberofplugin.ldif       |   17 +
 ldap/admin/src/scripts/50nameuidsyntaxplugin.ldif  |   14 +
 .../src/scripts/50numericstringsyntaxplugin.ldif   |   14 +
 .../src/scripts/50printablestringsyntaxplugin.ldif |   14 +
 ldap/admin/src/scripts/50schemareloadplugin.ldif   |   14 +
 ldap/admin/src/scripts/50syntaxvalidplugin.ldif    |   14 +
 .../scripts/50teletexterminalidsyntaxplugin.ldif   |   14 +
 .../src/scripts/50telexnumbersyntaxplugin.ldif     |   14 +
 ldap/admin/src/scripts/50usnplugin.ldif            |   15 +
 ldap/admin/src/scripts/60upgradeschemafiles.pl     |   54 ++
 ldap/admin/src/scripts/DSCreate.pm.in              |   51 ++-
 ldap/admin/src/scripts/DSUpdate.pm.in              |  505 ++++++++++++++++++++
 ldap/admin/src/scripts/DSUpdateDialogs.pm          |  181 +++++++
 ldap/admin/src/scripts/FileConn.pm                 |   20 +-
 ldap/admin/src/scripts/Inf.pm                      |   27 +-
 ldap/admin/src/scripts/Resource.pm                 |   17 +-
 ldap/admin/src/scripts/Setup.pm.in                 |   44 ++-
 ldap/admin/src/scripts/Util.pm.in                  |   41 +-
 ldap/admin/src/scripts/dnaplugindepends.ldif       |    4 +
 ldap/admin/src/scripts/dsupdate.map.in             |   65 +++
 ldap/admin/src/scripts/exampleupdate.ldif          |   40 ++
 ldap/admin/src/scripts/exampleupdate.pl            |   56 +++
 ldap/admin/src/scripts/exampleupdate.sh            |   63 +++
 ldap/admin/src/scripts/migrate-ds.res              |    1 -
 ldap/admin/src/scripts/setup-ds.pl.in              |   47 ++-
 ldap/admin/src/scripts/setup-ds.res.in             |   45 ++
 ldap/ldif/template-pampta.ldif.in                  |    6 +-
 43 files changed, 1628 insertions(+), 130 deletions(-)
 create mode 100644 ldap/admin/src/scripts/50addchainingsaslpwroles.ldif
 create mode 100644 ldap/admin/src/scripts/50bitstringsyntaxplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50deliverymethodsyntaxplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50derefplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50disableurisyntaxplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50enhancedguidesyntaxplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50entryusnindex.ldif
 create mode 100644 ldap/admin/src/scripts/50faxnumbersyntaxplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50faxsyntaxplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50guidesyntaxplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50linkedattrsplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50memberofindex.ldif
 create mode 100644 ldap/admin/src/scripts/50memberofplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50nameuidsyntaxplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50numericstringsyntaxplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50printablestringsyntaxplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50schemareloadplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50syntaxvalidplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50teletexterminalidsyntaxplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50telexnumbersyntaxplugin.ldif
 create mode 100644 ldap/admin/src/scripts/50usnplugin.ldif
 create mode 100644 ldap/admin/src/scripts/60upgradeschemafiles.pl
 create mode 100644 ldap/admin/src/scripts/DSUpdate.pm.in
 create mode 100644 ldap/admin/src/scripts/DSUpdateDialogs.pm
 create mode 100644 ldap/admin/src/scripts/dnaplugindepends.ldif
 create mode 100644 ldap/admin/src/scripts/dsupdate.map.in
 create mode 100644 ldap/admin/src/scripts/exampleupdate.ldif
 create mode 100644 ldap/admin/src/scripts/exampleupdate.pl
 create mode 100644 ldap/admin/src/scripts/exampleupdate.sh

diff --git a/Makefile.am b/Makefile.am
index 665b1f4..ade0d66 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -69,6 +69,7 @@ CLEANFILES =  dberrstrs.h ns-slapd.properties \
 	ldap/admin/src/scripts/template-dbverify ldap/admin/src/template-initconfig \
 	ldap/admin/src/scripts/dscreate.map ldap/admin/src/scripts/remove-ds.pl \
 	ldap/admin/src/scripts/DSCreate.pm ldap/admin/src/scripts/DSMigration.pm \
+	ldap/admin/src/scripts/DSUpdate.pm ldap/admin/src/scripts/dsupdate.map \
 	ldap/admin/src/scripts/dsorgentries.map ldap/admin/src/scripts/migrate-ds.pl \
 	ldap/admin/src/scripts/Migration.pm ldap/admin/src/scripts/SetupDialogs.pm \
 	ldap/admin/src/scripts/setup-ds.pl ldap/admin/src/scripts/setup-ds.res \
@@ -128,6 +129,7 @@ perldir = $(libdir)@perldir@
 infdir = $(datadir)@infdir@
 mibdir = $(datadir)@mibdir@
 policydir = $(datadir)/selinux/targeted
+updatedir = $(datadir)@updatedir@
 
 defaultuser=@defaultuser@
 defaultgroup=@defaultgroup@
@@ -307,7 +309,9 @@ perl_DATA = ldap/admin/src/scripts/SetupLog.pm \
 	ldap/admin/src/scripts/Migration.pm \
 	ldap/admin/src/scripts/DSMigration.pm \
 	ldap/admin/src/scripts/FileConn.pm \
-	ldap/admin/src/scripts/DSCreate.pm
+	ldap/admin/src/scripts/DSCreate.pm \
+	ldap/admin/src/scripts/DSUpdate.pm \
+	ldap/admin/src/scripts/DSUpdateDialogs.pm
 
 property_DATA = ldap/admin/src/scripts/setup-ds.res \
 	ldap/admin/src/scripts/migrate-ds.res
@@ -349,6 +353,7 @@ initconfig_DATA = ldap/admin/src/$(PACKAGE_NAME)
 
 inf_DATA = ldap/admin/src/slapd.inf \
 	ldap/admin/src/scripts/dscreate.map \
+	ldap/admin/src/scripts/dsupdate.map \
 	ldap/admin/src/scripts/dsorgentries.map
 
 mib_DATA = ldap/servers/snmp/RFC-1215.txt \
@@ -381,6 +386,44 @@ dist_man_MANS = man/man1/dbscan.1 \
         man/man8/setup-ds.pl.8 \
 	man/man8/remove-ds.pl.8
 
+#------------------------
+# updates
+# the first 3 are just the examples provided - since they
+# do not begin with two digits, they will be ignored
+# the remaining items should begin with two digits that
+# correspond to the order in which they should be applied
+# perl files and LDIF files are DATA - not executable
+# processed by the update script
+# shell scripts and other files are SCRIPTS - executable
+#------------------------
+update_DATA = ldap/admin/src/scripts/exampleupdate.pl \
+	ldap/admin/src/scripts/exampleupdate.ldif \
+	ldap/admin/src/scripts/50addchainingsaslpwroles.ldif \
+	ldap/admin/src/scripts/50memberofindex.ldif \
+	ldap/admin/src/scripts/50bitstringsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50memberofplugin.ldif \
+	ldap/admin/src/scripts/50deliverymethodsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50nameuidsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50derefplugin.ldif \
+	ldap/admin/src/scripts/50numericstringsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50disableurisyntaxplugin.ldif \
+	ldap/admin/src/scripts/50printablestringsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50enhancedguidesyntaxplugin.ldif \
+	ldap/admin/src/scripts/50schemareloadplugin.ldif \
+	ldap/admin/src/scripts/50entryusnindex.ldif \
+	ldap/admin/src/scripts/50syntaxvalidplugin.ldif \
+	ldap/admin/src/scripts/50faxnumbersyntaxplugin.ldif \
+	ldap/admin/src/scripts/50teletexterminalidsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50faxsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50telexnumbersyntaxplugin.ldif \
+	ldap/admin/src/scripts/50guidesyntaxplugin.ldif \
+	ldap/admin/src/scripts/50linkedattrsplugin.ldif \
+	ldap/admin/src/scripts/50usnplugin.ldif \
+	ldap/admin/src/scripts/60upgradeschemafiles.pl \
+	ldap/admin/src/scripts/dnaplugindepends.ldif
+
+update_SCRIPTS = ldap/admin/src/scripts/exampleupdate.sh
+
 #////////////////////////////////////////////////////////////////
 #
 #   Server Strings
@@ -1249,7 +1292,8 @@ fixupcmd = sed \
 	-e 's,@with_fhs_opt\@,@with_fhs_opt@,g' \
 	-e 's,@with_selinux\@,@with_selinux@,g' \
 	-e 's,@perlexec\@,@perlexec@,g' \
-	-e 's,@initconfigdir\@,$(initconfigdir),g'
+	-e 's,@initconfigdir\@,$(initconfigdir),g'\
+	-e 's,@updatedir\@,$(updatedir),g'
 else
 fixupcmd = sed \
 	-e 's,@bindir\@,$(bindir),g' \
@@ -1301,7 +1345,8 @@ fixupcmd = sed \
 	-e 's,@with_fhs_opt\@,@with_fhs_opt@,g' \
 	-e 's,@with_selinux\@,@with_selinux@,g' \
 	-e 's,@perlexec\@,@perlexec@,g' \
-	-e 's,@initconfigdir\@,$(initconfigdir),g'
+	-e 's,@initconfigdir\@,$(initconfigdir),g' \
+	-e 's,@updatedir\@,$(updatedir),g'
 endif
 
 %: %.in
diff --git a/Makefile.in b/Makefile.in
index a09bdd4..8526a03 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -97,13 +97,14 @@ am__installdirs = "$(DESTDIR)$(serverdir)" \
 	"$(DESTDIR)$(serverplugindir)" "$(DESTDIR)$(bindir)" \
 	"$(DESTDIR)$(sbindir)" "$(DESTDIR)$(bindir)" \
 	"$(DESTDIR)$(initdir)" "$(DESTDIR)$(sbindir)" \
-	"$(DESTDIR)$(taskdir)" "$(DESTDIR)$(man1dir)" \
-	"$(DESTDIR)$(man8dir)" "$(DESTDIR)$(configdir)" \
-	"$(DESTDIR)$(infdir)" "$(DESTDIR)$(initconfigdir)" \
-	"$(DESTDIR)$(mibdir)" "$(DESTDIR)$(propertydir)" \
-	"$(DESTDIR)$(perldir)" "$(DESTDIR)$(policydir)" \
-	"$(DESTDIR)$(propertydir)" "$(DESTDIR)$(sampledatadir)" \
-	"$(DESTDIR)$(schemadir)"
+	"$(DESTDIR)$(taskdir)" "$(DESTDIR)$(updatedir)" \
+	"$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)" \
+	"$(DESTDIR)$(configdir)" "$(DESTDIR)$(infdir)" \
+	"$(DESTDIR)$(initconfigdir)" "$(DESTDIR)$(mibdir)" \
+	"$(DESTDIR)$(propertydir)" "$(DESTDIR)$(perldir)" \
+	"$(DESTDIR)$(policydir)" "$(DESTDIR)$(propertydir)" \
+	"$(DESTDIR)$(sampledatadir)" "$(DESTDIR)$(schemadir)" \
+	"$(DESTDIR)$(updatedir)"
 serverLTLIBRARIES_INSTALL = $(INSTALL)
 serverpluginLTLIBRARIES_INSTALL = $(INSTALL)
 LTLIBRARIES = $(server_LTLIBRARIES) $(serverplugin_LTLIBRARIES)
@@ -794,8 +795,9 @@ binSCRIPT_INSTALL = $(INSTALL_SCRIPT)
 initSCRIPT_INSTALL = $(INSTALL_SCRIPT)
 sbinSCRIPT_INSTALL = $(INSTALL_SCRIPT)
 taskSCRIPT_INSTALL = $(INSTALL_SCRIPT)
+updateSCRIPT_INSTALL = $(INSTALL_SCRIPT)
 SCRIPTS = $(bin_SCRIPTS) $(init_SCRIPTS) $(sbin_SCRIPTS) \
-	$(task_SCRIPTS)
+	$(task_SCRIPTS) $(update_SCRIPTS)
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__depfiles_maybe = depfiles
@@ -889,9 +891,11 @@ policyDATA_INSTALL = $(INSTALL_DATA)
 propertyDATA_INSTALL = $(INSTALL_DATA)
 sampledataDATA_INSTALL = $(INSTALL_DATA)
 schemaDATA_INSTALL = $(INSTALL_DATA)
+updateDATA_INSTALL = $(INSTALL_DATA)
 DATA = $(config_DATA) $(inf_DATA) $(initconfig_DATA) $(mib_DATA) \
 	$(nodist_property_DATA) $(perl_DATA) $(policy_DATA) \
-	$(property_DATA) $(sampledata_DATA) $(schema_DATA)
+	$(property_DATA) $(sampledata_DATA) $(schema_DATA) \
+	$(update_DATA)
 ETAGS = etags
 CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -1106,6 +1110,7 @@ svrcore_inc = @svrcore_inc@
 svrcore_lib = @svrcore_lib@
 sysconfdir = @sysconfdir@
 target_alias = @target_alias@
+updatedir = $(datadir)@updatedir@
 vendor = @vendor@
 with_fhs_opt = @with_fhs_opt@
 with_selinux = @with_selinux@
@@ -1169,6 +1174,7 @@ CLEANFILES = dberrstrs.h ns-slapd.properties \
 	ldap/admin/src/scripts/template-dbverify ldap/admin/src/template-initconfig \
 	ldap/admin/src/scripts/dscreate.map ldap/admin/src/scripts/remove-ds.pl \
 	ldap/admin/src/scripts/DSCreate.pm ldap/admin/src/scripts/DSMigration.pm \
+	ldap/admin/src/scripts/DSUpdate.pm ldap/admin/src/scripts/dsupdate.map \
 	ldap/admin/src/scripts/dsorgentries.map ldap/admin/src/scripts/migrate-ds.pl \
 	ldap/admin/src/scripts/Migration.pm ldap/admin/src/scripts/SetupDialogs.pm \
 	ldap/admin/src/scripts/setup-ds.pl ldap/admin/src/scripts/setup-ds.res \
@@ -1346,7 +1352,9 @@ perl_DATA = ldap/admin/src/scripts/SetupLog.pm \
 	ldap/admin/src/scripts/Migration.pm \
 	ldap/admin/src/scripts/DSMigration.pm \
 	ldap/admin/src/scripts/FileConn.pm \
-	ldap/admin/src/scripts/DSCreate.pm
+	ldap/admin/src/scripts/DSCreate.pm \
+	ldap/admin/src/scripts/DSUpdate.pm \
+	ldap/admin/src/scripts/DSUpdateDialogs.pm
 
 property_DATA = ldap/admin/src/scripts/setup-ds.res \
 	ldap/admin/src/scripts/migrate-ds.res
@@ -1386,6 +1394,7 @@ init_SCRIPTS = wrappers/$(PACKAGE_NAME)
 initconfig_DATA = ldap/admin/src/$(PACKAGE_NAME)
 inf_DATA = ldap/admin/src/slapd.inf \
 	ldap/admin/src/scripts/dscreate.map \
+	ldap/admin/src/scripts/dsupdate.map \
 	ldap/admin/src/scripts/dsorgentries.map
 
 mib_DATA = ldap/servers/snmp/RFC-1215.txt \
@@ -1420,6 +1429,44 @@ dist_man_MANS = man/man1/dbscan.1 \
 	man/man8/remove-ds.pl.8
 
 
+#------------------------
+# updates
+# the first 3 are just the examples provided - since they
+# do not begin with two digits, they will be ignored
+# the remaining items should begin with two digits that
+# correspond to the order in which they should be applied
+# perl files and LDIF files are DATA - not executable
+# processed by the update script
+# shell scripts and other files are SCRIPTS - executable
+#------------------------
+update_DATA = ldap/admin/src/scripts/exampleupdate.pl \
+	ldap/admin/src/scripts/exampleupdate.ldif \
+	ldap/admin/src/scripts/50addchainingsaslpwroles.ldif \
+	ldap/admin/src/scripts/50memberofindex.ldif \
+	ldap/admin/src/scripts/50bitstringsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50memberofplugin.ldif \
+	ldap/admin/src/scripts/50deliverymethodsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50nameuidsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50derefplugin.ldif \
+	ldap/admin/src/scripts/50numericstringsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50disableurisyntaxplugin.ldif \
+	ldap/admin/src/scripts/50printablestringsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50enhancedguidesyntaxplugin.ldif \
+	ldap/admin/src/scripts/50schemareloadplugin.ldif \
+	ldap/admin/src/scripts/50entryusnindex.ldif \
+	ldap/admin/src/scripts/50syntaxvalidplugin.ldif \
+	ldap/admin/src/scripts/50faxnumbersyntaxplugin.ldif \
+	ldap/admin/src/scripts/50teletexterminalidsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50faxsyntaxplugin.ldif \
+	ldap/admin/src/scripts/50telexnumbersyntaxplugin.ldif \
+	ldap/admin/src/scripts/50guidesyntaxplugin.ldif \
+	ldap/admin/src/scripts/50linkedattrsplugin.ldif \
+	ldap/admin/src/scripts/50usnplugin.ldif \
+	ldap/admin/src/scripts/60upgradeschemafiles.pl \
+	ldap/admin/src/scripts/dnaplugindepends.ldif
+
+update_SCRIPTS = ldap/admin/src/scripts/exampleupdate.sh
+
 #////////////////////////////////////////////////////////////////
 #
 #   Server Strings
@@ -2193,7 +2240,8 @@ rsearch_bin_LDADD = $(NSPR_LINK) $(NSS_LINK) $(LDAPSDK_LINK) $(SASL_LINK) $(LIBS
 @BUNDLE_FALSE@	-e 's,@with_fhs_opt\@,@with_fhs_opt@,g' \
 @BUNDLE_FALSE@	-e 's,@with_selinux\@,@with_selinux@,g' \
 @BUNDLE_FALSE@	-e 's,@perlexec\@,@perlexec@,g' \
-@BUNDLE_FALSE@	-e 's,@initconfigdir\@,$(initconfigdir),g'
+@BUNDLE_FALSE@	-e 's,@initconfigdir\@,$(initconfigdir),g' \
+@BUNDLE_FALSE@	-e 's,@updatedir\@,$(updatedir),g'
 
 
 # these are for the config files and scripts that we need to generate and replace
@@ -2255,7 +2303,8 @@ rsearch_bin_LDADD = $(NSPR_LINK) $(NSS_LINK) $(LDAPSDK_LINK) $(SASL_LINK) $(LIBS
 @BUNDLE_TRUE@	-e 's,@with_fhs_opt\@,@with_fhs_opt@,g' \
 @BUNDLE_TRUE@	-e 's,@with_selinux\@,@with_selinux@,g' \
 @BUNDLE_TRUE@	-e 's,@perlexec\@,@perlexec@,g' \
-@BUNDLE_TRUE@	-e 's,@initconfigdir\@,$(initconfigdir),g'
+@BUNDLE_TRUE@	-e 's,@initconfigdir\@,$(initconfigdir),g'\
+@BUNDLE_TRUE@	-e 's,@updatedir\@,$(updatedir),g'
 
 all: $(BUILT_SOURCES) config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-am
@@ -4170,6 +4219,25 @@ uninstall-taskSCRIPTS:
 	  echo " rm -f '$(DESTDIR)$(taskdir)/$$f'"; \
 	  rm -f "$(DESTDIR)$(taskdir)/$$f"; \
 	done
+install-updateSCRIPTS: $(update_SCRIPTS)
+	@$(NORMAL_INSTALL)
+	test -z "$(updatedir)" || $(mkdir_p) "$(DESTDIR)$(updatedir)"
+	@list='$(update_SCRIPTS)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  if test -f $$d$$p; then \
+	    f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+	    echo " $(updateSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(updatedir)/$$f'"; \
+	    $(updateSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(updatedir)/$$f"; \
+	  else :; fi; \
+	done
+
+uninstall-updateSCRIPTS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(update_SCRIPTS)'; for p in $$list; do \
+	  f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
+	  echo " rm -f '$(DESTDIR)$(updatedir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(updatedir)/$$f"; \
+	done
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
@@ -9417,6 +9485,23 @@ uninstall-schemaDATA:
 	  echo " rm -f '$(DESTDIR)$(schemadir)/$$f'"; \
 	  rm -f "$(DESTDIR)$(schemadir)/$$f"; \
 	done
+install-updateDATA: $(update_DATA)
+	@$(NORMAL_INSTALL)
+	test -z "$(updatedir)" || $(mkdir_p) "$(DESTDIR)$(updatedir)"
+	@list='$(update_DATA)'; for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  f=$(am__strip_dir) \
+	  echo " $(updateDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(updatedir)/$$f'"; \
+	  $(updateDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(updatedir)/$$f"; \
+	done
+
+uninstall-updateDATA:
+	@$(NORMAL_UNINSTALL)
+	@list='$(update_DATA)'; for p in $$list; do \
+	  f=$(am__strip_dir) \
+	  echo " rm -f '$(DESTDIR)$(updatedir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(updatedir)/$$f"; \
+	done
 
 ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
 	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
@@ -9599,7 +9684,7 @@ check: $(BUILT_SOURCES)
 all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) \
 		$(MANS) $(DATA) config.h
 installdirs:
-	for dir in "$(DESTDIR)$(serverdir)" "$(DESTDIR)$(serverplugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(initdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(taskdir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(configdir)" "$(DESTDIR)$(infdir)" "$(DESTDIR)$(initconfigdir)" "$(DESTDIR)$(mibdir)" "$(DESTDIR)$(propertydir)" "$(DESTDIR)$(perldir)" "$(DESTDIR)$(policydir)" "$(DESTDIR)$(propertydir)" "$(DESTDIR)$(sampledatadir)" "$(DESTDIR)$(schemadir)"; do \
+	for dir in "$(DESTDIR)$(serverdir)" "$(DESTDIR)$(serverplugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(initdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(taskdir)" "$(DESTDIR)$(updatedir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(configdir)" "$(DESTDIR)$(infdir)" "$(DESTDIR)$(initconfigdir)" "$(DESTDIR)$(mibdir)" "$(DESTDIR)$(propertydir)" "$(DESTDIR)$(perldir)" "$(DESTDIR)$(policydir)" "$(DESTDIR)$(propertydir)" "$(DESTDIR)$(sampledatadir)" "$(DESTDIR)$(schemadir)" "$(DESTDIR)$(updatedir)"; do \
 	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
 	done
 install: $(BUILT_SOURCES)
@@ -9738,7 +9823,8 @@ install-data-am: install-configDATA install-infDATA \
 	install-mibDATA install-nodist_propertyDATA install-perlDATA \
 	install-policyDATA install-propertyDATA install-sampledataDATA \
 	install-schemaDATA install-serverLTLIBRARIES \
-	install-serverpluginLTLIBRARIES install-taskSCRIPTS
+	install-serverpluginLTLIBRARIES install-taskSCRIPTS \
+	install-updateDATA install-updateSCRIPTS
 
 install-exec-am: install-binPROGRAMS install-binSCRIPTS \
 	install-sbinPROGRAMS install-sbinSCRIPTS
@@ -9777,7 +9863,8 @@ uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \
 	uninstall-sampledataDATA uninstall-sbinPROGRAMS \
 	uninstall-sbinSCRIPTS uninstall-schemaDATA \
 	uninstall-serverLTLIBRARIES uninstall-serverpluginLTLIBRARIES \
-	uninstall-taskSCRIPTS
+	uninstall-taskSCRIPTS uninstall-updateDATA \
+	uninstall-updateSCRIPTS
 
 uninstall-man: uninstall-man1 uninstall-man8
 
@@ -9799,11 +9886,12 @@ uninstall-man: uninstall-man1 uninstall-man8
 	install-policyDATA install-propertyDATA install-sampledataDATA \
 	install-sbinPROGRAMS install-sbinSCRIPTS install-schemaDATA \
 	install-serverLTLIBRARIES install-serverpluginLTLIBRARIES \
-	install-strip install-taskSCRIPTS installcheck installcheck-am \
-	installdirs maintainer-clean maintainer-clean-generic \
-	mostlyclean mostlyclean-compile mostlyclean-generic \
-	mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
-	uninstall-am uninstall-binPROGRAMS uninstall-binSCRIPTS \
+	install-strip install-taskSCRIPTS install-updateDATA \
+	install-updateSCRIPTS installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags uninstall uninstall-am \
+	uninstall-binPROGRAMS uninstall-binSCRIPTS \
 	uninstall-configDATA uninstall-infDATA uninstall-info-am \
 	uninstall-initSCRIPTS uninstall-initconfigDATA uninstall-man \
 	uninstall-man1 uninstall-man8 uninstall-mibDATA \
@@ -9812,7 +9900,8 @@ uninstall-man: uninstall-man1 uninstall-man8
 	uninstall-sampledataDATA uninstall-sbinPROGRAMS \
 	uninstall-sbinSCRIPTS uninstall-schemaDATA \
 	uninstall-serverLTLIBRARIES uninstall-serverpluginLTLIBRARIES \
-	uninstall-taskSCRIPTS
+	uninstall-taskSCRIPTS uninstall-updateDATA \
+	uninstall-updateSCRIPTS
 
 
 clean-local:
diff --git a/configure b/configure
index d63d882..9f0902c 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59 for dirsrv 1.2.2.
+# Generated by GNU Autoconf 2.59 for dirsrv 1.2.3.
 #
 # Report bugs to <http://bugzilla.redhat.com/>.
 #
@@ -423,8 +423,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='dirsrv'
 PACKAGE_TARNAME='dirsrv'
-PACKAGE_VERSION='1.2.2'
-PACKAGE_STRING='dirsrv 1.2.2'
+PACKAGE_VERSION='1.2.3'
+PACKAGE_STRING='dirsrv 1.2.3'
 PACKAGE_BUGREPORT='http://bugzilla.redhat.com/'
 
 # Factoring default headers for most tests.
@@ -465,7 +465,7 @@ ac_includes_default="\
 #endif"
 
 ac_default_prefix=/opt/$PACKAGE_NAME
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT build build_cpu build_vendor build_os host host_cpu host_vendor host_os CXX CXXFLAGS LDFLAGS CPPFLAGS ac_ct_CXX EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CC CFLAGS ac_ct_CC CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CCAS CCASFLAGS SED EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CPP CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL LIBOBJS debug_defs BUNDLE_TRUE BUNDLE_FALSE enable_pam_passthru_TRUE enable_pam_passthru_FALSE enable_dna_TRUE enable_dna_FALSE enable_ldapi_TRUE enable_ldapi_FALSE enable_autobind_TRUE enable_autobind_FALSE enable_auto_dn_suffix_TRUE enable_auto_dn_suffix_FALSE enable_bitwise_TRUE enable_bitwise_FALSE enable_presence_TRUE enable_presence_FALSE with_fhs_opt configdir sampledatadir propertydir schemadir serverdir serverplugindir scripttemplatedir perldir infdir mibdir defaultuser defaultgroup instconfigdir WINNT_TRUE WINNT_FALSE LIBSOCKET LIBNSL LIBDL LIBCSTD LIBCRUN initdir perlexec initconfigdir HPUX_TRUE HPUX_FALSE SOLARIS_TRUE SOLARIS_FALSE PKG_CONFIG ICU_CONFIG NETSNMP_CONFIG KRB5_CONFIG_BIN kerberos_inc kerberos_lib kerberos_libdir with_selinux PACKAGE_BASE_VERSION SELINUX_TRUE SELINUX_FALSE OPENLDAP_TRUE OPENLDAP_FALSE nspr_inc nspr_lib nspr_libdir nss_inc nss_lib nss_libdir ldapsdk_inc ldapsdk_lib ldapsdk_libdir ldapsdk_bindir openldap_inc openldap_lib openldap_libdir openldap_bindir ol_libver db_inc db_incdir db_lib db_libdir db_bindir db_libver sasl_inc sasl_lib sasl_libdir sasl_path svrcore_inc svrcore_lib icu_lib icu_inc icu_bin netsnmp_inc netsnmp_lib netsnmp_libdir netsnmp_link pcre_inc pcre_lib pcre_libdir brand capbrand vendor LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT build build_cpu build_vendor build_os host host_cpu host_vendor host_os CXX CXXFLAGS LDFLAGS CPPFLAGS ac_ct_CXX EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CC CFLAGS ac_ct_CC CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CCAS CCASFLAGS SED EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CPP CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL LIBOBJS debug_defs BUNDLE_TRUE BUNDLE_FALSE enable_pam_passthru_TRUE enable_pam_passthru_FALSE enable_dna_TRUE enable_dna_FALSE enable_ldapi_TRUE enable_ldapi_FALSE enable_autobind_TRUE enable_autobind_FALSE enable_auto_dn_suffix_TRUE enable_auto_dn_suffix_FALSE enable_bitwise_TRUE enable_bitwise_FALSE enable_presence_TRUE enable_presence_FALSE with_fhs_opt configdir sampledatadir propertydir schemadir serverdir serverplugindir scripttemplatedir perldir infdir mibdir updatedir defaultuser defaultgroup instconfigdir WINNT_TRUE WINNT_FALSE LIBSOCKET LIBNSL LIBDL LIBCSTD LIBCRUN initdir perlexec initconfigdir HPUX_TRUE HPUX_FALSE SOLARIS_TRUE SOLARIS_FALSE PKG_CONFIG ICU_CONFIG NETSNMP_CONFIG KRB5_CONFIG_BIN kerberos_inc kerberos_lib kerberos_libdir with_selinux PACKAGE_BASE_VERSION SELINUX_TRUE SELINUX_FALSE OPENLDAP_TRUE OPENLDAP_FALSE nspr_inc nspr_lib nspr_libdir nss_inc nss_lib nss_libdir ldapsdk_inc ldapsdk_lib ldapsdk_libdir ldapsdk_bindir openldap_inc openldap_lib openldap_libdir openldap_bindir ol_libver db_inc db_incdir db_lib db_libdir db_bindir db_libver sasl_inc sasl_lib sasl_libdir sasl_path svrcore_inc svrcore_lib icu_lib icu_inc icu_bin netsnmp_inc netsnmp_lib netsnmp_libdir netsnmp_link pcre_inc pcre_lib pcre_libdir brand capbrand vendor LTLIBOBJS'
 ac_subst_files=''
 
 # Initialize some variables set by options.
@@ -962,7 +962,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures dirsrv 1.2.2 to adapt to many kinds of systems.
+\`configure' configures dirsrv 1.2.3 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1028,7 +1028,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of dirsrv 1.2.2:";;
+     short | recursive ) echo "Configuration of dirsrv 1.2.3:";;
    esac
   cat <<\_ACEOF
 
@@ -1241,7 +1241,7 @@ fi
 test -n "$ac_init_help" && exit 0
 if $ac_init_version; then
   cat <<\_ACEOF
-dirsrv configure 1.2.2
+dirsrv configure 1.2.3
 generated by GNU Autoconf 2.59
 
 Copyright (C) 2003 Free Software Foundation, Inc.
@@ -1255,7 +1255,7 @@ cat >&5 <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by dirsrv $as_me 1.2.2, which was
+It was created by dirsrv $as_me 1.2.3, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   $ $0 $@
@@ -1901,7 +1901,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='dirsrv'
- VERSION='1.2.2'
+ VERSION='1.2.3'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -23301,6 +23301,8 @@ if test "$with_fhs_opt" = "yes"; then
   sampledatadir=/data
   # relative to datadir
   scripttemplatedir=/script-templates
+  # relative to datadir
+  updatedir=/updates
   # relative to libdir
   serverdir=
   # relative to libdir
@@ -23325,6 +23327,8 @@ else
   sampledatadir=/$PACKAGE_NAME/data
   # relative to datadir
   scripttemplatedir=/$PACKAGE_NAME/script-templates
+  # relative to datadir
+  updatedir=/$PACKAGE_NAME/updates
   # relative to libdir
   serverdir=/$PACKAGE_NAME
   # relative to libdir
@@ -23370,6 +23374,7 @@ defaultgroup=nobody
 
 
 
+
 # check for --with-instconfigdir
 echo "$as_me:$LINENO: checking for --with-instconfigdir" >&5
 echo $ECHO_N "checking for --with-instconfigdir... $ECHO_C" >&6
@@ -27728,7 +27733,7 @@ _ASBOX
 } >&5
 cat >&5 <<_CSEOF
 
-This file was extended by dirsrv $as_me 1.2.2, which was
+This file was extended by dirsrv $as_me 1.2.3, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -27791,7 +27796,7 @@ _ACEOF
 
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-dirsrv config.status 1.2.2
+dirsrv config.status 1.2.3
 configured by $0, generated by GNU Autoconf 2.59,
   with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
 
@@ -28089,6 +28094,7 @@ s,@scripttemplatedir@,$scripttemplatedir,;t t
 s,@perldir@,$perldir,;t t
 s,@infdir@,$infdir,;t t
 s,@mibdir@,$mibdir,;t t
+s,@updatedir@,$updatedir,;t t
 s,@defaultuser@,$defaultuser,;t t
 s,@defaultgroup@,$defaultgroup,;t t
 s,@instconfigdir@,$instconfigdir,;t t
diff --git a/configure.ac b/configure.ac
index b886643..0e32cd8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 AC_PREREQ(2.59)
 # This version is the version returned by ns-slapd -v
-AC_INIT([dirsrv], [1.2.2], [http://bugzilla.redhat.com/])
+AC_INIT([dirsrv], [1.2.3], [http://bugzilla.redhat.com/])
 # AC_CONFIG_HEADER must be called right after AC_INIT.
 AC_CONFIG_HEADERS([config.h])
 AM_INIT_AUTOMAKE([1.9 foreign subdir-objects])
@@ -205,6 +205,8 @@ if test "$with_fhs_opt" = "yes"; then
   sampledatadir=/data
   # relative to datadir
   scripttemplatedir=/script-templates
+  # relative to datadir
+  updatedir=/updates
   # relative to libdir
   serverdir=
   # relative to libdir
@@ -231,6 +233,8 @@ else
   sampledatadir=/$PACKAGE_NAME/data
   # relative to datadir
   scripttemplatedir=/$PACKAGE_NAME/script-templates
+  # relative to datadir
+  updatedir=/$PACKAGE_NAME/updates
   # relative to libdir
   serverdir=/$PACKAGE_NAME
   # relative to libdir
@@ -272,6 +276,7 @@ AC_SUBST(perldir)
 AC_SUBST(infdir)
 AC_SUBST(mibdir)
 AC_SUBST(mandir)
+AC_SUBST(updatedir)
 
 AC_SUBST(defaultuser)
 AC_SUBST(defaultgroup)
diff --git a/ldap/admin/src/scripts/50addchainingsaslpwroles.ldif b/ldap/admin/src/scripts/50addchainingsaslpwroles.ldif
new file mode 100644
index 0000000..07ee93a
--- /dev/null
+++ b/ldap/admin/src/scripts/50addchainingsaslpwroles.ldif
@@ -0,0 +1,6 @@
+dn: cn=config,cn=chaining database,cn=plugins,cn=config
+changetype: modify
+add: nsPossibleChainingComponents
+nsPossibleChainingComponents: cn=password policy,cn=components,cn=config
+nsPossibleChainingComponents: cn=sasl,cn=components,cn=config
+nsPossibleChainingComponents: cn=roles,cn=components,cn=config
diff --git a/ldap/admin/src/scripts/50bitstringsyntaxplugin.ldif b/ldap/admin/src/scripts/50bitstringsyntaxplugin.ldif
new file mode 100644
index 0000000..8091630
--- /dev/null
+++ b/ldap/admin/src/scripts/50bitstringsyntaxplugin.ldif
@@ -0,0 +1,14 @@
+dn: cn=Bit String Syntax,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Bit String
+nsslapd-pluginpath: libsyntax-plugin
+nsslapd-plugininitfunc: bitstring_init
+nsslapd-plugintype: syntax
+nsslapd-pluginenabled: on
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50deliverymethodsyntaxplugin.ldif b/ldap/admin/src/scripts/50deliverymethodsyntaxplugin.ldif
new file mode 100644
index 0000000..0103c5b
--- /dev/null
+++ b/ldap/admin/src/scripts/50deliverymethodsyntaxplugin.ldif
@@ -0,0 +1,14 @@
+dn: cn=Delivery Method Syntax,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Delivery Method Syntax
+nsslapd-pluginpath: libsyntax-plugin
+nsslapd-plugininitfunc: delivery_init
+nsslapd-plugintype: syntax
+nsslapd-pluginenabled: on
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50derefplugin.ldif b/ldap/admin/src/scripts/50derefplugin.ldif
new file mode 100644
index 0000000..decadac
--- /dev/null
+++ b/ldap/admin/src/scripts/50derefplugin.ldif
@@ -0,0 +1,16 @@
+dn: cn=deref,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+objectclass: nsContainer
+cn: deref
+nsslapd-pluginpath: libderef-plugin
+nsslapd-plugininitfunc: deref_init
+nsslapd-plugintype: preoperation
+nsslapd-pluginenabled: on
+nsslapd-plugin-depends-on-type: database
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50disableurisyntaxplugin.ldif b/ldap/admin/src/scripts/50disableurisyntaxplugin.ldif
new file mode 100644
index 0000000..2838036
--- /dev/null
+++ b/ldap/admin/src/scripts/50disableurisyntaxplugin.ldif
@@ -0,0 +1,9 @@
+dn: cn=URI Syntax,cn=plugins,cn=config
+changetype: modify
+replace: nsslapd-pluginenabled
+nsslapd-pluginenabled: off
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50enhancedguidesyntaxplugin.ldif b/ldap/admin/src/scripts/50enhancedguidesyntaxplugin.ldif
new file mode 100644
index 0000000..b5f8ddc
--- /dev/null
+++ b/ldap/admin/src/scripts/50enhancedguidesyntaxplugin.ldif
@@ -0,0 +1,14 @@
+dn: cn=Enhanced Guide Syntax,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Enhanced Guide Syntax
+nsslapd-pluginpath: libsyntax-plugin
+nsslapd-plugininitfunc: enhancedguide_init
+nsslapd-plugintype: syntax
+nsslapd-pluginenabled: on
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50entryusnindex.ldif b/ldap/admin/src/scripts/50entryusnindex.ldif
new file mode 100644
index 0000000..9196f67
--- /dev/null
+++ b/ldap/admin/src/scripts/50entryusnindex.ldif
@@ -0,0 +1,7 @@
+dn: cn=entryusn,cn=default indexes, cn=config,cn=ldbm database,cn=plugins,cn=config
+objectclass: top
+objectclass: nsIndex
+cn: entryusn
+nssystemindex: true
+nsindextype: eq
+nsmatchingrule: integerOrderingMatch
diff --git a/ldap/admin/src/scripts/50faxnumbersyntaxplugin.ldif b/ldap/admin/src/scripts/50faxnumbersyntaxplugin.ldif
new file mode 100644
index 0000000..1959cd3
--- /dev/null
+++ b/ldap/admin/src/scripts/50faxnumbersyntaxplugin.ldif
@@ -0,0 +1,14 @@
+dn: cn=Facsimile Telephone Number Syntax,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Facsimile Telephone Number Syntax
+nsslapd-pluginpath: libsyntax-plugin
+nsslapd-plugininitfunc: facsimile_init
+nsslapd-plugintype: syntax
+nsslapd-pluginenabled: on
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50faxsyntaxplugin.ldif b/ldap/admin/src/scripts/50faxsyntaxplugin.ldif
new file mode 100644
index 0000000..3410c32
--- /dev/null
+++ b/ldap/admin/src/scripts/50faxsyntaxplugin.ldif
@@ -0,0 +1,14 @@
+dn: cn=Fax Syntax,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Fax Syntax
+nsslapd-pluginpath: libsyntax-plugin
+nsslapd-plugininitfunc: fax_init
+nsslapd-plugintype: syntax
+nsslapd-pluginenabled: on
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50guidesyntaxplugin.ldif b/ldap/admin/src/scripts/50guidesyntaxplugin.ldif
new file mode 100644
index 0000000..d9c3a08
--- /dev/null
+++ b/ldap/admin/src/scripts/50guidesyntaxplugin.ldif
@@ -0,0 +1,14 @@
+dn: cn=Guide Syntax,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Guide Syntax
+nsslapd-pluginpath: libsyntax-plugin
+nsslapd-plugininitfunc: guide_init
+nsslapd-plugintype: syntax
+nsslapd-pluginenabled: on
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50linkedattrsplugin.ldif b/ldap/admin/src/scripts/50linkedattrsplugin.ldif
new file mode 100644
index 0000000..a321673
--- /dev/null
+++ b/ldap/admin/src/scripts/50linkedattrsplugin.ldif
@@ -0,0 +1,16 @@
+dn: cn=Linked Attributes,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+objectclass: nsContainer
+cn: Linked Attributes
+nsslapd-pluginpath: liblinkedattrs-plugin
+nsslapd-plugininitfunc: linked_attrs_init
+nsslapd-plugintype: preoperation
+nsslapd-pluginenabled: on
+nsslapd-plugin-depends-on-type: database
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50memberofindex.ldif b/ldap/admin/src/scripts/50memberofindex.ldif
new file mode 100644
index 0000000..6ede083
--- /dev/null
+++ b/ldap/admin/src/scripts/50memberofindex.ldif
@@ -0,0 +1,6 @@
+dn: cn=memberOf,cn=default indexes, cn=config,cn=ldbm database,cn=plugins,cn=config
+objectclass: top
+objectclass: nsIndex
+cn: memberOf
+nssystemindex: false
+nsindextype: eq
diff --git a/ldap/admin/src/scripts/50memberofplugin.ldif b/ldap/admin/src/scripts/50memberofplugin.ldif
new file mode 100644
index 0000000..722e943
--- /dev/null
+++ b/ldap/admin/src/scripts/50memberofplugin.ldif
@@ -0,0 +1,17 @@
+dn: cn=MemberOf Plugin,cn=plugins,cn=config
+objectClass: top
+objectClass: nsSlapdPlugin
+objectClass: extensibleObject
+cn: MemberOf Plugin
+nsslapd-pluginpath: libmemberof-plugin
+nsslapd-plugininitfunc: memberof_postop_init
+nsslapd-plugintype: postoperation
+nsslapd-pluginenabled: off
+nsslapd-plugin-depends-on-type: database
+memberOfGroupAttr: member
+memberOfAttr: memberOf
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50nameuidsyntaxplugin.ldif b/ldap/admin/src/scripts/50nameuidsyntaxplugin.ldif
new file mode 100644
index 0000000..f4a3305
--- /dev/null
+++ b/ldap/admin/src/scripts/50nameuidsyntaxplugin.ldif
@@ -0,0 +1,14 @@
+dn: cn=Name And Optional UID Syntax,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Name And Optional UID Syntax
+nsslapd-pluginpath: libsyntax-plugin
+nsslapd-plugininitfunc: nameoptuid_init
+nsslapd-plugintype: syntax
+nsslapd-pluginenabled: on
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50numericstringsyntaxplugin.ldif b/ldap/admin/src/scripts/50numericstringsyntaxplugin.ldif
new file mode 100644
index 0000000..a5ba17f
--- /dev/null
+++ b/ldap/admin/src/scripts/50numericstringsyntaxplugin.ldif
@@ -0,0 +1,14 @@
+dn: cn=Numeric String Syntax,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Numeric String Syntax
+nsslapd-pluginpath: libsyntax-plugin
+nsslapd-plugininitfunc: numstr_init
+nsslapd-plugintype: syntax
+nsslapd-pluginenabled: on
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50printablestringsyntaxplugin.ldif b/ldap/admin/src/scripts/50printablestringsyntaxplugin.ldif
new file mode 100644
index 0000000..d8dad9b
--- /dev/null
+++ b/ldap/admin/src/scripts/50printablestringsyntaxplugin.ldif
@@ -0,0 +1,14 @@
+dn: cn=Printable String Syntax,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Printable String Syntax
+nsslapd-pluginpath: libsyntax-plugin
+nsslapd-plugininitfunc: printable_init
+nsslapd-plugintype: syntax
+nsslapd-pluginenabled: on
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50schemareloadplugin.ldif b/ldap/admin/src/scripts/50schemareloadplugin.ldif
new file mode 100644
index 0000000..b6d12a5
--- /dev/null
+++ b/ldap/admin/src/scripts/50schemareloadplugin.ldif
@@ -0,0 +1,14 @@
+dn: cn=Schema Reload,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Schema Reload
+nsslapd-pluginpath: libschemareload-plugin
+nsslapd-plugininitfunc: schemareload_init
+nsslapd-plugintype: object
+nsslapd-pluginenabled: on
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50syntaxvalidplugin.ldif b/ldap/admin/src/scripts/50syntaxvalidplugin.ldif
new file mode 100644
index 0000000..ee0a085
--- /dev/null
+++ b/ldap/admin/src/scripts/50syntaxvalidplugin.ldif
@@ -0,0 +1,14 @@
+dn: cn=Syntax Validation Task,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Syntax Validation Task
+nsslapd-pluginpath: libsyntax-plugin
+nsslapd-plugininitfunc: syntax_validate_task_init
+nsslapd-plugintype: object
+nsslapd-pluginenabled: on
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50teletexterminalidsyntaxplugin.ldif b/ldap/admin/src/scripts/50teletexterminalidsyntaxplugin.ldif
new file mode 100644
index 0000000..ae16488
--- /dev/null
+++ b/ldap/admin/src/scripts/50teletexterminalidsyntaxplugin.ldif
@@ -0,0 +1,14 @@
+dn: cn=Teletex Terminal Identifier Syntax,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Teletex Terminal Identifier Syntax
+nsslapd-pluginpath: libsyntax-plugin
+nsslapd-plugininitfunc: teletex_init
+nsslapd-plugintype: syntax
+nsslapd-pluginenabled: on
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50telexnumbersyntaxplugin.ldif b/ldap/admin/src/scripts/50telexnumbersyntaxplugin.ldif
new file mode 100644
index 0000000..cf28820
--- /dev/null
+++ b/ldap/admin/src/scripts/50telexnumbersyntaxplugin.ldif
@@ -0,0 +1,14 @@
+dn: cn=Telex Number Syntax,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Telex Number Syntax
+nsslapd-pluginpath: libsyntax-plugin
+nsslapd-plugininitfunc: telex_init
+nsslapd-plugintype: syntax
+nsslapd-pluginenabled: on
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/50usnplugin.ldif b/ldap/admin/src/scripts/50usnplugin.ldif
new file mode 100644
index 0000000..5fd2cfb
--- /dev/null
+++ b/ldap/admin/src/scripts/50usnplugin.ldif
@@ -0,0 +1,15 @@
+dn: cn=USN,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: USN
+nsslapd-pluginpath: libusn-plugin
+nsslapd-plugininitfunc: usn_init
+nsslapd-plugintype: object
+nsslapd-pluginenabled: off
+nsslapd-plugin-depends-on-type: database
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
diff --git a/ldap/admin/src/scripts/60upgradeschemafiles.pl b/ldap/admin/src/scripts/60upgradeschemafiles.pl
new file mode 100644
index 0000000..b0f5758
--- /dev/null
+++ b/ldap/admin/src/scripts/60upgradeschemafiles.pl
@@ -0,0 +1,54 @@
+
+use DSCreate qw(installSchema);
+
+sub runinst {
+    my ($inf, $inst, $dseldif, $conn) = @_;
+
+    if (!$inf->{slapd}->{schema_dir} or (! -d $inf->{slapd}->{schema_dir})) {
+        return ('error_reading_schema_dir', $inf->{slapd}->{schema_dir});
+    }
+
+    # these schema files are obsolete, or we want to replace
+    # them with newer versions
+    my @toremove = qw(00core.ldif 01common.ldif 05rfc2247.ldif 10presence.ldif 28pilot.ldif 50ns-directory.ldif 60mozilla.ldif);
+
+    # make a backup directory to store the deleted schema, then
+    # don't really delete it, just move it to that directory
+    my $mode = (stat($inf->{slapd}->{schema_dir}))[2];
+    my $bakdir = $inf->{slapd}->{schema_dir} . ".bak";
+    if (! -d $bakdir) {
+        $! = 0; # clear
+        mkdir $bakdir, $mode;
+        if ($!) {
+            return ('error_creating_directory', $bakdir, $!);
+        }
+    }
+
+    my @errs;
+    for my $file (@toremove) {
+        my $oldname = $inf->{slapd}->{schema_dir} . "/" . $file;
+        next if (! -f $oldname); # does not exist - skip - already (re)moved
+        my $newname = "$bakdir/$file";
+        $! = 0; # clear
+        rename $oldname, $newname;
+        if ($!) {
+            push @errs, ["error_renaming_schema", $oldname, $newname, $!];
+        }
+    }
+
+    if (@errs) { # errors backing up schema
+        # restore the original schema files
+        for my $file (@toremove) {
+            my $oldname = "$bakdir/$file";
+            next if (! -f $oldname); # does not exist - not backed up
+            my $newname = $inf->{slapd}->{schema_dir} . "/" . $file;
+            next if (-f $newname); # not removed
+            rename $oldname, $newname;
+        }
+        return @errs;
+    }
+
+    # after removing them, just add everything in the default
+    # schema directory
+    return installSchema($inf, 1);
+}
diff --git a/ldap/admin/src/scripts/DSCreate.pm.in b/ldap/admin/src/scripts/DSCreate.pm.in
index 15302b9..a7ab5fa 100644
--- a/ldap/admin/src/scripts/DSCreate.pm.in
+++ b/ldap/admin/src/scripts/DSCreate.pm.in
@@ -64,8 +64,8 @@ use Mozilla::LDAP::LDIF;
 
 use Exporter;
 @ISA       = qw(Exporter);
-@EXPORT    = qw(createDSInstance removeDSInstance);
-@EXPORT_OK = qw(createDSInstance removeDSInstance);
+@EXPORT    = qw(createDSInstance removeDSInstance setDefaults createInstanceScripts installSchema);
+@EXPORT_OK = qw(createDSInstance removeDSInstance setDefaults createInstanceScripts installSchema);
 
 use strict;
 
@@ -207,9 +207,9 @@ sub makeDSDirs {
     # more privileged user than the directory server, but
     # still allows the admin server to manage directory
     # server files/dirs without being root
-    for (qw(inst_dir config_dir schema_dir log_dir lock_dir run_dir tmp_dir
+    for my $kw (qw(inst_dir config_dir schema_dir log_dir lock_dir run_dir tmp_dir
             cert_dir db_dir ldif_dir bak_dir)) {
-        my $dir = $inf->{slapd}->{$_};
+        my $dir = $inf->{slapd}->{$kw};
         @errs = makePaths($dir, $mode, $inf->{General}->{SuiteSpotUserID},
                           $inf->{General}->{SuiteSpotGroup});
         if (@errs) {
@@ -240,8 +240,8 @@ sub makeDSDirs {
     }
     # set the group of the parent dir of config_dir and inst_dir
     if (defined($inf->{General}->{SuiteSpotGroup})) {
-        for (qw(inst_dir config_dir)) {
-            my $dir = $inf->{slapd}->{$_};
+        for my $kw (qw(inst_dir config_dir)) {
+            my $dir = $inf->{slapd}->{$kw};
             my $parent = dirname($dir);
                   # changeOwnerMode(inf, mode, file, gidonly & default mode);
             @errs = changeOwnerMode($inf, 7, $parent, 5);
@@ -256,6 +256,7 @@ sub makeDSDirs {
 
 sub createInstanceScripts {
     my $inf = shift;
+    my $skip = shift;
     my $perlexec = "@perlexec@" || "/usr/bin/env perl";
     my $myperl = "!$perlexec";
     my $mydevnull = (-f "/dev/null" ? " /dev/null " : " NUL ");
@@ -280,18 +281,21 @@ sub createInstanceScripts {
     );
 
     my $dir = "$inf->{General}->{prefix}@taskdir@";
-    for (glob("$dir/template-*")) {
-        my $basename = $_;
+    for my $file (glob("$dir/template-*")) {
+        my $basename = $file;
         $basename =~ s/^.*template-//;
         my $destfile = "$inf->{slapd}->{inst_dir}/$basename";
-        if (!open(SRC, "< $_")) {
-            return ("error_opening_scripttmpl", $_, $!);
+
+        next if ($skip and -f $destfile); # in skip mode, skip files that already exist
+
+        if (!open(SRC, "< $file")) {
+            return ("error_opening_scripttmpl", $file, $!);
         }
         if (!open(DEST, "> $destfile")) {
             return ("error_opening_scripttmpl", $destfile, $!);
         }
         my $contents; # slurp entire file into memory
-        read SRC, $contents, int(-s $_);
+        read SRC, $contents, int(-s $file);
         close(SRC);
         while (my ($key, $val) = each %maptable) {
             $contents =~ s/\{\{$key\}\}/$val/g;
@@ -482,6 +486,7 @@ sub makeOtherConfigFiles {
 
 sub installSchema {
     my $inf = shift;
+    my $skip = shift;
     my @errs;
     my @schemafiles = ();
     if (!defined($inf->{slapd}->{install_full_schema}) or
@@ -499,10 +504,13 @@ sub installSchema {
             push @schemafiles, $inf->{slapd}->{SchemaFile};
         }
     }
-    for (@schemafiles) {
-        my $src = $_;
+    for my $file (@schemafiles) {
+        my $src = $file;
         my $basename = basename($src);
         my $dest = "$inf->{slapd}->{schema_dir}/$basename";
+
+        next if ($skip and -f $dest); # skip files that already exist
+
         $! = 0; # clear errno
         copy($src, $dest);
         if ($!) {
@@ -667,17 +675,18 @@ sub startServer {
     }
         
     my $pos = tell(IN);
+    my $line;
     while (($done == 0) && (time < $timeout)) {
-        for (; ($done == 0) && ($_ = <IN>); $pos = tell(IN)) {
-            $lastLine = $_;
-            debug(1, $_);
-            if (/$cmdPat/) {
+        for (; ($done == 0) && ($line = <IN>); $pos = tell(IN)) {
+            $lastLine = $line;
+            debug(1, $line);
+            if ($line =~ /$cmdPat/) {
                 $done = 1;
                 $started = 1;
-            } elsif (/Initialization Failed/) {
+            } elsif ($line =~ /Initialization Failed/) {
                 debug(1, "Server failed to start, retrying . . .\n");
                 $code = system($startcmd);
-            } elsif (/exiting\./) {
+            } elsif ($line =~ /exiting\./) {
                 debug(1, "Server failed to start, retrying . . .\n");
                 $code = system($startcmd);
             }
@@ -894,9 +903,9 @@ sub updateSelinuxPolicy {
     # if selinux is not available, do nothing
     if ("@with_selinux@") {
         # run restorecon on all directories we created
-        for (qw(inst_dir config_dir schema_dir log_dir lock_dir run_dir tmp_dir
+        for my $kw (qw(inst_dir config_dir schema_dir log_dir lock_dir run_dir tmp_dir
                 cert_dir db_dir ldif_dir bak_dir)) {
-            my $dir = $inf->{slapd}->{$_};
+            my $dir = $inf->{slapd}->{$kw};
             system("restorecon -R $dir");
         }
 
diff --git a/ldap/admin/src/scripts/DSUpdate.pm.in b/ldap/admin/src/scripts/DSUpdate.pm.in
new file mode 100644
index 0000000..23f3389
--- /dev/null
+++ b/ldap/admin/src/scripts/DSUpdate.pm.in
@@ -0,0 +1,505 @@
+# 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) 2009 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+###########################
+#
+# This perl module provides code to update/upgrade directory
+# server shared files/config and instance specific files/config
+#
+##########################
+
+package DSUpdate;
+use Util;
+use Inf;
+use FileConn;
+use DSCreate qw(setDefaults createInstanceScripts);
+
+use File::Basename qw(basename dirname);
+
+# load perldap
+use Mozilla::LDAP::Conn;
+use Mozilla::LDAP::Utils qw(normalizeDN);
+use Mozilla::LDAP::API qw(ldap_explode_dn);
+use Mozilla::LDAP::LDIF;
+
+use Exporter;
+@ISA       = qw(Exporter);
+@EXPORT    = qw(updateDS);
+@EXPORT_OK = qw(updateDS);
+
+use strict;
+
+use SetupLog;
+
+# the default location of the updates - this is a subdir
+# of the directory server data dir (e.g. /usr/share/dirsrv)
+# the default directory is read-only - if you need to provide
+# additional updates, pass in additional update directories
+# to updateDS
+my $DS_UPDATE_PATH = "@updatedir@";
+
+my $PRE_STAGE = "pre";
+my $PREINST_STAGE = "preinst";
+my $RUNINST_STAGE = "runinst";
+my $POSTINST_STAGE = "postinst";
+my $POST_STAGE = "post";
+
+my @STAGES = ($PRE_STAGE, $PREINST_STAGE, $RUNINST_STAGE, $POSTINST_STAGE, $POST_STAGE);
+my @INSTSTAGES = ($PREINST_STAGE, $RUNINST_STAGE, $POSTINST_STAGE);
+
+# used to create unique package names for loading updates
+# from perl scriptlets
+my $pkgname = "Package00000000000";
+
+# generate and return a unique package name that is a 
+# subpackage of our current package
+sub get_pkgname {
+        return __PACKAGE__ . "::" . $pkgname++;
+}
+
+sub loadUpdates {
+    my $errs = shift;
+    my $dirs = shift;
+    my $mapinfo = shift || {};
+    my @updates; # a list of hash refs, sorted in execution order
+
+    for my $dir (@{$dirs}) {
+        for my $file (glob("$dir/*")) {
+            my $name = basename($file);
+            next if $name !~ /^\d\d/; # we only consider files that begin with two digits
+#            print "name = $name\n";
+            my $href = { path => $file, name => $name };
+            if ($file =~ /\.(pl|pm)$/) { # a perl file
+                my $fullpkg = get_pkgname(); # get a unique package name for the file
+                # this will import the update functions from the given file
+                # each file is given its own private namespace via the package
+                # directive below
+                # we have to use the eval because package takes a "bareword" -
+                # you cannot pass a dynamically constructed string to package
+                eval "package $fullpkg; require q($file)"; # "import" it
+                if ($@) {
+                    if ($@ =~ /did not return a true value/) {
+                        # this usually means the file did not end with 1; - just use it anyway
+                        debug(3, "notice: $file does not return a true value - using anyway\n");
+                    } else {
+                        # probably a syntax or other compilation error in the file
+                        # we can't safely use it, so log it and skip it
+                        push @{$errs}, ['error_loading_update', $file, $@];
+                        debug(0, "Error: not applying update $file. Error: $@\n");
+                        next; # skip this one
+                    }
+                }
+                # grab the hook functions from the update
+                for my $fn (@STAGES) {
+                    # this is some deep perl magic - see the perl Symbol Table
+                    # documentation for the gory details
+                    # We're trying to find if the file defined a symbol called
+                    # pre, run, post, etc. and if so, if that symbol is code
+                    no strict 'refs'; # turn off strict refs to use magic
+                    if (*{$fullpkg . "::" . $fn}{CODE}) {
+                        debug(5, "$file $fn is defined\n");
+                        # store the "function pointer" in the href for this update
+                        $href->{$fn} = \&{$fullpkg . "::" . $fn};
+                    } else {
+                        debug(5, "$file $fn is not defined or not a subroutine\n");
+                    }
+                }
+            } else { # some other type of file
+                $href->{file} = 1;
+            }
+            if ($mapinfo->{$file}) {
+                $href->{mapper} = $mapinfo->{$file}->{mapper};
+                $href->{infary} = $mapinfo->{$file}->{infary};
+            }
+            push @updates, $href;
+        }
+    }
+
+    # we have all the updates now - sort by the name
+    @updates = sort { $a->{name} cmp $b->{name} } @updates;
+
+    return @updates;
+}
+
+sub applyLDIFUpdate {
+    my ($upd, $conn, $inf) = @_;
+    my @errs;
+    my $path = ref($upd) ? $upd->{path} : $upd;
+
+    my $mapper;
+    my @infary;
+    # caller can set mapper to use and additional inf to use
+    if (ref($upd)) {
+        if ($upd->{mapper}) {
+            $mapper = new Inf($upd->{mapper});
+        }
+        if ($upd->{infary}) {
+            @infary = @{$upd->{infary}};
+        }
+    }
+    if (!$mapper) {
+        $mapper = new Inf("$inf->{General}->{prefix}@infdir@/dsupdate.map");
+    }
+    my $dsinf = new Inf("$inf->{General}->{prefix}@infdir@/slapd.inf");
+
+    $mapper = process_maptbl($mapper, \@errs, $inf, $dsinf, @infary);
+    if (!$mapper or @errs) {
+        return @errs;
+    }
+
+    getMappedEntries($mapper, [$path], \@errs, \&check_and_add_entry,
+                     [$conn]);
+
+    return @errs;
+}
+
+# process an update from an ldif file or executable
+# LDIF files only apply to instance updates, so ignore
+# LDIF files when not processing updates for instances
+sub processUpdate {
+    my ($upd, $inf, $configdir, $stage, $inst, $dseldif, $conn) = @_;
+    my @errs;
+    # $upd is either a hashref or a simple path name
+    my $path = ref($upd) ? $upd->{path} : $upd;
+    if ($path =~ /\.ldif$/) {
+        # ldif files are only processed during the runinst stage
+        if ($stage eq $RUNINST_STAGE) {
+            @errs = applyLDIFUpdate($upd, $conn, $inf);
+        }
+    } elsif (-x $path) {
+        # setup environment
+        $ENV{DS_UPDATE_STAGE} = $stage;
+        $ENV{DS_UPDATE_DIR} = $configdir;
+        $ENV{DS_UPDATE_INST} = $inst; # empty if not instance specific
+        $ENV{DS_UPDATE_DSELDIF} = $dseldif; # empty if not instance specific
+        $? = 0; # clear error condition
+        my $output = `$path 2>&1`;
+        if ($?) {
+            @errs = ('error_executing_update', $path, $?, $output);
+        }
+        debug(1, $output);
+    } else {
+        @errs = ('error_unknown_update', $path);
+    }
+
+    return @errs;
+}
+
+# 
+sub updateDS {
+    # get base configdir, instances from setup
+    my $setup = shift;
+    # get other info from inf
+    my $inf = $setup->{inf};
+    # directories containing updates to apply
+    my $dirs = shift || [];
+    my $mapinfo = shift;
+    # the default directory server update path
+    if ($inf->{slapd}->{updatedir}) {
+        push @{$dirs}, $inf->{General}->{prefix} . $inf->{slapd}->{updatedir};
+    } else {
+        push @{$dirs}, $inf->{General}->{prefix} . $DS_UPDATE_PATH;
+    }
+    my @errs;
+    my $force = $setup->{force};
+
+    my @updates = loadUpdates(\@errs, $dirs, $mapinfo);
+
+    if (@errs and !$force) {
+        return @errs;
+    }
+
+    if (!@updates) {
+        # nothing to do?
+        debug(0, "No updates to apply in @{$dirs}\n");
+        return @errs;
+    }
+
+    # run pre-update hooks
+    for my $upd (@updates) {
+        my @localerrs;
+        if ($upd->{$PRE_STAGE}) {
+            debug(1, "Running stage $PRE_STAGE update ", $upd->{path}, "\n");
+            @localerrs = &{$upd->{$PRE_STAGE}}($inf, $setup->{configdir});
+        } elsif ($upd->{file}) {
+            debug(1, "Running stage $PRE_STAGE update ", $upd->{path}, "\n");
+            @localerrs = processUpdate($upd, $inf, $setup->{configdir}, $PRE_STAGE);
+        }
+        if (@localerrs) {
+            push @errs, @localerrs;
+            if (!$force) {
+                return @errs;
+            }
+        }
+    }
+
+    # update each instance
+    for my $inst ($setup->getDirServers()) {
+        my @localerrs = updateDSInstance($inst, $inf, $setup->{configdir}, \@updates, $force);
+        if (@localerrs) {
+            # push array here because localerrs will likely be an array of
+            # array refs already
+            push @errs, @localerrs;
+            if (!$force) {
+                return @errs;
+            }
+        }
+    }
+
+    # run post-update hooks
+    for my $upd (@updates) {
+        my @localerrs;
+        if ($upd->{$POST_STAGE}) {
+            debug(1, "Running stage $POST_STAGE update ", $upd->{path}, "\n");
+            @localerrs = &{$upd->{$POST_STAGE}}($inf, $setup->{configdir});
+        } elsif ($upd->{file}) {
+            debug(1, "Running stage $POST_STAGE update ", $upd->{path}, "\n");
+            @localerrs = processUpdate($upd, $inf, $setup->{configdir}, $POST_STAGE);
+        }
+        if (@localerrs) {
+            push @errs, @localerrs;
+            if (!$force) {
+                return @errs;
+            }
+        }
+    }
+
+    return @errs;
+}
+
+sub updateDSInstance {
+    my ($inst, $inf, $configdir, $updates, $force) = @_;
+    my @errs;
+
+    my $dseldif = "$configdir/$inst/dse.ldif";
+
+    # get the information we need from the instance
+    delete $inf->{slapd}; # delete old data, if any
+    if (@errs = initInfFromInst($inf, $dseldif, $configdir, $inst)) {
+        return @errs;
+    }
+
+    # upgrade instance scripts
+    if (@errs = createInstanceScripts($inf, 1)) {
+        return @errs;
+    }
+
+    my $conn;
+    if ($inf->{General}->{UpdateMode} eq 'online') {
+        # open a connection to the directory server to upgrade
+        my $host = $inf->{General}->{FullMachineName};
+        my $port = $inf->{slapd}->{ServerPort};
+        # this says RootDN and password, but it can be any administrative DN
+        # such as the one used by the console
+        my $binddn = $inf->{$inst}->{RootDN} || $inf->{slapd}->{RootDN};
+        my $bindpw = $inf->{$inst}->{RootDNPwd};
+        my $certdir = $inf->{$inst}->{cert_dir} || $inf->{$inst}->{config_dir} || $inf->{slapd}->{cert_dir};
+
+        $conn = new Mozilla::LDAP::Conn({ host => $host, port => $port, bind => $binddn,
+                                          pswd => $bindpw, cert => $certdir, starttls => 1 });
+        if (!$conn) {
+            debug(0, "Could not open TLS connection to $host:$port - trying regular connection\n");
+            $conn = new Mozilla::LDAP::Conn({ host => $host, port => $port, bind => $binddn,
+                                              pswd => $bindpw });
+        }
+
+        if (!$conn) {
+            debug(0, "Could not open a connection to $host:$port\n");
+            return ('error_online_update', $host, $port, $binddn);
+        }
+    } else {
+        $conn = new FileConn($dseldif);
+        if (!$conn) {
+            debug(0, "Could not open a connection to $dseldif: $!\n");
+            return ('error_offline_update', $dseldif, $!);
+        }
+    }
+
+    # run pre-instance hooks first, then runinst hooks, then postinst hooks
+    # the DS_UPDATE_STAGE 
+    for my $stage (@INSTSTAGES) {
+        # always process these first in the runinst stage - we don't really have any
+        # other good way to process conditional features during update
+        if ($stage eq $RUNINST_STAGE) {
+            my @ldiffiles;
+            if ("@enable_pam_passthru@") {
+                push @ldiffiles, "$inf->{General}->{prefix}@templatedir@/template-pampta.ldif";
+            }
+            if ("@enable_bitwise@") {
+                push @ldiffiles, "$inf->{General}->{prefix}@templatedir@/template-bitwise.ldif";
+            }
+            if ("@enable_dna@") {
+                push @ldiffiles, "$inf->{General}->{prefix}@templatedir@/template-dnaplugin.ldif";
+                push @ldiffiles, $inf->{General}->{prefix} . $DS_UPDATE_PATH . "/dnaplugindepends.ldif";
+            }
+            for my $ldiffile (@ldiffiles) {
+                my @localerrs = processUpdate($ldiffile, $inf, $configdir, $stage,
+                                              $inst, $dseldif, $conn);
+                if (@localerrs) {
+                    push @errs, @localerrs;
+                    if (!$force) {
+                        $conn->close();
+                        return @errs;
+                    }
+                }
+            }
+        }
+        for my $upd (@{$updates}) {
+            my @localerrs;
+            if ($upd->{$stage}) {
+                debug(1, "Running stage $stage update ", $upd->{path}, "\n");
+                @localerrs = &{$upd->{$stage}}($inf, $inst, $dseldif, $conn);
+            } elsif ($upd->{file}) {
+                debug(1, "Running stage $stage update ", $upd->{path}, "\n");
+                @localerrs = processUpdate($upd, $inf, $configdir, $stage,
+                                           $inst, $dseldif, $conn);
+            }
+            if (@localerrs) {
+                push @errs, @localerrs;
+                if (!$force) {
+                    $conn->close();
+                    return @errs;
+                }
+            }
+        }
+    }
+
+    $conn->close();
+    return @errs;
+}
+
+# populate the fields in the inf we need to perform upgrade
+# tasks from the information in the instance dse.ldif and
+# other config
+sub initInfFromInst {
+    my ($inf, $dseldif, $configdir, $inst) = @_;
+    my $conn = new FileConn($dseldif, 1);
+    if (!$conn) {
+        debug(1, "Error: Could not open config file $dseldif: Error $!\n");
+        return ('error_opening_dseldif', $dseldif, $!);
+    }
+
+    my $dn = "cn=config";
+    my $entry = $conn->search($dn, "base", "(cn=*)", 0);
+    if (!$entry) {
+        $conn->close();
+        debug(1, "Error: Search $dn in $dseldif failed: ".$conn->getErrorString()."\n");
+        return ('error_finding_config_entry', $dn, $dseldif, $conn->getErrorString());
+    }
+
+    my $servid = $inst;
+    $servid =~ s/slapd-//;
+
+    $inf->{General}->{FullMachineName} = $entry->getValue("nsslapd-localhost");
+    $inf->{General}->{SuiteSpotUserID} = $entry->getValue("nsslapd-localuser");
+    $inf->{slapd}->{ServerPort} = $entry->getValue("nsslapd-port");
+    $inf->{slapd}->{ldapifilepath} = $entry->getValue("nsslapd-ldapifilepath");
+    if (!$inf->{$inst}->{RootDN}) {
+        $inf->{$inst}->{RootDN} || $entry->getValue('nsslapd-rootdn');
+    }
+    # we don't use this password - we either use {$inst} password or
+    # none at all
+    $inf->{slapd}->{RootDNPwd} = '{SSHA}dummy';
+    if (!$inf->{$inst}->{cert_dir}) {
+        $inf->{$inst}->{cert_dir} = $entry->getValue('nsslapd-certdir');
+    }
+    $inf->{slapd}->{cert_dir} = $inf->{$inst}->{cert_dir};
+    if (!$inf->{slapd}->{ldif_dir}) {
+        $inf->{slapd}->{ldif_dir} = $entry->getValue('nsslapd-ldifdir');
+    }
+    if (!$inf->{slapd}->{ServerIdentifier}) {
+        $inf->{slapd}->{ServerIdentifier} = $servid;
+    }
+    if (!$inf->{slapd}->{bak_dir}) {
+        $inf->{slapd}->{bak_dir} = $entry->getValue('nsslapd-bakdir');
+    }
+    if (!$inf->{slapd}->{config_dir}) {
+        $inf->{slapd}->{config_dir} = $configdir;
+    }
+    if (!$inf->{slapd}->{inst_dir}) {
+        $inf->{slapd}->{inst_dir} = $entry->getValue('nsslapd-instancedir');
+    }
+    if (!$inf->{slapd}->{run_dir}) {
+        $inf->{slapd}->{run_dir} = $entry->getValue('nsslapd-rundir');
+    }
+    if (!$inf->{slapd}->{schema_dir}) {
+        $inf->{slapd}->{schema_dir} = $entry->getValue('nsslapd-schemadir');
+    }
+    if (!$inf->{slapd}->{lock_dir}) {
+        $inf->{slapd}->{lock_dir} = $entry->getValue('nsslapd-lockdir');
+    }
+    if (!$inf->{slapd}->{log_dir}) {
+        # use the errorlog dir
+        my $logfile = $entry->getValue('nsslapd-errorlog');
+        if ($logfile) {
+            $inf->{slapd}->{log_dir} = dirname($logfile);
+        }
+    }
+    if (!$inf->{slapd}->{sasl_path}) {
+        $inf->{slapd}->{sasl_path} = $entry->getValue('nsslapd-saslpath');
+    }
+
+
+    # dn: cn=config,cn=ldbm database,cn=plugins,cn=config
+    $dn = "cn=config,cn=ldbm database,cn=plugins,cn=config";
+    $entry = $conn->search($dn, "base", "(cn=*)", 0);
+    if (!$entry) {
+        $conn->close();
+        debug(1, "Error: Search $dn in $dseldif failed: ".$conn->getErrorString()."\n");
+        return ('error_finding_config_entry', $dn, $dseldif, $conn->getErrorString());
+    }
+
+    if (!$inf->{slapd}->{db_dir}) {
+        $inf->{slapd}->{db_dir} = $entry->getValue('nsslapd-directory');
+    }
+
+    $conn->close(); # don't need this anymore
+
+    # set defaults for things we don't know how to find, after setting the values
+    # we do know how to find
+    return setDefaults($inf);
+}
+
+1;
+
+# emacs settings
+# Local Variables:
+# mode:perl
+# indent-tabs-mode: nil
+# tab-width: 4
+# End:
diff --git a/ldap/admin/src/scripts/DSUpdateDialogs.pm b/ldap/admin/src/scripts/DSUpdateDialogs.pm
new file mode 100644
index 0000000..32185b8
--- /dev/null
+++ b/ldap/admin/src/scripts/DSUpdateDialogs.pm
@@ -0,0 +1,181 @@
+# 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) 2009 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+package DSUpdateDialogs;
+
+use strict;
+
+use DialogManager;
+use Setup;
+use Dialog;
+use Util;
+use FileConn;
+
+my @updateadmindialogs;
+
+my $updatewelcome = new DialogYesNo (
+    $EXPRESS,
+    ['update_dialog_first', 'brand', 'brand'],
+    1,
+    sub {
+        my $self = shift;
+        my $ans = shift;
+        my $res = $self->handleResponse($ans);
+        if ($res == $DialogManager::NEXT) {
+            $res = $DialogManager::ERR if (!$self->isYes());
+        }
+        return $res;
+    },
+    ['update_dialog_first_prompt'],
+);
+
+my $updatemode = new Dialog (
+    $EXPRESS,
+    'update_dialog_mode',
+    sub {
+        my $self = shift;
+        return $self->{manager}->{inf}->{General}->{UpdateMode} ||
+            'quit';
+    },
+    sub {
+        my $self = shift;
+        my $ans = shift;
+        my $res = $DialogManager::ERR;
+
+        if ($ans =~ /^off/i) {
+            $self->{manager}->{inf}->{General}->{UpdateMode} = 'offline';
+            $res = $DialogManager::NEXT;
+            for (@updateadmindialogs) {
+                $_->disable(); # don't need admins and passwords
+            }
+        } elsif ($ans =~ /^on/i) {
+            $self->{manager}->{inf}->{General}->{UpdateMode} = 'online';
+            $res = $DialogManager::NEXT;
+            if (!@updateadmindialogs) {
+                @updateadmindialogs = makeInstanceDialogs($self->{manager});
+                $self->{manager}->addDialog(@updateadmindialogs);
+            }
+            for (@updateadmindialogs) {
+                $_->enable(); # need admins and passwords
+            }
+        }
+        return $res;
+    },
+    ['update_dialog_mode_prompt']
+);
+
+sub makeInstanceDialogs {
+    my $manager = shift;
+    # for each directory server instance, create a dialog that prompts
+    # for the admin user and password for that instance
+    # the default admin user for each instance is the rootdn for that
+    # instance
+    for my $inst ($manager->{setup}->getDirServers()) {
+        my $innerinst = $inst;
+        if (!$manager->{inf}->{$inst}->{RootDN}) {
+            # if we don't already have an admin DN set for this
+            # instance, look in the dse.ldif for the nsslapd-rootdn
+            my $dseldif = $manager->{setup}->{configdir} . "/" . $inst . "/dse.ldif";
+            my $conn = new FileConn($dseldif, 1);
+            my $rootdn;
+            if ($conn) {
+                my $ent = $conn->search("cn=config", "base", '(objectclass=*)');
+                if ($ent) {
+                    $rootdn = $ent->getValue('nsslapd-rootdn');
+                } else {
+                    $manager->alert('error_finding_config_entry',
+                                    "cn=config", $dseldif, $conn->getErrorString());
+                }
+                $conn->close();
+            } else {
+                $manager->alert('error_opening_dseldif', $dseldif, $!);
+            }
+            if ($rootdn) {
+                $manager->{inf}->{$inst}->{RootDN} = $rootdn;
+            } else {
+                $manager->{inf}->{$inst}->{RootDN} = "cn=Directory Manager";
+            }
+        }
+        my $dlg = new Dialog (
+            $EXPRESS,
+            ['update_admin_dialog', $innerinst],
+            sub {
+                my $self = shift;
+                my $index = shift;
+                my $id;
+                if ($index == 0) { # return undef for password defaults
+                    $id = $self->{manager}->{inf}->{$innerinst}->{RootDN};
+                }
+                return $id;
+            },
+            sub {
+                my $self = shift;
+                my $ans = shift;
+                my $index = shift;
+
+                my $res = $DialogManager::SAME;
+                if ($index == 0) {
+                    if (!isValidDN($ans)) {
+                        $self->{manager}->alert("dialog_dsrootdn_error", $ans);
+                    } else {
+                        $self->{manager}->{inf}->{$innerinst}->{RootDN} = $ans;
+                        $res = $DialogManager::NEXT;
+                    }
+                } else {
+                    if (!$ans or !length($ans)) {
+                        $self->{manager}->alert("dialog_dsrootpw_invalid");
+                    } else {
+                        $self->{manager}->{inf}->{$innerinst}->{RootDNPwd} = $ans;
+                        $res = $DialogManager::NEXT;
+                    }
+                }
+                return $res;
+            },
+            ['update_admin_id_prompt'], ['update_admin_pwd_prompt', 1]
+        );
+        push @updateadmindialogs, $dlg;
+    }
+
+    return @updateadmindialogs;
+}
+
+sub getDialogs {
+    return ($updatewelcome, $updatemode);
+}
+
+1;
diff --git a/ldap/admin/src/scripts/FileConn.pm b/ldap/admin/src/scripts/FileConn.pm
index fe5acb5..bead2a4 100644
--- a/ldap/admin/src/scripts/FileConn.pm
+++ b/ldap/admin/src/scripts/FileConn.pm
@@ -63,8 +63,8 @@ sub new {
     $self = bless $self, $class;
 
     $self->{readonly} = $readonly;
-    for (@namingContexts) {
-        $self->setNamingContext($_);
+    for my $ctx (@namingContexts) {
+        $self->setNamingContext($ctx);
     }
     $self->setNamingContext(""); # root DSE
     if (!$self->read($filename)) {
@@ -192,9 +192,9 @@ sub write {
     }
 
     $self->iterate("", LDAP_SCOPE_SUBTREE, \&writecb, \*MYLDIF);
-    for (keys %{$self->{namingContexts}}) {
-        next if (!$_); # skip "" - we already did that
-        $self->iterate($_, LDAP_SCOPE_SUBTREE, \&writecb, \*MYLDIF);
+    for my $ctx (keys %{$self->{namingContexts}}) {
+        next if (!$ctx); # skip "" - we already did that
+        $self->iterate($ctx, LDAP_SCOPE_SUBTREE, \&writecb, \*MYLDIF);
     }
     close( MYLDIF );
 
@@ -354,12 +354,12 @@ sub cloneEntry {
     }
     my $dest = new Mozilla::LDAP::Entry();
     $dest->setDN($src->getDN());
-    for (keys %{$src}) {
-        if (ref($src->{$_})) {
-            my @copyary = @{$src->{$_}};
-            $dest->{$_} = [ @copyary ]; # make a deep copy
+    for my $key (keys %{$src}) {
+        if (ref($src->{$key})) {
+            my @copyary = @{$src->{$key}};
+            $dest->{$key} = [ @copyary ]; # make a deep copy
         } else {
-            $dest->{$_} = $src->{$_};
+            $dest->{$key} = $src->{$key};
         }
     }
 
diff --git a/ldap/admin/src/scripts/Inf.pm b/ldap/admin/src/scripts/Inf.pm
index 091940b..bb22913 100644
--- a/ldap/admin/src/scripts/Inf.pm
+++ b/ldap/admin/src/scripts/Inf.pm
@@ -88,31 +88,32 @@ sub read {
         }
         $inffh = \*INF;
     }
-    while (<$inffh>) {
+    my $line;
+    while ($line = <$inffh>) {
         my $iscontinuation;
-        chop; # trim trailing newline
-        if (/^\s*$/) { # skip blank/empty lines
+        chop $line; # trim trailing newline
+        if ($line =~ /^\s*$/) { # skip blank/empty lines
             $incontinuation = 0;
             next;
         }
-        if (/^\s*\#/) { # skip comment lines
+        if ($line =~ /^\s*\#/) { # skip comment lines
             $incontinuation = 0;
             next;
         }
-        if (/\\$/) { # line ends in \ - continued on next line
-            chop;
+        if ($line =~ /\\$/) { # line ends in \ - continued on next line
+            chop $line;
             $iscontinuation = 1;
         }
         if ($incontinuation) {
             if ($curval) {
-                $self->{$curSection}->{$curkey}->[$curval] .= "\n" . $_; # add line in entirety to current value
+                $self->{$curSection}->{$curkey}->[$curval] .= "\n" . $line; # add line in entirety to current value
             } else {
-                $self->{$curSection}->{$curkey} .= "\n" . $_; # add line in entirety to current value
+                $self->{$curSection}->{$curkey} .= "\n" . $line; # add line in entirety to current value
             }
-        } elsif (/^\[(.*?)\]/) { # e.g. [General]
+        } elsif ($line =~ /^\[(.*?)\]/) { # e.g. [General]
             $curSection = $1;
             $iscontinuation = 0; # disallow section continuations
-        } elsif (/^\s*(.*?)\s*=\s*(.*?)\s*$/) { # key = value
+        } elsif ($line =~ /^\s*(.*?)\s*=\s*(.*?)\s*$/) { # key = value
             $curkey = $1;
             # a single value is just a single scalar
             # multiple values are represented by an array ref
@@ -207,8 +208,8 @@ sub updateFromArgs {
     }
 
     # read args into temp inf
-    for (@_) {
-        if (/^([\w_-]+)\.([\w_-]+)=(.*)$/) { # e.g. section.param=value
+    for my $arg (@_) {
+        if ($arg =~ /^([\w_-]+)\.([\w_-]+)=(.*)$/) { # e.g. section.param=value
             my $sec = $1;
             my $parm = $2;
             my $val = $3;
@@ -227,7 +228,7 @@ sub updateFromArgs {
                 $argsinf->{$sec}->{$parm} = $val;
             }
         } else { # error
-            print STDERR "Error: unknown command line option $_\n";
+            print STDERR "Error: unknown command line option $arg\n";
             return;
         }
     }
diff --git a/ldap/admin/src/scripts/Resource.pm b/ldap/admin/src/scripts/Resource.pm
index 1fcd44c..911ab08 100644
--- a/ldap/admin/src/scripts/Resource.pm
+++ b/ldap/admin/src/scripts/Resource.pm
@@ -77,27 +77,28 @@ sub read {
         my $incontinuation = 0;
         my $curkey;
         open RES, $filename or die "Error: could not open resource file $filename: $!";
-        while (<RES>) {
+        my $line;
+        while ($line = <RES>) {
             my $iscontinuation;
-            chop; # trim trailing newline
-            if (/^\s*$/) { # skip blank/empty lines
+            chop $line; # trim trailing newline
+            if ($line =~ /^\s*$/) { # skip blank/empty lines
                 $incontinuation = 0;
                 next;
             }
-            if (/^\s*\#/) { # skip comment lines
+            if ($line =~ /^\s*\#/) { # skip comment lines
                 $incontinuation = 0;
                 next;
             }
             # read name = value pairs like this
             # bol whitespace* name whitespace* '=' whitespace* value eol
             # the value will include any trailing whitespace
-            if (/\\$/) {
-                chop;
+            if ($line =~ /\\$/) {
+                chop $line;
                 $iscontinuation = 1;
             }
             if ($incontinuation) {
-                $self->{res}->{$curkey} .= "\n" . $_;
-            } elsif (/^\s*(.*?)\s*=\s*(.*?)$/) {
+                $self->{res}->{$curkey} .= "\n" . $line;
+            } elsif ($line =~ /^\s*(.*?)\s*=\s*(.*?)$/) {
                 # replace \n with real newline
                 if ($curkey) {
                     $self->{res}->{$curkey} =~ s/\\n/\n/g;
diff --git a/ldap/admin/src/scripts/Setup.pm.in b/ldap/admin/src/scripts/Setup.pm.in
index 7ad57c1..f314d67 100644
--- a/ldap/admin/src/scripts/Setup.pm.in
+++ b/ldap/admin/src/scripts/Setup.pm.in
@@ -99,6 +99,8 @@ options:
     --file=name  Use the file 'name' in .inf format to supply the default answers
     --keepcache  Do not delete the temporary .inf file generated by this program
     --logfile    Log setup messages to this file - otherwise, a temp file will be used
+    --update     Update an existing installation (e.g. after upgrading packages)
+    --continue   (update only) keep going despite errors (also --force)
 For all options, you can also use the short name e.g. -h, -d, etc.  For the -d argument,
 specifying it more than once will increase the debug level e.g. -ddddd
 
@@ -124,7 +126,7 @@ sub new {
 sub init {
     my $self = shift;
     $self->{res} = shift;
-    my ($silent, $inffile, $keep, $preonly, $logfile, $update);
+    my ($silent, $inffile, $keep, $preonly, $logfile, $update, $force);
 
     GetOptions('help|h|?' => sub { VersionMessage(); HelpMessage(); exit 0 },
                'version|v' => sub { VersionMessage(); exit 0 },
@@ -134,7 +136,8 @@ sub init {
                'keepcache|k' => \$keep,
                'preonly|p' => \$preonly,
                'logfile|l=s' => \$logfile,
-               'update|u' => \$update
+               'update|u' => \$update,
+               'continue|force|c' => \$force
                );
 
     $self->{silent} = $silent;
@@ -142,6 +145,7 @@ sub init {
     $self->{keep} = $keep;
     $self->{preonly} = $preonly;
     $self->{update} = $update;
+    $self->{force} = $update;
     $self->{logfile} = $logfile;
     $self->{log} = new SetupLog($self->{logfile});
     # if user supplied inf file, use that to initialize
@@ -193,21 +197,40 @@ sub log {
 sub msg {
     my $self = shift;
     my $level = shift;
-    my @text = @_;
-    if (!$level && @text) {
+    my @ary = @_;
+    if (!$level && @ary) {
         # e.g. msg(0, "string") - no logging
-    } elsif ($level and @text and grep {/^$level$/} $self->{log}->levels()) {
+    } elsif ($level and @ary and grep {/^$level$/} $self->{log}->levels()) {
         # e.g. msg($WARN, "string") - print and log
     } else {
         # log at default INFO level
-        unshift @text, $level;
+        unshift @ary, $level;
         $level = $INFO;
     }
-    my $string = $self->{res}->getText(@text);
-    if ($level) {
-        $self->log($level, $string);
+    # @text is an array of strings for one message or 
+    # an array of array refs, each one is a message
+    while (@ary) {
+        my @text = shift @ary;
+
+        last if (!@text or !$text[0]);
+
+        # element is an array ref - just pass to getText
+        # else is a list of strings
+        # NOTE: this will NOT work if ary contains
+        # consecutive simple string errors not separated
+        # by an array ref e.g. this will work
+        # ARRAY, 'errkey', arg, arg, ARRAY
+        # this will not work
+        # ARRAY, 'errkey', arg, 'errkey2', arg2, ARRAY
+        while (@ary and !ref($ary[0])) {
+            push @text, shift @ary;
+        }
+        my $string = $self->{res}->getText(@text);
+        if ($level) {
+            $self->log($level, $string);
+        }
+        print $string;
     }
-    print $string;
 }
 
 sub doExit {
@@ -231,6 +254,7 @@ sub getDirServers {
     if (!$self->{dirservers}) {
         $self->{dirservers} = [];
         for my $dir (glob("$self->{configdir}/slapd-*")) {
+            next if ($dir =~ /\.removed$/); # skip removed instances
             if (-d $dir) {
                 $dir =~ s,$self->{configdir}/,,; # strip off dir part
                 push @{$self->{dirservers}}, $dir;
diff --git a/ldap/admin/src/scripts/Util.pm.in b/ldap/admin/src/scripts/Util.pm.in
index 6d54648..29f268f 100644
--- a/ldap/admin/src/scripts/Util.pm.in
+++ b/ldap/admin/src/scripts/Util.pm.in
@@ -46,11 +46,11 @@ use Mozilla::LDAP::LDIF;
 require Exporter;
 @ISA       = qw(Exporter);
 @EXPORT    = qw(portAvailable getAvailablePort isValidDN addSuffix getMappedEntries
-                process_maptbl check_and_add_entry getMappedEntries
+                process_maptbl check_and_add_entry getMappedEntries addErr
                 getHashedPassword debug createInfFromConfig shellEscape
                 isValidServerID isValidUser makePaths getLogin remove_tree remove_pidfile);
 @EXPORT_OK = qw(portAvailable getAvailablePort isValidDN addSuffix getMappedEntries
-                process_maptbl check_and_add_entry getMappedEntries
+                process_maptbl check_and_add_entry getMappedEntries addErr
                 getHashedPassword debug createInfFromConfig shellEscape
                 isValidServerID isValidUser makePaths getLogin remove_tree remove_pidfile);
 
@@ -658,7 +658,7 @@ sub process_maptbl
                 }
                 else
                 {
-                    push @{$errs}, 'no_mapvalue_for_key', $value, $key;
+                    push @{$errs}, ['no_mapvalue_for_key', $value, $key];
                     return {};
                 }
             }
@@ -813,21 +813,21 @@ sub makePaths {
          $parent = dirname($parent)) {
         unshift @dirnames, $parent;
     }
-    for (@dirnames) {
-        next if (-d $_);
+    for my $dir (@dirnames) {
+        next if (-d $dir);
         $! = 0; # clear
-        mkdir $_, $mode;
+        mkdir $dir, $mode;
         if ($!) {
-            return ('error_creating_directory', $_, $!);
+            return ('error_creating_directory', $dir, $!);
         }
-        chown $uid, $gid, $_;
+        chown $uid, $gid, $dir;
         if ($!) {
-            return ('error_chowning_directory', $_, $!);
+            return ('error_chowning_directory', $dir, $!);
         }
-        chmod $mode, $_;
+        chmod $mode, $dir;
         $mode_string = sprintf "%lo", $mode;
-        debug(1, "makePaths: created directory $_ mode $mode_string user $user group $group\n");
-        debug(2, "\t" . `ls -ld $_`);
+        debug(1, "makePaths: created directory $dir mode $mode_string user $user group $group\n");
+        debug(2, "\t" . `ls -ld $dir`);
     }
 
     return ();
@@ -926,9 +926,10 @@ sub remove_pidfile
     unless(open(INFILE,"$instdir/start-slapd")) {
         print("Cannot open start-slapd file for reading "); return 0;
     }
-    while(<INFILE>) {
-        if (/start-dirsrv /g) {
-            my @servline=split(/start-dirsrv /, );
+    my $line;
+    while($line = <INFILE>) {
+        if ($line =~ /start-dirsrv /g) {
+            my @servline=split(/start-dirsrv /, $line);
             @servline=split(/\s+/, $servline[1]);
             $serv_id=$servline[0];
         }
@@ -939,14 +940,14 @@ sub remove_pidfile
     unless(open(INFILE,"@initconfigdir@/@package_name@-$serv_id")) {
         print("Couldn't open @initconfigdir@/@package_name@-$serv_id "); return 0;
     }
-    while(<INFILE>) {
-        if (/RUN_DIR=/g) {
-            my @rundir_line=split(/RUN_DIR=+/, );
+    while($line = <INFILE>) {
+        if ($line =~ /RUN_DIR=/g) {
+            my @rundir_line=split(/RUN_DIR=+/, $line);
             @rundir_line=split(/;/, $rundir_line[1]);
             $run_dir = $rundir_line[0];
             chop($run_dir);
-        } elsif (/PRODUCT_NAME=/g) {
-            my @product_line=split(/PRODUCT_NAME=+/, );
+        } elsif ($line =~ /PRODUCT_NAME=/g) {
+            my @product_line=split(/PRODUCT_NAME=+/, $line);
             @product_line=split(/;/, $product_line[1]);
             $product_name = $product_line[0];
             chop($product_name);
diff --git a/ldap/admin/src/scripts/dnaplugindepends.ldif b/ldap/admin/src/scripts/dnaplugindepends.ldif
new file mode 100644
index 0000000..9622c42
--- /dev/null
+++ b/ldap/admin/src/scripts/dnaplugindepends.ldif
@@ -0,0 +1,4 @@
+dn: cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
+changetype: modify
+add: nsslapd-plugin-depends-on-type
+nsslapd-plugin-depends-on-type: database
diff --git a/ldap/admin/src/scripts/dsupdate.map.in b/ldap/admin/src/scripts/dsupdate.map.in
new file mode 100644
index 0000000..a1c0633
--- /dev/null
+++ b/ldap/admin/src/scripts/dsupdate.map.in
@@ -0,0 +1,65 @@
+# 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) 2007 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# [Parameter resolution rules]
+# * If the right-hand value is in ` (backquote), the value is eval'ed by perl.
+#   The output should be stored in $returnvalue to pass to the internal hash.
+# * If the right-hand value is in " (doublequote), the value is passed as is.
+# * If the right-hand value is not in any quote, the value should be found
+#   in either of the setup inf file (static) or the install inf file (dynamic).
+# * Variables surrounded by @ (e.g., @configdir@) are replaced with the 
+#   system path at the compile time.
+# * The right-hand value can contain variables surrounded by % (e.g., %asid%)
+#   which refers the right-hand value (key) of this map file.
+# 
+fqdn =			FullMachineName
+dsid =			ServerIdentifier
+ds_user =		SuiteSpotUserID
+ds_port =		ServerPort
+rootdn =		RootDN
+
+schema_dir =    schema_dir
+lock_dir =      lock_dir
+tmp_dir =       tmp_dir
+cert_dir =      cert_dir
+ldif_dir =      ldif_dir
+bak_dir =       bak_dir
+inst_dir =      inst_dir
+log_dir =       log_dir
+config_dir =    config_dir
+db_dir =        db_dir
+run_dir =       run_dir
diff --git a/ldap/admin/src/scripts/exampleupdate.ldif b/ldap/admin/src/scripts/exampleupdate.ldif
new file mode 100644
index 0000000..00f9a70
--- /dev/null
+++ b/ldap/admin/src/scripts/exampleupdate.ldif
@@ -0,0 +1,40 @@
+# 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) 2009 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# These files work the same way as the LDIF templates in
+# /usr/share/dirsrv/ldif/template*.ldif
diff --git a/ldap/admin/src/scripts/exampleupdate.pl b/ldap/admin/src/scripts/exampleupdate.pl
new file mode 100644
index 0000000..cff4a3d
--- /dev/null
+++ b/ldap/admin/src/scripts/exampleupdate.pl
@@ -0,0 +1,56 @@
+# 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) 2009 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+sub pre {
+    my ($inf, $configdir) = @_;
+}
+
+sub preinst {
+    my ($inf, $inst, $dseldif, $conn) = @_;
+}
+sub runinst {
+    my ($inf, $inst, $dseldif, $conn) = @_;
+}
+
+sub postinst {
+    my ($inf, $inst, $dseldif, $conn) = @_;
+}
+
+sub post {
+    my ($inf, $configdir) = @_;
+}
diff --git a/ldap/admin/src/scripts/exampleupdate.sh b/ldap/admin/src/scripts/exampleupdate.sh
new file mode 100644
index 0000000..dae2e4c
--- /dev/null
+++ b/ldap/admin/src/scripts/exampleupdate.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# 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) 2009 Red Hat, Inc.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# There are several environment variables passed in:
+my $PRE_STAGE = "pre";
+my $PREINST_STAGE = "preinst";
+my $RUNINST_STAGE = "runinst";
+my $POSTINST_STAGE = "postinst";
+my $POST_STAGE = "post";
+
+# $DS_UPDATE_STAGE - the current stage of the update - one of
+# pre - called at the beginning of the update
+# preinst - called before processing an instance
+# runinst - the main update stage for an instance
+# postinst - called after processing an instance
+# post - called the the end of the update
+# you should definitely check the stage to make sure you only perform
+# your actions during the correct stage e.g.
+
+if [ "$DS_UPDATE_STAGE" != "pre" ] ; then
+    exit 0
+fi
+
+# $DS_UPDATE_DIR - the main config directory containing the schema dir
+#   the config dir and the instance specific (slapd-instance) directories
+# $DS_UPDATE_INST - the name of the instance (slapd-instance), if one of the instance specific stages
+# $DS_UPDATE_DSELDIF - the full path ane filename of the dse.ldif file for the instance
diff --git a/ldap/admin/src/scripts/migrate-ds.res b/ldap/admin/src/scripts/migrate-ds.res
index 3d01f0f..d58649b 100644
--- a/ldap/admin/src/scripts/migrate-ds.res
+++ b/ldap/admin/src/scripts/migrate-ds.res
@@ -9,7 +9,6 @@ error_reading_olddbconfig = Could not read the old database configuration inform
 error_migrating_schema = Could not copy old schema file '%s'.  Error: %s\n
 error_opening_schema = Could not open new schema file '%s'.  Error: %s\n
 error_schema_permissions = Could not reset permissions on schema file '%s'.  Error: %s\n
-error_renaming_schema = Could not rename schema file '%s' tp '%s'.  Error: %s\n
 error_copying_dbdir = Could not copy database directory '%s' to '%s'.  Error: %s\n
 error_copying_dbfile = Could not copy database file '%s' to '%s'.  Error: %s\n
 error_dbsrcdir_not_exist = Could not copy from the database source directory '%s' because it does not exist.  Please check your configuration.\n
diff --git a/ldap/admin/src/scripts/setup-ds.pl.in b/ldap/admin/src/scripts/setup-ds.pl.in
index 7fdc977..aad6bfc 100644
--- a/ldap/admin/src/scripts/setup-ds.pl.in
+++ b/ldap/admin/src/scripts/setup-ds.pl.in
@@ -48,6 +48,7 @@ use Resource;
 use DialogManager;
 use Util;
 use DSCreate;
+use DSUpdate;
 
 my $res = new Resource("@propertydir@/setup-ds.res");
 
@@ -56,11 +57,16 @@ my $setup = new Setup($res);
 if (!$setup->{silent}) {
     my $dialogmgr = new DialogManager($setup, $res, $TYPICAL);
 
-    require SetupDialogs;
-    require DSDialogs;
-
-    my @dialogs = SetupDialogs->getDialogs();
-    push @dialogs, DSDialogs->getDialogs();
+    my @dialogs;
+    if ($setup->{update}) {
+        require DSUpdateDialogs;
+        push @dialogs, DSUpdateDialogs->getDialogs();
+    } else {
+        require SetupDialogs;
+        require DSDialogs;
+        push @dialogs, SetupDialogs->getDialogs();
+        push @dialogs, DSDialogs->getDialogs();
+    }
 
     $dialogmgr->addDialog(@dialogs);
 
@@ -71,15 +77,29 @@ if (!$setup->{silent}) {
     $setup->{inf}->write();
 }
 
-my @errs = createDSInstance($setup->{inf});
+my @errs;
+if ($setup->{update}) {
+    @errs = updateDS($setup);
+} else {
+    @errs = createDSInstance($setup->{inf});
+}
+
 if (@errs) {
     $setup->msg(@errs);
-    $setup->msg($FATAL, 'error_creating_dsinstance',
-                $setup->{inf}->{slapd}->{ServerIdentifier});
+    if ($setup->{update}) {
+        $setup->msg($FATAL, 'error_updating');
+    } else {
+        $setup->msg($FATAL, 'error_creating_dsinstance',
+                    $setup->{inf}->{slapd}->{ServerIdentifier});
+    }
     $setup->doExit(1);
 } else {
-    $setup->msg('created_dsinstance',
-                $setup->{inf}->{slapd}->{ServerIdentifier});
+    if ($setup->{update}) {
+        $setup->msg('update_successful');
+    } else {
+        $setup->msg('created_dsinstance',
+                    $setup->{inf}->{slapd}->{ServerIdentifier});
+    }
 }
 
 $setup->doExit(0);
@@ -91,3 +111,10 @@ END {
         }
     }
 }
+
+# emacs settings
+# Local Variables:
+# mode:perl
+# indent-tabs-mode: nil
+# tab-width: 4
+# End:
diff --git a/ldap/admin/src/scripts/setup-ds.res.in b/ldap/admin/src/scripts/setup-ds.res.in
index 5326963..c4be658 100644
--- a/ldap/admin/src/scripts/setup-ds.res.in
+++ b/ldap/admin/src/scripts/setup-ds.res.in
@@ -136,3 +136,48 @@ error_no_such_instance = Error: could not find directory server configuration di
 error_finding_config_entry = Error: could not find the config entry '%s' in '%s'.  Error: %s\n
 error_removing_path = Error: could not remove path '%s'.  Error: %s\n
 error_removing_port_label = Error: could not remove selinux label from port '%s'.  Error: %s\n
+error_loading_update = Error: not applying update '%s'.  Error: %s\n
+error_unknown_update = Error: cannot apply update '%s'.  Not a recognized update type.\n
+error_executing_update = Error: update '%s' returned code '%s': %s\n
+error_updating = Error: could not update the directory server.\n
+update_successful = Finished successful update of directory server.\n
+
+update_dialog_first = This program will update the %s Directory Server.\n\nIt is recommended that you have "root" privilege to perform the update.\nTips for using this  program:\n  - Press "Enter" to choose the default and go to the next screen\n  - Type "Control-B" or the word "back" then "Enter" to go back to the previous screen\n  - Type "Control-C" to cancel the update\n\n
+# %s -> brand
+
+update_dialog_first_prompt = Would you like to continue with update?
+
+update_dialog_mode =\
+The update process can work in one of two modes:\
+\
+  - Online: The changes are made to the running directory servers using LDAP.\
+            The operations must be performed as an administrative user.\
+            You must provide the name and password, for each instance\
+            if there is more than one instance of directory server.\
+            Some operations may require a directory server restart to take\
+            effect.  The update script will notify you if you need to restart\
+            the server.\
+\
+  - Offline: The changes are made to the server configuration files.  The\
+             servers MUST FIRST BE SHUTDOWN BY YOU.  The script will not\
+             shutdown the servers for you.  You MUST shutdown the\
+             servers in order to use this mode.  A username and password\
+             are not required to use Offline mode.  If the servers are not\
+             shutdown, CHANGES WILL BE LOST.\
+\
+To summarize:\
+  Online - servers remain running - you must provide admin name and password\
+           for each server - servers may need to be restarted\
+  Offline - servers must be shutdown - no username or password required\n\n
+
+update_dialog_mode_prompt = Which update mode do you want to use?
+
+update_admin_dialog = Please specify the authentication data for '%s'\n\n
+update_admin_id_prompt = Full DN of administrative user
+update_admin_pwd_prompt = Password for this user
+error_renaming_schema = Could not rename schema file '%s' tp '%s'.  Error: %s\n
+error_reading_schema_dir = Schema directory '%s' does not exist or is not readable\n
+error_online_update = Could not open a connection to the server at %s port %s as '%s'.\
+Please make sure the server is up and running before using online mode,\
+or use offline mode.\n\n
+error_offline_update = Could not read the server config file '%s'. Error: %s\n\n
diff --git a/ldap/ldif/template-pampta.ldif.in b/ldap/ldif/template-pampta.ldif.in
index 2875df7..10df352 100644
--- a/ldap/ldif/template-pampta.ldif.in
+++ b/ldap/ldif/template-pampta.ldif.in
@@ -17,4 +17,8 @@ pamIDAttr: notUsedWithRDNMethod
 pamFallback: FALSE
 pamSecure: TRUE
 pamService: ldapserver
-
+# these will be replaced when the server loads the plugin
+nsslapd-pluginId: ID
+nsslapd-pluginVersion: PACKAGE_VERSION
+nsslapd-pluginVendor: VENDOR
+nsslapd-pluginDescription: DESC
-- 
1.5.5.6

