config: keep Store mirrors authoritative
Debian Trixie package bundle / packages (push) Successful in 22m24s

This commit is contained in:
Mario Fetka
2026-07-27 21:33:35 +02:00
parent 1056e0c489
commit fbb5c97ab0
4 changed files with 135 additions and 12 deletions
+111
View File
@@ -28,12 +28,14 @@
#include <nmlib.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <syslog.h>
#include <time.h>
@@ -273,12 +275,103 @@ ReadConfigurationInput(char **content, size_t *length)
return 0;
}
static int
WriteConfigurationMirror(const char *name, const char *content, size_t length,
uint64_t modified)
{
char path[XPL_MAX_PATH + 1];
char temporary[XPL_MAX_PATH + 32];
struct stat details;
struct timespec times[2];
const char *cursor = content;
size_t remaining = length;
int descriptor = -1;
int directory = -1;
int saved_error = 0;
int result = 0;
temporary[0] = '\0';
/* Alias Store documents are a compiled per-domain view of aliases.d,
* rather than a one-to-one local document. Public alias operations
* therefore update aliases.d transactionally before the manager compiles
* that view. */
if (strchr(name, '/'))
return 1;
if (snprintf(path, sizeof(path), "%s/%s", XPL_DEFAULT_CONFIG_DIR, name) >=
(int)sizeof(path) ||
snprintf(temporary, sizeof(temporary), "%s.tmp.XXXXXX", path) >=
(int)sizeof(temporary)) {
errno = ENAMETOOLONG;
goto done;
}
if (lstat(path, &details) != 0 || !S_ISREG(details.st_mode)) {
fprintf(stderr,
"bongo-admin: configuration mirror is missing or unsafe: %s\n",
path);
errno = EINVAL;
goto done;
}
times[0] = details.st_atim;
times[1].tv_sec = (time_t)modified;
times[1].tv_nsec = 0;
if ((uint64_t)times[1].tv_sec != modified ||
(descriptor = mkstemp(temporary)) < 0)
goto done;
while (remaining) {
ssize_t written = write(descriptor, cursor, remaining);
if (written < 0) {
if (errno == EINTR)
continue;
goto done;
}
cursor += written;
remaining -= (size_t)written;
}
if (fchmod(descriptor, details.st_mode & 0777) != 0 ||
fchown(descriptor, details.st_uid, details.st_gid) != 0 ||
futimens(descriptor, times) != 0 || fsync(descriptor) != 0)
goto done;
if (close(descriptor) != 0) {
descriptor = -1;
goto done;
}
descriptor = -1;
if (rename(temporary, path) != 0)
goto done;
temporary[0] = '\0';
result = 1;
directory = open(XPL_DEFAULT_CONFIG_DIR,
O_RDONLY | O_DIRECTORY | O_CLOEXEC);
if (directory < 0 || fsync(directory) != 0)
fprintf(stderr,
"bongo-admin: warning: cannot sync configuration directory: %s\n",
strerror(errno));
done:
saved_error = errno;
if (descriptor >= 0)
close(descriptor);
if (directory >= 0)
close(directory);
if (!result && temporary[0])
unlink(temporary);
errno = saved_error;
if (!result)
fprintf(stderr,
"bongo-admin: cannot update configuration mirror %s: %s\n",
path, strerror(errno));
return result;
}
static int
AccessConfiguration(const char *name, int replace)
{
BongoJsonNode *root = NULL;
char *content = NULL;
char *original = NULL;
size_t length = 0;
uint64_t modified = 0;
int conn_started = 0;
int msg_started = 0;
int result = 1;
@@ -309,11 +402,27 @@ AccessConfiguration(const char *name, int replace)
goto done;
}
if (replace) {
if (!strchr(name, '/') &&
(!NMAPReadConfigFile(name, &original) || !original)) {
fprintf(stderr,
"bongo-admin: cannot snapshot configuration %s\n", name);
goto done;
}
if (!NMAPReplaceConfigFile(name, content, length)) {
fprintf(stderr, "bongo-admin: cannot replace configuration %s\n",
name);
goto done;
}
if (!strchr(name, '/') &&
(!NMAPReadConfigFileModified(name, &modified) ||
!WriteConfigurationMirror(name, content, length, modified))) {
if (!original ||
!NMAPReplaceConfigFile(name, original, strlen(original)))
fprintf(stderr,
"bongo-admin: CRITICAL: cannot roll back configuration %s\n",
name);
goto done;
}
openlog("bongo-admin", LOG_PID, LOG_AUTHPRIV);
syslog(LOG_NOTICE, "administrator replaced Bongo configuration %s",
name);
@@ -334,6 +443,8 @@ AccessConfiguration(const char *name, int replace)
done:
if (root)
BongoJsonNodeFree(root);
if (original)
MemFree(original);
if (content) {
if (replace)
free(content);
+1 -3
View File
@@ -834,9 +834,7 @@ SyncConfigurationDocument(const char *storeName, const char *path)
result = SetConfigurationFileTime(path, &details, storeModified);
goto done;
}
if ((uint64_t)details.st_mtime > storeModified ||
((uint64_t)details.st_mtime == storeModified &&
details.st_mtim.tv_nsec != 0)) {
if ((uint64_t)details.st_mtime > storeModified) {
if (!SyncConfigurationContent(storeName, path, local) ||
!NMAPReadConfigFileModified(storeName, &storeModified))
goto done;