Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 116 additions & 27 deletions cf-agent/files_changes.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@
#include <eval_context.h>
#include <known_dirs.h>

bool IsChangeSilenced(const Attributes *attr, FileChangeSilence category)
{
assert(attr != NULL);
return (attr->change.silence & category) != 0;
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
}

/*
The format of the changes database is as follows:

Expand Down Expand Up @@ -495,10 +501,13 @@
different = (memcmp(digest, dbdigest, size) != 0);
if (different)
{
Log(LOG_LEVEL_INFO, "Hash '%s' for '%s' changed!", HashNameFromId(type), filename);
if (pp->comment)
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_CONTENT))
{
Log(LOG_LEVEL_VERBOSE, "Preceding promise '%s'", pp->comment);
Log(LOG_LEVEL_INFO, "Hash '%s' for '%s' changed!", HashNameFromId(type), filename);
if (pp->comment)

Check notice

Code scanning / CodeQL

Pointer argument is dereferenced without checking for NULL Note

Parameter pp in FileChangesCheckAndUpdateHash() is dereferenced without an explicit null-check
{
Log(LOG_LEVEL_VERBOSE, "Preceding promise '%s'", pp->comment);

Check notice

Code scanning / CodeQL

Pointer argument is dereferenced without checking for NULL Note

Parameter pp in FileChangesCheckAndUpdateHash() is dereferenced without an explicit null-check
}
}
}
}
Expand All @@ -521,9 +530,16 @@
{
const char *action = found ? "Updated" : "Stored";
char buffer[CF_HOSTKEY_STRING_SIZE];
RecordChange(ctx, pp, attr, "%s %s hash for '%s' (%s)",
action, HashNameFromId(type), filename,
HashPrintSafe(buffer, sizeof(buffer), digest, type, true));
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_CONTENT))
{
RecordChange(ctx, pp, attr, "%s %s hash for '%s' (%s)",
action, HashNameFromId(type), filename,
HashPrintSafe(buffer, sizeof(buffer), digest, type, true));
}
else
{
SetPromiseOutcomeClasses(ctx, PROMISE_RESULT_CHANGE, &(attr->classes));
}
*result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE);

WriteHash(dbp, type, filename, digest);
Expand All @@ -548,9 +564,12 @@
return ret;
}

bool FileChangesLogNewFile(const char *path, const Promise *pp)
bool FileChangesLogNewFile(const char *path, const Promise *pp, bool silent)
{
Log(LOG_LEVEL_NOTICE, "New file '%s' found", path);
if (!silent)
{
Log(LOG_LEVEL_NOTICE, "New file '%s' found", path);
}
return FileChangesLogChange(path, FILE_STATE_NEW, "New file found", pp);
}

Expand Down Expand Up @@ -618,13 +637,23 @@
char path[strlen(name) + strlen(db_file) + 2];
xsnprintf(path, sizeof(path), "%s/%s", name, db_file);

Log(LOG_LEVEL_NOTICE, "File '%s' no longer exists", path);
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_REMOVE))
{
Log(LOG_LEVEL_NOTICE, "File '%s' no longer exists", path);
}
if (MakingInternalChanges(ctx, pp, attr, result,
"record removal of '%s'", path))
{
if (FileChangesLogChange(path, FILE_STATE_REMOVED, "File removed", pp))
{
RecordChange(ctx, pp, attr, "Removal of '%s' recorded", path);
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_REMOVE))
{
RecordChange(ctx, pp, attr, "Removal of '%s' recorded", path);
}
else
{
SetPromiseOutcomeClasses(ctx, PROMISE_RESULT_CHANGE, &(attr->classes));

Check notice

Code scanning / CodeQL

Pointer argument is dereferenced without checking for NULL Note

Parameter attr in FileChangesCheckAndUpdateDirectory() is dereferenced without an explicit null-check
}
*result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE);
}
else
Expand Down Expand Up @@ -702,7 +731,14 @@
}
else
{
RecordChange(ctx, pp, attr, "Wrote stat information for '%s' to database", file);
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_PERMS))
{
RecordChange(ctx, pp, attr, "Wrote stat information for '%s' to database", file);
}
else
{
SetPromiseOutcomeClasses(ctx, PROMISE_RESULT_CHANGE, &(attr->classes));

Check notice

Code scanning / CodeQL

Pointer argument is dereferenced without checking for NULL Note

Parameter attr in FileChangesCheckAndUpdateStats() is dereferenced without an explicit null-check
}
*result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE);
}
}
Expand All @@ -725,8 +761,11 @@

if (cmpsb.st_mode != sb->st_mode)
{
Log(LOG_LEVEL_NOTICE, "Permissions for '%s' changed %04jo -> %04jo",
file, (uintmax_t)cmpsb.st_mode, (uintmax_t)sb->st_mode);
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_PERMS))
{
Log(LOG_LEVEL_NOTICE, "Permissions for '%s' changed %04jo -> %04jo",
file, (uintmax_t)cmpsb.st_mode, (uintmax_t)sb->st_mode);

Check notice

Code scanning / CodeQL

Pointer argument is dereferenced without checking for NULL Note

Parameter sb in FileChangesCheckAndUpdateStats() is dereferenced without an explicit null-check
}

char msg_temp[CF_MAXVARSIZE];
snprintf(msg_temp, sizeof(msg_temp), "Permission: %04jo -> %04jo",
Expand All @@ -736,7 +775,14 @@
{
if (FileChangesLogChange(file, FILE_STATE_STATS_CHANGED, msg_temp, pp))
{
RecordChange(ctx, pp, attr, "Recorded permissions changes in '%s'", file);
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_PERMS))
{
RecordChange(ctx, pp, attr, "Recorded permissions changes in '%s'", file);
}
else
{
SetPromiseOutcomeClasses(ctx, PROMISE_RESULT_CHANGE, &(attr->classes));

Check notice

Code scanning / CodeQL

Pointer argument is dereferenced without checking for NULL Note

Parameter attr in FileChangesCheckAndUpdateStats() is dereferenced without an explicit null-check
}
*result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE);
}
else
Expand All @@ -749,8 +795,11 @@

if (cmpsb.st_uid != sb->st_uid)
{
Log(LOG_LEVEL_NOTICE, "Owner for '%s' changed %ju -> %ju",
file, (uintmax_t) cmpsb.st_uid, (uintmax_t) sb->st_uid);
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_OWNER))
{
Log(LOG_LEVEL_NOTICE, "Owner for '%s' changed %ju -> %ju",
file, (uintmax_t) cmpsb.st_uid, (uintmax_t) sb->st_uid);

Check notice

Code scanning / CodeQL

Pointer argument is dereferenced without checking for NULL Note

Parameter sb in FileChangesCheckAndUpdateStats() is dereferenced without an explicit null-check
}

char msg_temp[CF_MAXVARSIZE];
snprintf(msg_temp, sizeof(msg_temp), "Owner: %ju -> %ju",
Expand All @@ -761,7 +810,14 @@
{
if (FileChangesLogChange(file, FILE_STATE_STATS_CHANGED, msg_temp, pp))
{
RecordChange(ctx, pp, attr, "Recorded ownership changes in '%s'", file);
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_OWNER))
{
RecordChange(ctx, pp, attr, "Recorded ownership changes in '%s'", file);
}
else
{
SetPromiseOutcomeClasses(ctx, PROMISE_RESULT_CHANGE, &(attr->classes));

Check notice

Code scanning / CodeQL

Pointer argument is dereferenced without checking for NULL Note

Parameter attr in FileChangesCheckAndUpdateStats() is dereferenced without an explicit null-check
}
*result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE);
}
else
Expand All @@ -774,8 +830,11 @@

if (cmpsb.st_gid != sb->st_gid)
{
Log(LOG_LEVEL_NOTICE, "Group for '%s' changed %ju -> %ju",
file, (uintmax_t) cmpsb.st_gid, (uintmax_t) sb->st_gid);
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_GROUP))
{
Log(LOG_LEVEL_NOTICE, "Group for '%s' changed %ju -> %ju",
file, (uintmax_t) cmpsb.st_gid, (uintmax_t) sb->st_gid);

Check notice

Code scanning / CodeQL

Pointer argument is dereferenced without checking for NULL Note

Parameter sb in FileChangesCheckAndUpdateStats() is dereferenced without an explicit null-check
}

char msg_temp[CF_MAXVARSIZE];
snprintf(msg_temp, sizeof(msg_temp), "Group: %ju -> %ju",
Expand All @@ -786,7 +845,14 @@
{
if (FileChangesLogChange(file, FILE_STATE_STATS_CHANGED, msg_temp, pp))
{
RecordChange(ctx, pp, attr, "Recorded group changes in '%s'", file);
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_GROUP))
{
RecordChange(ctx, pp, attr, "Recorded group changes in '%s'", file);
}
else
{
SetPromiseOutcomeClasses(ctx, PROMISE_RESULT_CHANGE, &(attr->classes));

Check notice

Code scanning / CodeQL

Pointer argument is dereferenced without checking for NULL Note

Parameter attr in FileChangesCheckAndUpdateStats() is dereferenced without an explicit null-check
}
*result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE);
}
else
Expand All @@ -799,8 +865,11 @@

if (cmpsb.st_dev != sb->st_dev)
{
Log(LOG_LEVEL_NOTICE, "Device for '%s' changed %ju -> %ju",
file, (uintmax_t) cmpsb.st_dev, (uintmax_t) sb->st_dev);
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_DEVICE))
{
Log(LOG_LEVEL_NOTICE, "Device for '%s' changed %ju -> %ju",
file, (uintmax_t) cmpsb.st_dev, (uintmax_t) sb->st_dev);

Check notice

Code scanning / CodeQL

Pointer argument is dereferenced without checking for NULL Note

Parameter sb in FileChangesCheckAndUpdateStats() is dereferenced without an explicit null-check
}

char msg_temp[CF_MAXVARSIZE];
snprintf(msg_temp, sizeof(msg_temp), "Device: %ju -> %ju",
Expand All @@ -810,7 +879,14 @@
{
if (FileChangesLogChange(file, FILE_STATE_STATS_CHANGED, msg_temp, pp))
{
RecordChange(ctx, pp, attr, "Recorded device changes in '%s'", file);
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_DEVICE))
{
RecordChange(ctx, pp, attr, "Recorded device changes in '%s'", file);
}
else
{
SetPromiseOutcomeClasses(ctx, PROMISE_RESULT_CHANGE, &(attr->classes));

Check notice

Code scanning / CodeQL

Pointer argument is dereferenced without checking for NULL Note

Parameter attr in FileChangesCheckAndUpdateStats() is dereferenced without an explicit null-check
}
*result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE);
}
else
Expand All @@ -823,8 +899,11 @@

if (cmpsb.st_ino != sb->st_ino)
{
Log(LOG_LEVEL_NOTICE, "inode for '%s' changed %ju -> %ju",
file, (uintmax_t) cmpsb.st_ino, (uintmax_t) sb->st_ino);
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_INODE))
{
Log(LOG_LEVEL_NOTICE, "inode for '%s' changed %ju -> %ju",
file, (uintmax_t) cmpsb.st_ino, (uintmax_t) sb->st_ino);

Check notice

Code scanning / CodeQL

Pointer argument is dereferenced without checking for NULL Note

Parameter sb in FileChangesCheckAndUpdateStats() is dereferenced without an explicit null-check
}
}

if (cmpsb.st_mtime != sb->st_mtime)
Expand All @@ -842,7 +921,10 @@
assert(strlen(from) == 24);
assert(strlen(to) == 24);

Log(LOG_LEVEL_NOTICE, "Last modified time for '%s' changed '%s' -> '%s'", file, from, to);
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_MTIME))
{
Log(LOG_LEVEL_NOTICE, "Last modified time for '%s' changed '%s' -> '%s'", file, from, to);
}

char msg_temp[CF_MAXVARSIZE];
snprintf(msg_temp, sizeof(msg_temp), "Modified time: %s -> %s",
Expand All @@ -852,7 +934,14 @@
{
if (FileChangesLogChange(file, FILE_STATE_STATS_CHANGED, msg_temp, pp))
{
RecordChange(ctx, pp, attr, "Recorded mtime changes in '%s'", file);
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_MTIME))
{
RecordChange(ctx, pp, attr, "Recorded mtime changes in '%s'", file);
}
else
{
SetPromiseOutcomeClasses(ctx, PROMISE_RESULT_CHANGE, &(attr->classes));

Check notice

Code scanning / CodeQL

Pointer argument is dereferenced without checking for NULL Note

Parameter attr in FileChangesCheckAndUpdateStats() is dereferenced without an explicit null-check
}
*result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE);
}
else
Expand Down
5 changes: 4 additions & 1 deletion cf-agent/files_changes.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@

#include <promises.h>

/* Returns true if the given change category should be silenced. */
bool IsChangeSilenced(const Attributes *attr, FileChangeSilence category);

typedef enum
{
FILE_STATE_NEW,
Expand All @@ -44,7 +47,7 @@ bool FileChangesCheckAndUpdateHash(EvalContext *ctx,
const Promise *pp,
PromiseResult *result);
bool FileChangesGetDirectoryList(const char *path, Seq *files);
bool FileChangesLogNewFile(const char *path, const Promise *pp);
bool FileChangesLogNewFile(const char *path, const Promise *pp, bool silent);
void FileChangesCheckAndUpdateDirectory(EvalContext *ctx, const Attributes *attr,
const char *name, const Seq *file_set, const Seq *db_file_set,
bool update, const Promise *pp, PromiseResult *result);
Expand Down
16 changes: 14 additions & 2 deletions cf-agent/verify_files_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,8 @@ static PromiseResult PurgeLocalFiles(EvalContext *ctx, Item *filelist, const cha
static PromiseResult SourceSearchAndCopy(EvalContext *ctx, const char *from, char *to, int maxrecurse, const Attributes *attr,
const Promise *pp, dev_t rootdevice, CompressedArray **inode_cache, AgentConnection *conn)
{
assert(attr != NULL);

/* TODO overflow check all these str*cpy()s in here! */
Item *namecache = NULL;

Expand Down Expand Up @@ -2437,6 +2439,7 @@ static PromiseResult VerifyDelete(EvalContext *ctx,
const Attributes *attr, const Promise *pp)
{
assert(attr != NULL);
assert(sb != NULL);
Log(LOG_LEVEL_VERBOSE, "Verifying file deletions for '%s'", path);

const char *changes_path = path;
Expand Down Expand Up @@ -2571,6 +2574,8 @@ static inline char *GetFileTypeDescription(const struct stat *const stat_buf,

static PromiseResult VerifyFileAttributes(EvalContext *ctx, const char *file, const struct stat *dstat, const Attributes *attr, const Promise *pp)
{
assert(dstat != NULL);

PromiseResult result = PROMISE_RESULT_NOOP;

#ifndef __MINGW32__
Expand Down Expand Up @@ -2996,7 +3001,7 @@ bool DepthSearch(EvalContext *ctx, char *name, const struct stat *sb, int rlevel
{
// See comments in FileChangesCheckAndUpdateDirectory(),
// regarding this function call.
FileChangesLogNewFile(path, pp);
FileChangesLogNewFile(path, pp, IsChangeSilenced(attr, FILE_CHANGE_SILENCE_ADD));
}
SeqAppend(selected_files, xstrdup(dirp->d_name));
}
Expand Down Expand Up @@ -3726,7 +3731,14 @@ static PromiseResult VerifyFileIntegrity(EvalContext *ctx, const char *file, con
EvalContextClassPutSoft(ctx, "checksum_alerts", CONTEXT_SCOPE_NAMESPACE, "");
if (FileChangesLogChange(file, FILE_STATE_CONTENT_CHANGED, "Content changed", pp))
{
RecordChange(ctx, pp, attr, "Recorded integrity changes in '%s'", file);
if (!IsChangeSilenced(attr, FILE_CHANGE_SILENCE_CONTENT))
{
RecordChange(ctx, pp, attr, "Recorded integrity changes in '%s'", file);
}
else
{
SetPromiseOutcomeClasses(ctx, PROMISE_RESULT_CHANGE, &(attr->classes));
}
result = PromiseResultUpdate(result, PROMISE_RESULT_CHANGE);
}
else
Expand Down
40 changes: 40 additions & 0 deletions libpromises/attributes.c
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,25 @@ ENTERPRISE_FUNC_0ARG_DEFINE_STUB(HashMethod, GetBestFileChangeHashMethod)
return HASH_METHOD_BEST;
}

static FileChangeSilence FileChangeSilenceFromString(const char *s)
{
static const struct { const char *name; FileChangeSilence flag; } categories[] = {
{ "content", FILE_CHANGE_SILENCE_CONTENT }, { "add", FILE_CHANGE_SILENCE_ADD },
{ "remove", FILE_CHANGE_SILENCE_REMOVE }, { "owner", FILE_CHANGE_SILENCE_OWNER },
{ "group", FILE_CHANGE_SILENCE_GROUP }, { "perms", FILE_CHANGE_SILENCE_PERMS },
{ "device", FILE_CHANGE_SILENCE_DEVICE }, { "mtime", FILE_CHANGE_SILENCE_MTIME },
{ "inode", FILE_CHANGE_SILENCE_INODE }, { "all", FILE_CHANGE_SILENCE_ALL },
};
for (size_t i = 0; i < sizeof(categories) / sizeof(categories[0]); i++)
{
if (strcmp(s, categories[i].name) == 0)
{
return categories[i].flag;
}
}
return FILE_CHANGE_SILENCE_NONE;
}

FileChange GetChangeMgtConstraints(const EvalContext *ctx, const Promise *pp)
{
FileChange c;
Expand Down Expand Up @@ -940,6 +959,25 @@ FileChange GetChangeMgtConstraints(const EvalContext *ctx, const Promise *pp)
c.report_changes = FILE_CHANGE_REPORT_NONE;
}

c.silence = FILE_CHANGE_SILENCE_NONE;

for (const Rlist *rp = PromiseGetConstraintAsList(ctx, "silence", pp);
rp != NULL; rp = rp->next)
{
const char *cat = RlistScalarValue(rp);
FileChangeSilence flag = FileChangeSilenceFromString(cat);
if (flag != FILE_CHANGE_SILENCE_NONE)
{
c.silence |= flag;
}
else
{
Log(LOG_LEVEL_WARNING,
"Unknown 'silence' category '%s' in changes body", cat);
PromiseRef(LOG_LEVEL_WARNING, pp);
}
}

if (PromiseGetConstraintAsRval(pp, "update_hashes", RVAL_TYPE_SCALAR))
{
c.update = PromiseGetConstraintAsBoolean(ctx, "update_hashes", pp);
Expand Down Expand Up @@ -1126,6 +1164,8 @@ EditDefaults GetEditDefaults(const EvalContext *ctx, const Promise *pp)

ContextConstraint GetContextConstraints(const EvalContext *ctx, const Promise *pp)
{
assert(pp != NULL);

ContextConstraint a;

a.nconstraints = 0;
Expand Down
Loading
Loading