diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..f1f5afa4 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/docker/docker-credential-helpers + +go 1.13 + +require github.com/danieljoos/wincred v1.1.0 diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..b0c5dc40 --- /dev/null +++ b/go.sum @@ -0,0 +1,14 @@ +github.com/danieljoos/wincred v1.1.0 h1:3RNcEpBg4IhIChZdFRSdlQt1QjCp1sMAPIrOnm7Yf8g= +github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/danieljoos/wincred/.gitattributes b/vendor/github.com/danieljoos/wincred/.gitattributes new file mode 100644 index 00000000..d207b180 --- /dev/null +++ b/vendor/github.com/danieljoos/wincred/.gitattributes @@ -0,0 +1 @@ +*.go text eol=lf diff --git a/vendor/github.com/danieljoos/wincred/.gitignore b/vendor/github.com/danieljoos/wincred/.gitignore new file mode 100644 index 00000000..83656241 --- /dev/null +++ b/vendor/github.com/danieljoos/wincred/.gitignore @@ -0,0 +1,23 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test diff --git a/vendor/github.com/danieljoos/wincred/README.md b/vendor/github.com/danieljoos/wincred/README.md new file mode 100644 index 00000000..064efb76 --- /dev/null +++ b/vendor/github.com/danieljoos/wincred/README.md @@ -0,0 +1,98 @@ +wincred +======= + +Go wrapper around the Windows Credential Manager API functions. + +![Go](https://github.com/danieljoos/wincred/workflows/Go/badge.svg) +[![GoDoc](https://godoc.org/github.com/danieljoos/wincred?status.svg)](https://godoc.org/github.com/danieljoos/wincred) + + +Installation +------------ + +```Go +go get github.com/danieljoos/wincred +``` + + +Usage +----- + +See the following examples: + +### Create and store a new generic credential object +```Go +package main + +import ( + "fmt" + "github.com/danieljoos/wincred" +) + +func main() { + cred := wincred.NewGenericCredential("myGoApplication") + cred.CredentialBlob = []byte("my secret") + err := cred.Write() + + if err != nil { + fmt.Println(err) + } +} +``` + +### Retrieve a credential object +```Go +package main + +import ( + "fmt" + "github.com/danieljoos/wincred" +) + +func main() { + cred, err := wincred.GetGenericCredential("myGoApplication") + if err == nil { + fmt.Println(string(cred.CredentialBlob)) + } +} +``` + +### Remove a credential object +```Go +package main + +import ( + "fmt" + "github.com/danieljoos/wincred" +) + +func main() { + cred, err := wincred.GetGenericCredential("myGoApplication") + if err != nil { + fmt.Println(err) + return + } + cred.Delete() +} +``` + +### List all available credentials +```Go +package main + +import ( + "fmt" + "github.com/danieljoos/wincred" +) + +func main() { + creds, err := wincred.List() + if err != nil { + fmt.Println(err) + return + } + for i := range(creds) { + fmt.Println(creds[i].TargetName) + } +} +``` diff --git a/vendor/github.com/danieljoos/wincred/conversion.go b/vendor/github.com/danieljoos/wincred/conversion.go index e36f876f..685f90a8 100644 --- a/vendor/github.com/danieljoos/wincred/conversion.go +++ b/vendor/github.com/danieljoos/wincred/conversion.go @@ -1,3 +1,5 @@ +// +build windows + package wincred import ( @@ -9,48 +11,57 @@ import ( "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 +// uf16PtrToString creates a Go string from a pointer to a UTF16 encoded zero-terminated string. +// Such pointers are returned from the Windows API calls. +// The function creates a copy of the string. 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)) + for len := 0; ; len++ { + ptr := unsafe.Pointer(uintptr(unsafe.Pointer(wstr)) + uintptr(len)*unsafe.Sizeof(*wstr)) // see https://golang.org/pkg/unsafe/#Pointer (3) + if *(*uint16)(ptr) == 0 { + return string(utf16.Decode(*(*[]uint16)(unsafe.Pointer(&reflect.SliceHeader{ + Data: uintptr(unsafe.Pointer(wstr)), + Len: len, + Cap: len, + })))) } - buf = append(buf, rune) } } - return "" } -// Create a byte array from a given UTF 16 char array +// utf16ToByte creates 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 { + 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 { +// utf16FromString creates a UTF16 char array from a string. +func utf16FromString(str string) []uint16 { + return syscall.StringToUTF16(str) +} + +// goBytes copies the given C byte array to a Go byte array (see `C.GoBytes`). +// This function avoids having cgo as dependency. +func goBytes(src uintptr, len uint32) []byte { + if src == uintptr(0) { return []byte{} } - slice := (*[1 << 30]byte)(src)[0:len] rv := make([]byte, len) - copy(rv, slice) - return rv[:] + copy(rv, *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ + Data: src, + Len: int(len), + Cap: int(len), + }))) + return rv } // Convert the given CREDENTIAL struct to a more usable structure -func nativeToCredential(cred *nativeCREDENTIAL) (result *Credential) { - if unsafe.Pointer(cred) == nullPointer { +func sysToCredential(cred *sysCREDENTIAL) (result *Credential) { + if cred == nil { return nil } result = new(Credential) @@ -60,29 +71,28 @@ func nativeToCredential(cred *nativeCREDENTIAL) (result *Credential) { 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.CredentialBlob = goBytes(cred.CredentialBlob, cred.CredentialBlobSize) result.Attributes = make([]CredentialAttribute, cred.AttributeCount) - attrSliceHeader := reflect.SliceHeader{ + attrSlice := *(*[]sysCREDENTIAL_ATTRIBUTE)(unsafe.Pointer(&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) + resultAttr.Value = goBytes(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) { +func sysFromCredential(cred *Credential) (result *sysCREDENTIAL) { if cred == nil { return nil } - result = new(nativeCREDENTIAL) + result = new(sysCREDENTIAL) result.Flags = 0 result.Type = 0 result.TargetName, _ = syscall.UTF16PtrFromString(cred.TargetName) @@ -96,13 +106,13 @@ func nativeFromCredential(cred *Credential) (result *nativeCREDENTIAL) { } result.Persist = uint32(cred.Persist) result.AttributeCount = uint32(len(cred.Attributes)) - attributes := make([]nativeCREDENTIAL_ATTRIBUTE, len(cred.Attributes)) + attributes := make([]sysCREDENTIAL_ATTRIBUTE, len(cred.Attributes)) if len(attributes) > 0 { result.Attributes = uintptr(unsafe.Pointer(&attributes[0])) } else { result.Attributes = 0 } - for i, _ := range cred.Attributes { + for i := range cred.Attributes { inAttr := &cred.Attributes[i] outAttr := &attributes[i] outAttr.Keyword, _ = syscall.UTF16PtrFromString(inAttr.Keyword) diff --git a/vendor/github.com/danieljoos/wincred/conversion_unsupported.go b/vendor/github.com/danieljoos/wincred/conversion_unsupported.go new file mode 100644 index 00000000..a1ea7207 --- /dev/null +++ b/vendor/github.com/danieljoos/wincred/conversion_unsupported.go @@ -0,0 +1,11 @@ +// +build !windows + +package wincred + +func utf16ToByte(...interface{}) []byte { + return nil +} + +func utf16FromString(...interface{}) []uint16 { + return nil +} diff --git a/vendor/github.com/danieljoos/wincred/go.mod b/vendor/github.com/danieljoos/wincred/go.mod new file mode 100644 index 00000000..b5615804 --- /dev/null +++ b/vendor/github.com/danieljoos/wincred/go.mod @@ -0,0 +1,5 @@ +module github.com/danieljoos/wincred + +go 1.13 + +require github.com/stretchr/testify v1.5.1 diff --git a/vendor/github.com/danieljoos/wincred/go.sum b/vendor/github.com/danieljoos/wincred/go.sum new file mode 100644 index 00000000..c0565d71 --- /dev/null +++ b/vendor/github.com/danieljoos/wincred/go.sum @@ -0,0 +1,12 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/danieljoos/wincred/native.go b/vendor/github.com/danieljoos/wincred/native.go deleted file mode 100644 index 55926c87..00000000 --- a/vendor/github.com/danieljoos/wincred/native.go +++ /dev/null @@ -1,137 +0,0 @@ -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 -} diff --git a/vendor/github.com/danieljoos/wincred/sys.go b/vendor/github.com/danieljoos/wincred/sys.go new file mode 100644 index 00000000..7b83e843 --- /dev/null +++ b/vendor/github.com/danieljoos/wincred/sys.go @@ -0,0 +1,143 @@ +// +build windows + +package wincred + +import ( + "reflect" + "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) +} + +// https://docs.microsoft.com/en-us/windows/desktop/api/wincred/ns-wincred-_credentialw +type sysCREDENTIAL 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 +} + +// https://docs.microsoft.com/en-us/windows/desktop/api/wincred/ns-wincred-_credential_attributew +type sysCREDENTIAL_ATTRIBUTE struct { + Keyword *uint16 + Flags uint32 + ValueSize uint32 + Value uintptr +} + +// https://docs.microsoft.com/en-us/windows/desktop/api/wincred/ns-wincred-_credentialw +type sysCRED_TYPE uint32 + +const ( + sysCRED_TYPE_GENERIC sysCRED_TYPE = 0x1 + sysCRED_TYPE_DOMAIN_PASSWORD sysCRED_TYPE = 0x2 + sysCRED_TYPE_DOMAIN_CERTIFICATE sysCRED_TYPE = 0x3 + sysCRED_TYPE_DOMAIN_VISIBLE_PASSWORD sysCRED_TYPE = 0x4 + sysCRED_TYPE_GENERIC_CERTIFICATE sysCRED_TYPE = 0x5 + sysCRED_TYPE_DOMAIN_EXTENDED sysCRED_TYPE = 0x6 + + // https://docs.microsoft.com/en-us/windows/desktop/Debug/system-error-codes + sysERROR_NOT_FOUND = syscall.Errno(1168) + sysERROR_INVALID_PARAMETER = syscall.Errno(87) +) + +// https://docs.microsoft.com/en-us/windows/desktop/api/wincred/nf-wincred-credreadw +func sysCredRead(targetName string, typ sysCRED_TYPE) (*Credential, error) { + var pcred *sysCREDENTIAL + 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(uintptr(unsafe.Pointer(pcred))) + + return sysToCredential(pcred), nil +} + +// https://docs.microsoft.com/en-us/windows/desktop/api/wincred/nf-wincred-credwritew +func sysCredWrite(cred *Credential, typ sysCRED_TYPE) error { + ncred := sysFromCredential(cred) + ncred.Type = uint32(typ) + ret, _, err := procCredWrite.Call( + uintptr(unsafe.Pointer(ncred)), + 0, + ) + if ret == 0 { + return err + } + + return nil +} + +// https://docs.microsoft.com/en-us/windows/desktop/api/wincred/nf-wincred-creddeletew +func sysCredDelete(cred *Credential, typ sysCRED_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://docs.microsoft.com/en-us/windows/desktop/api/wincred/nf-wincred-credenumeratew +func sysCredEnumerate(filter string, all bool) ([]*Credential, error) { + var count int + var pcreds uintptr + var filterPtr *uint16 + if !all { + filterPtr, _ = syscall.UTF16PtrFromString(filter) + } + ret, _, err := procCredEnumerate.Call( + uintptr(unsafe.Pointer(filterPtr)), + 0, + uintptr(unsafe.Pointer(&count)), + uintptr(unsafe.Pointer(&pcreds)), + ) + if ret == 0 { + return nil, err + } + defer procCredFree.Call(pcreds) + credsSlice := *(*[]*sysCREDENTIAL)(unsafe.Pointer(&reflect.SliceHeader{ + Data: pcreds, + Len: count, + Cap: count, + })) + creds := make([]*Credential, count, count) + for i, cred := range credsSlice { + creds[i] = sysToCredential(cred) + } + + return creds, nil +} diff --git a/vendor/github.com/danieljoos/wincred/sys_unsupported.go b/vendor/github.com/danieljoos/wincred/sys_unsupported.go new file mode 100644 index 00000000..b47bccf8 --- /dev/null +++ b/vendor/github.com/danieljoos/wincred/sys_unsupported.go @@ -0,0 +1,36 @@ +// +build !windows + +package wincred + +import ( + "errors" + "syscall" +) + +const ( + sysCRED_TYPE_GENERIC = 0 + sysCRED_TYPE_DOMAIN_PASSWORD = 0 + sysCRED_TYPE_DOMAIN_CERTIFICATE = 0 + sysCRED_TYPE_DOMAIN_VISIBLE_PASSWORD = 0 + sysCRED_TYPE_GENERIC_CERTIFICATE = 0 + sysCRED_TYPE_DOMAIN_EXTENDED = 0 + + sysERROR_NOT_FOUND = syscall.Errno(1) + sysERROR_INVALID_PARAMETER = syscall.Errno(1) +) + +func sysCredRead(...interface{}) (*Credential, error) { + return nil, errors.New("Operation not supported") +} + +func sysCredWrite(...interface{}) error { + return errors.New("Operation not supported") +} + +func sysCredDelete(...interface{}) error { + return errors.New("Operation not supported") +} + +func sysCredEnumerate(...interface{}) ([]*Credential, error) { + return nil, errors.New("Operation not supported") +} diff --git a/vendor/github.com/danieljoos/wincred/types.go b/vendor/github.com/danieljoos/wincred/types.go index a0679921..28debc93 100644 --- a/vendor/github.com/danieljoos/wincred/types.go +++ b/vendor/github.com/danieljoos/wincred/types.go @@ -4,19 +4,38 @@ import ( "time" ) +// CredentialPersistence describes one of three persistence modes of a credential. +// A detailed description of the available modes can be found on +// Docs: https://docs.microsoft.com/en-us/windows/desktop/api/wincred/ns-wincred-_credentialw type CredentialPersistence uint32 const ( - PersistSession CredentialPersistence = 0x1 + // PersistSession indicates that the credential only persists for the life + // of the current Windows login session. Such a credential is not visible in + // any other logon session, even from the same user. + PersistSession CredentialPersistence = 0x1 + + // PersistLocalMachine indicates that the credential persists for this and + // all subsequent logon sessions on this local machine/computer. It is + // however not visible for logon sessions of this user on a different + // machine. PersistLocalMachine CredentialPersistence = 0x2 - PersistEnterprise CredentialPersistence = 0x3 + + // PersistEnterprise indicates that the credential persists for this and all + // subsequent logon sessions for this user. It is also visible for logon + // sessions on different computers. + PersistEnterprise CredentialPersistence = 0x3 ) +// CredentialAttribute represents an application-specific attribute of a credential. type CredentialAttribute struct { Keyword string Value []byte } +// Credential is the basic credential structure. +// A credential is identified by its target name. +// The actual credential secret is available in the CredentialBlob field. type Credential struct { TargetName string Comment string @@ -28,10 +47,23 @@ type Credential struct { Persist CredentialPersistence } +// GenericCredential holds a credential for generic usage. +// It is typically defined and used by applications that need to manage user +// secrets. +// +// More information about the available kinds of credentials of the Windows +// Credential Management API can be found on Docs: +// https://docs.microsoft.com/en-us/windows/desktop/SecAuthN/kinds-of-credentials type GenericCredential struct { Credential } +// DomainPassword holds a domain credential that is typically used by the +// operating system for user logon. +// +// More information about the available kinds of credentials of the Windows +// Credential Management API can be found on Docs: +// https://docs.microsoft.com/en-us/windows/desktop/SecAuthN/kinds-of-credentials type DomainPassword struct { Credential } diff --git a/vendor/github.com/danieljoos/wincred/wincred.go b/vendor/github.com/danieljoos/wincred/wincred.go index ac5d4a70..c5dbc2c9 100644 --- a/vendor/github.com/danieljoos/wincred/wincred.go +++ b/vendor/github.com/danieljoos/wincred/wincred.go @@ -1,19 +1,36 @@ +// Package wincred provides primitives for accessing the Windows Credentials Management API. +// This includes functions for retrieval, listing and storage of credentials as well as Go structures for convenient access to the credential data. +// +// A more detailed description of Windows Credentials Management can be found on +// Docs: https://docs.microsoft.com/en-us/windows/desktop/SecAuthN/credentials-management package wincred -import ( - "syscall" +import "errors" + +const ( + // ErrElementNotFound is the error that is returned if a requested element cannot be found. + // This error constant can be used to check if a credential could not be found. + ErrElementNotFound = sysERROR_NOT_FOUND + + // ErrInvalidParameter is the error that is returned for invalid parameters. + // This error constant can be used to check if the given function parameters were invalid. + // For example when trying to create a new generic credential with an empty target name. + ErrInvalidParameter = sysERROR_INVALID_PARAMETER ) -// Get the generic credential with the given name from Windows credential manager +// GetGenericCredential fetches the generic credential with the given name from Windows credential manager. +// It returns nil and an error if the credential could not be found or an error occurred. func GetGenericCredential(targetName string) (*GenericCredential, error) { - cred, err := nativeCredRead(targetName, naCRED_TYPE_GENERIC) + cred, err := sysCredRead(targetName, sysCRED_TYPE_GENERIC) if cred != nil { return &GenericCredential{*cred}, err } return nil, err } -// Create a new generic credential with the given name +// NewGenericCredential creates a new generic credential object with the given name. +// The persist mode of the newly created object is set to a default value that indicates local-machine-wide storage. +// The credential object is NOT yet persisted to the Windows credential vault. func NewGenericCredential(targetName string) (result *GenericCredential) { result = new(GenericCredential) result.TargetName = targetName @@ -21,28 +38,31 @@ func NewGenericCredential(targetName string) (result *GenericCredential) { return } -// Persist the credential to Windows credential manager +// Write persists the generic credential object to Windows credential manager. func (t *GenericCredential) Write() (err error) { - err = nativeCredWrite(&t.Credential, naCRED_TYPE_GENERIC) + err = sysCredWrite(&t.Credential, sysCRED_TYPE_GENERIC) return } -// Delete the credential from Windows credential manager +// Delete removes the credential object from Windows credential manager. func (t *GenericCredential) Delete() (err error) { - err = nativeCredDelete(&t.Credential, naCRED_TYPE_GENERIC) + err = sysCredDelete(&t.Credential, sysCRED_TYPE_GENERIC) return } -// Get the domain password credential with the given target host name +// GetDomainPassword fetches the domain-password credential with the given target host name from Windows credential manager. +// It returns nil and an error if the credential could not be found or an error occurred. func GetDomainPassword(targetName string) (*DomainPassword, error) { - cred, err := nativeCredRead(targetName, naCRED_TYPE_DOMAIN_PASSWORD) + cred, err := sysCredRead(targetName, sysCRED_TYPE_DOMAIN_PASSWORD) if cred != nil { return &DomainPassword{*cred}, err } return nil, err } -// Create a new domain password credential used for login to the given target host name +// NewDomainPassword creates a new domain-password credential used for login to the given target host name. +// The persist mode of the newly created object is set to a default value that indicates local-machine-wide storage. +// The credential object is NOT yet persisted to the Windows credential vault. func NewDomainPassword(targetName string) (result *DomainPassword) { result = new(DomainPassword) result.TargetName = targetName @@ -50,28 +70,39 @@ func NewDomainPassword(targetName string) (result *DomainPassword) { return } -// Persist the domain password credential to Windows credential manager +// Write persists the domain-password credential to Windows credential manager. func (t *DomainPassword) Write() (err error) { - err = nativeCredWrite(&t.Credential, naCRED_TYPE_DOMAIN_PASSWORD) + err = sysCredWrite(&t.Credential, sysCRED_TYPE_DOMAIN_PASSWORD) return } -// Delete the domain password credential from Windows credential manager +// Delete removes the domain-password credential from Windows credential manager. func (t *DomainPassword) Delete() (err error) { - err = nativeCredDelete(&t.Credential, naCRED_TYPE_DOMAIN_PASSWORD) + err = sysCredDelete(&t.Credential, sysCRED_TYPE_DOMAIN_PASSWORD) return } -// Set the CredentialBlob field of a domain password credential -// using an UTF16 encoded password string +// SetPassword sets the CredentialBlob field of a domain password credential to the given string. func (t *DomainPassword) SetPassword(pw string) { - t.CredentialBlob = utf16ToByte(syscall.StringToUTF16(pw)) + t.CredentialBlob = utf16ToByte(utf16FromString(pw)) } -// List the contents of the Credentials store +// List retrieves all credentials of the Credentials store. func List() ([]*Credential, error) { - creds, err := nativeCredEnumerate("", true) - if err != nil && err.Error() == naERROR_NOT_FOUND { + creds, err := sysCredEnumerate("", true) + if err != nil && errors.Is(err, ErrElementNotFound) { + // Ignore ERROR_NOT_FOUND and return an empty list instead + creds = []*Credential{} + err = nil + } + return creds, err +} + +// FilteredList retrieves the list of credentials from the Credentials store that match the given filter. +// The filter string defines the prefix followed by an asterisk for the `TargetName` attribute of the credentials. +func FilteredList(filter string) ([]*Credential, error) { + creds, err := sysCredEnumerate(filter, false) + if err != nil && errors.Is(err, ErrElementNotFound) { // Ignore ERROR_NOT_FOUND and return an empty list instead creds = []*Credential{} err = nil diff --git a/vendor/modules.txt b/vendor/modules.txt new file mode 100644 index 00000000..58bb51a6 --- /dev/null +++ b/vendor/modules.txt @@ -0,0 +1,2 @@ +# github.com/danieljoos/wincred v1.1.0 +github.com/danieljoos/wincred