CS/CredentialManager.cs
using System;
using System.ComponentModel; using System.Management.Automation; using System.Runtime.InteropServices; namespace Valentia.CS { public enum CredType : uint { Generic = 1, DomainPassword = 2, DomainCertificate = 3, DomainVisiblePassword = 4, GenericCertificate = 5, DomainExtended = 6, Maximum = 7, // Maximum supported cred Type MaximumEx = (Maximum + 1000), // Allow new applications to run on old OSes } public class CredentialManager { public static void Write(string target, PSCredential credential, CredType type) { if (credential == null) throw new NullReferenceException("Credential"); var user = credential.GetNetworkCredential().UserName; var pass = credential.GetNetworkCredential().Password; var domain = credential.GetNetworkCredential().Domain; if (!string.IsNullOrWhiteSpace(domain)) { user = string.Format(@"{0}\{1}", domain, user); } var nativeCredential = new NativeWriteCredential { Flags = 0, Type = type, TargetName = Marshal.StringToCoTaskMemUni(target), UserName = Marshal.StringToCoTaskMemUni(user), AttributeCount = 0, Persist = 2, CredentialBlobSize = (uint)System.Text.Encoding.Unicode.GetByteCount(pass), CredentialBlob = Marshal.StringToCoTaskMemUni(pass), }; if (!NativeMethod.CredWrite(ref nativeCredential, 0)) { var errorCode = Marshal.GetLastWin32Error(); throw new Exception("Failed to write credentials", new Win32Exception(errorCode)); } } public static PSCredential Read(string target, CredType type, string userName) { IntPtr credentialPtr; if (!NativeMethod.CredRead(target, type, 0, out credentialPtr)) { throw new NullReferenceException("Failed to find credentials in Windows Credential Manager. TargetName: {0}, Type {1}"); } var handler = new CriticalCredentialHandle(credentialPtr); var credential = handler.GetCredential(); if (string.IsNullOrWhiteSpace(userName)) { userName = credential.UserName; } var secureString = new System.Security.SecureString(); foreach (var c in credential.CredentialBlob) secureString.AppendChar(c); var psCredential = new PSCredential(userName, secureString); return psCredential; } public static bool Exists(string target, CredType type) { try { Read(target, type, ""); return true; } catch (Exception) { return false; } } public static void Remove(string target, CredType type) { if (!NativeMethod.CredDelete(target, type, 0)) { throw new NullReferenceException(string.Format("Failed to find credentials in Windows Credential Manager. TargetName: {0}, Type {1}", target, type)); } } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct NativeReadCredential { public uint Flags; public CredType Type; public string TargetName; public string Comment; public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten; public uint CredentialBlobSize; public string CredentialBlob; public uint Persist; public uint AttributeCount; public IntPtr Attributes; public string TargetAlias; public string UserName; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct NativeWriteCredential { public uint Flags; public CredType Type; public IntPtr TargetName; public IntPtr Comment; public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten; public uint CredentialBlobSize; public IntPtr CredentialBlob; public uint Persist; public uint AttributeCount; public IntPtr Attributes; public IntPtr TargetAlias; public IntPtr UserName; public static NativeWriteCredential GetNativeCredential(NativeReadCredential cred) { var nativeCredential = new NativeWriteCredential { AttributeCount = 0, Attributes = IntPtr.Zero, Comment = IntPtr.Zero, TargetAlias = IntPtr.Zero, Type = CredType.Generic, Persist = (uint)1, CredentialBlobSize = (uint)cred.CredentialBlobSize, TargetName = Marshal.StringToCoTaskMemUni(cred.TargetName), CredentialBlob = Marshal.StringToCoTaskMemUni(cred.CredentialBlob), UserName = Marshal.StringToCoTaskMemUni(Environment.UserName) }; return nativeCredential; } } internal class CriticalCredentialHandle : Microsoft.Win32.SafeHandles.CriticalHandleZeroOrMinusOneIsInvalid { public CriticalCredentialHandle(IntPtr preexistingHandle) { this.SetHandle(preexistingHandle); } public NativeReadCredential GetCredential() { if (this.IsInvalid) throw new InvalidOperationException("Invalid CriticalHandle!"); var ncred = (NativeWriteCredential)Marshal.PtrToStructure(this.handle, typeof(NativeWriteCredential)); var cred = new NativeReadCredential { CredentialBlobSize = ncred.CredentialBlobSize, CredentialBlob = Marshal.PtrToStringUni(ncred.CredentialBlob, (int) ncred.CredentialBlobSize / 2), UserName = Marshal.PtrToStringUni(ncred.UserName), TargetName = Marshal.PtrToStringUni(ncred.TargetName), TargetAlias = Marshal.PtrToStringUni(ncred.TargetAlias), Type = ncred.Type, Flags = ncred.Flags, Persist = ncred.Persist }; return cred; } protected override bool ReleaseHandle() { if (this.IsInvalid) return false; NativeMethod.CredFree(this.handle); this.SetHandleAsInvalid(); return true; } } internal class NativeMethod { [DllImport("Advapi32.dll", SetLastError = true, EntryPoint = "CredWriteW", CharSet = CharSet.Unicode)] public static extern bool CredWrite([In] ref NativeWriteCredential userWriteCredential, [In] uint flags); [DllImport("Advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)] public static extern bool CredRead(string target, CredType type, int reservedFlag, out IntPtr CredentialPtr); [DllImport("Advapi32.dll", EntryPoint = "CredFree", SetLastError = true)] public static extern bool CredFree([In] IntPtr cred); [DllImport("Advapi32.dll", EntryPoint = "CredDeleteW", CharSet = CharSet.Unicode, SetLastError = true)] public static extern bool CredDelete(string target, CredType type, int reservedFlag); } } |