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.
Then, add the source file and give it a suitable name.
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(LFreeing up the ptgrp buffer...\n);
HeapFree(GetProcessHeap(), 0, (LPVOID)ptgrp);
}
else
wprintf(Lptgrp 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(LThe ppsid pointer is NULL lol!\n);
Cleanup(ptgrp);
}
else
wprintf(LThe 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(LGetTokenInformation() - buffer is OK!\n);
Cleanup(ptgrp);
}
else
{
wprintf(LNot enough buffer, re-allocate...\n);
ptgrp = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
}
if(ptgrp == NULL)
{
wprintf(LFailed to allocate heap for ptgrp, error %u\n, GetLastError());
Cleanup(ptgrp);
}
else
wprintf(LWell, buffer for ptgrp has been allocated!\n);
}
else
wprintf(LGetTokenInformation() 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(LGetTokenInformation() failed, error %u\n, GetLastError());
Cleanup(ptgrp);
}
else
wprintf(LGetTokenInformation() - 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(LLogon 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(LAllocating heap for ppsid...\n);
ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
// and verify again...
if(ppsid == NULL)
Cleanup(ptgrp);
else
wprintf(LHeap for ppsid allocated!\n);
// If Copying the SID fails...
if(!CopySid(dwLength,
ppsid, // Destination
ptgrp->Groups[dwIndex].Sid)) // Source
{
wprintf(LFailed to copy the SID, error %u\n, GetLastError());
HeapFree(GetProcessHeap(), 0, (LPVOID)ppsid);
Cleanup(ptgrp);
}
else
wprintf(LThe 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(LConvertSidToStringSid() failed, error %u\n, GetLastError());
Cleanup(ptgrp);
exit(1);
}
else
{
wprintf(LConvertSidToStringSid() is OK.\n);
wprintf(LThe 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(LOpenProcessToken()-Getting the handle to access token failed, error %u\n, GetLastError());
}
else
wprintf(LOpenProcessToken()-Got the handle to access token!\n);
// Call the GetLogonSID()
if(GetLogonSID(hToken, ppsid))
wprintf(LGetLogonSID() is OK\n);
else
wprintf(LGetLogonSID() failed, error %u\n\n, GetLastError());
// Release the allocation for ppsid
if(FreeLogonSID(ppsid))
wprintf(LThe ppsid has been freed...\n);
// Close the handle lol
if(CloseHandle(hToken))
wprintf(LThe handle to the process is closed.\n);
return 0;
}
Build and run the project. The following screenshot is a sample output.
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).