• 3rdp/dist/Botan.tar.xz src/build/botan.gmake src/ssh/posix/threads.c t

    From Deucе@1:103/705 to Git commit to main/sbbs/master on Thu Apr 23 03:33:46 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/8f25a245bb9a6abc4b191b69
    Added Files:
    3rdp/dist/Botan.tar.xz src/build/botan.gmake src/ssh/posix/threads.c threads.h src/ssh/win32/threads.c threads.h src/syncterm/ini_crypt.c ini_crypt.h src/syncterm/legacy_ciphers/idea.c legacy_ciphers.h rc2.c register.c src/syncterm/xp_crypt.h xp_crypt_botan3.cpp xp_crypt_none.c xp_crypt_openssl.c xp_sndfile.c xp_sndfile.h xp_tls.h xp_tls_botan3.cpp xp_tls_none.c xp_tls_openssl.c src/xpdev/extdeps.mk
    Modified Files:
    .gitlab-ci-unix.yml .gitlab-ci.yml 3rdp/build/Common.gmake GNUmakefile src/build/Common.gmake src/doors/gac/gac_bj/src/GNUmakefile src/doors/gac/gac_fc/src/GNUmakefile src/doors/gac/gac_wh/src/GNUmakefile src/ssh/CMakeLists.txt TODO.md deucessh-portable.h src/ssh/kex/sntrup761.c src/ssh/key_algo/rsa-sha2-256-botan.cpp rsa-sha2-512-botan.cpp ssh-ed25519-botan.cpp src/ssh/ssh-internal.h ssh-trans.c src/syncterm/CHANGES CMakeLists.txt GNUmakefile audio_apc.c bbslist.c bbslist.h build.bat conn.c release.bat ssh.c ssh.h syncterm.c syncterm.h targets.mk telnets.c webget.c src/xpdev/CMakeLists.txt Common.gmake GNUmakefile ini_file.c ini_file.h xpbeep.c
    Log Message:
    SyncTERM: drop Cryptlib — move SSH to DeuceSSH + TLS/symmetric crypto
    to OpenSSL or Botan 3

    SyncTERM's SSH, TLS (TelnetS + HTTPS cache refresh), and encrypted-
    bbslist.ini paths all ran through a single monolithic Cryptlib
    dependency. Cryptlib is aging, actively deprecated in parts of
    Synchronet, and its opaque session model fit awkwardly with
    SyncTERM's ring-buffered I/O threads. This branch ports all of it:

    - SSH: Cryptlib → DeuceSSH (src/ssh/, from-scratch library
    already maintained in this repo).
    - TLS client: Cryptlib → xp_tls shim backed by OpenSSL or Botan 3.
    - Encrypted
    bbslist.ini: Cryptlib KDF + ciphers → xp_crypt shim backed by the
    same two backends.

    DeuceSSH's explicit-callback API maps cleanly onto SyncTERM's ring
    buffers; its test suite + branch coverage live alongside. All three
    workloads share a single backend choice at compile time.

    Architecture
    ------------

    - xp_tls.[ch] (syncterm/): thin client-TLS API — open/push/pop/
    flush/close — matching the shape of the old inline
    cryptPushData / cryptPopData calls in telnets.c and
    webget.c. OpenSSL / Botan 3 / none stubs.
    - xp_crypt.[ch] (syncterm/): thin symmetric-crypto + KDF API —
    xp_crypt_open(algo, keySize, salt, kdf, pwd, encrypt)
    → handle-based process(buf, n) semantics. Same
    backend trio.
    - ini_crypt.c (syncterm/): iniReadEncryptedFile /
    iniWriteEncryptedFile built on xp_crypt + ini_file.c.
    Moved out of xpdev so libxpdev / libsbbs /
    Synchronet server binaries don't transitively
    depend on OpenSSL / Botan 3 when they don't use TLS
    or encrypted INI themselves.
    - src/ssh/ DeuceSSH: src/syncterm/ssh.c rewritten against its
    native session + channel API. Algorithm preferences
    registered once at init; host-key callback does
    SHA-256 fingerprint verification; authentication
    tries pubkey → password → keyboard-interactive;
    channel setup passes terminal type + PTY size; resize
    via dssh_chan_send_window_change.
    - SFTP pubkey
    upload: ssh.c's add_public_key() rewritten on top of a
    DeuceSSH "sftp" subsystem channel. src/sftp/ itself
    had zero Cryptlib references and is unchanged.

    Encrypted bbslist.ini format
    ----------------------------

    Reader honours both on-disk formats so existing files keep opening:

    v1 (Cryptlib era): PBKDF2-HMAC-SHA256, KDFiterations literal. Any
    of 3DES / IDEA / CAST / RC2 / RC4 / AES / ChaCha20.
    v2 (new writes): scrypt, N=2^15 / r=8 / p=1 by default — KDF
    parameters embedded in the header so the reader
    never has to guess. Write-side cipher choice
    restricted to AES-256 and ChaCha20; the list-
    encryption menu drops the legacy-cipher options.

    Legacy-read support: OpenSSL's legacy provider (3DES / CAST5 / RC4)
    is loaded lazily on first decrypt; IDEA and RC2
    don't exist in either backend today, so
    SyncTERM ships bundled decrypt-only reference
    implementations (src/syncterm/legacy_ciphers/)
    registered with xp_crypt at startup.

    Automatic v1 → v2 migration:
    iniReadBBSList does a one-shot migration
    immediately after a successful decrypt of the
    user bbslist. A PBKDF2 KDF or a
    3DES/IDEA/CAST/RC2/RC4 cipher triggers
    re-encryption as AES-256 + scrypt and a matching
    update to syncterm.ini's KeyDerivationIterations
    setting. Both files (bbslist r+b,
    syncterm.ini r+) are opened and syncterm.ini is
    pre-read before either is mutated; any open or
    write failure emits a uifc.msg and exit(
    EXIT_FAILURE) so in-memory algo / keysize / KDF
    spec can't drift out of sync with disk. On the
    good-path the bbslist is rewritten first, then
    the syncterm.ini setting; the original PBKDF2
    iteration hint survives until both writes
    commit.

    KeyDerivationIterations:
    Now a KDF-spec string in syncterm.ini, not an
    integer. New installs get "scrypt-N15" (N=2^15
    = 32,768, ~16 MiB). Cryptlib-era digit values
    (e.g. "50000") are still recognised on read as
    the PBKDF2 iteration hint for v1 files and
    survive until the auto-migration above rewrites
    them. The config menu still takes an integer
    from the user — scrypt's cost_log2 (8..24) —
    stored as "scrypt-N<X>"; writer parses the
    string and falls back to the compiled-in default
    for anything it can't interpret as scrypt, so
    a PBKDF2-shaped write is impossible by
    construction. iniWriteEncryptedFile's parameter
    type switched from int KDFiterations to
    const char *kdf_spec to match.

    SSH host-key fingerprints
    -------------------------

    Stored SHA-1 fingerprints from pre-migration bbslist.ini files remain
    valid on first reconnect — on a match, the stored value is silently
    upgraded to SHA-256. The three-option mismatch dialog
    (Disconnect / Update / Ignore) is preserved.

    Build-time knobs
    ----------------

    - DEUCESSH_BACKEND / OpenSSL | Botan. Shared probe in
    XP_CRYPTO_BACKEND build/Common.gmake picks one for the
    whole tree so every subproject of a
    given source tree + command-line
    agrees. Cached libxpdev_mt.a
    interoperates with its downstream
    linkers.
    - USE_VENDORED_BOTAN Fall back to building Botan 3 from
    3rdp/dist/Botan.tar.xz when neither
    system Botan 3.6+ nor OpenSSL 3.0+ is
    available. Windows cross-compile
    always uses vendored. A shared
    3rdp/build `botan:` delegation target
    mirrors the existing `cryptlib:`
    machinery.
    - WITHOUT_DEUCESSH Drops src/syncterm/ssh.c,
    CONN_TYPE_SSH / _SSHNA, the SFTP
    pubkey-upload bridge, and the
    DeuceSSH sub-build.
    - WITHOUT_CRYPTO Drops src/syncterm/telnets.c,
    CONN_TYPE_TELNETS, the encrypted
    bbslist.ini menu + dispatch, and the
    bundled legacy-cipher reference
    code. webget.c still compiles; its
    HTTPS paths no-op. xp_tls / xp_crypt
    fall back to "none" stub backends
    so nothing drags in OpenSSL or
    Botan 3.

    Auto-degradations so CI stays honest across the runner fleet:

    - Python 3 absent on Windows (needed for vendored Botan's
    configure.py) → WITHOUT_CRYPTO + WITHOUT_DEUCESSH.
    - Compiler cmake can't drive at C17, OR the SDK/libc doesn't ship
    the C11 runtime functions DeuceSSH uses (pre-10.15 macOS SDKs lack
    timespec_get / TIME_UTC even with an AppleClang that nominally
    supports -std=c17) → DeuceSSH configure fails → WITHOUT_DEUCESSH;
    the rest of syncterm still builds. DeuceSSH's CMakeLists probes
    timespec_get explicitly — CMake's C_STANDARD 17 +
    C_STANDARD_REQUIRED ON only checks compiler-version tables, not
    the actual SDK. DeuceSSH stays strict-C17 as its upstream-
    portability guarantee; the probe covers the handful of platforms
    that fall outside that window.

    The SyncTERM Build Options dialog reflects all of this — [*] / [ ]
    columns for DeuceSSH, OpenSSL, Botan 3, JPEG XL, libsndfile, display
    backends, audio backends — so users can tell at a glance what the
    binary they're running actually has.

    MinGW + MSVC + older macOS portability
    --------------------------------------

    DeuceSSH is strict C17. Added thin shims where the libc falls short
    of C11's <threads.h> requirement:

    - src/ssh/posix/threads.{h,c}: pthread → C11 threads wrapper
    (mtx_*, cnd_*, thrd_*). Platform-
    gated in DeuceSSH's CMakeLists via
    a HAVE_THREADS_IN_LIBC probe. Covers
    macOS pre-14 SDK, older NetBSD, any
    libc without <threads.h>.
    - src/ssh/win32/threads.{h,c}: CRITICAL_SECTION / CONDITION_VARIABLE
    / _beginthreadex wrapper. MinGW-w64
    and MSVC both lack the libc header.

    xpdev MSVC cmake: added /experimental:c11atomics (the hand-written xpdev.vcxproj has it; cmake path was missing it) and three C source
    files that had been in the gmake objects.mk but not the cmake
    SOURCE list (os_info.c, rwlockwrap.c, stbuf.c).

    SyncTERM MSVC Windows build moved onto cmake: src/syncterm/build.bat
    calls VsDevCmd.bat then cmake / nmake / msbuild. The hand-written SyncTERM.vcxproj + helpers are no longer the path of record.

    Build ordering + CI
    -------------------

    The top-level all-target rule is Botan → xpdev-mt → ciolib-mt →
    uifc-mt → (sftp-mt + deucessh) → syncterm. Both gmake and cmake
    paths pre-probe DeuceSSH's configure once the crypto backend it
    needs is on disk; if cmake can't produce deucessh.pc for any reason
    (C17 unsupported, incomplete C11 runtime, missing crypto headers,
    etc.), WITHOUT_DEUCESSH is set automatically and the main build
    continues.

    New .gitlab-ci-unix.yml [botan] job mirrors [cryptlib]: it runs
    `gmake botan`, archives 3rdp/*.release/botan, and on systems where
    the build is a no-op (system Botan/OpenSSL detected) produces an empty-directory placeholder archive so `tar -T /dev/null` never has
    to emit an empty tarball. The .pc file is rewritten to use ${pcfiledir}-relative prefix at install time so the archive relocates
    cleanly across runner concurrent-ids. [syncterm] extracts the
    archive; other jobs that don't build SyncTERM don't (dropping the
    botan.tgz extract + [botan] dep from 20+ non-syncterm jobs).
    [syncterm-cmake] also extracts the archive rather than building a
    second vendored copy via its own ExternalProject.

    Files moved / renamed
    ---------------------

    src/xpdev/{xp_tls,xp_crypt}*.[ch,cpp] →
    src/syncterm/{xp_tls,xp_crypt}*.[ch,cpp]
    src/xpdev/ini_crypt.c → src/syncterm/ini_crypt.c
    src/xpdev/ini_file.h : encrypted-INI decls moved to new
    src/syncterm/ini_crypt.h (including
    enum iniCryptAlgo); ini_file.h stays
    crypto-free.
    src/syncterm/sndfile.{h,c} → src/syncterm/xp_sndfile.{h,c}
    (the old name shadowed libsndfile's
    <sndfile.h> when the syncterm source dir
    was on -I path).

    Verification
    ------------

    SSH:
    - password auth, pubkey auth, keyboard-interactive auth against
    Synchronet test BBS.
    - first-connect fingerprint prompt; reconnect uses stored
    fingerprint; stored-SHA-1 upgrade to SHA-256 on next connect.
    - SFTP pubkey upload round-trip.

    TLS:
    - TelnetS handshake + interactive session against a known TelnetS
    BBS (Dave's, vert).
    - HTTPS: `lst://` bbslist refresh path; ETag / Last-Modified
    caching behaves unchanged.

    Encrypted bbslist.ini:
    - Read-compat: pre-migration files (AES-256, 3DES, ChaCha20, IDEA,
    RC2) all decrypt and populate entries. v1 PBKDF2 header is
    honoured; KDFiterations hint in syncterm.ini supplies the count.
    - Auto-migration: v1 files (PBKDF2 or legacy cipher) are
    re-encrypted as AES-256/scrypt in one shot at decrypt time,
    and syncterm.ini's KeyDerivationIterations is updated to
    "scrypt-N15" the same way. Any migration failure
    exit()s — next run retries from the untouched v1 state.
    - Round-trip: save encrypted → reload → verify entries.
    - Legacy-write UI gone — menu offers AES-256 + ChaCha20 only.
    - Scrypt params embedded in v2 header; reader reconstructs N / r /
    p from there rather than guessing.

    Automated:
    - cterm_test + termtest pass unchanged.
    - Disconnect from an active SSH session doesn't leak threads.

    Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)