You need to discover information about a user or group, and you have a username or user ID or a group name or ID.
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.
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:
lpSystemName
String representing the name of the remote system on which to look up
the name. If you specify this argument as NULL
,
the lookup will be done on the local system.
lpAccountName
String representing the name of the user or group to look up. This
argument may not be specified as NULL
.
Sid
Buffer into which the SID will be written. Initially, you may specify
this argument as NULL
to determine how large a
buffer is required to hold the SID.
cbSid
Pointer to an integer that both specifies the size of the buffer to receive the SID, and receives the size of the buffer required for the SID.
ReferencedDomainName
Buffer into which the domain name where the user or group name was
found is to be written. Initially, you may specify this argument as
NULL
to determine how large a buffer is required
to hold the domain name.
cbReferencedDomainName
Pointer to an integer that both specifies the size of the buffer to receive the domain name, and receives the size of the buffer required for the domain name.
peUse
Pointer to an enumeration that receives the type of SID to which the
looked-up name corresponds. The most commonly returned values are
SidTypeUser
(1) and
SidTypeGroup
(2).
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:
lpSystemName
String representing the name of the remote system on which to look up
the SID. If you specify this argument as NULL
, the
lookup will be done on the local system.
Sid
Buffer containing the SID to look up. This argument may not be
specified as NULL
.
Name
Buffer into which the name will be written. Initially, you may
specify this argument as NULL
to determine how
large a buffer is required to hold the name.
cbName
Pointer to an integer that both specifies the size of the buffer to receive the name, and receives the size of the buffer required for the name.
ReferencedDomainName
Buffer into which the domain name where the SID was found is to be
written. Initially, you may specify this argument as
NULL
to determine how large a buffer is required
to hold the domain name.
cbReferencedDomainName
Pointer to an integer that both specifies the size of the buffer to receive the domain name, and receives the size of the buffer required for the domain name.
peUse
Pointer to an enumeration that receives the type of SID to which the
looked-up SID corresponds. The most commonly returned values are
SidTypeUser
(1) and
SidTypeGroup
(2).
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; }