|
|
//
// 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; }
|