From 87105447624e226db84504d950ea5479d765588f Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Fri, 26 Jun 2026 20:37:29 +0300 Subject: [PATCH 01/52] Add CI job to install-test the Windows MSI The opendj-msi package was built and uploaded but never installed or exercised in CI. Add a test-msi job (needs: build-maven) that, on a windows-latest runner, installs the built .msi silently (msiexec /i), runs setup, registers and starts/stops the OpenDJ Windows service with an ldapsearch liveness check, then uninstalls (msiexec /x). --- .github/workflows/build.yml | 50 +++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 58927fe9e8..29cf33ada0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -441,3 +441,53 @@ jobs: timeout 3m bash -c 'until docker inspect --format="{{json .State.Health.Status}}" test_custom | grep -q \"healthy\"; do sleep 10; done' docker exec test_custom 'sh' '-c' '/opt/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword custom_password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1' docker kill test_custom + + test-msi: + needs: build-maven + runs-on: 'windows-latest' + steps: + - name: Download artifacts + uses: actions/download-artifact@v8 + with: + name: windows-latest-11 + - name: Set up Java + uses: actions/setup-java@v5 + with: + java-version: '21' + distribution: 'zulu' + - name: Install MSI (silent) + shell: pwsh + run: | + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + if (-not $msi) { throw "MSI not found in the windows-latest-11 artifact" } + Write-Host "MSI: $msi" + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart OPENDJ=C:\opendj /l*v install.log" + if ($p.ExitCode -ne 0) { Get-Content install.log -Tail 80; throw "msiexec /i failed: $($p.ExitCode)" } + $root = @("C:\opendj","C:\Program Files (x86)\OpenDJ","C:\Program Files\OpenDJ") | Where-Object { Test-Path "$_\setup.bat" } | Select-Object -First 1 + if (-not $root) { Get-Content install.log -Tail 80; throw "OpenDJ install root with setup.bat not found" } + Write-Host "Installed to $root" + "OPENDJ_ROOT=$root" | Out-File -FilePath $env:GITHUB_ENV -Append + - name: Setup and start/stop the Windows service + shell: pwsh + run: | + $root = $env:OPENDJ_ROOT + $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" + & "$root\setup.bat" -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --addBaseEntry --cli --acceptLicense --no-prompt + if ($LASTEXITCODE -ne 0) { throw "setup.bat failed: $LASTEXITCODE" } + & "$root\bat\windows-service.bat" --enableService + if ($LASTEXITCODE -ne 0) { throw "windows-service --enableService failed: $LASTEXITCODE" } + net start "OpenDJ Server" + if ($LASTEXITCODE -ne 0) { throw "net start failed: $LASTEXITCODE" } + for ($i=0; $i -lt 12; $i++) { try { $c = New-Object System.Net.Sockets.TcpClient('localhost', 1636); $c.Close(); break } catch { Start-Sleep -Seconds 5 } } + & "$root\bat\ldapsearch.bat" --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1 + if ($LASTEXITCODE -ne 0) { throw "ldapsearch failed: $LASTEXITCODE" } + net stop "OpenDJ Server" + if ($LASTEXITCODE -ne 0) { throw "net stop failed: $LASTEXITCODE" } + & "$root\bat\windows-service.bat" --disableService + - name: Uninstall MSI + shell: pwsh + run: | + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall.log" + if ($p.ExitCode -ne 0) { Get-Content uninstall.log -Tail 80; throw "msiexec /x failed: $($p.ExitCode)" } + Write-Host "Uninstalled OK" From 830629c6b44711338863b3d1a54146f6f55c9ab0 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Sun, 28 Jun 2026 11:45:42 +0300 Subject: [PATCH 02/52] Require Java via MSI launch condition; fix test-msi (--doNotStart, JRE 25) The MSI ships no JRE, so add a WiX launch condition that fails the install early with a clear message when Java is not detected (it does not install Java). JAVA_HOME is captured from the environment before LaunchConditions; `Installed` keeps uninstall/repair working regardless of Java. Fix the test-msi CI job (it failed with `net start` exit 2 "service already started"): - setup.bat is now invoked with --doNotStart, so the server is started only by `net start "OpenDJ Server"` (setup.bat no longer starts a standalone instance first). - Bump actions/setup-java from 21 to 25 (latest LTS; smoke-tests the MSI under a fresh JRE). The runner has JAVA_HOME from setup-java, so the new launch condition is satisfied and the install proceeds. --- .github/workflows/build.yml | 4 ++-- .../opendj-msi-standard/resources/msi/package.wxs | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 29cf33ada0..9384c3ad51 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -453,7 +453,7 @@ jobs: - name: Set up Java uses: actions/setup-java@v5 with: - java-version: '21' + java-version: '25' distribution: 'zulu' - name: Install MSI (silent) shell: pwsh @@ -472,7 +472,7 @@ jobs: run: | $root = $env:OPENDJ_ROOT $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" - & "$root\setup.bat" -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --addBaseEntry --cli --acceptLicense --no-prompt + & "$root\setup.bat" -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --addBaseEntry --cli --acceptLicense --no-prompt --doNotStart if ($LASTEXITCODE -ne 0) { throw "setup.bat failed: $LASTEXITCODE" } & "$root\bat\windows-service.bat" --enableService if ($LASTEXITCODE -ne 0) { throw "windows-service --enableService failed: $LASTEXITCODE" } diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 23f4dd4471..9835892c2b 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -13,7 +13,7 @@ ! information: "Portions Copyright [year] [name of copyright owner]". ! ! Copyright 2013-2016 ForgeRock AS. - ! Portion Copyright 2018 Open Identity Platform Community + ! Portions Copyright 2018-2026 3A Systems, LLC ! --> + + + + + + + From 2b2d25d31d520faa51a63b7372a7a6ab44fb069a Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Sun, 28 Jun 2026 23:22:01 +0300 Subject: [PATCH 03/52] remove MSI JAVA_HOME launch condition The launch condition (Installed OR JAVA_HOME_ENV) false-blocked valid installs: a JRE does not always set JAVA_HOME (it may be only on PATH). Drop it - the MSI again only copies files and Java availability stays the admin's responsibility. The test-msi fix (--doNotStart, JRE 25) is unaffected. --- .../opendj-msi-standard/resources/msi/package.wxs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 9835892c2b..f77dda7a14 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -35,15 +35,6 @@ - - - - - - - From 3edfa16347ed34e2ce4c3b448cd848be6a607475 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Sun, 28 Jun 2026 23:22:01 +0300 Subject: [PATCH 04/52] document MSI install/upgrade/uninstall The install guide covered only the .zip and native .deb/.rpm. Add Windows MSI sections to chap-install/chap-upgrade/chap-uninstall: GUI and silent msiexec install, Java as a runtime prerequisite the installer does not enforce, configure via setup.bat, optional Windows service registration via windows-service.bat, MSI upgrade (disable service, back up, install newer .msi, upgrade.bat, re-enable), and uninstall via Apps & features / msiexec /x. --- .../asciidoc/install-guide/chap-install.adoc | 44 +++++++++++++++++ .../install-guide/chap-uninstall.adoc | 29 +++++++++++- .../asciidoc/install-guide/chap-upgrade.adoc | 47 +++++++++++++++++++ 3 files changed, 119 insertions(+), 1 deletion(-) 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 92be08f08a..f976103528 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 @@ -40,6 +40,8 @@ This chapter covers installation of OpenDJ server software and includes the foll * xref:#install-rpm["To Install From the RPM Package"] +* xref:#install-msi["To Install With the Windows Installer (MSI)"] + * xref:#install-properties-file["To Install OpenDJ Directory Server With a Properties File"] * xref:#pdb-to-je["To Move Data from a PDB Backend to a JE Backend"] @@ -635,6 +637,48 @@ opendj 0:off 1:off 2:on 3:on 4:on 5:on 6:off ==== +[#install-msi] +.To Install With the Windows Installer (MSI) +==== +On Windows you can install OpenDJ directory server from the `.msi` package. The installer only copies the server files to disk: it does not configure or start a server, it does not register a Windows service, and it does not install a Java runtime. + +. Make sure a supported Java runtime is available, as described in xref:#before-you-install["To Prepare For Installation"]. ++ +The installer does not check for Java. If your default Java environment is not appropriate, set `OPENDJ_JAVA_HOME` to the correct Java installation (or `OPENDJ_JAVA_BIN` to the absolute path of the `java` command), or make sure `java` is on the `PATH`, before you run `setup` or start the server. + +. Install the package, either with the GUI or silently: ++ +* GUI: double-click `opendj-{opendj-version}.msi` and follow the wizard. ++ +* Silent: run the following command (optionally set the installation directory with the `OPENDJ` property): ++ + +[source, console, subs="attributes"] +---- +C:\> msiexec /i opendj-{opendj-version}.msi /quiet OPENDJ="C:\opendj" +---- ++ +By default the package installs under `C:\Program Files\OpenDJ` (the 32-bit installer uses `C:\Program Files (x86)\OpenDJ` on 64-bit Windows). + +. Configure OpenDJ directory server by running the `setup` command, described in xref:../reference/admin-tools-ref.adoc#setup-1[setup(1)] in the __Reference__, from the installation directory. Use `setup.bat` for the GUI wizard or `setup.bat --cli` for the command-line: ++ + +[source, console] +---- +C:\path\to\opendj> setup.bat --cli +---- + +. (Optional) Register OpenDJ as a Windows service and start it. The MSI does not register the service; use the `windows-service` command: ++ + +[source, console] +---- +C:\path\to\opendj\bat> windows-service.bat --enableService +C:\> net start "OpenDJ Server" +---- + +==== + [#install-properties-file] .To Install OpenDJ Directory Server With a Properties File ==== 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 19cc3a3875..17e0413635 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 @@ -12,7 +12,7 @@ information: "Portions copyright [year] [name of copyright owner]". Copyright 2017 ForgeRock AS. - Portions Copyright 2024 3A Systems LLC. + Portions Copyright 2024-2026 3A Systems LLC. //// :figure-caption!: @@ -33,6 +33,8 @@ This chapter includes the following procedures: * xref:#uninstall-rpm["To Uninstall the RPM Package"] +* xref:#uninstall-msi["To Uninstall the Windows MSI Package"] + [#uninstall-gui] .To Remove OpenDJ With the GUI Uninstaller @@ -157,3 +159,28 @@ Removing the package does not remove your data or configuration. You must remove ==== +[#uninstall-msi] +.To Uninstall the Windows MSI Package +==== +Remove OpenDJ directory server installed from the `.msi` package like any other Windows program. + +. If OpenDJ is registered as a Windows service, remove the service first: ++ + +[source, console] +---- +C:\path\to\opendj\bat> windows-service.bat --disableService +---- + +. Uninstall the package, either through __Settings > Apps__ (or __Control Panel > Programs and Features__) by selecting OpenDJ and choosing Uninstall, or from the command-line: ++ + +[source, console, subs="attributes"] +---- +C:\> msiexec /x opendj-{opendj-version}.msi /quiet +---- ++ +Uninstalling removes the files installed by the package. Your configured instance data under the installation directory (for example `config`, `db`, and `logs`) is not removed; delete the installation directory manually to remove all files. + +==== + 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 cf0268dec0..c514e71c82 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 @@ -45,6 +45,8 @@ This chapter includes the following procedures and examples: * xref:#upgrade-zip-example["Upgrading to OpenDJ {opendj-version-short}"] +* xref:#upgrade-msi["To Upgrade the Windows MSI Installation"] + * xref:#upgrade-repl["To Upgrade Replicated Servers"] * xref:#new-repl-mixed-topology["To Add a New Replica to an Existing Topology"] @@ -243,6 +245,51 @@ $ ---- ==== +[#upgrade-msi] +.To Upgrade the Windows MSI Installation +==== +Before starting this procedure, follow the steps in xref:#before-you-upgrade["Before You Upgrade"]. Installing the newer `.msi` performs a major upgrade that replaces the installed program files, so make a full file-system backup of the current installation first. + +. Stop the current OpenDJ server. + +. If OpenDJ is registered as a Windows service, disable the service: ++ + +[source, console] +---- +C:\path\to\opendj\bat> windows-service.bat --disableService +---- + +. Back up the file-system directory where OpenDJ is installed. + +. Install the newer package (GUI or silent), using the same installation directory as the current server. Your configured instance data (`config`, `db`, `logs`) is kept; only the program files are replaced: ++ + +[source, console, subs="attributes"] +---- +C:\> msiexec /i opendj-{opendj-version}.msi /quiet OPENDJ="C:\path\to\opendj" +---- + +. Run the `upgrade` command, described in xref:../reference/admin-tools-ref.adoc#upgrade-1[upgrade(1)] in the __Reference__, to bring the configuration and application data up to date with the new binary and script files: ++ + +[source, console] +---- +C:\path\to\opendj> upgrade.bat --no-prompt --acceptLicense +---- + +. Start the upgraded OpenDJ server. + +. If you disabled the Windows service, enable it again: ++ + +[source, console] +---- +C:\path\to\opendj\bat> windows-service.bat --enableService +---- + +==== + [#upgrade-repl] .To Upgrade Replicated Servers ==== From f3b7a1561f358d429e481520ed2f88f4272dfc22 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Mon, 29 Jun 2026 15:54:37 +0300 Subject: [PATCH 05/52] Modernize MSI: WiX v5, x64, register service via WiX, drop wine Migrate the Windows MSI off the EOL WiX 3.11.1 (heat/candle/light run under wine + winetricks dotnet40) to the cross-platform WiX v5 .NET tool, and address the MSI validation findings: - package.wxs rewritten to the WiX v4+ schema: single , x64 (ProgramFiles64Folder), MediaTemplate CompressionLevel="high", InstallerVersion=500, directory harvest (replaces heat), and a / on opendj_service.exe so the MSI itself registers the "OpenDJ Server" Windows service (Start=auto, not started during install - setup must configure the instance first). UpgradeCode preserved. - opendj-msi-standard/pom.xml builds the MSI with `wix build -arch x64`; removed the external-dependency-plugin (wix3111 + winetricks), heat/candle/light and the wine/winetricks antrun steps. - opendj-msi/pom.xml: wine-path profiles replaced by an unconditional module so the MSI builds natively on every OS where opendj-msi is included. - build.yml: drop wine (keep rpm); add a "Setup WiX (.NET tool)" step; test-msi no longer calls windows-service.bat --enableService (the MSI registers it). - install guide: x64 install path; the MSI registers the service. Signing (#4) deferred (no certificate). The Burn bundle that auto-installs a JRE is a follow-up, to be added after this MSI build is validated in CI. --- .github/workflows/build.yml | 23 +- .../asciidoc/install-guide/chap-install.adoc | 7 +- .../opendj-msi/opendj-msi-standard/pom.xml | 288 +++++------------- .../resources/msi/package.wxs | 83 +++-- opendj-packages/opendj-msi/pom.xml | 65 +--- 5 files changed, 138 insertions(+), 328 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9384c3ad51..3f65adc5b2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,19 +28,12 @@ jobs: os: [ 'ubuntu-latest', 'macos-latest', 'windows-latest' ] fail-fast: false steps: - - name: Install wine+rpm for distribution + - name: Install rpm for distribution if: runner.os == 'Linux' shell: bash run: | - sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list - sudo dpkg --add-architecture i386 - sudo mkdir -pm755 /etc/apt/keyrings && sudo wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key - sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/$(lsb_release -c -s)/winehq-$(lsb_release -c -s).sources sudo apt-get update - sudo apt install --install-recommends winehq-stable || sudo apt install --install-recommends winehq-staging - wine --version - version="9.4.0"; sudo wget "https://dl.winehq.org/wine/wine-mono/$version/wine-mono-$version-x86.msi" -O /tmp/wine-mono.msi - wine msiexec /i /tmp/wine-mono.msi + sudo apt-get install -y rpm - uses: actions/checkout@v6 with: fetch-depth: 0 @@ -79,6 +72,14 @@ jobs: run: | echo "MAVEN_PROFILE_FLAG=-P precommit" >> $GITHUB_OUTPUT + - name: Setup WiX (.NET tool) for MSI + shell: bash + run: | + dotnet tool install --global wix --version 5.0.2 || dotnet tool update --global wix --version 5.0.2 + echo "$HOME/.dotnet/tools" >> "$GITHUB_PATH" + export PATH="$HOME/.dotnet/tools:$PATH" + wix --version + wix extension add -g WixToolset.UI.wixext/5.0.2 || true - name: Build with Maven timeout-minutes: 180 env: @@ -474,8 +475,7 @@ jobs: $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" & "$root\setup.bat" -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --addBaseEntry --cli --acceptLicense --no-prompt --doNotStart if ($LASTEXITCODE -ne 0) { throw "setup.bat failed: $LASTEXITCODE" } - & "$root\bat\windows-service.bat" --enableService - if ($LASTEXITCODE -ne 0) { throw "windows-service --enableService failed: $LASTEXITCODE" } + # The service is already registered by the MSI (WiX ServiceInstall); just start it. net start "OpenDJ Server" if ($LASTEXITCODE -ne 0) { throw "net start failed: $LASTEXITCODE" } for ($i=0; $i -lt 12; $i++) { try { $c = New-Object System.Net.Sockets.TcpClient('localhost', 1636); $c.Close(); break } catch { Start-Sleep -Seconds 5 } } @@ -483,7 +483,6 @@ jobs: if ($LASTEXITCODE -ne 0) { throw "ldapsearch failed: $LASTEXITCODE" } net stop "OpenDJ Server" if ($LASTEXITCODE -ne 0) { throw "net stop failed: $LASTEXITCODE" } - & "$root\bat\windows-service.bat" --disableService - name: Uninstall MSI shell: pwsh run: | 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 f976103528..66e9f855b6 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 @@ -640,7 +640,7 @@ opendj 0:off 1:off 2:on 3:on 4:on 5:on 6:off [#install-msi] .To Install With the Windows Installer (MSI) ==== -On Windows you can install OpenDJ directory server from the `.msi` package. The installer only copies the server files to disk: it does not configure or start a server, it does not register a Windows service, and it does not install a Java runtime. +On Windows you can install OpenDJ directory server from the `.msi` package. The installer copies the server files to disk and registers the `OpenDJ Server` Windows service, but it does not configure or start a server (run `setup` first) and it does not install a Java runtime. . Make sure a supported Java runtime is available, as described in xref:#before-you-install["To Prepare For Installation"]. + @@ -658,7 +658,7 @@ The installer does not check for Java. If your default Java environment is not a C:\> msiexec /i opendj-{opendj-version}.msi /quiet OPENDJ="C:\opendj" ---- + -By default the package installs under `C:\Program Files\OpenDJ` (the 32-bit installer uses `C:\Program Files (x86)\OpenDJ` on 64-bit Windows). +By default the x64 package installs under `C:\Program Files\OpenDJ`. . Configure OpenDJ directory server by running the `setup` command, described in xref:../reference/admin-tools-ref.adoc#setup-1[setup(1)] in the __Reference__, from the installation directory. Use `setup.bat` for the GUI wizard or `setup.bat --cli` for the command-line: + @@ -668,12 +668,11 @@ By default the package installs under `C:\Program Files\OpenDJ` (the 32-bit inst C:\path\to\opendj> setup.bat --cli ---- -. (Optional) Register OpenDJ as a Windows service and start it. The MSI does not register the service; use the `windows-service` command: +. Start the OpenDJ Windows service. The installer already registered it as `OpenDJ Server`; after configuring with `setup`, start it (it is not started automatically during installation): + [source, console] ---- -C:\path\to\opendj\bat> windows-service.bat --enableService C:\> net start "OpenDJ Server" ---- diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml b/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml index 9b4bf07b7e..0c89fea8c7 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml +++ b/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml @@ -13,7 +13,7 @@ information: "Portions Copyright [year] [name of copyright owner]". Copyright 2015-2016 ForgeRock AS. - Portions Copyright 2018 Open Identity Platform Community + Portions Copyright 2018-2026 3A Systems, LLC --> 4.0.0 @@ -29,265 +29,113 @@ OpenDJ MSI Standard Package - This module generates an OpenDJ MSI package. + This module generates an OpenDJ MSI package using the WiX Toolset v5 .NET tool + (cross-platform; no wine). The `wix` tool must be on the PATH (CI installs it via + `dotnet tool install --global wix`). ${basedir}/resources/msi ${project.build.directory}/${product.name.lowercase} + ${project.build.directory}/msi-staging + ${project.build.directory}/${product.name.lowercase}-${project.version}.msi + 5.0.2 - - - + + ${project.groupId}.${project.artifactId} + org.codehaus.mojo build-helper-maven-plugin - - - - org.openidentityplatform.commons - maven-external-dependency-plugin - false - - - ${project.build.directory}/dependencies/ - - false - true - false - - - openidentityplatform.org - wixtoolset - 3.11.1 - zip - - https://github.com/wixtoolset/wix3/releases/download/wix3111rtm/wix311-binaries.zip - - false - - - openidentityplatform.org - winetricks - LAST - sh - - https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks - - false - - - - - - clean-external-dependencies - clean - - clean-external - - - - resolve-install-external-dependencies - process-resources - - resolve-external - install-external - - - - deploy-external-dependencies - deploy - - deploy-external - - - - - - org.apache.maven.plugins - maven-dependency-plugin - unpack-wix - package - - unpack - - - - - openidentityplatform.org - wixtoolset - 3.11.1 - zip - - - - ${project.build.directory}/wix - - - - - unpack-winetricks + attach-msi-and-bundle package - copy + attach-artifact - - - openidentityplatform.org - winetricks - LAST - sh - - - - ${project.build.directory}/winetricks - + + ${msi.file}msi + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + org.apache.maven.plugins maven-antrun-plugin - build-msi-package-prepare + stage-msi-payload package run - - - + + + - - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ------------------- ${exec.heat} ${param.heat} ------------------- - - - - - - - - - - - - - - - - ------------------- ${exec.candle} ${param.candle} ------------------- - - - - - - - - - - - - - ------------------- ${exec.light} ${param.light} ------------------- - - - - - - - - - - - - - - - - - + + + + org.codehaus.mojo + exec-maven-plugin + + + wix-build-msi + package + + exec + + + wix + ${project.build.directory} + + build + ${msi.resources}/package.wxs + -archx64 + -extWixToolset.UI.wixext + -bindpath${msi.resources} + -dname=${product.name} + -dmajor=${parsedVersion.majorVersion} + -dminor=${parsedVersion.minorVersion} + -dpoint=${parsedVersion.incrementalVersion} + -dstaging=${staging.dir} + -o${msi.file} + + + + + - \ No newline at end of file + diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index f77dda7a14..6e6db00722 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -15,45 +15,62 @@ ! Copyright 2013-2016 ForgeRock AS. ! Portions Copyright 2018-2026 3A Systems, LLC ! --> - - - - - - - + + + + + + + + - - + + - - - - - - - + + + + - + + + + + + + + + + + + + + + + - - + + + + - - - - - - - NOT Installed - 1 - - + + + diff --git a/opendj-packages/opendj-msi/pom.xml b/opendj-packages/opendj-msi/pom.xml index f652541ac6..3a697e73f4 100644 --- a/opendj-packages/opendj-msi/pom.xml +++ b/opendj-packages/opendj-msi/pom.xml @@ -32,63 +32,10 @@ This module contains configuration and generic plugin call to build OpenDJ MSI packages. - - - /usr/bin/wine - - unix - /usr/bin/wine - - - opendj-msi-standard - - - /usr/bin/wine${project.build.directory}/wix/heat.exe - /usr/bin/wine${project.build.directory}/wix/candle.exe - /usr/bin/wine${project.build.directory}/wix/light.exe - - - - /usr/local/bin/wine - - unix - /usr/local/bin/wine - - - opendj-msi-standard - - - /usr/local/bin/wine${project.build.directory}/wix/heat.exe - /usr/local/bin/wine${project.build.directory}/wix/candle.exe - /usr/local/bin/wine${project.build.directory}/wix/light.exe - - - - /opt/local/bin/wine - - unix - /opt/local/bin/wine - - - opendj-msi-standard - - - /opt/local/bin/wine${project.build.directory}/wix/heat.exe - /opt/local/bin/wine${project.build.directory}/wix/candle.exe - /opt/local/bin/wine${project.build.directory}/wix/light.exe - - - - windows - windows - - opendj-msi-standard - - - ${project.build.directory}\wix\heat.exe - ${project.build.directory}\wix\candle.exe - ${project.build.directory}\wix\light.exe - - - + + + opendj-msi-standard + From f92565627ecc4aee61993d732d885c729c56a8b3 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Mon, 29 Jun 2026 15:59:23 +0300 Subject: [PATCH 06/52] Fix MSI CI: DOTNET_ROLL_FORWARD=Major so the net6.0 wix tool runs WiX 5 ships as a net6.0 .NET tool, but the runners only have a newer .NET runtime (no .NET 6), so 'wix' failed to launch (exit 131, missing_runtime) on arm64 macOS. Set DOTNET_ROLL_FORWARD=Major in the Setup WiX step (exported and written to GITHUB_ENV) so the tool rolls forward to the installed runtime, both for that step and the Maven build that invokes 'wix build'. --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3f65adc5b2..0a24aa407e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -75,6 +75,9 @@ jobs: - name: Setup WiX (.NET tool) for MSI shell: bash run: | + # WiX 5 ships as a net6.0 tool; allow it to run on the newer .NET runtime present on the runners. + echo "DOTNET_ROLL_FORWARD=Major" >> "$GITHUB_ENV" + export DOTNET_ROLL_FORWARD=Major dotnet tool install --global wix --version 5.0.2 || dotnet tool update --global wix --version 5.0.2 echo "$HOME/.dotnet/tools" >> "$GITHUB_PATH" export PATH="$HOME/.dotnet/tools:$PATH" From 60364d50000b6eb34922378388835d7137393607 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Mon, 29 Jun 2026 16:12:17 +0300 Subject: [PATCH 07/52] Fix MSI build: WiX v5 Files child Exclude; .NET runtime for wix on macOS wix build failed with WIX0004 ('Files element contains an unexpected attribute Exclude'): in WiX 5.0.2 exclusion is a child element (with ), not an inline attribute. Convert both harvests to the child-element form. macOS (arm64) runners have no .NET runtime for the net6.0 wix apphost (DOTNET_ROOT unset, exit 131); add actions/setup-dotnet (8.0.x) on macOS so the tool finds a runtime and rolls forward. --- .github/workflows/build.yml | 5 +++++ .../opendj-msi-standard/resources/msi/package.wxs | 10 ++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0a24aa407e..0e3a276dec 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -72,6 +72,11 @@ jobs: run: | echo "MAVEN_PROFILE_FLAG=-P precommit" >> $GITHUB_OUTPUT + - name: Setup .NET runtime for WiX (macOS) + if: runner.os == 'macOS' + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' - name: Setup WiX (.NET tool) for MSI shell: bash run: | diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 6e6db00722..7e24a13621 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -58,10 +58,16 @@ - + + + + - + + + + From 8571e3d9c53fdd1408aefb2f31c986c851e52461 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Mon, 29 Jun 2026 16:53:42 +0300 Subject: [PATCH 08/52] Fix MSI build: do Files exclusions in Ant staging (WiX 5 Files takes only Include) WiX 5.0.2 requires Include as an attribute on and rejects an Exclude attribute as well as / child elements (WIX0004/0005/0010). Move all exclusions to the Ant staging step: stagingRoot = payload minus lib (and macOS/Unix bits), stagingLib = lib minus opendj_service.exe (registered via an explicit component sourced from the package dir). Each now uses only the Include attribute, and there is no duplicate lib directory. --- .../opendj-msi/opendj-msi-standard/pom.xml | 28 +++++++++++++++---- .../resources/msi/package.wxs | 17 ++++------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml b/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml index 0c89fea8c7..c1eb2ff709 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml +++ b/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml @@ -37,7 +37,11 @@ ${basedir}/resources/msi ${project.build.directory}/${product.name.lowercase} - ${project.build.directory}/msi-staging + + ${project.build.directory}/msi-staging + ${project.build.directory}/msi-staging-lib + ${package.dir}/lib/opendj_service.exe ${project.build.directory}/${product.name.lowercase}-${project.version}.msi 5.0.2 @@ -86,19 +90,31 @@ - - - + + + + + + + + + + + + + + @@ -129,7 +145,9 @@ -dmajor=${parsedVersion.majorVersion} -dminor=${parsedVersion.minorVersion} -dpoint=${parsedVersion.incrementalVersion} - -dstaging=${staging.dir} + -dstagingRoot=${staging.root} + -dstagingLib=${staging.lib} + -dserviceExe=${service.exe} -o${msi.file} diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 7e24a13621..2866f91801 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -46,7 +46,7 @@ Registered here, but NOT started during install (the instance must be configured by setup.bat first). --> - + - + - - - - + - - - - + From 7ebd48bc45e1258502efea744a0a1ce470a4e5bf Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Wed, 1 Jul 2026 15:13:01 +0300 Subject: [PATCH 09/52] Use forward slashes in WiX Files Include (test non-Windows wix build) On Linux/macOS the wix tool treats backslash as a literal, not a path separator, which may cascade into the WIX0389 'not a relative path' errors. Use '/**' (accepted on Windows too) to test whether the cross-platform wix build then succeeds. --- .../opendj-msi/opendj-msi-standard/resources/msi/package.wxs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 2866f91801..520121247f 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -59,10 +59,10 @@ needs only the Include attribute (WiX 5 requires it; no Exclude here): stagingRoot has everything except lib; stagingLib has lib minus the service wrapper. --> - + - + From 8e297c034cc08b127dc451aedc9deb65e831ea40 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Wed, 1 Jul 2026 15:50:24 +0300 Subject: [PATCH 10/52] Build the MSI on Windows only (WiX cannot author MSIs on Linux/macOS) The WiX Toolset can create MSI databases on Windows only: it warns "only supports Windows" and, on Linux/macOS, fails with WIX0389 on every Directory name and (with no name) on a missing msi.dll (the Windows Installer library). Verified locally on macOS with WiX 5.0.2, 6.0.1 and 7.0.0 - none can build. - opendj-packages/pom.xml: build opendj-msi only in the distribution-windows profile (removed from distribution-unix and distribution-mac). - build.yml: run the WiX setup step only on Windows; drop macOS setup-dotnet. - package.wxs: keep the Windows-proven backslash glob in . - .gitattributes: force LF for *.wxs/*.wxi. --- .gitattributes | 3 +++ .github/workflows/build.yml | 9 +++------ .../opendj-msi-standard/resources/msi/package.wxs | 4 ++-- opendj-packages/pom.xml | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..2676ab14f7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# WiX sources must stay LF so the WiX toolset parses them consistently across runners. +*.wxs text eol=lf +*.wxi text eol=lf diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0e3a276dec..e1136a25e9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -72,15 +72,12 @@ jobs: run: | echo "MAVEN_PROFILE_FLAG=-P precommit" >> $GITHUB_OUTPUT - - name: Setup .NET runtime for WiX (macOS) - if: runner.os == 'macOS' - uses: actions/setup-dotnet@v4 - with: - dotnet-version: '8.0.x' - name: Setup WiX (.NET tool) for MSI + if: runner.os == 'Windows' shell: bash run: | - # WiX 5 ships as a net6.0 tool; allow it to run on the newer .NET runtime present on the runners. + # The MSI builds on Windows only (WiX cannot author MSIs on Linux/macOS). WiX 5 ships as a + # net6.0 tool; allow it to run on the newer .NET runtime present on the runner. echo "DOTNET_ROLL_FORWARD=Major" >> "$GITHUB_ENV" export DOTNET_ROLL_FORWARD=Major dotnet tool install --global wix --version 5.0.2 || dotnet tool update --global wix --version 5.0.2 diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 520121247f..2866f91801 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -59,10 +59,10 @@ needs only the Include attribute (WiX 5 requires it; no Exclude here): stagingRoot has everything except lib; stagingLib has lib minus the service wrapper. --> - + - + diff --git a/opendj-packages/pom.xml b/opendj-packages/pom.xml index 739e77779f..83d43d7ec0 100644 --- a/opendj-packages/pom.xml +++ b/opendj-packages/pom.xml @@ -55,7 +55,6 @@ opendj-deb opendj-rpm opendj-svr4 - opendj-msi opendj-docker @@ -69,7 +68,6 @@ opendj-svr4 - opendj-msi opendj-docker @@ -79,6 +77,8 @@ windows + opendj-msi opendj-docker From a3e3d00f580eb5dbad7cf719c68a0fd952d3383e Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Thu, 2 Jul 2026 15:13:40 +0300 Subject: [PATCH 11/52] Publish the Windows MSI in release/deploy without rebuilding the server The MSI can only be built on Windows. Instead of rebuilding opendj-server-legacy on a Windows runner: - deploy.yml: reuse the MSI already built by the triggering Build run (download the windows-latest-11 artifact, re-upload as "OpenDJ MSI Package"); both steps continue-on-error; drop wine (rpm only). - release.yml: release-maven uploads the released server zip as an artifact; new release-msi job (windows, continue-on-error so an MSI failure does not break the release) installs the zip into the local Maven repository and only packages :opendj-msi-standard (no -am), then attaches the MSI to the GitHub release; drop the .msi from the ubuntu release file list; drop wine. --- .github/workflows/deploy.yml | 25 ++++++----- .github/workflows/release.yml | 80 ++++++++++++++++++++++++++++++----- 2 files changed, 85 insertions(+), 20 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 8b56d45faa..723c8606be 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -14,19 +14,12 @@ jobs: env: GITHUB_CONTEXT: ${{ toJSON(github) }} run: echo "$GITHUB_CONTEXT" - - name: Install wine+rpm for distribution + - name: Install rpm for distribution if: runner.os == 'Linux' shell: bash run: | - sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list - sudo dpkg --add-architecture i386 - sudo mkdir -pm755 /etc/apt/keyrings && sudo wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key - sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/$(lsb_release -c -s)/winehq-$(lsb_release -c -s).sources sudo apt-get update - sudo apt install --install-recommends winehq-stable || sudo apt install --install-recommends winehq-staging - wine --version - version="9.4.0"; sudo wget "https://dl.winehq.org/wine/wine-mono/$version/wine-mono-$version-x86.msi" -O /tmp/wine-mono.msi - wine msiexec /i /tmp/wine-mono.msi + sudo apt-get install -y rpm - uses: actions/checkout@v6 with: fetch-depth: 0 @@ -90,11 +83,22 @@ jobs: with: name: OpenDJ RPM Package path: opendj-packages/opendj-rpm/opendj-rpm-standard/target/rpm/opendj/RPMS/noarch/*.rpm + # The MSI can only be built on Windows; reuse the one already built by the triggering + # Build run (windows-latest-11 artifact) instead of rebuilding it here. + - name: Download Windows build artifact (contains the MSI) + continue-on-error: true + uses: actions/download-artifact@v8 + with: + name: windows-latest-11 + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + path: windows-build - name: Upload artifacts OpenDJ MSI Package + continue-on-error: true uses: actions/upload-artifact@v7 with: name: OpenDJ MSI Package - path: opendj-packages/opendj-msi/opendj-msi-standard/target/*.msi + path: windows-build/opendj-packages/opendj-msi/opendj-msi-standard/target/*.msi - name: Upload artifacts OpenDJ Docker Packages uses: actions/upload-artifact@v7 with: @@ -169,3 +173,4 @@ jobs: git commit -a -m "upload ${{github.event.repository.name}} docs after deploy ${{ github.sha }}" git push --force https://github.com/OpenIdentityPlatform/doc.openidentityplatform.org.git fi + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 41bb3bc8b0..1533fc5d3a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,18 +19,11 @@ jobs: env: GITHUB_CONTEXT: ${{ toJSON(github) }} run: echo "$GITHUB_CONTEXT" - - name: Install wine+rpm for distribution + - name: Install rpm for distribution shell: bash run: | - sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list - sudo dpkg --add-architecture i386 - sudo mkdir -pm755 /etc/apt/keyrings && sudo wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key - sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/$(lsb_release -c -s)/winehq-$(lsb_release -c -s).sources sudo apt-get update - sudo apt install --install-recommends winehq-stable || sudo apt install --install-recommends winehq-staging - wine --version - version="9.4.0"; sudo wget "https://dl.winehq.org/wine/wine-mono/$version/wine-mono-$version-x86.msi" -O /tmp/wine-mono.msi - wine msiexec /i /tmp/wine-mono.msi + sudo apt-get install -y rpm - uses: actions/checkout@v6 with: fetch-depth: 0 @@ -70,6 +63,15 @@ jobs: MAVEN_OPTS: -Dhttps.protocols=TLSv1.2 -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.requestSentEnabled=true -Dmaven.wagon.http.retryHandler.count=10 if: ${{ env.MAVEN_USERNAME!='' && env.MAVEN_PASSWORD!='' }} run: mvn --batch-mode -Darguments="-Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }}" -DsignTag=true -DtagNameFormat="${{ github.event.inputs.releaseVersion }}" -DreleaseVersion=${{ github.event.inputs.releaseVersion }} -DdevelopmentVersion=${{ github.event.inputs.developmentVersion }} release:prepare release:perform --file pom.xml + # Hand the just-released server zip to the release-msi job (the MSI can only be + # built on Windows), so it does not have to rebuild opendj-server-legacy. + - name: Upload the server zip for the MSI job + continue-on-error: true + uses: actions/upload-artifact@v7 + with: + name: release-server-zip + retention-days: 1 + path: target/checkout/opendj-server-legacy/target/package/*.zip - name: Release on GitHub uses: softprops/action-gh-release@v2 with: @@ -84,7 +86,6 @@ jobs: target/checkout/opendj-ldap-toolkit/target/*.zip target/checkout/opendj-packages/opendj-deb/opendj-deb-standard/target/*.deb target/checkout/opendj-packages/opendj-rpm/opendj-rpm-standard/target/rpm/opendj/RPMS/noarch/*.rpm - target/checkout/opendj-packages/opendj-msi/opendj-msi-standard/target/*.msi target/checkout/opendj-packages/opendj-docker/target/Dockerfile.zip target/checkout/opendj-packages/opendj-openshift-template/*.yaml target/checkout/opendj-doc-generated-ref/target/*.zip @@ -130,6 +131,65 @@ jobs: git tag -f ${TAG_NAME} git push --quiet --force origin ${TAG_NAME} + # The MSI can only be built on Windows. Reuses the server zip built by release-maven + # (installed into the local repo), so only the opendj-msi-standard module is built here. + # continue-on-error: an MSI failure must not break the release. + release-msi: + name: Windows MSI release + runs-on: 'windows-latest' + continue-on-error: true + needs: + - release-maven + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ github.event.inputs.releaseVersion }} + submodules: recursive + - name: Set up Java + uses: actions/setup-java@v5 + with: + java-version: '11' + distribution: 'temurin' + - name: Cache Maven packages + uses: actions/cache@v5 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-m2-repository-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2-repository + - name: Setup WiX (.NET tool) + shell: bash + run: | + echo "DOTNET_ROLL_FORWARD=Major" >> "$GITHUB_ENV" + export DOTNET_ROLL_FORWARD=Major + dotnet tool install --global wix --version 5.0.2 || dotnet tool update --global wix --version 5.0.2 + echo "$HOME/.dotnet/tools" >> "$GITHUB_PATH" + export PATH="$HOME/.dotnet/tools:$PATH" + wix --version + wix extension add -g WixToolset.UI.wixext/5.0.2 || true + - name: Download the server zip built by release-maven + uses: actions/download-artifact@v8 + with: + name: release-server-zip + path: server-zip + - name: Install the server zip into the local Maven repository + shell: bash + run: | + ZIP=$(ls server-zip/*.zip | head -1) + echo "Installing $ZIP as opendj-server-legacy:${{ github.event.inputs.releaseVersion }}:zip" + mvn --batch-mode install:install-file -Dfile="$ZIP" \ + -DgroupId=org.openidentityplatform.opendj -DartifactId=opendj-server-legacy \ + -Dversion=${{ github.event.inputs.releaseVersion }} -Dpackaging=zip + - name: Build the MSI (packaging only, no rebuild) + env: + MAVEN_OPTS: -Dhttps.protocols=TLSv1.2 -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.requestSentEnabled=true -Dmaven.wagon.http.retryHandler.count=10 + run: mvn --batch-mode --errors -DskipTests package -pl :opendj-msi-standard --file pom.xml + - name: Attach the MSI to the GitHub release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ github.event.inputs.releaseVersion }} + fail_on_unmatched_files: true + files: opendj-packages/opendj-msi/opendj-msi-standard/target/*.msi + release-docker: name: Docker release runs-on: 'ubuntu-latest' From 431b69343540e879b99bdb9ae83a36f1dc5c69aa Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Thu, 2 Jul 2026 15:39:48 +0300 Subject: [PATCH 12/52] MSI: require a JRE at install, upgrade over existing installs, replace legacy service - package.wxs: refuse to install when no Java is detectable (JAVA_HOME\bin\java.exe or java-looking PATH entries; MSI cannot scan PATH, so substring heuristic) with a message pointing at https://adoptium.net; detect an existing install (InstallDir registry value written by this package, else the legacy x86 default directory) and apply it only when OPENDJ is not set explicitly; drop the legacy windows-service.bat "OpenDJ Server" service before InstallServices (its display name collides with the MSI ServiceInstall). - build.yml: test-msi asserts the installer fails without a JRE before one is set up; new test-win-upgrade installs the released 5.1.1 x86 MSI, configures an instance with the legacy service, upgrades with the newly built x64 MSI without OPENDJ and asserts same directory, intact data, MSI-managed service, then runs upgrade.bat, starts the service and searches the pre-upgrade data. - docs: Java is required by the installer (adoptium.net link); MSI upgrade autodetects the directory and replaces the service; uninstall removes the service automatically. --- .github/workflows/build.yml | 81 +++++++++++++++++++ .../asciidoc/install-guide/chap-install.adoc | 2 +- .../install-guide/chap-uninstall.adoc | 12 +-- .../asciidoc/install-guide/chap-upgrade.adoc | 20 ++--- .../resources/msi/package.wxs | 44 ++++++++++ 5 files changed, 134 insertions(+), 25 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e1136a25e9..4cd47cddf5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -456,6 +456,18 @@ jobs: uses: actions/download-artifact@v8 with: name: windows-latest-11 + - name: Install must fail without a JRE + shell: pwsh + run: | + # Simulate a machine with no Java: clear JAVA_HOME and strip java-looking PATH entries. + $env:JAVA_HOME = "" + $env:PATH = (($env:PATH -split ';') | Where-Object { $_ -notmatch 'java|jdk|jre|zulu|javapath' }) -join ';' + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + if (-not $msi) { throw "MSI not found in the windows-latest-11 artifact" } + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v install-nojre.log" + if ($p.ExitCode -eq 0) { throw "installer succeeded without a JRE, but the Java launch condition must fail it" } + Write-Host "Installer refused to install without a JRE as expected (exit $($p.ExitCode))" + Select-String -Path install-nojre.log -Pattern "requires Java" | Select-Object -First 1 - name: Set up Java uses: actions/setup-java@v5 with: @@ -495,3 +507,72 @@ jobs: $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall.log" if ($p.ExitCode -ne 0) { Get-Content uninstall.log -Tail 80; throw "msiexec /x failed: $($p.ExitCode)" } Write-Host "Uninstalled OK" + + # Upgrade path: released 5.1.1 x86 MSI (wine-built, WiX3) -> this build's x64 MSI. + # Verifies the new installer detects the legacy Program Files (x86) install, keeps the + # instance data in place, replaces the windows-service.bat service with the MSI-managed + # one, and the upgraded server starts with the old data. + test-win-upgrade: + needs: build-maven + runs-on: 'windows-latest' + steps: + - name: Download artifacts + uses: actions/download-artifact@v8 + with: + name: windows-latest-11 + - name: Set up Java + uses: actions/setup-java@v5 + with: + java-version: '25' + distribution: 'zulu' + - name: Install released 5.1.1 MSI and configure an instance + shell: pwsh + run: | + Invoke-WebRequest -Uri "https://github.com/OpenIdentityPlatform/OpenDJ/releases/download/5.1.1/opendj-5.1.1.msi" -OutFile opendj-5.1.1.msi + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.1.msi /quiet /qn /norestart /l*v install-old.log" + if ($p.ExitCode -ne 0) { Get-Content install-old.log -Tail 80; throw "msiexec /i (5.1.1) failed: $($p.ExitCode)" } + $root = "C:\Program Files (x86)\OpenDJ" + if (-not (Test-Path "$root\setup.bat")) { Get-Content install-old.log -Tail 80; throw "5.1.1 install root not found at $root" } + $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" + & "$root\setup.bat" -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --addBaseEntry --cli --acceptLicense --no-prompt --doNotStart + if ($LASTEXITCODE -ne 0) { throw "setup.bat (5.1.1) failed: $LASTEXITCODE" } + # Register the LEGACY service the pre-MSI way and prove it works, then stop it. + & "$root\bat\windows-service.bat" --enableService + if ($LASTEXITCODE -ne 0) { throw "windows-service --enableService failed: $LASTEXITCODE" } + net start "OpenDJ Server" + if ($LASTEXITCODE -ne 0) { throw "net start (5.1.1) failed: $LASTEXITCODE" } + net stop "OpenDJ Server" + if ($LASTEXITCODE -ne 0) { throw "net stop (5.1.1) failed: $LASTEXITCODE" } + - name: Upgrade with the newly built MSI (no OPENDJ property - must auto-detect) + shell: pwsh + run: | + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + if (-not $msi) { throw "MSI not found in the windows-latest-11 artifact" } + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade.log" + if ($p.ExitCode -ne 0) { Get-Content upgrade.log -Tail 120; throw "msiexec /i (upgrade) failed: $($p.ExitCode)" } + $root = "C:\Program Files (x86)\OpenDJ" + # New package files landed in the legacy directory, not the x64 default + if (-not (Test-Path "$root\setup.bat")) { throw "upgrade did not keep the legacy install dir" } + if (Test-Path "C:\Program Files\OpenDJ") { throw "upgrade unexpectedly installed into the x64 default dir" } + # Instance data survived + if (-not (Test-Path "$root\config\config.ldif")) { throw "instance data (config\config.ldif) lost by the upgrade" } + # Legacy service replaced by the MSI-managed one: display name maps to key 'OpenDJ' + $key = (sc.exe getkeyname "OpenDJ Server" | Select-String -Pattern "Name = (.+)").Matches[0].Groups[1].Value.Trim() + if ($key -ne "OpenDJ") { sc.exe query; throw "expected MSI-managed service key 'OpenDJ', got '$key'" } + sc.exe qc OpenDJ + "OPENDJ_ROOT=$root" | Out-File -FilePath $env:GITHUB_ENV -Append + - name: Run upgrade.bat and start the upgraded server + shell: pwsh + run: | + $root = $env:OPENDJ_ROOT + $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" + & "$root\upgrade.bat" --no-prompt --acceptLicense --force + if ($LASTEXITCODE -ne 0) { throw "upgrade.bat failed: $LASTEXITCODE" } + net start "OpenDJ Server" + if ($LASTEXITCODE -ne 0) { throw "net start (upgraded) failed: $LASTEXITCODE" } + for ($i=0; $i -lt 12; $i++) { try { $c = New-Object System.Net.Sockets.TcpClient('localhost', 1636); $c.Close(); break } catch { Start-Sleep -Seconds 5 } } + # The pre-upgrade data must still be served + & "$root\bat\ldapsearch.bat" --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1 + if ($LASTEXITCODE -ne 0) { throw "ldapsearch after upgrade failed: $LASTEXITCODE" } + net stop "OpenDJ Server" + if ($LASTEXITCODE -ne 0) { throw "net stop (upgraded) failed: $LASTEXITCODE" } 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 66e9f855b6..7fdbe50c62 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 @@ -644,7 +644,7 @@ On Windows you can install OpenDJ directory server from the `.msi` package. The . Make sure a supported Java runtime is available, as described in xref:#before-you-install["To Prepare For Installation"]. + -The installer does not check for Java. If your default Java environment is not appropriate, set `OPENDJ_JAVA_HOME` to the correct Java installation (or `OPENDJ_JAVA_BIN` to the absolute path of the `java` command), or make sure `java` is on the `PATH`, before you run `setup` or start the server. +The installer refuses to install when it cannot detect a Java installation: install a JRE (for example link:https://adoptium.net[Eclipse Temurin, window=\_blank]), set `JAVA_HOME` to your Java installation, or make sure the `java` executable is on the `PATH`, before running it. If your default Java environment is not the one OpenDJ should use, additionally set `OPENDJ_JAVA_HOME` to the correct Java installation (or `OPENDJ_JAVA_BIN` to the absolute path of the `java` command) before you run `setup` or start the server. . Install the package, either with the GUI or silently: + 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 17e0413635..3adc45d381 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 @@ -162,17 +162,9 @@ Removing the package does not remove your data or configuration. You must remove [#uninstall-msi] .To Uninstall the Windows MSI Package ==== -Remove OpenDJ directory server installed from the `.msi` package like any other Windows program. +Remove OpenDJ directory server installed from the `.msi` package like any other Windows program. The uninstaller stops and removes the `OpenDJ Server` Windows service that the package registered. -. If OpenDJ is registered as a Windows service, remove the service first: -+ - -[source, console] ----- -C:\path\to\opendj\bat> windows-service.bat --disableService ----- - -. Uninstall the package, either through __Settings > Apps__ (or __Control Panel > Programs and Features__) by selecting OpenDJ and choosing Uninstall, or from the command-line: +* Uninstall the package, either through __Settings > Apps__ (or __Control Panel > Programs and Features__) by selecting OpenDJ and choosing Uninstall, or from the command-line: + [source, console, subs="attributes"] 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 c514e71c82..d91b763711 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 @@ -250,25 +250,19 @@ $ ==== Before starting this procedure, follow the steps in xref:#before-you-upgrade["Before You Upgrade"]. Installing the newer `.msi` performs a major upgrade that replaces the installed program files, so make a full file-system backup of the current installation first. -. Stop the current OpenDJ server. - -. If OpenDJ is registered as a Windows service, disable the service: -+ - -[source, console] ----- -C:\path\to\opendj\bat> windows-service.bat --disableService ----- +. Stop the current OpenDJ server (if it runs as a Windows service, `net stop "OpenDJ Server"`). . Back up the file-system directory where OpenDJ is installed. -. Install the newer package (GUI or silent), using the same installation directory as the current server. Your configured instance data (`config`, `db`, `logs`) is kept; only the program files are replaced: +. Install the newer package (GUI or silent). The installer detects the existing installation — the location recorded in the registry by a previous x64 package, or the default directory of the older 32-bit package (`C:\Program Files (x86)\OpenDJ`) — and installs into the same directory, so your configured instance data (`config`, `db`, `logs`) is kept and only the program files are replaced. If the older server was installed in a custom directory the installer did not detect, select that directory in the GUI or pass it explicitly: + [source, console, subs="attributes"] ---- C:\> msiexec /i opendj-{opendj-version}.msi /quiet OPENDJ="C:\path\to\opendj" ---- ++ +The installer replaces a service registered by the older `windows-service.bat` command with the MSI-managed `OpenDJ Server` service automatically; no manual `--disableService`/`--enableService` is needed. . Run the `upgrade` command, described in xref:../reference/admin-tools-ref.adoc#upgrade-1[upgrade(1)] in the __Reference__, to bring the configuration and application data up to date with the new binary and script files: + @@ -278,14 +272,12 @@ C:\> msiexec /i opendj-{opendj-version}.msi /quiet OPENDJ="C:\path\to\opendj" C:\path\to\opendj> upgrade.bat --no-prompt --acceptLicense ---- -. Start the upgraded OpenDJ server. - -. If you disabled the Windows service, enable it again: +. Start the upgraded OpenDJ server: + [source, console] ---- -C:\path\to\opendj\bat> windows-service.bat --enableService +C:\> net start "OpenDJ Server" ---- ==== diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 2866f91801..142d1ced45 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -31,6 +31,43 @@ + + + + + + + + + + + + + + + + + + + + + + + @@ -55,6 +92,12 @@ Stop="both" Remove="uninstall" Wait="yes"/> + + + + + @@ -67,6 +110,7 @@ + From 50247e1e5b30de8b9ff91ac7ce1cddf0e2f0c414 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Thu, 2 Jul 2026 17:53:28 +0300 Subject: [PATCH 13/52] Document the unsigned-MSI SmartScreen warning; drop unused wix.version property --- .../src/main/asciidoc/install-guide/chap-install.adoc | 2 ++ opendj-packages/opendj-msi/opendj-msi-standard/pom.xml | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) 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 7fdbe50c62..5770bfc24d 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 @@ -648,6 +648,8 @@ The installer refuses to install when it cannot detect a Java installation: inst . Install the package, either with the GUI or silently: + +The package is not code-signed, so Windows SmartScreen or User Account Control may warn about an unrecognized publisher; choose to run the installer anyway. ++ * GUI: double-click `opendj-{opendj-version}.msi` and follow the wizard. + * Silent: run the following command (optionally set the installation directory with the `OPENDJ` property): diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml b/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml index c1eb2ff709..f7505785c1 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml +++ b/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml @@ -43,7 +43,6 @@ ${project.build.directory}/msi-staging-lib ${package.dir}/lib/opendj_service.exe ${project.build.directory}/${product.name.lowercase}-${project.version}.msi - 5.0.2 From 20fbcca8530b41b5873bf3404f365b62f9de68b4 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Thu, 2 Jul 2026 21:28:34 +0300 Subject: [PATCH 14/52] Fix unquoted java.io.tmpdir (paths with spaces); harden MSI tests - _script-util.bat: quote -Djava.io.tmpdir="%OPENDJ_TMP_DIR%" - any install directory containing spaces (including the x64 default C:\Program Files\OpenDJ and the legacy Program Files (x86)) broke the CheckJVMVersion probe and every script with "The detected Java version could not be used". - build.yml test-msi: the no-JRE negative test now hides Java at MACHINE scope (the Windows Installer service evaluates launch conditions with the machine environment) and restarts msiserver, restoring everything afterwards; the positive install now goes to the spaced x64 default directory end-to-end. - build.yml test-msi-upgrade (renamed from test-win-upgrade): the released 5.1.1 scripts cannot run from a spaced directory, so the old install lives in C:\opendj and the upgrade passes OPENDJ explicitly; added a fresh-install scenario asserting the legacy default directory is auto-detected when OPENDJ is not given, plus uninstall/service cleanup checks. - ADNotificationRequestControl: escape && in the javadoc code sample (javadoc "invalid input: '&'" warnings). --- .github/workflows/build.yml | 73 ++++++++++++++----- .../ADNotificationRequestControl.java | 5 +- .../resource/bin/_script-util.bat | 4 +- 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4cd47cddf5..ab2c5faab7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -459,15 +459,31 @@ jobs: - name: Install must fail without a JRE shell: pwsh run: | - # Simulate a machine with no Java: clear JAVA_HOME and strip java-looking PATH entries. + # Simulate a machine with no Java. The launch condition is evaluated by the Windows + # Installer service, which sees the MACHINE environment - so hide Java there too and + # restart msiserver to make it pick the change up; restore everything afterwards. + Stop-Service msiserver -Force -ErrorAction SilentlyContinue + $oldJH = [Environment]::GetEnvironmentVariable('JAVA_HOME','Machine') + $oldPM = [Environment]::GetEnvironmentVariable('Path','Machine') + [Environment]::SetEnvironmentVariable('JAVA_HOME',$null,'Machine') + [Environment]::SetEnvironmentVariable('Path',((($oldPM -split ';') | Where-Object { $_ -notmatch 'java|jdk|jre|zulu|javapath' }) -join ';'),'Machine') $env:JAVA_HOME = "" $env:PATH = (($env:PATH -split ';') | Where-Object { $_ -notmatch 'java|jdk|jre|zulu|javapath' }) -join ';' - $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName - if (-not $msi) { throw "MSI not found in the windows-latest-11 artifact" } - $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v install-nojre.log" - if ($p.ExitCode -eq 0) { throw "installer succeeded without a JRE, but the Java launch condition must fail it" } - Write-Host "Installer refused to install without a JRE as expected (exit $($p.ExitCode))" - Select-String -Path install-nojre.log -Pattern "requires Java" | Select-Object -First 1 + try { + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + if (-not $msi) { throw "MSI not found in the windows-latest-11 artifact" } + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v install-nojre.log" + if ($p.ExitCode -eq 0) { + Get-Content install-nojre.log -Tail 60 + throw "installer succeeded without a JRE, but the Java launch condition must fail it" + } + Write-Host "Installer refused to install without a JRE as expected (exit $($p.ExitCode))" + Select-String -Path install-nojre.log -Pattern "requires Java" | Select-Object -First 1 + } finally { + [Environment]::SetEnvironmentVariable('JAVA_HOME',$oldJH,'Machine') + [Environment]::SetEnvironmentVariable('Path',$oldPM,'Machine') + Stop-Service msiserver -Force -ErrorAction SilentlyContinue + } - name: Set up Java uses: actions/setup-java@v5 with: @@ -479,10 +495,12 @@ jobs: $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName if (-not $msi) { throw "MSI not found in the windows-latest-11 artifact" } Write-Host "MSI: $msi" - $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart OPENDJ=C:\opendj /l*v install.log" + # No OPENDJ property: exercise the x64 default C:\Program Files\OpenDJ (a path with + # spaces, which the server scripts must handle). + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v install.log" if ($p.ExitCode -ne 0) { Get-Content install.log -Tail 80; throw "msiexec /i failed: $($p.ExitCode)" } - $root = @("C:\opendj","C:\Program Files (x86)\OpenDJ","C:\Program Files\OpenDJ") | Where-Object { Test-Path "$_\setup.bat" } | Select-Object -First 1 - if (-not $root) { Get-Content install.log -Tail 80; throw "OpenDJ install root with setup.bat not found" } + $root = "C:\Program Files\OpenDJ" + if (-not (Test-Path "$root\setup.bat")) { Get-Content install.log -Tail 80; throw "OpenDJ not installed into the x64 default $root" } Write-Host "Installed to $root" "OPENDJ_ROOT=$root" | Out-File -FilePath $env:GITHUB_ENV -Append - name: Setup and start/stop the Windows service @@ -512,7 +530,7 @@ jobs: # Verifies the new installer detects the legacy Program Files (x86) install, keeps the # instance data in place, replaces the windows-service.bat service with the MSI-managed # one, and the upgraded server starts with the old data. - test-win-upgrade: + test-msi-upgrade: needs: build-maven runs-on: 'windows-latest' steps: @@ -529,9 +547,11 @@ jobs: shell: pwsh run: | Invoke-WebRequest -Uri "https://github.com/OpenIdentityPlatform/OpenDJ/releases/download/5.1.1/opendj-5.1.1.msi" -OutFile opendj-5.1.1.msi - $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.1.msi /quiet /qn /norestart /l*v install-old.log" + # The released 5.1.1 scripts cannot run from a directory with spaces (unquoted + # java.io.tmpdir), so put the old install into C:\opendj. + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.1.msi /quiet /qn /norestart OPENDJ=C:\opendj /l*v install-old.log" if ($p.ExitCode -ne 0) { Get-Content install-old.log -Tail 80; throw "msiexec /i (5.1.1) failed: $($p.ExitCode)" } - $root = "C:\Program Files (x86)\OpenDJ" + $root = "C:\opendj" if (-not (Test-Path "$root\setup.bat")) { Get-Content install-old.log -Tail 80; throw "5.1.1 install root not found at $root" } $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" & "$root\setup.bat" -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --addBaseEntry --cli --acceptLicense --no-prompt --doNotStart @@ -543,16 +563,16 @@ jobs: if ($LASTEXITCODE -ne 0) { throw "net start (5.1.1) failed: $LASTEXITCODE" } net stop "OpenDJ Server" if ($LASTEXITCODE -ne 0) { throw "net stop (5.1.1) failed: $LASTEXITCODE" } - - name: Upgrade with the newly built MSI (no OPENDJ property - must auto-detect) + - name: Upgrade with the newly built MSI (same directory passed explicitly) shell: pwsh run: | $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName if (-not $msi) { throw "MSI not found in the windows-latest-11 artifact" } - $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade.log" + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart OPENDJ=C:\opendj /l*v upgrade.log" if ($p.ExitCode -ne 0) { Get-Content upgrade.log -Tail 120; throw "msiexec /i (upgrade) failed: $($p.ExitCode)" } - $root = "C:\Program Files (x86)\OpenDJ" - # New package files landed in the legacy directory, not the x64 default - if (-not (Test-Path "$root\setup.bat")) { throw "upgrade did not keep the legacy install dir" } + $root = "C:\opendj" + # New package files landed in the old directory, not the x64 default + if (-not (Test-Path "$root\setup.bat")) { throw "upgrade did not keep the old install dir" } if (Test-Path "C:\Program Files\OpenDJ") { throw "upgrade unexpectedly installed into the x64 default dir" } # Instance data survived if (-not (Test-Path "$root\config\config.ldif")) { throw "instance data (config\config.ldif) lost by the upgrade" } @@ -576,3 +596,20 @@ jobs: if ($LASTEXITCODE -ne 0) { throw "ldapsearch after upgrade failed: $LASTEXITCODE" } net stop "OpenDJ Server" if ($LASTEXITCODE -ne 0) { throw "net stop (upgraded) failed: $LASTEXITCODE" } + - name: Auto-detect the legacy default directory on a fresh install + shell: pwsh + run: | + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + # Clean up the previous scenario first. + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall1.log" + if ($p.ExitCode -ne 0) { Get-Content uninstall1.log -Tail 80; throw "msiexec /x failed: $($p.ExitCode)" } + if (Get-Service OpenDJ -ErrorAction SilentlyContinue) { throw "service not removed by uninstall" } + # An existing legacy default directory must be picked up when OPENDJ is not given. + New-Item -ItemType Directory -Force "C:\Program Files (x86)\OpenDJ" | Out-Null + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v install-autodetect.log" + if ($p.ExitCode -ne 0) { Get-Content install-autodetect.log -Tail 80; throw "msiexec /i (autodetect) failed: $($p.ExitCode)" } + if (-not (Test-Path "C:\Program Files (x86)\OpenDJ\setup.bat")) { Get-Content install-autodetect.log -Tail 80; throw "installer did not auto-detect the legacy default dir" } + if (Test-Path "C:\Program Files\OpenDJ") { throw "installer used the x64 default dir despite an existing legacy dir" } + Write-Host "Legacy default directory auto-detected OK" + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall2.log" + if ($p.ExitCode -ne 0) { Get-Content uninstall2.log -Tail 80; throw "msiexec /x (cleanup) failed: $($p.ExitCode)" } diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/controls/ADNotificationRequestControl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/controls/ADNotificationRequestControl.java index c2c6ea3669..631f5e1e05 100644 --- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/controls/ADNotificationRequestControl.java +++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/controls/ADNotificationRequestControl.java @@ -12,6 +12,7 @@ * information: "Portions Copyright [year] [name of copyright owner]". * * Copyright 2013-2016 ForgeRock AS. + * Portions Copyright 2026 3A Systems, LLC */ package org.forgerock.opendj.ldap.controls; @@ -39,12 +40,12 @@ * SearchResultEntry entry = reader.readEntry(); // Entry that changed * * Boolean isDeleted = entry.parseAttribute("isDeleted").asBoolean(); - * if (isDeleted != null && isDeleted) { + * if (isDeleted != null && isDeleted) { * // Handle entry deletion * } * String whenCreated = entry.parseAttribute("whenCreated").asString(); * String whenChanged = entry.parseAttribute("whenChanged").asString(); - * if (whenCreated != null && whenChanged != null) { + * if (whenCreated != null && whenChanged != null) { * if (whenCreated.equals(whenChanged)) { * //Handle entry addition * } else { diff --git a/opendj-server-legacy/resource/bin/_script-util.bat b/opendj-server-legacy/resource/bin/_script-util.bat index f6bacbb9d1..30ef80d811 100644 --- a/opendj-server-legacy/resource/bin/_script-util.bat +++ b/opendj-server-legacy/resource/bin/_script-util.bat @@ -13,7 +13,7 @@ rem information: "Portions Copyright [year] [name of copyright owner]". rem rem Copyright 2008-2010 Sun Microsystems, Inc. rem Portions Copyright 2011-2016 ForgeRock AS. -rem Portions Copyright 2020-2025 3A Systems, LLC. +rem Portions Copyright 2020-2026 3A Systems, LLC. set SET_JAVA_HOME_AND_ARGS_DONE=false set SET_ENVIRONMENT_VARS_DONE=false @@ -186,7 +186,7 @@ goto scriptBegin if %SET_TEMP_DIR_DONE% == "true" goto end set OPENDJ_TMP_DIR=%INSTANCE_ROOT%\tmp if not exist "%OPENDJ_TMP_DIR%" mkdir "%OPENDJ_TMP_DIR%" -set OPENDJ_JAVA_ARGS=%OPENDJ_JAVA_ARGS% -Djava.io.tmpdir=%OPENDJ_TMP_DIR% +set OPENDJ_JAVA_ARGS=%OPENDJ_JAVA_ARGS% -Djava.io.tmpdir="%OPENDJ_TMP_DIR%" set SET_TEMP_DIR_DONE=true goto scriptBegin From 23b355af8302cbc99826b80844cfe5a12901fc22 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Thu, 2 Jul 2026 21:34:55 +0300 Subject: [PATCH 15/52] Fix unquoted java.io.tmpdir in Windows scripts (install paths with spaces) _script-util.bat appends -Djava.io.tmpdir=%OPENDJ_TMP_DIR% to OPENDJ_JAVA_ARGS without quotes, so in any install directory containing spaces (for example C:\Program Files (x86)\OpenDJ) the CheckJVMVersion probe - and with it setup and every other command-line tool - fails with "The detected Java version could not be used with the set of Java arguments". Quote the value: -Djava.io.tmpdir="%OPENDJ_TMP_DIR%". --- opendj-server-legacy/resource/bin/_script-util.bat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opendj-server-legacy/resource/bin/_script-util.bat b/opendj-server-legacy/resource/bin/_script-util.bat index f6bacbb9d1..30ef80d811 100644 --- a/opendj-server-legacy/resource/bin/_script-util.bat +++ b/opendj-server-legacy/resource/bin/_script-util.bat @@ -13,7 +13,7 @@ rem information: "Portions Copyright [year] [name of copyright owner]". rem rem Copyright 2008-2010 Sun Microsystems, Inc. rem Portions Copyright 2011-2016 ForgeRock AS. -rem Portions Copyright 2020-2025 3A Systems, LLC. +rem Portions Copyright 2020-2026 3A Systems, LLC. set SET_JAVA_HOME_AND_ARGS_DONE=false set SET_ENVIRONMENT_VARS_DONE=false @@ -186,7 +186,7 @@ goto scriptBegin if %SET_TEMP_DIR_DONE% == "true" goto end set OPENDJ_TMP_DIR=%INSTANCE_ROOT%\tmp if not exist "%OPENDJ_TMP_DIR%" mkdir "%OPENDJ_TMP_DIR%" -set OPENDJ_JAVA_ARGS=%OPENDJ_JAVA_ARGS% -Djava.io.tmpdir=%OPENDJ_TMP_DIR% +set OPENDJ_JAVA_ARGS=%OPENDJ_JAVA_ARGS% -Djava.io.tmpdir="%OPENDJ_TMP_DIR%" set SET_TEMP_DIR_DONE=true goto scriptBegin From a80fcdbd24be809b04684c86760719074263c0b1 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Fri, 3 Jul 2026 12:53:59 +0300 Subject: [PATCH 16/52] Fix classpath building for install paths with spaces/parentheses (setcp.bat) _script-util.bat passed unquoted paths to setcp.bat, and setcp.bat compared arguments with if ""%1""=="""". The argument-joining hack survived spaces, but a parenthesis in the path (C:\Program Files (x86)\OpenDJ - the default MSI directory) breaks the cmd parser with "... was unexpected at this time", so setup.bat and every tool exit with 255. Quote the setcp.bat arguments at the three call sites and switch setcp.bat to %~1 with quoted comparisons. --- opendj-server-legacy/resource/bin/_script-util.bat | 6 +++--- opendj-server-legacy/resource/bin/setcp.bat | 11 +++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/opendj-server-legacy/resource/bin/_script-util.bat b/opendj-server-legacy/resource/bin/_script-util.bat index 30ef80d811..37538a75b3 100644 --- a/opendj-server-legacy/resource/bin/_script-util.bat +++ b/opendj-server-legacy/resource/bin/_script-util.bat @@ -56,10 +56,10 @@ rem get the absolute paths before building the classpath rem it also helps comparing the two paths FOR /F "delims=" %%i IN ("%INSTALL_ROOT%") DO set INSTALL_ROOT=%%~dpnxi FOR /F "delims=" %%i IN ("%INSTANCE_ROOT%") DO set INSTANCE_ROOT=%%~dpnxi -call "%INSTALL_ROOT%\lib\setcp.bat" %INSTALL_ROOT%\lib\bootstrap-client.jar +call "%INSTALL_ROOT%\lib\setcp.bat" "%INSTALL_ROOT%\lib\bootstrap-client.jar" set CLASSPATH=%INSTANCE_ROOT%\classes;%CLASSPATH% if "%INSTALL_ROOT%" == "%INSTANCE_ROOT%" goto setClassPathDone -FOR %%x in ("%INSTANCE_ROOT%\lib\*.jar") DO call "%INSTANCE_ROOT%\lib\setcp.bat" %%x +FOR %%x in ("%INSTANCE_ROOT%\lib\*.jar") DO call "%INSTANCE_ROOT%\lib\setcp.bat" "%%x" :setClassPathDone set SET_CLASSPATH_DONE=true goto scriptBegin @@ -71,7 +71,7 @@ rem get the absolute paths before building the classpath rem it also helps comparing the two paths FOR /F "delims=" %%i IN ("%INSTALL_ROOT%") DO set INSTALL_ROOT=%%~dpnxi FOR /F "delims=" %%i IN ("%INSTANCE_ROOT%") DO set INSTANCE_ROOT=%%~dpnxi -call "%INSTALL_ROOT%\lib\setcp.bat" %INSTALL_ROOT%\lib\* +call "%INSTALL_ROOT%\lib\setcp.bat" "%INSTALL_ROOT%\lib\*" set CLASSPATH=%INSTANCE_ROOT%\classes;%CLASSPATH% set SET_CLASSPATH_DONE=true goto scriptBegin diff --git a/opendj-server-legacy/resource/bin/setcp.bat b/opendj-server-legacy/resource/bin/setcp.bat index a47d4e6ac5..eca179c082 100644 --- a/opendj-server-legacy/resource/bin/setcp.bat +++ b/opendj-server-legacy/resource/bin/setcp.bat @@ -12,14 +12,17 @@ rem Header, with the fields enclosed by brackets [] replaced by your own identif rem information: "Portions Copyright [year] [name of copyright owner]". rem rem Copyright 2006-2008 Sun Microsystems, Inc. +rem Portions Copyright 2026 3A Systems, LLC -set CLASSPATHCOMPONENT=%1 -if ""%1""=="""" goto gotAllArgs +rem Use %~1 and quoted comparisons so paths containing spaces and parentheses +rem (for example C:\Program Files (x86)\OpenDJ) do not break the parser. +set CLASSPATHCOMPONENT=%~1 +if "%~1"=="" goto gotAllArgs shift :argCheck -if ""%1""=="""" goto gotAllArgs -set CLASSPATHCOMPONENT=%CLASSPATHCOMPONENT% %1 +if "%~1"=="" goto gotAllArgs +set CLASSPATHCOMPONENT=%CLASSPATHCOMPONENT% %~1 shift goto argCheck From dc97ea4420824267509f3f060893ef8d201a8fae Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Fri, 3 Jul 2026 16:33:26 +0300 Subject: [PATCH 17/52] Use "if defined" for JAVA_ARGS checks: the quoted java.io.tmpdir broke "%VAR%" == "" comparisons After -Djava.io.tmpdir="%OPENDJ_TMP_DIR%" is appended, OPENDJ_JAVA_ARGS contains embedded quotes, and the subsequent if "%OPENDJ_JAVA_ARGS%" == "" checks blow up the cmd parser ('...\tmp"" was unexpected at this time', every tool exits 255) regardless of whether the install path has spaces. Compare with "if defined", which does not expand the value. --- opendj-server-legacy/resource/bin/_script-util.bat | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/opendj-server-legacy/resource/bin/_script-util.bat b/opendj-server-legacy/resource/bin/_script-util.bat index 37538a75b3..bea162b7cd 100644 --- a/opendj-server-legacy/resource/bin/_script-util.bat +++ b/opendj-server-legacy/resource/bin/_script-util.bat @@ -100,7 +100,8 @@ rem if not "%OPENDJ_JAVA_ARGS%" == "" goto checkEnvJavaHome set SCRIPT_JAVA_ARGS_PROPERTY=%SCRIPT_NAME%.java-args call:readProperty %SCRIPT_JAVA_ARGS_PROPERTY% set OPENDJ_JAVA_ARGS=%OPENDJ_JAVA_ARGS% %PROPERTY_VALUE% -if not "%OPENDJ_JAVA_ARGS%" == "" goto checkEnvJavaHome +rem "if defined" comparisons: the value may contain quotes (java.io.tmpdir), which break "%VAR%" == "" checks. +if defined OPENDJ_JAVA_ARGS goto checkEnvJavaHome call:readProperty default.java-args set OPENDJ_JAVA_ARGS=%OPENDJ_JAVA_ARGS% %PROPERTY_VALUE if "%OPENDJ_JAVA_BIN%" == "" goto checkEnvJavaHome @@ -191,7 +192,7 @@ set SET_TEMP_DIR_DONE=true goto scriptBegin :testJava -if "%OPENDJ_JAVA_ARGS%" == "" goto checkLegacyArgs +if not defined OPENDJ_JAVA_ARGS goto checkLegacyArgs :continueTestJava "%OPENDJ_JAVA_BIN%" %OPENDJ_JAVA_ARGS% org.opends.server.tools.CheckJVMVersion > NUL 2>&1 set RESULT_CODE=%errorlevel% @@ -200,12 +201,12 @@ if not %RESULT_CODE% == 0 goto noValidJavaHome goto end :checkLegacyArgs -if "%OPENDS_JAVA_ARGS%" == "" goto continueTestJava +if not defined OPENDS_JAVA_ARGS goto continueTestJava set OPENDJ_JAVA_ARGS=%OPENDS_JAVA_ARGS% goto continueTestJava :noValidJavaHome -if NOT "%OPENDJ_JAVA_ARGS%" == "" goto noValidHomeWithArgs +if defined OPENDJ_JAVA_ARGS goto noValidHomeWithArgs echo ERROR: The detected Java version could not be used. The detected echo Java binary is: echo %OPENDJ_JAVA_BIN% From a6c9fb021c11713671289e50a29afd9c637a9de5 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Sat, 4 Jul 2026 09:47:27 +0300 Subject: [PATCH 18/52] MSI: ship the empty instance directories and fix the service ImagePath quoting - The harvest ships files only (heat had -ke), so the empty instance directories (bak, changelogDb, classes, db, import-tmp, ldif, locks, logs, tmp and the template ones) were missing from the installed tree and the server could not create its lock/pid files - setup aborted with "error stopping server". Create them with explicit CreateFolder components. - [OPENDJ] ends with a backslash which escaped the closing quote in the service ImagePath ('start "C:\opendj\"' -> broken argv), so the MSI-managed service failed to start (NET HELPMSG 2186). Append an extra backslash so \\" parses as backslash + closing quote. --- .../resources/msi/package.wxs | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 142d1ced45..d90e9cb4e0 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -76,18 +76,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Arguments="start "[OPENDJ]\"" Vital="no"/> @@ -113,6 +156,7 @@ + From 1a4f66eb9ebfbdb2a9bf9bd93a28549ad6c579a7 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Sat, 4 Jul 2026 13:03:22 +0300 Subject: [PATCH 19/52] MSI: explicit GUIDs for the CreateFolder components (WIX0230) Components whose KeyPath is a directory cannot use auto-generated GUIDs, so the empty-instance-directory components broke wix build with WIX0230. Assign fixed GUIDs. --- .../resources/msi/package.wxs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index d90e9cb4e0..cef70bf31b 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -101,23 +101,23 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + + Arguments="start "[OPENDJ]."" Vital="no"/> diff --git a/opendj-server-legacy/src/build-tools/windows/service.c b/opendj-server-legacy/src/build-tools/windows/service.c index 1fd7e373d0..29fbb87381 100644 --- a/opendj-server-legacy/src/build-tools/windows/service.c +++ b/opendj-server-legacy/src/build-tools/windows/service.c @@ -826,6 +826,118 @@ ServiceReturnCode createServiceBinPath(char* serviceBinPath) return returnValue; } // createServiceBinPath +// ---------------------------------------------------- +// Reads the next command line token starting at *p into out (at most +// outSize - 1 characters). A token is either a run of non-blank +// characters or a double-quoted string; quotes are treated as plain +// delimiters without escape processing, so a trailing backslash-quote +// sequence (as written by msiexec) leaves trailing backslashes on the +// token, which normalizeInstanceDir strips. Returns the position right +// after the token. +// ---------------------------------------------------- + +static const char* nextCmdToken(const char* p, char* out, int outSize) +{ + int i = 0; + while ((*p == ' ') || (*p == '\t')) + { + p++; + } + if (*p == '"') + { + p++; + while ((*p != '\0') && (*p != '"')) + { + if (i < (outSize - 1)) + { + out[i++] = *p; + } + p++; + } + if (*p == '"') + { + p++; + } + } + else + { + while ((*p != '\0') && (*p != ' ') && (*p != '\t')) + { + if (i < (outSize - 1)) + { + out[i++] = *p; + } + p++; + } + } + out[i] = '\0'; + return p; +} // nextCmdToken + +// ---------------------------------------------------- +// Strips trailing backslashes and "\." path segments from an instance +// dir so that "C:\opendj", "C:\opendj\" and "C:\opendj\." all compare +// equal. +// ---------------------------------------------------- + +static void normalizeInstanceDir(char* dir) +{ + size_t len = strlen(dir); + BOOL changed = TRUE; + while (changed && (len > 0)) + { + changed = FALSE; + if (dir[len - 1] == '\\') + { + dir[--len] = '\0'; + changed = TRUE; + } + else if ((len > 1) && (dir[len - 1] == '.') && (dir[len - 2] == '\\')) + { + dir[--len] = '\0'; + changed = TRUE; + } + } +} // normalizeInstanceDir + +// ---------------------------------------------------- +// Tells whether two service command lines refer to the same server +// instance. The strings cannot be compared verbatim because every +// writer quotes differently: this executable and the java tools write +// '"\lib\opendj_service.exe" start ""' while the MSI +// ServiceInstall writes the executable unquoted (when the path has no +// spaces) and the instance dir with a trailing backslash. Instead the +// executable path, the subcommand and the normalized instance dir are +// compared token by token, case-insensitively. +// ---------------------------------------------------- + +static BOOL serviceCmdsMatch(const char* cmd1, const char* cmd2) +{ + char exe1[COMMAND_SIZE]; + char exe2[COMMAND_SIZE]; + char sub1[COMMAND_SIZE]; + char sub2[COMMAND_SIZE]; + char dir1[COMMAND_SIZE]; + char dir2[COMMAND_SIZE]; + const char* p1 = cmd1; + const char* p2 = cmd2; + + p1 = nextCmdToken(p1, exe1, COMMAND_SIZE); + p1 = nextCmdToken(p1, sub1, COMMAND_SIZE); + nextCmdToken(p1, dir1, COMMAND_SIZE); + + p2 = nextCmdToken(p2, exe2, COMMAND_SIZE); + p2 = nextCmdToken(p2, sub2, COMMAND_SIZE); + nextCmdToken(p2, dir2, COMMAND_SIZE); + + normalizeInstanceDir(dir1); + normalizeInstanceDir(dir2); + + return (_stricmp(exe1, exe2) == 0) + && (_stricmp(sub1, sub2) == 0) + && (_stricmp(dir1, dir2) == 0); +} // serviceCmdsMatch + // ---------------------------------------------------- // Returns the service name that maps the command used to start the // product. All commands are supposed to be unique because they have @@ -866,7 +978,7 @@ ServiceReturnCode getServiceName(char* cmdToRun, char* serviceName) ServiceDescriptor curService = serviceList[i]; if (curService.cmdToRun != NULL) { - if (_stricmp(cmdToRun, curService.cmdToRun) == 0) + if (serviceCmdsMatch(cmdToRun, curService.cmdToRun)) { if (strlen(curService.serviceName) < MAX_SERVICE_NAME) { From b23db327ba80b8723eae3fa5b1e936b9fb142620 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Tue, 7 Jul 2026 09:31:46 +0300 Subject: [PATCH 22/52] Rebuild Windows native binaries with the ImagePath fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace opendj_service.exe, winlauncher.exe and launcher_administrator.exe with the CI-built artifacts from the fixed service.c (tolerant ImagePath matching, commit 262f98f66). Verified by green test-msi and test-msi-upgrade — the Windows service now starts (no more error 2186). --- .../lib/launcher_administrator.exe | Bin 159232 -> 160256 bytes opendj-server-legacy/lib/opendj_service.exe | Bin 169984 -> 170496 bytes opendj-server-legacy/lib/winlauncher.exe | Bin 158208 -> 159232 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/opendj-server-legacy/lib/launcher_administrator.exe b/opendj-server-legacy/lib/launcher_administrator.exe index 50b885811d2d0f841b4af5d8500c3298e195084b..bfb8ae4fdff4b313043dfb3daa18f939576aeef2 100644 GIT binary patch delta 46115 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 delta 46047 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 diff --git a/opendj-server-legacy/lib/opendj_service.exe b/opendj-server-legacy/lib/opendj_service.exe index 0b458d8f72c8796c7336720edb0adc56d21533c8..4e20ac794117bc1ec049ade896455928ec0b70fd 100644 GIT binary patch delta 56361 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%0AIzyFP~$M8m)nLfx%6NO-;dXIRE?Euy92NgeM9< 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 delta 55489 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

POCZZ^s!JPkg?( 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 DT&Gwr From 72f5ac27c121337087415f4fafaab05b8cd3218c Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Mon, 20 Jul 2026 18:25:42 +0300 Subject: [PATCH 23/52] [#701] restrict build workflow permissions and pin action-gh-release CodeQL flagged the MSI upgrade test job for the default token permissions and the release step for using a floating tag. Add permissions: contents: read to the build workflow and pin softprops/action-gh-release to v3.0.2 (3d0d988). --- .github/workflows/build.yml | 5 +++++ .github/workflows/release.yml | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 54849081d1..ae780952da 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,6 +23,11 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +# The build only checks out sources and publishes artifacts through the actions +# API; no job needs to write back to the repository. +permissions: + contents: read + jobs: build-maven: runs-on: ${{ matrix.os }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 59e6c7da4c..62750246f6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -92,7 +92,7 @@ jobs: retention-days: 1 path: target/checkout/opendj-server-legacy/target/package/*.zip - name: Release on GitHub - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 with: name: ${{ github.event.inputs.releaseVersion }} tag_name: ${{ github.event.inputs.releaseVersion }} @@ -203,7 +203,7 @@ jobs: MAVEN_OPTS: -Dhttps.protocols=TLSv1.2 -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.requestSentEnabled=true -Dmaven.wagon.http.retryHandler.count=10 run: mvn --batch-mode --errors -DskipTests package -pl :opendj-msi-standard --file pom.xml - name: Attach the MSI to the GitHub release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 with: tag_name: ${{ github.event.inputs.releaseVersion }} fail_on_unmatched_files: true From 597c6c4765d6ec680ba888d373deed97ae0439e8 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Thu, 6 Aug 2026 13:27:49 +0300 Subject: [PATCH 24/52] Upgrade test: take the released 5.1.2 MSI as the upgrade source --- .github/workflows/build.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dfe2264816..fdc19eaec7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -695,7 +695,7 @@ jobs: if ($p.ExitCode -ne 0) { Get-Content uninstall.log -Tail 80; throw "msiexec /x failed: $($p.ExitCode)" } Write-Host "Uninstalled OK" - # Upgrade path: released 5.1.1 x86 MSI (wine-built, WiX3) -> this build's x64 MSI. + # Upgrade path: released 5.1.2 x86 MSI (wine-built, WiX3) -> this build's x64 MSI. # Verifies the new installer detects the legacy Program Files (x86) install, keeps the # instance data in place, replaces the windows-service.bat service with the MSI-managed # one, and the upgraded server starts with the old data. @@ -712,26 +712,26 @@ jobs: with: java-version: '25' distribution: 'zulu' - - name: Install released 5.1.1 MSI and configure an instance + - name: Install released 5.1.2 MSI and configure an instance shell: pwsh run: | - Invoke-WebRequest -Uri "https://github.com/OpenIdentityPlatform/OpenDJ/releases/download/5.1.1/opendj-5.1.1.msi" -OutFile opendj-5.1.1.msi - # The released 5.1.1 scripts cannot run from a directory with spaces (unquoted + Invoke-WebRequest -Uri "https://github.com/OpenIdentityPlatform/OpenDJ/releases/download/5.1.2/opendj-5.1.2.msi" -OutFile opendj-5.1.2.msi + # The released 5.1.2 scripts cannot run from a directory with spaces (unquoted # java.io.tmpdir), so put the old install into C:\opendj. - $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.1.msi /quiet /qn /norestart OPENDJ=C:\opendj /l*v install-old.log" - if ($p.ExitCode -ne 0) { Get-Content install-old.log -Tail 80; throw "msiexec /i (5.1.1) failed: $($p.ExitCode)" } + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart OPENDJ=C:\opendj /l*v install-old.log" + if ($p.ExitCode -ne 0) { Get-Content install-old.log -Tail 80; throw "msiexec /i (5.1.2) failed: $($p.ExitCode)" } $root = "C:\opendj" - if (-not (Test-Path "$root\setup.bat")) { Get-Content install-old.log -Tail 80; throw "5.1.1 install root not found at $root" } + if (-not (Test-Path "$root\setup.bat")) { Get-Content install-old.log -Tail 80; throw "5.1.2 install root not found at $root" } $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" & "$root\setup.bat" -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --addBaseEntry --cli --acceptLicense --no-prompt --doNotStart - if ($LASTEXITCODE -ne 0) { throw "setup.bat (5.1.1) failed: $LASTEXITCODE" } + if ($LASTEXITCODE -ne 0) { throw "setup.bat (5.1.2) failed: $LASTEXITCODE" } # Register the LEGACY service the pre-MSI way and prove it works, then stop it. & "$root\bat\windows-service.bat" --enableService if ($LASTEXITCODE -ne 0) { throw "windows-service --enableService failed: $LASTEXITCODE" } net start "OpenDJ Server" - if ($LASTEXITCODE -ne 0) { throw "net start (5.1.1) failed: $LASTEXITCODE" } + if ($LASTEXITCODE -ne 0) { throw "net start (5.1.2) failed: $LASTEXITCODE" } net stop "OpenDJ Server" - if ($LASTEXITCODE -ne 0) { throw "net stop (5.1.1) failed: $LASTEXITCODE" } + if ($LASTEXITCODE -ne 0) { throw "net stop (5.1.2) failed: $LASTEXITCODE" } - name: Upgrade with the newly built MSI (same directory passed explicitly) shell: pwsh run: | From e108320f458088772d9236c66e82a45c048cafe5 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Thu, 6 Aug 2026 13:48:19 +0300 Subject: [PATCH 25/52] Refresh the checked-in Windows launcher binaries from the CI build --- .../lib/launcher_administrator.exe | Bin 160256 -> 163840 bytes opendj-server-legacy/lib/opendj_service.exe | Bin 170496 -> 175104 bytes opendj-server-legacy/lib/winlauncher.exe | Bin 159232 -> 162816 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/opendj-server-legacy/lib/launcher_administrator.exe b/opendj-server-legacy/lib/launcher_administrator.exe index bfb8ae4fdff4b313043dfb3daa18f939576aeef2..f29f6d04b6791eaf4096c5cedb399cb274aed71b 100644 GIT binary patch delta 54937 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 LKwsH#*K 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 j!J1qB}owu&s0qE=?t)yi_$N2v=gd}F;) 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%0Dp40)LB2eat>PDK3Qekp9U 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 diff --git a/opendj-server-legacy/lib/winlauncher.exe b/opendj-server-legacy/lib/winlauncher.exe index d1e3eaef75dc16f4dea4d216bb25328e3044f05c..17f5c41df5980ff6bce6bd348d7e719585eb39ec 100644 GIT binary patch delta 54877 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 DA1+d@ delta 51430 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 W@c*qOJz0v%D_5>y){#-Ql>Y%tFM=ij From 3aa24c56f4cb50016f823e49f84cf35b9e74f758 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Thu, 6 Aug 2026 17:42:31 +0300 Subject: [PATCH 26/52] Address review: harden MSI service handling, CI permissions and location detection - release.yml: grant release-msi contents:write so the MSI attaches to the release - deploy.yml: grant actions:read so the cross-run MSI artifact download works - package.wxs: replace the cmd.exe/net/sc legacy-service custom action with ServiceControl; drop the Java launch condition; skip the placeholder EULA dialog; split the install-location searches with explicit precedence; add AllowSameVersionUpgrades, ARPINSTALLLOCATION, Secure OPENDJ and the event-log source - service.c: refuse to remove the MSI-managed service from --disableService and expand 8.3 paths in serviceCmdsMatch (launcher binaries to be refreshed from CI) - Gate the MSI module on an installed wix tool (distribution-windows-msi profile), pin exec-maven-plugin, attach the MSI only after the wix build produces it - CI: assert committed launcher binaries match the sources, assert a quoted ImagePath, cover the registry install-location branch and the --disableService guard, retry the 5.1.2 download, parse sc.exe output null-safely, build the MSI on the java 11 job only - Docs: scope --disableService advice to zip installs, fix the default-directory and Java wording --- .gitattributes | 4 +- .github/workflows/build.yml | 99 +++++++++++-------- .github/workflows/deploy.yml | 3 + .github/workflows/release.yml | 4 + .../asciidoc/install-guide/chap-install.adoc | 4 +- .../asciidoc/install-guide/chap-upgrade.adoc | 4 +- .../opendj-msi/opendj-msi-standard/pom.xml | 55 ++++++----- .../resources/msi/package.wxs | 89 +++++++++++------ opendj-packages/opendj-msi/pom.xml | 8 +- opendj-packages/pom.xml | 21 +++- .../src/build-tools/windows/service.c | 43 +++++++- .../src/build-tools/windows/service.h | 7 ++ 12 files changed, 234 insertions(+), 107 deletions(-) diff --git a/.gitattributes b/.gitattributes index 464d174671..849c1c0aed 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,8 @@ # WiX sources must stay LF so the WiX toolset parses them consistently across runners. *.wxs text eol=lf -*.wxi text eol=lf +# The checked-in Windows launcher/service binaries are actively maintained: never diff, +# merge or eol-convert them. +*.exe binary # Keep HTML checked out with LF on all platforms so javadoc doclint # (JDK 25/26) does not treat CR (from CRLF) as part of a multi-line tag name. *.html text eol=lf diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fdc19eaec7..35f451635a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -83,6 +83,21 @@ jobs: nmake all xcopy /Y *.exe ..\..\..\lib\ git status + - name: Upload Windows exe artifacts + if: runner.os == 'Windows' + uses: actions/upload-artifact@v7 + with: + name: windows-exe-${{ matrix.java }} + retention-days: 5 + path: opendj-server-legacy/src/build-tools/windows/*.exe + - name: Committed launcher binaries must match the sources + if: runner.os == 'Windows' + # The release pipeline builds the server zip on Linux from the committed + # opendj-server-legacy/lib/*.exe, so a source change that is not re-committed as a + # refreshed binary would ship the old wrapper in the tagged release while CI stays + # green. The freshly built binaries are uploaded just above, so when this fails, + # refresh lib/*.exe from the windows-exe artifact of this very run and commit them. + run: git diff --exit-code -- opendj-server-legacy/lib - name: Set Integration Test Environment id: failsafe if: runner.os == 'Linux' @@ -90,7 +105,11 @@ jobs: echo "MAVEN_PROFILE_FLAG=-P precommit" >> $GITHUB_OUTPUT - name: Setup WiX (.NET tool) for MSI - if: runner.os == 'Windows' + # Only the java 11 job's MSI is consumed downstream (test-msi*, deploy.yml); without + # wix installed the distribution-windows-msi profile stays inactive, so the other + # Windows jobs skip the MSI build entirely instead of producing an artifact nothing + # uses. + if: runner.os == 'Windows' && matrix.java == '11' shell: bash run: | # The MSI builds on Windows only (WiX cannot author MSIs on Linux/macOS). WiX 5 ships as a @@ -373,14 +392,6 @@ jobs: if ($LASTEXITCODE -ne 0) { throw "net stop 'OpenDJ Server' failed with exit code $LASTEXITCODE" } opendj-server-legacy\target\package\opendj\bat\windows-service.bat --disableService - - name: Upload Windows exe artifacts - if: runner.os == 'Windows' - uses: actions/upload-artifact@v7 - with: - name: windows-exe-${{ matrix.java }} - retention-days: 5 - path: opendj-server-legacy/src/build-tools/windows/*.exe - - name: Upload artifacts OpenDJ Server uses: actions/upload-artifact@v7 with: @@ -625,34 +636,6 @@ jobs: uses: actions/download-artifact@v8 with: name: windows-latest-11 - - name: Install must fail without a JRE - shell: pwsh - run: | - # Simulate a machine with no Java. The launch condition is evaluated by the Windows - # Installer service, which sees the MACHINE environment - so hide Java there too and - # restart msiserver to make it pick the change up; restore everything afterwards. - Stop-Service msiserver -Force -ErrorAction SilentlyContinue - $oldJH = [Environment]::GetEnvironmentVariable('JAVA_HOME','Machine') - $oldPM = [Environment]::GetEnvironmentVariable('Path','Machine') - [Environment]::SetEnvironmentVariable('JAVA_HOME',$null,'Machine') - [Environment]::SetEnvironmentVariable('Path',((($oldPM -split ';') | Where-Object { $_ -notmatch 'java|jdk|jre|zulu|javapath' }) -join ';'),'Machine') - $env:JAVA_HOME = "" - $env:PATH = (($env:PATH -split ';') | Where-Object { $_ -notmatch 'java|jdk|jre|zulu|javapath' }) -join ';' - try { - $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName - if (-not $msi) { throw "MSI not found in the windows-latest-11 artifact" } - $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v install-nojre.log" - if ($p.ExitCode -eq 0) { - Get-Content install-nojre.log -Tail 60 - throw "installer succeeded without a JRE, but the Java launch condition must fail it" - } - Write-Host "Installer refused to install without a JRE as expected (exit $($p.ExitCode))" - Select-String -Path install-nojre.log -Pattern "requires Java" | Select-Object -First 1 - } finally { - [Environment]::SetEnvironmentVariable('JAVA_HOME',$oldJH,'Machine') - [Environment]::SetEnvironmentVariable('Path',$oldPM,'Machine') - Stop-Service msiserver -Force -ErrorAction SilentlyContinue - } - name: Set up Java uses: actions/setup-java@v5 with: @@ -671,6 +654,11 @@ jobs: $root = "C:\Program Files\OpenDJ" if (-not (Test-Path "$root\setup.bat")) { Get-Content install.log -Tail 80; throw "OpenDJ not installed into the x64 default $root" } Write-Host "Installed to $root" + # The whole [OPENDJ]. ImagePath hack rests on msiexec quoting the exe path; + # unquoted-with-spaces would be an unquoted service path (CWE-428). + $image = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\OpenDJ).ImagePath + Write-Host "ImagePath: $image" + if ($image -notmatch '^"C:\\Program Files\\OpenDJ\\lib\\opendj_service\.exe"') { throw "ImagePath must quote the exe path (CWE-428): $image" } "OPENDJ_ROOT=$root" | Out-File -FilePath $env:GITHUB_ENV -Append - name: Setup and start/stop the Windows service shell: pwsh @@ -687,6 +675,15 @@ jobs: if ($LASTEXITCODE -ne 0) { throw "ldapsearch failed: $LASTEXITCODE" } net stop "OpenDJ Server" if ($LASTEXITCODE -ne 0) { throw "net stop failed: $LASTEXITCODE" } + - name: windows-service.bat must not delete the MSI-managed service + shell: pwsh + run: | + # Deleting the service here would leave msiexec /x targeting a key that no longer + # exists; opendj_service.exe refuses to remove the MSI-managed key 'OpenDJ'. + $root = $env:OPENDJ_ROOT + & "$root\bat\windows-service.bat" --disableService + if (-not (Get-Service OpenDJ -ErrorAction SilentlyContinue)) { throw "--disableService deleted the MSI-managed service" } + Write-Host "--disableService left the MSI-managed service in place (exit $LASTEXITCODE)" - name: Uninstall MSI shell: pwsh run: | @@ -715,7 +712,11 @@ jobs: - name: Install released 5.1.2 MSI and configure an instance shell: pwsh run: | - Invoke-WebRequest -Uri "https://github.com/OpenIdentityPlatform/OpenDJ/releases/download/5.1.2/opendj-5.1.2.msi" -OutFile opendj-5.1.2.msi + $uri = "https://github.com/OpenIdentityPlatform/OpenDJ/releases/download/5.1.2/opendj-5.1.2.msi" + for ($i = 1; $i -le 5; $i++) { + try { Invoke-WebRequest -Uri $uri -OutFile opendj-5.1.2.msi; break } + catch { if ($i -eq 5) { throw }; Write-Host "download attempt $i failed, retrying"; Start-Sleep -Seconds (10 * $i) } + } # The released 5.1.2 scripts cannot run from a directory with spaces (unquoted # java.io.tmpdir), so put the old install into C:\opendj. $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart OPENDJ=C:\opendj /l*v install-old.log" @@ -746,7 +747,10 @@ jobs: # Instance data survived if (-not (Test-Path "$root\config\config.ldif")) { throw "instance data (config\config.ldif) lost by the upgrade" } # Legacy service replaced by the MSI-managed one: display name maps to key 'OpenDJ' - $key = (sc.exe getkeyname "OpenDJ Server" | Select-String -Pattern "Name = (.+)").Matches[0].Groups[1].Value.Trim() + # (match on '= ' only: the 'Name' label in sc.exe output is localized). + $m = sc.exe getkeyname "OpenDJ Server" | Select-String -Pattern "= (.+)$" | Select-Object -First 1 + if (-not $m) { sc.exe query; throw "no service with display name 'OpenDJ Server' found" } + $key = $m.Matches[0].Groups[1].Value.Trim() if ($key -ne "OpenDJ") { sc.exe query; throw "expected MSI-managed service key 'OpenDJ', got '$key'" } sc.exe qc OpenDJ "OPENDJ_ROOT=$root" | Out-File -FilePath $env:GITHUB_ENV -Append @@ -782,3 +786,20 @@ jobs: Write-Host "Legacy default directory auto-detected OK" $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall2.log" if ($p.ExitCode -ne 0) { Get-Content uninstall2.log -Tail 80; throw "msiexec /x (cleanup) failed: $($p.ExitCode)" } + - name: Registry install-location detection on a fresh install + shell: pwsh + run: | + # The InstallDir registry value must be picked up when OPENDJ is not given, and it + # must beat the legacy Program Files (x86) directory (explicit SetProperty order). + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + New-Item -ItemType Directory -Force "C:\opendj-registry" | Out-Null + New-Item -ItemType Directory -Force "C:\Program Files (x86)\OpenDJ" | Out-Null + New-Item -Path HKLM:\SOFTWARE\OpenDJ -Force | Out-Null + Set-ItemProperty -Path HKLM:\SOFTWARE\OpenDJ -Name InstallDir -Value 'C:\opendj-registry\' + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v install-registry.log" + if ($p.ExitCode -ne 0) { Get-Content install-registry.log -Tail 80; throw "msiexec /i (registry detect) failed: $($p.ExitCode)" } + if (-not (Test-Path "C:\opendj-registry\setup.bat")) { Get-Content install-registry.log -Tail 80; throw "installer did not use the registry InstallDir" } + if (Test-Path "C:\Program Files (x86)\OpenDJ\setup.bat") { throw "legacy directory beat the registry InstallDir" } + Write-Host "Registry install location detected OK" + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall3.log" + if ($p.ExitCode -ne 0) { Get-Content uninstall3.log -Tail 80; throw "msiexec /x (registry cleanup) failed: $($p.ExitCode)" } diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9dfeaefeba..971ab7d53d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -26,8 +26,11 @@ concurrency: # contents: write is required to push the generated documentation to the project wiki # with github.token. The doc site push uses a separate PAT, not this token. +# actions: read is required to download the MSI artifact from the triggering Build run +# (a permissions block sets every unlisted scope to none). permissions: contents: write + actions: read jobs: package-deploy-maven: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9b1cbe1210..2ebc09a921 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -164,6 +164,10 @@ jobs: name: Windows MSI release runs-on: 'windows-latest' continue-on-error: true + # contents: write is required by action-gh-release to attach the MSI to the release; + # the workflow-level default above is contents: read. + permissions: + contents: write needs: - release-maven steps: 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 5770bfc24d..c792b2a6a7 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 @@ -644,7 +644,7 @@ On Windows you can install OpenDJ directory server from the `.msi` package. The . Make sure a supported Java runtime is available, as described in xref:#before-you-install["To Prepare For Installation"]. + -The installer refuses to install when it cannot detect a Java installation: install a JRE (for example link:https://adoptium.net[Eclipse Temurin, window=\_blank]), set `JAVA_HOME` to your Java installation, or make sure the `java` executable is on the `PATH`, before running it. If your default Java environment is not the one OpenDJ should use, additionally set `OPENDJ_JAVA_HOME` to the correct Java installation (or `OPENDJ_JAVA_BIN` to the absolute path of the `java` command) before you run `setup` or start the server. +The installer itself does not check for or install Java, but `setup` and the server require it: install a JRE (for example link:https://adoptium.net[Eclipse Temurin, window=\_blank]) and set `JAVA_HOME` to your Java installation, or make sure the `java` executable is on the `PATH`. If your default Java environment is not the one OpenDJ should use, set `OPENDJ_JAVA_HOME` to the correct Java installation (or `OPENDJ_JAVA_BIN` to the absolute path of the `java` command) before you run `setup` or start the server. . Install the package, either with the GUI or silently: + @@ -660,7 +660,7 @@ The package is not code-signed, so Windows SmartScreen or User Account Control m C:\> msiexec /i opendj-{opendj-version}.msi /quiet OPENDJ="C:\opendj" ---- + -By default the x64 package installs under `C:\Program Files\OpenDJ`. +When `OPENDJ` is not given, the installer uses an existing OpenDJ installation directory when it detects one — the location recorded in the registry by a previous x64 package, or the legacy 32-bit default `C:\Program Files (x86)\OpenDJ` — and otherwise installs under `C:\Program Files\OpenDJ`. . Configure OpenDJ directory server by running the `setup` command, described in xref:../reference/admin-tools-ref.adoc#setup-1[setup(1)] in the __Reference__, from the installation directory. Use `setup.bat` for the GUI wizard or `setup.bat --cli` for the command-line: + 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 19531ab9f8..cbfebd2d58 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 @@ -70,7 +70,7 @@ To move to a newer version, edit the `default.java-home` setting in the `opendj/ . Download the latest release from the link:https://github.com/OpenIdentityPlatform/OpenDJ/releases[GitHub, window=\_blank] site. -. (Optional) If you are upgrading OpenDJ directory server on Windows, and OpenDJ is registered as a Windows service, disable OpenDJ as a Windows service before upgrade, as in the following example: +. (Optional) If you are upgrading OpenDJ directory server installed from the cross-platform (.zip) delivery on Windows, and OpenDJ is registered as a Windows service, disable OpenDJ as a Windows service before upgrade, as in the following example: + [source, console] @@ -79,6 +79,8 @@ C:\path\to\opendj\bat> windows-service.bat --disableService ---- + After upgrade, you can enable OpenDJ as a Windows service again. ++ +This step does not apply to servers installed from the `.msi` package: the installer manages the `OpenDJ Server` service itself (see xref:#upgrade-msi["To Upgrade the Windows MSI Installation"]), and `windows-service.bat --disableService` refuses to remove the installer-managed service. . Make sure you perform a full backup of your current OpenDJ installation to revert if the upgrade fails. + diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml b/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml index aa5ea6b003..42a15f7550 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml +++ b/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml @@ -30,8 +30,13 @@ This module generates an OpenDJ MSI package using the WiX Toolset v5 .NET tool - (cross-platform; no wine). The `wix` tool must be on the PATH (CI installs it via - `dotnet tool install --global wix`). + (Windows only: WiX's build task P/Invokes msi.dll). The `wix` tool must be on the + PATH with the UI extension installed: + set DOTNET_ROLL_FORWARD=Major + dotnet tool install --global wix --version 5.0.2 + wix extension add -g WixToolset.UI.wixext/5.0.2 + The module is activated by the opendj-packages distribution-windows-msi profile + only when %USERPROFILE%\.dotnet\tools\wix.exe exists. @@ -49,26 +54,6 @@ ${project.groupId}.${project.artifactId} - - - org.codehaus.mojo - build-helper-maven-plugin - - - attach-msi-and-bundle - package - - attach-artifact - - - - ${msi.file}msi - - - - - - @@ -120,10 +105,11 @@ - + org.codehaus.mojo exec-maven-plugin + 3.6.3 wix-build-msi @@ -153,6 +139,29 @@ + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-msi + package + + attach-artifact + + + + ${msi.file}msi + + + + + diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index cfb0d85b79..9e0069eb50 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -26,47 +26,47 @@ - + + - - + Two separate searches with explicit SetProperty ordering (AppSearch row order is + formally undefined): the registry value written by this package (custom paths, new + installs) beats the legacy x86 default directory ([ProgramFilesFolder] is + Program Files (x86) in an x64 package). The legacy-directory fallback applies to + fresh installs only; the registry SetProperty is deliberately unconditional + (Remember Property pattern) so maintenance and uninstall resolve the real location. + Both results apply only when OPENDJ was not set explicitly (command line / UI). --> + - - - - - - - - - + + - + + + + + - - - - - + + @@ -137,6 +137,23 @@ Arguments="start "[OPENDJ]."" Vital="no"/> + + + + + + + + + @@ -163,7 +180,15 @@ - + + + + + diff --git a/opendj-packages/opendj-msi/pom.xml b/opendj-packages/opendj-msi/pom.xml index 1611afa4bb..39749b2a8f 100644 --- a/opendj-packages/opendj-msi/pom.xml +++ b/opendj-packages/opendj-msi/pom.xml @@ -13,6 +13,7 @@ information: "Portions Copyright [year] [name of copyright owner]". Copyright 2015-2016 ForgeRock AS. + Portions Copyright 2026 3A Systems, LLC. --> 4.0.0 @@ -32,9 +33,10 @@ This module contains configuration and generic plugin call to build OpenDJ MSI packages. - + opendj-msi-standard diff --git a/opendj-packages/pom.xml b/opendj-packages/pom.xml index d6d05e72d9..f17635345a 100644 --- a/opendj-packages/pom.xml +++ b/opendj-packages/pom.xml @@ -13,6 +13,7 @@ information: "Portions Copyright [year] [name of copyright owner]". Copyright 2015-2016 ForgeRock AS. + Portions Copyright 2026 3A Systems, LLC. --> 4.0.0 @@ -77,12 +78,26 @@ windows - - opendj-msi opendj-docker + + distribution-windows-msi + + + windows + ${env.USERPROFILE}/.dotnet/tools/wix.exe + + + opendj-msi + + ${project.groupId}.${project.artifactId} diff --git a/opendj-server-legacy/src/build-tools/windows/service.c b/opendj-server-legacy/src/build-tools/windows/service.c index 3ec27cee87..cb923424f0 100644 --- a/opendj-server-legacy/src/build-tools/windows/service.c +++ b/opendj-server-legacy/src/build-tools/windows/service.c @@ -1039,6 +1039,23 @@ static void normalizeInstanceDir(char* dir) } } // normalizeInstanceDir +// ---------------------------------------------------- +// Expands 8.3 short-name components (e.g. PROGRA~1) so that the short +// and long spellings of the same existing path compare equal. When the +// path cannot be resolved (for example it no longer exists) it is left +// untouched. +// ---------------------------------------------------- + +static void expandLongPath(char* path) +{ + char expanded[COMMAND_SIZE]; + DWORD len = GetLongPathName(path, expanded, COMMAND_SIZE); + if ((len > 0) && (len < COMMAND_SIZE)) + { + strcpy(path, expanded); + } +} // expandLongPath + // ---------------------------------------------------- // Tells whether two service command lines refer to the same server // instance. The strings cannot be compared verbatim because every @@ -1046,8 +1063,9 @@ static void normalizeInstanceDir(char* dir) // '"\lib\opendj_service.exe" start ""' while the MSI // ServiceInstall writes the executable unquoted (when the path has no // spaces) and the instance dir with a trailing backslash. Instead the -// executable path, the subcommand and the normalized instance dir are -// compared token by token, case-insensitively. +// executable path, the subcommand and the normalized instance dir +// (both expanded from 8.3 short names) are compared token by token, +// case-insensitively. // ---------------------------------------------------- static BOOL serviceCmdsMatch(const char* cmd1, const char* cmd2) @@ -1069,8 +1087,13 @@ static BOOL serviceCmdsMatch(const char* cmd1, const char* cmd2) p2 = nextCmdToken(p2, sub2, COMMAND_SIZE); nextCmdToken(p2, dir2, COMMAND_SIZE); + expandLongPath(exe1); + expandLongPath(exe2); + normalizeInstanceDir(dir1); normalizeInstanceDir(dir2); + expandLongPath(dir1); + expandLongPath(dir2); return (_stricmp(exe1, exe2) == 0) && (_stricmp(sub1, sub2) == 0) @@ -2635,7 +2658,21 @@ int removeService() code = getServiceName(cmdToRun, serviceName); if (code == SERVICE_RETURN_OK) { - returnCode = removeServiceWithServiceName(serviceName); + if (_stricmp(serviceName, MSI_SERVICE_NAME) == 0) + { + // The MSI-managed service belongs to the installer: deleting it here + // would leave msiexec /x targeting a key that no longer exists, and a + // later --enableService would re-create it under a different key. + fprintf(stdout, + "The service is managed by the OpenDJ installer (MSI) " + "and is removed when the package is uninstalled.\n"); + debug("Refusing to remove the MSI-managed service '%s'.", serviceName); + returnCode = 3; + } + else + { + returnCode = removeServiceWithServiceName(serviceName); + } } else { diff --git a/opendj-server-legacy/src/build-tools/windows/service.h b/opendj-server-legacy/src/build-tools/windows/service.h index 5b3330ecb7..1d99c53b2a 100644 --- a/opendj-server-legacy/src/build-tools/windows/service.h +++ b/opendj-server-legacy/src/build-tools/windows/service.h @@ -58,6 +58,13 @@ // ---------------------------------------------------- #define EVENT_LOG_KEY "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s" +// ---------------------------------------------------- +// Service key name registered by the MSI package (WiX ServiceInstall). +// This service belongs to the installer: windows-service.bat must not +// delete it, or msiexec /x is left targeting a key that no longer exists. +// ---------------------------------------------------- +#define MSI_SERVICE_NAME "OpenDJ" + // ---------------------------------------------------- // Max size of the registry key // ---------------------------------------------------- From be03df284cc03d17532657b203f480d3026adcec Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Thu, 6 Aug 2026 18:10:19 +0300 Subject: [PATCH 27/52] Refresh the Windows launcher binaries; make their build reproducible (/Brepro) lib/*.exe are taken from the windows-exe-11 artifact of Build run 31112196230: opendj_service.exe now refuses to remove the MSI-managed service and expands 8.3 paths in serviceCmdsMatch; the launchers pick up only PE-timestamp changes. /Brepro is added to cl and link so the PE TimeDateStamp becomes a content hash: without it every build differs in the timestamp fields and the binaries-match-sources CI guard could never pass. These binaries still predate the flag, so the guard stays red for one more run; the follow-up refresh from the first /Brepro build is final. --- .../lib/launcher_administrator.exe | Bin 163840 -> 163840 bytes opendj-server-legacy/lib/opendj_service.exe | Bin 175104 -> 175616 bytes opendj-server-legacy/lib/winlauncher.exe | Bin 162816 -> 162816 bytes .../src/build-tools/windows/Makefile | 8 ++++++-- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/opendj-server-legacy/lib/launcher_administrator.exe b/opendj-server-legacy/lib/launcher_administrator.exe index f29f6d04b6791eaf4096c5cedb399cb274aed71b..d7fecc2a0dcfdac69a52b1da8d3c71adc3b4540c 100644 GIT binary patch delta 42 wcmZo@;A&{#+Q7lclsA7e7o#7u^a`ftXvX$vM#k;Yj7*6RK=JMS9GRT#00)c=Q2+n{ delta 42 wcmZo@;A&{#+Q7lcWF9k_i_wpHjUsb%G-G=-BjfgHMy5mup!oKEj!aH=0QQRuXaE2J diff --git a/opendj-server-legacy/lib/opendj_service.exe b/opendj-server-legacy/lib/opendj_service.exe index a8da61e427a7295ccf697e2526f0fa17792b6332..656928bb7b7fb63177f13efd97bd24d23a179120 100644 GIT binary patch delta 24205 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 X^gn2>G+#E?o1OMDyu`qNCHwyX(u$&E diff --git a/opendj-server-legacy/lib/winlauncher.exe b/opendj-server-legacy/lib/winlauncher.exe index 17f5c41df5980ff6bce6bd348d7e719585eb39ec..d7900c6c6021a6e0c0b0ef1aead3080b3807ff01 100644 GIT binary patch delta 34 ocmZqp!P)SGa{~t>Q{Mb$F2;5)M#k-2j7*yxfc)+I9GRS~0LuXilUYnN7h^jYBja{1My5>;K>qf9j!aHg0K6v&?*IS* diff --git a/opendj-server-legacy/src/build-tools/windows/Makefile b/opendj-server-legacy/src/build-tools/windows/Makefile index c1da51e953..b03970d73c 100644 --- a/opendj-server-legacy/src/build-tools/windows/Makefile +++ b/opendj-server-legacy/src/build-tools/windows/Makefile @@ -13,6 +13,7 @@ # # Copyright 2008 Sun Microsystems, Inc. # Portions Copyright 2011 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. # # This is the Makefile than can be used to generate the executables @@ -36,10 +37,13 @@ CC=cl SERVICE_PROGNAME=opendj_service.exe LAUNCHER_ADMINISTRATOR_PROGNAME=launcher_administrator.exe WINLAUNCHER_PROGNAME=winlauncher.exe -LINKER=link -nologo /machine:x86 +# /Brepro makes the outputs reproducible (content-hash PE timestamps instead of the +# build time), so CI can assert that the committed lib/*.exe match the sources with a +# plain byte comparison. +LINKER=link -nologo /machine:x86 /Brepro LIBS=advapi32.lib -CFLAGS= -D_WINDOWS -nologo -W3 -O2 +CFLAGS= -D_WINDOWS -nologo -W3 -O2 /Brepro RC=rc MC=mc MT=mt From ac4eeedf19e2311fdfb059a09955268270475dd0 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Thu, 6 Aug 2026 18:55:10 +0300 Subject: [PATCH 28/52] Refresh the launcher binaries from the first /Brepro build lib/*.exe are taken from the windows-exe-11 artifact of Build run 31114568111 - the first build with /Brepro, so the PE timestamp fields are now content hashes. No source change: this only realigns the committed bytes with the reproducible toolchain output, after which the binaries-match-sources CI guard stays green. --- .../lib/launcher_administrator.exe | Bin 163840 -> 163840 bytes opendj-server-legacy/lib/opendj_service.exe | Bin 175616 -> 175616 bytes opendj-server-legacy/lib/winlauncher.exe | Bin 162816 -> 162816 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/opendj-server-legacy/lib/launcher_administrator.exe b/opendj-server-legacy/lib/launcher_administrator.exe index d7fecc2a0dcfdac69a52b1da8d3c71adc3b4540c..12649a9dd1b8bd59b809e56bced9593c9befcb77 100644 GIT binary patch delta 1920 zcmeIx|8Em@7zglsK0UNswm4y6b!F*D8BW6NUB4OzZe{LU3{0)0+2-1;?tkkXd_-H*E6~zB2^f&<|j|ue(}_PJwCqn%jmsKG?}5OGGH*J zFs|<2(m(QEpGzl{hJtIvF8>|dw$jWqzFvtsxA0V^*h|kd$yPd7d9tF7C%5w6>MI%w zNZVhWppdfmrNT7yls)fgXi{0`dx9~8Pbpuw`xz=!e%jYX(_ z(9!LbP@YyF;mM&q`*}H0SlTgMg^Hht5A(RUzOT;mj9aHPkG2!Vl?&gdqv<;7`gfJ& zm5RoiC@2k%xzL|Z9-2d8ukD}zJx~PZF;Jquo~CX=n}>?s0WMbEKhNDTRGY1F++noTtgo*^2&Y>d8kl6 z?x9Z97kOy`QBZZ)(WVp{QNM4ZT{&3xN-tGsFs@O>GZ|mT42`q@u&RvF`&v36zkHf< zX-4imO?n!X-^H+erryb2xmbVaZeL%I%c$MyOzWwbHlMh>f7PA4(Fq@t-~2lnNAiti zvPQn1>{BDB$0#>tw$zVO^#vb0PF+_wFm47?n;55qd?vm zaSI?9iope&VHfOy2poq~5Qp2KZDE`q98dbX3)M6ytI_0f8jj0v^VhZ489O>U{Phi}8blS3F~6AbPv#kTkSb=;2E%GWG@t|>!!=+5CdMntFCOx^&`$tU9S<5;mRPVRzdD_K-blpR_0JnGT)9;&7;WTi6-;3w8=V=l}o! delta 1875 zcmeIx|8Emz90&0GJS|wr7AuTdTuBDu%NAhXwbw6(p{(Fo7lK76X#lr&Eo=-N%^ap7 z%Qn6x#SPPWlbc8YmBbB}*m%e_xGXs5#JMaNS!5D|g+K&c+uR)KJO$_nC7&J4 zrVd55G#OYjAfG)#ibD59)?ZAAvf6}jSl10|HDq32LpsdzWHzd#n{%F!kww^Dw5ih=w}_>+}0 znI4k5&g>^md0u_mNM_}wFTF%j=|Im0R9x>lWyHh9zq({(qhV$HKs`}Xx%zD;nuaC) zJ0H2FqQM&SOWlKI=uh8wO`)iAN~<qBXHZ^#`vi7xR*ZK(!?w-R7r%FrMXI>l zf;;*3?g57D?EEux5p~FWt+a`vYRXCji`eKEwR06+GE!3A>m}DrHoise*+ic*a?9Zg zsvwKpUqKD1FA7jLkze%(Y3DTRP={;i-MQHIMk{SJv(YLQFJ)*c8?T!DIaOtlJ~B~* z{Q3o2NF#E?1+vmU`2!5gMk+nrt!tGN599HcviYWio{W~#d-n4;kFA_|nCuK8`OTBb z6q0+=Nm16*eMC8PgceSlEDfVnT^C~g)YQL~aU*aIbeLMhxGcy6HxxrT)WSYE4BgNN zgK!1LVCpu;S-}ZwpavQs4xdLDcNXIS{0P@Thly>hi8F0yTrRj_J=8)Y#NlH&4Sk@& z75EJ%!1^ZRmcUxr0(B6BBXAOuFbpZU2j*H_2b@p>We})sV%*!9#NaS=LoaBM0v#Se z#tv)-5!ON&>fjwX3MZi#h9L#F;XW`txfPt?gG#7}7<9l1Bfk37-4|(D&E!8?K3Bvn z(tReX86LLDkbjwRTtQtpSRb6fYuB!DWfjM9u>j+Y7z^s^L-V~wMVNA}a@)&n=JNQz zQ)Q1*?N7uuY)F@PAlC2{T0|#XN7Jz^`6^oE=T+kXU|FzrGG$Mv3K5IZKQS>K>zC&g zvu$k)%<{QnmU^}%=;7u~k!It5IX~v8=Bk4pc}FRmEo-aUip()Y)7f#1S@N6`_KRVt z($h9~maKc3QO@<(S?x3W-5LO9gLR8o%v3O|xCLneDvYXOGyU_GWvl{kr|8-6ZCTyjUnk#JJck zCPYotMYDr<_#6>O+>vl-4&7mP^7EWNXT%wICY+j6cbZ+i%jb%?;;w{CbB(!lSBBfH J<~Op7^cUh0JsSW3 diff --git a/opendj-server-legacy/lib/opendj_service.exe b/opendj-server-legacy/lib/opendj_service.exe index 656928bb7b7fb63177f13efd97bd24d23a179120..76d97cbfd64055c201c74e3fb0f01c675600ab30 100644 GIT binary patch delta 2127 zcmeIyk8cxY7zgls-WKR)hlqt0hNdG$${;A&lHK+9>PQ9>oZ1ka`%!di7ls>U!-Y&+ zngz-V!noN(AlO8dB8wRuQnDZ^6QPO2po}qKLNObR9}xrs#F*jtHYM;c7@K_hzW2P( z^W5(X^rZ*-(%Utp-uvt9KSeDqP*q=J;#)M0j*6>kCh;xVSz?krWR_>J6ZvG4?+bnv zD+)>H_R>uG3)@9inm**>!pCg-kQgqQJW<*54OEnW-_^C~uwi7$FucSJA^A*!BaM0g zsebvD731k8IbL>?Sn;}%j;AVe)l@Bysr0Lo&zuIQOZR3z>`Q-TC_?;bUI<@UY~HCipbR8MGp>9-6< zN%3a?YfQ62bPZIINo*T%qdQ&RJ&KCtJ=eV&RO#-{dxk>s@=>%C)p1oiwWChjucfbP zP^!qFFw=YzzmY*9My7cEIMPlhuN2IuQYwmH%%}XRsLCv%^J;XtQ%?G4DH+%LXcuFe zjncPuRE{>fdTK;^OFc~_bcwB``ZV&!pAS&S9F(2iODA$DCSjZvKh;M^#xU(VDbkM{ zTPYptrzzx?&SJ1uHoLg1w|zqoH*E^LjhYQEZFv6O+~nZrZwx&=*bv6z=_eOcSPUwQ z>h;o`0m@<+7Y@+0wBh7BB#VErCVzJe<8FX@GvjnH74o1E-0&WJ46X1L9E2oXfLp+c zjGG9vU_O+C@@vMp6=HAzy5JoA4nv@AWt_2<`MEqy=7R@TLI`%iJ~#|NK@VJp+o1gv z2MJbq9cm#65tzJ{aS4oF&b zhXqgqwGe~|?1N6|g==sR*cQg=AqT9m5Io?6AZ&&m@J%uPI-v({!RXI$8^8d0PzZ~_ z1J%#~o1qPkK`&f`AsCCZ&xxP7LNBf!{!B!wm_AeaUMTlt92nu&TI^^U!@YklzMzVg zs{AGu$IbRtE~#5$T(xRd<=gKgOBcdL!#LYl_l|L1K>?W|=v0%54gct=KlrK3=*%GfO$^mTX<*1D49{#kXzhC~=bV zTn=K6j@*NgOS-w7O_IjdFlR>NIv1y`hA{4w%4*mZRcW)UC3}KYyPT;dPc7?K6^4~S zB#7s_=!7Xkp-?1L3SOaBXb=KIldxWh3Nhi3&?`I; z^k&|?*z7S^o1^B0Ic4T728+{DWGS|kTJ~EGT6!%HESyzqby_{vMr*(twI-}7D`zv< zoHmawV2j!kMqA3p*$sB5-D3~fqxOV7W#=3QhtuJ41RUEPQO6-iBK~e0+eUu__hFh6 delta 2068 zcmeIy|8Em@7zglsK38O$U7T}Zg=q#EGQMOEx466Z+HQ3}01}+BAx# z(3UybmjZ6w+*Ks9L?R#yDIRhSA!JO%#Q>S|tw00CbbJX5ATHXF1$^J8BL9N%l2@O* z=kq*Iuld|H5K9Zh(!wcZSh>TyTsG1?KGVs|3uy{%mp9N1%5I-DQSPH^%2cPZlf}fT ze~5mb>Yn&e>Vgz@^7XP~O`yAvlC92p*68Xj3 zQhO>Z`K$ZY*VbfGimENTLoBalbmHl%LIahlV{7~d`JEM+YG~OhM%C)l6(1QWq~5B# z$x}o=yQZH-Thv`%yOAYZ)Ej{go=oZojT7|J&_>Nn0k!;S9Z{Fs)B6OY9`%P~sXmoTv=;(&XcpQo?5C5{DWD+E)K16f=vbC$ zRyq^dSV=jYplq6{TtJYdRtIEU3&Hpot7|{s2u$9VzyrSpJnY`n%g1cMM`M2=~Fbm2ufH6Kt>mR>FtS23>Fv z`XCCo!5}kkGQ0x%u>{cr0oVdN;Tt#(=O6*YGV^oB4m5%Q^Pw8nLMwE_SFjI`z>koC z`;hf1a+rA_y=S+^`(h!p3rZY=eE!2bWKI z$%cFopbW}kIW)o-5Qbhj2iJgUC$G~>8%F*nI%}Cp{+$(R^J-ZI?>F!qm+z@r>|LC@ zZr!??B}=hOcbl+ti1{AxTe)*eOZA-_dMxL5>$&8=bI#Ga;m2~LbzC#!wvWX;-^lm) z^xo~CFfNbdl&Py&`m|%X$U-u|cBG(CFNh*{hW^PF>A7xY(JCglPsvd7RqSc+EQL2{~o3x6L@JeeFu7PLLewc^2XaSW6Ge_{S}FU}<$&KAo>mslazh(0kOc8FoI zU%V@3mWJ4&*@Ldd5)6+ diff --git a/opendj-server-legacy/lib/winlauncher.exe b/opendj-server-legacy/lib/winlauncher.exe index d7900c6c6021a6e0c0b0ef1aead3080b3807ff01..a80a4ee9bc06fb935950a4065e404e977854d4a9 100644 GIT binary patch delta 1912 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 BJnaAg From c287e5b3cfa2cadffae2626b71977a50b0b56fda Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Fri, 7 Aug 2026 09:25:07 +0300 Subject: [PATCH 29/52] Fix the two new MSI CI scenarios The registry install-location action must run before the legacy-directory fallback: both are guarded by NOT OPENDJ, so with the legacy action first an existing Program Files (x86)\OpenDJ directory won over the InstallDir registry value. Precedence is now explicit OPENDJ -> registry -> legacy directory. The --disableService guard test failed on the expected non-zero exit code of windows-service.bat (the pwsh wrapper turns the last exit code into the step result): capture it, assert the refusal, and finish with an explicit exit 0. --- .github/workflows/build.yml | 7 ++++++- .../resources/msi/package.wxs | 21 ++++++++++--------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 35f451635a..0e6fbc6de9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -680,10 +680,15 @@ jobs: run: | # Deleting the service here would leave msiexec /x targeting a key that no longer # exists; opendj_service.exe refuses to remove the MSI-managed key 'OpenDJ'. + # The refusal makes the bat exit non-zero, and the pwsh shell wrapper would turn + # that into a step failure - so capture it and finish with an explicit exit 0. $root = $env:OPENDJ_ROOT & "$root\bat\windows-service.bat" --disableService + $code = $LASTEXITCODE + if ($code -eq 0) { throw "--disableService reported success on an MSI-managed service" } if (-not (Get-Service OpenDJ -ErrorAction SilentlyContinue)) { throw "--disableService deleted the MSI-managed service" } - Write-Host "--disableService left the MSI-managed service in place (exit $LASTEXITCODE)" + Write-Host "--disableService refused as expected (exit $code) and left the service in place" + exit 0 - name: Uninstall MSI shell: pwsh run: | diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 9e0069eb50..2cb9c7f444 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -42,12 +42,13 @@ + formally undefined). Precedence: an explicit OPENDJ (command line / UI) always + wins; then the registry value written by this package (custom paths, new + installs); then the legacy x86 default directory ([ProgramFilesFolder] is + Program Files (x86) in an x64 package), fresh installs only. The registry action + runs FIRST: each action is guarded by NOT OPENDJ, so whichever runs earlier wins + and the registry has no NOT Installed guard (Remember Property pattern) so + maintenance and uninstall resolve the real location. --> @@ -55,11 +56,11 @@ - - + From af7d80f9dadb1e669d732e20a86777cbfa1003d9 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Fri, 7 Aug 2026 18:15:07 +0300 Subject: [PATCH 30/52] Address review round 2: service ownership edge cases - opendj_service.exe refuses to remove the MSI-managed key with a dedicated code (4): uninstall.bat and windows-service.bat now treat it as an informational skip instead of failing, and --cleanupService is covered too - Name the MSI service 'OpenDJ' (key = display name): the windows-service.bat naming loop checks key names only, so any other display name made every additional zip instance's --enableService fail with a duplicate name - Drop Vital="no": a failed service registration fails the install instead of reporting success with no service; Stop="uninstall" keeps repair from silently stopping a production server - Stop a running legacy service before RemoveExistingProducts (immediate action, full net.exe path) and remove it only when an existing OpenDJ was detected - a fresh install must not touch an unrelated instance's service - Refuse a silent upgrade when the existing location cannot be determined (5.1.x wrote no registry value) instead of relocating to the default - CI: upgrade from 5.1.2 at its real x86 default without OPENDJ, uninstall.bat and refusal scenarios, if-no-files-found: error on the MSI-chain uploads, nmake/xcopy error propagation, binaries guard downgraded to a warning - Manage exec-maven-plugin centrally (3.6.3), document the new behaviors --- .github/workflows/build.yml | 88 ++++++++++++++----- .github/workflows/deploy.yml | 3 + .github/workflows/release.yml | 8 +- .../asciidoc/install-guide/chap-install.adoc | 15 +++- .../install-guide/chap-uninstall.adoc | 4 +- .../asciidoc/install-guide/chap-upgrade.adoc | 10 +-- .../opendj-msi/opendj-msi-standard/pom.xml | 4 +- .../resources/msi/package.wxs | 65 +++++++++++--- opendj-server-legacy/pom.xml | 1 - .../src/build-tools/windows/service.c | 36 ++++---- .../guitools/uninstaller/Uninstaller.java | 3 + .../server/tools/ConfigureWindowsService.java | 12 +++ .../org/opends/messages/tool.properties | 3 + pom.xml | 6 ++ 14 files changed, 193 insertions(+), 65 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0e6fbc6de9..9c29fa83fa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -80,8 +80,8 @@ jobs: shell: cmd run: | cd opendj-server-legacy\src\build-tools\windows - nmake all - xcopy /Y *.exe ..\..\..\lib\ + nmake all || exit /b 1 + xcopy /Y *.exe ..\..\..\lib\ || exit /b 1 git status - name: Upload Windows exe artifacts if: runner.os == 'Windows' @@ -95,9 +95,17 @@ jobs: # The release pipeline builds the server zip on Linux from the committed # opendj-server-legacy/lib/*.exe, so a source change that is not re-committed as a # refreshed binary would ship the old wrapper in the tagged release while CI stays - # green. The freshly built binaries are uploaded just above, so when this fails, - # refresh lib/*.exe from the windows-exe artifact of this very run and commit them. - run: git diff --exit-code -- opendj-server-legacy/lib + # green. Warning-only: an MSVC toolchain bump on the runner image also changes the + # bytes, and failing here would kill the artifact consumers (test-msi*, deploy.yml). + # The freshly built binaries are uploaded just above - refresh lib/*.exe from the + # windows-exe artifact of this very run and commit them. + continue-on-error: true + shell: bash + run: | + if ! git diff --exit-code -- opendj-server-legacy/lib; then + echo "::warning title=Stale launcher binaries::opendj-server-legacy/lib/*.exe differ from what this CI build produced (source change or MSVC toolchain bump). Refresh them from the windows-exe artifact of this run." + exit 1 + fi - name: Set Integration Test Environment id: failsafe if: runner.os == 'Linux' @@ -667,13 +675,14 @@ jobs: $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" & "$root\setup.bat" -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --addBaseEntry --cli --acceptLicense --no-prompt --doNotStart if ($LASTEXITCODE -ne 0) { throw "setup.bat failed: $LASTEXITCODE" } - # The service is already registered by the MSI (WiX ServiceInstall); just start it. - net start "OpenDJ Server" + # The service is already registered by the MSI (WiX ServiceInstall, key and + # display name 'OpenDJ'); just start it. + net start OpenDJ if ($LASTEXITCODE -ne 0) { throw "net start failed: $LASTEXITCODE" } for ($i=0; $i -lt 12; $i++) { try { $c = New-Object System.Net.Sockets.TcpClient('localhost', 1636); $c.Close(); break } catch { Start-Sleep -Seconds 5 } } & "$root\bat\ldapsearch.bat" --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1 if ($LASTEXITCODE -ne 0) { throw "ldapsearch failed: $LASTEXITCODE" } - net stop "OpenDJ Server" + net stop OpenDJ if ($LASTEXITCODE -ne 0) { throw "net stop failed: $LASTEXITCODE" } - name: windows-service.bat must not delete the MSI-managed service shell: pwsh @@ -689,12 +698,25 @@ jobs: if (-not (Get-Service OpenDJ -ErrorAction SilentlyContinue)) { throw "--disableService deleted the MSI-managed service" } Write-Host "--disableService refused as expected (exit $code) and left the service in place" exit 0 + - name: uninstall.bat works on an MSI install and leaves the service to msiexec + shell: pwsh + run: | + # The uninstaller must treat the MSI-managed service as a skip (not an error), + # delete the instance files, and leave the service for msiexec /x to remove. + $root = $env:OPENDJ_ROOT + & "$root\uninstall.bat" --cli --remove-all --no-prompt --forceOnError --quiet + if ($LASTEXITCODE -ne 0) { throw "uninstall.bat failed: $LASTEXITCODE" } + if (Test-Path "$root\config\config.ldif") { throw "uninstall.bat did not remove the instance files" } + if (-not (Get-Service OpenDJ -ErrorAction SilentlyContinue)) { throw "uninstall.bat removed the MSI-managed service" } + Write-Host "uninstall.bat completed and left the MSI-managed service in place" + exit 0 - name: Uninstall MSI shell: pwsh run: | $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall.log" if ($p.ExitCode -ne 0) { Get-Content uninstall.log -Tail 80; throw "msiexec /x failed: $($p.ExitCode)" } + if (Get-Service OpenDJ -ErrorAction SilentlyContinue) { throw "service not removed by msiexec /x" } Write-Host "Uninstalled OK" # Upgrade path: released 5.1.2 x86 MSI (wine-built, WiX3) -> this build's x64 MSI. @@ -722,11 +744,12 @@ jobs: try { Invoke-WebRequest -Uri $uri -OutFile opendj-5.1.2.msi; break } catch { if ($i -eq 5) { throw }; Write-Host "download attempt $i failed, retrying"; Start-Sleep -Seconds (10 * $i) } } - # The released 5.1.2 scripts cannot run from a directory with spaces (unquoted - # java.io.tmpdir), so put the old install into C:\opendj. - $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart OPENDJ=C:\opendj /l*v install-old.log" + # 5.1.2 already contains the script-quoting fixes from #671 (the tag post-dates + # the merge), so install it into its own x86 default - spaces and parentheses + # included - to reproduce the real upgrade starting point. + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart /l*v install-old.log" if ($p.ExitCode -ne 0) { Get-Content install-old.log -Tail 80; throw "msiexec /i (5.1.2) failed: $($p.ExitCode)" } - $root = "C:\opendj" + $root = "C:\Program Files (x86)\OpenDJ" if (-not (Test-Path "$root\setup.bat")) { Get-Content install-old.log -Tail 80; throw "5.1.2 install root not found at $root" } $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" & "$root\setup.bat" -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --addBaseEntry --cli --acceptLicense --no-prompt --doNotStart @@ -738,25 +761,26 @@ jobs: if ($LASTEXITCODE -ne 0) { throw "net start (5.1.2) failed: $LASTEXITCODE" } net stop "OpenDJ Server" if ($LASTEXITCODE -ne 0) { throw "net stop (5.1.2) failed: $LASTEXITCODE" } - - name: Upgrade with the newly built MSI (same directory passed explicitly) + - name: Upgrade with the newly built MSI (no OPENDJ - location auto-detected) shell: pwsh run: | $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName if (-not $msi) { throw "MSI not found in the windows-latest-11 artifact" } - $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart OPENDJ=C:\opendj /l*v upgrade.log" + # The headline upgrade path: no OPENDJ property, the installer must find the + # legacy default directory on its own. + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade.log" if ($p.ExitCode -ne 0) { Get-Content upgrade.log -Tail 120; throw "msiexec /i (upgrade) failed: $($p.ExitCode)" } - $root = "C:\opendj" + $root = "C:\Program Files (x86)\OpenDJ" # New package files landed in the old directory, not the x64 default if (-not (Test-Path "$root\setup.bat")) { throw "upgrade did not keep the old install dir" } if (Test-Path "C:\Program Files\OpenDJ") { throw "upgrade unexpectedly installed into the x64 default dir" } # Instance data survived if (-not (Test-Path "$root\config\config.ldif")) { throw "instance data (config\config.ldif) lost by the upgrade" } - # Legacy service replaced by the MSI-managed one: display name maps to key 'OpenDJ' - # (match on '= ' only: the 'Name' label in sc.exe output is localized). - $m = sc.exe getkeyname "OpenDJ Server" | Select-String -Pattern "= (.+)$" | Select-Object -First 1 - if (-not $m) { sc.exe query; throw "no service with display name 'OpenDJ Server' found" } - $key = $m.Matches[0].Groups[1].Value.Trim() - if ($key -ne "OpenDJ") { sc.exe query; throw "expected MSI-managed service key 'OpenDJ', got '$key'" } + # Legacy service replaced by the MSI-managed one (key = display name = 'OpenDJ') + $svc = Get-Service OpenDJ -ErrorAction SilentlyContinue + if (-not $svc) { sc.exe query; throw "MSI-managed service 'OpenDJ' not registered" } + if ($svc.DisplayName -ne "OpenDJ") { throw "expected display name 'OpenDJ', got '$($svc.DisplayName)'" } + if (Get-Service -DisplayName "OpenDJ Server" -ErrorAction SilentlyContinue) { sc.exe query; throw "legacy service 'OpenDJ Server' still present after the upgrade" } sc.exe qc OpenDJ "OPENDJ_ROOT=$root" | Out-File -FilePath $env:GITHUB_ENV -Append - name: Run upgrade.bat and start the upgraded server @@ -766,13 +790,13 @@ jobs: $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" & "$root\upgrade.bat" --no-prompt --acceptLicense --force if ($LASTEXITCODE -ne 0) { throw "upgrade.bat failed: $LASTEXITCODE" } - net start "OpenDJ Server" + net start OpenDJ if ($LASTEXITCODE -ne 0) { throw "net start (upgraded) failed: $LASTEXITCODE" } for ($i=0; $i -lt 12; $i++) { try { $c = New-Object System.Net.Sockets.TcpClient('localhost', 1636); $c.Close(); break } catch { Start-Sleep -Seconds 5 } } # The pre-upgrade data must still be served & "$root\bat\ldapsearch.bat" --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1 if ($LASTEXITCODE -ne 0) { throw "ldapsearch after upgrade failed: $LASTEXITCODE" } - net stop "OpenDJ Server" + net stop OpenDJ if ($LASTEXITCODE -ne 0) { throw "net stop (upgraded) failed: $LASTEXITCODE" } - name: Auto-detect the legacy default directory on a fresh install shell: pwsh @@ -808,3 +832,21 @@ jobs: Write-Host "Registry install location detected OK" $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall3.log" if ($p.ExitCode -ne 0) { Get-Content uninstall3.log -Tail 80; throw "msiexec /x (registry cleanup) failed: $($p.ExitCode)" } + - name: Silent upgrade from an undetectable directory must refuse with guidance + shell: pwsh + run: | + # A 5.1.x at a custom directory wrote no registry value: a /quiet upgrade + # without OPENDJ used to relocate to the default while RemoveExistingProducts + # emptied the old tree. The installer must refuse instead. + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + # No detection signals: remove the leftover legacy default directory. + Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart OPENDJ=C:\opendj-custom /l*v install-custom.log" + if ($p.ExitCode -ne 0) { Get-Content install-custom.log -Tail 80; throw "msiexec /i (5.1.2 custom dir) failed: $($p.ExitCode)" } + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade-custom.log" + if ($p.ExitCode -eq 0) { Get-Content upgrade-custom.log -Tail 80; throw "upgrade without OPENDJ must refuse when the old location cannot be determined" } + if (-not (Select-String -Path upgrade-custom.log -Pattern "passed explicitly" -Quiet)) { Get-Content upgrade-custom.log -Tail 60; throw "expected the explicit-OPENDJ guidance message in the log" } + if (-not (Test-Path "C:\opendj-custom\setup.bat")) { throw "the refused upgrade damaged the original install" } + Write-Host "Upgrade refused with guidance, original install untouched (exit $($p.ExitCode))" + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x opendj-5.1.2.msi /quiet /qn /norestart /l*v uninstall-custom.log" + if ($p.ExitCode -ne 0) { Get-Content uninstall-custom.log -Tail 80; throw "msiexec /x (5.1.2 cleanup) failed: $($p.ExitCode)" } diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 971ab7d53d..88f62f0130 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -126,6 +126,9 @@ jobs: with: name: OpenDJ MSI Package path: windows-build/opendj-packages/opendj-msi/opendj-msi-standard/target/*.msi + # Make a silently-missing MSI visible: the step fails (job continues via + # continue-on-error) instead of warning and publishing nothing. + if-no-files-found: error - name: Upload artifacts OpenDJ Docker Packages uses: actions/upload-artifact@v7 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2ebc09a921..00d591eee5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -98,6 +98,9 @@ jobs: name: release-server-zip retention-days: 1 path: target/checkout/opendj-server-legacy/target/package/*.zip + # A missing zip means release-msi cannot build: fail this step (the job keeps + # going thanks to continue-on-error, but the loss is visible). + if-no-files-found: error - name: Release on GitHub uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 with: @@ -212,7 +215,10 @@ jobs: - name: Build the MSI (packaging only, no rebuild) env: MAVEN_OPTS: -Dhttps.protocols=TLSv1.2 -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.requestSentEnabled=true -Dmaven.wagon.http.retryHandler.count=10 - run: mvn --batch-mode --errors -DskipTests package -pl :opendj-msi-standard --file pom.xml + # -P: do not rely on the wix.exe file-activation of distribution-windows-msi - + # a path drift would otherwise yield "Could not find the selected project in + # the reactor", swallowed by the job's continue-on-error. + run: mvn --batch-mode --errors -DskipTests package -pl :opendj-msi-standard -Pdistribution-windows-msi --file pom.xml - name: Attach the MSI to the GitHub release uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 with: 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 c792b2a6a7..932fcf8fa2 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 @@ -640,7 +640,12 @@ opendj 0:off 1:off 2:on 3:on 4:on 5:on 6:off [#install-msi] .To Install With the Windows Installer (MSI) ==== -On Windows you can install OpenDJ directory server from the `.msi` package. The installer copies the server files to disk and registers the `OpenDJ Server` Windows service, but it does not configure or start a server (run `setup` first) and it does not install a Java runtime. +On Windows you can install OpenDJ directory server from the `.msi` package. The installer copies the server files to disk and registers the `OpenDJ` Windows service, but it does not configure or start a server (run `setup` first) and it does not install a Java runtime. + +[NOTE] +====== +When the installer detects an existing OpenDJ installation (an upgrade, or a detected installation directory), it stops and removes a service registered by the legacy `windows-service.bat` command, replacing it with the installer-managed `OpenDJ` service. Because the service is registered with automatic start, Windows logs a start failure at every boot until the instance has been configured with `setup`. +====== . Make sure a supported Java runtime is available, as described in xref:#before-you-install["To Prepare For Installation"]. + @@ -661,8 +666,10 @@ C:\> msiexec /i opendj-{opendj-version}.msi /quiet OPENDJ="C:\opendj" ---- + When `OPENDJ` is not given, the installer uses an existing OpenDJ installation directory when it detects one — the location recorded in the registry by a previous x64 package, or the legacy 32-bit default `C:\Program Files (x86)\OpenDJ` — and otherwise installs under `C:\Program Files\OpenDJ`. ++ +The service runs as `LocalSystem`. A directory created directly under the drive root (for example `C:\opendj`) is writable by all authenticated users by default, which would let a standard user replace the server scripts that the service runs. Prefer the default location under `Program Files`, or restrict the ACL of a custom installation directory. -. Configure OpenDJ directory server by running the `setup` command, described in xref:../reference/admin-tools-ref.adoc#setup-1[setup(1)] in the __Reference__, from the installation directory. Use `setup.bat` for the GUI wizard or `setup.bat --cli` for the command-line: +. Configure OpenDJ directory server by running the `setup` command, described in xref:../reference/admin-tools-ref.adoc#setup-1[setup(1)] in the __Reference__, from the installation directory. Use `setup.bat` for the GUI wizard or `setup.bat --cli` for the command-line. When OpenDJ is installed under `Program Files`, run the command from an elevated (run as Administrator) prompt — the server writes into its installation directory: + [source, console] @@ -670,12 +677,12 @@ When `OPENDJ` is not given, the installer uses an existing OpenDJ installation d C:\path\to\opendj> setup.bat --cli ---- -. Start the OpenDJ Windows service. The installer already registered it as `OpenDJ Server`; after configuring with `setup`, start it (it is not started automatically during installation): +. Start the OpenDJ Windows service. The installer already registered it as `OpenDJ`; after configuring with `setup`, start it from an elevated prompt (it is not started automatically during installation): + [source, console] ---- -C:\> net start "OpenDJ Server" +C:\> net start OpenDJ ---- ==== 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 3adc45d381..f19a1df58d 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 @@ -162,7 +162,7 @@ Removing the package does not remove your data or configuration. You must remove [#uninstall-msi] .To Uninstall the Windows MSI Package ==== -Remove OpenDJ directory server installed from the `.msi` package like any other Windows program. The uninstaller stops and removes the `OpenDJ Server` Windows service that the package registered. +Remove OpenDJ directory server installed from the `.msi` package like any other Windows program. Removing the package stops and removes the `OpenDJ` Windows service that it registered. * Uninstall the package, either through __Settings > Apps__ (or __Control Panel > Programs and Features__) by selecting OpenDJ and choosing Uninstall, or from the command-line: + @@ -172,7 +172,7 @@ Remove OpenDJ directory server installed from the `.msi` package like any other C:\> msiexec /x opendj-{opendj-version}.msi /quiet ---- + -Uninstalling removes the files installed by the package. Your configured instance data under the installation directory (for example `config`, `db`, and `logs`) is not removed; delete the installation directory manually to remove all files. +Uninstalling removes the files installed by the package. Your configured instance data under the installation directory (for example `config`, `db`, and `logs`) is not removed; delete the installation directory manually, or run `uninstall.bat` before removing the package, to remove all files. The `uninstall.bat` command leaves the `OpenDJ` service in place — the service belongs to the package and is removed by `msiexec /x`. ==== 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 cbfebd2d58..542cf40e75 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 @@ -80,7 +80,7 @@ C:\path\to\opendj\bat> windows-service.bat --disableService + After upgrade, you can enable OpenDJ as a Windows service again. + -This step does not apply to servers installed from the `.msi` package: the installer manages the `OpenDJ Server` service itself (see xref:#upgrade-msi["To Upgrade the Windows MSI Installation"]), and `windows-service.bat --disableService` refuses to remove the installer-managed service. +This step does not apply to servers installed from the `.msi` package: the installer manages the `OpenDJ` service itself (see xref:#upgrade-msi["To Upgrade the Windows MSI Installation"]), and `windows-service.bat --disableService` refuses to remove the installer-managed service. . Make sure you perform a full backup of your current OpenDJ installation to revert if the upgrade fails. + @@ -259,11 +259,11 @@ $ ==== Before starting this procedure, follow the steps in xref:#before-you-upgrade["Before You Upgrade"]. Installing the newer `.msi` performs a major upgrade that replaces the installed program files, so make a full file-system backup of the current installation first. -. Stop the current OpenDJ server (if it runs as a Windows service, `net stop "OpenDJ Server"`). +. Stop the current OpenDJ server (if it runs as a Windows service, `net stop "OpenDJ Server"`, or `net stop OpenDJ` for a server installed from a previous x64 `.msi` package). . Back up the file-system directory where OpenDJ is installed. -. Install the newer package (GUI or silent). The installer detects the existing installation — the location recorded in the registry by a previous x64 package, or the default directory of the older 32-bit package (`C:\Program Files (x86)\OpenDJ`) — and installs into the same directory, so your configured instance data (`config`, `db`, `logs`) is kept and only the program files are replaced. If the older server was installed in a custom directory the installer did not detect, select that directory in the GUI or pass it explicitly: +. Install the newer package (GUI or silent). The installer detects the existing installation — the location recorded in the registry by a previous x64 package, or the default directory of the older 32-bit package (`C:\Program Files (x86)\OpenDJ`) — and installs into the same directory, so your configured instance data (`config`, `db`, `logs`) is kept and only the program files are replaced. If the older server was installed in a custom directory the installer cannot detect, select that directory in the GUI or pass it explicitly; a silent upgrade refuses to continue when it cannot determine the existing location, rather than installing into the default directory: + [source, console, subs="attributes"] @@ -271,7 +271,7 @@ Before starting this procedure, follow the steps in xref:#before-you-upgrade["Be C:\> msiexec /i opendj-{opendj-version}.msi /quiet OPENDJ="C:\path\to\opendj" ---- + -The installer replaces a service registered by the older `windows-service.bat` command with the MSI-managed `OpenDJ Server` service automatically; no manual `--disableService`/`--enableService` is needed. +The installer replaces a service registered by the older `windows-service.bat` command with the installer-managed `OpenDJ` service automatically; no manual `--disableService`/`--enableService` is needed. Custom service configuration (a dedicated service account, recovery actions, dependencies) is not carried over: the service is re-registered with its defaults on every upgrade, so re-apply such hardening afterwards. . Run the `upgrade` command, described in xref:../reference/admin-tools-ref.adoc#upgrade-1[upgrade(1)] in the __Reference__, to bring the configuration and application data up to date with the new binary and script files: + @@ -286,7 +286,7 @@ C:\path\to\opendj> upgrade.bat --no-prompt --acceptLicense [source, console] ---- -C:\> net start "OpenDJ Server" +C:\> net start OpenDJ ---- ==== diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml b/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml index 42a15f7550..627f1353f8 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml +++ b/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml @@ -105,11 +105,11 @@ - + org.codehaus.mojo exec-maven-plugin - 3.6.3 wix-build-msi diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 2cb9c7f444..7a6ef18233 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -69,6 +69,30 @@ + + + + + + + + + + @@ -132,20 +156,21 @@ its own service entry up (msiexec cannot write the canonical '"\lib\opendj_service.exe" start ""' form: it only quotes the exe when the path has spaces). --> - + + Arguments="start "[OPENDJ].""/> + - - + Stop="uninstall" Remove="uninstall" Wait="yes"/> @@ -157,6 +182,23 @@ + + + + + + + diff --git a/opendj-server-legacy/pom.xml b/opendj-server-legacy/pom.xml index 8bb06a60c5..9a2eb22138 100644 --- a/opendj-server-legacy/pom.xml +++ b/opendj-server-legacy/pom.xml @@ -1403,7 +1403,6 @@ org.codehaus.mojo exec-maven-plugin - 1.3.2 mib-generation diff --git a/opendj-server-legacy/src/build-tools/windows/service.c b/opendj-server-legacy/src/build-tools/windows/service.c index cb923424f0..dc332268ee 100644 --- a/opendj-server-legacy/src/build-tools/windows/service.c +++ b/opendj-server-legacy/src/build-tools/windows/service.c @@ -2596,14 +2596,30 @@ int serviceState() // Returns 2 if the service was marked for deletion but is still in // use. // Returns 3 if an error occurred. +// Returns 4 if the service is managed by the MSI package and was +// deliberately left untouched. // --------------------------------------------------------------- int removeServiceWithServiceName(char *serviceName) { int returnCode = 0; - ServiceReturnCode code = serviceNameInUse(serviceName); + ServiceReturnCode code; debug("Removing service with name %s.", serviceName); + if (_stricmp(serviceName, MSI_SERVICE_NAME) == 0) + { + // The MSI-managed service belongs to the installer: deleting it here + // (remove or cleanup subcommand) would leave msiexec /x targeting a key + // that no longer exists. Callers map this code to an informational skip. + fprintf(stdout, + "The service is managed by the OpenDJ installer (MSI) " + "and is removed when the package is uninstalled.\n"); + debug("Refusing to remove the MSI-managed service '%s'.", serviceName); + return 4; + } + + code = serviceNameInUse(serviceName); + if (code != SERVICE_IN_USE) { returnCode = 1; @@ -2642,6 +2658,8 @@ int removeServiceWithServiceName(char *serviceName) // Returns 2 if the service was marked for deletion but is still in // use. // Returns 3 if an error occurred. +// Returns 4 if the service is managed by the MSI package and was +// deliberately left untouched. // --------------------------------------------------------------- int removeService() { @@ -2658,21 +2676,7 @@ int removeService() code = getServiceName(cmdToRun, serviceName); if (code == SERVICE_RETURN_OK) { - if (_stricmp(serviceName, MSI_SERVICE_NAME) == 0) - { - // The MSI-managed service belongs to the installer: deleting it here - // would leave msiexec /x targeting a key that no longer exists, and a - // later --enableService would re-create it under a different key. - fprintf(stdout, - "The service is managed by the OpenDJ installer (MSI) " - "and is removed when the package is uninstalled.\n"); - debug("Refusing to remove the MSI-managed service '%s'.", serviceName); - returnCode = 3; - } - else - { - returnCode = removeServiceWithServiceName(serviceName); - } + returnCode = removeServiceWithServiceName(serviceName); } else { diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/uninstaller/Uninstaller.java b/opendj-server-legacy/src/main/java/org/opends/guitools/uninstaller/Uninstaller.java index 808f87be21..3d13431c82 100644 --- a/opendj-server-legacy/src/main/java/org/opends/guitools/uninstaller/Uninstaller.java +++ b/opendj-server-legacy/src/main/java/org/opends/guitools/uninstaller/Uninstaller.java @@ -1371,6 +1371,9 @@ private void disableWindowsService() throws ApplicationException { switch (code) { case SERVICE_DISABLE_SUCCESS: case SERVICE_ALREADY_DISABLED: + // The MSI-managed service is removed by the Windows Installer package, + // not by this uninstaller: continue deleting the files. + case SERVICE_MSI_MANAGED: break; default: LocalizableMessage errorMessage = INFO_ERROR_DISABLING_WINDOWS_SERVICE.get(getInstallationPath()); diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java b/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java index c4fe83f871..fd15be044b 100644 --- a/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java +++ b/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java @@ -97,6 +97,12 @@ public class ConfigureWindowsService private static final int SERVICE_MARKED_FOR_DELETION = 2; /** An error occurred disabling the service. */ public static final int SERVICE_DISABLE_ERROR = 3; + /** + * The service is managed by the MSI package and was deliberately left + * untouched (it is removed when the package is uninstalled). Also returned + * by cleanupService for the same reason. + */ + public static final int SERVICE_MSI_MANAGED = 4; /** Return codes for the method serviceState. */ /** The service is enabled. */ @@ -486,6 +492,9 @@ public static int disableService(PrintStream out, PrintStream err) case 3: printWrappedText(err, ERR_WINDOWS_SERVICE_DISABLE_ERROR.get()); return SERVICE_DISABLE_ERROR; + case 4: + printWrappedText(out, INFO_WINDOWS_SERVICE_MSI_MANAGED.get()); + return SERVICE_MSI_MANAGED; default: printWrappedText(err, ERR_WINDOWS_SERVICE_DISABLE_ERROR.get()); return SERVICE_DISABLE_ERROR; @@ -556,6 +565,9 @@ private static int cleanupService(String serviceName, PrintStream out, PrintStre case 3: printWrappedText(err, ERR_WINDOWS_SERVICE_CLEANUP_ERROR.get(serviceName)); return SERVICE_CLEANUP_ERROR; + case 4: + printWrappedText(out, INFO_WINDOWS_SERVICE_MSI_MANAGED.get()); + return SERVICE_MSI_MANAGED; default: printWrappedText(err, ERR_WINDOWS_SERVICE_CLEANUP_ERROR.get(serviceName)); return SERVICE_CLEANUP_ERROR; diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool.properties index c03e0bc29f..697ab55ea6 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool.properties @@ -1337,6 +1337,9 @@ ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=An unexpected error occurred \ trying to disable the server as a Windows service%nCheck that you have \ administrator rights (only Administrators can disable the server as a Windows \ Service) +INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=The service is managed by the OpenDJ \ + Windows Installer package (MSI) and was left untouched. It is removed \ + automatically when the package is uninstalled INFO_WINDOWS_SERVICE_ENABLED_835=The server is enabled as a Windows service. \ The service name for the server is: %s INFO_WINDOWS_SERVICE_DISABLED_836=The server is disabled as a Windows service diff --git a/pom.xml b/pom.xml index 23cdba7234..b32d68425e 100644 --- a/pom.xml +++ b/pom.xml @@ -619,6 +619,12 @@ + + org.codehaus.mojo + exec-maven-plugin + 3.6.3 + + org.codehaus.mojo From 4bf7927489563c0104dcdc7c19a10a5adbdb4fd8 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Fri, 7 Aug 2026 18:26:08 +0300 Subject: [PATCH 31/52] Refresh opendj_service.exe for the round-2 guard changes Taken from the windows-exe-11 artifact of Build run 31191804954. Only the service wrapper changed (the MSI-managed guard moved into removeServiceWithServiceName and gained the dedicated return code 4); winlauncher.exe and launcher_administrator.exe came out byte-identical to the committed ones - the first live confirmation that the /Brepro build is reproducible. --- opendj-server-legacy/lib/opendj_service.exe | Bin 175616 -> 175616 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/opendj-server-legacy/lib/opendj_service.exe b/opendj-server-legacy/lib/opendj_service.exe index 76d97cbfd64055c201c74e3fb0f01c675600ab30..44b234d72f629aad9c601f16d92d3816fbf58e50 100644 GIT binary patch delta 2064 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 Date: Mon, 10 Aug 2026 09:35:33 +0300 Subject: [PATCH 32/52] Address review round 3: prove legacy-service ownership, ship the full zip in release MSI - release.yml: package the MSI from the full server zip (the slim zip sorted first and silently dropped the JDBC/Cassandra drivers) - package.wxs: LEGACY_MSI_DETECTED detect-only Upgrade row (< 5.2.0) replaces WIX_UPGRADE_DETECTED/OPENDJ_REG in the legacy-service removal condition; Transitive component so repair cannot re-fire it; the pre-upgrade net stop is deferred/no-impersonation (Schedule=afterInstallInitialize) and legacy-only; the custom-directory upgrade guard also runs in the UI sequence; explicit Vital="yes" (WiX 5 defaults to no); lib\extensions component; WixUI_ErrorProgressText restored - service.c: the MSI guard now verifies ownership (InstallDir registry value matches the service's instance dir), keeping orphaned services removable; the native refusal message drops to debug (the Java side prints it localized) - ConfigureWindowsService: SERVICE_CLEANUP_MSI_MANAGED in the cleanup code block; WindowsServicePanel treats the refusal as an informational skip - check-native-launchers.yml: standalone failing check for stale committed launcher binaries, triggered only by native source/binary changes - docs: uninstall ordering warning, tightened service-replacement note; test-msi asserts lib\extensions --- .github/workflows/build.yml | 10 +- .github/workflows/check-native-launchers.yml | 63 ++++++++++++ .github/workflows/release.yml | 5 +- .../asciidoc/install-guide/chap-install.adoc | 2 +- .../install-guide/chap-uninstall.adoc | 2 +- .../resources/msi/package.wxs | 98 +++++++++++++------ .../src/build-tools/windows/service.c | 97 +++++++++++++++++- .../controlpanel/ui/WindowsServicePanel.java | 6 +- .../server/tools/ConfigureWindowsService.java | 13 ++- 9 files changed, 253 insertions(+), 43 deletions(-) create mode 100644 .github/workflows/check-native-launchers.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f73c49d5b2..501e3174a4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -98,8 +98,11 @@ jobs: # refreshed binary would ship the old wrapper in the tagged release while CI stays # green. Warning-only: an MSVC toolchain bump on the runner image also changes the # bytes, and failing here would kill the artifact consumers (test-msi*, deploy.yml). - # The freshly built binaries are uploaded just above - refresh lib/*.exe from the - # windows-exe artifact of this very run and commit them. + # The failing signal lives in the standalone Native launchers workflow + # (check-native-launchers.yml), which triggers only when the native sources or the + # committed binaries change and gates nothing. The freshly built binaries are + # uploaded just above - refresh lib/*.exe from the windows-exe artifact of this + # very run and commit them. continue-on-error: true shell: bash run: | @@ -720,6 +723,9 @@ jobs: $image = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\OpenDJ).ImagePath Write-Host "ImagePath: $image" if ($image -notmatch '^"C:\\Program Files\\OpenDJ\\lib\\opendj_service\.exe"') { throw "ImagePath must quote the exe path (CWE-428): $image" } + # Custom extension jars go into lib\extensions; the server warns on startup + # (WARN_ADMIN_NO_EXTENSIONS_DIR) when it is missing. + if (-not (Test-Path "$root\lib\extensions")) { throw "lib\extensions missing from the MSI install" } "OPENDJ_ROOT=$root" | Out-File -FilePath $env:GITHUB_ENV -Append - name: Setup and start/stop the Windows service shell: pwsh diff --git a/.github/workflows/check-native-launchers.yml b/.github/workflows/check-native-launchers.yml new file mode 100644 index 0000000000..cdbfaf7e94 --- /dev/null +++ b/.github/workflows/check-native-launchers.yml @@ -0,0 +1,63 @@ +# 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. + +# The committed opendj-server-legacy/lib/*.exe launchers are what Linux-built server +# zips - and therefore tagged releases - ship, while the Windows CI jobs overwrite them +# with freshly compiled ones before testing. Build's own comparison step is warning-only +# so an MSVC toolchain bump on the runner image cannot take down the artifact consumers +# (test-msi*, deploy.yml). This standalone workflow is the failing signal instead: it +# triggers only when the native sources or the committed binaries change - exactly the +# case where stale binaries must block a merge - and its conclusion gates nothing else. +name: Native launchers + +on: + push: + branches: [ 'master' ] + paths: + - 'opendj-server-legacy/src/build-tools/windows/**' + - 'opendj-server-legacy/lib/*.exe' + pull_request: + paths: + - 'opendj-server-legacy/src/build-tools/windows/**' + - 'opendj-server-legacy/lib/*.exe' + +permissions: + contents: read + +jobs: + compare: + runs-on: 'windows-latest' + steps: + - uses: actions/checkout@v6 + - name: Setup MSVC Developer Command Prompt (x86) + uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 + env: + # Opt in to Node.js 24 for this action, which still ships on Node.js 20. + # See https://github.com/ilammy/msvc-dev-cmd/issues/99 + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + with: + arch: x86 + - name: Build the native launchers from source + shell: cmd + run: | + cd opendj-server-legacy\src\build-tools\windows + nmake all || exit /b 1 + xcopy /Y *.exe ..\..\..\lib\ || exit /b 1 + - name: Committed launcher binaries must match the sources + shell: bash + run: | + if ! git diff --exit-code -- opendj-server-legacy/lib; then + echo "::error title=Stale launcher binaries::opendj-server-legacy/lib/*.exe do not match the sources. Refresh them from the windows-exe artifact of a Build run on this branch and commit them." + exit 1 + fi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 00d591eee5..a291377b0b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -207,7 +207,10 @@ jobs: - name: Install the server zip into the local Maven repository shell: bash run: | - ZIP=$(ls server-zip/*.zip | head -1) + # The artifact carries both zips and the slim one sorts first ('-' < '.'), so + # filter it out: the slim zip lacks the JDBC/Cassandra backend drivers and the + # MSI must be packaged from the full server zip. + ZIP=$(ls server-zip/*.zip | grep -v -- '-slim\.zip$' | head -1) echo "Installing $ZIP as opendj-server-legacy:${{ github.event.inputs.releaseVersion }}:zip" mvn --batch-mode install:install-file -Dfile="$ZIP" \ -DgroupId=org.openidentityplatform.opendj -DartifactId=opendj-server-legacy \ 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 932fcf8fa2..e7a613f6c7 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 @@ -644,7 +644,7 @@ On Windows you can install OpenDJ directory server from the `.msi` package. The [NOTE] ====== -When the installer detects an existing OpenDJ installation (an upgrade, or a detected installation directory), it stops and removes a service registered by the legacy `windows-service.bat` command, replacing it with the installer-managed `OpenDJ` service. Because the service is registered with automatic start, Windows logs a start failure at every boot until the instance has been configured with `setup`. +When the installer replaces a legacy OpenDJ installation (an upgrade from a pre-5.2.0 package, or a fresh install into a detected legacy default directory), it stops and removes the service registered by the legacy `windows-service.bat` command, replacing it with the installer-managed `OpenDJ` service. Services belonging to other server instances are not touched: upgrades between 5.2.0-or-later packages and repairs leave any `OpenDJ Server` service in place. Because the installer-managed service is registered with automatic start, Windows logs a start failure at every boot until the instance has been configured with `setup`. ====== . Make sure a supported Java runtime is available, as described in xref:#before-you-install["To Prepare For Installation"]. 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 f19a1df58d..f88e878dcf 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 @@ -172,7 +172,7 @@ Remove OpenDJ directory server installed from the `.msi` package like any other C:\> msiexec /x opendj-{opendj-version}.msi /quiet ---- + -Uninstalling removes the files installed by the package. Your configured instance data under the installation directory (for example `config`, `db`, and `logs`) is not removed; delete the installation directory manually, or run `uninstall.bat` before removing the package, to remove all files. The `uninstall.bat` command leaves the `OpenDJ` service in place — the service belongs to the package and is removed by `msiexec /x`. +Uninstalling removes the files installed by the package. Your configured instance data under the installation directory (for example `config`, `db`, and `logs`) is not removed; delete the installation directory manually, or run `uninstall.bat` before removing the package, to remove all files. The `uninstall.bat` command leaves the `OpenDJ` service in place — the service belongs to the package and is removed by `msiexec /x`. Run `msiexec /x` promptly after `uninstall.bat`: until the package is removed, the auto-start service still points at the deleted files and Windows logs a service start failure if the host reboots in between. ==== diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 7a6ef18233..1fc1bc2959 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -28,14 +28,17 @@ + Schedule=afterInstallInitialize keeps RemoveExistingProducts early (the late + afterInstallExecute variant requires matching component GUIDs for matching paths, + which the auto-generated GUIDs of the old WiX3 x86 package cannot guarantee - a + late RemoveExistingProducts would then delete freshly installed files; removing + the old product early is safe here because instance data (config, db, logs) is + not part of any component set) while placing it after InstallInitialize, so the + deferred StopLegacyServiceBeforeUpgrade action below can be sequenced before it - + deferred actions cannot run before InstallInitialize, which the + afterInstallValidate default would require. --> + AllowSameVersionUpgrades="yes" Schedule="afterInstallInitialize"/> @@ -56,6 +59,18 @@ + + + + + + empties the old tree. Refuse instead - in BOTH sequences: in a full-UI session the + UI sequence's CostFinalize resolves the OPENDJ directory to the default before the + execute sequence runs, so an execute-only guard could never fire there (and + InstallDirDlg would show the default, not the existing install). --> - + + Execute="deferred" Impersonate="no" Return="ignore"/> + Condition="LEGACY_MSI_DETECTED"/> + + + @@ -100,7 +126,13 @@ - + + + + @@ -135,6 +167,7 @@ + @@ -160,11 +193,13 @@ naming loop starts at display name "OpenDJ Server" and checks key names only, so any other display name here would make CreateService fail with ERROR_DUPLICATE_SERVICE_NAME for every additional zip instance on the host. - A failed registration fails the install (Vital defaults to yes) instead of - reporting success with no service. --> + Vital="yes" must be explicit - WiX 4/5 default Vital to no despite what the + schema prose says (wixtoolset/wix#5974) - so that a failed registration (e.g. + ERROR_SERVICE_MARKED_FOR_DELETE from a lingering handle on the old service) + fails the install with rollback instead of reporting success with no service. --> + the install instead of silently proceeding. Guarded by its own component, and only + on evidence that the service belongs to the tree being replaced: an upgrade from a + WiX3-era release (LEGACY_MSI_DETECTED; a new-MSI-to-new-MSI upgrade must not + match - its own service is named "OpenDJ", so "OpenDJ Server" can only belong to + an unrelated zip instance), or a fresh install adopting the legacy x86 default + directory. OPENDJ_REG is deliberately NOT part of the condition: it reads the + value this package itself writes, which would make the condition permanently true + on any host after the first install. Transitive: maintenance re-evaluates the + condition (both signals are then gone), so the component leaves the install set + and a repair cannot re-run the removal against a zip instance registered later. --> + Guid="3F2A9C41-7D28-4E0B-9B1D-6C54A0D2E7F3" Transitive="yes" + Condition="LEGACY_MSI_DETECTED OR (NOT Installed AND OPENDJ_LEGACY)"> @@ -228,6 +269,7 @@ accepted by setup, and the stock dialog would otherwise display WiX's placeholder License.rtf (Lorem ipsum) because WixUILicenseRtf is a build-time default. --> + diff --git a/opendj-server-legacy/src/build-tools/windows/service.c b/opendj-server-legacy/src/build-tools/windows/service.c index dc332268ee..4c2a96a16c 100644 --- a/opendj-server-legacy/src/build-tools/windows/service.c +++ b/opendj-server-legacy/src/build-tools/windows/service.c @@ -2588,6 +2588,94 @@ int serviceState() return returnCode; } // serviceState +// --------------------------------------------------------------- +// Tells whether the service with the given key name is genuinely +// managed by the MSI package: the InstallDir value the package writes +// to HKLM\SOFTWARE\OpenDJ exists and the service command points into +// that directory. An orphaned service that merely reuses the "OpenDJ" +// key name (rolled-back install, hand-run sc create) fails the check +// and stays removable by the remove and cleanup subcommands. +// --------------------------------------------------------------- +static BOOL isMsiManagedService(char *serviceName) +{ + HKEY hKey; + char installDir[COMMAND_SIZE]; + char token[COMMAND_SIZE]; + char serviceDir[COMMAND_SIZE]; + DWORD size = sizeof(installDir) - 1; + DWORD type = REG_NONE; + LONG result; + BOOL managed = FALSE; + ServiceDescriptor* serviceList = NULL; + int nbServices = -1; + + if (_stricmp(serviceName, MSI_SERVICE_NAME) != 0) + { + return FALSE; + } + + // KEY_WOW64_64KEY: the x64 package writes the 64-bit registry view and + // this executable is built 32-bit, so without the flag the lookup would + // be redirected to WOW6432Node and never find the value. + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenDJ", 0, + KEY_QUERY_VALUE | KEY_WOW64_64KEY, &hKey) != ERROR_SUCCESS) + { + debug("isMsiManagedService: no HKLM\\SOFTWARE\\OpenDJ key, " + "treating '%s' as orphaned.", serviceName); + return FALSE; + } + result = RegQueryValueEx(hKey, "InstallDir", NULL, &type, + (LPBYTE)installDir, &size); + RegCloseKey(hKey); + if ((result != ERROR_SUCCESS) || + ((type != REG_SZ) && (type != REG_EXPAND_SZ)) || (size == 0)) + { + debug("isMsiManagedService: no InstallDir value, " + "treating '%s' as orphaned.", serviceName); + return FALSE; + } + // RegQueryValueEx does not guarantee the terminating null. + installDir[size] = '\0'; + + if (getServiceList(&serviceList, &nbServices) == SERVICE_RETURN_OK) + { + if (nbServices > 0) + { + int i; + for (i = 0; i < nbServices; i++) + { + ServiceDescriptor curService = serviceList[i]; + if ((curService.serviceName != NULL) && + (_stricmp(curService.serviceName, serviceName) == 0) && + (curService.cmdToRun != NULL)) + { + // Third token of ' start "\."' is the instance dir. + const char* p = curService.cmdToRun; + p = nextCmdToken(p, token, COMMAND_SIZE); + p = nextCmdToken(p, token, COMMAND_SIZE); + nextCmdToken(p, serviceDir, COMMAND_SIZE); + normalizeInstanceDir(serviceDir); + expandLongPath(serviceDir); + normalizeInstanceDir(installDir); + expandLongPath(installDir); + managed = (_stricmp(serviceDir, installDir) == 0); + debug("isMsiManagedService: service dir '%s' vs InstallDir '%s' " + "-> %s.", serviceDir, installDir, + managed ? "MSI-managed" : "orphaned"); + break; + } + } + free(serviceList); + } + } + else + { + debug("isMsiManagedService: could not get service list."); + } + + return managed; +} // isMsiManagedService + // --------------------------------------------------------------- // Function called to remove the service associated with a given // service name. @@ -2606,14 +2694,13 @@ int removeServiceWithServiceName(char *serviceName) debug("Removing service with name %s.", serviceName); - if (_stricmp(serviceName, MSI_SERVICE_NAME) == 0) + if (isMsiManagedService(serviceName)) { // The MSI-managed service belongs to the installer: deleting it here // (remove or cleanup subcommand) would leave msiexec /x targeting a key - // that no longer exists. Callers map this code to an informational skip. - fprintf(stdout, - "The service is managed by the OpenDJ installer (MSI) " - "and is removed when the package is uninstalled.\n"); + // that no longer exists. Callers map this code to an informational skip + // and print the localized message; nothing on stdout here or the user + // would see it twice. debug("Refusing to remove the MSI-managed service '%s'.", serviceName); return 4; } diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/WindowsServicePanel.java b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/WindowsServicePanel.java index f6cf128113..40409ad7ef 100644 --- a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/WindowsServicePanel.java +++ b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/WindowsServicePanel.java @@ -334,8 +334,12 @@ public void runTask() else { returnCode = ConfigureWindowsService.disableService(outPrintStream, errorPrintStream); + // SERVICE_MSI_MANAGED is an informational skip, not an error: the + // MSI-managed service belongs to the installer and is removed by + // msiexec /x (disableService already printed the explanation). if (returnCode != ConfigureWindowsService.SERVICE_ALREADY_DISABLED - && returnCode != ConfigureWindowsService.SERVICE_DISABLE_SUCCESS) + && returnCode != ConfigureWindowsService.SERVICE_DISABLE_SUCCESS + && returnCode != ConfigureWindowsService.SERVICE_MSI_MANAGED) { state = State.FINISHED_WITH_ERROR; } diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java b/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java index fd15be044b..96e69af35d 100644 --- a/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java +++ b/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java @@ -99,8 +99,7 @@ public class ConfigureWindowsService public static final int SERVICE_DISABLE_ERROR = 3; /** * The service is managed by the MSI package and was deliberately left - * untouched (it is removed when the package is uninstalled). Also returned - * by cleanupService for the same reason. + * untouched (it is removed when the package is uninstalled). */ public static final int SERVICE_MSI_MANAGED = 4; @@ -121,6 +120,11 @@ public class ConfigureWindowsService private static final int SERVICE_CLEANUP_ERROR = 2; /** The service is marked for deletion. */ private static final int SERVICE_CLEANUP_MARKED_FOR_DELETION = 3; + /** + * The service is managed by the MSI package and was deliberately left + * untouched (it is removed when the package is uninstalled). + */ + private static final int SERVICE_CLEANUP_MSI_MANAGED = 4; /** * Configures the Windows service for this instance on this machine. This tool @@ -519,7 +523,8 @@ public static int disableService(PrintStream out, PrintStream err) * the stream used to write the error output. * @return SERVICE_CLEANUP_SUCCESS, * SERVICE_NOT_FOUND, - * SERVICE_MARKED_FOR_DELETION or + * SERVICE_MARKED_FOR_DELETION, + * SERVICE_CLEANUP_MSI_MANAGED or * SERVICE_CLEANUP_ERROR depending on whether the service * could be found or not. */ @@ -567,7 +572,7 @@ private static int cleanupService(String serviceName, PrintStream out, PrintStre return SERVICE_CLEANUP_ERROR; case 4: printWrappedText(out, INFO_WINDOWS_SERVICE_MSI_MANAGED.get()); - return SERVICE_MSI_MANAGED; + return SERVICE_CLEANUP_MSI_MANAGED; default: printWrappedText(err, ERR_WINDOWS_SERVICE_CLEANUP_ERROR.get(serviceName)); return SERVICE_CLEANUP_ERROR; From 1417a25d5d4fa0b785c2db5570b8531169e2c026 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Mon, 10 Aug 2026 10:00:30 +0300 Subject: [PATCH 33/52] Refresh opendj_service.exe for the round-3 ownership guard Built by CI (windows-exe-11 artifact of the Build run for 0d886578cd); winlauncher.exe and launcher_administrator.exe are unchanged byte-for-byte. --- opendj-server-legacy/lib/opendj_service.exe | Bin 175616 -> 176640 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/opendj-server-legacy/lib/opendj_service.exe b/opendj-server-legacy/lib/opendj_service.exe index 44b234d72f629aad9c601f16d92d3816fbf58e50..5ffd8f5bf76781bf8f57b81fb23fd3ae7b218a8d 100644 GIT binary patch delta 27423 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 delta 26439 zcmeIae|(MgAOC;7u8kerVFw$-aBwgh&hOv9HXEbiu-W_=CYz2~3}>jOGd3C9m@c^_ zv_h$GB-`nl`&v)IP=l*)We*bvBp0C$+ zoumBb;QWihWmc9Uo9&~$f%ePSGF>J2rK~xr^n2)K%~MOAB9lx11k-OMmEIMZT-qjb zYH7WgKDqQdcr9~s2@mE9$)znK-!2hEPAR3FvS6N@w!!@8Z@4R-VG>D4=IoMvQ|_lV zF)RroT{O)1gkkFZu}x#Sfn+4R@pEnp8N$|X;+`S{JJs}Hn6@=6W86HTPq+~Q=lv=~ zvdnpY?h|Yuu9Zmic~?-G4Dqzmz<=dqHvZ>MQ2!|VWl&N zpBuSn*rCJ9kn+%H%t@KBfzbd=h)%oxj;3W_6Da7e2TrN;VJ?R zWEv*~P9-ZjdxuG+gxlCbPV%_7J1E$1)ZCXH@_Q6AvCQs-H)EO89i-*4Vnc#w0k^PY zpW*usFidHjLhiyxv`f&vDXL1ByQxDgQ(CA<$GEaGT*BM~Tt&x0gUV17Vk>BDnoAgO zr#yu+g^Htya|uQ}cci*xH)hVa0I@SwWl6BX{3Mw_L)P zs~D!ZwV+nA_D-(N=TXRn7u+;+pgW>tER#iq4J$;|C9J_{k*~N!QPY88=FFZoQ&TT| zFp9e=N$URU9)@v;p+Jhz8QD^Vw^wqhod&Tvd$_z#OGC2JAv8Y17oNxc(WyVXWhB=- zINCISB*Uz(m0+|dF=v4;Uw8&G(%uc-C-V#v9iNf+LxF5R?VQcnsUAon? zcPhAx-3G899^ic4Mzh-$TwM2QthR#N)qMc__kQkp_xP?~4WfOGz%0wMh)bxFa6Q9@ zhnLe9eBKwXokW*E#N0DN-rHPC*bvsapL-@Oxohyhi?sxC{|g&J%DLch9s9%}E+%}U zy)Uw?u8ovnChNt&m(#Ih*4B8sS~?^nkBPxKzu6tALgc(;SvT{aJPG`W`lm_R`eX) zt?4>lf-sbiU}>uB7WY=qsF1BUXtXp{cs`4}(leHwew`Z}F*WQJIqh=<9M8!Vm%9y( z2_JGBBl@$OUgF-47~Cb{LAsD8=f01a*3&31k2^0YmRX;zPzWq~TWr&ElY0#|{znU)2`9z|5aDMgkdMOeLyJJ8G6H5-=}Jk3u{gPk-r?Q(_UhVNzI3_w^g=tiTw`ywYw0yQM>5Tw zmTGwTT1FmHALIk@m2Qm@G*ZeuHDimViIepuKFD;7R6Y^yw$L z{gcm^DjeIv<@f194s(1T>rh$=@+4RqJ)M$-nf`*LUcBn>zL+3Pcv0-n?3NMk^K{Ej zz~GQuj(HUQ-H7|?o!v|r9j7?>K%~jt(KI4bjF1$coHJ`CEaxQG(7!+Xa~pTFe~(~+ zwiK8o9Qc{*Dt8X~k*Z;9?|8alSW>wD5R_joW|GjDEY>AVn9Z$_%jf$er)H5XHc9id z(CanYODT1JX<@@-vA}5oyew6Ubt76V1VNH@au;Pzq&6z#(fqOjK`yU@A ze98SSkC-n`ha~BA5VbhL_xpjs-`#h z^nhMT{#-4c-SW;TG(%JasXIl5q8B_Jgg(F*(!-;r*FQb=`-y*lR!8EX7VdCg4;Va^ z!QOJG4Mv@(#5tB~?yU7a)5E8&OmSz^=(iC)1``N-_^H50ynWsIh=yYgpDXs)C3J@U zVa>0-*b&CHEbvIpU~ck2!?-$RYuQ`8Op+p8^RN7F>XKk!At`Px60Z$LfvG~|9hl8R zS@F}-si|&>98CtJNq846jMXKq`i1*!VBdbb{t_EWMe!kSE6r8^19HVFlrCZ5&zy8n z?$IY>`)9LMOcKt(H?(whm!amC4(?jo zK*|r?%0W7|{}0^TgL?J4y;U6U|KV3Ja#sfRATq9Pki{D@1f%->Z&Xf4ZSmW1`=~<; zC*Jes#vQTJQHV#hs6ALOgQ#2eAS@RnS5Bb6@wL zgqRSknBbl^(tokwX16a)v1ldI(nN)#x*Bz9E=+a_cm5|%r0~|ST$3U~dA?mO`PJvU z))avApcOgahht}iYB4QP$f0SqNIMcYgo_$%8JS4OdHSx;=UXNb^16!6t*r?ye4Lg~ zAB0|yMN$96esG=JJh&&@+{V2z_>qVlnt1Dbe;3}kg?jIysUs^n*T9inpCQ5Cd|Gvf z_Nw2*wUv52RJ|A3+$FU1T9l@ffHarT2IttmlA&uK#a{Slj>P0%Z4V_!wsxs1b@+3724N;*JlAN^~*Qh(p&FVTy2F zfL2`hGPP{fBwhW-P@HtR!DvHPj^4HmDfpwaUu6_fd#?UNjttc;bE(}^7Nr+khzB2(OH{_1m4J(k=hJmGJk z;1gexdnM9@iS6%q(^LNGOw(;tLlq2f|eMA)5HSzb4!^`})nrmE>-u z2|N6yN>`CEkXc6WTcjFNSiQ~FQ55m>b5Iu-}?jn~K z-B-KpqG*5qc9PtO`XjePjFX@)rN6Er?R7QK)R>Fhf#^P7dey+yg`Ukp7`mt?DzwF? z+iw|%MAM5pnSxA`6t{dJiZ)z;6Lcb!B6Pr$F>XZgV#D1Dh=GNvQrb;m7*;&RT|rCi zLJ4H6hTSl;Po@aFuq|OG1#Mo|)3dr6S;U>=5|)b@1B*}5TnqlDrC|0RYe8E_WVB*S z9)pvDaZGqPV-6e+GFC^@bQlBDM?9SFYEQq5hBS9vg6yBfuI)E*oUqk_M)6p!8Zl~q zkH0WN2AwR0btxGJjyK?;C^@_nqFS*%{kd>5!LD5?!li$rN)*N@G1tcrMa7{?6s$s2 zv2F{OI5NLW4Z?6#5~R3 zo(*pon2f9JwGA|$5l)Knfe+%BBHmp_OS%!lOg~6UrAhl}(u9YSBE{;gG_97VsS&#G zwR&*tl;)V0ui;X3TMoix+W+(Ewm}m<7aNa!(86)#EK4ytnMIKGkUbEsiDOmzP!G~D zc}na*mvFU-8>{NeN`B_%tK>t5APEzIR-@fAl)zJT0&G2taVNvg>~_ON3+&h2ew9xD z3Fe-jLULR+Rz3MJI}KFjq~kLX_QKMP@^$?k|A zsB*uS(ljdE;rLF+aWOqW>axhD5A$m!QLq3g9IL3*4pmcFCO81Jqk< zA&&r0w)W@hV60haf{--TolUFV`6Vo-FMSBbm=>HBunE@Vn*VY>7o~9y)%u@|P)~RF zewtlFvnMLTuv9JOI1j=Y&oboQq%n{mxzn17WF6N-+uuQbqUaIf%NL%%KRjbrpbJkj zq8Dt%l$hH6o;wQjAj}iRM(pnaKm*PcG4Hz9G$9vB;J-_a@^59Q7Dua!s+0*Jecu0?roj2>)FpmyOGg% zM>3Z%`v-9?VI_SaX%%v~>y}7m#RMlK zOoGV>GsGMb;_jh-ajM`(jPNTyumL)|%O6F~FFB(%vfDiIIX+NuBCW8-(?R%vn{Uqm)qB#gg zJWF8N-_rt0;Q)}D;!_H5b2n_g$uh2!-4Mx$=c43fai$>1(QCAB$zOGq$?YI?<~qBw$DF6%tBXp5sl!v6An*Mf`4fIrbA>1H_!PFspG<9RGpqiZeOlM=*LZp88qOz z7jcZ7f&Jh%9Cz;bZ)W#7^ZPfYF}_(R{dNDsaWRvI9Kxa%$G2(XZ?BKP>kF@ds-l5H zf1ot}Iu?FECyCues<~~kgNcJX7CV}K|0EYMdI_oJaz`fy$*^|5@S|Ma=mhUwoLcLZ z#dsmZN@++Ki*7vFlJ%!M?87+dpMS@u9E-qUici@nmi0|7wy*Vhf{Q=(g`dar_`WVU z6}b8yO)CkkPwyW~PM+u24!G)IbjB-;7-scGX7`>(RDb~@L;&WL9(~KT+LgIHpZnOnE z^DoA)6W$}|E8m(pG?1-GO#Z9&sPVieQy#{b;Y>%QU4EP3nr+W^UQk;iQ?{ zHFX$iFGa&>8t_+Gx^`b4))@(sq*>0qmCfT)-?{?=ADu zQ$^_>pp1U(hg3uA=W|nLz0lqHIO1LSm33Q$Ai2TR16tvh?KRPcQ7F6LkhDzJQPAr?>$|XE;E~uzIuJ59u zESs$2#^fwS&kp8vC1|;JiH^O?aDOdXCS_n2yTkUwAi@K=r|R$UW%xGwZ?ytFj1uAs@gAuzsNRawt-ge}}t zIroJxNWaQgoXjJ;oy=&+ddT~b8p!`3*LQPMUOdQ7d#$qL4wjWq+v{ZPuR56&$PUOk z$QO`15FdnF{ZjAB*j?o;yR((MuxD^(r;LYds>6X*WzAeaXX0k$r&YZp0D2v2-Jl(&-lT%WK{@k;*vE)ncOzm*I zroLS}72bXPM?<>S(Uv0c?xMZ$$K2|V;s@53J}8XR#j7N1eYxF*y|?g$(PK9JzKIh) zn$^?xkN#OCPSaB@U8kfZ3EjA~Q@zOh-11YS$S>Thr&9W=<){u876$ul>6R5B9%Jos zGOpL@L4(R+dt)uD?&j`pzgq~6c(*aV;2!aGD7Y7p8zLyUIj1A~2(-Ihdx;ZMaPMAj zAE6of3gnD%lY8#;u&{&e+K1q22KP}$n8JN}dPMIf?Fr9_33MV`K1dPD(QW>136V<^ z9~6k@V(Vf<|A(aMC$l2ll43OZ7su5pOrPLPX81tdcRFCK~qq zw0>5zFIOh4eGmO#KkF_HmvXIjy~zbG-k{0gB~=r z9j}wo(EQ?6Qk`K~m+8E?eZRHMs@eERQ z=ZE5R*7@FSO)>Z6`L%3$@pE5JLX_*v;XNbirAvwrfxCwhO?NA3gq+*_of>PpRW`19QW-os~4b2+=H&Aka*0{(1w+lX-H1}fn zm2i>Ghl#*_(QGA;bFv?X5hrKt z<8Kqb?M`p6xgj`Z&U0`5q(f($e@ejTh?Y#&c$3@G5lOz*UeD|L9{$^l5Y=}7 zE||qsBj3F1H(!y^Zm#cGe2TldFN_@F_T0)u`@z4i=$9Z) zdg${t^d!RT$}|2wS1k>LPq@Lo^y_n|L4AAhAhCu3EChY4sX04SxIKm*4WeOI%V_TI z$Q{GIe|ru}^!e@oQX=G`5)rh-aBkjjmyvt)ol)J|dx-k+-5;(08?NwkC(*N#F(zvJp?jN;x2TE6qlJWL? z^bO+1-0Q+^_4R;uz&8SucEQ&-B+`k|gwc=4=L3kEM8B&id)Sa1)PtQ=hAFE0fhG9! zR9y`qUdqQikQ=xW@+m>2iY+Rw3Y8FV07>9Cg^>OsEByugqac4Igjk4&|1E^T-uanQ zlFIHYtvVznvq_gcf4=U%+z8r+ybBpZ`n$wP&o?cd1?B7X+`#i2&Xw7-PU8HjE9Emo zNjkaBp9&=jtWe6!WMl)8RJ|x8>sb<2HMl$ZL&`d1s^oIgDS)kU@{bH6{lKb62a)0c zl2`Th5b_&gKYyg^TohSEh`h=+oV*qglJD*L#!N+X|7^YHI!$kyO#h-wKc4trj~&(M;myC=lJmB!!o|E2_n;1V|Sf|fYQ#HuJA zSr9-9tDZBGWI~qnS50I*>)yy~%w#5;u(7JlOq_%iRefe5eFtR#735| zZXIv86IGb(sr$$1wc!Lesw8(t3}0X;3Ko35ouArC6xIK*lPQ!F93)ZtxF$4R`=m2G(6 z6n_^lhSula6%_a~aytE5ldFxM}so8-M;r0?~&ac^4(5Q}7cZS|*v-j3Wu; zGM_h&EDdsDK&gVB|7{$Z5tJq>Usk1zCzW(*gA>UBX>#^I6MmI9B$9sphChh;0GEAD z&9&dqtS>jRbV9T6F25|1d?Jlm_)n?x{P+n(LAvsbfuPj=nB`d~`5hC;JW_IaBAJQJ zSd})3uz^J2=OmH-*b&|&GL)a4gw60)5_z1(ZtIZ(tIDfNO(C`bvW0(sI{Axi<2TPB zLwa4E9m70w9B*Jt12?#Y$6eIj$>251_=Xwq0A+l@Ol(F?)$p09J0y~bo}eq;(8+0J zLC8zr-NVU~C2{ZD$k(Nj8$HX$(Z{rxOZ+JEqi`I5b{0{QJ-lxg=|Rf*9<#|wvajmf z*(8gQh^qK>GK;W98>{xrCDRGn!QXof&SGDcc^;WV$jPeh83d0a`}vPEiD5tm`he@@ z6uiJzZh@_}O;5r#rK|7-hq*z|EBJx)iMlJzhVyaeYoeOCUK^ zWm-s9ckEnEv$eIb#lNQr2l>-W$Uw5J>Zc{7ko-dKj;RD%6HWG7pVaN##W^k61ju~@+(V- zE>un(med_V(ZMa_kCtHAlB&xkb2dZMeOR9y~Iho{MBAEpHx@bUM1ZLj9~I>gd=^n?7`Qk!bW^fpRTDX&8(-twV_v0 zVK(pEM+WqqCT5r-X25gZi7ck&?Ia<#%J4dIvE<9DqBlu?kTz#KDro5m4~HGsazTS% zLd_DRSj`>Hg%rU>mEx17nb-fRe*kZ-B&W$CKJXBXvyPvAhzt)Z+Jr+=KD7#OJT+uU z87A_=th+DXIWF9TIGC2JyF}~WhoIie=X!xVmWP~~2pSh7%P$q__*Ub-|eqny-w2x_A zIpS`KdejKUpZ*)--;m|d{@*mX?|$8 zaN4O`p|cwh?wpSBdw8GBv}md7%B{L{goKek4PyOKXg{iLe(16Wq&`zKKQy^RYc4+l17P$lkXmx2oZN@^QzIdjE#*@S*HW ze(wn~z#DZghDpKOk?Ut;@ba&TrA|J+S%Mm_ee_URjg$02vXmyj>Q5HK-Tle*%V3la zqsi+Ygj)vV$h#FP>tIB}t^a3h%sPqs0_YQc%XE~9;3u9WdhG1AC&>U3!M}D= zbQ)iuBqJgtP^_gFGDXsW3;_iV1R)U3%WK7AskJ2DJg`27(LrJ$$&hr&GRS7gc1RxN zI%F~in+=%qu!Yjh_bpV0w1+H|sj{3Q-3XiGLl#-048=9?=QMr`!* zx=+ZX>?>Y=%_n3Xdk@vrV;Kh3lVPxh3H3zP9ycHA)q3J(Z+Ln4S+bEXPTN`1uUj)} z3;x-|e$y0u#v{4Z;f|M&I!BU-?6tgegd|$?W0`NxeDn9EZ)l4b`$j{D+u0@l_+i=U zi=7h@(emM?4%+`@RNT)v~S!>Dyj z*5DQW)qB*yug!qD&^X2)7n<6k75T&@2a@ns9jTc7Q5|Uc`#D!E6EpIQJ}15W6+7=I z-LLotcAAY|_H&K@spS9c#0li3}G4!|32-ug8$ zv&mQZm0y#RF1MOunC~HhZNyoTmS1(ckyzPiIVvrV4_kXCbZrS{ z$i^_O-dr1+>r8h!Ms|F8cyWA$*nfW11)`^W;_(YuSBBqw0j3GH@dBPLBKWZv$@tOY zOtq0*D+)a{U78x|Do|bB^4TsrUO~f16^Qn}3zR9JD3dtjN1y_Osj`ukea(w!=jH+QjkRGhJZ}L4~wRAna zVA8UCzOu67WQC+OR$4s1UQ;J9NGu+I7oj^z$d-XOpx2`Rovjs#-_XQlyhywj`tQVM zBp&^z;nJ~yeh!zqDNrudaJOkMRc@nj z2*YD^kl_#`BoQ(Lk^@--*$O!bIRR;e`~!p^UTf8&Ri;w znvgVZn0)S{44Qdq<`avTBl8M(<{~kB&fIwmQJkjbF1lYRVV zOv~{vc4jZZ%d84zja3J_uvGzGS*nwXcqEqohKx~wL0~jUuOCK`))LoF7YP5#q=TVg z4oLImfp`PJ6t?SS?cCAMeITv30;KgF1?kK2x<_KYVg;Wgg8rQc1Hp?REzk_YQ!@fc z*X4RUTifGrx9e@~yxUGD+CLyENXyAUT2ENJ9?{OoXdIC=LEfH0(atE4o^H|Yy0V?x zb{auiv9(=yw(D{2dP2LN*si&7+ zs0Q)dPNoi|6*YsjLxH1WnZaN*r~s4O^*rzq==(sLzZR5(0yq$qDr1=_&^4X{6sC%0@D0{K`R^OueVe+!=J#zu ziJ2z!U)$YZ0;Q_zr*Kx^ak#Sp-y?bOyMQO1%+y5-7cE|~NS?WJUS^JG!Qw?IQ1nlF z)%Zwud4RX=M<=2gX6RKvyLF0T=0lnub&8Uf7Q-BZE<&ITvJJ8a zvL8|nsfE-*>LHDg>kuN22mi7aVaAC40Fgl=AaY0)LXdq#1G@avO3N5@^DRA(0Rz#0sfLd;*vZNr&V>3L#q{`yfXlwUBy96GUQ0 z`Kp%(u#X4KDnqydBDG+aAbF5#2xCQEko^z=qOf76AmxxIh|-P$KpG%&2WA|S07-}B zK&l}Oe`PQ`sH$i%E9+=uVh{ldY!?YgMcOX1c0ICPk80PoRImE-5q6!V%ND$DDu?Wc zRFC7cv}~-m)#Z1cZ6I|7%w)gMmw+9hMu2qx%R%a~qCo1glpys7MvxvNPLOWT1dwi9 z7f5&0G?4m>bdWk6Hz)&hKx}I-vl0QiZ}UNX)yEWp)D@P2;ovrqersM1Mu7W3y00rh z>QJgdy8mlHy6@{i>M0w*eqbX=Jzx_k2L*5d*a{A$4yP8gK|Ng?BBq91cc-)UzqUXwV3b0G;3{FagwqE)c(!VWxpbFda03ZqSbQnH&Th;7ZU5 z=7V&@7lEU}GB6I@295#C!Li^za2!|xjt8s3N5L9!B3K7b0vkZQ5M~;|6tD?Q1qIMM z1A$fqGQl<)0WwM0m4Wc-APdUC05B2^1gkM)9l$8)9YHM^1Uf+pm zU`I9Sx`EVCyMyJ352HF54pxIbz*><08`B1`7kClu z4GLf%@HQ9;GRd$BPzv?~Bf$QkBH0V0KtPFz0iYEe2qu7oz+{mAST!9S3}%Bvz?C5V zCqISYFt7|94(F0)g-- z)G-Bt+n{#>_kh7*1t<*p>!@wr62Y4Oq4Yq-OL0Kx60E`4JpcbURgmr?W z!9;MO1m>QB0D;T$fPr8>7zCDpoxp8iFt`Vlf)!wI@F-{j&w~rWCXm3jwSs}*T`&lg zOhY|j7#Ix7K`9sw_VyxRM8E>ZfdsBE84Lu|!5}aj>;$d^gTX?O{+OT)><#V!E#M)L zz(v-Aoxlb#7`zBdK>_Ry-Ucn8bUL;>fzOOYpc5Dc27_9#H|PW{;53lPVO(G*&;tg8 z`7|9Yq3H^AgrEK104hqw;|4B4@L=!+}1`Kbtni%y+(SoT;fvjn8aDE*6s-Uvp4--2539ncAu zgNfiKa2oh2m;rtX=767rdEo0{5qJdL0@i}%;6-{|?ni(g3e{jeSPOm#Hh^`Y5k8!r zQWv4W2;K%4g7kEw$DVXvEHjVl=r92zpkpQ&1-J@Sf>j`c{49_FJsymJ9!O7zWJJ)@ zCmmb|%8@`X3fa&xli~$|UKmzFe+4WAH-lv$J*{?tmEb<`O^_Zs^t3w!y%I<#z(>Jk zum(&AzW|+RuoIXK{WEYScnK^7y z2eyJu;9c;2P?8zToCCwaE1(>_07iq~fkyBfFfJ3@(J?q#Eo=%HEM(I0jrS?N5llqk7eElWgxwf zq$9pF7zuq6s6@FaFv^RFEClG~tv{%RJ{NRD?*clZWBZD?%TO>8`t#s4a5A_O`D9=Q z^eHqR6^{UOpf9EA&{bd_^p#)@bTe24eGTZ%M+IFGpm!$+xCII8!98FSn2&fhSONV> zFar8u@F?`hK^b%fSOd9V!W-N6j#rC>Sg)q^?Ep8>Za zJ&Z1D9wJg`21JB|MbJ~hE#Nj950-!x;7ec)xDVWi{5`-1=+kIA^q$~F=+kLD8nl7} z^tIq^@HLQe<7*2*3hqGr;zhp~7=ehHAcKMf0R{97PzfFbo#08(1y+FRU^SQnegfu$ zr@=aOq&HXwJq;A#^Zy6#fPMlz1bzV4gWgvWXhz@#umJ`8fOny92PF&en+dQ89nyed z(4PWZp*ul2^bKGIbR(#Qo)1<-H-T2@tHDOp8wn;rpA9C1i@>JI*#CVINJqpRa2pEh zz-;JwAbpaNgDasw1`4RCA6N)I9V|nBEhY3_;6CtaFbeTQ!5Zibz|5PBAj~jTrE}Q7gS$Ath+*=-iebti zIp_IpS?m@s{Q{Pbh<V-+o{roNomzc1CX1AjJl;Ge4*_b$g&>{t5|A3#7Le}q9bg2w2c*`! zAEZ`$2pk9=1qXpOAl=usAl>hE;1IB3HQyzhz18V_0nYzxF-#4Ky0}=~k@p9VHNMcdS|9AiY5k?0Zh;_JLi0?MCSTXT_8XYukw{;y}xIe+7_PzsT zZ(?hsz59Ozfeh%`?Qt^x_#(Ea>ESFiYwH`>U=J0e4ef_s{ZLVwhw!RJZ1-UgXQjoX z(W>xJaoTDd)%hcf*#2IcB!?raz!uAY3@bYiY$eQ2NG;?F1 zdP=fl+UOXXr|Ca&G_si=ki&MD3I9qO7sD%a*sxwSL+gK1MkDSvzXXMB687OX#?3$q zBmGyLOKew$I0@4HeQ`~r`6Bq^sA5Fqzq5-~$p00WELNdFoRlX^*zRW8YSh&J|C@6b z;JYkZv#2YU(wZZ&u5?-2 zZW%kIK zouRm5+Tzw{*+Aa7oV9igz3gO$U*?}$&h`uH@ZEz(dw%f!gG%W1((c}UP`Gs&E8$z0 zv$CMX<_D$NoBtChd&qgg$uvUf-~H~@{-?XmzxXHUkDtZnS=CKHAHC)04!<6B^QKsj zI5F&Bzl(Db(4EBaFM8O%gEG5`yW*c#{yQn%d&cnZBV)jnUNQXB%h|p|FNi+mLB9_D zr(f%Oi#7Te;#}kdC16mTzlxyG{mx6w60mS#du;Oj2YG`spLw8=1^mlTvi%4Al`qEq z)7R?%v>eGFM>g`Km^2cL(| zuvqN>|0e_g-~MD^^0xoCe=@*7m&ZO^6}^f*FX39*#>3CD+X$N<%Wq%DJ{Q8oWwTy-~`Ns#i+biGg4-^rY;MM!f4=Z@F7sqK zoy^1O|7Tj&$j$7HPWZup-xt|F-j`Kxs*b8osLrdds{U4WQukNKsOPAERflT^Xl82) zHCr?=%^#Ww?FemxcA|EMcAfTP?PuC1ZAV>SU5>6$H&pM?Kc+9%zoGv?e?}i* z7+{!Zs4&bkZZN)KeBb!Bk(ex|7}H$SX46qqs5#lZ(Y({#V(w~*vN*h!IhJjfH!bg4 z&RRmOL#-<7Q`XhiSFCSYtE?xi4c05xtJXiPLAKGh>9&Qo=WNGqmuz=!z3qDYGJBc* z2m4*S&N0QY!|{sa1IIPT4aXl2dRkiv!vrb2CQe1??Gf$gT0#4}cA##IE)!#aPPa|>n(nZ!QFm1rr0=R9q&Mkj>I?OI^tJjH{nLh? zCZ$PdnqbN_EjHzwHke*C?KPb+eP;UB^u4LY^t;#8!Q8_vH!I9h=4i9hJk~tZ{EGP< z^9l1AbA$Oy^JVi*^KWLxGT1WQqOzo07F+Ty#g@&MTFb|l%a&Hmnb{g|O|`DE?y(-T z)>*%@Ua&^k`q?sVS++H{jkYbe-M05^muXJv2YSY@g*L%9S~_KxynJ z&s0CcVnWqnYK2;(Hmb*}v(zipdFo>I+v?-$Q|d3(x7B~DiDrn#sEO4~&?ITHG|y{Z z(!8#DTk{EKxI1Qdp;!B))~h|JP0%gX-O>G}>#QHIpQWF#U#Q=%e@TBpe_cP>SZw^r z*kZhE>~8978fsF(nBq;7Ov_DAn@UXwO-D>0VmdFFu9z~-x#qp*v*z1osbwH$%WN5I zaa(dM8!cNcpIN@PsH_>*C9tkTR$>dXEyet-w|TeQ_Sz2Gj@Ul7eQEp6=Cg&^_u1dE zAF+ozRybBUo^@<;Y;){#>~S1%eB}7dKSM4&T4AC(z`%OK#D*(%FtV}A3Ce8cQkdBq zWwCOz@&)BC^w-@`m!Z@=v8i)dlmXSFKV%s=KI@=_B;R^#-qgy1s{@k70!2 zZ^OH$I+N4r@?SdM`dI5@{{y1eOly#g#!u2)`B z-cx!5RC@Jzb%u6@_Id4Y?PPtCev^KSew%)WzFdDtZ!tIxafSp#qT#UVebZUfFtgG8 zDz@tfmS=3JB}c4}>8N~HnTb`c)BLRY75heq{qn4~Si4iZRsX7fzG0zZm0^pCn7doX zS&mswTFzL`S-!Gdw0v**$!n2YU$VYx-EWoHjJ9L8^R`v?_w2Ry%XYWpyo1Td<1yOF zP_Dwxovg}M?NsfB!@8gzp?h6#G^{YKF+Fd3$@BqcZjjl5)jw&zVeVl`usmidf?qjk zId1vXa=~)d@|&fDwKwK9*}A~$wU$`7TVIDAoUwW@S%0)nvY&O_bYwSfmE%<>z^Zzy-c}cCi?k)$GVK=aHth~=xi(oh&5&kDH)I&xhHOKQ z!DCRHW6ZZqsD8r*z@ejQG;y>uFsLrNK(Jh2~eouEs_qnb~=hVmROZ8jz`Ebj-jr)yBq|j`0qr3GZdlNurd%dkn?Cn5axq&QZFRPbxPk-%$RfY*hxTVpaKA z#NSj>b(DIxS9BR`)%EJBnz@vJ=c-!!S;ez3|;SWPM;~-;{@oi(h@j25@(|GvNEOUW*iREcn z!V$|z>sae#>n!U!>l@a0tS)%R3fqUavo`Nfwp+G7_JMYjeUg1Wj+6%b*BDQ*qpxGA z!|7P(*y1?p_|(C);=x-SSx@B@<#griu#X!`r)mj|kx?&JuT{%6|I@T+{?^E~8m(RH z($3T7VL!crMQPOz)+u#X-F)2>x}Carbnol_*0Fl2ek4xKsa_nLoc=@oH~KDyctfgT zo#72b7h^x8#W>!WZ`@}5!x(LP()1}d-VL+XvfNUR?en!|y0zH)uJyF_GwZL`FxzU| zYqoQ?Uu;?EewFm0gCx^$d$S-Pim#kw-x^DwB- zbrOB3exTj}=QU5iMqdJd@s|E${YCvx`d{?7^<51*!&1Xm!)u00EKj|m(a_O2+&IIy z7(+T_Y=kRUn1-A5rUcUjuW5>DnQ1Mq2CthcaVR#Mg3MjvWMa+3ty=3AtKK%==C-|R z`_XpTe%{`}(cRI{k?yFWTT({E*Wg4cgPCQ(Kb%m;t7fS-sTx!=^=s;n)n_$7YDQ_t zXcyz?-j6HGciMYei7pPqc>@bz(yzz);(g4p*s$GDX54D5G@dtJFy1msOyQ>9rYO^F z(@&;Ab0@RM+Rrw`cGZ5-(d_t%HjLwuK5oCN?5JL3deZuW6^fEj7r_iseyA)}eUEc7 zQvHhNxUOEeK>xIUwO(tm86sib+!`R zjLL1V+bV4z*uJoRYrAUu%f{F{;=CW~c+v4X?X;7KU$>mWMel;@imDY?9-y5e8}*_tydy(pAOr>n~pG9qUG0rsGuylTO4J#XeQDx=9nH?XR7peMa|!Znv(7{z(|v``G`T4PiJd zbvTkH8fL;1D*&6e$!U6wtTeU`Uy0vyE&aLMwkWsr4( zb-lH#&2G!aao@`^*|7x2y7!RdS2{g8MEqjFrJN;R5)UYkDeIMAD0x+-`Xlvk>h8D= zM``Su1WhD-f3kjt-mPDx_rUfy>wna5GrVlLikS*A_BD<&#u$@~nZ^~y^~M*C2aF#Y zn_yFcrXH}U@#bL5v$%@9Y3*jSq8p#vLcDN2u{iIRIMz7U;}-jl<8z#P{x^B}H|KDj zFDNUO=ak)5BUNKnYjE*;3m4W8U|xgN!__LaUA+kh%M0pVu=rZdSf%Zbq1r_ zGR9JE`N1Ny_O-gKnbyVDCd{=L*B$!0kREgay3;!E-?~732z=2M+cjLP2iTc%BK~5i zRJ9ncc^~d_!FrR`iEH>B>pGjk?!YPVy(mnYWUI;@e=Y5+|##?CfE#9L-3_BDhN?_Rc=d`2CUv}ex;j(6M7>%43(T^YW|&5&iPPNDsPO=@3>R>zE*$5aMPF*@XdY^DS-!P2 zTYkbi_ptV}Mq7>6M{z68vM#q4Sa-tE?pTM|l5MkW^KFaaO|IKoaU*WSlY|$)RIy9! zQoGC^h6`4tU5=A(sr{1ucYB~i>zIb?Q;wq$OVjFL8VJ3QFlUsXDZjzx>6$V~6^avJ zm1;AtC9kW_!0njTv3Pn~tbSU(LA_IRP9xKf)n?#0E6_G*r|Wj;>~}!}>9X`G)0& zPYm_Oi(cc;#@~z`U>+Zu7Fu#G>n$9vSCz2ZuPs+B0oKme0oEv-TPgIq)kMTEfi~du zPgYG+rK!?YCspC-(F z%W(6LP&0D8_(yt)p$tcIId*!5q1sSms53Oc?>8CnKfN}z85pC)C^JSF3OsZqph=g?jeA~>O2EO{roF4hPmpvHom3~okrb(u<5-H) zMdLu#>WuK^i8@@qbZPME89KKv8}}WLZlx|ymybuYB3%g%tSxvz+o3Dh?a}Si?blW4 z4(Y0OM|Cy2T3sF7bA#@@u2F&ec$2PKC+MzY@^0(eba!?5#gkrwQ(C5v)XVh>eH6d@ z4R*3uY1ZO&vYMUdICFwI(d@$G>@;(lIo+ILcAK-!IcAS}r8&=>Z!Rf*NFz=~)|4nup;lmHGqxq;eSZCF?1FVFQ68`14 z*mV(14l8~E^`7Gxw%#fD7nX@cpLq2F*6dZPwQ7%gr8-~TsBTp!YFwIhO$Hu>>7)NP z+{X56Dm2xa22B$l*>2;pn9)XPtysV`W4bX92YR`2A8wO%#s(ap%{V;6Op&HI9PJq< zw<*W85)ZwF7+JY#A0GZ2O>L$K%-=N3SGKv_Tw`t;j)z;h#fdAs%aUd}1eeulX|pg^ qDSS@4HP4!FEw|Rdbul(MKemD$D%pVt)uXrpRBfnWmlM21QT#teArpWA From 461644ab0185b9d7b85ab639ee6820d62e9d33de Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Mon, 10 Aug 2026 13:26:41 +0300 Subject: [PATCH 34/52] Address review round 4: immediate legacy-service stop, NOT OPENDJ_REG guard - StopLegacyServiceBeforeUpgrade back to Execute="immediate": a deferred action is only written into the installation script (ICE63 forbids script-generating actions between InstallInitialize and RemoveExistingProducts) and would run long after the old tree is gone. Immediate covers elevated/silent installs; a UAC double-click no-ops and RemoveLegacyServiceControl still stops and removes the service in the script, so a missed stop only costs files held until reboot. - RemoveLegacyServiceControl: AND NOT OPENDJ_REG on the fresh-install disjunct - NOT Installed is also true during every major upgrade, and on hosts upgraded from 5.1.x the install root IS the legacy directory, so the component would otherwise fire on every 5.2.x-to-5.2.y upgrade and delete an unrelated zip instance's service. Install guide wording aligned. - isMsiManagedService fails closed: an SCM query failure or unreadable command line now counts as MSI-managed instead of orphaned. - Control panel no longer reports the MSI-managed skip as "Windows Service Disabled": the task overrides the success summary with "Windows Service Left Enabled" plus the INFO_WINDOWS_SERVICE_MSI_MANAGED explanation. - Launcher gates use git status --porcelain (catches untracked binaries); concurrency group added to check-native-launchers.yml. --- .github/workflows/build.yml | 5 +- .github/workflows/check-native-launchers.yml | 9 +++- .../asciidoc/install-guide/chap-install.adoc | 2 +- .../resources/msi/package.wxs | 52 +++++++++++-------- .../src/build-tools/windows/service.c | 31 ++++++++--- .../guitools/controlpanel/task/Task.java | 40 ++++++++++++++ .../controlpanel/ui/StatusGenericPanel.java | 7 ++- .../controlpanel/ui/WindowsServicePanel.java | 11 +++- .../org/opends/messages/admin_tool.properties | 3 ++ 9 files changed, 128 insertions(+), 32 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 501e3174a4..4889ef3c96 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -106,7 +106,10 @@ jobs: continue-on-error: true shell: bash run: | - if ! git diff --exit-code -- opendj-server-legacy/lib; then + # git diff alone misses a brand-new launcher that was never git-added: + # status --porcelain reports modified and untracked files alike. + if [ -n "$(git status --porcelain -- opendj-server-legacy/lib)" ]; then + git status --porcelain -- opendj-server-legacy/lib echo "::warning title=Stale launcher binaries::opendj-server-legacy/lib/*.exe differ from what this CI build produced (source change or MSVC toolchain bump). Refresh them from the windows-exe artifact of this run." exit 1 fi diff --git a/.github/workflows/check-native-launchers.yml b/.github/workflows/check-native-launchers.yml index cdbfaf7e94..817dd4eaa3 100644 --- a/.github/workflows/check-native-launchers.yml +++ b/.github/workflows/check-native-launchers.yml @@ -35,6 +35,10 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: compare: runs-on: 'windows-latest' @@ -57,7 +61,10 @@ jobs: - name: Committed launcher binaries must match the sources shell: bash run: | - if ! git diff --exit-code -- opendj-server-legacy/lib; then + # git diff alone misses a brand-new launcher that was never git-added: + # status --porcelain reports modified and untracked files alike. + if [ -n "$(git status --porcelain -- opendj-server-legacy/lib)" ]; then + git status --porcelain -- opendj-server-legacy/lib echo "::error title=Stale launcher binaries::opendj-server-legacy/lib/*.exe do not match the sources. Refresh them from the windows-exe artifact of a Build run on this branch and commit them." exit 1 fi 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 e7a613f6c7..7f965c6dcd 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 @@ -644,7 +644,7 @@ On Windows you can install OpenDJ directory server from the `.msi` package. The [NOTE] ====== -When the installer replaces a legacy OpenDJ installation (an upgrade from a pre-5.2.0 package, or a fresh install into a detected legacy default directory), it stops and removes the service registered by the legacy `windows-service.bat` command, replacing it with the installer-managed `OpenDJ` service. Services belonging to other server instances are not touched: upgrades between 5.2.0-or-later packages and repairs leave any `OpenDJ Server` service in place. Because the installer-managed service is registered with automatic start, Windows logs a start failure at every boot until the instance has been configured with `setup`. +When the installer replaces a legacy OpenDJ installation (an upgrade from a pre-5.2.0 package, or a fresh install that adopts a detected legacy default directory on a host where no 5.2.0-or-later package has recorded its installation location), it stops and removes the service registered by the legacy `windows-service.bat` command, replacing it with the installer-managed `OpenDJ` service. Services belonging to other server instances are not touched: upgrades between 5.2.0-or-later packages and repairs leave any `OpenDJ Server` service in place. Because the installer-managed service is registered with automatic start, Windows logs a start failure at every boot until the instance has been configured with `setup`. ====== . Make sure a supported Java runtime is available, as described in xref:#before-you-install["To Prepare For Installation"]. diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 1fc1bc2959..f432900ae5 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -33,10 +33,9 @@ which the auto-generated GUIDs of the old WiX3 x86 package cannot guarantee - a late RemoveExistingProducts would then delete freshly installed files; removing the old product early is safe here because instance data (config, db, logs) is - not part of any component set) while placing it after InstallInitialize, so the - deferred StopLegacyServiceBeforeUpgrade action below can be sequenced before it - - deferred actions cannot run before InstallInitialize, which the - afterInstallValidate default would require. --> + not part of any component set) while placing it inside the installation + transaction: a failed upgrade rolls the removal back and restores the old + product, which the afterInstallValidate default does not. --> @@ -93,21 +92,27 @@ - + Execute="immediate" Return="ignore"/> @@ -226,15 +231,20 @@ on evidence that the service belongs to the tree being replaced: an upgrade from a WiX3-era release (LEGACY_MSI_DETECTED; a new-MSI-to-new-MSI upgrade must not match - its own service is named "OpenDJ", so "OpenDJ Server" can only belong to - an unrelated zip instance), or a fresh install adopting the legacy x86 default - directory. OPENDJ_REG is deliberately NOT part of the condition: it reads the - value this package itself writes, which would make the condition permanently true - on any host after the first install. Transitive: maintenance re-evaluates the - condition (both signals are then gone), so the component leaves the install set - and a repair cannot re-run the removal against a zip instance registered later. --> + an unrelated zip instance), or a fresh install genuinely adopting the legacy x86 + default directory. NOT OPENDJ_REG mirrors SetOpendjFromLegacyDir and is + essential: NOT Installed is also true during every major upgrade (each build + carries a new ProductCode), and on a host that came through a 5.1.x upgrade the + install root IS the legacy directory, so without the registry guard the second + disjunct would fire on every later 5.2.x-to-5.2.y upgrade and delete a zip + instance's service registered since. Once this package has recorded InstallDir, + "OpenDJ Server" can only be such an unrelated instance. Transitive: maintenance + re-evaluates the condition (all signals are then gone), so the component leaves + the install set and a repair cannot re-run the removal against a zip instance + registered later. --> + Condition="LEGACY_MSI_DETECTED OR (NOT Installed AND OPENDJ_LEGACY AND NOT OPENDJ_REG)"> diff --git a/opendj-server-legacy/src/build-tools/windows/service.c b/opendj-server-legacy/src/build-tools/windows/service.c index 4c2a96a16c..4b35b157f9 100644 --- a/opendj-server-legacy/src/build-tools/windows/service.c +++ b/opendj-server-legacy/src/build-tools/windows/service.c @@ -2594,7 +2594,11 @@ int serviceState() // to HKLM\SOFTWARE\OpenDJ exists and the service command points into // that directory. An orphaned service that merely reuses the "OpenDJ" // key name (rolled-back install, hand-run sc create) fails the check -// and stays removable by the remove and cleanup subcommands. +// and stays removable by the remove and cleanup subcommands. When the +// SCM query fails, or the entry's command line cannot be read, the +// service is treated as managed: wrongly deleting the MSI's own +// service is worse than leaving an orphan to msiexec /x or a manual +// 'sc delete'. // --------------------------------------------------------------- static BOOL isMsiManagedService(char *serviceName) { @@ -2645,9 +2649,20 @@ static BOOL isMsiManagedService(char *serviceName) for (i = 0; i < nbServices; i++) { ServiceDescriptor curService = serviceList[i]; - if ((curService.serviceName != NULL) && - (_stricmp(curService.serviceName, serviceName) == 0) && - (curService.cmdToRun != NULL)) + if ((curService.serviceName == NULL) || + (_stricmp(curService.serviceName, serviceName) != 0)) + { + continue; + } + if (curService.cmdToRun == NULL) + { + // Fail closed: the entry exists but its command line could not be + // read, so it cannot be proven orphaned. + debug("isMsiManagedService: no command line for '%s', " + "treating it as MSI-managed.", serviceName); + managed = TRUE; + break; + } { // Third token of ' start "\."' is the instance dir. const char* p = curService.cmdToRun; @@ -2662,15 +2677,19 @@ static BOOL isMsiManagedService(char *serviceName) debug("isMsiManagedService: service dir '%s' vs InstallDir '%s' " "-> %s.", serviceDir, installDir, managed ? "MSI-managed" : "orphaned"); - break; } + break; } free(serviceList); } } else { - debug("isMsiManagedService: could not get service list."); + // Fail closed for the same reason as above: without the service list the + // entry cannot be proven orphaned. + debug("isMsiManagedService: could not get service list, " + "treating '%s' as MSI-managed.", serviceName); + managed = TRUE; } return managed; diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/task/Task.java b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/task/Task.java index 97afd84191..6c01b32cbd 100644 --- a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/task/Task.java +++ b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/task/Task.java @@ -153,6 +153,13 @@ public enum State protected Integer returnCode; /** The last exception encountered during the task execution. */ protected Throwable lastException; + /** + * Success summary and detail that replace the fixed messages the launching + * panel passed to launchOperation, for runs whose successful completion is + * an informational skip rather than the operation those messages describe. + */ + private LocalizableMessage successSummaryOverride; + private LocalizableMessage successDetailOverride; /** * The progress logs of the task. Note that the user of StringBuffer is not * a bug, because of the way the contents of logs is updated, using @@ -316,6 +323,39 @@ public Integer getReturnCode() return returnCode; } + /** + * Returns the success summary that replaces the one passed to + * launchOperation, or null to use the passed one. + * @return the success summary override. + */ + public LocalizableMessage getSuccessSummaryOverride() + { + return successSummaryOverride; + } + + /** + * Returns the success detail that accompanies the success summary override. + * Only used when {@link #getSuccessSummaryOverride()} is not + * null. + * @return the success detail override. + */ + public LocalizableMessage getSuccessDetailOverride() + { + return successDetailOverride; + } + + /** + * Sets the success summary and detail displayed instead of the ones passed + * to launchOperation when the task finishes successfully. + * @param summary the success summary override. + * @param detail the success detail override. + */ + protected void setSuccessMessageOverride(LocalizableMessage summary, LocalizableMessage detail) + { + successSummaryOverride = summary; + successDetailOverride = detail; + } + /** * Returns the process that the task launched. * Returns null if not process was launched. diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java index f2850c331c..9c71d17d4c 100644 --- a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java +++ b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java @@ -1744,8 +1744,13 @@ public void backgroundTaskCompleted(final Task returnValue, Throwable t) String summaryMsg; if (task.getState() == Task.State.FINISHED_SUCCESSFULLY) { + // A task can replace the fixed success messages when its successful + // completion is an informational skip (e.g. the windows-service task + // leaving an MSI-managed service in place). + final boolean override = task.getSuccessSummaryOverride() != null; summaryMsg = - Utilities.getFormattedSuccess(successSummary, ColorAndFontConstants.errorTitleFont, successDetail, + Utilities.getFormattedSuccess(override ? task.getSuccessSummaryOverride() : successSummary, + ColorAndFontConstants.errorTitleFont, override ? task.getSuccessDetailOverride() : successDetail, ColorAndFontConstants.defaultFont); } else diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/WindowsServicePanel.java b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/WindowsServicePanel.java index 40409ad7ef..ce42bb210a 100644 --- a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/WindowsServicePanel.java +++ b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/WindowsServicePanel.java @@ -19,6 +19,7 @@ package org.opends.guitools.controlpanel.ui; import static org.opends.messages.AdminToolMessages.*; +import static org.opends.messages.ToolMessages.INFO_WINDOWS_SERVICE_MSI_MANAGED; import java.awt.Component; import java.awt.Dimension; @@ -336,7 +337,9 @@ public void runTask() returnCode = ConfigureWindowsService.disableService(outPrintStream, errorPrintStream); // SERVICE_MSI_MANAGED is an informational skip, not an error: the // MSI-managed service belongs to the installer and is removed by - // msiexec /x (disableService already printed the explanation). + // msiexec /x (disableService already printed the explanation). The + // dialog summary must not claim the service was disabled, so the + // fixed success messages are replaced for that outcome. if (returnCode != ConfigureWindowsService.SERVICE_ALREADY_DISABLED && returnCode != ConfigureWindowsService.SERVICE_DISABLE_SUCCESS && returnCode != ConfigureWindowsService.SERVICE_MSI_MANAGED) @@ -345,6 +348,12 @@ public void runTask() } else { + if (returnCode == ConfigureWindowsService.SERVICE_MSI_MANAGED) + { + setSuccessMessageOverride( + INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY.get(), + INFO_WINDOWS_SERVICE_MSI_MANAGED.get()); + } state = State.FINISHED_SUCCESSFULLY; } } diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool.properties index c7a8fdde86..ff62180fd2 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. # Portions copyright 2012 profiq s.r.o. @@ -2463,6 +2464,8 @@ INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_SUMMARY=Windows Service \ Disabled INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_DETAILS=The Windows \ service was successfully disabled. +INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Windows Service Left \ + Enabled ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_SUMMARY=Error during \ Disabling of Windows Service ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_DETAILS=An error occurred \ From 775322d725453d73ce9b253c12afb01c23a29aa9 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Mon, 10 Aug 2026 13:30:35 +0300 Subject: [PATCH 35/52] Refresh opendj_service.exe for the round-4 fail-closed ownership check --- opendj-server-legacy/lib/opendj_service.exe | Bin 176640 -> 176640 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/opendj-server-legacy/lib/opendj_service.exe b/opendj-server-legacy/lib/opendj_service.exe index 5ffd8f5bf76781bf8f57b81fb23fd3ae7b218a8d..5781c2a92dc8c980cb11c60d4b41c01950e10f25 100644 GIT binary patch delta 20378 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 IuuIAR0k27zU;qFB delta 20120 zcmeIZeO%4=AOHV;y*ufYLkA%#6-Pqsea`z_U)Ms&cB~}CG8a2?)hJiPiE1J&-t3(* zYa7NeS*V$9O^p!R<|1T^#g1i`&8(T}`*@wQi_h=x-|hR)_uOuebALTw*VnJt`+X{_ z!7r=9uZZ-%JV0(|+CKFROWKo;Jad~cOjWCA(Fmb88SFLaH&#d>ec7A>VF`)wuF7T^ z{f6+KL@InibRr3uq@vuksSbB1;Xpe+;1Md8mU04dauml9;&8j|!ozkq z+4uJdSA7!MZ)XUcbXv-k1q_p28IW6^**`y4A2R+^YY{Jht)kqUVP2dxaROiMUZxW6OA|ULz0WYt z03=9qcR;ix_lrW3uY!aLull}45``XqgGhuh%uf;U&dZ+MCLtFI>WdtH<^-2tB>N>N z?D2~rqe^Q0rb_~~Q4F)9GQf*rDiBi+78Aq`6`u2NNHGqifl?%|a5}ogFzzkCwY1P0 zQv)^rcwSqL$sg38)>wwfWe}>3Z2lPVcLvqfqZ5+GIvIo^W&Ivuy*!@1sVJ$FbA(Ob zEp+T$&AwkE)O8LgbA>0JW65~o*)HSQTOSGAyM(j*4+vj$8Pe&E2wGquMogYY9PZNg zLiYd*86=De=*KpFC@c?1>~y;Cf1)({3Eu~#Ad0=~^X&D$!iKI+c79*s&#sX@#_jOb zzD1L`H-jzx3Dx&$)0~lI1t#kV_|RFp~9n{Vrb7!o-#2XgY)AR@}Z{RmtLcD zFCT@w&%GrS2iw?nZwdEu@}WKeC6sKMF6}K#^xVWDB$3) z38^97#-sA`lUO`0__&8|eOkyM)KKPd5_D36GqQIK<762otEFoo6T{?|XY?EE)Wg%= z*X@}uFY@IRP;Z()=1NhBr{jdW5RGdcGQj!?$ZjSXzS+&Jf9|WTK7qOA{yB5uwlHX| zfA(59^HL;XC^vWvUC99s_xq1Lxg%z72u(Fh5tjRt|N35V^AB@>TCT}YRLH0MhsI(t zOBUqIR_3Ryl;)nw=r(q=d*qw6DK05GOp<#oQ$?c=HT|~qGVkd&cb%uHlKhH^lV1E+ z-46$Q>W+p~IBCVONkqyqQ4-uE{jgp=UTYO9H3 zv=x(?FGoLM@Q(Zw&wUzhAt|gsJMp2gBCM<5rCYQ#NrHR7P!wh-$AlYUUD*Y6kQ<#wPGTxliw+*~;j?IXw4aMrSlY?r=I}D7a^9RK#QwRzKq|5+;W~OR9vO z;j!dB;m2@8r{N8rac}J44C{dS;~NBZ@8mJ^AJIm21UxQ%Ps3%H11-zDwWv#yoUzpV zb9fJhKbFRi*)7Bs;!K7&_Na@gv@Q~dJLCsX#&@>1!)%%_`M5AbxY1iTya>@6cjnKR zCb|D;?Y{TuPJ*e^KFKLV;GMomFvh*@SM=CSdH$=iF=L(5FccYtA~7Or&(N*AD@^Va z(yLeN7CIKmBb;U$tL~;}1qshjMbr1Uq`Qktcz}8?wM@7<6 zj`HMrthqIao;5O0ko(G=mX^j&&I07z={o($v>jI^P8SlB*~eDXznqH z(OS=isEmTvvo-dt-#tBxHk&;G&g8-EJbj-qsjcs~dInXtE?%K1D??uVH7u8Qp8TZl z!S{vqzJbp))O&Jq%TTX7^*F+uO^EpkwjRb^a#)~-7%ghd3hQy&V(h=GCeG>mO4aRANr2@3kyA=LLC zEbNW&b0yQ9z1wnLgC&nSM04JWXig_hz4^P=4x>ASTZ(aMyB7H8j>I1IcMo}j>52Py za8z3`cHTg_#g65i=oiDR#@>emMFB;+4IwmhdZTeBqbt$Vbe4IJU59(rbzyYB(Y+U; z5{(hre{{(7Lr(HqYIa}oM;OkmvdF$M%+V~NvY) z=%mJ=?4=4Bli|x>`>cuDexJ}%K5K>>%kRK=TyGriKRjJ6bH9Vx-ni&vCQ_Ij86|N2 zeQ@2=_wUzR9qEa!L2S=rUDg^u`%FuM(}6Je-I5jkjilSbYb`BF&RQSz33|`TU^E== zYT>H^1K3xt34aZ+urFK_%mbsz&%*M7;j*(=TaZCv2r@V>>>U^!v=biK@N$333~A|_ z#o$Jl;H;&=`-B?O#+ z>Xv=Q)1mnqnn!~3P$;r^{)!MfD3~36MX(GSF=Q6qkn3wvUAGbQ3%#F&vopZCmikx0 zAJr(sSTU0-+*>fXXf}?>jP7OSh~OD0hx;9&dQixSK#c5Xn9ykHB2PL={)tHyN$z~i zPNXVprU}py2v7cZ_{_HOT7>ft9d1)?2|su^>uS2#(()Wi&we8DU)6wgEsDcUW;^4| z2t?JsMkvPZj4!Q{bP}ePB(Vq9!cpqaxJx|#l7IZ)g}<|arYwXD_4y}g6%E==gO>d( zsFNqVSv0JYhP`xAkST|-JueCg%E)f_FSN82M4&cSXdILQNrVkbo&OF5VI^>wUJiHn zZ-vXs5VBkNO&K1Mgb-AgE*NLM$<8=hy2fK%(imqVX3Bd`%y+lyf?!rnAQy!~mASJU z%L@rGAc@YvZU}u}xUE`C-WKNbQRJ*p#Lr--d@ZzBpCDU>uhspCAUsk}V+VaDOxBpm zd11TedDc}U{H(FEwi@9XtzG`tdCz*4)60w8;eH~xv^Mgg@VRy<`|^3gN2g&O=LM^- zyXxfEo=$pt#)RS;C-EFJ=<@;bZL@!#Cz6aWuW*n3PFSUj>@WxwcBXWS!DZHcP&lSb z3|U+4DKXCB%z?Li)H#poNJHO@{ze$24`V~m3D4`FC07MOpG@8n?&|H4_OqVS8x>`B zNJJ;a;5Hw6M&qd|vNQ4uIx8d^4CFguy+KL#3+0BcL=-L=hOncng%D$U`|r-6GWFdN z6TN91#TE<|elUixd1r)nrkA=%5Q+!bQ{TWREb-%(LkZ z;Z1WSNfj#0**@+(+%Rj#mW;Aw6LP=gE9-B>N4nbMCx#v-5hcIcx3lC=VdJx(vo+5P z39&BUS|rIoVX4g%uEhp*qt?7zFHWkcu1@-_zBQ=c6U5f%mGm3ZU)pnOB;E3!aZ(kU)y^_CD?+_pPnt%08mnpo2 zM3oGCdAApyh?~*^QIPLUMW1*To`y&)zR@eKpE3D&lk)HTk1by}RN^? z-2X_G|B)fGb&{&=de<7skVPdE3O5m=E@|3wf%KZP)6QIjeuWIX?95Ck9TK2zyM&ut zKO)kS&D*@#FzIePa}R2_$Iiq<%b{#&7jys;Iu!+#e7(JhC8LD2oe?El-l_4z({tL+ zp%Q8GVLB+eu|nCN;7%GC10fDFKo;TFo^+B|lJvnSub@Rd4(f$mLehz0dg9KX$uNyw za5NE_rV;7hX0d}T4!X)>oXA9HV2Fk$jD>5VSH zo&KPua)%`_%(!u;lk=};PitV(+Ph`K*-E{<=j-sU z$Zx?=j!qiu?j>~nGKO3blD`~44hz{|jv*Dol`kVY<`3$)y zXig?|RfZuu?6iRdZSI`r)siW7hX_R{EuAjoyc?JOgk*SUKk>?J@9rbqI~mw>H?5Ss zho|}3Po8A4>;IneFmOnaLh37(ZZyvK|$$l0n0oAw7VKVO>)1D z%852#5+)n@PlAEMS5-0oHxV?hA}!EaMT>kS^gg99oc{UmzMdH5>1${9G8wbLiV>Fi7WTYG=vojxt-Ho4PHiwNod z&!D#Zr=Tr8JOxe9Una|K$+(qeLqSBj5P#x*-h?_pITla`v(Y8dxce zIvq?3g|yRZzlGGlC9}ajMc941FDWQFcX~7_39D8}*^FO>p%=bjv(^f}7jv=RUcY#k z-SDfh?9z|yhrbFlF8A%SNkh-Tmab}y5RSTV=RQrzJD2|=Y|+}1qAPI(cdt8F$FuIW zB}1;Iu3&@Y}-) zc}tl2Lj{|+PT<@QwrZWQ(mjK9uM>W9C$PKM2{CtOv(0MZ;GF|N$xA<$6W0B!ptu`N zoAC18HPrg`?g+N%w-Vb=dugp2?-da5lBGXi_CcYEzrQ1qRoZEt=vSp(Adh>=>Ztny z{i?GI10RRBmqo)Zp1 zWnd9omBd42U5(kdF#dB{K+16_j<8NPS&th>r10Lkvx`luP;5)g*3}ZVCjJ{;^)N{ zMvI^HA-%xTYkkNHZ}x+z(n}(@_0eveb*+_p_c{Y*&)Y-`Uh?!$2v%AEhfIGqTF?wQfOJ-QYia+h5 zB$`B#SWy{`M6u!o3bU9SO{zP@BX&z>z?S@`vSXUkNik#^Ar7(fS)wFN>BDDuz5HeUdgd~#K(wjq2v5>DE(M-?L(M%+?8Tz@6p)W);s?ukN5tA3% zgm)==SdXn~QvFK!8J~O)(XiEKGC3k$-stMwwm1H1WJwfc3P5O7-?J1ovpICuI zA+mH*HknMwc(FVOy+6M6b`A-bvUM4v?>eHEH)mjQWzHrFZ>Kv$9JP*wv-KIJ>FdZr zAKy^;`yY|5>m?4@OgL#U%yp97z|xmClbK%Zp$zeSA*ugwtYGoN783AJ)TS+DJdIi! z{}#ChUiN6CG7VEyjOL1{oc#acgP%RF8XH)pY-H*QWa?pQe84@cYGMM-Hm-$nP zH8sOZbB~g)q-PPlkueI7Y@Y5vzXpNJ%cuJ%dY3N{4}U^d_Al_{k&FnJ;uVtXcxI}& z?p*`Vis}BxLyF;Ohv*>%3rbUuk#E|u<(EZG1qpZ6)A;dd(Y!1dZ|gQ#D{mGUb$t__+bR-Pg8WS-cm z8i&leEKz=z1d1iqWI~&9oBb?HY(7iY(;m+|M|yQWgw%dNWw2N3{Z3^_uX~@!63fn! z1hzg)>~Nm6jFhd2VXmCI^4Ik%w1~Qp$B2*BzTNZgV*bgx4#9}f`1y5j$^S%r@H8Tw zmkYMnbqFXOTSF4rgyNMk%z^+qBWvNx{^1Foly}Bs)Tv)htDpZ^?{c_2K{f>C50N1h zefx|zP5(6J!ug(v;*+mQkJgOsPlKLjd=IO`!pImVQ~y7i{C_KP9C2xSTCvuQ)4m}* zTf9>9}Lk9LE^6dgwIB$;w`59b5%r$Jk$ES);-}%X z7^yhrI?iCJca@$k1e0nz#~-;oVI&epTQ^Gq&wsV7&^ z4L{WrHH-71&kb_09b3Ixyz~PWwL*OS0|_PpVh=Y7HY;#NzVpkxCoKg9_#sBRE=HC= z;sIafK9KOFrA)sTffxT9SdYMsG_Z25_==nKWWn`r(%07$IRlYPM{i&+5Le+wmMMm+ zpjzlQ)C@@lmI;KSAS;vv&4QLg1yB)m1ge5+p?i>I6U+35v=IHg1kQu9p!LuW=p*O^ zbO~zM#JZTraL6_zA*6?%gHoXd&>H9sXczP$^ci#-YJeU=0dKI(04NR`56yvod6Q)d z!5z>cs2n;6)j_wRCr~$$WzRYSGVJ%}x289AhYR8Sl= z9-0HKf!>6Qq2tgw=ql6%v0G44C<4+$BcSn68nnQLuh*bAp%0-d=v(M6)C|ecnqX)! zq=#Z52b2coK--~W=s0uYd()= zhAxR_xUZxCPLOlU&ZHiXWUSuvolQtW9W~3%wrHw@QfrX#`7R52kBWE+{Q={8w#Tb{lPepKCmW&xE3=h zZML(G8Ewo0X})h!2WkIQwy~{LXU=A}(JbY;>jy5KO)IYh6DQ!#zX+O_u<06oDPZmg< zxfTonceL5XU}xBsAl?Zu4IqA>W+a1KZN*^pJN1Zd^Oy?uft?59EdjFw39}sJu3dj7 zCkC&??2LV>of$J{=A5|;=Y&mLG-X_RWs?mKq)GR);R9&aDb zbdyChMc5apWG_ZDQz33;G~!q48*X`ss`K z^wSZfe&OxW`{0@*$wT3ilIYL8FUOPhpM0&s1|B~nxJM#qQ_i>WRP4RBOVB2 z!(D0^W+)DFKmkxPlnObabZ9A*0~J8qpdx4oR18%@#8X#>se!u|s)yWA6Vwbb1{4eh zLXnUjiic7SnB?hjs2P&kQ4vTF#X$uSBaV(>`;<2KW##Rxwb95Fs%uj{NY&6Lcbom7&1Pa+ z!)0JYbm`D2_BCn8S$Ire1m!>lBgCs}HpW#ox^=eKfONgrf^?s*2kE+R0_i$$2IADK(IX+2Fk!lkp3YU2hx2(57K?b4&n!7CJw~%bukV&=<-YkyMU=6 z-SM1YS1=u0Z5m5AxM{Z5lA<{-C!@U7^E9r85jnZgW+Hm z*c;_D+t3?yN2`Gc-Johgx0bZ2yf{lF%$KiCY?4T(u;-N2+^6ihid2n+i`q z5PS|S0-pzWgATA5OajZmv0ypq8V^Sm9MixW>H*e*1e2f+WI;FR1wH^JU;%o}8)OnO zH$WNa0|tUpPyzaabg8rlIoLAL40ZtHz>Z*IBG$1#9I5b-gR{U+lqjGxNGEC+a1s0i zs10@n3&3vRHjw^B+itK2cnAyv%fX&tH5d%mf+1i7*b8g|L&3+1E=&qIq+>8CzyPo} z7zXwMqd*0y2m6AtUa=fOJA0lL8#zz1Lw$c)9L0%hQMFc_Q$Mu9Uy zGdK&32Umc}AdzCaO@%{(9ffX8K43a*UvMet2j+n?a1$s8i@+}6J}>|*1G|BhU=UaX zhJbF6{?X9`&;-ho(PLmB_$;UZXG$^M&2SKGS@EC*Oa^_xsh}^I4*G#hK^d3_27#ME z6SxnY36_BbTU!+<0WW|)U_Iyy-Ua=@W>5x7#vvaU9CA2JU@%Cq^+kaaP!IZmv7j&L z0R6xePzE}|ATR?ofonm6Epi*^3+@K}z(b%6EC++YYS08WfG&bP^8p;bbnhIG1fUEI z0s}!4$blpblMD0(<3T?#nTCT?X}AIvq2XW_4F}iKaIlbuN1{SB96UtB!SeA~|0D`E zq5)tn4FDTJ!eO0KfABH&2c;9>uf{S3eZer$4~(Mzdh{5z!B}dW(PPvGQ>bl6k5L=U zpo~RDC*a3(zc|#Cdc>oqln$&{P_h*36$}E)CzNWxCpGH$7K#2 z^iU`OtHEvH=iqLz3Y4RQ^prXTdn;HC&IIY{MvuJ)*i)#D3KOsiHhO}23@!tuQ)8G? zklq7WFbwt(klq6%^mK@V2R(iC;3|+_47|Zu*yu^m1%X}|9I)R7Q@{8U1%Ed_VOevh6`hu}C1mV^7iYVZ_T3vL7(z@uOj z_$BxlJOoOo#W0t^0I&uO14n{UU^%D_ey|w)4m<`5U=>&oUI0G<>%nv2UGN6j3|<2z(_@%#K{Hxhc)DT7UiibKXSuo5=Ck=PMV zuSPYnGr$6bV^Y8Aia?2;okv#0Q-4Rigb}6<9eC?{);X|giufhdopN;-4P6g zjpggPUHXFx*qcEP91S`UPY#-4zd-$w@gOh`_B0BM!7|vh!AdY2 zEQY@YtbzR+UH?V!Fu|h^9ywqfYz}n8ehYj6E(95843i1Sz%gJd3hoRB!hQo(fQcXn zil7tWT|hJJb>Jf8s|Dj=F9*{R9zX{*5gti20zA5csj$a_v%o^?53U9Cz_-Cda5tER z_}#$Wu#;&x?C#(p*yE@_3N(Y|uyes`@O`irTmUwJ+fcseqTd5-g2x0J0U7lMAH$vs zN@w7Y2f;wF0*nNUK|NRo#(`(RWbh! z4E7{23Y-I$y@2%}0*4+RFM{bvr~zYPF9qq7Oc>~Z{SsJ?jCz47uv0-N;;SiPZwIr$ zS3w5;{eVK)Gr%3-T(B7Q0?WahU`<*-JUGHp2ak6^H~10w0Q>-C@Xl>0AS)d`iro{^ zq3I%CXIzP9>`<8KGn3uyqQB+QHqhVWXs^>>25BeKpZ!8X`O4OL7zl>L4g=}Rra#+x zwgix_>`3_2mCS+O;A8mHw(4Qid2R;7Ks!jcpjZ%l+!Q7r4mxiWLE6hHAe~NALAtVM zfq`HKNayQPkj~Q_us66C>;o2nbR};B=?X6dBfz4S;__MSFTR^{uoc~nX3B*dtf?LS zrt2=i%k@ zyw)%pPCxR!Se7X1>4(6ffF0H5Cl{mVvfT&$I|_~3^a1Ajzmm~RXTe@XlZyA};ALit z*l8}?rQ7a*#iE&)!7k4cjdR&vE*e&YwV#T~$W2485cex#MnM_S2IxcR4CIEq9}rL1 zdS!WKDbP^52vR@?co|>autked9n}5>%xCCr=v`9i${ged^Cnuup{)Z8b`GU`u1a-{#B zFoQFuEy_^Lri;(hu*YDl-y*n5lhRo$=}@x*p7W+o&X^28@ts%LEgJ;l6DOA*RUjgfR=hEiKQ@?Wf)uKPz z{OG>H6mAr^&tu;R8`?PY{GKoWG`{?9TEl>_!|(naJbYT^)`MQdwDo7`tlbbEAUfx> z0p9!wI}<0an9ufX_jSCTxfL(2$zX%prH!{Ui^q#WnQX6){Hu1FHFIr=o%vyjcyB%% z)a&4)R==i&cIGkEYSCC2uf<|S2HU$^;cBc$Z=naBy1U^9Eg2lx^_nw>Z7nk^irPw{yqSXn`_bl|vOg7l3V6z=QjM$RF_8{pZ zS%93%zw&fJ_|glWFb4m_;wihTjZf|8#mR^sD!KGe5&tfV_JCw9E$WTeSczD+fHk-K z{Dz&mdP97)fbHdTxZab!r|9mpZ~c=A?LJ!1WB(*h&tRou`a)Lj^Z52Zsn~aJdj>8d zr_s*jLG<&qc9s8A+fBcC`iI@qH$MUQCFL~T|KU(AMv=Lbjsr|3ifQ?yQ;jA%Z~Lp{+vd3${`G+O*~ z0UP48a_B$4q^EcTG4XRRSpsww!zp@*(Llew+5au2?0-tBe(hfwz2QkiCW>DyVS9Q% zERSXa#2auvbEPqwxeL*C^z@UsiMm-Pc*8$_Yu>XfjqtubdHnI2` zH<*u^{Vj=>^_I6R*DS;uXnn@|yfx3d)w^>FnV^*r_a>htPGwU4%!R;f+V zPS?Jn-Ko8xb!%I+?Q~sr19U1~tZt-kvTmVnnQo14kM6jxR`-LhvtFwoqtDQ<)aU6% z{Vsi#-gR03yWZcx8O9kF8@3oeF^n|+U}DVP<`A>SY%@E|u zt>F%EmE39WI`6?)%F)VXa6Oj%7^dHD|jV8 zlYfO@gC48k8~A4aFMg=np-xh7Q14QIihjGGZczWKZdUtf254M5jaf5NGgq@h^O|O} z=8)#7<_pbjO|yp8cF=aw4$zL#zNnp{ovY2)?$Caty`>$fGw5u(c{-_Hr9YzoM1NNA zX9zJw7zP@~8(uWbHtaKWGL1Cln)aHGnZ7YyH~nC`Z~D{ZZT2^7F`q`6=b0CqU6@l_ z(W8AW8kc37Wu4`arP^}SavxphV~s?oJ!eg_Zm^2h`&NZbX^TczePKIEd&q%X9H8Q2 zFr~(G)3|xuV)W5wZYTQb6E0af8U6CPvY%>@N~^M|;#AM65>+!)nW`14RjR|P&r~N> zU!$LHsqSH>{iO=#UA_4zUd5aEXnr{V9RCvkGCHn+-_GygKj6#w&-e@cZGMpEPu*I5 zIi|~1{SSIy!wJI~!*#=c<23Uk%!G}Wi`E;~M>cxxqm?6^hBI)lavQmKxc5=5<6ISY zi)-Y5=lRDBSsuyqIH}D_wCH!smBXxkTpKgdQK}QUFgUt|Yh%>|+9EM$nMne;pakJsE zVLGPmGV>L)+nj{yH`~gj;}Hdw8_XS1P2;;_P#0<6(!Qs4eU340uhZ&Gx>35Jh9pBb zV^8BCW32h0xx(^?WsY^eb+L81^)>5S>qgAr8te16BwLED3{w`lW#Rc8n8W38gOq8? z4CU*}Kvj+^fFHz<;fXp}Jqn9;f;wMwT{q6)HuN*A%tOr2n`finzA^u79%GsBvTV1U zurymbTlLmB>r2*GtS)OlMt-ODu=O;$RbuO5d&XwAjj)ZgO|>nyt+TyB3ogJ)0b00a zs(q@{Dz_?%pN&1@4nIt@mp;N4;mHknOZ5?dntxHF*6DR-ogI5ZoGxDH&`I=Cqs%Bb z1{hs|#$aQZQDMAkzHdf~Vmt~0S2#Bprs=1N)x>GyH4aUp=1WZ%LzH2g@u=~8BO;Wy zR-loKQvRW;=kN22)a%rj)gNQ^oTL?~Y3&(?OIJ$xK;F#9@eBDq{EvJ;#7omSbTf2I zu`z9Q=?Zo4=swn+)Sc5^*8QYwr|+o`)2HbdV~;A(H|c-VTMR=DoXKcPFr}ELn_Q;V zrsJklrteMN&ArSS*59qmY=yQ%w&S*owt8Emjj6{SALV;-oj5g@!Y#z)yTIMV?(u|c zuMAQSR_c_`W8%G}T%vR-^Oddw z|H5+^$(`zB>RNS2^h=aRqgkr))^^ek(>k=t+7fM~?ySzHU$5VyuhkPnC&M(u2Zj#~ zM-0aeb%w6S0Y;6{VvI9BXB=mI(Ky?fZ`@(rV?1vB#$~KEzGzx%iow?K$lTr%WZ^C0 z)`6G}GpygDb;Q=ern8N=O|~&jc!`6SFzNU;(%~MsVnpJW94Bn_tRe!5a*1V)C#da*kcC6ICqFtyR zrAyRJ)1~R=>Xz$X*KN{m!TEMn_qnc8cR_bc_oMD-U5iex@2U^d573+RcKr~{rEB^M6(Ph`FGlf z+EATNm!eyuTd(_2SEhS__Ke2>+|e5h6Ahh>p~ewLyJ@ItiYdpGZ+h2MX8O`}+Ei=m zXnxat$o#QcVLNBLL@Nq*QEyc5 zS68cF(7vKys_%i*OlfE^+%rh9Nd#ech%^p1s*HN0)fkJS9ma*m_l)O_p=O17tK~hM z`NwePpR-)I+{3xwV)31MX4v*)_hjtEvvcZP zoEc}CgB!<9;bwE$ILkzCFIUVR;VyEQl_OQ-REyO)>U^BtMe4okgX&WC8TB{n{u+xW zTeDuXRr9_^sWoXwYhTi?*VgFF#udi*jc1L&8%LUcHBC0pHy4>ti|{X}cBbrQ~jSvUvQS>LmM zWBto&!0C_sQF`ly3g%{Tr<6n$j+1?=>OB?1ci@L%Doy0)@Jsn@ewccSCR4LhQ=$1v zQ>(d$t4y_4uag-341tDT1_kDRwBZdyoN=^K#1`cG1l{$W@xIZ^)Ya6_WWe2JqG_(F z0F&yF=>(?KBlA&<*1Ezv0bA@{8-mMtP=>2iDue0;)nwI5^xu!F zK-?sz@XK-e`j-ElSE=plN$Qu?voX8AQD0TxP~TJAaIOs3Jf|6}$#7|xX*X*twD+}~ z{s-et%R`IPx*6BRvsMPz#86uS?d*cq_gv3#W4IFCLTp8caPj(9&lC~Qi@Xio7TgfO z;w;$J`e~9iFKUkJ?^v6xB28P|8b`0!0@XIvC#o-0(YTC{R*zFpR=d=z z)OXasseLtFHQ}0Q&D)rmr!-eIw=@ql?`m&q{d9eF@9U1~zQi%tsJ9r8m@iux>l*7O z7cLd=Sx;EcS?jEBJWTl5f@~2s-ZlyoZCC3Wt|6Wuha_AFt{WGM?PMEQ#O>gAbNjGP z4sm7NF|HhUxt*riFTZkUx3FK zsamF%tLLk~RD0<{bc1!%5_JW-OS+-@4f-Per`VtUaie>BH+gzBsW2v)CYWYpr+XX4 zrr`4Yp_yqSo*PgZcT2fT6^k2x9>0@6&VR>0=KF}__OJs(rs|#gbp0ZI79MsA^o1y3 zx4sz10KLc7h`D>%lP-p183mp=!c+=Xq{@yHGfq{mslv&40c)pDQ?F^zxHWe%h|QYE z8vI2GP9d3At_{{Iv{714tJdnZX02TttBupf<06oVt3Zl2RXbJd)XvhTYcp`mT&m5| z=4kV@YqbU1P1-{3Hf<3eC3b7~X^X`JAFv@}%?GU7D@B(odhNv@0!mFXliUlf#r~O2&04)r20lvrHbEP^jFdEW%x8w{oAd7{gzt zJcjFZrLsy{t*pT;PBEq$ry8Bcea1t^W5!BjwefRbMU+Qa-I%u zm|CHZQpc(j)yZn7dX_p}y+~bv-Ft`nkh%<$tycY5&lrLYVK{^BhE#*oFw2l Date: Mon, 10 Aug 2026 15:43:10 +0300 Subject: [PATCH 36/52] Address review round 5: ImagePath ownership proof, refuse upgrade on a running legacy service - LEGACY_SVC_IMAGEPATH (raw registry search of the legacy service's own ImagePath) gates RemoveLegacyServiceControl and both custom actions: the "OpenDJ Server" service - the name the first zip instance on a host claims - is only ever stopped or removed when it provably points into [OPENDJ], the directory this install resolves to. - The immediate net stop cannot elevate under a filtered UAC token, so a CheckLegacyServiceStopped action (PowerShell state query, needs no elevation) now refuses the upgrade with error 1722 while the owned legacy service is still running, instead of proceeding into REP with locked jars (JVM opens them without FILE_SHARE_DELETE, JDK-8224794). - test-msi-upgrade: the headline upgrade now runs with the legacy service RUNNING (exercises stop+check elevated), plus a repair scenario and a fresh-install-elsewhere scenario assert the component leaves an unrelated instance's service alone. - OPENDJ_REG search Type raw: existence validation dropped the value for a renamed/offline directory, silently un-registering the host. - removeService reports an error (exit 3) when the SCM cannot be enumerated instead of mapping to "already disabled"; isMsiManagedService expands REG_EXPAND_SZ InstallDir values. - Both MSI-managed messages localized into the nine bundles. - New Validate the MSI (ICE) step: wix build runs no ICE validation. --- .github/workflows/build.yml | 54 ++++++++- .../asciidoc/install-guide/chap-install.adoc | 2 +- .../resources/msi/package.wxs | 108 ++++++++++++------ .../src/build-tools/windows/service.c | 26 +++++ .../src/build-tools/windows/service.h | 2 +- .../messages/admin_tool_ca_ES.properties | 2 + .../opends/messages/admin_tool_de.properties | 2 + .../opends/messages/admin_tool_es.properties | 2 + .../opends/messages/admin_tool_fr.properties | 2 + .../opends/messages/admin_tool_ja.properties | 2 + .../opends/messages/admin_tool_ko.properties | 2 + .../opends/messages/admin_tool_pl.properties | 2 + .../messages/admin_tool_zh_CN.properties | 2 + .../messages/admin_tool_zh_TW.properties | 2 + .../org/opends/messages/tool_ca_ES.properties | 2 + .../org/opends/messages/tool_de.properties | 2 + .../org/opends/messages/tool_es.properties | 2 + .../org/opends/messages/tool_fr.properties | 2 + .../org/opends/messages/tool_ja.properties | 2 + .../org/opends/messages/tool_ko.properties | 2 + .../org/opends/messages/tool_pl.properties | 2 + .../org/opends/messages/tool_zh_CN.properties | 2 + .../org/opends/messages/tool_zh_TW.properties | 2 + 23 files changed, 186 insertions(+), 42 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4889ef3c96..1ae768bcb3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -141,6 +141,16 @@ jobs: env: MAVEN_OPTS: -Dhttps.protocols=TLSv1.2 -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.requestSentEnabled=true -Dmaven.wagon.http.retryHandler.count=10 run: mvn --batch-mode --errors --update-snapshots verify --file pom.xml ${{ steps.failsafe.outputs.MAVEN_PROFILE_FLAG }} + - name: Validate the MSI (ICE) + # wix build runs no ICE validation (only MSBuild projects or an explicit validate + # do), so a green build alone proves the authoring compiles, not that it validates - + # e.g. the ICE63 rule about script-generating actions sequenced before + # RemoveExistingProducts would go unnoticed without this step. + if: runner.os == 'Windows' && matrix.java == '11' + shell: bash + run: | + msi=$(ls opendj-packages/opendj-msi/opendj-msi-standard/target/*.msi) + wix msi validate "$msi" - name: Test on Unix if: runner.os == 'Linux' run: | @@ -816,13 +826,13 @@ jobs: $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" & "$root\setup.bat" -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --addBaseEntry --cli --acceptLicense --no-prompt --doNotStart if ($LASTEXITCODE -ne 0) { throw "setup.bat (5.1.2) failed: $LASTEXITCODE" } - # Register the LEGACY service the pre-MSI way and prove it works, then stop it. + # Register the LEGACY service the pre-MSI way, prove it works, and LEAVE IT + # RUNNING: the upgrade itself must stop it (StopLegacyServiceBeforeUpgrade runs + # elevated here) before CheckLegacyServiceStopped would otherwise refuse. & "$root\bat\windows-service.bat" --enableService if ($LASTEXITCODE -ne 0) { throw "windows-service --enableService failed: $LASTEXITCODE" } net start "OpenDJ Server" if ($LASTEXITCODE -ne 0) { throw "net start (5.1.2) failed: $LASTEXITCODE" } - net stop "OpenDJ Server" - if ($LASTEXITCODE -ne 0) { throw "net stop (5.1.2) failed: $LASTEXITCODE" } - name: Upgrade with the newly built MSI (no OPENDJ - location auto-detected) shell: pwsh run: | @@ -860,6 +870,23 @@ jobs: if ($LASTEXITCODE -ne 0) { throw "ldapsearch after upgrade failed: $LASTEXITCODE" } net stop OpenDJ if ($LASTEXITCODE -ne 0) { throw "net stop (upgraded) failed: $LASTEXITCODE" } + - name: Repair must not touch an unrelated instance's legacy-named service + shell: pwsh + run: | + # RemoveLegacyServiceControl is Transitive and both of its signals are gone in + # maintenance mode (FindRelatedProducts does not run there at all), so a repair + # must leave an "OpenDJ Server" registered by a zip instance AFTER the upgrade + # alone. This is the assertion review rounds 3-5 were about: the component + # condition was wrong twice and nothing in CI exercised it. + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + sc.exe create "OpenDJ Server" binPath= "C:\zip-instance\lib\opendj_service.exe start ""C:\zip-instance.""" start= demand + if ($LASTEXITCODE -ne 0) { throw "sc create failed: $LASTEXITCODE" } + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" REINSTALL=ALL REINSTALLMODE=vomus /quiet /qn /norestart /l*v repair.log" + if ($p.ExitCode -ne 0) { Get-Content repair.log -Tail 80; throw "repair failed: $($p.ExitCode)" } + if (-not (Get-Service "OpenDJ Server" -ErrorAction SilentlyContinue)) { throw "repair deleted an unrelated instance's service" } + sc.exe delete "OpenDJ Server" + if ($LASTEXITCODE -ne 0) { throw "sc delete failed: $LASTEXITCODE" } + Write-Host "Repair left the unrelated 'OpenDJ Server' service in place" - name: Auto-detect the legacy default directory on a fresh install shell: pwsh run: | @@ -912,3 +939,24 @@ jobs: Write-Host "Upgrade refused with guidance, original install untouched (exit $($p.ExitCode))" $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x opendj-5.1.2.msi /quiet /qn /norestart /l*v uninstall-custom.log" if ($p.ExitCode -ne 0) { Get-Content uninstall-custom.log -Tail 80; throw "msiexec /x (5.1.2 cleanup) failed: $($p.ExitCode)" } + - name: Fresh install elsewhere must not touch a legacy-named service it does not own + shell: pwsh + run: | + # A leftover Program Files (x86)\OpenDJ makes the legacy fresh-install disjunct + # of RemoveLegacyServiceControl true, but the ownership gate (the service's + # ImagePath must point into [OPENDJ]) has to keep the installer away from an + # "OpenDJ Server" registered by a zip instance when the install goes somewhere + # else entirely - the round-5 blocker scenario. + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue + New-Item -ItemType Directory -Force "C:\Program Files (x86)\OpenDJ" | Out-Null + sc.exe create "OpenDJ Server" binPath= "C:\zip-instance\lib\opendj_service.exe start ""C:\zip-instance.""" start= demand + if ($LASTEXITCODE -ne 0) { throw "sc create failed: $LASTEXITCODE" } + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=C:\opendj-elsewhere /quiet /qn /norestart /l*v install-elsewhere.log" + if ($p.ExitCode -ne 0) { Get-Content install-elsewhere.log -Tail 80; throw "msiexec /i (elsewhere) failed: $($p.ExitCode)" } + if (-not (Test-Path "C:\opendj-elsewhere\setup.bat")) { throw "install did not land in C:\opendj-elsewhere" } + if (-not (Get-Service "OpenDJ Server" -ErrorAction SilentlyContinue)) { throw "fresh install elsewhere deleted an unrelated instance's service" } + sc.exe delete "OpenDJ Server" + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall-elsewhere.log" + if ($p.ExitCode -ne 0) { Get-Content uninstall-elsewhere.log -Tail 80; throw "msiexec /x (elsewhere cleanup) failed: $($p.ExitCode)" } + Write-Host "Fresh install elsewhere left the unrelated 'OpenDJ Server' service in place" 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 7f965c6dcd..d660950cc7 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 @@ -644,7 +644,7 @@ On Windows you can install OpenDJ directory server from the `.msi` package. The [NOTE] ====== -When the installer replaces a legacy OpenDJ installation (an upgrade from a pre-5.2.0 package, or a fresh install that adopts a detected legacy default directory on a host where no 5.2.0-or-later package has recorded its installation location), it stops and removes the service registered by the legacy `windows-service.bat` command, replacing it with the installer-managed `OpenDJ` service. Services belonging to other server instances are not touched: upgrades between 5.2.0-or-later packages and repairs leave any `OpenDJ Server` service in place. Because the installer-managed service is registered with automatic start, Windows logs a start failure at every boot until the instance has been configured with `setup`. +When the installer replaces a legacy OpenDJ installation (an upgrade from a pre-5.2.0 package, or a fresh install that adopts a detected legacy default directory on a host where no 5.2.0-or-later package has recorded its installation location), it stops and removes the service registered by the legacy `windows-service.bat` command, replacing it with the installer-managed `OpenDJ` service. The legacy service is only ever touched when its own registration points into the directory being upgraded; services belonging to other server instances are not touched, and upgrades between 5.2.0-or-later packages and repairs leave any `OpenDJ Server` service in place. If the legacy service is still running and the installer cannot stop it — for example when the installer was started without elevation — the upgrade fails with Windows Installer error 1722 naming the `CheckLegacyServiceStopped` action rather than proceeding against a running server: stop the service first (`net stop "OpenDJ Server"` from an elevated prompt) or run the installer from an elevated prompt, then retry. Because the installer-managed service is registered with automatic start, Windows logs a start failure at every boot until the instance has been configured with `setup`. ====== . Make sure a supported Java runtime is available, as described in xref:#before-you-install["To Prepare For Installation"]. diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index f432900ae5..9d51ac200e 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -47,17 +47,33 @@ formally undefined). Precedence: an explicit OPENDJ (command line / UI) always wins; then the registry value written by this package (custom paths, new installs); then the legacy x86 default directory ([ProgramFilesFolder] is - Program Files (x86) in an x64 package), fresh installs only. The registry action - runs FIRST: each action is guarded by NOT OPENDJ, so whichever runs earlier wins - and the registry has no NOT Installed guard (Remember Property pattern) so - maintenance and uninstall resolve the real location. --> + Program Files (x86) in an x64 package), fresh installs with no recorded location + only. The registry action runs FIRST: each action is guarded by NOT OPENDJ, so + whichever runs earlier wins and the registry has no NOT Installed guard + (Remember Property pattern) so maintenance and uninstall resolve the real + location. Type="raw", not "directory": an existence-validated search silently + drops the value when the recorded directory is renamed or its volume is offline, + un-registering a properly registered host - the value this package writes is + REG_SZ, which raw returns unmangled. --> + Name="InstallDir" Type="raw"/> + + + + + they are removed. Proceeding on a missed stop is NOT benign: the JVM opens jars + without FILE_SHARE_DELETE (hardcoded, JDK-8224794 is Won't Fix), so locked jars + cannot be renamed into Config.Msi and the nested uninstall degrades to + delete-on-reboot entries naming the original paths. So: a best-effort immediate + '"net.exe" stop' first, then an immediate check that REFUSES the upgrade while + "OpenDJ Server" is still running. Immediate actions impersonate the invoking + user (a deferred elevated stop cannot be used: it is only written into the + installation script, breaking the RemoveExistingProducts placement rule - ICE63 + - and executing only after the old tree is gone), so the stop succeeds from an + elevated console / SCCM / SYSTEM / CI but fails access-denied under the filtered + token of a UAC double-click (swallowed by Return="ignore", which also covers the + service simply not running). Querying the state needs no elevation, so the check + works everywhere and turns the silent half-upgrade into a deterministic msiexec + failure (error 1722 naming CheckLegacyServiceStopped; guidance in the install + guide: stop the service or run the installer elevated). PowerShell instead of + 'sc query | findstr': the exit code needs no parsing of localized output - and + no square brackets in the command, ExeCommand is a Formatted field. Full paths + prevent resolving the exes from the working directory. Both actions are gated on + LEGACY_MSI_DETECTED (not WIX_UPGRADE_DETECTED: on a new-MSI-to-new-MSI upgrade + "OpenDJ Server" can only be an unrelated zip instance's service) AND on the + ImagePath ownership evidence, like the component below. --> + - + + + on PROOF that the service belongs to the tree being replaced - two conjuncts: + (1) a legacy-era signal: an upgrade from a WiX3-era release (LEGACY_MSI_DETECTED; + a new-MSI-to-new-MSI upgrade must not match - its own service is named "OpenDJ") + or a fresh install genuinely adopting the legacy x86 default directory + (NOT OPENDJ_REG mirrors SetOpendjFromLegacyDir and is essential: NOT Installed is + also true during every major upgrade, and on a host that came through a 5.1.x + upgrade the install root IS the legacy directory, so without the registry guard + this disjunct would fire on every later 5.2.x-to-5.2.y upgrade); AND + (2) ownership evidence: the service's own ImagePath must point into [OPENDJ], + the directory this install resolves to. Without (2), "OpenDJ Server" - the name + the FIRST zip instance on a host claims - would be deleted whenever a leftover + legacy directory exists, even when installing somewhere else entirely. [OPENDJ] + from the searches ends with a backslash, making the substring match a real + prefix test; an explicit command-line OPENDJ without one could prefix-match a + sibling directory (C:\dj vs C:\dj2) - accepted residual, a legacy signal must + also hold. Transitive: maintenance re-evaluates the condition and it is then + always false (FindRelatedProducts does not run at all in maintenance mode, so + LEGACY_MSI_DETECTED is unset, and Installed kills the second disjunct), so the + component leaves the install set and a repair cannot re-run the removal against + a zip instance registered later - asserted by the repair scenario in + test-msi-upgrade. --> + Condition="(LEGACY_MSI_DETECTED OR (NOT Installed AND OPENDJ_LEGACY AND NOT OPENDJ_REG)) AND (LEGACY_SVC_IMAGEPATH ~>< OPENDJ)"> diff --git a/opendj-server-legacy/src/build-tools/windows/service.c b/opendj-server-legacy/src/build-tools/windows/service.c index 4b35b157f9..51bad671b5 100644 --- a/opendj-server-legacy/src/build-tools/windows/service.c +++ b/opendj-server-legacy/src/build-tools/windows/service.c @@ -1164,6 +1164,9 @@ ServiceReturnCode getServiceName(char* cmdToRun, char* serviceName) } else { + // Distinct from "no service matched": callers such as removeService must + // report an error instead of concluding the service does not exist. + returnValue = SERVICE_LIST_UNAVAILABLE; debug("getServiceName: could not get service list."); } @@ -2640,6 +2643,22 @@ static BOOL isMsiManagedService(char *serviceName) } // RegQueryValueEx does not guarantee the terminating null. installDir[size] = '\0'; + // The package writes REG_SZ; a hand-edited REG_EXPAND_SZ value would + // otherwise compare literally ('%ProgramFiles%...' vs the expanded path). + if (type == REG_EXPAND_SZ) + { + char expanded[COMMAND_SIZE]; + DWORD n = ExpandEnvironmentStrings(installDir, expanded, sizeof(expanded)); + if ((n == 0) || (n > sizeof(expanded))) + { + // Fail closed, as below: the reference directory cannot be resolved, so + // the entry cannot be proven orphaned. + debug("isMsiManagedService: could not expand InstallDir '%s', " + "treating '%s' as MSI-managed.", installDir, serviceName); + return TRUE; + } + strcpy(installDir, expanded); + } if (getServiceList(&serviceList, &nbServices) == SERVICE_RETURN_OK) { @@ -2784,6 +2803,13 @@ int removeService() { returnCode = removeServiceWithServiceName(serviceName); } + else if (code == SERVICE_LIST_UNAVAILABLE) + { + // The SCM could not be enumerated: "the service does not exist" cannot + // be proven, so report an error instead of the "already disabled" + // success the callers map exit code 1 to. + returnCode = 3; + } else { returnCode = 1; diff --git a/opendj-server-legacy/src/build-tools/windows/service.h b/opendj-server-legacy/src/build-tools/windows/service.h index 1d99c53b2a..42e2c1b24e 100644 --- a/opendj-server-legacy/src/build-tools/windows/service.h +++ b/opendj-server-legacy/src/build-tools/windows/service.h @@ -86,7 +86,7 @@ typedef struct { typedef enum { SERVICE_RETURN_OK, SERVICE_RETURN_ERROR, SERVICE_IN_USE, SERVICE_NOT_IN_USE, DUPLICATED_SERVICE_NAME, SERVICE_ALREADY_EXISTS, - SERVICE_MARKED_FOR_DELETION + SERVICE_MARKED_FOR_DELETION, SERVICE_LIST_UNAVAILABLE } ServiceReturnCode; diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ca_ES.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ca_ES.properties index 1305a566df..55f860360b 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ca_ES.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ca_ES.properties @@ -1,3 +1,4 @@ +# Portions Copyright 2026 3A Systems, LLC. INFO_CLI_UNINSTALL_CONFIRM_BACKUPS=Voleu treure els fitxers de c\u00f2pia de seguretat continguts al directori bak? INFO_CLI_UNINSTALL_CONFIRM_CONFIGURATION_SCHEMA=Voleu treure els fitxers de configuraci\u00f3 i d'esquema? INFO_CLI_UNINSTALL_CONFIRM_DATABASES=Voleu treure el contingut de la base de dades? @@ -62,3 +63,4 @@ INFO_DESCRIPTION_SUBCMD_ENABLE_REPLICATION=Actualitza la configuraci\u00f3 dels INFO_DESCRIPTION_SUBCMD_DISABLE_REPLICATION=Deshabilita la replicaci\u00f3 en el servidor especificat per al DN base proporcionat i treu les refer\u00e8ncies en els altres servidors amb els quals est\u00e0 replicant les dades INFO_DESCRIPTION_SUBCMD_STATUS_REPLICATION=Mostra un llistat amb la configuraci\u00f3 de replicaci\u00f3 b\u00e0sica dels DN base dels servidors definits en la informaci\u00f3 de registrament. Si no s'especifica el DN base com a par\u00e0metre es mostra la informaci\u00f3 per a tots els DN base INFO_REPLICATION_DESCRIPTION_EQUIVALENT_COMMAND_FILE_PATH=La ruta sencera al fitxer on les comandes equivalents sense interacci\u00f3 seran escrites quant aquesta comanda s'executa en mode interactiu +INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=El servei de Windows es mant\u00e9 habilitat diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_de.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_de.properties index 1dd9824a45..350bea57a2 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_de.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_de.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. @@ -1593,6 +1594,7 @@ INFO_CTRL_PANEL_DISABLE_WINDOWS_SERVICE_BUTTON=Deaktivieren... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUMMARY=Windows-Dienst wird deaktiviert... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_SUMMARY=Windows-Dienst deaktiviert INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_DETAILS=Der Windows-Dienst wurde erfolgreich deaktiviert. +INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Windows-Dienst bleibt aktiviert ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_SUMMARY=Fehler beim Deaktivieren des Windows-Diensts ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_DETAILS=Beim Deaktivieren des Windows-Diensts ist ein Fehler aufgetreten. Fehlercode: %d. INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUMMARY=Windows-Dienst wird aktiviert... diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_es.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_es.properties index 4c984c0e69..4b05783f0c 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_es.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_es.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. @@ -1593,6 +1594,7 @@ INFO_CTRL_PANEL_DISABLE_WINDOWS_SERVICE_BUTTON=Deshabilitar... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUMMARY=Inhabilitando el servicio de Windows... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_SUMMARY=Windows Service deshabilitado INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_DETAILS=El servicio de Windows se ha deshabilitado correctamente. +INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=El servicio de Windows permanece habilitado ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_SUMMARY=Error al deshabilitar Windows Service ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_DETAILS=Se produjo un error al deshabilitar Windows Service. C\u00f3digo de error: %d. INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUMMARY=Habilitando el servicio de Windows... diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_fr.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_fr.properties index b315ccf894..eb0b8a8924 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_fr.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_fr.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. @@ -1593,6 +1594,7 @@ INFO_CTRL_PANEL_DISABLE_WINDOWS_SERVICE_BUTTON=D\u00e9sactiver... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUMMARY=D\u00e9sactivation du service Windows... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_SUMMARY=Service Windows d\u00e9sactiv\u00e9 INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_DETAILS=Le Service Windows a \u00e9t\u00e9 d\u00e9sactiv\u00e9. +INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Service Windows laiss\u00e9 activ\u00e9 ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_SUMMARY=Erreur lors de la d\u00e9sactivation du Service Windows ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_DETAILS=Une erreur s'est produite lors de la d\u00e9sactivation du service Windows. Code d'erreur\u00a0: %d. INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUMMARY=Activation du service Windows... diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ja.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ja.properties index 738f140346..98d1441e24 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ja.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ja.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. @@ -1592,6 +1593,7 @@ INFO_CTRL_PANEL_DISABLE_WINDOWS_SERVICE_BUTTON=\u7121\u52b9\u5316... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUMMARY=Windows \u30b5\u30fc\u30d3\u30b9\u3092\u7121\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_SUMMARY=Windows \u30b5\u30fc\u30d3\u30b9\u304c\u7121\u52b9\u306b\u306a\u308a\u307e\u3057\u305f INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_DETAILS=Windows \u30b5\u30fc\u30d3\u30b9\u304c\u6b63\u5e38\u306b\u7121\u52b9\u306b\u306a\u308a\u307e\u3057\u305f\u3002 +INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Windows \u30b5\u30fc\u30d3\u30b9\u306f\u6709\u52b9\u306e\u307e\u307e\u3067\u3059 ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_SUMMARY=Windows \u30b5\u30fc\u30d3\u30b9\u306e\u7121\u52b9\u5316\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_DETAILS=Windows \u30b5\u30fc\u30d3\u30b9\u306e\u7121\u52b9\u5316\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u30a8\u30e9\u30fc\u30b3\u30fc\u30c9: %d. INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUMMARY=Windows \u30b5\u30fc\u30d3\u30b9\u3092\u6709\u52b9\u5316\u3057\u3066\u3044\u307e\u3059... diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ko.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ko.properties index eaff621d1f..b106fc2d17 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ko.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ko.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2009 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. @@ -325,3 +326,4 @@ INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUMMARY=Windows \uc11c\ube44\uc2a4\ub97 INFO_CTRL_PANEL_ERROR_DIALOG_TITLE=\uc624\ub958 INFO_CTRL_PANEL_DB_HEADER=\ubc31\uc5d4\ub4dc \uc544\uc774\ub514 INFO_PROGRESS_IMPORT_AUTOMATICALLY_GENERATED_REMOTE=\uc790\ub3d9\uc73c\ub85c \uc0dd\uc131\ub41c \ub370\uc774\ud130(%s \ud56d\ubaa9)\ub97c \uac00\uc838\uc624\ub294 \uc911 +INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Windows \uc11c\ube44\uc2a4\uac00 \ud65c\uc131\ud654\ub41c \uc0c1\ud0dc\ub85c \uc720\uc9c0\ub428 diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_pl.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_pl.properties index 17604066d2..595aa3acec 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_pl.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_pl.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. @@ -540,3 +541,4 @@ INFO_CTRL_PANEL_STOPPING_SERVER_SUCCESSFUL_DETAILS=Serwer zatrzymany pomy\u015bl INFO_CTRL_PANEL_CONFIRMATION_EXPORT_LDIF_DETAILS=File '%s' exists and its contents will be overwritten.

Czy chcesz kontynuowa\u0107? ERR_ADMINISTRATOR_PWD_DO_NOT_MATCH=Podane has\u0142a r\u00f3\u017cni\u0105 si\u0119. INFO_REMOVE_SCHEMA_AND_CONFIGURATION_LABEL=Pliki Konfiguracyjne i Schematy +INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Us\u0142uga systemu Windows pozosta\u0142a w\u0142\u0105czona diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_CN.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_CN.properties index f2c6442f2e..3e2014fee5 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_CN.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_CN.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. @@ -1593,6 +1594,7 @@ INFO_CTRL_PANEL_DISABLE_WINDOWS_SERVICE_BUTTON=\u7981\u7528... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUMMARY=\u6b63\u5728\u7981\u7528 Windows \u670d\u52a1... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_SUMMARY=Windows \u670d\u52a1\u5df2\u7981\u7528 INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_DETAILS=\u5df2\u6210\u529f\u7981\u7528 Windows \u670d\u52a1\u3002 +INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Windows \u670d\u52a1\u4fdd\u6301\u542f\u7528\u72b6\u6001 ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_SUMMARY=\u7981\u7528 Windows \u670d\u52a1\u671f\u95f4\u51fa\u9519 ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_DETAILS=\u7981\u7528 Windows \u670d\u52a1\u671f\u95f4\u51fa\u73b0\u9519\u8bef\u3002\u9519\u8bef\u4ee3\u7801: %d\u3002 INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUMMARY=\u6b63\u5728\u542f\u7528 Windows \u670d\u52a1... diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_TW.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_TW.properties index b3c9b04224..b1cde49bf4 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_TW.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_TW.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2009 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. @@ -325,3 +326,4 @@ INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUMMARY=\u6b63\u5728\u555f\u7528 Window INFO_CTRL_PANEL_ERROR_DIALOG_TITLE=\u932f\u8aa4 INFO_PROGRESS_IMPORT_AUTOMATICALLY_GENERATED_REMOTE=\u6b63\u5728\u532f\u5165\u81ea\u52d5\u7522\u751f\u7684\u8cc7\u6599 (%s \u500b\u9805\u76ee) INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TIME=\u6642\u9593: +INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Windows \u670d\u52d9\u4fdd\u6301\u555f\u7528\u72c0\u614b diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_ca_ES.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_ca_ES.properties index 3fc8354b3d..1fc2102d47 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_ca_ES.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_ca_ES.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. INFO_ENCPW_DESCRIPTION_LISTSCHEMES_7=Llistar els esquemes d'emmagatzemament de contrasenya disponibles INFO_ENCPW_DESCRIPTION_CLEAR_PW_8=Contrasenya de text-clar per codificar o per comparar contra una contrasenya codificada @@ -465,3 +466,4 @@ INFO_LDIFDIFF_DESCRIPTION_CHECK_SCHEMA_1674=T\u00e9 en compte la sintaxis dels a INFO_INSTALLDS_PROVIDE_BASE_DN_PROMPT_1700=Voleu crear DNs base al servidor? ERR_INSTALLDS_NO_BASE_DN_AND_CONFLICTING_ARG_1701=Heu especificat no crear un DN base. Si no es crea cap DN base no es pot especificar l'argument '%s' INFO_DESCRIPTION_BACKEND_TOOL_1893=Aquesta utilitat pot utilitzar-se per a depurar una infraestructura de fons +INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=El servei est\u00e0 gestionat pel paquet Windows Installer (MSI) d'OpenDJ i no s'ha modificat. S'elimina autom\u00e0ticament quan es desinstal\u00b7la el paquet diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_de.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_de.properties index aa69607206..623a999d9b 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_de.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_de.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. @@ -653,6 +654,7 @@ INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED_831=Der Server wurde erfolgreich als W INFO_WINDOWS_SERVICE_ALREADY_DISABLED_832=Der Server wurde bereits als Windows-Dienst deaktiviert WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION_833=Der Server wurde f\u00fcr die L\u00f6schung als Windows-Dienst markiert ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=Unerwarteter Fehler beim Versuch, den Server als Windows-Dienst zu deaktivieren%nStellen Sie sicher, dass Sie die Administratorrechte besitzen (nur Administratoren k\u00f6nnen den Server als Windows-Dienst deaktivieren) +INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=Der Dienst wird vom OpenDJ Windows Installer-Paket (MSI) verwaltet und wurde nicht ver\u00e4ndert. Er wird automatisch entfernt, wenn das Paket deinstalliert wird INFO_WINDOWS_SERVICE_ENABLED_835=Der Server ist als Windows-Dienst aktiviert. Der Dienstname f\u00fcr den Server ist: %s INFO_WINDOWS_SERVICE_DISABLED_836=Der Server ist nicht als Windows-Dienst aktiv ERR_WINDOWS_SERVICE_STATE_ERROR_837=Unerwarteter Fehler beim Versuch, den Status des Servers als Windows-Dienst abzurufen diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_es.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_es.properties index d38b8b63a5..fceb3e6820 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_es.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_es.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. @@ -653,6 +654,7 @@ INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED_831=El servidor se ha deshabilitado co INFO_WINDOWS_SERVICE_ALREADY_DISABLED_832=El servidor ya se ha deshabilitado como servicio de Windows WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION_833=El servidor ha sido marcado para su eliminaci\u00f3n como servicio de Windows ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=Se ha producido un error inesperado al tratar de inhabilitar el servidor como servicio de Windows%nCompruebe si posee los derechos de administrador (s\u00f3lo los Administradores pueden inhabilitar el servidor como servicio de Windows) +INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=El servicio est\u00e1 administrado por el paquete de Windows Installer (MSI) de OpenDJ y no se ha modificado. Se elimina autom\u00e1ticamente al desinstalar el paquete INFO_WINDOWS_SERVICE_ENABLED_835=El servidor est\u00e1 habilitado como servicio de Windows. El nombre de servicio para el servidor es: %s INFO_WINDOWS_SERVICE_DISABLED_836=El servidor est\u00e1 deshabilitado como servicio de Windows ERR_WINDOWS_SERVICE_STATE_ERROR_837=Se ha producido un error inesperado al tratar de recuperar el estado del servidor como un servicio de Windows diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_fr.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_fr.properties index c8934aa03c..fb7d5b2ef8 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_fr.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_fr.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. @@ -653,6 +654,7 @@ INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED_831=Le serveur a \u00e9t\u00e9 d\u00e9 INFO_WINDOWS_SERVICE_ALREADY_DISABLED_832=Le serveur a d\u00e9j\u00e0 \u00e9t\u00e9 d\u00e9sactiv\u00e9 en tant que service Windows WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION_833=Le serveur a \u00e9t\u00e9 marqu\u00e9 pour suppression en tant que service Windows ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=Une erreur inattendue s'est produite lors de la tentative de d\u00e9sactivation du serveur en tant que service Windows.%nV\u00e9rifiez que vous disposez de droits d'administrateur (seuls les administrateurs peuvent d\u00e9sactiver le serveur en tant que service Windows) +INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=Le service est g\u00e9r\u00e9 par le package Windows Installer (MSI) d'OpenDJ et n'a pas \u00e9t\u00e9 modifi\u00e9. Il est supprim\u00e9 automatiquement lors de la d\u00e9sinstallation du package INFO_WINDOWS_SERVICE_ENABLED_835=Le serveur est activ\u00e9 en tant que service Windows. Le nom de service du serveur est\u00a0: %s INFO_WINDOWS_SERVICE_DISABLED_836=Le serveur est d\u00e9sactiv\u00e9 en tant que service Windows ERR_WINDOWS_SERVICE_STATE_ERROR_837=Une erreur inattendue s'est produite lors de la tentative de r\u00e9cup\u00e9ration de l'\u00e9tat du serveur en tant que service Windows diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_ja.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_ja.properties index bee708142d..495ab54d46 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_ja.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_ja.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. @@ -653,6 +654,7 @@ INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED_831=Windows \u30b5\u30fc\u30d3\u30b9\u INFO_WINDOWS_SERVICE_ALREADY_DISABLED_832=Windows \u30b5\u30fc\u30d3\u30b9\u3068\u3057\u3066\u5b9f\u884c\u3055\u308c\u3066\u3044\u305f\u30b5\u30fc\u30d0\u30fc\u306f\u3059\u3067\u306b\u7121\u52b9\u306b\u3055\u308c\u3066\u3044\u307e\u3057\u305f WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION_833=\u30b5\u30fc\u30d0\u30fc\u306b\u306f\u3001Windows \u30b5\u30fc\u30d3\u30b9\u3068\u3057\u3066\u524a\u9664\u306e\u30de\u30fc\u30af\u304c\u4ed8\u3051\u3089\u308c\u307e\u3057\u305f ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=Windows \u30b5\u30fc\u30d3\u30b9\u3068\u3057\u3066\u5b9f\u884c\u3055\u308c\u3066\u3044\u308b\u30b5\u30fc\u30d3\u30b9\u3092\u7121\u52b9\u306b\u3057\u3066\u3044\u308b\u3068\u304d\u306b\u4e88\u671f\u3057\u306a\u3044\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f%n\u7ba1\u7406\u8005\u6a29\u9650\u304c\u3042\u308b\u3053\u3068\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044 (\u7ba1\u7406\u8005\u306e\u307f\u304c Windows \u30b5\u30fc\u30d3\u30b9\u3068\u3057\u3066\u5b9f\u884c\u3055\u308c\u3066\u3044\u308b\u30b5\u30fc\u30d0\u30fc\u3092\u7121\u52b9\u306b\u3067\u304d\u307e\u3059) +INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=\u3053\u306e\u30b5\u30fc\u30d3\u30b9\u306f OpenDJ Windows \u30a4\u30f3\u30b9\u30c8\u30fc\u30e9\u30fc\u30d1\u30c3\u30b1\u30fc\u30b8 (MSI) \u306b\u3088\u3063\u3066\u7ba1\u7406\u3055\u308c\u3066\u3044\u308b\u305f\u3081\u3001\u5909\u66f4\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30d1\u30c3\u30b1\u30fc\u30b8\u306e\u30a2\u30f3\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u6642\u306b\u81ea\u52d5\u7684\u306b\u524a\u9664\u3055\u308c\u307e\u3059 INFO_WINDOWS_SERVICE_ENABLED_835=\u30b5\u30fc\u30d0\u30fc\u306f Windows \u30b5\u30fc\u30d3\u30b9\u3068\u3057\u3066\u6709\u52b9\u306b\u3055\u308c\u307e\u3059\u3002\u30b5\u30fc\u30d0\u30fc\u306e\u30b5\u30fc\u30d3\u30b9\u540d: %s INFO_WINDOWS_SERVICE_DISABLED_836=Windows \u30b5\u30fc\u30d3\u30b9\u3068\u3057\u3066\u5b9f\u884c\u3055\u308c\u3066\u3044\u308b\u30b5\u30fc\u30d0\u30fc\u3092\u7121\u52b9\u306b\u3057\u307e\u3059 ERR_WINDOWS_SERVICE_STATE_ERROR_837=Windows \u30b5\u30fc\u30d3\u30b9\u3068\u3057\u3066\u5b9f\u884c\u3055\u308c\u3066\u3044\u308b\u30b5\u30fc\u30d0\u30fc\u306e\u72b6\u614b\u3092\u53d6\u5f97\u3057\u3066\u3044\u308b\u3068\u304d\u306b\u4e88\u671f\u3057\u306a\u3044\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_ko.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_ko.properties index 7e8d974835..80c99a99b0 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_ko.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_ko.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2009 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. @@ -651,6 +652,7 @@ INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED_831=The server was successfully disabl INFO_WINDOWS_SERVICE_ALREADY_DISABLED_832=The server was already disabled as a Windows service WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION_833=The server has been marked for deletion as a Windows Service ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=An unexpected error occurred trying to disable the server as a Windows service%nCheck that you have administrator rights (only Administrators can disable the server as a Windows Service) +INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=\uc774 \uc11c\ube44\uc2a4\ub294 OpenDJ Windows Installer \ud328\ud0a4\uc9c0(MSI)\uc5d0\uc11c \uad00\ub9ac\ud558\ubbc0\ub85c \ubcc0\uacbd\ud558\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. \ud328\ud0a4\uc9c0\ub97c \uc81c\uac70\ud558\uba74 \uc790\ub3d9\uc73c\ub85c \uc81c\uac70\ub429\ub2c8\ub2e4 INFO_WINDOWS_SERVICE_ENABLED_835=The server is enabled as a Windows service. The service name for the server is: %s INFO_WINDOWS_SERVICE_DISABLED_836=The server is disabled as a Windows service ERR_WINDOWS_SERVICE_STATE_ERROR_837=An unexpected error occurred trying to retrieve the state of the server as a Windows service diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_pl.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_pl.properties index 43ebcc4087..145c3e329f 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_pl.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_pl.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. INFO_LISTBACKENDS_TOOL_DESCRIPTION_723=To narz\u0119dzie mo\u017ce by\u0107 u\u017cyte do wy\u015bwietlenia listy zapleczy i bazowych DN skonfigurowanych na Directory Serverze INFO_INSTALLDS_CERT_OPTION_SELF_SIGNED_1388=Wygeneruj certyfikat podpisany przez siebie (zalecane tylko podczas testowania) @@ -372,3 +373,4 @@ INFO_VERIFYINDEX_DESCRIPTION_COUNT_ERRORS_1199=Licz ilo\u015b\u0107 b\u0142\u011 INFO_LDAPPWMOD_TOOL_DESCRIPTION_692=To narz\u0119dzie mo\u017ce by\u0107 u\u017cyte do przeprowadzenia operacji modyfikacji has\u0142a LDAP na Directory Server INFO_DESCRIPTION_BACKEND_TOOL_1893=To narz\u0119dzie mo\u017ce by\u0107 wykorzystane do debugowania zaplecza +INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=Us\u0142uga jest zarz\u0105dzana przez pakiet Instalatora Windows (MSI) OpenDJ i nie zosta\u0142a zmieniona. Zostanie usuni\u0119ta automatycznie podczas odinstalowywania pakietu diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_CN.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_CN.properties index 0dee50fb1f..d646c6b00c 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_CN.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_CN.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. @@ -653,6 +654,7 @@ INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED_831=\u5df2\u6210\u529f\u5c06\u670d\u52 INFO_WINDOWS_SERVICE_ALREADY_DISABLED_832=\u5df2\u5c06\u670d\u52a1\u5668\u4f5c\u4e3a Windows \u670d\u52a1\u7981\u7528 WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION_833=\u5df2\u5c06\u670d\u52a1\u5668\u4f5c\u4e3a Windows \u670d\u52a1\u6807\u8bb0\u4e3a\u5220\u9664 ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=\u5728\u5c1d\u8bd5\u5c06\u670d\u52a1\u5668\u4f5c\u4e3a Windows \u670d\u52a1\u7981\u7528\u65f6\u51fa\u73b0\u610f\u5916\u9519\u8bef%n\u68c0\u67e5\u60a8\u662f\u5426\u62e5\u6709\u7ba1\u7406\u5458\u6743\u9650\uff08\u53ea\u6709\u7ba1\u7406\u5458\u624d\u80fd\u542f\u7528\u670d\u52a1\u5668\u4ee5\u4f5c\u4e3a Windows \u670d\u52a1\u8fd0\u884c\uff09 +INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=\u8be5\u670d\u52a1\u7531 OpenDJ Windows Installer \u8f6f\u4ef6\u5305 (MSI) \u7ba1\u7406\uff0c\u56e0\u6b64\u672a\u4f5c\u66f4\u6539\u3002\u5378\u8f7d\u8be5\u8f6f\u4ef6\u5305\u65f6\u5c06\u81ea\u52a8\u5220\u9664\u8be5\u670d\u52a1 INFO_WINDOWS_SERVICE_ENABLED_835=\u5df2\u5c06\u670d\u52a1\u5668\u4f5c\u4e3a Windows \u670d\u52a1\u542f\u7528\u3002\u670d\u52a1\u5668\u7684\u670d\u52a1\u540d\u79f0\u4e3a: %s INFO_WINDOWS_SERVICE_DISABLED_836=\u5df2\u5c06\u670d\u52a1\u5668\u4f5c\u4e3a Windows \u670d\u52a1\u7981\u7528 ERR_WINDOWS_SERVICE_STATE_ERROR_837=\u5728\u5c1d\u8bd5\u68c0\u7d22\u670d\u52a1\u5668\u4f5c\u4e3a Windows \u670d\u52a1\u7684\u72b6\u6001\u65f6\u51fa\u73b0\u610f\u5916\u9519\u8bef diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_TW.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_TW.properties index 838753a201..b7bd92b540 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_TW.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_TW.properties @@ -12,6 +12,7 @@ # # Copyright 2006-2009 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. +# Portions Copyright 2026 3A Systems, LLC. @@ -651,6 +652,7 @@ INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED_831=The server was successfully disabl INFO_WINDOWS_SERVICE_ALREADY_DISABLED_832=The server was already disabled as a Windows service WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION_833=The server has been marked for deletion as a Windows Service ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=An unexpected error occurred trying to disable the server as a Windows service%nCheck that you have administrator rights (only Administrators can disable the server as a Windows Service) +INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=\u8a72\u670d\u52d9\u7531 OpenDJ Windows Installer \u5957\u4ef6 (MSI) \u7ba1\u7406\uff0c\u56e0\u6b64\u672a\u8b8a\u66f4\u3002\u89e3\u9664\u5b89\u88dd\u8a72\u5957\u4ef6\u6642\u5c07\u81ea\u52d5\u79fb\u9664\u8a72\u670d\u52d9 INFO_WINDOWS_SERVICE_ENABLED_835=The server is enabled as a Windows service. The service name for the server is: %s INFO_WINDOWS_SERVICE_DISABLED_836=The server is disabled as a Windows service ERR_WINDOWS_SERVICE_STATE_ERROR_837=An unexpected error occurred trying to retrieve the state of the server as a Windows service From 252d5ba9b830b992a61787cd4b479db4ce14ce96 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Mon, 10 Aug 2026 16:42:59 +0300 Subject: [PATCH 37/52] Refresh opendj_service.exe for the round-5 SCM-failure and REG_EXPAND_SZ handling --- opendj-server-legacy/lib/opendj_service.exe | Bin 176640 -> 177152 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/opendj-server-legacy/lib/opendj_service.exe b/opendj-server-legacy/lib/opendj_service.exe index 5781c2a92dc8c980cb11c60d4b41c01950e10f25..c4997a47e65c3e018c5badee7a8cbb73a56b1187 100644 GIT binary patch delta 27061 zcmeFad0bUhAOE}8_ArPjM+HR%1vv^T>Y3*W1VcqV3Nkq2e8eGAP*V&PP!UmVt6R%T z%ZkdUC``!5422Yxip&8M6-#X!SY&2ckR*ed^E7F!mA4=P!A7F2m4z znI@zMg8Rz9WQUR$B}&rHsU&O3`{f@c{!6*Vp8bZ#eaJAyF|rT`ej**h z#rH*3?r=7FL^H+tvNUufeV#)gA97`$%AP+)L7jdInet`FkmL{=xZga#Cp>q>YYO?2 z8|l4ZTEZ%Z$*b`%sLC2r6eE-7wYf4woDWc)L&#dsFh#9-HQogevn;MmnN%<=p_wJl zK+k9Wx~eosOQ-jIj4Nmy5QY zDroyVD>~Xv9?^K(c3)(!grEbc=kBn-E2yiRl#rC{WRQlE^<1%ZJUL%}RjME)jqBRu z3$mNL+G8L)>qE}fV-!0!f{W>yLN0Kx^c+ZD;i`I$mTnBE7YoF!Nz;i#c$@3xKP;e> ziDn91IeYI`o$9;3 z$DsXU6Jb*-TzrW`ILM{;8$^EMa{A3N7riDXVltL^qp7DlOle*SZ9y8Ms_UNq%WLtb zMw>9DXo<|93l17FC9g(WP~}%}5S=c{mPw0K2)erMZKz4AhcpP2Ws2gFB3W4!w7w{2 zy>~%XW)H^{p?43lH&_T=X!>Z=@7Y(I#}%C`o=CvGAS$p(-Pru1?-{r zS>=~c2hSoF+C;rv@m5&~aup}aLQ1xf;xS}1TRfTMS7qHVj#0{jXlY-EF!v8}H0WG> zfDuV3nl1||xazm94vOj_oi8a>mlE!U{((L3!y}{fn2D*QO}}P;J4Gnr?)49xwlJ8^ zI~|8=YN;|fx`7z8`a868UvaI@d}<8z|753TfvGenJN02G@v2zD`!t4z&d(GfnAV^3 zAn5P<-6OD77Ky%1atK>|;I_m;*(%e!qgFi?6@%eIu6c;UsKrBb2tT+Lhp2oDZ-W*m zI)r)}9V1I|2&dd}(;X<1Msrz&3wtpfSC5vUjRjSopDgt_F92(pyR4e8b8&Mn#sNrLd{UG6}Lt#{pbRQE4-$O={BrZI3C>h304xP+4e9yfVI*Kj-o@)-(OH;q6rM#QFIzzf5dpf5Yn3@=J z*X44y4~Bk6tkjpT+ZTGd)a6M|-*7~Kh3L_kek{-*^IRk+*cpOoIOdCK;)-+#!`-ue z_Z?5z{tC$_Xz?i={Gqv0lXI$ca-0b13q4lriykuHp z+Iw>VxVtE@zR)m1Eo zUSb($;*beJG{;ZauAQw&{V)6wBQ%I<5`m#<=aKfw zE%dACl-~e5vqfs`p4B)1d}fa=4q}8i-Y@Ip*n?7eE;h%<*+K{4bi2#tTH!6kcNa~7 zx~(jF1!fSsvk;ZLhxMA(J5(4LMHmS4d*T=MVX7L#9o@KkbSM>2d^AY-+|A0+xjGlem-AZ)%eNQ7VtqLtI5 zp)&<1E_9Kataxs52opI+_~bA<+R!{W?@`w*A5hVgd`-moWyb56~`~y?5y*q?I#R>8i-oR38Uj0ce5{phfWj$O*L@*~G;+0;H zl)G6t_tAEY9RnxPnj{Rw5F`~f2=DHo?ec97N^-Wls}D!@m`8_@!#J4V2lC!}JQ-aBJGB5^*(AdD8A3B7r z=h}x_$sEo!EShy);c|wBbiH=Pg$wKn#s$t_;SLS!C;u2RbWrYP1-k-r863_NoDDSn zn3&*OypG&`4g;Ow^zDyW_}yUaNC>wsatw};rz6AIj~cj^ z$lw63L7d_u4Xri7d3XSd&*J(I4<@rY^YC$_P@;|HOZUcxMSMS&9%E^-mH{lS*k) z@l#1svAS%URzuU4b6pgp>0YN8(u*Lrq!-#U0x||N5AuN9q0n_Z{Eg@Y)O{a*5Fd^E!AAIg7ZB#QRL>(8E=^-$Z+ykQrkOytb3bWpWFj|08zt@fmFQKZ)K^L!LN_i)Yh#ap$yI4% z$tuoMr^Q{6MHi^Jj0<4Qp6sdvaLAR28!M(@Xne;S+8}1~RaI3B3%QNDA>Ax!u5)^K ztkpK*#24JBx`d#8=fn%fIh^^37iN4Rs*ZH@aW)sJ5A_;}n4;mOT%z8}{#eKD)F-na z)^Ydrws1$C*oJ0VWh07GbFp^B(1Qu?lp}he#-Ut-!Pwi+>R{tS-=EK-olU(_`u16FuQ9$$?lX4GOFH8UIK;IY{mCBA z!!)<2KeFKlEAKIz)!kV`Pxvgi)|ATDp5ZQ;PGY3?nuoBCiCm3&gQrj!%{Z&LcuTsc zltr+WJ7yW-*+LM!#kE@ENn^RiTF82OZ=w14{vVU@@?Y&aWbiS}eNk+iD)vEPY`ZI< z5~_j*HoF7Gu`RHh!`zi+Vb18X5!8y>3EYnKgIu3{w8j4>>yHK9v?fx zi=5=v#$Swx971=Fkxois`-_Bn37BWUA`Oix`ZArkvb=FoZuR)-tZ^K)s+ z_M;;KG$y%OCajt-S|R4N5iv!l(JRc~Q<>lt68@D(_;m}z&|6Mt+H5*(O(^#Ut&~0} z8Rk5O^@pLR_2YW|56~3cceygVBesR>lr)sIa3hk2kTxzQNrNXl+mc3-_VVLNT?iYp zfIF9*)PL-JJ5w~?w~&Y@_PaOW!%oN6;1{TE;%q6?$pLO(%C`YOBV#(I-PchxzI{^B z6z|CxhVr6RPYJ6|=eQY~KI(KdQC1uSl+d4eND5>LcXP%|J)3BBD}LG_-iz%_(BkrK zGo7qwt2p9Zds;RI`}x^RiKn#aAA{>TS0!O1i@3Oj|G|^I^4}M}&yq&&t@JVIS!;SA z>#O2?7KerTtMI^q_~Q5PTi7W@ElEYc_$5~rkCr%2d$w?n#e-02<>En#7A199<8a=F zDLjnzCYfE*eUpUrENUCx*cWD;lrSit{@9rzwywNxu@B42A8-vzzx0fAM;%%g!IB5u z#f&9rcl2}J3EGvoTtg(>mgP%(p3A_*xdOalB5(K~qE_I``K$=>&qd#azn0=c^KW4^ zyS2Ij%sw=C#sI^c>ZSwid7E;eG$ciI9xDT>M$iIJ%J_Raj z6~09vHPv(~vo=}yl7=zmtKEih#Jx)wwI&N;Auiu2nvoQ+U%)=fdIT*XZX^eS%6CiPIsbUaAIOinvfoi1}STT#X0 zRN8-ECabp)tN6SBSIZkVxrk>R&Eep#6~0JLm1k@zWQn=_kFC)xc~oxMzLl^`CUe&9 zjojNiK45P+Xs}$(<*?*T`QcsL*uGIPyk=He<#(jk??|j~v7|PyDQAl$)~+g_zGna- zN4f01D_B`+`7e84B7yHdgEQY~?^E_5Qn)(MwbDC*{s|oS#>=6>32)h%bCB;LL*BMC z(;#V(Jjhn==F3rR&u6%Gdk1i%_D#aN-nDOAV2{!NxApy5ZhB<~327^}GuPj-GY=u= zckRqF$O_1A$ZHU;`~JS%`B&BK$e8lk`#Tfp6Ue3VwEaB@JN^N;_{~A(dk@riLb!bK zo3WD4aYyJfFHj%hK6$5Kk3rD-K|&xyAj6MvciwrHb*Rge-`&WP6z=+=&->ZcxK&ss zPe?lTjGhQZi*aw$6ZYkO+@a=<|3^=balij(IN8PxdVdw^#l7;p!W4QIR6XA% zugaWvx~9-G?;D)8(#;9U!XLw7*lk7M7LAtd?bJpidwz>(jx!z(4*dM@L~nOupqMz5 zd-iZJDdCC_XOmAjpO5Du{OrfClY3l`BSj>Dd-cc!@+o)k$UgL8OGST@$-Pr?xR`p3A?o8n}ROa+bQ(>O!E3*&4U7s%=>+ctPq8jJP-k)g6d~U)g?~^0k zU!R2H!To@vvE)$s{G_b${Wx2QF8~LiQ>@ zRFgnFH`6Q;oX4r>h?!e;Y9XEk-#9gh9OpbvZw%IixE)0h+){Io^iJ6LgwT$-K(6$3 z7>?(4r;VPaw31NHw{{Yl!p*E5C3yo6dU#uBoZ&yOoglpfEwws5&{<3KbqVCc&Wyl` zee#*NJp~#wf^(heg@@0*&Q_3}~f{1IwNUB1Q&W~D%rthU-~>e0^Ns)kppxD zy1);@=i&?yiI_Uk4W+xB?{m(}gDumwbUSwi=#hj|L#Q(o5w5IOSAZEYMXh+~)D>lm zzU(-*T*_P5id#i7hnhQg`9H+SJ>Ot~qpN86!E--tY$12>%By$*GU{6$(Q|9Roea13 z<+pu3y|*FJ#{Kl|6iP5P(47j$z^Bf(H-Q3&PhLN%5-&~tbJiT@3)@IIl zW5|=>q8n4NBYk#5-amp?r6+_Ddi%oYGJMg@{(1A;aonN1O4p_dB$=Duqz~zjTcVkj z12F=#W>nJ$b2F-iMYt>LFe(>!xM>JBpzBSC(2k;;1F+Yt6kJK-QB&Cz%y(LUlQaUTtwJHnatz%-yR~1qc$LU zW%GZ4@$H4#-hmjx=3c^Z+(?~faD&GPUAcR=hxY2&&4Qe9^b(Rkv9Edw?{dTMywr_u zeh)`Skj(Dr2o4l?=p+vN!AACSi+>0o{nRD$;`MI-;KISL+1e(wAcfLmMPr=;hhxCqGN@?n? z-=AD#6X&=aHK15b6)hyM#UEE!ory{xRTvkD;Ay6cE4$0*C}C8osq|p>_c5VGTI9X{ zQI#f|$@G~dbVml{PjzLO1rK-Fl_3}Y@N-`)LoNLLB&Zi|Jqbn#SDpkTg)g53?LzgF zV2n^ngFYCNvNS9fOj`YqbNXNI$%xNxlii1T%zAY~l5-w1;C9oV^q$6di0@oANB(REr8 z_i1ww`GNbkxqr@I8<81j^1{*aGvS=P9KtdhgEfpBUbN3I|5a=dxXY*%sQc*g2gr%DE+zY>I@rwK7Ux(vJ|NXBc`a94P%*3uLdO*YyJ>&LI zmA?Kkra!rn4_-vYCm(2gkY}i?6s@~bN)vI_2T|O(-)14hd%tOW1djeELmkM=+8lJ zXnRPP3p7|qe=cxSptsQAE&9{K<+g|TN}>^Lr@ADXJJdeFH;6{~)1RPd?sB^c`%BNi z%y>BA_$wU0tN#j3QWLt#QqS(*Wt%q(et7Qh-bKVWW7w1Fjy(?(VgAgo6fE;?0XPmS93rA)enxl%i{qNYI=D&{h^`szQUWZdHOJ1ik-5%xS^;2 zK^NQP$6?s{Rz5c4xBPL~s0>^X_lGjK8=B!7MDNMPNkh2hN%(+o74B$UO-~YTJxM?& zf$QTMj@q7ag%KyW*flcTy#+RR7yBe+Vd-KkUE;n_;NO+EaVK0Vl=}_kGI#YMXxA
RbUJC3xB0lPWDY6f-|I?-k!Aelu4Gfd%Xq$; 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 delta 26828 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 OX`Jqzi1)ag=iXoUr4e=j From 24b1b7ec4b9a6100f597e5bc44e1c6b392aee46c Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Tue, 11 Aug 2026 17:34:35 +0300 Subject: [PATCH 38/52] Commit the rebuilt Windows launchers from the deploy run The byte comparison ran in two places on every PR - a warning-only step in build.yml and the standalone Native launchers workflow - and neither could block what actually matters: opendj-server-legacy/lib/*.exe is what Linux-built server zips, tagged releases and Maven Central artifacts ship. Master proved the gap real, carrying launchers from April against a service.c changed in July. Drop both and let Package/Deploy commit what the Build run already compiled: it downloads windows-exe-11 from the triggering run and pushes the binaries back when they changed. It holds contents: write for the wiki push already, so build-maven stays read-only; it only runs once Build succeeded on a push to a release branch; and committing before the Maven steps means the snapshot this job publishes carries the fresh launchers too. /Brepro in the Makefile keeps the output a function of the sources, without which this would commit on every run. --- .github/workflows/build.yml | 27 ++------ .github/workflows/check-native-launchers.yml | 70 -------------------- .github/workflows/deploy.yml | 69 +++++++++++++++++++ 3 files changed, 74 insertions(+), 92 deletions(-) delete mode 100644 .github/workflows/check-native-launchers.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1ae768bcb3..1cd630c9e1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -84,6 +84,11 @@ jobs: nmake all || exit /b 1 xcopy /Y *.exe ..\..\..\lib\ || exit /b 1 git status + # Also the source of truth for the committed opendj-server-legacy/lib/*.exe: on a + # successful push build, deploy.yml downloads windows-exe-11 from this very run and + # commits its contents back to the branch. Nothing here compares them with what is + # committed - an MSVC toolchain bump on the runner image changes the bytes on its own, + # so a byte-for-byte gate would fire without a source change. - name: Upload Windows exe artifacts if: runner.os == 'Windows' uses: actions/upload-artifact@v7 @@ -91,28 +96,6 @@ jobs: name: windows-exe-${{ matrix.java }} retention-days: 5 path: opendj-server-legacy/src/build-tools/windows/*.exe - - name: Committed launcher binaries must match the sources - if: runner.os == 'Windows' - # The release pipeline builds the server zip on Linux from the committed - # opendj-server-legacy/lib/*.exe, so a source change that is not re-committed as a - # refreshed binary would ship the old wrapper in the tagged release while CI stays - # green. Warning-only: an MSVC toolchain bump on the runner image also changes the - # bytes, and failing here would kill the artifact consumers (test-msi*, deploy.yml). - # The failing signal lives in the standalone Native launchers workflow - # (check-native-launchers.yml), which triggers only when the native sources or the - # committed binaries change and gates nothing. The freshly built binaries are - # uploaded just above - refresh lib/*.exe from the windows-exe artifact of this - # very run and commit them. - continue-on-error: true - shell: bash - run: | - # git diff alone misses a brand-new launcher that was never git-added: - # status --porcelain reports modified and untracked files alike. - if [ -n "$(git status --porcelain -- opendj-server-legacy/lib)" ]; then - git status --porcelain -- opendj-server-legacy/lib - echo "::warning title=Stale launcher binaries::opendj-server-legacy/lib/*.exe differ from what this CI build produced (source change or MSVC toolchain bump). Refresh them from the windows-exe artifact of this run." - exit 1 - fi - name: Set Integration Test Environment id: failsafe if: runner.os == 'Linux' diff --git a/.github/workflows/check-native-launchers.yml b/.github/workflows/check-native-launchers.yml deleted file mode 100644 index 817dd4eaa3..0000000000 --- a/.github/workflows/check-native-launchers.yml +++ /dev/null @@ -1,70 +0,0 @@ -# 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. - -# The committed opendj-server-legacy/lib/*.exe launchers are what Linux-built server -# zips - and therefore tagged releases - ship, while the Windows CI jobs overwrite them -# with freshly compiled ones before testing. Build's own comparison step is warning-only -# so an MSVC toolchain bump on the runner image cannot take down the artifact consumers -# (test-msi*, deploy.yml). This standalone workflow is the failing signal instead: it -# triggers only when the native sources or the committed binaries change - exactly the -# case where stale binaries must block a merge - and its conclusion gates nothing else. -name: Native launchers - -on: - push: - branches: [ 'master' ] - paths: - - 'opendj-server-legacy/src/build-tools/windows/**' - - 'opendj-server-legacy/lib/*.exe' - pull_request: - paths: - - 'opendj-server-legacy/src/build-tools/windows/**' - - 'opendj-server-legacy/lib/*.exe' - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - compare: - runs-on: 'windows-latest' - steps: - - uses: actions/checkout@v6 - - name: Setup MSVC Developer Command Prompt (x86) - uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 - env: - # Opt in to Node.js 24 for this action, which still ships on Node.js 20. - # See https://github.com/ilammy/msvc-dev-cmd/issues/99 - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - with: - arch: x86 - - name: Build the native launchers from source - shell: cmd - run: | - cd opendj-server-legacy\src\build-tools\windows - nmake all || exit /b 1 - xcopy /Y *.exe ..\..\..\lib\ || exit /b 1 - - name: Committed launcher binaries must match the sources - shell: bash - run: | - # git diff alone misses a brand-new launcher that was never git-added: - # status --porcelain reports modified and untracked files alike. - if [ -n "$(git status --porcelain -- opendj-server-legacy/lib)" ]; then - git status --porcelain -- opendj-server-legacy/lib - echo "::error title=Stale launcher binaries::opendj-server-legacy/lib/*.exe do not match the sources. Refresh them from the windows-exe artifact of a Build run on this branch and commit them." - exit 1 - fi diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 88f62f0130..6816427693 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -52,6 +52,75 @@ jobs: fetch-depth: 0 submodules: recursive ref: ${{ github.event.workflow_run.head_branch }} + # The committed opendj-server-legacy/lib/*.exe are what every Linux-built server zip + # ships - the snapshots this job publishes, and later the tagged releases and their + # Maven Central artifacts - while only a Windows job can rebuild them. Nothing used + # to make the two meet, so a native source change that was never re-committed as a + # refreshed binary shipped the old wrapper while CI stayed green (master carried such + # a gap for weeks). The triggering Build run compiled them from source already, so + # take its binaries and commit them here rather than rebuild. + # + # Here rather than in build.yml: this workflow already holds contents: write for the + # wiki push, so build-maven - which runs the whole Maven plugin tree - stays + # read-only, and it only runs at all once the Build succeeded on a push to a release + # branch. The cost is latency: the refresh lands after the full matrix, not minutes + # into it. Committing before the Maven steps below also means the snapshot zip this + # job publishes carries the fresh launchers. + # + # This only works because the Makefile passes /Brepro to both cl and link: the output + # is a function of the sources, not of the build time. Without it every run would + # produce different bytes and this would commit on every push. An MSVC toolchain bump + # on the runner image does change them, and that refresh commit is correct - the + # committed binary then matches what CI verifies. Pushes made with GITHUB_TOKEN do + # not start new workflow runs, so this cannot loop; a PAT would break that. + - name: Download the launchers built by the triggering Build run + continue-on-error: true + uses: actions/download-artifact@v8 + with: + name: windows-exe-11 + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + path: ${{ runner.temp }}/windows-exe + - name: Commit the rebuilt launchers + shell: bash + env: + # NOT github.ref: on a workflow_run event that is the default branch, not the + # branch the triggering run was for. + BRANCH: ${{ github.event.workflow_run.head_branch }} + BUILT: ${{ runner.temp }}/windows-exe + HEAD_SHA: ${{ github.event.workflow_run.head_sha }} + RUN_ID: ${{ github.event.workflow_run.id }} + run: | + set -e + if ! ls "$BUILT"/*.exe >/dev/null 2>&1; then + echo "::warning title=No launcher binaries from the Build run::windows-exe-11 could not be downloaded, leaving opendj-server-legacy/lib/*.exe as committed." + exit 0 + fi + cp "$BUILT"/*.exe opendj-server-legacy/lib/ + # status --porcelain, not diff: it reports a brand-new launcher that was never + # git-added just as well as a modified one. + if [ -z "$(git status --porcelain -- opendj-server-legacy/lib)" ]; then + echo "Committed launchers already match the sources." + exit 0 + fi + git status --porcelain -- opendj-server-legacy/lib + git config user.name "Open Identity Platform Community" + git config user.email "open-identity-platform-opendj@googlegroups.com" + git add -- opendj-server-legacy/lib + git commit --quiet \ + -m "Refresh the Windows native launchers" \ + -m "Rebuilt from opendj-server-legacy/src/build-tools/windows for ${HEAD_SHA} by the Build workflow (run ${RUN_ID})." + # The checkout is of the branch, which may have moved on since the Build run: + # rebase onto its current tip. An identical refresh already there leaves an empty + # commit that rebase drops, and the push then has nothing to send. + git fetch --quiet origin "$BRANCH" + if ! git rebase --quiet FETCH_HEAD; then + git rebase --abort || true + echo "::error title=Could not refresh the launcher binaries::$BRANCH moved on and the rebuilt launchers conflict with it. Refresh opendj-server-legacy/lib/*.exe from the windows-exe-11 artifact of Build run ${RUN_ID} and commit them." + exit 1 + fi + git push --quiet origin "HEAD:refs/heads/$BRANCH" + echo "Refreshed launchers pushed to $BRANCH." - name: Set up Java for publishing to Maven Central Repository OSS uses: actions/setup-java@v5 with: From b2de060753b1eb5e2f067d56375d8aaf461d8a31 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Tue, 11 Aug 2026 17:50:31 +0300 Subject: [PATCH 39/52] Revert the MSI to the legacy service registration scheme Registering the service from the package turned every msiexec /i into a service install: serviceState() reported ENABLED for any MSI install, so start-ds.bat dispatched to the SCM and -N failed outright, even for an administrator who ran setup --cli --doNotStart and never asked for service mode. Drop ServiceInstall/ServiceControl and let windows-service.bat register the service as it does for the zip delivery. Everything that existed only to support an installer-owned service goes with it: isMsiManagedService and its return code 4, the SERVICE_MSI_MANAGED handling in ConfigureWindowsService, Uninstaller and the control panel, both localized messages, and serviceCmdsMatch - with no msiexec-written ImagePath left to parse, matching returns to a plain compare. SERVICE_LIST_UNAVAILABLE stays: it fixes the "already disabled" answer the SCM never gave. RemoveLegacyServiceControl goes too - an in-place upgrade replaces the wrapper the registration names, so the service keeps working and is not ours to remove. The stop-and-verify pair stays and now covers every upgrade over a running instance, not just legacy ones: the JVM holds lib\*.jar open through RemoveExistingProducts whatever package installed them. test-msi now starts the server with start-ds.bat before touching the service at all, then enables, exercises and disables it; test-msi-upgrade asserts the administrator's registration survives the upgrade. The install guide documents the service as the opt-in step it is again. --- .github/workflows/build.yml | 142 +++++---- .../asciidoc/install-guide/chap-install.adoc | 14 +- .../install-guide/chap-uninstall.adoc | 14 +- .../asciidoc/install-guide/chap-upgrade.adoc | 12 +- .../opendj-msi/opendj-msi-standard/pom.xml | 8 +- .../resources/msi/package.wxs | 182 ++++-------- .../src/build-tools/windows/Makefile | 5 +- .../src/build-tools/windows/service.c | 279 +----------------- .../src/build-tools/windows/service.h | 7 - .../guitools/controlpanel/task/Task.java | 40 --- .../controlpanel/ui/StatusGenericPanel.java | 7 +- .../controlpanel/ui/WindowsServicePanel.java | 15 +- .../guitools/uninstaller/Uninstaller.java | 3 - .../server/tools/ConfigureWindowsService.java | 19 +- .../org/opends/messages/admin_tool.properties | 3 - .../messages/admin_tool_ca_ES.properties | 2 - .../opends/messages/admin_tool_de.properties | 2 - .../opends/messages/admin_tool_es.properties | 2 - .../opends/messages/admin_tool_fr.properties | 2 - .../opends/messages/admin_tool_ja.properties | 2 - .../opends/messages/admin_tool_ko.properties | 2 - .../opends/messages/admin_tool_pl.properties | 2 - .../messages/admin_tool_zh_CN.properties | 2 - .../messages/admin_tool_zh_TW.properties | 2 - .../org/opends/messages/tool.properties | 3 - .../org/opends/messages/tool_ca_ES.properties | 2 - .../org/opends/messages/tool_de.properties | 2 - .../org/opends/messages/tool_es.properties | 2 - .../org/opends/messages/tool_fr.properties | 2 - .../org/opends/messages/tool_ja.properties | 2 - .../org/opends/messages/tool_ko.properties | 2 - .../org/opends/messages/tool_pl.properties | 2 - .../org/opends/messages/tool_zh_CN.properties | 2 - .../org/opends/messages/tool_zh_TW.properties | 2 - 34 files changed, 169 insertions(+), 620 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1cd630c9e1..c4d45640ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -714,56 +714,67 @@ jobs: $root = "C:\Program Files\OpenDJ" if (-not (Test-Path "$root\setup.bat")) { Get-Content install.log -Tail 80; throw "OpenDJ not installed into the x64 default $root" } Write-Host "Installed to $root" - # The whole [OPENDJ]. ImagePath hack rests on msiexec quoting the exe path; - # unquoted-with-spaces would be an unquoted service path (CWE-428). - $image = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\OpenDJ).ImagePath - Write-Host "ImagePath: $image" - if ($image -notmatch '^"C:\\Program Files\\OpenDJ\\lib\\opendj_service\.exe"') { throw "ImagePath must quote the exe path (CWE-428): $image" } + # The package lays the files down and registers no service: enabling one stays + # the administrator's explicit step (windows-service.bat / setup), exactly as + # for the zip distribution, so start-ds.bat keeps starting the server directly. + if (Get-Service OpenDJ -ErrorAction SilentlyContinue) { throw "the package must not register a service of its own" } + if (Get-Service "OpenDJ Server" -ErrorAction SilentlyContinue) { throw "the package must not register a service of its own" } + # The SCM wrapper is harvested with the rest of lib; windows-service.bat needs it. + if (-not (Test-Path "$root\lib\opendj_service.exe")) { throw "lib\opendj_service.exe missing from the MSI install" } # Custom extension jars go into lib\extensions; the server warns on startup # (WARN_ADMIN_NO_EXTENSIONS_DIR) when it is missing. if (-not (Test-Path "$root\lib\extensions")) { throw "lib\extensions missing from the MSI install" } "OPENDJ_ROOT=$root" | Out-File -FilePath $env:GITHUB_ENV -Append - - name: Setup and start/stop the Windows service + - name: Setup, then start and stop the server without a service shell: pwsh run: | + # An MSI install that was never asked for service mode must behave exactly like + # a zip one: start-ds.bat starts the server in this very session rather than + # dispatching to the SCM, and needs no elevation to do it. $root = $env:OPENDJ_ROOT $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" & "$root\setup.bat" -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --addBaseEntry --cli --acceptLicense --no-prompt --doNotStart if ($LASTEXITCODE -ne 0) { throw "setup.bat failed: $LASTEXITCODE" } - # The service is already registered by the MSI (WiX ServiceInstall, key and - # display name 'OpenDJ'); just start it. - net start OpenDJ - if ($LASTEXITCODE -ne 0) { throw "net start failed: $LASTEXITCODE" } + & "$root\bat\start-ds.bat" + if ($LASTEXITCODE -ne 0) { throw "start-ds.bat failed: $LASTEXITCODE" } for ($i=0; $i -lt 12; $i++) { try { $c = New-Object System.Net.Sockets.TcpClient('localhost', 1636); $c.Close(); break } catch { Start-Sleep -Seconds 5 } } & "$root\bat\ldapsearch.bat" --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1 if ($LASTEXITCODE -ne 0) { throw "ldapsearch failed: $LASTEXITCODE" } - net stop OpenDJ - if ($LASTEXITCODE -ne 0) { throw "net stop failed: $LASTEXITCODE" } - - name: windows-service.bat must not delete the MSI-managed service + & "$root\bat\stop-ds.bat" + if ($LASTEXITCODE -ne 0) { throw "stop-ds.bat failed: $LASTEXITCODE" } + - name: Enable, start, stop and disable the Windows service shell: pwsh run: | - # Deleting the service here would leave msiexec /x targeting a key that no longer - # exists; opendj_service.exe refuses to remove the MSI-managed key 'OpenDJ'. - # The refusal makes the bat exit non-zero, and the pwsh shell wrapper would turn - # that into a step failure - so capture it and finish with an explicit exit 0. + # Service mode is opt-in and driven entirely by windows-service.bat, the same + # command the zip distribution uses. The service it registers takes the display + # name "OpenDJ Server" for the first instance on the host. $root = $env:OPENDJ_ROOT + & "$root\bat\windows-service.bat" --enableService + if ($LASTEXITCODE -ne 0) { throw "--enableService failed: $LASTEXITCODE" } + if (-not (Get-Service -DisplayName "OpenDJ Server" -ErrorAction SilentlyContinue)) { sc.exe query; throw "--enableService did not register the service" } + net start "OpenDJ Server" + if ($LASTEXITCODE -ne 0) { throw "net start failed: $LASTEXITCODE" } + for ($i=0; $i -lt 12; $i++) { try { $c = New-Object System.Net.Sockets.TcpClient('localhost', 1636); $c.Close(); break } catch { Start-Sleep -Seconds 5 } } + & "$root\bat\ldapsearch.bat" --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1 + if ($LASTEXITCODE -ne 0) { throw "ldapsearch (as a service) failed: $LASTEXITCODE" } + net stop "OpenDJ Server" + if ($LASTEXITCODE -ne 0) { throw "net stop failed: $LASTEXITCODE" } & "$root\bat\windows-service.bat" --disableService - $code = $LASTEXITCODE - if ($code -eq 0) { throw "--disableService reported success on an MSI-managed service" } - if (-not (Get-Service OpenDJ -ErrorAction SilentlyContinue)) { throw "--disableService deleted the MSI-managed service" } - Write-Host "--disableService refused as expected (exit $code) and left the service in place" - exit 0 - - name: uninstall.bat works on an MSI install and leaves the service to msiexec + if ($LASTEXITCODE -ne 0) { throw "--disableService failed: $LASTEXITCODE" } + if (Get-Service -DisplayName "OpenDJ Server" -ErrorAction SilentlyContinue) { throw "--disableService left the service registered" } + - name: uninstall.bat disables the service it finds and removes the instance shell: pwsh run: | - # The uninstaller must treat the MSI-managed service as a skip (not an error), - # delete the instance files, and leave the service for msiexec /x to remove. + # Re-enable the service so the uninstaller exercises its disable path: nothing + # in the package owns the service, so removing it is the uninstaller's job. $root = $env:OPENDJ_ROOT + & "$root\bat\windows-service.bat" --enableService + if ($LASTEXITCODE -ne 0) { throw "--enableService failed: $LASTEXITCODE" } & "$root\uninstall.bat" --cli --remove-all --no-prompt --forceOnError --quiet if ($LASTEXITCODE -ne 0) { throw "uninstall.bat failed: $LASTEXITCODE" } if (Test-Path "$root\config\config.ldif") { throw "uninstall.bat did not remove the instance files" } - if (-not (Get-Service OpenDJ -ErrorAction SilentlyContinue)) { throw "uninstall.bat removed the MSI-managed service" } - Write-Host "uninstall.bat completed and left the MSI-managed service in place" + if (Get-Service -DisplayName "OpenDJ Server" -ErrorAction SilentlyContinue) { throw "uninstall.bat left the service registered" } + Write-Host "uninstall.bat removed the instance and disabled the service" exit 0 - name: Uninstall MSI shell: pwsh @@ -771,13 +782,13 @@ jobs: $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall.log" if ($p.ExitCode -ne 0) { Get-Content uninstall.log -Tail 80; throw "msiexec /x failed: $($p.ExitCode)" } - if (Get-Service OpenDJ -ErrorAction SilentlyContinue) { throw "service not removed by msiexec /x" } + if (Test-Path "$env:OPENDJ_ROOT\lib\opendj_service.exe") { throw "msiexec /x left the payload behind" } Write-Host "Uninstalled OK" # Upgrade path: released 5.1.2 x86 MSI (wine-built, WiX3) -> this build's x64 MSI. # Verifies the new installer detects the legacy Program Files (x86) install, keeps the - # instance data in place, replaces the windows-service.bat service with the MSI-managed - # one, and the upgraded server starts with the old data. + # instance data in place, stops the running service for the file replacement and leaves + # its registration alone, and that the upgraded server starts with the old data. test-msi-upgrade: needs: build-maven runs-on: 'windows-latest' @@ -809,9 +820,9 @@ jobs: $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" & "$root\setup.bat" -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --addBaseEntry --cli --acceptLicense --no-prompt --doNotStart if ($LASTEXITCODE -ne 0) { throw "setup.bat (5.1.2) failed: $LASTEXITCODE" } - # Register the LEGACY service the pre-MSI way, prove it works, and LEAVE IT - # RUNNING: the upgrade itself must stop it (StopLegacyServiceBeforeUpgrade runs - # elevated here) before CheckLegacyServiceStopped would otherwise refuse. + # Register the service the pre-MSI way, prove it works, and LEAVE IT RUNNING: + # the upgrade itself must stop it (StopServiceBeforeUpgrade runs elevated here) + # before CheckServiceStopped would otherwise refuse. & "$root\bat\windows-service.bat" --enableService if ($LASTEXITCODE -ne 0) { throw "windows-service --enableService failed: $LASTEXITCODE" } net start "OpenDJ Server" @@ -831,45 +842,56 @@ jobs: if (Test-Path "C:\Program Files\OpenDJ") { throw "upgrade unexpectedly installed into the x64 default dir" } # Instance data survived if (-not (Test-Path "$root\config\config.ldif")) { throw "instance data (config\config.ldif) lost by the upgrade" } - # Legacy service replaced by the MSI-managed one (key = display name = 'OpenDJ') - $svc = Get-Service OpenDJ -ErrorAction SilentlyContinue - if (-not $svc) { sc.exe query; throw "MSI-managed service 'OpenDJ' not registered" } - if ($svc.DisplayName -ne "OpenDJ") { throw "expected display name 'OpenDJ', got '$($svc.DisplayName)'" } - if (Get-Service -DisplayName "OpenDJ Server" -ErrorAction SilentlyContinue) { sc.exe query; throw "legacy service 'OpenDJ Server' still present after the upgrade" } - sc.exe qc OpenDJ + # The service registration is the administrator's, not the package's: the upgrade + # stopped it to free the jars, and must have left it registered and pointing at + # the same tree - the wrapper it names has just been replaced in place. + $svc = Get-Service -DisplayName "OpenDJ Server" -ErrorAction SilentlyContinue + if (-not $svc) { sc.exe query; throw "the upgrade unregistered the administrator's service" } + if ($svc.Status -ne "Stopped") { throw "the upgrade left the service $($svc.Status), expected Stopped" } + if (Get-Service OpenDJ -ErrorAction SilentlyContinue) { sc.exe query; throw "the package registered a service of its own" } + sc.exe qc "$($svc.Name)" "OPENDJ_ROOT=$root" | Out-File -FilePath $env:GITHUB_ENV -Append - - name: Run upgrade.bat and start the upgraded server + - name: Run upgrade.bat and start the upgraded server through the service shell: pwsh run: | $root = $env:OPENDJ_ROOT $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" & "$root\upgrade.bat" --no-prompt --acceptLicense --force if ($LASTEXITCODE -ne 0) { throw "upgrade.bat failed: $LASTEXITCODE" } - net start OpenDJ + # The service registered before the upgrade still drives the refreshed tree. + net start "OpenDJ Server" if ($LASTEXITCODE -ne 0) { throw "net start (upgraded) failed: $LASTEXITCODE" } for ($i=0; $i -lt 12; $i++) { try { $c = New-Object System.Net.Sockets.TcpClient('localhost', 1636); $c.Close(); break } catch { Start-Sleep -Seconds 5 } } # The pre-upgrade data must still be served & "$root\bat\ldapsearch.bat" --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1 if ($LASTEXITCODE -ne 0) { throw "ldapsearch after upgrade failed: $LASTEXITCODE" } - net stop OpenDJ + net stop "OpenDJ Server" if ($LASTEXITCODE -ne 0) { throw "net stop (upgraded) failed: $LASTEXITCODE" } - - name: Repair must not touch an unrelated instance's legacy-named service + - name: Repair must leave the service registration alone shell: pwsh run: | - # RemoveLegacyServiceControl is Transitive and both of its signals are gone in - # maintenance mode (FindRelatedProducts does not run there at all), so a repair - # must leave an "OpenDJ Server" registered by a zip instance AFTER the upgrade - # alone. This is the assertion review rounds 3-5 were about: the component - # condition was wrong twice and nothing in CI exercised it. + # Nothing in the package controls a service, so a repair must not disturb the + # registration the administrator made - neither the one this upgrade inherited + # nor one belonging to an unrelated instance. $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName - sc.exe create "OpenDJ Server" binPath= "C:\zip-instance\lib\opendj_service.exe start ""C:\zip-instance.""" start= demand - if ($LASTEXITCODE -ne 0) { throw "sc create failed: $LASTEXITCODE" } + $before = (Get-Service -DisplayName "OpenDJ Server").Name $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" REINSTALL=ALL REINSTALLMODE=vomus /quiet /qn /norestart /l*v repair.log" if ($p.ExitCode -ne 0) { Get-Content repair.log -Tail 80; throw "repair failed: $($p.ExitCode)" } - if (-not (Get-Service "OpenDJ Server" -ErrorAction SilentlyContinue)) { throw "repair deleted an unrelated instance's service" } - sc.exe delete "OpenDJ Server" - if ($LASTEXITCODE -ne 0) { throw "sc delete failed: $LASTEXITCODE" } - Write-Host "Repair left the unrelated 'OpenDJ Server' service in place" + $after = Get-Service -DisplayName "OpenDJ Server" -ErrorAction SilentlyContinue + if (-not $after) { throw "repair unregistered the service" } + if ($after.Name -ne $before) { throw "repair changed the service key name: $before -> $($after.Name)" } + Write-Host "Repair left the '$before' service in place" + - name: Disabling the service before uninstalling leaves no orphan + shell: pwsh + run: | + # msiexec /x removes the files it installed and nothing else - as the WiX3-era + # package did. Disabling the service is the administrator's step (the install + # guide says so, and uninstall.bat does it too); skipping it would leave an + # auto-start service pointing at a deleted tree. + $root = $env:OPENDJ_ROOT + & "$root\bat\windows-service.bat" --disableService + if ($LASTEXITCODE -ne 0) { throw "--disableService failed: $LASTEXITCODE" } + if (Get-Service -DisplayName "OpenDJ Server" -ErrorAction SilentlyContinue) { throw "--disableService left the service registered" } - name: Auto-detect the legacy default directory on a fresh install shell: pwsh run: | @@ -877,7 +899,6 @@ jobs: # Clean up the previous scenario first. $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall1.log" if ($p.ExitCode -ne 0) { Get-Content uninstall1.log -Tail 80; throw "msiexec /x failed: $($p.ExitCode)" } - if (Get-Service OpenDJ -ErrorAction SilentlyContinue) { throw "service not removed by uninstall" } # An existing legacy default directory must be picked up when OPENDJ is not given. New-Item -ItemType Directory -Force "C:\Program Files (x86)\OpenDJ" | Out-Null $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v install-autodetect.log" @@ -922,14 +943,13 @@ jobs: Write-Host "Upgrade refused with guidance, original install untouched (exit $($p.ExitCode))" $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x opendj-5.1.2.msi /quiet /qn /norestart /l*v uninstall-custom.log" if ($p.ExitCode -ne 0) { Get-Content uninstall-custom.log -Tail 80; throw "msiexec /x (5.1.2 cleanup) failed: $($p.ExitCode)" } - - name: Fresh install elsewhere must not touch a legacy-named service it does not own + - name: Fresh install must not touch a service registered by another instance shell: pwsh run: | - # A leftover Program Files (x86)\OpenDJ makes the legacy fresh-install disjunct - # of RemoveLegacyServiceControl true, but the ownership gate (the service's - # ImagePath must point into [OPENDJ]) has to keep the installer away from an - # "OpenDJ Server" registered by a zip instance when the install goes somewhere - # else entirely - the round-5 blocker scenario. + # A leftover Program Files (x86)\OpenDJ plus an "OpenDJ Server" belonging to a + # zip instance elsewhere: installing to a third directory must leave that + # registration completely alone. The package controls no service at all, so this + # holds by construction - the scenario guards against reintroducing one. $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue New-Item -ItemType Directory -Force "C:\Program Files (x86)\OpenDJ" | Out-Null 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 d660950cc7..cfa49751c3 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 @@ -640,12 +640,7 @@ opendj 0:off 1:off 2:on 3:on 4:on 5:on 6:off [#install-msi] .To Install With the Windows Installer (MSI) ==== -On Windows you can install OpenDJ directory server from the `.msi` package. The installer copies the server files to disk and registers the `OpenDJ` Windows service, but it does not configure or start a server (run `setup` first) and it does not install a Java runtime. - -[NOTE] -====== -When the installer replaces a legacy OpenDJ installation (an upgrade from a pre-5.2.0 package, or a fresh install that adopts a detected legacy default directory on a host where no 5.2.0-or-later package has recorded its installation location), it stops and removes the service registered by the legacy `windows-service.bat` command, replacing it with the installer-managed `OpenDJ` service. The legacy service is only ever touched when its own registration points into the directory being upgraded; services belonging to other server instances are not touched, and upgrades between 5.2.0-or-later packages and repairs leave any `OpenDJ Server` service in place. If the legacy service is still running and the installer cannot stop it — for example when the installer was started without elevation — the upgrade fails with Windows Installer error 1722 naming the `CheckLegacyServiceStopped` action rather than proceeding against a running server: stop the service first (`net stop "OpenDJ Server"` from an elevated prompt) or run the installer from an elevated prompt, then retry. Because the installer-managed service is registered with automatic start, Windows logs a start failure at every boot until the instance has been configured with `setup`. -====== +On Windows you can install OpenDJ directory server from the `.msi` package. The installer only copies the server files to disk: it does not configure or start a server, it does not register a Windows service, and it does not install a Java runtime. Registering the server as a Windows service stays an explicit step you take with the `windows-service` command, exactly as for the cross-platform (.zip) delivery, and the service you register is yours: the package never creates, removes or reconfigures one. . Make sure a supported Java runtime is available, as described in xref:#before-you-install["To Prepare For Installation"]. + @@ -677,13 +672,16 @@ The service runs as `LocalSystem`. A directory created directly under the drive C:\path\to\opendj> setup.bat --cli ---- -. Start the OpenDJ Windows service. The installer already registered it as `OpenDJ`; after configuring with `setup`, start it from an elevated prompt (it is not started automatically during installation): +. (Optional) Register OpenDJ as a Windows service and start it. The MSI does not register the service; use the `windows-service` command from an elevated prompt: + [source, console] ---- -C:\> net start OpenDJ +C:\path\to\opendj\bat> windows-service.bat --enableService +C:\> net start "OpenDJ Server" ---- ++ +The service takes the display name `OpenDJ Server`; when a host already runs another registered instance, the next one gets a key name such as `OpenDJ Server-2`. Remember to disable the service with `windows-service.bat --disableService` before you uninstall the package, or the registration is left pointing at removed files. ==== 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 f88e878dcf..7f5e201190 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 @@ -162,9 +162,17 @@ Removing the package does not remove your data or configuration. You must remove [#uninstall-msi] .To Uninstall the Windows MSI Package ==== -Remove OpenDJ directory server installed from the `.msi` package like any other Windows program. Removing the package stops and removes the `OpenDJ` Windows service that it registered. +Remove OpenDJ directory server installed from the `.msi` package like any other Windows program. -* Uninstall the package, either through __Settings > Apps__ (or __Control Panel > Programs and Features__) by selecting OpenDJ and choosing Uninstall, or from the command-line: +. If OpenDJ is registered as a Windows service, remove the service first — the package does not manage it and leaves the registration behind, pointing at files that are about to be deleted: ++ + +[source, console] +---- +C:\path\to\opendj\bat> windows-service.bat --disableService +---- + +. Uninstall the package, either through __Settings > Apps__ (or __Control Panel > Programs and Features__) by selecting OpenDJ and choosing Uninstall, or from the command-line: + [source, console, subs="attributes"] @@ -172,7 +180,7 @@ Remove OpenDJ directory server installed from the `.msi` package like any other C:\> msiexec /x opendj-{opendj-version}.msi /quiet ---- + -Uninstalling removes the files installed by the package. Your configured instance data under the installation directory (for example `config`, `db`, and `logs`) is not removed; delete the installation directory manually, or run `uninstall.bat` before removing the package, to remove all files. The `uninstall.bat` command leaves the `OpenDJ` service in place — the service belongs to the package and is removed by `msiexec /x`. Run `msiexec /x` promptly after `uninstall.bat`: until the package is removed, the auto-start service still points at the deleted files and Windows logs a service start failure if the host reboots in between. +Uninstalling removes the files installed by the package. Your configured instance data under the installation directory (for example `config`, `db`, and `logs`) is not removed; delete the installation directory manually, or run `uninstall.bat` before removing the package, to remove all files. Running `uninstall.bat` also disables the Windows service if one is registered, which covers the first step above. ==== 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 542cf40e75..410081bfd5 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 @@ -70,7 +70,7 @@ To move to a newer version, edit the `default.java-home` setting in the `opendj/ . Download the latest release from the link:https://github.com/OpenIdentityPlatform/OpenDJ/releases[GitHub, window=\_blank] site. -. (Optional) If you are upgrading OpenDJ directory server installed from the cross-platform (.zip) delivery on Windows, and OpenDJ is registered as a Windows service, disable OpenDJ as a Windows service before upgrade, as in the following example: +. (Optional) If you are upgrading OpenDJ directory server on Windows, and OpenDJ is registered as a Windows service, disable OpenDJ as a Windows service before upgrade, as in the following example: + [source, console] @@ -79,8 +79,6 @@ C:\path\to\opendj\bat> windows-service.bat --disableService ---- + After upgrade, you can enable OpenDJ as a Windows service again. -+ -This step does not apply to servers installed from the `.msi` package: the installer manages the `OpenDJ` service itself (see xref:#upgrade-msi["To Upgrade the Windows MSI Installation"]), and `windows-service.bat --disableService` refuses to remove the installer-managed service. . Make sure you perform a full backup of your current OpenDJ installation to revert if the upgrade fails. + @@ -259,7 +257,7 @@ $ ==== Before starting this procedure, follow the steps in xref:#before-you-upgrade["Before You Upgrade"]. Installing the newer `.msi` performs a major upgrade that replaces the installed program files, so make a full file-system backup of the current installation first. -. Stop the current OpenDJ server (if it runs as a Windows service, `net stop "OpenDJ Server"`, or `net stop OpenDJ` for a server installed from a previous x64 `.msi` package). +. Stop the current OpenDJ server; if it runs as a Windows service, stop the service with `net stop "OpenDJ Server"` from an elevated prompt. The installer also tries to stop it, but only succeeds when it is itself running elevated: started by double-click, it cannot, and refuses the upgrade with Windows Installer error 1722 naming the `CheckServiceStopped` action rather than replacing the files under a running server. . Back up the file-system directory where OpenDJ is installed. @@ -271,7 +269,7 @@ Before starting this procedure, follow the steps in xref:#before-you-upgrade["Be C:\> msiexec /i opendj-{opendj-version}.msi /quiet OPENDJ="C:\path\to\opendj" ---- + -The installer replaces a service registered by the older `windows-service.bat` command with the installer-managed `OpenDJ` service automatically; no manual `--disableService`/`--enableService` is needed. Custom service configuration (a dedicated service account, recovery actions, dependencies) is not carried over: the service is re-registered with its defaults on every upgrade, so re-apply such hardening afterwards. +A registered Windows service survives the upgrade untouched: it names the service wrapper inside the installation directory, which the upgrade replaces in place, so the registration — including a dedicated service account, recovery actions or dependencies you configured — keeps working against the refreshed server. No `--disableService`/`--enableService` cycle is needed. . Run the `upgrade` command, described in xref:../reference/admin-tools-ref.adoc#upgrade-1[upgrade(1)] in the __Reference__, to bring the configuration and application data up to date with the new binary and script files: + @@ -281,12 +279,12 @@ The installer replaces a service registered by the older `windows-service.bat` c C:\path\to\opendj> upgrade.bat --no-prompt --acceptLicense ---- -. Start the upgraded OpenDJ server: +. Start the upgraded OpenDJ server; if it is registered as a Windows service, start the service again: + [source, console] ---- -C:\> net start OpenDJ +C:\> net start "OpenDJ Server" ---- ==== diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml b/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml index 627f1353f8..5a099472d3 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml +++ b/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml @@ -43,10 +43,9 @@ ${basedir}/resources/msi ${project.build.directory}/${product.name.lowercase} + stagingRoot = payload minus lib; stagingLib = lib minus the Unix scripts. --> ${project.build.directory}/msi-staging ${project.build.directory}/msi-staging-lib - ${package.dir}/lib/opendj_service.exe ${project.build.directory}/${product.name.lowercase}-${project.version}.msi @@ -89,13 +88,11 @@ - + - @@ -132,7 +129,6 @@ -dpoint=${parsedVersion.incrementalVersion} -dstagingRoot=${staging.root} -dstagingLib=${staging.lib} - -dserviceExe=${service.exe} -o${msi.file} diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 9d51ac200e..544bfd6e46 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -62,30 +62,31 @@ - - - \lib\opendj_service.exe" start ""'). Compared below with a + case-insensitive substring match (~><) against the resolved [OPENDJ], gating the + stop-and-verify pair: only a service that provably points into that tree is ever + acted on. Unset (no such service) fails the comparison, so the actions correctly + do nothing. + Type="raw" and substring rather than equality on purpose: CreateService stores + ImagePath as REG_EXPAND_SZ, which a raw search returns unexpanded and prefixed + with '#%', so neither an equality test nor the prefix operator (<<) would ever + match. The residual is that a bare directory name could also match a sibling + (C:\dj vs C:\dj2) when OPENDJ is passed on the command line without a trailing + backslash - accepted: the worst case is refusing an upgrade whose neighbouring + instance is running. + Additional instances get key names like "OpenDJ Server-2", which this search does + not see; upgrading such an instance while it runs falls back to the WiX3-era + behaviour (locked jars go to delete-on-reboot). The Services key is shared + between registry views. --> + + - - - - - + - - - + + - - - - - - - - - - - - - - - - - - - - - - - needs only the Include attribute (WiX 5 requires it; no Exclude here): - stagingRoot has everything except lib; stagingLib has lib minus the service wrapper. --> + stagingRoot has everything except lib; stagingLib has lib, opendj_service.exe + included - the package lays the wrapper down like any other file and registers no + service of its own; windows-service.bat does that when the administrator asks. --> @@ -301,8 +233,6 @@ - - diff --git a/opendj-server-legacy/src/build-tools/windows/Makefile b/opendj-server-legacy/src/build-tools/windows/Makefile index b03970d73c..2f73f590a1 100644 --- a/opendj-server-legacy/src/build-tools/windows/Makefile +++ b/opendj-server-legacy/src/build-tools/windows/Makefile @@ -38,8 +38,9 @@ SERVICE_PROGNAME=opendj_service.exe LAUNCHER_ADMINISTRATOR_PROGNAME=launcher_administrator.exe WINLAUNCHER_PROGNAME=winlauncher.exe # /Brepro makes the outputs reproducible (content-hash PE timestamps instead of the -# build time), so CI can assert that the committed lib/*.exe match the sources with a -# plain byte comparison. +# build time). The Package/Deploy workflow commits these binaries back to the branch +# whenever their bytes differ from the committed ones; without /Brepro every build +# would differ and it would commit on every push. LINKER=link -nologo /machine:x86 /Brepro LIBS=advapi32.lib diff --git a/opendj-server-legacy/src/build-tools/windows/service.c b/opendj-server-legacy/src/build-tools/windows/service.c index 51bad671b5..d84f4dcd25 100644 --- a/opendj-server-legacy/src/build-tools/windows/service.c +++ b/opendj-server-legacy/src/build-tools/windows/service.c @@ -965,141 +965,6 @@ ServiceReturnCode createServiceBinPath(char* serviceBinPath) return returnValue; } // createServiceBinPath -// ---------------------------------------------------- -// Reads the next command line token starting at *p into out (at most -// outSize - 1 characters). A token is either a run of non-blank -// characters or a double-quoted string; quotes are treated as plain -// delimiters without escape processing, so a trailing backslash-quote -// sequence (as written by msiexec) leaves trailing backslashes on the -// token, which normalizeInstanceDir strips. Returns the position right -// after the token. -// ---------------------------------------------------- - -static const char* nextCmdToken(const char* p, char* out, int outSize) -{ - int i = 0; - while ((*p == ' ') || (*p == '\t')) - { - p++; - } - if (*p == '"') - { - p++; - while ((*p != '\0') && (*p != '"')) - { - if (i < (outSize - 1)) - { - out[i++] = *p; - } - p++; - } - if (*p == '"') - { - p++; - } - } - else - { - while ((*p != '\0') && (*p != ' ') && (*p != '\t')) - { - if (i < (outSize - 1)) - { - out[i++] = *p; - } - p++; - } - } - out[i] = '\0'; - return p; -} // nextCmdToken - -// ---------------------------------------------------- -// Strips trailing backslashes and "\." path segments from an instance -// dir so that "C:\opendj", "C:\opendj\" and "C:\opendj\." all compare -// equal. -// ---------------------------------------------------- - -static void normalizeInstanceDir(char* dir) -{ - size_t len = strlen(dir); - BOOL changed = TRUE; - while (changed && (len > 0)) - { - changed = FALSE; - if (dir[len - 1] == '\\') - { - dir[--len] = '\0'; - changed = TRUE; - } - else if ((len > 1) && (dir[len - 1] == '.') && (dir[len - 2] == '\\')) - { - dir[--len] = '\0'; - changed = TRUE; - } - } -} // normalizeInstanceDir - -// ---------------------------------------------------- -// Expands 8.3 short-name components (e.g. PROGRA~1) so that the short -// and long spellings of the same existing path compare equal. When the -// path cannot be resolved (for example it no longer exists) it is left -// untouched. -// ---------------------------------------------------- - -static void expandLongPath(char* path) -{ - char expanded[COMMAND_SIZE]; - DWORD len = GetLongPathName(path, expanded, COMMAND_SIZE); - if ((len > 0) && (len < COMMAND_SIZE)) - { - strcpy(path, expanded); - } -} // expandLongPath - -// ---------------------------------------------------- -// Tells whether two service command lines refer to the same server -// instance. The strings cannot be compared verbatim because every -// writer quotes differently: this executable and the java tools write -// '"\lib\opendj_service.exe" start ""' while the MSI -// ServiceInstall writes the executable unquoted (when the path has no -// spaces) and the instance dir with a trailing backslash. Instead the -// executable path, the subcommand and the normalized instance dir -// (both expanded from 8.3 short names) are compared token by token, -// case-insensitively. -// ---------------------------------------------------- - -static BOOL serviceCmdsMatch(const char* cmd1, const char* cmd2) -{ - char exe1[COMMAND_SIZE]; - char exe2[COMMAND_SIZE]; - char sub1[COMMAND_SIZE]; - char sub2[COMMAND_SIZE]; - char dir1[COMMAND_SIZE]; - char dir2[COMMAND_SIZE]; - const char* p1 = cmd1; - const char* p2 = cmd2; - - p1 = nextCmdToken(p1, exe1, COMMAND_SIZE); - p1 = nextCmdToken(p1, sub1, COMMAND_SIZE); - nextCmdToken(p1, dir1, COMMAND_SIZE); - - p2 = nextCmdToken(p2, exe2, COMMAND_SIZE); - p2 = nextCmdToken(p2, sub2, COMMAND_SIZE); - nextCmdToken(p2, dir2, COMMAND_SIZE); - - expandLongPath(exe1); - expandLongPath(exe2); - - normalizeInstanceDir(dir1); - normalizeInstanceDir(dir2); - expandLongPath(dir1); - expandLongPath(dir2); - - return (_stricmp(exe1, exe2) == 0) - && (_stricmp(sub1, sub2) == 0) - && (_stricmp(dir1, dir2) == 0); -} // serviceCmdsMatch - // ---------------------------------------------------- // Returns the service name that maps the command used to start the // product. All commands are supposed to be unique because they have @@ -1140,7 +1005,7 @@ ServiceReturnCode getServiceName(char* cmdToRun, char* serviceName) ServiceDescriptor curService = serviceList[i]; if (curService.cmdToRun != NULL) { - if (serviceCmdsMatch(cmdToRun, curService.cmdToRun)) + if (_stricmp(cmdToRun, curService.cmdToRun) == 0) { if (strlen(curService.serviceName) < MAX_SERVICE_NAME) { @@ -2591,129 +2456,6 @@ int serviceState() return returnCode; } // serviceState -// --------------------------------------------------------------- -// Tells whether the service with the given key name is genuinely -// managed by the MSI package: the InstallDir value the package writes -// to HKLM\SOFTWARE\OpenDJ exists and the service command points into -// that directory. An orphaned service that merely reuses the "OpenDJ" -// key name (rolled-back install, hand-run sc create) fails the check -// and stays removable by the remove and cleanup subcommands. When the -// SCM query fails, or the entry's command line cannot be read, the -// service is treated as managed: wrongly deleting the MSI's own -// service is worse than leaving an orphan to msiexec /x or a manual -// 'sc delete'. -// --------------------------------------------------------------- -static BOOL isMsiManagedService(char *serviceName) -{ - HKEY hKey; - char installDir[COMMAND_SIZE]; - char token[COMMAND_SIZE]; - char serviceDir[COMMAND_SIZE]; - DWORD size = sizeof(installDir) - 1; - DWORD type = REG_NONE; - LONG result; - BOOL managed = FALSE; - ServiceDescriptor* serviceList = NULL; - int nbServices = -1; - - if (_stricmp(serviceName, MSI_SERVICE_NAME) != 0) - { - return FALSE; - } - - // KEY_WOW64_64KEY: the x64 package writes the 64-bit registry view and - // this executable is built 32-bit, so without the flag the lookup would - // be redirected to WOW6432Node and never find the value. - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenDJ", 0, - KEY_QUERY_VALUE | KEY_WOW64_64KEY, &hKey) != ERROR_SUCCESS) - { - debug("isMsiManagedService: no HKLM\\SOFTWARE\\OpenDJ key, " - "treating '%s' as orphaned.", serviceName); - return FALSE; - } - result = RegQueryValueEx(hKey, "InstallDir", NULL, &type, - (LPBYTE)installDir, &size); - RegCloseKey(hKey); - if ((result != ERROR_SUCCESS) || - ((type != REG_SZ) && (type != REG_EXPAND_SZ)) || (size == 0)) - { - debug("isMsiManagedService: no InstallDir value, " - "treating '%s' as orphaned.", serviceName); - return FALSE; - } - // RegQueryValueEx does not guarantee the terminating null. - installDir[size] = '\0'; - // The package writes REG_SZ; a hand-edited REG_EXPAND_SZ value would - // otherwise compare literally ('%ProgramFiles%...' vs the expanded path). - if (type == REG_EXPAND_SZ) - { - char expanded[COMMAND_SIZE]; - DWORD n = ExpandEnvironmentStrings(installDir, expanded, sizeof(expanded)); - if ((n == 0) || (n > sizeof(expanded))) - { - // Fail closed, as below: the reference directory cannot be resolved, so - // the entry cannot be proven orphaned. - debug("isMsiManagedService: could not expand InstallDir '%s', " - "treating '%s' as MSI-managed.", installDir, serviceName); - return TRUE; - } - strcpy(installDir, expanded); - } - - if (getServiceList(&serviceList, &nbServices) == SERVICE_RETURN_OK) - { - if (nbServices > 0) - { - int i; - for (i = 0; i < nbServices; i++) - { - ServiceDescriptor curService = serviceList[i]; - if ((curService.serviceName == NULL) || - (_stricmp(curService.serviceName, serviceName) != 0)) - { - continue; - } - if (curService.cmdToRun == NULL) - { - // Fail closed: the entry exists but its command line could not be - // read, so it cannot be proven orphaned. - debug("isMsiManagedService: no command line for '%s', " - "treating it as MSI-managed.", serviceName); - managed = TRUE; - break; - } - { - // Third token of ' start "\."' is the instance dir. - const char* p = curService.cmdToRun; - p = nextCmdToken(p, token, COMMAND_SIZE); - p = nextCmdToken(p, token, COMMAND_SIZE); - nextCmdToken(p, serviceDir, COMMAND_SIZE); - normalizeInstanceDir(serviceDir); - expandLongPath(serviceDir); - normalizeInstanceDir(installDir); - expandLongPath(installDir); - managed = (_stricmp(serviceDir, installDir) == 0); - debug("isMsiManagedService: service dir '%s' vs InstallDir '%s' " - "-> %s.", serviceDir, installDir, - managed ? "MSI-managed" : "orphaned"); - } - break; - } - free(serviceList); - } - } - else - { - // Fail closed for the same reason as above: without the service list the - // entry cannot be proven orphaned. - debug("isMsiManagedService: could not get service list, " - "treating '%s' as MSI-managed.", serviceName); - managed = TRUE; - } - - return managed; -} // isMsiManagedService - // --------------------------------------------------------------- // Function called to remove the service associated with a given // service name. @@ -2722,29 +2464,14 @@ static BOOL isMsiManagedService(char *serviceName) // Returns 2 if the service was marked for deletion but is still in // use. // Returns 3 if an error occurred. -// Returns 4 if the service is managed by the MSI package and was -// deliberately left untouched. // --------------------------------------------------------------- int removeServiceWithServiceName(char *serviceName) { int returnCode = 0; - ServiceReturnCode code; + ServiceReturnCode code = serviceNameInUse(serviceName); debug("Removing service with name %s.", serviceName); - if (isMsiManagedService(serviceName)) - { - // The MSI-managed service belongs to the installer: deleting it here - // (remove or cleanup subcommand) would leave msiexec /x targeting a key - // that no longer exists. Callers map this code to an informational skip - // and print the localized message; nothing on stdout here or the user - // would see it twice. - debug("Refusing to remove the MSI-managed service '%s'.", serviceName); - return 4; - } - - code = serviceNameInUse(serviceName); - if (code != SERVICE_IN_USE) { returnCode = 1; @@ -2783,8 +2510,6 @@ int removeServiceWithServiceName(char *serviceName) // Returns 2 if the service was marked for deletion but is still in // use. // Returns 3 if an error occurred. -// Returns 4 if the service is managed by the MSI package and was -// deliberately left untouched. // --------------------------------------------------------------- int removeService() { diff --git a/opendj-server-legacy/src/build-tools/windows/service.h b/opendj-server-legacy/src/build-tools/windows/service.h index 42e2c1b24e..754c87c148 100644 --- a/opendj-server-legacy/src/build-tools/windows/service.h +++ b/opendj-server-legacy/src/build-tools/windows/service.h @@ -58,13 +58,6 @@ // ---------------------------------------------------- #define EVENT_LOG_KEY "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s" -// ---------------------------------------------------- -// Service key name registered by the MSI package (WiX ServiceInstall). -// This service belongs to the installer: windows-service.bat must not -// delete it, or msiexec /x is left targeting a key that no longer exists. -// ---------------------------------------------------- -#define MSI_SERVICE_NAME "OpenDJ" - // ---------------------------------------------------- // Max size of the registry key // ---------------------------------------------------- diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/task/Task.java b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/task/Task.java index 6c01b32cbd..97afd84191 100644 --- a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/task/Task.java +++ b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/task/Task.java @@ -153,13 +153,6 @@ public enum State protected Integer returnCode; /** The last exception encountered during the task execution. */ protected Throwable lastException; - /** - * Success summary and detail that replace the fixed messages the launching - * panel passed to launchOperation, for runs whose successful completion is - * an informational skip rather than the operation those messages describe. - */ - private LocalizableMessage successSummaryOverride; - private LocalizableMessage successDetailOverride; /** * The progress logs of the task. Note that the user of StringBuffer is not * a bug, because of the way the contents of logs is updated, using @@ -323,39 +316,6 @@ public Integer getReturnCode() return returnCode; } - /** - * Returns the success summary that replaces the one passed to - * launchOperation, or null to use the passed one. - * @return the success summary override. - */ - public LocalizableMessage getSuccessSummaryOverride() - { - return successSummaryOverride; - } - - /** - * Returns the success detail that accompanies the success summary override. - * Only used when {@link #getSuccessSummaryOverride()} is not - * null. - * @return the success detail override. - */ - public LocalizableMessage getSuccessDetailOverride() - { - return successDetailOverride; - } - - /** - * Sets the success summary and detail displayed instead of the ones passed - * to launchOperation when the task finishes successfully. - * @param summary the success summary override. - * @param detail the success detail override. - */ - protected void setSuccessMessageOverride(LocalizableMessage summary, LocalizableMessage detail) - { - successSummaryOverride = summary; - successDetailOverride = detail; - } - /** * Returns the process that the task launched. * Returns null if not process was launched. diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java index 9c71d17d4c..f2850c331c 100644 --- a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java +++ b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/StatusGenericPanel.java @@ -1744,13 +1744,8 @@ public void backgroundTaskCompleted(final Task returnValue, Throwable t) String summaryMsg; if (task.getState() == Task.State.FINISHED_SUCCESSFULLY) { - // A task can replace the fixed success messages when its successful - // completion is an informational skip (e.g. the windows-service task - // leaving an MSI-managed service in place). - final boolean override = task.getSuccessSummaryOverride() != null; summaryMsg = - Utilities.getFormattedSuccess(override ? task.getSuccessSummaryOverride() : successSummary, - ColorAndFontConstants.errorTitleFont, override ? task.getSuccessDetailOverride() : successDetail, + Utilities.getFormattedSuccess(successSummary, ColorAndFontConstants.errorTitleFont, successDetail, ColorAndFontConstants.defaultFont); } else diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/WindowsServicePanel.java b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/WindowsServicePanel.java index ce42bb210a..f6cf128113 100644 --- a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/WindowsServicePanel.java +++ b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/WindowsServicePanel.java @@ -19,7 +19,6 @@ package org.opends.guitools.controlpanel.ui; import static org.opends.messages.AdminToolMessages.*; -import static org.opends.messages.ToolMessages.INFO_WINDOWS_SERVICE_MSI_MANAGED; import java.awt.Component; import java.awt.Dimension; @@ -335,25 +334,13 @@ public void runTask() else { returnCode = ConfigureWindowsService.disableService(outPrintStream, errorPrintStream); - // SERVICE_MSI_MANAGED is an informational skip, not an error: the - // MSI-managed service belongs to the installer and is removed by - // msiexec /x (disableService already printed the explanation). The - // dialog summary must not claim the service was disabled, so the - // fixed success messages are replaced for that outcome. if (returnCode != ConfigureWindowsService.SERVICE_ALREADY_DISABLED - && returnCode != ConfigureWindowsService.SERVICE_DISABLE_SUCCESS - && returnCode != ConfigureWindowsService.SERVICE_MSI_MANAGED) + && returnCode != ConfigureWindowsService.SERVICE_DISABLE_SUCCESS) { state = State.FINISHED_WITH_ERROR; } else { - if (returnCode == ConfigureWindowsService.SERVICE_MSI_MANAGED) - { - setSuccessMessageOverride( - INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY.get(), - INFO_WINDOWS_SERVICE_MSI_MANAGED.get()); - } state = State.FINISHED_SUCCESSFULLY; } } diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/uninstaller/Uninstaller.java b/opendj-server-legacy/src/main/java/org/opends/guitools/uninstaller/Uninstaller.java index 3d13431c82..808f87be21 100644 --- a/opendj-server-legacy/src/main/java/org/opends/guitools/uninstaller/Uninstaller.java +++ b/opendj-server-legacy/src/main/java/org/opends/guitools/uninstaller/Uninstaller.java @@ -1371,9 +1371,6 @@ private void disableWindowsService() throws ApplicationException { switch (code) { case SERVICE_DISABLE_SUCCESS: case SERVICE_ALREADY_DISABLED: - // The MSI-managed service is removed by the Windows Installer package, - // not by this uninstaller: continue deleting the files. - case SERVICE_MSI_MANAGED: break; default: LocalizableMessage errorMessage = INFO_ERROR_DISABLING_WINDOWS_SERVICE.get(getInstallationPath()); diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java b/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java index 96e69af35d..c4fe83f871 100644 --- a/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java +++ b/opendj-server-legacy/src/main/java/org/opends/server/tools/ConfigureWindowsService.java @@ -97,11 +97,6 @@ public class ConfigureWindowsService private static final int SERVICE_MARKED_FOR_DELETION = 2; /** An error occurred disabling the service. */ public static final int SERVICE_DISABLE_ERROR = 3; - /** - * The service is managed by the MSI package and was deliberately left - * untouched (it is removed when the package is uninstalled). - */ - public static final int SERVICE_MSI_MANAGED = 4; /** Return codes for the method serviceState. */ /** The service is enabled. */ @@ -120,11 +115,6 @@ public class ConfigureWindowsService private static final int SERVICE_CLEANUP_ERROR = 2; /** The service is marked for deletion. */ private static final int SERVICE_CLEANUP_MARKED_FOR_DELETION = 3; - /** - * The service is managed by the MSI package and was deliberately left - * untouched (it is removed when the package is uninstalled). - */ - private static final int SERVICE_CLEANUP_MSI_MANAGED = 4; /** * Configures the Windows service for this instance on this machine. This tool @@ -496,9 +486,6 @@ public static int disableService(PrintStream out, PrintStream err) case 3: printWrappedText(err, ERR_WINDOWS_SERVICE_DISABLE_ERROR.get()); return SERVICE_DISABLE_ERROR; - case 4: - printWrappedText(out, INFO_WINDOWS_SERVICE_MSI_MANAGED.get()); - return SERVICE_MSI_MANAGED; default: printWrappedText(err, ERR_WINDOWS_SERVICE_DISABLE_ERROR.get()); return SERVICE_DISABLE_ERROR; @@ -523,8 +510,7 @@ public static int disableService(PrintStream out, PrintStream err) * the stream used to write the error output. * @return SERVICE_CLEANUP_SUCCESS, * SERVICE_NOT_FOUND, - * SERVICE_MARKED_FOR_DELETION, - * SERVICE_CLEANUP_MSI_MANAGED or + * SERVICE_MARKED_FOR_DELETION or * SERVICE_CLEANUP_ERROR depending on whether the service * could be found or not. */ @@ -570,9 +556,6 @@ private static int cleanupService(String serviceName, PrintStream out, PrintStre case 3: printWrappedText(err, ERR_WINDOWS_SERVICE_CLEANUP_ERROR.get(serviceName)); return SERVICE_CLEANUP_ERROR; - case 4: - printWrappedText(out, INFO_WINDOWS_SERVICE_MSI_MANAGED.get()); - return SERVICE_CLEANUP_MSI_MANAGED; default: printWrappedText(err, ERR_WINDOWS_SERVICE_CLEANUP_ERROR.get(serviceName)); return SERVICE_CLEANUP_ERROR; diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool.properties index ff62180fd2..c7a8fdde86 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. # Portions copyright 2012 profiq s.r.o. @@ -2464,8 +2463,6 @@ INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_SUMMARY=Windows Service \ Disabled INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_DETAILS=The Windows \ service was successfully disabled. -INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Windows Service Left \ - Enabled ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_SUMMARY=Error during \ Disabling of Windows Service ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_DETAILS=An error occurred \ diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ca_ES.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ca_ES.properties index 55f860360b..1305a566df 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ca_ES.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ca_ES.properties @@ -1,4 +1,3 @@ -# Portions Copyright 2026 3A Systems, LLC. INFO_CLI_UNINSTALL_CONFIRM_BACKUPS=Voleu treure els fitxers de c\u00f2pia de seguretat continguts al directori bak? INFO_CLI_UNINSTALL_CONFIRM_CONFIGURATION_SCHEMA=Voleu treure els fitxers de configuraci\u00f3 i d'esquema? INFO_CLI_UNINSTALL_CONFIRM_DATABASES=Voleu treure el contingut de la base de dades? @@ -63,4 +62,3 @@ INFO_DESCRIPTION_SUBCMD_ENABLE_REPLICATION=Actualitza la configuraci\u00f3 dels INFO_DESCRIPTION_SUBCMD_DISABLE_REPLICATION=Deshabilita la replicaci\u00f3 en el servidor especificat per al DN base proporcionat i treu les refer\u00e8ncies en els altres servidors amb els quals est\u00e0 replicant les dades INFO_DESCRIPTION_SUBCMD_STATUS_REPLICATION=Mostra un llistat amb la configuraci\u00f3 de replicaci\u00f3 b\u00e0sica dels DN base dels servidors definits en la informaci\u00f3 de registrament. Si no s'especifica el DN base com a par\u00e0metre es mostra la informaci\u00f3 per a tots els DN base INFO_REPLICATION_DESCRIPTION_EQUIVALENT_COMMAND_FILE_PATH=La ruta sencera al fitxer on les comandes equivalents sense interacci\u00f3 seran escrites quant aquesta comanda s'executa en mode interactiu -INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=El servei de Windows es mant\u00e9 habilitat diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_de.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_de.properties index 350bea57a2..1dd9824a45 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_de.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_de.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. @@ -1594,7 +1593,6 @@ INFO_CTRL_PANEL_DISABLE_WINDOWS_SERVICE_BUTTON=Deaktivieren... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUMMARY=Windows-Dienst wird deaktiviert... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_SUMMARY=Windows-Dienst deaktiviert INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_DETAILS=Der Windows-Dienst wurde erfolgreich deaktiviert. -INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Windows-Dienst bleibt aktiviert ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_SUMMARY=Fehler beim Deaktivieren des Windows-Diensts ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_DETAILS=Beim Deaktivieren des Windows-Diensts ist ein Fehler aufgetreten. Fehlercode: %d. INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUMMARY=Windows-Dienst wird aktiviert... diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_es.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_es.properties index 4b05783f0c..4c984c0e69 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_es.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_es.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. @@ -1594,7 +1593,6 @@ INFO_CTRL_PANEL_DISABLE_WINDOWS_SERVICE_BUTTON=Deshabilitar... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUMMARY=Inhabilitando el servicio de Windows... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_SUMMARY=Windows Service deshabilitado INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_DETAILS=El servicio de Windows se ha deshabilitado correctamente. -INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=El servicio de Windows permanece habilitado ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_SUMMARY=Error al deshabilitar Windows Service ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_DETAILS=Se produjo un error al deshabilitar Windows Service. C\u00f3digo de error: %d. INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUMMARY=Habilitando el servicio de Windows... diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_fr.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_fr.properties index eb0b8a8924..b315ccf894 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_fr.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_fr.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. @@ -1594,7 +1593,6 @@ INFO_CTRL_PANEL_DISABLE_WINDOWS_SERVICE_BUTTON=D\u00e9sactiver... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUMMARY=D\u00e9sactivation du service Windows... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_SUMMARY=Service Windows d\u00e9sactiv\u00e9 INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_DETAILS=Le Service Windows a \u00e9t\u00e9 d\u00e9sactiv\u00e9. -INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Service Windows laiss\u00e9 activ\u00e9 ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_SUMMARY=Erreur lors de la d\u00e9sactivation du Service Windows ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_DETAILS=Une erreur s'est produite lors de la d\u00e9sactivation du service Windows. Code d'erreur\u00a0: %d. INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUMMARY=Activation du service Windows... diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ja.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ja.properties index 98d1441e24..738f140346 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ja.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ja.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. @@ -1593,7 +1592,6 @@ INFO_CTRL_PANEL_DISABLE_WINDOWS_SERVICE_BUTTON=\u7121\u52b9\u5316... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUMMARY=Windows \u30b5\u30fc\u30d3\u30b9\u3092\u7121\u52b9\u306b\u3057\u3066\u3044\u307e\u3059... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_SUMMARY=Windows \u30b5\u30fc\u30d3\u30b9\u304c\u7121\u52b9\u306b\u306a\u308a\u307e\u3057\u305f INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_DETAILS=Windows \u30b5\u30fc\u30d3\u30b9\u304c\u6b63\u5e38\u306b\u7121\u52b9\u306b\u306a\u308a\u307e\u3057\u305f\u3002 -INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Windows \u30b5\u30fc\u30d3\u30b9\u306f\u6709\u52b9\u306e\u307e\u307e\u3067\u3059 ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_SUMMARY=Windows \u30b5\u30fc\u30d3\u30b9\u306e\u7121\u52b9\u5316\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_DETAILS=Windows \u30b5\u30fc\u30d3\u30b9\u306e\u7121\u52b9\u5316\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u30a8\u30e9\u30fc\u30b3\u30fc\u30c9: %d. INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUMMARY=Windows \u30b5\u30fc\u30d3\u30b9\u3092\u6709\u52b9\u5316\u3057\u3066\u3044\u307e\u3059... diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ko.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ko.properties index b106fc2d17..eaff621d1f 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ko.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_ko.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2009 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. @@ -326,4 +325,3 @@ INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUMMARY=Windows \uc11c\ube44\uc2a4\ub97 INFO_CTRL_PANEL_ERROR_DIALOG_TITLE=\uc624\ub958 INFO_CTRL_PANEL_DB_HEADER=\ubc31\uc5d4\ub4dc \uc544\uc774\ub514 INFO_PROGRESS_IMPORT_AUTOMATICALLY_GENERATED_REMOTE=\uc790\ub3d9\uc73c\ub85c \uc0dd\uc131\ub41c \ub370\uc774\ud130(%s \ud56d\ubaa9)\ub97c \uac00\uc838\uc624\ub294 \uc911 -INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Windows \uc11c\ube44\uc2a4\uac00 \ud65c\uc131\ud654\ub41c \uc0c1\ud0dc\ub85c \uc720\uc9c0\ub428 diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_pl.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_pl.properties index 595aa3acec..17604066d2 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_pl.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_pl.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. @@ -541,4 +540,3 @@ INFO_CTRL_PANEL_STOPPING_SERVER_SUCCESSFUL_DETAILS=Serwer zatrzymany pomy\u015bl INFO_CTRL_PANEL_CONFIRMATION_EXPORT_LDIF_DETAILS=File '%s' exists and its contents will be overwritten.

Czy chcesz kontynuowa\u0107? ERR_ADMINISTRATOR_PWD_DO_NOT_MATCH=Podane has\u0142a r\u00f3\u017cni\u0105 si\u0119. INFO_REMOVE_SCHEMA_AND_CONFIGURATION_LABEL=Pliki Konfiguracyjne i Schematy -INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Us\u0142uga systemu Windows pozosta\u0142a w\u0142\u0105czona diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_CN.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_CN.properties index 3e2014fee5..f2c6442f2e 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_CN.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_CN.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. @@ -1594,7 +1593,6 @@ INFO_CTRL_PANEL_DISABLE_WINDOWS_SERVICE_BUTTON=\u7981\u7528... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUMMARY=\u6b63\u5728\u7981\u7528 Windows \u670d\u52a1... INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_SUMMARY=Windows \u670d\u52a1\u5df2\u7981\u7528 INFO_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_SUCCESSFUL_DETAILS=\u5df2\u6210\u529f\u7981\u7528 Windows \u670d\u52a1\u3002 -INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Windows \u670d\u52a1\u4fdd\u6301\u542f\u7528\u72b6\u6001 ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_SUMMARY=\u7981\u7528 Windows \u670d\u52a1\u671f\u95f4\u51fa\u9519 ERR_CTRL_PANEL_DISABLING_WINDOWS_SERVICE_ERROR_DETAILS=\u7981\u7528 Windows \u670d\u52a1\u671f\u95f4\u51fa\u73b0\u9519\u8bef\u3002\u9519\u8bef\u4ee3\u7801: %d\u3002 INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUMMARY=\u6b63\u5728\u542f\u7528 Windows \u670d\u52a1... diff --git a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_TW.properties b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_TW.properties index b1cde49bf4..b3c9b04224 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_TW.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/admin_tool_zh_TW.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2009 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. @@ -326,4 +325,3 @@ INFO_CTRL_PANEL_ENABLING_WINDOWS_SERVICE_SUMMARY=\u6b63\u5728\u555f\u7528 Window INFO_CTRL_PANEL_ERROR_DIALOG_TITLE=\u932f\u8aa4 INFO_PROGRESS_IMPORT_AUTOMATICALLY_GENERATED_REMOTE=\u6b63\u5728\u532f\u5165\u81ea\u52d5\u7522\u751f\u7684\u8cc7\u6599 (%s \u500b\u9805\u76ee) INFO_CTRL_PANEL_TASK_TO_SCHEDULE_TIME=\u6642\u9593: -INFO_CTRL_PANEL_WINDOWS_SERVICE_MSI_MANAGED_SUMMARY=Windows \u670d\u52d9\u4fdd\u6301\u555f\u7528\u72c0\u614b diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool.properties index 697ab55ea6..c03e0bc29f 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool.properties @@ -1337,9 +1337,6 @@ ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=An unexpected error occurred \ trying to disable the server as a Windows service%nCheck that you have \ administrator rights (only Administrators can disable the server as a Windows \ Service) -INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=The service is managed by the OpenDJ \ - Windows Installer package (MSI) and was left untouched. It is removed \ - automatically when the package is uninstalled INFO_WINDOWS_SERVICE_ENABLED_835=The server is enabled as a Windows service. \ The service name for the server is: %s INFO_WINDOWS_SERVICE_DISABLED_836=The server is disabled as a Windows service diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_ca_ES.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_ca_ES.properties index 1fc2102d47..3fc8354b3d 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_ca_ES.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_ca_ES.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. INFO_ENCPW_DESCRIPTION_LISTSCHEMES_7=Llistar els esquemes d'emmagatzemament de contrasenya disponibles INFO_ENCPW_DESCRIPTION_CLEAR_PW_8=Contrasenya de text-clar per codificar o per comparar contra una contrasenya codificada @@ -466,4 +465,3 @@ INFO_LDIFDIFF_DESCRIPTION_CHECK_SCHEMA_1674=T\u00e9 en compte la sintaxis dels a INFO_INSTALLDS_PROVIDE_BASE_DN_PROMPT_1700=Voleu crear DNs base al servidor? ERR_INSTALLDS_NO_BASE_DN_AND_CONFLICTING_ARG_1701=Heu especificat no crear un DN base. Si no es crea cap DN base no es pot especificar l'argument '%s' INFO_DESCRIPTION_BACKEND_TOOL_1893=Aquesta utilitat pot utilitzar-se per a depurar una infraestructura de fons -INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=El servei est\u00e0 gestionat pel paquet Windows Installer (MSI) d'OpenDJ i no s'ha modificat. S'elimina autom\u00e0ticament quan es desinstal\u00b7la el paquet diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_de.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_de.properties index 623a999d9b..aa69607206 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_de.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_de.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. @@ -654,7 +653,6 @@ INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED_831=Der Server wurde erfolgreich als W INFO_WINDOWS_SERVICE_ALREADY_DISABLED_832=Der Server wurde bereits als Windows-Dienst deaktiviert WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION_833=Der Server wurde f\u00fcr die L\u00f6schung als Windows-Dienst markiert ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=Unerwarteter Fehler beim Versuch, den Server als Windows-Dienst zu deaktivieren%nStellen Sie sicher, dass Sie die Administratorrechte besitzen (nur Administratoren k\u00f6nnen den Server als Windows-Dienst deaktivieren) -INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=Der Dienst wird vom OpenDJ Windows Installer-Paket (MSI) verwaltet und wurde nicht ver\u00e4ndert. Er wird automatisch entfernt, wenn das Paket deinstalliert wird INFO_WINDOWS_SERVICE_ENABLED_835=Der Server ist als Windows-Dienst aktiviert. Der Dienstname f\u00fcr den Server ist: %s INFO_WINDOWS_SERVICE_DISABLED_836=Der Server ist nicht als Windows-Dienst aktiv ERR_WINDOWS_SERVICE_STATE_ERROR_837=Unerwarteter Fehler beim Versuch, den Status des Servers als Windows-Dienst abzurufen diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_es.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_es.properties index fceb3e6820..d38b8b63a5 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_es.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_es.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. @@ -654,7 +653,6 @@ INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED_831=El servidor se ha deshabilitado co INFO_WINDOWS_SERVICE_ALREADY_DISABLED_832=El servidor ya se ha deshabilitado como servicio de Windows WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION_833=El servidor ha sido marcado para su eliminaci\u00f3n como servicio de Windows ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=Se ha producido un error inesperado al tratar de inhabilitar el servidor como servicio de Windows%nCompruebe si posee los derechos de administrador (s\u00f3lo los Administradores pueden inhabilitar el servidor como servicio de Windows) -INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=El servicio est\u00e1 administrado por el paquete de Windows Installer (MSI) de OpenDJ y no se ha modificado. Se elimina autom\u00e1ticamente al desinstalar el paquete INFO_WINDOWS_SERVICE_ENABLED_835=El servidor est\u00e1 habilitado como servicio de Windows. El nombre de servicio para el servidor es: %s INFO_WINDOWS_SERVICE_DISABLED_836=El servidor est\u00e1 deshabilitado como servicio de Windows ERR_WINDOWS_SERVICE_STATE_ERROR_837=Se ha producido un error inesperado al tratar de recuperar el estado del servidor como un servicio de Windows diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_fr.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_fr.properties index fb7d5b2ef8..c8934aa03c 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_fr.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_fr.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. @@ -654,7 +653,6 @@ INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED_831=Le serveur a \u00e9t\u00e9 d\u00e9 INFO_WINDOWS_SERVICE_ALREADY_DISABLED_832=Le serveur a d\u00e9j\u00e0 \u00e9t\u00e9 d\u00e9sactiv\u00e9 en tant que service Windows WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION_833=Le serveur a \u00e9t\u00e9 marqu\u00e9 pour suppression en tant que service Windows ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=Une erreur inattendue s'est produite lors de la tentative de d\u00e9sactivation du serveur en tant que service Windows.%nV\u00e9rifiez que vous disposez de droits d'administrateur (seuls les administrateurs peuvent d\u00e9sactiver le serveur en tant que service Windows) -INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=Le service est g\u00e9r\u00e9 par le package Windows Installer (MSI) d'OpenDJ et n'a pas \u00e9t\u00e9 modifi\u00e9. Il est supprim\u00e9 automatiquement lors de la d\u00e9sinstallation du package INFO_WINDOWS_SERVICE_ENABLED_835=Le serveur est activ\u00e9 en tant que service Windows. Le nom de service du serveur est\u00a0: %s INFO_WINDOWS_SERVICE_DISABLED_836=Le serveur est d\u00e9sactiv\u00e9 en tant que service Windows ERR_WINDOWS_SERVICE_STATE_ERROR_837=Une erreur inattendue s'est produite lors de la tentative de r\u00e9cup\u00e9ration de l'\u00e9tat du serveur en tant que service Windows diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_ja.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_ja.properties index 495ab54d46..bee708142d 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_ja.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_ja.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. @@ -654,7 +653,6 @@ INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED_831=Windows \u30b5\u30fc\u30d3\u30b9\u INFO_WINDOWS_SERVICE_ALREADY_DISABLED_832=Windows \u30b5\u30fc\u30d3\u30b9\u3068\u3057\u3066\u5b9f\u884c\u3055\u308c\u3066\u3044\u305f\u30b5\u30fc\u30d0\u30fc\u306f\u3059\u3067\u306b\u7121\u52b9\u306b\u3055\u308c\u3066\u3044\u307e\u3057\u305f WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION_833=\u30b5\u30fc\u30d0\u30fc\u306b\u306f\u3001Windows \u30b5\u30fc\u30d3\u30b9\u3068\u3057\u3066\u524a\u9664\u306e\u30de\u30fc\u30af\u304c\u4ed8\u3051\u3089\u308c\u307e\u3057\u305f ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=Windows \u30b5\u30fc\u30d3\u30b9\u3068\u3057\u3066\u5b9f\u884c\u3055\u308c\u3066\u3044\u308b\u30b5\u30fc\u30d3\u30b9\u3092\u7121\u52b9\u306b\u3057\u3066\u3044\u308b\u3068\u304d\u306b\u4e88\u671f\u3057\u306a\u3044\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f%n\u7ba1\u7406\u8005\u6a29\u9650\u304c\u3042\u308b\u3053\u3068\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044 (\u7ba1\u7406\u8005\u306e\u307f\u304c Windows \u30b5\u30fc\u30d3\u30b9\u3068\u3057\u3066\u5b9f\u884c\u3055\u308c\u3066\u3044\u308b\u30b5\u30fc\u30d0\u30fc\u3092\u7121\u52b9\u306b\u3067\u304d\u307e\u3059) -INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=\u3053\u306e\u30b5\u30fc\u30d3\u30b9\u306f OpenDJ Windows \u30a4\u30f3\u30b9\u30c8\u30fc\u30e9\u30fc\u30d1\u30c3\u30b1\u30fc\u30b8 (MSI) \u306b\u3088\u3063\u3066\u7ba1\u7406\u3055\u308c\u3066\u3044\u308b\u305f\u3081\u3001\u5909\u66f4\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u30d1\u30c3\u30b1\u30fc\u30b8\u306e\u30a2\u30f3\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u6642\u306b\u81ea\u52d5\u7684\u306b\u524a\u9664\u3055\u308c\u307e\u3059 INFO_WINDOWS_SERVICE_ENABLED_835=\u30b5\u30fc\u30d0\u30fc\u306f Windows \u30b5\u30fc\u30d3\u30b9\u3068\u3057\u3066\u6709\u52b9\u306b\u3055\u308c\u307e\u3059\u3002\u30b5\u30fc\u30d0\u30fc\u306e\u30b5\u30fc\u30d3\u30b9\u540d: %s INFO_WINDOWS_SERVICE_DISABLED_836=Windows \u30b5\u30fc\u30d3\u30b9\u3068\u3057\u3066\u5b9f\u884c\u3055\u308c\u3066\u3044\u308b\u30b5\u30fc\u30d0\u30fc\u3092\u7121\u52b9\u306b\u3057\u307e\u3059 ERR_WINDOWS_SERVICE_STATE_ERROR_837=Windows \u30b5\u30fc\u30d3\u30b9\u3068\u3057\u3066\u5b9f\u884c\u3055\u308c\u3066\u3044\u308b\u30b5\u30fc\u30d0\u30fc\u306e\u72b6\u614b\u3092\u53d6\u5f97\u3057\u3066\u3044\u308b\u3068\u304d\u306b\u4e88\u671f\u3057\u306a\u3044\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_ko.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_ko.properties index 80c99a99b0..7e8d974835 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_ko.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_ko.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2009 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. @@ -652,7 +651,6 @@ INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED_831=The server was successfully disabl INFO_WINDOWS_SERVICE_ALREADY_DISABLED_832=The server was already disabled as a Windows service WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION_833=The server has been marked for deletion as a Windows Service ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=An unexpected error occurred trying to disable the server as a Windows service%nCheck that you have administrator rights (only Administrators can disable the server as a Windows Service) -INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=\uc774 \uc11c\ube44\uc2a4\ub294 OpenDJ Windows Installer \ud328\ud0a4\uc9c0(MSI)\uc5d0\uc11c \uad00\ub9ac\ud558\ubbc0\ub85c \ubcc0\uacbd\ud558\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. \ud328\ud0a4\uc9c0\ub97c \uc81c\uac70\ud558\uba74 \uc790\ub3d9\uc73c\ub85c \uc81c\uac70\ub429\ub2c8\ub2e4 INFO_WINDOWS_SERVICE_ENABLED_835=The server is enabled as a Windows service. The service name for the server is: %s INFO_WINDOWS_SERVICE_DISABLED_836=The server is disabled as a Windows service ERR_WINDOWS_SERVICE_STATE_ERROR_837=An unexpected error occurred trying to retrieve the state of the server as a Windows service diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_pl.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_pl.properties index 145c3e329f..43ebcc4087 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_pl.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_pl.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. INFO_LISTBACKENDS_TOOL_DESCRIPTION_723=To narz\u0119dzie mo\u017ce by\u0107 u\u017cyte do wy\u015bwietlenia listy zapleczy i bazowych DN skonfigurowanych na Directory Serverze INFO_INSTALLDS_CERT_OPTION_SELF_SIGNED_1388=Wygeneruj certyfikat podpisany przez siebie (zalecane tylko podczas testowania) @@ -373,4 +372,3 @@ INFO_VERIFYINDEX_DESCRIPTION_COUNT_ERRORS_1199=Licz ilo\u015b\u0107 b\u0142\u011 INFO_LDAPPWMOD_TOOL_DESCRIPTION_692=To narz\u0119dzie mo\u017ce by\u0107 u\u017cyte do przeprowadzenia operacji modyfikacji has\u0142a LDAP na Directory Server INFO_DESCRIPTION_BACKEND_TOOL_1893=To narz\u0119dzie mo\u017ce by\u0107 wykorzystane do debugowania zaplecza -INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=Us\u0142uga jest zarz\u0105dzana przez pakiet Instalatora Windows (MSI) OpenDJ i nie zosta\u0142a zmieniona. Zostanie usuni\u0119ta automatycznie podczas odinstalowywania pakietu diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_CN.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_CN.properties index d646c6b00c..0dee50fb1f 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_CN.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_CN.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2010 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. @@ -654,7 +653,6 @@ INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED_831=\u5df2\u6210\u529f\u5c06\u670d\u52 INFO_WINDOWS_SERVICE_ALREADY_DISABLED_832=\u5df2\u5c06\u670d\u52a1\u5668\u4f5c\u4e3a Windows \u670d\u52a1\u7981\u7528 WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION_833=\u5df2\u5c06\u670d\u52a1\u5668\u4f5c\u4e3a Windows \u670d\u52a1\u6807\u8bb0\u4e3a\u5220\u9664 ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=\u5728\u5c1d\u8bd5\u5c06\u670d\u52a1\u5668\u4f5c\u4e3a Windows \u670d\u52a1\u7981\u7528\u65f6\u51fa\u73b0\u610f\u5916\u9519\u8bef%n\u68c0\u67e5\u60a8\u662f\u5426\u62e5\u6709\u7ba1\u7406\u5458\u6743\u9650\uff08\u53ea\u6709\u7ba1\u7406\u5458\u624d\u80fd\u542f\u7528\u670d\u52a1\u5668\u4ee5\u4f5c\u4e3a Windows \u670d\u52a1\u8fd0\u884c\uff09 -INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=\u8be5\u670d\u52a1\u7531 OpenDJ Windows Installer \u8f6f\u4ef6\u5305 (MSI) \u7ba1\u7406\uff0c\u56e0\u6b64\u672a\u4f5c\u66f4\u6539\u3002\u5378\u8f7d\u8be5\u8f6f\u4ef6\u5305\u65f6\u5c06\u81ea\u52a8\u5220\u9664\u8be5\u670d\u52a1 INFO_WINDOWS_SERVICE_ENABLED_835=\u5df2\u5c06\u670d\u52a1\u5668\u4f5c\u4e3a Windows \u670d\u52a1\u542f\u7528\u3002\u670d\u52a1\u5668\u7684\u670d\u52a1\u540d\u79f0\u4e3a: %s INFO_WINDOWS_SERVICE_DISABLED_836=\u5df2\u5c06\u670d\u52a1\u5668\u4f5c\u4e3a Windows \u670d\u52a1\u7981\u7528 ERR_WINDOWS_SERVICE_STATE_ERROR_837=\u5728\u5c1d\u8bd5\u68c0\u7d22\u670d\u52a1\u5668\u4f5c\u4e3a Windows \u670d\u52a1\u7684\u72b6\u6001\u65f6\u51fa\u73b0\u610f\u5916\u9519\u8bef diff --git a/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_TW.properties b/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_TW.properties index b7bd92b540..838753a201 100644 --- a/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_TW.properties +++ b/opendj-server-legacy/src/messages/org/opends/messages/tool_zh_TW.properties @@ -12,7 +12,6 @@ # # Copyright 2006-2009 Sun Microsystems, Inc. # Portions Copyright 2011-2016 ForgeRock AS. -# Portions Copyright 2026 3A Systems, LLC. @@ -652,7 +651,6 @@ INFO_WINDOWS_SERVICE_SUCCESSULLY_DISABLED_831=The server was successfully disabl INFO_WINDOWS_SERVICE_ALREADY_DISABLED_832=The server was already disabled as a Windows service WARN_WINDOWS_SERVICE_MARKED_FOR_DELETION_833=The server has been marked for deletion as a Windows Service ERR_WINDOWS_SERVICE_DISABLE_ERROR_834=An unexpected error occurred trying to disable the server as a Windows service%nCheck that you have administrator rights (only Administrators can disable the server as a Windows Service) -INFO_WINDOWS_SERVICE_MSI_MANAGED_20018=\u8a72\u670d\u52d9\u7531 OpenDJ Windows Installer \u5957\u4ef6 (MSI) \u7ba1\u7406\uff0c\u56e0\u6b64\u672a\u8b8a\u66f4\u3002\u89e3\u9664\u5b89\u88dd\u8a72\u5957\u4ef6\u6642\u5c07\u81ea\u52d5\u79fb\u9664\u8a72\u670d\u52d9 INFO_WINDOWS_SERVICE_ENABLED_835=The server is enabled as a Windows service. The service name for the server is: %s INFO_WINDOWS_SERVICE_DISABLED_836=The server is disabled as a Windows service ERR_WINDOWS_SERVICE_STATE_ERROR_837=An unexpected error occurred trying to retrieve the state of the server as a Windows service From 92b30bd208c4d1eff43a846ffa6a4d4bef9c31a3 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Tue, 11 Aug 2026 18:25:59 +0300 Subject: [PATCH 40/52] Refuse the upgrades that would destroy an installation, and stop lying about the service state serviceState() collapsed an unreadable service list into "disabled", so the uninstaller skipped disabling a registered service, the control panel offered to enable one that already existed, and stop-ds killed the JVM behind the SCM's back. Report the error the exit code already has a mapping for. The location guards move to the execute sequence and become value-based. The old UI-sequence row aborted a GUI upgrade before WelcomeDlg whenever the location could not be detected, leaving a command line as the only way out; now the wizard runs, the administrator browses to the existing directory, and the refusal only fires when the resolved directory is the default with no server in it - which still covers the silent install that names nothing. A second guard refuses an upgrade that would relocate: OPENDJ pointing somewhere other than the detected installation strands config, db and logs in the old tree that RemoveExistingProducts is about to empty. Two searches now ask whether the default directories actually hold a server rather than merely exist, so neither guard acts on a leftover empty directory. ICE61 is suppressed in the validation step - AllowSameVersionUpgrades authors it by design - and the refusal scenario clears every detection signal itself instead of inheriting the previous step's cleanup. --- .github/workflows/build.yml | 49 ++++++++++++-- .../asciidoc/install-guide/chap-upgrade.adoc | 2 +- .../resources/msi/package.wxs | 66 +++++++++++++++---- .../src/build-tools/windows/service.c | 11 ++++ 4 files changed, 110 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c4d45640ef..af07b3eb97 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -133,7 +133,12 @@ jobs: shell: bash run: | msi=$(ls opendj-packages/opendj-msi/opendj-msi-standard/target/*.msi) - wix msi validate "$msi" + # ICE61 fires by design: AllowSameVersionUpgrades authors an UpgradeVersion row + # whose range includes the product's own version, which is exactly what makes a + # rebuilt hotfix at the same 3-part version upgrade rather than install alongside. + # Left unsuppressed it is permanent noise this step could not tell from a real + # regression. + wix msi validate -sice ICE61 "$msi" - name: Test on Unix if: runner.os == 'Linux' run: | @@ -932,8 +937,12 @@ jobs: # without OPENDJ used to relocate to the default while RemoveExistingProducts # emptied the old tree. The installer must refuse instead. $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName - # No detection signals: remove the leftover legacy default directory. + # No detection signals at all - the guard under test is the one that fires when + # none resolves, so clear every one of them here rather than rely on the + # preceding step's uninstall having removed the registry value. Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart OPENDJ=C:\opendj-custom /l*v install-custom.log" if ($p.ExitCode -ne 0) { Get-Content install-custom.log -Tail 80; throw "msiexec /i (5.1.2 custom dir) failed: $($p.ExitCode)" } $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade-custom.log" @@ -941,8 +950,40 @@ jobs: if (-not (Select-String -Path upgrade-custom.log -Pattern "passed explicitly" -Quiet)) { Get-Content upgrade-custom.log -Tail 60; throw "expected the explicit-OPENDJ guidance message in the log" } if (-not (Test-Path "C:\opendj-custom\setup.bat")) { throw "the refused upgrade damaged the original install" } Write-Host "Upgrade refused with guidance, original install untouched (exit $($p.ExitCode))" - $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x opendj-5.1.2.msi /quiet /qn /norestart /l*v uninstall-custom.log" - if ($p.ExitCode -ne 0) { Get-Content uninstall-custom.log -Tail 80; throw "msiexec /x (5.1.2 cleanup) failed: $($p.ExitCode)" } + # ...and naming the directory makes the very same upgrade proceed. This is what + # a GUI administrator does by browsing to it in InstallDirDlg, which the refusal + # must leave reachable: it fires on the resolved directory, not on the absence + # of a command-line property. + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=C:\opendj-custom /quiet /qn /norestart /l*v upgrade-custom-ok.log" + if ($p.ExitCode -ne 0) { Get-Content upgrade-custom-ok.log -Tail 120; throw "upgrade with an explicit OPENDJ must succeed: $($p.ExitCode)" } + if (-not (Test-Path "C:\opendj-custom\lib\opendj_service.exe")) { throw "the upgrade did not land in C:\opendj-custom" } + if (Test-Path "C:\Program Files\OpenDJ") { throw "the upgrade installed into the default directory as well" } + Write-Host "Upgrade into the named directory succeeded" + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall-custom.log" + if ($p.ExitCode -ne 0) { Get-Content uninstall-custom.log -Tail 80; throw "msiexec /x (custom cleanup) failed: $($p.ExitCode)" } + Remove-Item -Recurse -Force "C:\opendj-custom" -ErrorAction SilentlyContinue + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue + - name: An upgrade that would relocate the installation must refuse + shell: pwsh + run: | + # Passing a different OPENDJ over a detected installation is not a move: + # RemoveExistingProducts would empty the old tree while the new one is installed + # elsewhere, stranding config/db/logs (and any service registration) behind. + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=C:\opendj-a /quiet /qn /norestart /l*v install-a.log" + if ($p.ExitCode -ne 0) { Get-Content install-a.log -Tail 80; throw "msiexec /i (C:\opendj-a) failed: $($p.ExitCode)" } + if (-not (Test-Path "C:\opendj-a\setup.bat")) { throw "install did not land in C:\opendj-a" } + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=C:\opendj-b /quiet /qn /norestart /l*v relocate.log" + if ($p.ExitCode -eq 0) { Get-Content relocate.log -Tail 120; throw "a relocating upgrade must be refused" } + if (-not (Select-String -Path relocate.log -Pattern "cannot move an existing installation" -Quiet)) { Get-Content relocate.log -Tail 60; throw "expected the relocation guidance message in the log" } + if (-not (Test-Path "C:\opendj-a\setup.bat")) { throw "the refused relocation damaged the original install" } + if (Test-Path "C:\opendj-b") { throw "the refused relocation still created C:\opendj-b" } + Write-Host "Relocating upgrade refused, original install untouched (exit $($p.ExitCode))" + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall-a.log" + if ($p.ExitCode -ne 0) { Get-Content uninstall-a.log -Tail 80; throw "msiexec /x (C:\opendj-a cleanup) failed: $($p.ExitCode)" } + Remove-Item -Recurse -Force "C:\opendj-a" -ErrorAction SilentlyContinue + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue - name: Fresh install must not touch a service registered by another instance shell: pwsh run: | 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 410081bfd5..b4aad44455 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 @@ -261,7 +261,7 @@ Before starting this procedure, follow the steps in xref:#before-you-upgrade["Be . Back up the file-system directory where OpenDJ is installed. -. Install the newer package (GUI or silent). The installer detects the existing installation — the location recorded in the registry by a previous x64 package, or the default directory of the older 32-bit package (`C:\Program Files (x86)\OpenDJ`) — and installs into the same directory, so your configured instance data (`config`, `db`, `logs`) is kept and only the program files are replaced. If the older server was installed in a custom directory the installer cannot detect, select that directory in the GUI or pass it explicitly; a silent upgrade refuses to continue when it cannot determine the existing location, rather than installing into the default directory: +. Install the newer package (GUI or silent). The installer detects the existing installation — the location recorded in the registry by a previous x64 package, or the default directory of the older 32-bit package (`C:\Program Files (x86)\OpenDJ`) — and installs into the same directory, so your configured instance data (`config`, `db`, `logs`) is kept and only the program files are replaced. If the older server was installed in a custom directory the installer cannot detect, select that directory in the wizard or pass it explicitly on the command line; rather than installing a fresh server into the default directory while emptying the old one, the installer refuses to continue when the directory it resolved is the default and no server is installed there. It also refuses to install into a directory other than the detected one: the installer replaces an installation in place and cannot move one, so uninstall the existing server first if you want it somewhere else. + [source, console, subs="attributes"] diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 544bfd6e46..230780942a 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -62,6 +62,20 @@ + + + + + + + + + + + - + + + + + Error="An existing OpenDJ installation was detected, but its location could not be determined. Run the installer again and select the existing installation directory, or pass it explicitly: msiexec /i opendj.msi OPENDJ="C:\path\to\opendj""/> + diff --git a/opendj-server-legacy/src/build-tools/windows/service.c b/opendj-server-legacy/src/build-tools/windows/service.c index d84f4dcd25..11a76f6358 100644 --- a/opendj-server-legacy/src/build-tools/windows/service.c +++ b/opendj-server-legacy/src/build-tools/windows/service.c @@ -2441,6 +2441,17 @@ int serviceState() returnCode = 0; debug("Service '%s' is enabled.", serviceName); } + else if (code == SERVICE_LIST_UNAVAILABLE) + { + // The SCM could not be enumerated, so whether a service is registered + // is simply unknown. Reporting "disabled" here would make the callers + // act on a lie: the uninstaller would skip disabling a registered + // service, the control panel would offer to enable one that already + // exists, and isRunningAsWindowsService would return false, letting + // stop-ds kill the JVM behind the SCM's back. + returnCode = 2; + debug("Could not determine the state of the service: no service list."); + } else { returnCode = 1; From 1cf5a88546231e017621a577fc440ccefe1d330a Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Wed, 12 Aug 2026 09:02:47 +0300 Subject: [PATCH 41/52] Close the gaps the seventh review found in the upgrade guards and their tests Two of the new CI assertions could not pass. The refusal scenario grepped for "passed explicitly" while the installer says "pass it explicitly"; it now matches on the condition the message states rather than the instruction it gives. The relocation scenario reinstalled the same MSI over itself, which is maintenance mode - FindRelatedProducts does not run there, so WIX_UPGRADE_DETECTED was never set and the guard could not fire; it now installs the released 5.1.2 package first and exercises both branches of the guard, recorded location and legacy directory. NOT Installed is true during a major upgrade too, so the legacy-directory fallback fired on a leftover empty directory: the new tree landed there while RemoveExistingProducts emptied the real installation elsewhere. During an upgrade the directory now has to hold a server; a fresh install still adopts an empty one. Covered by a new scenario. RefuseRelocatingUpgrade compared with a two-way substring test, which admitted C:\opendj\v2 over a recorded C:\opendj - the relocation it exists to stop. It compares directories for equality now, with the legacy side built from ProgramFilesFolder so both sides carry the trailing backslash. test-msi started the service straight after stop-ds.bat; a zero exit code there does not mean the JVM released the lock (#768). Wait-ServerStopped moves to .github/scripts so both jobs share one copy. The launcher commit in Package/Deploy runs before the Maven deploy, the package uploads and the wiki push, so a lost push race would have cost all of them: it retries, then warns and lets the job continue. release-msi restores the Maven cache instead of saving it, so its dependency-less generated pom cannot reach the shared key. --- .github/scripts/wait-server-stopped.ps1 | 38 ++++++++ .github/workflows/build.yml | 93 +++++++++++++------ .github/workflows/deploy.yml | 35 ++++--- .github/workflows/release.yml | 6 +- .../resources/msi/package.wxs | 36 +++++-- .../src/build-tools/windows/service.c | 11 ++- 6 files changed, 164 insertions(+), 55 deletions(-) create mode 100644 .github/scripts/wait-server-stopped.ps1 diff --git a/.github/scripts/wait-server-stopped.ps1 b/.github/scripts/wait-server-stopped.ps1 new file mode 100644 index 0000000000..870533a6f2 --- /dev/null +++ b/.github/scripts/wait-server-stopped.ps1 @@ -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. + +# Verify a stop took effect before moving on: wait until the server releases the exclusive +# byte-range lock it holds on locks\server.lock. Checking the exit code of stop-ds is not a +# substitute - #768 was exactly the case where winlauncher.exe reported success without +# having stopped the server - and starting the service on a lock the old JVM still holds +# fails in ways that look like flakiness. +# +# The explicit Lock(0, 1) probe is required: a byte-range lock does not prevent opening the +# file, so a bare Open() would always succeed. +# +# Dot-source this file to use it: . .github\scripts\wait-server-stopped.ps1 + +function Wait-ServerStopped($lockFile) { + # Callers pass either a workspace-relative path (the zip build) or an absolute one (an + # installed tree), so only resolve the relative ones. + if (-not [System.IO.Path]::IsPathRooted($lockFile)) { $lockFile = Join-Path $PWD $lockFile } + for ($i = 0; $i -lt 30; $i++) { + if (-not (Test-Path $lockFile)) { return } + try { + $fs = [System.IO.File]::Open($lockFile, 'Open', 'ReadWrite', 'ReadWrite') + try { $fs.Lock(0, 1); $fs.Unlock(0, 1); return } finally { $fs.Close() } + } catch { Start-Sleep -Seconds 2 } + } + throw "The server still holds the lock on ${lockFile}: the stop did not take effect" +} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index af07b3eb97..81cd59dd55 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -331,21 +331,7 @@ jobs: - name: Test on Windows if: runner.os == 'Windows' run: | - # Verify a stop took effect before moving on: wait until the server - # releases the exclusive byte-range lock it holds on locks\server.lock. - # The explicit Lock(0, 1) probe is required: a byte-range lock does not - # prevent opening the file, so a bare Open() would always succeed. - function Wait-ServerStopped($lockFile) { - $lockFile = Join-Path $PWD $lockFile - for ($i = 0; $i -lt 30; $i++) { - if (-not (Test-Path $lockFile)) { return } - try { - $fs = [System.IO.File]::Open($lockFile, 'Open', 'ReadWrite', 'ReadWrite') - try { $fs.Lock(0, 1); $fs.Unlock(0, 1); return } finally { $fs.Close() } - } catch { Start-Sleep -Seconds 2 } - } - throw "The server still holds the lock on ${lockFile}: the stop did not take effect" - } + . .github\scripts\wait-server-stopped.ps1 set OPENDJ_JAVA_ARGS="-server -Xmx512m" opendj-server-legacy\target\package\opendj\setup.bat -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --sampleData 5000 --cli --acceptLicense --no-prompt opendj-server-legacy\target\package\opendj\bat\status.bat --hostname localhost --bindDN "cn=Directory Manager" --bindPassword password --trustAll @@ -697,6 +683,9 @@ jobs: needs: build-maven runs-on: 'windows-latest' steps: + # Only for .github/scripts/wait-server-stopped.ps1, and it has to come first: + # checkout cleans the workspace the artifact is unpacked into. + - uses: actions/checkout@v6 - name: Download artifacts uses: actions/download-artifact@v8 with: @@ -747,6 +736,10 @@ jobs: if ($LASTEXITCODE -ne 0) { throw "ldapsearch failed: $LASTEXITCODE" } & "$root\bat\stop-ds.bat" if ($LASTEXITCODE -ne 0) { throw "stop-ds.bat failed: $LASTEXITCODE" } + # A zero exit code from stop-ds does not mean the JVM let go of the lock (#768), + # and the next step registers and starts the service against this same instance. + . .github\scripts\wait-server-stopped.ps1 + Wait-ServerStopped "$root\locks\server.lock" - name: Enable, start, stop and disable the Windows service shell: pwsh run: | @@ -947,7 +940,9 @@ jobs: if ($p.ExitCode -ne 0) { Get-Content install-custom.log -Tail 80; throw "msiexec /i (5.1.2 custom dir) failed: $($p.ExitCode)" } $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade-custom.log" if ($p.ExitCode -eq 0) { Get-Content upgrade-custom.log -Tail 80; throw "upgrade without OPENDJ must refuse when the old location cannot be determined" } - if (-not (Select-String -Path upgrade-custom.log -Pattern "passed explicitly" -Quiet)) { Get-Content upgrade-custom.log -Tail 60; throw "expected the explicit-OPENDJ guidance message in the log" } + # Match on the part of the message that states the condition, not on the + # instruction: the wording of the guidance has already been reworded once. + if (-not (Select-String -Path upgrade-custom.log -Pattern "location could not be determined" -Quiet)) { Get-Content upgrade-custom.log -Tail 60; throw "expected the explicit-OPENDJ guidance message in the log" } if (-not (Test-Path "C:\opendj-custom\setup.bat")) { throw "the refused upgrade damaged the original install" } Write-Host "Upgrade refused with guidance, original install untouched (exit $($p.ExitCode))" # ...and naming the directory makes the very same upgrade proceed. This is what @@ -963,26 +958,68 @@ jobs: if ($p.ExitCode -ne 0) { Get-Content uninstall-custom.log -Tail 80; throw "msiexec /x (custom cleanup) failed: $($p.ExitCode)" } Remove-Item -Recurse -Force "C:\opendj-custom" -ErrorAction SilentlyContinue Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue + - name: An empty legacy directory must not be adopted during an upgrade + shell: pwsh + run: | + # NOT Installed holds during a major upgrade too, so the legacy-directory + # fallback used to fire on a leftover EMPTY Program Files (x86)\OpenDJ: the new + # tree would land there while RemoveExistingProducts emptied the real install + # somewhere else. During an upgrade the directory must prove it holds a server. + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart OPENDJ=C:\opendj-old /l*v install-old-custom.log" + if ($p.ExitCode -ne 0) { Get-Content install-old-custom.log -Tail 80; throw "msiexec /i (5.1.2 at C:\opendj-old) failed: $($p.ExitCode)" } + New-Item -ItemType Directory -Force "C:\Program Files (x86)\OpenDJ" | Out-Null + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade-emptylegacy.log" + if ($p.ExitCode -eq 0) { Get-Content upgrade-emptylegacy.log -Tail 120; throw "an upgrade with no determinable location must be refused, not routed to an empty legacy directory" } + if (Test-Path "C:\Program Files (x86)\OpenDJ\setup.bat") { throw "the upgrade installed into the empty legacy directory" } + if (-not (Test-Path "C:\opendj-old\setup.bat")) { throw "the refused upgrade damaged the original install" } + Write-Host "Empty legacy directory not adopted, upgrade refused (exit $($p.ExitCode))" + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x opendj-5.1.2.msi /quiet /qn /norestart /l*v uninstall-old-custom.log" + if ($p.ExitCode -ne 0) { Get-Content uninstall-old-custom.log -Tail 80; throw "msiexec /x (5.1.2 cleanup) failed: $($p.ExitCode)" } + Remove-Item -Recurse -Force "C:\opendj-old" -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue - name: An upgrade that would relocate the installation must refuse shell: pwsh run: | # Passing a different OPENDJ over a detected installation is not a move: # RemoveExistingProducts would empty the old tree while the new one is installed # elsewhere, stranding config/db/logs (and any service registration) behind. + # + # The older package has to be a different ProductCode for this to be an upgrade + # at all: reinstalling this very MSI over itself is maintenance mode, where + # FindRelatedProducts does not run, so WIX_UPGRADE_DETECTED would never be set + # and the guard could not fire. Hence the released 5.1.2 package, installed at + # its native legacy default so both branches of the guard have something to + # compare against. $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName - Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue - $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=C:\opendj-a /quiet /qn /norestart /l*v install-a.log" - if ($p.ExitCode -ne 0) { Get-Content install-a.log -Tail 80; throw "msiexec /i (C:\opendj-a) failed: $($p.ExitCode)" } - if (-not (Test-Path "C:\opendj-a\setup.bat")) { throw "install did not land in C:\opendj-a" } - $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=C:\opendj-b /quiet /qn /norestart /l*v relocate.log" - if ($p.ExitCode -eq 0) { Get-Content relocate.log -Tail 120; throw "a relocating upgrade must be refused" } - if (-not (Select-String -Path relocate.log -Pattern "cannot move an existing installation" -Quiet)) { Get-Content relocate.log -Tail 60; throw "expected the relocation guidance message in the log" } - if (-not (Test-Path "C:\opendj-a\setup.bat")) { throw "the refused relocation damaged the original install" } + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files\OpenDJ" -ErrorAction SilentlyContinue + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart /l*v install-old-legacy.log" + if ($p.ExitCode -ne 0) { Get-Content install-old-legacy.log -Tail 80; throw "msiexec /i (5.1.2) failed: $($p.ExitCode)" } + if (-not (Test-Path "C:\Program Files (x86)\OpenDJ\setup.bat")) { throw "5.1.2 did not install into the legacy default" } + # (a) the recorded-location branch: a host that came through a 5.2.0-or-later + # package has its install directory in the registry. + New-Item -Path HKLM:\SOFTWARE\OpenDJ -Force | Out-Null + Set-ItemProperty -Path HKLM:\SOFTWARE\OpenDJ -Name InstallDir -Value 'C:\Program Files (x86)\OpenDJ\' + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=C:\opendj-b /quiet /qn /norestart /l*v relocate-reg.log" + if ($p.ExitCode -eq 0) { Get-Content relocate-reg.log -Tail 120; throw "a relocating upgrade must be refused (recorded location)" } + if (-not (Select-String -Path relocate-reg.log -Pattern "cannot move an existing installation" -Quiet)) { Get-Content relocate-reg.log -Tail 60; throw "expected the relocation guidance message in the log" } + if (Test-Path "C:\opendj-b") { throw "the refused relocation still created C:\opendj-b" } + # (b) the legacy-directory branch: no registry value, the old install proven by + # the setup.bat in the legacy default. + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=C:\opendj-b /quiet /qn /norestart /l*v relocate-legacy.log" + if ($p.ExitCode -eq 0) { Get-Content relocate-legacy.log -Tail 120; throw "a relocating upgrade must be refused (legacy directory)" } + if (-not (Select-String -Path relocate-legacy.log -Pattern "cannot move an existing installation" -Quiet)) { Get-Content relocate-legacy.log -Tail 60; throw "expected the relocation guidance message in the log" } if (Test-Path "C:\opendj-b") { throw "the refused relocation still created C:\opendj-b" } - Write-Host "Relocating upgrade refused, original install untouched (exit $($p.ExitCode))" - $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall-a.log" - if ($p.ExitCode -ne 0) { Get-Content uninstall-a.log -Tail 80; throw "msiexec /x (C:\opendj-a cleanup) failed: $($p.ExitCode)" } - Remove-Item -Recurse -Force "C:\opendj-a" -ErrorAction SilentlyContinue + if (-not (Test-Path "C:\Program Files (x86)\OpenDJ\setup.bat")) { throw "the refused relocation damaged the original install" } + Write-Host "Relocating upgrade refused on both branches, original install untouched" + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x opendj-5.1.2.msi /quiet /qn /norestart /l*v uninstall-old-legacy.log" + if ($p.ExitCode -ne 0) { Get-Content uninstall-old-legacy.log -Tail 80; throw "msiexec /x (5.1.2 cleanup) failed: $($p.ExitCode)" } + Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue - name: Fresh install must not touch a service registered by another instance shell: pwsh diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 6816427693..f852185a15 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -110,17 +110,30 @@ jobs: git commit --quiet \ -m "Refresh the Windows native launchers" \ -m "Rebuilt from opendj-server-legacy/src/build-tools/windows for ${HEAD_SHA} by the Build workflow (run ${RUN_ID})." - # The checkout is of the branch, which may have moved on since the Build run: - # rebase onto its current tip. An identical refresh already there leaves an empty - # commit that rebase drops, and the push then has nothing to send. - git fetch --quiet origin "$BRANCH" - if ! git rebase --quiet FETCH_HEAD; then - git rebase --abort || true - echo "::error title=Could not refresh the launcher binaries::$BRANCH moved on and the rebuilt launchers conflict with it. Refresh opendj-server-legacy/lib/*.exe from the windows-exe-11 artifact of Build run ${RUN_ID} and commit them." - exit 1 - fi - git push --quiet origin "HEAD:refs/heads/$BRANCH" - echo "Refreshed launchers pushed to $BRANCH." + # The checkout is of the branch, which may have moved on since the Build run, and + # it can move again while we push: rebase onto the current tip and retry. An + # identical refresh already there leaves an empty commit that rebase drops, and + # the push then has nothing to send. + # + # This step runs before the Maven deploy, the package uploads and the wiki push, + # so it must not be the thing that costs them: a refresh that cannot be landed + # warns and lets the job carry on. The next push to this branch retries it, and + # nothing downstream depends on the committed binaries being current - the Build + # run that produced them compiled its own. + for attempt in 1 2 3; do + git fetch --quiet origin "$BRANCH" + if ! git rebase --quiet FETCH_HEAD; then + git rebase --abort || true + echo "::warning title=Could not refresh the launcher binaries::$BRANCH moved on and the rebuilt launchers conflict with it. Refresh opendj-server-legacy/lib/*.exe from the windows-exe-11 artifact of Build run ${RUN_ID} and commit them." + exit 0 + fi + if git push --quiet origin "HEAD:refs/heads/$BRANCH"; then + echo "Refreshed launchers pushed to $BRANCH." + exit 0 + fi + echo "$BRANCH moved while pushing - retrying ($attempt/3)." + done + echo "::warning title=Could not refresh the launcher binaries::$BRANCH kept moving under this job. Refresh opendj-server-legacy/lib/*.exe from the windows-exe-11 artifact of Build run ${RUN_ID} and commit them." - name: Set up Java for publishing to Maven Central Repository OSS uses: actions/setup-java@v5 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a291377b0b..ced2358746 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -183,8 +183,12 @@ jobs: with: java-version: '11' distribution: 'temurin' + # restore, not the full cache action: the install:install-file below puts a + # dependency-less generated pom for opendj-server-legacy into the local repository, + # and saving that under the key build-maven restores from would seed every later + # Windows build with it. - name: Cache Maven packages - uses: actions/cache@v5 + uses: actions/cache/restore@v5 with: path: ~/.m2/repository key: ${{ runner.os }}-m2-repository-${{ hashFiles('**/pom.xml') }} diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 230780942a..b9934df66f 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -63,9 +63,10 @@
+ rather than merely exist. OPENDJ_LEGACY above stays a bare existence test only + because a fresh install may legitimately adopt an empty legacy directory; every + decision taken during an upgrade uses these instead, since "the directory is + there" says nothing about where the product being upgraded lives. --> @@ -103,9 +104,15 @@ + + Condition="NOT Installed AND OPENDJ_LEGACY AND NOT OPENDJ AND (NOT WIX_UPGRADE_DETECTED OR OPENDJ_LEGACY_INSTALL)"/> @@ -119,6 +126,10 @@ [Directory] references inside string literals, SetProperty does. --> + + + server - and the requested one is not the same directory. Plain equality, not a + substring test: a two-way "one contains the other" would tolerate the trailing + backslash but also admit C:\opendj\v2 over a recorded C:\opendj, which is the very + relocation being guarded against. Both sides carry the backslash by construction - + CostFinalize resolves OPENDJ as a directory property, the registry value is the + resolved [OPENDJ] this package wrote, and the legacy side is built above rather + than read from a search. A hand-edited registry value without one is the accepted + residual: it refuses, and the message says what to do. When OPENDJ is not given at + all, the SetProperty actions above have already set it to the known location, so + the comparison passes and nothing fires. --> + Condition="WIX_UPGRADE_DETECTED AND ((OPENDJ_REG AND (OPENDJ_REG ~<> OPENDJ)) OR (NOT OPENDJ_REG AND OPENDJ_LEGACY_INSTALL AND (OPENDJ_LEGACY_DEFAULT ~<> OPENDJ)))"/> Date: Wed, 12 Aug 2026 09:15:43 +0300 Subject: [PATCH 42/52] State the Package/Deploy trust boundary in the job condition The job checks out the ref of the run that triggered it, and the workflow_run branches filter matches that run's head branch NAME - which a fork can also call master. What keeps the ref trusted is event == 'push': a Build run for a pull request carries event 'pull_request', and a push to a fork runs the fork's own workflows rather than this repository's. Check head_repository as well so the boundary is written down instead of re-derived, and so relaxing the event condition later cannot quietly open it. CodeQL flags the checkout (actions/untrusted-checkout, alert 1262) on the pattern rather than on the conditions, so it will keep flagging it; the alert is a false positive for this configuration. --- .github/workflows/deploy.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f852185a15..817e29f140 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -34,7 +34,14 @@ permissions: jobs: package-deploy-maven: - if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event=='push'}} + # head_repository states the trust boundary instead of leaving it to be re-derived. + # The checkout below takes its ref from the triggering run, and the branches filter + # above matches that run's head branch NAME - which a fork can also call master. What + # actually keeps the ref trusted is event=='push': a Build run for a pull request + # carries event 'pull_request', and a push to a fork runs the fork's own workflows, + # never ours. The repository check makes that explicit for the next reader, and for + # the next person tempted to relax the event condition. + if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push' && github.event.workflow_run.head_repository.full_name == github.repository }} runs-on: 'ubuntu-latest' steps: - name: Print github context From 90c427153adfad681fd90c053e4f2456358acea8 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Wed, 12 Aug 2026 11:30:50 +0300 Subject: [PATCH 43/52] Close the two silent-failure defects the eighth review found in the upgrade guards CheckServiceStopped sampled the SCM once and accepted every state that was not Running, so a stop that had not taken effect - StopPending after an administrator's own 'net stop', StartPending for the five and a half minutes service.c allows a start - waved the upgrade through under a running JVM. The jars are unversioned, so the delete-on-reboot entries the nested uninstall leaves behind name the paths the new jars occupy. The action now polls: gone or Stopped passes, StopPending is waited out for 90 s, anything else refuses immediately. RequireDirOnCustomUpgrade stood down whenever a setup.bat existed in the x64 default directory, which any unrelated OpenDJ tree provides. A 5.1.x in a custom directory recorded nothing, so RemoveExistingProducts gutted it while InstallFiles landed on the stranger, at exit code 0. The guard now keys on "nothing recorded a location", with an explicitly named directory as the way through for an old server that really does live in the default one: OpendjDirGiven is read before AppSearch and sequenced "first", so the wizard keeps its refusal. The same decoy in the legacy default directory stays undetectable - the signal that would separate it does not exist for a registry-less 5.1.x - and is documented in the install guide instead. test-msi and test-msi-upgrade no longer wait for the whole build matrix. They need one artifact, published by the Windows leg after about fifteen minutes; waiting for the two-hour ubuntu legs is what let five consecutive pushes cancel them before they ran. Also: guard the launcher-refresh fetch in deploy.yml so a transient failure cannot skip the deploy, stop reporting a push that was a no-op, catch only IOException while waiting for the server lock, assert the guard message in the empty-legacy scenario, make the relocation scenario clear its own starting state, and sparse-checkout the one script test-msi needs. --- .github/scripts/wait-server-stopped.ps1 | 6 +- .github/workflows/build.yml | 180 +++++++++++++++++- .github/workflows/deploy.yml | 19 +- .../asciidoc/install-guide/chap-upgrade.adoc | 9 +- .../resources/msi/package.wxs | 86 +++++++-- .../src/build-tools/windows/service.c | 6 +- 6 files changed, 278 insertions(+), 28 deletions(-) diff --git a/.github/scripts/wait-server-stopped.ps1 b/.github/scripts/wait-server-stopped.ps1 index 870533a6f2..9e7814a89d 100644 --- a/.github/scripts/wait-server-stopped.ps1 +++ b/.github/scripts/wait-server-stopped.ps1 @@ -29,10 +29,14 @@ function Wait-ServerStopped($lockFile) { if (-not [System.IO.Path]::IsPathRooted($lockFile)) { $lockFile = Join-Path $PWD $lockFile } for ($i = 0; $i -lt 30; $i++) { if (-not (Test-Path $lockFile)) { return } + # IOException only - that is what both a held byte-range lock and a sharing + # violation raise. A blanket catch would also swallow UnauthorizedAccessException, + # spin out the full minute on a permissions problem under Program Files and then + # report a lock that was never held; let anything else surface with its own message. try { $fs = [System.IO.File]::Open($lockFile, 'Open', 'ReadWrite', 'ReadWrite') try { $fs.Lock(0, 1); $fs.Unlock(0, 1); return } finally { $fs.Close() } - } catch { Start-Sleep -Seconds 2 } + } catch [System.IO.IOException] { Start-Sleep -Seconds 2 } } throw "The server still holds the lock on ${lockFile}: the stop did not take effect" } diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 81cd59dd55..d4ea3e074b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -680,12 +680,46 @@ jobs: retention-days: 90 test-msi: - needs: build-maven + # Deliberately not "needs: build-maven": that waits for the whole matrix, whose ubuntu + # legs run for about two hours, so any push landing inside that window cancels the run + # before this two-minute job has started - which is how the MSI work reached its eighth + # review round with no completed run behind it. The only input is the windows-latest-11 + # artifact, published by the Windows leg after about fifteen minutes; wait for that. runs-on: 'windows-latest' + permissions: + contents: read + # Listing the run's artifacts and jobs, which the wait below polls. + actions: read steps: # Only for .github/scripts/wait-server-stopped.ps1, and it has to come first: - # checkout cleans the workspace the artifact is unpacked into. + # checkout cleans the workspace the artifact is unpacked into. Sparse because that + # one script is the entire reason for the checkout. - uses: actions/checkout@v6 + with: + sparse-checkout: .github/scripts + - name: Wait for the Windows build artifact + shell: pwsh + env: + GH_TOKEN: ${{ github.token }} + run: | + $deadline = (Get-Date).AddMinutes(45) + do { + $names = @(gh api "repos/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID/artifacts" --jq '.artifacts[].name') + if ($names -contains 'windows-latest-11') { Write-Host 'windows-latest-11 is available'; exit 0 } + # Stop waiting the moment the leg that would publish it has finished without + # doing so, instead of sitting out the deadline. The job name is matched here + # rather than inside the jq filter: an argument carrying both spaces and + # double quotes has to survive PowerShell's native-command quoting to reach + # jq intact, and there is no reason to depend on that. + $legs = @(gh api "repos/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID/jobs?per_page=100" --jq '.jobs[] | [.name, .conclusion] | @tsv') + $leg = $legs | Where-Object { $_ -like 'build-maven (windows-latest, 11)*' } | Select-Object -First 1 + if ($leg) { + $conclusion = ($leg -split "`t")[1] + if ($conclusion) { throw "the Windows build leg finished as '$conclusion' without publishing windows-latest-11" } + } + Start-Sleep -Seconds 30 + } while ((Get-Date) -lt $deadline) + throw 'windows-latest-11 was not published within 45 minutes' - name: Download artifacts uses: actions/download-artifact@v8 with: @@ -788,9 +822,30 @@ jobs: # instance data in place, stops the running service for the file replacement and leaves # its registration alone, and that the upgraded server starts with the old data. test-msi-upgrade: - needs: build-maven + # Not "needs: build-maven", for the reason given on test-msi above. runs-on: 'windows-latest' + permissions: + contents: read + actions: read steps: + - name: Wait for the Windows build artifact + shell: pwsh + env: + GH_TOKEN: ${{ github.token }} + run: | + $deadline = (Get-Date).AddMinutes(45) + do { + $names = @(gh api "repos/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID/artifacts" --jq '.artifacts[].name') + if ($names -contains 'windows-latest-11') { Write-Host 'windows-latest-11 is available'; exit 0 } + $legs = @(gh api "repos/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID/jobs?per_page=100" --jq '.jobs[] | [.name, .conclusion] | @tsv') + $leg = $legs | Where-Object { $_ -like 'build-maven (windows-latest, 11)*' } | Select-Object -First 1 + if ($leg) { + $conclusion = ($leg -split "`t")[1] + if ($conclusion) { throw "the Windows build leg finished as '$conclusion' without publishing windows-latest-11" } + } + Start-Sleep -Seconds 30 + } while ((Get-Date) -lt $deadline) + throw 'windows-latest-11 was not published within 45 minutes' - name: Download artifacts uses: actions/download-artifact@v8 with: @@ -974,6 +1029,9 @@ jobs: New-Item -ItemType Directory -Force "C:\Program Files (x86)\OpenDJ" | Out-Null $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade-emptylegacy.log" if ($p.ExitCode -eq 0) { Get-Content upgrade-emptylegacy.log -Tail 120; throw "an upgrade with no determinable location must be refused, not routed to an empty legacy directory" } + # A non-zero exit code on its own only says msiexec failed; both neighbouring + # scenarios name the guard they are about, and so must this one. + if (-not (Select-String -Path upgrade-emptylegacy.log -Pattern "location could not be determined" -Quiet)) { Get-Content upgrade-emptylegacy.log -Tail 60; throw "expected the explicit-OPENDJ guidance message in the log" } if (Test-Path "C:\Program Files (x86)\OpenDJ\setup.bat") { throw "the upgrade installed into the empty legacy directory" } if (-not (Test-Path "C:\opendj-old\setup.bat")) { throw "the refused upgrade damaged the original install" } Write-Host "Empty legacy directory not adopted, upgrade refused (exit $($p.ExitCode))" @@ -995,8 +1053,13 @@ jobs: # its native legacy default so both branches of the guard have something to # compare against. $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + # Clear every location this scenario reasons about itself, rather than inheriting + # the previous step's teardown: the starting state is what the guard is judged + # against, so it belongs in the step that makes the judgement. Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue Remove-Item -Recurse -Force "C:\Program Files\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\opendj-b" -ErrorAction SilentlyContinue $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart /l*v install-old-legacy.log" if ($p.ExitCode -ne 0) { Get-Content install-old-legacy.log -Tail 80; throw "msiexec /i (5.1.2) failed: $($p.ExitCode)" } if (-not (Test-Path "C:\Program Files (x86)\OpenDJ\setup.bat")) { throw "5.1.2 did not install into the legacy default" } @@ -1021,6 +1084,65 @@ jobs: if ($p.ExitCode -ne 0) { Get-Content uninstall-old-legacy.log -Tail 80; throw "msiexec /x (5.1.2 cleanup) failed: $($p.ExitCode)" } Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue + - name: A stray OpenDJ tree in the default directory must not be adopted + shell: pwsh + run: | + # The product being upgraded is a 5.1.x in a custom directory, which recorded + # nothing, while some unrelated OpenDJ tree - a zip install, a copy - sits in the + # x64 default. A setup.bat existence test cannot tell the two apart, so a guard + # keyed on it stood down: RemoveExistingProducts gutted the real installation + # while InstallFiles landed on the stranger, and msiexec exited 0. + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files\OpenDJ" -ErrorAction SilentlyContinue + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart OPENDJ=C:\opendj-real /l*v install-old-real.log" + if ($p.ExitCode -ne 0) { Get-Content install-old-real.log -Tail 80; throw "msiexec /i (5.1.2 at C:\opendj-real) failed: $($p.ExitCode)" } + # The decoy: everything the installer is able to ask about a directory. + New-Item -ItemType Directory -Force "C:\Program Files\OpenDJ\lib" | Out-Null + Set-Content "C:\Program Files\OpenDJ\setup.bat" '@echo off' + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade-decoy.log" + if ($p.ExitCode -eq 0) { Get-Content upgrade-decoy.log -Tail 120; throw "an upgrade must not adopt a stray tree in the default directory" } + if (-not (Select-String -Path upgrade-decoy.log -Pattern "location could not be determined" -Quiet)) { Get-Content upgrade-decoy.log -Tail 60; throw "expected the explicit-OPENDJ guidance message in the log" } + if (Test-Path "C:\Program Files\OpenDJ\lib\opendj_service.exe") { throw "the refused upgrade installed into the stray tree" } + if (-not (Test-Path "C:\opendj-real\setup.bat")) { throw "the refused upgrade damaged the original install" } + # ...and naming the real directory gets the administrator through, decoy or not. + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=C:\opendj-real /quiet /qn /norestart /l*v upgrade-decoy-ok.log" + if ($p.ExitCode -ne 0) { Get-Content upgrade-decoy-ok.log -Tail 120; throw "upgrade with an explicit OPENDJ must succeed: $($p.ExitCode)" } + if (-not (Test-Path "C:\opendj-real\lib\opendj_service.exe")) { throw "the upgrade did not land in C:\opendj-real" } + if (Test-Path "C:\Program Files\OpenDJ\lib\opendj_service.exe") { throw "the upgrade also installed into the stray tree" } + Write-Host "Stray default-directory tree ignored: refused, then upgraded where told" + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall-real.log" + if ($p.ExitCode -ne 0) { Get-Content uninstall-real.log -Tail 80; throw "msiexec /x (decoy cleanup) failed: $($p.ExitCode)" } + Remove-Item -Recurse -Force "C:\opendj-real" -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue + - name: An old server in the default directory upgrades once it is named + shell: pwsh + run: | + # The price of the scenario above: a 5.1.x that really does live in the x64 + # default recorded nothing either, so the package cannot tell it from the decoy + # and refuses the silent upgrade that would have gone through before. What it + # must not do is dead-end - the directory is a configurable property, and naming + # it (which is also what browsing to it in the wizard amounts to) has to work. + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files\OpenDJ" -ErrorAction SilentlyContinue + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart OPENDJ=`"C:\Program Files\OpenDJ`" /l*v install-old-x64.log" + if ($p.ExitCode -ne 0) { Get-Content install-old-x64.log -Tail 80; throw "msiexec /i (5.1.2 at the x64 default) failed: $($p.ExitCode)" } + if (-not (Test-Path "C:\Program Files\OpenDJ\setup.bat")) { throw "5.1.2 did not install into C:\Program Files\OpenDJ" } + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade-x64-silent.log" + if ($p.ExitCode -eq 0) { Get-Content upgrade-x64-silent.log -Tail 120; throw "a silent upgrade with nothing recording the location must refuse" } + if (-not (Select-String -Path upgrade-x64-silent.log -Pattern "location could not be determined" -Quiet)) { Get-Content upgrade-x64-silent.log -Tail 60; throw "expected the explicit-OPENDJ guidance message in the log" } + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=`"C:\Program Files\OpenDJ`" /quiet /qn /norestart /l*v upgrade-x64-named.log" + if ($p.ExitCode -ne 0) { Get-Content upgrade-x64-named.log -Tail 120; throw "the named upgrade into the default directory must succeed: $($p.ExitCode)" } + if (-not (Test-Path "C:\Program Files\OpenDJ\lib\opendj_service.exe")) { throw "the upgrade did not land in C:\Program Files\OpenDJ" } + Write-Host "Default-directory upgrade refused silently, accepted when named" + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall-x64.log" + if ($p.ExitCode -ne 0) { Get-Content uninstall-x64.log -Tail 80; throw "msiexec /x (x64 default cleanup) failed: $($p.ExitCode)" } + Remove-Item -Recurse -Force "C:\Program Files\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue - name: Fresh install must not touch a service registered by another instance shell: pwsh run: | @@ -1041,3 +1163,55 @@ jobs: $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall-elsewhere.log" if ($p.ExitCode -ne 0) { Get-Content uninstall-elsewhere.log -Tail 80; throw "msiexec /x (elsewhere cleanup) failed: $($p.ExitCode)" } Write-Host "Fresh install elsewhere left the unrelated 'OpenDJ Server' service in place" + - name: An upgrade must refuse while the service is still starting + shell: pwsh + run: | + # The SCM takes no controls in a pending state: StopServiceBeforeUpgrade's + # 'net stop' fails instantly with ERROR_SERVICE_CANNOT_ACCEPT_CTRL and + # Return="ignore" eats it. StartPending is not 'Running', so a check that + # sampled the state once waved the upgrade through with a JVM coming up on the + # tree being replaced - and the jars are unversioned, so the delete-on-reboot + # entries left behind by the nested uninstall name the paths the NEW jars + # occupy. Reproducible because the wrapper reports START_PENDING for as long as + # bat\start-ds.bat runs, which service.c gives 300 s. + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files\OpenDJ" -ErrorAction SilentlyContinue + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart /l*v install-old-pending.log" + if ($p.ExitCode -ne 0) { Get-Content install-old-pending.log -Tail 80; throw "msiexec /i (5.1.2) failed: $($p.ExitCode)" } + $root = "C:\Program Files (x86)\OpenDJ" + $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" + & "$root\setup.bat" -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --addBaseEntry --cli --acceptLicense --no-prompt --doNotStart + if ($LASTEXITCODE -ne 0) { throw "setup.bat (5.1.2) failed: $LASTEXITCODE" } + & "$root\bat\windows-service.bat" --enableService + if ($LASTEXITCODE -ne 0) { throw "windows-service --enableService failed: $LASTEXITCODE" } + # Hold the start open: the wrapper waits for this script, reporting START_PENDING + # the whole time. No JVM is needed - the guard is being asked about a service + # state, not about a lock. + Copy-Item "$root\bat\start-ds.bat" "$root\bat\start-ds.bat.orig" + Set-Content "$root\bat\start-ds.bat" "@echo off`r`nping -n 240 127.0.0.1 >nul" + sc.exe start "OpenDJ Server" | Out-Null + for ($i = 0; $i -lt 15; $i++) { + $st = (Get-Service "OpenDJ Server" -ErrorAction SilentlyContinue).Status + if ($st -eq 'StartPending') { break } + Start-Sleep -Seconds 1 + } + $st = (Get-Service "OpenDJ Server" -ErrorAction SilentlyContinue).Status + if ($st -ne 'StartPending') { throw "expected the service to be StartPending, got '$st'" } + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade-pending.log" + if ($p.ExitCode -eq 0) { Get-Content upgrade-pending.log -Tail 120; throw "the upgrade must refuse while the service is starting" } + if (-not (Select-String -Path upgrade-pending.log -Pattern "CheckServiceStopped" -Quiet)) { Get-Content upgrade-pending.log -Tail 60; throw "the refusal must come from CheckServiceStopped" } + if (-not (Test-Path "$root\config\config.ldif")) { throw "the refused upgrade damaged the instance" } + if (-not (Test-Path "$root\setup.bat")) { throw "the refused upgrade damaged the installation" } + Write-Host "Upgrade refused while the service was StartPending (exit $($p.ExitCode))" + # Teardown: the wrapper is still sitting on the held-open start. + Stop-Process -Name opendj_service -Force -ErrorAction SilentlyContinue + Get-Process -Name PING -ErrorAction SilentlyContinue | Stop-Process -Force + Start-Sleep -Seconds 5 + Move-Item -Force "$root\bat\start-ds.bat.orig" "$root\bat\start-ds.bat" + & "$root\bat\windows-service.bat" --disableService + if (Get-Service "OpenDJ Server" -ErrorAction SilentlyContinue) { sc.exe delete "OpenDJ Server" } + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x opendj-5.1.2.msi /quiet /qn /norestart /l*v uninstall-pending.log" + if ($p.ExitCode -ne 0) { Get-Content uninstall-pending.log -Tail 80; throw "msiexec /x (5.1.2 cleanup) failed: $($p.ExitCode)" } + Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 817e29f140..2195c7e14f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -128,14 +128,29 @@ jobs: # nothing downstream depends on the committed binaries being current - the Build # run that produced them compiled its own. for attempt in 1 2 3; do - git fetch --quiet origin "$BRANCH" + # Guarded like everything else in this block: bare, it is the one command left + # that could still take the job down with it. The step runs under set -e with + # no continue-on-error, so a transient fetch failure would skip the Maven + # deploy, all eight artifact uploads, the MSI attachment and both documentation + # pushes over a refresh that is allowed to fail. + if ! git fetch --quiet origin "$BRANCH"; then + echo "::warning title=Could not refresh the launcher binaries::$BRANCH could not be fetched. Refresh opendj-server-legacy/lib/*.exe from the windows-exe-11 artifact of Build run ${RUN_ID} and commit them." + exit 0 + fi if ! git rebase --quiet FETCH_HEAD; then git rebase --abort || true echo "::warning title=Could not refresh the launcher binaries::$BRANCH moved on and the rebuilt launchers conflict with it. Refresh opendj-server-legacy/lib/*.exe from the windows-exe-11 artifact of Build run ${RUN_ID} and commit them." exit 0 fi if git push --quiet origin "HEAD:refs/heads/$BRANCH"; then - echo "Refreshed launchers pushed to $BRANCH." + # A refresh that already landed leaves the rebase with nothing to replay and + # the push with nothing to send, both of them silently successful: report + # what happened rather than claiming a push that was a no-op. + if [ "$(git rev-parse HEAD)" = "$(git rev-parse FETCH_HEAD)" ]; then + echo "The launchers committed on $BRANCH already match the rebuilt ones." + else + echo "Refreshed launchers pushed to $BRANCH." + fi exit 0 fi echo "$BRANCH moved while pushing - retrying ($attempt/3)." 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 b4aad44455..83b5dc5460 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 @@ -257,11 +257,11 @@ $ ==== Before starting this procedure, follow the steps in xref:#before-you-upgrade["Before You Upgrade"]. Installing the newer `.msi` performs a major upgrade that replaces the installed program files, so make a full file-system backup of the current installation first. -. Stop the current OpenDJ server; if it runs as a Windows service, stop the service with `net stop "OpenDJ Server"` from an elevated prompt. The installer also tries to stop it, but only succeeds when it is itself running elevated: started by double-click, it cannot, and refuses the upgrade with Windows Installer error 1722 naming the `CheckServiceStopped` action rather than replacing the files under a running server. +. Stop the current OpenDJ server; if it runs as a Windows service, stop the service with `net stop "OpenDJ Server"` from an elevated prompt and let the command finish. The installer also tries to stop it, but only succeeds when it is itself running elevated: started by double-click, it cannot, and refuses the upgrade with Windows Installer error 1722 naming the `CheckServiceStopped` action rather than replacing the files under a running server. It refuses in the same way while the service is still starting, and gives a stop that is already under way 90 seconds to complete. . Back up the file-system directory where OpenDJ is installed. -. Install the newer package (GUI or silent). The installer detects the existing installation — the location recorded in the registry by a previous x64 package, or the default directory of the older 32-bit package (`C:\Program Files (x86)\OpenDJ`) — and installs into the same directory, so your configured instance data (`config`, `db`, `logs`) is kept and only the program files are replaced. If the older server was installed in a custom directory the installer cannot detect, select that directory in the wizard or pass it explicitly on the command line; rather than installing a fresh server into the default directory while emptying the old one, the installer refuses to continue when the directory it resolved is the default and no server is installed there. It also refuses to install into a directory other than the detected one: the installer replaces an installation in place and cannot move one, so uninstall the existing server first if you want it somewhere else. +. Install the newer package (GUI or silent). The installer detects the existing installation — the location recorded in the registry by a previous x64 package, or the default directory of the older 32-bit package (`C:\Program Files (x86)\OpenDJ`) — and installs into the same directory, so your configured instance data (`config`, `db`, `logs`) is kept and only the program files are replaced. If the older server was installed in a custom directory the installer cannot detect, select that directory in the wizard or pass it explicitly on the command line: rather than installing a fresh server into the default directory while emptying the old one, the installer refuses to continue whenever it falls back to the default directory with nothing having recorded where the old server lives. That refusal also covers an old server that really is installed in `C:\Program Files\OpenDJ`, because the 32-bit packages recorded no location at all; name the directory and the same upgrade proceeds. The installer further refuses to install into a directory other than the detected one: it replaces an installation in place and cannot move one, so uninstall the existing server first if you want it somewhere else. + [source, console, subs="attributes"] @@ -269,6 +269,11 @@ Before starting this procedure, follow the steps in xref:#before-you-upgrade["Be C:\> msiexec /i opendj-{opendj-version}.msi /quiet OPENDJ="C:\path\to\opendj" ---- + +[NOTE] +====== +Pass `OPENDJ` explicitly whenever an unrelated OpenDJ directory tree — a Zip installation, a copy, a decommissioned instance — sits in `C:\Program Files (x86)\OpenDJ` while the server you are upgrading lives somewhere else and was installed by a package that recorded no location (5.1.x and earlier). Detection can only ask whether that directory holds a server, not which server, so it adopts the stray tree: the upgrade then replaces the files there while removing the installation you meant to upgrade. +====== ++ A registered Windows service survives the upgrade untouched: it names the service wrapper inside the installation directory, which the upgrade replaces in place, so the registration — including a dedicated service account, recovery actions or dependencies you configured — keeps working against the refreshed server. No `--disableService`/`--enableService` cycle is needed. . Run the `upgrade` command, described in xref:../reference/admin-tools-ref.adoc#upgrade-1[upgrade(1)] in the __Reference__, to bring the configuration and application data up to date with the new binary and script files: diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index b9934df66f..712a5d4196 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -62,16 +62,12 @@ - - - - - - + @@ -102,6 +98,25 @@ Name="ImagePath" Type="raw"/> + + + Condition="WIX_UPGRADE_DETECTED AND (OPENDJ ~= OPENDJ_DEFAULT) AND NOT OPENDJ_REG AND NOT OpendjDirGiven"/> Date: Wed, 12 Aug 2026 13:52:21 +0300 Subject: [PATCH 44/52] Keep Restart Manager from restarting the service the upgrade stopped RM maps the JVM holding lib\*.jar to the "OpenDJ Server" service at InstallValidate, stops it before StopServiceBeforeUpgrade runs, and restarts it at the end of the install: the upgraded server comes up against instance data upgrade.bat has not migrated, and the post-upgrade state the package promises - registered but Stopped - is broken (test-msi-upgrade caught it as StartPending). RM also disarms the starting-service refusal by stopping a StartPending service before CheckServiceStopped samples it. /norestart only suppresses reboots, so disable RM for this package: the service holder is handled deterministically by the custom actions, and any other holder falls back to the WiX3-era in-use behaviour. --- .../opendj-msi-standard/resources/msi/package.wxs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 712a5d4196..8727e5afa0 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -242,6 +242,20 @@ ImagePath evidence alone: any upgrade over a tree whose service is running has the locking problem, whether the installed product came from a WiX3-era package or from this one. --> + + From ff54e5fa378b35526b3f48546494cd7ef515d15b Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Wed, 12 Aug 2026 14:56:06 +0300 Subject: [PATCH 45/52] Stop asking a 32-bit MSI to install into the 64-bit Program Files The "old server in the default directory" scenario arranged itself with msiexec /i opendj-5.1.2.msi OPENDJ="C:\Program Files\OpenDJ", which cannot work: Windows Installer resolves a 32-bit package's [ProgramFilesFolder] to Program Files (x86) whatever the directory property says, so msiexec exited 0 while the files landed in the legacy default and the step failed on its own precondition - silently, because the verbose log is dumped only when msiexec itself reports a failure. Install 5.1.2 into a custom directory and move the tree instead. That leaves exactly what the scenario is about: an upgradable 5.1.x registration, no recorded location, no legacy directory, and a real old server sitting in C:\Program Files\OpenDJ. The registration left pointing at the emptied directory costs nothing - no guard reads it, and RemoveExistingProducts tolerates the files being gone. The assertions had to move with it. 5.1.x ships lib\opendj_service.exe itself, so its presence no longer separates the new payload from the old tree: both halves are now judged on what only the new package produces - the wrapper's content and the InstallDir registry value - and the named upgrade additionally proves that the one OPENDJ value in this workflow carrying spaces reaches the elevated server context intact. A precondition msiexec accepts and then ignores now prints the log and both Program Files directories. --- .github/workflows/build.yml | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d4ea3e074b..5534288ba8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1125,23 +1125,51 @@ jobs: # and refuses the silent upgrade that would have gone through before. What it # must not do is dead-end - the directory is a configurable property, and naming # it (which is also what browsing to it in the wizard amounts to) has to work. + # + # The old tree gets there by hand rather than through OPENDJ=: the released + # 5.1.x package is x86, and a 32-bit package cannot install into the 64-bit + # Program Files at all - Windows Installer resolves its [ProgramFilesFolder] to + # Program Files (x86) whatever the directory property says, so msiexec exits 0 + # while the files land in the legacy default, which is a different scenario (one + # the legacy-directory search resolves on its own). Installing into a custom + # directory and moving the tree leaves exactly what this one needs: an + # upgradable 5.1.x registration, no recorded location, no legacy directory, and + # a real old server sitting in C:\Program Files\OpenDJ. That the registration is + # left pointing at the directory the move emptied costs nothing - no guard reads + # it, and RemoveExistingProducts tolerates the files being gone. $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue Remove-Item -Recurse -Force "C:\Program Files\OpenDJ" -ErrorAction SilentlyContinue - $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart OPENDJ=`"C:\Program Files\OpenDJ`" /l*v install-old-x64.log" - if ($p.ExitCode -ne 0) { Get-Content install-old-x64.log -Tail 80; throw "msiexec /i (5.1.2 at the x64 default) failed: $($p.ExitCode)" } - if (-not (Test-Path "C:\Program Files\OpenDJ\setup.bat")) { throw "5.1.2 did not install into C:\Program Files\OpenDJ" } + Remove-Item -Recurse -Force "C:\opendj-x64src" -ErrorAction SilentlyContinue + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart OPENDJ=C:\opendj-x64src /l*v install-old-x64.log" + if ($p.ExitCode -ne 0) { Get-Content install-old-x64.log -Tail 80; throw "msiexec /i (5.1.2 at C:\opendj-x64src) failed: $($p.ExitCode)" } + # Exit code 0 says msiexec ran, not that it put the files where it was told, and + # a directory it silently declined to use is worth naming in the failure. + if (-not (Test-Path "C:\opendj-x64src\setup.bat")) { Get-ChildItem "C:\Program Files\OpenDJ","C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue | Select-Object -First 5 -ExpandProperty FullName; Get-Content install-old-x64.log -Tail 80; throw "5.1.2 did not install into C:\opendj-x64src" } + Move-Item "C:\opendj-x64src" "C:\Program Files\OpenDJ" + if (-not (Test-Path "C:\Program Files\OpenDJ\setup.bat")) { throw "the 5.1.2 tree did not move into C:\Program Files\OpenDJ" } + # 5.1.x ships lib\opendj_service.exe itself, so the file cannot say whose tree + # this is; its content can. Both halves below are judged on the two things only + # the new package produces: this payload, and the InstallDir registry value. + $oldWrapper = (Get-FileHash "C:\Program Files\OpenDJ\lib\opendj_service.exe").Hash $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade-x64-silent.log" if ($p.ExitCode -eq 0) { Get-Content upgrade-x64-silent.log -Tail 120; throw "a silent upgrade with nothing recording the location must refuse" } if (-not (Select-String -Path upgrade-x64-silent.log -Pattern "location could not be determined" -Quiet)) { Get-Content upgrade-x64-silent.log -Tail 60; throw "expected the explicit-OPENDJ guidance message in the log" } + if (Test-Path HKLM:\SOFTWARE\OpenDJ) { throw "the refused upgrade registered an install location" } + if ((Get-FileHash "C:\Program Files\OpenDJ\lib\opendj_service.exe").Hash -ne $oldWrapper) { throw "the refused upgrade overwrote the old server" } $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=`"C:\Program Files\OpenDJ`" /quiet /qn /norestart /l*v upgrade-x64-named.log" if ($p.ExitCode -ne 0) { Get-Content upgrade-x64-named.log -Tail 120; throw "the named upgrade into the default directory must succeed: $($p.ExitCode)" } - if (-not (Test-Path "C:\Program Files\OpenDJ\lib\opendj_service.exe")) { throw "the upgrade did not land in C:\Program Files\OpenDJ" } + if ((Get-FileHash "C:\Program Files\OpenDJ\lib\opendj_service.exe").Hash -eq $oldWrapper) { Get-Content upgrade-x64-named.log -Tail 120; throw "the upgrade did not land in C:\Program Files\OpenDJ" } + # The only OPENDJ in this workflow whose value carries spaces: what the package + # recorded proves it survived the command line and the elevation intact. + $recorded = (Get-ItemProperty -Path HKLM:\SOFTWARE\OpenDJ -Name InstallDir -ErrorAction SilentlyContinue).InstallDir + if ($recorded -notlike "C:\Program Files\OpenDJ*") { throw "the upgrade recorded '$recorded', not the directory it was told to use" } Write-Host "Default-directory upgrade refused silently, accepted when named" $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall-x64.log" if ($p.ExitCode -ne 0) { Get-Content uninstall-x64.log -Tail 80; throw "msiexec /x (x64 default cleanup) failed: $($p.ExitCode)" } Remove-Item -Recurse -Force "C:\Program Files\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\opendj-x64src" -ErrorAction SilentlyContinue Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue - name: Fresh install must not touch a service registered by another instance shell: pwsh From 99a0116285da6bc848d0ecb11cc287ac3e058f71 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Wed, 12 Aug 2026 18:37:22 +0300 Subject: [PATCH 46/52] Close the ninth review round: relocation guard, in-use detection, CI gate RefuseRelocatingUpgrade's legacy branch refused the workaround its own comment and the install guide prescribe: with a stray OpenDJ tree in the legacy default directory, naming the real one - the documented way past a decoy the searches cannot tell from the product being upgraded - read as a relocation, so that installation had no upgrade path at all, silent or named. The branch now makes an exception for a named directory that holds a server (OpendjDirGiven AND OpendjGivenInstall, a new setup.bat search on the command-line value of OPENDJ). Naming an empty directory is still a relocation and still refused, and the registry branch is untouched. Restart Manager was disabled outright, which disabled its detection with it, leaving a server started by start-ds.bat - the mode this package ships, since it registers no service - with nothing watching the jars it holds: the legacy in-use scan only finds windowed applications. DisableShutdown keeps the detection and leaves the shutting down to us, and a new CheckServerNotRunning refuses the upgrade while the byte-range lock on locks\server.lock is held, in /quiet too, where no FilesInUse dialog can appear. The MSI jobs waited 45 minutes for an artifact whose leg is queued as well as run - in run 31578978374 it appeared at +52 minutes, so both would have failed a healthy build - and each held a windows-latest runner from t=0 doing it. The wait becomes one ubuntu gate job they depend on, which retires the duplicated block as well. RequireDirOnCustomUpgrade promised a wizard route that cannot exist: OpendjDirGiven is read before AppSearch and InstallDirDlg never sets it, so an old server in the x64 default can only be named on the command line. The message, the comments and the install guide say so now. openScm tested scm instead of *scm, so a failed OpenSCManager was never reported (pre-existing; the error still surfaced from the NULL handle, without the message). CI covers both new behaviours: a decoy in the legacy default with the real 5.1.x elsewhere, and an upgrade over a running non-service server. --- .github/workflows/build.yml | 187 +++++++++++++----- .../asciidoc/install-guide/chap-upgrade.adoc | 6 +- .../resources/msi/package.wxs | 152 +++++++++++--- .../src/build-tools/windows/service.c | 6 +- 4 files changed, 268 insertions(+), 83 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5534288ba8..fbfabe23e2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -679,17 +679,62 @@ jobs: if-no-files-found: warn retention-days: 90 - test-msi: - # Deliberately not "needs: build-maven": that waits for the whole matrix, whose ubuntu - # legs run for about two hours, so any push landing inside that window cancels the run - # before this two-minute job has started - which is how the MSI work reached its eighth - # review round with no completed run behind it. The only input is the windows-latest-11 - # artifact, published by the Windows leg after about fifteen minutes; wait for that. - runs-on: 'windows-latest' + # The gate both MSI jobs wait on. Deliberately not "needs: build-maven": that waits for + # the whole matrix, whose ubuntu legs run for about two hours, so any push landing inside + # that window cancels the run before those two-minute jobs have started - which is how the + # MSI work reached its eighth review round with no completed run behind it. The only input + # they have is the windows-latest-11 artifact, so wait for exactly that. + # + # On ubuntu, and in a job of its own, for two reasons. A waiter on windows-latest holds a + # Windows runner from t=0 for the whole wait, competing for the capacity the leg it is + # waiting for needs - in run 31578978374 the windows-latest-11 leg sat in the queue for 38 + # minutes while windows-latest-26 started within one. And the wait was duplicated + # verbatim in both jobs, with a 45-minute budget measured from t=0 that covered the leg's + # runtime but not its queue time: in that same run the artifact appeared at +52 minutes, + # so both jobs would have failed a perfectly healthy build. + wait-msi-artifact: + runs-on: 'ubuntu-latest' + # Well past any queue seen so far, and only reached if the Windows leg neither publishes + # nor finishes; the usual exits are the artifact appearing or the leg failing. + timeout-minutes: 130 permissions: contents: read # Listing the run's artifacts and jobs, which the wait below polls. actions: read + steps: + - name: Wait for the Windows build artifact + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + deadline=$(( $(date +%s) + 120 * 60 )) + while true; do + if gh api "repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/artifacts" \ + --jq '.artifacts[].name' | grep -qx 'windows-latest-11'; then + echo 'windows-latest-11 is available' + exit 0 + fi + # Stop waiting the moment the leg that would publish it has finished without + # doing so, instead of sitting out the deadline. + # || true: a transient API error is a reason to poll again, not to fail the run. + conclusion=$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/jobs?per_page=100" \ + --jq '.jobs[] | select(.name | startswith("build-maven (windows-latest, 11)")) | .conclusion' || true) + if [ -n "$conclusion" ] && [ "$conclusion" != "null" ]; then + echo "the Windows build leg finished as '$conclusion' without publishing windows-latest-11" >&2 + exit 1 + fi + if [ "$(date +%s)" -ge "$deadline" ]; then + echo 'windows-latest-11 was not published within 120 minutes' >&2 + exit 1 + fi + sleep 30 + done + + test-msi: + needs: wait-msi-artifact + runs-on: 'windows-latest' + permissions: + contents: read steps: # Only for .github/scripts/wait-server-stopped.ps1, and it has to come first: # checkout cleans the workspace the artifact is unpacked into. Sparse because that @@ -697,29 +742,6 @@ jobs: - uses: actions/checkout@v6 with: sparse-checkout: .github/scripts - - name: Wait for the Windows build artifact - shell: pwsh - env: - GH_TOKEN: ${{ github.token }} - run: | - $deadline = (Get-Date).AddMinutes(45) - do { - $names = @(gh api "repos/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID/artifacts" --jq '.artifacts[].name') - if ($names -contains 'windows-latest-11') { Write-Host 'windows-latest-11 is available'; exit 0 } - # Stop waiting the moment the leg that would publish it has finished without - # doing so, instead of sitting out the deadline. The job name is matched here - # rather than inside the jq filter: an argument carrying both spaces and - # double quotes has to survive PowerShell's native-command quoting to reach - # jq intact, and there is no reason to depend on that. - $legs = @(gh api "repos/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID/jobs?per_page=100" --jq '.jobs[] | [.name, .conclusion] | @tsv') - $leg = $legs | Where-Object { $_ -like 'build-maven (windows-latest, 11)*' } | Select-Object -First 1 - if ($leg) { - $conclusion = ($leg -split "`t")[1] - if ($conclusion) { throw "the Windows build leg finished as '$conclusion' without publishing windows-latest-11" } - } - Start-Sleep -Seconds 30 - } while ((Get-Date) -lt $deadline) - throw 'windows-latest-11 was not published within 45 minutes' - name: Download artifacts uses: actions/download-artifact@v8 with: @@ -822,30 +844,11 @@ jobs: # instance data in place, stops the running service for the file replacement and leaves # its registration alone, and that the upgraded server starts with the old data. test-msi-upgrade: - # Not "needs: build-maven", for the reason given on test-msi above. + needs: wait-msi-artifact runs-on: 'windows-latest' permissions: contents: read - actions: read steps: - - name: Wait for the Windows build artifact - shell: pwsh - env: - GH_TOKEN: ${{ github.token }} - run: | - $deadline = (Get-Date).AddMinutes(45) - do { - $names = @(gh api "repos/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID/artifacts" --jq '.artifacts[].name') - if ($names -contains 'windows-latest-11') { Write-Host 'windows-latest-11 is available'; exit 0 } - $legs = @(gh api "repos/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID/jobs?per_page=100" --jq '.jobs[] | [.name, .conclusion] | @tsv') - $leg = $legs | Where-Object { $_ -like 'build-maven (windows-latest, 11)*' } | Select-Object -First 1 - if ($leg) { - $conclusion = ($leg -split "`t")[1] - if ($conclusion) { throw "the Windows build leg finished as '$conclusion' without publishing windows-latest-11" } - } - Start-Sleep -Seconds 30 - } while ((Get-Date) -lt $deadline) - throw 'windows-latest-11 was not published within 45 minutes' - name: Download artifacts uses: actions/download-artifact@v8 with: @@ -1243,3 +1246,87 @@ jobs: $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x opendj-5.1.2.msi /quiet /qn /norestart /l*v uninstall-pending.log" if ($p.ExitCode -ne 0) { Get-Content uninstall-pending.log -Tail 80; throw "msiexec /x (5.1.2 cleanup) failed: $($p.ExitCode)" } Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue + - name: A decoy in the legacy default must not block the documented workaround + shell: pwsh + run: | + # The mirror of "a stray OpenDJ tree in the default directory must not be adopted", + # with the stray tree in the LEGACY default instead - where the install guide says + # to pass OPENDJ, and where the relocation guard used to refuse that very command: + # the legacy directory holds A server, the named directory is not it, refuse. The + # installation then had no upgrade path at all, silent or named. + # Both halves are asserted here, because the exception that fixes it is narrow: the + # named directory has to hold a server. Naming an empty one is still a relocation. + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\opendj-b" -ErrorAction SilentlyContinue + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart OPENDJ=C:\opendj-mine /l*v install-old-mine.log" + if ($p.ExitCode -ne 0) { Get-Content install-old-mine.log -Tail 80; throw "msiexec /i (5.1.2 at C:\opendj-mine) failed: $($p.ExitCode)" } + if (-not (Test-Path "C:\opendj-mine\setup.bat")) { Get-Content install-old-mine.log -Tail 80; throw "5.1.2 did not install into C:\opendj-mine" } + # The decoy: a zip installation, a copy, a decommissioned instance - anything a + # setup.bat search cannot tell from the product being upgraded. + New-Item -ItemType Directory -Force "C:\Program Files (x86)\OpenDJ\lib" | Out-Null + Set-Content "C:\Program Files (x86)\OpenDJ\setup.bat" '@echo off' + # Naming a directory that holds no server is still a relocation, decoy or not. + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=C:\opendj-b /quiet /qn /norestart /l*v relocate-decoy.log" + if ($p.ExitCode -eq 0) { Get-Content relocate-decoy.log -Tail 120; throw "naming an empty directory is a relocation and must be refused" } + if (-not (Select-String -Path relocate-decoy.log -Pattern "cannot move an existing installation" -Quiet)) { Get-Content relocate-decoy.log -Tail 60; throw "expected the relocation guidance message in the log" } + if (Test-Path "C:\opendj-b") { throw "the refused relocation still created C:\opendj-b" } + # ...and naming the real one is the workaround the install guide prescribes. + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=C:\opendj-mine /quiet /qn /norestart /l*v upgrade-mine.log" + if ($p.ExitCode -ne 0) { Get-Content upgrade-mine.log -Tail 120; throw "the documented workaround must upgrade the named installation: $($p.ExitCode)" } + if (-not (Test-Path "C:\opendj-mine\lib\opendj_service.exe")) { throw "the upgrade did not land in C:\opendj-mine" } + if (Test-Path "C:\Program Files (x86)\OpenDJ\lib\opendj_service.exe") { throw "the upgrade also installed into the decoy" } + Write-Host "Legacy-default decoy: empty target refused, named installation upgraded" + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall-mine.log" + if ($p.ExitCode -ne 0) { Get-Content uninstall-mine.log -Tail 80; throw "msiexec /x (decoy cleanup) failed: $($p.ExitCode)" } + Remove-Item -Recurse -Force "C:\opendj-mine" -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue + - name: An upgrade must refuse while a server runs without a service + shell: pwsh + run: | + # The mode this package ships by default: setup registers no service, so the + # server started by bat\start-ds.bat is a plain JVM holding lib\*.jar. There is no + # service key for the ImagePath-gated pair to match, and Restart Manager is not + # allowed to shut anything down, so CheckServerNotRunning - the byte-range lock on + # locks\server.lock - is the only thing standing between a running server and + # RemoveExistingProducts renaming its jars into delete-on-reboot entries. + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force "C:\Program Files\OpenDJ" -ErrorAction SilentlyContinue + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i opendj-5.1.2.msi /quiet /qn /norestart /l*v install-old-running.log" + if ($p.ExitCode -ne 0) { Get-Content install-old-running.log -Tail 80; throw "msiexec /i (5.1.2) failed: $($p.ExitCode)" } + $root = "C:\Program Files (x86)\OpenDJ" + $env:OPENDJ_JAVA_ARGS = "-server -Xmx512m" + & "$root\setup.bat" -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --addBaseEntry --cli --acceptLicense --no-prompt --doNotStart + if ($LASTEXITCODE -ne 0) { throw "setup.bat (5.1.2) failed: $LASTEXITCODE" } + & "$root\bat\start-ds.bat" + if ($LASTEXITCODE -ne 0) { throw "start-ds.bat failed: $LASTEXITCODE" } + for ($i=0; $i -lt 12; $i++) { try { $c = New-Object System.Net.Sockets.TcpClient('localhost', 1636); $c.Close(); break } catch { Start-Sleep -Seconds 5 } } + if (Get-Service "OpenDJ Server" -ErrorAction SilentlyContinue) { throw "this scenario is about a server with NO service registered" } + # The headline auto-detected upgrade, which would otherwise proceed straight into + # the running server's tree. + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade-running.log" + if ($p.ExitCode -eq 0) { Get-Content upgrade-running.log -Tail 120; throw "the upgrade must refuse while a server is running out of the tree" } + if (-not (Select-String -Path upgrade-running.log -Pattern "CheckServerNotRunning" -Quiet)) { Get-Content upgrade-running.log -Tail 60; throw "the refusal must come from CheckServerNotRunning" } + if (-not (Test-Path "$root\config\config.ldif")) { throw "the refused upgrade damaged the instance" } + & "$root\bat\ldapsearch.bat" --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1 + if ($LASTEXITCODE -ne 0) { throw "the refused upgrade disturbed the running server" } + Write-Host "Upgrade refused while a non-service server was running (exit $($p.ExitCode))" + # Stopping it makes the very same upgrade proceed - and the 60 s grace inside the + # check is what absorbs the gap between stop-ds returning and the JVM releasing + # the lock, so no wait is needed here to keep this half honest. + & "$root\bat\stop-ds.bat" + if ($LASTEXITCODE -ne 0) { throw "stop-ds.bat failed: $LASTEXITCODE" } + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade-stopped.log" + if ($p.ExitCode -ne 0) { Get-Content upgrade-stopped.log -Tail 120; throw "the upgrade must proceed once the server is stopped: $($p.ExitCode)" } + if (-not (Test-Path "$root\lib\opendj_service.exe")) { throw "the upgrade did not land in $root" } + if (-not (Test-Path "$root\config\config.ldif")) { throw "the upgrade lost the instance data" } + Write-Host "The same upgrade proceeded once the server was stopped" + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/x `"$msi`" /quiet /qn /norestart /l*v uninstall-running.log" + if ($p.ExitCode -ne 0) { Get-Content uninstall-running.log -Tail 80; throw "msiexec /x (running-server cleanup) failed: $($p.ExitCode)" } + Remove-Item -Recurse -Force "C:\Program Files (x86)\OpenDJ" -ErrorAction SilentlyContinue + Remove-Item -Path HKLM:\SOFTWARE\OpenDJ -Recurse -Force -ErrorAction SilentlyContinue 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 83b5dc5460..98bcda0752 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 @@ -258,10 +258,12 @@ $ Before starting this procedure, follow the steps in xref:#before-you-upgrade["Before You Upgrade"]. Installing the newer `.msi` performs a major upgrade that replaces the installed program files, so make a full file-system backup of the current installation first. . Stop the current OpenDJ server; if it runs as a Windows service, stop the service with `net stop "OpenDJ Server"` from an elevated prompt and let the command finish. The installer also tries to stop it, but only succeeds when it is itself running elevated: started by double-click, it cannot, and refuses the upgrade with Windows Installer error 1722 naming the `CheckServiceStopped` action rather than replacing the files under a running server. It refuses in the same way while the service is still starting, and gives a stop that is already under way 90 seconds to complete. ++ +A server started with `start-ds.bat` rather than as a service is refused in the same way, by the `CheckServerNotRunning` action: it holds the same program files, and the installer will not replace them underneath it. Stop it with `stop-ds.bat` and let the command finish. The check allows 60 seconds for a stop that is already under way, because a stop command returning is not the same as the server having released its files. . Back up the file-system directory where OpenDJ is installed. -. Install the newer package (GUI or silent). The installer detects the existing installation — the location recorded in the registry by a previous x64 package, or the default directory of the older 32-bit package (`C:\Program Files (x86)\OpenDJ`) — and installs into the same directory, so your configured instance data (`config`, `db`, `logs`) is kept and only the program files are replaced. If the older server was installed in a custom directory the installer cannot detect, select that directory in the wizard or pass it explicitly on the command line: rather than installing a fresh server into the default directory while emptying the old one, the installer refuses to continue whenever it falls back to the default directory with nothing having recorded where the old server lives. That refusal also covers an old server that really is installed in `C:\Program Files\OpenDJ`, because the 32-bit packages recorded no location at all; name the directory and the same upgrade proceeds. The installer further refuses to install into a directory other than the detected one: it replaces an installation in place and cannot move one, so uninstall the existing server first if you want it somewhere else. +. Install the newer package (GUI or silent). The installer detects the existing installation — the location recorded in the registry by a previous x64 package, or the default directory of the older 32-bit package (`C:\Program Files (x86)\OpenDJ`) — and installs into the same directory, so your configured instance data (`config`, `db`, `logs`) is kept and only the program files are replaced. If the older server was installed in a custom directory the installer cannot detect, select that directory in the wizard or pass it explicitly on the command line: rather than installing a fresh server into the default directory while emptying the old one, the installer refuses to continue whenever it falls back to the default directory with nothing having recorded where the old server lives. That refusal also covers an old server that really is installed in `C:\Program Files\OpenDJ`, because the 32-bit packages recorded no location at all — and that one case the wizard cannot resolve: choosing the default directory in the wizard leaves the installer with the same values it would have had if you had chosen nothing, so pass `OPENDJ` on the command line instead. The installer further refuses to install into a directory other than the detected one: it replaces an installation in place and cannot move one, so uninstall the existing server first if you want it somewhere else. + [source, console, subs="attributes"] @@ -271,7 +273,7 @@ C:\> msiexec /i opendj-{opendj-version}.msi /quiet OPENDJ="C:\path\to\opendj" + [NOTE] ====== -Pass `OPENDJ` explicitly whenever an unrelated OpenDJ directory tree — a Zip installation, a copy, a decommissioned instance — sits in `C:\Program Files (x86)\OpenDJ` while the server you are upgrading lives somewhere else and was installed by a package that recorded no location (5.1.x and earlier). Detection can only ask whether that directory holds a server, not which server, so it adopts the stray tree: the upgrade then replaces the files there while removing the installation you meant to upgrade. +Pass `OPENDJ` explicitly whenever an unrelated OpenDJ directory tree — a Zip installation, a copy, a decommissioned instance — sits in `C:\Program Files (x86)\OpenDJ` while the server you are upgrading lives somewhere else and was installed by a package that recorded no location (5.1.x and earlier). Detection can only ask whether that directory holds a server, not which server, so left to itself it adopts the stray tree: the upgrade then replaces the files there while removing the installation you meant to upgrade. Naming the directory settles it — the installer takes an explicitly named directory that holds a server as the one to upgrade, and only refuses the name if that directory holds no server, which is what relocating an installation looks like. ====== + A registered Windows service survives the upgrade untouched: it names the service wrapper inside the installation directory, which the upgrade replaces in place, so the registration — including a dedicated service account, recovery actions or dependencies you configured — keeps working against the refreshed server. No `--disableService`/`--enableService` cycle is needed. diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 8727e5afa0..a0b63e38f8 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -73,6 +73,27 @@ + + + + + + + the comparison passes and nothing fires. + + The legacy branch of (2) carries one exception, and it is the workaround the + residual of (1) prescribes: a named directory that HOLDS A SERVER is not a + relocation. Without it the two guards contradicted each other - the only way past + a decoy in the legacy default is to name the real directory, and naming it made + this branch refuse, leaving that installation with no upgrade path at all. The + exception is deliberately narrow: it needs both OpendjDirGiven (the directory came + from the command line, not from a search or a dialog) and OpendjGivenInstall + (a setup.bat is there). Naming an empty or new directory is still refused, which + is what a relocation looks like, so the case CI exercises - 5.1.x in the legacy + default, OPENDJ=C:\opendj-b - refuses exactly as before. It does NOT extend to the + registry branch: a location this package recorded is authoritative, and an + administrator who wants to move an installation it knows about can uninstall it + first. Residual: naming a directory that holds SOME OpenDJ tree while the product + being upgraded lives elsewhere now proceeds and strands that installation's data. + Directory evidence cannot tell the two apart at all, and between refusing the + documented workaround and trusting an explicit instruction, the explicit + instruction wins. --> + Error="An existing OpenDJ installation was detected, but its location could not be determined: 32-bit packages recorded none. Select the existing installation directory in the wizard, or pass it explicitly: msiexec /i opendj.msi OPENDJ="C:\path\to\opendj". If that installation is the default directory itself, the command line is the only way - the wizard cannot tell a confirmed default from an unchanged one."/> + Error="OpenDJ is already installed in a different directory, and this installer cannot move an existing installation: its configuration, database and logs would be left behind. Install into the existing directory, or uninstall the existing OpenDJ first. If the directory that was detected holds an unrelated OpenDJ tree - a Zip installation, a copy, a decommissioned instance - and the server you are upgrading is elsewhere, pass that server's directory on the command line: msiexec /i opendj.msi OPENDJ="C:\path\to\opendj"."/> - - + + + + + Condition="WIX_UPGRADE_DETECTED AND ((OPENDJ_REG AND (OPENDJ_REG ~<> OPENDJ)) OR (NOT OPENDJ_REG AND OPENDJ_LEGACY_INSTALL AND (OPENDJ_LEGACY_DEFAULT ~<> OPENDJ) AND NOT (OpendjDirGiven AND OpendjGivenInstall)))"/> - + + diff --git a/opendj-server-legacy/src/build-tools/windows/service.c b/opendj-server-legacy/src/build-tools/windows/service.c index 9add466b3a..60f4ef8fa2 100644 --- a/opendj-server-legacy/src/build-tools/windows/service.c +++ b/opendj-server-legacy/src/build-tools/windows/service.c @@ -143,7 +143,11 @@ ServiceReturnCode openScm(DWORD accessRights, SC_HANDLE *scm) NULL, // ServicesActive database accessRights // desired rights ); - if (scm == NULL) + // *scm, not scm: the latter is the address of the caller's variable and is never + // NULL, so the failure went unreported and callers saw SERVICE_RETURN_OK with a NULL + // handle. The outcome was still an error - EnumServicesStatus and friends reject the + // NULL handle - but one attributed to the wrong call and without this message. + if (*scm == NULL) { debugError("Failed to open the Service Control Manager. Last error = %d", GetLastError()); From 777b77334ad173ecea7d9e1275a66b85c4a5cc1e Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Wed, 12 Aug 2026 19:02:34 +0300 Subject: [PATCH 47/52] Make the named-directory search public, as WiX requires, without reopening it WIX0012: a property AppSearch fills cannot be private, so OpendjGivenInstall does not compile - which was the whole of the previous commit's answer to "a public property can be handed in on the command line and switch the guard off". OPENDJ_GIVEN_INSTALL is public, and the guard stops testing it for truth: the search sets it to the full path of the setup.bat it found, so requiring that path to contain the resolved OPENDJ is both the "a server is there" test and the reason OPENDJ_GIVEN_INSTALL=1 says nothing. A value spelled out as a path inside the named directory still passes - deliberate construction rather than a slip, and the comment says so. --- .../resources/msi/package.wxs | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index a0b63e38f8..2ebb8df162 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -85,11 +85,17 @@ fixed drive instead. That costs a handful of stat calls and cannot change a decision: every use of this property is paired with OpendjDirGiven, which is unset in exactly that case. - Private (mixed case) and not Secure, for the reason OpendjDirGiven is: a public - property survives the command line, so OpendjGivenInstall=1 next to a relocating - OPENDJ would switch the guard off - AppSearch only overwrites what it finds. Only - the client-side guard reads it, and private properties are visible there. --> - + Public, because a search property has to be (WIX0012: AppSearch cannot fill a + private one) - so unlike OpendjDirGiven it CAN be handed in on the command line, + and AppSearch only overwrites what it finds. The guard below therefore does not + test it for truth: it requires the value to be the setup.bat inside the directory + that was named (OPENDJ_GIVEN_INSTALL ~>< OPENDJ, the search sets it to the full + path of the file found). OPENDJ_GIVEN_INSTALL=1 no longer says anything. That + makes it not a switch rather than a lock - a value spelled out as the path inside + the named directory would still pass, which is deliberate construction rather + than a slip. Not Secure: only the client-side guard reads it, so it has no reason + to reach the elevated server process. --> + @@ -234,8 +240,11 @@ a decoy in the legacy default is to name the real directory, and naming it made this branch refuse, leaving that installation with no upgrade path at all. The exception is deliberately narrow: it needs both OpendjDirGiven (the directory came - from the command line, not from a search or a dialog) and OpendjGivenInstall - (a setup.bat is there). Naming an empty or new directory is still refused, which + from the command line, not from a search or a dialog) and a setup.bat found INSIDE + that directory (OPENDJ_GIVEN_INSTALL holds its full path, so requiring the path to + contain the resolved OPENDJ is both the "a server is there" test and the reason a + hand-passed OPENDJ_GIVEN_INSTALL cannot stand in for one). Naming an empty or new + directory is still refused, which is what a relocation looks like, so the case CI exercises - 5.1.x in the legacy default, OPENDJ=C:\opendj-b - refuses exactly as before. It does NOT extend to the registry branch: a location this package recorded is authoritative, and an @@ -353,7 +362,7 @@ + Condition="WIX_UPGRADE_DETECTED AND ((OPENDJ_REG AND (OPENDJ_REG ~<> OPENDJ)) OR (NOT OPENDJ_REG AND OPENDJ_LEGACY_INSTALL AND (OPENDJ_LEGACY_DEFAULT ~<> OPENDJ) AND NOT (OpendjDirGiven AND (OPENDJ_GIVEN_INSTALL ~>< OPENDJ))))"/> Date: Wed, 12 Aug 2026 19:53:55 +0300 Subject: [PATCH 48/52] Put Restart Manager back to Disable: DisableShutdown still restarts Measured, not reasoned. DisableShutdown was chosen to keep RM's detection - "The installer still uses the Restart Manager to detect files in use by applications" - on the reading that only the shutting down and the restarting were disabled. Run 31615584455 says otherwise: the headline upgrade scenario finished with the service StartPending after an otherwise successful install, so the installer restarts what the RM session listed at InstallValidate whether RM stopped it or CheckServiceStopped did. That is the failure the guards exist to prevent - the upgraded server coming up before upgrade.bat has migrated the instance data. So Disable, and the detection goes with it. CheckServerNotRunning is what replaces it and why the trade is affordable: the byte-range lock on locks\server.lock answers for both the service and the start-ds.bat modes, and answers in /quiet, where a FilesInUse dialog could not be shown. What stays uncovered is some other process holding payload files - the WiX3-era behaviour, now stated as the residual it is. --- .../resources/msi/package.wxs | 49 ++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 2ebb8df162..721891cf21 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -301,29 +301,32 @@ ImagePath evidence alone: any upgrade over a tree whose service is running has the locking problem, whether the installed product came from a WiX3-era package or from this one. --> - - + + From 59b75708cd40932f6d9910eb07ec52f12ace2726 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Thu, 13 Aug 2026 13:07:34 +0300 Subject: [PATCH 49/52] Make the upgrade guards able to refuse at all CheckServerNotRunning could not refuse anything: PowerShell wraps an exception thrown out of a .NET method or constructor in a MethodInvocationException, so the catch-all's $_.Exception.GetType().FullName -ne 'System.IO.IOException' test held for every exception, including the byte-range lock the action exists to detect - the exit 1 was unreachable. Use the typed catch wait-server-stopped.ps1 has always had, with the Formatted-field escapes ([\[] and [\]]) an ExeCommand needs so the type literal is not substituted away. The scenario covering it passed regardless: it asserted a non-zero exit code, which the fail-open outcome satisfies (3010, locked jars deferred to a reboot), and grepped for an action name the log carries whether the action refused or not. Assert the exact 1603, the action's "Return value 3", and that nothing was scheduled for delete-on-reboot; likewise for the StartPending scenario. OpendjDirGiven was private, and a private property set in the UI sequence never reaches the execute sequence, which is processed in the installer service rather than the client. Every full-UI session therefore read it as empty at the guards - including one started with OPENDJ= on the command line, the single route both the refusal message and the install guide prescribe - so the wizard refused the documented workaround and the relocation guard's exception could never apply. No scenario could see it: all 42 msiexec calls in build.yml are /qn. Replace it with a public, secure OPENDJ_GIVEN holding the named path, which the guards require the resolved OPENDJ to start with, so it is not a switch. Add a test-msi step that reads the built MSI: guard conditions may name only public properties, OPENDJ and OPENDJ_GIVEN must be secure, and CheckServerNotRunning's command, resolved the way msiexec resolves it, must exit 0 with no lock file, 0 with an unlocked one, and 1 while another process holds the lock. getServiceName's doc comment now names SERVICE_LIST_UNAVAILABLE, and the upgrade chapter notes that OPENDJ can be passed with or without /quiet. --- .github/workflows/build.yml | 126 +++++++++++- .../asciidoc/install-guide/chap-upgrade.adoc | 2 +- .../resources/msi/package.wxs | 180 ++++++++++++------ .../src/build-tools/windows/service.c | 6 +- 4 files changed, 247 insertions(+), 67 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fbfabe23e2..c96242b440 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -751,6 +751,94 @@ jobs: with: java-version: '25' distribution: 'zulu' + - name: The upgrade guards must hold up on their own + shell: pwsh + run: | + # Two things no install scenario can see, both of which have already gone wrong here. + # The first is what a guard is allowed to READ: the execute sequence is processed in + # the installer service, so a private property set in the UI sequence is empty by the + # time the guard evaluates - which inverts it in exactly the full-UI sessions that no + # /qn scenario runs. The second is the inline PowerShell itself: the scenarios reach + # it only through a ten-minute install and can then only look at msiexec's exit code, + # so a guard that always exits 0 looks the same as one that never has to refuse. + $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName + if (-not $msi) { throw "MSI not found in the windows-latest-11 artifact" } + $installer = New-Object -ComObject WindowsInstaller.Installer + $db = $installer.GetType().InvokeMember('OpenDatabase', 'InvokeMethod', $null, $installer, @($msi, 0)) + function Get-MsiRows($database, $sql, $columns) { + $view = $database.GetType().InvokeMember('OpenView', 'InvokeMethod', $null, $database, @($sql)) + $view.GetType().InvokeMember('Execute', 'InvokeMethod', $null, $view, $null) | Out-Null + $rows = @() + while ($true) { + $record = $view.GetType().InvokeMember('Fetch', 'InvokeMethod', $null, $view, $null) + if (-not $record) { break } + $row = @() + for ($i = 1; $i -le $columns; $i++) { $row += $record.GetType().InvokeMember('StringData', 'GetProperty', $null, $record, @($i)) } + $rows += ,$row + } + $view.GetType().InvokeMember('Close', 'InvokeMethod', $null, $view, $null) | Out-Null + return ,$rows + } + $conditions = @{} + foreach ($row in Get-MsiRows $db 'SELECT `Action`, `Condition` FROM `InstallExecuteSequence`' 2) { $conditions[$row[0]] = $row[1] } + foreach ($action in @('RequireDirOnCustomUpgrade', 'RefuseRelocatingUpgrade')) { + $condition = $conditions[$action] + if (-not $condition) { throw "$action is not scheduled in InstallExecuteSequence" } + # Property names in these conditions are upper case, and so are AND/NOT: a + # lower-case letter is a private property, which reads as empty in the service. + if ($condition -cmatch '[a-z]') { throw "$action reads a private property, which never reaches the installer service: $condition" } + Write-Host "$action : $condition" + } + $secureRows = Get-MsiRows $db 'SELECT `Value` FROM `Property` WHERE `Property` = ''SecureCustomProperties''' 1 + if (-not $secureRows.Count) { throw "SecureCustomProperties is not set at all" } + $secure = $secureRows[0][0] -split ';' + foreach ($property in @('OPENDJ', 'OPENDJ_GIVEN')) { + if ($secure -notcontains $property) { throw "$property must be secure: the guards read it in the service, where a non-administrator's value is dropped otherwise" } + } + # CheckServerNotRunning, run exactly as msiexec runs it: the Formatted field + # resolved - [\[] and [\]] are its escapes for literal brackets, [property] + # references become their values - and handed to cmd.exe. Windows PowerShell 5.1 is + # what the command names, so that is what this exercises. + $targetRows = Get-MsiRows $db 'SELECT `Target` FROM `CustomAction` WHERE `Action` = ''CheckServerNotRunning''' 1 + if (-not $targetRows.Count) { throw "the CheckServerNotRunning custom action is not in the MSI" } + $target = $targetRows[0][0] + $probeRoot = Join-Path $PWD 'guard-probe' + New-Item -ItemType Directory -Force (Join-Path $probeRoot 'locks') | Out-Null + $command = $target.Replace('[\[]', '[').Replace('[\]]', ']').Replace('[System64Folder]', "$env:SystemRoot\System32\").Replace('[OPENDJ]', "$probeRoot\") + Set-Content -Encoding Ascii -Path guard-probe.cmd -Value $command + Write-Host $command + function Invoke-Guard { (Start-Process cmd.exe -Wait -PassThru -ArgumentList '/c', 'guard-probe.cmd' -WorkingDirectory $PWD).ExitCode } + $lock = Join-Path $probeRoot 'locks\server.lock' + Remove-Item $lock -Force -ErrorAction SilentlyContinue + $rc = Invoke-Guard + if ($rc -ne 0) { throw "no lock file at all must let the upgrade proceed, got $rc" } + Set-Content -Path $lock -Value '' + $rc = Invoke-Guard + if ($rc -ne 0) { throw "an unlocked server.lock must let the upgrade proceed, got $rc" } + # A running server holds a mandatory byte-range lock over the whole file + # (LockFileManager: RandomAccessFile "rw" plus tryLock) and opens it shared, so the + # open succeeds by design and only the Lock call raises IOException - the exception + # PowerShell hands to the catch wrapped in a MethodInvocationException. + Set-Content -Path guard-holder.ps1 -Value @( + '$fs = [System.IO.File]::Open($env:GUARD_PROBE_LOCK, ''Open'', ''ReadWrite'', ''ReadWrite'')', + '$fs.Lock(0, [Int64]::MaxValue)', + 'New-Item -ItemType File -Force -Path "$env:GUARD_PROBE_LOCK.held" | Out-Null', + 'Start-Sleep -Seconds 300' + ) + $env:GUARD_PROBE_LOCK = $lock + Remove-Item "$lock.held" -Force -ErrorAction SilentlyContinue + $holder = Start-Process pwsh -PassThru -ArgumentList '-NoProfile', '-File', 'guard-holder.ps1' -WorkingDirectory $PWD + for ($i = 0; $i -lt 30 -and -not (Test-Path "$lock.held"); $i++) { Start-Sleep -Seconds 1 } + if (-not (Test-Path "$lock.held")) { throw "the holder process never took the lock" } + $started = Get-Date + $rc = Invoke-Guard + $elapsed = [int]((Get-Date) - $started).TotalSeconds + Stop-Process -Id $holder.Id -Force -ErrorAction SilentlyContinue + if ($rc -ne 1) { throw "a held server.lock must refuse the upgrade (exit 1), got $rc after ${elapsed}s" } + # Refusing before the grace is up would mean the loop exited for some other reason. + if ($elapsed -lt 55) { throw "the refusal came after ${elapsed}s, so the 60 s grace was not polled through" } + Write-Host "CheckServerNotRunning: 0 with no lock file, 0 unlocked, 1 while held (after ${elapsed}s)" + Remove-Item -Recurse -Force $probeRoot, guard-probe.cmd, guard-holder.ps1 -ErrorAction SilentlyContinue - name: Install MSI (silent) shell: pwsh run: | @@ -1161,6 +1249,15 @@ jobs: if (-not (Select-String -Path upgrade-x64-silent.log -Pattern "location could not be determined" -Quiet)) { Get-Content upgrade-x64-silent.log -Tail 60; throw "expected the explicit-OPENDJ guidance message in the log" } if (Test-Path HKLM:\SOFTWARE\OpenDJ) { throw "the refused upgrade registered an install location" } if ((Get-FileHash "C:\Program Files\OpenDJ\lib\opendj_service.exe").Hash -ne $oldWrapper) { throw "the refused upgrade overwrote the old server" } + # The signal that says "this directory was named" has to be public - a private + # property set in the UI sequence never reaches the installer service, where the + # guards run - so it must not be usable as a switch. It holds the named path and + # the guard requires the resolved directory to START WITH it: a flag-shaped value + # disarms nothing, and a value that does pass has spelled out the directory, which + # is naming it. + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ_GIVEN=1 /quiet /qn /norestart /l*v upgrade-x64-switch.log" + if ($p.ExitCode -eq 0) { Get-Content upgrade-x64-switch.log -Tail 120; throw "OPENDJ_GIVEN=1 must not switch the guard off" } + if ((Get-FileHash "C:\Program Files\OpenDJ\lib\opendj_service.exe").Hash -ne $oldWrapper) { throw "the upgrade that OPENDJ_GIVEN=1 let through overwrote the old server" } $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=`"C:\Program Files\OpenDJ`" /quiet /qn /norestart /l*v upgrade-x64-named.log" if ($p.ExitCode -ne 0) { Get-Content upgrade-x64-named.log -Tail 120; throw "the named upgrade into the default directory must succeed: $($p.ExitCode)" } if ((Get-FileHash "C:\Program Files\OpenDJ\lib\opendj_service.exe").Hash -eq $oldWrapper) { Get-Content upgrade-x64-named.log -Tail 120; throw "the upgrade did not land in C:\Program Files\OpenDJ" } @@ -1231,8 +1328,14 @@ jobs: $st = (Get-Service "OpenDJ Server" -ErrorAction SilentlyContinue).Status if ($st -ne 'StartPending') { throw "expected the service to be StartPending, got '$st'" } $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade-pending.log" - if ($p.ExitCode -eq 0) { Get-Content upgrade-pending.log -Tail 120; throw "the upgrade must refuse while the service is starting" } - if (-not (Select-String -Path upgrade-pending.log -Pattern "CheckServiceStopped" -Quiet)) { Get-Content upgrade-pending.log -Tail 60; throw "the refusal must come from CheckServiceStopped" } + # A refusal from a Return="check" custom action is 1722 in the log and 1603 out of + # msiexec, and nothing else. "-ne 0" would also accept 3010 - which is the FAIL-OPEN + # outcome, the upgrade going through and leaving the files it could not replace to a + # reboot - so the exact code is what gets asserted. Same reasoning for the log: the + # action NAME appears whether it ran and passed, ran and failed, or was skipped by + # its condition, so the return value has to be part of the pattern. + if ($p.ExitCode -ne 1603) { Get-Content upgrade-pending.log -Tail 120; throw "the upgrade must refuse while the service is starting (expected 1603, got $($p.ExitCode))" } + if (-not (Select-String -Path upgrade-pending.log -Pattern "CheckServiceStopped\. Return value 3" -Quiet)) { Get-Content upgrade-pending.log -Tail 60; throw "the refusal must come from CheckServiceStopped" } if (-not (Test-Path "$root\config\config.ldif")) { throw "the refused upgrade damaged the instance" } if (-not (Test-Path "$root\setup.bat")) { throw "the refused upgrade damaged the installation" } Write-Host "Upgrade refused while the service was StartPending (exit $($p.ExitCode))" @@ -1308,10 +1411,23 @@ jobs: for ($i=0; $i -lt 12; $i++) { try { $c = New-Object System.Net.Sockets.TcpClient('localhost', 1636); $c.Close(); break } catch { Start-Sleep -Seconds 5 } } if (Get-Service "OpenDJ Server" -ErrorAction SilentlyContinue) { throw "this scenario is about a server with NO service registered" } # The headline auto-detected upgrade, which would otherwise proceed straight into - # the running server's tree. + # the running server's tree. The refusal costs the full 60 s grace inside the + # check: a server that is genuinely up never releases the lock. + $pendingKey = "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" + $pendingBefore = @((Get-ItemProperty -Path $pendingKey -Name PendingFileRenameOperations -ErrorAction SilentlyContinue).PendingFileRenameOperations) $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" /quiet /qn /norestart /l*v upgrade-running.log" - if ($p.ExitCode -eq 0) { Get-Content upgrade-running.log -Tail 120; throw "the upgrade must refuse while a server is running out of the tree" } - if (-not (Select-String -Path upgrade-running.log -Pattern "CheckServerNotRunning" -Quiet)) { Get-Content upgrade-running.log -Tail 60; throw "the refusal must come from CheckServerNotRunning" } + # Exactly 1603 (custom action 1722), for the reason spelled out in the StartPending + # scenario above: 3010 is what a guard that fails open produces here, and "-ne 0" + # cannot tell the two apart. The action name alone cannot either - it is written to + # the log whether the action refused or waved the upgrade through. + if ($p.ExitCode -ne 1603) { Get-Content upgrade-running.log -Tail 120; throw "the upgrade must refuse while a server is running out of the tree (expected 1603, got $($p.ExitCode))" } + if (-not (Select-String -Path upgrade-running.log -Pattern "CheckServerNotRunning\. Return value 3" -Quiet)) { Get-Content upgrade-running.log -Tail 60; throw "the refusal must come from CheckServerNotRunning" } + # The signature of the fail-open, and the damage it does: RemoveExistingProducts + # cannot rename a jar the JVM holds, so it leaves a delete-on-reboot entry naming + # the path the new jar occupies. A refusal leaves none. + $pendingAfter = @((Get-ItemProperty -Path $pendingKey -Name PendingFileRenameOperations -ErrorAction SilentlyContinue).PendingFileRenameOperations) + $pendingNew = $pendingAfter | Where-Object { $_ -and $pendingBefore -notcontains $_ } + if ($pendingNew) { throw "the refused upgrade still scheduled files for delete-on-reboot: $($pendingNew -join '; ')" } if (-not (Test-Path "$root\config\config.ldif")) { throw "the refused upgrade damaged the instance" } & "$root\bat\ldapsearch.bat" --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1 if ($LASTEXITCODE -ne 0) { throw "the refused upgrade disturbed the running server" } 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 98bcda0752..22506daf6b 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 @@ -263,7 +263,7 @@ A server started with `start-ds.bat` rather than as a service is refused in the . Back up the file-system directory where OpenDJ is installed. -. Install the newer package (GUI or silent). The installer detects the existing installation — the location recorded in the registry by a previous x64 package, or the default directory of the older 32-bit package (`C:\Program Files (x86)\OpenDJ`) — and installs into the same directory, so your configured instance data (`config`, `db`, `logs`) is kept and only the program files are replaced. If the older server was installed in a custom directory the installer cannot detect, select that directory in the wizard or pass it explicitly on the command line: rather than installing a fresh server into the default directory while emptying the old one, the installer refuses to continue whenever it falls back to the default directory with nothing having recorded where the old server lives. That refusal also covers an old server that really is installed in `C:\Program Files\OpenDJ`, because the 32-bit packages recorded no location at all — and that one case the wizard cannot resolve: choosing the default directory in the wizard leaves the installer with the same values it would have had if you had chosen nothing, so pass `OPENDJ` on the command line instead. The installer further refuses to install into a directory other than the detected one: it replaces an installation in place and cannot move one, so uninstall the existing server first if you want it somewhere else. +. Install the newer package (GUI or silent). The installer detects the existing installation — the location recorded in the registry by a previous x64 package, or the default directory of the older 32-bit package (`C:\Program Files (x86)\OpenDJ`) — and installs into the same directory, so your configured instance data (`config`, `db`, `logs`) is kept and only the program files are replaced. If the older server was installed in a custom directory the installer cannot detect, select that directory in the wizard or pass it explicitly on the command line: rather than installing a fresh server into the default directory while emptying the old one, the installer refuses to continue whenever it falls back to the default directory with nothing having recorded where the old server lives. That refusal also covers an old server that really is installed in `C:\Program Files\OpenDJ`, because the 32-bit packages recorded no location at all — and that one case the wizard cannot resolve: choosing the default directory in the wizard leaves the installer with the same values it would have had if you had chosen nothing, so pass `OPENDJ` on the command line instead — it can be given with or without `/quiet`, so a wizard installation takes it just as a silent one does. The installer further refuses to install into a directory other than the detected one: it replaces an installation in place and cannot move one, so uninstall the existing server first if you want it somewhere else. + [source, console, subs="attributes"] diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index 721891cf21..b9016eae02 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -73,28 +73,35 @@ - + private one), so it CAN be handed in on the command line, and AppSearch only + overwrites what it finds. The guard below therefore does not test it for truth: it + requires the value to be the setup.bat inside the directory concerned + (OPENDJ_GIVEN_INSTALL ~>< OPENDJ, the search sets it to the full path of the file + found). OPENDJ_GIVEN_INSTALL=1 no longer says anything. That makes it not a switch + rather than a lock - a value spelled out as the path inside that directory would + still pass, which is deliberate construction rather than a slip. Not Secure because + it does not need to be: AppSearch re-runs in the execute sequence and fills it there, + so unlike OPENDJ_GIVEN it depends on no client-to-server transfer. --> @@ -125,33 +132,52 @@ Name="ImagePath" Type="raw"/> - - + + + + instruction wins. + Second residual, and the reason the exception asks for OPENDJ_GIVEN rather than the + setup.bat evidence alone: in that decoy topology a wizard session that BROWSES to + the real directory is still refused, because browsing sets no property this guard + can read - InstallDirDlg runs long after the capture point above. It is the safe + half of the wizard's behaviour (nothing is installed and nothing is removed) and the + message names the command line, which now works in a wizard session too. Widening + the exception to "the target holds a server, however it was chosen" would cover it, + at the cost of letting a hand-passed OPENDJ_GIVEN_INSTALL stand alone. --> + + A held byte-range lock and a sharing violation raise IOException, and only that is + retried; anything else means the question could not be asked rather than answered - + a read-only handle or a denied open under Program Files - and lets the upgrade + proceed. That is the same fail-open the swallowed 'net stop' has, and for the same + reason: an immediate action impersonates the invoking user, who under the filtered + token of a UAC double-click may not be able to open a file the elevated install + would replace happily. The file going away between the test and the open raises an + IOException subclass, so it costs one sleep before Test-Path lets the next pass out + at exit 0. + The typed 'catch [System.IO.IOException]' is load-bearing and has to be a TYPE, not + a name comparison: PowerShell wraps anything thrown out of a .NET method or + constructor in a MethodInvocationException, so inside a plain catch-all + $_.Exception is that wrapper and the real exception is its InnerException. An + earlier version of this action asked $_.Exception.GetType().FullName -ne + 'System.IO.IOException' and so took the fail-open branch on EVERY exception, + including the held lock it exists to detect: the exit 1 was unreachable and the CI + scenario that covers it passed on msiexec 3010 - the upgrade going through and + deferring the locked jars to a reboot - instead of the 1603 a refusal produces. A + typed catch matches on the inner exception; wait-server-stopped.ps1 has always had + it, and the copy inlined here had lost it. build.yml now runs this very command + against a real held lock, extracted from the built MSI. + [\[] and [\]] are the Formatted-field escapes for literal brackets: ExeCommand + resolves [property] references, so an unescaped [System.IO.IOException] would be + substituted away, leaving two catch-all blocks and a script that fails to parse - + which this time would refuse every upgrade rather than none. --> + Condition="WIX_UPGRADE_DETECTED AND (OPENDJ ~= OPENDJ_DEFAULT) AND NOT OPENDJ_REG AND NOT (OPENDJ_GIVEN AND (OPENDJ ~<< OPENDJ_GIVEN))"/> + Condition="WIX_UPGRADE_DETECTED AND ((OPENDJ_REG AND (OPENDJ_REG ~<> OPENDJ)) OR (NOT OPENDJ_REG AND OPENDJ_LEGACY_INSTALL AND (OPENDJ_LEGACY_DEFAULT ~<> OPENDJ) AND NOT (OPENDJ_GIVEN AND (OPENDJ ~<< OPENDJ_GIVEN) AND (OPENDJ_GIVEN_INSTALL ~>< OPENDJ))))"/> Date: Thu, 13 Aug 2026 16:06:29 +0300 Subject: [PATCH 50/52] Read the guard authoring instead of the MSI tables in test-msi The step added with the guard fixes could not read the built MSI: the WindowsInstaller.Installer COM view returned no rows in pwsh 7 without raising anything, so the first assertion failed as "RequireDirOnCustomUpgrade is not scheduled in InstallExecuteSequence" while test-msi-upgrade proved on the same head that it is scheduled and fires. Take the two guard conditions, the Secure declarations and CheckServerNotRunning's ExeCommand from package.wxs instead - wix copies all three into the tables verbatim, and it is test-msi-upgrade that judges the artifact, now on the refusal's own 1603 and "Return value 3". The lock probe itself is unchanged. --- .github/workflows/build.yml | 55 +++++++++++++++---------------------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c96242b440..3964752dae 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -736,12 +736,14 @@ jobs: permissions: contents: read steps: - # Only for .github/scripts/wait-server-stopped.ps1, and it has to come first: - # checkout cleans the workspace the artifact is unpacked into. Sparse because that - # one script is the entire reason for the checkout. + # Only for .github/scripts/wait-server-stopped.ps1 and the MSI authoring the guard + # step below reads, and it has to come first: checkout cleans the workspace the + # artifact is unpacked into. Sparse because those two are the entire reason for it. - uses: actions/checkout@v6 with: - sparse-checkout: .github/scripts + sparse-checkout: | + .github/scripts + opendj-packages/opendj-msi/opendj-msi-standard/resources/msi - name: Download artifacts uses: actions/download-artifact@v8 with: @@ -761,47 +763,34 @@ jobs: # /qn scenario runs. The second is the inline PowerShell itself: the scenarios reach # it only through a ten-minute install and can then only look at msiexec's exit code, # so a guard that always exits 0 looks the same as one that never has to refuse. - $msi = (Get-ChildItem -Recurse -Filter *.msi -Path opendj-packages/opendj-msi | Select-Object -First 1).FullName - if (-not $msi) { throw "MSI not found in the windows-latest-11 artifact" } - $installer = New-Object -ComObject WindowsInstaller.Installer - $db = $installer.GetType().InvokeMember('OpenDatabase', 'InvokeMethod', $null, $installer, @($msi, 0)) - function Get-MsiRows($database, $sql, $columns) { - $view = $database.GetType().InvokeMember('OpenView', 'InvokeMethod', $null, $database, @($sql)) - $view.GetType().InvokeMember('Execute', 'InvokeMethod', $null, $view, $null) | Out-Null - $rows = @() - while ($true) { - $record = $view.GetType().InvokeMember('Fetch', 'InvokeMethod', $null, $view, $null) - if (-not $record) { break } - $row = @() - for ($i = 1; $i -le $columns; $i++) { $row += $record.GetType().InvokeMember('StringData', 'GetProperty', $null, $record, @($i)) } - $rows += ,$row - } - $view.GetType().InvokeMember('Close', 'InvokeMethod', $null, $view, $null) | Out-Null - return ,$rows - } - $conditions = @{} - foreach ($row in Get-MsiRows $db 'SELECT `Action`, `Condition` FROM `InstallExecuteSequence`' 2) { $conditions[$row[0]] = $row[1] } + # Read from the authoring rather than from the built MSI's tables: wix copies both + # the sequence conditions and ExeCommand across verbatim, and it is test-msi-upgrade + # that judges the artifact - those scenarios now assert the refusal's own 1603 and + # "Return value 3" rather than any non-zero exit code. + $wxs = Get-Content -Raw opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs + $sequence = [regex]::Match($wxs, '(?s)(.*?)') + if (-not $sequence.Success) { throw "package.wxs has no InstallExecuteSequence" } foreach ($action in @('RequireDirOnCustomUpgrade', 'RefuseRelocatingUpgrade')) { - $condition = $conditions[$action] - if (-not $condition) { throw "$action is not scheduled in InstallExecuteSequence" } + $scheduled = [regex]::Match($sequence.Groups[1].Value, '(?s)') + if (-not $scheduled.Success) { throw "$action is not scheduled in InstallExecuteSequence" } + $found = [regex]::Match($scheduled.Groups[1].Value, '(?s)Condition="([^"]*)"') + if (-not $found.Success) { throw "$action is scheduled without a condition" } + $condition = [System.Net.WebUtility]::HtmlDecode($found.Groups[1].Value) # Property names in these conditions are upper case, and so are AND/NOT: a # lower-case letter is a private property, which reads as empty in the service. if ($condition -cmatch '[a-z]') { throw "$action reads a private property, which never reaches the installer service: $condition" } Write-Host "$action : $condition" } - $secureRows = Get-MsiRows $db 'SELECT `Value` FROM `Property` WHERE `Property` = ''SecureCustomProperties''' 1 - if (-not $secureRows.Count) { throw "SecureCustomProperties is not set at all" } - $secure = $secureRows[0][0] -split ';' foreach ($property in @('OPENDJ', 'OPENDJ_GIVEN')) { - if ($secure -notcontains $property) { throw "$property must be secure: the guards read it in the service, where a non-administrator's value is dropped otherwise" } + if ($wxs -notmatch (']*Secure="yes"')) { throw "$property must be Secure: the guards read it in the service, where a non-administrator's value is dropped otherwise" } } # CheckServerNotRunning, run exactly as msiexec runs it: the Formatted field # resolved - [\[] and [\]] are its escapes for literal brackets, [property] # references become their values - and handed to cmd.exe. Windows PowerShell 5.1 is # what the command names, so that is what this exercises. - $targetRows = Get-MsiRows $db 'SELECT `Target` FROM `CustomAction` WHERE `Action` = ''CheckServerNotRunning''' 1 - if (-not $targetRows.Count) { throw "the CheckServerNotRunning custom action is not in the MSI" } - $target = $targetRows[0][0] + $found = [regex]::Match($wxs, '(?s) Date: Thu, 13 Aug 2026 18:43:02 +0300 Subject: [PATCH 51/52] Keep the MSI modules in every reactor so releases keep versioning them maven-release-plugin rewrites the versions of ${reactorProjects}, and release.yml runs release:prepare on ubuntu-latest with no -P. Gating opendj-msi on Windows plus an installed wix.exe therefore froze both MSI poms at whatever parent version they happened to carry. Maven does not fail on that skew - it resolves the parent from the repository instead - so the module would have kept building as the previous version: unpacking that line's published snapshot rather than the server zip built beside it, naming the package after it, and handing parse-version the numbers ProductVersion is built from, which is what FindRelatedProducts keys the upgrade on. The first release would have attached opendj--SNAPSHOT.msi built from pre-release bits, and the next development cycle would have pointed the MSI tests at a stale published zip instead of at the branch under test. What cannot run outside Windows is the wix invocation, not the module, so that is what the profile gates now: opendj-msi is back in the unix, mac and windows module lists, and distribution-windows-msi moved into opendj-msi-standard around its . Inactive, the module is a pom that builds nothing - the same "no MSI artifact, no 'Cannot run program wix'" behaviour as before. maven.deploy.skip keeps it out of Maven Central, which reactor membership would otherwise put it back into. Verified with release:prepare -DdryRun=true: both MSI poms are rewritten to the release version, and the set of rewritten poms matches the active reactor. --- .../opendj-msi/opendj-msi-standard/pom.xml | 24 ++++++++++++-- opendj-packages/opendj-msi/pom.xml | 16 +++++++-- opendj-packages/pom.xml | 33 +++++++++---------- 3 files changed, 51 insertions(+), 22 deletions(-) diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml b/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml index 5a099472d3..650cefdf69 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml +++ b/opendj-packages/opendj-msi/opendj-msi-standard/pom.xml @@ -35,8 +35,9 @@ set DOTNET_ROLL_FORWARD=Major dotnet tool install --global wix --version 5.0.2 wix extension add -g WixToolset.UI.wixext/5.0.2 - The module is activated by the opendj-packages distribution-windows-msi profile - only when %USERPROFILE%\.dotnet\tools\wix.exe exists. + The module itself is part of every reactor so that the release plugin keeps its + version in step with the rest of the build; the toolchain profile below is what + turns the MSI build on, and only when %USERPROFILE%\.dotnet\tools\wix.exe exists. @@ -51,6 +52,23 @@ + + + + + distribution-windows-msi + + windows + ${env.USERPROFILE}/.dotnet/tools/wix.exe + ${project.groupId}.${project.artifactId} + + true + + + P/Invokes msi.dll), which is what the distribution-windows-msi profile inside + opendj-msi-standard gates. The module list here is unconditional: everywhere else + the module simply builds nothing. --> opendj-msi-standard diff --git a/opendj-packages/pom.xml b/opendj-packages/pom.xml index f17635345a..8a5343d87f 100644 --- a/opendj-packages/pom.xml +++ b/opendj-packages/pom.xml @@ -56,6 +56,7 @@ opendj-deb opendj-rpm opendj-svr4 + opendj-msi opendj-docker @@ -69,6 +70,7 @@ opendj-svr4 + opendj-msi opendj-docker @@ -78,27 +80,24 @@ windows + opendj-msi opendj-docker - - distribution-windows-msi - - - windows - ${env.USERPROFILE}/.dotnet/tools/wix.exe - - - opendj-msi - - + + ${project.groupId}.${project.artifactId} From c22a4daea7fbb304a9742c1539c2ce4f4ce3ad23 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Thu, 13 Aug 2026 18:51:36 +0300 Subject: [PATCH 52/52] Refuse an upgrade whose target cannot prove it is the installation RequireDirOnCustomUpgrade only asked whether the resolved directory was the x64 default, so with nothing in the registry and no server in the legacy default a mistyped target - msiexec /i opendj.msi OPENDJ=C:\opendj-custmo over a server in C:\opendj-custom - passed it, and RefuseRelocatingUpgrade has nothing to compare against in that topology either. RemoveExistingProducts emptied one directory and InstallFiles populated another one letter away; the only thing that had ever refused it was an unrelated tree happening to sit in the legacy default. Key the guard on the registry-less, legacy-less case as a whole and let it through on directory evidence instead: the target holds a setup.bat AND either it is not the fallback default or it was named. NOT OPENDJ_LEGACY_INSTALL keeps the headline legacy-default upgrade out of it, which guard (2) watches for relocation. That also settles OPENDJ_GIVEN: with the evidence a conjunct rather than an alternative, a hand-passed prefix as short as "C" - which matches every resolved path - disarms nothing, because the directory still has to hold a server. And it covers the wizard for the first time: browsing to the real installation carries its own evidence, browsing to an empty directory is refused like the typo. CI gets the typo scenario on the topology the neighbouring one already sets up. The OPENDJ_GIVEN=1 scenario now asserts 1603 and the guard's own message rather than a non-zero exit code, and the step that reads the authoring pins Sequence="first" - without it OPENDJ_GIVEN is re-set after CostFinalize in a full-UI install and its prefix test compares a value with itself, which no /qn scenario can see. The refusal message and chap-upgrade.adoc now say what the guard actually does, and three comments claiming build.yml reads the built MSI are corrected to the authoring it has read since 6bcada5. --- .github/workflows/build.yml | 23 ++++- .../asciidoc/install-guide/chap-upgrade.adoc | 2 +- .../resources/msi/package.wxs | 88 ++++++++++++------- 3 files changed, 76 insertions(+), 37 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3964752dae..fb7aebb3da 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -784,6 +784,12 @@ jobs: foreach ($property in @('OPENDJ', 'OPENDJ_GIVEN')) { if ($wxs -notmatch (']*Secure="yes"')) { throw "$property must be Secure: the guards read it in the service, where a non-administrator's value is dropped otherwise" } } + # Sequence="first" is what keeps OPENDJ_GIVEN meaning "the directory was named": + # without it the action re-runs in the execute sequence of a full-UI install, where + # OPENDJ has long been resolved, and the guards' prefix test would be comparing a + # value with itself. Every msiexec call in this workflow is /qn, which runs no UI + # sequence, so nothing else here would notice it going. + if ($wxs -notmatch ']*Sequence="first"') { throw 'OPENDJ_GIVEN must be captured with Sequence="first", or it stops meaning "named" in a full-UI install' } # CheckServerNotRunning, run exactly as msiexec runs it: the Formatted field # resolved - [\[] and [\]] are its escapes for literal brackets, [property] # references become their values - and handed to cmd.exe. Windows PowerShell 5.1 is @@ -1080,6 +1086,17 @@ jobs: if (-not (Select-String -Path upgrade-custom.log -Pattern "location could not be determined" -Quiet)) { Get-Content upgrade-custom.log -Tail 60; throw "expected the explicit-OPENDJ guidance message in the log" } if (-not (Test-Path "C:\opendj-custom\setup.bat")) { throw "the refused upgrade damaged the original install" } Write-Host "Upgrade refused with guidance, original install untouched (exit $($p.ExitCode))" + # A named directory that is not the installation strands exactly as much data as + # naming none. With no registry value and no server in the legacy default, a typo + # used to satisfy this guard - the resolved directory is not the default - and the + # relocation guard had nothing to compare it against, so RemoveExistingProducts + # emptied C:\opendj-custom while the new tree landed one letter away. + $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=C:\opendj-custmo /quiet /qn /norestart /l*v upgrade-typo.log" + if ($p.ExitCode -ne 1603) { Get-Content upgrade-typo.log -Tail 120; throw "a named directory holding no server must be refused (expected 1603, got $($p.ExitCode))" } + if (-not (Select-String -Path upgrade-typo.log -Pattern "location could not be determined" -Quiet)) { Get-Content upgrade-typo.log -Tail 60; throw "expected the explicit-OPENDJ guidance message in the log" } + if (Test-Path "C:\opendj-custmo") { throw "the refused upgrade still created the mistyped directory" } + if (-not (Test-Path "C:\opendj-custom\setup.bat")) { throw "the refused upgrade damaged the original install" } + Write-Host "A mistyped target was refused, original install untouched (exit $($p.ExitCode))" # ...and naming the directory makes the very same upgrade proceed. This is what # a GUI administrator does by browsing to it in InstallDirDlg, which the refusal # must leave reachable: it fires on the resolved directory, not on the absence @@ -1243,9 +1260,11 @@ jobs: # guards run - so it must not be usable as a switch. It holds the named path and # the guard requires the resolved directory to START WITH it: a flag-shaped value # disarms nothing, and a value that does pass has spelled out the directory, which - # is naming it. + # is naming it. It is not the only conjunct either - the target still has to hold a + # server - so even a matching prefix cannot stand in for that evidence. $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ_GIVEN=1 /quiet /qn /norestart /l*v upgrade-x64-switch.log" - if ($p.ExitCode -eq 0) { Get-Content upgrade-x64-switch.log -Tail 120; throw "OPENDJ_GIVEN=1 must not switch the guard off" } + if ($p.ExitCode -ne 1603) { Get-Content upgrade-x64-switch.log -Tail 120; throw "OPENDJ_GIVEN=1 must not switch the guard off (expected 1603, got $($p.ExitCode))" } + if (-not (Select-String -Path upgrade-x64-switch.log -Pattern "location could not be determined" -Quiet)) { Get-Content upgrade-x64-switch.log -Tail 60; throw "the refusal must still come from the same guard" } if ((Get-FileHash "C:\Program Files\OpenDJ\lib\opendj_service.exe").Hash -ne $oldWrapper) { throw "the upgrade that OPENDJ_GIVEN=1 let through overwrote the old server" } $p = Start-Process msiexec -Wait -PassThru -ArgumentList "/i `"$msi`" OPENDJ=`"C:\Program Files\OpenDJ`" /quiet /qn /norestart /l*v upgrade-x64-named.log" if ($p.ExitCode -ne 0) { Get-Content upgrade-x64-named.log -Tail 120; throw "the named upgrade into the default directory must succeed: $($p.ExitCode)" } 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 22506daf6b..5c5ac0e9ca 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 @@ -263,7 +263,7 @@ A server started with `start-ds.bat` rather than as a service is refused in the . Back up the file-system directory where OpenDJ is installed. -. Install the newer package (GUI or silent). The installer detects the existing installation — the location recorded in the registry by a previous x64 package, or the default directory of the older 32-bit package (`C:\Program Files (x86)\OpenDJ`) — and installs into the same directory, so your configured instance data (`config`, `db`, `logs`) is kept and only the program files are replaced. If the older server was installed in a custom directory the installer cannot detect, select that directory in the wizard or pass it explicitly on the command line: rather than installing a fresh server into the default directory while emptying the old one, the installer refuses to continue whenever it falls back to the default directory with nothing having recorded where the old server lives. That refusal also covers an old server that really is installed in `C:\Program Files\OpenDJ`, because the 32-bit packages recorded no location at all — and that one case the wizard cannot resolve: choosing the default directory in the wizard leaves the installer with the same values it would have had if you had chosen nothing, so pass `OPENDJ` on the command line instead — it can be given with or without `/quiet`, so a wizard installation takes it just as a silent one does. The installer further refuses to install into a directory other than the detected one: it replaces an installation in place and cannot move one, so uninstall the existing server first if you want it somewhere else. +. Install the newer package (GUI or silent). The installer detects the existing installation — the location recorded in the registry by a previous x64 package, or the default directory of the older 32-bit package (`C:\Program Files (x86)\OpenDJ`) — and installs into the same directory, so your configured instance data (`config`, `db`, `logs`) is kept and only the program files are replaced. If the older server was installed in a custom directory the installer cannot detect, select that directory in the wizard or pass it explicitly on the command line: rather than installing a fresh server into the default directory while emptying the old one, the installer refuses to continue whenever nothing has recorded where the old server lives and the directory it is about to install into holds no OpenDJ server -- which also catches a mistyped directory name. That refusal also covers an old server that really is installed in `C:\Program Files\OpenDJ`, because the 32-bit packages recorded no location at all — and that one case the wizard cannot resolve: choosing the default directory in the wizard leaves the installer with the same values it would have had if you had chosen nothing, so pass `OPENDJ` on the command line instead — it can be given with or without `/quiet`, so a wizard installation takes it just as a silent one does. The installer further refuses to install into a directory other than the one it detected, unless the directory you name holds an OpenDJ server itself (see the note below): it replaces an installation in place and cannot move one, so uninstall the existing server first if you want it somewhere else. + [source, console, subs="attributes"] diff --git a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs index b9016eae02..1e72559544 100644 --- a/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs +++ b/opendj-packages/opendj-msi/opendj-msi-standard/resources/msi/package.wxs @@ -83,15 +83,15 @@ full-UI session runs AppSearch twice: once in the client with the same command-line value, and again in the execute sequence, by which point OPENDJ has arrived from the client fully resolved. So the property means "the NAMED directory holds a server" - silently and "the TARGET directory holds a server" in the wizard. Both readings suit - the guard, which pairs it with OPENDJ_GIVEN - and OPENDJ_GIVEN passes only when the - resolved OPENDJ starts with the named path, so the two agree on which directory is - meant whenever the exception applies at all. + silently and "the TARGET directory holds a server" in the wizard, and both readings + are the question the guards ask: silently there is nothing but the command line to + aim an upgrade at a directory no search can see, and in the wizard the browse dialog + is that same instruction. When OPENDJ is empty the path does not expand to a full path and, with no Parent and the default depth of zero, the installer looks for setup.bat in the root of each fixed drive instead. That costs a handful of stat calls and cannot change a decision: - every use of this property is paired with OPENDJ_GIVEN, which is unset in exactly - that case. + the containment test below fails for a hit in a drive root, which is not inside the + directory being asked about. Public, because a search property has to be (WIX0012: AppSearch cannot fill a private one), so it CAN be handed in on the command line, and AppSearch only overwrites what it finds. The guard below therefore does not test it for truth: it @@ -155,9 +155,10 @@ guards in EVERY full-UI session, including one started with OPENDJ= on the command line, which is the single route this package's refusal messages and the install guide prescribe. The wizard therefore refused the documented workaround, and the - exception in guard (2) below could never apply. No CI scenario could see it: all 42 - msiexec calls in build.yml are /qn, and the UI sequence is not processed below full - UI level. + exception in guard (2) below could never apply. No CI scenario could see it: every + msiexec call in build.yml is /qn, and the UI sequence is not processed below full + UI level - which is also why build.yml pins Sequence="first" by reading it out of + this file. Public means the command line can hand it in, so the value carries the weight rather than the presence: the guards require the resolved OPENDJ to START WITH it (~<< in the condition, not ~=: the captured value is the raw command-line string and the resolved @@ -215,26 +216,44 @@ and leaves a GUI-only administrator with nothing but a command line to retype, even though WixUI_InstallDir ships the browse dialog that would have resolved it. - (1) The location cannot be determined. 5.1.x wrote no registry value, so an - upgrade from a custom directory resolves no search and OPENDJ falls back to the - default - proceeding would install a fresh server there while - RemoveExistingProducts empties the old tree, leaving config/db/logs stranded. - Refuse whenever the resolved directory IS that fallback and nothing recorded a - location. The test is "nothing recorded it", not "no server is installed there": - a foreign OpenDJ tree in the default directory (a zip install, a manual copy) - satisfies a setup.bat search without being the product being upgraded, so keying - the guard on that let the decoy disarm it while RemoveExistingProducts gutted the - real installation elsewhere and InstallFiles landed on top of the stranger. - Selecting the real directory in InstallDirDlg, or passing OPENDJ, makes the - comparison fail and the install proceed as before; naming the DEFAULT directory - on the command line proceeds through OPENDJ_GIVEN, which is the way out for an - old server that really does live there - 5.1.x installed into it recorded - nothing, so the package cannot tell that tree from the decoy on its own and has - to be told. Only the command line: see OPENDJ_GIVEN above for why the wizard - cannot confirm the default directory, and the message below for what it says - instead. The command line does work WITH the wizard, which is what OPENDJ_GIVEN - being public and secure buys: msiexec /i opendj.msi OPENDJ="..." and then click - through the dialogs reaches this guard with the property intact. + (1) Nothing recorded where the old server lives, and the target cannot prove it is + that server. 5.1.x wrote no registry value, so an upgrade from a custom directory + resolves no search and OPENDJ falls back to the default - proceeding would install + a fresh server there while RemoveExistingProducts empties the old tree, leaving + config/db/logs stranded. A directory that WAS named loses exactly as much when it + is not the installation: + + msiexec /i opendj.msi OPENDJ=C:\opendj-custmo /qn + + over a server in C:\opendj-custom passed this guard while it only asked whether the + resolved directory was the default, and guard (2) has nothing to say either with no + registry value and no server in the legacy default - so one typo emptied one + directory and populated another, and the only thing that had ever refused it was an + unrelated tree happening to sit in the legacy default. + So the guard covers the registry-less, legacy-less case as a whole, and what lets an + upgrade through is directory evidence: [OPENDJ] holds a setup.bat, AND either it is + not the fallback default or it was named. The second half is what keeps a decoy from + disarming it - a foreign OpenDJ tree in the default directory (a zip install, a + manual copy) satisfies a setup.bat search without being the product being upgraded, + so evidence alone would let it through while RemoveExistingProducts gutted the real + installation elsewhere and InstallFiles landed on top of the stranger. Naming the + DEFAULT directory is the way out for an old server that really does live there: + 5.1.x installed into it recorded nothing, so the package cannot tell that tree from + the decoy on its own and has to be told. Only the command line for THAT case: see + OPENDJ_GIVEN above for why the wizard cannot confirm the default directory, and the + message below for what it says instead. The command line does work WITH the wizard, + which is what OPENDJ_GIVEN being public and secure buys: msiexec /i opendj.msi + OPENDJ="..." and then click through the dialogs reaches this guard with the property + intact. Every other directory the wizard can reach now carries its own evidence: + browsing to the real installation proceeds, browsing to an empty directory is + refused like the typo above. + Evidence being a conjunct rather than an alternative is also what stops OPENDJ_GIVEN + from being handed in as a bypass: a prefix as short as "C" does match the resolved + path, but the directory still has to hold a server - and a target that holds one is + one this guard was going to let through anyway. + NOT OPENDJ_LEGACY_INSTALL is load-bearing rather than tidiness: a server in the + legacy default is the headline upgrade path, resolved with nothing named and nothing + recorded, and it is guard (2) that watches that one for relocation. Residual: the same decoy in the LEGACY default directory is not detectable when nothing is named. SetOpendjFromLegacyDir adopts it, so the resolved directory is @@ -295,11 +314,11 @@ secured ones reach it for a non-administrator. Every property named in the two conditions below is therefore public (WIX_UPGRADE_DETECTED, OPENDJ, OPENDJ_DEFAULT, OPENDJ_REG, OPENDJ_GIVEN, OPENDJ_LEGACY_INSTALL, OPENDJ_LEGACY_DEFAULT, - OPENDJ_GIVEN_INSTALL), and build.yml asserts that in the built MSI - a private + OPENDJ_GIVEN_INSTALL), and build.yml asserts that against this file - a private property here reads as empty and silently inverts a guard, which is exactly what happened to the OpendjDirGiven flag these conditions used to carry. --> + Error="An existing OpenDJ installation was detected, but its location could not be determined: 32-bit packages recorded none, and the directory this installation would use holds no OpenDJ server. Select the existing installation directory in the wizard, or pass it explicitly: msiexec /i opendj.msi OPENDJ="C:\path\to\opendj" - and if a directory was given already, check it for a typo. If that installation is the default directory itself, the command line is the only way - the wizard cannot tell a confirmed default from an unchanged one."/> @@ -414,8 +433,9 @@ scenario that covers it passed on msiexec 3010 - the upgrade going through and deferring the locked jars to a reboot - instead of the 1603 a refusal produces. A typed catch matches on the inner exception; wait-server-stopped.ps1 has always had - it, and the copy inlined here had lost it. build.yml now runs this very command - against a real held lock, extracted from the built MSI. + it, and the copy inlined here had lost it. build.yml now takes this command out of + this file, resolves it the way msiexec resolves a Formatted field and runs it + against a real held lock. [\[] and [\]] are the Formatted-field escapes for literal brackets: ExeCommand resolves [property] references, so an unescaped [System.IO.IOException] would be substituted away, leaving two catch-all blocks and a script that fails to parse - @@ -425,7 +445,7 @@ Execute="immediate" Return="check"/> + Condition="WIX_UPGRADE_DETECTED AND NOT OPENDJ_REG AND NOT OPENDJ_LEGACY_INSTALL AND NOT ((OPENDJ_GIVEN_INSTALL ~>< OPENDJ) AND ((OPENDJ ~<> OPENDJ_DEFAULT) OR (OPENDJ_GIVEN AND (OPENDJ ~<< OPENDJ_GIVEN))))"/>