Reputation: 1020
I have problems with enumerating Windows Credentials from VB.Net application with WinAPI functions. My code is below.
<DllImport("advapi32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
Private Shared Function CredEnumerate(filter As String, flag As Integer, ByRef count As Integer, ByRef pCredentials As IntPtr) As Boolean
End Function
Public Enum CRED_PERSIST As UInteger
SESSION = 1
LOCAL_MACHINE = 2
ENTERPRISE = 3
End Enum
Public Enum CRED_TYPE As UInteger
GENERIC = 1
DOMAIN_PASSWORD = 2
DOMAIN_CERTIFICATE = 3
DOMAIN_VISIBLE_PASSWORD = 4
GENERIC_CERTIFICATE = 5
DOMAIN_EXTENDED = 6
MAXIMUM = 7
' Maximum supported cred type
MAXIMUM_EX = (MAXIMUM + 1000)
' Allow new applications to run on old OSes
End Enum
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
Public Structure CREDENTIAL_ATTRIBUTE
Private Keyword As String
Private Flags As UInteger
Private ValueSize As UInteger
Private Value As IntPtr
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>
Private Class Credential
Public Flags As UInt32
Public Type As CRED_TYPE
Public TargetName As String
Public Comment As String
Public LastWritten As ComTypes.FILETIME
Public CredentialBlobSize As UInt32
Public CredentialBlob As IntPtr
Public Persist As CRED_PERSIST
Public AttributeCount As UInt32
Public Attributes As IntPtr
Public TargetAlias As String
Public UserName As String
End Class
Private Function GetCredentials() As Credential()
Dim count As Integer = 0
Dim pCredentials As IntPtr = IntPtr.Zero
Dim credentials As List(Of Credential) = New List(Of Credential)
Dim ret As Boolean = CredEnumerate(Nothing, 0, count, pCredentials)
If ret <> False Then
Dim p As IntPtr = pCredentials
For n As Integer = 0 To count - 1
If Marshal.SizeOf(p) = 4 Then
p = New IntPtr(p.ToInt32() + n)
Else
p = New IntPtr(p.ToInt64() + n)
End If
credentials.Add(Marshal.PtrToStructure(Marshal.ReadIntPtr(p), GetType(Credential)))
Next
End If
Return credentials.ToArray
End Function
Marshal.PtrToStructure
function throws System.ExecetionEngineException
without any useful information. I suspected with wrong credential structure but it seems correct to me. If you have any idea about what is wrong, I'm waiting your answers.
Thanks
Edit: Thanks to @Zaggler here is my corrected function now it adds credentials to array but whole structure is empty. Here is new function.
Private Function GetCredentials() As Credential()
Dim count As Integer = 0
Dim pCredentials As IntPtr = IntPtr.Zero
Dim credentials As List(Of Credential) = New List(Of Credential)
Dim ret As Boolean = CredEnumerate(Nothing, 0, count, pCredentials)
If ret <> False Then
Dim p As IntPtr = pCredentials
For n As Integer = 0 To count - 1
Dim cred As Credential = New Credential
Dim pnt As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(cred))
Try
If Marshal.SizeOf(p) = 4 Then
p = New IntPtr(p.ToInt32() + n)
Else
p = New IntPtr(p.ToInt64() + n)
End If
Marshal.StructureToPtr(cred, pnt, False)
credentials.Add(Marshal.PtrToStructure(pnt, GetType(Credential)))
Finally
Marshal.FreeHGlobal(pnt)
End Try
Next
End If
Return credentials.ToArray
End Function
Upvotes: 0
Views: 167
Reputation: 473
Your first attempt was better. Don't use AllocHGlobal and FreeHGlobal. Winapi is allocating memory. Lookup CredFree to release allocated memory (after marshalling structs).
There is a mistake in your pointer arithmetic. You have to increment with pointer size so try:
...
Dim p As IntPtr = pCredentials
For n As Integer = 0 To count - 1
credentials.Add(Marshal.PtrToStructure(Marshal.ReadIntPtr(p), GetType(Credential)))
p = p + IntPtr.Size
Next
...
UInt32 and UInteger are the same, so be consistent and choose one.
You could try to use Charset.Auto for everything, if that doesn't work, try Charset.Unicode and use CredEnumerateW function.
Upvotes: 1