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.
548 lines
16 KiB
548 lines
16 KiB
//
|
|
|
|
// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
#include "precomp.h"
|
|
|
|
|
|
const WCHAR QueryConvertor::wchAND = L'&';
|
|
const WCHAR QueryConvertor::wchOR = L'|';
|
|
const WCHAR QueryConvertor::wchNOT = L'!';
|
|
const WCHAR QueryConvertor::wchSTAR = L'*';
|
|
const WCHAR QueryConvertor::wchEQUAL = L'=';
|
|
const WCHAR QueryConvertor::wchLEFT_BRACKET = L'(';
|
|
const WCHAR QueryConvertor::wchRIGHT_BRACKET = L')';
|
|
const WCHAR QueryConvertor::wchBACK_SLASH = L'\\';
|
|
LPCWSTR QueryConvertor::pszGE = L">=";
|
|
LPCWSTR QueryConvertor::pszLE = L"<=";
|
|
|
|
int Stack::s_iMax = 100;
|
|
|
|
// This assumes that enough memory has been allocated to the resulting query
|
|
BOOLEAN QueryConvertor::ConvertQueryToLDAP(SQL_LEVEL_1_RPN_EXPRESSION *pExp, LPWSTR pszLDAPQuery, int nLength)
|
|
{
|
|
Stack t_stack;
|
|
|
|
int iCurrentOperator = 0, idwNumOperandsLeft = 0;
|
|
int iOutputIndex = 0;
|
|
|
|
if(pExp->nNumTokens == 0)
|
|
return TRUE;
|
|
|
|
int iCurrentToken = pExp->nNumTokens -1;
|
|
|
|
SQL_LEVEL_1_TOKEN *pNextToken = pExp->pArrayOfTokens + iCurrentToken;
|
|
|
|
BOOLEAN retVal = FALSE, done = FALSE;
|
|
|
|
// Write a '(' at the head of the LDAP Query
|
|
pszLDAPQuery[iOutputIndex ++] = wchLEFT_BRACKET;
|
|
|
|
while (!done && iCurrentToken >= 0)
|
|
{
|
|
switch(pNextToken->nTokenType)
|
|
{
|
|
case SQL_LEVEL_1_TOKEN::OP_EXPRESSION:
|
|
{
|
|
// Try to tranlsate expression to LDAP
|
|
if(TranslateExpression(pszLDAPQuery, &iOutputIndex, pNextToken->nOperator, pNextToken->pPropertyName, &pNextToken->vConstValue, nLength))
|
|
{
|
|
// If we've finished all the operands for the current operator, get the next one
|
|
idwNumOperandsLeft --;
|
|
while(idwNumOperandsLeft == 0)
|
|
{
|
|
pszLDAPQuery[iOutputIndex ++] = wchRIGHT_BRACKET;
|
|
if(!t_stack.Pop(&iCurrentOperator, &idwNumOperandsLeft))
|
|
done = TRUE;
|
|
idwNumOperandsLeft --;
|
|
}
|
|
iCurrentToken --;
|
|
}
|
|
else
|
|
done = TRUE;
|
|
pNextToken --;
|
|
break;
|
|
}
|
|
|
|
case SQL_LEVEL_1_TOKEN::TOKEN_AND:
|
|
{
|
|
if(iCurrentOperator)
|
|
{
|
|
if(!t_stack.Push(iCurrentOperator, idwNumOperandsLeft))
|
|
done = TRUE;
|
|
iCurrentOperator = SQL_LEVEL_1_TOKEN::TOKEN_AND;
|
|
idwNumOperandsLeft = 2;
|
|
pszLDAPQuery[iOutputIndex ++] = wchLEFT_BRACKET;
|
|
pszLDAPQuery[iOutputIndex ++] = wchAND;
|
|
}
|
|
else
|
|
{
|
|
pszLDAPQuery[iOutputIndex ++] = wchLEFT_BRACKET;
|
|
pszLDAPQuery[iOutputIndex ++] = wchAND;
|
|
iCurrentOperator = SQL_LEVEL_1_TOKEN::TOKEN_AND;
|
|
idwNumOperandsLeft = 2;
|
|
}
|
|
iCurrentToken --;
|
|
pNextToken --;
|
|
|
|
break;
|
|
}
|
|
|
|
case SQL_LEVEL_1_TOKEN::TOKEN_OR:
|
|
{
|
|
if(iCurrentOperator)
|
|
{
|
|
if(!t_stack.Push(iCurrentOperator, idwNumOperandsLeft))
|
|
done = TRUE;
|
|
iCurrentOperator = SQL_LEVEL_1_TOKEN::TOKEN_OR;
|
|
idwNumOperandsLeft = 2;
|
|
pszLDAPQuery[iOutputIndex ++] = wchLEFT_BRACKET;
|
|
pszLDAPQuery[iOutputIndex ++] = wchOR;
|
|
}
|
|
else
|
|
{
|
|
pszLDAPQuery[iOutputIndex ++] = wchLEFT_BRACKET;
|
|
pszLDAPQuery[iOutputIndex ++] = wchOR;
|
|
iCurrentOperator = SQL_LEVEL_1_TOKEN::TOKEN_OR;
|
|
idwNumOperandsLeft = 2;
|
|
}
|
|
iCurrentToken --;
|
|
pNextToken --;
|
|
break;
|
|
}
|
|
|
|
case SQL_LEVEL_1_TOKEN::TOKEN_NOT:
|
|
{
|
|
if(iCurrentOperator)
|
|
{
|
|
if(!t_stack.Push(iCurrentOperator, idwNumOperandsLeft))
|
|
done = TRUE;
|
|
iCurrentOperator = SQL_LEVEL_1_TOKEN::TOKEN_NOT;
|
|
idwNumOperandsLeft = 1;
|
|
pszLDAPQuery[iOutputIndex ++] = wchLEFT_BRACKET;
|
|
pszLDAPQuery[iOutputIndex ++] = wchNOT;
|
|
}
|
|
else
|
|
{
|
|
pszLDAPQuery[iOutputIndex ++] = wchLEFT_BRACKET;
|
|
pszLDAPQuery[iOutputIndex ++] = wchNOT;
|
|
iCurrentOperator = SQL_LEVEL_1_TOKEN::TOKEN_NOT;
|
|
idwNumOperandsLeft = 1;
|
|
}
|
|
iCurrentToken --;
|
|
pNextToken --;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
done = TRUE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
// Check if we used up all the tokens
|
|
if(iCurrentToken == -1)
|
|
retVal = TRUE;
|
|
|
|
// Write a ')' at the end of the LDAP Query
|
|
pszLDAPQuery[iOutputIndex ++] = wchRIGHT_BRACKET;
|
|
pszLDAPQuery[iOutputIndex ++] = NULL;
|
|
return retVal;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN QueryConvertor::TranslateExpression(LPWSTR pszLDAPQuery, int *piOutputIndex,
|
|
int iOperator, LPCWSTR pszPropertyName, VARIANT *pValue, int nLength)
|
|
{
|
|
// If it is a CIMOM System property, then dont attempt to map it to LDAP
|
|
if(pszPropertyName[0] == L'_' &&
|
|
pszPropertyName[1] == L'_' )
|
|
return TRUE;
|
|
|
|
// If it is ADSIPath, convert it to distinguishedName attribute
|
|
if(_wcsicmp(pszPropertyName, ADSI_PATH_ATTR) == 0 )
|
|
{
|
|
if(pValue== NULL || pValue->vt == VT_NULL)
|
|
{
|
|
if(iOperator == SQL_LEVEL_1_TOKEN::OP_NOT_EQUAL)
|
|
{
|
|
// Put the property name as DistiguishedName
|
|
|
|
if((*piOutputIndex) + (int)wcslen(DISTINGUISHED_NAME_ATTR) < nLength ) {
|
|
wcscpy(pszLDAPQuery + *piOutputIndex, DISTINGUISHED_NAME_ATTR);
|
|
*piOutputIndex += wcslen(DISTINGUISHED_NAME_ATTR);
|
|
}else return FALSE;
|
|
|
|
|
|
if(*piOutputIndex + 2 < nLength){
|
|
*(pszLDAPQuery + *piOutputIndex) = wchEQUAL;
|
|
(*piOutputIndex) ++;
|
|
*(pszLDAPQuery + *piOutputIndex) = wchSTAR;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
// The '!'
|
|
if(*piOutputIndex + 1 < nLength){
|
|
*(pszLDAPQuery + *piOutputIndex) = wchNOT;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
|
|
// The '('
|
|
if(*piOutputIndex + 1 < nLength){
|
|
*(pszLDAPQuery + *piOutputIndex) = wchLEFT_BRACKET;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
if(TranslateExpression(pszLDAPQuery, piOutputIndex, SQL_LEVEL_1_TOKEN::OP_NOT_EQUAL, pszPropertyName, NULL, nLength))
|
|
{
|
|
// The ')'
|
|
if(*piOutputIndex + 1 < nLength){
|
|
*(pszLDAPQuery + *piOutputIndex) = wchRIGHT_BRACKET;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// TODO - WinMgmt should not allow this. It should check that the property type matches the property value
|
|
// As soon as Winmgmt has fixed this bug, the next 2 lines may be deleted
|
|
if(pValue->vt != VT_BSTR)
|
|
return FALSE;
|
|
|
|
// Get the parentADSI path and RDN from the ADSI Path
|
|
IADsPathname *pADsPathName = NULL;
|
|
BSTR strADSIPath = SysAllocString(pValue->bstrVal);
|
|
BSTR strDN = NULL;
|
|
BOOLEAN bRetVal = FALSE;
|
|
HRESULT result = E_FAIL;
|
|
if(SUCCEEDED(result = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_ALL, IID_IADsPathname, (LPVOID *)&pADsPathName)))
|
|
{
|
|
if(SUCCEEDED(result = pADsPathName->Set(strADSIPath, ADS_SETTYPE_FULL)))
|
|
{
|
|
// This gives the DN
|
|
if(SUCCEEDED(result = pADsPathName->Retrieve(ADS_FORMAT_X500_DN, &strDN)))
|
|
{
|
|
// Put the property name as DistiguishedName
|
|
|
|
if(*piOutputIndex + (int)wcslen(DISTINGUISHED_NAME_ATTR) < nLength){
|
|
wcscpy(pszLDAPQuery + *piOutputIndex, DISTINGUISHED_NAME_ATTR);
|
|
*piOutputIndex += wcslen(DISTINGUISHED_NAME_ATTR);
|
|
}else return FALSE;
|
|
|
|
// Put the LDAP Operator
|
|
if(iOperator == SQL_LEVEL_1_TOKEN::OP_EQUAL)
|
|
{
|
|
if(*piOutputIndex + 1 < nLength){
|
|
*(pszLDAPQuery + *piOutputIndex) = wchEQUAL;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// The '!'
|
|
if(*piOutputIndex + 2 < nLength){
|
|
*(pszLDAPQuery + *piOutputIndex) = wchNOT;
|
|
(*piOutputIndex) ++;
|
|
*(pszLDAPQuery + *piOutputIndex) = wchEQUAL;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
}
|
|
|
|
// Look for the special characters ( ) * and \ and escape them with a \
|
|
LPWSTR pszEscapedValue = EscapeStringValue(strDN);
|
|
|
|
if(*piOutputIndex + (int)wcslen(pszEscapedValue) < nLength){
|
|
wcscpy(pszLDAPQuery + *piOutputIndex, pszEscapedValue);
|
|
(*piOutputIndex) += wcslen(pszEscapedValue);
|
|
}else return FALSE;
|
|
delete [] pszEscapedValue;
|
|
|
|
SysFreeString(strDN);
|
|
bRetVal = TRUE;
|
|
}
|
|
}
|
|
pADsPathName->Release();
|
|
}
|
|
SysFreeString(strADSIPath);
|
|
|
|
return bRetVal;
|
|
}
|
|
|
|
// Write a '('
|
|
if(*piOutputIndex + 1 < nLength){
|
|
pszLDAPQuery[(*piOutputIndex) ++] = wchLEFT_BRACKET;
|
|
}
|
|
|
|
switch(iOperator)
|
|
{
|
|
case SQL_LEVEL_1_TOKEN::OP_EQUAL:
|
|
{
|
|
// Special case where we use '*' LDAP operator
|
|
// is NULL translates to !( x=*)
|
|
if(pValue->vt == VT_NULL)
|
|
{
|
|
if(*piOutputIndex + 2 < nLength){
|
|
// The '!'
|
|
*(pszLDAPQuery + *piOutputIndex) = wchNOT;
|
|
(*piOutputIndex) ++;
|
|
|
|
// The '('
|
|
*(pszLDAPQuery + *piOutputIndex) = wchLEFT_BRACKET;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
|
|
if(!TranslateExpression(pszLDAPQuery, piOutputIndex, SQL_LEVEL_1_TOKEN::OP_NOT_EQUAL, pszPropertyName, NULL, nLength))
|
|
return FALSE;
|
|
|
|
if(*piOutputIndex + 1 < nLength){
|
|
// The ')'
|
|
*(pszLDAPQuery + *piOutputIndex) = wchRIGHT_BRACKET;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Followthru
|
|
}
|
|
}
|
|
case SQL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN:
|
|
case SQL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN:
|
|
{
|
|
// Get the LDAP name of the property
|
|
LPWSTR pszLDAPName = CLDAPHelper::UnmangleWBEMNameToLDAP(pszPropertyName);
|
|
if(*piOutputIndex + (int)wcslen(pszLDAPName) < nLength){
|
|
wcscpy(pszLDAPQuery + *piOutputIndex, pszLDAPName);
|
|
*piOutputIndex += wcslen(pszLDAPName);
|
|
}else return FALSE;
|
|
delete [] pszLDAPName;
|
|
|
|
// Put the LDAP Operator
|
|
if(iOperator == SQL_LEVEL_1_TOKEN::OP_EQUAL)
|
|
{
|
|
if(*piOutputIndex + 1 < nLength){
|
|
*(pszLDAPQuery + *piOutputIndex) = wchEQUAL;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
}
|
|
else if(iOperator == SQL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN)
|
|
{
|
|
if(*piOutputIndex + 2 < nLength){
|
|
wcscpy(pszLDAPQuery + *piOutputIndex, pszGE);
|
|
*piOutputIndex += 2;
|
|
}else return FALSE;
|
|
}
|
|
else
|
|
{
|
|
if(*piOutputIndex + 2 < nLength){
|
|
wcscpy(pszLDAPQuery + *piOutputIndex, pszLE);
|
|
*piOutputIndex += 2;
|
|
}else return FALSE;
|
|
}
|
|
|
|
// Put the value of the property
|
|
if(!TranslateValueToLDAP(pszLDAPQuery, piOutputIndex, pValue))
|
|
return FALSE;
|
|
|
|
}
|
|
break;
|
|
|
|
case SQL_LEVEL_1_TOKEN::OP_NOT_EQUAL:
|
|
{
|
|
// Special case for use of '*'
|
|
if(pValue == NULL || pValue->vt == VT_NULL)
|
|
{
|
|
|
|
// Get the LDAP name of the property
|
|
LPWSTR pszLDAPName = CLDAPHelper::UnmangleWBEMNameToLDAP(pszPropertyName);
|
|
if(*piOutputIndex + (int)wcslen(pszLDAPName) < nLength){
|
|
wcscpy(pszLDAPQuery + *piOutputIndex, pszLDAPName);
|
|
*piOutputIndex += wcslen(pszLDAPName);
|
|
}else return FALSE;
|
|
delete [] pszLDAPName;
|
|
|
|
if(*piOutputIndex + 2 < nLength){
|
|
*(pszLDAPQuery + *piOutputIndex) = wchEQUAL;
|
|
(*piOutputIndex) ++;
|
|
|
|
|
|
*(pszLDAPQuery + *piOutputIndex) = wchSTAR;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
|
|
}
|
|
else
|
|
{
|
|
if(*piOutputIndex + 2 < nLength){
|
|
// The '!'
|
|
*(pszLDAPQuery + *piOutputIndex) = wchNOT;
|
|
(*piOutputIndex) ++;
|
|
|
|
// The '('
|
|
*(pszLDAPQuery + *piOutputIndex) = wchLEFT_BRACKET;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
|
|
if(TranslateExpression(pszLDAPQuery, piOutputIndex, SQL_LEVEL_1_TOKEN::OP_EQUAL, pszPropertyName, pValue, nLength))
|
|
{
|
|
if(*piOutputIndex + 1 < nLength){
|
|
// The ')'
|
|
*(pszLDAPQuery + *piOutputIndex) = wchRIGHT_BRACKET;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SQL_LEVEL_1_TOKEN::OP_LESSTHAN:
|
|
{
|
|
if(*piOutputIndex + 2 < nLength){
|
|
// The '!'
|
|
*(pszLDAPQuery + *piOutputIndex) = wchNOT;
|
|
(*piOutputIndex) ++;
|
|
|
|
// The '('
|
|
*(pszLDAPQuery + *piOutputIndex) = wchLEFT_BRACKET;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
|
|
if(TranslateExpression(pszLDAPQuery, piOutputIndex, SQL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN, pszPropertyName, pValue,nLength))
|
|
{
|
|
if(*piOutputIndex + 1 < nLength){
|
|
// The ')'
|
|
*(pszLDAPQuery + *piOutputIndex) = wchRIGHT_BRACKET;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case SQL_LEVEL_1_TOKEN::OP_GREATERTHAN:
|
|
{
|
|
if(*piOutputIndex + 2 < nLength){
|
|
// The '!'
|
|
*(pszLDAPQuery + *piOutputIndex) = wchNOT;
|
|
(*piOutputIndex) ++;
|
|
|
|
// The '('
|
|
*(pszLDAPQuery + *piOutputIndex) = wchLEFT_BRACKET;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
|
|
if(TranslateExpression(pszLDAPQuery, piOutputIndex, SQL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN, pszPropertyName, pValue, nLength))
|
|
{
|
|
if(*piOutputIndex + 1 < nLength){
|
|
// The ')'
|
|
*(pszLDAPQuery + *piOutputIndex) = wchRIGHT_BRACKET;
|
|
(*piOutputIndex) ++;
|
|
}else return FALSE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
if(*piOutputIndex + 1 < nLength){
|
|
// Write a ')'
|
|
pszLDAPQuery[(*piOutputIndex) ++] = wchRIGHT_BRACKET;
|
|
} else return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN QueryConvertor::TranslateValueToLDAP(LPWSTR pszLDAPQuery, int *piOutputIndex, VARIANT *pValue)
|
|
{
|
|
switch(pValue->vt)
|
|
{
|
|
case VT_BSTR:
|
|
{
|
|
// Look for the special characters ( ) * and \ and escape them with a \
|
|
LPWSTR pszEscapedValue = EscapeStringValue(pValue->bstrVal);
|
|
wcscpy(pszLDAPQuery + *piOutputIndex, pszEscapedValue);
|
|
(*piOutputIndex) += wcslen(pszEscapedValue);
|
|
delete [] pszEscapedValue;
|
|
}
|
|
break;
|
|
|
|
case VT_I4:
|
|
{
|
|
WCHAR temp[18];
|
|
swprintf(temp, L"%d", pValue->lVal);
|
|
wcscpy(pszLDAPQuery + *piOutputIndex, temp);
|
|
(*piOutputIndex) += wcslen(temp);
|
|
}
|
|
break;
|
|
|
|
case VT_BOOL:
|
|
{
|
|
if(pValue->boolVal == VARIANT_TRUE)
|
|
{
|
|
wcscpy(pszLDAPQuery + *piOutputIndex, L"TRUE");
|
|
(*piOutputIndex) += wcslen(L"TRUE");
|
|
}
|
|
else
|
|
{
|
|
wcscpy(pszLDAPQuery + *piOutputIndex, L"FALSE");
|
|
(*piOutputIndex) += wcslen(L"FALSE");
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
LPWSTR QueryConvertor::EscapeStringValue(LPCWSTR pszValue)
|
|
{
|
|
// Escape the special characters in a string value in a query
|
|
LPWSTR pszRetValue = new WCHAR [wcslen(pszValue)*2 + 1];
|
|
DWORD j=0;
|
|
for(DWORD i=0; i<wcslen(pszValue); i++)
|
|
{
|
|
switch(pszValue[i])
|
|
{
|
|
case wchLEFT_BRACKET:
|
|
pszRetValue[j++] = wchBACK_SLASH;
|
|
pszRetValue[j++] = '2';
|
|
pszRetValue[j++] = '8';
|
|
break;
|
|
case wchRIGHT_BRACKET:
|
|
pszRetValue[j++] = wchBACK_SLASH;
|
|
pszRetValue[j++] = '2';
|
|
pszRetValue[j++] = '9';
|
|
break;
|
|
case wchSTAR:
|
|
pszRetValue[j++] = wchBACK_SLASH;
|
|
pszRetValue[j++] = '2';
|
|
pszRetValue[j++] = 'a';
|
|
break;
|
|
case wchBACK_SLASH:
|
|
pszRetValue[j++] = wchBACK_SLASH;
|
|
pszRetValue[j++] = '5';
|
|
pszRetValue[j++] = 'c';
|
|
break;
|
|
|
|
default:
|
|
pszRetValue[j++] = pszValue[i];
|
|
break;
|
|
}
|
|
}
|
|
pszRetValue[j] = NULL;
|
|
return pszRetValue;
|
|
}
|