Holy cow, I wrote a book!
Inherited permissions on an object are established when it is created.
Once the object has been created, you can change the permissions of
the parent and it won't have any effect unless you explicitly ask for
the inheritable properties to be re-propagated to the child objects.
(You may recall that
the CREATOR_OWNER SID
works in a similar way.)
This rule applies to files, though that can lead to behavior
that some people might consider non-intuitive.
Files are strange from a security perspective because a single
file can have multiple parent folders, thanks to hard links.
Suppose you have two directories DirA and
DirA has an inheritable permission
that gives UserA full access
and denies access to UserB,
while DirB does the same with the roles of the two users reversed.
It's easy to tell who the parent of a file is when it is created,
since a file is created by giving a path, and you can extract
the parent from the path.
For example, if the file DirA\File is created,
it will naturally inherit permissions from DirA.
One the file is created, though, that's the end of it.
Inheritable permissions don't have any effect any more.
This simple rule wouldn't normally cause any problems, except
that files have properties unusual among most named objects:
They can go by multiple names (thanks to hard links)
and can change their names (via renaming).
The apparently counter-intuitive behavior stems from confusing
the object with its name.
For example, suppose we create a hard link to DirA\File
under the name DirB\File.
What effect does this have on the file's ACLs?
Answer: None whatsoever.
The inheritable ACLs on DirB aren't applied to the file
since the file is not being created.
Besides, you couldn't apply the inheritable ACLs from DirB
even if you wanted to because it would create a paradox:
The file resides in both DirA and DirB,
but each of those directories contains contradictory inheritable permissions.
What would the result be if you somehow managed to apply both of them?
All right, then.
We have no choice but to decide that
a file's ACLs don't change when you create a hard link.
Now delete the original link DirA\File, leaving just
Does this change the ACLs now?
If you believe that it should, then you're saying that
inheritable ACLs can take effect even when nothing got created!
After all, we didn't create a hard link; we deleted one.
Okay, maybe you concede that deleting a hard link shouldn't
affect the ACL.
But what did we just do by creating a hard link and then deleting
The net effect is that we moved the file from DirA\File
Which brings us to our third example:
Renaming/moving a file does not change its ACL.
We've just rediscovered the
simple rule that inheritable ACLs take effect
only when a file is created.
Nothing special happens
when a new hard link is created or when the file is moved.
Of course, that simple rule holds only when you look at the file
system at a low level.
Layers built on top of the low-level file system can end up
complicating our simple rule.
When you move a file across volumes
with the MOVEFILE_COPY_ALLOWED flag,
you're saying that "move the file if possible; if not, then
convert it to a copy/delete operation".
The copy operation creates a new file, which means that
inheritable properties on the destination folder
do take effect.
But only if the file motion crosses volumes.
If you're moving the file within the same volume,
then the ACL remains unchanged.
When you pass the MOVEFILE_COPY_ALLOWED
flag, you lose control of the ACL.
(You actually lose control of much more than just the ACL.
Since the file is being copied, none of the attributes from the
original file are kept on the copy.
The copy inherits its encryption and compression
status from the new parent directory.
The copy also gets a new owner, which has follow-on consequences
for things like disk quota.)
Another layer built on top of the low-level file system operations
is the shell's copy engine.
If you use SHFileOperation to move a file
and pass the FOF_NOCOPYSECURITYATTRIBUTES flag,
then it will not preserve the original ACLs on the moved files
but will rather recalculate them from the destination's
(If you want to do the same thing in your own code,
you can call the
SetNamedSecurityInfo function, specifying that
you want an empty, unprotected DACL.)
In Windows XP,
the shell decides whether or not to use this "naive mode" ACL management
based on the following algorithm: