Initial import
This commit is contained in:
104
keyring_windows.go
Normal file
104
keyring_windows.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package secret
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||
procCredRead = modadvapi32.NewProc("CredReadW")
|
||||
procCredFree winproc = modadvapi32.NewProc("CredFree")
|
||||
)
|
||||
|
||||
// Interface for syscall.Proc: helps testing
|
||||
type winproc interface {
|
||||
Call(a ...uintptr) (r1, r2 uintptr, lastErr error)
|
||||
}
|
||||
|
||||
type keyring struct {
|
||||
service string
|
||||
}
|
||||
|
||||
func keyringProvider(service string) (Provider, error) {
|
||||
return keyring{service}, nil
|
||||
}
|
||||
|
||||
func (p keyring) GetSecret(key string) (value []byte, err error) {
|
||||
return sysCredRead(p.service+":"+key, sysCRED_TYPE_GENERIC)
|
||||
}
|
||||
|
||||
// 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 windows.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-_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/api/wincred/nf-wincred-credreadw
|
||||
func sysCredRead(targetName string, typ sysCRED_TYPE) ([]byte, error) {
|
||||
var pcred *sysCREDENTIAL
|
||||
targetNamePtr, _ := windows.UTF16PtrFromString(targetName)
|
||||
ret, _, err := syscall.SyscallN(
|
||||
procCredRead.Addr(),
|
||||
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 goBytes(pcred.CredentialBlob, pcred.CredentialBlobSize), nil
|
||||
}
|
||||
|
||||
// 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{}
|
||||
}
|
||||
rv := make([]byte, len)
|
||||
copy(rv, *(*[]byte)(unsafe.Pointer(&struct {
|
||||
Data unsafe.Pointer
|
||||
Len int
|
||||
Cap int
|
||||
}{
|
||||
Data: unsafe.Pointer(src),
|
||||
Len: int(len),
|
||||
Cap: int(len),
|
||||
})))
|
||||
/*
|
||||
copy(rv, *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
|
||||
Data: src,
|
||||
Len: int(len),
|
||||
Cap: int(len),
|
||||
})))
|
||||
*/
|
||||
return rv
|
||||
}
|
Reference in New Issue
Block a user