Skip to content

Instantly share code, notes, and snippets.

@toburger
Created May 5, 2014 09:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save toburger/813c4765348fe43d4db1 to your computer and use it in GitHub Desktop.
Save toburger/813c4765348fe43d4db1 to your computer and use it in GitHub Desktop.
#nowarn "9"
module private Internals =
open System.Runtime.InteropServices
type CRED_TYPE =
| GENERIC = 1
| DOMAIN_PASSWORD = 2
| DOMAIN_CERTIFICATE = 3
| DOMAIN_VISIBLE_PASSWORD = 4
| GENERIC_CERTIFICATE = 5
| DOMAIN_EXTENDED = 6
| MAXIMUM = 7
| MAXIMUM_EX = 7000
[<StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)>]
type NativeCredential =
struct
val mutable Flags: uint32
val mutable Type: CRED_TYPE
val mutable TargetName: nativeint
val mutable Comment: nativeint
val mutable LastWritten: ComTypes.FILETIME
val mutable CredentialBlobSize: uint32
val mutable CredentialBlob: nativeint
val mutable Persist: uint32
val mutable AttributeCount: uint32
val mutable Attributes: nativeint
val mutable TargetAlias: nativeint
val mutable UserName: nativeint
end
[<StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)>]
type Credential =
struct
val mutable Flags: uint32
val mutable Type: CRED_TYPE
val mutable TargetName: string
val mutable Comment: string
val mutable LastWritte: ComTypes.FILETIME
val mutable CredentialBlobSize: uint32
val mutable CredentialBlob: string
val mutable Persist: uint32
val mutable AttributeCount: uint32
val mutable Attributes: nativeint
val mutable TargetAlias: string
val mutable UserName: string
end
module NativeCalls =
[<DllImport("Advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)>]
extern bool CredRead(string target, CRED_TYPE ``type``, int reservedFlag, nativeint& CredentialPtr)
[<DllImport("Advapi32.dll", EntryPoint = "CredFree", SetLastError = true)>]
extern bool CredFree([<In>] nativeint cred)
type CriticalCredentialHandle(preexistingHandle) as self =
inherit Microsoft.Win32.SafeHandles.CriticalHandleMinusOneIsInvalid()
do self.SetHandle(preexistingHandle)
let getNativeCredential(cred: Credential) =
let zero = System.IntPtr.Zero
NativeCredential(
AttributeCount = 0u,
Attributes = zero,
Comment = zero,
TargetAlias = zero,
Type = CRED_TYPE.GENERIC,
Persist = 1u,
CredentialBlobSize = cred.CredentialBlobSize,
TargetName = Marshal.StringToCoTaskMemUni(cred.TargetName),
CredentialBlob = Marshal.StringToCoTaskMemUni(cred.CredentialBlob),
UserName = Marshal.StringToCoTaskMemUni(System.Environment.UserName)
)
member self.GetCredential() =
if (not self.IsInvalid) then
let ncred = Marshal.PtrToStructure(preexistingHandle, typeof<NativeCredential>) :?> NativeCredential
Credential(
CredentialBlobSize = ncred.CredentialBlobSize,
CredentialBlob = Marshal.PtrToStringUni(ncred.CredentialBlob, int (ncred.CredentialBlobSize / 2u)),
UserName = Marshal.PtrToStringUni(ncred.UserName),
TargetName = Marshal.PtrToStringUni(ncred.TargetName),
TargetAlias = Marshal.PtrToStringUni(ncred.TargetAlias),
Type = ncred.Type,
Flags = ncred.Flags,
Persist = ncred.Persist
)
else
invalidOp "Invalid CriticalHandle!"
override self.ReleaseHandle() =
if not self.IsInvalid then
ignore (NativeCalls.CredFree(preexistingHandle))
self.SetHandleAsInvalid()
true
else
false
open Internals
let readCredential targetName =
let mutable credPtr = nativeint 0
if NativeCalls.CredRead(targetName, enum 1, 0, &credPtr) then
use critCred = new CriticalCredentialHandle(credPtr)
let cred = critCred.GetCredential()
let username = cred.UserName
let password = cred.CredentialBlob
Some (username, password)
else None
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment