|
|
//+-------------------------------------------------------------------------
//
// 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>
#include "Ntdsapi.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; DSQUERY_COMMAND_ENUM g_eGC = (DSQUERY_COMMAND_ENUM)-1;
//
// 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);
BOOL TranslateNameFromDnToDns(const CComBSTR& bstrInputDN, CComBSTR& bstrOutputDNS);
HRESULT GetGCIndex(PDSQueryObjectTableEntry pObjectEntry, int& nCommandEnum);
//
//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
DWORD dwErr = GetCommandInput(&argc,&pToken); hr = HRESULT_FROM_WIN32(dwErr); 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,TRUE); hr = E_INVALIDARG; break; }
if(argc == 2) { if(IsTokenHelpSwitch(pToken + 1)) { hr = S_OK; DisplayMessage(USAGE_DSQUERY,TRUE); 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; } //Security Review:Both strings are null terminated.
if (0 == _wcsicmp(pObjectEntry->pszCommandLineObjectType, pszObjectType)) { break; } }
if (!pObjectEntry) { //
// Display the error message and then break out of the false loop
//
hr = E_INVALIDARG; if (FAILED(hr)) { DisplayErrorMessage(g_pszDSCommandName, NULL, hr, IDS_INVALID_OBJECTTYPE);
} 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(g_pszDSCommandName, pNewCommandArgs, argc-1, pToken+1, pObjectEntry->pUsageTable, &Error, TRUE)) { //ParseCmd did not display any error. Error should
//be handled here. Check DisplayParseError for the
//cases where Error is not shown by ParseCmd
if(!Error.MessageShown) { hr = E_INVALIDARG; DisplayErrorMessage(g_pszDSCommandName, NULL, hr);
break; } if(Error.ErrorSource == ERROR_FROM_PARSER && Error.Error == PARSE_ERROR_HELP_SWITCH) { hr = S_OK; break; }
hr = E_INVALIDARG; 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
// Get the GC switch (if supported)
int nCommandEnum = -1; if (FAILED(GetGCIndex(pObjectEntry, nCommandEnum))) { // An object type is missing in GetGCIndex
if(!Error.MessageShown) { hr = E_INVALIDARG; DisplayErrorMessage(g_pszDSCommandName, NULL, hr);
break; } } g_eGC = (DSQUERY_COMMAND_ENUM) nCommandEnum;
//
// 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; }
// Check to be sure the server and domain switches
// are mutually exclusive
if (pCommandArgs[eCommServer].bDefined && pCommandArgs[eCommDomain].bDefined) { hr = E_INVALIDARG; DisplayErrorMessage(g_pszDSCommandName, NULL, hr);
return hr; }
//
//Validate OutputFormat for "dsquery objectType"
//
//Security Review:Both strings are null terminated.
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) { //Security Review:Both strings are null terminated.
if(_wcsicmp(pCommandArgs[eCommOutputFormat].strValue, pObjectEntry->ppValidOutput[i]->pszOutputFormat) == 0 ) { bMatch = TRUE; pcommon_info->outputFormat = pObjectEntry->ppValidOutput[i]->outputFormat; break; } } if(!bMatch) { hr = E_INVALIDARG; DisplayErrorMessage(g_pszDSCommandName, NULL, hr, IDS_INVALID_OUTPUT);
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) { hr = E_INVALIDARG; DisplayErrorMessage(g_pszDSCommandName, NULL, hr, IDS_O_NOT_FOR_STAR); 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; //Security Review:Both strings are null terminated.
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); hr = E_INVALIDARG; DisplayErrorMessage(g_pszDSCommandName, NULL, hr, IDS_ERROR_SCOPE);
return hr; } } }
//
//if startnode is forestroot, only valid scope is ADS_SCOPE_SUBTREE
//NTRAID#NTBUG9-382511-2001/05/14-hiteshr
//
if(pCommandArgs[eCommStartNode].bDefined && pCommandArgs[eCommStartNode].strValue) { //Security Review:Both strings are null terminated.
if((_wcsicmp(pCommandArgs[eCommStartNode].strValue, g_pszForestRoot) == 0 ) && (pcommon_info->scope != ADS_SCOPE_SUBTREE)) { DEBUG_OUTPUT(MINIMAL_LOGGING, L"Startnode is forestroot, Scope must be SubTree");
hr = E_INVALIDARG; DisplayErrorMessage(g_pszDSCommandName, NULL, hr, IDS_FOREST_SEARCH_SCOPE);
return hr; }
if((_wcsicmp(pCommandArgs[eCommStartNode].strValue, g_pszForestRoot) == 0 ) && _wcsicmp(pObjectEntry->pszCommandLineObjectType, g_pszQuota) == 0) { DEBUG_OUTPUT(MINIMAL_LOGGING, L"A Startnode of forestroot is not allowed for quotas");
hr = E_INVALIDARG; DisplayErrorMessage(g_pszDSCommandName, NULL, hr, IDS_FOREST_SEARCH_SCOPE_QUOTAS);
return hr; }
}
//
//Limit must be 0 or greater
//
if(pCommandArgs[eCommLimit].bDefined) { if(pCommandArgs[eCommLimit].nValue < 0) { hr = E_INVALIDARG; DisplayErrorMessage(g_pszDSCommandName, NULL, hr, IDS_ERROR_LIMIT); return hr; } }
//
//Forestwide Search implies the -GC switch so define it if it isn't already
//
if(pCommandArgs[eCommStartNode].bDefined && pCommandArgs[eCommStartNode].strValue ) { //Security Review:Both strings are null terminated.
if(_wcsicmp(pCommandArgs[eCommStartNode].strValue,g_pszForestRoot) == 0) { // partitions and quotas don't support forestRoot so
// g_eGC will be valid unless there is an upstream bug
// so this ASSERT will catch that in private tests
ASSERT(g_eGC != -1); if(!(pCommandArgs[g_eGC].bDefined && pCommandArgs[g_eGC].bValue)) { pCommandArgs[g_eGC].bDefined = TRUE; pCommandArgs[g_eGC].bValue = TRUE; } } }
//
//For dsquery server, if none of the -domain, -forest, -site is
//specified, then define -domain as its default
//
//Security Review:Both strings are null terminated.
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) { //Security Review:pCommandArgs[eCommPassword].strValue is encrypted.
//Decrypt pCommandArgs[eCommPassword].strValue and then pass it to the
//credentialObject.SetPassword.
//See NTRAID#NTBUG9-571544-2000/11/13-hiteshr
credentialObject.SetEncryptedPassword(&pCommandArgs[eCommPassword].encryptedDataBlob); credentialObject.SetUsingCredentials(true); }
// If this is something that supports the GC switch then do the next check
if(g_eGC != -1) { //if -GC and -s flags are specified together than server must be
//GC.
if(pCommandArgs[g_eGC].bDefined && pCommandArgs[g_eGC].bValue && pCommandArgs[eCommServer].bDefined && pCommandArgs[eCommServer].strValue) { if(!IsServerGC(pCommandArgs[eCommServer].strValue,credentialObject)) { hr = E_INVALIDARG; DisplayErrorMessage(g_pszDSCommandName, NULL, hr, IDS_SEVER_NOT_GC); return hr; } } }
//
// 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)) { //Error is displayed in the function itself.
return hr; }
DEBUG_OUTPUT(MINIMAL_LOGGING, L"start node = %s", sbstrObjectDN);
//
//Build The Filter For Query
//
CComBSTR strSubSiteSuffix; PVOID pParam = NULL; //Security Review:Both strings are null terminated.
if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszSubnet) == 0) { GetSiteContainerPath(basePathsInfo, strSubSiteSuffix); pParam = (PVOID)&strSubSiteSuffix; }
CComBSTR strLDAPFilter; hr = BuildQueryFilter(pCommandArgs, pObjectEntry, basePathsInfo, credentialObject, 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)) { //Error is displayed in the function itself.
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) //Security Review:Both strings are null terminated.
{ //
// "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
//
//Security Review:Both strings are null terminated.
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;
if(_wcsicmp(pObjectEntry->pszCommandLineObjectType, g_pszPartition) == 0) pszAttr = g_szAttrNCName; else pszAttr = g_szAttrDistinguishedName; } else if(pcommon_info->outputFormat == DSQUERY_OUTPUT_ATTRONLY) pszAttr = g_szAttrDistinguishedName; else if(pcommon_info->outputFormat == DSQUERY_OUTPUT_DN) { if(_wcsicmp(pObjectEntry->pszCommandLineObjectType, g_pszPartition) == 0) pszAttr = g_szAttrNCName; else 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; //Security Review:Both strings are null terminated.
if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszServer) == 0) { //
// Add an addition space for the serverReference
++entries; }
LPWSTR *ppszAttr = (LPWSTR *)LocalAlloc(LPTR,sizeof(LPWSTR) * entries); if(!ppszAttr) { hr = E_OUTOFMEMORY; return hr; }
//Security Review:Correct buffer size is passed.
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; }
//Security Review:Both strings are null terminated.
if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszServer) == 0) { 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 GC switch isn't supported then set to false
// otherwise check to see if it has been passed
if(g_eGC == -1) { *pbSearchAtGC = FALSE; } else { if(pCommandArgs[g_eGC].bDefined && pCommandArgs[g_eGC].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; //Security Review:Both strings are null terminated.
if(_wcsicmp(pszInputDN,g_pszDomainRoot) == 0) { refsbstrDN = refBasePathsInfo.GetDefaultNamingContext(); } //Security Review:Both strings are null terminated.
else if(_wcsicmp(pszInputDN,g_pszForestRoot) == 0) { *pbSearchAtForestRoot = TRUE; } else { //
//DN is entered
//
refsbstrDN = pszInputDN; } } else { //Security Review:Both strings are null terminated.
if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszServer) == 0) { if (pCommandArgs[eServerDomain].bDefined && !pCommandArgs[eServerDomain].strValue) { PWSTR pszName = 0; CComBSTR bstrDomainName = refBasePathsInfo.GetDefaultNamingContext(); HRESULT hr = CrackName(bstrDomainName, &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); } //Security Review:Both strings are null terminated.
else if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszSite) == 0) { //
// Scope is the configuration container
//
refsbstrDN = refBasePathsInfo.GetConfigurationNamingContext(); } //Security Review:Both strings are null terminated.
else if (_wcsicmp(pObjectEntry->pszObjectClass, g_pszSubnet) == 0) { //
// Get the base path that corresponds with the scope
//
GetSubnetSearchRoot(refBasePathsInfo, refsbstrDN); } else if (_wcsicmp(pObjectEntry->pszCommandLineObjectType, g_pszPartition) == 0) { // For partitions, search from Configuration
refsbstrDN = L"CN=Partitions,"; refsbstrDN += refBasePathsInfo.GetConfigurationNamingContext(); } 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) {
ENTER_FUNCTION_HR(MINIMAL_LOGGING, GetSearchObject, hr);
if(!pObjectEntry || !pCommandArgs) return E_POINTER;
//
//Rules for determining where to search.
//if -s server is given always search at server
//if -gc is given search at gc.
//if startnode is forestroot, search at gc. so -gc is implicit here.
//if startnode is forestroot, and -s server is provided, server must
//be gc.
//if -s server and -gc are given, server must be gc. This check is
//done in DoQueryValidation
//
if(!bSearchAtForestRoot) { CComBSTR sbstrObjectPath; bool bBindToServer = true; //
//Search at GC
//
if(bSearchAtGC) { //
//Change the provider in sbstrObjectPath from LDAP to GC
//
CComPtr<IADsPathname> spPathNameObject; //Security Review:CLSCTX_INPROC_SERVER is passed. This is fine.
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(CComBSTR(L"GC"), ADS_SETTYPE_PROVIDER); ASSERT(SUCCEEDED(hr));
//Set the DN
hr = spPathNameObject->Set(refsbstrDN, ADS_SETTYPE_DN); ASSERT(SUCCEEDED(hr)); //If server name present, search there. Server must be GC, check
//already done DoQueryValidation.
if(pCommandArgs[eCommServer].bDefined && pCommandArgs[eCommServer].strValue) { //Convert DN to adsi path with GC provider
hr = spPathNameObject->Set(CComBSTR(pCommandArgs[eCommServer].strValue), ADS_SETTYPE_SERVER); //
//server name in path
//
bBindToServer = true; } else { //
//No server name in path
//
bBindToServer = false; }
hr = spPathNameObject->Retrieve(bBindToServer ? ADS_FORMAT_X500 : ADS_FORMAT_X500_NO_SERVER, &sbstrObjectPath); ASSERT(SUCCEEDED(hr));
} else { //
// Convert the DN to an ADSI path
//
refBasePathsInfo.ComposePathFromDN(refsbstrDN, sbstrObjectPath); //Security Review:Both strings are null terminated.
if((_wcsicmp(pObjectEntry->pszObjectClass, g_pszUser) == 0 && pCommandArgs[eUserInactive].bDefined) || //Security Review:Both strings are null terminated.
(_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 (SUCCEEDED(hr)) { CComVariant varVer; hr = spDomain->GetInfo();
if(SUCCEEDED(hr)) { CComBSTR bstrVer = L"msDS-Behavior-Version"; hr = spDomain->Get(bstrVer, &varVer); if(SUCCEEDED(hr)) { ASSERT(varVer.vt == VT_I4); nDomainBehaviorVersion = static_cast<UINT>(varVer.lVal); } } }
if(nDomainBehaviorVersion == 0) { DEBUG_OUTPUT(LEVEL3_LOGGING, L"DomainBehaviorVersion is 0."); hr = E_INVALIDARG; DisplayErrorMessage(g_pszDSCommandName, NULL, hr, IDS_FILTER_LAST_LOGON_VERSION); return hr; } } }
hr = DSCmdOpenObject(refCredentialObject, sbstrObjectPath, IID_IDirectorySearch, (void**)&refspSearchObject, bBindToServer); if (FAILED(hr)) { DisplayErrorMessage(g_pszDSCommandName, NULL, hr); return hr; } } else { CComBSTR bstrSearchRoot = L"GC://"; bool bBindToServer = false;
//If server name is provided search there
if(pCommandArgs[eCommServer].bDefined && pCommandArgs[eCommServer].strValue) { bstrSearchRoot += pCommandArgs[eCommServer].strValue; bBindToServer = true; } else { //Get RootDse
CComPtr<IADs> spRootDSE = refBasePathsInfo.GetRootDSE();
//Get name of forest
VARIANT Default; VariantInit(&Default); hr = spRootDSE->Get (CComBSTR(L"rootDomainNamingContext"), &Default); if(FAILED(hr)) { DisplayErrorMessage(g_pszDSCommandName, NULL, hr); return hr; }
ASSERT(Default.vt == VT_BSTR); CComBSTR bstrForestDN = Default.bstrVal; ::VariantClear(&Default);
//Convert DN to dns path
CComBSTR bstrForestDNS; if(!TranslateNameFromDnToDns(bstrForestDN, bstrForestDNS)) { hr = E_FAIL; DisplayErrorMessage(g_pszDSCommandName, NULL, hr); return hr; }
bBindToServer = false; bstrSearchRoot += bstrForestDNS; }
//BIND to GC to search entire forest
hr = DSCmdOpenObject(refCredentialObject, bstrSearchRoot, IID_IDirectorySearch, (void**)&refspSearchObject, bBindToServer);
if (FAILED(hr)) { DisplayErrorMessage(g_pszDSCommandName, NULL, hr); return hr; } }
return hr; }
BOOL TranslateNameFromDnToDns(const CComBSTR& bstrInputDN, CComBSTR& bstrOutputDNS) { if(bstrInputDN.Length() == 0) return FALSE;
bstrOutputDNS.Empty(); LPCWSTR pstrName = bstrInputDN; PDS_NAME_RESULT pResult = NULL; if( DS_NAME_NO_ERROR == DsCrackNames(NULL, DS_NAME_FLAG_SYNTACTICAL_ONLY, DS_FQDN_1779_NAME, DS_CANONICAL_NAME, 1, (LPWSTR*)(&pstrName), &pResult)) { if(pResult && pResult->cItems == 1 && pResult->rItems[0].status == DS_NAME_NO_ERROR && pResult->rItems[0].pDomain) { bstrOutputDNS = pResult->rItems[0].pDomain; }
if(pResult) { DsFreeNameResult(pResult); } } return !!bstrOutputDNS.Length(); }
//+--------------------------------------------------------------------------
//
// Function: GetGCIndex
//
// Synopsis: Performs a lookup to determine which enum value is holding
// the GC (if any). This was necessary removing -gc from common
//
// Arguments: [pObjectEntry IN] : ObjectEntry from the parser
// [nCommandEnum OUT] : Enum value of the object, else -1
//
// Returns: HRESULT : S_OK if everything succeeded
// E_INVALIDARG
//
// Remarks:
//
//
// History: 10-Sep-2002 ronmart Created
//
//---------------------------------------------------------------------------
HRESULT GetGCIndex(PDSQueryObjectTableEntry pObjectEntry, int& nCommandEnum) { HRESULT hr = S_OK;
do // false loop
{ // Init nCommandEnum to an error value by default
nCommandEnum = -1;
if(NULL == pObjectEntry) { hr = E_INVALIDARG; break; }
// Get a pointer to the object class for readability
PCWSTR pszCommandLineObjectType = pObjectEntry->pszCommandLineObjectType;
// Now compare each object type against the specified
// object class to see what the enum index is
if(0 == lstrcmpi(pszCommandLineObjectType, g_pszStar)) { nCommandEnum = eStarGC; break; } else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszOU)) { nCommandEnum = eOUGC; break; } else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszUser)) { nCommandEnum = eUserGC; break; } else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszContact)) { nCommandEnum = eContactGC; break; } else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszComputer)) { nCommandEnum = eComputerGC; break; } else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszGroup)) { nCommandEnum = eGroupGC; break; } else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszServer)) { nCommandEnum = eServerGC; break; } else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszSite)) { nCommandEnum = eSiteGC; break; } else if(0 == lstrcmpi(pszCommandLineObjectType,g_pszSubnet)) { nCommandEnum = eSubnetGC; break; } else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszQuota)) { nCommandEnum = -1; // -gc not supported
break; } else if(0 == lstrcmpi(pszCommandLineObjectType, g_pszPartition)) { nCommandEnum = -1; // -gc not supported
break; } else { hr = E_FAIL; // If you get here, then you've added a new object
// to cstrings.* without adding it to the
// if statement. This should only happen
// when testing a new object for the first time
// without a corresponding check above.
ASSERT(FALSE); break; } } while(false); return hr; }
|