Windows Пользовательский провайдер учетных данных, использующий MSV1_0, завершается ошибкой с INVALID_PARAMETER - PullRequest
0 голосов
/ 11 февраля 2020

Я пытаюсь реализовать локальный вход в систему из своего пользовательского провайдера учетных данных. Для этого я пытаюсь использовать пакет аутентификации MSV1_0, но он продолжает отказывать, давая статус INVALID_PARAMETER.

Код выглядит так:

static void _UnicodeStringPackedUnicodeStringCopy(
    const UNICODE_STRING& rus,
    PWSTR pwzBuffer,
    UNICODE_STRING* pus
) {
    pus->Length = rus.Length;
    pus->MaximumLength = rus.Length;
    pus->Buffer = pwzBuffer;

    CopyMemory(pus->Buffer, rus.Buffer, pus->Length);
}

HRESULT LsaInitStringW(PUNICODE_STRING pszDestinationString, PCWSTR pszSourceString)
{
    size_t cchLength;
    HRESULT hr = StringCchLengthW(pszSourceString, USHORT_MAX, &cchLength);
    if (SUCCEEDED(hr))
    {
        USHORT usLength;
        hr = SizeTToUShort(cchLength, &usLength);

        if (SUCCEEDED(hr))
        {
            pszDestinationString->Buffer = (PWCHAR)pszSourceString;
            pszDestinationString->Length = usLength * sizeof(WCHAR);
            pszDestinationString->MaximumLength = pszDestinationString->Length + 1;
            hr = S_OK;
        }
    }
    return hr;
}

HRESULT MsvLogonPack(
    const MSV1_0_INTERACTIVE_LOGON& milIn,
    BYTE** prgb,
    DWORD* pcb
) {
    size_t cb = sizeof(milIn)
        + milIn.LogonDomainName.Length
        + milIn.UserName.Length
        + milIn.Password.Length;
    MSV1_0_INTERACTIVE_LOGON* milOut = (MSV1_0_INTERACTIVE_LOGON*)CoTaskMemAlloc(cb);
    if (!milOut) {
        return E_OUTOFMEMORY;
    }
    milOut->MessageType = milIn.MessageType;
    BYTE *pbBuffer = (BYTE*)milOut + sizeof(*milOut);
    _UnicodeStringPackedUnicodeStringCopy(milIn.LogonDomainName, (PWSTR)pbBuffer, &milOut->LogonDomainName);
    pbBuffer += milOut->LogonDomainName.Length;

    _UnicodeStringPackedUnicodeStringCopy(milIn.UserName, (PWSTR)pbBuffer, &milOut->UserName);
    pbBuffer += milOut->UserName.Length;

    _UnicodeStringPackedUnicodeStringCopy(milIn.Password, (PWSTR)pbBuffer, &milOut->Password);
    pbBuffer += milOut->Password.Length;

    if (pbBuffer != (BYTE*)milOut + cb) {
        return E_ABORT;
    }

    *prgb = (BYTE*)milOut;
    *pcb = cb;
    return S_OK;
}

HRESULT GetMsvPackage(ULONG * pulAuthPackage) {
    HRESULT hr;
    HANDLE hLsa;

    NTSTATUS status = LsaConnectUntrusted(&hLsa);
    if (SUCCEEDED(HRESULT_FROM_NT(status))) {

        ULONG ulAuthPackage;
        LSA_STRING lsaszKerberosName;
        LsaInitString(&lsaszKerberosName, MSV1_0_PACKAGE_NAME);

        status = LsaLookupAuthenticationPackage(hLsa, &lsaszKerberosName, &ulAuthPackage);
        if (SUCCEEDED(HRESULT_FROM_NT(status))) {
            *pulAuthPackage = ulAuthPackage;
            hr = S_OK;
        }
        else {
            hr = HRESULT_FROM_NT(status);
        }
        LsaDeregisterLogonProcess(hLsa);
    }
    else {
        hr = HRESULT_FROM_NT(status);
    }

    return hr;
}

HRESULT MyCredential::CompleteAuthentication(CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr,
    CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs,
    PWSTR* ppwszOptionalStatusText,
    CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon) {
    HRESULT hr;

    pcpcs->clsidCredentialProvider = CLSID_MyProvider;

    MSV1_0_INTERACTIVE_LOGON mil;
    mil.MessageType = MsV1_0WorkstationUnlockLogon;
    hr = LsaInitStringW(&mil.LogonDomainName, L"");
    if (SUCCEEDED(hr)) hr = LsaInitStringW(&mil.UserName, L"tester");
    if (SUCCEEDED(hr)) hr = LsaInitStringW(&mil.Password, L"12345");

    if (SUCCEEDED(hr)) {
        hr = MsvLogonPack(mil, &pcpcs->rgbSerialization, &pcpcs->cbSerialization);

        if (SUCCEEDED(hr)) {
            ULONG ulAuthPackage;
            hr = GetMsvPackage(&ulAuthPackage);
            if (SUCCEEDED(hr)) {
                pcpcs->ulAuthenticationPackage = ulAuthPackage;
            }
        }
    }
    return hr;
}

Это продолжает давать статус INVALID_PARAMETER с под-статусом 0. Я попытался заменить MsV1_0InteractiveLogon на MsV1_0WorkstationUnlockLogon, что дало мне статус STATUS_LOGON_FAILURE с под-статусом INTERNAL_ERROR.

Что бы предложить решить эту проблему?

1 Ответ

0 голосов
/ 11 февраля 2020

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

    _UnicodeStringPackedUnicodeStringCopy(milIn.LogonDomainName, (PWSTR)pbBuffer, &milOut->LogonDomainName);
    milOut->LogonDomainName.Buffer = (PWSTR)(pbBuffer - (BYTE*)milOut);
    pbBuffer += milOut->LogonDomainName.Length;

    _UnicodeStringPackedUnicodeStringCopy(milIn.UserName, (PWSTR)pbBuffer, &milOut->UserName);
    milOut->UserName.Buffer = (PWSTR)(pbBuffer - (BYTE*)milOut);
    pbBuffer += milOut->UserName.Length;

    _UnicodeStringPackedUnicodeStringCopy(milIn.Password, (PWSTR)pbBuffer, &milOut->Password);
    milOut->Password.Buffer = (PWSTR)(pbBuffer - (BYTE*)milOut);
    pbBuffer += milOut->Password.Length;

Это поведение задокументировано для KERB_CERTIFICATE_LOGON структуры, но не для MSV1_0_INTERACTIVE_LOGON , по некоторым причинам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...