|
59 | 59 | #include <known_dirs.h>
|
60 | 60 | #include <evalfunction.h>
|
61 | 61 | #include <changes_chroot.h> /* PrepareChangesChroot(), RecordFileChangedInChroot() */
|
| 62 | +#include <fsattrs.h> |
62 | 63 |
|
63 | 64 | static PromiseResult FindFilePromiserObjects(EvalContext *ctx, const Promise *pp);
|
64 | 65 | static PromiseResult VerifyFilePromise(EvalContext *ctx, char *path, const Promise *pp);
|
@@ -303,6 +304,7 @@ static PromiseResult VerifyFilePromise(EvalContext *ctx, char *path, const Promi
|
303 | 304 | CfLock thislock;
|
304 | 305 | int exists;
|
305 | 306 | bool link = false;
|
| 307 | + bool is_immutable = false; |
306 | 308 |
|
307 | 309 | Attributes attr = GetFilesAttributes(ctx, pp);
|
308 | 310 |
|
@@ -351,6 +353,82 @@ static PromiseResult VerifyFilePromise(EvalContext *ctx, char *path, const Promi
|
351 | 353 | changes_path = chrooted_path;
|
352 | 354 | }
|
353 | 355 |
|
| 356 | + FSAttrsResult res = FileGetImmutableFlag(path, &is_immutable); |
| 357 | + switch (res) |
| 358 | + { |
| 359 | + case FS_ATTRS_SUCCESS: |
| 360 | + /* Nothing more to do */ |
| 361 | + break; |
| 362 | + case FS_ATTRS_FAILURE: |
| 363 | + Log(LOG_LEVEL_VERBOSE, "Failed to get immutable bit for file '%s': %s", changes_path, GetErrorStr()); |
| 364 | + break; |
| 365 | + case FS_ATTRS_NOTSUPP: |
| 366 | + Log(LOG_LEVEL_VERBOSE, "Failed to get immutable bit for file '%s': Operation not supported", changes_path); |
| 367 | + break; |
| 368 | + case FS_ATTRS_NOENTRY: |
| 369 | + /* The file does not exist. Nothing more to do */ |
| 370 | + break; |
| 371 | + } |
| 372 | + |
| 373 | + if (a.havefsattrs && a.fsattrs.haveimmutable) |
| 374 | + { |
| 375 | + if (a.fsattrs.immutable) /* file should be immutable */ |
| 376 | + { |
| 377 | + if (is_immutable) /* file is already immutable */ |
| 378 | + { |
| 379 | + /* Temporarily remove the immutable flag */ |
| 380 | + res = FileUpdateImmutableFlag(changes_path, false); |
| 381 | + switch (res) |
| 382 | + { |
| 383 | + case FS_ATTRS_SUCCESS: |
| 384 | + Log(LOG_LEVEL_VERBOSE, "Temporarily cleared immutable bit for file '%s'", changes_path); |
| 385 | + break; |
| 386 | + case FS_ATTRS_FAILURE: |
| 387 | + /* Things still may be fine as long as the agent does not try to mutate the file */ |
| 388 | + Log(LOG_LEVEL_VERBOSE, "Failed to temporarily clear immutable bit for file '%s': %s", changes_path, GetErrorStr()); |
| 389 | + break; |
| 390 | + case FS_ATTRS_NOTSUPP: |
| 391 | + /* Things still may be fine as long as the agent does not try to mutate the file */ |
| 392 | + Log(LOG_LEVEL_VERBOSE, "Failed to temporarily clear immutable bit for file '%s': Operation not supported", changes_path); |
| 393 | + break; |
| 394 | + case FS_ATTRS_NOENTRY: |
| 395 | + /* The file does not exist. Nothing more to do */ |
| 396 | + break; |
| 397 | + } |
| 398 | + } /* else then file is not immutable, but we will fix that later */ |
| 399 | + } |
| 400 | + else /* file should not be immutable */ |
| 401 | + { |
| 402 | + if (is_immutable) /* file is immutable */ |
| 403 | + { |
| 404 | + /* Remove immutable flag for good */ |
| 405 | + res = FileUpdateImmutableFlag(changes_path, false); |
| 406 | + switch (res) |
| 407 | + { |
| 408 | + case FS_ATTRS_SUCCESS: |
| 409 | + RecordChange(ctx, pp, &a, "Cleared immutable bit for file '%s'", changes_path); |
| 410 | + result = PromiseResultUpdate(result, PROMISE_RESULT_CHANGE); |
| 411 | + break; |
| 412 | + case FS_ATTRS_FAILURE: |
| 413 | + RecordFailure(ctx, pp, &a, "Failed to clear immutable bit for file '%s'", changes_path); |
| 414 | + result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); |
| 415 | + break; |
| 416 | + case FS_ATTRS_NOTSUPP: |
| 417 | + /* We will not treat this as a promise failure because this will happen on many platforms. Instead we will log a verbose message. */ |
| 418 | + Log(LOG_LEVEL_VERBOSE, "Failed to temporarily clear immutable bit for file '%s': Operation not supported", changes_path); |
| 419 | + break; |
| 420 | + case FS_ATTRS_NOENTRY: |
| 421 | + /* Nothing to do */ |
| 422 | + break; |
| 423 | + } |
| 424 | + } |
| 425 | + else /* file is not immutable */ |
| 426 | + { |
| 427 | + RecordNoChange(ctx, pp, &a, "Immutable bit is not set for file '%s' as promised", changes_path); |
| 428 | + } |
| 429 | + } |
| 430 | + } |
| 431 | + |
354 | 432 | if (lstat(changes_path, &oslb) == -1) /* Careful if the object is a link */
|
355 | 433 | {
|
356 | 434 | if ((a.create) || (a.touch))
|
@@ -609,6 +687,76 @@ static PromiseResult VerifyFilePromise(EvalContext *ctx, char *path, const Promi
|
609 | 687 | }
|
610 | 688 |
|
611 | 689 | exit:
|
| 690 | + ; /* A label can only be part of a statement and a declaration is not a |
| 691 | + * statement. This is a quirk of standard C grammar. Hence, we put an |
| 692 | + * empty statement here. */ |
| 693 | + bool was_immutable = is_immutable; |
| 694 | + is_immutable = false; |
| 695 | + res = FileGetImmutableFlag(path, &is_immutable); |
| 696 | + switch (res) |
| 697 | + { |
| 698 | + case FS_ATTRS_SUCCESS: |
| 699 | + /* Nothing to do */ |
| 700 | + break; |
| 701 | + case FS_ATTRS_FAILURE: |
| 702 | + Log(LOG_LEVEL_VERBOSE, "Failed to get immutable bit for file '%s': %s", changes_path, GetErrorStr()); |
| 703 | + break; |
| 704 | + case FS_ATTRS_NOTSUPP: |
| 705 | + Log(LOG_LEVEL_VERBOSE, "Failed to get immutable bit for file '%s': Operation not supported", changes_path); |
| 706 | + break; |
| 707 | + case FS_ATTRS_NOENTRY: |
| 708 | + /* Nothing to do */ |
| 709 | + break; |
| 710 | + } |
| 711 | + |
| 712 | + if (a.havefsattrs && a.fsattrs.haveimmutable && a.fsattrs.immutable) { |
| 713 | + if (was_immutable && !is_immutable) |
| 714 | + { |
| 715 | + /* Reset immutable flag that we cleared before */ |
| 716 | + res = FileUpdateImmutableFlag(changes_path, true); |
| 717 | + switch (res) |
| 718 | + { |
| 719 | + case FS_ATTRS_SUCCESS: |
| 720 | + Log(LOG_LEVEL_VERBOSE, "Reset immutable bit for file '%s' after temporarily clearing it", changes_path); |
| 721 | + break; |
| 722 | + case FS_ATTRS_FAILURE: |
| 723 | + /* Things still may be fine as long as the agent does not try to mutate the file */ |
| 724 | + Log(LOG_LEVEL_VERBOSE, "Failed to reset immutable bit for file '%s' after temporarily clearing it: %s", changes_path, GetErrorStr()); |
| 725 | + break; |
| 726 | + case FS_ATTRS_NOTSUPP: |
| 727 | + /* Things still may be fine as long as the agent does not try to mutate the file */ |
| 728 | + Log(LOG_LEVEL_VERBOSE, "Failed to reset immutable bit for file '%s' after temporarily clearing it: Operation not supported", changes_path); |
| 729 | + break; |
| 730 | + case FS_ATTRS_NOENTRY: |
| 731 | + /* The file must have been removed by the agent. Nothing more to do */ |
| 732 | + break; |
| 733 | + } |
| 734 | + } |
| 735 | + else |
| 736 | + { |
| 737 | + /* The file was never immutable, but should be. We'll fix that now */ |
| 738 | + res = FileUpdateImmutableFlag(changes_path, true); |
| 739 | + switch (res) |
| 740 | + { |
| 741 | + case FS_ATTRS_SUCCESS: |
| 742 | + RecordChange(ctx, pp, &a, "Set immutable bit for file '%s'", changes_path); |
| 743 | + result = PromiseResultUpdate(result, PROMISE_RESULT_CHANGE); |
| 744 | + break; |
| 745 | + case FS_ATTRS_FAILURE: |
| 746 | + RecordFailure(ctx, pp, &a, "Failed to set immutable bit for file '%s'", changes_path); |
| 747 | + result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); |
| 748 | + break; |
| 749 | + case FS_ATTRS_NOTSUPP: |
| 750 | + /* We will not treat this as a promise failure because this will happen on many platforms. Instead we will log a verbose message. */ |
| 751 | + Log(LOG_LEVEL_VERBOSE, "Failed set immutable bit for file '%s': Operation not supported", changes_path); |
| 752 | + break; |
| 753 | + case FS_ATTRS_NOENTRY: |
| 754 | + /* The file must have been removed by the agent. Nothing more to do */ |
| 755 | + break; |
| 756 | + } |
| 757 | + } |
| 758 | + } |
| 759 | + |
612 | 760 | free(chrooted_path);
|
613 | 761 | if (AttrHasNoAction(&a))
|
614 | 762 | {
|
|
0 commit comments