C# 自定义凭据提供程序 RDP 问题

3

我正在开发一个C#实现的自定义凭据提供程序。

在交互式会话中,它可以正常工作没有任何问题。然而,当我尝试使用RDP(mstsc)连接该计算机时,在凭证序列化后会出现错误信息。错误信息如下:

"身份验证错误。提供给函数的令牌无效。" 在我的服务器上,GetSeralization方法如下所示;

public override int GetSerialization(out _CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE pcpgsr, out _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION pcpcs, out string ppszOptionalStatusText, out _CREDENTIAL_PROVIDER_STATUS_ICON pcpsiOptionalStatusIcon)
{
    pcpgsr = _CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE.CPGSR_NO_CREDENTIAL_NOT_FINISHED;
    pcpcs = new _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION();
    ppszOptionalStatusText = "";
    pcpsiOptionalStatusIcon = _CREDENTIAL_PROVIDER_STATUS_ICON.CPSI_NONE;

    var otpResult = DialogResult.Yes;

    // make OTP operation here

    if (otpResult == DialogResult.Yes)
    {
        CredHelper.Instance.RetrieveNegotiateAuthPackage(out var authPackage);

        var userNameField = credentialView.GetField(FieldTypeEnum.UsernameField);
        var passwordField = credentialView.GetField(FieldTypeEnum.PasswordField);

        var userNameSplitted = userNameField.Value.SplitSpecial('\\');

        if (userNameSplitted.Count <= 1)
        {
            ppszOptionalStatusText = "Failed to pack credentials";
            pcpsiOptionalStatusIcon = _CREDENTIAL_PROVIDER_STATUS_ICON.CPSI_ERROR;
            return HResult.Fail;
        }

        pcpgsr = _CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE.CPGSR_RETURN_CREDENTIAL_FINISHED;
        pcpcs = new _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION();

        NativeLogon.KerbInteractiveUnlockLogonInit(userNameSplitted.First(), userNameSplitted.Last(), passwordField.Value, (int)usageScenario, out KerbInteractiveUnlockLogon pkiul);

        NativeLogon.KerbInteractiveUnlockLogonPack(ref pkiul, out IntPtr inCredBuffer, out int inCredSize);

        ppszOptionalStatusText = string.Empty;
        pcpsiOptionalStatusIcon = _CREDENTIAL_PROVIDER_STATUS_ICON.CPSI_SUCCESS;
        pcpcs.clsidCredentialProvider = Statics.CredentialProviderGuid;

        pcpcs.rgbSerialization = inCredBuffer;
        pcpcs.cbSerialization = (uint)inCredSize;
        pcpcs.ulAuthenticationPackage = authPackage;

        return HResult.Ok;
    }

    ppszOptionalStatusText = "Failed to pack credentials";
    pcpsiOptionalStatusIcon = _CREDENTIAL_PROVIDER_STATUS_ICON.CPSI_ERROR;
    return HResult.Fail;
}

以下是我的ICredentialProviderFilter实现,但我认为它是错误的。

public int UpdateRemoteCredential(ref _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION pcpcsIn, out _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION pcpcsOut)
{
    pcpcsOut = pcpcsIn;

    return HResult.Ok;
}

我卡在这里了,无法继续前进。谢谢。


我在客户端和服务器计算机上安装了我的自定义提供程序。当rdp credUI出现时,我的登录磁贴会出现。但是它无法登录。我还在注册表中将相同的凭据提供程序注册为凭据提供程序过滤器。 - candogg
1个回答

2

我通过更改C++助手库以解决问题。在CredUI场景中,Kerberos票证是不正确的。它应该像下面这样;

switch (scenario)
                {
                case 1: //CPUS_LOGON
                    pkil->MessageType = KerbInteractiveLogon;
                    hr = S_OK;
                    break;
                case 2: //CPUS_UNLOCK_WORKSTATION
                    pkil->MessageType = KerbWorkstationUnlockLogon;
                    hr = S_OK;
                    break;
                case 4: //CPUS_CREDUI
                    pkil->MessageType = KerbInteractiveLogon;
                    hr = S_OK;
                    break;
                default:
                    hr = E_FAIL;
                    break;
                }

现在我可以连接到远程计算机。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接