How can I detect that a user’s SID has changed and recover their old data?

A customer maintained a database which recorded information per user. The information in the database is keyed by the user's SID. This works out great most of the time, but there are cases in which a user's SID can change.

"Wait, I thought SIDs don't change."

While it's true that SIDs don't change, it is also true that the SID associated with a user can change. Since SIDs encode the domain to which they belong, a user which moves from one domain to another within an organization, will need to be assigned a new SID.

But wait, does that mean that the user lost access to all their stuff? After all, all their stuff was marked "Owned by X\UserName" but the user's SID is now Y\UserName.

No, the user doesn't lose access to their stuff thanks to SID history, and if you move users around a lot, the SID history can get quite large.

A token for a user contains not only their current identity but also all of their earlier identities. That is what permits Y\UserName to continue to access things that was marked "Owned by X\UserName": The token for Y\UserName includes an entry that says, "Oh, I used to be X\UserName."

The customer's database can take advantage of the SID history to match up users with their former selves. Our customer was lucky in that their database recorded only users who had logged into the local machine, so that list is typically pretty small. The simplest solution for this particular customer is just to go through all the users in the database, and for each one, see if the current user has that database user in their SID history. And the easy way to do that is to make the security system do the work for you: To see if the current user has user X in their SID history, create a security descriptor that grants access only to user X, then call Access­Check to see if the current user can access it. If so, then that means that the current user was at one point in the past known as X.

(If you have a large database where iterating over all users is impractical, you can ask for the current user's SID-History attribute and walk through the previous identities manually.)

Comments (9)
  1. NB says:

    Sounds a little unfortunate.

    Would it have been better to make SIDs like GUIDs instead if it were possible to start over from scratch?

  2. Guest says:


    Wouldn't you just have the same problem?

  3. NB says:

    The idea was that they would not ever change in that case. So the domain would not be encoded in the GUID/SID but stored elsewhere.

    [The tradeoff is that the question "What domain does this SID belong to?" becomes unanswerable, which is kind of a problem if you need to authenticate that SID. -Raymond]
  4. "What domain does this SID belong to?"

    But if you moved users to a new domain and deleted the old domain, how can you answer "What domain does this SID belong to?" for the old SID's?

    [Strip off the last component from the SID to get the domain. This does not require that the domain actually exist. -Raymond]
  5. Joshua says:

    [The tradeoff is that the question "What domain does this SID belong to?" becomes unanswerable, which is kind of a problem if you need to authenticate that SID. -Raymond]

    Let us suppose for a moment another way.

    S-1-0-* = Well Known SID (Administrator, etc.)

    S-1-1-* = Local Machine SID

    S-1-2-* = Remote Machine SID (expression of S-1-1-* when seen on a share)

    S-1-3-n-* = Domain SID

    Where * is a guid and n is the guid established for the domain on create. The map-reduction table on domain migration would now be old-n to new-n and doesn't contain user ids. This keeps it short enough you should never have to purge.

    [That wouldn't handle migration within a domain, though. -Raymond]
  6. Neil says:

    I wish local users could have a SID history.

  7. 640k says:

    The problem with authentication would be solved if the domain doesnt exist.

    [If you are getting the old domain for authentication purposes, then yes, getting the old domain doesn't help if it doesn't exist. But you may be getting it for display purposes. And in general, if the domain were not encoded in the SID, then how would you know who to send the SID to for authentication? Where is that "elsewhere" that knows how to extract the domain from a SID? -Raymond]
  8. Joshua. says:

    Actually that elsewhere is easy. You ask yourself. You ask the DC (don't care which) and you ask a DC for each trusted domain. If you can't find it that way you never will. This is still a worse choice then direct encoding though.

  9. cheong00 says:

    @Joshua. : If that's the case, things get funny when VPN and VM enters the scene.

    Consider what if your VPN client connects you to 2 different network with same domain name (these 2 domains never have connection so don't know each other exist). Now when you accessed share drive of first domain and then try to access share on second domain, your machine thinks you've logged in while the remote side does not.

    In the current implementation this problem does not exist because just the SID is exchanged, and the second domain's server will know it's not their SID.

    This case is common for first-line support environments. AFAIK 2 secondary schools in HK have the same domain name because the abbreviation of the schools' name are the same.

Comments are closed.