Question

I have an application where the user enters credential using which I create a WindowsIdentity object which I subsequently use to impersonate the user corresponding to the entered credential and make the CredWrite call. However, it is returning

ERROR_NO_SUCH_LOGON_SESSION 1312 (0x520) A specified logon session does not exist. It may already have been terminated.

When I take out the impersonation code, everything works as expected. However, even when I impersonate myself (current logged in user), same 1312 error returns.

I am baffled as to what I am doing wrong. Any pointers are appreciated.

IntPtr token = new IntPtr(0);
securityUtils = new Security.Utility();
string user = "someuser";
string pass = "somepassword";
token = securityUtils.GetToken(user, "somedomain", pass.ConvertToSecureString());
var newId = new WindowsIdentity(token);
string currentUser1 = WindowsIdentity.GetCurrent().Name;
Impersonation.Impersonate(newId);
string currentUser2 = WindowsIdentity.GetCurrent().Name;
int result = WriteCredential("dummykey", user.ConvertToSecureString(), pass.ConvertToSecureString());
Impersonation.UnImpersonate();
string currentUser3 = WindowsIdentity.GetCurrent().Name;

The GetToken method makes the LogonUser call. I have verified that the impersonation is working by looking at currentUser1/2/3.

The WriteCredential method looks like this:

public static int WriteCredential(string key, SecureString userName, SecureString password)
{
    if (string.IsNullOrEmpty(key))
    {
        throw new ArgumentNullException("key is null or empty");
    }

    if (userName == null || userName.Length == 0)
    {
        throw new ArgumentNullException("userName is null or empty");
    }

    if (password == null || password.Length == 0)
    {
        throw new ArgumentNullException("password is null or empty");
    }

    string passwordAsString = password.ConvertToUnsecureString();
    byte[] byteArray = Encoding.Unicode.GetBytes(passwordAsString);

    if (byteArray.Length > MaximumCredentialBlobSize)
    {
        throw new ArgumentOutOfRangeException(string.Format("The password message has exceeded {0} bytes.", MaximumCredentialBlobSize));
    }

    Credential cred = new Credential();
    cred.TargetName = System.Runtime.InteropServices.Marshal.StringToCoTaskMemUni(key);
    cred.CredentialBlob = System.Runtime.InteropServices.Marshal.StringToCoTaskMemUni(passwordAsString);
    cred.CredentialBlobSize = (uint)Encoding.Unicode.GetBytes(passwordAsString).Length;
    cred.AttributeCount = 0;
    cred.Attributes = IntPtr.Zero;
    cred.Comment = IntPtr.Zero;
    cred.TargetAlias = System.Runtime.InteropServices.Marshal.StringToCoTaskMemUni(key);
    cred.Type = CredentialType.CRED_TYPE_GENERIC;
    cred.Persist = Persistance.CRED_PERSIST_ENTERPRISE;
    cred.UserName = System.Runtime.InteropServices.Marshal.StringToCoTaskMemUni(userName.ConvertToUnsecureString());

    bool written = CredWrite(ref cred, 0);
    int lastError = Marshal.GetLastWin32Error();

    if (!written)
    {
        return lastError;
    }

    return 0;
}

The Credential struct:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct Credential
{
    public uint Flags;
    public CredentialType Type;
    public IntPtr TargetName;
    public IntPtr Comment;
    public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
    public uint CredentialBlobSize;
    public IntPtr CredentialBlob;
    public Persistance Persist;
    public uint AttributeCount;
    public IntPtr Attributes;
    public IntPtr TargetAlias;
    public IntPtr UserName;
}

The DllImport:

[DllImport("Advapi32.dll", EntryPoint = "CredWriteW", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool CredWrite([In] ref Credential userCredential, [In] uint flags);
Was it helpful?

Solution

The solution was to explicitly load profile for the user being impersonated before making the WriteCredential call. It is important to make the LoadProfile call before impersonating that user.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top