windows-nt/Source/XPSP1/NT/admin/dscmd/dsquery/dsquery.cpp
2020-09-26 16:20:57 +08:00

1284 lines
38 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000
//
// File: dsquery.cpp
//
// Contents: Defines the main function DSQUERY
// command line utility
//
// History: 06-Sep-2000 hiteshr Created
//
//
//--------------------------------------------------------------------------
#include "pch.h"
#include "cstrings.h"
#include "usage.h"
#include "querytable.h"
#include "querybld.h"
#include "dsquery.h"
#include "query.h"
#include "resource.h"
#include "output.h"
#include <dscmn.h>
//
//Structure Defined to Store Global Values at one place.
//
typedef struct _GlobalInfo
{
ADS_SCOPEENUM scope; //Scope of query
DSQUERY_OUTPUT_FORMAT outputFormat; //Output Format
}GLOBAL_INFO,*PGLOBAL_INFO;
bool g_bQuiet = false;
int g_iQueryLimit = 100;
bool g_bDeafultLimit = true;
//
// Forward Function Declarations
//
HRESULT DoQueryValidation(PARG_RECORD pCommandArgs,
PDSQueryObjectTableEntry pObjectEntry,
PGLOBAL_INFO pcommon_info);
HRESULT DoQuery(PARG_RECORD pCommandArgs,
PDSQueryObjectTableEntry pObjectEntry,
PGLOBAL_INFO pcommon_info);
HRESULT GetAttributesToFetch(IN PGLOBAL_INFO pcommon_info,
IN PARG_RECORD pCommandArgs,
IN PDSQueryObjectTableEntry pObjectEntry,
OUT LPWSTR **ppszAttributes,
OUT DWORD * pCount);
VOID FreeAttributesToFetch( IN LPWSTR *ppszAttributes,
IN DWORD dwCount);
HRESULT GetSearchRoot(IN IN PDSQueryObjectTableEntry pObjectEntry,
IN PARG_RECORD pCommandArgs,
IN CDSCmdBasePathsInfo& refBasePathsInfo,
OUT CComBSTR& refsbstrDN,
OUT BOOL *pbSearchAtForestRoot,
OUT BOOL *pbSearchAtGC);
HRESULT GetSearchObject(IN IN PDSQueryObjectTableEntry pObjectEntry,
IN CDSCmdBasePathsInfo& refBasePathsInfo,
IN PARG_RECORD pCommandArgs,
IN CDSCmdCredentialObject& refCredentialObject,
IN CComBSTR& refsbstrDN,
IN BOOL bSearchAtForestRoot,
IN BOOL bSearchAtGC,
OUT CComPtr<IDirectorySearch>& refspSearchObject);
//
//Main Function
//
int __cdecl _tmain( VOID )
{
int argc = 0;
LPTOKEN pToken = NULL;
HRESULT hr = S_OK;
PARG_RECORD pNewCommandArgs = 0;
//
// False loop
//
do
{
//
// Initialize COM
//
hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
break;
}
//Get CommandLine Input
hr = HRESULT_FROM_WIN32(GetCommandInput(&argc,&pToken));
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
break;
}
if(argc == 1)
{
//
// Display the error message and then break out of the false loop
//
DisplayMessage(USAGE_DSQUERY);
hr = E_INVALIDARG;
break;
}
//
// Find which object table entry to use from
// the second command line argument
//
PDSQueryObjectTableEntry pObjectEntry = NULL;
UINT idx = 0;
PWSTR pszObjectType = (pToken+1)->GetToken();
while (true)
{
pObjectEntry = g_DSObjectTable[idx++];
if (!pObjectEntry)
{
break;
}
if (0 == _wcsicmp(pObjectEntry->pszCommandLineObjectType, pszObjectType))
{
break;
}
}
if (!pObjectEntry)
{
hr = E_INVALIDARG;
if(argc == 2)
{
if(pToken[1].IsSwitch())
{
if(!wcscmp(pToken[1].GetToken(),L"/?") ||
!wcscmp(pToken[1].GetToken(),L"/h") ||
!wcscmp(pToken[1].GetToken(),L"-?") ||
!wcscmp(pToken[1].GetToken(),L"-h"))
hr = S_OK;
}
}
//
// Display the error message and then break out of the false loop
//
DisplayMessage(USAGE_DSQUERY);
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
}
break;
}
//
// Now that we have the correct table entry, merge the command line table
// for this object with the common commands
//
hr = MergeArgCommand(DSQUERY_COMMON_COMMANDS,
pObjectEntry->pParserTable,
&pNewCommandArgs);
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
break;
}
//
//Parse the Input
//
PARSE_ERROR Error;
if(!ParseCmd(pNewCommandArgs,
argc-1,
pToken+1,
pObjectEntry->nUsageID,
&Error,
TRUE))
{
if(Error.ErrorSource == ERROR_FROM_PARSER
&& Error.Error == PARSE_ERROR_HELP_SWITCH)
{
hr = S_OK;
break;
}
hr = E_INVALIDARG;
DisplayMessage(pObjectEntry->nUsageID);
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
break;
}
//
// Check to see if we are doing debug spew
//
#ifdef DBG
bool bDebugging = pNewCommandArgs[eCommDebug].bDefined &&
pNewCommandArgs[eCommDebug].nValue;
if (bDebugging)
{
ENABLE_DEBUG_OUTPUT(pNewCommandArgs[eCommDebug].nValue);
}
#else
DISABLE_DEBUG_OUTPUT();
#endif
//
// Set the global quiet flag
//
g_bQuiet = pNewCommandArgs[eCommQuiet].bDefined &&
pNewCommandArgs[eCommQuiet].bValue;
//
//
//
if(pNewCommandArgs[eCommLimit].bDefined)
{
g_iQueryLimit = pNewCommandArgs[eCommLimit].nValue;
g_bDeafultLimit = false;
}
GLOBAL_INFO common_info;
common_info.scope = ADS_SCOPE_SUBTREE;
common_info.outputFormat = DSQUERY_OUTPUT_DN;
//
// Do extra validation like switch dependency check etc.
// Also collect Query Scope and Output format
//
hr = DoQueryValidation(pNewCommandArgs,
pObjectEntry,
&common_info);
if (FAILED(hr))
break;
//
// Command line parsing succeeded
//
hr = DoQuery(pNewCommandArgs,
pObjectEntry,
&common_info);
if(FAILED(hr))
break;
} while (false); //False Loop
//
//Do the CleanUp
//
//
// Free the memory associated with the command values
//
if(pNewCommandArgs)
FreeCmd(pNewCommandArgs);
//
// Free the tokens
//
if (pToken)
{
delete[] pToken;
pToken = 0;
}
//
// Uninitialize COM
//
CoUninitialize();
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: DoQueryValidation
//
// Synopsis: Checks to be sure that command line switches that are mutually
// exclusive are not both present and those that are dependent are
// both presetn, and other validations which cannot be done by parser.
//
// Arguments: [pCommandArgs - IN] : the command line argument structure used
// to retrieve the values for each switch
// [pObjectEntry - IN] : pointer to the object table entry for the
// object type that will be queryied
// [pcommon_info - OUT]: gets scope and output format info
//
// Returns: HRESULT : S_OK if everything succeeded
// E_INVALIDARG if the object entry wasn't found
//
// History: 25-Sep-2000 hiteshr Created
//
//---------------------------------------------------------------------------
HRESULT DoQueryValidation(IN PARG_RECORD pCommandArgs,
IN PDSQueryObjectTableEntry pObjectEntry,
OUT PGLOBAL_INFO pcommon_info)
{
ENTER_FUNCTION_HR(MINIMAL_LOGGING, DoQueryValidation, hr);
if (!pCommandArgs || !pObjectEntry || !pcommon_info)
{
ASSERT(pCommandArgs);
ASSERT(pObjectEntry);
ASSERT(pcommon_info);
hr = E_INVALIDARG;
return hr;
}
//
//Validate OutputFormat for "dsquery objectType"
//
if(_wcsicmp(pObjectEntry->pszCommandLineObjectType,g_pszStar))
{
DEBUG_OUTPUT(MINIMAL_LOGGING, L"dsquery <objectType> processing will be performed");
if(pCommandArgs[eCommOutputFormat].bDefined &&
pCommandArgs[eCommOutputFormat].strValue)
{
//
//ppValidOutput contains the validoutput type for a
//given object type
//
ASSERT(pObjectEntry->ppValidOutput);
BOOL bMatch = FALSE;
for(UINT i = 0; i < pObjectEntry->dwOutputCount; ++i)
{
if(_wcsicmp(pCommandArgs[eCommOutputFormat].strValue,
pObjectEntry->ppValidOutput[i]->pszOutputFormat) == 0 )
{
bMatch = TRUE;
pcommon_info->outputFormat = pObjectEntry->ppValidOutput[i]->outputFormat;
break;
}
}
if(!bMatch)
{
DisplayMessage(pObjectEntry->nUsageID);
hr = E_INVALIDARG;
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
}
//
//default output format is DN
//
else
pcommon_info->outputFormat = DSQUERY_OUTPUT_DN;
}
else
{
//
//-o is invalid switch form dsquery *, but since its
//common for all other objects its kept in common table
//and we do the special casing for dsquery *
//
if(pCommandArgs[eCommOutputFormat].bDefined &&
pCommandArgs[eCommOutputFormat].strValue)
{
DisplayMessage(pObjectEntry->nUsageID);
hr = E_INVALIDARG;
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
DEBUG_OUTPUT(MINIMAL_LOGGING, L"dsquery * processing will be performed");
if(pCommandArgs[eStarAttrsOnly].bDefined)
pcommon_info->outputFormat = DSQUERY_OUTPUT_ATTRONLY;
else
pcommon_info->outputFormat = DSQUERY_OUTPUT_ATTR;
}
//
//Validate Scope string.
//default scope is subtree.
//
pcommon_info->scope = ADS_SCOPE_SUBTREE;
if(pObjectEntry->nScopeID != -1)
{
if( pCommandArgs[pObjectEntry->nScopeID].bDefined &&
pCommandArgs[pObjectEntry->nScopeID].strValue )
{
LPCWSTR pszScope = pCommandArgs[pObjectEntry->nScopeID].strValue;
if( _wcsicmp(pszScope,g_pszSubTree) == 0 )
{
DEBUG_OUTPUT(MINIMAL_LOGGING, L"scope = subtree");
pcommon_info->scope = ADS_SCOPE_SUBTREE;
}
else if( _wcsicmp(pszScope,g_pszOneLevel) == 0 )
{
DEBUG_OUTPUT(MINIMAL_LOGGING, L"scope = onelevel");
pcommon_info->scope = ADS_SCOPE_ONELEVEL;
}
else if( _wcsicmp(pszScope,g_pszBase) == 0 )
{
DEBUG_OUTPUT(MINIMAL_LOGGING, L"scope = base");
pcommon_info->scope = ADS_SCOPE_BASE;
}
else
{
DEBUG_OUTPUT(MINIMAL_LOGGING, L"Unknown scope = %s", pszScope);
DisplayMessage(pObjectEntry->nUsageID);
hr = E_INVALIDARG;
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
}
}
//
//Limit must be 0 or greater
//
if(pCommandArgs[eCommLimit].bDefined)
{
if(pCommandArgs[eCommLimit].nValue < 0)
{
DisplayMessage(pObjectEntry->nUsageID);
hr = E_INVALIDARG;
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
}
//
//Forestwide Search implies the -GC switch so define it if it isn't already
//
if(pCommandArgs[eCommStartNode].bDefined &&
pCommandArgs[eCommStartNode].strValue )
{
if(_wcsicmp(pCommandArgs[eCommStartNode].strValue,g_pszForestRoot) == 0)
{
if(!(pCommandArgs[eCommGC].bDefined &&
pCommandArgs[eCommGC].bValue))
{
pCommandArgs[eCommGC].bDefined = TRUE;
pCommandArgs[eCommGC].bValue = TRUE;
}
}
}
//
//For dsquery server, if none of the -domain, -forest, -site is
//specified, then define -domain as its default
//
if(!_wcsicmp(pObjectEntry->pszCommandLineObjectType,g_pszServer))
{
//
//Value is assigned in DoQuery function
//
if(!pCommandArgs[eServerDomain].bDefined &&
!pCommandArgs[eServerForest].bDefined &&
!pCommandArgs[eServerSite].bDefined)
{
pCommandArgs[eServerDomain].bDefined = TRUE;
}
}
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: DoQuery
//
// Synopsis: Does the query
// Arguments: [pCommandArgs - IN] : the command line argument structure used
// to retrieve the values for each switch
// [pObjectEntry - IN] : pointer to the object table entry for the
// object type that will be modified
// [pcommon_info - IN] : scope and outputformat info
//
// Returns: HRESULT : S_OK if everything succeeded
// E_INVALIDARG if the object entry wasn't found
// Anything else is a failure code from an ADSI call
//
// History: 25-Sep-2000 hiteshr Created
//
//---------------------------------------------------------------------------
HRESULT DoQuery(PARG_RECORD pCommandArgs,
PDSQueryObjectTableEntry pObjectEntry,
PGLOBAL_INFO pcommon_info)
{
ENTER_FUNCTION_HR(MINIMAL_LOGGING, DoQuery, hr);
if (!pCommandArgs || !pObjectEntry || !pcommon_info)
{
ASSERT(pCommandArgs);
ASSERT(pObjectEntry);
ASSERT(pcommon_info);
hr = E_INVALIDARG;
return hr;
}
CDSCmdCredentialObject credentialObject;
if (pCommandArgs[eCommUserName].bDefined)
{
credentialObject.SetUsername(pCommandArgs[eCommUserName].strValue);
credentialObject.SetUsingCredentials(true);
}
if (pCommandArgs[eCommPassword].bDefined)
{
credentialObject.SetPassword(pCommandArgs[eCommPassword].strValue);
credentialObject.SetUsingCredentials(true);
}
//
// Initialize the base paths info from the command line args
//
CDSCmdBasePathsInfo basePathsInfo;
if (pCommandArgs[eCommServer].bDefined)
{
hr = basePathsInfo.InitializeFromName(credentialObject,
pCommandArgs[eCommServer].strValue,
true);
}
else if (pCommandArgs[eCommDomain].bDefined)
{
hr = basePathsInfo.InitializeFromName(credentialObject,
pCommandArgs[eCommDomain].strValue,
false);
}
else
{
hr = basePathsInfo.InitializeFromName(credentialObject, NULL, false);
}
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
//
//Check if to search GC and get the search root path
//
BOOL bSearchAtGC = FALSE;
BOOL bSearchAtForestRoot = FALSE;
CComBSTR sbstrObjectDN;
hr = GetSearchRoot(pObjectEntry,
pCommandArgs,
basePathsInfo,
sbstrObjectDN,
&bSearchAtForestRoot,
&bSearchAtGC);
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
DEBUG_OUTPUT(MINIMAL_LOGGING, L"start node = %s", sbstrObjectDN);
//
//Build The Filter For Query
//
PVOID pParam = NULL;
if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszSubnet) == 0)
{
CComBSTR strSubSiteSuffix;
GetSiteContainerPath(basePathsInfo, strSubSiteSuffix);
pParam = (PVOID)&strSubSiteSuffix;
}
CComBSTR strLDAPFilter;
hr = BuildQueryFilter(pCommandArgs,
pObjectEntry,
pParam,
strLDAPFilter);
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
//
//Create The IDirectorySearchObject
//
CComPtr<IDirectorySearch> spSearchObject;
hr = GetSearchObject(pObjectEntry,
basePathsInfo,
pCommandArgs,
credentialObject,
sbstrObjectDN,
bSearchAtForestRoot,
bSearchAtGC,
spSearchObject);
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
//
//Get the arributes to fetch
//
LPWSTR *ppszAttributes = NULL;
DWORD dwCountAttr = 0;
hr = GetAttributesToFetch(pcommon_info,
pCommandArgs,
pObjectEntry,
&ppszAttributes,
&dwCountAttr);
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
//
//Lets Query Now
//
CDSSearch searchObject;
hr = searchObject.Init(spSearchObject);
if (FAILED(hr))
{
DEBUG_OUTPUT(MINIMAL_LOGGING,
L"Initializing search object failed: hr = 0x%x",
hr);
FreeAttributesToFetch(ppszAttributes, dwCountAttr);
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
searchObject.SetFilterString(strLDAPFilter);
searchObject.SetSearchScope(pcommon_info->scope);
searchObject.SetAttributeList(ppszAttributes,dwCountAttr?dwCountAttr:-1);
hr = searchObject.DoQuery();
if(FAILED(hr))
{
DEBUG_OUTPUT(MINIMAL_LOGGING, L"DoQuery failed hr = 0x%x", hr);
FreeAttributesToFetch(ppszAttributes,dwCountAttr);
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
//
//Find out the display format for dsquery *
//It can be either List or Table
//
BOOL bListFormat = TRUE;
if(pcommon_info->outputFormat == DSQUERY_OUTPUT_ATTR)
{
//
//If all attributes are to be displayed, only List Format is valid
//If attributes to fetch are specified at commandline, Table is default format.
if(dwCountAttr &&
!pCommandArgs[eStarList].bDefined)
bListFormat = FALSE;
}
bool bUseStandardOutput = true;
if (pCommandArgs[eCommObjectType].bDefined &&
_wcsicmp(pCommandArgs[eCommObjectType].strValue, g_pszServer) == 0)
{
//
// "dsquery server" requires additional processing if either the
// -isgc or the -hasfsmo switch is specified
//
if ((pCommandArgs[eServerIsGC].bDefined && pCommandArgs[eServerIsGC].bValue) ||
(pCommandArgs[eServerHasFSMO].bDefined && pCommandArgs[eServerHasFSMO].strValue)||
(pCommandArgs[eServerDomain].bDefined && pCommandArgs[eServerDomain].strValue))
{
bUseStandardOutput = false;
hr = DsQueryServerOutput(pcommon_info->outputFormat,
ppszAttributes,
dwCountAttr,
searchObject,
credentialObject,
basePathsInfo,
pCommandArgs);
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
}
}
}
if (bUseStandardOutput)
{
//
//Output the result of search
//
hr = DsQueryOutput(pcommon_info->outputFormat,
ppszAttributes,
dwCountAttr,
&searchObject,
bListFormat);
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
}
}
FreeAttributesToFetch(ppszAttributes,dwCountAttr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: GetAttributesToFetch
//
// Synopsis: Make an array of attributes to fetch.
// Arguments: [pcommon_info - IN] : outputformat and scope info
// [ppszAttributes - OUT] : array of attributes to fetch
// [pCount - OUT] : count of attributes in array
//
// Returns: HRESULT : S_OK if everything succeeded
// E_INVALIDARG if the object entry wasn't found
// Anything else is a failure code from an ADSI call
//
// History: 25-Sep-2000 hiteshr Created
//
//---------------------------------------------------------------------------
HRESULT GetAttributesToFetch(IN PGLOBAL_INFO pcommon_info,
IN PARG_RECORD pCommandArgs,
IN PDSQueryObjectTableEntry pObjectEntry,
OUT LPWSTR **ppszAttributes,
OUT DWORD * pCount)
{
ENTER_FUNCTION_HR(MINIMAL_LOGGING, GetAttributesToFetch, hr);
if(!pcommon_info || !pCommandArgs || !pObjectEntry)
{
ASSERT(pcommon_info);
ASSERT(pCommandArgs);
ASSERT(pObjectEntry);
hr = E_INVALIDARG;
return hr;
}
if(pcommon_info->outputFormat == DSQUERY_OUTPUT_ATTR ||
pcommon_info->outputFormat == DSQUERY_OUTPUT_ATTRONLY)
{
if(pCommandArgs[eStarAttr].bDefined)
{
//
//If input is "*", fetch all attributes
//
if(wcscmp(pCommandArgs[eStarAttr].strValue,L"*") == 0 )
{
*ppszAttributes = NULL;
*pCount = 0;
return hr;
}
LPWSTR *ppszTemp = NULL;
UINT argc = 0;
ParseNullSeparatedString(pCommandArgs[eStarAttr].strValue,
&ppszTemp,
&argc);
LPWSTR *ppszAttr = (LPWSTR *)LocalAlloc(LPTR,argc*sizeof(LPCTSTR));
if(!ppszAttr)
{
hr = E_OUTOFMEMORY;
return hr;
}
for(UINT i = 0; i < argc; ++i)
{
if(FAILED(LocalCopyString(ppszAttr+i, ppszTemp[i])))
{
LocalFree(ppszAttr);
hr = E_OUTOFMEMORY;
return hr;
}
}
*ppszAttributes = ppszAttr;
*pCount = argc;
if(ppszTemp)
LocalFree(ppszTemp);
hr = S_OK;
return hr;
}
}
LPCWSTR pszAttr = NULL;
if(pcommon_info->outputFormat == DSQUERY_OUTPUT_ATTR)
{
//
//If eStarAttr is not defined, Fetch only DN
pcommon_info->outputFormat = DSQUERY_OUTPUT_DN;
pszAttr = g_szAttrDistinguishedName;
}
else if(pcommon_info->outputFormat == DSQUERY_OUTPUT_ATTRONLY)
pszAttr = g_szAttrDistinguishedName;
else if(pcommon_info->outputFormat == DSQUERY_OUTPUT_DN)
pszAttr = g_szAttrDistinguishedName;
else if(pcommon_info->outputFormat == DSQUERY_OUTPUT_UPN)
pszAttr = g_szAttrUserPrincipalName;
else if(pcommon_info->outputFormat == DSQUERY_OUTPUT_SAMID)
pszAttr = g_szAttrSamAccountName;
else if(pcommon_info->outputFormat == DSQUERY_OUTPUT_RDN)
pszAttr = g_szAttrRDN;
//
// Always include the DN in the search results as well. It is quite useful.
//
size_t entries = 2;
if (pCommandArgs[eServerDomain].bDefined &&
pCommandArgs[eServerDomain].strValue)
{
//
// If the scope is DOMAIN then add an addition space for the serverReference
++entries;
}
LPWSTR *ppszAttr = (LPWSTR *)LocalAlloc(LPTR,sizeof(LPWSTR) * entries);
if(!ppszAttr)
{
hr = E_OUTOFMEMORY;
return hr;
}
ZeroMemory(ppszAttr, sizeof(LPWSTR) * entries);
if(FAILED(LocalCopyString(ppszAttr,pszAttr)))
{
LocalFree(ppszAttr);
hr = E_OUTOFMEMORY;
return hr;
}
//
// Always include the DN in the search results as well. It is quite useful.
//
if (FAILED(LocalCopyString(&(ppszAttr[1]), g_szAttrDistinguishedName)))
{
LocalFree(ppszAttr);
hr = E_OUTOFMEMORY;
return hr;
}
if (pCommandArgs[eServerDomain].bDefined &&
pCommandArgs[eServerDomain].strValue)
{
ASSERT(entries >= 3);
if (FAILED(LocalCopyString(&(ppszAttr[2]), g_szAttrServerReference)))
{
LocalFree(ppszAttr);
hr = E_OUTOFMEMORY;
return hr;
}
}
*ppszAttributes = ppszAttr;
*pCount = static_cast<DWORD>(entries);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: FreeAttributesToFetch
//
// Synopsis: Function to free memory allocated by GetAttributesToFetch
// Arguments: [dwszAttributes - in] : array of attributes to fetch
// [dwCount - in] : count of attributes in array
//
// Returns: HRESULT : S_OK if everything succeeded
// E_INVALIDARG if the object entry wasn't found
// Anything else is a failure code from an ADSI call
//
// History: 25-Sep-2000 hiteshr Created
//
//---------------------------------------------------------------------------
VOID FreeAttributesToFetch( IN LPWSTR *ppszAttributes,
IN DWORD dwCount)
{
while(dwCount)
{
LocalFree(ppszAttributes[--dwCount]);
}
LocalFree(ppszAttributes);
}
//+--------------------------------------------------------------------------
//
// Function: GetSearchRoot
//
// Synopsis: Builds the path to the root of the search as determined by
// the parameters passed in from the command line.
//
// Arguments: [pObjectEntry - IN] : pointer to the object table entry for the
// object type that will be modified
// [pCommandArgs IN] : the table of the command line input
// [refBasePathsInfo IN] : reference to the base paths info
// [refsbstrDN OUT] : reference to a CComBSTR that will
// receive the DN at which to start
// the search
// [pbSearchAtForestRoot] :Set to true is startnode is equal to
// forestroot
//
// Returns: HRESULT
//
// History: 24-April-2001 hiteshr Created
//
//---------------------------------------------------------------------------
HRESULT GetSearchRoot(IN IN PDSQueryObjectTableEntry pObjectEntry,
IN PARG_RECORD pCommandArgs,
IN CDSCmdBasePathsInfo& refBasePathsInfo,
OUT CComBSTR& refsbstrDN,
OUT BOOL *pbSearchAtForestRoot,
OUT BOOL *pbSearchAtGC)
{
if(!pCommandArgs ||
!pObjectEntry ||
!pbSearchAtForestRoot ||
!pbSearchAtGC)
{
return E_POINTER;
}
PWSTR pszInputDN = NULL;
if(pCommandArgs[eCommGC].bDefined &&
pCommandArgs[eCommGC].bValue)
{
DEBUG_OUTPUT(LEVEL5_LOGGING, L"Searching the GC");
*pbSearchAtGC = TRUE;
}
//
//Get the starting node
//
if(pCommandArgs[eCommStartNode].bDefined &&
pCommandArgs[eCommStartNode].strValue )
{
pszInputDN = pCommandArgs[eCommStartNode].strValue;
if(_wcsicmp(pszInputDN,g_pszDomainRoot) == 0)
{
refsbstrDN = refBasePathsInfo.GetDefaultNamingContext();
}
else if(_wcsicmp(pszInputDN,g_pszForestRoot) == 0)
{
*pbSearchAtForestRoot = TRUE;
}
else
{
//
//DN is entered
//
refsbstrDN = pszInputDN;
}
}
else
{
if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszServer) == 0)
{
if (pCommandArgs[eServerDomain].bDefined &&
!pCommandArgs[eServerDomain].strValue)
{
PWSTR pszName = 0;
PWSTR pszDomainName = refBasePathsInfo.GetDefaultNamingContext();
HRESULT hr = CrackName(pszDomainName,
&pszName,
GET_DNS_DOMAIN_NAME,
NULL);
if (FAILED(hr))
{
DEBUG_OUTPUT(LEVEL3_LOGGING,
L"Failed to crack the DN into a domain name: hr = 0x%x",
hr);
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
pCommandArgs[eServerDomain].strValue = pszName;
}
//
// Get the base path that corresponds with the scope
//
GetServerSearchRoot(pCommandArgs,
refBasePathsInfo,
refsbstrDN);
}
else if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszSite) == 0)
{
//
// Scope is the configuration container
//
refsbstrDN = refBasePathsInfo.GetConfigurationNamingContext();
}
else if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszSubnet) == 0)
{
//
// Get the base path that corresponds with the scope
//
GetSubnetSearchRoot(refBasePathsInfo,
refsbstrDN);
}
else
{
//
//default is Domain DN
//
refsbstrDN = refBasePathsInfo.GetDefaultNamingContext();
}
}
return S_OK;
}
HRESULT GetSearchObject(IN IN PDSQueryObjectTableEntry pObjectEntry,
IN CDSCmdBasePathsInfo& refBasePathsInfo,
IN PARG_RECORD pCommandArgs,
IN CDSCmdCredentialObject& refCredentialObject,
IN CComBSTR& refsbstrDN,
IN BOOL bSearchAtForestRoot,
IN BOOL bSearchAtGC,
OUT CComPtr<IDirectorySearch>& refspSearchObject)
{
HRESULT hr = S_OK;
if(!pObjectEntry || !pCommandArgs)
return E_POINTER;
if(!bSearchAtForestRoot)
{
CComBSTR sbstrObjectPath;
bool bBindToServer = true;
if(bSearchAtGC)
{
//
//Change the provider in sbstrObjectPath from LDAP to GC
//
CComPtr<IADsPathname> spPathNameObject;
hr = CoCreateInstance(CLSID_Pathname,
NULL,
CLSCTX_INPROC_SERVER,
IID_IADsPathname,
(LPVOID*)&spPathNameObject);
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
//Set Provider to GC
hr = spPathNameObject->Set(L"GC", ADS_SETTYPE_PROVIDER);
ASSERT(SUCCEEDED(hr));
//Set the DN
hr = spPathNameObject->Set(refsbstrDN, ADS_SETTYPE_DN);
ASSERT(SUCCEEDED(hr));
hr = spPathNameObject->Retrieve(ADS_FORMAT_X500_NO_SERVER, &sbstrObjectPath);
ASSERT(SUCCEEDED(hr));
//
//No server name in path
//
bBindToServer = false;
}
else
{
//
// Convert the DN to an ADSI path
//
refBasePathsInfo.ComposePathFromDN(refsbstrDN, sbstrObjectPath);
if((_wcsicmp(pObjectEntry->pszObjectClass, g_pszUser) == 0 &&
pCommandArgs[eUserInactive].bDefined) ||
(_wcsicmp(pObjectEntry->pszObjectClass, g_pszComputer) == 0 &&
pCommandArgs[eComputerInactive].bDefined))
{
INT nDomainBehaviorVersion = 0;
CComPtr<IADs> spDomain;
CComBSTR sbstrBasePath;
refBasePathsInfo.ComposePathFromDN(refBasePathsInfo.GetDefaultNamingContext(),
sbstrBasePath);
hr = DSCmdOpenObject(refCredentialObject,
sbstrBasePath,
IID_IADs,
(void**)&spDomain,
bBindToServer);
if (FAILED(hr))
{
nDomainBehaviorVersion = 0;
}
CComVariant varVer;
hr = spDomain->GetInfo();
if(SUCCEEDED(hr))
{
CComBSTR bstrVer = L"msDS-Behavior-Version";
hr = spDomain->Get(bstrVer, &varVer);
}
if (FAILED(hr))
{
nDomainBehaviorVersion = 0;
}
else
{
ASSERT(varVer.vt == VT_I4);
nDomainBehaviorVersion = static_cast<UINT>(varVer.lVal);
}
if(nDomainBehaviorVersion == 0)
{
DisplayMessage(pObjectEntry->nUsageID);
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr,
IDS_FILTER_LAST_LOGON_VERSION);
hr = E_INVALIDARG;
return hr;
}
}
}
hr = DSCmdOpenObject(refCredentialObject,
sbstrObjectPath,
IID_IDirectorySearch,
(void**)&refspSearchObject,
bBindToServer);
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
}
else
{
//
//BIND to GC to search entire forest
//
CComPtr<IADsContainer> spContainer;
hr = DSCmdOpenObject(refCredentialObject,
L"GC:",
IID_IADsContainer,
(void**)&spContainer,
false);
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
//
// Get an enumeration interface for the GC container to enumerate the
// contents. The "real" GC is the only child of the GC container.
//
CComPtr<IEnumVARIANT> spEnum = NULL;
hr = ADsBuildEnumerator(spContainer, &spEnum);
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
//
// Now enumerate. There's only one child of the GC: object.
//
VARIANT var;
ULONG lFetch;
hr = spEnum->Next(1, &var, &lFetch);
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
// Get the IDirectorySearch pointer.
if (lFetch == 1)
{
CComPtr<IDispatch> spDisp = V_DISPATCH(&var);
hr = spDisp->QueryInterface( IID_IDirectorySearch, (void**)&refspSearchObject);
if (FAILED(hr))
{
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return hr;
}
}
else
{
//
//Need to put a better message here
//
DisplayErrorMessage(g_pszDSCommandName,
NULL,
hr);
return E_FAIL;
}
}
return hr;
}