Classic registration and security system
Galactic Empire 3.2e contains a board-specific registration system, a time-limited test-drive system, protected Btrieve database handling, and a second concealed system check. These mechanisms are separate from PLAYKEY and SYSKEY, which control user access and administrative privileges.
The released source contains two largely independent layers. The documented registration and test-drive system is implemented by SECURE.C and was introduced in release 3.0d so GE could be distributed generally. The concealed c4angle() account check has no visible connection to that system and may have an older origin.
SECURE.C registration system
Security state
The shared secure structure records three states:
open_stat |
Meaning |
|---|---|
1 |
The configured registration number is valid for this BBS |
-1 |
The registration number is invalid or absent, but the test drive remains active |
0 |
Security validation failed or the test drive has expired; GE is disabled |
days_run holds the test-drive startup-day count and days_tot holds its permitted length. At startup, classic reports the registration number, the current test-drive day, or that the unregistered game is disabled.
When disabled, GE does not schedule ship, NPC, planet, or automatic-update callbacks. Login, cleanup, deletion, hangup, and ordinary command entry also contain guards against operating on the protected databases. A player who enters the module receives the trial-expired notice instead of the game. The records are not erased: entering a valid registration number allows the game to continue where it stopped.
Original registration number
Classic's REGNO configuration option accepts an eight-character registration number tied to the host BBS registration number. The internal registration utility identifies Galactic Empire as using seed 10094056 and method 1. These are also the values actually selected by GEMAIN.H.
The standalone SECURE.H contains generic example values (including a different seed and method 0). They are not Galactic Empire's effective values: sec_opnbtv() receives GE's values as arguments from GEMAIN.C.
Generation algorithm
The publisher's REGISTER utility asks for the product seed, method, and customer's eight-digit MajorBBS or Worldgroup registration number. For GE it generates the key as follows:
- Convert the seed and BBS registration number to integers.
- XOR the two integer values.
- Represent the result as an eight-position, right-aligned decimal value.
- For method 1, add the corresponding seed digit to each position and retain only the last decimal digit.
In compact form, the final operation for each position is:
registration_digit[i] = (xor_digit[i] + seed_digit[i]) % 10
The runtime protect() routine independently derives the same value from MajorBBS's bturno and compares it with REGNO. Consequently, a key generated for one registered BBS does not register another.
REGISTER.EXE was the utility specified for Galactic Empire and The Legend of Elyth Gor. The accompanying REG2 and REG3 algorithms were intended for other M.B. Murdock products and are not used by GE.
Protected databases
The ship and mail databases are opened normally. The planet and user databases are opened through sec_opnbtv().
The routine derives the correct board-specific registration value even while the game is running as an unregistered test drive. It supplies that value to the Btrieve open path and invokes Btrieve operation 29 (Set Owner), binding the protected files to the board-specific value.
Each protected database also receives a concealed record whose first key is a high-valued byte string defined by KEY. The remaining bytes hold four encoded fields:
- the first test-drive date;
- the last date on which the module was started;
- the number of distinct startup dates; and
- a second copy of the first date tied to the BBS registration number.
The stored bytes are additionally offset by their positions in the record. This is obfuscation and tamper detection, not encryption in the modern sense. On each new calendar date, the run counter and last-run date are updated.
For the original GE seed, characters 1 and 7 are combined to produce a 15-day test-drive limit. The test drive is rejected if its initial date is in the future, elapsed calendar time exceeds the limit, the startup-day count exceeds the limit, or the redundant board-bound date does not agree. This means both clock rollback and simply avoiding daily use are accounted for: elapsed calendar time is checked independently of the number of days on which GE started.
Because the security information is stored as an otherwise valid database record, code that walks the user database must recognize and skip the KEY record. Classic's midnight cleanup does this explicitly. A port or database tool that treats every record as a player can expose the security record in a roster or, worse, rewrite it as player data.
Startup cross-check
GEMAIN.C first opens the planet database and saves its resulting security state. It then opens the user database and requires both databases to agree on open_stat and days_tot. A disagreement causes a fatal Secure Stat Open failure or Secure Days Open failure. This prevents the game from quietly combining protected files with incompatible security state.
FAKESECURE
GEMAIN.C contains a commented build-time FAKESECURE switch. When enabled, the planet and user files use ordinary opnbtv(), and a dummy secure structure reports a registered state. It bypasses the protected open, trial counter, and cross-database registration checks.
The switch is disabled in the released source. It is also not a complete removal of all security-related code: the separate c4angle() check remains compiled and callable.
Common online 3.2e build
A 3.2e package commonly distributed with MBBSEmu differs from the released source configuration. Its REGIST.TXT instructs the sysop to "Use your activation code for MBBS" rather than obtain the derived GE registration number.
Running the DLL with the default REGNO produces GE's trial-expired message. It also creates and evaluates the concealed records in both protected databases. It therefore is not a FAKESECURE build.
Decoding a newly created security record shows that its date is stored without the XOR transformation that the original 10094056 seed would produce. The DLL contains no 10094056 string and instead has a second 00000000 string consistent with a replaced seed. Its effective security seed is 00000000.
That change has two consequences:
- XOR with zero leaves
bturnounchanged, and method-1 digit addition with zero changes no digits. The validREGNOis therefore the BBS's own eight-digit registration number. - The test-drive length is derived from positions 1 and 7 of the seed. A zero seed produces a zero-day allowance, so an incorrect or absent
REGNOis disabled immediately.
This exactly matches the package's instructions and observed behavior. The change could have been made by rebuilding after changing the source constant, or by replacing the eight ASCII bytes 10094056 with 00000000 directly in the DLL. The resulting binary alone cannot distinguish between those methods.
The concealed c4angle() check
GELIB.C describes c4angle() only as "Verify system." Its name does not describe its operation. On its first call, it constructs the otherwise unobvious account key Glperr, selects MajorBBS's account database, and searches key 0. If that account record exists, GE terminates with GE SYSTEM FAULT. If it does not exist, a static flag prevents the test from running again during that module load.
The released GE source contains no routine that creates the Glperr account, so the intended path by which that marker would be placed cannot be established from GE's source alone.
Rather than calling this check visibly during initialization, classic places it inside absol(), GE's floating-point absolute-value helper. Normal navigation and combat mathematics eventually call absol(), which makes the security test occur indirectly. The function also changes the current Btrieve context to the account database and does not restore the prior context; ports should understand that as an implementation side effect, not as part of absolute-value behavior.
Possible earlier origin
Before version 3, GE was distributed for MajorBBS 5.x as source that became part of the compiled BBS rather than as a drop-in module DLL. The release notes specifically identify the SECURE.C-style registration protection as a new 3.0d feature. By contrast, c4angle() is independent of that system, survives the FAKESECURE bypass, and checks for a marker that no surviving 3.2e routine creates.
These facts make it plausible that c4angle() is a remnant of an earlier source-distribution-era protection scheme, perhaps paired with an old installer, build procedure, or security component that created Glperr. No pre-3.x implementation or marker-creation utility is present in the available archive, however, so this remains a historical hypothesis rather than an established fact.
Source integration
The classic implementation is distributed across several locations:
| Location | Role |
|---|---|
SECURE.C |
Protected Btrieve open, owner setup, registration comparison, trial record, counters, and tamper checks |
SECURE.H |
Generic declarations and sample defaults; not the authoritative GE constants |
GEMAIN.H |
GE's actual method, seed, high-key value, structure declaration, and prototype |
GEMAIN.C |
Protected database opens, cross-checks, scheduler and entry guards, status messages, and FAKESECURE
|
GELIB.C |
Concealed c4angle() account check through absol()
|
GECMDS.C |
Implementation of the diagnostic RG# display
|
MBMGEMP.LNK |
Links the separately compiled security object into the module |
register/REGISTER.CPP |
Publisher-side method-1 registration-number generator |
The installation manual documents RG# as a technical-support command that reports the configured registration number, security state, and test-drive day. Its command-table entry is commented out in 3.2e, although the handler remains in the source; see Commands#Administration and diagnostics. The classic WHO terminal-support command likewise exposes the BBS registration number in PHARLAP/MajorBBS 6.x builds.
ge-next
ge-next does not enforce classic's commercial registration or test-drive system and does not place security records in its databases. Its REGNO setting is only an optional installation identifier, not an unlock key. Since version 0.3.2, a blank or zero value produces no registration line at startup; a configured value is shown there and can distinguish multiple installations. REGNO is not player authentication or a frontend pairing code: the separate FRONTEND option controls DATA access.
Home · Play · Reference · Versions & history · Sysop · Development · Classic bugs