Вызов WMI из C ++ приводит к HRESULT = 0x80041003 - PullRequest
2 голосов
/ 10 февраля 2012

Я не уверен, почему я получаю этот странный результат. Может кто-нибудь пролить свет на это?

Я использую вызовы WMI из программы на C ++ для экспорта части приложения в журнал событий Windows.

Это делается из локальной службы, и код прекрасно работает под Windows 7. Проблема возникает, когда я запускаю его на Windows XP. По какой-то странной причине ExecMethod () интерфейса WMI возвращает HRESULT = 0x80041003, что означает отказ в доступе.

Но если я помещаю точно такой же код в простой пользовательский процесс и запускаю его оттуда, все прекрасно работает. Как это может быть, код не запускается из более привилегированной локальной службы, но работает из простого пользовательского процесса?

PS. Буду признателен за любые идеи, потому что я работаю над этим в течение нескольких дней безрезультатно ...

PS2. Я включил следующие привилегии (например, если мне нужно сделать это для локальной службы), и это все равно не помогло: SE_SECURITY_NAME SE_BACKUP_NAME

РЕДАКТИРОВАТЬ: Я думаю, добавление примера кода не повредит. (Извините за длинный кусок, но этот проклятый WMI / COM тоже не прелесть ....) Я отметил место, где я получаю ошибку ниже:

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

1 Ответ

2 голосов
/ 11 февраля 2012

Думаю, я понял ... Для тех, кто не хочет тратить 3 дня на поиски ответа, вот он: в Windows XP замените RPC_C_IMP_LEVEL_IMPERSONATE на RPC_C_IMP_LEVEL_DELEGATE в вызовах CoInitializeSecurity () и CoSetProxyBlanket ().Я не знаю, что именно он делает, но это заставляет код выше работать!Ура !!!

...