forked from danieljoos/wincred
-
Notifications
You must be signed in to change notification settings - Fork 1
/
sys.go
135 lines (119 loc) · 3.31 KB
/
sys.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// +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
}
func convertErr(err error) error {
sysErr, ok := err.(syscall.Errno)
if ok {
return Err(sysErr)
}
return err
}
// 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, convertErr(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 convertErr(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 convertErr(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, convertErr(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
}