예제 #1
0
// SetSerialization takes the kind of buffer that you would normally return to LogonUI for
// an authentication attempt.  It's the opposite of ICredentialProviderCredential::GetSerialization.
// GetSerialization is implemented by a credential and serializes that credential.  Instead,
// SetSerialization takes the serialization and uses it to create a tile.
//
// SetSerialization is called for two main scenarios.  The first scenario is in the credui case, which
// we'll talk about in greater detail in a bit.  The second situation is in a remote logon case 
// where the remote client may wish to prepopulate a tile with a username, or in some cases, 
// completely populate the tile and use it to logon without showing any UI.  In this scenario,
// typically the remote logon software would also come with a filter that would direct the
// remote logon to the correct credential provider.
//
// This sample shows some advanced uses of SetSerialization in the CPUS_CREDUI scenario.
//  - if the in-cred's auth package is different than the auth package that we support, we 
//      don't want to enumerate any tiles (since we can't provide creds that match the auth
//      package the caller is requesting).  So we return a special return code from SetSerialization
//      that tells it we don't want it to call GetCredentialCount on us.
//  - Even if we can handle the auth package, both smartcards and username/password use our same
//      auth package.  So we need to look at the MessageType to know if smartcard creds are
//      being requested.  If they are, then we can't serialize a tile from this info.
//  - as long as CREDUIWIN_IN_CRED_ONLY is NOT specified, we enumerate our normal tiles, plus
//      an extra with the info from the in-cred specified (as long as we can handle the auth 
//      package).
//  - if CREDUIWIN_IN_CRED_ONLY is specified (and we can handle the auth package and message type), 
//      then only enumerate a tile with the info from the in-cred filled into it and no other tiles.
//  There are a few other credui scenarios that are not shown in this sample.  Depending on your
//  purpose in writing a credprov that handles CPUS_CREDUI, you may or may not wish to handle those
//  scenarios.  We suggest you read the technical references about the CREDUIWIN_* flags
//  for additional information.
//
STDMETHODIMP CSampleProvider::SetSerialization(
    const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs
    )
{
    HRESULT hr = E_INVALIDARG;

    if ((CLSID_CSampleProvider == pcpcs->clsidCredentialProvider) || (CPUS_CREDUI == _cpus))
    {
        // Get the current AuthenticationPackageID that we are supporting
        ULONG ulNegotiateAuthPackage;
        hr = RetrieveNegotiateAuthPackage(&ulNegotiateAuthPackage);

        if (SUCCEEDED(hr))
        {
            if (CPUS_CREDUI == _cpus)
            {
                if (CREDUIWIN_IN_CRED_ONLY & _dwCredUIFlags)
                {
                    // If we are being told to enumerate only the incoming credential, we must not return
                    // success unless we can enumerate it.  We'll set hr to failure here and let it be
                    // overridden if the enumeration logic below succeeds.
                    hr = E_INVALIDARG;
                }
                else if (_dwCredUIFlags & CREDUIWIN_AUTHPACKAGE_ONLY)
                {
                    if (ulNegotiateAuthPackage == pcpcs->ulAuthenticationPackage)
                    {
                        // In the credui case, SetSerialization should only ever return S_OK if it is able to serialize the input cred.
                        // Unfortunately, SetSerialization had to be overloaded to indicate whether or not it will be able to GetSerialization 
                        // for the specific Auth Package that is being requested for CREDUIWIN_AUTHPACKAGE_ONLY to work, so when that flag is 
                        // set, it should return S_FALSE unless it is ALSO able to serialize the input cred, then it can return S_OK.
                        // So in this case, we can set it to be S_FALSE because we support the authpackage, and then if we
                        // can serialize the input cred, it will get overwritten with S_OK.
                        hr = S_FALSE;
                    }
                    else
                    {
                        //we don't support this auth package, so we want to let logonUI know that by failing
                        hr = E_INVALIDARG;
                    }
                }
            }

            if ((ulNegotiateAuthPackage == pcpcs->ulAuthenticationPackage) &&
                (0 < pcpcs->cbSerialization && pcpcs->rgbSerialization))
            {
                KERB_INTERACTIVE_UNLOCK_LOGON* pkil = (KERB_INTERACTIVE_UNLOCK_LOGON*) pcpcs->rgbSerialization;
                if (KerbInteractiveLogon == pkil->Logon.MessageType)
                {
                    // If there isn't a username, we can't serialize or create a tile for this credential.
                    if (0 < pkil->Logon.UserName.Length && pkil->Logon.UserName.Buffer)
                    {
                        if ((CPUS_CREDUI == _cpus) && (CREDUIWIN_PACK_32_WOW & _dwCredUIFlags))
                        {
                            BYTE* rgbNativeSerialization;
                            DWORD cbNativeSerialization;
                            if (SUCCEEDED(KerbInteractiveUnlockLogonRepackNative(pcpcs->rgbSerialization, pcpcs->cbSerialization, &rgbNativeSerialization, &cbNativeSerialization)))
                            {
                                KerbInteractiveUnlockLogonUnpackInPlace((PKERB_INTERACTIVE_UNLOCK_LOGON)rgbNativeSerialization, cbNativeSerialization);

                                _pkiulSetSerialization = (PKERB_INTERACTIVE_UNLOCK_LOGON)rgbNativeSerialization;
                                hr = S_OK;
                            }
                        }
                        else
                        {
                            BYTE* rgbSerialization;
                            rgbSerialization = (BYTE*)HeapAlloc(GetProcessHeap(), 0, pcpcs->cbSerialization);
                            HRESULT hrCreateCred = rgbSerialization ? S_OK : E_OUTOFMEMORY;

                            if (SUCCEEDED(hrCreateCred))
                            {
                                CopyMemory(rgbSerialization, pcpcs->rgbSerialization, pcpcs->cbSerialization);
                                KerbInteractiveUnlockLogonUnpackInPlace((KERB_INTERACTIVE_UNLOCK_LOGON*)rgbSerialization,pcpcs->cbSerialization);

                                if (_pkiulSetSerialization)
                                {
                                    HeapFree(GetProcessHeap(), 0, _pkiulSetSerialization);
                                }
                                _pkiulSetSerialization = (KERB_INTERACTIVE_UNLOCK_LOGON*)rgbSerialization;
                                if (SUCCEEDED(hrCreateCred))
                                {
                                    // we allow success to override the S_FALSE for the CREDUIWIN_AUTHPACKAGE_ONLY, but
                                    // failure to create the cred shouldn't override that we can still handle
                                    // the auth package
                                    hr = hrCreateCred;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    return hr;
}
// Collect the username and password into a serialized credential for the correct usage scenario 
// (logon/unlock is what's demonstrated in this sample).  LogonUI then passes these credentials 
// back to the system to log on.
HRESULT CCustomCredential::GetSerialization(
    CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr,
    CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs, 
    PWSTR* ppwzOptionalStatusText, 
    CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon
    )
{
    UNREFERENCED_PARAMETER(ppwzOptionalStatusText);
    UNREFERENCED_PARAMETER(pcpsiOptionalStatusIcon);

    HRESULT hr;

    WCHAR wsz[MAX_COMPUTERNAME_LENGTH+1];
    DWORD cch = ARRAYSIZE(wsz);

    DWORD cb = 0;
    BYTE* rgb = NULL;

    if (GetComputerNameW(wsz, &cch))
    {
        PWSTR pwzProtectedPassword;

		UserNameSerialized = FieldStrings[SFI_USERNAME];
		PasswordProtected = FieldStrings[SFI_PASSWORD];
        hr = ProtectIfNecessaryAndCopyPassword(PasswordProtected, _cpus, &pwzProtectedPassword);

        // Only CredUI scenarios should use CredPackAuthenticationBuffer.  Custom packing logic is necessary for
        // logon and unlock scenarios in order to specify the correct MessageType.
        if (CPUS_CREDUI == _cpus)
        {
            if (SUCCEEDED(hr))
            {
                PWSTR pwzDomainUsername = NULL;
                hr = DomainUsernameStringAlloc(wsz, UserNameSerialized.data(), &pwzDomainUsername);
                if (SUCCEEDED(hr))
                {
                    // We use KERB_INTERACTIVE_UNLOCK_LOGON in both unlock and logon scenarios.  It contains a
                    // KERB_INTERACTIVE_LOGON to hold the creds plus a LUID that is filled in for us by Winlogon
                    // as necessary.
                    if (!CredPackAuthenticationBufferW((CREDUIWIN_PACK_32_WOW & _dwFlags) ? CRED_PACK_WOW_BUFFER : 0, pwzDomainUsername, pwzProtectedPassword, rgb, &cb))
                    {
                        if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
                        {
                            rgb = (BYTE*)HeapAlloc(GetProcessHeap(), 0, cb);
                            if (rgb)
                            {
                                // If the CREDUIWIN_PACK_32_WOW flag is set we need to return 32 bit buffers to our caller we do this by 
                                // passing CRED_PACK_WOW_BUFFER to CredPacAuthenticationBufferW.
                                if (!CredPackAuthenticationBufferW((CREDUIWIN_PACK_32_WOW & _dwFlags) ? CRED_PACK_WOW_BUFFER : 0, pwzDomainUsername, pwzProtectedPassword, rgb, &cb))
                                {
                                    HeapFree(GetProcessHeap(), 0, rgb);
                                    hr = HRESULT_FROM_WIN32(GetLastError());
                                }
                                else
                                {
                                    hr = S_OK;
                                }
                            }
                            else
                            {
                                hr = E_OUTOFMEMORY;
                            }
                        }
                        else
                        {
                            hr = E_FAIL;
                        }
                        HeapFree(GetProcessHeap(), 0, pwzDomainUsername);
                    }
                    else
                    {
                        hr = E_FAIL;
                    }
                }
                CoTaskMemFree(pwzProtectedPassword);
            }
        }
        else
        {
            KERB_INTERACTIVE_UNLOCK_LOGON kiul;

            // Initialize kiul with weak references to our credential.
            hr = KerbInteractiveUnlockLogonInit(wsz, UserNameSerialized.data(), pwzProtectedPassword, _cpus, &kiul);

            if (SUCCEEDED(hr))
            {
                // We use KERB_INTERACTIVE_UNLOCK_LOGON in both unlock and logon scenarios.  It contains a
                // KERB_INTERACTIVE_LOGON to hold the creds plus a LUID that is filled in for us by Winlogon
                // as necessary.
                hr = KerbInteractiveUnlockLogonPack(kiul, &pcpcs->rgbSerialization, &pcpcs->cbSerialization);
            }
        }

        if (SUCCEEDED(hr))
        {
            ULONG ulAuthPackage;
            hr = RetrieveNegotiateAuthPackage(&ulAuthPackage);
            if (SUCCEEDED(hr))
            {
                pcpcs->ulAuthenticationPackage = ulAuthPackage;
                pcpcs->clsidCredentialProvider = CLSID_CCustomProvider;

                // In CredUI scenarios, we must pass back the buffer constructed with CredPackAuthenticationBuffer.
                if (CPUS_CREDUI == _cpus)
                {
                    pcpcs->rgbSerialization = rgb;
                    pcpcs->cbSerialization = cb;
                }

                // At this point the credential has created the serialized credential used for logon
                // By setting this to CPGSR_RETURN_CREDENTIAL_FINISHED we are letting logonUI know
                // that we have all the information we need and it should attempt to submit the 
                // serialized credential.
                *pcpgsr = CPGSR_RETURN_CREDENTIAL_FINISHED;
            }
            else 
            {
                HeapFree(GetProcessHeap(), 0, rgb);
            }
        }
    }
    else
    {
        DWORD dwErr = GetLastError();
        hr = HRESULT_FROM_WIN32(dwErr);
    }

	pLoginCommander->LoginFailed();
	return hr;
}
// Collect the username and password into a serialized credential for the correct usage scenario
// (logon/unlock is what's demonstrated in this sample).  LogonUI then passes these credentials
// back to the system to log on.
HRESULT CardUnlockCredential::GetSerialization(
    CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr,
    CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs,
    PWSTR* ppwszOptionalStatusText,
    CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon
)
{
    //while (!_pListener->GetConnectedStatus());
    //SetUserData(_pListener->GetUserName(), _pListener->GetPassword());

    UNREFERENCED_PARAMETER(ppwszOptionalStatusText);
    UNREFERENCED_PARAMETER(pcpsiOptionalStatusIcon);

    KERB_INTERACTIVE_LOGON kil;
    ZeroMemory(&kil, sizeof(kil));

    HRESULT hr;

    WCHAR wsz[MAX_COMPUTERNAME_LENGTH+1];
    DWORD cch = ARRAYSIZE(wsz);
    if (GetComputerNameW(wsz, &cch))
    {
        PWSTR pwzProtectedPassword;

        hr = ProtectIfNecessaryAndCopyPassword(_rgFieldStrings[SFI_PASSWORD], _cpus, &pwzProtectedPassword);

        if (SUCCEEDED(hr))
        {
            KERB_INTERACTIVE_UNLOCK_LOGON kiul;

            // Initialize kiul with weak references to our credential.
            hr = KerbInteractiveUnlockLogonInit(wsz, _rgFieldStrings[SFI_USERNAME], pwzProtectedPassword, _cpus, &kiul);

            if (SUCCEEDED(hr))
            {
                // We use KERB_INTERACTIVE_UNLOCK_LOGON in both unlock and logon scenarios.  It contains a
                // KERB_INTERACTIVE_LOGON to hold the creds plus a LUID that is filled in for us by Winlogon
                // as necessary.
                hr = KerbInteractiveUnlockLogonPack(kiul, &pcpcs->rgbSerialization, &pcpcs->cbSerialization);

                if (SUCCEEDED(hr))
                {
                    ULONG ulAuthPackage;
                    hr = RetrieveNegotiateAuthPackage(&ulAuthPackage);
                    if (SUCCEEDED(hr))
                    {
                        pcpcs->ulAuthenticationPackage = ulAuthPackage;
                        pcpcs->clsidCredentialProvider = CLSID_CardUnlockProvider;

                        // At this point the credential has created the serialized credential used for logon
                        // By setting this to CPGSR_RETURN_CREDENTIAL_FINISHED we are letting logonUI know
                        // that we have all the information we need and it should attempt to submit the
                        // serialized credential.
                        *pcpgsr = CPGSR_RETURN_CREDENTIAL_FINISHED;
                    }
                }
            }

            CoTaskMemFree(pwzProtectedPassword);
        }
    }
    else
    {
        DWORD dwErr = GetLastError();
        hr = HRESULT_FROM_WIN32(dwErr);
    }

    return hr;
}