Windows Access Control List (ACL) Example 26

 

 

 

 

 

Getting the Logon (Session) SID in C++

 

A logon security identifier (SID) identifies the logon session associated with an access token. A typical use of a logon SID is in an ACE that allows access for the duration of a client's logon session. For example, a Windows service can use the LogonUser() function to start a new logon session. The LogonUser function returns an access token from which the service can extract the logon SID. The service can then use the SID in an ACE that allows the client's logon session to access the interactive window station and desktop.

The following program example gets the logon SID from an access token. It uses the GetTokenInformation() function to fill a TOKEN_GROUPS buffer with an array of the group SIDs from an access token. This array includes the logon SID, which is identified by the SE_GROUP_LOGON_ID attribute. The example function allocates a buffer for the logon SID; it is the caller's responsibility to free the buffer.

Create a new empty Win32 console application project. Give a suitable project name and change the project location if needed.

 

Getting the Logon (Session) SID in C++: Creating new C++ Win32 console mode application

 

Then, add the source file and give it a suitable name.

 

Getting the Logon (Session) SID in C++: Adding new C++ source file for the source code sample

 

Next, add the following source code.

 

// Getting the current Logon SID

#include <windows.h>

#include <stdio.h>

// For SID conversion

#include <sddl.h>

#include <aclapi.h>

 

// Simple clean up routine

void Cleanup(PTOKEN_GROUPS ptgrp)

{

      // Release the buffer for the token groups.

      if(ptgrp != NULL)

      {

            wprintf(L"Freeing up the ptgrp buffer...\n");

            HeapFree(GetProcessHeap(), 0, (LPVOID)ptgrp);

      }

      else

            wprintf(L"ptgrp buffer has been freed-up!\n");

}

 

// Get the logon SID and convert it to SID string...

BOOL GetLogonSID(HANDLE hToken, PSID ppsid)

{

      BOOL bSuccess = FALSE;

      DWORD dwIndex;

      DWORD dwLength = 0;

      PTOKEN_GROUPS ptgrp = NULL;  

      // Dummy initialization...

      LPTSTR pSid = L"";

     

      // Verify the parameter passed in is not NULL.

      // Although we just provide an empty buffer...

      if(ppsid == NULL)

      {

            wprintf(L"The ppsid pointer is NULL lol!\n");

            Cleanup(ptgrp);

      }

      else

            wprintf(L"The ppsid pointer is valid.\n");

     

      // Get the required buffer size and allocate the TOKEN_GROUPS buffer.

      if(!GetTokenInformation(

            hToken,               // handle to the access token

            TokenGroups,    // get information about the token's groups

            (LPVOID) ptgrp, // pointer to TOKEN_GROUPS buffer

            0,                         // size of buffer

            &dwLength        // receives required buffer size

            ))

      {

            if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)

            {

                  wprintf(L"GetTokenInformation() - buffer is OK!\n");

                  Cleanup(ptgrp);

            }

            else

            {

                  wprintf(L"Not enough buffer, re-allocate...\n");

                  ptgrp = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);

            }

           

            if(ptgrp == NULL)

            {

                  wprintf(L"Failed to allocate heap for ptgrp, error %u\n", GetLastError());

                  Cleanup(ptgrp);

            }

            else

                  wprintf(L"Well, buffer for ptgrp has been allocated!\n");

      }

      else

            wprintf(L"GetTokenInformation() is pretty fine!\n");

     

      // Get the token group information from the access token.

      if(!GetTokenInformation(

            hToken,         // handle to the access token

            TokenGroups,    // get information about the token's groups

            (LPVOID) ptgrp, // pointer to TOKEN_GROUPS buffer

            dwLength,       // size of buffer

            &dwLength       // receives required buffer size

            ))

      {

            wprintf(L"GetTokenInformation()  failed, error %u\n", GetLastError());

            Cleanup(ptgrp);

      }

      else

            wprintf(L"GetTokenInformation() - got the token group information!\n");

     

      // Loop through the groups to find the logon SID.

      for(dwIndex = 0; dwIndex < ptgrp->GroupCount; dwIndex++)

            if((ptgrp->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) ==  SE_GROUP_LOGON_ID)

            {

                  wprintf(L"Logon SID found!\n");

                  // If the logon SID is found then make a copy of it.

                  dwLength = GetLengthSid(ptgrp->Groups[dwIndex].Sid);

                  // Allocate a storage

                  wprintf(L"Allocating heap for ppsid...\n");

                  ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);

                  // and verify again...

                  if(ppsid == NULL)

                        Cleanup(ptgrp);

                  else

                        wprintf(L"Heap for ppsid allocated!\n");

                 

                  // If Copying the SID fails...

                  if(!CopySid(dwLength,

                        ppsid,    // Destination

                        ptgrp->Groups[dwIndex].Sid))  // Source

                  {

                        wprintf(L"Failed to copy the SID, error %u\n", GetLastError());

                        HeapFree(GetProcessHeap(), 0, (LPVOID)ppsid);

                        Cleanup(ptgrp);

                  }

                  else

                        wprintf(L"The SID was copied successfully!\n");

                 

                  // Convert the logon sid to SID string format

                  if(!(ConvertSidToStringSid(

                        ppsid,  // Pointer to the SID structure to be converted

                        &pSid))) // Pointer to variable that receives the null-terminated SID string

                  {

                        wprintf(L"ConvertSidToStringSid() failed, error %u\n", GetLastError());

                        Cleanup(ptgrp);

                        exit(1);

                  }

                  else

                  {

                        wprintf(L"ConvertSidToStringSid() is OK.\n");

                        wprintf(L"The logon SID string is: %s\n", pSid);

                  }

                  // The search was found, so break out from the loop

                  break;

            }

           

            LocalFree(pSid);

            // If everything OK, returns a clean slate...

            bSuccess = TRUE;

            return bSuccess;

}

 

// The following function release the buffer allocated by the GetLogonSID() function.

BOOL FreeLogonSID(PSID ppsid)

{

      HeapFree(GetProcessHeap(), 0, (LPVOID)ppsid);

      return TRUE;

}

 

int wmain(int argc, WCHAR **argv)

{

      // Handle to token

      HANDLE hToken;

     

      // A 'dummy' initial size of SID to avoid a NULL pointer

      BYTE sidBuffer[256];

      PSID ppsid = (PSID)&sidBuffer;

     

      // Open a handle to the access token for the calling process

      // that is the currently login access token

      if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))

      {

            wprintf(L"OpenProcessToken()-Getting the handle to access token failed, error %u\n", GetLastError());

      }

      else

            wprintf(L"OpenProcessToken()-Got the handle to access token!\n");

     

      // Call the GetLogonSID()

      if(GetLogonSID(hToken, ppsid))

            wprintf(L"GetLogonSID() is OK\n");

      else

            wprintf(L"GetLogonSID() failed, error %u\n\n", GetLastError());

     

      // Release the allocation for ppsid

      if(FreeLogonSID(ppsid))

            wprintf(L"The ppsid has been freed...\n");

      // Close the handle lol

      if(CloseHandle(hToken))

            wprintf(L"The handle to the process is closed.\n");

      return 0;

}

 

Build and run the project. The following screenshot is a sample output.

 

Getting the Logon (Session) SID in C++: A sample output with the created SID displayed in the  SID string format

 

The SID string is in the S-1-5-5-X-Y format which indicates a logon session. The X and Y values for these SIDs are different for each session. The well-known SID string for user, group and domain can be found at Windows well-known SID. The SID string is S-1-5-5-0-90455 is a logon session SID for the machine that used to run the program example.  This is used for process in a given logon session, gaining access to the window-station objects for that session.  The constant format is S-1-5-5-X-Y (SECURITY_LOGON_IDS_RID).  The X and Y values for these SIDs are different for each logon session.  The value of the SECURITY_LOGON_IDS_RID_COUNT is the number of RIDs in this identifier (5-X-Y).

 

 

 

 

< Windows ACL Example 25 | Windows Access Control List (ACL) Main | Win32 Programming | Windows ACL Example 27 >