Be careful when interpreting security descriptors across machine boundaries

While it's true the AccessCheck function can be used to check whether a particular security descriptor grants access to a token, you need to be aware of where that security descriptor came from. If the security descriptor came from another machine (for example, if you got it by calling GetNamedSecurityInfo and passing the path to a file on a network share), calling the AccessCheck function on your machine may give different results from the remote machine. In other words, it is possible for the AccessCheck function to indicate that you have access, when in fact you don't.

How can that be?

For one thing, there are many SIDs that are machine-relative. If the remote object grants access to, say, the Builtin Administrators group, running the AccessCheck function checks the token against the Builtin Administrators group of the machine that is running the check. If you are a member of the Builtin Administrators group of your own machine but aren't a member of the Builtin Administrators group of the remote machine, you will think you have access when you don't.

In addition to the machine-relative SID problem, there's also the problem that tokens can lose their identity as they travel across the network. If the server has the ForceGuest policy enabled, then it doesn't matter what your token is on your machine. On the remote machine, you are treated as Guest.

The moral of the story is that trying to determine whether you have access to an object without actually accessing it is harder than it looks. You're usually much better off just trying to access it. No point trying to emulate what another computer is going to do if you can just have it do it!

Comments (6)
  1. Alun Jones says:

    I’ve recommended for a long time that if you want to know "do I have X access to Y resource", you simply try to do X to Y. [Note – this is valid advice for software development, not for relationships!]

    There are a couple of caveats – sometimes a user wants to see a list of access rights, and you would like to enumerate them for display – so go ahead and enumerate what AccessCheck tells you, but don’t use that as a basis to prevent a user trying to access a file if he thinks he has that access.

    The second caveat is that this behaviour, of actually trying to access a resource, rather than first determining that you have access, may lead to audit logs noting a failed security event. Beginner admins often troll through the list of failed accesses, and intuit that they have discovered a hacker. That’s not reason to change your software’s behaviour – it’s reason for the admin to get an education.

  2. Reinder says:

    I would hope/assume that the system has some way to prevent forgery of security access descriptors. Couldn’t the system use that same mechanism to return a meaningful error (‘descriptor not valid on this machine’) when someone passes a descriptor from a different machine?

  3. David Wilson says:

    Is there some way to do the equivalent of AccessCheck() in a cross-machine-friendly way, assuming ForceGuest is disabled? I was thinking of the problem that Alun Jones raised.

    Side thought: when ForceGuest is enabled, do the client and server perform a login handshake, the result of which is then ignored? If that is so, then surely ForceGuest causes the server to run out of spec for the SMB protocol.

    If it is not true, then why would the client think it was authenticated when it were not? Surely it would assume the Guest SID for the connection until a handshake were successfully completed.

  4. bmm6o says:

    It can make for a much better user experience to alter the interface based on what the user is allowed to do right now.

    As you explain, this can be difficult/impossible to implement without the cooperation of the module that’s going to be enforcing the rules. But in some domains (e.g. most web applications, many client-server applications) it’s standard.

  5. Dean Harding says:

    It can make for a much better user experience to alter the

    > interface based on what the user is allowed to do right now.

    But that’s not what we’re talking about. People are asking for "advanced" vs. "novice" user interfaces. You can still "do" everything the advanced user interface can do, but it’s just not presented in the UI.

    Kind of like the difference between "Simple" file sharing and old-style file sharing, where the functionality is the same underneath, but you just provide a simpler UI for the "novice" users.

  6. bmm6o says:

    > People are asking for "advanced" vs. "novice" user interfaces

    If you hadn’t quoted my post, I don’t think I would have realized that you were responding to what I wrote. Which people are you talking about?

    Maybe I wasn’t clear, but I was saying that although Raymond’s conclusion of "you’re usually much better off just trying to access [the resource]" is *in general* the best that you can do, the user experience leaves something to be desired. If the operation fails because the user isn’t sufficiently privileged, the user can be left with the reaction of "if that wasn’t going to work, why did you let me try" (to e.g. delete that resource, view that resource). It’s true that it’s an attitude more likely to be held by a novice user, if that’s what you’re getting at.

    Also, I’m not really talking about UI that is simplified in any significant way, just one that lacks options that *predictably* result in "access denied" or "operation not allowed" messages.

Comments are closed.

Skip to main content