My Training Period: xx hours. Before you begin, read someinstruction here. This is continuation fromWindows Access Control Programming 13. All the program examples run in the Debug mode, the WinXp machine logged as normal/restricted userMike, who is a member of Administrators group except whenever mentioned. Beware the codes that span more than one line.
SID conversion: String-to-Binary-to-String
TheConvertSidToStringSid() and ConvertStringSidToSid() functions convert a SID to and from string format. For Windows NT 4.0 and earlier theConvertSidToStringSid() and ConvertStringSidToSid() are not supported.
// Playing with SID format // For Win Xp #define _WIN32_WINNT 0x0501 #include <windows.h> #include <stdio.h> #include <sddl.h> #include <aclapi.h>
int main() { DWORD SidSize, SidSize2; PSID TheSID = NULL; LPTSTR pSid = "";
SidSize = SECURITY_MAX_SID_SIZE;
printf("Create a well known \"WinLocalSystemSid\" SID.\n"); printf("--------------------------------------------\n"); // Allocate enough memory for the largest possible SID. if(!(TheSID = LocalAlloc(LMEM_FIXED, SidSize))) { printf("Could not allocate memory, error %u.\n", GetLastError()); // Just exit exit(1); } else printf("Memory allocated successfully.\n");
// Create a SID for the Local system on the local computer. if(!CreateWellKnownSid( WinLocalSystemSid, // Well known Local system SID NULL, // Domain SID, NULL for local computer TheSID, // Pointer to memory for new SID &SidSize// Pointer in DWORD the number of byte of TheSid )) { printf("CreateWellKnownSid() error %u.\n\n", GetLastError()); } |
else
{
printf("CreateWellKnownSid() for Local system is OK.\n\n", GetLastError());
printf("Convert the \"WinLocalSystemSid\" SID to string SID.\n");
printf("--------------------------------------------------\n");
// Get the string version of the SID (S-R-I-I...)
if(!(ConvertSidToStringSid(
TheSID, // Pointer to the SID structure to be converted
&pSid)))// Pointer to variable that receives the null-terminated SID string
{
printf("ConvertSidToStringSid() error %u\n", GetLastError());
exit(1);
}
else
{
printf("ConvertSidToStringSid() is OK.\n");
printf("The SID string for WinLocalSystemSid is: %s\n", pSid);
}
}
if(IsValidSid(TheSID))
printf("The SID is valid\n");
else
printf("The SID is not valid!\n");
//**********************************************************
// TODO: Then, use the string SID as needed.
// ...
// When done, don't forget to release the memory used.
//**********************************************************
if(LocalFree(TheSID) == NULL)
printf("Memory is freed up...\n");
//************************************************************
LPTSTR StringSid = "S-1-5-18";// or "SY" - a well known Local System
PSID TheSID2 = NULL;
SidSize2 = SECURITY_MAX_SID_SIZE;
// S-R-5-18 and equal to...
// SECURITY_NT_AUTHORITY\\SECURITY_LOCAL_SYSTEM_RID
// But they are stored as in binary format in a SID structure
printf("\nConvert the \"S-1-5-18\" string SID to SID and then reconvert.\n");
printf("------------------------------------------------------------\n");
if(!(TheSID2 = LocalAlloc(LMEM_FIXED, SidSize2)))
{
printf("Could not allocate memory, error %u.\n", GetLastError());
exit(1);
}
else
printf("Memory allocated successfully.\n");
//*************************************************
if(!ConvertStringSidToSid(
StringSid, // Pointer to a null-terminated string containing the string-format SID to convert
&TheSID2)) // Pointer to a variable that receives a pointer to the converted SID
{
printf("ConvertStringSidToSid() for Local system error %u\n", GetLastError());
exit(1);
}
else
{
printf("ConvertStringSidToSid() for Local system is OK.\n");
}
if(!(ConvertSidToStringSid(
TheSID2, // Pointer to the SID structure to be converted
&StringSid))) // Pointer to variable that receives the null-terminated SID string
{
printf("Reconversion-ConvertSidToStringSid() error %u\n", GetLastError());
exit(1);
}
else
{
printf("Reconversion-ConvertSidToStringSid() is OK.\n");
printf("The SID string for WinLocalSystemSid is: %s\n", pSid);
}
if(IsWellKnownSid(TheSID2, WinLocalSystemSid))
printf("The SID is a well known SID.\n");
else
printf("It is non well known SID, error %u.\n", GetLastError());
//**************************************************
if(IsValidSid(TheSID2))
printf("The SID is valid.\n");
else
printf("The SID is not valid!, error %u\n", GetLastError());
if(LocalFree(TheSID2) == NULL)
printf("Memory is freed up...\n");
return 0;
}
A sample output:
|
Getting the Logon SID
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 theLogonUser() function to start a new logon session. TheLogonUser() 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 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 theSE_GROUP_LOGON_ID attribute. The example function allocates a buffer for the logon SID and it is the caller's responsibility to free the buffer.
// Getting the Logon SID
// For Win Xp
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <stdio.h>
#include <sddl.h>
#include <aclapi.h>
//************************************************************
void Cleanup(PTOKEN_GROUPS ptgrp)
{
// Release the buffer for the token groups.
if(ptgrp != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)ptgrp);
}
//***************************************************************
//**************************************************************
// 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;
// Again, dummy initialization...
LPTSTR pSid = "";
// Verify the parameter passed in is not NULL.
// Although we just provide an empty buffer...
if(ppsid == NULL)
{
printf("The ppsid pointer is NULL lol!\n");
Cleanup(ptgrp);
}
else
printf("The ppsid pointer is OK.\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)
Cleanup(ptgrp);
else
ptgrp = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
if(ptgrp == NULL)
Cleanup(ptgrp);
else
printf("Buffer for TOKEN_GROUPS is OK.\n");
}
else
printf("GetTokenInformation()-Getting all the buffer and their size is OK\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
))
{ Cleanup(ptgrp); }
else
printf("GetTokenInformation()-Getting the group info is OK\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)
{
// If the logon SID is found then make a copy of it.
dwLength = GetLengthSid(ptgrp->Groups[dwIndex].Sid);
// Allocate a storage
ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
// and verify again...
if(ppsid == NULL)
Cleanup(ptgrp);
else
printf("The ppsid pointer is OK.\n");
// If Copying the SID fails...
if(!CopySid(dwLength,
ppsid, // Destination
ptgrp->Groups[dwIndex].Sid)) // Source
{
HeapFree(GetProcessHeap(), 0, (LPVOID)ppsid);
Cleanup(ptgrp);
}
else
printf("CopySid() is OK lol!\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
{
printf("ConvertSidToStringSid() error %u\n", GetLastError());
Cleanup(ptgrp);
exit(1);
}
else
{
printf("ConvertSidToStringSid() is OK.\n");
printf("The logon SID string is: %s\n", 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 main()
{
// Handle to token
HANDLE hToken;
// Just 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))
{
printf("OpenProcessToken()-Getting the handle to access token failed: %u\n", GetLastError());
}
else
printf("OpenProcessToken()-Getting the handle to access token is OK\n");
// Call the GetLogonSID()
if(GetLogonSID(hToken, ppsid))
printf("GetLogonSID() is OK. Error if any: %u\n\n", GetLastError());
else
printf("GetLogonSID() is not OK, error %u\n\n", GetLastError());
// Release the allocation for ppsid
if(FreeLogonSID(ppsid))
printf("The ppsid has been freed...\n");
// Close the handle lol
if(CloseHandle(hToken))
printf("The handle to the process is closed.\n");
return 0;
}
A sample output:
OpenProcessToken()-Getting the handle to access token is OK
The ppsid pointer is OK.
Buffer for TOKEN_GROUPS is OK.
GetTokenInformation()-Getting the group info is OK
The ppsid pointer is OK.
CopySid() is OK lol!
ConvertSidToStringSid() is OK.
The logon SID string is: S-1-5-5-0-55363
GetLogonSID() is OK. Error if any: 0
The ppsid has been freed...
The handle to the process is closed.
Press any key to continue
The SID string isS-1-5-5-0-55363 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 isS-1-5-5-X-Y (SECURITY_LOGON_IDS_RID). TheX andY values for these SIDs are different for each logon session. The value of theSECURITY_LOGON_IDS_RID_COUNT is the number of RIDs in this identifier (5-X-Y).
Further reading and digging:
For Multi bytes, Unicode characters and Localization please refer to Locale, wide characters & Unicode (Story) and Windows users & groups programming tutorials (Implementation).
Structure, enum, union and typedef story can be foundC/C++ struct, enum, union & typedef.
Notation used in MSDN is Hungarian Notation instead of CamelCase and is discussedWindows programming notations.
Windows data type information is inWindows data types used in Win32 programming.
Check the best selling C, C++ and Windows books at Amazon.com.
Microsoft C references, online MSDN.
Microsoft Visual C++, online MSDN.
ReactOS - Windows binary compatible OS - C/C++ source code repository, Doxygen.
Linux Access Control Lists (ACL) info can be found atAccess Control Lists.