forked from iamacarpet/go-win64api
/
bitlocker.go
executable file
·166 lines (139 loc) · 5.5 KB
/
bitlocker.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// +build windows,amd64
package winapi
import (
"fmt"
ole "github.com/go-ole/go-ole"
"github.com/go-ole/go-ole/oleutil"
so "github.com/iamacarpet/go-win64api/shared"
)
func GetBitLockerRecoveryInfo() ([]*so.BitLockerDeviceInfo, error) {
return getBitLockerRecoveryInfoInternal("")
}
func GetBitLockerRecoveryInfoForDrive(driveLetter string) (*so.BitLockerDeviceInfo, error) {
result, err := getBitLockerRecoveryInfoInternal(" WHERE DriveLetter = '" + driveLetter + "'")
if err != nil {
return nil, err
}
if len(result) < 1 {
return nil, fmt.Errorf("Error getting BitLocker Recovery Info, Drive not found: %s", driveLetter)
} else if len(result) > 1 {
return nil, fmt.Errorf("Error getting BitLocker Recovery Info, Too many results: %s", driveLetter)
} else {
return result[0], err
}
}
func getBitLockerRecoveryInfoInternal(where string) ([]*so.BitLockerDeviceInfo, error) {
ole.CoInitialize(0)
defer ole.CoUninitialize()
unknown, err := oleutil.CreateObject("WbemScripting.SWbemLocator")
if err != nil {
return nil, fmt.Errorf("Unable to create initial object, %s", err.Error())
}
defer unknown.Release()
wmi, err := unknown.QueryInterface(ole.IID_IDispatch)
if err != nil {
return nil, fmt.Errorf("Unable to create initial object, %s", err.Error())
}
defer wmi.Release()
serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer", nil, `\\.\ROOT\CIMV2\Security\MicrosoftVolumeEncryption`)
if err != nil {
return nil, fmt.Errorf("Permission Denied - %s", err)
}
service := serviceRaw.ToIDispatch()
defer service.Release()
resultRaw, err := oleutil.CallMethod(service, "ExecQuery", "SELECT * FROM Win32_EncryptableVolume"+where)
if err != nil {
return nil, fmt.Errorf("Unable to execute query while getting BitLocker info. %s", err.Error())
}
result := resultRaw.ToIDispatch()
defer result.Release()
retBitLocker := []*so.BitLockerDeviceInfo{}
countVar, err := oleutil.GetProperty(result, "Count")
if err != nil {
return nil, fmt.Errorf("Unable to get property Count while processing BitLocker info. %s", err.Error())
}
count := int(countVar.Val)
for i := 0; i < count; i++ {
retData, err := bitlockerRecoveryInfo(result, i)
if err != nil {
return nil, err
}
retBitLocker = append(retBitLocker, retData)
}
return retBitLocker, nil
}
func bitlockerRecoveryInfo(result *ole.IDispatch, i int) (*so.BitLockerDeviceInfo, error) {
itemRaw, err := oleutil.CallMethod(result, "ItemIndex", i)
if err != nil {
return nil, fmt.Errorf("Failed to fetch result row while processing BitLocker info. %s", err.Error())
}
item := itemRaw.ToIDispatch()
defer item.Release()
retData := &so.BitLockerDeviceInfo{
RecoveryKeys: []string{},
}
resDeviceID, err := oleutil.GetProperty(item, "DeviceID")
if err != nil {
return nil, fmt.Errorf("Error while getting property DeviceID from BitLocker info. %s", err.Error())
}
retData.DeviceID = resDeviceID.ToString()
resPersistentVolumeID, err := oleutil.GetProperty(item, "PersistentVolumeID")
if err != nil {
return nil, fmt.Errorf("Error while getting property PersistentVolumeID from BitLocker info. %s", err.Error())
}
retData.PersistentVolumeID = resPersistentVolumeID.ToString()
resDriveLetter, err := oleutil.GetProperty(item, "DriveLetter")
if err != nil {
return nil, fmt.Errorf("Error while getting property DriveLetter from BitLocker info. %s", err.Error())
}
retData.DriveLetter = resDriveLetter.ToString()
resProtectionStatus, err := oleutil.GetProperty(item, "ProtectionStatus")
if err != nil {
return nil, fmt.Errorf("Error while getting property ProtectionStatus from BitLocker info. %s", err.Error())
}
var ok bool
retData.ProtectionStatus, ok = resProtectionStatus.Value().(int32)
if !ok {
return nil, fmt.Errorf("Failed to parse ProtectionStatus from BitLocker info as uint32")
}
resConversionStatus, err := oleutil.GetProperty(item, "ConversionStatus")
if err != nil {
return nil, fmt.Errorf("Error while getting property ConversionStatus from BitLocker info. %s", err.Error())
}
ok = false
retData.ConversionStatus, ok = resConversionStatus.Value().(int32)
if !ok {
return nil, fmt.Errorf("Failed to parse ConversionStatus from BitLocker info as uint32")
}
var keyProtectorResults ole.VARIANT
ole.VariantInit(&keyProtectorResults)
keyIDResultRaw, err := oleutil.CallMethod(item, "GetKeyProtectors", 3, &keyProtectorResults)
if err != nil {
return nil, fmt.Errorf("Unable to get Key Protectors while getting BitLocker info. %s", err.Error())
} else if val, ok := keyIDResultRaw.Value().(int32); val != 0 || !ok {
return nil, fmt.Errorf("Unable to get Key Protectors while getting BitLocker info. Return code %d", val)
}
keyProtectorValues := keyProtectorResults.ToArray().ToValueArray()
for _, keyIDItemRaw := range keyProtectorValues {
err = func() error {
keyIDItem, ok := keyIDItemRaw.(string)
if !ok {
return fmt.Errorf("KeyProtectorID wasn't a string...")
}
var recoveryKey ole.VARIANT
ole.VariantInit(&recoveryKey)
recoveryKeyResultRaw, err := oleutil.CallMethod(item, "GetKeyProtectorNumericalPassword", keyIDItem, &recoveryKey)
if err != nil {
return fmt.Errorf("Unable to get Recovery Key while getting BitLocker info. %s", err.Error())
} else if val, ok := recoveryKeyResultRaw.Value().(int32); val != 0 || !ok {
return fmt.Errorf("Unable to get Recovery Key while getting BitLocker info. Return code %d", val)
}
retData.RecoveryKeys = append(retData.RecoveryKeys, recoveryKey.ToString())
return nil
}()
if err != nil {
return nil, err
}
}
return retData, nil
}