SID Translator Library






4.43/5 (18 votes)
Jan 17, 2005
1 min read

57802

754
The article briefly describes the library for conversion of Windows domain account name into its security identifier (SID) and vice versa.
Introduction
SidTranslator is a simple library with only two methods:
GetSid
, which converts the given MS Windows account name into its security identifier (SID).GetName
, which converts the SID into the domain account name.
It has only about one hundred lines of code, but I spent a couple of hours to make it working, so I'd like to share it with others to help them avoid the mistakes I did.
Using the code
I use four methods provided by the unmanaged dynamic-link library advapi32.dll - LookupAccountSid
, LookupAccountName
, ConvertSidToStringSid
and ConvertStringSidToSid
. They are declared at the first part of the code:
[DllImport( "advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern bool LookupAccountSid(
[In,MarshalAs(UnmanagedType.LPTStr)] string systemName,
IntPtr sid,
[Out,MarshalAs(UnmanagedType.LPTStr)] StringBuilder name,
ref int cbName,
StringBuilder referencedDomainName,
ref int cbReferencedDomainName,
out int use );
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool LookupAccountName(
[In,MarshalAs(UnmanagedType.LPTStr)] string systemName,
[In,MarshalAs(UnmanagedType.LPTStr)] string accountName,
IntPtr sid,
ref int cbSid,
StringBuilder referencedDomainName,
ref int cbReferencedDomainName,
out int use);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
internal static extern bool ConvertSidToStringSid(
IntPtr sid,
[In,Out,MarshalAs(UnmanagedType.LPTStr)] ref string pStringSid);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
internal static extern bool ConvertStringSidToSid(
[In, MarshalAs(UnmanagedType.LPTStr)] string pStringSid,
ref IntPtr sid);
The first method, GetSid
takes an account name as a parameter and returns the SID in its string form.
public static string GetSid(string name)
{
IntPtr _sid = IntPtr.Zero; //pointer to binary form of SID string.
int _sidLength = 0; //size of SID buffer.
int _domainLength = 0; //size of domain name buffer.
int _use; //type of object.
//stringBuilder for domain name.
StringBuilder _domain = new StringBuilder();
int _error = 0;
string _sidString = "";
//first call of the function only returns the size
//of buffers (SID, domain name)
LookupAccountName(null, name, _sid, ref _sidLength, _domain,
ref _domainLength, out _use);
_error = Marshal.GetLastWin32Error();
//error 122 (The data area passed to a system call is too small)
// normal behaviour.
if (_error != 122)
{
throw(new Exception(new Win32Exception(_error).Message));
}
else
{
//allocates memory for domain name
_domain = new StringBuilder(_domainLength);
//allocates memory for SID
_sid = Marshal.AllocHGlobal(_sidLength);
bool _rc = LookupAccountName(null, name, _sid, ref _sidLength, _domain,
ref _domainLength, out _use);
if (_rc == false)
{
_error = Marshal.GetLastWin32Error();
Marshal.FreeHGlobal(_sid);
throw(new Exception(new Win32Exception(_error).Message));
}
else
{
// converts binary SID into string
_rc = ConvertSidToStringSid(_sid, ref _sidString);
if (_rc == false)
{
_error = Marshal.GetLastWin32Error();
Marshal.FreeHGlobal(_sid);
throw(new Exception(new Win32Exception(_error).Message));
}
else
{
Marshal.FreeHGlobal(_sid);
return _sidString;
}
}
}
}
Please notice that the LookupAccountName
method is called twice. The first call returns the number of bytes you need to store SID and domain name only. The second call does the rest. At the end of the code, I call ConvertSidToStringSid
method which converts binary form of security identifier into the string representation of SID.
The second method, GetName
, takes string representation of SID and returns account name.
public static string GetName(string sid)
{
IntPtr _sid = IntPtr.Zero; //pointer to binary form of SID string.
int _nameLength = 0; //size of object name buffer
int _domainLength = 0; //size of domain name buffer
int _use; //type of object
StringBuilder _domain = new StringBuilder(); //domain name variable
int _error = 0;
StringBuilder _name = new StringBuilder(); //object name variable
//converts SID string into the binary form
bool _rc0 = ConvertStringSidToSid(sid, ref _sid);
if (_rc0 == false)
{
_error = Marshal.GetLastWin32Error();
Marshal.FreeHGlobal(_sid);
throw(new Exception(new Win32Exception(_error).Message));
}
//first call of method returns the size of domain name
//and object name buffers
bool _rc = LookupAccountSid(null, _sid, _name, ref _nameLength, _domain,
ref _domainLength, out _use);
_domain = new StringBuilder(_domainLength); //allocates memory for domain name
_name = new StringBuilder(_nameLength); //allocates memory for object name
_rc = LookupAccountSid(null, _sid, _name, ref _nameLength, _domain,
ref _domainLength, out _use);
if (_rc == false)
{
_error = Marshal.GetLastWin32Error();
Marshal.FreeHGlobal(_sid);
throw(new Exception(new Win32Exception(_error).Message));
}
else
{
Marshal.FreeHGlobal(_sid);
return _domain.ToString() + "\\" + _name.ToString();
}
}
As the first step it's necessary to convert string SID into its binary form using the ConvertStringSidToSid
method. LookupAccountSid
method does the rest. Again, it's necessary to call it twice, as the first call returns the size of buffers only.