https://gitlab.synchro.net/main/sbbs/-/issues/1202#note_9744
Fixed in `d394e7bef6` (2026-07-26): `CopyFile()` now `fstat()`s the source and `fchmod()`s the destination to match, beside the existing `setfdate()` call. The
mode is masked to `0777`, so set-user-ID and set-group-ID bits are not propagated to a copy.
Measured before and after, umask 022:
| source mode | before | after |
|---|---|---|
| 0755 | 0644 | 0755 |
| 0770 | 0644 | 0770 |
| 0600 | 0644 | 0600 |
| 0666 | 0644 | 0666 |
| 04755 | 0644 | 0755 |
Every destination was 0644 regardless of the source; each now matches, with the set-user-ID case landing as 0755.
The same omission turned out to exist in Synchronet's own copy routine, `nopen.c`'s `fcopy()`, which creates its destination through `nopen()` at `DEFFILEMODE & ~umask`. That one is worse in effect than a lost execute bit: its
only caller is `backup()`, and on the copy path `backup()` backs up `user.tab` and the user index, the mail base, `sbbs.ini`, and SBBSecho's configuration — which holds node passwords. Under the default umask a backup of a 0600 file was world-readable at 0644, so the copy was *widening* permissions, and `backup()` was inconsistent with itself: its rename path keeps the original's mode because `rename()` keeps the inode. Fixed the same way in `dc6bd4c407` (2026-07-26), and
that function is now named `nfcopy()` (`faf0950ba4`, 2026-07-26) to mark it as the share-aware, retrying counterpart of `CopyFile()` rather than a second routine that does the same job.
Release note added for v3.22 in `0f26bcb87e` (2026-07-26).
Reported after a sysop hit it installing a game door, whose binary arrived non-executable; the door deploy helper's own chmod workaround
(`03a61c1973`, 2026-07-26) is redundant against a fixed xpdev but harmless, and still earns its keep on systems building against an older one.
— *Authored by Claude (Claude Code), on behalf of @rswindell*
--- SBBSecho 3.37-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)