-
Notifications
You must be signed in to change notification settings - Fork 99
/
ioreg.go
148 lines (121 loc) · 4 KB
/
ioreg.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
//go:build darwin
// +build darwin
// Package ioreg provides a table wrapper around the `ioreg` macOS
// command.
//
// As the returned data is a complex nested plist, this uses the
// dataflatten tooling. (See
// https://godoc.org/github.com/kolide/launcher/pkg/dataflatten)
package ioreg
import (
"context"
"strings"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"github.com/kolide/launcher/pkg/dataflatten"
"github.com/kolide/launcher/pkg/osquery/tables/dataflattentable"
"github.com/kolide/launcher/pkg/osquery/tables/tablehelpers"
"github.com/osquery/osquery-go"
"github.com/osquery/osquery-go/plugin/table"
)
const ioregPath = "/usr/sbin/ioreg"
const allowedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
type Table struct {
client *osquery.ExtensionManagerClient
logger log.Logger
tableName string
}
func TablePlugin(client *osquery.ExtensionManagerClient, logger log.Logger) *table.Plugin {
columns := dataflattentable.Columns(
// ioreg input options. These match the ioreg
// command line. See the ioreg man page.
table.TextColumn("c"),
table.IntegerColumn("d"),
table.TextColumn("k"),
table.TextColumn("n"),
table.TextColumn("p"),
table.IntegerColumn("r"), // boolean
)
t := &Table{
client: client,
logger: logger,
tableName: "kolide_ioreg",
}
return table.NewPlugin(t.tableName, columns, t.generate)
}
func (t *Table) generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) {
var results []map[string]string
gcOpts := []tablehelpers.GetConstraintOpts{
tablehelpers.WithDefaults(""),
tablehelpers.WithAllowedCharacters(allowedCharacters),
tablehelpers.WithLogger(t.logger),
}
for _, ioC := range tablehelpers.GetConstraints(queryContext, "c", gcOpts...) {
// We always need "-a", it's the "archive" output
ioregArgs := []string{"-a"}
if ioC != "" {
ioregArgs = append(ioregArgs, "-c", ioC)
}
for _, ioD := range tablehelpers.GetConstraints(queryContext, "d", gcOpts...) {
if ioD != "" {
ioregArgs = append(ioregArgs, "-d", ioD)
}
for _, ioK := range tablehelpers.GetConstraints(queryContext, "k", gcOpts...) {
if ioK != "" {
ioregArgs = append(ioregArgs, "-k", ioK)
}
for _, ioN := range tablehelpers.GetConstraints(queryContext, "n", gcOpts...) {
if ioN != "" {
ioregArgs = append(ioregArgs, "-n", ioN)
}
for _, ioP := range tablehelpers.GetConstraints(queryContext, "p", gcOpts...) {
if ioP != "" {
ioregArgs = append(ioregArgs, "-p", ioP)
}
for _, ioR := range tablehelpers.GetConstraints(queryContext, "r", gcOpts...) {
switch ioR {
case "", "0":
// do nothing
case "1":
ioregArgs = append(ioregArgs, "-r")
default:
level.Info(t.logger).Log("msg", "r should be blank, 0, or 1")
continue
}
for _, dataQuery := range tablehelpers.GetConstraints(queryContext, "query", tablehelpers.WithDefaults("*")) {
// Finally, an inner loop
ioregOutput, err := tablehelpers.Exec(ctx, t.logger, 30, []string{ioregPath}, ioregArgs)
if err != nil {
level.Info(t.logger).Log("msg", "ioreg failed", "err", err)
continue
}
flatData, err := t.flattenOutput(dataQuery, ioregOutput)
if err != nil {
level.Info(t.logger).Log("msg", "flatten failed", "err", err)
continue
}
rowData := map[string]string{
"c": ioC,
"d": ioD,
"k": ioK,
"n": ioN,
"p": ioP,
"r": ioR,
}
results = append(results, dataflattentable.ToMap(flatData, dataQuery, rowData)...)
}
}
}
}
}
}
}
return results, nil
}
func (t *Table) flattenOutput(dataQuery string, systemOutput []byte) ([]dataflatten.Row, error) {
flattenOpts := []dataflatten.FlattenOpts{
dataflatten.WithLogger(t.logger),
dataflatten.WithQuery(strings.Split(dataQuery, "/")),
}
return dataflatten.Plist(systemOutput, flattenOpts...)
}