mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Valery Kharseko
18 hours ago 91fcddb2d3bc7be859d60c062089ed947f480dd1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#!/bin/bash
#
# The contents of this file are subject to the terms of the Common Development and
# Distribution License (the License). You may not use this file except in compliance with the
# License.
#
# You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
# specific language governing permission and limitations under the License.
#
# When distributing Covered Software, include this CDDL Header Notice in each file and include
# the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
# Header, with the fields enclosed by brackets [] replaced by your own identifying
# information: "Portions copyright [year] [name of copyright owner]".
#
# Copyright 2026 3A Systems, LLC.
 
# Checks same-pe-code.py and refresh-launchers.sh against launchers committed in the
# history of master, so that neither can start keeping a changed launcher, or refreshing
# one that differs only in the toolchain stamp, while CI stays green. Needs the full
# history (fetch-depth: 0). Run from the root of the repository.
set -e
here=$(dirname "$0")
t=$(mktemp -d)
trap 'rm -rf "$t"' EXIT
 
g() { git show "$1:opendj-server-legacy/lib/$2.exe" > "$t/$2-$3.exe"; }
expect() {
  local rc=0
  python3 "$here/same-pe-code.py" "$t/$2" "$t/$3" || rc=$?
  if [ "$rc" != "$1" ]; then
    echo "::error::same-pe-code.py $2 $3 exited $rc, expected $1 ($4)"
    exit 1
  fi
  echo "ok: $2 $3 -> $rc ($4)"
}
 
for f in launcher_administrator winlauncher opendj_service; do
  g a611c10c46^ $f 36252
  g a611c10c46 $f 36256
  g a8a18f000d $f 36257
  g 74cb4f5a84 $f old-code
  expect 0 $f-36256.exe $f-36257.exe "the toolchain stamp only"
  expect 0 $f-36257.exe $f-36256.exe "the toolchain stamp only"
  expect 1 $f-old-code.exe $f-36257.exe "before and after a change of the launcher sources"
done
# winlauncher.exe has CheckSum 0 in both builds, launcher_administrator.exe does not.
for f in launcher_administrator winlauncher; do
  expect 0 $f-36252.exe $f-36256.exe "the same code, the PE header at 0x100 and at 0xf0"
done
expect 1 opendj_service-36252.exe opendj_service-36256.exe "a code change of the 05.09 refresh"
expect 1 winlauncher-36257.exe launcher_administrator-36257.exe "two different launchers"
# A real change moves the headers too; this one does not, so the sections must be compared.
python3 - "$t/winlauncher-36257.exe" "$t/winlauncher-text-byte.exe" <<'EOF'
import struct, sys
b = bytearray(open(sys.argv[1], "rb").read())
pe = struct.unpack_from("<I", b, 0x3C)[0]
table = pe + 24 + struct.unpack_from("<H", b, pe + 20)[0]
b[struct.unpack_from("<I", b, table + 20)[0] + 16] ^= 1    # the first section: .text
open(sys.argv[2], "wb").write(b)
EOF
expect 1 winlauncher-36257.exe winlauncher-text-byte.exe "one byte of .text flipped"
# A linker flag, the DOS stub or a section flag changes the headers only, so they must be
# compared as well.
for field in nx stub section; do
  python3 - "$t/winlauncher-36257.exe" "$t/winlauncher-$field.exe" $field <<'EOF'
import struct, sys
b = bytearray(open(sys.argv[1], "rb").read())
pe = struct.unpack_from("<I", b, 0x3C)[0]
table = pe + 24 + struct.unpack_from("<H", b, pe + 20)[0]
off = {"nx": pe + 24 + 71,                  # DllCharacteristics, high byte: NX_COMPAT
       "stub": 0x4E,                        # "This program cannot be run in DOS mode."
       "section": table + 39}[sys.argv[3]]  # the first section's Characteristics, top byte
b[off] ^= 1
open(sys.argv[2], "wb").write(b)
EOF
  expect 1 winlauncher-36257.exe winlauncher-$field.exe "$field: a change of the headers only"
done
# No committed launcher has a PDB. Retype the POGO debug entry as CodeView in two copies
# whose PDB GUID and age differ, and nothing else.
for n in 1 2; do
  python3 - "$t/winlauncher-36257.exe" "$t/winlauncher-rsds$n.exe" $n <<'EOF'
import struct, sys
b = bytearray(open(sys.argv[1], "rb").read())
pe = struct.unpack_from("<I", b, 0x3C)[0]
opt = pe + 24
dirs = opt + (96 if struct.unpack_from("<H", b, opt)[0] == 0x10B else 112)
table = opt + struct.unpack_from("<H", b, pe + 20)[0]
rva = struct.unpack_from("<I", b, dirs + 6 * 8)[0]            # the debug directory
for i in range(struct.unpack_from("<H", b, pe + 6)[0]):
    va, vsize, raw = (struct.unpack_from("<I", b, table + 40 * i + o)[0] for o in (12, 8, 20))
    if va <= rva < va + vsize:
        entry = raw + rva - va
while struct.unpack_from("<I", b, entry + 12)[0] != 13:       # the POGO entry
    entry += 28
struct.pack_into("<I", b, entry + 12, 2)                       # retyped as CodeView
data = struct.unpack_from("<I", b, entry + 24)[0]
b[data:data + 24] = b"RSDS" + bytes([int(sys.argv[3])]) * 20  # GUID and age differ
open(sys.argv[2], "wb").write(b)
EOF
done
expect 0 winlauncher-rsds1.exe winlauncher-rsds2.exe "the PDB GUID and age of a CodeView entry"
head -c 64 "$t/winlauncher-36257.exe" > "$t/truncated.exe"
expect 2 truncated.exe winlauncher-36257.exe "a file that is not a PE image"
 
# The loop: keeps a launcher that differs only in the stamp, refreshes one whose code
# changed, adds one that is not committed yet, and refreshes one whose committed file
# is not a PE image.
mkdir "$t/built" "$t/lib"
cp "$t/winlauncher-36257.exe" "$t/built/winlauncher.exe"
cp "$t/winlauncher-36256.exe" "$t/lib/winlauncher.exe"
cp "$t/launcher_administrator-36257.exe" "$t/built/launcher_administrator.exe"
cp "$t/launcher_administrator-old-code.exe" "$t/lib/launcher_administrator.exe"
cp "$t/opendj_service-36257.exe" "$t/built/opendj_service.exe"
cp "$t/winlauncher-36257.exe" "$t/built/unreadable.exe"
cp "$t/truncated.exe" "$t/lib/unreadable.exe"
bash "$here/refresh-launchers.sh" "$t/built" "$t/lib"
cmp "$t/lib/winlauncher.exe" "$t/winlauncher-36256.exe"
cmp "$t/lib/launcher_administrator.exe" "$t/built/launcher_administrator.exe"
cmp "$t/lib/opendj_service.exe" "$t/built/opendj_service.exe"
cmp "$t/lib/unreadable.exe" "$t/built/unreadable.exe"
echo "ok: refresh-launchers.sh keeps, refreshes and adds as expected"