Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

SID Translator Library

0.00/5 (No votes)
17 Jan 2005 1  
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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here