1570 lines
48 KiB
C++
1570 lines
48 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1992 - 2000
|
||
|
//
|
||
|
// File: output.cpp
|
||
|
//
|
||
|
// Contents: Defines the functions which displays the query output
|
||
|
// History: 05-OCT-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 "stdlib.h"
|
||
|
#include "output.h"
|
||
|
#include "sddl.h"
|
||
|
|
||
|
#include <dscmn.h>
|
||
|
|
||
|
//
|
||
|
// list was causing unused formal parameter warnings when compiling with /W4
|
||
|
//
|
||
|
#pragma warning(disable : 4100)
|
||
|
#include <list>
|
||
|
#pragma warning(default : 4100)
|
||
|
|
||
|
HRESULT GetStringFromADs(const ADSVALUE *pValues,
|
||
|
ADSTYPE dwADsType,
|
||
|
LPWSTR pBuffer,
|
||
|
DWORD dwBufferLen,
|
||
|
LPCWSTR lpszAttrName);
|
||
|
|
||
|
HRESULT OutputFetchAttr(IN LPWSTR * ppszAttributes,
|
||
|
IN DWORD cAttributes,
|
||
|
IN CDSSearch *pSearch,
|
||
|
IN BOOL bListFormat);
|
||
|
|
||
|
HRESULT OutputAllAttr(IN CDSSearch *pSearch, BOOL bAttrOnly);
|
||
|
|
||
|
|
||
|
HRESULT OutputSingleAttr(IN LPWSTR * ppszAttributes,
|
||
|
IN DWORD cAttributes,
|
||
|
IN CDSSearch *pSearch);
|
||
|
|
||
|
BOOL IsQueryLimitReached(int iResultsDisplayed)
|
||
|
{
|
||
|
if(g_iQueryLimit != 0)
|
||
|
{
|
||
|
if(iResultsDisplayed == g_iQueryLimit)
|
||
|
{
|
||
|
if(!g_bQuiet)
|
||
|
{
|
||
|
if(g_bDeafultLimit)
|
||
|
WriteStringIDToStandardOut(IDS_DEFAULT_QUERY_LIMIT_REACHED);
|
||
|
else
|
||
|
WriteStringIDToStandardOut(IDS_QUERY_LIMIT_REACHED);
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT LocalCopyString(LPTSTR* ppResult, LPCTSTR pString)
|
||
|
{
|
||
|
if ( !ppResult || !pString )
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*ppResult = (LPTSTR)LocalAlloc(LPTR, (wcslen(pString)+1)*sizeof(WCHAR) );
|
||
|
|
||
|
if ( !*ppResult )
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
lstrcpy(*ppResult, pString);
|
||
|
return S_OK; // success
|
||
|
}
|
||
|
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DisplayList
|
||
|
//
|
||
|
// Synopsis: Dispalys a name and value in list format.
|
||
|
// Arguments: [szName - IN] : name of the attribute
|
||
|
// [szValue - IN]: value of the attribute
|
||
|
// [bShowAttribute - IN] : if true the attribute name will be
|
||
|
// prepended to the output
|
||
|
//
|
||
|
//
|
||
|
// History: 05-OCT-2000 hiteshr Created
|
||
|
// 13-Dec-2000 JeffJon Modified - Added the bShowAttribute flag
|
||
|
// so that the caller can determine whether
|
||
|
// or not to show the attribute name
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
VOID DisplayList(LPCWSTR szName, LPCWSTR szValue, bool bShowAttribute = true)
|
||
|
{
|
||
|
if(!szName)
|
||
|
return;
|
||
|
CComBSTR strTemp;
|
||
|
if (bShowAttribute)
|
||
|
{
|
||
|
strTemp = szName;
|
||
|
strTemp += L": ";
|
||
|
}
|
||
|
if(szValue)
|
||
|
strTemp += szValue;
|
||
|
DisplayOutput(strTemp);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DsQueryOutput
|
||
|
//
|
||
|
// Synopsis: This functions outputs the query results.
|
||
|
//
|
||
|
// Arguments: [outputFormat IN] Output format specified at commandline.
|
||
|
// [ppszAttributes IN] List of attributes fetched by query
|
||
|
// [cAttributes,IN] Number of arributes in above array
|
||
|
// [*pSeach,IN] Search Object which has queryhandle
|
||
|
// [bListFormat IN] Is Output to shown in List Format.
|
||
|
// This is valid for "dsquery *" only.
|
||
|
// Returns: HRESULT : S_OK if everything succeeded
|
||
|
// E_INVALIDARG
|
||
|
// Anything else is a failure code from an ADSI call
|
||
|
//
|
||
|
// History: 25-Sep-2000 hiteshr Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT DsQueryOutput( IN DSQUERY_OUTPUT_FORMAT outputFormat,
|
||
|
IN LPWSTR * ppszAttributes,
|
||
|
IN DWORD cAttributes,
|
||
|
IN CDSSearch *pSearch,
|
||
|
IN BOOL bListFormat )
|
||
|
{
|
||
|
ENTER_FUNCTION_HR(FULL_LOGGING, DsQueryOutput, hr);
|
||
|
|
||
|
if(!pSearch)
|
||
|
{
|
||
|
ASSERT(FALSE);
|
||
|
hr = E_INVALIDARG;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
if(outputFormat == DSQUERY_OUTPUT_ATTRONLY)
|
||
|
{
|
||
|
hr = OutputAllAttr(pSearch, TRUE);
|
||
|
return hr;
|
||
|
}
|
||
|
else if(outputFormat == DSQUERY_OUTPUT_ATTR)
|
||
|
{
|
||
|
//
|
||
|
//Attributes to display were specified at command line
|
||
|
//
|
||
|
if(cAttributes)
|
||
|
{
|
||
|
hr = OutputFetchAttr(ppszAttributes,
|
||
|
cAttributes,
|
||
|
pSearch,
|
||
|
bListFormat);
|
||
|
return hr;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
//No attributes were specified at commandline Display All the attributes.
|
||
|
//
|
||
|
hr = OutputAllAttr(pSearch, FALSE);
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
//Do the output for "dsquery objecttype"
|
||
|
//
|
||
|
hr = OutputSingleAttr(ppszAttributes,
|
||
|
cAttributes,
|
||
|
pSearch);
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetServerSearchRoot
|
||
|
//
|
||
|
// Synopsis: Builds the path to the root of the search as determined by
|
||
|
// the parameters passed in from the command line.
|
||
|
//
|
||
|
// Arguments: [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
|
||
|
//
|
||
|
// Returns: SERVER_QUERY_SCOPE : a value from the enumeration that represents
|
||
|
// the scope that will be searched
|
||
|
//
|
||
|
// History: 11-Dec-2000 JeffJon Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
DWORD GetServerSearchRoot(IN PARG_RECORD pCommandArgs,
|
||
|
IN CDSCmdBasePathsInfo& refBasePathsInfo,
|
||
|
OUT CComBSTR& refsbstrDN)
|
||
|
{
|
||
|
ENTER_FUNCTION(LEVEL3_LOGGING, GetServerSearchRoot);
|
||
|
|
||
|
DWORD scope = SERVER_QUERY_SCOPE_FOREST;
|
||
|
CComBSTR sbstrRootDN = L"CN=Sites,";
|
||
|
sbstrRootDN += refBasePathsInfo.GetConfigurationNamingContext();
|
||
|
|
||
|
do // false loop
|
||
|
{
|
||
|
//
|
||
|
// Validate parameters
|
||
|
//
|
||
|
if (!pCommandArgs)
|
||
|
{
|
||
|
ASSERT(pCommandArgs);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (pCommandArgs[eServerSite].bDefined &&
|
||
|
pCommandArgs[eServerSite].strValue)
|
||
|
{
|
||
|
DEBUG_OUTPUT(FULL_LOGGING,
|
||
|
L"Using the site as the root of the search: %s",
|
||
|
pCommandArgs[eServerSite].strValue);
|
||
|
|
||
|
//
|
||
|
// Prepend the named site container to the current root
|
||
|
//
|
||
|
CComBSTR sbstrTemp = L"CN=";
|
||
|
sbstrTemp += pCommandArgs[eServerSite].strValue;
|
||
|
sbstrTemp += L",";
|
||
|
sbstrTemp += sbstrRootDN;
|
||
|
sbstrRootDN = sbstrTemp;
|
||
|
|
||
|
DEBUG_OUTPUT(FULL_LOGGING,
|
||
|
L"scope = SERVER_QUERY_SCOPE_SITE");
|
||
|
scope = SERVER_QUERY_SCOPE_SITE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUG_OUTPUT(FULL_LOGGING,
|
||
|
L"scope = SERVER_QUERY_SCOPE_FOREST");
|
||
|
scope = SERVER_QUERY_SCOPE_FOREST;
|
||
|
}
|
||
|
|
||
|
if (pCommandArgs[eServerDomain].bDefined &&
|
||
|
pCommandArgs[eServerDomain].strValue)
|
||
|
{
|
||
|
DEBUG_OUTPUT(FULL_LOGGING,
|
||
|
L"scope |= SERVER_QUERY_SCOPE_DOMAIN");
|
||
|
scope |= SERVER_QUERY_SCOPE_DOMAIN;
|
||
|
}
|
||
|
|
||
|
refsbstrDN = sbstrRootDN;
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"search root = %s",
|
||
|
refsbstrDN);
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"search scope = 0x%x",
|
||
|
scope);
|
||
|
} while (false);
|
||
|
|
||
|
return scope;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetSubnetSearchRoot
|
||
|
//
|
||
|
// Synopsis: Builds search root path for Subnet. Its always
|
||
|
// cn=subnet,cn=site in configuration container
|
||
|
//
|
||
|
// Arguments: [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
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// History: 24-April-2001 hiteshr Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
VOID GetSubnetSearchRoot(IN CDSCmdBasePathsInfo& refBasePathsInfo,
|
||
|
OUT CComBSTR& refsbstrDN)
|
||
|
{
|
||
|
ENTER_FUNCTION(LEVEL3_LOGGING, GetSubnetSearchRoot);
|
||
|
|
||
|
refsbstrDN = L"CN=subnets,CN=Sites,";
|
||
|
refsbstrDN += refBasePathsInfo.GetConfigurationNamingContext();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetSiteContainerPath
|
||
|
//
|
||
|
// Synopsis: Returns the DN for site container in Configuration
|
||
|
// container
|
||
|
//
|
||
|
// Arguments: [refBasePathsInfo IN] : reference to the base paths info
|
||
|
// [refsbstrDN OUT] : reference to a CComBSTR that will
|
||
|
// receive the DN
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// History: 24-April-2001 hiteshr Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
VOID GetSiteContainerPath(IN CDSCmdBasePathsInfo& refBasePathsInfo,
|
||
|
OUT CComBSTR& refSubSiteSuffix)
|
||
|
{
|
||
|
ENTER_FUNCTION(LEVEL3_LOGGING, GetSubnetSearchRoot);
|
||
|
|
||
|
refSubSiteSuffix = L"CN=Sites,";
|
||
|
refSubSiteSuffix += refBasePathsInfo.GetConfigurationNamingContext();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetGCList
|
||
|
//
|
||
|
// Synopsis: Does a search from the passed in path looking for GCs
|
||
|
//
|
||
|
// Arguments: [pszSearchRootPath IN] : the path to the root of the search
|
||
|
// [refCredObject IN] : reference to the credential object
|
||
|
// [refGCList OUT] : reference to an STL list that will
|
||
|
// take the DNs of the GCs
|
||
|
//
|
||
|
//
|
||
|
// Returns: HRESULT : S_OK if everything succeeded
|
||
|
// E_INVALIDARG
|
||
|
// Anything else is a failure code from an ADSI call
|
||
|
//
|
||
|
// Remarks: Caller must free all strings added to the list by calling
|
||
|
// SysFreeString()
|
||
|
//
|
||
|
// History: 08-Dec-2000 JeffJon Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
HRESULT GetGCList( IN PCWSTR pszSearchRootPath,
|
||
|
IN const CDSCmdCredentialObject& refCredObject,
|
||
|
OUT std::list<PWSTR>& refGCList)
|
||
|
{
|
||
|
ENTER_FUNCTION_HR(LEVEL3_LOGGING, GetGCList, hr);
|
||
|
|
||
|
do // false loop
|
||
|
{
|
||
|
//
|
||
|
// Verify parameters
|
||
|
//
|
||
|
if (!pszSearchRootPath)
|
||
|
{
|
||
|
ASSERT(pszSearchRootPath);
|
||
|
|
||
|
hr = E_INVALIDARG;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Search for NTDSDSA objects that have the options bit set for a GC
|
||
|
//
|
||
|
CDSSearch gcSearchObj;
|
||
|
hr = gcSearchObj.Init(pszSearchRootPath,
|
||
|
refCredObject);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Prepare the search object
|
||
|
//
|
||
|
PWSTR ppszAttrs[] = { L"distinguishedName" };
|
||
|
DWORD dwAttrCount = sizeof(ppszAttrs)/sizeof(PCWSTR);
|
||
|
PWSTR pszGCFilter = L"(&(objectClass=nTDSDSA)(options:LDAP_MATCHING_RULE_BIT_AND_W:=1))";
|
||
|
|
||
|
gcSearchObj.SetFilterString(pszGCFilter);
|
||
|
gcSearchObj.SetSearchScope(ADS_SCOPE_SUBTREE);
|
||
|
gcSearchObj.SetAttributeList(ppszAttrs, dwAttrCount);
|
||
|
|
||
|
hr = gcSearchObj.DoQuery();
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"Failed to search for NTDSDSA objects that are GCs: hr = 0x%x",
|
||
|
hr);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
while (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = gcSearchObj.GetNextRow();
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"GetNextRow() failed: hr = 0x%x",
|
||
|
hr);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (hr == S_ADS_NOMORE_ROWS)
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ADS_SEARCH_COLUMN column;
|
||
|
ZeroMemory(&column, sizeof(ADS_SEARCH_COLUMN));
|
||
|
|
||
|
hr = gcSearchObj.GetColumn(ppszAttrs[0], &column);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"Failed to get column %s",
|
||
|
ppszAttrs[0]);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ASSERT(0 == _wcsicmp(column.pszAttrName, ppszAttrs[0]));
|
||
|
if (column.dwNumValues == 1 &&
|
||
|
column.pADsValues)
|
||
|
{
|
||
|
//
|
||
|
// Since the server is really the parent of the NTDSDSA object,
|
||
|
// get the server DN and add it to the list
|
||
|
//
|
||
|
CComBSTR sbstrParentDN;
|
||
|
hr = CPathCracker::GetParentDN(column.pADsValues->DNString,
|
||
|
sbstrParentDN);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
refGCList.push_back(sbstrParentDN.Copy());
|
||
|
DEBUG_OUTPUT(FULL_LOGGING,
|
||
|
L"GC found: %s",
|
||
|
column.pADsValues->DNString);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"Failed to get the parent DN from the NTDSDSA DN: %s",
|
||
|
column.pADsValues->DNString);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"The column has no values!");
|
||
|
}
|
||
|
|
||
|
hr = gcSearchObj.FreeColumn(&column);
|
||
|
ASSERT(SUCCEEDED(hr));
|
||
|
}
|
||
|
} while (false);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetFSMOList
|
||
|
//
|
||
|
// Synopsis: Does a search from the passed in path looking for the FSMO
|
||
|
// role owners
|
||
|
//
|
||
|
// Arguments: [pszSearchRootPath IN] : the path to the root of the search
|
||
|
// [refBasePathsInfo IN] : reference to the base paths info
|
||
|
// [refCredObject IN] : reference to the credential object
|
||
|
// [pszFSMOArg IN] : the value of the -hasfsmo arg
|
||
|
// [refFSMOList OUT] : reference to the search object that
|
||
|
// will hold the results
|
||
|
//
|
||
|
//
|
||
|
// Returns: HRESULT : S_OK if everything succeeded
|
||
|
// E_INVALIDARG
|
||
|
// Anything else is a failure code from an ADSI call
|
||
|
//
|
||
|
// Remarks: Caller must free all strings added to the list by calling
|
||
|
// SysFreeString()
|
||
|
//
|
||
|
// History: 11-Dec-2000 JeffJon Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
HRESULT GetFSMOList( IN PCWSTR pszSearchRootPath,
|
||
|
IN CDSCmdBasePathsInfo& refBasePathsInfo,
|
||
|
IN const CDSCmdCredentialObject& refCredObject,
|
||
|
IN PCWSTR pszFSMOArg,
|
||
|
OUT std::list<PWSTR>& refFSMOList)
|
||
|
{
|
||
|
ENTER_FUNCTION_HR(LEVEL3_LOGGING, GetFSMOList, hr);
|
||
|
|
||
|
do // false loop
|
||
|
{
|
||
|
//
|
||
|
// Verify parameters
|
||
|
//
|
||
|
if (!pszSearchRootPath ||
|
||
|
!pszFSMOArg)
|
||
|
{
|
||
|
ASSERT(pszSearchRootPath);
|
||
|
|
||
|
hr = E_INVALIDARG;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
FSMO_TYPE fsmoType = SCHEMA_FSMO;
|
||
|
|
||
|
if (0 == _wcsicmp(pszFSMOArg, g_pszSchema))
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"Searching for the schema FSMO holder");
|
||
|
fsmoType = SCHEMA_FSMO;
|
||
|
}
|
||
|
else if (0 == _wcsicmp(pszFSMOArg, g_pszName))
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"Searching for the domain naming master FSMO holder");
|
||
|
fsmoType = DOMAIN_NAMING_FSMO;
|
||
|
}
|
||
|
else if (0 == _wcsicmp(pszFSMOArg, g_pszInfr))
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"Searching for the infrastructure FSMO holder");
|
||
|
fsmoType = INFRASTUCTURE_FSMO;
|
||
|
}
|
||
|
else if (0 == _wcsicmp(pszFSMOArg, g_pszPDC))
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"Searching for the PDC FSMO holder");
|
||
|
fsmoType = PDC_FSMO;
|
||
|
}
|
||
|
else if (0 == _wcsicmp(pszFSMOArg, g_pszRID))
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"Searching for the RID FSMO holder");
|
||
|
fsmoType = RID_POOL_FSMO;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"Unknown FSMO was passed in: %s",
|
||
|
pszFSMOArg);
|
||
|
hr = E_INVALIDARG;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
CComBSTR sbstrServerDN;
|
||
|
hr = FindFSMOOwner(refBasePathsInfo,
|
||
|
refCredObject,
|
||
|
fsmoType,
|
||
|
sbstrServerDN);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
refFSMOList.push_back(sbstrServerDN.Copy());
|
||
|
} while (false);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: IsObjectValidInAllLists
|
||
|
//
|
||
|
// Synopsis: Determines if the passed in DN exists in the other lists
|
||
|
//
|
||
|
// Arguments: [pszDN IN] : DN to search for in the lists
|
||
|
// [refGCList IN] : reference to the list of GCs found
|
||
|
// [bUseGCList IN] : if true refGCList will be used to validate DN
|
||
|
// [refFSMOList IN] : reference to the list of FSMO holders found
|
||
|
// [bUseFSMOList IN] : if true refFSMOList will be used to validate DN
|
||
|
//
|
||
|
// Returns: bool : true if the object is in all valid lists
|
||
|
// false otherwise
|
||
|
//
|
||
|
// History: 12-Dec-2000 JeffJon Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
bool IsObjectValidInAllLists(IN PCWSTR pszDN,
|
||
|
IN DWORD scope,
|
||
|
IN PCWSTR pszDomain,
|
||
|
IN const std::list<PWSTR>& refGCList,
|
||
|
IN bool bUseGCList,
|
||
|
IN const std::list<PWSTR>& refFSMOList,
|
||
|
IN bool bUseFSMOList)
|
||
|
{
|
||
|
ENTER_FUNCTION(LEVEL3_LOGGING, IsObjectValidInAllLists);
|
||
|
|
||
|
bool bReturn = false;
|
||
|
PWSTR pszName = 0;
|
||
|
do // false loop
|
||
|
{
|
||
|
//
|
||
|
// Validate parameters
|
||
|
//
|
||
|
if (!pszDN)
|
||
|
{
|
||
|
ASSERT(pszDN);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool bFoundInGCList = false;
|
||
|
bool bFoundInFSMOList = false;
|
||
|
|
||
|
DEBUG_OUTPUT(LEVEL7_LOGGING,
|
||
|
L"Searching for %s",
|
||
|
pszDN);
|
||
|
|
||
|
if (scope & SERVER_QUERY_SCOPE_DOMAIN)
|
||
|
{
|
||
|
if (!pszDomain)
|
||
|
{
|
||
|
//
|
||
|
// If no domain was specified there is no way we could find a match
|
||
|
//
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"The scope is domain but no domain argument was specified!");
|
||
|
bReturn = false;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DEBUG_OUTPUT(FULL_LOGGING,
|
||
|
L"Looking for domain: %s",
|
||
|
pszDomain);
|
||
|
|
||
|
//
|
||
|
// Use CrackName to get the domain name from the DN
|
||
|
//
|
||
|
|
||
|
HRESULT hr = CrackName(const_cast<PTSTR>(pszDN),
|
||
|
&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);
|
||
|
bReturn = false;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (0 != _wcsicmp(pszName, pszDomain))
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"Domain names don't match");
|
||
|
bReturn = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if (bUseGCList)
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"Searching through GC list...");
|
||
|
|
||
|
std::list<PWSTR>::iterator itr;
|
||
|
for (itr = refGCList.begin(); itr != refGCList.end(); ++itr)
|
||
|
{
|
||
|
if (0 == _wcsicmp(*itr, pszDN))
|
||
|
{
|
||
|
bFoundInGCList = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (bUseFSMOList)
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"Searching through FSMO list...");
|
||
|
|
||
|
std::list<PWSTR>::iterator itr;
|
||
|
for (itr = refFSMOList.begin(); itr != refFSMOList.end(); ++itr)
|
||
|
{
|
||
|
DEBUG_OUTPUT(FULL_LOGGING,
|
||
|
L"Comparing: %s and %s",
|
||
|
*itr,
|
||
|
pszDN);
|
||
|
if (0 == _wcsicmp(*itr, pszDN))
|
||
|
{
|
||
|
bFoundInFSMOList = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bReturn = ((bUseGCList && bFoundInGCList) || !bUseGCList) &&
|
||
|
((bUseFSMOList && bFoundInFSMOList) || !bUseFSMOList);
|
||
|
|
||
|
} while (false);
|
||
|
|
||
|
|
||
|
if(pszName)
|
||
|
LocalFree(pszName);
|
||
|
|
||
|
|
||
|
if (bReturn)
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"%s is a valid result",
|
||
|
pszDN);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"%s is NOT a valid result",
|
||
|
pszDN);
|
||
|
}
|
||
|
|
||
|
return bReturn;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: OutputValidSearchResult
|
||
|
//
|
||
|
// Synopsis: Determines if the passed in DN exists in the other lists
|
||
|
//
|
||
|
// Arguments: [refSearchObject - IN] : reference to the object that performed
|
||
|
// the search
|
||
|
// [ppszAttributes - IN] : list of attributes to be displayed
|
||
|
// [cAttributes - IN] : count of attributes in ppszAttributes
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// History: 12-Dec-2000 JeffJon Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
void OutputValidSearchResult(IN DSQUERY_OUTPUT_FORMAT outputFormat,
|
||
|
IN CDSSearch& refSearchObject,
|
||
|
IN PWSTR* ppszAttributes,
|
||
|
IN DWORD cAttributes)
|
||
|
{
|
||
|
ENTER_FUNCTION(LEVEL5_LOGGING, OutputValidSearchResult);
|
||
|
|
||
|
HRESULT hr = S_OK;
|
||
|
WCHAR pBuffer[MAXSTR];
|
||
|
|
||
|
if (!ppszAttributes ||
|
||
|
cAttributes == 0)
|
||
|
{
|
||
|
ASSERT(cAttributes > 0);
|
||
|
ASSERT(ppszAttributes);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Output in list format, note that we are only displaying one attribute
|
||
|
// The first attribute in the array must be the one we want to display
|
||
|
//
|
||
|
ADS_SEARCH_COLUMN ColumnData;
|
||
|
hr = refSearchObject.GetColumn(ppszAttributes[0], &ColumnData);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
ADSVALUE *pValues = ColumnData.pADsValues;
|
||
|
for( DWORD j = 0; j < ColumnData.dwNumValues && pValues; ++j )
|
||
|
{
|
||
|
hr = GetStringFromADs(pValues,
|
||
|
ColumnData.dwADsType,
|
||
|
pBuffer,
|
||
|
MAXSTR,
|
||
|
ppszAttributes[0]);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
|
||
|
CComBSTR sbstrTemp;
|
||
|
if (outputFormat == DSQUERY_OUTPUT_DN)
|
||
|
{
|
||
|
sbstrTemp = L"\"";
|
||
|
sbstrTemp += pBuffer;
|
||
|
sbstrTemp += L"\"";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sbstrTemp = pBuffer;
|
||
|
}
|
||
|
DisplayList(ppszAttributes[0], sbstrTemp, false);
|
||
|
}
|
||
|
++pValues;
|
||
|
}
|
||
|
refSearchObject.FreeColumn(&ColumnData);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DsQueryServerOutput
|
||
|
//
|
||
|
// Synopsis: This functions outputs the query results for server object.
|
||
|
//
|
||
|
// Arguments: [outputFormat IN] Output format specified at commandline.
|
||
|
// [ppszAttributes IN] List of attributes fetched by query
|
||
|
// [cAttributes,IN] Number of arributes in above array
|
||
|
// [refServerSearch,IN]reference to the search Object
|
||
|
// [refBasePathsInfo IN] reference to the base paths info
|
||
|
// [pCommandArgs,IN] The pointer to the commands table
|
||
|
//
|
||
|
// Returns: HRESULT : S_OK if everything succeeded
|
||
|
// E_INVALIDARG
|
||
|
// Anything else is a failure code from an ADSI call
|
||
|
//
|
||
|
// History: 08-Dec-2000 JeffJon Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
HRESULT DsQueryServerOutput( IN DSQUERY_OUTPUT_FORMAT outputFormat,
|
||
|
IN LPWSTR* ppszAttributes,
|
||
|
IN DWORD cAttributes,
|
||
|
IN CDSSearch& refServerSearch,
|
||
|
IN const CDSCmdCredentialObject& refCredObject,
|
||
|
IN CDSCmdBasePathsInfo& refBasePathsInfo,
|
||
|
IN PARG_RECORD pCommandArgs)
|
||
|
{
|
||
|
ENTER_FUNCTION_HR(LEVEL3_LOGGING, DsQueryServerOutput, hr);
|
||
|
|
||
|
std::list<PWSTR> gcList;
|
||
|
std::list<PWSTR> fsmoList;
|
||
|
|
||
|
do // false loop
|
||
|
{
|
||
|
//
|
||
|
// Validate parameters
|
||
|
//
|
||
|
if (!ppszAttributes ||
|
||
|
!pCommandArgs)
|
||
|
{
|
||
|
ASSERT(ppszAttributes);
|
||
|
ASSERT(pCommandArgs);
|
||
|
hr = E_INVALIDARG;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Determine the scope that should be used
|
||
|
//
|
||
|
CComBSTR sbstrSearchRootDN;
|
||
|
DWORD scope = GetServerSearchRoot(pCommandArgs,
|
||
|
refBasePathsInfo,
|
||
|
sbstrSearchRootDN);
|
||
|
CComBSTR sbstrSearchRootPath;
|
||
|
refBasePathsInfo.ComposePathFromDN(sbstrSearchRootDN, sbstrSearchRootPath);
|
||
|
|
||
|
//
|
||
|
// Build the list of GCs if needed
|
||
|
//
|
||
|
bool bUseGCSearchResults = false;
|
||
|
if (pCommandArgs[eServerIsGC].bDefined &&
|
||
|
pCommandArgs[eServerIsGC].bValue)
|
||
|
{
|
||
|
hr = GetGCList(sbstrSearchRootPath,
|
||
|
refCredObject,
|
||
|
gcList);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If we didn't get any values then there is no reason to continue
|
||
|
// since we won't have anything that matches the -isgc flag
|
||
|
//
|
||
|
if (gcList.size() < 1)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
bUseGCSearchResults = true;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Build the list of FSMO owners if needed
|
||
|
//
|
||
|
bool bUseFSMOSearchResults = false;
|
||
|
if (pCommandArgs[eServerHasFSMO].bDefined &&
|
||
|
pCommandArgs[eServerHasFSMO].strValue)
|
||
|
{
|
||
|
hr = GetFSMOList(sbstrSearchRootPath,
|
||
|
refBasePathsInfo,
|
||
|
refCredObject,
|
||
|
pCommandArgs[eServerHasFSMO].strValue,
|
||
|
fsmoList);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
bUseFSMOSearchResults = true;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// See if we need to filter on domain
|
||
|
//
|
||
|
bool bUseDomainFiltering = false;
|
||
|
if (pCommandArgs[eServerDomain].bDefined &&
|
||
|
pCommandArgs[eServerDomain].strValue)
|
||
|
{
|
||
|
bUseDomainFiltering = true;
|
||
|
}
|
||
|
|
||
|
if (!bUseGCSearchResults &&
|
||
|
!bUseFSMOSearchResults &&
|
||
|
!bUseDomainFiltering)
|
||
|
{
|
||
|
hr = DsQueryOutput(outputFormat,
|
||
|
ppszAttributes,
|
||
|
cAttributes,
|
||
|
&refServerSearch,
|
||
|
true);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Either -isgc or -hasfsmo was specified so we have to take the intersection
|
||
|
// of the lists of objects found in each search to use as output
|
||
|
//
|
||
|
while (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = refServerSearch.GetNextRow();
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (hr == S_ADS_NOMORE_ROWS)
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ADS_SEARCH_COLUMN column;
|
||
|
ZeroMemory(&column, sizeof(ADS_SEARCH_COLUMN));
|
||
|
|
||
|
//
|
||
|
// Get the DN
|
||
|
//
|
||
|
hr = refServerSearch.GetColumn((PWSTR)g_szAttrServerReference, &column);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"Failed to get the distinguishedName for a column: hr = 0x%x",
|
||
|
hr);
|
||
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
||
|
L"continuing...");
|
||
|
hr = S_OK;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (column.dwNumValues == 1 &&
|
||
|
column.pADsValues)
|
||
|
{
|
||
|
//
|
||
|
// Search the lists and determine if the DN exists in all the lists
|
||
|
//
|
||
|
bool bValidEntry = IsObjectValidInAllLists(column.pADsValues->DNString,
|
||
|
scope,
|
||
|
pCommandArgs[eServerDomain].strValue,
|
||
|
gcList,
|
||
|
bUseGCSearchResults,
|
||
|
fsmoList,
|
||
|
bUseFSMOSearchResults);
|
||
|
if (bValidEntry)
|
||
|
{
|
||
|
//
|
||
|
// Output this server object since it matches all search criteria
|
||
|
//
|
||
|
OutputValidSearchResult(outputFormat,
|
||
|
refServerSearch,
|
||
|
ppszAttributes,
|
||
|
cAttributes);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hr = refServerSearch.FreeColumn(&column);
|
||
|
ASSERT(SUCCEEDED(hr));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} while (false);
|
||
|
|
||
|
std::list<PWSTR>::iterator gcItr;
|
||
|
for (gcItr = gcList.begin(); gcItr != gcList.end(); ++gcItr)
|
||
|
{
|
||
|
SysFreeString(*gcItr);
|
||
|
}
|
||
|
|
||
|
std::list<PWSTR>::iterator fsmoItr;
|
||
|
for (fsmoItr = fsmoList.begin(); fsmoItr != fsmoList.end(); ++fsmoItr)
|
||
|
{
|
||
|
SysFreeString(*fsmoItr);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: OutputFetchAttr
|
||
|
//
|
||
|
// Synopsis: Dispalys the fetched attributes in either list or table format
|
||
|
// Arguments: [ppszAttributes - IN] : Array containing list of attributes to display
|
||
|
// [cAttributes - IN]: Count of attributes in ppszAttributes
|
||
|
// [pSearch - IN]: pointer to search object
|
||
|
// [bListFormat - IN]: List or Table format
|
||
|
// Returns HRESULT S_OK if Successful
|
||
|
// E_INVALIDARG
|
||
|
// Anything else is a failure code from an ADSI call
|
||
|
//
|
||
|
//
|
||
|
// History: 05-OCT-2000 hiteshr Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT OutputFetchAttr(IN LPWSTR * ppszAttributes,
|
||
|
IN DWORD cAttributes,
|
||
|
IN CDSSearch *pSearch,
|
||
|
IN BOOL bListFormat)
|
||
|
{
|
||
|
ENTER_FUNCTION_HR(FULL_LOGGING, OutputFetchAttr, hr);
|
||
|
|
||
|
WCHAR pBuffer[MAXSTR];
|
||
|
ZeroMemory(pBuffer, sizeof(pBuffer));
|
||
|
|
||
|
if(bListFormat)
|
||
|
{
|
||
|
//
|
||
|
//Display in list format
|
||
|
//
|
||
|
int cListDisplayed = 0;
|
||
|
while(TRUE)
|
||
|
{
|
||
|
hr = pSearch->GetNextRow();
|
||
|
|
||
|
if(IsQueryLimitReached(cListDisplayed))
|
||
|
break;
|
||
|
|
||
|
if(hr == S_ADS_NOMORE_ROWS || FAILED(hr))
|
||
|
break;
|
||
|
|
||
|
bool bShowAttributes = false;
|
||
|
if (cAttributes > 1)
|
||
|
{
|
||
|
bShowAttributes = true;
|
||
|
}
|
||
|
|
||
|
for(DWORD i = 0; i < cAttributes; ++i)
|
||
|
{
|
||
|
ADS_SEARCH_COLUMN ColumnData;
|
||
|
hr = pSearch->GetColumn(ppszAttributes[i], &ColumnData);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
ADSVALUE *pValues = ColumnData.pADsValues;
|
||
|
for( DWORD j = 0; j < ColumnData.dwNumValues; ++j )
|
||
|
{
|
||
|
hr = GetStringFromADs(pValues,
|
||
|
ColumnData.dwADsType,
|
||
|
pBuffer,
|
||
|
MAXSTR,
|
||
|
ppszAttributes[i]);
|
||
|
if(SUCCEEDED(hr))
|
||
|
DisplayList(ppszAttributes[i], pBuffer, bShowAttributes);
|
||
|
|
||
|
++pValues;
|
||
|
}
|
||
|
pSearch->FreeColumn(&ColumnData);
|
||
|
}
|
||
|
else if(hr == E_ADS_COLUMN_NOT_SET)
|
||
|
DisplayList(ppszAttributes[i], L"", bShowAttributes);
|
||
|
}
|
||
|
cListDisplayed++;
|
||
|
|
||
|
}
|
||
|
if(hr == S_ADS_NOMORE_ROWS)
|
||
|
hr = S_OK;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
//Display in table format
|
||
|
//
|
||
|
|
||
|
//
|
||
|
//format will use first 80 rows to calculate column width
|
||
|
//
|
||
|
CFormatInfo format;
|
||
|
LONG sampleSize = 80;
|
||
|
|
||
|
//
|
||
|
//sampleSize should be lessthan or equal to QueryLimit
|
||
|
//
|
||
|
if(g_iQueryLimit != 0 && (sampleSize > g_iQueryLimit))
|
||
|
sampleSize = g_iQueryLimit;
|
||
|
|
||
|
LONG cRow = 0;
|
||
|
hr = format.Init(sampleSize,cAttributes,ppszAttributes);
|
||
|
if(FAILED(hr))
|
||
|
return hr;
|
||
|
|
||
|
//
|
||
|
//Display in table format
|
||
|
//
|
||
|
while(TRUE)
|
||
|
{
|
||
|
|
||
|
//
|
||
|
//we have reached sampleSize, so display column headers and
|
||
|
//display all the sample rows.
|
||
|
//
|
||
|
if(cRow == sampleSize)
|
||
|
{
|
||
|
format.DisplayHeaders();
|
||
|
format.DisplayAllRows();
|
||
|
}
|
||
|
|
||
|
hr = pSearch->GetNextRow();
|
||
|
//We are done
|
||
|
if(hr == S_ADS_NOMORE_ROWS || FAILED(hr))
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
//Check if we have reached querylimit
|
||
|
//
|
||
|
if(IsQueryLimitReached(cRow))
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
//Fetch columns
|
||
|
//
|
||
|
for( DWORD i = 0; i < cAttributes; ++i )
|
||
|
{
|
||
|
ADS_SEARCH_COLUMN ColumnData;
|
||
|
hr = pSearch->GetColumn(ppszAttributes[i], &ColumnData);
|
||
|
CComBSTR strValue;
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
strValue = "";
|
||
|
ADSVALUE *pValues = ColumnData.pADsValues;
|
||
|
for( DWORD j = 0; j < ColumnData.dwNumValues; ++j )
|
||
|
{
|
||
|
hr = GetStringFromADs(pValues,
|
||
|
ColumnData.dwADsType,
|
||
|
pBuffer,
|
||
|
MAXSTR,
|
||
|
ppszAttributes[i]);
|
||
|
//
|
||
|
//In table format multiple values are shown separated by ;
|
||
|
//
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
strValue += pBuffer;
|
||
|
if(ColumnData.dwNumValues > 1)
|
||
|
{
|
||
|
strValue += L";";
|
||
|
}
|
||
|
}
|
||
|
++pValues;
|
||
|
}
|
||
|
pSearch->FreeColumn(&ColumnData);
|
||
|
}
|
||
|
|
||
|
if(SUCCEEDED(hr) || hr == E_ADS_COLUMN_NOT_SET)
|
||
|
{
|
||
|
if(cRow < sampleSize)
|
||
|
{
|
||
|
//
|
||
|
//Cache this value in format and use it to calculate column width
|
||
|
//
|
||
|
format.Set(cRow,i,strValue);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
//Display the column value
|
||
|
//
|
||
|
format.DisplayColumn(i,strValue);
|
||
|
if(i == (cAttributes - 1))
|
||
|
format.NewLine();
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
++cRow;
|
||
|
|
||
|
}//End of while loop
|
||
|
if(hr == S_ADS_NOMORE_ROWS)
|
||
|
hr = S_OK;
|
||
|
|
||
|
if(cRow && (cRow < sampleSize))
|
||
|
{
|
||
|
//
|
||
|
//if total number of rows is less that sample size they are not
|
||
|
//displayed yet. Display them
|
||
|
//
|
||
|
format.DisplayHeaders();
|
||
|
format.DisplayAllRows();
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: OutputSingleAttr
|
||
|
//
|
||
|
// Synopsis: Displays the single attribute which user has asked for.
|
||
|
// Arguments: [ppszAttributes - IN] : Array containing list of attributes to display
|
||
|
// [cAttributes - IN]: Count of attributes in ppszAttributes. Should be 1
|
||
|
// [pSearch - IN]: pointer to search object
|
||
|
// Returns HRESULT S_OK if Successful
|
||
|
// E_INVALIDARG
|
||
|
// Anything else is a failure code from an ADSI call
|
||
|
//
|
||
|
//
|
||
|
// History: 05-OCT-2000 hiteshr Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT OutputSingleAttr(IN LPWSTR * ppszAttributes,
|
||
|
IN DWORD cAttributes,
|
||
|
IN CDSSearch *pSearch)
|
||
|
{
|
||
|
ENTER_FUNCTION_HR(FULL_LOGGING, OutputSingleAttr, hr);
|
||
|
|
||
|
if(!ppszAttributes || !cAttributes || !pSearch)
|
||
|
{
|
||
|
ASSERT(FALSE);
|
||
|
hr = E_INVALIDARG;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
ASSERT(cAttributes > 0);
|
||
|
|
||
|
WCHAR pBuffer[MAXSTR];
|
||
|
ZeroMemory(pBuffer, sizeof(pBuffer));
|
||
|
LONG cRow = 0;
|
||
|
|
||
|
while(TRUE)
|
||
|
{
|
||
|
hr = pSearch->GetNextRow();
|
||
|
|
||
|
//We are done
|
||
|
if(hr == S_ADS_NOMORE_ROWS || FAILED(hr))
|
||
|
break;
|
||
|
//
|
||
|
//Check if we have reached querylimit
|
||
|
//
|
||
|
if(IsQueryLimitReached(cRow))
|
||
|
break;
|
||
|
|
||
|
ADS_SEARCH_COLUMN ColumnData;
|
||
|
hr = pSearch->GetColumn(ppszAttributes[0], &ColumnData);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = GetStringFromADs(ColumnData.pADsValues,
|
||
|
ColumnData.dwADsType,
|
||
|
pBuffer,
|
||
|
MAXSTR,
|
||
|
ppszAttributes[0]);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
//Display the output enclosed in Double Quotes
|
||
|
CComBSTR strTemp;
|
||
|
strTemp = L"\"" ;
|
||
|
strTemp += pBuffer;
|
||
|
strTemp += L"\"";
|
||
|
DisplayOutput(strTemp);
|
||
|
}
|
||
|
pSearch->FreeColumn(&ColumnData);
|
||
|
}
|
||
|
else if(hr == E_ADS_COLUMN_NOT_SET)
|
||
|
{
|
||
|
//
|
||
|
//If Attribute is not set display ""
|
||
|
//
|
||
|
DisplayOutput(L"\"\"");
|
||
|
}
|
||
|
//
|
||
|
//Increment number of Row displayed
|
||
|
//
|
||
|
cRow++;
|
||
|
}//End of while loop
|
||
|
|
||
|
if(hr == S_ADS_NOMORE_ROWS)
|
||
|
hr = S_OK;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: OutputAllAttr
|
||
|
//
|
||
|
// Synopsis: Displays all the attributes.
|
||
|
// Arguments: [pSearch - IN]: pointer to search object
|
||
|
// [bAttrOnly - IN]: display attributes names only
|
||
|
// Returns HRESULT S_OK if Successful
|
||
|
// E_INVALIDARG
|
||
|
// Anything else is a failure code from an ADSI
|
||
|
// call
|
||
|
//
|
||
|
//
|
||
|
// History: 05-OCT-2000 hiteshr Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
HRESULT OutputAllAttr(IN CDSSearch *pSearch, BOOL bAttrOnly)
|
||
|
{
|
||
|
ENTER_FUNCTION_HR(FULL_LOGGING, OutputAllAttr, hr);
|
||
|
|
||
|
if(!pSearch)
|
||
|
{
|
||
|
ASSERT(FALSE);
|
||
|
hr = E_INVALIDARG;
|
||
|
return hr;
|
||
|
}
|
||
|
WCHAR pBuffer[MAXSTR];
|
||
|
LONG cRow = 0;
|
||
|
|
||
|
while(TRUE)
|
||
|
{
|
||
|
hr = pSearch->GetNextRow();
|
||
|
|
||
|
//We are done
|
||
|
if(hr == S_ADS_NOMORE_ROWS || FAILED(hr))
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
//Check if we reached querylimit
|
||
|
//
|
||
|
if(IsQueryLimitReached(cRow))
|
||
|
break;
|
||
|
|
||
|
LPWSTR pszColumnName;
|
||
|
BOOL bColumnNameDisplayed = FALSE;
|
||
|
//
|
||
|
//Get the name of next column which has value
|
||
|
//
|
||
|
while(pSearch->GetNextColumnName(&pszColumnName) != S_ADS_NOMORE_COLUMNS)
|
||
|
{
|
||
|
if(bAttrOnly)
|
||
|
{
|
||
|
wsprintf(pBuffer, L"%ws ", pszColumnName);
|
||
|
DisplayOutputNoNewline(pBuffer);
|
||
|
bColumnNameDisplayed = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ADS_SEARCH_COLUMN ColumnData;
|
||
|
hr = pSearch->GetColumn(pszColumnName, &ColumnData);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
ADSVALUE *pValues = ColumnData.pADsValues;
|
||
|
for( DWORD j = 0; j < ColumnData.dwNumValues; ++j )
|
||
|
{
|
||
|
hr = GetStringFromADs(pValues,
|
||
|
ColumnData.dwADsType,
|
||
|
pBuffer,
|
||
|
MAXSTR,
|
||
|
pszColumnName);
|
||
|
if(SUCCEEDED(hr))
|
||
|
DisplayList(pszColumnName, pBuffer);
|
||
|
++pValues;
|
||
|
}
|
||
|
pSearch->FreeColumn(&ColumnData);
|
||
|
}
|
||
|
else if(hr == E_ADS_COLUMN_NOT_SET)
|
||
|
DisplayList(pszColumnName, L"");
|
||
|
}
|
||
|
pSearch->FreeColumnName(pszColumnName);
|
||
|
}
|
||
|
|
||
|
|
||
|
if(bAttrOnly)
|
||
|
{
|
||
|
if(bColumnNameDisplayed)
|
||
|
{
|
||
|
DisplayOutputNoNewline(L"\r\n");
|
||
|
cRow++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
cRow++;
|
||
|
|
||
|
}//End of while loop
|
||
|
|
||
|
if(hr == S_ADS_NOMORE_ROWS)
|
||
|
hr = S_OK;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: GetStringFromADs
|
||
|
//
|
||
|
// Synopsis: Converts Value into string depending upon type
|
||
|
// Arguments: [pValues - IN]: Value to be converted to string
|
||
|
// [dwADsType-IN]: ADSTYPE of pValue
|
||
|
// [pBuffer - OUT]:Output buffer which gets the string
|
||
|
// [dwBufferLen-IN]:Size of output buffer
|
||
|
// Returns HRESULT S_OK if Successful
|
||
|
// E_INVALIDARG
|
||
|
// Anything else is a failure code from an ADSI
|
||
|
// call
|
||
|
//
|
||
|
//
|
||
|
// History: 05-OCT-2000 hiteshr Created
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
HRESULT GetStringFromADs(IN const ADSVALUE *pValues,
|
||
|
IN ADSTYPE dwADsType,
|
||
|
OUT LPWSTR pBuffer,
|
||
|
IN DWORD dwBufferLen,
|
||
|
IN LPCWSTR pszAttrName)
|
||
|
{
|
||
|
ENTER_FUNCTION_HR(FULL_LOGGING, GetStringFromADs, hr);
|
||
|
|
||
|
if(!pValues || !pBuffer || !dwBufferLen)
|
||
|
{
|
||
|
ASSERT(FALSE);
|
||
|
hr = E_INVALIDARG;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
pBuffer[0] = 0;
|
||
|
if( dwADsType == ADSTYPE_INVALID )
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
switch( dwADsType )
|
||
|
{
|
||
|
case ADSTYPE_DN_STRING :
|
||
|
{
|
||
|
CComBSTR sbstrOutputDN;
|
||
|
HRESULT hr = GetOutputDN( &sbstrOutputDN, pValues->DNString );
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
wcsncpy(pBuffer, (BSTR)sbstrOutputDN, dwBufferLen-1);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case ADSTYPE_CASE_EXACT_STRING :
|
||
|
wcsncpy(pBuffer ,pValues->CaseExactString, dwBufferLen-1);
|
||
|
break;
|
||
|
|
||
|
case ADSTYPE_CASE_IGNORE_STRING:
|
||
|
wcsncpy(pBuffer ,pValues->CaseIgnoreString, dwBufferLen-1);
|
||
|
break;
|
||
|
|
||
|
case ADSTYPE_PRINTABLE_STRING :
|
||
|
wcsncpy(pBuffer ,pValues->PrintableString, dwBufferLen-1);
|
||
|
break;
|
||
|
|
||
|
case ADSTYPE_NUMERIC_STRING :
|
||
|
wcsncpy(pBuffer ,pValues->NumericString, dwBufferLen-1);
|
||
|
break;
|
||
|
|
||
|
case ADSTYPE_OBJECT_CLASS :
|
||
|
wcsncpy(pBuffer ,pValues->ClassName, dwBufferLen-1);
|
||
|
break;
|
||
|
|
||
|
case ADSTYPE_BOOLEAN :
|
||
|
wsprintf(pBuffer ,L"%s", ((DWORD)pValues->Boolean) ? L"TRUE" : L"FALSE");
|
||
|
break;
|
||
|
|
||
|
case ADSTYPE_INTEGER :
|
||
|
wsprintf(pBuffer ,L"%d", (DWORD) pValues->Integer);
|
||
|
break;
|
||
|
|
||
|
case ADSTYPE_OCTET_STRING :
|
||
|
{
|
||
|
BYTE b;
|
||
|
WCHAR sOctet[128];
|
||
|
DWORD dwLen = 0;
|
||
|
//
|
||
|
//Special case objectguid and objectsid attribute
|
||
|
//
|
||
|
if(pszAttrName && !_wcsicmp(pszAttrName, L"objectguid"))
|
||
|
{
|
||
|
GUID *pguid = (GUID*)pValues->OctetString.lpValue;
|
||
|
StringFromGUID2(*pguid,(LPOLESTR)pBuffer,dwBufferLen);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(pszAttrName && !_wcsicmp(pszAttrName, L"objectsid"))
|
||
|
{
|
||
|
LPWSTR pszSid = NULL;
|
||
|
PSID pSid = (PSID)pValues->OctetString.lpValue;
|
||
|
if(ConvertSidToStringSid(pSid, &pszSid))
|
||
|
{
|
||
|
wcscpy(pBuffer,pszSid);
|
||
|
LocalFree(pszSid);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for ( DWORD idx=0; idx<pValues->OctetString.dwLength; idx++)
|
||
|
{
|
||
|
b = ((BYTE *)pValues->OctetString.lpValue)[idx];
|
||
|
wsprintf(sOctet,L"0x%02x ", b);
|
||
|
dwLen += static_cast<DWORD>(wcslen(sOctet));
|
||
|
if(dwLen > (dwBufferLen - 1) )
|
||
|
break;
|
||
|
else
|
||
|
wcscat(pBuffer,sOctet);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case ADSTYPE_LARGE_INTEGER :
|
||
|
{
|
||
|
CComBSTR strLarge;
|
||
|
LARGE_INTEGER li = pValues->LargeInteger;
|
||
|
litow(li, strLarge);
|
||
|
wcsncpy(pBuffer,strLarge,dwBufferLen-1);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case ADSTYPE_UTC_TIME :
|
||
|
wsprintf(pBuffer,
|
||
|
L"%02d/%02d/%04d %02d:%02d:%02d", pValues->UTCTime.wMonth, pValues->UTCTime.wDay, pValues->UTCTime.wYear,
|
||
|
pValues->UTCTime.wHour, pValues->UTCTime.wMinute, pValues->UTCTime.wSecond
|
||
|
);
|
||
|
break;
|
||
|
|
||
|
case ADSTYPE_NT_SECURITY_DESCRIPTOR: // I use the ACLEditor instead
|
||
|
{
|
||
|
//ISSUE:2000/01/05-hiteshr
|
||
|
//I am not sure what to do with the NT_SECURITY_DESCRIPTOR and also
|
||
|
//with someother datatypes not coverd by dsquery.
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default :
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DEBUG_OUTPUT(FULL_LOGGING, L"string = %w", pBuffer);
|
||
|
return hr;
|
||
|
}
|
||
|
|