Reputation: 3986
I need to pass a unique windows user account identifier between various processes (unique within the scope of a single computer running Windows 10 x64 1803 or higher).
The account's SID is the natural choice, but opaque IDs make debugging painful, so I'd prefer something human readable that maps 1:1 to a SID.
I originally tried just the logon name (e.g. "Rosalyn"). I could map that back to the correct SID, but the mapping method I used didn't work when running under a different user account for some reason (see edit below).
There seem to be at least two other forms of user account IDs that Windows uses:
...but these make me a little nervous; the documentation mentions environments not all users have (e.g. LDAP, domains, Directory Services, etc). This has to work for all users, regardless of whether they're at home or in a corporate environment.
Anyone have experience with this sort of thing? Bonus points if there's documentation somewhere on how to map back and forth.
... but the mapping method I used didn't work when running under a different user account for some reason.
Can you explain the reason? – Strive Sun - MSFT
// Get the SID for this user
try
{
var ntAccount = new NTAccount(logonUser); // e.g. logonUser = "Scott"
return (SecurityIdentifier)ntAccount.Translate(typeof(SecurityIdentifier));
}
catch (Exception)
{
Trace.WriteLine($"Unable to get SID for {logonUser}", "ERROR");
throw;
}
When running as the logon user, this code returned the correct SID (S-1-5-21-4275680301-1639116052-1993100807-1001), but when running under the SYSTEM account, given the same logonUser, this code returned the SID for Local System (S-1-5-18).
I thought the logon user name might be under-qualified, so I tried "<user-domain-name>\<user-name>"
and "<machine-name>\<user-name>"
, but those didn't work, regardless of the account I was running under.
Also, using things like UserDomainName made me a bit nervous, because whatever method I choose has to work for all users, regardless of their environment (home or corporate LAN). This is a case of being uneasy about what I don't know...
Upvotes: 0
Views: 344
Reputation: 6289
You can use LookupAccountNameA to get the sid.
The LookupAccountName function accepts the name of a system and an account as input. It retrieves a security identifier (SID) for the account and the name of the domain on which the account was found.
And using this api does not need to run in the context of the LocalSystem account.
Code Sample: (C++)
#include <Windows.h>
#include <Sddl.h>
#include <stdio.h>
int main(int argc, char** argv)
{
LPCTSTR wszAccName = TEXT("domainname\\username");
LPTSTR wszDomainName = (LPTSTR)GlobalAlloc(GPTR, sizeof(TCHAR) * 1024);
DWORD cchDomainName = 1024;
SID_NAME_USE eSidType;
LPTSTR sidstring;
char sid_buffer[1024];
DWORD cbSid = 1024;
SID* sid = (SID*)sid_buffer;
if (!LookupAccountName(NULL, wszAccName, sid_buffer, &cbSid, wszDomainName, &cchDomainName, &eSidType)) {
return GetLastError();
}
if (!ConvertSidToStringSid(sid, &sidstring)) {
return GetLastError();
}
printf("%ws\n", sidstring);
return 0;
}
Upvotes: 1