Contact

Subscribe via Email

Subscribe via RSS/JSON

Categories

Recent Posts

Creative Commons Attribution 4.0 International License
© Rakhesh Sasidharan

Elsewhere

Start Menu and other directory junctions access denied

Here’s a screenshot of my c:\Users\UserName folder. Notice the “Start Menu” folder:

users-folder

It is a directory junction to another folder, left behind for compatibility purposes. If I double click the folder though I get an access denied:

access-denied

 

The actual target to which this points is accessible, but the junction itself isn’t. Every time I encounter this I think I must make a note of “why” this is so, but I forget. Today I intend to note it down once and for all. 

Remember from an earlier post: there are hard links and there are soft links. The former points to the data itself, and so only work for files. The latter points to the folder/ file containing the data. Soft links are an evolution of directory junctions (there are directory junctions and volume junctions). While directory junctions make use of something called reparse points and were introduced in Windows 2000, soft links were introduced in Vista and are baked into the kernel itself. Microsoft uses directory junctions – as we saw above – to redirect some of its special folders.

The important thing with both directory junctions and soft links is that they can have their own ACLs. So while a user might have full permissions to the target folder, the directory junction or soft link itself may not grant the user permissions and so the contents cannot be accessed via the directory junction or soft link. That’s what happening here too. 

First, from the command prompt note that this is a junction and that I can enter the directory junction but cannot see any files:

The files exist, however, as I can directly browse the target:

Compare the ACLs of the target and directory junction and we see the problem:

(I could have used the Explorer GUI here but I prefer icacls. In the GUI we have to dig down a bit more to see the relevant ACEs).

Notice a DENY entry for Everyone on the directory junction for listing the contents (RD). That’s why I can’t list the junction contents (in Explorer double clicking results in trying to list the contents, while in Command Prompt entering a junction and listing are two separate tasks – that’s why entering the junction worked, but listing the contents failed). 

What the above tells us is that only listing the junction contents is prohibited. If we know the names of some folders in there – as older software for whom this directory junction is present would know – we can go to those locations using the directory junction. Thus the following works:

There you go!

Setting file ACLs via PowerShell

Yesterday I ran WireShark at work with my admin account and saved the results to a file. Later I moved that file (as my admin account) to the desktop of my regular account so I could email it to someone. But as you know moving has the effect that the original permissions are retained so even though the file was now in my regular Desktop I as a regular user couldn’t access it.

Running Explorer as an administrator doesn’t help either. Because of UAC when I right click Explorer and do “Run as administrator” it still runs as me but in an elevated context. This is an Explorer specific quirk. So unless I were to logout and login as my admin account, there seemed to be no way of changing the file ACLs to give my regular account permissions.

But of course there are ways. PowerShell was my first choice (coz I knew it had a Set-ACL cmdlet) but I wasn’t sure how to assign permissions using PowerShell. A quick web search got me to this blog post that summarizes what needs to be done. Up shot of the matter is you do something along these lines:

What you do here is that first you store the current ACLs of the file into a variable. Then you create a new ACE object with the permissions you want. Add that to the previous variable and assign the new ACL to the file.

While the above is useful, it would be good if I could just copy the ACLs from a file with ACEs I like to the file I want to modify. Something like this:

This doesn’t work though.

If I run this in a PowerShell session under my regular account it fails (obviously):

But if I run this under my admin account, then too it fails (though for not an obvious reason):

This is because by default Set-ACL also tries to set the owner ACE, and since the owner is different from the user account under which Set-ACL is running it gives an error. In Windows you can’t assign someone else as an owner unless you have a privilege for doing that (the SeRestorePrivilege privilege, see this MSDN page). All you can do is grant someone a Take Ownership permission and then they have to take ownership. (See this forum post for more info. Another forum post gives a workaround. Also, this blog post from Lee Holmes is useful in the context of the second forum post).

So a simple copy-paste is out of the question …

I still might be able to fix this easily though. Remember the reason the file (in my case) has a different set of permissions is because its ACEs are protected from inheritance. If I had copied the file over instead of moving, then permissions won’t be protected and inheritance would have kicked in. But since I moved the file here its permissions are protected. I can confirm this via Get-ACL too:

So all I need to do here is remove protection. That can be done via the SetAccessRuleProtection method. This takes two parameters – the first determines whether protection is enabled ($true) or not ($false). The second is ignored if protection is disabled; but if protection is enabled then it determines whether the inherited rules are kept ($true) or discarded ($false) . Thus, in my case, all I need to do is the following:

After this the file has both the original ACEs as well as the ones inherited from my home folder (notice the last three rules in the list below):

Now I can just copy the ACLs from another file – with PowerShell running under my account – as I had tried earlier. This is optional, I did it so the permissions are consistent with others.

While on Set-ACL the following snippet too might be useful:

This takes the ACLs from an existing file and adds these to the file I want. Again, this only works if you already have permissions on the file – in case above, I could do this after I have turned off protection.

While on PowerShell and ACLs its worth pointing to this Tip post. That’s where I first learnt about PowerShell and ACLs though I admit I have forgotten most of what I learnt from lack of use. This blog post which I came across today is a good read too. I came across it while searching for how to enable inheritance.

Apart from PowerShell there are other commands which can set/ get ACLs. One of these is ICACLS, which is present in Windows Vista/ Server 2003 SP2 and upwards.

Interestingly ICACLS seems to be able to set the owner to another account even though PowerShell fails. Not sure why that succeeds …

ICACLS can also easily reset the ACLs with inherited ones (i.e. like the PowerShell above it disables protection but also replaces the non-inherited entries with inherited ones).

This is a good post on using ICACLS. Apart from resetting and changing owners, you can also use ICACL to add/ remove ACEs, find files belonging to a particular user, and even substitute an ACE username/ SID with another. You can even save all ACEs of files in a folder and then restore them.

Lastly, if you are an administrator and want to take ownership of a file or directory, the takeown command is useful. It is not as useful as ICACLS which lets you assign someone else as the owner, but is useful if you are an admin and want take ownership.