• Web Server: anonymous file-vpath downloads bypass the credit check (FT

    From Rob Swindell@1:103/705 to GitLab issue in main/sbbs on Fri Jul 31 21:43:33 2026
    close https://gitlab.synchro.net/main/sbbs/-/issues/1192
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell@1:103/705 to GitLab note in main/sbbs on Sat Aug 1 20:35:45 2026
    https://gitlab.synchro.net/main/sbbs/-/issues/1192#note_9886

    Fixed, but one claim in the report above needs correcting: the credit gate
    was described as sitting past the password check, so that only authenticated sessions reached it. That is true of the control flow, but it implies the gate worked for those sessions. It did not work for anyone.

    `resolve_vpath()` loaded the file record at `file_detail_index`, and `smb_getfile()` skips `smb_getmsghdr()` entirely at that detail level, while `cost` is only ever set from the `SMB_COST` header field. So `session->file.cost` was always 0, and the authenticated comparison (`download_is_free() || session->user.cdt >= session->file.cost`) reduced to `cdt >= 0`: always true.

    Two consequences beyond what the report describes:

    - Costed files downloaded free of charge for authenticated users as well as
    anonymous ones.
    - `user_downloaded_file()` still billed the account after the transfer,
    because it reloads the record itself at `file_detail_normal`. A user with
    fewer credits than the file cost was allowed the download and then charged
    for it, so an account could go credit-negative.

    Fixed in two commits:

    - 72303693ef (zinc-13-these, 2026-07-31) applies the credit gate to the
    unauthenticated path and puts both authorization paths on a single shared
    predicate, so they cannot drift apart again. The gate now measures cost
    against `user_available_credits()` rather than `user.cdt`, so free credits
    count toward a download as they already do on the Terminal and FTP servers,
    and as `subtract_cdt()` already assumed when charging: it spends free
    credits first.
    - 4de1032086 (payroll-20-queue, 2026-08-01) reads the header record, so the
    cost is a real value. A free directory still loads at index detail alone,
    since `loadfile()` zeroes the cost there and `download_is_free()`
    short-circuits on the same `DIR_FREE` flag before any credit comparison.

    Verified against a live file base, using two files in the same non-free directory with no ARS, differing only in cost:

    - costed file (2,639,434 credits), unauthenticated: `401 Unauthorized`, logged
    as `!Unauthenticated download denied (reason: 262)`, that being
    `NotEnoughCredits`
    - zero-cost file, same directory, unauthenticated: `200`, transfers in full
    - file in a `DIR_FREE` directory: `200`, transfers in full

    For sysops running `FileVPathPrefix`: files carrying a credit cost are no longer downloadable without authentication, which is what anonymous FTP has always done. If a published archive should stay open to the web, mark the directory's downloads free or give it an exempt ARS.

    -- *Authored by Claude (Claude Code), on behalf of @rswindell*
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)