-
Notifications
You must be signed in to change notification settings - Fork 189
ENT-10961, CFE-1840: Files promise can now modify immutable bit in file system attributes #5752
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d7e8ff3
4ebc7b2
5243590
1e74204
c07955f
d5ada41
c9ba31d
0c53319
83e0ed8
b69401b
f8db2b0
1e6b326
d1f222a
2cf862f
048e9a6
d5394a0
81bc75e
2db3cf9
ec88ef0
1823cff
dab2d99
983faa4
4b6c26e
4053710
c99718d
5b13fea
841a313
f75ea3b
8e85661
9f2b689
23b6519
6b0b70d
587ed51
4369f2f
40a4547
b0ce49b
c61fe03
7dc51ff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -60,6 +60,8 @@ | |||||
#include <evalfunction.h> | ||||||
#include <changes_chroot.h> /* PrepareChangesChroot(), RecordFileChangedInChroot() */ | ||||||
#include <cf3.defs.h> | ||||||
#include <fsattrs.h> | ||||||
#include <override_fsattrs.h> | ||||||
|
||||||
static PromiseResult FindFilePromiserObjects(EvalContext *ctx, const Promise *pp); | ||||||
static PromiseResult VerifyFilePromise(EvalContext *ctx, char *path, const Promise *pp); | ||||||
|
@@ -345,6 +347,67 @@ static PromiseResult VerifyFilePromise(EvalContext *ctx, char *path, const Promi | |||||
changes_path = chrooted_path; | ||||||
} | ||||||
|
||||||
bool is_immutable = false; /* We assume not in case of failure */ | ||||||
FSAttrsResult res = FSAttrsGetImmutableFlag(changes_path, &is_immutable); | ||||||
if (res != FS_ATTRS_SUCCESS) | ||||||
{ | ||||||
Log((res == FS_ATTRS_FAILURE) ? LOG_LEVEL_ERR : LOG_LEVEL_VERBOSE, | ||||||
"Failed to get the state of the immutable bit from file '%s': %s", | ||||||
changes_path, FSAttrsErrorCodeToString(res)); | ||||||
} | ||||||
|
||||||
if (a.havefsattrs && a.fsattrs.haveimmutable && !a.fsattrs.immutable) | ||||||
{ | ||||||
/* Here we only handle the clearing of the immutable the immutable | ||||||
* bit. Later we'll handle the setting of the immutable bit. */ | ||||||
if (is_immutable) | ||||||
{ | ||||||
res = FSAttrsUpdateImmutableFlag(changes_path, false); | ||||||
switch (res) | ||||||
{ | ||||||
case FS_ATTRS_SUCCESS: | ||||||
RecordChange(ctx, pp, &a, | ||||||
"Cleared the immutable bit on file '%s'", | ||||||
changes_path); | ||||||
result = PromiseResultUpdate(result, PROMISE_RESULT_CHANGE); | ||||||
break; | ||||||
case FS_ATTRS_FAILURE: | ||||||
RecordFailure(ctx, pp, &a, | ||||||
"Failed to clear the immutable bit on file '%s'", | ||||||
changes_path); | ||||||
result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); | ||||||
break; | ||||||
case FS_ATTRS_NOT_SUPPORTED: | ||||||
/* We will not treat this as a promise failure because this | ||||||
* will happen on many platforms and filesystems. Instead we | ||||||
* will log a verbose message to make it apparent for the | ||||||
* users. */ | ||||||
Log(LOG_LEVEL_VERBOSE, | ||||||
"Failed to clear the immutable bit on file '%s': %s", | ||||||
larsewi marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
changes_path, FSAttrsErrorCodeToString(res)); | ||||||
break; | ||||||
case FS_ATTRS_DOES_NOT_EXIST: | ||||||
/* File does not exist. Nothing to do really, but let's log a | ||||||
* debug message for good measures */ | ||||||
Log(LOG_LEVEL_DEBUG, | ||||||
"Failed to clear the immutable bit on file '%s': %s", | ||||||
larsewi marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
changes_path, FSAttrsErrorCodeToString(res)); | ||||||
break; | ||||||
} | ||||||
} | ||||||
else | ||||||
{ | ||||||
RecordNoChange(ctx, pp, &a, | ||||||
"The immutable bit is not set on file '%s' as promised", | ||||||
changes_path); | ||||||
} | ||||||
} | ||||||
|
||||||
/* If we encounter any promises to mutate the file and the immutable | ||||||
* attribute in body fsattrs is "true", we will override the immutable bit | ||||||
* by temporarily clearing it when ever needed. */ | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
EvalContextOverrideImmutableSet(ctx, a.havefsattrs && a.fsattrs.haveimmutable && a.fsattrs.immutable && is_immutable); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's already in the attributes and we do pass those into gazillions functions already, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not passed everywhere. We also would need to pass the |
||||||
|
||||||
if (lstat(changes_path, &oslb) == -1) /* Careful if the object is a link */ | ||||||
{ | ||||||
if ((a.create) || (a.touch)) | ||||||
|
@@ -586,6 +649,51 @@ static PromiseResult VerifyFilePromise(EvalContext *ctx, char *path, const Promi | |||||
} | ||||||
} | ||||||
|
||||||
if (a.havefsattrs && a.fsattrs.haveimmutable && a.fsattrs.immutable) | ||||||
{ | ||||||
/* Here we only handle the setting of the immutable bit. Previously we | ||||||
* handled the clearing of the immutable bit. */ | ||||||
if (is_immutable) | ||||||
{ | ||||||
RecordNoChange(ctx, pp, &a, | ||||||
"The immutable bit is already set on file '%s' as promised", | ||||||
changes_path); | ||||||
} | ||||||
else | ||||||
{ | ||||||
res = FSAttrsUpdateImmutableFlag(changes_path, true); | ||||||
switch (res) | ||||||
{ | ||||||
case FS_ATTRS_SUCCESS: | ||||||
Log(LOG_LEVEL_VERBOSE, "Set the immutable bit on file '%s'", | ||||||
changes_path); | ||||||
break; | ||||||
case FS_ATTRS_FAILURE: | ||||||
/* Things still may be fine as long as the agent does not try to mutate the file */ | ||||||
Log(LOG_LEVEL_VERBOSE, | ||||||
"Failed to set the immutable bit on file '%s': %s", | ||||||
changes_path, FSAttrsErrorCodeToString(res)); | ||||||
break; | ||||||
case FS_ATTRS_NOT_SUPPORTED: | ||||||
/* We will not treat this as a promise failure because this | ||||||
* will happen on many platforms and filesystems. Instead we | ||||||
* will log a verbose message to make it apparent for the | ||||||
* users. */ | ||||||
Log(LOG_LEVEL_VERBOSE, | ||||||
"Failed to set the immutable bit on file '%s': %s", | ||||||
changes_path, FSAttrsErrorCodeToString(res)); | ||||||
break; | ||||||
case FS_ATTRS_DOES_NOT_EXIST: | ||||||
/* File does not exist. Nothing to do really, but let's log a | ||||||
* debug message for good measures */ | ||||||
Log(LOG_LEVEL_DEBUG, | ||||||
"Failed to set the immutable bit on file '%s': %s", | ||||||
changes_path, FSAttrsErrorCodeToString(res)); | ||||||
break; | ||||||
larsewi marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
// Once more in case a file has been created as a result of editing or copying | ||||||
|
||||||
exists = (lstat(changes_path, &osb) != -1); | ||||||
|
@@ -603,6 +711,9 @@ static PromiseResult VerifyFilePromise(EvalContext *ctx, char *path, const Promi | |||||
} | ||||||
|
||||||
exit: | ||||||
/* Reset this to false before next file promise */ | ||||||
EvalContextOverrideImmutableSet(ctx, false); | ||||||
|
||||||
free(chrooted_path); | ||||||
if (AttrHasNoAction(&a)) | ||||||
{ | ||||||
|
@@ -686,37 +797,53 @@ static PromiseResult WriteContentFromString(EvalContext *ctx, const char *path, | |||||
|
||||||
if (!HashesMatch(existing_content_digest, promised_content_digest, CF_DEFAULT_DIGEST)) | ||||||
{ | ||||||
bool override_immutable = EvalContextOverrideImmutableGet(ctx); | ||||||
if (!MakingChanges(ctx, pp, attr, &result, | ||||||
"update file '%s' with content '%s'", | ||||||
path, attr->content)) | ||||||
{ | ||||||
return result; | ||||||
} | ||||||
|
||||||
FILE *f = safe_fopen(changes_path, "w"); | ||||||
char override_path[PATH_MAX]; | ||||||
if (!OverrideImmutableBegin(changes_path, override_path, sizeof(override_path), override_immutable)) | ||||||
{ | ||||||
RecordFailure(ctx, pp, attr, "Failed to override immutable bit on file '%s'", changes_path); | ||||||
return PromiseResultUpdate(result, PROMISE_RESULT_FAIL); | ||||||
} | ||||||
|
||||||
FILE *f = safe_fopen(override_path, "w"); | ||||||
if (f == NULL) | ||||||
{ | ||||||
RecordFailure(ctx, pp, attr, "Cannot open file '%s' for writing", path); | ||||||
OverrideImmutableCommit(changes_path, override_path, override_immutable, true); | ||||||
return PromiseResultUpdate(result, PROMISE_RESULT_FAIL); | ||||||
} | ||||||
|
||||||
bool override_abort = false; | ||||||
Writer *w = FileWriter(f); | ||||||
if (WriterWriteLen(w, attr->content, bytes_to_write) == bytes_to_write ) | ||||||
{ | ||||||
RecordChange(ctx, pp, attr, | ||||||
"Updated file '%s' with content '%s'", | ||||||
path, attr->content); | ||||||
|
||||||
result = PromiseResultUpdate(result, PROMISE_RESULT_CHANGE); | ||||||
} | ||||||
else | ||||||
{ | ||||||
RecordFailure(ctx, pp, attr, | ||||||
"Failed to update file '%s' with content '%s'", | ||||||
path, attr->content); | ||||||
override_abort = true; | ||||||
result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); | ||||||
} | ||||||
WriterClose(w); | ||||||
|
||||||
if (!OverrideImmutableCommit(changes_path, override_path, override_immutable, override_abort)) | ||||||
{ | ||||||
RecordFailure(ctx, pp, attr, "Failed to override immutable bit on file '%s'", changes_path); | ||||||
result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); | ||||||
} | ||||||
} | ||||||
|
||||||
return result; | ||||||
|
@@ -861,7 +988,7 @@ static PromiseResult RenderTemplateMustache(EvalContext *ctx, | |||||
edcontext->filename, message); | ||||||
result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); | ||||||
} | ||||||
else if (SaveAsFile(SaveBufferCallback, output_buffer, | ||||||
else if (SaveAsFile(ctx, SaveBufferCallback, output_buffer, | ||||||
edcontext->changes_filename, attr, | ||||||
edcontext->new_line_mode)) | ||||||
{ | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.