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

533 lines
16 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000
//
// File: querybld.cpp
//
// Contents: Contains implementatin of functions to build query.
//
// History: 24-Sep-2000 Hiteshr Created
//
//
//--------------------------------------------------------------------------
#include "pch.h"
#include "cstrings.h"
#include "querytable.h"
#include "usage.h"
#include "querybld.h"
#include <lmaccess.h> // UF_ACCOUNTDISABLE and UF_DONT_EXPIRE_PASSWD
#include <ntldap.h> // LDAP_MATCHING_RULE_BIT_AND_W
static const LPWSTR g_szUserAccountCtrlQuery = L"(userAccountControl:" LDAP_MATCHING_RULE_BIT_AND_W L":=%u)";
static const LPWSTR g_szServerIsGCQuery = L"(&(objectCategory=NTDS-DSA)(options:" LDAP_MATCHING_RULE_BIT_AND_W L":=1))";
static const LPWSTR g_szCommonQueryFormat= L"(%s=%s)";
//+--------------------------------------------------------------------------
//
// Function: LdapEscape
//
// Synopsis: Escape the characters in *[pszInput] as required by
// RFC 2254.
//
// Arguments: [pszInput] - string to escape
//
// History: 06-23-2000 DavidMun Created
//
// Notes: RFC 2254
//
// If a value should contain any of the following characters
//
// Character ASCII value
// ---------------------------
// * 0x2a
// ( 0x28
// ) 0x29
// \ 0x5c
// NUL 0x00
//
// the character must be encoded as the backslash '\'
// character (ASCII 0x5c) followed by the two hexadecimal
// digits representing the ASCII value of the encoded
// character. The case of the two hexadecimal digits is not
// significant.
//
//---------------------------------------------------------------------------
bool
LdapEscape(IN LPCWSTR pszInput, OUT CComBSTR& strFilter)
{
if(!pszInput)
return FALSE;
int iLen = (int)wcslen(pszInput);
for( int i = 0; i < iLen; ++i)
{
switch (*(pszInput+i))
{
case L'(':
strFilter += L"\\28";
break;
case L')':
strFilter += L"\\29";
break;
case L'\\':
if( i + 1 < iLen )
{
// \\ is treated as '\'
switch (*(pszInput+i + 1))
{
case L'\\':
strFilter += L"\\5c";
i++;
break;
// \* is treated as '*'
case L'*':
strFilter += L"\\2a";
i++;
break;
default:
// \X is treated \X only
strFilter += L"\\5c";
break;
}
}
else
strFilter += L"\\5c";
break;
default:
strFilter.Append(pszInput+i,1);
break;
}
}
return TRUE;
}
HRESULT MakeQuery(IN LPCWSTR pszAttrName,
IN LPCWSTR pszCommandLineFilter,
OUT CComBSTR& strFilter)
{
ENTER_FUNCTION_HR(LEVEL3_LOGGING, MakeQuery, hr);
if(!pszAttrName || !pszCommandLineFilter)
{
ASSERT(FALSE);
hr = E_INVALIDARG;
return hr;
}
CComBSTR strEscapedCLFilter;
LdapEscape(pszCommandLineFilter,strEscapedCLFilter);
strFilter = L"(";
strFilter += pszAttrName;
strFilter += L"=";
strFilter += strEscapedCLFilter;
strFilter += L")";
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: CommonFilterFunc
//
// Synopsis: This function takes the input filter from the commandline
// and converts it into ldapfilter.
// For ex -user (ab* | bc*) is converted to |(cn=ab*)(cn=bc*)
// The pEntry->pszName given the attribute name to use in
// filter( cn in above example).
//
// Arguments: [pRecord - IN] : the command line argument structure used
// to retrieve the filter entered by user
// [pObjectEntry - IN] : pointer to the DSQUERY_ATTR_TABLE_ENTRY
// which has info on attribute corresponding
// switch in pRecord
// [pVoid - IN] :Not used.
// [strFilter - OUT] :Contains the output filter.
// 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 CommonFilterFunc(IN DSQUERY_ATTR_TABLE_ENTRY *pEntry,
IN ARG_RECORD* pRecord,
IN PVOID ,
OUT CComBSTR& strFilter)
{
ENTER_FUNCTION_HR(LEVEL3_LOGGING, CommonFilterFunc, hr);
//validate input
if( !pEntry || !pRecord
//validate DSQUERY_ATTR_TABLE_ENTRY entry
|| !pEntry->pszName || !pEntry->nAttributeID
//validate pRecord
|| !pRecord->bDefined || !pRecord->strValue)
{
ASSERT(FALSE);
hr = E_INVALIDARG;
return hr;
}
//Make Query
hr = MakeQuery(pEntry->pszName,
pRecord->strValue,
strFilter);
DEBUG_OUTPUT(LEVEL3_LOGGING, L"filter = %s", strFilter);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: StarFilterFunc
//
// Synopsis: Filter Function for dsquery *. It returns the value of
// -filter flag.
//
// Arguments: [pRecord - IN] : the command line argument structure used
// to retrieve the filter entered by user
// [pObjectEntry - IN] : pointer to the DSQUERY_ATTR_TABLE_ENTRY
// which has info on attribute corresponding
// switch in pRecord
// [pVoid - IN] :Not used.
// [strFilter - OUT] :Contains the output filter.
// 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 StarFilterFunc(IN DSQUERY_ATTR_TABLE_ENTRY *pEntry,
IN ARG_RECORD* pRecord,
IN PVOID ,
OUT CComBSTR& strFilter)
{
ENTER_FUNCTION_HR(LEVEL3_LOGGING, StarFilterFunc, hr);
//validate input
if(!pEntry || !pRecord
//validate DSQUERY_ATTR_TABLE_ENTRY entry
|| !pEntry->nAttributeID
//validate pRecord
|| !pRecord->bDefined || !pRecord->strValue)
{
ASSERT(FALSE);
hr = E_INVALIDARG;
return hr;
}
strFilter = pRecord->strValue;
DEBUG_OUTPUT(LEVEL3_LOGGING, L"filter = %s", strFilter);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: InactiveFilterFunc
//
// Synopsis: Filter Function for account disabled query.
//
// Arguments: [pRecord - IN] : Not Used
// [pObjectEntry - IN] : Not Used
// [pVoid - IN] :Not used.
// [strFilter - OUT] :Contains the output filter.
// 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 InactiveFilterFunc(IN DSQUERY_ATTR_TABLE_ENTRY *pEntry,
IN ARG_RECORD* pRecord,
IN PVOID ,
OUT CComBSTR& strFilter)
{
ENTER_FUNCTION_HR(LEVEL3_LOGGING, InactiveFilterFunc, hr);
if( !pEntry || !pRecord || !pRecord->bDefined )
{
hr = E_INVALIDARG;
return hr;
}
//
//Unit at commandline is Week
//
int nDays = pRecord->nValue * 7;
FILETIME ftCurrent;
::GetSystemTimeAsFileTime(&ftCurrent);
LARGE_INTEGER li;
li.LowPart = ftCurrent.dwLowDateTime;
li.HighPart = ftCurrent.dwHighDateTime;
//
//Get the number of days since the reference time
//
int nDaysSince1600 = (int)(li.QuadPart/(((LONGLONG) (24 * 60) * 60) * 10000000));
if(nDaysSince1600 < nDays)
{
hr = E_INVALIDARG;
return hr;
}
li.QuadPart -= ((((LONGLONG)nDays * 24) * 60) * 60) * 10000000;
CComBSTR strTime;
litow(li, strTime);
WCHAR buffer[256];
wsprintf(buffer,L"(lastLogonTimestamp<=%s)",strTime);
strFilter = buffer;
DEBUG_OUTPUT(LEVEL3_LOGGING, L"filter = %s", strFilter);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: StalepwdFilterFunc
//
// Synopsis: Filter Function for Stale Password query.
//
// Arguments: [pRecord - IN] : Not Used
// [pObjectEntry - IN] : Not Used
// [pVoid - IN] :Not used.
// [strFilter - OUT] :Contains the output filter.
// 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 StalepwdFilterFunc(IN DSQUERY_ATTR_TABLE_ENTRY *pEntry,
IN ARG_RECORD* pRecord,
IN PVOID ,
OUT CComBSTR& strFilter)
{
ENTER_FUNCTION_HR(LEVEL3_LOGGING, StalepwdFilterFunc, hr);
if( !pEntry || !pRecord || !pRecord->bDefined )
{
hr = E_INVALIDARG;
return hr;
}
int nDays = pRecord->nValue;
FILETIME ftCurrent;
::GetSystemTimeAsFileTime(&ftCurrent);
LARGE_INTEGER li;
li.LowPart = ftCurrent.dwLowDateTime;
li.HighPart = ftCurrent.dwHighDateTime;
//
//Get the number of days since the reference time
//
int nDaysSince1600 = (int)(li.QuadPart/(((LONGLONG) (24 * 60) * 60) * 10000000));
if(nDaysSince1600 < nDays)
{
hr = E_INVALIDARG;
return hr;
}
li.QuadPart -= ((((ULONGLONG)nDays * 24) * 60) * 60) * 10000000;
CComBSTR strTime;
litow(li, strTime);
WCHAR buffer[256];
wsprintf(buffer,L"(pwdLastSet<=%s)",strTime);
strFilter = buffer;
DEBUG_OUTPUT(LEVEL3_LOGGING, L"filter = %s", strFilter);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: DisabledFilterFunc
//
// Synopsis: Filter Function for account disabled query.
//
// Arguments: [pRecord - IN] : Not Used
// [pObjectEntry - IN] : Not Used
// [pVoid - IN] :Not used.
// [strFilter - OUT] :Contains the output filter.
// 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 DisabledFilterFunc(IN DSQUERY_ATTR_TABLE_ENTRY *,
IN ARG_RECORD* ,
IN PVOID ,
OUT CComBSTR& strFilter)
{
ENTER_FUNCTION_HR(LEVEL3_LOGGING, DisabledFilterFunc, hr);
WCHAR buffer[256]; //This is long enough
wsprintf(buffer, g_szUserAccountCtrlQuery,UF_ACCOUNTDISABLE);
strFilter = buffer;
DEBUG_OUTPUT(LEVEL3_LOGGING, L"filter = %s", strFilter);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: SubnetSiteFilterFunc
//
// Synopsis: Filter Function for -site switch in dsquery subnet.
//
// Arguments: [pEntry - IN] : Not Used
// [pRecord - IN] : Command Line value supplied by user
// [pVoid - IN] : suffix for the siteobject attribute.
// [strFilter - OUT] :Contains the output filter.
// Returns: HRESULT : S_OK if everything succeeded
//
// History: 24-April-2001 hiteshr Created
//
//---------------------------------------------------------------------------
HRESULT SubnetSiteFilterFunc(IN DSQUERY_ATTR_TABLE_ENTRY *,
IN ARG_RECORD* pRecord,
IN PVOID pParam,
OUT CComBSTR& strFilter)
{
ENTER_FUNCTION_HR(LEVEL3_LOGGING, InactiveFilterFunc, hr);
if( !pRecord || !pRecord->bDefined || !pParam)
{
hr = E_INVALIDARG;
return hr;
}
CComBSTR strEscapedCLFilter;
LdapEscape(pRecord->strValue,strEscapedCLFilter);
strFilter = L"(siteobject=cn=";
strFilter += strEscapedCLFilter;
strFilter += L",";
strFilter += *(static_cast<BSTR*>(pParam));
strFilter += L")";
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: BuildQueryFilter
//
// Synopsis: This function builds the LDAP query filter for given object type.
//
// Arguments: [pCommandArgs - IN] :the command line argument structure used
// to retrieve the values of switches
// [pObjectEntry - IN] :Contains info about the object type
// [pParam -IN] :This value is passed to filter function.
// [strLDAPFilter - OUT] :Contains the output filter.
// 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 BuildQueryFilter(PARG_RECORD pCommandArgs,
PDSQueryObjectTableEntry pObjectEntry,
PVOID pParam,
CComBSTR& strLDAPFilter)
{
ENTER_FUNCTION_HR(LEVEL3_LOGGING, BuildQueryFilter, hr);
if( !pCommandArgs || !pObjectEntry )
{
ASSERT(FALSE);
hr = E_INVALIDARG;
return hr;
}
DSQUERY_ATTR_TABLE_ENTRY** pAttributeTable;
DWORD dwAttributeCount;
pAttributeTable = pObjectEntry->pAttributeTable;
dwAttributeCount = pObjectEntry->dwAttributeCount;
if( !pAttributeTable || !dwAttributeCount )
{
hr = E_INVALIDARG;
return hr;
}
BOOL bUseDefaultFilter = TRUE;
CComBSTR strFilter;
for( UINT i = 0; i < dwAttributeCount; ++i )
{
if(pCommandArgs[pAttributeTable[i]->nAttributeID].bDefined)
{
bUseDefaultFilter = FALSE;
CComBSTR strLocalFilter;
hr = pAttributeTable[i]->pMakeFilterFunc(pAttributeTable[i],
pCommandArgs + pAttributeTable[i]->nAttributeID,
pParam,
strLocalFilter);
if(FAILED(hr))
return hr;
strFilter += strLocalFilter;
DEBUG_OUTPUT(FULL_LOGGING, L"Current filter = %s", strFilter);
}
}
//
//If none of the commandline filter switches are specified, use
//default filter
//
strLDAPFilter = L"(";
if(bUseDefaultFilter)
{
strLDAPFilter += pObjectEntry->pszDefaultFilter;
}
else
{
if(pObjectEntry->pszPrefixFilter)
{
strLDAPFilter += pObjectEntry->pszPrefixFilter;
strLDAPFilter += strFilter;
}
else
strLDAPFilter += strFilter;
}
strLDAPFilter += L")";
DEBUG_OUTPUT(LEVEL3_LOGGING, L"ldapfilter = %s", strLDAPFilter);
return hr;
}