You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
555 lines
20 KiB
555 lines
20 KiB
/*---------------------------------------------------------------------------
|
|
File: NT4Dom.cpp
|
|
|
|
Comments: Implementation of NT4 object enumeration. This object enumerates
|
|
members in USERS,GROUPS,COMPUTERS container for NT4 domain. It
|
|
returns a fixed set of columns. For more information please refer
|
|
to the code below.
|
|
|
|
(c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
|
|
Proprietary and confidential to Mission Critical Software, Inc.
|
|
|
|
REVISION LOG ENTRY
|
|
|
|
Revision By: Sham Chauthani
|
|
Revised on 07/02/99 12:40:00
|
|
---------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "TNode.hpp"
|
|
#include "NetNode.h"
|
|
#include "AttrNode.h"
|
|
#include <lm.h>
|
|
#include "NT4Dom.h"
|
|
#include "NT4Enum.h"
|
|
#include "GetDcName.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#define MAX_BUF 100
|
|
#define LEN_Path 255
|
|
CNT4Dom::CNT4Dom()
|
|
{
|
|
|
|
}
|
|
|
|
CNT4Dom::~CNT4Dom()
|
|
{
|
|
mDCMap.clear();
|
|
}
|
|
|
|
bool GetSamNameFromInfo( WCHAR * sInfo, WCHAR * sDomain, WCHAR * sName)
|
|
{
|
|
WCHAR domain[LEN_Path];
|
|
DWORD dwArraySizeOfDomain = sizeof(domain)/sizeof(domain[0]);
|
|
WCHAR * temp;
|
|
bool rc = false;
|
|
|
|
if (sInfo == NULL || wcslen(sInfo) >= dwArraySizeOfDomain)
|
|
return rc;
|
|
wcscpy(domain, sInfo);
|
|
temp = wcschr(domain, L'\\');
|
|
if ( temp )
|
|
{
|
|
*temp = 0;
|
|
if (!_wcsicmp(domain, sDomain) || !wcsncmp(sDomain, L"\\\\", 2))
|
|
{
|
|
rc = true;
|
|
wcscpy(sName, ++temp);
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GetEnumeration: This function Enumerates all objects in the above specified
|
|
// containers and their 6 standard values which are
|
|
// 'name,comment,user/groupID,flags,FullName,description'
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CNT4Dom::GetEnumeration(
|
|
BSTR sContainerName, //in -Container path
|
|
BSTR sDomainName, //in -Domain name
|
|
BSTR m_sQuery, //in -IGNORED...
|
|
long attrCnt, //in -IGNORED...
|
|
LPWSTR * sAttr, //in -IGNORED...
|
|
ADS_SEARCHPREF_INFO prefInfo, //in -IGNORED...
|
|
BOOL bMultiVal, //in -IGNORED...
|
|
IEnumVARIANT **& pVarEnum //out -Pointer to the enumeration object
|
|
)
|
|
{
|
|
// From the full LDAP path truncate to appropriate LDAP subpath
|
|
// This function enumerates four types of containers
|
|
// USERS, COMPUTERS, GROUPS, DOMAIN CONTROLLERS
|
|
// if the container parameter specifies anything other than the three containers then
|
|
// we returns UNEXPECTED.
|
|
|
|
DWORD ulCount = 0;
|
|
DWORD rc=0;
|
|
DWORD ndx = 0;
|
|
TNodeList * pNodeList = new TNodeList();
|
|
WCHAR sServerName[LEN_Path];
|
|
|
|
if (!pNodeList)
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
if ( wcsncmp((WCHAR*)sDomainName, L"\\\\", 2) )
|
|
{
|
|
_bstr_t sDC = GetDC(sDomainName);
|
|
wcscpy(sServerName, (WCHAR*)sDC);
|
|
}
|
|
else
|
|
wcscpy((WCHAR*)sServerName, (WCHAR*) sDomainName);
|
|
|
|
if ( ! rc )
|
|
{
|
|
for (UINT i = 0; i < wcslen(sContainerName); i++)
|
|
sContainerName[i] = towupper(sContainerName[i]);
|
|
|
|
if ( wcscmp(sContainerName,L"CN=USERS") &&
|
|
wcscmp(sContainerName,L"CN=COMPUTERS") &&
|
|
wcscmp(sContainerName,L"CN=GROUPS") &&
|
|
wcscmp(sContainerName,L"CN=DOMAIN CONTROLLERS") )
|
|
{
|
|
// if they selected a group we enumerate the membership of that group.
|
|
WCHAR * sTemp = wcstok( sContainerName, L",");
|
|
WCHAR * ndx = wcstok( NULL, L",");
|
|
|
|
if ((!ndx) || ( ndx && _wcsicmp(ndx, L"CN=GROUPS") ))
|
|
{
|
|
delete pNodeList;
|
|
return E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
// Get the members of the group and add them to the List,
|
|
GROUP_USERS_INFO_0 * pbufNetUser;
|
|
// DWORD resume=0, total=0;
|
|
DWORD total=0;
|
|
DWORD_PTR resume=0;
|
|
// Get the first set of Members from the Group
|
|
rc = NetGroupGetUsers((WCHAR*) sServerName, sTemp, 0, (LPBYTE*) &pbufNetUser, sizeof(GROUP_USERS_INFO_0) * MAX_BUF, &ulCount, &total, &resume);
|
|
if ((rc != ERROR_SUCCESS) && (rc != NERR_GroupNotFound) && (rc != ERROR_MORE_DATA))
|
|
{
|
|
delete pNodeList;
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
|
|
while ( ulCount > 0 )
|
|
{
|
|
// For each user construnct the array of the properties that they asked for. Then construct a node of that
|
|
// array and stuff that into the List.
|
|
for ( DWORD dwIdx = 0; dwIdx < ulCount; dwIdx++ )
|
|
{
|
|
_variant_t varArr[6] = { pbufNetUser[dwIdx].grui0_name, (long)0, (long)0, (long)0, (long)0, (long)0 } ;
|
|
TAttrNode * pNode = new TAttrNode(6, varArr);
|
|
if (!pNode)
|
|
{
|
|
delete pNodeList;
|
|
NetApiBufferFree(pbufNetUser);
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pNodeList->InsertBottom(pNode);
|
|
}
|
|
NetApiBufferFree(pbufNetUser);
|
|
// Get the next set of objects
|
|
if ( rc == ERROR_MORE_DATA )
|
|
{
|
|
rc = NetGroupGetUsers((WCHAR*) sServerName, sTemp, 0, (LPBYTE*) &pbufNetUser, sizeof(GROUP_USERS_INFO_0) * MAX_BUF, &ulCount, &total, &resume);
|
|
if ((rc != ERROR_SUCCESS) && (rc != NERR_GroupNotFound) && (rc != ERROR_MORE_DATA))
|
|
{
|
|
delete pNodeList;
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
}
|
|
else
|
|
ulCount = 0;
|
|
}
|
|
// Get the members of the local group and add them to the List,
|
|
LOCALGROUP_MEMBERS_INFO_3 * pbufNetInfo;
|
|
resume=0;
|
|
total=0;
|
|
WCHAR sTempName[LEN_Path];
|
|
WCHAR sName[LEN_Path];
|
|
// Get the first set of Members from the Group
|
|
rc = NetLocalGroupGetMembers((WCHAR*) sServerName, sTemp, 3, (LPBYTE*) &pbufNetInfo, sizeof(LOCALGROUP_MEMBERS_INFO_3) * MAX_BUF, &ulCount, &total, &resume);
|
|
if ((rc != ERROR_SUCCESS) && (rc != ERROR_NO_SUCH_ALIAS) && (rc != ERROR_MORE_DATA))
|
|
{
|
|
delete pNodeList;
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
|
|
while ( ulCount > 0 )
|
|
{
|
|
// For each user create a node set the value of the node to the object name and add it to the list.
|
|
for ( DWORD dwIdx = 0; dwIdx < ulCount; dwIdx++ )
|
|
{
|
|
wcscpy(sTempName, pbufNetInfo[dwIdx].lgrmi3_domainandname);
|
|
if (GetSamNameFromInfo(sTempName, (WCHAR*)sDomainName, sName))
|
|
{
|
|
_variant_t varArr[6] = { sName, (long)0, (long)0, (long)0, (long)0, (long)0 } ;
|
|
TAttrNode * pNode = new TAttrNode(6, varArr);
|
|
if (!pNode)
|
|
{
|
|
delete pNodeList;
|
|
NetApiBufferFree(pbufNetInfo);
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pNodeList->InsertBottom(pNode);
|
|
}
|
|
}
|
|
NetApiBufferFree(pbufNetInfo);
|
|
// Get the next set of objects
|
|
if ( rc == ERROR_MORE_DATA )
|
|
{
|
|
rc = NetLocalGroupGetMembers((WCHAR*) sServerName, sTemp, 3, (LPBYTE*) &pbufNetInfo, sizeof(LOCALGROUP_MEMBERS_INFO_3) * MAX_BUF, &ulCount, &total, &resume);
|
|
if ((rc != ERROR_SUCCESS) && (rc != ERROR_NO_SUCH_ALIAS) && (rc != ERROR_MORE_DATA))
|
|
{
|
|
delete pNodeList;
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
|
|
}
|
|
else
|
|
ulCount = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!wcscmp(sContainerName,L"CN=USERS"))
|
|
{
|
|
// Build User enumeration
|
|
NET_DISPLAY_USER * pbufNetUser;
|
|
|
|
// Get the first set of users from the domain
|
|
rc = NetQueryDisplayInformation((WCHAR *)sServerName, 1, ndx, MAX_BUF, sizeof(NET_DISPLAY_USER) * MAX_BUF, &ulCount, (void **)&pbufNetUser);
|
|
if ((rc != ERROR_SUCCESS) && (rc != ERROR_MORE_DATA))
|
|
{
|
|
delete pNodeList;
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
|
|
while ( ulCount > 0 )
|
|
{
|
|
// For each user create a node set the value of the node to the object name and add it to the list.
|
|
TAttrNode * pNode;
|
|
for ( DWORD dwIdx = 0; dwIdx < ulCount; dwIdx++ )
|
|
{
|
|
{
|
|
_variant_t val[6] = { pbufNetUser[dwIdx].usri1_name,
|
|
pbufNetUser[dwIdx].usri1_comment,
|
|
(long)0,
|
|
(long)0,
|
|
pbufNetUser[dwIdx].usri1_full_name,
|
|
L"" };
|
|
val[2].vt = VT_UI4;
|
|
val[2].ulVal = pbufNetUser[dwIdx].usri1_user_id;
|
|
|
|
val[3].vt = VT_UI4;
|
|
val[3].ulVal = pbufNetUser[dwIdx].usri1_flags;
|
|
|
|
|
|
pNode = new TAttrNode(6, val);
|
|
if (!pNode)
|
|
{
|
|
delete pNodeList;
|
|
NetApiBufferFree(pbufNetUser);
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
}
|
|
pNodeList->InsertBottom(pNode);
|
|
}
|
|
|
|
// Set the index for next set of users.
|
|
if ( ulCount > 0 )
|
|
ndx = pbufNetUser[ulCount-1].usri1_next_index;
|
|
|
|
NetApiBufferFree(pbufNetUser);
|
|
// Get the next set of objects
|
|
if ( rc == ERROR_MORE_DATA )
|
|
{
|
|
|
|
rc = NetQueryDisplayInformation((WCHAR *)sServerName, 1, ndx, MAX_BUF, sizeof(NET_DISPLAY_USER) * MAX_BUF, &ulCount, (void **)&pbufNetUser);
|
|
if ((rc != ERROR_SUCCESS) && (rc != ERROR_MORE_DATA))
|
|
{
|
|
delete pNodeList;
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
}
|
|
else
|
|
ulCount = 0;
|
|
}
|
|
}
|
|
|
|
else if (!wcscmp(sContainerName,L"CN=COMPUTERS"))
|
|
{
|
|
// Build Computers enumeration
|
|
NET_DISPLAY_MACHINE * pbufNetUser;
|
|
|
|
// Get the first set of users from the domain
|
|
rc = NetQueryDisplayInformation((WCHAR *)sServerName, 2, ndx, MAX_BUF, sizeof(NET_DISPLAY_MACHINE) * MAX_BUF, &ulCount, (void **)&pbufNetUser);
|
|
if ((rc != ERROR_SUCCESS) && (rc != ERROR_MORE_DATA))
|
|
{
|
|
delete pNodeList;
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
|
|
// Build the PDC account name.
|
|
WCHAR server[LEN_Path];
|
|
WCHAR name[LEN_Path];
|
|
BOOL bPDCFound = FALSE;
|
|
wcscpy(server, (WCHAR*)(sServerName + (2*sizeof(WCHAR))));
|
|
wsprintf(name, L"%s$", server);
|
|
|
|
while ( ulCount > 0 )
|
|
{
|
|
// For each user create a node set the value of the node to the object name and add it to the list.
|
|
TAttrNode * pNode;
|
|
for ( DWORD dwIdx = 0; dwIdx < ulCount; dwIdx++ )
|
|
{
|
|
// if we process the PDC then we need to let the function know.
|
|
if ( wcscmp(pbufNetUser[dwIdx].usri2_name, name) == 0 )
|
|
bPDCFound = TRUE;
|
|
|
|
_variant_t val[6] = { pbufNetUser[dwIdx].usri2_name,
|
|
pbufNetUser[dwIdx].usri2_comment,
|
|
(long)0,
|
|
(long)0,
|
|
(long)0,
|
|
L"" };
|
|
|
|
val[2].vt = VT_UI4;
|
|
val[2].ulVal = pbufNetUser[dwIdx].usri2_user_id;
|
|
|
|
val[3].vt = VT_UI4;
|
|
val[3].ulVal = pbufNetUser[dwIdx].usri2_flags;
|
|
|
|
pNode = new TAttrNode(6, val);
|
|
if (!pNode)
|
|
{
|
|
delete pNodeList;
|
|
NetApiBufferFree(pbufNetUser);
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pNodeList->InsertBottom(pNode);
|
|
}
|
|
|
|
// Set the index for next set of users.
|
|
if ( ulCount > 0 )
|
|
ndx = pbufNetUser[ulCount-1].usri2_next_index;
|
|
|
|
NetApiBufferFree(pbufNetUser);
|
|
// Get the next set of objects
|
|
if ( rc == ERROR_MORE_DATA )
|
|
{
|
|
rc = NetQueryDisplayInformation((WCHAR *)sServerName, 2, ndx, MAX_BUF, sizeof(NET_DISPLAY_MACHINE) * MAX_BUF, &ulCount, (void **)&pbufNetUser);
|
|
if ((rc != ERROR_SUCCESS) && (rc != ERROR_MORE_DATA))
|
|
{
|
|
delete pNodeList;
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
}
|
|
else
|
|
ulCount = 0;
|
|
}
|
|
// if pdc is already added then we dont need to do any of this.
|
|
if ( !bPDCFound )
|
|
{
|
|
// we will fake all other attributes other than the name
|
|
_variant_t val[6] = { name,
|
|
L"",
|
|
L"",
|
|
L"",
|
|
L"",
|
|
L"" };
|
|
|
|
val[2].vt = VT_UI4;
|
|
val[2].ulVal = 0;
|
|
|
|
val[3].vt = VT_UI4;
|
|
val[3].ulVal = UF_SERVER_TRUST_ACCOUNT | UF_SCRIPT;
|
|
|
|
TAttrNode * pNode = new TAttrNode(6, val);
|
|
if (!pNode)
|
|
{
|
|
delete pNodeList;
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pNodeList->InsertBottom(pNode);
|
|
}
|
|
}
|
|
|
|
else if (!wcscmp(sContainerName,L"CN=GROUPS"))
|
|
{
|
|
// Build Groups enumeration
|
|
// Build Computers enumeration
|
|
NET_DISPLAY_GROUP * pbufNetUser;
|
|
|
|
// Get the first set of users from the domain
|
|
rc = NetQueryDisplayInformation((WCHAR *)sServerName, 3, ndx, MAX_BUF, sizeof(NET_DISPLAY_GROUP) * MAX_BUF, &ulCount, (void **)&pbufNetUser);
|
|
if ((rc != ERROR_SUCCESS) && (rc != ERROR_MORE_DATA))
|
|
{
|
|
delete pNodeList;
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
|
|
while ( ulCount > 0 )
|
|
{
|
|
// For each user create a node set the value of the node to the object name and add it to the list.
|
|
TAttrNode * pNode;
|
|
for ( DWORD dwIdx = 0; dwIdx < ulCount; dwIdx++ )
|
|
{
|
|
_variant_t val[6] = { pbufNetUser[dwIdx].grpi3_name,
|
|
pbufNetUser[dwIdx].grpi3_comment,
|
|
L"",
|
|
L"",
|
|
L"",
|
|
L"" };
|
|
|
|
val[2].vt = VT_UI4;
|
|
val[2].ulVal = pbufNetUser[dwIdx].grpi3_group_id;
|
|
|
|
val[3].vt = VT_UI4;
|
|
val[3].ulVal = pbufNetUser[dwIdx].grpi3_attributes;
|
|
|
|
pNode = new TAttrNode(6, val);
|
|
if (!pNode)
|
|
{
|
|
delete pNodeList;
|
|
NetApiBufferFree(pbufNetUser);
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pNodeList->InsertBottom(pNode);
|
|
}
|
|
|
|
// Set the index for next set of users.
|
|
if ( ulCount > 0 )
|
|
ndx = pbufNetUser[ulCount-1].grpi3_next_index;
|
|
|
|
NetApiBufferFree(pbufNetUser);
|
|
// Get the next set of objects
|
|
if ( rc == ERROR_MORE_DATA )
|
|
{
|
|
rc = NetQueryDisplayInformation((WCHAR *)sServerName, 3, ndx, MAX_BUF, sizeof(NET_DISPLAY_GROUP) * MAX_BUF, &ulCount, (void **)&pbufNetUser);
|
|
if ((rc != ERROR_SUCCESS) && (rc != ERROR_MORE_DATA))
|
|
{
|
|
delete pNodeList;
|
|
return HRESULT_FROM_WIN32(rc);
|
|
}
|
|
}
|
|
else
|
|
ulCount = 0;
|
|
}
|
|
}
|
|
else if (!wcscmp(sContainerName,L"CN=DOMAIN CONTROLLERS"))
|
|
{
|
|
// Build Domain Controller enumeration
|
|
LPSERVER_INFO_101 pBuf = NULL;
|
|
DWORD dwLevel = 101;
|
|
DWORD dwSize = MAX_PREFERRED_LENGTH;
|
|
DWORD dwEntriesRead = 0L;
|
|
DWORD dwTotalEntries = 0L;
|
|
DWORD dwTotalCount = 0L;
|
|
DWORD dwServerType = SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL; // domain controllers
|
|
DWORD dwResumeHandle = 0L;
|
|
NET_API_STATUS nStatus;
|
|
DWORD dw;
|
|
|
|
//enumerate the primary and backup domain controllers
|
|
nStatus = NetServerEnum(NULL,
|
|
dwLevel,
|
|
(LPBYTE *) &pBuf,
|
|
dwSize,
|
|
&dwEntriesRead,
|
|
&dwTotalEntries,
|
|
dwServerType,
|
|
(WCHAR*) sDomainName,
|
|
&dwResumeHandle);
|
|
|
|
if (nStatus == NERR_Success)
|
|
{
|
|
if (pBuf != NULL)
|
|
{
|
|
// For each DC create a node set the value of the node to the object name and add it to the list.
|
|
for (dw = 0; dw < dwEntriesRead; dw++)
|
|
{
|
|
_variant_t varArr[6] = { pBuf[dw].sv101_name, (long)0, (long)0, (long)0, (long)0, (long)0 } ;
|
|
TAttrNode * pNode = new TAttrNode(6, varArr);
|
|
if (!pNode)
|
|
{
|
|
delete pNodeList;
|
|
NetApiBufferFree(pBuf);
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
pNodeList->InsertBottom(pNode);
|
|
}
|
|
NetApiBufferFree(pBuf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delete pNodeList;
|
|
return HRESULT_FROM_WIN32(nStatus);
|
|
}
|
|
}//end if enum DCs
|
|
|
|
// Build an enumerator and return it to the caller.
|
|
*pVarEnum = new CNT4Enum(pNodeList);
|
|
}
|
|
else
|
|
delete pNodeList;
|
|
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* *
|
|
* Written by: Paul Thompson *
|
|
* Date: 14 JUNE 2001 *
|
|
* *
|
|
* This function is responsible for getting the name of the PDC *
|
|
* for the given domain. We store the domain\PDC pairs in a map *
|
|
* class variable so that we only have to look up the PDC once per *
|
|
* instantiations of this object. *
|
|
* *
|
|
*********************************************************************/
|
|
|
|
//BEGIN GetDC
|
|
_bstr_t CNT4Dom::GetDC(_bstr_t sDomain)
|
|
{
|
|
/* local variables */
|
|
_bstr_t sDC;
|
|
CDCMap::iterator itDCMap;
|
|
|
|
/* function body */
|
|
if (!sDomain.length())
|
|
return L"";
|
|
|
|
//look if we have already cached the naming context for this domain
|
|
itDCMap = mDCMap.find(sDomain);
|
|
//if found, get the cached naming context
|
|
if (itDCMap != mDCMap.end())
|
|
{
|
|
sDC = itDCMap->second;
|
|
}
|
|
else //else, lookup the PDC from scratch and add that to the cache
|
|
{
|
|
if (GetAnyDcName5(sDomain, sDC) == ERROR_SUCCESS)
|
|
{
|
|
mDCMap.insert(CDCMap::value_type(sDomain, sDC));
|
|
}
|
|
}
|
|
|
|
return sDC;
|
|
}
|
|
//END GetDC
|