package wincred import ( "syscall" "unsafe" ) var ( modadvapi32 = syscall.NewLazyDLL("advapi32.dll") procCredRead proc = modadvapi32.NewProc("CredReadW") procCredWrite proc = modadvapi32.NewProc("CredWriteW") procCredDelete proc = modadvapi32.NewProc("CredDeleteW") procCredFree proc = modadvapi32.NewProc("CredFree") procCredEnumerate proc = modadvapi32.NewProc("CredEnumerateW") ) // Interface for syscall.Proc: helps testing type proc interface { Call(a ...uintptr) (r1, r2 uintptr, lastErr error) } // http://msdn.microsoft.com/en-us/library/windows/desktop/aa374788(v=vs.85).aspx type nativeCREDENTIAL struct { Flags uint32 Type uint32 TargetName *uint16 Comment *uint16 LastWritten syscall.Filetime CredentialBlobSize uint32 CredentialBlob uintptr Persist uint32 AttributeCount uint32 Attributes uintptr TargetAlias *uint16 UserName *uint16 } // http://msdn.microsoft.com/en-us/library/windows/desktop/aa374790(v=vs.85).aspx type nativeCREDENTIAL_ATTRIBUTE struct { Keyword *uint16 Flags uint32 ValueSize uint32 Value uintptr } // http://msdn.microsoft.com/en-us/library/windows/desktop/aa374788(v=vs.85).aspx type nativeCRED_TYPE uint32 const ( naCRED_TYPE_GENERIC nativeCRED_TYPE = 0x1 naCRED_TYPE_DOMAIN_PASSWORD nativeCRED_TYPE = 0x2 naCRED_TYPE_DOMAIN_CERTIFICATE nativeCRED_TYPE = 0x3 naCRED_TYPE_DOMAIN_VISIBLE_PASSWORD nativeCRED_TYPE = 0x4 naCRED_TYPE_GENERIC_CERTIFICATE nativeCRED_TYPE = 0x5 naCRED_TYPE_DOMAIN_EXTENDED nativeCRED_TYPE = 0x6 naERROR_NOT_FOUND = "Element not found." ) // http://msdn.microsoft.com/en-us/library/windows/desktop/aa374804(v=vs.85).aspx func nativeCredRead(targetName string, typ nativeCRED_TYPE) (*Credential, error) { var pcred uintptr targetNamePtr, _ := syscall.UTF16PtrFromString(targetName) ret, _, err := procCredRead.Call( uintptr(unsafe.Pointer(targetNamePtr)), uintptr(typ), 0, uintptr(unsafe.Pointer(&pcred)), ) if ret == 0 { return nil, err } defer procCredFree.Call(pcred) return nativeToCredential((*nativeCREDENTIAL)(unsafe.Pointer(pcred))), nil } // http://msdn.microsoft.com/en-us/library/windows/desktop/aa375187(v=vs.85).aspx func nativeCredWrite(cred *Credential, typ nativeCRED_TYPE) error { ncred := nativeFromCredential(cred) ncred.Type = uint32(typ) ret, _, err := procCredWrite.Call( uintptr(unsafe.Pointer(ncred)), 0, ) if ret == 0 { return err } return nil } // http://msdn.microsoft.com/en-us/library/windows/desktop/aa374787(v=vs.85).aspx func nativeCredDelete(cred *Credential, typ nativeCRED_TYPE) error { targetNamePtr, _ := syscall.UTF16PtrFromString(cred.TargetName) ret, _, err := procCredDelete.Call( uintptr(unsafe.Pointer(targetNamePtr)), uintptr(typ), 0, ) if ret == 0 { return err } return nil } // https://msdn.microsoft.com/en-us/library/windows/desktop/aa374794(v=vs.85).aspx func nativeCredEnumerate(filter string, all bool) ([]*Credential, error) { var count int var pcreds uintptr var filterPtr uintptr if !all { filterUtf16Ptr, _ := syscall.UTF16PtrFromString(filter) filterPtr = uintptr(unsafe.Pointer(filterUtf16Ptr)) } else { filterPtr = 0 } ret, _, err := procCredEnumerate.Call( filterPtr, 0, uintptr(unsafe.Pointer(&count)), uintptr(unsafe.Pointer(&pcreds)), ) if ret == 0 { return nil, err } defer procCredFree.Call(pcreds) pcredsSlice := (*[1 << 30]uintptr)(unsafe.Pointer(pcreds))[:count:count] creds := make([]*Credential, count) for i := range creds { creds[i] = nativeToCredential((*nativeCREDENTIAL)(unsafe.Pointer(pcredsSlice[i]))) } return creds, nil }