fix(a7-3/s1): fail closed on non-loopback peers; require plaintext opt-in before challenge
utils_fd_peer_is_local now returns true only when getpeername SUCCEEDS and the peer address classifies as loopback. A non-socket descriptor (pipe/socketpair) or any getpeername error is NOT local, so the daemon auth gate fails closed instead of treating an untestable --stdio pipe as trusted (daemon auth modules are --daemon-only and the stdio path never loads a daemon config). server_module_gate now requires --allow-unauthenticated for the loopback plaintext auth path: a plaintext loopback connection without the operator opt-in is refused at the config gate BEFORE server_auth_handshake, so no SCRAM challenge is sent. Remote peers still require verified TLS regardless of the flag; the handler keeps its defense-in-depth checks. Docs state the exact policy (verified TLS with matching --client-cn, or operator-opted-in loopback plaintext), drop the SSH/stdio auth-transport claim (they are daemon-only), and add the loopback trust-boundary relay caveat and the CN-only (no SAN) residual. Adds a unit-test negative for pipe/socketpair and an integration test where a relay observes no challenge when the flag is absent.
This commit is contained in:
+11
-8
@@ -383,19 +383,22 @@ static const char* server_module_gate(const Config* config, void* context) {
|
||||
"store is configured";
|
||||
}
|
||||
/* Transport policy (A7-3/S1): an auth-required module only accepts
|
||||
* credentials over an encrypted, verified TLS connection whose client
|
||||
* certificate matches --client-cn, or over a local/SSH transport (a
|
||||
* loopback TCP peer, or the --stdio pipe). A remote plaintext peer is
|
||||
* refused HERE, before the challenge is sent, so an unverified client never
|
||||
* receives a nonce. --allow-unauthenticated is intentionally NOT consulted:
|
||||
* that flag relaxes the standalone plaintext gate, never this one. */
|
||||
* credentials over (a) an encrypted, verified TLS connection whose client
|
||||
* certificate matches --client-cn, or (b) a plaintext connection from a
|
||||
* loopback peer that the operator explicitly opted into with
|
||||
* --allow-unauthenticated. A remote plaintext peer and an un-flagged
|
||||
* loopback plaintext peer are both refused HERE, before the challenge is
|
||||
* sent, so an unverified client never receives a nonce. The operator flag
|
||||
* never permits REMOTE plaintext auth: remote peers still require verified
|
||||
* TLS regardless of the flag. */
|
||||
bool tls_ok = gate_ctx && gate_ctx->ssl && SSL_get_verify_result(gate_ctx->ssl) == X509_V_OK &&
|
||||
tls_client_identity_allowed(gate_ctx->ssl);
|
||||
bool local_ok = gate_ctx && gate_ctx->fd >= 0 && utils_fd_peer_is_local(gate_ctx->fd);
|
||||
bool local_ok = allow_unauthenticated && gate_ctx && gate_ctx->fd >= 0 &&
|
||||
utils_fd_peer_is_local(gate_ctx->fd);
|
||||
if (!tls_ok && !local_ok) {
|
||||
log_message(LOG_LEVEL_ERROR,
|
||||
"daemon module '%s' requires authentication over an encrypted, verified TLS "
|
||||
"connection (or a local/SSH transport); refusing",
|
||||
"connection (or an opted-in loopback plaintext transport); refusing",
|
||||
config->module);
|
||||
return "daemon module requires authentication over an encrypted, verified TLS "
|
||||
"connection";
|
||||
|
||||
Reference in New Issue
Block a user