windows-nt/Source/XPSP1/NT/ds/adsi/winnt/grputils.cxx
2020-09-26 16:20:57 +08:00

829 lines
19 KiB
C++

//---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995
//
// File: cenumGroupCollection.cxx
//
// Contents: Windows NT 3.5 GroupCollection Enumeration Code
//
//
//
//
//
//
// History:
//----------------------------------------------------------------------------
#include "winnt.hxx"
#pragma hdrstop
COMPUTER_GROUP_MEMBER CompMember;
//
// This assumes that addr is an LPBYTE type.
//
#define WORD_ALIGN_DOWN(addr) \
addr = ((LPBYTE)((DWORD_PTR)addr & ~1))
DWORD ComputerGrpMemberStrings[]=
{
FIELD_OFFSET(COMPUTER_GROUP_MEMBER, Parent),
FIELD_OFFSET(COMPUTER_GROUP_MEMBER, Computer),
FIELD_OFFSET(COMPUTER_GROUP_MEMBER, Domain),
FIELD_OFFSET(COMPUTER_GROUP_MEMBER, Name),
0xFFFFFFFF
};
DECLARE_INFOLEVEL(GrpUt)
DECLARE_DEBUG(GrpUt)
#define GrpUtDebugOut(x) GrpUtInlineDebugOut x
BOOL
WinNTLocalGroupOpen(
LPWSTR szDomainName,
LPWSTR szComputerName,
LPWSTR szGroupName,
PHANDLE phGroup
)
{
WCHAR szTempBuffer[MAX_PATH];
PINI_COMP_GROUP pIniCompGrp;
HRESULT hr;
if (!phGroup) {
return(FALSE);
}
pIniCompGrp = (PINI_COMP_GROUP)AllocADsMem(
sizeof(INI_COMP_GROUP)
);
if (!pIniCompGrp) {
return(FALSE);
}
hr = MakeUncName(
szComputerName,
szTempBuffer
);
BAIL_ON_FAILURE(hr);
if (!(pIniCompGrp->szUncCompName = AllocADsStr(szTempBuffer))){
goto error;
}
// to guard against the case of domainName == NULL for no
// workstation services
if (szDomainName != NULL) {
if (!(pIniCompGrp->szDomainName = AllocADsStr(szDomainName))) {
goto error;
}
}
if (!(pIniCompGrp->szComputerName = AllocADsStr(szComputerName))){
goto error;
}
if (!(pIniCompGrp->szGroupName = AllocADsStr(szGroupName))){
goto error;
}
*phGroup = (HANDLE)pIniCompGrp;
return(TRUE);
error:
if (pIniCompGrp) {
FreeIniCompGroup(pIniCompGrp);
}
*phGroup = NULL;
return(FALSE);
}
BOOL
WinNTLocalGroupEnum(
HANDLE hGroup,
DWORD dwRequested,
LPBYTE * ppBuffer,
PDWORD pdwReturned
)
{
LPCOMPUTER_GROUP_MEMBER * ppGroupMembers = NULL;
DWORD i = 0;
BOOL dwRet = FALSE;
DWORD dwReturned = 0;
DWORD dwSize = 0;
LPCOMPUTER_GROUP_MEMBER pBuffer = NULL;
LPBYTE pEnd = NULL;
DWORD dwError;
BOOL fretVal = FALSE;
ppGroupMembers = (LPCOMPUTER_GROUP_MEMBER *)AllocADsMem(
sizeof(LPCOMPUTER_GROUP_MEMBER)* dwRequested
);
if (!ppGroupMembers) {
return(FALSE);
}
for (i = 0; i < dwRequested; i++) {
dwRet = WinNTLocalGroupGetObject(
hGroup,
&ppGroupMembers[dwReturned]
);
if (!dwRet) {
dwError = GetLastError();
if (dwError == ERROR_INVALID_SID) {
continue;
}
//
// it was not because of a bad sid
// so break out, nothing more can be done
//
break;
}
dwReturned++;
}
dwRet = ComputeLocalGroupDataSize(
ppGroupMembers,
dwReturned,
&dwSize
);
pBuffer = (LPCOMPUTER_GROUP_MEMBER)AllocADsMem(
dwSize
);
if (pBuffer) {
fretVal = TRUE;
pEnd = (LPBYTE)((LPBYTE)(pBuffer) + dwSize);
for (i = 0; i < dwReturned; i++) {
pEnd = CopyIniCompGroupToCompGroup(
ppGroupMembers[i],
(LPBYTE)(pBuffer + i),
pEnd
);
}
}
for (i = 0; i < dwReturned; i++ ) {
FreeIntCompGroup(*(ppGroupMembers + i));
}
FreeADsMem(ppGroupMembers);
//
// Will correctl set to NULL if alloc failed.
//
*ppBuffer = (LPBYTE)pBuffer;
*pdwReturned = fretVal ? dwReturned : 0;
if (!fretVal) {
return(FALSE);
}
if (dwReturned == dwRequested){
return(TRUE);
}else {
return(FALSE);
}
}
BOOL
WinNTLocalGroupGetObject(
HANDLE hGroup,
LPCOMPUTER_GROUP_MEMBER * ppGroupMember
)
{
BOOL dwRet = FALSE;
PINI_COMP_GROUP pIniCompGrp = (PINI_COMP_GROUP)hGroup;
NET_API_STATUS nasStatus = 0;
if ((!pIniCompGrp->_pBuffer) ||
(pIniCompGrp->_dwCurrentObject == pIniCompGrp->_dwObjectReturned)) {
if (pIniCompGrp->_bNoMore) {
//
// No more objects to return
//
return(FALSE);
}
if (pIniCompGrp->_pBuffer) {
NetApiBufferFree(pIniCompGrp->_pBuffer);
pIniCompGrp->_pBuffer = NULL;
}
pIniCompGrp->_dwObjectReturned = 0;
pIniCompGrp->_dwCurrentObject = 0;
pIniCompGrp->_dwTotalObjects = 0;
nasStatus = NetLocalGroupGetMembers(
pIniCompGrp->szUncCompName,
pIniCompGrp->szGroupName,
2,
&pIniCompGrp->_pBuffer,
MAX_PREFERRED_LENGTH,
&pIniCompGrp->_dwObjectReturned,
&pIniCompGrp->_dwTotalObjects,
&pIniCompGrp->_dwResumeHandle
);
if ((nasStatus != ERROR_SUCCESS) && (nasStatus != ERROR_MORE_DATA)){
SetLastError(nasStatus);
return(FALSE);
}
if (nasStatus != ERROR_MORE_DATA) {
pIniCompGrp->_bNoMore = TRUE;
}
//
// If there are no more objects to return,
// return FALSE
//
if (!pIniCompGrp->_dwObjectReturned) {
return(FALSE);
}
}
while ( dwRet != TRUE &&
(pIniCompGrp->_dwCurrentObject < pIniCompGrp->_dwTotalObjects))
{
dwRet = BuildLocalGroupMember(
hGroup,
(LPBYTE)((LPLOCALGROUP_MEMBERS_INFO_2)pIniCompGrp->_pBuffer
+ pIniCompGrp->_dwCurrentObject),
ppGroupMember
);
if (dwRet == FALSE) {
if (GetLastError() == ERROR_INVALID_SID) {
pIniCompGrp->_dwCurrentObject++;
continue;
//
// proceed to the top of the while loop
//
}
else
goto error;
}
}
//
// the while loop
//
if (dwRet == FALSE)
goto error;
pIniCompGrp->_dwCurrentObject++;
return(TRUE);
error:
return(FALSE);
}
BOOL
WinNTLocalGroupClose(
HANDLE hGroup
)
{
PINI_COMP_GROUP pIniCompGrp = (PINI_COMP_GROUP)hGroup;
if (pIniCompGrp) {
FreeIniCompGroup(pIniCompGrp);
}
return(TRUE);
}
void
FreeIniCompGroup(
PINI_COMP_GROUP pIniCompGrp
)
{
if (pIniCompGrp->szDomainName) {
FreeADsStr(pIniCompGrp->szDomainName);
}
if (pIniCompGrp->szComputerName) {
FreeADsStr(pIniCompGrp->szComputerName);
}
if (pIniCompGrp->szGroupName) {
FreeADsStr(pIniCompGrp->szGroupName);
}
if (pIniCompGrp->szUncCompName) {
FreeADsStr(pIniCompGrp->szUncCompName);
}
if (pIniCompGrp->_pBuffer) {
NetApiBufferFree(pIniCompGrp->_pBuffer);
}
if (pIniCompGrp) {
FreeADsMem(pIniCompGrp);
}
return;
}
void
FreeIntCompGroup(
LPCOMPUTER_GROUP_MEMBER pCompGroupMember
)
{
if (pCompGroupMember->Parent) {
FreeADsMem(pCompGroupMember->Parent);
}
if (pCompGroupMember->Computer) {
FreeADsStr(pCompGroupMember->Computer);
}
if (pCompGroupMember->Domain) {
FreeADsStr(pCompGroupMember->Domain);
}
if (pCompGroupMember->Name) {
FreeADsStr(pCompGroupMember->Name);
}
if (pCompGroupMember->Sid) {
FreeADsMem(pCompGroupMember->Sid);
}
FreeADsMem(pCompGroupMember);
}
BOOL
ComputeLocalGroupDataSize(
LPCOMPUTER_GROUP_MEMBER * ppGroupMembers,
DWORD dwReturned,
PDWORD pdwSize
)
{
DWORD i = 0;
DWORD cb = 0;
LPCOMPUTER_GROUP_MEMBER pMember = NULL;
for (i = 0; i < dwReturned; i++) {
pMember = *(ppGroupMembers + i);
cb += sizeof(COMPUTER_GROUP_MEMBER);
if (pMember->Parent) {
cb += wcslen(pMember->Parent)*sizeof(WCHAR) + sizeof(WCHAR);
}
if (pMember->Computer) {
cb += wcslen(pMember->Computer)*sizeof(WCHAR) + sizeof(WCHAR);
}
if (pMember->Domain) {
cb += wcslen(pMember->Domain)*sizeof(WCHAR) + sizeof(WCHAR);
}
if (pMember->Name) {
cb += wcslen(pMember->Name)*sizeof(WCHAR) + sizeof(WCHAR);
}
if (pMember->Sid) {
cb += GetLengthSid(pMember->Sid);
}
}
*pdwSize = cb;
return(TRUE);
}
LPBYTE
CopyIniCompGroupToCompGroup(
LPCOMPUTER_GROUP_MEMBER pIntCompGrp,
LPBYTE pExtCompGrp,
LPBYTE pEnd
)
{
LPWSTR SourceStrings[sizeof(COMPUTER_GROUP_MEMBER)/sizeof(LPWSTR)];
LPWSTR *pSourceStrings=SourceStrings;
LPCOMPUTER_GROUP_MEMBER pCompGrpMember = (LPCOMPUTER_GROUP_MEMBER)pExtCompGrp;
DWORD dwSidLength = 0;
memset(SourceStrings, 0, sizeof(COMPUTER_GROUP_MEMBER));
*pSourceStrings++ = pIntCompGrp->Parent;
*pSourceStrings++ = pIntCompGrp->Computer;
*pSourceStrings++ = pIntCompGrp->Domain;
*pSourceStrings++ = pIntCompGrp->Name;
pEnd = PackStrings(
SourceStrings,
pExtCompGrp,
ComputerGrpMemberStrings,
pEnd
);
pCompGrpMember->Type = pIntCompGrp->Type;
pCompGrpMember->ParentType = pIntCompGrp->ParentType;
if (pIntCompGrp->Sid) {
dwSidLength = GetLengthSid(pIntCompGrp->Sid);
pEnd -= dwSidLength;
memcpy(pEnd,
pIntCompGrp->Sid,
dwSidLength
);
pCompGrpMember->Sid = pEnd;
}
return pEnd;
}
BOOL
BuildLocalGroupMember(
HANDLE hGroup,
LPBYTE lpBuffer,
LPCOMPUTER_GROUP_MEMBER * ppGroupMember
)
{
LPINI_COMP_GROUP pGroup = (LPINI_COMP_GROUP)hGroup;
LPCOMPUTER_GROUP_MEMBER pGroupMember = NULL;
LPLOCALGROUP_MEMBERS_INFO_2 pGrpMem = (LPLOCALGROUP_MEMBERS_INFO_2)lpBuffer;
WCHAR szADsParent[MAX_PATH];
LPWSTR pMemberName = NULL;
LPWSTR pszSIDName = NULL;
DWORD cblen = 0, dwLen = 0, dwLenDomAndName = 0;
DWORD dwSidType = 0;
DWORD dwSidLength = 0;
BOOL fRet = FALSE;
BOOL fError = FALSE;
pGroupMember = (LPCOMPUTER_GROUP_MEMBER)AllocADsMem(
sizeof(COMPUTER_GROUP_MEMBER)
);
if (!pGroupMember) {
goto error;
}
dwSidType = pGrpMem->lgrmi2_sidusage;
pMemberName = wcschr(pGrpMem->lgrmi2_domainandname, L'\\');
cblen = wcslen(pGroup->szComputerName);
//
// Check to see if the lengthe of the domain name component in
// lgrmi2_domainandname and the comptuername are the same if not
// it cannot be a computer member object. We do this to catch the case
// where foo.foodom is computer name. foodom\user will incorrectly
// be identified as a local user rather than domain user
//
if (pMemberName) {
*pMemberName = L'\0';
dwLenDomAndName = wcslen(pGrpMem->lgrmi2_domainandname);
*pMemberName = L'\\';
}
else {
dwLenDomAndName = cblen;
}
if ((dwLenDomAndName == cblen) && !_wcsnicmp(pGroup->szComputerName, pGrpMem->lgrmi2_domainandname, cblen)) {
//
// This is the local user case
//
if (pMemberName) {
pMemberName++;
}
else {
pMemberName = pGrpMem->lgrmi2_domainandname ;
}
pGroupMember->Name = AllocADsStr(pMemberName);
pGroupMember->Computer = AllocADsStr(pGroup->szComputerName);
pGroupMember->Domain = AllocADsStr(pGroup->szDomainName);
if (pGroupMember->Domain != NULL) {
wsprintf(
szADsParent,
L"%s://%s/%s",
szProviderName,
pGroup->szDomainName,
pGroup->szComputerName
);
} else {
// Again we may have a null domain name for the case
// where there are no workstations services
wsprintf(
szADsParent,
L"%s://%s",
szProviderName,
pGroup->szComputerName
);
}
pGroupMember->Parent = AllocADsStr(szADsParent);
pGroupMember->ParentType = WINNT_COMPUTER_ID;
//
// Need to look at SID to see if this is a local group
// in which case the sid will be alias.
//
if (dwSidType == SidTypeAlias) {
pGroupMember->Type = WINNT_LOCALGROUP_ID;
}
else if (dwSidType == SidTypeUser) {
pGroupMember->Type = WINNT_USER_ID;
} else {
//
// Unknown ??
//
SetLastError(ERROR_INVALID_SID);
BAIL_ON_FAILURE(E_FAIL);
}
}else {
//
// This is the domain user, domain group case
//
pMemberName = wcschr(pGrpMem->lgrmi2_domainandname, L'\\');
if (pMemberName) {
*pMemberName = L'\0';
pMemberName++;
pGroupMember->Domain = AllocADsStr(pGrpMem->lgrmi2_domainandname);
pGroupMember->Computer = NULL;
wsprintf(
szADsParent,
L"%s://%s",
szProviderName,
pGrpMem->lgrmi2_domainandname
);
}
else {
//
// if name is well name like 'EveryOne' without the domain prefix,
// we end up with using the local computer name
//
pMemberName = pGrpMem->lgrmi2_domainandname ;
pGroupMember->Domain = NULL;
pGroupMember->Computer = AllocADsStr(L"") ;
wsprintf(
szADsParent,
L"WinNT:"
);
}
pGroupMember->Name = AllocADsStr(pMemberName);
pGroupMember->Parent = AllocADsStr(szADsParent);
switch (dwSidType) {
case SidTypeUser:
pGroupMember->Type = WINNT_USER_ID;
break;
case SidTypeGroup:
case SidTypeWellKnownGroup :
case SidTypeAlias :
pGroupMember->Type = WINNT_GROUP_ID;
break;
case SidTypeUnknown:
case SidTypeDeletedAccount:
#if !defined(WIN95)
//
// In this case we want to use the stringized SID.
// We use functions in sddl.h.
//
fRet = ConvertSidToStringSidWrapper(
pGrpMem->lgrmi2_sid,
&pszSIDName
);
if (!fRet || !pszSIDName) {
//
// Not much we can do here
//
SetLastError(ERROR_INVALID_SID);
fError = TRUE;
} else {
//
// We are always going to return just the SID.
//
if (pGroupMember->Name) {
FreeADsStr(pGroupMember->Name);
pGroupMember->Name = NULL;
}
if (pGroupMember->Parent) {
FreeADsStr(pGroupMember->Parent);
pGroupMember->Parent = NULL;
}
if (pGroupMember->Domain) {
FreeADsStr(pGroupMember->Domain);
pGroupMember->Domain = NULL;
}
//
// Got be either user so default to user.
//
pGroupMember->Type = WINNT_USER_ID;
pGroupMember->Name = AllocADsStr(pszSIDName);
pGroupMember->Parent = AllocADsStr(L"WinNT:");
if (!pGroupMember->Name || ! pGroupMember->Parent) {
//
// Not enough mem - rather than ignore like we do
// in the rest of the places in this fn, will
// set the last error and hope we recover.
//
SetLastError(ERROR_INVALID_SID);
fError = TRUE;
}
}
#else
SetLastError(ERROR_INVALID_SID);
fError = TRUE;
#endif
if (pszSIDName) {
LocalFree(pszSIDName);
}
if (fError)
goto error;
break;
default:
SetLastError(ERROR_INVALID_SID);
goto error;
break;
}
//
// Need to special case this as we cannot have a domain
// name that is NULL.
//
if (dwSidType == SidTypeDeletedAccount
|| dwSidType == SidTypeUnknown) {
pGroupMember->ParentType = WINNT_COMPUTER_ID;
}
else {
pGroupMember->ParentType = WINNT_DOMAIN_ID;
}
}
//
// Copy the SID
//
if (pGrpMem->lgrmi2_sid) {
//
// On NT4 for some reason GetLengthSID does not set lasterror to 0
//
SetLastError(NO_ERROR);
dwSidLength = GetLengthSid(pGrpMem->lgrmi2_sid);
//
// This is an extra check to make sure that we have the
// correct length.
//
if (GetLastError() != NO_ERROR) {
SetLastError(ERROR_INVALID_SID);
BAIL_ON_FAILURE(E_FAIL);
}
pGroupMember->Sid = AllocADsMem(dwSidLength);
if (!pGroupMember->Sid) {
SetLastError(ERROR_OUTOFMEMORY);
BAIL_ON_FAILURE(E_OUTOFMEMORY);
}
memcpy(pGroupMember->Sid, pGrpMem->lgrmi2_sid, dwSidLength);
}
*ppGroupMember = pGroupMember;
return(TRUE);
error:
if (pGroupMember) {
FreeIntCompGroup(pGroupMember);
}
*ppGroupMember = NULL;
return(FALSE);
}
LPBYTE
PackStrings(
LPWSTR *pSource,
LPBYTE pDest,
DWORD *DestOffsets,
LPBYTE pEnd
)
{
DWORD cbStr;
WORD_ALIGN_DOWN(pEnd);
while (*DestOffsets != -1) {
if (*pSource) {
cbStr = wcslen(*pSource)*sizeof(WCHAR) + sizeof(WCHAR);
pEnd -= cbStr;
CopyMemory( pEnd, *pSource, cbStr);
*(LPWSTR *)(pDest+*DestOffsets) = (LPWSTR)pEnd;
} else {
*(LPWSTR *)(pDest+*DestOffsets)=0;
}
pSource++;
DestOffsets++;
}
return pEnd;
}