From b6db4d342bdd1845c7ff5740ef69e6bf5afaf091 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Fri, 04 Sep 2026 08:12:29 +0000
Subject: [PATCH] Modernize Debian and RPM packaging (systemd, dedicated user, CI tests) (#663)

---
 opendj-packages/opendj-rpm/resources/specs/preinstall.sh                     |   79 +
 opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-upgrade.adoc   |    4 
 opendj-packages/opendj-deb/resources/control/postinst                        |  144 ++
 opendj-packages/resources/generate-changelog.sh                              |  144 +++
 opendj-packages/opendj-deb/resources/control/preinst                         |   65 +
 opendj-packages/opendj-rpm/opendj-rpm-standard/pom.xml                       |    3 
 opendj-packages/resources/sysv/opendj                                        |   92 +
 opendj-packages/opendj-deb/resources/changelog                               |  842 +++++++++++++++++
 opendj-packages/opendj-deb/resources/control/prerm                           |   66 +
 opendj-packages/opendj-rpm/resources/specs/preuninstall.sh                   |   71 +
 .github/scripts/wait-for-ldap.sh                                             |   32 
 opendj-packages/resources/env/opendj                                         |   38 
 opendj-packages/opendj-deb/resources/control/postrm                          |   36 
 opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-install.adoc   |   86 -
 opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-uninstall.adoc |   10 
 opendj-packages/opendj-rpm/resources/specs/postinstall.sh                    |  140 ++
 opendj-packages/opendj-rpm/resources/changelog                               |  577 +++++++++++
 opendj-packages/opendj-deb/opendj-deb-standard/pom.xml                       |    3 
 opendj-packages/opendj-deb/pom.xml                                           |   29 
 .github/workflows/build.yml                                                  |  237 ++++
 opendj-packages/opendj-rpm/resources/specs/postuninstall.sh                  |   17 
 opendj-packages/resources/systemd/opendj.service                             |   56 +
 opendj-packages/opendj-deb/resources/control/control                         |    5 
 opendj-server-legacy/resource/bin/_script-util.sh                            |    4 
 opendj-packages/opendj-rpm/pom.xml                                           |   48 
 25 files changed, 2,566 insertions(+), 262 deletions(-)

diff --git a/.github/scripts/wait-for-ldap.sh b/.github/scripts/wait-for-ldap.sh
new file mode 100755
index 0000000..386bcfe
--- /dev/null
+++ b/.github/scripts/wait-for-ldap.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# The contents of this file are subject to the terms of the Common Development and
+# Distribution License (the License). You may not use this file except in compliance with the
+# License.
+#
+# You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+# specific language governing permission and limitations under the License.
+#
+# When distributing Covered Software, include this CDDL Header Notice in each file and include
+# the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+# Header, with the fields enclosed by brackets [] replaced by your own identifying
+# information: "Portions copyright [year] [name of copyright owner]".
+#
+# Copyright 2026 3A Systems, LLC.
+
+# Waits until the OpenDJ instance under /opt/opendj answers a base search on
+# localhost:$1 (default 1389) with the CI test credentials. Exits non-zero if
+# the server does not come up within ~60 seconds.
+
+PORT="${1:-1389}"
+i=0
+while [ "$i" -lt 20 ] ; do
+    if /opt/opendj/bin/ldapsearch -h localhost -p "$PORT" -D "cn=Directory Manager" -w password \
+        -b "dc=example,dc=com" -s base "(objectClass=*)" 1.1 >/dev/null 2>&1 ; then
+        exit 0
+    fi
+    i=$((i + 1))
+    sleep 3
+done
+echo "OpenDJ did not answer on port $PORT within the timeout" >&2
+exit 1
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 90ecc71..efb811e 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -24,7 +24,8 @@
   cancel-in-progress: true
 
 # Nothing in this workflow writes back to the repository: the docker jobs push to
-# the local registry service, not to a remote one. The docker jobs additionally get
+# the local registry service, not to a remote one, and the other jobs only
+# publish artifacts through the actions API. The docker jobs additionally get
 # security-events: write to upload Trivy scan results to code scanning.
 permissions:
   contents: read
@@ -680,6 +681,240 @@
           if-no-files-found: warn
           retention-days: 90
 
+  test-deb:
+    needs: build-maven
+    runs-on: 'ubuntu-latest'
+    steps:
+      - uses: actions/checkout@v6
+      - name: Download artifacts
+        uses: actions/download-artifact@v8
+        with:
+          name: ubuntu-latest-11
+      - name: Clean-room install + SysV start/stop (debian:12 container)
+        shell: bash
+        run: |
+          docker run --rm -v "$PWD:/work" -w /work debian:12 bash -c '
+            set -e
+            export DEBIAN_FRONTEND=noninteractive
+            DEB=$(ls opendj-packages/opendj-deb/opendj-deb-standard/target/*.deb | head -1)
+            echo "Found $DEB"
+            apt-get update
+            apt-get install -y lintian
+            lintian --info --no-tag-display-limit "$DEB" || true
+            dpkg-deb -I "$DEB"
+            # Both service files must be present (two greps: a single alternation
+            # would pass with either one missing).
+            dpkg-deb -c "$DEB" | grep "lib/systemd/system/opendj.service"
+            dpkg-deb -c "$DEB" | grep "etc/init.d/opendj"
+            # /etc/default/opendj must be a real conffile, so admin edits survive
+            # upgrades and the file survives "apt remove".
+            dpkg-deb -e "$DEB" /tmp/ctrl
+            grep -qx "/etc/default/opendj" /tmp/ctrl/conffiles
+            apt-get install -y "./$DEB"
+            id opendj
+            test "$(stat -c %U /opt/opendj)" = opendj
+            # No JAVA_HOME in this clean container: Java resolves from the PATH
+            # java that the package JRE dependency pulled in.
+            runuser -u opendj -- /opt/opendj/setup --cli --no-prompt --acceptLicense --doNotStart \
+              --rootUserDN "cn=Directory Manager" --rootUserPassword password \
+              --hostname localhost --ldapPort 1389 --adminConnectorPort 4444 \
+              --baseDN dc=example,dc=com --addBaseEntry
+            /etc/init.d/opendj start
+            bash .github/scripts/wait-for-ldap.sh 1389
+            /etc/init.d/opendj status
+            /etc/init.d/opendj stop
+            apt-get purge -y opendj
+          '
+      - name: Live systemd install + start/stop (runner)
+        shell: bash
+        run: |
+          DEB=$(ls opendj-packages/opendj-deb/opendj-deb-standard/target/*.deb | head -1)
+          sudo apt-get update
+          sudo apt-get install -y "$PWD/$DEB"
+          test "$(stat -c '%U' /opt/opendj)" = opendj
+          # postinst must have enabled the unit; do not enable by hand here or
+          # the postinst registration would go untested.
+          sudo systemctl is-enabled --quiet opendj
+          # Before setup the unit's start condition must keep it from
+          # start-bursting: "start" succeeds but no process may appear.
+          sudo systemctl start opendj
+          sleep 2
+          if sudo systemctl is-failed --quiet opendj; then echo "unit failed before setup"; exit 1; fi
+          # sudo/runuser/systemd strip JAVA_HOME -> the service uses the PATH java.
+          # Privileged port 389: only AmbientCapabilities=CAP_NET_BIND_SERVICE lets
+          # the non-root service bind it - the very reason it can drop root. setup
+          # itself runs via runuser WITHOUT that capability, so it must skip its
+          # own bind probe; the systemd start below performs the real 389 bind.
+          sudo runuser -u opendj -- /opt/opendj/setup --cli --no-prompt --acceptLicense --doNotStart \
+            --rootUserDN "cn=Directory Manager" --rootUserPassword password \
+            --hostname localhost --ldapPort 389 --adminConnectorPort 4444 \
+            --baseDN dc=example,dc=com --addBaseEntry --skipPortCheck
+          sudo systemctl start opendj
+          bash .github/scripts/wait-for-ldap.sh 389
+          sudo systemctl is-active --quiet opendj
+          echo "OpenDJ is active under systemd"
+          sudo systemctl stop opendj
+          sleep 3
+          if sudo systemctl is-active --quiet opendj; then echo "still active"; exit 1; fi
+          sudo apt-get purge -y opendj
+
+  # Known coverage limit: the container has no booted systemd (/run/systemd/system
+  # is absent), so only the SysV/chkconfig path of the scriptlets is exercised
+  # here; start/stop through systemd is covered by the deb live-systemd jobs on
+  # the runner. The enable registration IS asserted below - systemctl enable is
+  # a pure symlink operation and works without a booted systemd.
+  test-rpm:
+    needs: build-maven
+    runs-on: 'ubuntu-latest'
+    steps:
+      - uses: actions/checkout@v6
+      - name: Download artifacts
+        uses: actions/download-artifact@v8
+        with:
+          name: ubuntu-latest-11
+      - name: Install and start/stop in Rocky Linux 9
+        shell: bash
+        run: |
+          docker run --rm -v "$PWD:/work" -w /work rockylinux:9 bash -c '
+            set -e
+            RPM=$(ls opendj-packages/opendj-rpm/opendj-rpm-standard/target/rpm/opendj/RPMS/noarch/*.rpm | head -1)
+            echo "Found $RPM"
+            # Both service files must be shipped.
+            rpm -qlp "$RPM" | grep "^/usr/lib/systemd/system/opendj.service$"
+            rpm -qlp "$RPM" | grep "^/etc/init.d/opendj$"
+            # The %pre user-creation dependency must be declared for minimal images.
+            rpm -qp --requires "$RPM" | grep "shadow-utils"
+            # A real EL9 host always has systemd, but the container image ships no
+            # systemctl at all - %post then (correctly) skips the enable in silence.
+            # Preinstall it as host infrastructure, deliberately NOT a package
+            # Requires, so the is-enabled assertion below tests the enable path.
+            dnf install -y systemd
+            # No further manual dependencies: the package must pull everything else
+            # itself (Requires).
+            dnf install -y "$RPM"
+            id opendj
+            test "$(stat -c %U /opt/opendj)" = opendj
+            # %post must have enabled the unit on initial install.
+            systemctl is-enabled opendj.service
+            # No JAVA_HOME here: Java resolves from the PATH java pulled in by
+            # the java-headless dependency.
+            runuser -u opendj -- /opt/opendj/setup --cli --no-prompt --acceptLicense --doNotStart \
+              --rootUserDN "cn=Directory Manager" --rootUserPassword password \
+              --hostname localhost --ldapPort 1389 --adminConnectorPort 4444 \
+              --baseDN dc=example,dc=com --addBaseEntry
+            /etc/init.d/opendj start
+            bash .github/scripts/wait-for-ldap.sh 1389
+            /etc/init.d/opendj status
+            /etc/init.d/opendj stop
+            rpm -e opendj
+          '
+
+  # Upgrade path: released 5.1.2 deb (root-owned, SysV) -> this build's deb, on the
+  # runner's LIVE systemd. The new package must stop the running server, create the
+  # opendj user, migrate ownership, run the upgrade tool and restart the server with
+  # the old data - through deb-systemd-invoke and the native unit, the path a real
+  # systemd host takes (docs: chap-upgrade).
+  test-deb-upgrade:
+    needs: build-maven
+    runs-on: 'ubuntu-latest'
+    steps:
+      - uses: actions/checkout@v6
+      - name: Download artifacts
+        uses: actions/download-artifact@v8
+        with:
+          name: ubuntu-latest-11
+      - name: Download released 5.1.2 deb
+        shell: bash
+        run: |
+          curl -fsSL -o opendj-5.1.2.deb https://github.com/OpenIdentityPlatform/OpenDJ/releases/download/5.1.2/opendj_5.1.2-1_all.deb
+          # Pin the upgrade source: a retagged release asset must fail loudly here,
+          # not surface as an unrelated upgrade-job failure.
+          echo "8f7f8bdd526b2d63eaef0621545be6aa55749cb60200d3bc2a2849d9ab69eb59  opendj-5.1.2.deb" | sha256sum -c -
+      - name: Upgrade 5.1.2 -> new deb (live systemd on the runner)
+        shell: bash
+        run: |
+          NEW=$(ls opendj-packages/opendj-deb/opendj-deb-standard/target/*.deb | head -1)
+          echo "New deb: $NEW"
+          sudo apt-get update
+          # No manual dependencies: even the released 5.1.2 deb declares a JRE dependency.
+          sudo apt-get install -y "$PWD/opendj-5.1.2.deb"
+          # 5.1.2 model: no dedicated user, root-owned tree, SysV only - on this
+          # booted host its unit comes from the systemd-sysv-generator.
+          sudo /opt/opendj/setup --cli --no-prompt --acceptLicense --doNotStart \
+            --rootUserDN "cn=Directory Manager" --rootUserPassword password \
+            --hostname localhost --ldapPort 1389 --adminConnectorPort 4444 \
+            --baseDN dc=example,dc=com --addBaseEntry
+          sudo systemctl daemon-reload
+          sudo /etc/init.d/opendj start
+          bash .github/scripts/wait-for-ldap.sh 1389
+          # Leave the server RUNNING: the new package must stop it, upgrade and
+          # restart it - through deb-systemd-invoke and the native unit this time.
+          sudo apt-get install -y "$PWD/$NEW"
+          id opendj
+          test "$(stat -c %U /opt/opendj)" = opendj
+          test -f /opt/opendj/config/config.ldif
+          # The systemd-hosted upgrade must leave the unit enabled and active.
+          sudo systemctl is-enabled --quiet opendj
+          sudo systemctl is-active --quiet opendj
+          # The pre-upgrade data must be served again, now by the dedicated user.
+          bash .github/scripts/wait-for-ldap.sh 1389
+          test "$(stat -c %U /proc/$(cat /opt/opendj/logs/server.pid))" = opendj
+          sudo systemctl stop opendj
+          sleep 3
+          if sudo systemctl is-active --quiet opendj; then echo "still active"; exit 1; fi
+          sudo apt-get purge -y opendj
+
+  test-rpm-upgrade:
+    needs: build-maven
+    runs-on: 'ubuntu-latest'
+    steps:
+      - uses: actions/checkout@v6
+      - name: Download artifacts
+        uses: actions/download-artifact@v8
+        with:
+          name: ubuntu-latest-11
+      - name: Download released 5.1.2 rpm
+        shell: bash
+        run: |
+          curl -fsSL -o opendj-5.1.2.rpm https://github.com/OpenIdentityPlatform/OpenDJ/releases/download/5.1.2/opendj-5.1.2-1.noarch.rpm
+          # Pin the upgrade source: a retagged release asset must fail loudly here,
+          # not surface as an unrelated upgrade-job failure.
+          echo "9622ef7c3292f0c156c96029a647ca704064aa93b567e5608734fe07d224ec58  opendj-5.1.2.rpm" | sha256sum -c -
+      - name: Upgrade 5.1.2 -> new rpm (Rocky Linux 9 container)
+        shell: bash
+        run: |
+          docker run --rm -v "$PWD:/work" -w /work rockylinux:9 bash -c '
+            set -e
+            NEW=$(ls opendj-packages/opendj-rpm/opendj-rpm-standard/target/rpm/opendj/RPMS/noarch/*.rpm | head -1)
+            echo "New rpm: $NEW"
+            # No manual dependencies: the released 5.1.2 rpm already declares its runtime
+            # requirements (#677), and everything the NEW package needs must come from its
+            # own Requires.
+            dnf install -y ./opendj-5.1.2.rpm
+            # 5.1.2 model: no dedicated user, root-owned tree, SysV only
+            /opt/opendj/setup --cli --no-prompt --acceptLicense --doNotStart \
+              --rootUserDN "cn=Directory Manager" --rootUserPassword password \
+              --hostname localhost --ldapPort 1389 --adminConnectorPort 4444 \
+              --baseDN dc=example,dc=com --addBaseEntry
+            /etc/init.d/opendj start
+            bash .github/scripts/wait-for-ldap.sh 1389
+            # Leave the server RUNNING: the new package must stop it, upgrade and restart it.
+            dnf install -y "./$NEW"
+            id opendj
+            test "$(stat -c %U /opt/opendj)" = opendj
+            test -f /opt/opendj/config/config.ldif
+            # 5.1.2 was chkconfig-enabled and the native unit now shadows the
+            # sysv-generator unit: %post must have migrated that enable state
+            # (a pure symlink operation, asserted fine without booted systemd).
+            systemctl is-enabled opendj.service
+            # The package restarted the server; the pre-upgrade data must be served again,
+            # now by the dedicated user.
+            bash .github/scripts/wait-for-ldap.sh 1389
+            test "$(stat -c %U /proc/$(cat /opt/opendj/logs/server.pid))" = opendj
+            /etc/init.d/opendj stop
+            rpm -e opendj
+          '
+
   test-msi:
     needs: build-maven
     runs-on: 'windows-latest'
diff --git a/opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-install.adoc b/opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-install.adoc
index f976103..4e7053f 100644
--- a/opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-install.adoc
+++ b/opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-install.adoc
@@ -434,51 +434,30 @@
 ====
 On Debian and related Linux distributions such as Ubuntu, you can install OpenDJ directory server from the Debian package:
 
-. (Optional)  Before you install OpenDJ, install a Java runtime environment if none is installed yet:
-+
-
-[source, console]
-----
-$ sudo apt-get install default-jre
-----
-
-. Install the OpenDJ directory server package:
+. Install the OpenDJ directory server package. Use `apt-get install ./<file>.deb` (rather than `dpkg -i`) so the required Java runtime dependency (`default-jre-headless`) is resolved and installed automatically:
 +
 
 [source, console, subs="attributes"]
 ----
-$ sudo dpkg -i opendj_{opendj-version}-1_all.deb
-Selecting previously unselected package opendj.
-(Reading database ... 185569 files and directories currently installed.)
-Unpacking opendj (from opendj_{opendj-version}-1_all.deb) ...
-
-Setting up opendj ({opendj-version}) ...
- Adding system startup for /etc/init.d/opendj ...
-   /etc/rc0.d/K20opendj -> ../init.d/opendj
-   /etc/rc1.d/K20opendj -> ../init.d/opendj
-   /etc/rc6.d/K20opendj -> ../init.d/opendj
-   /etc/rc2.d/S20opendj -> ../init.d/opendj
-   /etc/rc3.d/S20opendj -> ../init.d/opendj
-   /etc/rc4.d/S20opendj -> ../init.d/opendj
-   /etc/rc5.d/S20opendj -> ../init.d/opendj
-
-Processing triggers for ureadahead ...
-ureadahead will be reprofiled on next reboot
+$ sudo apt-get install ./opendj_{opendj-version}-1_all.deb
 ----
 +
-The Debian package installs OpenDJ directory server in the `/opt/opendj` directory, generates service management scripts, adds documentation files under `/usr/share/doc/opendj`, and adds man pages under `/opt/opendj/share/man`.
+The Debian package installs OpenDJ directory server in the `/opt/opendj` directory, registers the service with systemd (`opendj.service`, with a SysV init script kept as a fallback on non-systemd hosts), adds documentation files under `/usr/share/doc/opendj`, and adds man pages under `/opt/opendj/share/man`.
 +
-The files are owned by root by default, making it easier to have OpenDJ listen on ports 389 and 636.
+The package creates a dedicated `opendj` system user; the files under `/opt/opendj` are owned by it and the service runs as that user. The systemd service is granted `CAP_NET_BIND_SERVICE`, so it can bind privileged ports such as LDAP 389 and LDAPS 636 even though it runs as a non-root user. On non-systemd hosts that use the SysV init script, grant the capability another way (for example `authbind` or an `iptables` redirect) or use ports above 1024.
++
+To pin or override the Java runtime used by the service, set `OPENDJ_JAVA_HOME` (or `OPENDJ_JAVA_ARGS`) in `/etc/default/opendj`.
 
-. Configure OpenDJ directory server by using the command `sudo /opt/opendj/setup`:
+. Configure OpenDJ directory server by running `setup` as the `opendj` user (the account that owns the files and runs the service). Pass `--doNotStart` so that the server is started by systemd rather than by `setup` itself, then start the service:
 +
 
 [source, console]
 ----
-$ sudo /opt/opendj/setup --cli
+$ sudo -u opendj /opt/opendj/setup --cli --doNotStart
 ...
 To see basic server configuration status and configuration you can launch
  /opt/opendj/bin/status
+$ sudo systemctl start opendj
 ----
 
 . (Optional)  Check OpenDJ directory server status:
@@ -486,9 +465,9 @@
 
 [source, console, subs="attributes"]
 ----
-$ service opendj status
-opendj status: > Running.
-$ sudo /opt/opendj/bin/status
+$ systemctl is-active opendj
+active
+$ sudo -u opendj /opt/opendj/bin/status
 
 
 >>>> Specify OpenDJ LDAP connection parameters
@@ -543,41 +522,31 @@
 #
 ----
 
-. Before you install OpenDJ, install a Java runtime environment if none is installed yet.
-+
-You might need to download an RPM to install the Java runtime environment, and then install the RPM by using the `rpm` command:
-+
-
-[source, console]
-----
-# rpm -ivh jre-*.rpm
-----
-
-. Install the OpenDJ directory server package:
+. Install the OpenDJ directory server package. Use `dnf install ./<file>.rpm` (rather than `rpm -i`) so the required Java runtime dependency (`java-headless >= 11`) is resolved and installed automatically:
 +
 
 [source, console, subs="attributes"]
 ----
-# rpm -i opendj-{opendj-version}-1.noarch.rpm
-Pre Install - initial install
+# dnf install ./opendj-{opendj-version}-1.noarch.rpm
 Post Install - initial install
-
-#
 ----
 +
-The RPM package installs OpenDJ directory server in the `/opt/opendj` directory, generates service management scripts, and adds man pages under `/opt/opendj/share/man`.
+The RPM package installs OpenDJ directory server in the `/opt/opendj` directory, registers the service with systemd (`opendj.service`, with a SysV init script kept as a fallback on non-systemd hosts), and adds man pages under `/opt/opendj/share/man`.
 +
-The files are owned by root by default, making it easier to have OpenDJ listen on ports 389 and 636.
+The package creates a dedicated `opendj` system user; the files under `/opt/opendj` are owned by it and the service runs as that user. The systemd service is granted `CAP_NET_BIND_SERVICE`, so it can bind privileged ports such as LDAP 389 and LDAPS 636 even though it runs as a non-root user. On non-systemd hosts that use the SysV init script, grant the capability another way (for example `authbind` or an `iptables` redirect) or use ports above 1024.
++
+To pin or override the Java runtime used by the service, set `OPENDJ_JAVA_HOME` (or `OPENDJ_JAVA_ARGS`) in `/etc/sysconfig/opendj`.
 
-. Configure OpenDJ directory server by using the command `/opt/opendj/setup`:
+. Configure OpenDJ directory server by running `setup` as the `opendj` user (the account that owns the files and runs the service). Pass `--doNotStart` so that the server is started by systemd rather than by `setup` itself, then start the service:
 +
 
 [source, console]
 ----
-# /opt/opendj/setup --cli
+# runuser -u opendj -- /opt/opendj/setup --cli --doNotStart
 ...
 To see basic server configuration status and configuration you can launch
  /opt/opendj/bin/status
+# systemctl start opendj
 ----
 
 . (Optional)  Check OpenDJ directory server status:
@@ -585,9 +554,9 @@
 
 [source, console, subs="attributes"]
 ----
-# service opendj status
-opendj status: > Running.
-# /opt/opendj/bin/status
+# systemctl is-active opendj
+active
+# runuser -u opendj -- /opt/opendj/bin/status
 
 
 >>>> Specify OpenDJ LDAP connection parameters
@@ -625,14 +594,13 @@
 Replication:
 ----
 +
-By default OpenDJ starts in run levels 2, 3, 4, and 5:
+The service is enabled to start at boot:
 +
 
 [source, console]
 ----
-# chkconfig --list | grep opendj
-...
-opendj         0:off    1:off    2:on    3:on    4:on    5:on    6:off
+# systemctl is-enabled opendj
+enabled
 ----
 
 ====
diff --git a/opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-uninstall.adoc b/opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-uninstall.adoc
index 17e0413..665440d 100644
--- a/opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-uninstall.adoc
+++ b/opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-uninstall.adoc
@@ -124,12 +124,10 @@
 [03/Jun/2013:10:00:49 +0200] category=CORE severity=NOTICE
  msgID=458955 msg=The Directory Server is now stopped
 
-*OpenDJ successfully removed
-
 $
 ----
 +
-Removing the package does not remove your data or configuration. You must remove `/opt/opendj` manually to get rid of all files.
+Removing the package stops the server but does not remove your data or configuration, nor the dedicated `opendj` system user it created. Remove `/opt/opendj` manually to delete all files, and remove the `opendj` user if you no longer need it.
 
 ====
 
@@ -151,11 +149,13 @@
 [03/Jun/2013:10:42:46 +0200] category=CORE severity=NOTICE
  msgID=458955 msg=The Directory Server is now stopped
 Post Uninstall - uninstall
-OpenDJ successfully removed.
+OpenDJ package removed. Server data (config, db, changelogDb, logs)
+and the opendj system account are kept; remove them manually if they
+are no longer needed.
 #
 ----
 +
-Removing the package does not remove your data or configuration. You must remove `/opt/opendj` manually to get rid of all files.
+Removing the package stops the server but does not remove your data or configuration, nor the dedicated `opendj` system user it created. Remove `/opt/opendj` manually to delete all files, and remove the `opendj` user if you no longer need it.
 
 ====
 
diff --git a/opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-upgrade.adoc b/opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-upgrade.adoc
index 5077ecf..7b24f5b 100644
--- a/opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-upgrade.adoc
+++ b/opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-upgrade.adoc
@@ -91,7 +91,9 @@
 ====
 Before starting this procedure, follow the steps in xref:#before-you-upgrade["Before You Upgrade"].
 
-To upgrade to OpenDJ directory server installed from native packages (.deb, .rpm), use the command-line package management tools provided by the system.
+To upgrade OpenDJ directory server installed from native packages (.deb, .rpm), install the newer package with the system package manager (`sudo apt-get install ./opendj_{opendj-version}-1_all.deb` or `sudo dnf install ./opendj-{opendj-version}-1.noarch.rpm`). The package stops the running server, runs the `upgrade` tool as the dedicated `opendj` user, migrates file ownership under `/opt/opendj` to that user, and restarts the service (systemd, with a SysV init fallback) if it was running before the upgrade. Back up the installation directory first, as described in xref:#before-you-upgrade["Before You Upgrade"].
+
+After the upgrade the server runs as the non-root `opendj` user. An instance that listens on privileged ports such as LDAP 389 or LDAPS 636 keeps working under systemd, where the service is granted `CAP_NET_BIND_SERVICE`. On non-systemd hosts that use the SysV init script, grant the capability another way (for example `authbind` or an `iptables` redirect) or use ports above 1024, as described in the installation chapter.
 
 [NOTE]
 ======
diff --git a/opendj-packages/opendj-deb/opendj-deb-standard/pom.xml b/opendj-packages/opendj-deb/opendj-deb-standard/pom.xml
index 704a914..d29767c 100644
--- a/opendj-packages/opendj-deb/opendj-deb-standard/pom.xml
+++ b/opendj-packages/opendj-deb/opendj-deb-standard/pom.xml
@@ -13,6 +13,7 @@
   information: "Portions Copyright [year] [name of copyright owner]".
 
   Copyright 2015 ForgeRock AS.
+  Portions Copyright 2018-2026 3A Systems, LLC
 -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
@@ -33,6 +34,8 @@
 
     <properties>
         <sysv.file.location>${project.parent.parent.basedir}/resources/sysv/opendj</sysv.file.location>
+        <systemd.file.location>${project.parent.parent.basedir}/resources/systemd/opendj.service</systemd.file.location>
+        <env.file.location>${project.parent.parent.basedir}/resources/env/opendj</env.file.location>
         <deb.product.name>${product.name}</deb.product.name>
         <deb.product.name.lowercase>${product.name.lowercase}</deb.product.name.lowercase>
         <deb.product.summary>This OpenDJ package includes the Berkeley JE Backend and cannot be redistributed without a suitable license</deb.product.summary>
diff --git a/opendj-packages/opendj-deb/pom.xml b/opendj-packages/opendj-deb/pom.xml
index b516ffb..42ded66 100644
--- a/opendj-packages/opendj-deb/pom.xml
+++ b/opendj-packages/opendj-deb/pom.xml
@@ -13,6 +13,7 @@
   information: "Portions Copyright [year] [name of copyright owner]".
 
   Copyright 2015-2016 ForgeRock AS.
+  Portions Copyright 2018-2026 3A Systems, LLC
 -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
@@ -146,7 +147,7 @@
                 <plugin>
                     <groupId>org.vafer</groupId>
                     <artifactId>jdeb</artifactId>
-                    <version>1.3</version>
+                    <version>1.14</version>
                     <executions>
                         <execution>
                             <id>generate-deb-package</id>
@@ -158,7 +159,7 @@
                                 <deb>${project.build.directory}/${deb.product.name.lowercase}_${project.version}-${deb.release}_all.deb</deb>
                                 <controlDir>${project.build.directory}/deb/control</controlDir>
                                 <dataSet>
-                                    <!-- OpenDJ service file -->
+                                    <!-- OpenDJ SysV init service file (fallback for non-systemd hosts) -->
                                     <data>
                                         <src>${sysv.file.location}</src>
                                         <type>file</type>
@@ -169,6 +170,30 @@
                                         </mapper>
                                     </data>
 
+                                    <!-- OpenDJ systemd service unit (native service management) -->
+                                    <data>
+                                        <src>${systemd.file.location}</src>
+                                        <type>file</type>
+                                        <mapper>
+                                            <type>perm</type>
+                                            <prefix>/lib/systemd/system</prefix>
+                                            <filemode>644</filemode>
+                                        </mapper>
+                                    </data>
+
+                                    <!-- Service environment override. jdeb marks conffiles only via this
+                                         explicit flag; it never infers them from an /etc destination. -->
+                                    <data>
+                                        <src>${env.file.location}</src>
+                                        <type>file</type>
+                                        <conffile>true</conffile>
+                                        <mapper>
+                                            <type>perm</type>
+                                            <prefix>/etc/default</prefix>
+                                            <filemode>644</filemode>
+                                        </mapper>
+                                    </data>
+
                                     <!-- Debian copyright file in documentation -->
                                     <data>
                                         <src>${basedir}/resources/copyright</src>
diff --git a/opendj-packages/opendj-deb/resources/changelog b/opendj-packages/opendj-deb/resources/changelog
index c45ffce..c8263ca 100644
--- a/opendj-packages/opendj-deb/resources/changelog
+++ b/opendj-packages/opendj-deb/resources/changelog
@@ -1,17 +1,841 @@
- opendj (3.0.0) unstable; urgency=low
+opendj (5.2.0-1) unstable; urgency=medium
 
-  * init.d service script now generates and removes a lockfile.
+  * Modernize Debian and RPM packaging: systemd service unit, dedicated opendj
+    service account, package upgrade/install tests in CI (#663). This stanza
+    is replaced by the release notes when generate-changelog.sh is re-run at
+    release time.
 
- -- ForgeRock <opendj@forgerock.org>  Wed, 9 Dec 2015 16:24:00 +0100
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Thu, 06 Aug 2026 12:00:00 +0000
 
- opendj (3.0.0) unstable; urgency=low
+opendj (5.1.2-1) unstable; urgency=medium
 
-  * Package is now build using maven.
+  * Add an OpenDJ vs OpenLDAP LDAP benchmark GitHub Action
+  * CVE-2026-62366 OpenDJ Unauthenticated stack exhaustion when decoding an
+    LDAP search filter (DoS)
+  * CVE-2026-62373 OpenDJ JMX MBean-argument deserialization without a serial
+    filter
+  * CVE-2026-62375 OpenDJ Unbounded VLV offset array allocation leading to
+    memory-exhaustion DoS
+  * GHSA-68r5-9hpg-7qw9 OpenDJ unauthenticated SSRF, local file read and
+    unbounded-read DoS in the DSMLv2 gateway
+  * GHSA-p279-2cqp-84jg SASL PLAIN authzid bypassing the proxy ACI scope check
+  * CI: full Java matrix on ubuntu only; macOS/Windows build with Java 11 and
+    26
+  * Modernizes the OpenDJ Docker images and broadens their multi-architecture
+    build matrix.
+  * Benchmark the built Docker image against the released one
+  * Stabilize Oracle JDBC backend test on CI
+  * Log JMX RMI connector startup failure at error level
+  * Docs: add missing tools references
+  * CI: dump OpenDJ container logs when Docker image smoke tests fail
+  * Refactor file deletion logic to combine null check and length check.
+  * Add CI smoke tests for the addrate/authrate/modrate/searchrate tools
+  * Fix duplicate SNMP connection handler entries in packaged config.ldif
+  * Fix duplicate opendj-server-legacy classes in distribution lib/
+  * Add CI install-test for the Windows MSI + document MSI
+    install/upgrade/uninstall
+  * [#665] Fix StackOverflowError while parsing long ACI with repetitive
+    targets
+  * [#693] Fix Windows scripts for install paths with spaces and parentheses
+  * Fix two broken AciTests cases and enable the suite in the default build
+  * [#673] Fix ArrayIndexOutOfBoundsException on truncated percent-encoding in
+    LDAP URLs
+  * Declare the deb/rpm runtime dependencies (java, which, chkconfig)
+  * [#697] Fix global idle-time-limit having no effect on client connections
+  * Fix embedded server rebuildIndex failing with Connect Error
+  * Fix and enable broken tests from the slow group
+  * [#696] Fix embedded server setup failing with "Time service not started"
+  * Revive the quicksetup test suite
+  * Fix and enable the replication StressTest
+  * Remove the unfixable testStateMachineFull and fix the dead replay pool
+  * Fix ACI grouped bind rule wrongly rejected when a value contains
+    parentheses
+  * Enable the remaining slow-group tests in the default build
+  * Include *TestSuite classes in the failsafe run
+  * Enable the SNMP tests in the default build
+  * Fix and enable the AlternateRootDN ACI test
+  * [#709] Enable disabled and invisible tests across the sibling modules
+  * [#712] Fix StringIndexOutOfBoundsException on blank bind rule in ACI
+  * CVE-2026-9828 QOS.CH Sarl logback logback-core has a deserialization of
+    untrusted data vulnerability
+  * ci: add "Benchmark PDB vs JE" step to build-docker
+  * Add concurrency groups to GitHub Actions workflows
+  * [#695] Fix race in TraditionalWorkQueue.isIdle()
+  * [#690] Fix finalizeWorkQueue never cancelling queued operations
+  * [#692] Restore partial import semantics for include/exclude branches
+  * Restrict Unix integration-test steps to Linux only
+  * ci: add CodeQL code scanning workflow
+  * [#719] Fix NullPointerException decoding an ACI bind rule with a missing
+    and/or operand
+  * CVE-2026-10532 Logback vulnerable to Object Injection through
+    HardenedObjectInputStream modules
+  * [#728] Reject TCP self-connects in replication connect paths
+  * Fix flaky BindOperationTestCase subtree auth-info tests
+  * [#730] Fix import/export context leak on failed initializeRemote
+    validation
+  * Fix intermittent GenerationIdTest.testMultiRS by re-advertising genId on
+    change
+  * [#710] Fix replication catch-up re-sending updates with the original
+    assured flag
+  * [#726] Reject malformed bracketed IPv6 hosts in HostPort
+  * Enable Javadoc doclint (all,-missing) and fail on warnings
+  * [#735] Do not roll back a concurrently adopted generation ID on aborted
+    handshake
+  * [#737] Fix cn=changelog search failing when aliases are dereferenced
+  * [#738] Fix dereferencing an alias that points into another backend
+  * Harden opendj-docker apt step: force IPv4 + retries
+  * [#739] Fix alias dereferencing dropping entries and accumulating DNs
+  * [#744] Fix flaky ChangelogBackendTestCase: keep generated CSN batches
+    monotonic
+  * Bump org.openidentityplatform.commons to 3.1.2
+  * [#708] Fix OutOfMemory during replication initialize with JDBC backend
 
- -- ForgeRock <opendj@forgerock.org>  Tue, 10 Mar 2015 14:24:00 +0100
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Fri, 17 Jul 2026 14:34:15 +0000
 
- opendj (2.7.0) unstable; urgency=low
+opendj (5.1.1-1) unstable; urgency=medium
 
-  * Added changelog to /usr/share/doc/opendj/
+  * CVE-2026-46495 OpenDJ Unauthenticated RCE via Java Deserialization in JMX
+    RMI
+  * CVE-2026-42198 pgjdbc: Unbounded PBKDF2 iterations in SCRAM authentication
+    allows CPU exhaustion DoS
+  * [#648] slow DN.valueOf / AVA normalization for nested DN-syntax values
+  * chore: bump Bouncy Castle FIPS deps to latest 2.1.x patch releases
+  * Fix grizzly log level is always FINE
+  * Fix shell script issues in opendj-docker/run.sh
+  * Fix Windows CI: use ilammy/msvc-dev-cmd to set up MSVC env
+  * Add native access JVM flag for Bouncy Castle FIPS on newer Java releases
+  * Docker base DN entry creation opt-in and improves bootstrap LDIF loading
+    resilience
+  * Fix BasicRequestsTest.testReadSelectPartial for nesting-preserving field
+    projection
+  * Update org.openidentityplatform.commons to 3.1.1
+  * Fix JMX RMI connector startup failure introduced by CVE-2026-46495
+    hardening
 
- -- ForgeRock <opendj@forgerock.org>  Thu, 22 Aug 2013 15:47:00 +0100
\ No newline at end of file
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Thu, 11 Jun 2026 19:19:48 +0000
+
+opendj (5.1.0-1) unstable; urgency=medium
+
+  * [#72] Fix infinite loop in doStopApplication() on Windows service stop
+  * [#259] fix: retry loop for Windows Service start race condition (issue
+    #259)
+  * [#566] Fix AttributeValuePasswordValidator: inverted substring logic and
+    missing reversed-password substring check
+  * [#579] Fix ReferentialIntegrityPlugin silently bypassing check-references
+    on modify operations
+  * [#601] Fix server crash when File-Based Debug Logger is enabled
+  * Update build.yml add JDK 26 support
+  * Docs: set neutral version for the docs
+  * ci: add Windows service start/stop test to CI workflow
+  * CI: Build and upload Windows native executables (winlauncher,
+    opendj_service, launcher_administrator)
+  * fix: use 127.0.0.1 instead of localIP in LockdownModeTaskTestCase
+  * Filter branches to build workflow triggers (on push)
+  * Fix intermittent testMultiRS failure by doubling waitForStableGenerationId
+    timeout
+  * Fix race condition in ChangelogBackendTestCase flaky test
+  * Fix flaky testMultiRS: replace fixed sleep with deterministic domain-ready
+    wait
+  * increase replication connection timeout to fix Socket Timeout error on Mac
+    in integration test
+  * chore: bump GitHub Actions to latest major versions
+  * Fix snapshot version format
+  * Fix intermittent GenerationIdTest.testMultiRS race condition on RS-to-RS
+    topology
+  * [OpenIdentityPlatform/OpenAM#980] OpenDJ slim maven artifact
+  * Upgrade local Docker registry from registry:2 to registry:3 in CI
+  * status CLI: allow --hostname, --port, and --trustAll arguments
+  * Fix status CLI to accept --hostname, --port, and --trustAll arguments, and
+    add them to all status command invocations in build.yml
+  * Remove ENV ROOT_PASSWORD from Dockerfiles, fix HEALTHCHECK default, add
+    CDDL headers
+  * Update commons.version to 3.1.0
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 15 Apr 2026 08:40:44 +0000
+
+opendj (5.0.4-1) unstable; urgency=medium
+
+  * CVE-2025-24970 SslHandler doesn't correctly validate packets which can
+    lead to native crash when using native SSLEngine
+  * CVE‐2025‐12194 While the situation with the JVM garbage collector overrun
+    for Java 17 and Java 21 greatly improved with the changes in 2.1.1, we’ve
+    still had some reports that can only be related to the use of the disposal
+    daemon
+  * [#590] Fallback to $HOME/tmp dir as a temp if instance root is mounted as
+    noexec
+  * Bump logback to 1.5.32
+  * Migrate to caffeine 3
+  * Update commons.version from 3.0.2 to 3.0.4
+  * Docs: fix short version in the upgrade guide
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Mon, 23 Mar 2026 20:24:28 +0000
+
+opendj (5.0.3-1) unstable; urgency=medium
+
+  * CVE-2026-1225 Logback allows an attacker to instantiate classes already
+    present on the class path
+  * Fix three and more nodes replication process stuck error
+  * Update org.openidentityplatform.commons to 3.0.2
+  * Docs: update supported Java version
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 04 Feb 2026 06:46:31 +0000
+
+opendj (5.0.2-1) unstable; urgency=medium
+
+  * [#575] FIX unable to install: UnsatisfiedLinkError: /tmp/bc-fips
+  * [#577] Windows upgrading with Upgrade.bat: an error with "" unexpected
+  * [#573] Added the SAMPLE_DATA Docker environment variable to generate
+    sample data during setup.
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Tue, 25 Nov 2025 08:39:22 +0000
+
+opendj (5.0.1-1) unstable; urgency=medium
+
+  * Update target JDK to 11 and move to JakartaEE 9
+  * Add support LTS JDK 25
+  * Update base docker image Java version to 25 LTS
+  * CVE-2025-12194 Bouncy Castle Vulnerable to Uncontrolled Resource
+    Consumption
+  * CVE-2025-59250 JDBC Driver for SQL Server has improper input validation
+    issue
+  * CVE-2025-11226 logback-core is vulnerable to Arbitrary Code Execution
+    through file processing
+  * Switch from sun.security.x509 to Bouncy Castle API
+  * Update OpenDMK external library to fix SNMP monitoring
+  * Build & deploy: add branch sustaining/4.10.x
+  * Make GrizzlyLDAPListener close in a synchronous fasion to prevent test
+    race conditions
+  * [#141] Test large replication pending changes
+  * FIX bindFreePort Bind Unable to bind to a free port
+  * Fix unavailable monitoring attributes over JMX
+  * Bump org.openidentityplatform.commons to 3.0.1
+  * Improve ReplicationDomainTest stability
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Sat, 08 Nov 2025 19:43:23 +0000
+
+opendj (4.10.2-1) unstable; urgency=medium
+
+  * CVE-2025-9092 CVE-2025-9340 CVE-2025-9341 Uncontrolled Resource
+    Consumption vulnerability
+  * [#545] Add GroupManager writeLock performance
+  * [#540] Fix OnDiskMergeImporter::PhaseOneWriteableTransaction: update over
+    put (referral attr)
+  * [#544] Add requires-admin-action component-restart for max-request-size
+  * Update Java minimum version number in the setup UI
+  * Update README.md: add backers and sponsors
+  * ISSUE_TEMPLATE: add "Vote to raise the priority"
+  * Bump commons.version 2.4.1
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Thu, 04 Sep 2025 15:49:55 +0000
+
+opendj (4.10.1-1) unstable; urgency=medium
+
+  * [#529] FIX jdbc connection deadlock
+  * [#530] Fixed error when creating a backend for BASE_DN with OU in Docker
+  * Docker: Fix issues with quoting params
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Tue, 05 Aug 2025 16:47:18 +0000
+
+opendj (4.10.0-1) unstable; urgency=medium
+
+  * [#462] RFC5805 Lightweight Directory Access Protocol (LDAP) Transactions
+  * CVE-2025-49146 pgjdbc Client Allows Fallback to Insecure Authentication
+    Despite channelBinding=require Configuration
+  * Bump io.reactivex.rxjava to 3.x
+  * Bump various dependencies
+  * Bump commons to 2.2.5
+  * Take Glassfish Grizzly version from commons
+  * Bump bc.fips to 2.1.x
+  * Bump commons.version 2.3.0
+  * Deploy: migrating from Legacy OSSRH to Central Portal
+  * Fix OSGI bundle excluded package error for rxjava3
+  * Exclude BouncyCastle from OSGI Import-Package
+  * Fix makeldif templates: add objectClass to baseDN
+  * Bump org.openidentityplatform.commons 2.4.0
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Tue, 15 Jul 2025 14:28:53 +0000
+
+opendj (4.9.4-1) unstable; urgency=medium
+
+  * Configure backend type for Docker
+  * Docs: update OpenDJ release version to 4.9.3
+  * Add OpenDJ Docker tests to the build process
+  * Fix docker env variables + add VERSION autodetect
+  * Set isRunning later (EmbeddedServer check)
+  * Bump org.openidentityplatform.commons to 2.2.4
+  * [#498] FIX warning output from export-ldif: "grep: warning: stray \ before
+    -"
+  * move Java args to java.properties, upgrade docker alpine
+  * [#497] Set the same indexes for a new backend as for the initial backend
+  * Add support Java SE 24
+  * Bump test containers & cassandra driver
+  * [#496] FIX MySQL truncate PK default to 64 len
+  * [#496] FIX JDBC storage update concurrency
+  * FIX Replication IT tests unstable result
+  * made their first contribution
+  * made their first contribution
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 23 Apr 2025 14:31:19 +0000
+
+opendj (4.9.3-1) unstable; urgency=medium
+
+  * CVE-2025-27497 Fix Denial of Service (Dos) using alias loop ()
+  * [#477] Change permission config.ldif.startok to owner ()
+  * [#208] FIX The definition for the attribute type declared that it should
+    use the syntax which is not defined in the schema
+  * Documentation update
+  * Docs: Generate and publish javadoc
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 05 Mar 2025 10:11:22 +0000
+
+opendj (4.9.2-1) unstable; urgency=medium
+
+  * [#465] Fix custom library loading when put to the lib directory
+  * [#463] Disable warning message on downstream closed
+  * [#471] Fix table name truncate: make jdbc table 63 charter
+  * [#466] JDBC: added tests for Oracle, MySQL, MSSQL
+  * [#466] FIX compatibility jdbc backend: Postgres, Oracle, MySQL, MSSQL
+  * [#471] PluggableBackendImplTestCase: add duplicate mail test
+  * IT ReplicationDomainTest upper waitEndExport timeout
+  * Update year in generated documentation templates
+  * Update documentation issues and update links
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Tue, 04 Feb 2025 16:21:39 +0000
+
+opendj (4.9.1-1) unstable; urgency=medium
+
+  * [#460] Clear unused path info after backupConfig (memory pleasure)
+  * jdbc: make connection short-lived
+  * Replace import-ldif with ldapmodify in Postgres IT test
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Mon, 20 Jan 2025 08:49:34 +0000
+
+opendj (4.9.0-1) unstable; urgency=medium
+
+  * Store LDAPv3 database in SQL JDBC database
+  * CVE-2024-12798 CVE-2024-12801 logback-core Expression Language Injection,
+    Server-Side Request Forgery vulnerability
+  * FIX NoSuchMethodError: java.nio.MappedByteBuffer.duplicate
+  * FIX Unable to locate package winehq-stable
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Thu, 26 Dec 2024 08:36:50 +0000
+
+opendj (4.8.2-1) unstable; urgency=medium
+
+  * [#438] FIX import-ldif --offline "import has been aborted because the
+    entry does not have a parent entry"
+  * 00-core.ldif: X.501, cl. 14.2.2: 2.5.15.16 subentryNameForm OC subentry
+    MUST cn
+  * FIX makeldif -c suffix=dc=example: Unable to parse a constant argument
+    expecting name=value
+  * Bump commons.version 2.2.3
+  * Fix MAC OS build failure
+  * Actions: get ubuntu source from $(lsb_release -c -s)
+  * depoloy.yml: Fix documents deploy
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Tue, 12 Nov 2024 09:02:28 +0000
+
+opendj (4.8.1-1) unstable; urgency=medium
+
+  * [#393] FIX DIT SUP delimiter
+  * [#392] FIX RootDSE Entry allow user objectClass
+  * Addresses #397, #398, #399, #404
+  * Docs in asciidoc & deploy antora docs after build
+  * [#402] Change default SSL HandshakeTimeout -1 -> 10s (see #146)
+  * [#401] Change "Object class violation (65)" -> "Naming violation (64)"
+    LDAP result code for DIT Structure Rule violation
+  * [#394] FIX dsconfig --help-<subcommand>
+  * [#400] Reduce character escaping in example, add note
+  * Added missing documentation attachments
+  * Generate man pages in the AsciiDoc format
+  * Reduce character escaping in example, add note
+  * minor docs glitches fix
+  * Add JDK 23 build support
+  * Bump org.openidentityplatform.commons 2.2.2
+  * Docker: Use tail instead of sleep to allow the container to be stopped
+    with SIGTERM
+  * [#423] Eliminate asciidoctor warning messages when generating
+    documentation
+  * [#426] ADD maven.compiler.release=8 for cross compile compatibility
+  * Remove legacy files
+  * [#90, #432] FIX delete entries in overlapping backends
+  * [#425] Add option
+    -Dorg.openidentityplatform.opendj.ERR_ENTRY_SCHEMA_VIOLATES_PARENT_DSR for
+    force control "Entry is invalid according to the server schema because
+    there is no DIT structure rule that applies to that entry, but there is a
+    DIT structure rule for the parent entry". Default: warning level
+  * [#425] Workaround: Entry is invalid according to the server schema because
+    there is no DIT structure rule that applies to that entry, but there is a
+    DIT structure rule for the parent entry
+  * [#431] Update importldiff --offline and --clearBacked flags descriptions
+  * made their first contribution
+  * made their first contribution
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Thu, 17 Oct 2024 14:55:25 +0000
+
+opendj (4.8.0-1) unstable; urgency=medium
+
+  * Switch docker to last LTS JRE 21
+  * Add JDK 22 support
+  * [#376] JMX fix docs with "Allow insecure authentication"
+  * [#376] FIX SNMP monitoring config
+  * [#383] FIX docs: import-ldif and export-ldif binaries should be shown
+    using the --offline option
+  * [#384] FIX Control Panel: empty help URL values
+  * FIX do not check DIT structure parent/child on same ObjectClass (thanks
+    for the research )
+  * Bump org.openidentityplatform.commons 2.2.0
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Mon, 09 Sep 2024 11:26:09 +0000
+
+opendj (4.7.0-1) unstable; urgency=medium
+
+  * [#204] ADD LDAP Relax Rules Control
+  * [#287] ADD alias dereferencing for search requests
+  * [#187] FIX RFC3671: collective attribute values should be merged. Virtuals
+    with other virtuals and real values.
+  * [#84] FIX incorrect entry-Based ACIs is defined with only "deny"
+    permission without "allow"
+  * [#250] Add Overlapping Backend TestSuite
+  * [#294] Dont send client notification on IOException
+  * [#368] CASSANDRA ADD property -Dkeyspace=ldap_opendj
+  * Bump commons.version 2.1.6
+  * Publish docs to
+  * Fix documentation version
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Thu, 08 Aug 2024 08:24:48 +0000
+
+opendj (4.6.5-1) unstable; urgency=medium
+
+  * compress webhelp, xhtml and html docs after build
+  * add missing docs
+  * Update README.md
+  * [#354] FIX "OpenDJ fails to upgrade from version 3->4: An error occurred
+    while attempting to perform index rebuild: Unable to decode the provided
+    object class set because it used an undefined token"
+  * [#167] FIX control-panel ResetUserPasswordTask unpredictable result (wait
+    async result)
+  * Add rest operations modifyPassword, resetPassword to docs from
+  * [#148,#261,#282] FIX control-panel schema errors in remote mode
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Tue, 16 Jul 2024 17:31:29 +0000
+
+opendj (4.6.4-1) unstable; urgency=medium
+
+  * Embedded OpenDJ module initial commit
+  * Bump ch.qos.logback:logback-core from 1.2.11 to 1.2.13 in /opendj-embedded
+  * Bump ch.qos.logback:logback-classic from 1.2.9 to 1.2.13 in /opendj-
+    embedded
+  * update opendj-parent version
+  * Bump org.bouncycastle:bc-fips from 1.0.2.3 to 1.0.2.5 in /opendj-core
+  * Bump org.bouncycastle:bctls-fips from 1.0.13 to 1.0.19 in /opendj-core
+  * Bump org.openidentityplatform.commons 2.1.4
+  * move commons version to property & fix doc-maven-plugin version
+  * made their first contribution
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 26 Jun 2024 07:56:13 +0000
+
+opendj (4.6.3-1) unstable; urgency=medium
+
+  * ADD build test with memory pressure
+  * Update Docker jre 17->19
+  * org.openidentityplatform.commons 2.1.3-SNAPSHOT
+  * FIX OpenIDM compatibility
+  * [#329] make posixGroup AUXILIARY by default
+  * [#331] Allow downgrade version without upgrade task
+  * Bump org.openidentityplatform.commons 2.1.3
+  * Add Build test on MacOS M1 arm64
+  * Restore macos-latest build strategy
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Tue, 07 May 2024 17:54:49 +0000
+
+opendj (4.6.2-1) unstable; urgency=medium
+
+  * FIX CLIENT_SIDE_NO_RESULTS_RETURNED in hasNext()
+  * update org.openidentityplatform.commons to 2.1.2-SNAPSHOT
+  * FIX performance java.util.TimeZone.getTimeZone(TimeZone.java:516) is
+    synchronized
+  * [#317] sendUnsolicitedNotification can fail on client disconnect with
+    OnErrorNotImplementedException
+  * org.openidentityplatform.commons 2.1.2
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 17 Jan 2024 12:17:40 +0000
+
+opendj (4.6.1-1) unstable; urgency=medium
+
+  * Allow store LDAP catalog data in CASSANDRA noSQL cluster --backendType cas
+    (ldapv3 to cassandra)
+  * ADD IT test for wars
+  * Add TestContainers to test Apache Cassandra backend
+  * Bump org.openidentityplatform.commons 2.0.19-SNAPSHOT
+  * Update README.md: allow store LDAPv3 database in Cassandra/Scylla cluster
+  * Bump org.openidentityplatform.commons 2.1.1
+  * Add JDK 21 support
+  * CASSANDRA storage: cursor performance
+  * FIX newHeapBufferPool calculation (import OOM error)
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Thu, 26 Oct 2023 09:46:54 +0000
+
+opendj (4.5.9-1) unstable; urgency=medium
+
+  * Generate SHA256WithRSA certificate as default
+  * convert JMX metrics to appropriate type #293
+  * Fix attribute value. bean should return native object #293
+  * Remove TLSv1 as default protocol FIX
+  * nexus-staging-maven-plugin 1.6.13 + disable auto release
+  * made their first contribution
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Fri, 22 Sep 2023 07:10:00 +0000
+
+opendj (4.5.6-1) unstable; urgency=medium
+
+  * FIX unused trailing bytes in ASN.1 SEQUENCE
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 30 Aug 2023 09:28:52 +0000
+
+opendj (4.5.5-1) unstable; urgency=medium
+
+  * FIX build with Installation failure for grub-efi-amd64-signed on ubuntu-
+    latest
+  * FIX add-source for generate-sources
+  * Restore IT test for server-legacy and fix many errors
+  * change posixGroup type to structural. and add cn
+  * FIX argument listBackups is incompatible with use of this tool to interact
+  * PBKDF2-HMAC-SHA256 and PBKDF-HMAC-SHA512 password storage not configured
+    by default
+  * FIX Setup Issue - Error Creating Base Entry
+  * Extend admin port connection limits
+  * Restore TLSv1.3 support
+  * Bump org.openidentityplatform.commons 2.0.18
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Thu, 20 Jul 2023 09:50:13 +0000
+
+opendj (4.5.4-1) unstable; urgency=medium
+
+  * BUILD java: [ '8','11','17','19'] + fix install wine32:i386 without
+    conflicts
+  * FIX build allow fail for remove deb.sury.org
+  * Docker add jdk17 platforms: linux/amd64, linux/arm64/8, linux/arm/v7,
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Fri, 09 Dec 2022 10:41:35 +0000
+
+opendj (4.5.3-1) unstable; urgency=medium
+
+  * Create target directory before copying custom schema
+  * Copy ldif configs to the correct template directory
+  * UPDATE build process
+  * FIX DSML servlet can't find JAX-B runtime
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 30 Nov 2022 09:40:42 +0000
+
+opendj (4.5.1-1) unstable; urgency=medium
+
+  * update commons version to 2.0.16-SNAPSHOT
+  * 'find' command is missing in the 4.5.0 docker image #242
+  * FIX wine32 install (from ppa:ondrej/php so that we will be able to install
+    wine32:i386 without conflicts)
+  * Don't clone buffer in ldap codec
+  * Add BCFKS FIPS key store type support
+  * fix FipsStaticUtils code formatting
+  * made their first contribution
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Tue, 02 Aug 2022 11:04:58 +0000
+
+opendj (4.5.0-1) unstable; urgency=medium
+
+  * Switch base docker image to Java 17
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 01 Jun 2022 10:54:55 +0000
+
+opendj (4.4.15-1) unstable; urgency=medium
+
+  * Add alpine platforms linux/s390x, linux/386, linux/arm/v7, linux/arm/v6,
+    linux/ppc64le
+  * Implement PBKDF2-HMAC-SHA256 and PBKDF-HMAC-SHA512 password encoding
+    schemes
+  * Docker refactoring
+  * FIX tamil (ta.6) matching rule schema has typo in definition
+  * FIX Failed to delete entries under multiple backends
+  * Add support jdk '16','17','18'
+  * support AD attributes userAccountControl, msDS-UserAccountDisabled and
+    pwdLastSet
+  * Test + Run on jdk15+
+  * FIX OpenDJ is not logging errors to logfile #128
+  * FIX Windows install to path with spaces
+  * made their first contribution
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 01 Jun 2022 06:49:30 +0000
+
+opendj (4.4.14-1) unstable; urgency=medium
+
+  * add docker test
+  * Release multi-platform Docker images
+  * Support to load plain ldif files during container setup
+  * made their first contribution
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Mon, 02 May 2022 19:11:25 +0000
+
+opendj (4.4.13-1) unstable; urgency=medium
+
+  * FIX OpenDJ setup failure
+  * Add FIPS support
+  * GithubAction build
+  * Github action deploy
+  * actions: separate deploy
+  * Update opendj_service.exe
+  * Switch org.openidentityplatform.commons 2.0.13-SNAPSHOT
+  * Fix rebuild-index in FIPS mode
+  * ADD JSONEntryWriter JSONEntryReader
+  * FIX DN escape 'Equal sign':
+  * FIX JSONEntryWriter escape DN values
+  * move fips functions to separate class
+  * do not use fips when bc-fips classes not found
+  * Update pom.xml nexus-staging-maven-plugin 1.6.11
+  * Refactor Dockerfile debian and alpine
+  * Migrate release from Travis to GitHub
+  * FIX Deployment of external dependency failed. Failed to deploy artifacts:
+    Could not transfer artifact openidentityplatform.org:wixtoolset:zip
+  * made their first contribution
+  * made their first contribution
+  * made their first contribution
+  * made their first contribution
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Fri, 22 Apr 2022 21:42:56 +0000
+
+opendj (4.4.11-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.11
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Mon, 21 Jun 2021 12:11:50 +0000
+
+opendj (4.4.10-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.10
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Mon, 08 Feb 2021 12:09:47 +0000
+
+opendj (4.4.9-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.9
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 30 Dec 2020 13:11:33 +0000
+
+opendj (4.4.8-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.8
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Tue, 10 Nov 2020 15:01:48 +0000
+
+opendj (4.4.7-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.7
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 09 Sep 2020 18:41:03 +0000
+
+opendj (4.4.6-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.6
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Thu, 11 Jun 2020 10:34:37 +0000
+
+opendj (4.4.5-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.5
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Tue, 10 Mar 2020 18:32:09 +0000
+
+opendj (4.4.4-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.4
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Fri, 21 Feb 2020 10:07:17 +0000
+
+opendj (4.4.3-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.3
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Mon, 29 Jul 2019 12:46:28 +0000
+
+opendj (4.4.2-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.2
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Mon, 29 Apr 2019 18:00:35 +0000
+
+opendj (4.4.1-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.1
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Sun, 10 Mar 2019 17:15:42 +0000
+
+opendj (4.3.5-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.3.5
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Mon, 04 Mar 2019 19:44:44 +0000
+
+opendj (4.3.4-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.3.4
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Sun, 17 Feb 2019 18:38:19 +0000
+
+opendj (4.3.3-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.3.3
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Fri, 08 Feb 2019 09:15:48 +0000
+
+opendj (4.3.2-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.3.2
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Tue, 29 Jan 2019 16:23:25 +0000
+
+opendj (4.3.1-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.3.1
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Mon, 10 Dec 2018 13:19:19 +0000
+
+opendj (4.2.5-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.2.5
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Fri, 26 Oct 2018 20:44:31 +0000
+
+opendj (4.2.4-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.2.4
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Thu, 18 Oct 2018 11:54:57 +0000
+
+opendj (4.2.3-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.2.3
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 17 Oct 2018 09:17:53 +0000
+
+opendj (4.2.2-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.2.2
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Mon, 08 Oct 2018 14:04:29 +0000
+
+opendj (4.2.1-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.2.1
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Fri, 05 Oct 2018 20:50:10 +0000
+
+opendj (4.1.10-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.10
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 30 May 2018 21:12:00 +0000
+
+opendj (4.1.9-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.9
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Fri, 25 May 2018 05:03:41 +0000
+
+opendj (4.1.8-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.8
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Sat, 12 May 2018 03:36:28 +0000
+
+opendj (4.1.7-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.7
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Tue, 01 May 2018 09:49:37 +0000
+
+opendj (4.1.6-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.6
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Tue, 10 Apr 2018 15:40:59 +0000
+
+opendj (4.1.5-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.5
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Tue, 06 Mar 2018 18:34:23 +0000
+
+opendj (4.1.4-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.4
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Sat, 03 Mar 2018 09:32:59 +0000
+
+opendj (4.1.3-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.3
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 28 Feb 2018 11:55:36 +0000
+
+opendj (4.1.2-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.2
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Wed, 28 Feb 2018 10:44:28 +0000
+
+opendj (4.1.1-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.1
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Fri, 23 Feb 2018 11:58:58 +0000
+
+opendj (4.0.3-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.0.3
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Tue, 20 Feb 2018 14:19:55 +0000
+
+opendj (4.0.2-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.0.2
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Fri, 16 Feb 2018 16:56:23 +0000
+
+opendj (4.0.1-1) unstable; urgency=medium
+
+  * See release notes:
+    https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.0.1
+
+ -- Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>  Fri, 16 Feb 2018 16:10:46 +0000
diff --git a/opendj-packages/opendj-deb/resources/control/control b/opendj-packages/opendj-deb/resources/control/control
index 16b1c77..3a356dd 100644
--- a/opendj-packages/opendj-deb/resources/control/control
+++ b/opendj-packages/opendj-deb/resources/control/control
@@ -1,9 +1,10 @@
 Package: [[deb.product.name.lowercase]]
-Version: [[parsedVersion.majorVersion]].[[parsedVersion.minorVersion]].[[parsedVersion.incrementalVersion]]
-Section: misc
+Version: [[parsedVersion.majorVersion]].[[parsedVersion.minorVersion]].[[parsedVersion.incrementalVersion]]-[[deb.release]]
+Section: net
 Priority: optional
 Architecture: all
 Depends: default-jre-headless | default-jre | java25-runtime-headless | java25-runtime | java21-runtime-headless | java21-runtime | java17-runtime-headless | java17-runtime | java11-runtime-headless | java11-runtime
+Pre-Depends: adduser, init-system-helpers (>= 1.54~)
 Homepage: [[deb.doc.homepage.url]]
 Maintainer: [[deb.maintainer]]
 Description: [[deb.product.name]]
diff --git a/opendj-packages/opendj-deb/resources/control/postinst b/opendj-packages/opendj-deb/resources/control/postinst
index 5cfd125..2ff0167 100644
--- a/opendj-packages/opendj-deb/resources/control/postinst
+++ b/opendj-packages/opendj-deb/resources/control/postinst
@@ -13,59 +13,129 @@
 # information: "Portions Copyright [year] [name of copyright owner]".
 #
 # Copyright 2013-2015 ForgeRock AS.
+# Portions Copyright 2026 3A Systems, LLC
 
-# Post install script
-# Install is launched with an empty second arg.
-# If the package is already installed, the second arg. is not empty.
+# Post install script.
+# On a fresh install the second argument is empty; on upgrade it holds the
+# previously-installed version.
 
-# Registers the service
-update-rc.d opendj defaults
+set -e
 
-# Symlinks to process ID
-test -h "/var/run/opendj.pid" || ln -s ${deb.prefix}/logs/server.pid /var/run/opendj.pid
+# The instance root may have been relocated with instance.loc (split layout):
+# resolve it the way the server scripts (_script-util.sh) do. Empty-file reads
+# are tolerated; the result then simply fails the file checks below.
+resolve_instance_root() {
+    INSTANCE_ROOT=${deb.prefix}
+    if [ -f /etc/opendj/instance.loc ] ; then
+        read INSTANCE_ROOT < /etc/opendj/instance.loc || true
+    elif [ -f ${deb.prefix}/instance.loc ] ; then
+        read _loc < ${deb.prefix}/instance.loc || true
+        case "$_loc" in
+            /*) INSTANCE_ROOT=$_loc ;;
+            *)  INSTANCE_ROOT=${deb.prefix}/$_loc ;;
+        esac
+    fi
+}
+resolve_instance_root
 
-# In this case, we are in upgrade mode.
-if [ "$1" = "configure" ] && [ ! -z "$2" ] ; then
-    # For being secure, we check the buildinfo file too.
-    if [ -f ${deb.prefix}/config/buildinfo ] ; then
-        echo *Starting upgrade...
-        ${deb.prefix}/./upgrade -n --force --acceptLicense
-        echo
+# Create the dedicated system user/group that runs the service.
+if ! getent group opendj >/dev/null; then
+    addgroup --system opendj
+fi
+if ! getent passwd opendj >/dev/null; then
+    adduser --system --no-create-home --ingroup opendj \
+        --home ${deb.prefix} --shell /usr/sbin/nologin \
+        --gecos "OpenDJ Directory Server" opendj
+fi
 
-        if [ "$?" -eq 0 ] ; then
-            # Restarts the service if needed.
-            # If server is stopped by upgrade process, the server will restart after upgrade.
-            # If server is stopped before the upgrade process (eg. upgrade the new package), the server will not restart.
-            # Uses the flag for determining server status at this point.
-            if [ -f ${deb.prefix}/logs/status ] ; then
-                echo
+# Own the installation tree - and a split-layout instance - with the service
+# account. On upgrade this also migrates installations that were previously
+# owned by root. Do not abort the configure step on a partial failure - a real
+# problem surfaces on start.
+chown -R opendj:opendj ${deb.prefix} || true
+if [ "$INSTANCE_ROOT" != "${deb.prefix}" ] && [ -d "$INSTANCE_ROOT" ] ; then
+    chown -R opendj:opendj "$INSTANCE_ROOT" || true
+fi
+
+# Honour the documented admin overrides (OPENDJ_JAVA_HOME / OPENDJ_JAVA_BIN /
+# OPENDJ_JAVA_ARGS) for the upgrade tool and the restart below, exactly as the
+# service itself does via EnvironmentFile=. systemd's EnvironmentFile syntax
+# is not shell (no expansion, optional quotes), so extract the known keys
+# instead of sourcing the file.
+if [ -r /etc/default/opendj ] ; then
+    for _key in OPENDJ_JAVA_HOME OPENDJ_JAVA_BIN OPENDJ_JAVA_ARGS ; do
+        _val=$(sed -n "s/^$_key=//p" /etc/default/opendj | tail -n 1 \
+            | sed -e 's/^"\(.*\)"$/\1/' -e "s/^'\(.*\)'\$/\1/")
+        [ -n "$_val" ] && export "$_key=$_val" || true
+    done
+fi
+
+# Register the service. deb-systemd-helper and update-rc.d only manage
+# symlinks/state, so they intentionally run without a booted-systemd gate and
+# work in chroots/containers too. deb-systemd-helper records the enable state:
+# an admin's "systemctl disable" survives upgrades. The unit's start condition
+# keeps an unconfigured instance from failing at boot.
+if command -v deb-systemd-helper >/dev/null 2>&1 ; then
+    deb-systemd-helper unmask opendj.service >/dev/null 2>&1 || true
+    if deb-systemd-helper --quiet was-enabled opendj.service ; then
+        deb-systemd-helper enable opendj.service >/dev/null 2>&1 || true
+    else
+        deb-systemd-helper update-state opendj.service >/dev/null 2>&1 || true
+    fi
+fi
+update-rc.d opendj defaults >/dev/null 2>&1 || true
+if [ -d /run/systemd/system ] ; then
+    systemctl --system daemon-reload >/dev/null 2>&1 || true
+fi
+
+# Upgrade mode.
+if [ "$1" = "configure" ] && [ -n "$2" ] ; then
+    if [ -f "$INSTANCE_ROOT/config/buildinfo" ] && [ -f "$INSTANCE_ROOT/config/config.ldif" ] ; then
+        echo "*Starting upgrade..."
+        if runuser -u opendj -- ${deb.prefix}/upgrade -n --force --acceptLicense ; then
+            # Restart only if the server was running before the upgrade
+            # (preinst recorded this via the status flag).
+            if [ -f "$INSTANCE_ROOT/logs/status" ] ; then
                 echo "*Restarting server..."
-                ${deb.prefix}/./bin/start-ds
-                if [ "$?" -eq 0 ] ; then
-                    rm -f ${deb.prefix}/logs/status
+                STARTED=0
+                if [ -d /run/systemd/system ] ; then
+                    deb-systemd-invoke start opendj.service || true
+                    # policy-rc.d may deny the start and still exit 0: trust
+                    # the observable unit state, not the exit code.
+                    if systemctl is-active --quiet opendj.service ; then
+                        STARTED=1
+                    fi
                 else
-                    echo "start-ds failed with return code $?. Please read ${deb.prefix}/logs/status for more details."
+                    runuser -u opendj -- ${deb.prefix}/bin/start-ds && STARTED=1 || true
+                fi
+                if [ "$STARTED" = 1 ] ; then
+                    rm -f "$INSTANCE_ROOT/logs/status"
+                else
+                    # Keep the status flag so a later "dpkg-reconfigure opendj"
+                    # (or the next upgrade) retries the restart.
+                    echo "Server restart failed; see the logs under $INSTANCE_ROOT/logs and start the service manually."
                 fi
             fi
         else
-            # Upgrade fails - Requires mandatory user interaction.
-            # Nevertheless, exits successfully of the pkg process.
-            echo "upgrade failed with return code $?. Please read the installation guide for more information on the upgrade process."
+            # Upgrade failed - may require manual user interaction. Do not fail
+            # the package transaction.
+            echo "upgrade failed. Please read the installation guide for more information on the upgrade process."
             exit 0
         fi
     else
-        echo "Invalid installation, could not find the build info file."
-        exit -1
+        # Package files are in place but setup has never been run, so there is
+        # nothing to migrate. Same behaviour as the RPM package - do not fail
+        # the dpkg transaction after the new tree has been unpacked.
+        echo "Instance is not configured."
     fi
 fi
 
-
-# Add OpenDJ man pages to MANPATH
+# Add OpenDJ man pages to MANPATH.
 MAN_CONFIG_FILE=/etc/manpath.config
-MANPATH_DIRECTIVE=MANDATORY_MANPATH
-grep -q "$MANPATH_DIRECTIVE.*opendj" $MAN_CONFIG_FILE 2> /dev/null
-if [ $? -ne 0 ]; then
-    echo "$MANPATH_DIRECTIVE ${deb.prefix}/share/man" >> $MAN_CONFIG_FILE
+if [ -f "$MAN_CONFIG_FILE" ] && ! grep -q "MANDATORY_MANPATH.*opendj" "$MAN_CONFIG_FILE" 2>/dev/null ; then
+    echo "MANDATORY_MANPATH ${deb.prefix}/share/man" >> "$MAN_CONFIG_FILE"
 fi
-# End post install script
+
 echo
+exit 0
+# End post install script
diff --git a/opendj-packages/opendj-deb/resources/control/postrm b/opendj-packages/opendj-deb/resources/control/postrm
index 1d7c033..eb9d9cb 100644
--- a/opendj-packages/opendj-deb/resources/control/postrm
+++ b/opendj-packages/opendj-deb/resources/control/postrm
@@ -13,15 +13,39 @@
 # information: "Portions Copyright [year] [name of copyright owner]".
 #
 # Copyright 2013-2015 ForgeRock AS.
+# Portions Copyright 2026 3A Systems, LLC
 
 set -e
-# Post rm script
-# Files are removed automatically by pm.
+# Post rm script. Package files are removed automatically by the package manager.
+
 if [ "$1" = "remove" ] ; then
-    # Deletes the service.
-    update-rc.d -f opendj remove
-    echo
-    echo *OpenDJ successfully removed
+    # Mask the removed unit (as dh_installsystemd does): the enable symlink
+    # deliberately survives "remove" so the state is restored on re-install,
+    # and the mask keeps systemd from logging it as dangling on every boot.
+    if command -v deb-systemd-helper >/dev/null 2>&1 ; then
+        deb-systemd-helper mask opendj.service >/dev/null 2>&1 || true
+    fi
 fi
+
+if [ "$1" = "remove" ] || [ "$1" = "purge" ] ; then
+    # postinst registers the rc links unconditionally, so drop them on every
+    # host - a booted systemd is orthogonal to their existence.
+    update-rc.d opendj remove >/dev/null 2>&1 || true
+    if [ -d /run/systemd/system ] ; then
+        systemctl --system daemon-reload >/dev/null 2>&1 || true
+    fi
+fi
+
+if [ "$1" = "purge" ] ; then
+    if command -v deb-systemd-helper >/dev/null 2>&1 ; then
+        deb-systemd-helper purge opendj.service >/dev/null 2>&1 || true
+        deb-systemd-helper unmask opendj.service >/dev/null 2>&1 || true
+    fi
+    echo "*OpenDJ package removed. Server data under ${deb.prefix} (config, db,"
+    echo " changelogDb, logs) and the opendj system account are kept; remove"
+    echo " them manually if they are no longer needed."
+fi
+
 echo
+exit 0
 # End of the post rm script
diff --git a/opendj-packages/opendj-deb/resources/control/preinst b/opendj-packages/opendj-deb/resources/control/preinst
index 6956d8f..dcd8eee 100644
--- a/opendj-packages/opendj-deb/resources/control/preinst
+++ b/opendj-packages/opendj-deb/resources/control/preinst
@@ -13,22 +13,67 @@
 # information: "Portions Copyright [year] [name of copyright owner]".
 #
 # Copyright 2013-2015 ForgeRock AS.
+# Portions Copyright 2026 3A Systems, LLC
 
 set -e
 
-# Pre installation script
+# The instance root may have been relocated with instance.loc (split layout):
+# resolve it the way the server scripts (_script-util.sh) do. Empty-file reads
+# are tolerated; the result then simply fails the file checks below.
+resolve_instance_root() {
+    INSTANCE_ROOT=${deb.prefix}
+    if [ -f /etc/opendj/instance.loc ] ; then
+        read INSTANCE_ROOT < /etc/opendj/instance.loc || true
+    elif [ -f ${deb.prefix}/instance.loc ] ; then
+        read _loc < ${deb.prefix}/instance.loc || true
+        case "$_loc" in
+            /*) INSTANCE_ROOT=$_loc ;;
+            *)  INSTANCE_ROOT=${deb.prefix}/$_loc ;;
+        esac
+    fi
+}
+
+# Pre installation script.
 if [ "$1" = "upgrade" ] ; then
-    # Only if the instance has been configured
-    if [ -f ${deb.prefix}/config/buildinfo ] && [ "$(ls -A ${deb.prefix}/config/archived-configs)" ] ; then
-        # If the server is running before upgrade, creates a flag.
-        if [ -f ${deb.prefix}/logs/server.pid ] ; then
-            touch ${deb.prefix}/logs/status
+    resolve_instance_root
+    # Stop the server if it is running - keyed on a live PID, not on
+    # archived-configs, so a freshly set-up instance that was never upgraded
+    # before is stopped too (and a stale pid file does not block the upgrade).
+    SERVER_PID=$(cat "$INSTANCE_ROOT/logs/server.pid" 2>/dev/null || true)
+    if [ -x ${deb.prefix}/bin/stop-ds ] && [ -n "$SERVER_PID" ] && [ -d "/proc/$SERVER_PID" ] ; then
+        # Record that it was running so postinst restarts it after the upgrade.
+        touch "$INSTANCE_ROOT/logs/status"
+        echo "*Stopping OpenDJ server..."
+        if [ -d /run/systemd/system ] ; then
+            deb-systemd-invoke stop opendj.service || true
         fi
-        echo *Stopping OpenDJ server...
-        ${deb.prefix}/bin/./stop-ds
+        if [ -d "/proc/$SERVER_PID" ] ; then
+            # Run the tree's own script as the owner of the server *process*
+            # (the owner of the files says nothing about who started the
+            # server), so the stop is neither an EPERM kill nor a root
+            # execution of an opendj-writable script.
+            OWNER=$(stat -c %U "/proc/$SERVER_PID" 2>/dev/null || echo root)
+            if [ "$OWNER" != root ] && command -v runuser >/dev/null 2>&1 ; then
+                runuser -u "$OWNER" -- ${deb.prefix}/bin/stop-ds || true
+            else
+                ${deb.prefix}/bin/stop-ds || true
+            fi
+        fi
+        # The stop errors above are deliberately swallowed, but the new payload
+        # must not be unpacked over a live JVM: verify the stop happened.
+        for _i in 1 2 3 4 5 6 7 8 9 10 ; do
+            [ -d "/proc/$SERVER_PID" ] || break
+            sleep 2
+        done
+        if [ -d "/proc/$SERVER_PID" ] ; then
+            echo "Unable to stop the running OpenDJ server (pid $SERVER_PID); stop it manually and retry the upgrade." >&2
+            exit 1
+        fi
     else
-        echo "Instance is not configured. Upgrade aborted."
-        exit -1
+        # Not running: drop the restart flag a previously failed restart may
+        # have left behind, so this upgrade does not start a server the
+        # administrator deliberately stopped.
+        rm -f "$INSTANCE_ROOT/logs/status"
     fi
 fi
 echo
diff --git a/opendj-packages/opendj-deb/resources/control/prerm b/opendj-packages/opendj-deb/resources/control/prerm
index 69e3eee..59cfdb3 100644
--- a/opendj-packages/opendj-deb/resources/control/prerm
+++ b/opendj-packages/opendj-deb/resources/control/prerm
@@ -13,14 +13,66 @@
 # information: "Portions Copyright [year] [name of copyright owner]".
 #
 # Copyright 2013-2015 ForgeRock AS.
+# Portions Copyright 2026 3A Systems, LLC
 
 set -e
-# Pre rm script
-# Unlink the symlink to the process ID if it exists.
-test -h "/var/run/opendj.pid" && unlink /var/run/opendj.pid
+# Pre rm script.
 
-# Stops the server if the instance has been configured
-if [ "$1" = "remove" ] && ( [ -f ${deb.prefix}/config/buildinfo ] && [ "$(ls -A ${deb.prefix}/config/archived-configs)" ] ) ; then
-    ${deb.prefix}/bin/./stop-ds
+# The instance root may have been relocated with instance.loc (split layout):
+# resolve it the way the server scripts (_script-util.sh) do. Empty-file reads
+# are tolerated; the result then simply fails the file checks below.
+resolve_instance_root() {
+    INSTANCE_ROOT=${deb.prefix}
+    if [ -f /etc/opendj/instance.loc ] ; then
+        read INSTANCE_ROOT < /etc/opendj/instance.loc || true
+    elif [ -f ${deb.prefix}/instance.loc ] ; then
+        read _loc < ${deb.prefix}/instance.loc || true
+        case "$_loc" in
+            /*) INSTANCE_ROOT=$_loc ;;
+            *)  INSTANCE_ROOT=${deb.prefix}/$_loc ;;
+        esac
+    fi
+}
+
+# Stop the service before the package files are removed. Act on "remove" only:
+# "deconfigure" is a temporary state while dpkg unpacks an unrelated package,
+# and nothing would restart the server afterwards.
+if [ "$1" = "remove" ] ; then
+    resolve_instance_root
+    if [ -d /run/systemd/system ] ; then
+        deb-systemd-invoke stop opendj.service || true
+    fi
+    # Stop a still-running instance directly - keyed on a live PID, so an
+    # instance that was never upgraded is stopped too. Run the tree's own
+    # script as the owner of the server *process*, never as root for a
+    # non-root server.
+    SERVER_PID=$(cat "$INSTANCE_ROOT/logs/server.pid" 2>/dev/null || true)
+    if [ -x ${deb.prefix}/bin/stop-ds ] && [ -n "$SERVER_PID" ] && [ -d "/proc/$SERVER_PID" ] ; then
+        echo "*Stopping OpenDJ server..."
+        OWNER=$(stat -c %U "/proc/$SERVER_PID" 2>/dev/null || echo root)
+        if [ "$OWNER" != root ] && command -v runuser >/dev/null 2>&1 ; then
+            runuser -u "$OWNER" -- ${deb.prefix}/bin/stop-ds || true
+        else
+            ${deb.prefix}/bin/stop-ds || true
+        fi
+        # The package files must not be deleted under a live JVM: verify the
+        # stop happened (the stop errors above are deliberately swallowed).
+        for _i in 1 2 3 4 5 6 7 8 9 10 ; do
+            [ -d "/proc/$SERVER_PID" ] || break
+            sleep 2
+        done
+        if [ -d "/proc/$SERVER_PID" ] ; then
+            echo "Unable to stop the running OpenDJ server (pid $SERVER_PID); stop it manually and retry." >&2
+            exit 1
+        fi
+    fi
+    # A stale restart flag must not survive into a later re-install.
+    rm -f "$INSTANCE_ROOT/logs/status"
 fi
-# End prem script
+
+# Clean up the legacy PID symlink created by the SysV init script.
+[ -h /run/opendj.pid ] && rm -f /run/opendj.pid || true
+[ -h /var/run/opendj.pid ] && rm -f /var/run/opendj.pid || true
+
+exit 0
+# End prerm script
diff --git a/opendj-packages/opendj-rpm/opendj-rpm-standard/pom.xml b/opendj-packages/opendj-rpm/opendj-rpm-standard/pom.xml
index 046b31c..0c4da62 100644
--- a/opendj-packages/opendj-rpm/opendj-rpm-standard/pom.xml
+++ b/opendj-packages/opendj-rpm/opendj-rpm-standard/pom.xml
@@ -13,6 +13,7 @@
   information: "Portions Copyright [year] [name of copyright owner]".
 
   Copyright 2015 ForgeRock AS.
+  Portions Copyright 2018-2026 3A Systems, LLC
 -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
@@ -33,6 +34,8 @@
 
     <properties>
         <sysv.file.location>${project.parent.parent.basedir}/resources/sysv/opendj</sysv.file.location>
+        <systemd.file.location>${project.parent.parent.basedir}/resources/systemd/opendj.service</systemd.file.location>
+        <env.file.location>${project.parent.parent.basedir}/resources/env/opendj</env.file.location>
         <rpm.product.name>${product.name}</rpm.product.name>
         <rpm.product.name.lowercase>${product.name.lowercase}</rpm.product.name.lowercase>
         <rpm.resources.path>${project.parent.basedir}/resources</rpm.resources.path>
diff --git a/opendj-packages/opendj-rpm/pom.xml b/opendj-packages/opendj-rpm/pom.xml
index ceae32a..fb745df 100644
--- a/opendj-packages/opendj-rpm/pom.xml
+++ b/opendj-packages/opendj-rpm/pom.xml
@@ -13,7 +13,7 @@
   information: "Portions Copyright [year] [name of copyright owner]".
 
   Copyright 2015-2016 ForgeRock AS.
-  Portions Copyright 2026 3A Systems, LLC
+  Portions Copyright 2018-2026 3A Systems, LLC
 -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
@@ -155,13 +155,20 @@
                         <requires>
                             <!-- The server needs a JRE (11+) at run time. -->
                             <require>java-headless &gt;= 1:11</require>
-                            <!-- _script-util.sh locates java via "which java". -->
-                            <require>which</require>
-                            <!-- postinstall/preuninstall register the service via /sbin/chkconfig. -->
-                            <require>chkconfig</require>
-                            <!-- /etc/init.d/opendj sources /etc/init.d/functions on RedHat-family. -->
-                            <require>initscripts</require>
+                            <!-- postinstall runs the upgrade tool and the server via runuser. -->
+                            <require>util-linux</require>
+                            <!-- No hard chkconfig/initscripts dependency: systemd hosts do not
+                                 need them (and RHEL 10 drops SysV support), the scriptlets
+                                 guard every chkconfig call, and the init script falls back to
+                                 a self-contained mode without /etc/init.d/functions. -->
                         </requires>
+                        <!-- preinstall creates the dedicated opendj service user/group, so
+                             shadow-utils must be present before the payload is unpacked.
+                             The plugin has no requiresPre parameter; prereqs emits PreReq:,
+                             which rpm >= 4.8 treats as Requires(pre,preun). -->
+                        <prereqs>
+                            <prereq>shadow-utils</prereq>
+                        </prereqs>
                         <description>
                             ${rpm.description.header}
                             OpenDJ is an LDAPv3 compliant directory service, developed for the Java
@@ -230,7 +237,7 @@
                                 <directory>${rpm.prefix}/snmp/mib</directory>
                             </mapping>
 
-                            <!-- Add service script -->
+                            <!-- Add SysV init service script (fallback for non-systemd hosts) -->
                             <mapping>
                                 <directory>/etc/init.d</directory>
                                 <directoryIncluded>false</directoryIncluded>
@@ -242,6 +249,31 @@
                                 </sources>
                             </mapping>
 
+                            <!-- Add systemd service unit (native service management) -->
+                            <mapping>
+                                <directory>/usr/lib/systemd/system</directory>
+                                <directoryIncluded>false</directoryIncluded>
+                                <filemode>644</filemode>
+                                <sources>
+                                    <source>
+                                        <location>${systemd.file.location}</location>
+                                    </source>
+                                </sources>
+                            </mapping>
+
+                            <!-- Service environment override (%config(noreplace)) -->
+                            <mapping>
+                                <directory>/etc/sysconfig</directory>
+                                <directoryIncluded>false</directoryIncluded>
+                                <filemode>644</filemode>
+                                <configuration>noreplace</configuration>
+                                <sources>
+                                    <source>
+                                        <location>${env.file.location}</location>
+                                    </source>
+                                </sources>
+                            </mapping>
+
                             <!-- Add executable scripts and libraries -->
                             <mapping>
                                 <directory>${rpm.prefix}</directory>
diff --git a/opendj-packages/opendj-rpm/resources/changelog b/opendj-packages/opendj-rpm/resources/changelog
index 21db726..1f70512 100644
--- a/opendj-packages/opendj-rpm/resources/changelog
+++ b/opendj-packages/opendj-rpm/resources/changelog
@@ -12,30 +12,567 @@
 # information: "Portions Copyright [year] [name of copyright owner]".
 #
 # Copyright 2013-2015 ForgeRock AS.
+# Portions Copyright 2026 3A Systems, LLC.
 
 # =============================
 # opendj rpm package changelog
 # =============================
 
 %changelog
-* Wed Dec  9 2015 ForgeRock
-- init.d service script now generates and removes a lockfile.
+* Thu Aug  6 2026 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 5.2.0-1
+- Modernize Debian and RPM packaging: systemd service unit, dedicated opendj
+  service account, package upgrade/install tests in CI (#663). This stanza is
+  replaced by the release notes when generate-changelog.sh is re-run at
+  release time.
 
-* Thu Mar  5 2015 ForgeRock
-- Package is now build using maven.
-
-* Thu Aug 22 2013 ForgeRock
-- Modified init.d script.
-
-* Tue Aug 6 2013 ForgeRock
-- Added init.d service script.
-
-* Wed Jul 31 2013 ForgeRock
-- Fixed the doc's section.
-- Target no longer fails when build path contains spaces.
-
-* Thu Jul 18 2013 ForgeRock
-- Fixed the sections' order and added a new "clean" section.
-- Added '%doc' section.
-- Added '%changelog' at the end of the file.
-- Added license to header's files.
+* Fri Jul 17 2026 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 5.1.2-1
+- Add an OpenDJ vs OpenLDAP LDAP benchmark GitHub Action
+- CVE-2026-62366 OpenDJ Unauthenticated stack exhaustion when decoding an LDAP
+  search filter (DoS)
+- CVE-2026-62373 OpenDJ JMX MBean-argument deserialization without a serial
+  filter
+- CVE-2026-62375 OpenDJ Unbounded VLV offset array allocation leading to
+  memory-exhaustion DoS
+- GHSA-68r5-9hpg-7qw9 OpenDJ unauthenticated SSRF, local file read and
+  unbounded-read DoS in the DSMLv2 gateway
+- GHSA-p279-2cqp-84jg SASL PLAIN authzid bypassing the proxy ACI scope check
+- CI: full Java matrix on ubuntu only; macOS/Windows build with Java 11 and 26
+- Modernizes the OpenDJ Docker images and broadens their multi-architecture
+  build matrix.
+- Benchmark the built Docker image against the released one
+- Stabilize Oracle JDBC backend test on CI
+- Log JMX RMI connector startup failure at error level
+- Docs: add missing tools references
+- CI: dump OpenDJ container logs when Docker image smoke tests fail
+- Refactor file deletion logic to combine null check and length check.
+- Add CI smoke tests for the addrate/authrate/modrate/searchrate tools
+- Fix duplicate SNMP connection handler entries in packaged config.ldif
+- Fix duplicate opendj-server-legacy classes in distribution lib/
+- Add CI install-test for the Windows MSI + document MSI
+  install/upgrade/uninstall
+- [#665] Fix StackOverflowError while parsing long ACI with repetitive targets
+- [#693] Fix Windows scripts for install paths with spaces and parentheses
+- Fix two broken AciTests cases and enable the suite in the default build
+- [#673] Fix ArrayIndexOutOfBoundsException on truncated percent-encoding in
+  LDAP URLs
+- Declare the deb/rpm runtime dependencies (java, which, chkconfig)
+- [#697] Fix global idle-time-limit having no effect on client connections
+- Fix embedded server rebuildIndex failing with Connect Error
+- Fix and enable broken tests from the slow group
+- [#696] Fix embedded server setup failing with "Time service not started"
+- Revive the quicksetup test suite
+- Fix and enable the replication StressTest
+- Remove the unfixable testStateMachineFull and fix the dead replay pool
+- Fix ACI grouped bind rule wrongly rejected when a value contains parentheses
+- Enable the remaining slow-group tests in the default build
+- Include *TestSuite classes in the failsafe run
+- Enable the SNMP tests in the default build
+- Fix and enable the AlternateRootDN ACI test
+- [#709] Enable disabled and invisible tests across the sibling modules
+- [#712] Fix StringIndexOutOfBoundsException on blank bind rule in ACI
+- CVE-2026-9828 QOS.CH Sarl logback logback-core has a deserialization of
+  untrusted data vulnerability
+- ci: add "Benchmark PDB vs JE" step to build-docker
+- Add concurrency groups to GitHub Actions workflows
+- [#695] Fix race in TraditionalWorkQueue.isIdle()
+- [#690] Fix finalizeWorkQueue never cancelling queued operations
+- [#692] Restore partial import semantics for include/exclude branches
+- Restrict Unix integration-test steps to Linux only
+- ci: add CodeQL code scanning workflow
+- [#719] Fix NullPointerException decoding an ACI bind rule with a missing
+  and/or operand
+- CVE-2026-10532 Logback vulnerable to Object Injection through
+  HardenedObjectInputStream modules
+- [#728] Reject TCP self-connects in replication connect paths
+- Fix flaky BindOperationTestCase subtree auth-info tests
+- [#730] Fix import/export context leak on failed initializeRemote validation
+- Fix intermittent GenerationIdTest.testMultiRS by re-advertising genId on
+  change
+- [#710] Fix replication catch-up re-sending updates with the original assured
+  flag
+- [#726] Reject malformed bracketed IPv6 hosts in HostPort
+- Enable Javadoc doclint (all,-missing) and fail on warnings
+- [#735] Do not roll back a concurrently adopted generation ID on aborted
+  handshake
+- [#737] Fix cn=changelog search failing when aliases are dereferenced
+- [#738] Fix dereferencing an alias that points into another backend
+- Harden opendj-docker apt step: force IPv4 + retries
+- [#739] Fix alias dereferencing dropping entries and accumulating DNs
+- [#744] Fix flaky ChangelogBackendTestCase: keep generated CSN batches
+  monotonic
+- Bump org.openidentityplatform.commons to 3.1.2
+- [#708] Fix OutOfMemory during replication initialize with JDBC backend
+* Thu Jun 11 2026 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 5.1.1-1
+- CVE-2026-46495 OpenDJ Unauthenticated RCE via Java Deserialization in JMX
+  RMI
+- CVE-2026-42198 pgjdbc: Unbounded PBKDF2 iterations in SCRAM authentication
+  allows CPU exhaustion DoS
+- [#648] slow DN.valueOf / AVA normalization for nested DN-syntax values
+- chore: bump Bouncy Castle FIPS deps to latest 2.1.x patch releases
+- Fix grizzly log level is always FINE
+- Fix shell script issues in opendj-docker/run.sh
+- Fix Windows CI: use ilammy/msvc-dev-cmd to set up MSVC env
+- Add native access JVM flag for Bouncy Castle FIPS on newer Java releases
+- Docker base DN entry creation opt-in and improves bootstrap LDIF loading
+  resilience
+- Fix BasicRequestsTest.testReadSelectPartial for nesting-preserving field
+  projection
+- Update org.openidentityplatform.commons to 3.1.1
+- Fix JMX RMI connector startup failure introduced by CVE-2026-46495 hardening
+* Wed Apr 15 2026 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 5.1.0-1
+- [#72] Fix infinite loop in doStopApplication() on Windows service stop
+- [#259] fix: retry loop for Windows Service start race condition (issue #259)
+- [#566] Fix AttributeValuePasswordValidator: inverted substring logic and
+  missing reversed-password substring check
+- [#579] Fix ReferentialIntegrityPlugin silently bypassing check-references on
+  modify operations
+- [#601] Fix server crash when File-Based Debug Logger is enabled
+- Update build.yml add JDK 26 support
+- Docs: set neutral version for the docs
+- ci: add Windows service start/stop test to CI workflow
+- CI: Build and upload Windows native executables (winlauncher,
+  opendj_service, launcher_administrator)
+- fix: use 127.0.0.1 instead of localIP in LockdownModeTaskTestCase
+- Filter branches to build workflow triggers (on push)
+- Fix intermittent testMultiRS failure by doubling waitForStableGenerationId
+  timeout
+- Fix race condition in ChangelogBackendTestCase flaky test
+- Fix flaky testMultiRS: replace fixed sleep with deterministic domain-ready
+  wait
+- increase replication connection timeout to fix Socket Timeout error on Mac
+  in integration test
+- chore: bump GitHub Actions to latest major versions
+- Fix snapshot version format
+- Fix intermittent GenerationIdTest.testMultiRS race condition on RS-to-RS
+  topology
+- [OpenIdentityPlatform/OpenAM#980] OpenDJ slim maven artifact
+- Upgrade local Docker registry from registry:2 to registry:3 in CI
+- status CLI: allow --hostname, --port, and --trustAll arguments
+- Fix status CLI to accept --hostname, --port, and --trustAll arguments, and
+  add them to all status command invocations in build.yml
+- Remove ENV ROOT_PASSWORD from Dockerfiles, fix HEALTHCHECK default, add CDDL
+  headers
+- Update commons.version to 3.1.0
+* Mon Mar 23 2026 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 5.0.4-1
+- CVE-2025-24970 SslHandler doesn't correctly validate packets which can lead
+  to native crash when using native SSLEngine
+- CVE‐2025‐12194 While the situation with the JVM garbage collector overrun
+  for Java 17 and Java 21 greatly improved with the changes in 2.1.1, we’ve
+  still had some reports that can only be related to the use of the disposal
+  daemon
+- [#590] Fallback to $HOME/tmp dir as a temp if instance root is mounted as
+  noexec
+- Bump logback to 1.5.32
+- Migrate to caffeine 3
+- Update commons.version from 3.0.2 to 3.0.4
+- Docs: fix short version in the upgrade guide
+* Wed Feb  4 2026 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 5.0.3-1
+- CVE-2026-1225 Logback allows an attacker to instantiate classes already
+  present on the class path
+- Fix three and more nodes replication process stuck error
+- Update org.openidentityplatform.commons to 3.0.2
+- Docs: update supported Java version
+* Tue Nov 25 2025 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 5.0.2-1
+- [#575] FIX unable to install: UnsatisfiedLinkError: /tmp/bc-fips
+- [#577] Windows upgrading with Upgrade.bat: an error with "" unexpected
+- [#573] Added the SAMPLE_DATA Docker environment variable to generate sample
+  data during setup.
+* Sat Nov  8 2025 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 5.0.1-1
+- Update target JDK to 11 and move to JakartaEE 9
+- Add support LTS JDK 25
+- Update base docker image Java version to 25 LTS
+- CVE-2025-12194 Bouncy Castle Vulnerable to Uncontrolled Resource Consumption
+- CVE-2025-59250 JDBC Driver for SQL Server has improper input validation
+  issue
+- CVE-2025-11226 logback-core is vulnerable to Arbitrary Code Execution
+  through file processing
+- Switch from sun.security.x509 to Bouncy Castle API
+- Update OpenDMK external library to fix SNMP monitoring
+- Build & deploy: add branch sustaining/4.10.x
+- Make GrizzlyLDAPListener close in a synchronous fasion to prevent test race
+  conditions
+- [#141] Test large replication pending changes
+- FIX bindFreePort Bind Unable to bind to a free port
+- Fix unavailable monitoring attributes over JMX
+- Bump org.openidentityplatform.commons to 3.0.1
+- Improve ReplicationDomainTest stability
+* Thu Sep  4 2025 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.10.2-1
+- CVE-2025-9092 CVE-2025-9340 CVE-2025-9341 Uncontrolled Resource Consumption
+  vulnerability
+- [#545] Add GroupManager writeLock performance
+- [#540] Fix OnDiskMergeImporter::PhaseOneWriteableTransaction: update over
+  put (referral attr)
+- [#544] Add requires-admin-action component-restart for max-request-size
+- Update Java minimum version number in the setup UI
+- Update README.md: add backers and sponsors
+- ISSUE_TEMPLATE: add "Vote to raise the priority"
+- Bump commons.version 2.4.1
+* Tue Aug  5 2025 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.10.1-1
+- [#529] FIX jdbc connection deadlock
+- [#530] Fixed error when creating a backend for BASE_DN with OU in Docker
+- Docker: Fix issues with quoting params
+* Tue Jul 15 2025 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.10.0-1
+- [#462] RFC5805 Lightweight Directory Access Protocol (LDAP) Transactions
+- CVE-2025-49146 pgjdbc Client Allows Fallback to Insecure Authentication
+  Despite channelBinding=require Configuration
+- Bump io.reactivex.rxjava to 3.x
+- Bump various dependencies
+- Bump commons to 2.2.5
+- Take Glassfish Grizzly version from commons
+- Bump bc.fips to 2.1.x
+- Bump commons.version 2.3.0
+- Deploy: migrating from Legacy OSSRH to Central Portal
+- Fix OSGI bundle excluded package error for rxjava3
+- Exclude BouncyCastle from OSGI Import-Package
+- Fix makeldif templates: add objectClass to baseDN
+- Bump org.openidentityplatform.commons 2.4.0
+* Wed Apr 23 2025 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.9.4-1
+- Configure backend type for Docker
+- Docs: update OpenDJ release version to 4.9.3
+- Add OpenDJ Docker tests to the build process
+- Fix docker env variables + add VERSION autodetect
+- Set isRunning later (EmbeddedServer check)
+- Bump org.openidentityplatform.commons to 2.2.4
+- [#498] FIX warning output from export-ldif: "grep: warning: stray \ before
+  -"
+- move Java args to java.properties, upgrade docker alpine
+- [#497] Set the same indexes for a new backend as for the initial backend
+- Add support Java SE 24
+- Bump test containers & cassandra driver
+- [#496] FIX MySQL truncate PK default to 64 len
+- [#496] FIX JDBC storage update concurrency
+- FIX Replication IT tests unstable result
+- made their first contribution
+- made their first contribution
+* Wed Mar  5 2025 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.9.3-1
+- CVE-2025-27497 Fix Denial of Service (Dos) using alias loop ()
+- [#477] Change permission config.ldif.startok to owner ()
+- [#208] FIX The definition for the attribute type declared that it should use
+  the syntax which is not defined in the schema
+- Documentation update
+- Docs: Generate and publish javadoc
+* Tue Feb  4 2025 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.9.2-1
+- [#465] Fix custom library loading when put to the lib directory
+- [#463] Disable warning message on downstream closed
+- [#471] Fix table name truncate: make jdbc table 63 charter
+- [#466] JDBC: added tests for Oracle, MySQL, MSSQL
+- [#466] FIX compatibility jdbc backend: Postgres, Oracle, MySQL, MSSQL
+- [#471] PluggableBackendImplTestCase: add duplicate mail test
+- IT ReplicationDomainTest upper waitEndExport timeout
+- Update year in generated documentation templates
+- Update documentation issues and update links
+* Mon Jan 20 2025 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.9.1-1
+- [#460] Clear unused path info after backupConfig (memory pleasure)
+- jdbc: make connection short-lived
+- Replace import-ldif with ldapmodify in Postgres IT test
+* Thu Dec 26 2024 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.9.0-1
+- Store LDAPv3 database in SQL JDBC database
+- CVE-2024-12798 CVE-2024-12801 logback-core Expression Language Injection,
+  Server-Side Request Forgery vulnerability
+- FIX NoSuchMethodError: java.nio.MappedByteBuffer.duplicate
+- FIX Unable to locate package winehq-stable
+* Tue Nov 12 2024 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.8.2-1
+- [#438] FIX import-ldif --offline "import has been aborted because the entry
+  does not have a parent entry"
+- 00-core.ldif: X.501, cl. 14.2.2: 2.5.15.16 subentryNameForm OC subentry MUST
+  cn
+- FIX makeldif -c suffix=dc=example: Unable to parse a constant argument
+  expecting name=value
+- Bump commons.version 2.2.3
+- Fix MAC OS build failure
+- Actions: get ubuntu source from $(lsb_release -c -s)
+- depoloy.yml: Fix documents deploy
+* Thu Oct 17 2024 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.8.1-1
+- [#393] FIX DIT SUP delimiter
+- [#392] FIX RootDSE Entry allow user objectClass
+- Addresses #397, #398, #399, #404
+- Docs in asciidoc & deploy antora docs after build
+- [#402] Change default SSL HandshakeTimeout -1 -> 10s (see #146)
+- [#401] Change "Object class violation (65)" -> "Naming violation (64)" LDAP
+  result code for DIT Structure Rule violation
+- [#394] FIX dsconfig --help-<subcommand>
+- [#400] Reduce character escaping in example, add note
+- Added missing documentation attachments
+- Generate man pages in the AsciiDoc format
+- Reduce character escaping in example, add note
+- minor docs glitches fix
+- Add JDK 23 build support
+- Bump org.openidentityplatform.commons 2.2.2
+- Docker: Use tail instead of sleep to allow the container to be stopped with
+  SIGTERM
+- [#423] Eliminate asciidoctor warning messages when generating documentation
+- [#426] ADD maven.compiler.release=8 for cross compile compatibility
+- Remove legacy files
+- [#90, #432] FIX delete entries in overlapping backends
+- [#425] Add option
+  -Dorg.openidentityplatform.opendj.ERR_ENTRY_SCHEMA_VIOLATES_PARENT_DSR for
+  force control "Entry is invalid according to the server schema because there
+  is no DIT structure rule that applies to that entry, but there is a DIT
+  structure rule for the parent entry". Default: warning level
+- [#425] Workaround: Entry is invalid according to the server schema because
+  there is no DIT structure rule that applies to that entry, but there is a
+  DIT structure rule for the parent entry
+- [#431] Update importldiff --offline and --clearBacked flags descriptions
+- made their first contribution
+- made their first contribution
+* Mon Sep  9 2024 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.8.0-1
+- Switch docker to last LTS JRE 21
+- Add JDK 22 support
+- [#376] JMX fix docs with "Allow insecure authentication"
+- [#376] FIX SNMP monitoring config
+- [#383] FIX docs: import-ldif and export-ldif binaries should be shown using
+  the --offline option
+- [#384] FIX Control Panel: empty help URL values
+- FIX do not check DIT structure parent/child on same ObjectClass (thanks for
+  the research )
+- Bump org.openidentityplatform.commons 2.2.0
+* Thu Aug  8 2024 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.7.0-1
+- [#204] ADD LDAP Relax Rules Control
+- [#287] ADD alias dereferencing for search requests
+- [#187] FIX RFC3671: collective attribute values should be merged. Virtuals
+  with other virtuals and real values.
+- [#84] FIX incorrect entry-Based ACIs is defined with only "deny" permission
+  without "allow"
+- [#250] Add Overlapping Backend TestSuite
+- [#294] Dont send client notification on IOException
+- [#368] CASSANDRA ADD property -Dkeyspace=ldap_opendj
+- Bump commons.version 2.1.6
+- Publish docs to
+- Fix documentation version
+* Tue Jul 16 2024 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.6.5-1
+- compress webhelp, xhtml and html docs after build
+- add missing docs
+- Update README.md
+- [#354] FIX "OpenDJ fails to upgrade from version 3->4: An error occurred
+  while attempting to perform index rebuild: Unable to decode the provided
+  object class set because it used an undefined token"
+- [#167] FIX control-panel ResetUserPasswordTask unpredictable result (wait
+  async result)
+- Add rest operations modifyPassword, resetPassword to docs from
+- [#148,#261,#282] FIX control-panel schema errors in remote mode
+* Wed Jun 26 2024 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.6.4-1
+- Embedded OpenDJ module initial commit
+- Bump ch.qos.logback:logback-core from 1.2.11 to 1.2.13 in /opendj-embedded
+- Bump ch.qos.logback:logback-classic from 1.2.9 to 1.2.13 in /opendj-embedded
+- update opendj-parent version
+- Bump org.bouncycastle:bc-fips from 1.0.2.3 to 1.0.2.5 in /opendj-core
+- Bump org.bouncycastle:bctls-fips from 1.0.13 to 1.0.19 in /opendj-core
+- Bump org.openidentityplatform.commons 2.1.4
+- move commons version to property & fix doc-maven-plugin version
+- made their first contribution
+* Tue May  7 2024 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.6.3-1
+- ADD build test with memory pressure
+- Update Docker jre 17->19
+- org.openidentityplatform.commons 2.1.3-SNAPSHOT
+- FIX OpenIDM compatibility
+- [#329] make posixGroup AUXILIARY by default
+- [#331] Allow downgrade version without upgrade task
+- Bump org.openidentityplatform.commons 2.1.3
+- Add Build test on MacOS M1 arm64
+- Restore macos-latest build strategy
+* Wed Jan 17 2024 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.6.2-1
+- FIX CLIENT_SIDE_NO_RESULTS_RETURNED in hasNext()
+- update org.openidentityplatform.commons to 2.1.2-SNAPSHOT
+- FIX performance java.util.TimeZone.getTimeZone(TimeZone.java:516) is
+  synchronized
+- [#317] sendUnsolicitedNotification can fail on client disconnect with
+  OnErrorNotImplementedException
+- org.openidentityplatform.commons 2.1.2
+* Thu Oct 26 2023 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.6.1-1
+- Allow store LDAP catalog data in CASSANDRA noSQL cluster --backendType cas
+  (ldapv3 to cassandra)
+- ADD IT test for wars
+- Add TestContainers to test Apache Cassandra backend
+- Bump org.openidentityplatform.commons 2.0.19-SNAPSHOT
+- Update README.md: allow store LDAPv3 database in Cassandra/Scylla cluster
+- Bump org.openidentityplatform.commons 2.1.1
+- Add JDK 21 support
+- CASSANDRA storage: cursor performance
+- FIX newHeapBufferPool calculation (import OOM error)
+* Fri Sep 22 2023 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.5.9-1
+- Generate SHA256WithRSA certificate as default
+- convert JMX metrics to appropriate type #293
+- Fix attribute value. bean should return native object #293
+- Remove TLSv1 as default protocol FIX
+- nexus-staging-maven-plugin 1.6.13 + disable auto release
+- made their first contribution
+* Wed Aug 30 2023 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.5.6-1
+- FIX unused trailing bytes in ASN.1 SEQUENCE
+* Thu Jul 20 2023 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.5.5-1
+- FIX build with Installation failure for grub-efi-amd64-signed on ubuntu-
+  latest
+- FIX add-source for generate-sources
+- Restore IT test for server-legacy and fix many errors
+- change posixGroup type to structural. and add cn
+- FIX argument listBackups is incompatible with use of this tool to interact
+- PBKDF2-HMAC-SHA256 and PBKDF-HMAC-SHA512 password storage not configured by
+  default
+- FIX Setup Issue - Error Creating Base Entry
+- Extend admin port connection limits
+- Restore TLSv1.3 support
+- Bump org.openidentityplatform.commons 2.0.18
+* Fri Dec  9 2022 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.5.4-1
+- BUILD java: [ '8','11','17','19'] + fix install wine32:i386 without
+  conflicts
+- FIX build allow fail for remove deb.sury.org
+- Docker add jdk17 platforms: linux/amd64, linux/arm64/8, linux/arm/v7,
+* Wed Nov 30 2022 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.5.3-1
+- Create target directory before copying custom schema
+- Copy ldif configs to the correct template directory
+- UPDATE build process
+- FIX DSML servlet can't find JAX-B runtime
+* Tue Aug  2 2022 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.5.1-1
+- update commons version to 2.0.16-SNAPSHOT
+- 'find' command is missing in the 4.5.0 docker image #242
+- FIX wine32 install (from ppa:ondrej/php so that we will be able to install
+  wine32:i386 without conflicts)
+- Don't clone buffer in ldap codec
+- Add BCFKS FIPS key store type support
+- fix FipsStaticUtils code formatting
+- made their first contribution
+* Wed Jun  1 2022 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.5.0-1
+- Switch base docker image to Java 17
+* Wed Jun  1 2022 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.4.15-1
+- Add alpine platforms linux/s390x, linux/386, linux/arm/v7, linux/arm/v6,
+  linux/ppc64le
+- Implement PBKDF2-HMAC-SHA256 and PBKDF-HMAC-SHA512 password encoding schemes
+- Docker refactoring
+- FIX tamil (ta.6) matching rule schema has typo in definition
+- FIX Failed to delete entries under multiple backends
+- Add support jdk '16','17','18'
+- support AD attributes userAccountControl, msDS-UserAccountDisabled and
+  pwdLastSet
+- Test + Run on jdk15+
+- FIX OpenDJ is not logging errors to logfile #128
+- FIX Windows install to path with spaces
+- made their first contribution
+* Mon May  2 2022 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.4.14-1
+- add docker test
+- Release multi-platform Docker images
+- Support to load plain ldif files during container setup
+- made their first contribution
+* Fri Apr 22 2022 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.4.13-1
+- FIX OpenDJ setup failure
+- Add FIPS support
+- GithubAction build
+- Github action deploy
+- actions: separate deploy
+- Update opendj_service.exe
+- Switch org.openidentityplatform.commons 2.0.13-SNAPSHOT
+- Fix rebuild-index in FIPS mode
+- ADD JSONEntryWriter JSONEntryReader
+- FIX DN escape 'Equal sign':
+- FIX JSONEntryWriter escape DN values
+- move fips functions to separate class
+- do not use fips when bc-fips classes not found
+- Update pom.xml nexus-staging-maven-plugin 1.6.11
+- Refactor Dockerfile debian and alpine
+- Migrate release from Travis to GitHub
+- FIX Deployment of external dependency failed. Failed to deploy artifacts:
+  Could not transfer artifact openidentityplatform.org:wixtoolset:zip
+- made their first contribution
+- made their first contribution
+- made their first contribution
+- made their first contribution
+* Mon Jun 21 2021 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.4.11-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.11
+* Mon Feb  8 2021 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.4.10-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.10
+* Wed Dec 30 2020 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.4.9-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.9
+* Tue Nov 10 2020 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.4.8-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.8
+* Wed Sep  9 2020 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.4.7-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.7
+* Thu Jun 11 2020 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.4.6-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.6
+* Tue Mar 10 2020 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.4.5-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.5
+* Fri Feb 21 2020 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.4.4-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.4
+* Mon Jul 29 2019 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.4.3-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.3
+* Mon Apr 29 2019 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.4.2-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.2
+* Sun Mar 10 2019 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.4.1-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.4.1
+* Mon Mar  4 2019 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.3.5-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.3.5
+* Sun Feb 17 2019 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.3.4-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.3.4
+* Fri Feb  8 2019 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.3.3-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.3.3
+* Tue Jan 29 2019 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.3.2-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.3.2
+* Mon Dec 10 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.3.1-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.3.1
+* Fri Oct 26 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.2.5-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.2.5
+* Thu Oct 18 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.2.4-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.2.4
+* Wed Oct 17 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.2.3-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.2.3
+* Mon Oct  8 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.2.2-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.2.2
+* Fri Oct  5 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.2.1-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.2.1
+* Wed May 30 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.1.10-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.10
+* Fri May 25 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.1.9-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.9
+* Sat May 12 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.1.8-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.8
+* Tue May  1 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.1.7-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.7
+* Tue Apr 10 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.1.6-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.6
+* Tue Mar  6 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.1.5-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.5
+* Sat Mar  3 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.1.4-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.4
+* Wed Feb 28 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.1.3-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.3
+* Wed Feb 28 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.1.2-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.2
+* Fri Feb 23 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.1.1-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.1.1
+* Tue Feb 20 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.0.3-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.0.3
+* Fri Feb 16 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.0.2-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.0.2
+* Fri Feb 16 2018 Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com> - 4.0.1-1
+- See release notes:
+  https://github.com/OpenIdentityPlatform/OpenDJ/releases/tag/4.0.1
diff --git a/opendj-packages/opendj-rpm/resources/specs/postinstall.sh b/opendj-packages/opendj-rpm/resources/specs/postinstall.sh
index 5b62246..eff4505 100644
--- a/opendj-packages/opendj-rpm/resources/specs/postinstall.sh
+++ b/opendj-packages/opendj-rpm/resources/specs/postinstall.sh
@@ -13,50 +13,115 @@
 # information: "Portions Copyright [year] [name of copyright owner]".
 #
 # Copyright 2013-2015 ForgeRock AS.
+# Portions Copyright 2026 3A Systems, LLC
 
 # ===============================
 # RPM Post Install Script (%post)
 # ===============================
 
-# The arguments to a %post are 1 and 2 for a new installation
-#  and upgrade, respectively. (%pre and %post aren't executed during
-#  an uninstallation.)
+# $1 is 1 for an initial installation and 2 for an upgrade.
 
-# Registers the service
-/sbin/chkconfig --add opendj
-
-# Symlinks to process ID
-test -h "/var/run/opendj.pid" || ln -s /opt/opendj/logs/server.pid /var/run/opendj.pid
-
-if [ "$1" == "1" ] ; then
-    echo "Post Install - initial install"
-else if [ "$1" == "2" ] ; then
-    echo "Post Install - upgrade install"
-    # Only if the instance has been configured
-    if [ -e "%{_prefix}"/config/buildinfo ] && [ "$(ls -A "%{_prefix}"/config/archived-configs)" ] ; then
-        "%{_prefix}"/./upgrade -n --force --acceptLicense
-        # If upgrade is ok, checks the server status flag for restart
-        if [ "$?" == "0" ] && [ -f "%{_prefix}"/logs/status ] ; then
-            echo ""
-            echo "Restarting server..."
-            "%{_prefix}"/./bin/start-ds
-            echo ""
-            rm -f "%{_prefix}"/logs/status
-        fi
-
-        # Upgrade fails, needs user interaction (eg. manual mode)
-        if [ "$?" == "2" ] ; then
-            exit "0"
-        fi
-    else
-        echo "Instance is not configured. Upgrade aborted."
-        exit -1
+# The instance root may have been relocated with instance.loc (split layout):
+# resolve it the way the server scripts (_script-util.sh) do. Empty-file reads
+# are tolerated; the result then simply fails the file checks below.
+resolve_instance_root() {
+    INSTANCE_ROOT="%{_prefix}"
+    if [ -f /etc/opendj/instance.loc ] ; then
+        read INSTANCE_ROOT < /etc/opendj/instance.loc || true
+    elif [ -f "%{_prefix}"/instance.loc ] ; then
+        read _loc < "%{_prefix}"/instance.loc || true
+        case "$_loc" in
+            /*) INSTANCE_ROOT=$_loc ;;
+            *)  INSTANCE_ROOT="%{_prefix}"/$_loc ;;
+        esac
     fi
-    fi
+}
+resolve_instance_root
+
+# Own the install tree - and a split-layout instance - with the service
+# account (the account itself is created in %pre, before the payload lands).
+# On upgrade this also migrates installations previously owned by root.
+chown -R opendj:opendj "%{_prefix}" || true
+if [ "$INSTANCE_ROOT" != "%{_prefix}" ] && [ -d "$INSTANCE_ROOT" ] ; then
+    chown -R opendj:opendj "$INSTANCE_ROOT" || true
 fi
 
+# Honour the documented admin overrides (OPENDJ_JAVA_HOME / OPENDJ_JAVA_BIN /
+# OPENDJ_JAVA_ARGS) for the upgrade tool and the restart below, exactly as the
+# service itself does via EnvironmentFile=. systemd's EnvironmentFile syntax
+# is not shell (no expansion, optional quotes), so extract the known keys
+# instead of sourcing the file.
+if [ -r /etc/sysconfig/opendj ] ; then
+    for _key in OPENDJ_JAVA_HOME OPENDJ_JAVA_BIN OPENDJ_JAVA_ARGS ; do
+        _val=$(sed -n "s/^$_key=//p" /etc/sysconfig/opendj | tail -n 1 \
+            | sed -e 's/^"\(.*\)"$/\1/' -e "s/^'\(.*\)'\$/\1/")
+        [ -n "$_val" ] && export "$_key=$_val" || true
+    done
+fi
+
+# Register the service. Enable only on initial install, so an admin's
+# "systemctl disable" survives upgrades ("dnf update" must not re-enable) -
+# except on the first upgrade from a pre-systemd package (%pre left a marker):
+# there the enable state lives in the chkconfig rc links, which the native
+# unit now shadows, so an enabled SysV service is carried over exactly once.
+# This must run before "chkconfig --add" below creates fresh rc links.
+# systemctl enable works without a booted systemd (chroot/image builds); the
+# unit's start condition keeps an unconfigured instance from failing at boot.
+if command -v systemctl >/dev/null 2>&1 ; then
+    if [ "$1" = "1" ] ; then
+        systemctl enable opendj.service >/dev/null 2>&1 || true
+    elif [ -f /run/opendj-systemd-migration ] ; then
+        if ls /etc/rc.d/rc[2345].d/S??opendj >/dev/null 2>&1 \
+            || ls /etc/rc[2345].d/S??opendj >/dev/null 2>&1 ; then
+            systemctl enable opendj.service >/dev/null 2>&1 || true
+        fi
+    fi
+fi
+rm -f /run/opendj-systemd-migration 2>/dev/null || true
+/sbin/chkconfig --add opendj >/dev/null 2>&1 || true
+if [ -d /run/systemd/system ] ; then
+    systemctl daemon-reload >/dev/null 2>&1 || true
+fi
+
+if [ "$1" = "2" ] ; then
+    echo "Post Install - upgrade install"
+    # Only if the instance has been configured.
+    if [ -e "$INSTANCE_ROOT/config/buildinfo" ] && [ -f "$INSTANCE_ROOT/config/config.ldif" ] ; then
+        if runuser -u opendj -- "%{_prefix}"/upgrade -n --force --acceptLicense ; then
+            # If upgrade is ok, check the server status flag for restart.
+            if [ -f "$INSTANCE_ROOT/logs/status" ] ; then
+                echo "Restarting server..."
+                STARTED=0
+                if [ -d /run/systemd/system ] ; then
+                    systemctl start opendj.service && STARTED=1 || true
+                    # Trust the observable unit state, not just the exit code.
+                    if [ "$STARTED" = 1 ] && ! systemctl is-active --quiet opendj.service ; then
+                        STARTED=0
+                    fi
+                else
+                    runuser -u opendj -- "%{_prefix}"/bin/start-ds && STARTED=1 || true
+                fi
+                if [ "$STARTED" = 1 ] ; then
+                    rm -f "$INSTANCE_ROOT/logs/status"
+                else
+                    # Keep the status flag so the next upgrade retries the restart.
+                    echo "Server restart failed; see the logs under $INSTANCE_ROOT/logs and start the service manually."
+                fi
+            fi
+        else
+            # Upgrade failed; may need manual interaction. Do not fail the transaction.
+            echo "Upgrade failed; manual interaction may be required."
+            exit 0
+        fi
+    else
+        echo "Instance is not configured."
+    fi
+else
+    echo "Post Install - initial install"
+fi
+
+# Add OpenDJ man pages to MANPATH.
 MAN_CONFIG_FILE=NOT_SET
-# Add OpenDJ man pages to MANPATH
 if [ -e /etc/man.config ] ; then
     MAN_CONFIG_FILE=/etc/man.config
     MANPATH_DIRECTIVE=MANPATH
@@ -65,9 +130,8 @@
     MANPATH_DIRECTIVE=MANDATORY_MANPATH
 fi
 
-if [ $MAN_CONFIG_FILE != "NOT_SET" ] ; then
-    grep -q "$MANPATH_DIRECTIVE.*opendj" $MAN_CONFIG_FILE 2> /dev/null
-    if [ $? -ne 0 ]; then
-        echo "$MANPATH_DIRECTIVE %{_prefix}/share/man" >> $MAN_CONFIG_FILE
+if [ "$MAN_CONFIG_FILE" != "NOT_SET" ] ; then
+    if ! grep -q "$MANPATH_DIRECTIVE.*opendj" "$MAN_CONFIG_FILE" 2>/dev/null ; then
+        echo "$MANPATH_DIRECTIVE %{_prefix}/share/man" >> "$MAN_CONFIG_FILE"
     fi
 fi
diff --git a/opendj-packages/opendj-rpm/resources/specs/postuninstall.sh b/opendj-packages/opendj-rpm/resources/specs/postuninstall.sh
index c690a73..b2aedb4 100644
--- a/opendj-packages/opendj-rpm/resources/specs/postuninstall.sh
+++ b/opendj-packages/opendj-rpm/resources/specs/postuninstall.sh
@@ -13,18 +13,23 @@
 # information: "Portions Copyright [year] [name of copyright owner]".
 #
 # Copyright 2013-2015 ForgeRock AS.
+# Portions Copyright 2026 3A Systems, LLC
 
 # ===================================
 # RPM Post Uninstall Script (%postun)
 # ===================================
 
-# If the first argument to %preun and %postun is 0, the action is uninstallation.
-# If the first argument to %preun and %postun is 1, the action is an upgrade.
+# $1 is 0 for an uninstallation and 1 for an upgrade.
 
-if [ "$1" == "0" ] ; then
+if [ -d /run/systemd/system ] ; then
+    systemctl daemon-reload >/dev/null 2>&1 || true
+fi
+
+if [ "$1" = "0" ] ; then
     echo "Post Uninstall - uninstall"
-    echo "OpenDJ successfully removed."
-else if [ "$1" == "1" ] ; then
+    echo "OpenDJ package removed. Server data (config, db, changelogDb, logs)"
+    echo "and the opendj system account are kept; remove them manually if they"
+    echo "are no longer needed."
+elif [ "$1" = "1" ] ; then
     echo "Post Uninstall - upgrade uninstall"
-    fi
 fi
diff --git a/opendj-packages/opendj-rpm/resources/specs/preinstall.sh b/opendj-packages/opendj-rpm/resources/specs/preinstall.sh
index 14632db..8cec1b0 100644
--- a/opendj-packages/opendj-rpm/resources/specs/preinstall.sh
+++ b/opendj-packages/opendj-rpm/resources/specs/preinstall.sh
@@ -13,25 +13,82 @@
 # information: "Portions Copyright [year] [name of copyright owner]".
 #
 # Copyright 2013-2015 ForgeRock AS.
+# Portions Copyright 2026 3A Systems, LLC
 
 # =============================
 # RPM Pre Install Script (%pre)
 # =============================
 
-# If the first argument to %pre is 1, the RPM operation is an initial installation.
-# If the argument to %pre is 2, the operation is an upgrade from an existing version to a new one.
+# $1 is 1 for an initial installation and 2 for an upgrade.
 
-if [ "$1" == "1" ]; then
-    echo "Pre Install - initial install"
-else if [ "$1" == "2" ] ; then
-    # Only if the instance has been configured
-    if [ -e "%{_prefix}"/config/buildinfo ] && [ "$(ls -A "%{_prefix}"/config/archived-configs)" ] ; then
+# The instance root may have been relocated with instance.loc (split layout):
+# resolve it the way the server scripts (_script-util.sh) do. Empty-file reads
+# are tolerated; the result then simply fails the file checks below.
+resolve_instance_root() {
+    INSTANCE_ROOT="%{_prefix}"
+    if [ -f /etc/opendj/instance.loc ] ; then
+        read INSTANCE_ROOT < /etc/opendj/instance.loc || true
+    elif [ -f "%{_prefix}"/instance.loc ] ; then
+        read _loc < "%{_prefix}"/instance.loc || true
+        case "$_loc" in
+            /*) INSTANCE_ROOT=$_loc ;;
+            *)  INSTANCE_ROOT="%{_prefix}"/$_loc ;;
+        esac
+    fi
+}
+
+# Create the dedicated system user/group that runs the service.
+getent group opendj >/dev/null || groupadd -r opendj
+getent passwd opendj >/dev/null || \
+    useradd -r -g opendj -d "%{_prefix}" -s /sbin/nologin -c "OpenDJ Directory Server" opendj
+
+# Record whether the previous package was pre-systemd (shipped no native
+# unit): %post then migrates the chkconfig enable state to the unit exactly
+# once. Decided here, before the new payload installs the unit file.
+rm -f /run/opendj-systemd-migration 2>/dev/null || true
+if [ "$1" = "2" ] && [ ! -f /usr/lib/systemd/system/opendj.service ] ; then
+    touch /run/opendj-systemd-migration 2>/dev/null || true
+fi
+
+if [ "$1" = "2" ] ; then
+    resolve_instance_root
+    # Upgrade: stop the server if it is running - keyed on a live PID, not on
+    # archived-configs, so a freshly set-up instance is stopped too (and a
+    # stale pid file does not block the upgrade).
+    SERVER_PID=$(cat "$INSTANCE_ROOT/logs/server.pid" 2>/dev/null || true)
+    if [ -x "%{_prefix}"/bin/stop-ds ] && [ -n "$SERVER_PID" ] && [ -d "/proc/$SERVER_PID" ] ; then
         echo "Pre Install - upgrade install"
-        # If the server is running before upgrade, creates a file flag
-        if [ -f "%{_prefix}"/logs/server.pid ] ; then
-            touch "%{_prefix}"/logs/status
+        # Record that it was running so %post restarts it after the upgrade.
+        touch "$INSTANCE_ROOT/logs/status"
+        if [ -d /run/systemd/system ] ; then
+            systemctl stop opendj.service >/dev/null 2>&1 || true
         fi
-        "%{_prefix}"/bin/./stop-ds
+        if [ -d "/proc/$SERVER_PID" ] ; then
+            # Run the tree's own script as the owner of the server *process*
+            # (the owner of the files says nothing about who started the
+            # server), so the stop is neither an EPERM kill nor a root
+            # execution of an opendj-writable script.
+            OWNER=$(stat -c '%%U' "/proc/$SERVER_PID" 2>/dev/null || echo root)
+            if [ "$OWNER" != root ] && command -v runuser >/dev/null 2>&1 ; then
+                runuser -u "$OWNER" -- "%{_prefix}"/bin/stop-ds || true
+            else
+                "%{_prefix}"/bin/stop-ds || true
+            fi
         fi
+        # The stop errors above are deliberately swallowed, but the new payload
+        # must not be unpacked over a live JVM: verify the stop happened.
+        for _i in 1 2 3 4 5 6 7 8 9 10 ; do
+            [ -d "/proc/$SERVER_PID" ] || break
+            sleep 2
+        done
+        if [ -d "/proc/$SERVER_PID" ] ; then
+            echo "Unable to stop the running OpenDJ server (pid $SERVER_PID); stop it manually and retry the upgrade." >&2
+            exit 1
+        fi
+    else
+        # Not running: drop the restart flag a previously failed restart may
+        # have left behind, so this upgrade does not start a server the
+        # administrator deliberately stopped.
+        rm -f "$INSTANCE_ROOT/logs/status"
     fi
 fi
diff --git a/opendj-packages/opendj-rpm/resources/specs/preuninstall.sh b/opendj-packages/opendj-rpm/resources/specs/preuninstall.sh
index 613a5e7..9f5cddc 100644
--- a/opendj-packages/opendj-rpm/resources/specs/preuninstall.sh
+++ b/opendj-packages/opendj-rpm/resources/specs/preuninstall.sh
@@ -13,28 +13,71 @@
 # information: "Portions Copyright [year] [name of copyright owner]".
 #
 # Copyright 2013-2015 ForgeRock AS.
+# Portions Copyright 2026 3A Systems, LLC
 
 # =================================
 # RPM Pre Uninstall Script (%preun)
 # =================================
 
-# If the first argument to %preun and %postun is 0, the action is uninstallation.
-# If the first argument to %preun and %postun is 1, the action is an upgrade.
+# $1 is 0 for an uninstallation and 1 for an upgrade.
 
-if [ "$1" == "0" ] ; then
+# The instance root may have been relocated with instance.loc (split layout):
+# resolve it the way the server scripts (_script-util.sh) do. Empty-file reads
+# are tolerated; the result then simply fails the file checks below.
+resolve_instance_root() {
+    INSTANCE_ROOT="%{_prefix}"
+    if [ -f /etc/opendj/instance.loc ] ; then
+        read INSTANCE_ROOT < /etc/opendj/instance.loc || true
+    elif [ -f "%{_prefix}"/instance.loc ] ; then
+        read _loc < "%{_prefix}"/instance.loc || true
+        case "$_loc" in
+            /*) INSTANCE_ROOT=$_loc ;;
+            *)  INSTANCE_ROOT="%{_prefix}"/$_loc ;;
+        esac
+    fi
+}
+
+if [ "$1" = "0" ] ; then
     echo "Pre Uninstall - uninstall"
-    # Unlink the symlink to the process ID.
-    test -h "/var/run/opendj.pid" && unlink /var/run/opendj.pid
-    # Only if the instance has been configured
-    if [ -e "%{_prefix}"/config/buildinfo ] && [ "$(ls -A "%{_prefix}"/config/archived-configs)" ] ; then
-	   "%{_prefix}"/bin/./stop-ds
+    resolve_instance_root
+    # Stop and unregister the service. "disable" only manipulates symlinks, so
+    # it runs without a booted-systemd gate too (chroot/image builds) - or the
+    # wants link would dangle in the resulting image.
+    if command -v systemctl >/dev/null 2>&1 ; then
+        if [ -d /run/systemd/system ] ; then
+            systemctl stop opendj.service >/dev/null 2>&1 || true
+        fi
+        systemctl disable opendj.service >/dev/null 2>&1 || true
     fi
-
+    # Stop a still-running instance directly - keyed on a live PID, so an
+    # instance that was never upgraded is stopped too. Run the tree's own
+    # script as the owner of the server *process*, never as root for a
+    # non-root server.
+    SERVER_PID=$(cat "$INSTANCE_ROOT/logs/server.pid" 2>/dev/null || true)
+    if [ -x "%{_prefix}"/bin/stop-ds ] && [ -n "$SERVER_PID" ] && [ -d "/proc/$SERVER_PID" ] ; then
+        OWNER=$(stat -c '%%U' "/proc/$SERVER_PID" 2>/dev/null || echo root)
+        if [ "$OWNER" != root ] && command -v runuser >/dev/null 2>&1 ; then
+            runuser -u "$OWNER" -- "%{_prefix}"/bin/stop-ds || true
+        else
+            "%{_prefix}"/bin/stop-ds || true
+        fi
+        # The package files must not be deleted under a live JVM: verify the
+        # stop happened (the stop errors above are deliberately swallowed).
+        for _i in 1 2 3 4 5 6 7 8 9 10 ; do
+            [ -d "/proc/$SERVER_PID" ] || break
+            sleep 2
+        done
+        if [ -d "/proc/$SERVER_PID" ] ; then
+            echo "Unable to stop the running OpenDJ server (pid $SERVER_PID); stop it manually and retry." >&2
+            exit 1
+        fi
+    fi
+    # A stale restart flag must not survive into a later re-install.
+    rm -f "$INSTANCE_ROOT/logs/status"
     if [ -e /etc/init.d/opendj ] ; then
-        # Deletes the service.
-        /sbin/chkconfig --del opendj
+        /sbin/chkconfig --del opendj || true
     fi
-else if [ "$1" == "1" ] ; then
-    echo "Pre Uninstall - upgrade uninstall"
-    fi
+    # Clean up the legacy PID symlink created by the SysV init script.
+    [ -h /run/opendj.pid ] && rm -f /run/opendj.pid || true
+    [ -h /var/run/opendj.pid ] && rm -f /var/run/opendj.pid || true
 fi
diff --git a/opendj-packages/resources/env/opendj b/opendj-packages/resources/env/opendj
new file mode 100644
index 0000000..a8ecac5
--- /dev/null
+++ b/opendj-packages/resources/env/opendj
@@ -0,0 +1,38 @@
+#
+# The contents of this file are subject to the terms of the Common Development and
+# Distribution License (the License). You may not use this file except in compliance with the
+# License.
+#
+# You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+# specific language governing permission and limitations under the License.
+#
+# When distributing Covered Software, include this CDDL Header Notice in each file and include
+# the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+# Header, with the fields enclosed by brackets [] replaced by your own identifying
+# information: "Portions copyright [year] [name of copyright owner]".
+#
+# Copyright 2026 3A Systems, LLC.
+#
+# Environment overrides for the OpenDJ service.
+#
+# This file is read by the systemd unit (EnvironmentFile=) and parsed by the
+# SysV init script and the package maintainer scripts (package upgrade and
+# restart). It is NOT sourced as shell: only the three OPENDJ_* keys below are
+# recognized, written as KEY=value on a single line (no export, no variable
+# expansion); optional surrounding quotes are stripped by every consumer.
+# By default everything is commented out and the server uses the first java
+# found on the PATH (the package's JRE dependency guarantees one), unless the
+# administrator sets default.java-home in config/java.properties.
+#
+# Uncomment to override the JRE used by the service:
+#   - OPENDJ_JAVA_HOME: a JAVA_HOME directory (its bin/java is used)
+#   - OPENDJ_JAVA_BIN : a direct path to the java binary (takes precedence)
+# Using the stable /usr alternatives symlink survives Java upgrades:
+#
+#OPENDJ_JAVA_HOME=/usr/lib/jvm/default-java
+#OPENDJ_JAVA_BIN=/usr/bin/java
+#
+# JVM args for the server. Note: when set, this REPLACES the java-args
+# configured in config/java.properties (it does not extend them). Quotes are
+# optional but keep values with spaces readable:
+#OPENDJ_JAVA_ARGS="-server -Xmx2g"
diff --git a/opendj-packages/resources/generate-changelog.sh b/opendj-packages/resources/generate-changelog.sh
new file mode 100755
index 0000000..2c415e7
--- /dev/null
+++ b/opendj-packages/resources/generate-changelog.sh
@@ -0,0 +1,144 @@
+#!/usr/bin/env bash
+#
+# The contents of this file are subject to the terms of the Common Development and
+# Distribution License (the License). You may not use this file except in compliance with the
+# License.
+#
+# You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+# specific language governing permission and limitations under the License.
+#
+# When distributing Covered Software, include this CDDL Header Notice in each file and include
+# the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+# Header, with the fields enclosed by brackets [] replaced by your own identifying
+# information: "Portions Copyright [year] [name of copyright owner]".
+#
+# Copyright 2026 3A Systems, LLC
+#
+# Regenerates the Debian and RPM package changelogs from the GitHub Releases of
+# OpenIdentityPlatform/OpenDJ. Run this at release time (it needs network + an
+# authenticated `gh`); the produced files are committed so the Maven build stays
+# offline and reproducible.
+#
+# Usage (from the repository root):
+#   opendj-packages/resources/generate-changelog.sh
+#
+# Requires: gh (authenticated), python3.
+
+set -euo pipefail
+
+REPO="${OPENDJ_REPO:-OpenIdentityPlatform/OpenDJ}"
+HERE="$(cd "$(dirname "$0")" && pwd)"
+DEB_FILE="${HERE}/../opendj-deb/resources/changelog"
+RPM_FILE="${HERE}/../opendj-rpm/resources/changelog"
+
+echo "Fetching releases from ${REPO} ..." >&2
+RELEASES_TMP="$(mktemp)"
+trap 'rm -f "$RELEASES_TMP"' EXIT
+gh api --paginate "repos/${REPO}/releases" > "$RELEASES_TMP" 2>/dev/null
+
+DEB_FILE="${DEB_FILE}" RPM_FILE="${RPM_FILE}" RELEASES_TMP="${RELEASES_TMP}" REPO="${REPO}" python3 - <<'PY'
+import json, os, re, sys, textwrap
+
+with open(os.environ["RELEASES_TMP"]) as _f:
+    releases = json.load(_f)
+
+MAINTAINER = "Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>"
+DOW = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
+MON = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
+       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
+
+def parse_iso(ts):
+    # e.g. 2026-06-11T19:19:48Z -> (Y, M, D, h, m, s, weekday)
+    import datetime
+    dt = datetime.datetime.strptime(ts, "%Y-%m-%dT%H:%M:%SZ")
+    return dt
+
+def clean_bullets(body):
+    bullets = []
+    for raw in (body or "").splitlines():
+        line = raw.strip()
+        if not line.startswith(("* ", "- ")):
+            continue
+        line = line[2:].strip()
+        line = re.sub(r"\[([^\]]+)\]\([^)]+\)", r"\1", line)  # md link -> text
+        line = re.sub(r"\bin https?://\S+", "", line)        # drop PR url
+        line = re.sub(r"https?://\S+", "", line)             # drop bare urls
+        line = re.sub(r"\b(by|thanks)\s+@[\w-]+(\[bot\])?", "", line)  # drop "by/thanks @author"
+        line = re.sub(r"@[\w-]+(\[bot\])?", "", line)        # drop any leftover @mention
+        line = line.replace("**", "").replace("`", "")
+        line = re.sub(r"[←-➿️❤☀-⛿]", "", line)  # emoji/hearts
+        line = re.sub(r"\s+", " ", line).strip(" -")
+        if line:
+            bullets.append(line)
+    return bullets
+
+def version_of(rel):
+    return (rel.get("tag_name") or rel.get("name") or "").lstrip("v").strip()
+
+deb_chunks, rpm_chunks = [], []
+for rel in releases:
+    if rel.get("draft"):
+        continue
+    ver = version_of(rel)
+    if not ver or not ver[0].isdigit():
+        continue
+    dt = parse_iso(rel["published_at"])
+    bullets = clean_bullets(rel.get("body")) or [
+        "See release notes: https://github.com/%s/releases/tag/%s"
+        % (os.environ.get("REPO", "OpenIdentityPlatform/OpenDJ"), ver)
+    ]
+
+    # --- Debian stanza ---
+    # "-1" is the package revision the control file declares (deb.release).
+    deb = ["opendj (%s-1) unstable; urgency=medium" % ver, ""]
+    for b in bullets:
+        wrapped = textwrap.fill(b, width=78, initial_indent="  * ",
+                                subsequent_indent="    ")
+        deb.append(wrapped)
+    deb_date = "%s, %02d %s %d %02d:%02d:%02d +0000" % (
+        DOW[dt.weekday()], dt.day, MON[dt.month - 1], dt.year,
+        dt.hour, dt.minute, dt.second)
+    deb.append("")
+    deb.append(" -- %s  %s" % (MAINTAINER, deb_date))
+    deb_chunks.append("\n".join(deb))
+
+    # --- RPM stanza ---
+    rpm_date = "%s %s %2d %d" % (DOW[dt.weekday()], MON[dt.month - 1], dt.day, dt.year)
+    rpm = ["* %s %s - %s-1" % (rpm_date, MAINTAINER, ver)]
+    for b in bullets:
+        rpm.append(textwrap.fill(b, width=78, initial_indent="- ",
+                                 subsequent_indent="  "))
+    rpm_chunks.append("\n".join(rpm))
+
+with open(os.environ["DEB_FILE"], "w") as f:
+    f.write("\n\n".join(deb_chunks) + "\n")
+
+RPM_PREAMBLE = """#
+# The contents of this file are subject to the terms of the Common Development and
+# Distribution License (the License). You may not use this file except in compliance with the
+# License.
+#
+# You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+# specific language governing permission and limitations under the License.
+#
+# When distributing Covered Software, include this CDDL Header Notice in each file and include
+# the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+# Header, with the fields enclosed by brackets [] replaced by your own identifying
+# information: "Portions Copyright [year] [name of copyright owner]".
+#
+# Copyright 2013-2015 ForgeRock AS.
+# Portions Copyright 2026 3A Systems, LLC.
+
+# =============================
+# opendj rpm package changelog
+# =============================
+
+%changelog
+"""
+with open(os.environ["RPM_FILE"], "w") as f:
+    f.write(RPM_PREAMBLE + "\n".join(rpm_chunks) + "\n")
+
+print("Wrote %d releases to:\n  %s\n  %s"
+      % (len(deb_chunks), os.environ["DEB_FILE"], os.environ["RPM_FILE"]),
+      file=sys.stderr)
+PY
diff --git a/opendj-packages/resources/systemd/opendj.service b/opendj-packages/resources/systemd/opendj.service
new file mode 100644
index 0000000..87e9dae
--- /dev/null
+++ b/opendj-packages/resources/systemd/opendj.service
@@ -0,0 +1,56 @@
+#
+# The contents of this file are subject to the terms of the Common Development and
+# Distribution License (the License). You may not use this file except in compliance with the
+# License.
+#
+# You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+# specific language governing permission and limitations under the License.
+#
+# When distributing Covered Software, include this CDDL Header Notice in each file and include
+# the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+# Header, with the fields enclosed by brackets [] replaced by your own identifying
+# information: "Portions Copyright [year] [name of copyright owner]".
+#
+# Copyright 2026 3A Systems, LLC
+
+[Unit]
+Description=OpenDJ LDAPv3 Directory Server
+Documentation=https://github.com/OpenIdentityPlatform/OpenDJ
+After=network-online.target
+Wants=network-online.target
+# Do not attempt to start (and burst-fail) until the instance has been
+# configured with /opt/opendj/setup. The OR-group (|) also passes when the
+# instance root has been relocated with instance.loc (split layout); the
+# ExecCondition below then checks the resolved instance root precisely.
+ConditionPathExists=|/opt/opendj/config/config.ldif
+ConditionPathExists=|/opt/opendj/instance.loc
+ConditionPathExists=|/etc/opendj/instance.loc
+
+[Service]
+Type=simple
+User=opendj
+Group=opendj
+# Allow the non-root service to bind privileged ports (e.g. LDAP 389, LDAPS 636).
+AmbientCapabilities=CAP_NET_BIND_SERVICE
+CapabilityBoundingSet=CAP_NET_BIND_SERVICE
+# Optional admin overrides (OPENDJ_JAVA_HOME / OPENDJ_JAVA_BIN / OPENDJ_JAVA_ARGS).
+# The leading "-" makes the file optional; deb ships /etc/default, rpm /etc/sysconfig.
+EnvironmentFile=-/etc/default/opendj
+EnvironmentFile=-/etc/sysconfig/opendj
+# Skip the start (a no-op, not a failure) while the instance root - resolved
+# instance.loc-aware, exactly as _script-util.sh does - has no config.ldif
+# yet. "$$" is systemd's escape for a literal "$".
+ExecCondition=/bin/sh -c 'IR=/opt/opendj; if [ -f /etc/opendj/instance.loc ]; then read IR < /etc/opendj/instance.loc; elif [ -f "$$IR/instance.loc" ]; then read L < "$$IR/instance.loc"; case "$$L" in /*) IR="$$L";; *) IR="$$IR/$$L";; esac; fi; [ -f "$$IR/config/config.ldif" ]'
+# start-ds --nodetach keeps the JVM in the foreground so systemd supervises it
+# directly. No --quiet: a failed start must leave its message in the journal.
+ExecStart=/opt/opendj/bin/start-ds --nodetach
+# No ExecStop: the server shuts down gracefully on systemd's default SIGTERM,
+# and stop-ds would only add two cold JVM starts to every stop. Closing a
+# large JE backend can be slow - allow more than the 90 s default.
+TimeoutStopSec=300
+Restart=on-failure
+RestartSec=5
+LimitNOFILE=65536
+
+[Install]
+WantedBy=multi-user.target
diff --git a/opendj-packages/resources/sysv/opendj b/opendj-packages/resources/sysv/opendj
index 579d1dc..7cdd421 100644
--- a/opendj-packages/resources/sysv/opendj
+++ b/opendj-packages/resources/sysv/opendj
@@ -17,6 +17,7 @@
 # information: "Portions Copyright [year] [name of copyright owner]".
 #
 # Copyright 2013-2015 ForgeRock AS.
+# Portions Copyright 2025-2026 3A Systems, LLC
 
 
 # chkconfig: 2345 80 05
@@ -36,58 +37,104 @@
 #                    simplest and fastest directory servers to deploy and manage.
 ### END INIT INFO
 
-# Set up source function library depending on the distribution
-if [ -f /etc/redhat-release ] ; then
-    # Redhat
+# Set up the source function library by checking which one actually exists
+# (detecting the distribution is not enough: e.g. a RHEL-family system without
+# the optional initscripts package has /etc/redhat-release but no functions).
+if [ -f /etc/init.d/functions ] ; then
+    # RedHat-family (initscripts)
     . /etc/init.d/functions
     LOCKFILE=/var/lock/subsys/opendj
-elif [ -f /etc/SuSE-release ] ; then
+elif [ -f /etc/rc.status ] ; then
     # SuSE
     . /etc/rc.status
     LOCKFILE=/var/run/rcopendj
-elif [ -f /etc/lsb-release ] || lsb_release -a >/dev/null 2>&1 ; then
-    # Debian
-    # On Debian 8 the file /etc/lsb-release does not exist. The lsb_release command may be used instead.
+elif [ -f /lib/lsb/init-functions ] ; then
+    # Debian/LSB
     . /lib/lsb/init-functions
     LOCKFILE=/var/lock/opendj
 elif [ -f /etc/init.d/functions.sh ] ; then
     # Other dist.
     . /etc/init.d/functions.sh
     LOCKFILE=/tmp/unused-lockfile-opendj
+else
+    # No init function library: the script is self-contained anyway.
+    LOCKFILE=/tmp/opendj.lockfile
 fi
 # LOCKFILE is used by the service subsystem to know whether the opendj service is started and act upon it
 
 
+# Optional admin overrides (OPENDJ_JAVA_HOME / OPENDJ_JAVA_BIN / OPENDJ_JAVA_ARGS),
+# exported so they survive the runuser switch to the service account in run_as().
+# The same files feed systemd's EnvironmentFile=, whose syntax is not shell (no
+# expansion, optional quotes) - so extract the known keys instead of sourcing.
+for _envfile in /etc/default/opendj /etc/sysconfig/opendj ; do
+    [ -r "$_envfile" ] || continue
+    for _key in OPENDJ_JAVA_HOME OPENDJ_JAVA_BIN OPENDJ_JAVA_ARGS ; do
+        _val=`sed -n "s/^$_key=//p" "$_envfile" | tail -n 1 \
+            | sed -e 's/^"\(.*\)"$/\1/' -e "s/^'\(.*\)'\$/\1/"`
+        [ -n "$_val" ] && export "$_key=$_val"
+    done
+done
+
 # Sets the script vars
 INSTALL_ROOT="/opt/opendj"
 export INSTALL_ROOT
 DAEMON=opendj
 
+# The instance root may have been relocated with instance.loc (split layout):
+# resolve it the way the server scripts (_script-util.sh) do.
+INSTANCE_ROOT="$INSTALL_ROOT"
+if [ -f /etc/opendj/instance.loc ] ; then
+    read INSTANCE_ROOT < /etc/opendj/instance.loc
+elif [ -f "$INSTALL_ROOT/instance.loc" ] ; then
+    read _loc < "$INSTALL_ROOT/instance.loc"
+    case "$_loc" in
+        /*) INSTANCE_ROOT=$_loc ;;
+        *)  INSTANCE_ROOT=$INSTALL_ROOT/$_loc ;;
+    esac
+fi
+
 # Original PID file
-ORIGINPIDFILE=/opt/opendj/logs/server.pid
+ORIGINPIDFILE=$INSTANCE_ROOT/logs/server.pid
 
 # Pid file is a symlink to /opt/opendj/log/server.pid
-PIDFILE=/var/run/opendj.pid
+# /run is the canonical location (/var/run is a compatibility symlink to it).
+PIDFILE=/run/opendj.pid
 RETVAL=0
 
+# The dedicated service account the server runs as (created by the package).
+RUNASUSER=opendj
+
+# Runs the given command as $RUNASUSER when that account exists and we are root;
+# otherwise runs it as the current user (keeps old root-only installs working).
+run_as() {
+    if [ "$(id -un)" = "$RUNASUSER" ] || ! getent passwd "$RUNASUSER" >/dev/null 2>&1 ; then
+        "$@"
+    elif command -v runuser >/dev/null 2>&1 ; then
+        runuser -u "$RUNASUSER" -- "$@"
+    else
+        # Pass the argv through untouched: $1 becomes $0 of the -c script,
+        # the rest arrive as "$@", so arguments with spaces survive.
+        su -s /bin/sh "$RUNASUSER" -c 'exec "$0" "$@"' "$@"
+    fi
+}
+
 # If the daemon is not there, then exit / LSB return code.
 test -x "$INSTALL_ROOT/bin/start-ds" || exit 5
 
 # Recreates the symlink if needed (/var/run is deleted after reboot (eg. debian)).
 test -h "$PIDFILE" || ln -s $ORIGINPIDFILE $PIDFILE
 
+# Succeeds when the instance has been configured with setup. Keyed on
+# buildinfo + config.ldif, not on archived-configs (which can legitimately be
+# empty) - otherwise the runlevel K-script would skip stopping a live server.
 instance_configured() {
-  if [ -f $INSTALL_ROOT/config/buildinfo ] && [ "$(ls -A $INSTALL_ROOT/config/archived-configs)" ] ; then
-      return 1
-  fi
-
-  return 0
+    [ -f "$INSTANCE_ROOT/config/buildinfo" ] && [ -f "$INSTANCE_ROOT/config/config.ldif" ]
 }
 
 # Starts the server and creates pid file.
 start() {
-    instance_configured
-    if [ $? = 0 ] ; then
+    if ! instance_configured ; then
         echo "Instance is not configured. Please run $INSTALL_ROOT/setup"
         return 1
     fi
@@ -98,7 +145,7 @@
         echo "> Already running."
         return 0
     else
-        "$INSTALL_ROOT"/bin/start-ds --quiet
+        run_as "$INSTALL_ROOT"/bin/start-ds --quiet
         RETVAL=$?
         if [ $RETVAL = 0 ] ; then
             touch $LOCKFILE
@@ -113,8 +160,7 @@
 
 # Stops the server and removes pid file.
 stop() {
-    instance_configured
-    if [ $? = 0 ] ; then
+    if ! instance_configured ; then
         echo "Instance is not configured. Please run $INSTALL_ROOT/setup"
         return 1
     fi
@@ -123,7 +169,7 @@
     if [ -e $PIDFILE ]
     then
         # Server is running
-        "$INSTALL_ROOT"/bin/stop-ds --quiet
+        run_as "$INSTALL_ROOT"/bin/stop-ds --quiet
         RETVAL=$?
         if [ $RETVAL = 0 ] ; then
             echo "> SUCCESS."
@@ -142,8 +188,7 @@
 
 # Displays the service status
 status() {
-    instance_configured
-    if [ $? = 0 ] ; then
+    if ! instance_configured ; then
         echo "Instance is not configured. Please run $INSTALL_ROOT/setup"
         return 1
     fi
@@ -166,8 +211,7 @@
         stop
     ;;
     restart)
-        instance_configured
-        if [ $? = 0 ] ; then
+        if ! instance_configured ; then
             echo "Instance is not configured. Please run $INSTALL_ROOT/setup"
             exit 1
         else
diff --git a/opendj-server-legacy/resource/bin/_script-util.sh b/opendj-server-legacy/resource/bin/_script-util.sh
index da3a9e6..5a4fbe3 100644
--- a/opendj-server-legacy/resource/bin/_script-util.sh
+++ b/opendj-server-legacy/resource/bin/_script-util.sh
@@ -40,7 +40,7 @@
 #                                      is defined and 'SCRIPT_NAME.java-home'/bin/java points to a regular file
 # 4 - use the 'default.java-home' property from the config/java.properties file
 #                                      is defined and 'default.java-home'/bin/java points to a regular file
-# 5 - use `which java` command to find java path
+# 5 - use `command -v java` to find java path (POSIX builtin; no dependency on the `which` package)
 # 6 - use JAVA_BIN if defined and points to an existing regular file
 # 7 - use JAVA_HOME if defined and JAVA_HOME/bin/java points to a regural file
 # 8 - Displays an error message which says that java was not found on the running machine
@@ -63,7 +63,7 @@
       then
         OPENDJ_JAVA_BIN=${PROPERTY_VALUE}/bin/java
       else
-        TEST_JAVA_PATH=`which java 2> /dev/null`
+        TEST_JAVA_PATH=`command -v java 2> /dev/null`
         if test ! -z ${TEST_JAVA_PATH} -a -f ${TEST_JAVA_PATH}
         then
           OPENDJ_JAVA_BIN=${TEST_JAVA_PATH}

--
Gitblit v1.10.0