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:
@@ -315,15 +315,24 @@ static void test_loopback_helpers() {
|
||||
|
||||
EXPECT_FALSE(utils_sockaddr_is_loopback(NULL));
|
||||
|
||||
/* A pipe has no socket peer: getpeername fails with ENOTSOCK, which is the
|
||||
--stdio/SSH case and must count as local. */
|
||||
/* A pipe has no socket peer: getpeername fails with ENOTSOCK. The helper is
|
||||
fail-closed, so an unprovable channel is NOT local (daemon auth modules are
|
||||
daemon-only and never run over the --stdio pipe). */
|
||||
int pipe_fds[2];
|
||||
EXPECT_EQ_INT(pipe(pipe_fds), 0);
|
||||
EXPECT_TRUE(utils_fd_peer_is_local(pipe_fds[0]));
|
||||
EXPECT_FALSE(utils_fd_peer_is_local(pipe_fds[0]));
|
||||
close(pipe_fds[0]);
|
||||
close(pipe_fds[1]);
|
||||
EXPECT_FALSE(utils_fd_peer_is_local(-1));
|
||||
|
||||
/* A connected AF_UNIX socketpair is a socket, but its peer is not a loopback
|
||||
IP address, so it is not local either. */
|
||||
int pair_fds[2];
|
||||
EXPECT_EQ_INT(socketpair(AF_UNIX, SOCK_STREAM, 0, pair_fds), 0);
|
||||
EXPECT_FALSE(utils_fd_peer_is_local(pair_fds[0]));
|
||||
close(pair_fds[0]);
|
||||
close(pair_fds[1]);
|
||||
|
||||
/* A real loopback TCP peer is local. */
|
||||
int listener = socket(AF_INET, SOCK_STREAM, 0);
|
||||
EXPECT_TRUE(listener >= 0);
|
||||
|
||||
Reference in New Issue
Block a user