Click here to Skip to main content
Click here to Skip to main content

Converting SIDs between strings and binary

By , 17 Dec 2001
 
<!-- Download Links --> <!-- Add the rest of your HTML here -->

Introduction

Anyone who has ever used advanced security in Windows NT has probably run across SIDs before. SID is an acronym for Security IDentifier. A SID is a structure of variable length that uniquely identifies a user or group on Windows NT. SIDs are often viewed in string form, for example 'S-1-5-21-1431262831-1455604309-1834353910-1000'. However all the Win32 API that work with SIDs use the binary representation. As such the programmer may need to convert between string and binary representations of SIDs.

Starting in Windows 2000 Microsoft added two APIs for converting SIDs. They are ConvertStringSidToSid() and ConvertSidToStringSid(). The down-side to these APIs is they require the Platform SDK (for the file SDDL.H) and they don't work on Windows NT. If you are content with these restrictions, then I encourage you to use the Microsoft APIs. But if you need to convert SIDs in Windows NT then you'll need to write your own functions. Realizing there was no built-in way to convert SIDs in Windows NT, Microsoft released two Knowledgebase articles Q198907 and Q131320. These articles provide two functions to handle the conversion. I took these two functions, fixed a few minor bugs, and cleaned up the code to result in the following functions. It should be noted that no SID conversion functions work on Win95/98/ME. Only NT-based operating systems use SIDs and therefore only those systems contain the Win32 APIs that use SIDs.

//***********************************************
PSID GetBinarySid(LPCTSTR szSid)
{
     // This function is based off the KB article Q198907.
     // This function is the same as ConvertStringSidToSid(),
     // except that function is only on Windows 2000 and newer.
     // The calling function must free the returned SID with FreeSid.

     _ASSERTE(szSid);
     _ASSERTE(lstrlen(szSid));

     PSID pSid = NULL;
     LPTSTR szSidCopy = NULL;

     try
     {
          int i;
          LPTSTR ptr, ptr1;
          SID_IDENTIFIER_AUTHORITY sia; ZeroMemory(&sia, sizeof(sia));
          BYTE nByteAuthorityCount = 0;
          DWORD dwSubAuthority[8] = {0, 0, 0, 0, 0, 0, 0, 0};

          szSidCopy = new TCHAR[lstrlen(szSid) + 1];
          lstrcpy(szSidCopy, szSid);

          // S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL

          // Skip 'S'
          if(!(ptr = _tcschr(szSidCopy, _T('-'))))
               return NULL;

          // Skip '-'
          ptr++;

          // Skip SID_REVISION
          if(!(ptr = _tcschr(ptr, _T('-'))))
               return NULL;

          // Skip '-'
          ptr++;

          // Skip IdentifierAuthority
          if(!(ptr1 = _tcschr(ptr, _T('-'))))
               return NULL;
          *ptr1= 0;

          if((*ptr == _T('0')) && (*(ptr + 1) == _T('x')))
          {
               _stscanf(ptr, _T("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
                    &sia.Value[0],
                    &sia.Value[1],
                    &sia.Value[2],
                    &sia.Value[3],
                    &sia.Value[4],
                    &sia.Value[5]);
          }
          else
          {
               DWORD dwValue;
               _stscanf(ptr, _T("%lu"), &dwValue);

               sia.Value[5] = (BYTE)(dwValue & 0x000000FF);
               sia.Value[4] = (BYTE)(dwValue & 0x0000FF00) >> 8;
               sia.Value[3] = (BYTE)(dwValue & 0x00FF0000) >> 16;
               sia.Value[2] = (BYTE)(dwValue & 0xFF000000) >> 24;
          }

          // Skip '-'
          *ptr1 = '-';
          ptr = ptr1;
          ptr1++;

          for(i = 0; i < 8; i++)
          {
               // Get subauthority
               if(!(ptr = _tcschr(ptr, _T('-'))))
                    break;
               *ptr = 0;
               ptr++;
               nByteAuthorityCount++;
          }

          for(i = 0; i < nByteAuthorityCount; i++)
          {
               // Get subauthority
               _stscanf(ptr1, _T("%lu"), &dwSubAuthority[i]);
               ptr1 += lstrlen(ptr1) + 1;
          }
          delete[] szSidCopy;
          szSidCopy = NULL;

          if(!AllocateAndInitializeSid(&sia,
               nByteAuthorityCount,
               dwSubAuthority[0],
               dwSubAuthority[1],
               dwSubAuthority[2],
               dwSubAuthority[3],
               dwSubAuthority[4],
               dwSubAuthority[5],
               dwSubAuthority[6],
               dwSubAuthority[7],
               &pSid))
          {
               pSid = NULL;
          }
     }
     catch(...)
     {
          delete[] szSidCopy;
          pSid = NULL;
     }

     return pSid;
}

//***********************************************
bool GetTextualSid(const PSID pSid, LPTSTR szSid, DWORD &dwBufferSize)
{
     // This function is based off the KB article Q131320.
     // This function is the same as ConvertSidToStringSid(),
     // except that function is only on Windows 2000 and newer.

     _ASSERTE(pSid);
     _ASSERTE(szSid);

     bool bRtnVal = true;

     try
     {
          PSID_IDENTIFIER_AUTHORITY psia;
          DWORD dwSidSize, dwSubAuthorities;

          // Validate the binary SID
          if(!IsValidSid(pSid))
               return false;

          // Get the identifier authority value from the SID
          psia = GetSidIdentifierAuthority(pSid);

          // Get the number of subauthorities in the SID.
          dwSubAuthorities = *GetSidSubAuthorityCount(pSid);

          // Compute the buffer length
          // S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL
          dwSidSize = (15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);

          // Was the provided buffer large enough?
          if(dwBufferSize < dwSidSize)
          {
               dwBufferSize = dwSidSize;
               SetLastError(ERROR_INSUFFICIENT_BUFFER);
               return false;
          }

          // Add 'S' prefix and revision number to the string
          dwSidSize = _stprintf(szSid, _T("S-%lu-"), SID_REVISION);

          // Add SID identifier authority to the string.
          if((psia->Value[0] != 0) || (psia->Value[1] != 0))
          {
               dwSidSize += _stprintf(szSid + lstrlen(szSid),
                    _T("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
                    (USHORT)psia->Value[0],
                    (USHORT)psia->Value[1],
                    (USHORT)psia->Value[2],
                    (USHORT)psia->Value[3],
                    (USHORT)psia->Value[4],
                    (USHORT)psia->Value[5]);
          }
          else
          {
               dwSidSize += _stprintf(szSid + lstrlen(szSid),
                    _T("%lu"),
                    (ULONG)(psia->Value[5]) +
                    (ULONG)(psia->Value[4] << 8) +
                    (ULONG)(psia->Value[3] << 16) +
                    (ULONG)(psia->Value[2] << 24) );
          }

          // Add SID subauthorities to the string
          for(DWORD dwCounter = 0; dwCounter < dwSubAuthorities; dwCounter++)
          {
               dwSidSize += _stprintf(szSid + dwSidSize, _T("-%lu"),
                    *GetSidSubAuthority(pSid, dwCounter));
          }
     }
     catch(...)
     {
          bRtnVal = false;
     }

     return bRtnVal;
}

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

About the Author

Brian Friesen
Web Developer
United States United States
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralDoes it give the same output as that of GetBinaryFormmembersharad_sharma_2k8-Feb-07 20:56 
Very Good article.
Thanks.
 
Does it give the same output as that of GetBinaryForm method of SecurityIdentifier class ( Namespace: System.Security.Principal, .NET 2.0).
 
Regards
Sharad Sharma
 


 
Sharad Sharma
(sharad_sharma_2k@yahoo.com)

GeneralDoes it give the same output as that of SecurityIdentifier.GetBinaryForm() of .NET 2.0membersharad_sharma_2k8-Feb-07 20:54 
Very Good article.
Thanks.
 
Does it give the same output as that of GetBinaryForm methof of GetBinaryForm class of System.Security.Principal namespace of .NET 2.0 framework.
 
Regards
Sharad Sharma

 
Sharad Sharma
(sharad_sharma_2k@yahoo.com)
GeneralGreat ArticlememberAlois Kraus12-Jun-02 1:31 
This is exactly the function I was looking for. You are right, I dont want to
download the platform SDK for one missing include file.
 
Poke tongue | ;-P
GeneralUserlistmemberHaresh15-May-02 1:32 
Is there any api to find out the list of all the logged on user and machine name from Primary Domain Controller
 

 
HArish Chouksey
Software Engineer
Learnet India Limited
Mumbai-India
GeneralRe: UserlistsussKedar Babar16-Oct-02 21:59 
Yes it is possible, you are required to use the SID's which are stored in HKEY_USERS, use the function GetBinarySID(), and then pass that SID to the API LookUpAccountSid().
 
Kedar Babar
Software Engineer/Architect.
 

GeneralAther functionsmemberGil Messerman14-Feb-02 11:56 
He,
 
Why not to use two other functions:
1) UuidFromString
2) UuidToString
 
Both functions are found in RPC libraby and work on both Win2k ant Win NT.Confused | :confused:
 
Gil

GeneralRe: Ather functionsmemberBrian Friesen15-Feb-02 9:04 
UUIDs are not the same thing as SIDs, so those functions wouldn't work.
 
UUID (universally unique identifier) is the same thing as a GUID (globally unique identifier). Both are commonly represented in the form of 6B29FC40-CA47-1067-B31D-00DD010662DA. But a SID is a varying length structure not conforming to the same rules. Both S-1-5-21-81404079-1269637429-1532257752-1001 and S-1-5-18 are SIDs, which are completely different from UUIDs/GUIDs.

QuestionExamples (demos)??memberDaniel Madden18-Dec-01 19:06 
Hi,
 
Nice clean-up of the code...do you have any examples of this in work??
 
Thanks in advance,
 
Dan

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130617.1 | Last Updated 18 Dec 2001
Article Copyright 2001 by Brian Friesen
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid