Pettor
Pettor

Reputation: 491

Provide Credential Information from Credential Provider to C# Service

I have written a custom Windows Credentials Provider to capture the user login. One of the main purposes of this provider is to store the password of the user and use it in a C# service running on Windows when logged in.

This leads me to the problem of where and how to store the credential information. At the time of login (i.e. user provide valid login information and choose to login) the service should be able to fetch the information and use it.

What would be the proper way communicate the credential information to the service?

The part that login the user with the credentials are more or less according to the provided Microsoft sample for Credential Provider where GetSerialization looks like this:

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

g_pwzProtectedPassword = pwzProtectedPassword;

if (SUCCEEDED(hr))
{
    PWSTR pszDomain;
    PWSTR pszUsername;
    hr = SplitDomainAndUsername(_pszQualifiedUserName, &pszDomain, &pszUsername);
    if (SUCCEEDED(hr))
    {
        KERB_INTERACTIVE_UNLOCK_LOGON kiul;
        hr = KerbInteractiveUnlockLogonInit(pszDomain, pszUsername, 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_CredentialProvider;
                    // 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(pszDomain);
        CoTaskMemFree(pszUsername);
    }
    CoTaskMemFree(pwzProtectedPassword);
}

EDIT:

I tried to use the Windows Credential Manager API to save the password but that seems to have no effect. When I try to fetch the username / password afted being logged in I get nothing returned.

DWORD cbCreds = (DWORD)(1 + strlen(password));

CREDENTIALW cred = { 0 };
cred.Type = CRED_TYPE_GENERIC;
cred.TargetName = TargetName;
cred.CredentialBlobSize = cbCreds;
cred.CredentialBlob = (LPBYTE)password;
cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
cred.UserName = *username;

return ::CredWriteW(&cred, 0) ? true : false;

Upvotes: 1

Views: 1600

Answers (1)

KonstantinK
KonstantinK

Reputation: 1

Think pipes would be the proper way to communicate with the service. And using Windows Credential Manager to save/load password has no effect because of different logon sessions and user's SID disabled while not logged in yet.

Upvotes: 0

Related Questions