mirror of
https://github.com/docker/docker-credential-helpers.git
synced 2026-06-13 16:01:28 +05:30
a994ca1d54
This includes the following changes: - Removed need for `C` - Added some null checks to avoid possible panics - `List` returns an empty list instead of an error, in case no credentials are installed on the system Signed-off-by: Daniel Joos <daniel@joosweb.de>
122 lines
3.7 KiB
Go
122 lines
3.7 KiB
Go
package wincred
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"reflect"
|
|
"syscall"
|
|
"time"
|
|
"unicode/utf16"
|
|
"unsafe"
|
|
)
|
|
|
|
var nullPointer = unsafe.Pointer(uintptr(0))
|
|
|
|
// Create a Go string using a pointer to a zero-terminated UTF 16 encoded string.
|
|
// See github.com/AllenDang/w32
|
|
func utf16PtrToString(wstr *uint16) string {
|
|
if wstr != nil {
|
|
buf := make([]uint16, 0, 256)
|
|
for ptr := uintptr(unsafe.Pointer(wstr)); ; ptr += 2 {
|
|
rune := *(*uint16)(unsafe.Pointer(ptr))
|
|
if rune == 0 {
|
|
return string(utf16.Decode(buf))
|
|
}
|
|
buf = append(buf, rune)
|
|
}
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
// Create a byte array from a given UTF 16 char array
|
|
func utf16ToByte(wstr []uint16) (result []byte) {
|
|
result = make([]byte, len(wstr)*2)
|
|
for i, _ := range wstr {
|
|
binary.LittleEndian.PutUint16(result[(i*2):(i*2)+2], wstr[i])
|
|
}
|
|
return
|
|
}
|
|
|
|
// Copies the given C byte array to a Go byte array (see `C.GoBytes`)
|
|
func goBytes(src unsafe.Pointer, len uint32) []byte {
|
|
if src == nullPointer {
|
|
return []byte{}
|
|
}
|
|
slice := (*[1 << 30]byte)(src)[0:len]
|
|
rv := make([]byte, len)
|
|
copy(rv, slice)
|
|
return rv[:]
|
|
}
|
|
|
|
// Convert the given CREDENTIAL struct to a more usable structure
|
|
func nativeToCredential(cred *nativeCREDENTIAL) (result *Credential) {
|
|
if unsafe.Pointer(cred) == nullPointer {
|
|
return nil
|
|
}
|
|
result = new(Credential)
|
|
result.Comment = utf16PtrToString(cred.Comment)
|
|
result.TargetName = utf16PtrToString(cred.TargetName)
|
|
result.TargetAlias = utf16PtrToString(cred.TargetAlias)
|
|
result.UserName = utf16PtrToString(cred.UserName)
|
|
result.LastWritten = time.Unix(0, cred.LastWritten.Nanoseconds())
|
|
result.Persist = CredentialPersistence(cred.Persist)
|
|
result.CredentialBlob = goBytes(unsafe.Pointer(cred.CredentialBlob), cred.CredentialBlobSize)
|
|
result.Attributes = make([]CredentialAttribute, cred.AttributeCount)
|
|
attrSliceHeader := reflect.SliceHeader{
|
|
Data: cred.Attributes,
|
|
Len: int(cred.AttributeCount),
|
|
Cap: int(cred.AttributeCount),
|
|
}
|
|
attrSlice := *(*[]nativeCREDENTIAL_ATTRIBUTE)(unsafe.Pointer(&attrSliceHeader))
|
|
for i, attr := range attrSlice {
|
|
resultAttr := &result.Attributes[i]
|
|
resultAttr.Keyword = utf16PtrToString(attr.Keyword)
|
|
resultAttr.Value = goBytes(unsafe.Pointer(attr.Value), attr.ValueSize)
|
|
}
|
|
return result
|
|
}
|
|
|
|
// Convert the given Credential object back to a CREDENTIAL struct, which can be used for calling the
|
|
// Windows APIs
|
|
func nativeFromCredential(cred *Credential) (result *nativeCREDENTIAL) {
|
|
if cred == nil {
|
|
return nil
|
|
}
|
|
result = new(nativeCREDENTIAL)
|
|
result.Flags = 0
|
|
result.Type = 0
|
|
result.TargetName, _ = syscall.UTF16PtrFromString(cred.TargetName)
|
|
result.Comment, _ = syscall.UTF16PtrFromString(cred.Comment)
|
|
result.LastWritten = syscall.NsecToFiletime(cred.LastWritten.UnixNano())
|
|
result.CredentialBlobSize = uint32(len(cred.CredentialBlob))
|
|
if len(cred.CredentialBlob) > 0 {
|
|
result.CredentialBlob = uintptr(unsafe.Pointer(&cred.CredentialBlob[0]))
|
|
} else {
|
|
result.CredentialBlob = 0
|
|
}
|
|
result.Persist = uint32(cred.Persist)
|
|
result.AttributeCount = uint32(len(cred.Attributes))
|
|
attributes := make([]nativeCREDENTIAL_ATTRIBUTE, len(cred.Attributes))
|
|
if len(attributes) > 0 {
|
|
result.Attributes = uintptr(unsafe.Pointer(&attributes[0]))
|
|
} else {
|
|
result.Attributes = 0
|
|
}
|
|
for i, _ := range cred.Attributes {
|
|
inAttr := &cred.Attributes[i]
|
|
outAttr := &attributes[i]
|
|
outAttr.Keyword, _ = syscall.UTF16PtrFromString(inAttr.Keyword)
|
|
outAttr.Flags = 0
|
|
outAttr.ValueSize = uint32(len(inAttr.Value))
|
|
if len(inAttr.Value) > 0 {
|
|
outAttr.Value = uintptr(unsafe.Pointer(&inAttr.Value[0]))
|
|
} else {
|
|
outAttr.Value = 0
|
|
}
|
|
}
|
|
result.TargetAlias, _ = syscall.UTF16PtrFromString(cred.TargetAlias)
|
|
result.UserName, _ = syscall.UTF16PtrFromString(cred.UserName)
|
|
|
|
return
|
|
}
|