0

I wrote a C++ function that gets the PNPDeviceID of an USB-Drive by WMI Queries and tested it in a Win32-Console-Application. It worked perfectly, but when I put the code into the CredentialProvider-DLL, the CoInitialize() and CoInitializeSecurity() functions failed because the have been already called by the DLL-calling process (the Windows CredUI-Subsystem). So how can I make the WMI Queries work on that DLL? I need to reset the COM security settings what seems not to be possible to do by default.

Here is the function code:

std::wstring GetHardwareID(char driveLetter)
{
std::wstring returnString = L"";
wchar_t volumeAccessPath[] = L"\\\\.\\X:";
volumeAccessPath[4] = driveLetter;

HANDLE deviceHandle = CreateFileW(volumeAccessPath,
    0,                // no access to the drive
    FILE_SHARE_READ | // share mode
    FILE_SHARE_WRITE,
    NULL,             // default security attributes
    OPEN_EXISTING,    // disposition
    0,                // file attributes
    NULL);      // do not copy file attributes

DWORD bytes;
STORAGE_DEVICE_NUMBER  devd;
STORAGE_BUS_TYPE busType = BusTypeUnknown;


if (DeviceIoControl(deviceHandle,
    IOCTL_STORAGE_GET_DEVICE_NUMBER ,
    NULL, 0,
    &devd, sizeof(devd),
    &bytes, NULL))
{
    HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);

    if((FAILED(hRes = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0))))
    {
               return returnString;
            }

    IWbemLocator* pLocator = NULL;
    if(FAILED(hRes = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pLocator))))
    { return returnString;}

    IWbemServices* pService = NULL;

    if(FAILED(hRes = pLocator->ConnectServer(L"root\\CIMV2", NULL, NULL, NULL, WBEM_FLAG_CONNECT_USE_MAX_WAIT, NULL, NULL, &pService)))
    {
        pLocator->Release();
        dbg(convertInt(hRes).c_str());
        return returnString;
    }

    IEnumWbemClassObject* pEnumerator = NULL;
    if(FAILED(hRes = pService->ExecQuery(L"WQL", L"SELECT * FROM Win32_DiskDrive ", WBEM_FLAG_FORWARD_ONLY, NULL, &pEnumerator)))
    {
        pLocator->Release();
        pService->Release();
dbg(convertInt(hRes).c_str());
        return returnString;
    }

    IWbemClassObject* clsObj = NULL;
    int numElems;
    while((hRes = pEnumerator->Next(WBEM_INFINITE, 1, &clsObj, (ULONG*)&numElems)) != WBEM_S_FALSE)
    {
        if(FAILED(hRes))
            break;

        VARIANT vRet;
        VariantInit(&vRet);
        if(SUCCEEDED(clsObj->Get(L"DeviceID", 0, &vRet, NULL, NULL)) && vRet.vt == VT_BSTR)
        {
            bool found = false;
            std::wstring ws(vRet.bstrVal);
            if (ws[17] == '0' + devd.DeviceNumber)
            found = true;
            VariantClear(&vRet);

            if(SUCCEEDED(clsObj->Get(L"PNPDeviceID", 0, &vRet, NULL, NULL)) && vRet.vt == VT_BSTR  && found)
            {
                std::wstring retStr(vRet.bstrVal);
                VariantClear(&vRet);
                std::wstring k(L"&");
                int pos =retStr.rfind(k);
                returnString = retStr.substr(0, pos);
            }
        }

        clsObj->Release();
    }

    pEnumerator->Release();
    pService->Release();
    pLocator->Release();
}
return returnString;
}

Thanks in advance

adjan
  • 13,371
  • 2
  • 31
  • 48

1 Answers1

1

The solution can be to put all that code for getting PNPDeviceID of an USB-Drive into a windows service. And making an IPC between credential provider and windows service via named pipes.

P.S. These approach is also good in way that all "hard" stuff is done in windows service (which have more capabilities), and your provider is light and simple, and this will help you to avoid problems in future.

westwood
  • 1,774
  • 15
  • 29
  • Thank you, but I solved the problem in a different way. I had simply to remove the `CoInitializeSecurity()`-call (because this is set process-wide) and use `CoSetProxyBlanket()` instead, which can be used on a specific COM-Proxy. But I'll keep your solution in mind for future porblems that won't be that easy to solve... – adjan Aug 04 '12 at 15:20
  • Thank you too =) Your solution is also good in this situation, and I've didn't think about CoSetProxyBlanket(). – westwood Aug 05 '12 at 17:52
  • Could you also help me with my next question? http://stackoverflow.com/questions/11810046/is-the-pnpdeviceid-unique – adjan Aug 06 '12 at 11:32