This PR fixes an issue where, after an unclean exit, Webmin can leave `miniserv.pid` behind.
If the kernel later reuses that PID for an unrelated process, the startup guard only checked that the PID was alive and refused to start with “Webmin is already running”.
With systemd restart handling, this can leave Webmin permanently down until the PID file is manually removed.
This change verifies that the live PID actually belongs to `miniserv.pl` running the same config before treating it as an active Webmin instance.
On Linux, it reads `/proc/<pid>/cmdline`, checks the miniserv script, and compares the config file by inode so symlinked paths still match and Usermin is correctly distinguished.
If the PID is confirmed unrelated, the stale PID file is removed and startup continues. If the process cannot be inspected, the previous conservative behavior is preserved.
Also hardens PID-file parsing with chomp and numeric validation, and adds tests for unrelated PID reuse, matching config, symlinked config, different miniserv config, and unreadable command-line fallback.
This PR ensure proxied WebSocket backend writes complete the full buffer for both TLS and plain TCP connections.
Fail backend handshakes cleanly if writes cannot be completed, preventing truncated headers or frames from corrupting linked WebSocket tunnels.
Originally hinted by this code review: d1d1bad4ae (r189931785)
ⓘ Remove single-use ws-link routes when backend setup fails or after the backend handshake is consumed, with final loop cleanup kept as a fallback.
This prevents failed linked websocket retries from leaving temporary credential-bearing routes in `miniserv.conf`.
ⓘ Require websocket routes to opt in with allow_basic_ws before Basic auth is accepted in session mode. Mark linked ws-link routes and no-cookie backend-session routes as allowed, while leaving normal session-backed routes unmarked.
ⓘ Check OpenSSL's pending buffer before `select()` in the websocket forwarding loop so TLS-backed linked websocket streams do not stall during bursty backend output.
This PR adds general WebSocket proxying for linked Webmin servers, allowing modules such as `xterm` to work when opened through `servers/link.cgi`.
As requested in https://github.com/webmin/webmin/issues/1866.
This PR fixes Webmin IP access control handling for IPv6 CIDR prefixes that are not divisible by 8, such as `/29` as mentioned in this https://github.com/webmin/webmin/issues/1570 ticket.
Before Webmin validation rejected non-byte-aligned IPv6 network sizes, and the runtime matcher compared IPv6 networks only by whole bytes. This meant valid IPv6 CIDR prefixes could not be used safely in access control rules.
Changes:
- Allow IPv6 access-control prefixes from `/0` through `/128`, without requiring divisibility by 8.
- Add bit-accurate IPv6 prefix matching for ACL checks.
- Apply the same matching behavior in both `miniserv.pl` and `webmin/webmin-lib.pl`.
- Fix IPv6 canonicalization for `::` and trailing `::` forms used by the matcher.
- Add regression tests for `/0`, `/29`, `/32`, `/63`, `/64`, `/127`, and `/128`.
setup_ssl_contexts() registers CTX_set_tlsext_servername_callback only
on the default (*) context. Per-IP contexts from ipcert entries do not
get the callback. When a client connects to a dedicated IP, the per-IP
context is used directly, the SNI callback never fires, and the wrong
certificate is served regardless of the requested hostname.
Fix: register the same SNI callback on every context in %ssl_contexts.
The callback function is unchanged. Clients without SNI still receive
the per-IP certificate. Clients with SNI get the correct certificate
matched by hostname.
Related: https://github.com/virtualmin/virtualmin-gpl/pull/1229
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Note: Declare the SSL certificate lookup user as lexical inside `handle_request`, so a previously matched client certificate user cannot survive into later keep-alive requests handled by the same miniserv child.
Enlightened by: https://github.com/webmin/webmin/pull/2699
* Note: Fix Miniserv IPv6 hostname resolution and matching used by access control when `alwaysresolve` is enabled:
1. Correct `to_ip6address()` success handling (before getaddrinfo result was interpreted backwards)
2. In `ip_match()`, resolve hostnames with `to_ip6address()` for IPv6 clients instead of IPv4-only `to_ipaddress()`
3. Canonicalize IPv6 addresses before reverse and forward verification to avoid format-based mismatches.
4. Mirror the IPv6 logic change in "webmin/webmin-lib.pl"
https://forum.virtualmin.com/t/webmin-access-control-for-domain-names-with-ipv6/136661?u=ilia