How to Check Access Rights

Given that everyone is always pushing for better security mechanisms, I’m always surprised at how incredibly difficult the simple tasks can be in the Win32 security model. At work, we have an application that wants to do the right thing — it wants to show a UAC shield badge on a menu item, because that menu may require elevated privileges in order to function properly. However, it may not require elevation either — the menu is used to copy a file to a particular pre-defined directory. So we want to show the UAC badge only if necessary. So how do you do that?
The short answer is: with the GetFileSecurityand AccessCheck APIs. Of course, this would be a boring blog post if that was all there was to it.

The trick to checking whether a folder is accessible or not boils down to how many magic incantations you can figure out from the incredibly sparse documentation, and absolutely woeful “examples” on MSDN. The real keys boil down to this: understanding impersonation tokens, understanding the GENERIC_MAPPING structure, and understanding how AccessCheck works.

Impersonation tokens are quite easy — you open up a token to the process, and duplicate the token with the request for the duplicated token to be an impersonation token. Why is this required? Because the process token is a primary token, it cannot be used to ask questions about a particular user. So you make an impersonation token because you are pretending to be the user.

The GENERIC_MAPPING structure is something that I think most people struggle with. There is almost no documentation available for what this is, or how to use it. But at the end of the day, it’s actually a simple concept. Every HANDLE object in the system has specific access rights associated with it. You’ll often-times see them listed in the API documentation. For instance, the call to OpenProcessToken requires the process to have the PROCESS_QUERY_INFORMATION rights. However, most users are used to using generic access rights, like GENERIC_READ or GENERIC_WRITE. What the GENERIC_MAPPING structure does is allow you to map from the generic rights to the specific rights. So you fill out the map using the specific rights you want (in this case, the FILE rights such as FILE_GENERIC_READ), and then use the MapGenericMask function to modify your GENERIC_READ into the proper form.

The final task is to understand what AccessCheck does. It walks over the list of access control lists (or ACLs) in the security object you get back from GetFileSecurity, and looks for ones which specifically allow you access to the rights your are querying about. As it’s processing rights, it keeps a tally of the ones that are allowed, and the ones that are not allowed. At the end of the ACL list, if there’s nothing that’s on the not allowed list, then you have access to it. But it still tells you the things you were explicitly allowed access to, so long as you asked about them in your mapping. This means AccessCheck can actually do two different things for you. One is check whether you’ve got access to perform a particular operation. The other is to tell you what you’re allowed to do if you ask for MAXIMUM_ALLOWED access rights.

Since I wanted to set out to write a function that checks a folder to see if you can perform a read or write operation, I want to use AccessCheck the first way, not the second. So my code ended up looking like this:

So if you’re struggling with the terrible documentation on this subject, hopefully I’ve helped to shed a bit of light on it for you. Or at least given you some code that will let you check the access rights to a file or folder.

17 Responses to How to Check Access Rights

This is an interesting code sample. I tried it out myself cause I needed to find out if I had write and delete permissions on a network share.
However it always appeared to return true (even though I know I do not have delete access) explorer would give me an access denied. Any ideas would be appreciated.. Thanks

In order to test out delete functionality, you’d have to map it through one of the generic masks. I noticed that I am using FILE_GENERIC_WRITE, which tests whether you can write data. But that bitmask does not include FILE_DELETE_CHILD, which is what you’d need to test against.

That’s my best guess though — I don’t have access to a network (or local) folder to test it against though…

I tried to use this approach to check accessibility to write file from IE MIME plugin which runs with low integrity level. Your function always returns false to check for GENERIC_WRITE even if the requested folder was the right one C:\Users\\AppData\Local\Temp\Low\ and finally plugin created the file there and was able to wrote into it.
What is the reason for this behavior?

@Libor — I’m not certain why it would behave that way, truth be told. I think you’d have to look at the ACL for the folder on that machine to see what access rights are granted to it. Perhaps IE is interacting with the low integrity plugin in some fashion prior to the creation of the file? I’ve not done anything with IE plugins, so I’m just wildly guessing.

The code seems to be working fine on Win7 & below. However, its not working properly on Win8 and above. AccessCheck is returning true, and result is also true, when am checking for GENERIC_WRITE on a folder where I don’t have write access, only read access is there. If I turn off the read access also, then GetFileSecurity returns false and saves the day. But the write access check is not working. I don’t know what makes this non-conformable with win8.

Hi,
This function is gold!
Thanks for sharing.
By the way it is not working for paths that involve just a mapped drive.
For instance I have a mapped drive “pippo” that I can reach with : \\pippo
The function is working for the directory : \\pippo\VeryImportantDirectory
but it is not working for : \\pippo
Any idea how to extend the functionality? I have no enough experience in windows :(

@Andrea — The \\Server construct names the server, not a folder on the server. You need to include the share (\\Server\VeryImportantDirectory) in order to check the access control list because the server itself does not have an ACL (that I’m aware of).

@Sanju — I don’t have access to a Windows 8 machine currently, so I’m not certain what would have changed. I’d be surprised if this functionality broke with Windows 8. If I have the chance to spin up a VM, I’ll look into it.

Hello, Aaron,
the codes works for me … Great! But with one exception:
If the folder is a network share like “\\Server\Share” and in the filesystem behind i have all rights (Write, Read) but in the share permission i have only read access (no write access) your function returns for CanAccessFolder(“\\Server\Share “, GENERIC_WRITE) the result true … but it should be false, because of the missing share write permission. When i try to copy a file on the share it is denied … as expected. It seems that the file permission is checked but not the share permission. Do you know how to modify your code to take account of the share permissions? Or how to check the file permission?

I have found the solution: The function GetNamedSecurityInfo() (instead of GetFileSecurity()) is my friend …. with the parameter SE_LMSHARE as 2nd parameter … ;-)
Thanx again for your nice function … it saves me a lot of time!

Your email address will not be published. Required fields are marked *

Comment

Name *

Email *

Website

Who

Aaron Ballman is a software engineer for GrammaTech. He has almost two decades of experience writing cross-platform frameworks in C/C++, compiler & language design, and software engineering best practices and is currently a voting member of the C (WG14) and C++ (WG21) standards committees.

In case you can't figure it out easily enough, the views expressed here are my personal views and not the views of my employer, my past employers, my future employers, or some random person on the street. Please yell only at me if you disagree with what you read.