You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1838 lines
62 KiB
1838 lines
62 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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(IN const ADSVALUE *pValues,
|
|
IN ADSTYPE dwADsType,
|
|
OUT LPWSTR* ppBuffer,
|
|
IN PCWSTR pszAttrName);
|
|
|
|
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)
|
|
WriteStringIDToStandardErr(IDS_DEFAULT_QUERY_LIMIT_REACHED);
|
|
else
|
|
WriteStringIDToStandardErr(IDS_QUERY_LIMIT_REACHED);
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
HRESULT LocalCopyString(LPTSTR* ppResult, LPCTSTR pString)
|
|
{
|
|
if ( !ppResult || !pString )
|
|
return E_INVALIDARG;
|
|
|
|
//pString is NULL terminated.
|
|
*ppResult = (LPTSTR)LocalAlloc(LPTR, (wcslen(pString)+1)*sizeof(WCHAR) );
|
|
|
|
if ( !*ppResult )
|
|
return E_OUTOFMEMORY;
|
|
|
|
//Correct buffer is allocated above.
|
|
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<BSTR>& 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;
|
|
//Security Review:Correct Buffer size is passed.
|
|
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;
|
|
}
|
|
|
|
//Security Review:Done
|
|
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<BSTR>& 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;
|
|
|
|
//Security Reivew: Both strings are null terminated.
|
|
if (0 == _wcsicmp(pszFSMOArg, g_pszSchema))
|
|
{
|
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
|
L"Searching for the schema FSMO holder");
|
|
fsmoType = SCHEMA_FSMO;
|
|
}
|
|
//Security Reivew: Both strings are null terminated.
|
|
else if (0 == _wcsicmp(pszFSMOArg, g_pszName))
|
|
{
|
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
|
L"Searching for the domain naming master FSMO holder");
|
|
fsmoType = DOMAIN_NAMING_FSMO;
|
|
}
|
|
//Security Reivew: Both strings are null terminated.
|
|
else if (0 == _wcsicmp(pszFSMOArg, g_pszInfr))
|
|
{
|
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
|
L"Searching for the infrastructure FSMO holder");
|
|
fsmoType = INFRASTUCTURE_FSMO;
|
|
}
|
|
//Security Reivew: Both strings are null terminated.
|
|
else if (0 == _wcsicmp(pszFSMOArg, g_pszPDC))
|
|
{
|
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
|
L"Searching for the PDC FSMO holder");
|
|
fsmoType = PDC_FSMO;
|
|
}
|
|
//Security Reivew: Both strings are null terminated.
|
|
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 pszComputerDN,
|
|
IN PCWSTR pszDN,
|
|
IN DWORD scope,
|
|
IN PCWSTR pszDomain,
|
|
IN const std::list<BSTR>& refGCList,
|
|
IN bool bUseGCList,
|
|
IN const std::list<BSTR>& refFSMOList,
|
|
IN bool bUseFSMOList)
|
|
{
|
|
ENTER_FUNCTION(LEVEL3_LOGGING, IsObjectValidInAllLists);
|
|
|
|
bool bReturn = false;
|
|
PWSTR pszName = 0;
|
|
do // false loop
|
|
{
|
|
//
|
|
// Validate parameters
|
|
//
|
|
if (!pszDN ||
|
|
!pszComputerDN)
|
|
{
|
|
ASSERT(pszDN);
|
|
ASSERT(pszComputerDN);
|
|
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>(pszComputerDN),
|
|
&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;
|
|
}
|
|
|
|
//Both names are null terminated.
|
|
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)
|
|
{
|
|
//Both names are null terminated.
|
|
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);
|
|
//Both names are null terminated.
|
|
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;
|
|
|
|
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 )
|
|
{
|
|
LPWSTR pBuffer = NULL;
|
|
hr = GetStringFromADs(pValues,
|
|
ColumnData.dwADsType,
|
|
&pBuffer,
|
|
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);
|
|
delete pBuffer;
|
|
pBuffer = NULL;
|
|
}
|
|
++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<BSTR> gcList;
|
|
std::list<BSTR> 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 computerColumn;
|
|
//Security Review:Correct Buffer size is passed.
|
|
ZeroMemory(&computerColumn, sizeof(ADS_SEARCH_COLUMN));
|
|
|
|
//
|
|
// Get the DN
|
|
//
|
|
hr = refServerSearch.GetColumn((PWSTR)g_szAttrServerReference, &computerColumn);
|
|
if (FAILED(hr))
|
|
{
|
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
|
L"Failed to get the server reference for a column: hr = 0x%x",
|
|
hr);
|
|
DEBUG_OUTPUT(LEVEL3_LOGGING,
|
|
L"continuing...");
|
|
hr = S_OK;
|
|
continue;
|
|
}
|
|
|
|
ADS_SEARCH_COLUMN serverColumn;
|
|
//Security Review:Correct Buffer size is passed.
|
|
ZeroMemory(&serverColumn, sizeof(ADS_SEARCH_COLUMN));
|
|
|
|
hr = refServerSearch.GetColumn((PWSTR)g_szAttrDistinguishedName, &serverColumn);
|
|
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 (computerColumn.dwNumValues == 1 &&
|
|
computerColumn.pADsValues &&
|
|
serverColumn.dwNumValues == 1 &&
|
|
serverColumn.pADsValues)
|
|
{
|
|
//
|
|
// Search the lists and determine if the DN exists in all the lists
|
|
//
|
|
bool bValidEntry = IsObjectValidInAllLists(computerColumn.pADsValues->DNString,
|
|
serverColumn.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(&computerColumn);
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
}
|
|
|
|
} while (false);
|
|
|
|
std::list<BSTR>::iterator gcItr;
|
|
for (gcItr = gcList.begin(); gcItr != gcList.end(); ++gcItr)
|
|
{
|
|
// Prefast will bark at this but it is correct. The container
|
|
// is filled with BSTRs which need to be freed using SysFreeString
|
|
SysFreeString(*gcItr);
|
|
}
|
|
|
|
std::list<BSTR>::iterator fsmoItr;
|
|
for (fsmoItr = fsmoList.begin(); fsmoItr != fsmoList.end(); ++fsmoItr)
|
|
{
|
|
// Prefast will bark at this but it is correct. The container
|
|
// is filled with BSTRs which need to be freed using SysFreeString
|
|
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);
|
|
|
|
|
|
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 )
|
|
{
|
|
LPWSTR pBuffer = NULL;
|
|
hr = GetStringFromADs(pValues,
|
|
ColumnData.dwADsType,
|
|
&pBuffer,
|
|
ppszAttributes[i]);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
DisplayList(ppszAttributes[i], pBuffer, bShowAttributes);
|
|
delete pBuffer;
|
|
pBuffer = NULL;
|
|
}
|
|
|
|
++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 )
|
|
{
|
|
LPWSTR pBuffer = NULL;
|
|
hr = GetStringFromADs(pValues,
|
|
ColumnData.dwADsType,
|
|
&pBuffer,
|
|
ppszAttributes[i]);
|
|
//
|
|
//In table format multiple values are shown separated by ;
|
|
//
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
strValue += pBuffer;
|
|
delete pBuffer;
|
|
pBuffer = NULL;
|
|
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);
|
|
|
|
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))
|
|
{
|
|
LPWSTR pBuffer = NULL;
|
|
hr = GetStringFromADs(ColumnData.pADsValues,
|
|
ColumnData.dwADsType,
|
|
&pBuffer,
|
|
ppszAttributes[0]);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
//Display the output enclosed in Double Quotes
|
|
CComBSTR strTemp;
|
|
strTemp = L"\"" ;
|
|
strTemp += pBuffer;
|
|
strTemp += L"\"";
|
|
DisplayOutput(strTemp);
|
|
delete pBuffer;
|
|
pBuffer = NULL;
|
|
}
|
|
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;
|
|
}
|
|
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)
|
|
{
|
|
WCHAR szBuffer[MAXSTR];
|
|
|
|
if(bAttrOnly)
|
|
{
|
|
//Security Review:Replace with strsafe api
|
|
//NTRAID#NTBUG9-573989-2002/03/12-hiteshr
|
|
//Its fine to truncate.
|
|
hr = StringCchPrintf(szBuffer,MAXSTR, L"%ws ", pszColumnName);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
DisplayOutputNoNewline(szBuffer);
|
|
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 )
|
|
{
|
|
LPWSTR pBuffer = NULL;
|
|
hr = GetStringFromADs(pValues,
|
|
ColumnData.dwADsType,
|
|
&pBuffer,
|
|
pszColumnName);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
DisplayList(pszColumnName, pBuffer);
|
|
delete pBuffer;
|
|
pBuffer = NULL;
|
|
}
|
|
++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
|
|
// [pszAttrName-IN]:Name of the attribute being formatted
|
|
// 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* ppBuffer,
|
|
IN PCWSTR pszAttrName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(!pValues || !ppBuffer)
|
|
{
|
|
ASSERT(FALSE);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if( dwADsType == ADSTYPE_INVALID )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
switch( dwADsType )
|
|
{
|
|
case ADSTYPE_DN_STRING :
|
|
{
|
|
CComBSTR sbstrOutputDN;
|
|
hr = GetOutputDN( &sbstrOutputDN, pValues->DNString );
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
UINT length = sbstrOutputDN.Length();
|
|
*ppBuffer = new WCHAR[length + 1];
|
|
if (!(*ppBuffer))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return hr;
|
|
}
|
|
//Security Review:Correct Buffer size is passed.
|
|
ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
|
|
//Security Review:wcsncpy will copy length char
|
|
//lenght + 1 is already set to zero so we are fine.
|
|
wcsncpy(*ppBuffer, (BSTR)sbstrOutputDN, length);
|
|
}
|
|
break;
|
|
|
|
case ADSTYPE_CASE_EXACT_STRING :
|
|
{
|
|
//Security Review:This is null terminated.
|
|
size_t length = wcslen(pValues->CaseExactString);
|
|
*ppBuffer = new WCHAR[length + 1];
|
|
if (!(*ppBuffer))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return hr;
|
|
}
|
|
//Security Review:Correct Buffer size is passed.
|
|
ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
|
|
//Security Review:wcsncpy will copy length char
|
|
//lenght + 1 is already set to zero so we are fine.
|
|
wcsncpy(*ppBuffer ,pValues->CaseExactString, length);
|
|
}
|
|
break;
|
|
|
|
case ADSTYPE_CASE_IGNORE_STRING:
|
|
{
|
|
|
|
size_t length = wcslen(pValues->CaseIgnoreString);
|
|
*ppBuffer = new WCHAR[length + 1];
|
|
if (!(*ppBuffer))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return hr;
|
|
}
|
|
//Security Review:Correct Buffer size is passed.
|
|
ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
|
|
//Security Review:wcsncpy will copy length char
|
|
//lenght + 1 is already set to zero so we are fine.
|
|
wcsncpy(*ppBuffer ,pValues->CaseIgnoreString, length);
|
|
}
|
|
break;
|
|
|
|
case ADSTYPE_PRINTABLE_STRING :
|
|
{
|
|
//Security Review:Null terminated string.
|
|
size_t length = wcslen(pValues->PrintableString);
|
|
*ppBuffer = new WCHAR[length + 1];
|
|
if (!(*ppBuffer))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return hr;
|
|
}
|
|
//Security Review:Correct Buffer size is passed.
|
|
ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
|
|
//Security Review:wcsncpy will copy length char
|
|
//lenght + 1 is already set to zero so we are fine.
|
|
wcsncpy(*ppBuffer ,pValues->PrintableString, length);
|
|
}
|
|
break;
|
|
|
|
case ADSTYPE_NUMERIC_STRING :
|
|
{
|
|
//Security Review:Null terminated string.
|
|
size_t length = wcslen(pValues->NumericString);
|
|
*ppBuffer = new WCHAR[length + 1];
|
|
if (!(*ppBuffer))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return hr;
|
|
}
|
|
//Security Review:Correct Buffer size is passed.
|
|
ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
|
|
//Security Review:wcsncpy will copy length char
|
|
//lenght + 1 is already set to zero so we are fine.
|
|
wcsncpy(*ppBuffer ,pValues->NumericString, length);
|
|
}
|
|
break;
|
|
|
|
case ADSTYPE_OBJECT_CLASS :
|
|
{
|
|
//Security Review:Null terminated string.
|
|
size_t length = wcslen(pValues->ClassName);
|
|
*ppBuffer = new WCHAR[length + 1];
|
|
if (!(*ppBuffer))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return hr;
|
|
}
|
|
//Security Review:Correct Buffer size is passed.
|
|
ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
|
|
//Security Review:wcsncpy will copy length char
|
|
//length + 1 is already set to zero so we are fine.
|
|
wcsncpy(*ppBuffer ,pValues->ClassName, length);
|
|
}
|
|
break;
|
|
|
|
case ADSTYPE_BOOLEAN :
|
|
{
|
|
size_t length = 0;
|
|
if (pValues->Boolean)
|
|
{
|
|
length = wcslen(L"TRUE");
|
|
*ppBuffer = new WCHAR[length + 1];
|
|
}
|
|
else
|
|
{
|
|
length = wcslen(L"FALSE");
|
|
*ppBuffer = new WCHAR[length + 1];
|
|
}
|
|
|
|
if (!(*ppBuffer))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return hr;
|
|
}
|
|
//Security Review:Correct Buffer size is passed.
|
|
ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
|
|
//Security Review:Replace with strsafe api
|
|
//NTRAID#NTBUG9-573989-2002/03/12-hiteshr
|
|
hr = StringCchPrintf(*ppBuffer ,length + 1,L"%s", ((DWORD)pValues->Boolean) ? L"TRUE" : L"FALSE");
|
|
if(FAILED(hr))
|
|
{
|
|
delete[] *ppBuffer;
|
|
*ppBuffer = NULL;
|
|
return hr;
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case ADSTYPE_INTEGER :
|
|
// Just allocate too much...
|
|
*ppBuffer = new WCHAR[MAXSTR];
|
|
if (!(*ppBuffer))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return hr;
|
|
}
|
|
//Security Review:Correct Buffer size is passed.
|
|
ZeroMemory(*ppBuffer, MAXSTR * sizeof(WCHAR));
|
|
|
|
//Security Review:Replace with strsafe api
|
|
//NTRAID#NTBUG9-573989-2002/03/12-hiteshr
|
|
hr = StringCchPrintf(*ppBuffer,MAXSTR ,L"%d", (DWORD) pValues->Integer);
|
|
if(FAILED(hr))
|
|
{
|
|
delete[] *ppBuffer;
|
|
*ppBuffer = NULL;
|
|
return hr;
|
|
}
|
|
break;
|
|
|
|
case ADSTYPE_OCTET_STRING :
|
|
{
|
|
// I am just going to limit the buffer to MAXSTR.
|
|
// It will be a rare occasion when someone wants
|
|
// to look at a binary string that is not a GUID
|
|
// or a SID.
|
|
*ppBuffer = new WCHAR[MAXSTR];
|
|
if (!(*ppBuffer))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return hr;
|
|
}
|
|
//Security Review:Correct Buffer size is passed.
|
|
ZeroMemory(*ppBuffer, MAXSTR * sizeof(WCHAR));
|
|
|
|
//
|
|
//Special case objectguid and objectsid and sid history attribute
|
|
//
|
|
//Security Review:pszAttrName is null terminated
|
|
if(pszAttrName && !_wcsicmp(pszAttrName, L"objectguid"))
|
|
{
|
|
GUID *pguid = (GUID*)pValues->OctetString.lpValue;
|
|
StringFromGUID2(*pguid,(LPOLESTR)*ppBuffer,MAXSTR);
|
|
break;
|
|
}
|
|
//Security Review:pszAttrName is null terminated
|
|
if(pszAttrName && (!_wcsicmp(pszAttrName, L"objectsid") || !_wcsicmp(pszAttrName, L"sidhistory")))
|
|
{
|
|
LPWSTR pszSid = NULL;
|
|
PSID pSid = (PSID)pValues->OctetString.lpValue;
|
|
if(ConvertSidToStringSid(pSid, &pszSid))
|
|
{
|
|
LocalFree(pszSid);
|
|
//Security Review:
|
|
//NTRAID#NTBUG9-574198-2002/03/12-hiteshr
|
|
//Its fine to truncate
|
|
hr = StringCchCopy(*ppBuffer,MAXSTR,pszSid);
|
|
if(FAILED(hr))
|
|
{
|
|
delete[] *ppBuffer;
|
|
*ppBuffer = NULL;
|
|
return hr;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
for ( DWORD idx=0; idx<pValues->OctetString.dwLength; idx++)
|
|
{
|
|
BYTE b = ((BYTE *)pValues->OctetString.lpValue)[idx];
|
|
//Security Review:Replace with strsafe api
|
|
//NTRAID#NTBUG9-573989-2002/03/12-hiteshr
|
|
WCHAR sOctet[128];
|
|
hr = StringCchPrintf(sOctet,128,L"0x%02x ", b);
|
|
if(FAILED(hr))
|
|
{
|
|
delete[] *ppBuffer;
|
|
*ppBuffer = NULL;
|
|
return hr;
|
|
}
|
|
|
|
if(FAILED(StringCchCat(*ppBuffer,MAXSTR,sOctet)))
|
|
{
|
|
//We are truncating the string. We will display only
|
|
//MAXSTR -1 chars.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ADSTYPE_LARGE_INTEGER :
|
|
{
|
|
CComBSTR strLarge;
|
|
LARGE_INTEGER li = pValues->LargeInteger;
|
|
litow(li, strLarge);
|
|
|
|
UINT length = strLarge.Length();
|
|
*ppBuffer = new WCHAR[length + 1];
|
|
if (!(*ppBuffer))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return hr;
|
|
}
|
|
//Security Review:Correct Buffer size is passed.
|
|
ZeroMemory(*ppBuffer, (length + 1) * sizeof(WCHAR));
|
|
//Security Review:wcsncpy will copy length char
|
|
//length + 1 is already set to zero so we are fine.
|
|
wcsncpy(*ppBuffer,strLarge,length);
|
|
}
|
|
break;
|
|
|
|
case ADSTYPE_UTC_TIME :
|
|
// The longest date can be 20 characters including the NULL
|
|
*ppBuffer = new WCHAR[20];
|
|
if (!(*ppBuffer))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return hr;
|
|
}
|
|
//Security Review:Correct Buffer size is passed.
|
|
ZeroMemory(*ppBuffer, sizeof(WCHAR) * 20);
|
|
|
|
//Security Review:Replace with strsafe api
|
|
//NTRAID#NTBUG9-573989-2002/03/12-hiteshr
|
|
hr = StringCchPrintf(*ppBuffer,20,
|
|
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
|
|
);
|
|
//This should never fail
|
|
if(FAILED(hr))
|
|
{
|
|
ASSERT(FALSE);
|
|
delete[] *ppBuffer;
|
|
*ppBuffer = NULL;
|
|
return hr;
|
|
}
|
|
break;
|
|
|
|
case ADSTYPE_NT_SECURITY_DESCRIPTOR: // I use the ACLEditor instead
|
|
{
|
|
if((pValues->SecurityDescriptor).lpValue)
|
|
{
|
|
LPWSTR pszSD = NULL;
|
|
ULONG lLen = 0;
|
|
if(ConvertSecurityDescriptorToStringSecurityDescriptor(
|
|
(PSECURITY_DESCRIPTOR )((pValues->SecurityDescriptor).lpValue),
|
|
SDDL_REVISION_1,
|
|
OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION|SACL_SECURITY_INFORMATION,
|
|
&pszSD,
|
|
&lLen))
|
|
{
|
|
if(pszSD)
|
|
{
|
|
//pszSD is null terminated.
|
|
size_t length = wcslen(pszSD);
|
|
*ppBuffer = new WCHAR[length + 1];
|
|
if (!(*ppBuffer))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return hr;
|
|
}
|
|
//Security Review:Correct Buffer size is passed.
|
|
ZeroMemory(*ppBuffer, sizeof(WCHAR) * (length+1));
|
|
//Security Review:wcsncpy will copy length char
|
|
//length + 1 is already set to zero so we are fine.
|
|
wcsncpy(*ppBuffer,pszSD,length);
|
|
LocalFree(pszSD);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default :
|
|
break;
|
|
}
|
|
return S_OK;
|
|
}
|