fix(a7-3/s1): require TLS or local transport for daemon auth

Daemon modules that declare 'auth users' no longer accept credentials over a
remote plaintext connection: server_module_gate refuses at the config gate,
before any SCRAM challenge is sent, unless the connection is verified TLS with
a client certificate matching --client-cn, or a local/SSH transport (loopback
TCP peer or the --stdio pipe). --allow-unauthenticated does not relax this.

The TLS client-CN comparison now uses credentials_secure_equal (S2). Clients
sending --password-file to a non-loopback daemon must use --tls; validate_config
rejects the plaintext case before any network I/O.

Adds utils_sockaddr_is_loopback / utils_fd_peer_is_local / utils_host_is_loopback
helpers with unit tests, a client validation unit test, and integration tests
for the client-side plaintext rejection and the wrong-CN gate refusal.
This commit is contained in:
2026-09-12 19:02:05 +02:00
parent 2489d422e5
commit a7a1930e88
9 changed files with 312 additions and 11 deletions
+10
View File
@@ -3,6 +3,7 @@
#include "delay_updates.h"
#include "log.h"
#include "usage.h"
#include "utils.h"
#include <string.h>
#include <stdio.h>
@@ -136,6 +137,15 @@ bool validate_config(const Config* config) {
return false;
}
}
/* Daemon credentials (A7, protocol 2.19.0): a --password-file would send the
username in the clear and derive a SCRAM proof a network sniffer could
attack offline, so it is only allowed over TLS (which itself mandates a
verified --cert/--key/--ca set above) or to a loopback destination. A
remote plaintext daemon is refused here, before any network I/O. */
if (config->password_file && !config->use_tls && !utils_host_is_loopback(config->server_host)) {
log_message(LOG_LEVEL_ERROR, "sending daemon credentials to a non-local server requires --tls");
return false;
}
if (config->delay_updates && config->inplace) {
log_message(LOG_LEVEL_ERROR, "--delay-updates does not work with --inplace");
return false;