We help IT Professionals succeed at work.

We've partnered with Certified Experts, Carl Webster and Richard Faulkner, to bring you a podcast all about Citrix Workspace, moving to the cloud, and analytics & intelligence. Episode 2 coming soon!Listen Now

x

Why is IEnumWbemClassObject->Next returning E_ACCESSDENIED

gmain
gmain asked
on
Medium Priority
2,800 Views
Last Modified: 2012-06-22
I am trying to query the WMI information on other computers on the local network.  All of the computers are running Windows XP (with SP) and are on the same local workgroup.  All of the computers have the same administrator password which has been verified by successfully connecting to each computer and mapping to the C$ share using the administrator username/password.  However, the following code works correctly on 3 out of the 4 computers.  On one of the computers the code works up until the call to enumerator->Next which failes with an HRESULT of E_ACCESSDENIED.  First of all, how could the administrator get an access denied result.  Second, why does it only get an access denied on the next and not on any of the prior calls to connect to the computer or to setup the WMI query.  Thirdly, why would this work on 3 other extremely similar computers and not the 4th?

int main(int argc,char** argv)
{
      USES_CONVERSION;
      HRESULT hres;
      char username[]="administrator";
      char password[]="adminPassword";
      char domain[]="";
      char wmiNamespace[]="\\\\ServerName\\ROOT\\CIMV2";

      hres =  CoInitializeEx(0, COINIT_MULTITHREADED);
      if (FAILED(hres))
      {
            cout << "Failed to initialize COM library. Error code = 0x" << hex << hres << endl;
            return 1;                  // Program has failed.
      }

      hres =  CoInitializeSecurity(
            NULL,
            -1,                          // COM authentication
            NULL,                        // Authentication services
            NULL,                        // Reserved
            RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication
            RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation  
            NULL,                        // Authentication info
            EOAC_NONE,                   // Additional capabilities
            NULL                         // Reserved
      );
                     
    if (FAILED(hres)) {
        cout << "Failed to initialize security. Error code = 0x" << hex << hres << endl;
        CoUninitialize();
        return 1;                    // Program has failed.
    }

      IWbemLocator *pLoc = NULL;
      hres = CoCreateInstance( CLSID_WbemLocator,0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);
      if (FAILED(hres))
      {
            cout << "Failed to create IWbemLocator object." << " Err code = 0x" << hex << hres << endl;
            CoUninitialize();
            return 1;                 // Program has failed.
      }

      IWbemServices *pSvc = NULL;
      hres = pLoc->ConnectServer(
            T2W(wmiNamespace),                              // Object path of WMI namespace
            T2W(username),                    // User name. NULL = current user
            T2W(password),                    // User password. NULL = current
            0,                       // Locale. NULL indicates current              
            WBEM_FLAG_CONNECT_USE_MAX_WAIT,                    // Security flags.
            0,                       // Authority (e.g. Kerberos)        
            0,                       // Context object
            &pSvc                    // pointer to IWbemServices proxy
      );

      if (FAILED(hres))
      {
            cout << "Could not connect. Error code = 0x" << hex << hres << endl;
            pLoc->Release();      
            CoUninitialize();
            return 1;                // Program has failed.
      }

      cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;

      SEC_WINNT_AUTH_IDENTITY        authidentity;
      SecureZeroMemory( &authidentity, sizeof(authidentity) );
      authidentity.User = (LPUSTR)T2W( (LPTSTR)(LPCTSTR)username);
      authidentity.UserLength = strlen(username);
      authidentity.Domain = (LPUSTR)T2W( (LPTSTR)(LPCTSTR)domain);
      authidentity.DomainLength = strlen(domain );
      authidentity.Password = (LPUSTR)T2W( (LPTSTR)(LPCTSTR)password);
      authidentity.PasswordLength = strlen(password );
      authidentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;

      hres = CoSetProxyBlanket(
            pSvc,                        // Indicates the proxy to set
            RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
            RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
            NULL,                        // Server principal name
            RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx
            RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
            &authidentity,                        // client identity
            EOAC_NONE                    // proxy capabilities
      );

      if (FAILED(hres))
      {
            cout << "Could not set proxy blanket. Error code = 0x" << hex << hres << endl;
            pSvc->Release();
            pLoc->Release();      
            CoUninitialize();
            return 1;               // Program has failed.
      }

      IEnumWbemClassObject* pEnumerator = NULL;
      hres = pSvc->ExecQuery( bstr_t("WQL"),
            bstr_t("SELECT * FROM Win32_Desktop"),
            WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
   
      if (FAILED(hres))
      {
            cout << "Query for operating system name failed."
                  << " Error code = 0x"
                  << hex << hres << endl;
            pSvc->Release();
            pLoc->Release();
            CoUninitialize();
            return 1;               // Program has failed.
      }

      IWbemClassObject *pclsObj=NULL;
      ULONG uReturn = 0;
      while (pEnumerator)
      {
            HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
            if(0 == uReturn) break;
            VARIANT vtProp;
            VariantInit(&vtProp);
            hr = pclsObj->Get(L"ScreenSaverExecutable", 0, &vtProp, 0, 0);    
            cout << "Executable: ";
            char* executableName = W2T(vtProp.bstrVal);
            cout << executableName;
            VariantClear(&vtProp);
            pclsObj->Release();
    }
      cout<<endl<<"End."<<endl;
      pSvc->Release();
      pLoc->Release();
      pEnumerator->Release();
      CoUninitialize();
}
Comment
Watch Question

x4u

Commented:
>> First of all, how could the administrator get an access denied result.
Administrator accounts do not have access rights to everything on Windows just because they are administrators. It's possible to remove access rights even for adminstrators from files, directories (i.e. by default no access to /System Volume Information) or registry subtrees (i.e. cannot write to HKLM\SYSTEM\CurrentControlSet\Enum\Root by default). Although Administrators can modify all access rights they want and as a consequence of this gain access to everything. Revoking administrators (i.e. your own) access rights is sometimes actually quite usefull, i.e. to prevent programs (or malwale) from modifying certain files or registry entries.

Author

Commented:
Just as added info, the following VBScript works on all of the machines:

Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
Set objWMIService = objSWbemLocator.ConnectServer("computerName", _
    "root\CIMV2", "Administrator", "AdminPassword",NULL,NULL)
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Desktop",,48)

For Each objItem in colItems
    Wscript.Echo "ScreenSaverExecutable: " & objItem.ScreenSaverExecutable
Next

The key now is to get this same functionality to work in C++ code

Author

Commented:
In an effort to discover the reason for the E_ACCESSDENIED, I have done the following on the computer where the Next operation fails:
   - Ran WmiMgmt.msc and verified that the administrators group has full access to the CIMV2 namespace
   - Enabled WMI verbose logging (in WmiMgmt.msc) and ran the C++ code again and no errors appeared in the generated logs

Author

Commented:
Figured out the problem.... per a Microsoft website, you MUST call CoSetProxyBlanket on EVERY interface you retrieve.  This would include the enumerator class.  Once I successfully called that on the enumerator object I no longer got the E_ACCESSDENIED return from the next function.
x4u

Commented:
I'm happy that gmain found a solution to his problem and refunding the points is perfectly o.k. for me.
Commented:
PAQ-ing the question and refunding 500 points

Thanks x4u !

GranMod
The Experts Exchange
Community Support Moderator of all Ages

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts
Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.