Skip to content

Commit

Permalink
Implemented client metadata. (Velocidex#571)
Browse files Browse the repository at this point in the history
GUI allows setting arbitrary key/value pairs on clients.
VQL makes these key/value pairs available for automated setting or querying.
  • Loading branch information
scudette authored Aug 19, 2020
1 parent cc1ffec commit b4c5b7b
Show file tree
Hide file tree
Showing 21 changed files with 1,194 additions and 435 deletions.
2 changes: 1 addition & 1 deletion acls/acls.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const (
// Read results from already run hunts, flows or notebooks.
READ_RESULTS

// Can manipulate client labels.
// Can manipulate client labels and metadata.
LABEL_CLIENT

// Schedule or cancel new collections on clients.
Expand Down
41 changes: 0 additions & 41 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,47 +458,6 @@ func (self *ApiServer) LabelClients(
return &api_proto.APIResponse{}, nil
}

func (self *ApiServer) GetClient(
ctx context.Context,
in *api_proto.GetClientRequest) (*api_proto.ApiClient, error) {

user_name := GetGRPCUserInfo(self.config, ctx).Name
permissions := acls.READ_RESULTS
perm, err := acls.CheckAccess(self.config, user_name, permissions)
if !perm || err != nil {
return nil, status.Error(codes.PermissionDenied,
"User is not allowed to view clients.")
}

api_client, err := GetApiClient(
self.config,
self.server_obj,
in.ClientId,
!in.Lightweight, // Detailed
)
if err != nil {
return nil, err
}

return api_client, nil
}

func (self *ApiServer) GetClientFlows(
ctx context.Context,
in *api_proto.ApiFlowRequest) (*api_proto.ApiFlowResponse, error) {

user_name := GetGRPCUserInfo(self.config, ctx).Name
permissions := acls.READ_RESULTS
perm, err := acls.CheckAccess(self.config, user_name, permissions)
if !perm || err != nil {
return nil, status.Error(codes.PermissionDenied,
"User is not allowed to view flows.")
}

return flows.GetFlows(self.config, in.ClientId,
in.IncludeArchived, in.Offset, in.Count)
}

func (self *ApiServer) GetFlowDetails(
ctx context.Context,
in *api_proto.ApiFlowRequest) (*api_proto.FlowDetails, error) {
Expand Down
97 changes: 97 additions & 0 deletions api/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,22 @@ package api

import (
"errors"
"io"
"net"
"strings"
"time"

"github.com/golang/protobuf/ptypes/empty"
context "golang.org/x/net/context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"www.velocidex.com/golang/velociraptor/acls"
actions_proto "www.velocidex.com/golang/velociraptor/actions/proto"
api_proto "www.velocidex.com/golang/velociraptor/api/proto"
config_proto "www.velocidex.com/golang/velociraptor/config/proto"
crypto_proto "www.velocidex.com/golang/velociraptor/crypto/proto"
"www.velocidex.com/golang/velociraptor/datastore"
"www.velocidex.com/golang/velociraptor/flows"
"www.velocidex.com/golang/velociraptor/paths"
"www.velocidex.com/golang/velociraptor/server"
"www.velocidex.com/golang/velociraptor/services"
Expand Down Expand Up @@ -148,3 +155,93 @@ func _is_ip_in_ranges(remote string, ranges []string) bool {

return false
}

func (self *ApiServer) GetClientMetadata(
ctx context.Context,
in *api_proto.GetClientRequest) (*api_proto.ClientMetadata, error) {

user_name := GetGRPCUserInfo(self.config, ctx).Name
permissions := acls.READ_RESULTS
perm, err := acls.CheckAccess(self.config, user_name, permissions)
if !perm || err != nil {
return nil, status.Error(codes.PermissionDenied,
"User is not allowed to view clients.")
}

client_path_manager := paths.NewClientPathManager(in.ClientId)
db, err := datastore.GetDB(self.config)
if err != nil {
return nil, err
}

result := &api_proto.ClientMetadata{}
err = db.GetSubject(self.config, client_path_manager.Metadata(), result)
if err != nil && err == io.EOF {
// Metadata not set, start with empty set.
err = nil
}
return result, err
}

func (self *ApiServer) SetClientMetadata(
ctx context.Context,
in *api_proto.ClientMetadata) (*empty.Empty, error) {

user_name := GetGRPCUserInfo(self.config, ctx).Name
permissions := acls.LABEL_CLIENT
perm, err := acls.CheckAccess(self.config, user_name, permissions)
if !perm || err != nil {
return nil, status.Error(codes.PermissionDenied,
"User is not allowed to view clients.")
}

client_path_manager := paths.NewClientPathManager(in.ClientId)
db, err := datastore.GetDB(self.config)
if err != nil {
return nil, err
}

err = db.SetSubject(self.config, client_path_manager.Metadata(), in)
return &empty.Empty{}, err
}

func (self *ApiServer) GetClient(
ctx context.Context,
in *api_proto.GetClientRequest) (*api_proto.ApiClient, error) {

user_name := GetGRPCUserInfo(self.config, ctx).Name
permissions := acls.READ_RESULTS
perm, err := acls.CheckAccess(self.config, user_name, permissions)
if !perm || err != nil {
return nil, status.Error(codes.PermissionDenied,
"User is not allowed to view clients.")
}

api_client, err := GetApiClient(
self.config,
self.server_obj,
in.ClientId,
!in.Lightweight, // Detailed
)
if err != nil {
return nil, err
}

return api_client, nil
}

func (self *ApiServer) GetClientFlows(
ctx context.Context,
in *api_proto.ApiFlowRequest) (*api_proto.ApiFlowResponse, error) {

user_name := GetGRPCUserInfo(self.config, ctx).Name
permissions := acls.READ_RESULTS
perm, err := acls.CheckAccess(self.config, user_name, permissions)
if !perm || err != nil {
return nil, status.Error(codes.PermissionDenied,
"User is not allowed to view flows.")
}

return flows.GetFlows(self.config, in.ClientId,
in.IncludeArchived, in.Offset, in.Count)
}
40 changes: 40 additions & 0 deletions api/mock/api_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit b4c5b7b

Please sign in to comment.