* Fix: Correctly restore ACL inheritance state
When restoring a file or directory on Windows, the `IsInherited` property of its Access Control Entries (ACEs) was always being set to `False`, even if the ACEs were inherited in the original backup.
This was caused by the restore process calling the `SetNamedSecurityInfo` API without providing context about the object's inheritance policy. By default, this API applies the provided Discretionary Access Control List (DACL) as an explicit set of permissions, thereby losing the original inheritance state.
This commit fixes the issue by inspecting the `Control` flags of the saved Security Descriptor during restore. Based on whether the `SE_DACL_PROTECTED` flag is present, the code now adds the appropriate `PROTECTED_DACL_SECURITY_INFORMATION` or `UNPROTECTED_DACL_SECURITY_INFORMATION` flag to the `SetNamedSecurityInfo` API call.
By providing this crucial inheritance context, the Windows API can now correctly reconstruct the ACL, ensuring the `IsInherited` status of each ACE is preserved as it was at the time of backup.
* Fix: Correctly restore ACL inheritance flags
This commit resolves an issue where the ACL inheritance state (`IsInherited` property) was not being correctly restored for files and directories on Windows.
The root cause was that the `SECURITY_INFORMATION` flags used in the `SetNamedSecurityInfo` API call contained both the `PROTECTED_DACL_SECURITY_INFORMATION` and `UNPROTECTED_DACL_SECURITY_INFORMATION` flags simultaneously. When faced with this conflicting information, the Windows API defaulted to the more restrictive `PROTECTED` behavior, incorrectly disabling inheritance on restored items.
The fix modifies the `setNamedSecurityInfoHigh` function to first clear all existing inheritance-related flags from the `securityInfo` bitmask. It then adds the single, correct flag (`PROTECTED` or `UNPROTECTED`) based on the `SE_DACL_PROTECTED` control bit from the original, saved Security Descriptor.
This ensures that the API receives unambiguous instructions, allowing it to correctly preserve the inheritance state as it was at the time of backup. The accompanying test case for ACL inheritance now passes with this change.
* Fix inheritance flag handling in low-privilege security descriptor restore
When restoring files without admin privileges, the IsInherited property
of Access Control Entries (ACEs) was not being preserved correctly.
The low-privilege restore path (setNamedSecurityInfoLow) was using a
static PROTECTED_DACL_SECURITY_INFORMATION flag, which always marked
the restored DACL as explicitly set rather than inherited.
This commit updates setNamedSecurityInfoLow to dynamically determine
the correct inheritance flag based on the SE_DACL_PROTECTED control
flag from the original security descriptor, matching the behavior of
the high-privilege path (setNamedSecurityInfoHigh).
Changes:
- Update setNamedSecurityInfoLow to accept control flags parameter
- Add logic to set either PROTECTED_DACL_SECURITY_INFORMATION or
UNPROTECTED_DACL_SECURITY_INFORMATION based on the original SD
- Add TestRestoreSecurityDescriptorInheritanceLowPrivilege to verify
inheritance is correctly restored in low-privilege scenarios
This ensures that both admin and non-admin restore operations correctly
preserve the inheritance state of ACLs, maintaining the original
permissions flow on child objects.
Addresses review feedback on PR for issue #5427
* Refactor security flags into separate backup/restore variants
Split highSecurityFlags into highBackupSecurityFlags and
highRestoreSecurityFlags to avoid runtime bitwise operations.
This makes the code cleaner and more maintainable by using
appropriate flags for GET vs SET operations.
Addresses review feedback on PR for issue #5427
---------
Co-authored-by: Aneesh Nireshwalia <anireshw@akamai.com>
Instead of rebasing my code, I decided to start fresh, since WithBlobUploader()
has been introduced.
changelog/unreleased/issue-5453:
doc/045_working_with_repos.rst:
the usual
cmd/restic/cmd_copy.go:
gather all snaps to be collected - collectAllSnapshots()
run overall copy step - func copyTreeBatched()
helper copySaveSnapshot() to save the corresponding snapshot
internal/repository/repack.go:
introduce wrapper CopyBlobs(), which passes parameter `uploader restic.BlobSaver` from
WithBlobUploader() via copyTreeBatched() to repack().
internal/backend/local/local_windows.go:
I did not touch it, but gofmt did: whitespace
* Allow for a personal token to be specified for self-updates
This change will allow for setting the $GITHUB_ACCESS_TOKEN environment variable with a Github personal access token, allowing e.g. for higher rate limits
* Refactor github request and add test
---------
Co-authored-by: Paulo Saraiva <pauloman@cern.ch>
The intended usage here is to basically kick restic as a background
"do it, but don't bother my normal load" process.
This allows passing the following environment variables in to
influence scheduling:
- NICE: usual CPU nice. Defaults to 0. This requires CAP_SYS_NICE
to set a negative nice (IE, prioritize).
- IONICE_CLASS: usual ionice class. Note that setting realtime
requires CAP_SYS_ADMIN. Also note the actual ionice default
is "none".
- IONICE_PRIORITY: set the priority within the given class. Ignored
if no class is specified due to class default of "no scheduler".
---------
Signed-off-by: Brian Harring <ferringb@gmail.com>
Co-authored-by: Michael Eischer <michael.eischer@fau.de>
If the repo is on a mounted folder that doesn't support chmod (like
SMB), it was causing an "operation not supported" error when trying to
chmod 666 a file before deleting it.
But it isn't generally needed before deleting a file (the folder
permissions matter there, not the file permissions). So, just drop it.
cmd/restic/cmd_copy.go:
add function copyStats() and call it before the actual copying starts.
changelog/unreleased/pull-5319:
rephrased wording of the statistics counters.
to make the exit code behaviour consistent with files inaccessible during the backup phase, making this change to exit with code 3 if not all target files/folders are accessible for backup
---------
Co-authored-by: Michael Eischer <michael.eischer@fau.de>