WMI call from C++ results in HRESULT=0x80041003

2

I'm not sure why am I getting this strange result. Can someone please shed some light on this?

I'm using WMI calls from a C++ program to export the 'Application' part of the Windows Event Log.

This is done from a local service and the code works fine under Windows 7. The problem happens when I run it on Windows XP. For some weird reason the ExecMethod() of the WMI interface returns HRESULT=0x80041003, which is Access denied.

But if I put the exact same code into a simple user process and run it from there, everything works great. How could that be, the code fails to run from a more privileged local service but works from a simple user process?

PS. I'd appreciate any ideas because I've been working on this for several days to no avail....

PS2. I enabled the following privileges (like if I need to do this for the local service) and that still didn't help: SE_SECURITY_NAME SE_BACKUP_NAME

EDIT: I guess adding a sample code wouldn't hurt. (Sorry for the long chunk, but this darn WMI/COM isn't a beauty either....) I marked the spot where I get an error below:

// Initialize COM. ------------------------------------------
hr =  CoInitializeEx(0, COINIT_MULTITHREADED);

if(SUCCEEDED(hr))
{
    // Set general COM security levels --------------------------
    // Note: If you are using Windows 2000, you need to specify -
    // the default authentication credentials for a user by using
    // a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
    // parameter of CoInitializeSecurity ------------------------
    hr =  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(SUCCEEDED(hr))
    {
        // Obtain the initial locator to WMI -------------------------
        IWbemLocator *pLoc = NULL;
        hr = CoCreateInstance(
            CLSID_WbemLocator,             
            0, 
            CLSCTX_INPROC_SERVER, 
            IID_IWbemLocator, (LPVOID *) &pLoc);

        if(SUCCEEDED(hr))
        {
            // Connect to WMI through the IWbemLocator::ConnectServer method
            IWbemServices *pSvc = NULL;

            // Connect to the root\cimv2 namespace with
            // the current user and obtain pointer pSvc
            // to make IWbemServices calls.
            hr = pLoc->ConnectServer(
                 _bstr_t(L"\\\\.\\ROOT\\CIMV2"), // Object path of WMI namespace
                 NULL,                    // User name. NULL = current user
                 NULL,                    // User password. NULL = current
                 0,                       // Locale. NULL indicates current
                 NULL,                    // Security flags.
                 0,                       // Authority (e.g. Kerberos)
                 0,                       // Context object 
                 &pSvc                    // pointer to IWbemServices proxy
                 );

            if(SUCCEEDED(hr))
            {
                // Set security levels on the proxy -------------------------
                hr = 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
                   NULL,                        // client identity
                   EOAC_NONE                    // proxy capabilities 
                );

                if(SUCCEEDED(hr))
                {
                    // Use the IWbemServices pointer to make requests of WMI ----
                    // For example, get the name of the operating system
                    IEnumWbemClassObject* pEnumerator = NULL;

                    hr = pSvc->ExecQuery(
                        bstr_t("WQL"), 
                        bstr_t("Select * from Win32_NTEventLogFile Where LogFileName='Application'"),
                        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 
                        NULL,
                        &pEnumerator);

                    if(SUCCEEDED(hr))
                    {
                        IWbemClassObject *pclsObj = NULL;
                        int nCnt = -1;

                        //Go through all results
                        while (pEnumerator)
                        {
                            ULONG uReturn = 0;
                            hr = pEnumerator->Next(WBEM_INFINITE, 1, 
                                &pclsObj, &uReturn);

                            if(0 == uReturn)
                            {
                                break;
                            }

                            //Go to next iteration
                            nCnt++;

                            // Get a reference to the Win32_Printer class so we can find
                            // the RenamePrinter method.  This lets us create an object
                            // representing the input parameter block to be passed to the
                            // method when we call it.
                            IWbemClassObject *pNTEventLogFile = NULL;
                            IWbemClassObject *params = NULL;
                            IWbemClassObject *paramsInst = NULL;

                            hr = pSvc->GetObject( _bstr_t( L"Win32_NTEventLogFile" ), 0, NULL,
                                               &pNTEventLogFile, NULL );

                            if(SUCCEEDED(hr))
                            {
                                hr = pNTEventLogFile->GetMethod( _bstr_t( "BackupEventLog" ), 0, &params,
                                               NULL );
                                if(SUCCEEDED(hr))
                                {
                                    hr = params->SpawnInstance( 0, &paramsInst );
                                    if(SUCCEEDED(hr))
                                    {

                                        // Now that we've got an instance representing the input
                                        // parameters, we can fill in the parameter values
                                        _bstr_t paramValue( L"C:\\Users\\UserName\\Documents\\application.evt" );
                                        VARIANT paramVt;
                                        paramVt.vt = VT_BSTR;
                                        paramVt.bstrVal = paramValue;
                                        hr = paramsInst->Put( L"ArchiveFileName", 0, &paramVt, NULL );
                                        if(SUCCEEDED(hr))
                                        {
                                            // Get the "this" pointer to our object instance so that we
                                            // can call the RenamePrinter method on it
                                            CIMTYPE type;
                                            LONG flavor;
                                            VARIANT var;
                                            hr = pclsObj->Get( L"__PATH", 0, &var, &type, &flavor );

                                            if(SUCCEEDED(hr))
                                            {
                                                // Execute the RenamePrinter method on our object instance
                                                IWbemClassObject *results = NULL;
                                                hr = pSvc->ExecMethod( var.bstrVal, _bstr_t( L"BackupEventLog" ), 0,
                                                    NULL, paramsInst, &results, NULL );

**///////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////// THIS IS WHERE hr = 0x80041003 or wbemErrAccessDenied
//////////////////////////////////////////////// only when this code is run from a local service
//////////////////////////////////////////////// on a Windows XP machine, but if I run the exact same
//////////////////////////////////////////////// code from a user process on XP machine, it works!
//////////////////////////////////////////////// Note that this works fine on Windows Vista/7 in any configuration.
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////**

                                                if(SUCCEEDED(hr))
                                                {
                                                    //Get result code from the BackupEventLog method
                                                    VARIANT vtProp;
                                                    hr = results->Get(L"ReturnValue", 0, &vtProp, 0, 0);
                                                    if(SUCCEEDED(hr))
                                                    {
                                                        if(vtProp.vt == VT_I4)
                                                        {
                                                            //Check
                                                            // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384808(v=vs.85).aspx

                                                            //0 = Success
                                                            //8 = Privilege missing
                                                            //21 = Invalid parameter
                                                            //80 = Archive file name already exists. This value is returned starting with Windows Vista.
                                                            int nResV = vtProp.intVal;
                                                            //_tprintf(_T("result2 : %d\n"), nResV);

                                                        }
                                                        else
                                                        {
                                                            //Error
                                                        }

                                                        //Free
                                                        VariantClear(&vtProp);  
                                                    }
                                                    else
                                                    {
                                                        //Error
                                                    }

                                                }
                                                else
                                                {
                                                    //Error
                                                }


                                                //Free
                                                if(results)
                                                {
                                                    results->Release();
                                                    results = NULL;
                                                }

                                                //Clear
                                                VariantClear(&var);
                                            }
                                            else
                                            {
                                                //Error
                                            }

                                            //Clear
                                            VariantClear(&paramVt);
                                        }
                                        else
                                        {
                                            //Error
                                        }
                                    }
                                    else
                                    {
                                        //Error
                                    }
                                }
                                else
                                {
                                    //Error
                                }
                            }
                            else
                            {
                                //Error
                            }


                            //Free
                            if(pNTEventLogFile)
                            {
                                pNTEventLogFile->Release();
                                pNTEventLogFile = NULL;
                            }
                            if(params)
                            {
                                params->Release();
                                params = NULL;
                            }
                            if(paramsInst)
                            {
                                paramsInst->Release();
                                paramsInst = NULL;
                            }

                            if(pclsObj)
                            {
                                pclsObj->Release();
                                pclsObj = NULL;
                            }
                        }


                        //Free
                        if(pclsObj)
                        {
                            pclsObj->Release();
                            pclsObj = NULL;
                        }


                    }
                    else
                    {
                        //Error
                    }


                    //Free
                    if(pEnumerator)
                    {
                        pEnumerator->Release();
                        pEnumerator = NULL;
                    }
                }
                else
                {
                    //Error
                }

            }
            else
            {
                //Error
            }


            //Free
            if(pSvc)
            {
                pSvc->Release();
                pSvc = NULL;
            }


        }
        else
        {
            //Error
        }


        //Free
        if(pLoc)
        {
            pLoc->Release();
            pLoc = NULL;
        }

    }
    else
    {
        //Error
    }

    //Uninit
    CoUninitialize();
}
else
{
    //Error
}
c++
wmi
event-log
access-denied
asked on Stack Overflow Feb 10, 2012 by ahmd0 • edited Feb 10, 2012 by ahmd0

1 Answer

2

I think I got it... For anyone else who doesn't want to waste 3 days looking for an answer here it is: on Windows XP replace RPC_C_IMP_LEVEL_IMPERSONATE with RPC_C_IMP_LEVEL_DELEGATE in the calls to CoInitializeSecurity() and CoSetProxyBlanket(). I don't know what exactly it does, but it makes the code above work! Yay!!!

answered on Stack Overflow Feb 11, 2012 by ahmd0

User contributions licensed under CC BY-SA 3.0