NetHack 3.4.3, built from the official source on my VAXstations with the distribution’s own VMS build procedures and DEC C, installed for all users as a kit with an installer and an uninstaller, and set up so that players cannot read, delete, rename or overwrite each other’s save files without anyone being given a privilege. Version 3.4.3 (December 2003) is the last NetHack whose VMS port supports the VAX; 3.6 and 3.7 list Alpha and Itanium only.
Claude Code did much of the hard work.
It built without a single source change. The only thing I set is the one
setting the distribution’s own VMS notes tell you to set: where the
playground is (Local_HACKDIR in vmsconf.h). The interesting part turned
out to be the security of the playground.
Downloads, with SHA-256 sums in SHA256SUMS.TXT:
- NETHACK_VAX_343.BCK (2.9 MB): the kit to install.
- NETHACK_INSTALL.COM and NETHACK_UNINSTALL.COM.
- README.TXT, which says everything below about installing and security in more detail, and SHA256SUMS.TXT.
- The licence and the provenance: NETHACK_LICENSE.TXT and SOURCES.TXT.
- Source kit
(5.7 MB): the official 3.4.3 archive, the VMS-relevant part of it as a zip
for the VAX, the configuration change as a patch, the build, staging and kit
procedures, the lifecycle test, and
RECREATE.md, the recipe to recreate the kit from scratch with the hashes at each step. - The file list of the saveset: NETHACK_VAX_343_LIST.LIS.
What Was Built
Source:
nethack-343-src.tgz, 3,497,458 bytes, SHA-256bb39c3d2a9ee2df4a0c8fdde708fbc63740853a7608d2f4c560b488124866fe4, from the NetHack download area on SourceForge. A copy on my DECUS CD-ROMs (nethack-343-src-vms.tgz) contains exactly the same tar; I checked it, every file, rather than trusting the name.Compiler and procedure: DEC C V6.4 on OpenVMS VAX V7.3,
@VMSBUILD DECC(the procedure defaults to VAX C, which I do not have). No MMS, no lex or yacc (the pre-processed files insys/shareare used).Measured on the VAXstation 4000/90 (a 71 MHz KA49): 132 progress lines in the procedure’s own log (compile steps, six links), 28 minutes 54 seconds elapsed as a batch job (27 min 33 s CPU), a 3,414-block
NETHACK.EXEand a 15-blockRECOVER.EXE; then the distribution’s ownINSTALL.COMinto a staging directory in 21 seconds, which builds the data library; the kit withBACKUPin 9.4 seconds. The build printed no compiler warnings. The 4000/60 only installed the kit.The one change, as a patch in the source kit:
-#define Local_HACKDIR "DISK$USERS:[GAMES.NETHACK.3_4_X.PLAY]\0..." +#define Local_HACKDIR "SYS$COMMON:[SYSLIB.NETHACK]\0..."(The
HACKDIRlogical name does the same at run time, andNETHACK_SETUP.COMdefines it too.)
Installing and Playing
You need OpenVMS VAX 7.3, SYSTEM (or SYSPRV), and about 5,000 free blocks.
- Put the saveset and the two
.COMfiles in one directory on the VAX (.BCKin binary,.COMin ASCII; the installer puts back the saveset’s record attributes that a binary transfer loses). - As
SYSTEM:$ @NETHACK_INSTALL. It restores the files, makes the playground, sets the protections, writes a manifest, and runsNETHACK -sas a smoke test. Measured: the restore takes 7 seconds on the 4000/90 and 12 on the 4000/60; the whole procedure including the smoke test is a few seconds longer. - Each player:
$ @SYS$COMMON:[SYSLIB.NETHACK]NETHACK_SETUP, then$ NETHACK(options in quotes:NETHACK "-uConan-B",NETHACK "-s").Ssaves,NETHACKagain restores.
@NETHACK_UNINSTALL CHECK shows what would go and @NETHACK_UNINSTALL does it:
only files the manifest lists and that are still as installed. A score list
that has entries and saved games are kept, and a reinstall adopts them.
RECOVER is installed too.
The Unexpected: Making Players’ Files Private
NetHack on VMS wants one directory, the playground, that every player writes
into: level files while a game runs, the lock file, the save file in [.SAVE],
bones. The distribution’s own notes say its default is “world-writable files
… NOT secure and not advisable in any environment where there are untrustworthy
users”. The proper fix is to install the image with a rights identifier, which
needs INSTALL, a privilege and a startup entry. I did not want to grant a
game any of that, so I tried to do it with ACLs alone.
First attempt: a DEFAULT_PROTECTION ACE on the playground and [.SAVE], to
make new files owner-only. It does not work. I started a game as USER1, saved,
and as USER2 typed TYPE on the save file. It printed nothing, because it
read it. The C run-time library creates the file with an explicit protection
derived from the program’s creation mode (0660: the owner and the group
may read and write), and an explicit protection wins over the directory’s
default. On my systems every player is in the same UIC group, so everyone
could read, replace and delete everyone’s game. The file showed
(RWD,RWD,RWD,).
What works: an inheritable ACE that denies everybody:
$ SET ACL/ACL=((IDENTIFIER=[*,*],OPTIONS=DEFAULT,ACCESS=NONE), -
(DEFAULT_PROTECTION,S:RWED,O:RWED,G,W)) SYS$COMMON:[SYSLIB.NETHACK]SAVE.DIR
(and the same on the playground directory itself). A file created there carries
(IDENTIFIER=[*,*],ACCESS=NONE). I will not pretend to know VMS’s evaluation order
by heart: what I measured is that its owner keeps full access (USER1 saved and
restored its game over and over), that SYSTEM (which holds BYPASS) can still
read the file and back it up with BACKUP, and that every other user is stopped.
Measured, as USER2, against USER1’s files on both machines:
USER2 tries | Result |
|---|---|
DIRECTORY/SECURITY of the save file | insufficient privilege or object protection violation |
TYPE or COPY the save file | %RMS-E-PRV, insufficient privilege or file protection violation |
DELETE it | %RMS-E-PRV ... |
RENAME it | %RMS-F-RMV, ACP remove function failed ... NOPRIV |
APPEND NL: to it, SET FILE/PROTECTION, SET FILE/OWNER | refused |
COPY NL: ...same.name or COPY LOGIN.COM ...same.name (a new version with the same name, which would otherwise be what NetHack opens first) | %RMS-E-PRV ... |
| the same on the level files and lock file of a running game | refused |
DELETE or SET FILE/PROTECTION the program NETHACK.EXE | refused |
create and delete a file of its own in [.SAVE] | allowed |
USER1 saved and restored its game normally throughout, RECOVER rebuilt a
save file from the level files of a game I killed with STOP/ID, and a second
player’s game ended in the shared score list (“You made the top ten list!”),
updated in place.
Two details in the installer matter: the ACEs are put on the directories last
and taken off first. If they are on while the kit is restored, every
program file inherits NONE and nobody can run the game, and the same would
happen to the shared state files.
What this does not protect (residual risk)
- The shared files are world-writable.
RECORD,LOGFILE,PERMandPANICLOGare appended to by every player, so every local user can edit or delete the score list. Closing that needs the installed image with an identifier, which needsINSTALL,CMKRNLand a startup entry; this kit does not do that. - Bones files are private too, so one player never meets another’s ghost.
- The playground is world-writable, so anyone can fill it (disk quota is the only limit).
SHELL(the!command) and wizard mode are as the distribution ships them:!is compiled in; wizard mode needs the userNHWIZARD, who does not exist.
Tests
These are all measured, not estimated, on the real machines, as the
unprivileged accounts USER1 and USER2 over Telnet from a VT200-type
terminal:
LIFECYCLE_TEST.COM: install; refused second install; uninstallCHECK; uninstall that keeps a changed file and a user’s file; uninstall and reinstall;REPLACE; a score list entry survives all of it; ends with a clean tree. 25 of 25 passed in 42 seconds on the 4000/90 and 69 seconds on the 4000/60.- Start a game, 10 turns,
S, restore,S, restore,#quit; the log file (LOGFILE) gets one line per game; a game with points goes intoRECORDandNETHACK "-s" "all"lists it for the other user. - The table above, on both machines.
SHOW USERSandSHOW SYSTEMafter every session: no game process left behind, no level file, no save file.
Not Measured
- I did not try the build with VAX C or GNU C (the distribution’s notes say VAX C 3.2 and GNU C 2.7.1 worked on V5.5-2), nor on a simulator.
- I did not build the installed-image variant that would protect the score list; the paragraph above is why not, not a test result.
Licence
NetHack is under the NetHack General Public License (Copyright 1989 M. Stephenson, derived from the Bison GPL): you may copy and distribute it, source and binaries, if the licence and the means to get the source stay with it, and a modified version must say that it is modified. This kit is the unmodified source built with one configuration value; the source kit above is the corresponding source. The installer, uninstaller, setup procedure and test procedures are mine.
