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.
1219 lines
39 KiB
1219 lines
39 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 2000
|
|
//
|
|
// File: dsget.cpp
|
|
//
|
|
// Contents: Defines the main function DSGET
|
|
// command line utility
|
|
//
|
|
// History: 13-Oct-2000 JeffJon Created
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "pch.h"
|
|
#include "cstrings.h"
|
|
#include "usage.h"
|
|
#include "gettable.h"
|
|
#include "query.h"
|
|
#include "resource.h"
|
|
#include "output.h"
|
|
|
|
|
|
//
|
|
// Forward Function Declarations
|
|
//
|
|
HRESULT DoGetValidation(PARG_RECORD pCommandArgs,
|
|
PDSGetObjectTableEntry pObjectEntry,
|
|
BOOL& bErrorShown);
|
|
|
|
HRESULT DoGet(PARG_RECORD pCommandArgs,
|
|
PDSGetObjectTableEntry pObjectEntry);
|
|
|
|
HRESULT GetAttributesToFetch(IN PARG_RECORD pCommandArgs,
|
|
IN PDSGetObjectTableEntry pObjectEntry,
|
|
OUT LPWSTR **ppszAttributes,
|
|
OUT DWORD * pCount);
|
|
VOID FreeAttributesToFetch( IN LPWSTR *ppszAttributes,
|
|
IN DWORD dwCount);
|
|
|
|
HRESULT SetRange(IN LPCWSTR pszAttrName,
|
|
IN DWORD dwRangeUBound,
|
|
OUT LPWSTR* pszAttrs);
|
|
|
|
// NTRAID#NTBUG9-717576-2002/10/10-JeffJon
|
|
// set this global so that we don't show the success message
|
|
// when displaying members of a group or memberof or manager
|
|
|
|
bool bDontDisplaySuccess = false;
|
|
|
|
//
|
|
//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))
|
|
break;
|
|
|
|
//Get CommandLine Input
|
|
DWORD _dwErr = GetCommandInput(&argc,&pToken);
|
|
hr = HRESULT_FROM_WIN32(_dwErr);
|
|
if(FAILED(hr))
|
|
break;
|
|
|
|
|
|
|
|
if(argc == 1)
|
|
{
|
|
//
|
|
// Display the error message and then break out of the false loop
|
|
//
|
|
DisplayMessage(USAGE_DSGET,TRUE);
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
if(argc == 2)
|
|
{
|
|
if(IsTokenHelpSwitch(pToken + 1))
|
|
{
|
|
hr = S_OK;
|
|
DisplayMessage(USAGE_DSGET,TRUE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Find which object table entry to use from
|
|
// the second command line argument
|
|
//
|
|
PDSGetObjectTableEntry pObjectEntry = NULL;
|
|
UINT idx = 0;
|
|
PWSTR pszObjectType = (pToken+1)->GetToken();
|
|
while (true)
|
|
{
|
|
pObjectEntry = g_DSObjectTable[idx++];
|
|
if (!pObjectEntry)
|
|
{
|
|
break;
|
|
}
|
|
//Security Review:Both are null terminated.
|
|
if (0 == _wcsicmp(pObjectEntry->pszCommandLineObjectType, pszObjectType))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!pObjectEntry)
|
|
{
|
|
//
|
|
// Display the error message and then break out of the false loop
|
|
//
|
|
DisplayMessage(USAGE_DSGET);
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Now that we have the correct table entry, merge the command line table
|
|
// for this object with the common commands
|
|
//
|
|
hr = MergeArgCommand(DSGET_COMMON_COMMANDS,
|
|
pObjectEntry->pParserTable,
|
|
&pNewCommandArgs);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
|
|
//
|
|
//Parse the Input
|
|
//
|
|
PARSE_ERROR Error;
|
|
if(!ParseCmd(g_pszDSCommandName,
|
|
pNewCommandArgs,
|
|
argc-1,
|
|
pToken+1,
|
|
pObjectEntry->nUsageID,
|
|
&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
|
|
//
|
|
// Do extra validation like switch dependency check etc.
|
|
//
|
|
BOOL bErrorShown = FALSE;
|
|
hr = DoGetValidation(pNewCommandArgs,
|
|
pObjectEntry,
|
|
bErrorShown);
|
|
if (FAILED(hr))
|
|
{
|
|
if (!bErrorShown)
|
|
{
|
|
DisplayErrorMessage(g_pszDSCommandName, 0, hr);
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Command line parsing succeeded
|
|
//
|
|
hr = DoGet(pNewCommandArgs,
|
|
pObjectEntry);
|
|
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;
|
|
}
|
|
|
|
|
|
//
|
|
//Display Failure or Success Message
|
|
//
|
|
// NTRAID#NTBUG9-717576-2002/10/10-JeffJon
|
|
// don't show the success message when displaying members
|
|
// of a group or memberof
|
|
|
|
if(SUCCEEDED(hr) && !bDontDisplaySuccess)
|
|
{
|
|
DisplaySuccessMessage(g_pszDSCommandName,
|
|
NULL);
|
|
}
|
|
|
|
//
|
|
// Uninitialize COM
|
|
//
|
|
CoUninitialize();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: DoGetValidation
|
|
//
|
|
// Synopsis: Checks to be sure that command line switches that are mutually
|
|
// exclusive are not both present and those that are dependent are
|
|
// both present, 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
|
|
// [bErrorShown - OUT] : this is set to true if the error is
|
|
// displayed within this function
|
|
//
|
|
// Returns: HRESULT : S_OK if everything succeeded
|
|
// E_INVALIDARG if the object entry wasn't found
|
|
//
|
|
// History: 13-Oct-2000 JeffJon Created
|
|
// 15-Jan-2002 JeffJon Added the bErrorShown out parameter
|
|
// and a special error message for server/domain
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
HRESULT DoGetValidation(IN PARG_RECORD pCommandArgs,
|
|
IN PDSGetObjectTableEntry pObjectEntry,
|
|
OUT BOOL& bErrorShown)
|
|
{
|
|
ENTER_FUNCTION_HR(MINIMAL_LOGGING, DoGetValidation, hr);
|
|
|
|
do // false loop
|
|
{
|
|
if (!pCommandArgs ||
|
|
!pObjectEntry)
|
|
{
|
|
ASSERT(pCommandArgs);
|
|
ASSERT(pObjectEntry);
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
// 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, 0, hr, IDS_NO_SERVER_AND_DOMAIN);
|
|
bErrorShown = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Check the object type specific switches
|
|
//
|
|
PWSTR pszObjectType = NULL;
|
|
if (!pCommandArgs[eCommObjectType].bDefined &&
|
|
!pCommandArgs[eCommObjectType].strValue)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
pszObjectType = pCommandArgs[eCommObjectType].strValue;
|
|
|
|
UINT nMemberOfIdx = 0;
|
|
UINT nExpandIdx = 0;
|
|
UINT nIdxLast = 0;
|
|
UINT nMembersIdx = 0;
|
|
bool bMembersDefined = false;
|
|
bool bMemberOfDefined = false;
|
|
UINT nPartIdx = 0;
|
|
bool bServerPartDefined = false;
|
|
bool bPartitionTopObjDefined = false;
|
|
bool bServerTopObjDefined = false;
|
|
|
|
//Security Review:Both are null terminated.
|
|
if (0 == _wcsicmp(g_pszUser, pszObjectType) )
|
|
{
|
|
nMemberOfIdx = eUserMemberOf;
|
|
nExpandIdx = eUserExpand;
|
|
nIdxLast = eUserLast;
|
|
|
|
if (pCommandArgs[eUserMemberOf].bDefined)
|
|
{
|
|
bMemberOfDefined = true;
|
|
}
|
|
//
|
|
// If nothing is defined, then define DN, SAMAccountName, and Description
|
|
//
|
|
bool bSomethingDefined = false;
|
|
for (UINT nIdx = eCommDN; nIdx <= eUserLast; nIdx++)
|
|
{
|
|
if (pCommandArgs[nIdx].bDefined)
|
|
{
|
|
bSomethingDefined = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bSomethingDefined)
|
|
{
|
|
pCommandArgs[eCommDN].bDefined = TRUE;
|
|
pCommandArgs[eCommDN].bValue = TRUE;
|
|
pCommandArgs[eUserSamID].bDefined = TRUE;
|
|
pCommandArgs[eUserSamID].bValue = TRUE;
|
|
pCommandArgs[eCommDescription].bDefined = TRUE;
|
|
pCommandArgs[eCommDescription].bValue = TRUE;
|
|
}
|
|
|
|
if (pCommandArgs[eUserManager].bDefined)
|
|
{
|
|
bDontDisplaySuccess = true;
|
|
}
|
|
}
|
|
//Security Review:Both are null terminated.
|
|
else if (0 == _wcsicmp(g_pszComputer, pszObjectType) )
|
|
{
|
|
nMemberOfIdx = eComputerMemberOf;
|
|
nExpandIdx = eComputerExpand;
|
|
nIdxLast = eComputerLast;
|
|
|
|
if (pCommandArgs[eComputerMemberOf].bDefined)
|
|
{
|
|
bMemberOfDefined = true;
|
|
}
|
|
|
|
//
|
|
// If nothing is defined, then define DN, and Description
|
|
//
|
|
bool bSomethingDefined = false;
|
|
for (UINT nIdx = eCommDN; nIdx <= eComputerLast; nIdx++)
|
|
{
|
|
if (pCommandArgs[nIdx].bDefined)
|
|
{
|
|
bSomethingDefined = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bSomethingDefined)
|
|
{
|
|
pCommandArgs[eCommDN].bDefined = TRUE;
|
|
pCommandArgs[eCommDN].bValue = TRUE;
|
|
pCommandArgs[eCommDescription].bDefined = TRUE;
|
|
pCommandArgs[eCommDescription].bValue = TRUE;
|
|
}
|
|
}
|
|
// Both are null terminated.
|
|
else if (0 == _wcsicmp(g_pszPartition, pszObjectType) )
|
|
{
|
|
if (pCommandArgs[ePartitionTopObjOwner].bDefined)
|
|
{
|
|
nPartIdx = ePartitionTopObjOwner;
|
|
nIdxLast = ePartitionLast;
|
|
bPartitionTopObjDefined = true;
|
|
}
|
|
}
|
|
// Both are null terminated.
|
|
else if (0 == _wcsicmp(g_pszServer, pszObjectType) )
|
|
{
|
|
if (pCommandArgs[eServerPart].bDefined)
|
|
{
|
|
nPartIdx = eServerPart;
|
|
nIdxLast = eServerLast;
|
|
bServerPartDefined = true;
|
|
}
|
|
else if(pCommandArgs[eServerTopObjOwner].bDefined)
|
|
{
|
|
nPartIdx = eServerTopObjOwner;
|
|
nIdxLast = eServerLast;
|
|
bServerTopObjDefined = true;
|
|
}
|
|
}
|
|
//Security Review:Both are null terminated.
|
|
else if (0 == _wcsicmp(g_pszGroup, pszObjectType) )
|
|
{
|
|
nMemberOfIdx = eGroupMemberOf;
|
|
nExpandIdx = eGroupExpand;
|
|
nIdxLast = eGroupLast;
|
|
nMembersIdx = eGroupMembers;
|
|
|
|
if (pCommandArgs[eGroupMemberOf].bDefined)
|
|
{
|
|
bMemberOfDefined = true;
|
|
}
|
|
|
|
if (pCommandArgs[eGroupMembers].bDefined)
|
|
{
|
|
bMembersDefined = true;
|
|
}
|
|
//
|
|
// If nothing is defined, then define DN, and Description
|
|
//
|
|
bool bSomethingDefined = false;
|
|
for (UINT nIdx = eCommDN; nIdx <= eGroupLast; nIdx++)
|
|
{
|
|
if (pCommandArgs[nIdx].bDefined)
|
|
{
|
|
bSomethingDefined = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bSomethingDefined)
|
|
{
|
|
pCommandArgs[eCommDN].bDefined = TRUE;
|
|
pCommandArgs[eCommDN].bValue = TRUE;
|
|
pCommandArgs[eCommDescription].bDefined = TRUE;
|
|
pCommandArgs[eCommDescription].bValue = TRUE;
|
|
}
|
|
}
|
|
//Security Review:Both are null terminated.
|
|
else if (0 == _wcsicmp(g_pszOU, pszObjectType))
|
|
{
|
|
//
|
|
// If nothing is defined, then define DN, and Description
|
|
//
|
|
bool bSomethingDefined = false;
|
|
for (UINT nIdx = eCommDN; nIdx <= eCommDescription; nIdx++)
|
|
{
|
|
if (pCommandArgs[nIdx].bDefined)
|
|
{
|
|
bSomethingDefined = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bSomethingDefined)
|
|
{
|
|
pCommandArgs[eCommDN].bDefined = TRUE;
|
|
pCommandArgs[eCommDN].bValue = TRUE;
|
|
pCommandArgs[eCommDescription].bDefined = TRUE;
|
|
pCommandArgs[eCommDescription].bValue = TRUE;
|
|
}
|
|
}
|
|
//Security Review:Both are null terminated.
|
|
else if(0 == _wcsicmp(g_pszContact, pszObjectType))
|
|
{
|
|
//
|
|
// If nothing is defined, then define DN, and Description
|
|
//
|
|
bool bSomethingDefined = false;
|
|
for (UINT nIdx = eCommDN; nIdx <= eContactLast; nIdx++)
|
|
{
|
|
if (pCommandArgs[nIdx].bDefined)
|
|
{
|
|
bSomethingDefined = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bSomethingDefined)
|
|
{
|
|
pCommandArgs[eCommDN].bDefined = TRUE;
|
|
pCommandArgs[eCommDN].bValue = TRUE;
|
|
pCommandArgs[eCommDescription].bDefined = TRUE;
|
|
pCommandArgs[eCommDescription].bValue = TRUE;
|
|
}
|
|
}
|
|
//Security Review:Both are null terminated.
|
|
else if(0 == _wcsicmp(g_pszServer, pszObjectType))
|
|
{
|
|
//
|
|
// If nothing is defined, then define DN, and Description
|
|
//
|
|
bool bSomethingDefined = false;
|
|
for (UINT nIdx = eCommDN; nIdx <= eServerLast; nIdx++)
|
|
{
|
|
if (pCommandArgs[nIdx].bDefined)
|
|
{
|
|
bSomethingDefined = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bSomethingDefined)
|
|
{
|
|
pCommandArgs[eCommDN].bDefined = TRUE;
|
|
pCommandArgs[eCommDN].bValue = TRUE;
|
|
pCommandArgs[eServerDnsName].bDefined = TRUE;
|
|
pCommandArgs[eServerDnsName].bValue = TRUE;
|
|
}
|
|
}
|
|
//Security Review:Both are null terminated.
|
|
else if(0 == _wcsicmp(g_pszSite, pszObjectType))
|
|
{
|
|
//
|
|
// If nothing is defined, then define DN, and Description
|
|
//
|
|
bool bSomethingDefined = false;
|
|
for (UINT nIdx = eCommDN; nIdx <= eSiteLast; nIdx++)
|
|
{
|
|
if (pCommandArgs[nIdx].bDefined)
|
|
{
|
|
bSomethingDefined = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bSomethingDefined)
|
|
{
|
|
pCommandArgs[eCommDN].bDefined = TRUE;
|
|
pCommandArgs[eCommDN].bValue = TRUE;
|
|
pCommandArgs[eCommDescription].bDefined = TRUE;
|
|
pCommandArgs[eCommDescription].bValue = TRUE;
|
|
}
|
|
}
|
|
//Security Review:Both are null terminated.
|
|
else if(0 == _wcsicmp(g_pszSubnet, pszObjectType))
|
|
{
|
|
//
|
|
// If nothing is defined, then define DN, and Description
|
|
//
|
|
bool bSomethingDefined = false;
|
|
for (UINT nIdx = eCommDN; nIdx <= eSubnetLast; nIdx++)
|
|
{
|
|
if (pCommandArgs[nIdx].bDefined)
|
|
{
|
|
bSomethingDefined = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bSomethingDefined)
|
|
{
|
|
pCommandArgs[eCommDN].bDefined = TRUE;
|
|
pCommandArgs[eCommDN].bValue = TRUE;
|
|
pCommandArgs[eCommDescription].bDefined = TRUE;
|
|
pCommandArgs[eCommDescription].bValue = TRUE;
|
|
pCommandArgs[eSubnetSite].bDefined = TRUE;
|
|
pCommandArgs[eSubnetSite].bValue = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if the -members or the -memberof switch is defined
|
|
//
|
|
if (bMemberOfDefined ||
|
|
bMembersDefined)
|
|
{
|
|
// NTRAID#NTBUG9-717576-2002/10/10-JeffJon
|
|
// set this global so that we don't show the success message
|
|
// when displaying members of a group or memberof
|
|
|
|
bDontDisplaySuccess = true;
|
|
|
|
// 476206-2002/04/23-JonN
|
|
if (bMemberOfDefined && bMembersDefined)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If either the -members or -memberof switch is defined,
|
|
// no other switches may be defined
|
|
//
|
|
for (UINT nIdx = eCommDN; nIdx < nIdxLast; nIdx++)
|
|
{
|
|
// 476206-2002/04/23-JonN
|
|
if (pCommandArgs[nIdx].bDefined &&
|
|
nIdx != nMemberOfIdx &&
|
|
nIdx != nMembersIdx &&
|
|
nIdx != nExpandIdx)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// MemberOf should always be seen in list view
|
|
//
|
|
pCommandArgs[eCommList].bDefined = TRUE;
|
|
pCommandArgs[eCommList].bValue = TRUE;
|
|
}
|
|
//
|
|
// if the [server -part], [partition -topobjowner]
|
|
// or [server -topobjowner] switch is defined
|
|
//
|
|
if (bServerPartDefined || bPartitionTopObjDefined || bServerTopObjDefined)
|
|
{
|
|
// Server and Partition are mutually exclusive objects types so
|
|
// the parser will ensure that these two flags can never be true
|
|
// at the same time. The following check ensures that both values
|
|
// weren't passed at the same time
|
|
if (bServerPartDefined && bServerTopObjDefined)
|
|
{
|
|
DEBUG_OUTPUT(MINIMAL_LOGGING,
|
|
L"Server -part and server -topobjowner can not be defined at the same time");
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
// If one of these switches is defined,
|
|
// then no other switches may be defined
|
|
for (UINT nIdx = eCommDN; nIdx < nIdxLast; nIdx++)
|
|
{
|
|
if (pCommandArgs[nIdx].bDefined && nIdx != nPartIdx)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// should always be seen in a list view
|
|
//
|
|
pCommandArgs[eCommList].bDefined = TRUE;
|
|
pCommandArgs[eCommList].bValue = TRUE;
|
|
}
|
|
|
|
} while (false);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: DoGet
|
|
//
|
|
// Synopsis: Does the get
|
|
// 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
|
|
//
|
|
// 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: 13-Oct-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
HRESULT DoGet(PARG_RECORD pCommandArgs,
|
|
PDSGetObjectTableEntry pObjectEntry)
|
|
{
|
|
ENTER_FUNCTION_HR(MINIMAL_LOGGING, DoGet, hr);
|
|
|
|
PWSTR pszPartitionDN = NULL;
|
|
|
|
do // false loop
|
|
{
|
|
if (!pCommandArgs ||
|
|
!pObjectEntry)
|
|
{
|
|
ASSERT(pCommandArgs);
|
|
ASSERT(pObjectEntry);
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// The DNs or Names should be given as a \0 separated list
|
|
// So parse it and loop through each object
|
|
//
|
|
UINT nStrings = 0;
|
|
PWSTR* ppszArray = NULL;
|
|
ParseNullSeparatedString(pCommandArgs[eCommObjectDNorName].strValue,
|
|
&ppszArray,
|
|
&nStrings);
|
|
if (nStrings < 1 ||
|
|
!ppszArray)
|
|
{
|
|
//
|
|
// Display an error message and then fail
|
|
//
|
|
hr = E_INVALIDARG;
|
|
DisplayErrorMessage(g_pszDSCommandName, 0, hr);
|
|
break;
|
|
}
|
|
|
|
// Make sure all the DNs actually have DN syntax
|
|
|
|
bool bContinue = pCommandArgs[eCommContinue].bDefined &&
|
|
pCommandArgs[eCommContinue].bValue;
|
|
|
|
UINT nValidDNs = ValidateDNSyntax(ppszArray, nStrings);
|
|
if (nValidDNs < nStrings && !bContinue)
|
|
{
|
|
hr = E_ADS_BAD_PATHNAME;
|
|
DisplayErrorMessage(g_pszDSCommandName, 0, hr);
|
|
break;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
//
|
|
// 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))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Create the formatting object and initialize it
|
|
//
|
|
CFormatInfo formatInfo;
|
|
hr = formatInfo.Initialize(nStrings,
|
|
pCommandArgs[eCommList].bDefined != 0,
|
|
pCommandArgs[eCommQuiet].bDefined != 0);
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Loop through each of the objects
|
|
//
|
|
for (UINT nNameIdx = 0; nNameIdx < nStrings; nNameIdx++)
|
|
{
|
|
//
|
|
// Use a false do loop here so that we can break on an
|
|
// error but still have the chance to determine if we
|
|
// should continue the for loop if the -c option was provided
|
|
//
|
|
bool fDisplayedMessage = false; // 662519-2002/07/11-JonN double-display
|
|
do // false loop
|
|
{
|
|
|
|
PWSTR pszObjectDN = ppszArray[nNameIdx];
|
|
if (!pszObjectDN)
|
|
{
|
|
//
|
|
// Display an error message and then fail
|
|
//
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
// If partition object then look at first DN and then munge it
|
|
if(0 == lstrcmpi(pObjectEntry->pszCommandLineObjectType, g_pszPartition))
|
|
{
|
|
// Validate the partition and get the DN to the NTDS Quotas Container
|
|
hr = GetQuotaContainerDN(basePathsInfo, credentialObject,
|
|
pszObjectDN, &pszPartitionDN);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
DisplayErrorMessage(g_pszDSCommandName,
|
|
NULL,
|
|
hr,
|
|
IDS_ERRMSG_NO_QUOTAS_CONTAINER);
|
|
fDisplayedMessage = true;
|
|
break;
|
|
}
|
|
|
|
// Replace the object pointer with the new partition container DN
|
|
pszObjectDN = pszPartitionDN;
|
|
}
|
|
|
|
DEBUG_OUTPUT(MINIMAL_LOGGING, L"Object DN = %s", pszObjectDN);
|
|
|
|
CComBSTR sbstrObjectPath;
|
|
basePathsInfo.ComposePathFromDN(pszObjectDN, sbstrObjectPath);
|
|
|
|
CComPtr<IDirectoryObject> spObject;
|
|
hr = DSCmdOpenObject(credentialObject,
|
|
sbstrObjectPath,
|
|
IID_IDirectoryObject,
|
|
(void**)&spObject,
|
|
true);
|
|
if(FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// 602981-2002/04/25-JonN check object class
|
|
CComQIPtr<IADs> spADs(spObject);
|
|
if (!spADs)
|
|
{
|
|
ASSERT(spADs);
|
|
hr = E_INVALIDARG;
|
|
DisplayErrorMessage(g_pszDSCommandName,
|
|
pszObjectDN,
|
|
hr);
|
|
fDisplayedMessage = true; // 662519-2002/07/11-JonN double-display
|
|
break;
|
|
}
|
|
CComBSTR sbstrClass;
|
|
hr = spADs->get_Class( &sbstrClass );
|
|
if (FAILED(hr))
|
|
{
|
|
DEBUG_OUTPUT(MINIMAL_LOGGING,
|
|
L"get_Class failed: hr = 0x%x",
|
|
hr);
|
|
DisplayErrorMessage(g_pszDSCommandName,
|
|
pszObjectDN,
|
|
hr);
|
|
fDisplayedMessage = true; // 662519-2002/07/11-JonN double-display
|
|
break;
|
|
}
|
|
if (_wcsicmp(sbstrClass, pObjectEntry->pszObjectClass)
|
|
&& ( _wcsicmp(pObjectEntry->pszObjectClass,L"user")
|
|
|| _wcsicmp(sbstrClass,L"inetorgperson"))
|
|
// 662519-2002/07/11-JonN fix OU bug
|
|
&& ( _wcsicmp(pObjectEntry->pszObjectClass,L"ou")
|
|
|| _wcsicmp(sbstrClass,L"organizationalUnit"))
|
|
)
|
|
{
|
|
//
|
|
// Display error message and return
|
|
//
|
|
DEBUG_OUTPUT(MINIMAL_LOGGING, L"Command line type does not match object class");
|
|
DEBUG_OUTPUT(MINIMAL_LOGGING, L"command line type = %s", pCommandArgs[eCommObjectType].strValue);
|
|
DEBUG_OUTPUT(MINIMAL_LOGGING, L"object class = %s", sbstrClass);
|
|
|
|
DisplayErrorMessage(g_pszDSCommandName,
|
|
pszObjectDN,
|
|
hr,
|
|
IDS_ERRMSG_CLASS_NOT_EQUAL);
|
|
hr = E_INVALIDARG;
|
|
fDisplayedMessage = true; // 662519-2002/07/11-JonN double-display
|
|
break;
|
|
}
|
|
|
|
//
|
|
//Get the attributes to fetch
|
|
//
|
|
LPWSTR *ppszAttributes = NULL;
|
|
DWORD dwCountAttr = 0;
|
|
hr = GetAttributesToFetch(pCommandArgs,
|
|
pObjectEntry,
|
|
&ppszAttributes,
|
|
&dwCountAttr);
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
|
|
DEBUG_OUTPUT(MINIMAL_LOGGING,
|
|
L"Calling GetObjectAttributes for %d attributes.",
|
|
dwCountAttr);
|
|
|
|
DWORD dwAttrsReturned = 0;
|
|
PADS_ATTR_INFO pAttrInfo = NULL;
|
|
if(dwCountAttr > 0)
|
|
{
|
|
hr = spObject->GetObjectAttributes(ppszAttributes,
|
|
dwCountAttr,
|
|
&pAttrInfo,
|
|
&dwAttrsReturned);
|
|
if(FAILED(hr))
|
|
{
|
|
DEBUG_OUTPUT(MINIMAL_LOGGING,
|
|
L"GetObjectAttributes failed: hr = 0x%x",
|
|
hr);
|
|
FreeAttributesToFetch(ppszAttributes,dwCountAttr);
|
|
break;
|
|
}
|
|
DEBUG_OUTPUT(LEVEL5_LOGGING,
|
|
L"GetObjectAttributes succeeded: dwAttrsReturned = %d",
|
|
dwAttrsReturned);
|
|
}
|
|
//
|
|
// NOTE: there may be other items to display that are not
|
|
// part of the attributes fetched
|
|
//
|
|
/*
|
|
if (dwAttrsReturned == 0 || !pAttrInfo)
|
|
{
|
|
break;
|
|
}
|
|
*/
|
|
//
|
|
// Output the result of search
|
|
//
|
|
hr = DsGetOutputValuesList(pszObjectDN,
|
|
basePathsInfo,
|
|
credentialObject,
|
|
pCommandArgs,
|
|
pObjectEntry,
|
|
dwAttrsReturned,
|
|
pAttrInfo,
|
|
spObject,
|
|
formatInfo);
|
|
} while (false);
|
|
|
|
//
|
|
// If there was a failure and the -c (continue) flag wasn't given
|
|
// then stop processing names
|
|
//
|
|
if (FAILED(hr))
|
|
{
|
|
if (!fDisplayedMessage) // 662519-2002/07/11-JonN double-display
|
|
{
|
|
DisplayErrorMessage(g_pszDSCommandName, 0, hr);
|
|
}
|
|
if (!pCommandArgs[eCommContinue].bDefined)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If we alloc'd a partition DN, then free it
|
|
if(pszPartitionDN)
|
|
{
|
|
LocalFree(pszPartitionDN);
|
|
pszPartitionDN = NULL;
|
|
}
|
|
} // Names for loop
|
|
|
|
//
|
|
// Now display the results
|
|
//
|
|
formatInfo.Display();
|
|
|
|
} while (false);
|
|
|
|
// If we alloc'd a partition DN, then free it
|
|
if(pszPartitionDN)
|
|
{
|
|
LocalFree(pszPartitionDN);
|
|
pszPartitionDN = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: GetAttributesToFetch
|
|
//
|
|
// Synopsis: Make an array of attributes to fetch.
|
|
// Arguments: [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 PARG_RECORD pCommandArgs,
|
|
IN PDSGetObjectTableEntry pObjectEntry,
|
|
OUT LPWSTR **ppszAttributes,
|
|
OUT DWORD * pCount)
|
|
{
|
|
ENTER_FUNCTION_HR(LEVEL8_LOGGING, GetAttributesToFetch, hr);
|
|
|
|
do // false loop
|
|
{
|
|
|
|
if(!pCommandArgs ||
|
|
!pObjectEntry)
|
|
{
|
|
ASSERT(pCommandArgs);
|
|
ASSERT(pObjectEntry);
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
LPWSTR *ppszAttr = (LPWSTR *)LocalAlloc(LPTR,pObjectEntry->dwAttributeCount *sizeof(LPCTSTR));
|
|
if(!ppszAttr)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Loop through the attributes that are needed and copy
|
|
// them into the array.
|
|
//
|
|
// REVIEW_JEFFON : what if there are duplicates?
|
|
//
|
|
DEBUG_OUTPUT(FULL_LOGGING, L"Adding attributes to list:");
|
|
|
|
DWORD dwAttrCount = 0;
|
|
for(DWORD i = 0; i < pObjectEntry->dwAttributeCount; i++)
|
|
{
|
|
if (pObjectEntry->pAttributeTable[i])
|
|
{
|
|
UINT nCommandEntry = pObjectEntry->pAttributeTable[i]->nAttributeID;
|
|
if (pCommandArgs[nCommandEntry].bDefined)
|
|
{
|
|
LPWSTR pszAttr = pObjectEntry->pAttributeTable[i]->pszName;
|
|
if (pszAttr)
|
|
{
|
|
// 702724 ronmart 2002/09/18 If looking for top
|
|
// object owner then specify a range
|
|
if(0 == lstrcmpi(pObjectEntry->pszCommandLineObjectType, g_pszPartition)
|
|
&& pCommandArgs[ePartitionTopObjOwner].bDefined)
|
|
{
|
|
hr = SetRange(pszAttr, pCommandArgs[ePartitionTopObjOwner].nValue,
|
|
ppszAttr+dwAttrCount);
|
|
}
|
|
else if(0 == lstrcmpi(pObjectEntry->pszCommandLineObjectType, g_pszServer)
|
|
&& pCommandArgs[eServerTopObjOwner].bDefined)
|
|
{
|
|
hr = SetRange(pszAttr, pCommandArgs[eServerTopObjOwner].nValue,
|
|
ppszAttr+dwAttrCount);
|
|
}
|
|
// NTRAID#NTBUG9-765440-2003/01/17-ronmart-dsget user/group -qlimit -qused
|
|
// not returning values
|
|
// These do not appear on the user object so GetObjectAttributes
|
|
// will fail if these are included in the fetch array
|
|
else if(0 == lstrcmpi(pszAttr,g_pszAttrmsDSQuotaEffective) ||
|
|
0 == lstrcmpi(pszAttr,g_pszAttrmsDSQuotaUsed))
|
|
{
|
|
continue; // ignore
|
|
}
|
|
else
|
|
{
|
|
hr = LocalCopyString(ppszAttr+dwAttrCount, pszAttr);
|
|
}
|
|
if (FAILED(hr))
|
|
{
|
|
LocalFree(ppszAttr);
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
// 702724 ronmart 2002/09/18 Use the array value that has
|
|
// be created (and possibly modified to include the range)
|
|
// rather than the attribute name when spewing attrs
|
|
DEBUG_OUTPUT(FULL_LOGGING, L"\t%s", *(ppszAttr+dwAttrCount));
|
|
dwAttrCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
DEBUG_OUTPUT(FULL_LOGGING, L"Done adding %d attributes to list.", dwAttrCount);
|
|
}
|
|
|
|
*ppszAttributes = ppszAttr;
|
|
*pCount = dwAttrCount;
|
|
} while (false);
|
|
|
|
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: SetRange
|
|
//
|
|
// Synopsis: Set's the range qualifier for an attribute
|
|
// Arguments: [pszAttrName - IN] : attribute name to append the range to
|
|
// [dwRangeUBound - IN]: one based upper bound of the range
|
|
// [pszAttrs - OUT] : attr array entry that should be allocated
|
|
//
|
|
// 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: 18-Sep-2002 ronmart Created for 702724 fix
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
HRESULT SetRange(IN LPCWSTR pszAttrName,
|
|
IN DWORD dwRangeUBound,
|
|
OUT LPWSTR* pszAttrs)
|
|
{
|
|
ENTER_FUNCTION_HR(MINIMAL_LOGGING, SetRange, hr);
|
|
|
|
do // false loop
|
|
{
|
|
// Validate params
|
|
if(!pszAttrName ||
|
|
!pszAttrs )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
// Get the size of the base attribute name
|
|
size_t cbSize = lstrlen(pszAttrName);
|
|
if(cbSize == 0)
|
|
break;
|
|
cbSize += 64; // leave room for null term, range string and int value
|
|
cbSize *= sizeof(WCHAR);
|
|
|
|
// Allocate the buffer to hold the range
|
|
*pszAttrs = (LPWSTR) LocalAlloc(LPTR, cbSize);
|
|
if(NULL == *pszAttrs)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
// If zero then show all
|
|
if(dwRangeUBound == 0)
|
|
{
|
|
hr = StringCbPrintf(*pszAttrs, cbSize, L"%s%s=0-*", pszAttrName, g_pszRange);
|
|
}
|
|
// Otherwise show the value specified
|
|
else
|
|
{
|
|
hr = StringCbPrintf(*pszAttrs, cbSize, L"%s%s=0-%d",
|
|
pszAttrName, // Name of the attribute to append the range to
|
|
g_pszRange, // The range qualifer ;range
|
|
dwRangeUBound - 1); // Range is 0 based, and input is 1 based so adjust
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
break;
|
|
|
|
} while(false);
|
|
return hr;
|
|
}
|
|
|