8.3 Getting User and Group Information on Windows
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:
- 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;
}
|