Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
8.3.1 Problem
You need to discover information about a user or group, and you have a username or user ID or a group name or ID. 8.3.2 Solution
Windows identifies users and groups using security identifiers (SIDs), which are unique, variably sized values assigned by an authority such as the local machine or a Windows NT server domain. Functions and data structures typically represent users and groups using SIDs, rather than using names. The Win32 API provides numerous functions for manipulating SIDs, but of particular interest to us in this recipe are the functions LookupAccountName( ) and LookupAccountSid( ), which are used to map between names and SIDs. 8.3.3 Discussion
The Win32 API function LookupAccountName( ) is used to find the SID that corresponds to a name. You can use it to obtain information about a name on either the local system or a remote system. While it might seem that mapping a name to a SID is a simple operation, LookupAccountName( ) actually requires a large number of arguments to allow it to complete its work. LookupAccountName( ) has the following signature: BOOL LookupAccountName(LPCTSTR lpSystemName, LPCTSTR lpAccountName, PSID Sid, LPDWORD cbSid, LPTSTR ReferencedDomainName, LPDWORD cbReferencedDomainName, PSID_NAME_USE peUse); This function has the following arguments:
The following function, SpcLookupName( ), is essentially a wrapper around LookupAccountName( ). It handles the nuances of performing user and group name lookup, including allocating the necessary buffers and error conditions. If the name is successfully found, the return will be a pointer to a dynamically allocated SID structure, which you must later free using LocalFree( ). If the name could not be found, NULL will be returned, and GetLastError( ) will return ERROR_NONE_MAPPED. If any other kind of error occurs, SpcLookupName( ) will return NULL, and GetLastError( ) will return the relevant error code. #include <windows.h> PSID SpcLookupName(LPCTSTR lpszSystemName, LPCTSTR lpszAccountName) { PSID Sid; DWORD cbReferencedDomainName, cbSid; LPTSTR ReferencedDomainName; SID_NAME_USE eUse; cbReferencedDomainName = cbSid = 0; if (LookupAccountName(lpszSystemName, lpszAccountName, 0, &cbSid, 0, &cbReferencedDomainName, &eUse)) { SetLastError(ERROR_NONE_MAPPED); return 0; } if (GetLastError( ) != ERROR_INSUFFICIENT_BUFFER) return 0; if (!(Sid = (PSID)LocalAlloc(LMEM_FIXED, cbSid))) return 0; ReferencedDomainName = (LPTSTR)LocalAlloc(LMEM_FIXED, cbReferencedDomainName); if (!ReferencedDomainName) { LocalFree(Sid); return 0; } if (!LookupAccountName(lpszSystemName, lpszAccountName, Sid, &cbSid, ReferencedDomainName, &cbReferencedDomainName, &eUse)) { LocalFree(ReferencedDomainName); LocalFree(Sid); return 0; } LocalFree(ReferencedDomainName); return Sid; } The Win32 API function LookupAccountSid( ) is used to find the name that corresponds to a SID. You can use it to obtain information about a SID on either the local system or a remote system. While it might seem that mapping a SID to a name is a simple operation, LookupAccountSid( ) actually requires a large number of arguments to allow it to complete its work. LookupAccountSid( ) has the following signature: BOOL LookupAccountSid(LPCTSTR lpSystemName, PSID Sid,LPTSTR Name, LPDWORD cbName, LPTSTR ReferencedDomainName, LPDWORD cbReferencedDomainName, PSID_NAME_USE peUse); This function has the following arguments:
The following function, SpcLookupSid( ), is essentially a wrapper around LookupAccountSid( ). It handles the nuances of performing SID lookup, including allocating the necessary buffers and error conditions. If the SID is successfully found, the return will be a pointer to a dynamically allocated buffer containing the user or group name, which you must later free using LocalFree( ). If the SID could not be found, NULL will be returned, and GetLastError( ) will return ERROR_NONE_MAPPED. If any other kind of error occurs, SpcLookupSid( ) will return NULL, and GetLastError( ) will return the relevant error code. #include <windows.h> LPTSTR SpcLookupSid(LPCTSTR lpszSystemName, PSID Sid) { DWORD cbName, cbReferencedDomainName; LPTSTR lpszName, ReferencedDomainName; SID_NAME_USE eUse; cbName = cbReferencedDomainName = 0; if (LookupAccountSid(lpszSystemName, Sid, 0, &cbName, 0, &cbReferencedDomainName, &eUse)) { SetLastError(ERROR_NONE_MAPPED); return 0; } if (GetLastError( ) != ERROR_INSUFFICIENT_BUFFER) return 0; if (!(lpszName = (LPTSTR)LocalAlloc(LMEM_FIXED, cbName))) return 0; ReferencedDomainName = (LPTSTR)LocalAlloc(LMEM_FIXED, cbReferencedDomainName); if (!ReferencedDomainName) { LocalFree(lpszName); return 0; } if (!LookupAccountSid(lpszSystemName, Sid, lpszName, &cbName, ReferencedDomainName, &cbReferencedDomainName, &eUse)) { LocalFree(ReferencedDomainName); LocalFree(lpszName); return 0; } LocalFree(ReferencedDomainName); return lpszName; } |