/*++ Copyright (c) 1995-2000 Microsoft Corporation Module Name: dnsc_wmi.c Abstract: WMI functions for DNSCMD Author: Jeff Westhead (jwesth) November 2000 Revision History: --*/ #include "dnsclip.h" #include "dnsc_wmi.h" #define DNSCMD_CHECK_WMI_ENABLED() \ if ( !g_UseWmi ) \ { \ ASSERT( g_UseWmi ); \ printf( "Internal error: WMI is not enabled!\n" ); \ return ERROR_NOT_SUPPORTED; \ } #define HRES_TO_STATUS( hres ) ( hres ) #define DNS_WMI_NAMESPACE L"ROOT\\MicrosoftDNS" #define DNS_WMI_RELPATH L"__RELPATH" #define DNS_WMI_TIMEOUT 20000 // timeout in msecs #define DNS_WMI_BLANK_STRING \ L" " #define MYTEXT2(str) L##str #define MYTEXT(str) MYTEXT2(str) #define wmiRelease( pWmiObject ) \ if ( pWmiObject ) \ { \ pWmiObject->Release(); \ pWmiObject = NULL; \ } // // Globals // IWbemServices * g_pIWbemServices = NULL; // // Static functions // static DNS_STATUS getEnumerator( IN PSTR pszZoneName, OUT IEnumWbemClassObject ** ppEnum ) /*++ Routine Description: Retrieves WMI object enumerator. The caller must call Release on the enum object when done. Arguments: pszZoneName - zone name or NULL for server object ppEnum - ptr to ptr to WMI enumerator Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ { DNS_STATUS status = ERROR_SUCCESS; WCHAR wsz[ 1024 ]; BSTR bstrWQL = NULL; BSTR bstrQuery = NULL; HRESULT hres = 0; if ( pszZoneName ) { status = StringCchPrintfW( wsz, sizeofarray( wsz ), L"select * from MicrosoftDNS_Zone where Name='%S'", pszZoneName ); } else { status = StringCchPrintfW( wsz, sizeofarray( wsz ), L"select * from MicrosoftDNS_Server" ); } if ( FAILED( status ) ) { return status; } bstrWQL = SysAllocString( L"WQL" ); bstrQuery = SysAllocString( wsz ); if ( !bstrWQL || !bstrQuery ) { status = DNS_ERROR_NO_MEMORY; goto Done; } hres = g_pIWbemServices->ExecQuery( bstrWQL, bstrQuery, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, ppEnum ); if ( FAILED( hres ) ) { status = hres; goto Done; } Done: SysFreeString( bstrWQL ); SysFreeString( bstrQuery ); return status; } // getEnumerator static DNS_STATUS getRelpath( IN IWbemClassObject * pObj, OUT VARIANT * pVar ) /*++ Routine Description: Loads a VARIANT with the WMI __RELPATH of the object. Arguments: pObj - object to retrieve relpath for pVar - ptr to variant - caller must VariantClear() it later Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ { DNS_STATUS status = ERROR_SUCCESS; if ( pObj == NULL || pVar == NULL ) { status = ERROR_INVALID_PARAMETER; } else { VariantClear( pVar ); HRESULT hres = pObj->Get( DNS_WMI_RELPATH, 0, pVar, NULL, NULL ); status = hres; } return status; } // getRelpath static DNS_STATUS getNextObjectInEnum( IN IEnumWbemClassObject * pEnum, OUT IWbemClassObject ** ppObj, IN bool fPrintRelpath = TRUE ) /*++ Routine Description: Retrieves WMI object enumerator. The caller must call Release on the class object. When there are no more objects to enumerate this function will return a NULL pObj and ERROR_SUCCESS. Arguments: pszZoneName - zone name or NULL for server object ppEnum - ptr to ptr to WMI enumerator Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ { DNS_STATUS status = ERROR_SUCCESS; ULONG returnedCount = 0; HRESULT hres = 0; if ( !pEnum || !ppObj ) { status = ERROR_INVALID_PARAMETER; goto Done; } hres = pEnum->Next( DNS_WMI_TIMEOUT, 1, // requested instance count ppObj, &returnedCount ); if ( FAILED( hres ) ) { status = ERROR_SUCCESS; *ppObj = NULL; } if ( *ppObj && fPrintRelpath ) { // // Print RELPATH for this object. // VARIANT var; status = getRelpath( *ppObj, &var ); if ( status == ERROR_SUCCESS ) { printf( "%S\n", V_BSTR( &var ) ); } else { printf( "WMI error 0x%08X getting RELPATH\n", hres ); } VariantClear( &var ); } Done: return status; } // getNextObjectInEnum static SAFEARRAY * createSafeArrayForIpList( IN DWORD dwIpCount, IN PIP_ADDRESS pIpList ) /*++ Routine Description: Creates a SAFEARRAY of strings representing a list of IP addresses. Arguments: pIpList - array of IP address DWORDs dwIpCount - number of elements in pIpList Return Value: Safe array on success or NULL or failure. --*/ { if ( !pIpList ) { return NULL; } SAFEARRAYBOUND sabound = { dwIpCount, 0 }; SAFEARRAY * psa = SafeArrayCreate( VT_BSTR, 1, &sabound ); for ( ULONG i = 0; i < dwIpCount; ++i ) { PWSTR pwsz = ( PWSTR ) Dns_NameCopyAllocate( inet_ntoa( *( struct in_addr * ) &pIpList[ i ] ), 0, DnsCharSetUtf8, DnsCharSetUnicode ); BSTR bstr = SysAllocString( pwsz ); if ( FAILED( SafeArrayPutElement( psa, ( PLONG ) &i, bstr ) ) ) { SafeArrayDestroy( psa ); psa = NULL; } SysFreeString( bstr ); FREE_HEAP( pwsz ); } return psa; } static SAFEARRAY * createSafeArrayForIpArray( IN PIP_ARRAY pIpArray ) /*++ Routine Description: Creates a SAFEARRAY of strings representing the IP addresses in pIpArray. Arguments: pIpArray - IP array to create string SAFEARRAY for Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ { if ( !pIpArray ) { return NULL; } return createSafeArrayForIpList( pIpArray->AddrCount, pIpArray->AddrArray ); } PWCHAR valueToString( CIMTYPE dwType, VARIANT *pValue, WCHAR **pbuf ) /*++ Routine Description: Convert VARIANT to string. Stole this code from WMI\Samples\VC\UtilLib. Arguments: dwType - value CIMTYPE pValue - value to convert to string **pbuf - ptr to allocated string buffer - caller must free() it Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ { #define BLOCKSIZE ( 32 * sizeof( WCHAR ) ) #define CVTBUFSIZE ( 309 + 40 ) DWORD iTotBufSize, iLen; WCHAR *vbuf = NULL; WCHAR *buf = NULL; WCHAR lbuf[BLOCKSIZE]; switch (pValue->vt) { case VT_EMPTY: buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); break; case VT_NULL: buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); break; case VT_BOOL: { VARIANT_BOOL b = pValue->boolVal; buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; if (!b) { wcscpy(buf, L"FALSE"); } else { wcscpy(buf, L"TRUE"); } break; } case VT_I1: { char b = pValue->bVal; buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; if (b >= 32) { swprintf(buf, L"'%c' (%hd, 0x%hX)", b, (signed char)b, b); } else { swprintf(buf, L"%hd (0x%hX)", (signed char)b, b); } break; } case VT_UI1: { unsigned char b = pValue->bVal; buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; if (b >= 32) { swprintf(buf, L"'%c' (%hu, 0x%hX)", b, (unsigned char)b, b); } else { swprintf(buf, L"%hu (0x%hX)", (unsigned char)b, b); } break; } case VT_I2: { SHORT i = pValue->iVal; buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; swprintf(buf, L"%hd (0x%hX)", i, i); break; } case VT_UI2: { USHORT i = pValue->uiVal; buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; swprintf(buf, L"%hu (0x%hX)", i, i); break; } case VT_I4: { LONG l = pValue->lVal; buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; swprintf(buf, L"%d (0x%X)", l, l); break; } case VT_UI4: { ULONG l = pValue->ulVal; buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; swprintf(buf, L"%u (0x%X)", l, l); break; } case VT_R4: { float f = pValue->fltVal; buf = (WCHAR *)malloc(CVTBUFSIZE * sizeof(WCHAR)); if ( !buf ) goto AllocFailed; swprintf(buf, L"%10.4f", f); break; } case VT_R8: { double d = pValue->dblVal; buf = (WCHAR *)malloc(CVTBUFSIZE * sizeof(WCHAR)); if ( !buf ) goto AllocFailed; swprintf(buf, L"%10.4f", d); break; } case VT_BSTR: { if (dwType == CIM_SINT64) { // a little redundant, but it makes me feel better LPWSTR pWStr = pValue->bstrVal; __int64 l = _wtoi64(pWStr); buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; swprintf(buf, L"%I64d", l); } else if (dwType == CIM_UINT64) { // a little redundant, but it makes me feel better LPWSTR pWStr = pValue->bstrVal; __int64 l = _wtoi64(pWStr); buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; swprintf(buf, L"%I64u", l); } else // string, datetime, reference { LPWSTR pWStr = pValue->bstrVal; buf = (WCHAR *)malloc((wcslen(pWStr) * sizeof(WCHAR)) + sizeof(WCHAR) + (2 * sizeof(WCHAR))); if ( !buf ) goto AllocFailed; swprintf(buf, L"%wS", pWStr); } break; } case VT_BOOL|VT_ARRAY: { SAFEARRAY *pVec = pValue->parray; long iLBound, iUBound; BOOL bFirst = TRUE; SafeArrayGetLBound(pVec, 1, &iLBound); SafeArrayGetUBound(pVec, 1, &iUBound); if ((iUBound - iLBound + 1) == 0) { buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); break; } buf = (WCHAR *)malloc((iUBound - iLBound + 1) * BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); for (long i = iLBound; i <= iUBound; i++) { if (!bFirst) { wcscat(buf, L","); } else { bFirst = FALSE; } VARIANT_BOOL v; SafeArrayGetElement(pVec, &i, &v); if (v) { wcscat(buf, L"TRUE"); } else { wcscat(buf, L"FALSE"); } } break; } case VT_I1|VT_ARRAY: { SAFEARRAY *pVec = pValue->parray; long iLBound, iUBound; BOOL bFirst = TRUE; SafeArrayGetLBound(pVec, 1, &iLBound); SafeArrayGetUBound(pVec, 1, &iUBound); if ((iUBound - iLBound + 1) == 0) { buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); break; } buf = (WCHAR *)malloc((iUBound - iLBound + 1) * BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); WCHAR *pos = buf; DWORD len; BYTE *pbstr; SafeArrayAccessData(pVec, (void HUGEP* FAR*)&pbstr); for (long i = iLBound; i <= iUBound; i++) { if (!bFirst) { wcscpy(pos, L","); pos += 1; } else { bFirst = FALSE; } char v; // SafeArrayGetElement(pVec, &i, &v); v = pbstr[i]; if (v < 32) { len = swprintf(lbuf, L"%hd (0x%X)", v, v); } else { len = swprintf(lbuf, L"'%c' %hd (0x%X)", v, v, v); } wcscpy(pos, lbuf); pos += len; } SafeArrayUnaccessData(pVec); break; } case VT_UI1|VT_ARRAY: { SAFEARRAY *pVec = pValue->parray; long iLBound, iUBound; BOOL bFirst = TRUE; SafeArrayGetLBound(pVec, 1, &iLBound); SafeArrayGetUBound(pVec, 1, &iUBound); if ((iUBound - iLBound + 1) == 0) { buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); break; } buf = (WCHAR *)malloc((iUBound - iLBound + 1) * BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); WCHAR *pos = buf; DWORD len; BYTE *pbstr; SafeArrayAccessData(pVec, (void HUGEP* FAR*)&pbstr); for (long i = iLBound; i <= iUBound; i++) { if (!bFirst) { wcscpy(pos, L","); pos += 1; } else { bFirst = FALSE; } unsigned char v; // SafeArrayGetElement(pVec, &i, &v); v = pbstr[i]; if (v < 32) { len = swprintf(lbuf, L"%hu (0x%X)", v, v); } else { len = swprintf(lbuf, L"'%c' %hu (0x%X)", v, v, v); } wcscpy(pos, lbuf); pos += len; } SafeArrayUnaccessData(pVec); break; } case VT_I2|VT_ARRAY: { SAFEARRAY *pVec = pValue->parray; long iLBound, iUBound; BOOL bFirst = TRUE; SafeArrayGetLBound(pVec, 1, &iLBound); SafeArrayGetUBound(pVec, 1, &iUBound); if ((iUBound - iLBound + 1) == 0) { buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); break; } buf = (WCHAR *)malloc((iUBound - iLBound + 1) * BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); for (long i = iLBound; i <= iUBound; i++) { if (!bFirst) { wcscat(buf, L","); } else { bFirst = FALSE; } SHORT v; SafeArrayGetElement(pVec, &i, &v); swprintf(lbuf, L"%hd", v); wcscat(buf, lbuf); } break; } case VT_UI2|VT_ARRAY: { SAFEARRAY *pVec = pValue->parray; long iLBound, iUBound; BOOL bFirst = TRUE; SafeArrayGetLBound(pVec, 1, &iLBound); SafeArrayGetUBound(pVec, 1, &iUBound); if ((iUBound - iLBound + 1) == 0) { buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); break; } buf = (WCHAR *)malloc((iUBound - iLBound + 1) * BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); for (long i = iLBound; i <= iUBound; i++) { if (!bFirst) { wcscat(buf, L","); } else { bFirst = FALSE; } USHORT v; SafeArrayGetElement(pVec, &i, &v); swprintf(lbuf, L"%hu", v); wcscat(buf, lbuf); } break; } case VT_I4|VT_ARRAY: { SAFEARRAY *pVec = pValue->parray; long iLBound, iUBound; BOOL bFirst = TRUE; SafeArrayGetLBound(pVec, 1, &iLBound); SafeArrayGetUBound(pVec, 1, &iUBound); if ((iUBound - iLBound + 1) == 0) { buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); break; } buf = (WCHAR *)malloc((iUBound - iLBound + 1) * BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); for (long i = iLBound; i <= iUBound; i++) { if (!bFirst) { wcscat(buf, L","); } else { bFirst = FALSE; } LONG v; SafeArrayGetElement(pVec, &i, &v); _ltow(v, lbuf, 10); wcscat(buf, lbuf); } break; } case VT_UI4|VT_ARRAY: { SAFEARRAY *pVec = pValue->parray; long iLBound, iUBound; BOOL bFirst = TRUE; SafeArrayGetLBound(pVec, 1, &iLBound); SafeArrayGetUBound(pVec, 1, &iUBound); if ((iUBound - iLBound + 1) == 0) { buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); break; } buf = (WCHAR *)malloc((iUBound - iLBound + 1) * BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); for (long i = iLBound; i <= iUBound; i++) { if (!bFirst) { wcscat(buf, L","); } else { bFirst = FALSE; } ULONG v; SafeArrayGetElement(pVec, &i, &v); _ultow(v, lbuf, 10); wcscat(buf, lbuf); } break; } case CIM_REAL32|VT_ARRAY: { SAFEARRAY *pVec = pValue->parray; long iLBound, iUBound; BOOL bFirst = TRUE; SafeArrayGetLBound(pVec, 1, &iLBound); SafeArrayGetUBound(pVec, 1, &iUBound); if ((iUBound - iLBound + 1) == 0) { buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); break; } buf = (WCHAR *)malloc((iUBound - iLBound + 1) * (CVTBUFSIZE * sizeof(WCHAR))); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); for (long i = iLBound; i <= iUBound; i++) { if (!bFirst) { wcscat(buf, L","); } else { bFirst = FALSE; } FLOAT v; SafeArrayGetElement(pVec, &i, &v); swprintf(lbuf, L"%10.4f", v); wcscat(buf, lbuf); } break; } case CIM_REAL64|VT_ARRAY: { SAFEARRAY *pVec = pValue->parray; long iLBound, iUBound; BOOL bFirst = TRUE; SafeArrayGetLBound(pVec, 1, &iLBound); SafeArrayGetUBound(pVec, 1, &iUBound); if ((iUBound - iLBound + 1) == 0) { buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); break; } buf = (WCHAR *)malloc((iUBound - iLBound + 1) * (CVTBUFSIZE * sizeof(WCHAR))); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); for (long i = iLBound; i <= iUBound; i++) { if (!bFirst) { wcscat(buf, L","); } else { bFirst = FALSE; } double v; SafeArrayGetElement(pVec, &i, &v); swprintf(lbuf, L"%10.4f", v); wcscat(buf, lbuf); } break; } case VT_BSTR|VT_ARRAY: { if (dwType == (CIM_UINT64|VT_ARRAY)) { SAFEARRAY *pVec = pValue->parray; long iLBound, iUBound; BOOL bFirst = TRUE; SafeArrayGetLBound(pVec, 1, &iLBound); SafeArrayGetUBound(pVec, 1, &iUBound); if ((iUBound - iLBound + 1) == 0) { buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); break; } buf = (WCHAR *)malloc((iUBound - iLBound + 1) * BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); for (long i = iLBound; i <= iUBound; i++) { if (!bFirst) { wcscat(buf, L","); } else { bFirst = FALSE; } BSTR v = NULL; SafeArrayGetElement(pVec, &i, &v); swprintf(lbuf, L"%I64u", _wtoi64(v)); wcscat(buf, lbuf); } } else if (dwType == (CIM_SINT64|VT_ARRAY)) { SAFEARRAY *pVec = pValue->parray; long iLBound, iUBound; BOOL bFirst = TRUE; SafeArrayGetLBound(pVec, 1, &iLBound); SafeArrayGetUBound(pVec, 1, &iUBound); if ((iUBound - iLBound + 1) == 0) { buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); break; } buf = (WCHAR *)malloc((iUBound - iLBound + 1) * BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); for (long i = iLBound; i <= iUBound; i++) { if (!bFirst) { wcscat(buf, L","); } else { bFirst = FALSE; } BSTR v = NULL; SafeArrayGetElement(pVec, &i, &v); swprintf(lbuf, L"%I64d", _wtoi64(v)); wcscat(buf, lbuf); } } else // string, datetime, reference { SAFEARRAY *pVec = pValue->parray; long iLBound, iUBound; DWORD iNeed; DWORD iVSize; DWORD iCurBufSize; SafeArrayGetLBound(pVec, 1, &iLBound); SafeArrayGetUBound(pVec, 1, &iUBound); if ((iUBound - iLBound + 1) == 0) { buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); break; } iTotBufSize = (iUBound - iLBound + 1) * BLOCKSIZE; buf = (WCHAR *)malloc(iTotBufSize); if ( !buf ) goto AllocFailed; buf[0] = L'\0'; iCurBufSize = 0; iVSize = BLOCKSIZE; vbuf = (WCHAR *)malloc(BLOCKSIZE); if ( !vbuf ) goto AllocFailed; for (long i = iLBound; i <= iUBound; i++) { BSTR v = NULL; WCHAR * newbuf = NULL; SafeArrayGetElement(pVec, &i, &v); iLen = (wcslen(v) + 1) * sizeof(WCHAR); if (iLen > iVSize) { newbuf = (WCHAR *)realloc(vbuf, iLen + sizeof(WCHAR)); if ( !newbuf ) goto AllocFailed; vbuf = newbuf; iVSize = iLen; } // String size + (quotes + comma + null) iNeed = (swprintf(vbuf, L"%wS", v) + 4) * sizeof(WCHAR); if (iNeed + iCurBufSize > iTotBufSize) { iTotBufSize += (iNeed * 2); // Room enough for 2 more entries newbuf = (WCHAR *)realloc(buf, iTotBufSize); if ( !newbuf ) goto AllocFailed; buf = newbuf; } wcscat(buf, L"\""); wcscat(buf, vbuf); if (i + 1 <= iUBound) { wcscat(buf, L"\","); } else { wcscat(buf, L"\""); } iCurBufSize += iNeed; SysFreeString(v); } } break; } default: { buf = (WCHAR *)malloc(BLOCKSIZE); if ( !buf ) goto AllocFailed; wcscpy(buf, L""); break; } } AllocFailed: if ( vbuf ) { free( vbuf ); } *pbuf = buf; return buf; } // valueToString DNS_STATUS printWmiObjectProperties( IWbemClassObject * pObj ) { DNS_STATUS status = ERROR_SUCCESS; HRESULT hres = 0; SAFEARRAY * pNames = NULL; BSTR bstrPropName = NULL; VARIANT var; BSTR bstrCimType = SysAllocString( L"CIMTYPE" ); PWSTR pwszVal = NULL; if ( !bstrCimType ) { status = DNS_ERROR_NO_MEMORY; goto Done; } VariantClear( &var ); // // Get the RELPATH for this object. // status = getRelpath( pObj, &var ); if ( status != ERROR_SUCCESS ) { goto Done; } printf( "%S\n\n", V_BSTR( &var ) ); // // Enumerate all properties of this object. // hres = pObj->GetNames( NULL, // qualifier WBEM_FLAG_ALWAYS | WBEM_FLAG_NONSYSTEM_ONLY, NULL, // qualifier value &pNames ); if ( FAILED( hres ) ) { goto Done; } ASSERT( pNames ); long lowerBound; long upperBound; SafeArrayGetLBound( pNames, 1, &lowerBound ); SafeArrayGetUBound( pNames, 1, &upperBound ); for ( long i = lowerBound; i <= upperBound; ++i ) { // // Print the name and type of this property value. // hres = SafeArrayGetElement( pNames, &i, &bstrPropName ); if ( !SUCCEEDED( hres ) ) { ASSERT( SUCCEEDED( hres ) ); continue; } IWbemQualifierSet * pQualSet = NULL; hres = pObj->GetPropertyQualifierSet( bstrPropName, &pQualSet ); if ( !SUCCEEDED( hres ) ) { ASSERT( SUCCEEDED( hres ) ); continue; } VariantClear( &var ); pQualSet->Get( bstrCimType, 0, &var, NULL ); if ( !SUCCEEDED( hres ) ) { ASSERT( SUCCEEDED( hres ) ); continue; } int padlen = 30 - wcslen( bstrPropName ) - wcslen( V_BSTR( &var ) ); printf( "%S (%S) %.*S = ", bstrPropName, V_BSTR( &var ), padlen > 0 ? padlen : 0, DNS_WMI_BLANK_STRING ); // // Print the property value. // VariantClear( &var ); CIMTYPE cimType = 0; hres = pObj->Get( bstrPropName, 0, &var, &cimType, NULL ); if ( !SUCCEEDED( hres ) ) { ASSERT( SUCCEEDED( hres ) ); continue; } printf( "%S\n", valueToString( cimType, &var, &pwszVal ) ); free( pwszVal ); pwszVal = NULL; } Done: free( pwszVal ); SysFreeString( bstrCimType ); SafeArrayDestroy( pNames ); if ( status == ERROR_SUCCESS && FAILED( hres ) ) { status = HRES_TO_STATUS( hres ); } return status; } // printWmiObjectProperties // // External functions // DNS_STATUS DnscmdWmi_Initialize( IN PWSTR pwszServerName ) /*++ Routine Description: Setup mod buffer for max count of items. Arguments: pwszServerName -- IP address or name of target server Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ { static const char * fn = "DnscmdWmi_Initialize"; DNS_STATUS status = ERROR_SUCCESS; HRESULT hres = 0; IWbemLocator * pIWbemLocator = NULL; BSTR bstrNamespace = NULL; IWbemServices * pIWbemServices = NULL; WCHAR wsz[ 1024 ]; DNSCMD_CHECK_WMI_ENABLED(); // // Initialize COM. // if ( FAILED( hres = CoInitialize( NULL ) ) ) { printf( "%s: CoInitialize returned 0x%08X\n", fn, hres ); goto Done; } // // Initialize security. // hres = CoInitializeSecurity( NULL, // permissions -1, // auth service count NULL, // auth services NULL, // reserved RPC_C_AUTHZ_NONE, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, // auth list 0, // capabilities 0 ); // reserved if ( FAILED( hres ) ) { printf( "%s: CoInitializeSecurity() returned 0x%08X\n", fn, hres ); goto Done; } // // Create instance of WbemLocator interface. // hres = CoCreateInstance( CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, ( LPVOID * ) &pIWbemLocator ); if ( FAILED( hres ) ) { printf( "%s: CoCreateInstance( CLSID_WbemLocator ) returned 0x%08X\n", fn, hres ); goto Done; } // // Connect to MicrosoftDNS namespace on server. // wsprintfW( wsz, L"\\\\%s\\%s", pwszServerName, DNS_WMI_NAMESPACE ); bstrNamespace = SysAllocString( wsz ); if ( !bstrNamespace ) { ASSERT( bstrNamespace ); status = DNS_ERROR_NO_MEMORY; goto Done; } hres = pIWbemLocator->ConnectServer( bstrNamespace, NULL, // user id NULL, // password NULL, // locale 0, // security flags NULL, // domain NULL, // context &pIWbemServices ); if ( FAILED( hres ) ) { printf( "%s: ConnectServer( %S ) returned 0x%08X\n", fn, DNS_WMI_NAMESPACE, hres ); goto Done; } if ( !pIWbemServices ) { ASSERT( pIWbemServices ); status = DNS_ERROR_NO_MEMORY; goto Done; } // // Set security. // hres = CoSetProxyBlanket( pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, // principal name RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, // client identify EOAC_NONE ); if ( FAILED( hres ) ) { printf( "%s: CoSetProxyBlanket() returned 0x%08X\n", fn, hres ); goto Done; } // // Cleanup and return. // Done: SysFreeString( bstrNamespace ); if ( pIWbemLocator ) { pIWbemLocator->Release(); } if ( status == ERROR_SUCCESS && FAILED( hres ) ) { status = HRES_TO_STATUS( hres ); } if ( status == ERROR_SUCCESS ) { g_pIWbemServices = pIWbemServices; } return status; } // DnscmdWmi_Initialize DNS_STATUS DnscmdWmi_Free( VOID ) /*++ Routine Description: Close WMI session and free globals. Arguments: None. Return Value: None. --*/ { DBG_FN( "DnscmdWmi_Free" ) DNSCMD_CHECK_WMI_ENABLED(); if ( g_pIWbemServices ) { g_pIWbemServices->Release(); g_pIWbemServices = NULL; } CoUninitialize(); return ERROR_SUCCESS; } // DnscmdWmi_Free DNS_STATUS DnscmdWmi_ProcessDnssrvQuery( IN PSTR pszZoneName, IN PCSTR pszQuery ) /*++ Routine Description: Perform query. Arguments: pszZoneName -- zone name or NULL for server level query pszQuery -- query name Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ { DNS_STATUS status = ERROR_SUCCESS; BSTR bstrClassName = NULL; IEnumWbemClassObject * pEnum = NULL; IWbemClassObject * pObj = NULL; ULONG returnedCount = 1; DNSCMD_CHECK_WMI_ENABLED(); // // Get WMI object. // status = getEnumerator( pszZoneName, &pEnum ); if ( status != ERROR_SUCCESS ) { goto Done; } status = getNextObjectInEnum( pEnum, &pObj ); if ( status != ERROR_SUCCESS || !pObj ) { goto Done; } printWmiObjectProperties( pObj ); // // Cleanup and return. // Done: SysFreeString( bstrClassName ); if ( pObj ) { pObj->Release(); } if ( pEnum ) { pEnum->Release(); } return status; } // DnscmdWmi_ProcessDnssrvQuery DNS_STATUS DnscmdWmi_ProcessEnumZones( IN DWORD dwFilter ) /*++ Routine Description: Enumerate zones. Arguments: dwFilter -- filter Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ { DNS_STATUS status = ERROR_SUCCESS; BSTR bstrClassName = NULL; IEnumWbemClassObject * pEnum = NULL; IWbemClassObject * pObj = NULL; HRESULT hres = 0; ULONG returnedCount = 1; DNSCMD_CHECK_WMI_ENABLED(); // // Create zone enumerator. // bstrClassName = SysAllocString( L"MicrosoftDNS_Zone" ); if ( !bstrClassName ) { ASSERT( bstrClassName ); status = DNS_ERROR_NO_MEMORY; goto Done; } hres = g_pIWbemServices->CreateInstanceEnum( bstrClassName, 0, // flags NULL, // context &pEnum ); if ( FAILED( hres ) ) { goto Done; } ASSERT( pEnum ); // // Enumerate zones. // while ( returnedCount == 1 ) { VARIANT val; CIMTYPE cimtype = 0; PWSTR pwszVal = NULL; VariantInit( &val ); status = getNextObjectInEnum( pEnum, &pObj, FALSE ); if ( status != ERROR_SUCCESS || !pObj ) { goto Done; } // // Print properties for this zone. // #define CHECK_HRES( hresult, propname ) \ if ( FAILED( hresult ) ) \ { \ printf( "\n\nWMI error 0x%08X reading property %S!\n", \ hresult, propname ); \ goto Done; \ } hres = pObj->Get( L"Name", 0, &val, &cimtype, NULL ); CHECK_HRES( hres, L"Name" ); printf( " %-29S", valueToString( cimtype, &val, &pwszVal ) ); free( pwszVal ); VariantClear( &val ); hres = pObj->Get( L"ZoneType", 0, &val, &cimtype, NULL ); CHECK_HRES( hres, L"ZoneType" ); ASSERT( val.vt == VT_I4 ); printf( "%3d ", val.lVal ); VariantClear( &val ); hres = pObj->Get( L"DsIntegrated", 0, &val, &cimtype, NULL ); CHECK_HRES( hres, L"DsIntegrated" ); ASSERT( val.vt == VT_BOOL ); printf( "%-4S ", val.boolVal ? L"DS" : L"file" ); VariantClear( &val ); hres = pObj->Get( L"Reverse", 0, &val, &cimtype, NULL ); CHECK_HRES( hres, L"Reverse" ); ASSERT( val.vt == VT_BOOL ); printf( "%-3S ", val.boolVal ? L"Rev" : L"" ); VariantClear( &val ); hres = pObj->Get( L"AutoCreated", 0, &val, &cimtype, NULL ); CHECK_HRES( hres, L"AutoCreated" ); ASSERT( val.vt == VT_BOOL ); printf( "%-4S ", val.boolVal ? L"Auto" : L"" ); VariantClear( &val ); hres = pObj->Get( L"AllowUpdate", 0, &val, &cimtype, NULL ); CHECK_HRES( hres, L"AllowUpdate" ); ASSERT( val.vt == VT_BOOL ); printf( "Up=%d ", val.boolVal ? 1 : 0 ); VariantClear( &val ); hres = pObj->Get( L"Aging", 0, &val, &cimtype, NULL ); CHECK_HRES( hres, L"Aging" ); ASSERT( val.vt == VT_BOOL ); printf( "%-5S ", val.boolVal ? L"Aging" : L"" ); VariantClear( &val ); hres = pObj->Get( L"Paused", 0, &val, &cimtype, NULL ); CHECK_HRES( hres, L"Paused" ); ASSERT( val.vt == VT_BOOL ); printf( "%-6S ", val.boolVal ? L"Paused" : L"" ); VariantClear( &val ); hres = pObj->Get( L"Shutdown", 0, &val, &cimtype, NULL ); CHECK_HRES( hres, L"Shutdown" ); ASSERT( val.vt == VT_BOOL ); printf( "%-6S", val.boolVal ? L"Shutdn" : L"" ); VariantClear( &val ); printf( "\n\n" ); } // // Cleanup and return. // Done: SysFreeString( bstrClassName ); if ( pObj ) { pObj->Release(); } if ( pEnum ) { pEnum->Release(); } if ( status == ERROR_SUCCESS && FAILED( hres ) ) { status = HRES_TO_STATUS( hres ); } return status; } // DnscmdWmi_ProcessEnumZones DNS_STATUS DnscmdWmi_ProcessZoneInfo( IN LPSTR pszZone ) /*++ Routine Description: Enumerate zones. Arguments: dwFilter -- filter Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ { DNS_STATUS status = ERROR_SUCCESS; IWbemClassObject * pObj = NULL; IEnumWbemClassObject * pEnum = NULL; ULONG returnedCount = 1; WCHAR wsz[ 1024 ]; DNSCMD_CHECK_WMI_ENABLED(); // // Get WMI object. // status = getEnumerator( pszZone, &pEnum ); if ( status != ERROR_SUCCESS ) { goto Done; } status = getNextObjectInEnum( pEnum, &pObj, FALSE ); if ( status != ERROR_SUCCESS || !pObj ) { goto Done; } printWmiObjectProperties( pObj ); // // Cleanup and return. // Done: if ( pObj ) { pObj->Release(); } if ( pEnum ) { pEnum->Release(); } return status; } // DnscmdWmi_ProcessZoneInfo DNS_STATUS DnscmdWmi_ProcessEnumRecords( IN LPSTR pszZone, IN LPSTR pszNode, IN BOOL fDetail, IN DWORD dwFlags ) /*++ Routine Description: Enumerate Records. Arguments: pszZone -- zone name pszNode -- name of root node to at which to enumerate records fDetail -- print summary or full detail dwFlags -- search flags Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ { DNS_STATUS status = ERROR_SUCCESS; BSTR bstrWQL = NULL; BSTR bstrQuery = NULL; IWbemClassObject * pObj = NULL; IEnumWbemClassObject * pEnum = NULL; HRESULT hres = 0; ULONG returnedCount = 1; WCHAR wsz[ 1024 ]; DNSCMD_CHECK_WMI_ENABLED(); // // Query for zone. // if ( pszNode == NULL || strcmp( pszNode, "@" ) == 0 ) { wsprintfW( wsz, L"select * from MicrosoftDNS_ResourceRecord " L"where ContainerName='%S'", pszZone ); } else { wsprintfW( wsz, L"select * from MicrosoftDNS_ResourceRecord " L"where DomainName='%S'", pszNode ); } bstrWQL = SysAllocString( L"WQL" ); bstrQuery = SysAllocString( wsz ); if ( !bstrWQL || !bstrQuery ) { status = DNS_ERROR_NO_MEMORY; goto Done; } hres = g_pIWbemServices->ExecQuery( bstrWQL, bstrQuery, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum ); if ( FAILED( hres ) ) { goto Done; } ASSERT( pEnum ); // // Dump results. // while ( 1 ) { status = getNextObjectInEnum( pEnum, &pObj ); if ( status != ERROR_SUCCESS || !pObj ) { break; } if ( fDetail ) { printWmiObjectProperties( pObj ); } else { VARIANT val; CIMTYPE cimtype = 0; PWSTR pwszVal = NULL; VariantInit( &val ); hres = pObj->Get( L"TextRepresentation", 0, &val, &cimtype, NULL ); CHECK_HRES( hres, L"TextRepresentation" ); printf( "%S", valueToString( cimtype, &val, &pwszVal ) ); free( pwszVal ); VariantClear( &val ); printf( "\n" ); } } // // Cleanup and return. // Done: SysFreeString( bstrWQL ); SysFreeString( bstrQuery ); if ( pObj ) { pObj->Release(); } if ( pEnum ) { pEnum->Release(); } if ( status == ERROR_SUCCESS && FAILED( hres ) ) { status = HRES_TO_STATUS( hres ); } return status; } // DnscmdWmi_ProcessEnumRecords DNS_STATUS DnscmdWmi_ResetProperty( IN LPSTR pszZone, IN LPSTR pszProperty, IN DWORD cimType, IN PVOID value ) /*++ Routine Description: Reset a server or zone property. Arguments: pszZone -- zone name - NULL for server property pszProperty -- name of property to set cimType -- variant type of the property, use one of: VT_I4 - DWORD VT_BSTR - string ? - IP list value -- new value for property, interpreted based on cimtype: VT_I4 - cast pointer directly DWORD VT_BSTR - pointer to UTF-8 string ? - pointer to IP list Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ { DNS_STATUS status = ERROR_SUCCESS; BSTR bstrWQL = NULL; BSTR bstrQuery = NULL; BSTR bstrPropName = NULL; IWbemClassObject * pObj = NULL; IEnumWbemClassObject * pEnum = NULL; HRESULT hres = 0; ULONG returnedCount = 1; WCHAR wsz[ 1024 ]; PWSTR pwszPropertyName = NULL; PWSTR pwszPropertyValue = NULL; DNSCMD_CHECK_WMI_ENABLED(); // // Get WMI object. // status = getEnumerator( pszZone, &pEnum ); if ( status != ERROR_SUCCESS ) { goto Done; } status = getNextObjectInEnum( pEnum, &pObj ); if ( status != ERROR_SUCCESS || !pObj ) { goto Done; } // // Print the object's RELPATH (warm fuzzy). // VARIANT var; status = getRelpath( pObj, &var ); if ( status != ERROR_SUCCESS ) { goto Done; } printf( "%S\n\n", V_BSTR( &var) ); // // Set the property. // pwszPropertyName = ( PWSTR ) Dns_NameCopyAllocate( pszProperty, 0, DnsCharSetUtf8, DnsCharSetUnicode ); bstrPropName = SysAllocString( pwszPropertyName ); VariantClear( &var ); switch ( cimType ) { case VT_BSTR: pwszPropertyValue = ( PWSTR ) Dns_NameCopyAllocate( ( PCHAR ) value, 0, DnsCharSetUtf8, DnsCharSetUnicode ); V_VT( &var ) = VT_BSTR; V_BSTR( &var ) = pwszPropertyValue; break; case PRIVATE_VT_IPARRAY: { SAFEARRAY * psa = createSafeArrayForIpArray( ( PIP_ARRAY ) value ); V_VT( &var ) = VT_ARRAY | VT_BSTR; V_ARRAY( &var ) = psa; break; } default: // Assume this is DWORD property. V_VT( &var ) = VT_I4; V_I4( &var ) = ( DWORD ) ( DWORD_PTR ) value; break; } hres = pObj->Put( bstrPropName, 0, &var, 0 ); VariantClear( &var ); if ( !SUCCEEDED( hres ) ) { printf( "WMI: unable to Put property error=0x%08X\n", hres ); goto Done; } // // Commit the change back to WMI. // hres = g_pIWbemServices->PutInstance( pObj, 0, NULL, NULL ); if ( !SUCCEEDED( hres ) ) { printf( "WMI: unable to commit property error=0x%08X\n", hres ); goto Done; } // // Cleanup and return. // Done: FREE_HEAP( pwszPropertyName ); FREE_HEAP( pwszPropertyValue ); SysFreeString( bstrPropName ); if ( pObj ) { pObj->Release(); } if ( pEnum ) { pEnum->Release(); } if ( status == ERROR_SUCCESS && FAILED( hres ) ) { status = HRES_TO_STATUS( hres ); } return status; } // DnscmdWmi_ResetDwordProperty /*++ Routine Description: Reset server level forwarders. Arguments: cForwarders -- number of forwarder IP addresses aipForwarders -- array of forwarder IP addresses dwForwardTimeout -- timeout fSlave -- slave flag Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ DNS_STATUS DnscmdWmi_ProcessResetForwarders( IN DWORD cForwarders, IN PIP_ADDRESS aipForwarders, IN DWORD dwForwardTimeout, IN DWORD fSlave ) { DNS_STATUS status = ERROR_SUCCESS; IEnumWbemClassObject * pEnum = NULL; IWbemClassObject * pObj = NULL; SAFEARRAY * psa = NULL; HRESULT hres = 0; VARIANT var; VariantInit( &var ); // // Get WMI object for server. // status = getEnumerator( NULL, &pEnum ); if ( status != ERROR_SUCCESS ) { goto Done; } status = getNextObjectInEnum( pEnum, &pObj ); if ( status != ERROR_SUCCESS || !pObj ) { goto Done; } // // Set up parameters. // psa = createSafeArrayForIpList( cForwarders, aipForwarders ); if ( !psa ) { status = ERROR_INVALID_PARAMETER; goto Done; } V_VT( &var ) = VT_ARRAY | VT_BSTR; V_ARRAY( &var ) = psa; hres = pObj->Put( MYTEXT( DNS_REGKEY_FORWARDERS ), 0, &var, 0 ); VariantClear( &var ); if ( !SUCCEEDED( hres ) ) { printf( "WMI: unable to Put property %S error=0x%08X\n", MYTEXT( DNS_REGKEY_FORWARDERS ), hres ); goto Done; } V_VT( &var ) = VT_I4; V_I4( &var ) = dwForwardTimeout; hres = pObj->Put( MYTEXT( DNS_REGKEY_FORWARD_TIMEOUT ), 0, &var, 0 ); VariantClear( &var ); if ( !SUCCEEDED( hres ) ) { printf( "WMI: unable to Put property %S error=0x%08X\n", MYTEXT( DNS_REGKEY_FORWARD_TIMEOUT ), hres ); goto Done; } V_VT( &var ) = VT_BOOL; V_BOOL( &var ) = ( VARIANT_BOOL ) fSlave; hres = pObj->Put( MYTEXT( DNS_REGKEY_SLAVE ), 0, &var, 0 ); VariantClear( &var ); if ( !SUCCEEDED( hres ) ) { printf( "WMI: unable to Put property %S error=0x%08X\n", MYTEXT( DNS_REGKEY_SLAVE ), hres ); goto Done; } // // Commit the change back to WMI. // hres = g_pIWbemServices->PutInstance( pObj, 0, NULL, NULL ); if ( !SUCCEEDED( hres ) ) { printf( "WMI: unable to commit property error=0x%08X\n", hres ); goto Done; } // // Cleanup and return. // Done: if ( pObj ) { pObj->Release(); } if ( pEnum ) { pEnum->Release(); } VariantClear( &var ); if ( status == ERROR_SUCCESS && FAILED( hres ) ) { status = hres; } return status; } /*++ Routine Description: Send generic operation to server. Arguments: pszZone -- zone name or NULL for server level operation pszOperation -- string identifying operation dwTypeId -- DNS RPC data type of data at pvData pvData -- DNS RPC data in DNS RPC union format Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ DNS_STATUS DnscmdWmi_ProcessDnssrvOperation( IN LPSTR pszZoneName, IN LPSTR pszOperation, IN DWORD dwTypeId, IN PVOID pvData ) { DNS_STATUS status = ERROR_SUCCESS; HRESULT hres = 0; IEnumWbemClassObject * pEnum = NULL; IWbemClassObject * pObj = NULL; SAFEARRAY * psa = NULL; PWSTR pwszOperation = NULL; VARIANT var; VariantInit( &var ); // // Get WMI object. // status = getEnumerator( pszZoneName, &pEnum ); if ( status != ERROR_SUCCESS ) { goto Done; } status = getNextObjectInEnum( pEnum, &pObj ); if ( status != ERROR_SUCCESS || !pObj ) { goto Done; } // // Process operation. // pwszOperation = ( PWSTR ) Dns_NameCopyAllocate( pszOperation, 0, DnsCharSetUtf8, DnsCharSetUnicode ); if ( !pwszOperation ) { status = DNS_ERROR_NO_MEMORY; goto Done; } if ( _stricmp( pszOperation, DNS_REGKEY_ZONE_MASTERS ) == 0 || _stricmp( pszOperation, DNS_REGKEY_ZONE_LOCAL_MASTERS ) == 0 ) { // // For these properties do a simple Put operation by converting // the DNS RPC data into VARIANT format and calling Put. // switch ( dwTypeId ) { case DNSSRV_TYPEID_IPARRAY: { PIP_ARRAY pip = ( PIP_ARRAY ) pvData; psa = createSafeArrayForIpList( pip ? pip->AddrCount : 0, pip ? pip->AddrArray : NULL ); if ( !psa ) { status = ERROR_INVALID_PARAMETER; goto Done; } V_VT( &var ) = VT_ARRAY | VT_BSTR; V_ARRAY( &var ) = psa; hres = pObj->Put( pwszOperation, 0, &var, 0 ); break; } default: status = ERROR_NOT_SUPPORTED; break; } // // Commit the Put operation. // if ( status == ERROR_SUCCESS && SUCCEEDED( hres ) ) { hres = g_pIWbemServices->PutInstance( pObj, 0, NULL, NULL ); if ( FAILED( hres ) ) { printf( "WMI: unable to commit property %s error=0x%08X\n", pszOperation, hres ); goto Done; } } } else if ( _stricmp( pszOperation, DNSSRV_OP_ZONE_DELETE ) == 0 || _stricmp( pszOperation, DNSSRV_OP_ZONE_DELETE_FROM_DS ) == 0 ) { // // Delete the zone. // VARIANT relpath; status = getRelpath( pObj, &relpath ); if ( status == ERROR_SUCCESS ) { hres = g_pIWbemServices->DeleteInstance( V_BSTR( &relpath ), 0, NULL, NULL ); } VariantClear( &relpath ); } else { status = ERROR_NOT_SUPPORTED; } // // Cleanup and return. // Done: if ( psa ) { SafeArrayDestroy( psa ); } if ( pwszOperation ) { FREE_HEAP( pwszOperation ); } if ( pObj ) { pObj->Release(); } if ( pEnum ) { pEnum->Release(); } VariantClear( &var ); if ( status == ERROR_SUCCESS && FAILED( hres ) ) { status = hres; } return status; } // DnscmdWmi_ProcessDnssrvOperation DNS_STATUS DnscmdWmi_ProcessRecordAdd( IN LPSTR pszZoneName, IN LPSTR pszNodeName, IN PDNS_RPC_RECORD prrRpc, IN DWORD Argc, IN LPSTR * Argv ) /*++ Routine Description: Add or delete a resource record. This function will take of the necessary some data from the RPC record and some from the argument list. Arguments: pszZoneName -- zone name pszNodeName -- name of property to set prrRpc -- RPC record Argc -- count of arguments used to create RPC record Argv -- arguments used to create RPC record Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ { DNS_STATUS status = ERROR_SUCCESS; PWSTR pwszZoneName = NULL; PWSTR pwszArgs = NULL; PWSTR pwszCurrent; IWbemClassObject * pClassObj = NULL; IWbemClassObject * pServerObj = NULL; IWbemClassObject * pInSig = NULL; IWbemClassObject * pOutSig = NULL; IWbemClassObject * pInParams = NULL; IEnumWbemClassObject * pEnum = NULL; HRESULT hres = 0; BSTR bstrClassName; BSTR bstrMethodName; VARIANT var; int len; int i; DNSCMD_CHECK_WMI_ENABLED(); // // Allocate and initialize various stuff. // VariantInit( &var ); bstrClassName = SysAllocString( L"MicrosoftDNS_ResourceRecord" ); bstrMethodName = SysAllocString( L"CreateInstanceFromTextRepresentation" ); if ( !bstrClassName || !bstrMethodName ) { status = DNS_ERROR_NO_MEMORY; goto Done; } pwszZoneName = ( PWSTR ) Dns_NameCopyAllocate( pszZoneName, 0, DnsCharSetUtf8, DnsCharSetUnicode ); if ( !pwszZoneName ) { status = DNS_ERROR_NO_MEMORY; goto Done; } // // Get WMI class object for Resource Record class. // hres = g_pIWbemServices->GetObject( bstrClassName, WBEM_FLAG_RETURN_WBEM_COMPLETE, NULL, &pClassObj, NULL ); if ( FAILED( hres ) ) { goto Done; } ASSERT( pClassObj ); // // Get WMI object for server. // status = getEnumerator( NULL, &pEnum ); if ( status != ERROR_SUCCESS ) { goto Done; } ASSERT( pEnum ); status = getNextObjectInEnum( pEnum, &pServerObj ); if ( status != ERROR_SUCCESS ) { goto Done; } ASSERT( pServerObj ); // // Get WMI method signature for CreateInstanceFromTextRepresentation. // hres = pClassObj->GetMethod( bstrMethodName, 0, &pInSig, &pOutSig ); if ( FAILED( hres ) ) { goto Done; } if ( pInSig == NULL ) { status = ERROR_INVALID_PARAMETER; goto Done; } // // Create an instance of the method input parameters. // hres = pInSig->SpawnInstance( 0, &pInParams ); if ( FAILED( hres ) ) { goto Done; } ASSERT( pInParams ); // // Collect the arguments into one big string // -> owner name // -> record class // -> record type // -> Argv array (space separated) // len = Argc * 2 + // for spaces 30 + // for record type strlen( pszNodeName ); for ( i = 0; i < ( int ) Argc; ++i ) { len += strlen( Argv[ i ] ); } pwszCurrent = pwszArgs = new WCHAR [ len * sizeof( WCHAR ) ]; if ( !pwszArgs ) { status = DNS_ERROR_NO_MEMORY; goto Done; } for ( i = -3; i < ( int ) Argc; ++i ) { CHAR szBuff[ 40 ]; PSTR psz; if ( i == -3 ) { psz = pszNodeName; } else if ( i == -2 ) { psz = "IN"; } else if ( i == -1 ) { psz = Dns_RecordStringForType( prrRpc->wType ); } else { psz = Argv[ i ]; } PWSTR pwsz = ( PWSTR ) Dns_NameCopyAllocate( psz, 0, DnsCharSetUtf8, DnsCharSetUnicode ); if ( !pwsz ) { status = DNS_ERROR_NO_MEMORY; goto Done; } if ( pwszCurrent != pwszArgs ) { wcscpy( pwszCurrent++, L" " ); } wcscpy( pwszCurrent, pwsz ); pwszCurrent += wcslen( pwsz ); } // // Set method input parameters. // getRelpath( pServerObj, &var ); hres = pInParams->Put( L"DnsServerName", 0, &var, 0 ); VariantClear( &var ); V_VT( &var ) = VT_BSTR; V_BSTR( &var ) = SysAllocString( pwszZoneName ); hres = pInParams->Put( L"ContainerName", 0, &var, 0 ); VariantClear( &var ); V_VT( &var ) = VT_BSTR; V_BSTR( &var ) = SysAllocString( pwszArgs ); hres = pInParams->Put( L"TextRepresentation", 0, &var, 0 ); VariantClear( &var ); // // Execute the method (finally!) // hres = g_pIWbemServices->ExecMethod( bstrClassName, bstrMethodName, 0, // flags NULL, // context pInParams, // input params NULL, // output params NULL ); // call result if ( FAILED( hres ) ) { goto Done; } // // Cleanup and return. // Done: VariantClear( &var ); FREE_HEAP( pwszZoneName ); delete [] pwszArgs; SysFreeString( bstrMethodName ); SysFreeString( bstrClassName ); wmiRelease( pEnum ); wmiRelease( pClassObj ); wmiRelease( pServerObj ); wmiRelease( pInSig ); wmiRelease( pOutSig ); wmiRelease( pInParams ); if ( status == ERROR_SUCCESS && FAILED( hres ) ) { status = HRES_TO_STATUS( hres ); } return status; } // DnscmdWmi_ProcessRecordAdd DNS_STATUS DnscmdWmi_GetStatistics( IN DWORD dwStatId ) /*++ Routine Description: Retrieves and dumps all statistics matching the dwStatId mask. Arguments: dwStatId -- statistic filter Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ { DNS_STATUS status = ERROR_SUCCESS; WCHAR wsz[ 1024 ]; BSTR bstrWQL = NULL; BSTR bstrQuery = NULL; HRESULT hres = 0; IEnumWbemClassObject * pEnum = NULL; IWbemClassObject * pObj = NULL; // // Execute query for statistics. // wsprintfW( wsz, L"select * from MicrosoftDNS_Statistic" ); bstrWQL = SysAllocString( L"WQL" ); bstrQuery = SysAllocString( wsz ); if ( !bstrWQL || !bstrQuery ) { status = DNS_ERROR_NO_MEMORY; goto Done; } hres = g_pIWbemServices->ExecQuery( bstrWQL, bstrQuery, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum ); if ( FAILED( hres ) ) { status = hres; goto Done; } // // Dump query results. // VARIANT varLastColl; VariantInit( &varLastColl ); while ( 1 ) { status = getNextObjectInEnum( pEnum, &pObj, FALSE ); if ( status != ERROR_SUCCESS || !pObj ) { break; } CIMTYPE cimColl = 0; CIMTYPE cimName = 0; CIMTYPE cimValue = 0; CIMTYPE cimStringValue = 0; VARIANT varColl; VARIANT varName; VARIANT varValue; VARIANT varStringValue; VariantInit( &varColl ); VariantInit( &varName ); VariantInit( &varValue ); VariantInit( &varStringValue ); hres = pObj->Get( L"CollectionName", 0, &varColl, &cimColl, NULL ); CHECK_HRES( hres, L"CollectionName" ); hres = pObj->Get( L"Name", 0, &varName, &cimName, NULL ); CHECK_HRES( hres, L"Name" ); hres = pObj->Get( L"Value", 0, &varValue, &cimValue, NULL ); CHECK_HRES( hres, L"Value" ); hres = pObj->Get( L"StringValue", 0, &varStringValue, &cimValue, NULL ); CHECK_HRES( hres, L"StringValue" ); if ( V_VT( &varLastColl ) == VT_EMPTY || wcscmp( V_BSTR( &varLastColl ), V_BSTR( &varColl ) ) != 0 ) { // // Entering new collection. NOTE: this assumes that stats // are ordered by collection. Probably not a great assumption // but it works for now. // printf( "\n%S:\n", V_BSTR( &varColl ) ); hres = VariantCopy( &varLastColl, &varColl ); if ( FAILED( hres ) ) { goto Done; } } printf( " %-35S = ", V_BSTR( &varName ) ); if ( V_VT( &varValue ) != VT_NULL ) { printf( "%lu", V_UI4( &varValue ) ); // printf( "%lu (0x%08X)", V_UI4( &varValue ), V_UI4( &varValue ) ); } else if ( V_VT( &varStringValue ) == VT_BSTR ) { printf( "%S", V_BSTR( &varStringValue ) ); } else { printf( "invalid value!" ); } printf( "\n" ); VariantClear( &varColl ); VariantClear( &varName ); VariantClear( &varValue ); VariantClear( &varStringValue ); } VariantClear( &varLastColl ); // // Cleanup and return // Done: SysFreeString( bstrWQL ); SysFreeString( bstrQuery ); if ( pEnum ) { pEnum->Release(); } if ( pObj ) { pObj->Release(); } if ( status == ERROR_SUCCESS && FAILED( hres ) ) { status = HRES_TO_STATUS( hres ); } return status; } DNS_STATUS DnscmdWmi_ProcessResetZoneSecondaries( IN LPSTR pszZoneName, IN DWORD fSecureSecondaries, IN DWORD cSecondaries, IN PIP_ADDRESS aipSecondaries, IN DWORD fNotifyLevel, IN DWORD cNotify, IN PIP_ADDRESS aipNotify ) /*++ Routine Description: Send "zone reset secondaries" command to the server to reset the zone secondary and notify list parameters. Arguments: pszZoneName -- zone name fSecureSecondaries -- secondary directive (ZONE_SECSECURE_XXX) cSecondaries -- count of IP addresses in aipSecondaries aipSecondaries -- secondary server IP address array fNotifyLevel -- notify directive (ZONE_NOTIFY_XXX) cNotify -- count of IP addresses in aipNotify aipNotify -- notify server IP address array Return Value: ERROR_SUCCESS if successful or error code on failure. --*/ { DNS_STATUS status = ERROR_SUCCESS; BSTR bstrClassName; BSTR bstrMethodName; PWSTR pwszZoneName = NULL; IWbemClassObject * pObj = NULL; IWbemClassObject * pClassObj = NULL; IWbemClassObject * pInSig = NULL; IWbemClassObject * pOutSig = NULL; IWbemClassObject * pInParams = NULL; IEnumWbemClassObject * pEnum = NULL; VARIANT var; HRESULT hres; SAFEARRAY * psa; DNSCMD_CHECK_WMI_ENABLED(); // // Allocate and initialize various stuff. // VariantInit( &var ); bstrClassName = SysAllocString( L"MicrosoftDNS_Zone" ); bstrMethodName = SysAllocString( L"ResetSecondaries" ); if ( !bstrClassName || !bstrMethodName ) { status = DNS_ERROR_NO_MEMORY; goto Done; } // // Get WMI class object for the Zone class. // hres = g_pIWbemServices->GetObject( bstrClassName, WBEM_FLAG_RETURN_WBEM_COMPLETE, NULL, &pClassObj, NULL ); if ( FAILED( hres ) ) { goto Done; } ASSERT( pClassObj ); // // Get WMI object for specified zone. // status = getEnumerator( pszZoneName, &pEnum ); if ( status != ERROR_SUCCESS ) { goto Done; } status = getNextObjectInEnum( pEnum, &pObj ); if ( status != ERROR_SUCCESS || !pObj ) { goto Done; } // // Get WMI method signature for ResetSecondaries. // hres = pClassObj->GetMethod( bstrMethodName, 0, &pInSig, &pOutSig ); if ( FAILED( hres ) ) { goto Done; } if ( pInSig == NULL ) { status = ERROR_INVALID_PARAMETER; goto Done; } // // Create an instance of the method input parameters. // hres = pInSig->SpawnInstance( 0, &pInParams ); if ( FAILED( hres ) ) { goto Done; } ASSERT( pInParams ); // // Set method input parameters. // printWmiObjectProperties( pInParams ); { BSTR b = NULL; pInParams->GetObjectText( 0, &b ); printf( "\nObjectText:\n%S\n", b ); } VariantClear( &var ); { BSTR bstr = SysAllocString( L"SecureSecondaries" ); V_VT( &var ) = VT_UI4; V_UI4( &var ) = fSecureSecondaries; hres = pInParams->Put( bstr, 0, &var, 0 ); VariantClear( &var ); } #if 0 V_VT( &var ) = VT_UI4; V_UI4( &var ) = fSecureSecondaries; hres = pInParams->Put( L"SecureSecondaries", 0, &var, 0 ); VariantClear( &var ); #endif V_VT( &var ) = VT_UI4; V_UI4( &var ) = fNotifyLevel; hres = pInParams->Put( L"Notify", 0, &var, 0 ); VariantClear( &var ); psa = createSafeArrayForIpList( cSecondaries, aipSecondaries ); if ( !psa ) { status = DNS_ERROR_NO_MEMORY; goto Done; } V_VT( &var ) = VT_ARRAY | VT_BSTR; V_ARRAY( &var ) = psa; hres = pInParams->Put( L"SecondaryServers", 0, &var, 0 ); VariantClear( &var ); psa = createSafeArrayForIpList( cNotify, aipNotify ); if ( !psa ) { status = DNS_ERROR_NO_MEMORY; goto Done; } V_VT( &var ) = VT_ARRAY | VT_BSTR; V_ARRAY( &var ) = psa; hres = pInParams->Put( L"NotifyServers", 0, &var, 0 ); VariantClear( &var ); // // Execute the method. // hres = g_pIWbemServices->ExecMethod( bstrClassName, bstrMethodName, 0, // flags NULL, // context pInParams, // input params NULL, // output params NULL ); // call result if ( FAILED( hres ) ) { goto Done; } // // Cleanup and return. // Done: VariantClear( &var ); FREE_HEAP( pwszZoneName ); SysFreeString( bstrMethodName ); SysFreeString( bstrClassName ); wmiRelease( pEnum ); wmiRelease( pClassObj ); wmiRelease( pInSig ); wmiRelease( pOutSig ); wmiRelease( pInParams ); if ( status == ERROR_SUCCESS && FAILED( hres ) ) { status = HRES_TO_STATUS( hres ); } return status; } // DnscmdWmi_ProcessResetZoneSecondaries // // End dnsc_wmi.c //