From 359f9b80c109fef28f15f9d16713720afffceb37 Mon Sep 17 00:00:00 2001 From: Lars Erik Wik Date: Tue, 8 Oct 2024 18:29:01 +0200 Subject: [PATCH] Atomic copy_from in files promise Changes to `files` promise in `copy_from` attribute: - The new file (i.e., `.cfnew`) is now created with correct permission during remote copy. Previously it would be created with default permissions. - The destination file (``) is no longer deleted on backup during file copy. Previously it would be renamed to .cfsaved, causing the original file to dissappear. Now an actual copy of the original file with the same permissions is created instead. As a result, there will no longer be a brief moment where the original file is inaccessible. Ticket: ENT-11988 Changelog: Commit Signed-off-by: Lars Erik Wik --- cf-agent/verify_files_utils.c | 4 ++-- libcfnet/client_code.c | 4 ++-- libcfnet/client_code.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cf-agent/verify_files_utils.c b/cf-agent/verify_files_utils.c index db18da5091..64505eb0ff 100644 --- a/cf-agent/verify_files_utils.c +++ b/cf-agent/verify_files_utils.c @@ -1552,7 +1552,7 @@ bool CopyRegularFile(EvalContext *ctx, const char *source, const char *dest, con } if (!CopyRegularFileNet(source, ToChangesPath(new), - sstat->st_size, attr->copy.encrypt, conn)) + sstat->st_size, attr->copy.encrypt, conn, sstat->st_mode)) { RecordFailure(ctx, pp, attr, "Failed to copy file '%s' from '%s'", source, conn->remoteip); @@ -1712,7 +1712,7 @@ bool CopyRegularFile(EvalContext *ctx, const char *source, const char *dest, con } } - if (rename(dest, changes_backup) == 0) + if (FileCopyKeepPerms(dest, changes_backup)) { RecordChange(ctx, pp, attr, "Backed up '%s' as '%s'", dest, backup); *result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE); diff --git a/libcfnet/client_code.c b/libcfnet/client_code.c index f31463c385..7dccb88324 100644 --- a/libcfnet/client_code.c +++ b/libcfnet/client_code.c @@ -750,7 +750,7 @@ static void FlushFileStream(int sd, int toget) /* TODO finalise socket or TLS session in all cases that this function fails * and the transaction protocol is out of sync. */ bool CopyRegularFileNet(const char *source, const char *dest, off_t size, - bool encrypt, AgentConnection *conn) + bool encrypt, AgentConnection *conn, mode_t mode) { char *buf, workbuf[CF_BUFSIZE], cfchangedstr[265]; const int buf_size = 2048; @@ -774,7 +774,7 @@ bool CopyRegularFileNet(const char *source, const char *dest, off_t size, unlink(dest); /* To avoid link attacks */ - int dd = safe_open_create_perms(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_BINARY, CF_PERMS_DEFAULT); + int dd = safe_open_create_perms(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_BINARY, mode); if (dd == -1) { Log(LOG_LEVEL_ERR, diff --git a/libcfnet/client_code.h b/libcfnet/client_code.h index d926541721..4aaaa5ff4c 100644 --- a/libcfnet/client_code.h +++ b/libcfnet/client_code.h @@ -48,7 +48,7 @@ void DisconnectServer(AgentConnection *conn); bool CompareHashNet(const char *file1, const char *file2, bool encrypt, AgentConnection *conn); bool CopyRegularFileNet(const char *source, const char *dest, off_t size, - bool encrypt, AgentConnection *conn); + bool encrypt, AgentConnection *conn, mode_t mode); Item *RemoteDirList(const char *dirname, bool encrypt, AgentConnection *conn); int TLSConnectCallCollect(ConnectionInfo *conn_info, const char *username);