2016-11-16 13:47:49 +00:00
|
|
|
package inmem
|
2016-09-30 01:19:51 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2016-10-13 18:21:47 +00:00
|
|
|
"sort"
|
2016-11-02 14:59:53 +00:00
|
|
|
"strings"
|
2016-09-30 01:19:51 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/kolide/kolide-ose/server/kolide"
|
2016-12-20 21:54:30 +00:00
|
|
|
"github.com/patrickmn/sortutil"
|
2016-09-30 01:19:51 +00:00
|
|
|
)
|
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
func (d *Datastore) NewHost(host *kolide.Host) (*kolide.Host, error) {
|
|
|
|
d.mtx.Lock()
|
|
|
|
defer d.mtx.Unlock()
|
2016-09-30 01:19:51 +00:00
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
for _, h := range d.hosts {
|
2016-09-30 01:19:51 +00:00
|
|
|
if host.NodeKey == h.NodeKey || host.UUID == h.UUID {
|
2016-12-20 18:35:22 +00:00
|
|
|
return nil, alreadyExists("Host", host.ID)
|
2016-09-30 01:19:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
host.ID = d.nextID(host)
|
|
|
|
d.hosts[host.ID] = host
|
2016-09-30 01:19:51 +00:00
|
|
|
|
|
|
|
return host, nil
|
|
|
|
}
|
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
func (d *Datastore) SaveHost(host *kolide.Host) error {
|
|
|
|
d.mtx.Lock()
|
|
|
|
defer d.mtx.Unlock()
|
2016-09-30 01:19:51 +00:00
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
if _, ok := d.hosts[host.ID]; !ok {
|
2016-12-20 18:35:22 +00:00
|
|
|
return notFound("Host").WithID(host.ID)
|
2016-09-30 01:19:51 +00:00
|
|
|
}
|
|
|
|
|
2016-12-01 17:00:00 +00:00
|
|
|
for _, nic := range host.NetworkInterfaces {
|
|
|
|
if nic.ID == 0 {
|
2016-12-16 00:12:43 +00:00
|
|
|
nic.ID = d.nextID(nic)
|
2016-12-01 17:00:00 +00:00
|
|
|
}
|
|
|
|
nic.HostID = host.ID
|
|
|
|
}
|
|
|
|
host.ResetPrimaryNetwork()
|
2016-12-16 00:12:43 +00:00
|
|
|
d.hosts[host.ID] = host
|
2016-09-30 01:19:51 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-01-04 18:18:21 +00:00
|
|
|
func (d *Datastore) DeleteHost(hid uint) error {
|
2016-12-16 00:12:43 +00:00
|
|
|
d.mtx.Lock()
|
|
|
|
defer d.mtx.Unlock()
|
2016-09-30 01:19:51 +00:00
|
|
|
|
2017-01-04 18:18:21 +00:00
|
|
|
if _, ok := d.hosts[hid]; !ok {
|
|
|
|
return notFound("Host").WithID(hid)
|
2016-09-30 01:19:51 +00:00
|
|
|
}
|
|
|
|
|
2017-01-04 18:18:21 +00:00
|
|
|
delete(d.hosts, hid)
|
2016-09-30 01:19:51 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
func (d *Datastore) Host(id uint) (*kolide.Host, error) {
|
|
|
|
d.mtx.Lock()
|
|
|
|
defer d.mtx.Unlock()
|
2016-09-30 01:19:51 +00:00
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
host, ok := d.hosts[id]
|
2016-09-30 01:19:51 +00:00
|
|
|
if !ok {
|
2016-12-20 18:35:22 +00:00
|
|
|
return nil, notFound("Host").WithID(id)
|
2016-09-30 01:19:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return host, nil
|
|
|
|
}
|
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
func (d *Datastore) ListHosts(opt kolide.ListOptions) ([]*kolide.Host, error) {
|
|
|
|
d.mtx.Lock()
|
|
|
|
defer d.mtx.Unlock()
|
2016-09-30 01:19:51 +00:00
|
|
|
|
2016-10-13 18:21:47 +00:00
|
|
|
// We need to sort by keys to provide reliable ordering
|
|
|
|
keys := []int{}
|
2016-12-16 00:12:43 +00:00
|
|
|
for k, _ := range d.hosts {
|
2016-10-13 18:21:47 +00:00
|
|
|
keys = append(keys, int(k))
|
|
|
|
}
|
|
|
|
sort.Ints(keys)
|
|
|
|
|
2016-09-30 01:19:51 +00:00
|
|
|
hosts := []*kolide.Host{}
|
2016-10-13 18:21:47 +00:00
|
|
|
for _, k := range keys {
|
2016-12-16 00:12:43 +00:00
|
|
|
hosts = append(hosts, d.hosts[uint(k)])
|
2016-09-30 01:19:51 +00:00
|
|
|
}
|
|
|
|
|
2016-10-17 14:01:14 +00:00
|
|
|
// Apply ordering
|
|
|
|
if opt.OrderKey != "" {
|
|
|
|
var fields = map[string]string{
|
|
|
|
"id": "ID",
|
|
|
|
"created_at": "CreatedAt",
|
|
|
|
"updated_at": "UpdatedAt",
|
|
|
|
"detail_update_time": "DetailUpdateTime",
|
|
|
|
"hostname": "HostName",
|
|
|
|
"uuid": "UUID",
|
|
|
|
"platform": "Platform",
|
|
|
|
"osquery_version": "OsqueryVersion",
|
|
|
|
"os_version": "OSVersion",
|
|
|
|
"uptime": "Uptime",
|
|
|
|
"memory": "PhysicalMemory",
|
|
|
|
"mac": "PrimaryMAC",
|
|
|
|
"ip": "PrimaryIP",
|
|
|
|
}
|
|
|
|
if err := sortResults(hosts, opt, fields); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-13 18:21:47 +00:00
|
|
|
// Apply limit/offset
|
2016-12-16 00:12:43 +00:00
|
|
|
low, high := d.getLimitOffsetSliceBounds(opt, len(hosts))
|
2016-10-13 18:21:47 +00:00
|
|
|
hosts = hosts[low:high]
|
|
|
|
|
2016-09-30 01:19:51 +00:00
|
|
|
return hosts, nil
|
|
|
|
}
|
|
|
|
|
2017-01-04 21:16:17 +00:00
|
|
|
func (d *Datastore) GenerateHostStatusStatistics(now time.Time) (online, offline, mia uint, err error) {
|
|
|
|
d.mtx.Lock()
|
|
|
|
defer d.mtx.Unlock()
|
|
|
|
|
|
|
|
for _, host := range d.hosts {
|
|
|
|
status := host.Status(now)
|
|
|
|
switch status {
|
|
|
|
case kolide.StatusMIA:
|
|
|
|
mia++
|
|
|
|
case kolide.StatusOffline:
|
|
|
|
offline++
|
|
|
|
default:
|
|
|
|
online++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return online, offline, mia, nil
|
|
|
|
}
|
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
func (d *Datastore) EnrollHost(osQueryHostID string, nodeKeySize int) (*kolide.Host, error) {
|
|
|
|
d.mtx.Lock()
|
|
|
|
defer d.mtx.Unlock()
|
2016-09-30 01:19:51 +00:00
|
|
|
|
2016-12-06 19:51:11 +00:00
|
|
|
if osQueryHostID == "" {
|
|
|
|
return nil, errors.New("missing host identifier from osquery for host enrollment")
|
|
|
|
}
|
|
|
|
|
|
|
|
nodeKey, err := kolide.RandomText(nodeKeySize)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2016-09-30 01:19:51 +00:00
|
|
|
}
|
|
|
|
|
2016-10-05 00:17:55 +00:00
|
|
|
host := kolide.Host{
|
2016-12-06 19:51:11 +00:00
|
|
|
OsqueryHostID: osQueryHostID,
|
|
|
|
NodeKey: nodeKey,
|
2016-10-05 00:17:55 +00:00
|
|
|
DetailUpdateTime: time.Unix(0, 0).Add(24 * time.Hour),
|
|
|
|
}
|
2016-12-06 19:51:11 +00:00
|
|
|
|
|
|
|
host.CreatedAt = time.Now().UTC()
|
|
|
|
host.UpdatedAt = host.CreatedAt
|
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
for _, h := range d.hosts {
|
2016-12-06 19:51:11 +00:00
|
|
|
if h.OsqueryHostID == osQueryHostID {
|
2016-09-30 01:19:51 +00:00
|
|
|
host = *h
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if host.ID == 0 {
|
2016-12-16 00:12:43 +00:00
|
|
|
host.ID = d.nextID(host)
|
2016-09-30 01:19:51 +00:00
|
|
|
}
|
2016-12-16 00:12:43 +00:00
|
|
|
d.hosts[host.ID] = &host
|
2016-09-30 01:19:51 +00:00
|
|
|
|
|
|
|
return &host, nil
|
|
|
|
}
|
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
func (d *Datastore) AuthenticateHost(nodeKey string) (*kolide.Host, error) {
|
|
|
|
d.mtx.Lock()
|
|
|
|
defer d.mtx.Unlock()
|
2016-09-30 01:19:51 +00:00
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
for _, host := range d.hosts {
|
2016-09-30 01:19:51 +00:00
|
|
|
if host.NodeKey == nodeKey {
|
|
|
|
return host, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-20 18:35:22 +00:00
|
|
|
return nil, notFound("AuthenticateHost")
|
2016-09-30 01:19:51 +00:00
|
|
|
}
|
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
func (d *Datastore) MarkHostSeen(host *kolide.Host, t time.Time) error {
|
|
|
|
d.mtx.Lock()
|
|
|
|
defer d.mtx.Unlock()
|
2016-09-30 01:19:51 +00:00
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
for _, h := range d.hosts {
|
2016-09-30 01:19:51 +00:00
|
|
|
if h.ID == host.ID {
|
|
|
|
h.UpdatedAt = t
|
2017-01-04 21:16:17 +00:00
|
|
|
h.SeenTime = t
|
2016-09-30 01:19:51 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2016-11-02 14:59:53 +00:00
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
func (d *Datastore) SearchHosts(query string, omit ...uint) ([]*kolide.Host, error) {
|
2016-11-02 14:59:53 +00:00
|
|
|
omitLookup := map[uint]bool{}
|
|
|
|
for _, o := range omit {
|
|
|
|
omitLookup[o] = true
|
|
|
|
}
|
|
|
|
|
2016-12-06 19:51:11 +00:00
|
|
|
var results []*kolide.Host
|
2016-11-02 14:59:53 +00:00
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
d.mtx.Lock()
|
|
|
|
defer d.mtx.Unlock()
|
2016-11-02 14:59:53 +00:00
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
for _, h := range d.hosts {
|
2016-11-02 14:59:53 +00:00
|
|
|
if len(results) == 10 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2016-12-01 17:00:00 +00:00
|
|
|
if strings.Contains(h.HostName, query) && !omitLookup[h.ID] {
|
2016-12-06 19:51:11 +00:00
|
|
|
results = append(results, h)
|
2016-12-01 17:00:00 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, nic := range h.NetworkInterfaces {
|
|
|
|
if strings.Contains(nic.IPAddress, query) && !omitLookup[nic.HostID] {
|
2016-12-06 19:51:11 +00:00
|
|
|
results = append(results, h)
|
2016-12-20 21:54:30 +00:00
|
|
|
|
2016-12-01 17:00:00 +00:00
|
|
|
break
|
|
|
|
}
|
2016-11-02 14:59:53 +00:00
|
|
|
}
|
2016-12-20 21:54:30 +00:00
|
|
|
sortutil.AscByField(h.NetworkInterfaces, "ID")
|
2016-11-02 14:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return results, nil
|
|
|
|
}
|
2016-11-09 23:33:16 +00:00
|
|
|
|
2016-12-16 00:12:43 +00:00
|
|
|
func (d *Datastore) DistributedQueriesForHost(host *kolide.Host) (map[uint]string, error) {
|
2016-11-09 23:33:16 +00:00
|
|
|
// lookup of executions for this host
|
|
|
|
hostExecutions := map[uint]kolide.DistributedQueryExecutionStatus{}
|
2016-12-16 00:12:43 +00:00
|
|
|
for _, e := range d.distributedQueryExecutions {
|
2016-11-09 23:33:16 +00:00
|
|
|
if e.HostID == host.ID {
|
|
|
|
hostExecutions[e.DistributedQueryCampaignID] = e.Status
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// lookup of labels for this host (only including matching labels)
|
|
|
|
hostLabels := map[uint]bool{}
|
2016-12-16 00:12:43 +00:00
|
|
|
labels, err := d.ListLabelsForHost(host.ID)
|
2016-11-09 23:33:16 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
for _, l := range labels {
|
|
|
|
hostLabels[l.ID] = true
|
|
|
|
}
|
|
|
|
|
|
|
|
queries := map[uint]string{} // map campaign ID -> query string
|
2016-12-16 00:12:43 +00:00
|
|
|
for _, campaign := range d.distributedQueryCampaigns {
|
2016-11-09 23:33:16 +00:00
|
|
|
if campaign.Status != kolide.QueryRunning {
|
|
|
|
continue
|
|
|
|
}
|
2016-12-16 00:12:43 +00:00
|
|
|
for _, target := range d.distributedQueryCampaignTargets {
|
2016-11-09 23:33:16 +00:00
|
|
|
if campaign.ID == target.DistributedQueryCampaignID &&
|
|
|
|
((target.Type == kolide.TargetHost && target.TargetID == host.ID) ||
|
|
|
|
(target.Type == kolide.TargetLabel && hostLabels[target.TargetID])) &&
|
|
|
|
(hostExecutions[campaign.ID] == kolide.ExecutionWaiting) {
|
2016-12-16 00:12:43 +00:00
|
|
|
queries[campaign.ID] = d.queries[campaign.QueryID].Query
|
2016-11-09 23:33:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return queries, nil
|
|
|
|
}
|