diff --git a/actions/proto/vql.pb.go b/actions/proto/vql.pb.go index cf6697fe6e5..f9b4b7a2bca 100644 --- a/actions/proto/vql.pb.go +++ b/actions/proto/vql.pb.go @@ -452,6 +452,7 @@ func (m *VQLEventTable) GetVersion() uint64 { } type ClientInfo struct { + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` Hostname string `protobuf:"bytes,3,opt,name=hostname,proto3" json:"hostname,omitempty"` Fqdn string `protobuf:"bytes,4,opt,name=fqdn,proto3" json:"fqdn,omitempty"` System string `protobuf:"bytes,5,opt,name=system,proto3" json:"system,omitempty"` @@ -493,6 +494,13 @@ func (m *ClientInfo) XXX_DiscardUnknown() { var xxx_messageInfo_ClientInfo proto.InternalMessageInfo +func (m *ClientInfo) GetClientId() string { + if m != nil { + return m.ClientId + } + return "" +} + func (m *ClientInfo) GetHostname() string { if m != nil { return m.Hostname @@ -586,105 +594,105 @@ func init() { } var fileDescriptor_3e14263f319df14a = []byte{ - // 1587 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x56, 0x4f, 0x6f, 0x24, 0x47, - 0x15, 0xd7, 0xd8, 0x1e, 0x8f, 0xa7, 0xbc, 0x4e, 0x36, 0xa5, 0xb0, 0xf4, 0x2e, 0xb0, 0x14, 0x43, - 0x00, 0x87, 0x28, 0x3d, 0xde, 0x5d, 0xad, 0x76, 0x09, 0x02, 0xe4, 0x59, 0xef, 0x22, 0x23, 0x3b, - 0xc1, 0x1d, 0xc7, 0x41, 0xab, 0x88, 0xa1, 0xa6, 0xfb, 0xcd, 0x4c, 0x69, 0xab, 0xab, 0xda, 0x55, - 0xd5, 0xd3, 0x9e, 0x43, 0x4e, 0x1c, 0xe0, 0x1b, 0x20, 0x21, 0x71, 0xe0, 0x16, 0x71, 0xe1, 0x4b, - 0x70, 0x40, 0xf0, 0x0d, 0x38, 0x70, 0x80, 0x1b, 0x9f, 0x81, 0x03, 0x7a, 0xaf, 0xbb, 0x67, 0xec, - 0x15, 0x39, 0x75, 0xfd, 0xfd, 0xbd, 0xdf, 0xab, 0xf7, 0xde, 0xef, 0x35, 0xeb, 0x2f, 0x2e, 0x75, - 0x5c, 0x38, 0x1b, 0x2c, 0xef, 0xd2, 0xe7, 0xde, 0xdb, 0xf4, 0x19, 0x7a, 0xc8, 0xa5, 0x09, 0x2a, - 0xad, 0x37, 0xef, 0xdd, 0xad, 0x57, 0xa7, 0xda, 0x56, 0xe3, 0x1c, 0x82, 0xcc, 0x64, 0x90, 0xcd, - 0xd6, 0x7d, 0xe9, 0x82, 0x9a, 0xca, 0x34, 0xf8, 0x61, 0x7d, 0xa8, 0x9d, 0xd7, 0xfb, 0x83, 0x2f, - 0x36, 0x18, 0xbb, 0x38, 0x3b, 0x49, 0xe0, 0xb2, 0x04, 0x1f, 0xf8, 0x6f, 0x3b, 0x6c, 0xeb, 0x43, - 0x99, 0x43, 0xb4, 0x21, 0x3a, 0xfb, 0xfd, 0x51, 0xf8, 0xd7, 0x7f, 0xff, 0xfd, 0x97, 0x8e, 0xe1, - 0xfa, 0x7c, 0x0e, 0xc2, 0xc8, 0x1c, 0x84, 0x9d, 0x8a, 0x30, 0x57, 0x5e, 0x5c, 0x96, 0xe0, 0x96, - 0xb1, 0x38, 0xc7, 0xb1, 0x9f, 0xdb, 0x52, 0x67, 0x62, 0x02, 0x22, 0x03, 0x9f, 0x3a, 0x55, 0x04, - 0xb5, 0x00, 0x11, 0xac, 0x50, 0x26, 0x53, 0xa9, 0x0c, 0x20, 0xaa, 0xb9, 0x0c, 0x22, 0x2c, 0x0b, - 0xba, 0xaf, 0xcc, 0xd4, 0xba, 0x5c, 0xaa, 0x60, 0x8d, 0x08, 0x73, 0xa8, 0xa1, 0x84, 0x83, 0xe0, - 0x14, 0x2c, 0xc0, 0xc7, 0x09, 0x31, 0xe0, 0x27, 0x6c, 0xf7, 0xa8, 0x85, 0xb3, 0x26, 0xda, 0x24, - 0x42, 0xdf, 0x27, 0x42, 0xef, 0xf0, 0xc1, 0xa7, 0x84, 0xb8, 0x62, 0x22, 0x90, 0x46, 0x59, 0x14, - 0xd6, 0x43, 0x86, 0x96, 0x33, 0x1b, 0x27, 0xd7, 0xaf, 0xf3, 0x43, 0xb6, 0x79, 0x71, 0x76, 0x12, - 0x75, 0x08, 0x65, 0x48, 0x28, 0xef, 0xf2, 0xef, 0xa1, 0x5b, 0x17, 0x67, 0x27, 0x0d, 0x46, 0xb0, - 0x02, 0xae, 0x20, 0x2d, 0x03, 0x88, 0x86, 0x5a, 0xaa, 0x15, 0x98, 0x10, 0x27, 0x78, 0x77, 0x70, - 0xc0, 0xb6, 0x2f, 0xce, 0x4e, 0x9e, 0x9b, 0x05, 0xbf, 0xcd, 0x36, 0x5f, 0xc1, 0xb2, 0x06, 0x4b, - 0x70, 0xc8, 0xdf, 0x66, 0xdd, 0x85, 0xd4, 0x65, 0xf3, 0x6e, 0x49, 0x3d, 0x19, 0xfc, 0xad, 0xc7, - 0x6e, 0x5f, 0x9c, 0x9d, 0x3c, 0xb3, 0x5a, 0x43, 0x1a, 0xac, 0x3b, 0x74, 0x33, 0xcf, 0x3f, 0x63, - 0x9b, 0x60, 0x16, 0xd1, 0xa6, 0xd8, 0xdc, 0xdf, 0x7d, 0xb8, 0x57, 0x87, 0x21, 0xae, 0x81, 0x47, - 0x3f, 0x24, 0x62, 0x8f, 0xf9, 0xa3, 0xe7, 0x66, 0xa1, 0x9c, 0x35, 0x39, 0x98, 0x20, 0x16, 0xd2, - 0x29, 0x39, 0xd1, 0xe0, 0x91, 0xe0, 0x04, 0x44, 0xe1, 0xec, 0x42, 0x65, 0x90, 0x89, 0xa9, 0x75, - 0xeb, 0x07, 0x8c, 0x13, 0x84, 0xe5, 0x2f, 0x59, 0xf7, 0x0c, 0xa7, 0xd1, 0x06, 0xe1, 0xbf, 0xb5, - 0xc6, 0x6f, 0x42, 0x3c, 0x7a, 0x40, 0x36, 0xde, 0xe3, 0xef, 0x5e, 0x77, 0x5e, 0xd5, 0xe8, 0x5f, - 0xe2, 0x7e, 0x0d, 0xc9, 0xff, 0xd0, 0x61, 0xbd, 0x5c, 0x5e, 0x8d, 0x9d, 0xad, 0xa2, 0x2d, 0xd1, - 0xd9, 0xdf, 0x1a, 0xfd, 0xba, 0x43, 0x60, 0x9f, 0xf3, 0x09, 0x82, 0xe5, 0xf2, 0x4a, 0xe5, 0x65, - 0x2e, 0x9c, 0xad, 0xbc, 0x28, 0xc0, 0x09, 0x07, 0xbe, 0xb0, 0xc6, 0x43, 0x2c, 0x92, 0x66, 0xe4, - 0x85, 0x96, 0x6e, 0x06, 0xc8, 0x5b, 0x9a, 0x3a, 0x7e, 0x95, 0xd2, 0x1a, 0xdd, 0xf2, 0x85, 0x56, - 0x41, 0xc8, 0xd4, 0x59, 0xef, 0x45, 0x5e, 0xea, 0xa0, 0x0a, 0x0d, 0x2b, 0x08, 0x1f, 0x0f, 0xde, - 0x3a, 0x95, 0x57, 0x6b, 0xec, 0x42, 0xba, 0xf0, 0x70, 0xeb, 0xc1, 0xc1, 0xc1, 0x41, 0xb2, 0x9d, - 0xcb, 0xab, 0xc4, 0x56, 0xfc, 0xef, 0x1d, 0xb6, 0x83, 0xfc, 0x2a, 0xa9, 0x42, 0xb4, 0x4d, 0x04, - 0xff, 0x5c, 0x13, 0xfc, 0xa2, 0xc3, 0x3f, 0x7f, 0x61, 0x9d, 0xd0, 0xd6, 0xcc, 0x56, 0xfe, 0x56, - 0x88, 0x1e, 0x4a, 0x67, 0x08, 0x4b, 0x49, 0x8d, 0xc6, 0x4a, 0x1d, 0xbc, 0x90, 0xd3, 0x40, 0x14, - 0x95, 0xa7, 0x1b, 0x4d, 0x9a, 0x2b, 0x2f, 0x1c, 0x5c, 0x96, 0xca, 0x35, 0x4f, 0x0f, 0x0b, 0x8c, - 0x8e, 0x56, 0x3e, 0x80, 0x01, 0xe7, 0x45, 0x35, 0x57, 0xe9, 0x5c, 0x18, 0x58, 0x90, 0xe7, 0x52, - 0xeb, 0xa5, 0x48, 0x6d, 0x5e, 0x68, 0x08, 0x10, 0x0f, 0xbe, 0x3d, 0x92, 0x21, 0x9d, 0x13, 0x00, - 0xf8, 0xe0, 0xd1, 0xff, 0x20, 0x82, 0x7c, 0x05, 0xd7, 0xcc, 0x3c, 0xdc, 0x78, 0x70, 0x90, 0xe0, - 0x0b, 0x7f, 0x2a, 0x55, 0xe0, 0x7f, 0xed, 0xb0, 0x37, 0x6c, 0xe1, 0xc7, 0x05, 0xb8, 0xb1, 0x87, - 0xd4, 0x9a, 0x2c, 0x8a, 0x44, 0x67, 0x7f, 0x63, 0xf4, 0xc7, 0xda, 0xa7, 0xdf, 0x77, 0xf8, 0xef, - 0x3a, 0x87, 0x46, 0x7c, 0x54, 0x20, 0xb3, 0x0c, 0xa6, 0xca, 0x40, 0x26, 0xa4, 0x17, 0xde, 0xe6, - 0x20, 0xa4, 0x9b, 0xa8, 0xe0, 0xa4, 0x5b, 0x8a, 0xd2, 0xa8, 0x80, 0x65, 0x57, 0x59, 0xf7, 0xaa, - 0xf1, 0x44, 0x6a, 0x8d, 0xcf, 0x88, 0x2b, 0x4d, 0x4e, 0x69, 0x95, 0xab, 0x00, 0x59, 0x2c, 0xce, - 0x97, 0x85, 0x4a, 0x89, 0x3b, 0xa6, 0x46, 0xa1, 0xcb, 0x99, 0x32, 0x4d, 0x8c, 0x52, 0x5b, 0x9a, - 0x20, 0x6c, 0x81, 0x99, 0x52, 0x49, 0x97, 0xf9, 0x6b, 0xd5, 0x2b, 0xbd, 0x90, 0x45, 0xe1, 0x6c, - 0xe1, 0x94, 0x0c, 0x10, 0x27, 0xb7, 0x6c, 0xe1, 0x7f, 0x0e, 0xee, 0x63, 0xe2, 0xcd, 0x0d, 0xeb, - 0xaf, 0x64, 0x28, 0xea, 0x52, 0x62, 0xbe, 0xd9, 0x24, 0xe6, 0x61, 0xb3, 0x3e, 0xfa, 0x09, 0x39, - 0xf5, 0x03, 0xfe, 0xa4, 0x5d, 0xf1, 0xc2, 0xe3, 0xfb, 0x4e, 0x9d, 0xcd, 0xc9, 0x90, 0x07, 0x87, - 0x2f, 0x1b, 0xac, 0x98, 0x83, 0x2e, 0x44, 0xa5, 0xc2, 0xfc, 0xba, 0x14, 0x25, 0x6b, 0x13, 0xfc, - 0x88, 0xf5, 0x82, 0xca, 0xc1, 0x96, 0x21, 0xba, 0x4b, 0x69, 0xb0, 0x92, 0x8d, 0xd3, 0x26, 0x45, - 0x71, 0xfb, 0x66, 0xfd, 0x20, 0xb0, 0x2b, 0x4d, 0x9c, 0xb4, 0x57, 0x3f, 0xd8, 0xfb, 0xcf, 0x6f, - 0x44, 0x9f, 0xf5, 0x7e, 0x8a, 0xd1, 0x55, 0xe9, 0xe0, 0x29, 0x09, 0xe5, 0xf9, 0xb2, 0x80, 0x53, - 0x59, 0xf0, 0x3b, 0x6c, 0x3b, 0xb5, 0xba, 0xcc, 0x4d, 0xa3, 0x02, 0xcd, 0x8c, 0x73, 0xb6, 0x85, - 0x3a, 0xd7, 0xe8, 0x00, 0x8d, 0x07, 0xff, 0xe8, 0xb2, 0x5d, 0x2a, 0xc0, 0x3a, 0x95, 0xf9, 0x07, - 0x6c, 0xa7, 0x1d, 0x37, 0x82, 0x74, 0x9f, 0xf8, 0x45, 0xfc, 0xce, 0xcf, 0x3e, 0xfe, 0xe8, 0x43, - 0x01, 0x26, 0xb5, 0x58, 0xdf, 0xab, 0xf2, 0x49, 0x56, 0xe7, 0x79, 0xc2, 0x7a, 0xcf, 0xc8, 0x92, - 0xa7, 0x0a, 0xef, 0x8f, 0x9e, 0xd2, 0xd5, 0x87, 0xfc, 0xe0, 0x90, 0x52, 0x11, 0x23, 0x5d, 0x53, - 0x11, 0x73, 0x90, 0x99, 0x32, 0x33, 0x8f, 0x82, 0x91, 0x95, 0x29, 0x64, 0x62, 0xb2, 0xbc, 0xae, - 0x17, 0x2d, 0x10, 0xff, 0x25, 0xeb, 0x22, 0x4f, 0x1f, 0xed, 0xbc, 0xae, 0x19, 0x8d, 0xb7, 0xa3, - 0xc7, 0x64, 0x64, 0xc8, 0xdf, 0x3f, 0x95, 0x45, 0xa1, 0xcc, 0x4c, 0x4c, 0x20, 0x54, 0x00, 0xa6, - 0x35, 0x85, 0xad, 0xc1, 0x0b, 0x69, 0x32, 0xc4, 0x57, 0x8e, 0xa4, 0xde, 0xc7, 0x49, 0x0d, 0xcb, - 0x13, 0xb6, 0x43, 0x26, 0xc7, 0x2a, 0x8b, 0xba, 0x14, 0x8f, 0x27, 0x84, 0xf7, 0x80, 0x0f, 0x9f, - 0xcd, 0x9d, 0x35, 0x56, 0xdb, 0x19, 0x26, 0x9d, 0xb0, 0x2e, 0x03, 0x57, 0xb7, 0x98, 0x36, 0x2a, - 0x55, 0x2b, 0x01, 0x28, 0xeb, 0x71, 0xd2, 0xa3, 0xd5, 0xe3, 0x8c, 0x07, 0xb6, 0x85, 0x55, 0xdb, - 0x94, 0xf9, 0xaf, 0x08, 0xef, 0x25, 0xff, 0xc5, 0x09, 0xaa, 0x0b, 0xa5, 0xee, 0x4a, 0x38, 0x84, - 0x74, 0xaf, 0x8b, 0x8b, 0x34, 0x4b, 0xaa, 0x79, 0xdf, 0xd4, 0x43, 0x2a, 0x5d, 0xad, 0x80, 0x73, - 0xa0, 0xf5, 0x55, 0x97, 0x5b, 0x47, 0x80, 0xac, 0xf1, 0xd3, 0x56, 0x5d, 0xb1, 0x1b, 0xfd, 0x5f, - 0x75, 0x7d, 0x87, 0x98, 0xdc, 0xe7, 0x5f, 0x3f, 0x5f, 0x27, 0x16, 0x96, 0x7a, 0x25, 0x7d, 0xab, - 0xae, 0xd9, 0x4a, 0x50, 0x3f, 0x63, 0x7d, 0x4c, 0x36, 0x1f, 0x64, 0x5e, 0x34, 0x8a, 0xfa, 0x63, - 0xba, 0xff, 0x94, 0xed, 0x26, 0x47, 0x2f, 0x8e, 0x64, 0x00, 0xdc, 0xaf, 0xa5, 0x7a, 0x75, 0x92, - 0x68, 0xb6, 0xcc, 0x08, 0x78, 0x86, 0x29, 0x2a, 0x09, 0x79, 0x0d, 0xc8, 0x13, 0xc6, 0x82, 0x0d, - 0x52, 0xa3, 0x5e, 0xfb, 0xa8, 0x47, 0xf0, 0x8f, 0x08, 0xfe, 0x7d, 0xfe, 0xde, 0x39, 0xee, 0x08, - 0x53, 0xe6, 0x93, 0xfa, 0xc5, 0x49, 0x57, 0x95, 0xb9, 0xe9, 0x36, 0x3d, 0x06, 0x62, 0xe2, 0xe1, - 0xc4, 0x56, 0x1e, 0x3b, 0x9f, 0xb6, 0xb3, 0xa8, 0x5f, 0x77, 0x3e, 0x6d, 0x67, 0x83, 0xe7, 0x6c, - 0xeb, 0x13, 0x0f, 0x8e, 0xff, 0x88, 0xed, 0x94, 0x1e, 0x1c, 0x66, 0x42, 0x93, 0xd4, 0xdf, 0x22, - 0x5b, 0x5f, 0xe3, 0x77, 0x91, 0x7d, 0xbb, 0xd7, 0x46, 0x17, 0xe7, 0x71, 0xb2, 0xba, 0x32, 0xf8, - 0x53, 0x87, 0xed, 0x61, 0x13, 0x44, 0x4d, 0x3d, 0xc7, 0x6e, 0xc7, 0x3f, 0x61, 0x5d, 0x52, 0xd8, - 0xa8, 0x43, 0x59, 0xf9, 0xd5, 0xf5, 0x5b, 0xdf, 0xe8, 0xa7, 0xa3, 0xef, 0x92, 0x19, 0xc1, 0xef, - 0x1f, 0x0a, 0x0f, 0x14, 0xba, 0x5a, 0x98, 0xaf, 0xb5, 0x35, 0xaa, 0xeb, 0x1a, 0x8d, 0x8f, 0x58, - 0x6f, 0x01, 0xce, 0xe3, 0x2f, 0xc5, 0x06, 0x3d, 0xc9, 0x3e, 0xdd, 0x1f, 0x70, 0x81, 0x34, 0x9b, - 0xad, 0x55, 0x02, 0xd4, 0x50, 0x01, 0x09, 0xc5, 0x49, 0x7b, 0x71, 0xf0, 0xcf, 0x0d, 0xc6, 0x9e, - 0x51, 0x6f, 0x3c, 0x36, 0x53, 0xcb, 0xef, 0xb1, 0x9d, 0xb9, 0xf5, 0x81, 0x5c, 0xa7, 0xdf, 0x94, - 0x64, 0x35, 0x47, 0x3d, 0x98, 0x5e, 0x66, 0x86, 0xa2, 0xdb, 0x4f, 0x68, 0x8c, 0xda, 0xe1, 0x97, - 0x3e, 0x40, 0x4e, 0xd5, 0xd0, 0x4f, 0x9a, 0x19, 0x8f, 0x58, 0xcf, 0x81, 0x06, 0xe9, 0x81, 0xd2, - 0xba, 0x9f, 0xb4, 0x53, 0x3e, 0x60, 0xb7, 0xa4, 0x4b, 0xe7, 0x2a, 0x40, 0x1a, 0x4a, 0x07, 0x14, - 0xcc, 0x7e, 0x72, 0x63, 0x8d, 0x7f, 0x83, 0x31, 0x55, 0x8c, 0x65, 0x96, 0x39, 0xf0, 0x3e, 0x62, - 0x74, 0xa2, 0xaf, 0x8a, 0xc3, 0x7a, 0x01, 0x89, 0x60, 0xe5, 0x46, 0xbb, 0xe8, 0x74, 0x42, 0x63, - 0xfe, 0x1d, 0xf6, 0x46, 0xdd, 0xe2, 0xc7, 0xed, 0x93, 0xdc, 0xa2, 0x6b, 0x7b, 0xf5, 0xea, 0x45, - 0xbd, 0xc8, 0xbf, 0xc9, 0x76, 0x9b, 0x63, 0xe4, 0xe2, 0x1e, 0x9d, 0x61, 0xf5, 0x12, 0xfd, 0xaa, - 0xdd, 0x61, 0xdb, 0x5a, 0x4e, 0x40, 0xfb, 0xe8, 0x4d, 0xd4, 0xa4, 0xa4, 0x99, 0xf1, 0x27, 0x2c, - 0xd2, 0xd2, 0x87, 0xb1, 0x32, 0x01, 0x9c, 0xb3, 0x33, 0x19, 0x60, 0x4c, 0x3f, 0xa9, 0x2a, 0x8b, - 0x6e, 0x13, 0xca, 0x57, 0x70, 0xff, 0x78, 0xbd, 0xfd, 0x42, 0xdb, 0xea, 0x38, 0x1b, 0x3d, 0x7e, - 0xf9, 0xa8, 0xaa, 0xaa, 0x78, 0x01, 0xda, 0xa6, 0x2a, 0x83, 0xab, 0x38, 0xb5, 0xf9, 0x70, 0x66, - 0xb5, 0x34, 0xb3, 0x61, 0xbd, 0xe8, 0x64, 0x11, 0xac, 0x1b, 0xca, 0x14, 0xff, 0xee, 0x9a, 0x7f, - 0xdb, 0xc9, 0x36, 0x7d, 0x1e, 0xfd, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xbc, 0x8f, 0xea, 0x73, 0x38, - 0x0b, 0x00, 0x00, + // 1597 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x56, 0x4d, 0x6f, 0x24, 0x47, + 0x19, 0xd6, 0xf8, 0x6b, 0x3c, 0xe5, 0x75, 0xb2, 0x29, 0x85, 0xa5, 0x77, 0x03, 0x4b, 0x31, 0x04, + 0x70, 0x88, 0xd2, 0xf6, 0xee, 0x6a, 0xb5, 0x4b, 0x10, 0x20, 0xcf, 0x7e, 0x20, 0x23, 0x3b, 0xc1, + 0x1d, 0xc7, 0x41, 0xab, 0x08, 0x53, 0xd3, 0xfd, 0xce, 0x4c, 0x69, 0xab, 0xab, 0xda, 0x55, 0xd5, + 0xd3, 0x9e, 0x43, 0x4e, 0x1c, 0xe0, 0x1f, 0x20, 0x21, 0x71, 0xe0, 0x16, 0x71, 0xe1, 0x4f, 0x70, + 0x40, 0xf0, 0x0f, 0x38, 0xc2, 0x8d, 0xbf, 0x00, 0x07, 0xf4, 0xbe, 0xd5, 0x3d, 0xe3, 0x5d, 0xc1, + 0xa9, 0xeb, 0xf3, 0x79, 0x9f, 0xf7, 0xeb, 0xa9, 0x66, 0x83, 0xf9, 0xa5, 0x4e, 0x2b, 0x67, 0x83, + 0xe5, 0x9b, 0xf4, 0xb9, 0xf3, 0x36, 0x7d, 0xf6, 0x3d, 0x94, 0xd2, 0x04, 0x95, 0xc7, 0xcd, 0x3b, + 0xb7, 0xe3, 0xea, 0x44, 0xdb, 0xe6, 0xa2, 0x84, 0x20, 0x0b, 0x19, 0x64, 0xbb, 0x75, 0x57, 0xba, + 0xa0, 0x26, 0x32, 0x0f, 0x7e, 0x3f, 0x1e, 0xea, 0xe6, 0x71, 0x7f, 0xf8, 0xe5, 0x1a, 0x63, 0xe7, + 0xa7, 0xc7, 0x19, 0x5c, 0xd6, 0xe0, 0x03, 0xff, 0x4d, 0x8f, 0x6d, 0x7c, 0x24, 0x4b, 0x48, 0xd6, + 0x44, 0x6f, 0x6f, 0x30, 0x0a, 0xff, 0xf8, 0xcf, 0x3f, 0xff, 0xdc, 0x33, 0x5c, 0x9f, 0xcd, 0x40, + 0x18, 0x59, 0x82, 0xb0, 0x13, 0x11, 0x66, 0xca, 0x8b, 0xcb, 0x1a, 0xdc, 0x22, 0x15, 0x67, 0x38, + 0xf6, 0x33, 0x5b, 0xeb, 0x42, 0x8c, 0x41, 0x14, 0xe0, 0x73, 0xa7, 0xaa, 0xa0, 0xe6, 0x20, 0x82, + 0x15, 0xca, 0x14, 0x2a, 0x97, 0x01, 0x44, 0x33, 0x93, 0x41, 0x84, 0x45, 0x45, 0xf7, 0x95, 0x99, + 0x58, 0x57, 0x4a, 0x15, 0xac, 0x11, 0x61, 0x06, 0x11, 0x4a, 0x38, 0x08, 0x4e, 0xc1, 0x1c, 0x7c, + 0x9a, 0x11, 0x03, 0x7e, 0xcc, 0x76, 0x9e, 0x76, 0x70, 0xd6, 0x24, 0xeb, 0x44, 0xe8, 0x7b, 0x44, + 0xe8, 0x5d, 0x3e, 0xfc, 0x8c, 0x10, 0x97, 0x4c, 0x04, 0xd2, 0xa8, 0xab, 0xca, 0x7a, 0x28, 0xd0, + 0x72, 0x61, 0xd3, 0xec, 0xfa, 0x75, 0x7e, 0xc8, 0xd6, 0xcf, 0x4f, 0x8f, 0x93, 0x1e, 0xa1, 0xec, + 0x13, 0xca, 0x7b, 0xfc, 0xbb, 0xe8, 0xd6, 0xf9, 0xe9, 0x71, 0x8b, 0x11, 0xac, 0x80, 0x2b, 0xc8, + 0xeb, 0x00, 0xa2, 0xa5, 0x96, 0x6b, 0x05, 0x26, 0xa4, 0x19, 0xde, 0x1d, 0x1e, 0xb0, 0xad, 0xf3, + 0xd3, 0xe3, 0x67, 0x66, 0xce, 0x6f, 0xb2, 0xf5, 0x97, 0xb0, 0x88, 0x60, 0x19, 0x0e, 0xf9, 0xdb, + 0x6c, 0x73, 0x2e, 0x75, 0xdd, 0xc6, 0x2d, 0x8b, 0x93, 0xe1, 0x5f, 0xfb, 0xec, 0xe6, 0xf9, 0xe9, + 0xf1, 0x13, 0xab, 0x35, 0xe4, 0xc1, 0xba, 0x43, 0x37, 0xf5, 0xfc, 0x73, 0xb6, 0x0e, 0x66, 0x9e, + 0xac, 0x8b, 0xf5, 0xbd, 0x9d, 0xfb, 0xbb, 0x31, 0x0d, 0x69, 0x04, 0x1e, 0xfd, 0x80, 0x88, 0x3d, + 0xe4, 0x0f, 0x9e, 0x99, 0xb9, 0x72, 0xd6, 0x94, 0x60, 0x82, 0x98, 0x4b, 0xa7, 0xe4, 0x58, 0x83, + 0x47, 0x82, 0x63, 0x10, 0x95, 0xb3, 0x73, 0x55, 0x40, 0x21, 0x26, 0xd6, 0xad, 0x02, 0x98, 0x66, + 0x08, 0xcb, 0x5f, 0xb0, 0xcd, 0x53, 0x9c, 0x26, 0x6b, 0x84, 0xff, 0xd6, 0x0a, 0xbf, 0x4d, 0xf1, + 0xe8, 0x1e, 0xd9, 0x78, 0x9f, 0xbf, 0x77, 0xdd, 0x79, 0x15, 0xd1, 0xff, 0x8f, 0xfb, 0x11, 0x92, + 0xff, 0xbe, 0xc7, 0xfa, 0xa5, 0xbc, 0xba, 0x70, 0xb6, 0x49, 0x36, 0x44, 0x6f, 0x6f, 0x63, 0xf4, + 0xab, 0x1e, 0x81, 0x7d, 0xc1, 0xc7, 0x08, 0x56, 0xca, 0x2b, 0x55, 0xd6, 0xa5, 0x70, 0xb6, 0xf1, + 0xa2, 0x02, 0x27, 0x1c, 0xf8, 0xca, 0x1a, 0x0f, 0xa9, 0xc8, 0xda, 0x91, 0x17, 0x5a, 0xba, 0x29, + 0x20, 0x6f, 0x69, 0x62, 0xfe, 0x1a, 0xa5, 0x35, 0xba, 0xe5, 0x2b, 0xad, 0x82, 0x90, 0xb9, 0xb3, + 0xde, 0x8b, 0xb2, 0xd6, 0x41, 0x55, 0x1a, 0x96, 0x10, 0x3e, 0x1d, 0xbe, 0x75, 0x22, 0xaf, 0x56, + 0xd8, 0x95, 0x74, 0xe1, 0xfe, 0xc6, 0xbd, 0x83, 0x83, 0x83, 0x6c, 0xab, 0x94, 0x57, 0x99, 0x6d, + 0xf8, 0xdf, 0x7a, 0x6c, 0x1b, 0xf9, 0x35, 0x52, 0x85, 0x64, 0x8b, 0x08, 0xfe, 0x29, 0x12, 0xfc, + 0xb2, 0xc7, 0xbf, 0x78, 0x6e, 0x9d, 0xd0, 0xd6, 0x4c, 0x97, 0xfe, 0x36, 0x88, 0x1e, 0x6a, 0x67, + 0x08, 0x4b, 0x49, 0x8d, 0xc6, 0x6a, 0x1d, 0xbc, 0x90, 0x93, 0x40, 0x14, 0x95, 0xa7, 0x1b, 0x6d, + 0x99, 0x2b, 0x2f, 0x1c, 0x5c, 0xd6, 0xca, 0xb5, 0xa1, 0x87, 0x39, 0x66, 0x47, 0x2b, 0x1f, 0xc0, + 0x80, 0xf3, 0xa2, 0x99, 0xa9, 0x7c, 0x26, 0x0c, 0xcc, 0xc9, 0x73, 0xa9, 0xf5, 0x42, 0xe4, 0xb6, + 0xac, 0x34, 0x04, 0x48, 0x87, 0xdf, 0x1a, 0xc9, 0x90, 0xcf, 0x08, 0x00, 0x7c, 0xf0, 0xe8, 0x7f, + 0x10, 0x41, 0xbe, 0x84, 0x6b, 0x66, 0xee, 0xaf, 0xdd, 0x3b, 0xc8, 0x30, 0xc2, 0x9f, 0x49, 0x15, + 0xf8, 0x5f, 0x7a, 0xec, 0x0d, 0x5b, 0xf9, 0x8b, 0x0a, 0xdc, 0x85, 0x87, 0xdc, 0x9a, 0x22, 0x49, + 0x44, 0x6f, 0x6f, 0x6d, 0xf4, 0x87, 0xe8, 0xd3, 0xef, 0x7a, 0xfc, 0xb7, 0xbd, 0x43, 0x23, 0x3e, + 0xae, 0x90, 0x59, 0x01, 0x13, 0x65, 0xa0, 0x10, 0xd2, 0x0b, 0x6f, 0x4b, 0x10, 0xd2, 0x8d, 0x55, + 0x70, 0xd2, 0x2d, 0x44, 0x6d, 0x54, 0xc0, 0xb6, 0x6b, 0xac, 0x7b, 0xd9, 0x7a, 0x22, 0xb5, 0xc6, + 0x30, 0xe2, 0x4a, 0x5b, 0x53, 0x5a, 0x95, 0x2a, 0x40, 0x91, 0x8a, 0xb3, 0x45, 0xa5, 0x72, 0xe2, + 0x8e, 0xa5, 0x51, 0xe9, 0x7a, 0xaa, 0x4c, 0x9b, 0xa3, 0xdc, 0xd6, 0x26, 0x08, 0x5b, 0x61, 0xa5, + 0x34, 0xd2, 0x15, 0xfe, 0x5a, 0xf7, 0x4a, 0x2f, 0x64, 0x55, 0x39, 0x5b, 0x39, 0x25, 0x03, 0xa4, + 0xd9, 0x0d, 0x5b, 0xf9, 0x9f, 0x81, 0xfb, 0x84, 0x78, 0x73, 0xc3, 0x06, 0x4b, 0x19, 0x4a, 0x36, + 0xa9, 0x30, 0xdf, 0x6c, 0x0b, 0xf3, 0xb0, 0x5d, 0x1f, 0xfd, 0x98, 0x9c, 0xfa, 0x3e, 0x7f, 0xd4, + 0xad, 0x78, 0xe1, 0x31, 0xbe, 0x13, 0x67, 0x4b, 0x32, 0xe4, 0xc1, 0x61, 0x64, 0x83, 0x15, 0x33, + 0xd0, 0x95, 0x68, 0x54, 0x98, 0x5d, 0x97, 0xa2, 0x6c, 0x65, 0x82, 0x3f, 0x65, 0xfd, 0xa0, 0x4a, + 0xb0, 0x75, 0x48, 0x6e, 0x53, 0x19, 0x2c, 0x65, 0xe3, 0xa4, 0x2d, 0x51, 0xdc, 0x7e, 0xb5, 0x7f, + 0x10, 0xd8, 0xd5, 0x26, 0xcd, 0xba, 0xab, 0x1f, 0xee, 0xfe, 0xeb, 0xd7, 0x62, 0xc0, 0xfa, 0x3f, + 0xc1, 0xec, 0xaa, 0x7c, 0xf8, 0x98, 0x84, 0xf2, 0x6c, 0x51, 0xc1, 0x89, 0xac, 0xf8, 0x2d, 0xb6, + 0x95, 0x5b, 0x5d, 0x97, 0xa6, 0x55, 0x81, 0x76, 0xc6, 0x39, 0xdb, 0x40, 0x9d, 0x6b, 0x75, 0x80, + 0xc6, 0xc3, 0xbf, 0x6f, 0xb2, 0x1d, 0x6a, 0xc0, 0x58, 0xca, 0xfc, 0x43, 0xb6, 0xdd, 0x8d, 0x5b, + 0x41, 0xba, 0x4b, 0xfc, 0x12, 0x7e, 0xeb, 0xa7, 0x9f, 0x7c, 0xfc, 0x91, 0x00, 0x93, 0x5b, 0xec, + 0xef, 0x65, 0xfb, 0x64, 0xcb, 0xf3, 0x3c, 0x63, 0xfd, 0x27, 0x64, 0xc9, 0x53, 0x87, 0x0f, 0x46, + 0x8f, 0xe9, 0xea, 0x7d, 0x7e, 0x70, 0x48, 0xa5, 0x88, 0x99, 0x8e, 0x54, 0xc4, 0x0c, 0x64, 0xa1, + 0xcc, 0xd4, 0xa3, 0x60, 0x14, 0x75, 0x0e, 0x85, 0x18, 0x2f, 0xae, 0xeb, 0x45, 0x07, 0xc4, 0x7f, + 0xc1, 0x36, 0x91, 0xa7, 0x4f, 0xb6, 0x5f, 0xd7, 0x8c, 0xd6, 0xdb, 0xd1, 0x43, 0x32, 0xb2, 0xcf, + 0x3f, 0x38, 0x91, 0x55, 0xa5, 0xcc, 0x54, 0x8c, 0x21, 0x34, 0x00, 0xa6, 0x33, 0x85, 0x4f, 0x83, + 0x17, 0xd2, 0x14, 0x88, 0xaf, 0x1c, 0x49, 0xbd, 0x4f, 0xb3, 0x08, 0xcb, 0x33, 0xb6, 0x4d, 0x26, + 0x2f, 0x54, 0x91, 0x6c, 0x52, 0x3e, 0x1e, 0x11, 0xde, 0x3d, 0xbe, 0xff, 0x64, 0xe6, 0xac, 0xb1, + 0xda, 0x4e, 0xb1, 0xe8, 0x84, 0x75, 0x05, 0xb8, 0xf8, 0xc4, 0x74, 0x59, 0x69, 0x3a, 0x09, 0x40, + 0x59, 0x4f, 0xb3, 0x3e, 0xad, 0x1e, 0x15, 0x3c, 0xb0, 0x0d, 0xec, 0xda, 0xb6, 0xcd, 0x7f, 0x49, + 0x78, 0x2f, 0xf8, 0xcf, 0x8f, 0x51, 0x5d, 0xa8, 0x74, 0x97, 0xc2, 0x21, 0xa4, 0x7b, 0x5d, 0x5c, + 0xa4, 0x59, 0x50, 0xcf, 0xfb, 0xb6, 0x1f, 0x72, 0xe9, 0xa2, 0x02, 0xce, 0x80, 0xd6, 0x97, 0xaf, + 0xdc, 0x2a, 0x03, 0x64, 0x8d, 0x9f, 0x74, 0xea, 0x8a, 0xaf, 0xd1, 0xff, 0x54, 0xd7, 0x77, 0x89, + 0xc9, 0x5d, 0xfe, 0xb5, 0xb3, 0x55, 0x61, 0x61, 0xab, 0x37, 0xd2, 0x77, 0xea, 0x5a, 0x2c, 0x05, + 0xf5, 0x73, 0x36, 0xc0, 0x62, 0xf3, 0x41, 0x96, 0x55, 0xab, 0xa8, 0x3f, 0xa2, 0xfb, 0x8f, 0xd9, + 0x4e, 0xf6, 0xf4, 0xf9, 0x53, 0x19, 0x00, 0xf7, 0xa3, 0x54, 0x2f, 0x4f, 0x12, 0xcd, 0x8e, 0x19, + 0x01, 0x4f, 0xb1, 0x44, 0x25, 0x21, 0xaf, 0x00, 0x79, 0xc6, 0x58, 0xb0, 0x41, 0x6a, 0xd4, 0x6b, + 0x9f, 0xf4, 0x09, 0xfe, 0x01, 0xc1, 0x7f, 0xc0, 0xdf, 0x3f, 0xc3, 0x1d, 0x61, 0xea, 0x72, 0x1c, + 0x23, 0x4e, 0xba, 0xaa, 0xcc, 0xab, 0x6e, 0x53, 0x30, 0x10, 0x13, 0x0f, 0x67, 0xb6, 0xf1, 0xf8, + 0xf2, 0x69, 0x3b, 0x4d, 0x06, 0xf1, 0xe5, 0xd3, 0x76, 0x3a, 0x7c, 0xc6, 0x36, 0x3e, 0xf5, 0xe0, + 0xf8, 0x0f, 0xd9, 0x76, 0xed, 0xc1, 0x61, 0x25, 0xb4, 0x45, 0xfd, 0x4d, 0xb2, 0xf5, 0x0e, 0xbf, + 0x8d, 0xec, 0xbb, 0xbd, 0x2e, 0xbb, 0x38, 0x4f, 0xb3, 0xe5, 0x95, 0xe1, 0x1f, 0x7b, 0x6c, 0x17, + 0x1f, 0x41, 0xd4, 0xd4, 0x33, 0x7c, 0xed, 0xf8, 0xa7, 0x6c, 0x93, 0x14, 0x36, 0xe9, 0x51, 0x55, + 0x7e, 0x75, 0x15, 0xeb, 0x57, 0xde, 0xd3, 0xd1, 0x77, 0xc8, 0x8c, 0xe0, 0x77, 0x0f, 0x85, 0x07, + 0x4a, 0x5d, 0x14, 0xe6, 0x6b, 0xcf, 0x1a, 0xf5, 0x75, 0x44, 0xe3, 0x23, 0xd6, 0x9f, 0x83, 0xf3, + 0xf8, 0x4b, 0xb1, 0x46, 0x21, 0xd9, 0xa3, 0xfb, 0x43, 0x2e, 0x90, 0x66, 0xbb, 0xb5, 0x2c, 0x80, + 0x08, 0x15, 0x90, 0x50, 0x9a, 0x75, 0x17, 0x87, 0xff, 0x5e, 0x63, 0xec, 0x09, 0xbd, 0x8d, 0x47, + 0x66, 0x62, 0xf9, 0x3b, 0x6c, 0x10, 0x5f, 0x4a, 0x2c, 0xf0, 0x28, 0x07, 0xdb, 0x71, 0xe1, 0xa8, + 0xe0, 0x77, 0xd8, 0xf6, 0xcc, 0xfa, 0x40, 0x71, 0x59, 0x8f, 0x7b, 0xdd, 0x1c, 0xc5, 0x62, 0x72, + 0x59, 0x18, 0x4a, 0xfd, 0x20, 0xa3, 0x31, 0x0a, 0x8b, 0x5f, 0xf8, 0x00, 0x25, 0xb5, 0xca, 0x20, + 0x6b, 0x67, 0x3c, 0x61, 0x7d, 0x07, 0x1a, 0xa4, 0x07, 0xaa, 0xf9, 0x41, 0xd6, 0x4d, 0xf9, 0x90, + 0xdd, 0x90, 0x2e, 0x9f, 0xa9, 0x00, 0x79, 0xa8, 0x1d, 0x50, 0xa6, 0x07, 0xd9, 0x2b, 0x6b, 0xfc, + 0xeb, 0x8c, 0xa9, 0xea, 0x42, 0x16, 0x85, 0x03, 0xef, 0x13, 0x46, 0x27, 0x06, 0xaa, 0x3a, 0x8c, + 0x0b, 0x48, 0x04, 0xdb, 0x3a, 0xd9, 0xc1, 0x88, 0x64, 0x34, 0xe6, 0xdf, 0x66, 0x6f, 0xb4, 0x5e, + 0x75, 0xf1, 0xba, 0x41, 0xd7, 0x76, 0xe3, 0xea, 0x79, 0x5c, 0xe4, 0xdf, 0x60, 0x3b, 0xed, 0x31, + 0x72, 0x71, 0x97, 0xce, 0xb0, 0xb8, 0x44, 0xff, 0x71, 0xb7, 0xd8, 0x96, 0x96, 0x63, 0xd0, 0x3e, + 0x79, 0x13, 0x05, 0x2b, 0x6b, 0x67, 0xfc, 0x11, 0x4b, 0xb4, 0xf4, 0xe1, 0x42, 0x99, 0x00, 0xce, + 0xd9, 0xa9, 0x0c, 0x70, 0x41, 0x7f, 0xb0, 0xaa, 0x48, 0x6e, 0x12, 0xca, 0x57, 0x70, 0xff, 0x68, + 0xb5, 0xfd, 0x5c, 0xdb, 0xe6, 0xa8, 0x18, 0x3d, 0x7c, 0xf1, 0xa0, 0x69, 0x9a, 0x74, 0x0e, 0xda, + 0xe6, 0xaa, 0x80, 0xab, 0x34, 0xb7, 0xe5, 0xfe, 0xd4, 0x6a, 0x69, 0xa6, 0xfb, 0x71, 0xd1, 0xc9, + 0x2a, 0x58, 0xb7, 0x2f, 0x73, 0xfc, 0xf5, 0x6b, 0x7f, 0x7c, 0xc7, 0x5b, 0xf4, 0x79, 0xf0, 0xdf, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xa6, 0x23, 0xf1, 0xe3, 0x55, 0x0b, 0x00, 0x00, } diff --git a/actions/proto/vql.proto b/actions/proto/vql.proto index dba4e1e1b98..be039d605d4 100644 --- a/actions/proto/vql.proto +++ b/actions/proto/vql.proto @@ -128,6 +128,7 @@ message VQLEventTable { } message ClientInfo { + string client_id = 1; string hostname = 3; string fqdn = 4; string system = 5; diff --git a/api/api.go b/api/api.go index 7b5bfb45c15..f64e79664ea 100644 --- a/api/api.go +++ b/api/api.go @@ -172,7 +172,7 @@ func (self *ApiServer) CollectArtifact( } } - flow_id, err := flows.ScheduleArtifactCollection( + flow_id, err := artifacts.ScheduleArtifactCollection( self.config, in.Creator, in) if err != nil { return nil, err diff --git a/api/reflect_test.go b/api/reflect_test.go index ed499bbb43e..854aa321236 100644 --- a/api/reflect_test.go +++ b/api/reflect_test.go @@ -24,7 +24,6 @@ import ( "github.com/golang/protobuf/jsonpb" assert "github.com/stretchr/testify/assert" artifacts_proto "www.velocidex.com/golang/velociraptor/artifacts/proto" - // utils "www.velocidex.com/golang/velociraptor/testing" ) func TestDescriptor(t *testing.T) { diff --git a/artifacts/artifacts.go b/artifacts/artifacts.go index efe24f80fb7..116a8c7a717 100644 --- a/artifacts/artifacts.go +++ b/artifacts/artifacts.go @@ -187,6 +187,20 @@ func (self *Repository) LoadProto(artifact *artifacts_proto.Artifact, validate b } } + if source.Query != "" { + multi_vql, err := vfilter.MultiParse(source.Query) + if err != nil { + return nil, err + } + + scope := vql_subsystem.MakeScope() + + // Append the queries to the query list. + for _, vql := range multi_vql { + source.Queries = append(source.Queries, vql.ToString(scope)) + } + } + if len(source.Queries) == 0 { return nil, errors.New(fmt.Sprintf( "Source %s in artifact %s contains no queries!", diff --git a/artifacts/assets/ab0x.go b/artifacts/assets/ab0x.go index f25caa40fbc..4066e319d0a 100644 --- a/artifacts/assets/ab0x.go +++ b/artifacts/assets/ab0x.go @@ -67,7 +67,7 @@ var FileArtifactsDefinitionsElasticFlowsUploadYaml = []byte("\x1f\x8b\x08\x00\x0 var FileArtifactsDefinitionsGenericApplicationsOfficeKeywordsYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x55\x6d\x6f\xdb\xb6\x13\x7f\xaf\x4f\x71\x08\xfe\x40\x93\xfc\x35\xb9\xd8\xde\x19\xf0\x80\xa2\xcd\x43\xb1\x64\x29\xea\x0c\x1b\x8a\x02\xc6\x99\x3a\x5b\x44\x44\x52\xe3\x9d\x66\x3b\x6d\xbf\xfb\x70\x94\x6c\x4b\x49\xda\x19\x30\x21\x92\xf7\xf8\xbb\xbb\x1f\x3d\x3a\x9a\xc2\x15\x79\x8a\xd6\x14\x6f\x9a\xa6\xb6\x06\xc5\x06\xcf\xc5\xdd\x6a\x65\x0d\x15\xbf\xd1\x6e\x13\x62\xc9\x59\x49\x6c\xa2\x6d\xf4\x72\x0a\x5f\x33\x80\x5b\x6b\x62\xe0\xb0\x12\xe8\x44\xa1\x0c\xa6\x75\xe4\x85\x01\x5d\xf0\x6b\x08\x52\x51\x3c\x9c\xc2\x2a\x44\x87\x02\xa7\xdc\x9a\x0a\x90\x33\x80\x1b\xbb\x8c\xd8\x29\x9f\x01\x46\x02\x34\xd2\x62\x5d\xef\x80\x25\x44\x2a\xc1\x7a\x78\xb4\x0d\xac\x6c\x4d\x5c\xc0\x7d\x45\x87\x2d\x98\xe0\x05\xad\xcf\x00\xa4\x3a\xba\x06\xf2\x26\x94\x54\x02\x32\xfc\x75\x7b\xa3\x06\x10\x7c\xeb\x96\x14\x21\xac\x92\xb6\x23\xdd\x71\x91\x65\x00\xf7\x95\x65\x70\xf8\x40\x0c\x56\xa0\xb4\x1a\x4a\x5b\x0b\x48\x00\x26\x8c\xa6\xd2\xa0\xe1\xa1\x87\x00\x36\x56\x2a\xeb\x21\xa4\x88\x33\x18\x24\xbc\x24\x83\x2d\x53\x8a\xe5\xd3\xfb\x0f\x5d\xc4\x29\x25\xd9\x35\xd6\xa4\x9c\x4c\x70\x4d\x24\x66\x2a\x8f\xbe\x31\x8a\x5d\xa1\x91\xde\x1d\x71\x72\x18\x9e\xe2\xb9\xdc\x75\x49\xd3\x56\xc8\xb3\x0d\x1e\xd0\x97\x19\xc0\xba\x0e\x4b\xf5\xe9\xa1\x65\xe2\xe4\xfd\x80\xd7\x8e\x85\x1c\xa0\x31\xc4\x1c\xa2\xa6\x54\x63\xeb\x15\x7a\xd8\x61\x44\x60\x83\x8a\x1e\xae\xd1\xfa\xa4\xd9\xfa\x63\x84\x50\xa2\xa0\x22\x36\x04\xb7\x80\x7d\x33\xa4\xcc\x5c\x88\x0a\x42\x6d\x1f\xa8\xde\xa9\x7d\x87\x62\x2a\xd8\x68\x38\x6a\xdc\x5b\xbf\xee\xf4\x69\x60\x58\xab\xa2\xc6\x7b\x0c\xe8\x08\x41\x24\x69\xa3\x67\xc0\x54\x5b\xda\x0a\x60\x0c\xad\x2f\x93\x8d\xbe\x06\x50\x59\x49\x9a\xbf\xdf\xdd\x5f\x4c\x93\xfe\x7b\x2f\x14\x3d\xd6\xb7\x62\x9d\xb6\x45\xdd\x3a\x0f\x5c\x85\x4d\x87\x87\x89\x94\x1a\x1a\xd2\x75\x9f\xd1\xa3\x6d\x32\xe8\x3b\x61\x5f\xd5\x51\x1b\x6d\x2a\x6b\x2a\x70\xb8\x83\x48\x1a\x79\x77\x46\x4f\xa5\x52\x17\x5b\x6f\xc5\x76\x15\x56\x5f\x7d\x79\xe7\xa4\xe0\x54\x22\x0d\x4f\x27\x13\xf2\xc5\xc6\x3e\xd8\x86\x4a\x8b\x45\x88\xeb\x89\xee\x26\x37\x96\x65\x11\x56\x8b\xc3\x24\x2d\xba\x61\x58\x68\x01\x75\x34\x17\x87\x82\xf3\xc0\x98\xea\x16\xa1\x21\xdf\xf5\xc9\xd1\xde\xbb\x3e\xb0\x94\xf0\xe4\xee\x2e\xfc\xb2\xf8\x83\x29\x2e\xae\x5a\x5b\x12\x4f\xae\x48\xc4\xfa\xf5\x62\x2e\x18\x85\xca\xc9\xa5\xad\x69\xd1\x4d\x25\x67\x59\x83\x11\x1d\x09\x45\x9e\x66\x00\x3f\x41\x47\x0d\xfb\x5c\xaf\xea\xb0\xd4\x18\x00\x4a\x5a\x61\x5b\xcb\x14\x26\xe7\xc5\x97\x32\x98\x6d\x5e\x06\xe3\xf2\x32\x88\x7e\x89\x7e\x99\x65\xbe\xad\x79\xab\x8b\xcb\xb7\xb5\xe8\x97\xb8\xbc\x69\x64\xab\x8b\xcb\x1b\x15\x6e\x42\x3a\x43\x5d\x58\x2f\xd8\xe5\x5c\x97\x5b\x5d\x5c\x1e\x4a\xc9\x83\xe8\xbf\xca\x43\xe9\xbe\x0d\x62\xea\x66\x45\x23\x1a\x07\xf4\x76\xfa\x59\xd3\xe5\xcf\xe7\xe7\x03\x69\x6d\xf6\x8f\x6d\x4d\x63\xd9\xaf\x69\x0b\x10\xdb\x9a\xe0\xda\x0a\x7c\xe9\x0f\x00\x58\xa2\xf5\xeb\x84\xc2\xfe\xf7\x3f\x84\x19\x9c\x30\x99\x48\x72\x02\x1b\x5b\x12\xf8\x60\x90\x69\x28\xb3\x1c\xca\xf4\xd7\x87\x7b\x13\x7c\x69\x13\x77\x0e\x54\xd0\xef\xfa\x8e\x74\xfd\xe9\xb7\x2c\xe3\xd0\x46\x43\x7d\x11\xfe\x6e\x29\xee\x8e\xd1\x02\xdc\x5c\xdc\xf7\xf4\xb0\x28\x83\x61\x98\xc1\xfc\xe2\xe6\xe2\xed\x3d\x5c\xb6\x75\xfd\x01\xa5\x82\x37\xf3\x9e\x8f\x75\x97\x0f\xbc\x01\xa4\x19\x60\x41\xd7\x9c\x52\x13\x4c\x35\x4b\x33\x53\xcc\xc9\x9c\x29\x61\x76\x6a\xe9\xec\x89\xde\xdc\x3e\xd2\x51\x42\x77\x87\xfb\xcb\x8f\x77\xb7\x89\x87\x4e\x75\xe1\xd9\xb1\x38\xf0\xff\x71\xf7\x9c\x1d\xd1\x98\x4c\xe0\x0d\xd4\x96\xe5\x09\x29\x83\xf5\xac\xe0\xf6\x53\x06\x52\xa1\x40\x85\xff\x10\x70\x70\x1d\xe7\x2b\x0f\x8d\xd0\xd8\xfb\x58\x34\x18\x65\x00\xc8\x77\x41\x18\x22\xf5\xc9\x36\xb7\xc9\xb5\x1e\x7c\x37\xa7\x36\xd6\xa7\x63\x1b\x6c\x2a\x72\x34\x3b\xd1\x41\x3d\xc9\xa1\x41\xa9\x66\x03\x87\xb0\x8a\xb8\xd6\xa0\x66\x27\x93\xf3\xf3\x93\xb3\x62\x9e\x7a\xea\x49\x20\x7b\x6e\x9e\xbd\x7a\xb4\xcd\xab\xb3\xc3\xe5\x9f\xd7\x17\x1f\x2f\xc0\x07\x81\xf7\xfc\xce\x46\xe5\xfa\xae\x02\xbf\xc2\xeb\x11\x86\x97\x21\x02\xa1\xa9\x0e\x18\xe4\x89\x78\x01\xeb\x1a\xac\x30\x74\x88\xe8\x8b\x32\xa0\xd0\x23\x7a\xff\x05\x14\xfc\xa0\x23\x60\xd0\x0b\xcf\xae\x94\x58\x8a\xdb\x50\xde\x2b\xe5\x22\x8f\x29\xfa\x99\x74\x87\x4d\x71\x4d\xdb\x77\xfa\xe8\x20\xc3\x35\x6d\xdf\x76\x4f\xc0\xb8\x24\xab\x10\x35\xdd\x51\x2d\x62\xd8\xcc\x06\x03\x31\xb2\x9e\xa6\x67\xf6\xe5\x89\xc3\xfd\xc0\xd8\x9a\xf2\xde\x79\xfe\x23\x10\x9e\x43\xf1\xd2\x1c\x0c\xc2\x54\xc6\x39\x7d\x6e\x45\xa9\x86\x67\x7b\x3a\x7a\xc1\x4d\x7a\xb6\x67\xe3\x7e\x2e\x46\x1d\xfa\x82\x52\xff\x56\xce\x7e\x7e\xfd\xfa\x85\xdb\xef\xb5\xd8\xb7\xb3\xec\xdf\x00\x00\x00\xff\xff\x8f\x1b\x64\x6d\xfb\x09\x00\x00") // FileArtifactsDefinitionsGenericClientInfoYaml is "artifacts/definitions/Generic/Client/Info.yaml" -var FileArtifactsDefinitionsGenericClientInfoYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x55\x5d\x6f\xdb\x36\x14\x7d\xd7\xaf\x38\xd0\x06\xc4\x2a\x5c\xcd\x2d\x8a\x61\x08\xa0\x61\xae\xeb\xb4\xc6\x9c\x8f\x45\x4e\x8a\x3d\x19\x8c\x74\x15\x13\x90\x48\x85\xa4\xa2\x18\x4d\xff\xfb\x40\x52\x91\x15\xdb\x79\x18\x5f\x4c\x89\xf7\xe3\x9c\xc3\xa3\x6b\xc1\x2a\x3a\xc5\x57\x12\xa4\x78\x16\xcf\x4a\x4e\xc2\xc4\x0b\x51\xc8\x20\x27\x9d\x29\x5e\x1b\x2e\xc5\x29\x9e\x03\x60\x26\xcb\x92\x32\x83\x3b\xa6\x79\x06\x2e\x0a\xa9\x2a\x66\x8f\xc1\xee\x64\x63\x60\x36\x84\xcc\x17\x08\x02\x60\xb5\xe1\x1a\x4c\x19\x5e\xb0\xcc\x80\x6b\x64\x3e\x9f\x72\xb4\x1b\x12\x60\x62\x0b\x41\x6d\x97\x62\x03\x48\x28\x1b\x92\x83\x0b\x23\x6d\xb9\x00\xd0\x5b\x6d\xa8\x8a\x71\x4b\xa5\xcc\xb8\x62\xb5\x91\x0a\x2d\x2f\x4b\xb4\xcc\x64\x1b\x14\x52\xc1\xbc\xea\xc4\x44\x8e\x5a\xd6\x4d\xc9\x0c\x81\x1b\x1d\xc0\xd6\x23\x25\x58\x09\x2e\x72\x7a\x22\x8d\x42\xc9\x6a\x3f\x4d\xa3\xa5\xb2\x74\xd0\xff\x95\x0d\x32\x26\x40\x39\x37\x7b\x61\x46\x82\xc4\x86\x89\x8c\x06\x7c\x4f\xb4\x6f\xa1\xe4\xbd\x13\xc4\xb5\x1c\xc8\xa3\xa1\xe8\xa1\xe1\x8a\xf2\x38\x08\xb4\x6c\x54\x46\xfa\x34\x00\xde\xc3\xcb\xff\xd9\x2a\xba\xd8\x65\x04\x00\x70\xa0\xbf\x5d\x4e\x54\x5f\xc1\x2a\xd6\x68\xaf\x96\x63\x57\x6e\x2d\xba\x9e\x3a\xbb\x77\xb2\x8a\x42\xc6\xf8\x22\x21\xa4\xe9\x6a\x28\xaa\xe4\x23\x79\x5e\x0f\x0d\xa9\x6d\xec\x0e\xec\x96\x7b\x5c\x76\xbd\xef\x7b\x02\xe9\x7c\x39\x9f\xad\x90\x49\x51\xf0\xfb\xf8\x96\x94\xe6\x52\xc4\x17\xac\x22\x4c\x53\xd8\xdf\x71\x1f\xdb\xad\xbd\xd8\xcf\x0d\x2f\xf3\x15\xaf\xc8\x8a\xd1\x3f\xbc\x95\xb5\x64\x77\x54\x6a\x5b\xdb\xef\x0e\xe2\xbe\x49\x6d\xac\x74\x63\x5c\xa6\x63\x4c\x55\xb6\xe1\x86\x32\xd3\xa8\xc3\x92\x57\x25\x33\x56\xd8\x71\xbf\xeb\x30\x8d\xf1\x37\x29\x41\x65\xff\x78\xf6\x90\x8b\x3e\xfb\xec\xfa\xf2\xdc\x89\x37\x8a\x82\xc1\x4d\xdd\x68\x52\xda\x05\xd5\x8a\x32\x29\x72\xee\xef\xa7\x53\xe8\x32\xc5\x99\xb5\x96\x4f\xb4\x3e\x57\x64\x5f\x26\x38\x69\xb9\xc8\x65\xab\x4f\x8e\x6b\xdd\xe5\x3b\x29\xf1\x65\x77\xf3\x07\x74\x78\x31\xea\xdb\x26\xe7\xc6\x8a\x68\x8d\x28\x12\xbb\xd5\x86\x55\xf5\x88\x6a\x99\x6d\xfc\x59\x14\x79\x11\xb5\x59\xca\x7b\xbe\xc7\x6e\xda\x79\x3a\xfe\xee\xa1\xc5\xe9\x56\xc7\x8e\xa0\xe5\xac\xa8\x96\xca\x74\x36\x35\xdb\x9a\x4e\x31\x5b\x2e\xe6\x17\x2b\x57\xc4\x50\x55\x5b\x97\xed\x9c\xf9\xe3\x07\x7e\xf5\x5f\xc3\xda\xb2\xc7\x69\x82\x7f\xac\xb9\x10\x76\xdc\xde\xf9\xae\x3e\x46\x8f\x5e\x62\xf3\xc4\x0f\x9d\x45\x1e\x61\xb9\x38\x5f\xac\xf0\x21\xc4\xcf\x9f\xc1\xa0\x6c\x51\xca\x76\xcd\xf3\xc3\x92\xfb\x9c\x59\x66\xf8\x23\xad\xed\x6b\xfc\x86\x0f\x13\xb7\x9c\x04\xab\x97\x48\x0f\xc2\x56\x3c\x06\x61\x8c\xae\x57\x72\x56\xca\x76\x91\x47\x43\x28\xbf\x58\x30\x5f\xc9\xbc\xe6\x19\x4e\x62\xa9\xdd\x36\x2e\x1e\x72\x61\x13\x30\x7a\x2b\xb2\xef\xe8\xc2\x22\xfc\xd5\x07\xbe\x70\x0c\x27\x71\x8f\x75\x4f\x87\xa3\x72\xfa\x59\x30\xf2\x3f\xc9\xc9\xfe\x24\x39\x89\x42\x3c\x63\xc5\xee\x4a\x7a\xc5\xe4\x9c\x2a\xa9\xb6\x6e\x56\xce\xae\x6e\x50\x48\x69\x6a\xc5\x85\x81\x7c\x24\xe5\x26\x5b\xcd\xb4\xc1\xc7\x4f\xd8\xc8\x46\xe9\x01\x8a\x9c\x0a\x2e\x08\xa1\xa2\x6e\x90\x39\x94\x03\x87\x76\xf8\x7a\x16\x63\x28\x66\x68\xf4\x94\xcc\xae\x6e\xc6\xd8\x26\xfd\x41\x84\x77\xf6\x8e\x30\xd5\x16\xc3\x15\xa9\x8c\x84\x39\x30\x3c\x80\xeb\x34\xdd\x5d\xa7\xbd\x4d\x8f\xfe\x46\xd3\x30\x78\x28\xc7\xcb\xb8\x4e\xc2\xbd\x7f\xb6\xd4\x30\xa3\xc3\x63\x4d\xfc\xfc\x39\x74\xc4\x5b\xa1\x95\xcc\x29\x09\xfd\x27\xb1\x9e\xdf\xce\x2f\x56\x6f\x97\xd5\x86\x29\xe3\x6c\x99\x08\xd9\x8e\x22\xbc\xc7\x1f\xbf\x7f\x9a\x4c\xa2\x61\xc2\xf7\x6f\xf3\xeb\xf9\x40\x09\xfc\x99\x60\xb2\xd3\x9d\x44\x7e\xd4\x0e\x83\x7b\x78\xc6\x92\x0b\x9a\x6d\x98\x32\x08\x9f\xd8\x13\xd7\x6b\x8b\x32\x44\x68\x5b\x87\x08\xaf\xd3\x34\xde\xda\xf7\x21\x3e\xbe\xb2\xc3\xd4\x7d\x38\xdd\x74\xfb\x7f\x8e\x73\x39\x7b\x36\xfb\x2f\x00\x00\xff\xff\xdf\x09\x90\x91\x55\x08\x00\x00") +var FileArtifactsDefinitionsGenericClientInfoYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x55\x5d\x6f\xdb\x36\x14\x7d\xd7\xaf\x38\xd0\x06\xc4\x2a\x5c\xcd\x2d\x8a\x61\x08\xa0\x61\xae\xeb\xb4\xc6\x9c\x8f\x45\x4e\x8a\x3d\x19\x8c\x74\x15\x13\x90\x48\x85\xa4\xa2\x18\x4d\xff\xfb\x40\x52\x96\x15\x3b\x79\x98\x5e\x4c\x49\xf7\xe3\x9c\x73\x8f\xae\x05\xab\xe8\x14\x5f\x49\x90\xe2\x59\x3c\x2b\x39\x09\x13\x2f\x44\x21\x83\x9c\x74\xa6\x78\x6d\xb8\x14\xa7\x78\x0e\x80\x99\x2c\x4b\xca\x0c\xee\x98\xe6\x19\xb8\x28\xa4\xaa\x98\x7d\x0d\x76\x27\x1b\x03\xb3\x21\x64\xbe\x40\x10\x00\xab\x0d\xd7\x60\xca\xf0\x82\x65\x06\x5c\x23\xf3\xf9\x94\xa3\xdd\x90\x00\x13\x5b\x08\x6a\xbb\x14\x1b\x40\x42\xd9\x90\x1c\x5c\x18\x69\xcb\x05\x80\xde\x6a\x43\x55\x8c\x5b\x2a\x65\xc6\x15\xab\x8d\x54\x68\x79\x59\xa2\x65\x26\xdb\xa0\x90\x0a\xe6\x45\x27\x26\x72\xd4\xb2\x6e\x4a\x66\x08\xdc\xe8\x00\xb6\x1e\x29\xc1\x4a\x70\x91\xd3\x13\x69\x14\x4a\x56\x87\x69\x1a\x2d\x95\xa5\x83\xfe\xaf\x6c\x90\x31\x01\xca\xb9\x39\x08\x33\x12\x24\x36\x4c\x64\x34\xe0\x7b\xa2\x7d\x0b\x25\xef\x9d\x20\xae\xe5\x40\x1e\x0d\x45\x0f\x0d\x57\x94\xc7\x41\xa0\x65\xa3\x32\xd2\xa7\x01\xf0\x1e\x5e\xfe\xcf\x56\xd1\xc5\x3e\x23\x00\x80\x23\xfd\xed\xe5\x44\xf5\x15\xac\x62\x8d\xf6\x6a\x39\x76\xe5\xd6\xa2\xeb\xa9\xb3\x7b\x27\xab\x28\x64\x8c\x2f\x12\x42\x9a\xae\x86\xa2\x4a\x3e\x92\xe7\xf5\xd0\x90\xda\xc6\xee\x85\x3b\xee\x3b\x01\xe9\x7c\x39\x9f\xad\x90\x49\x51\xf0\xfb\xf8\x96\x94\xe6\x52\xc4\x17\xac\x22\x4c\x53\xd8\xdf\x71\x1f\xdb\x5d\x07\xb1\x9f\x1b\x5e\xe6\x2b\x5e\x91\x95\xa0\xbf\x79\x2b\x6b\xc9\xee\xa8\xd4\xb6\xb6\x3f\x1d\xc5\x7d\x93\xda\x58\xc1\xc6\xb8\x4c\xc7\x98\xaa\x6c\xc3\x0d\x65\xa6\x51\xc7\x25\xaf\x4a\x66\xac\x9c\xe3\xfe\xd4\x61\x1a\xe3\x6f\x52\x82\xca\xfe\xf6\xec\x21\x17\x7d\xf6\xd9\xf5\xe5\xb9\x93\x6c\x14\x05\x83\xf9\xdc\x68\x52\xda\x05\xd5\x8a\x32\x29\x72\xee\xa7\xd2\x29\x74\x99\xe2\xcc\x1a\xca\x27\x5a\x77\x2b\xb2\x0f\x13\x9c\xb4\x5c\xe4\xb2\xd5\x27\xbd\xc2\xdc\x4f\xde\x5e\xef\x77\xf9\x4e\x4a\x7c\xd9\xcf\xfb\x88\x0e\x2f\x46\x7d\xdb\xe4\xdc\x58\x11\xad\xfd\x44\x62\x8f\xda\xb0\xaa\x1e\x51\x2d\xb3\x8d\x7f\x17\x45\x5e\x44\x6d\x96\xf2\x9e\x1f\xb0\x9b\x76\x4e\x8e\xbf\x7b\x68\x71\xba\xd5\xb1\x23\x68\x39\x2b\xaa\xa5\x32\x9d\x39\xcd\xb6\xa6\x53\xcc\x96\x8b\xf9\xc5\xca\x15\x31\x54\xd5\xd6\x5b\x7b\x97\xfc\xf8\x81\x5f\xfd\x37\xb0\xb6\xec\x71\x9a\xe0\x1f\xeb\x23\x84\x1d\xb7\x77\xbe\xab\x8f\xd1\xa3\x5d\x6c\x9e\xf8\x55\xb3\xc8\x23\x2c\x17\xe7\x8b\x15\x3e\x84\xf8\xf9\x33\x18\x94\x2d\x4a\xd9\xae\x79\x7e\x5c\xf2\x90\x33\xcb\x0c\x7f\xa4\xb5\x7d\x8c\xdf\xf0\x61\xe2\x2e\x27\xc1\x6a\x17\xe9\x41\xd8\x8a\xaf\x41\x18\xa3\xeb\x95\x9c\x95\xb2\x5d\xe4\xd1\x10\xca\x2f\x16\xcc\x57\x32\x2f\x79\x86\x93\x58\x6a\x77\x8c\x8b\x87\x5c\xd8\x04\x8c\xde\x8a\xec\x3b\xba\xb0\x08\x7f\xf5\x81\x3b\x8e\xe1\x24\xee\xb1\x1e\xe8\xf0\xaa\x9c\x7e\x03\x8c\xfc\x4f\x72\x72\xb8\x3f\x4e\xa2\x10\xcf\x58\xb1\xbb\x92\x5e\x30\x39\xa7\x4a\xaa\xad\xdb\x90\xb3\xab\x1b\x14\x52\x9a\x5a\x71\x61\x20\x1f\x49\xb9\x7d\x56\x33\x6d\xf0\xf1\x13\x36\xb2\x51\x7a\x80\x22\xa7\x82\x0b\x42\xa8\xa8\x5b\x5f\x0e\xe5\xc0\xa1\x1d\xbe\x9e\xc5\x18\x8a\x19\x1a\x3d\x25\xb3\xab\x9b\x31\xb6\x49\xff\x22\xc2\x3b\x3b\x23\x4c\xb5\xc5\x70\x45\x2a\x23\x61\x8e\x0c\x0f\xe0\x3a\x4d\xf7\xe3\xb4\xd3\xf4\xe8\x6f\x34\x0d\x83\x87\x72\xec\x96\x74\x12\x1e\xfc\x9f\xa5\x86\x19\x1d\xbe\xd6\xc4\xef\x9f\x63\x47\xbc\x15\x5a\xc9\x9c\x92\xd0\x7f\x12\xeb\xf9\xed\xfc\x62\xf5\x76\x59\x6d\x98\x32\xce\x96\x89\x90\xed\x28\xc2\x7b\xfc\xf1\xfb\xa7\xc9\x24\x1a\x26\x7c\xff\x36\xbf\x9e\x0f\x94\xc0\x9f\x09\x26\x7b\xdd\x49\xe4\xaf\xda\x61\x30\x87\x67\x2c\xb9\xa0\xd9\x86\x29\x83\xf0\x89\x3d\x71\xbd\xb6\x28\x43\x84\xb6\x75\x88\xf0\x3a\x4d\xe3\xad\x7d\x1e\xe2\xe3\x0b\x3b\x4c\xdd\x87\xd3\x6d\xb7\xff\xe7\x38\x97\x73\x60\xb3\xff\x02\x00\x00\xff\xff\x15\xd9\x08\xa3\x4b\x08\x00\x00") // FileArtifactsDefinitionsGenericClientStatsYaml is "artifacts/definitions/Generic/Client/Stats.yaml" var FileArtifactsDefinitionsGenericClientStatsYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xe4\x56\xdd\x8e\xda\x48\x13\xbd\xe7\x29\x8e\xc8\xf7\x29\x90\x4c\x0c\x44\xda\x8b\x45\x22\xd2\x68\xc2\x64\x91\x98\x99\x04\xc3\x44\xab\xd5\x6a\x68\xec\x32\x6e\xc5\xee\xf6\x74\x97\x01\xe7\xe7\xdd\x57\xed\x1f\x30\xca\xec\xae\x14\xed\x5d\x7c\x03\xdd\x5d\xa7\xea\x54\x55\x57\x55\x2b\x91\xd2\x18\xef\x48\x91\x91\x81\x77\x95\x48\x52\xec\xf9\x2c\xd8\x76\x42\xb2\x81\x91\x19\x4b\xad\xc6\xb8\x54\x98\xee\x48\x31\x84\x61\x19\x89\x80\xb1\x8f\x65\x10\x63\xeb\x90\x82\xc9\x22\x28\xb1\xcf\x2d\xae\xde\xaf\x20\x54\x88\x94\x52\x6d\x0a\x58\x16\x2c\x2d\xcb\xc0\x7a\x9d\x4c\x18\x91\x12\x93\xb1\xe3\x0e\xf0\x0a\x95\xf5\x6b\x43\x8f\x39\xa9\xa0\xe8\x00\xc0\x99\xd9\x05\x71\x6e\x54\xa9\xc3\x82\x76\x64\x0a\x70\x2c\x2d\x52\xa1\x0a\x58\x0a\xb4\x0a\xad\x57\xc3\x22\x91\x27\x3c\x46\x77\x34\xec\x76\xb8\xc8\x68\x8c\xab\xf9\x6c\x7a\xbb\x7c\x98\xde\x4f\x6f\x97\x9d\x8e\xd5\xb9\x09\xa8\xb6\x9c\x99\x12\x2c\x2b\x33\xfe\x74\x3e\xbd\x5a\xe2\xce\xc7\xb5\xd1\x29\xa4\x8a\x74\xaf\x8f\x7d\x4c\x86\xdc\xe6\x04\xcf\xf7\x52\x85\x7a\x6f\x9f\x97\xb6\x1e\x73\x32\xb2\xd2\xe4\xbe\x57\x0d\xfe\x05\x22\x07\x8f\xb4\x21\x11\xc4\xbd\xfa\x18\x80\xd1\xfb\xc9\x97\xd3\x12\x0d\x60\xa5\xe4\xe1\x56\x28\x8d\xeb\xc5\xdd\x0d\x82\x44\x07\x9f\x7a\x19\x19\xa9\xc3\x89\x60\x2d\x7b\x96\x8d\x54\xdb\xc9\x31\x40\xfd\xfe\x49\xc9\xb7\x8b\xd3\x7f\x47\xa8\xf8\x67\x0b\x03\x8c\x86\xcd\x07\x61\xb1\x94\x29\x59\x16\x69\x76\xd1\x46\xd5\xdf\xca\x92\xc1\x4b\xf8\x85\x65\x4a\x9d\xf4\xd5\xfb\xd5\x53\x72\x37\x65\x8a\xbd\x8f\xda\x7c\x92\x6a\xeb\x13\xfb\xf2\x33\x39\xf9\x85\xef\xb7\xc5\x4b\xf7\x32\x9b\x48\xcb\xbd\x4c\x86\x93\x2d\x71\x26\xc3\xde\x99\x3b\xfd\xce\x0f\x25\x26\x91\x2a\x3f\xfc\x24\x69\x29\x0f\x3d\x5b\x65\xe5\x65\xbd\xcc\x5d\xae\xfe\x2d\x45\x33\x15\x69\x6f\xe1\xfb\x3f\x9e\x9b\x8e\xa1\x4c\x1b\xae\xcb\xa7\xaa\x2f\x7f\xba\xb8\x9f\x2e\xea\xfa\x72\x82\x4c\x69\x96\x08\xa6\x31\xbe\xd6\xe8\x2f\x5f\x5c\x65\x4a\x45\xe8\x1a\xaa\x2b\xb0\x8b\x6f\xdf\x9e\x88\xc9\xc9\x75\xb8\x8e\xd2\x3b\x4c\x9c\x4b\x28\x26\xc7\x83\x3e\x5e\xb8\x70\xe1\xb2\xf4\xf6\x3d\x99\x80\x14\x3f\xe5\xb4\xf3\xf4\x18\x59\x5c\xfa\x75\x14\x56\x96\xbe\xf3\xbc\xe2\xd4\xeb\xb7\x0f\x3e\xfe\x36\x5d\x4c\x5b\x26\xf0\x66\x82\xe1\xc9\x21\x52\xa1\xf3\xe0\xb4\xf1\xc1\xe5\xf9\xcc\xc1\xaf\x98\x4b\x45\x57\xb1\x30\x8c\xee\x41\x1c\xa4\x7d\x48\x75\x48\x5d\x74\x59\xa6\xee\x67\xe1\xfb\x5e\xe1\xf6\xbb\x78\x5d\x2b\x6b\xa2\x7a\x73\x77\x3b\x5b\xde\x2d\x66\xb7\xef\x1e\xde\x5e\xce\xe6\xbf\xff\xcc\x91\xfd\x5f\x35\x55\x1e\x5c\xe1\x63\x3c\x69\x22\x7d\x2c\xec\xba\x40\x9d\x8c\xed\x35\xb2\xe1\xa4\x9a\x63\xb3\xb0\x8f\xf9\xec\x66\xb6\xc4\xa8\xdb\x52\xfb\x0c\xd5\x31\xae\xb5\xe6\xcc\x48\xc5\xae\x35\x38\x6b\xef\x88\xcf\x2d\x76\x87\xde\x9d\x2d\x6b\xe7\xfa\x31\x54\x6d\x25\xcb\x98\x6a\xbb\x88\x85\x85\x68\x16\xb3\xb7\xd0\xd1\xdf\xe9\x3a\x12\x74\x9a\xbc\x5a\x53\x45\xc6\xa2\xaa\x2f\x70\x4c\xb8\xa7\x44\x07\xd2\x88\x8c\xb5\x41\x66\x74\x40\xd6\x22\x3a\xb2\x65\xed\xa4\x6a\xb8\x25\xb3\x23\x53\xcf\xc6\xd1\xf0\x38\x14\x4b\x86\xa1\x60\x01\xa9\x82\x24\x0f\xc9\x96\xaa\x59\xb3\x48\x5c\x02\x6a\x78\xce\x32\x91\x9f\x85\xeb\xb6\x17\xe5\xd4\x76\x42\x86\xac\x0c\x9d\x37\xcd\x08\x77\x5d\x3d\xb7\x14\x62\x53\x94\x02\x95\x23\x5e\x3b\x18\x91\x4e\x12\xbd\x97\x6a\x8b\xad\x11\x59\x0c\x1b\xeb\x7d\xdb\x64\xcb\x90\x57\x5f\x9a\xef\x29\xc0\x8d\x76\x12\xb9\x35\x14\x42\x2a\xac\x6f\x36\x6b\xf7\xd0\x48\xa8\x7c\x55\xac\xce\x24\x6b\x78\x4a\xc2\xe6\xa6\xe2\xb6\x6e\xae\x95\x8e\xa0\x15\x21\xd0\x86\xd6\x47\x9a\x1f\x09\x7b\x9d\x27\x21\xe8\x90\x51\xc0\x2d\x4f\x5c\x48\x73\x4b\x10\x46\xe7\x2a\xc4\xe8\xd5\x2f\xff\x6f\xab\x70\x03\x47\xd5\x4a\x64\x98\xd0\x05\x36\x39\x43\x46\x10\x88\x49\xec\x0a\xc4\xb9\x62\xc7\xdd\xe4\x4a\xb9\x10\x54\x6f\x14\xb9\x8d\xd9\x19\x48\x37\x4d\xae\xf2\x8d\x65\xa1\x58\x8a\x24\x29\xbc\xff\xbc\x81\x94\x97\xfb\x19\xee\x3f\xcc\x2b\x85\x4f\xa7\xc7\x1d\x97\x83\x09\x7b\x61\xab\xac\xb2\x46\x96\xe8\x2a\x20\x55\xf6\xc4\x46\xef\xe8\xc8\x70\xbd\x5e\xdb\xc7\xe4\x44\xb7\x69\x46\x4f\x77\x9e\xf5\x7a\xdd\x00\xdf\x60\xa9\x91\x90\x30\xca\x69\xcc\xd9\xbd\xdb\xc4\xd6\xb1\x70\x95\x9e\x69\x77\x9b\x33\x32\x91\x36\xa9\x50\x01\x61\x2f\x39\x3e\xbf\xfd\x96\x4e\x8d\xc5\xd1\xfb\x63\x93\xe8\x2d\x32\x6d\xf9\xcf\x5e\xcc\x9c\xd9\xf1\x60\x10\xea\xc0\x7a\xbb\x16\xaa\x5e\x84\x74\xf0\x02\x9d\x0e\x1c\x64\x10\x73\x9a\x0c\x5e\x0f\x47\xbf\x0e\x86\xaf\x07\xa3\xe1\xa0\x2d\xff\xd0\xe2\xe0\x39\xc1\xbe\xd7\xf9\x2b\x00\x00\xff\xff\xd0\xcd\xcd\xca\x19\x0b\x00\x00") @@ -186,6 +186,9 @@ var FileArtifactsDefinitionsServerInformationUsersYaml = []byte("\x1f\x8b\x08\x0 // FileArtifactsDefinitionsServerInternalArtifactDescriptionYaml is "artifacts/definitions/Server/Internal/ArtifactDescription.yaml" var FileArtifactsDefinitionsServerInternalArtifactDescriptionYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\x93\xcd\x8e\xa3\x3a\x10\x85\xf7\x3c\x45\x09\x7a\x71\xef\x82\xb0\x47\x34\x52\xa4\x9e\x45\x4b\xa3\x68\x66\xd2\x0f\x10\x07\x57\x06\x24\x30\xc4\xae\x44\x8a\x98\x7e\xf7\x91\x7f\x02\x36\x34\xb3\x89\x54\x75\xbe\x3a\x8e\x8f\x0b\xc1\x3a\xcc\xe1\x88\xf2\x8e\x72\xf7\x2e\x08\xa5\x60\xed\x6e\x2f\xa9\xb9\xb0\x8a\xde\x50\x55\xb2\x19\xa8\xe9\x45\x14\xd1\x63\xc0\x1c\xde\x0f\x1f\xdf\x7e\x1d\xf6\xdf\xa3\x48\xe2\xd0\x4b\x52\x79\x04\x90\xc2\x42\x04\x00\x20\xec\x86\x96\x11\xe6\xf0\xc7\xd4\x00\xe3\x08\x2f\xcc\x59\x43\xfe\x0a\xc7\xaa\x1f\x10\xe2\x67\x2b\x86\xcf\xcf\xc8\xa1\x49\x12\xd0\xbb\x03\xeb\x30\x90\x93\x04\x3e\xcc\x99\x01\xa6\x5b\x1e\x36\x8e\xd0\x5c\x3c\x79\x7f\xa3\xba\x97\x1a\x98\x6d\x12\x38\x3f\x42\x93\x25\x35\x8e\x28\x78\x60\x3a\xb3\x5e\x42\xff\x38\xf7\x07\x93\xac\x43\x42\xa9\xc2\x3b\xc0\x2c\x3c\xbb\x05\xb1\x73\x8b\x50\xb5\x4c\xa9\xd7\xd8\x16\xe6\x37\x55\x24\x9b\x01\xb9\xab\xea\xfe\x8e\x32\x2e\xa7\xa9\x1a\x19\x7f\x56\xa6\x21\xbd\xca\x00\xa5\xce\xb0\xc8\xa8\x5e\x09\x3a\xb5\x2f\x85\x37\xbc\xb0\x5b\x4b\x0b\xad\xc8\x66\x73\x2d\x79\x27\x17\x74\xee\xf9\xa3\x9c\x63\x90\x4c\xfc\x46\x78\x69\x08\x3b\xfd\xe2\x5b\x91\x4c\xde\x36\x39\xd1\x13\xfc\x87\x57\x3b\x67\x1f\x35\xae\x1b\xce\x51\xc4\xff\x07\xf8\xfa\xa2\xb6\xc7\x4b\xf3\x4c\x66\xdc\xad\x4e\x91\x11\xff\x92\x9c\x40\xb7\x3c\x9b\x60\x31\x48\x9c\x69\x97\x8d\x19\xd0\xc2\x6a\xcc\x8f\xc9\xde\x0c\x05\xf7\xb7\x2a\xac\x8b\xcc\x66\x57\x64\xe6\x81\xcb\x68\xc5\xad\x52\x55\xfd\x4d\x56\x18\xe6\x7a\x34\xbd\xe5\x9e\xd9\xae\xc9\xc4\x0e\x4d\x1f\x94\x1f\xfb\x53\xfb\x79\x43\xf9\xf0\x1c\x4e\xa7\xd3\xfd\xda\x7a\xeb\xbf\xe4\x26\x6c\xfe\x8f\x29\x60\xab\x10\xd2\x6d\x17\x77\x89\xab\x31\xd1\x77\xf0\x5c\x1b\x54\x66\x74\x76\x73\x5c\xba\x99\x9f\x3e\x7d\x3b\x31\xd7\xf8\x1b\x00\x00\xff\xff\x87\x77\x3d\xf3\xef\x04\x00\x00") +// FileArtifactsDefinitionsServerInternalEnrollmentYaml is "artifacts/definitions/Server/Internal/Enrollment.yaml" +var FileArtifactsDefinitionsServerInternalEnrollmentYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x44\x90\x41\x6a\xc3\x50\x0c\x44\xf7\xff\x14\x73\x02\x1f\x20\x7b\x2f\xba\xc9\x22\x0d\x81\xae\x8a\x6a\x8f\x6b\x81\xbf\x7e\x2a\xc9\x09\x81\x1e\xbe\x98\x98\x74\x2d\xf4\xe6\xcd\x98\x54\x1e\xf0\x4e\xbf\xd1\xbb\x37\x4b\xba\xc9\xd2\xf5\xe6\x6d\x59\x2a\x2d\xcb\xc8\x18\x5c\xaf\xa9\xcd\x0e\xf8\x2d\xc0\x79\xd6\x00\x6f\xb4\x84\x78\xea\x24\x43\x42\x03\x62\xd0\xfd\x7d\xbf\x46\x3a\xa5\xa2\xdd\xe8\xb8\xcf\x3a\xcc\x18\x16\xdd\x90\x00\x5f\xfc\x80\x38\x11\xb4\xec\xf0\xd1\x56\x0c\x62\xb8\x4b\x0e\x33\xf2\x3f\xe7\x67\xe5\xca\x40\x36\x7c\x11\xd6\x52\x27\xe5\x58\x80\x66\x10\x7b\xc0\x78\xdf\xd1\xb1\x93\xd5\xbe\x31\x35\x47\xce\xc4\xa4\x1e\x89\xd4\xca\xae\x14\xe0\xd8\x92\x87\x67\x89\xa7\xb5\xac\xd9\xaa\x24\x47\xc4\x23\x92\xf5\xd5\xea\x29\x34\xb6\x2d\x11\x46\x8e\x9b\x40\xa4\x78\x42\xb3\x2b\x25\x1f\xd7\x6d\xba\xfe\x74\xe9\x4f\x9f\xfd\xa5\x3f\x9e\xcb\x5f\x00\x00\x00\xff\xff\x60\xdf\x3b\x71\x4e\x01\x00\x00") + // FileArtifactsDefinitionsServerInternalInterrogateYaml is "artifacts/definitions/Server/Internal/Interrogate.yaml" var FileArtifactsDefinitionsServerInternalInterrogateYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x93\xcd\x6e\xda\x40\x10\xc7\xef\x7e\x8a\x11\x17\x42\x95\xf8\x01\x90\x7c\x48\x90\x69\xac\x52\x52\x01\xa2\x47\xb4\xac\x87\xb0\xaa\xbd\x4b\x66\xc7\xb1\x50\x4b\x9f\xbd\x5a\x1b\x5a\xa0\x6b\x9b\xcc\x01\x31\x9e\xff\x8c\xe7\xe3\x67\x2d\x72\x1c\xc2\x1c\xe9\x1d\x29\x4c\x34\x23\x69\x91\xd5\x7f\xc8\xbc\x0a\xc6\x20\x45\x2b\x49\xed\x58\x19\x3d\x84\x5f\x01\xc0\xa3\x06\x75\x14\x82\x20\x56\x1b\x21\x19\x0a\x8b\x29\x30\x09\xf9\x03\x34\x96\x20\x33\x85\x9a\x6b\x5d\x55\x47\x19\x6d\x61\xbd\x07\xde\x62\x00\x90\x9c\x3f\x07\x8b\xf4\xae\x24\x86\x41\xc0\xfb\x9d\xeb\x26\x9e\x2d\xe3\xd9\x2a\x5e\xc6\xd3\x45\x10\x58\x53\x90\x44\x3b\x0c\x00\x1e\xe0\xad\x40\x52\xb5\xe3\xec\x01\xe6\xf1\x24\x1e\x2d\xe0\x13\x8c\x67\x2f\x5f\x61\x63\x08\x85\xdc\xde\x1d\xc3\xce\xc8\x94\xd1\xcf\x33\x1f\xe0\x94\x33\xaa\x7a\x4c\xd2\x7b\x18\x67\xa6\xac\x7f\x93\xf4\x52\x5a\x55\x2d\x05\xcb\xed\x2a\x37\x5a\xb1\x21\xa5\x5f\xef\x4e\x53\x47\xfd\xf9\xde\x32\xe6\xa1\x4b\x0d\x47\x26\xdf\x65\xe8\x26\xea\x0f\x2e\xab\x7c\x7f\x8e\x67\x71\x55\x3f\x3c\xa5\xda\x55\xa9\x78\xbb\x22\xb4\x45\xc6\x16\xa2\xdf\xd0\xff\x8c\x1a\x49\xc9\xb0\xee\x2b\x4c\xf4\xc6\xf4\xcf\xea\x1c\xee\xcf\x1c\xb7\x87\xfd\xd5\x5c\x97\xab\xb0\xa5\xe2\xcb\x4d\x38\x13\xd7\xbb\xf0\x2e\xc4\x23\x81\xe3\x7a\xfc\xb1\x47\x92\x5b\xc5\x28\xb9\x20\xf4\x2b\x9e\x0a\x95\xa5\x0b\x95\x37\x84\xc7\x6f\xa9\xf6\x47\x9e\x8d\x65\x07\xa9\x3f\xfa\x05\x49\x63\xb6\x44\xb2\xca\x34\x14\x98\x88\x35\x66\xd6\x1f\x9b\x36\x16\x7e\x99\xfb\x9f\x7f\xcb\x04\x6f\x0c\xe5\xed\xd1\x63\x43\xff\x6b\xea\xd3\x54\x44\x5f\x9f\xa6\xb6\xfa\xc3\x59\xa9\x34\x6a\xbf\xc6\x26\x33\xa5\x53\xb5\x5d\xa5\x7e\x4f\xd4\x7b\x12\x56\x49\x87\x13\xe5\xd5\x07\xd7\xf3\xcb\xff\x52\xdd\x1b\x15\x96\x4d\x1e\x7a\x80\x6c\x48\xcd\x4d\x8a\x51\x6f\x34\x49\xe2\xe9\xa2\x37\xb8\x96\x1c\x2e\x93\xd6\x1e\x06\x6f\x20\xb0\x79\xd2\x2e\xfa\x5a\xd9\x6b\x22\xaf\x8d\xbb\x4e\xea\x9a\x99\x6b\x22\xce\xcf\x5b\x1b\x6d\x1d\xac\x75\x90\x76\x1b\x67\xdd\x94\x7d\x88\xb1\x7f\x84\xdd\x8a\x56\x0b\x58\x87\x73\xf7\x30\x08\xfe\x04\x00\x00\xff\xff\x47\x0a\xd1\x23\xca\x06\x00\x00") @@ -2741,6 +2744,40 @@ func Init() { + rb = bytes.NewReader(FileArtifactsDefinitionsServerInternalEnrollmentYaml) + r, err = gzip.NewReader(rb) + if err != nil { + panic(err) + } + + err = r.Close() + if err != nil { + panic(err) + } + + + + f, err = FS.OpenFile(CTX, "artifacts/definitions/Server/Internal/Enrollment.yaml", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777) + if err != nil { + panic(err) + } + + + + _, err = io.Copy(f, r) + if err != nil { + panic(err) + } + + + + err = f.Close() + if err != nil { + panic(err) + } + + + rb = bytes.NewReader(FileArtifactsDefinitionsServerInternalInterrogateYaml) r, err = gzip.NewReader(rb) if err != nil { diff --git a/artifacts/definitions/Generic/Client/Info.yaml b/artifacts/definitions/Generic/Client/Info.yaml index a9513496717..e422d7e5c29 100644 --- a/artifacts/definitions/Generic/Client/Info.yaml +++ b/artifacts/definitions/Generic/Client/Info.yaml @@ -14,8 +14,7 @@ sources: description: | This source is used internally to populate agent info. Do not remove this query. - queries: - - | + query: | SELECT config.Version.Name AS Name, config.Version.BuildTime as BuildTime, config.Labels AS Labels, diff --git a/artifacts/definitions/Server/Internal/Enrollment.yaml b/artifacts/definitions/Server/Internal/Enrollment.yaml new file mode 100644 index 00000000000..2e7183d4836 --- /dev/null +++ b/artifacts/definitions/Server/Internal/Enrollment.yaml @@ -0,0 +1,9 @@ +name: Server.Internal.Enrollment +description: | + This event artifact is an internal event stream over which client + enrollments are sent. You can watch this event queues to be notified + on any new clients enrolling for the first time. + + Note: This is an automated system artifact. You do not need to start it. + +type: SERVER_EVENT diff --git a/artifacts/schedule.go b/artifacts/schedule.go new file mode 100644 index 00000000000..e10162aea9c --- /dev/null +++ b/artifacts/schedule.go @@ -0,0 +1,182 @@ +package artifacts + +import ( + "crypto/rand" + "encoding/base32" + "encoding/binary" + "time" + + errors "github.com/pkg/errors" + actions_proto "www.velocidex.com/golang/velociraptor/actions/proto" + api_proto "www.velocidex.com/golang/velociraptor/api/proto" + artifacts_proto "www.velocidex.com/golang/velociraptor/artifacts/proto" + config_proto "www.velocidex.com/golang/velociraptor/config/proto" + "www.velocidex.com/golang/velociraptor/constants" + crypto_proto "www.velocidex.com/golang/velociraptor/crypto/proto" + "www.velocidex.com/golang/velociraptor/datastore" + flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" + "www.velocidex.com/golang/velociraptor/paths" +) + +func CompileCollectorArgs( + config_obj *config_proto.Config, + principal string, + collector_request *flows_proto.ArtifactCollectorArgs) ( + *actions_proto.VQLCollectorArgs, error) { + repository, err := GetGlobalRepository(config_obj) + if err != nil { + return nil, err + } + + // Update the flow's artifacts list. + vql_collector_args := &actions_proto.VQLCollectorArgs{ + OpsPerSecond: collector_request.OpsPerSecond, + Timeout: collector_request.Timeout, + MaxRow: 1000, + } + for _, name := range collector_request.Artifacts { + var artifact *artifacts_proto.Artifact = nil + if collector_request.AllowCustomOverrides { + artifact, _ = repository.Get("Custom." + name) + } + + if artifact == nil { + artifact, _ = repository.Get(name) + } + + if artifact == nil { + return nil, errors.New("Unknown artifact " + name) + } + + err := repository.CheckAccess(config_obj, artifact, principal) + if err != nil { + return nil, err + } + + err = repository.Compile(artifact, vql_collector_args) + if err != nil { + return nil, err + } + } + + // Add any artifact dependencies. + err = repository.PopulateArtifactsVQLCollectorArgs(vql_collector_args) + if err != nil { + return nil, err + } + + err = AddArtifactCollectorArgs( + config_obj, vql_collector_args, collector_request) + if err != nil { + return nil, err + } + + err = Obfuscate(config_obj, vql_collector_args) + return vql_collector_args, err +} + +func ScheduleArtifactCollection( + config_obj *config_proto.Config, + principal string, + collector_request *flows_proto.ArtifactCollectorArgs) (string, error) { + + args := collector_request.CompiledCollectorArgs + if args == nil { + var err error + args, err = CompileCollectorArgs( + config_obj, principal, collector_request) + if err != nil { + return "", err + } + } + + return ScheduleArtifactCollectionFromCollectorArgs( + config_obj, collector_request, args) +} + +func ScheduleArtifactCollectionFromCollectorArgs( + config_obj *config_proto.Config, + collector_request *flows_proto.ArtifactCollectorArgs, + vql_collector_args *actions_proto.VQLCollectorArgs) (string, error) { + + client_id := collector_request.ClientId + if client_id == "" { + return "", errors.New("Client id not provided.") + } + + // Generate a new collection context. + collection_context := &flows_proto.ArtifactCollectorContext{ + SessionId: NewFlowId(client_id), + CreateTime: uint64(time.Now().UnixNano() / 1000), + State: flows_proto.ArtifactCollectorContext_RUNNING, + Request: collector_request, + ClientId: client_id, + } + db, err := datastore.GetDB(config_obj) + if err != nil { + return "", err + } + + // Save the collection context. + flow_path_manager := paths.NewFlowPathManager(client_id, + collection_context.SessionId) + err = db.SetSubject(config_obj, + flow_path_manager.Path(), + collection_context) + if err != nil { + return "", err + } + + // The task we will schedule for the client. + task := &crypto_proto.GrrMessage{ + SessionId: collection_context.SessionId, + RequestId: constants.ProcessVQLResponses, + VQLClientAction: vql_collector_args} + + // Send an urgent request to the client. + if collector_request.Urgent { + task.Urgent = true + } + + // Record the tasks for provenance of what we actually did. + err = db.SetSubject(config_obj, + flow_path_manager.Task().Path(), + &api_proto.ApiFlowRequestDetails{ + Items: []*crypto_proto.GrrMessage{task}}) + if err != nil { + return "", err + } + + return collection_context.SessionId, db.QueueMessageForClient( + config_obj, client_id, task) +} + +// Adds any parameters set in the ArtifactCollectorArgs into the +// VQLCollectorArgs. +func AddArtifactCollectorArgs( + config_obj *config_proto.Config, + vql_collector_args *actions_proto.VQLCollectorArgs, + collector_args *flows_proto.ArtifactCollectorArgs) error { + + // Add any Environment Parameters from the request. + if collector_args.Parameters == nil { + return nil + } + + for _, item := range collector_args.Parameters.Env { + vql_collector_args.Env = append(vql_collector_args.Env, + &actions_proto.VQLEnv{Key: item.Key, Value: item.Value}) + } + + return nil +} + +func NewFlowId(client_id string) string { + buf := make([]byte, 8) + rand.Read(buf) + + binary.BigEndian.PutUint32(buf, uint32(time.Now().Unix())) + result := base32.HexEncoding.EncodeToString(buf)[:13] + + return constants.FLOW_PREFIX + result +} diff --git a/bin/artifacts.go b/bin/artifacts.go index b66360da04a..48d49e56545 100644 --- a/bin/artifacts.go +++ b/bin/artifacts.go @@ -287,6 +287,8 @@ func valid_parameter(param_name string, repository *artifacts.Repository) bool { func doArtifactCollect() { config_obj := load_config_or_default() + load_config_artifacts(config_obj) + repository, err := getRepository(config_obj) kingpin.FatalIfError(err, "Loading extra artifacts") diff --git a/bin/golden.go b/bin/golden.go index c6e454301d3..e23cc99424f 100644 --- a/bin/golden.go +++ b/bin/golden.go @@ -34,7 +34,6 @@ import ( artifacts "www.velocidex.com/golang/velociraptor/artifacts" config_proto "www.velocidex.com/golang/velociraptor/config/proto" "www.velocidex.com/golang/velociraptor/constants" - "www.velocidex.com/golang/velociraptor/flows" flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" "www.velocidex.com/golang/velociraptor/reporting" vql_subsystem "www.velocidex.com/golang/velociraptor/vql" @@ -74,7 +73,7 @@ func vqlCollectorArgsFromFixture( } vql_collector_args := &actions_proto.VQLCollectorArgs{} - err := flows.AddArtifactCollectorArgs( + err := artifacts.AddArtifactCollectorArgs( config_obj, vql_collector_args, artifact_collector_args) diff --git a/datastore/filebased.go b/datastore/filebased.go index 2b9f87ba299..d2d3d51544f 100644 --- a/datastore/filebased.go +++ b/datastore/filebased.go @@ -56,18 +56,18 @@ import ( crypto_proto "www.velocidex.com/golang/velociraptor/crypto/proto" "www.velocidex.com/golang/velociraptor/logging" "www.velocidex.com/golang/velociraptor/paths" - "www.velocidex.com/golang/velociraptor/testing" "www.velocidex.com/golang/velociraptor/utils" + "www.velocidex.com/golang/velociraptor/vtesting" ) var ( file_based_imp = &FileBaseDataStore{ - clock: testing.RealClock{}, + clock: vtesting.RealClock{}, } ) type FileBaseDataStore struct { - clock testing.Clock + clock vtesting.Clock } func (self *FileBaseDataStore) GetClientTasks( diff --git a/datastore/memory.go b/datastore/memory.go index 50a2bd7938e..e54faad559e 100644 --- a/datastore/memory.go +++ b/datastore/memory.go @@ -9,6 +9,7 @@ import ( "github.com/golang/protobuf/ptypes/empty" config_proto "www.velocidex.com/golang/velociraptor/config/proto" crypto_proto "www.velocidex.com/golang/velociraptor/crypto/proto" + "www.velocidex.com/golang/velociraptor/utils" ) var ( @@ -116,7 +117,8 @@ func (self *TestDataStore) ListChildren( if strings.HasPrefix(k, urn) { k = strings.TrimLeft(strings.TrimPrefix(k, urn), "/") components := strings.Split(k, "/") - if len(components) > 0 { + if len(components) > 0 && + !utils.InString(result, components[0]) { result = append(result, components[0]) } } diff --git a/datastore/mysql.go b/datastore/mysql.go index d4930df3a38..299457b7892 100644 --- a/datastore/mysql.go +++ b/datastore/mysql.go @@ -15,9 +15,9 @@ import ( errors "github.com/pkg/errors" config_proto "www.velocidex.com/golang/velociraptor/config/proto" crypto_proto "www.velocidex.com/golang/velociraptor/crypto/proto" - "www.velocidex.com/golang/velociraptor/testing" "www.velocidex.com/golang/velociraptor/third_party/cache" "www.velocidex.com/golang/velociraptor/utils" + "www.velocidex.com/golang/velociraptor/vtesting" ) var ( @@ -306,7 +306,7 @@ func NewMySQLDataStore(config_obj *config_proto.Config) (DataStore, error) { } } - return &MySQLDataStore{FileBaseDataStore{clock: testing.RealClock{}}}, nil + return &MySQLDataStore{FileBaseDataStore{clock: vtesting.RealClock{}}}, nil } func initializeDatabase( diff --git a/file_store/memory/queue.go b/file_store/memory/queue.go index ba56c5c2744..03858c49721 100644 --- a/file_store/memory/queue.go +++ b/file_store/memory/queue.go @@ -39,7 +39,7 @@ func (self *QueuePool) Register(vfs_path string) (<-chan *ordereddict.Dict, func registrations, _ := self.registrations[vfs_path] new_registration := &Listener{ - Channel: make(chan *ordereddict.Dict, 1000), + Channel: make(chan *ordereddict.Dict, 100000), id: time.Now().UnixNano(), } registrations = append(registrations, new_registration) diff --git a/file_store/test_utils/testing.go b/file_store/test_utils/testing.go new file mode 100644 index 00000000000..ff899a50923 --- /dev/null +++ b/file_store/test_utils/testing.go @@ -0,0 +1,19 @@ +package test_utils + +import ( + "testing" + + "github.com/stretchr/testify/require" + config_proto "www.velocidex.com/golang/velociraptor/config/proto" + "www.velocidex.com/golang/velociraptor/file_store" + "www.velocidex.com/golang/velociraptor/file_store/memory" +) + +func GetMemoryFileStore( + t *testing.T, + config_obj *config_proto.Config) *memory.MemoryFileStore { + file_store_factory, ok := file_store.GetFileStore(config_obj).(*memory.MemoryFileStore) + require.True(t, ok) + + return file_store_factory +} diff --git a/flows/artifacts.go b/flows/artifacts.go index 8356ac277bb..c966bf67a4e 100644 --- a/flows/artifacts.go +++ b/flows/artifacts.go @@ -19,9 +19,6 @@ package flows import ( "context" - "crypto/rand" - "encoding/base32" - "encoding/binary" "fmt" "path" "strings" @@ -31,10 +28,8 @@ import ( errors "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - actions_proto "www.velocidex.com/golang/velociraptor/actions/proto" api_proto "www.velocidex.com/golang/velociraptor/api/proto" artifacts "www.velocidex.com/golang/velociraptor/artifacts" - artifacts_proto "www.velocidex.com/golang/velociraptor/artifacts/proto" config_proto "www.velocidex.com/golang/velociraptor/config/proto" constants "www.velocidex.com/golang/velociraptor/constants" "www.velocidex.com/golang/velociraptor/crypto" @@ -61,158 +56,10 @@ var ( }) ) -const ( - _ = iota - processVQLResponses uint64 = iota -) - -func NewFlowId(client_id string) string { - buf := make([]byte, 8) - rand.Read(buf) - - binary.BigEndian.PutUint32(buf, uint32(time.Now().Unix())) - result := base32.HexEncoding.EncodeToString(buf)[:13] - - return constants.FLOW_PREFIX + result -} - func GetCollectionPath(client_id, flow_id string) string { return path.Join("/clients", client_id, "collections", flow_id) } -func ScheduleArtifactCollection( - config_obj *config_proto.Config, - principal string, - collector_request *flows_proto.ArtifactCollectorArgs) (string, error) { - - args := collector_request.CompiledCollectorArgs - if args == nil { - var err error - args, err = CompileCollectorArgs( - config_obj, principal, collector_request) - if err != nil { - return "", err - } - } - - return ScheduleArtifactCollectionFromCollectorArgs( - config_obj, collector_request, args) -} - -func CompileCollectorArgs( - config_obj *config_proto.Config, - principal string, - collector_request *flows_proto.ArtifactCollectorArgs) ( - *actions_proto.VQLCollectorArgs, error) { - repository, err := artifacts.GetGlobalRepository(config_obj) - if err != nil { - return nil, err - } - - // Update the flow's artifacts list. - vql_collector_args := &actions_proto.VQLCollectorArgs{ - OpsPerSecond: collector_request.OpsPerSecond, - Timeout: collector_request.Timeout, - MaxRow: 1000, - } - for _, name := range collector_request.Artifacts { - var artifact *artifacts_proto.Artifact = nil - if collector_request.AllowCustomOverrides { - artifact, _ = repository.Get("Custom." + name) - } - - if artifact == nil { - artifact, _ = repository.Get(name) - } - - if artifact == nil { - return nil, errors.New("Unknown artifact " + name) - } - - err := repository.CheckAccess(config_obj, artifact, principal) - if err != nil { - return nil, err - } - - err = repository.Compile(artifact, vql_collector_args) - if err != nil { - return nil, err - } - } - - // Add any artifact dependencies. - err = repository.PopulateArtifactsVQLCollectorArgs(vql_collector_args) - if err != nil { - return nil, err - } - - err = AddArtifactCollectorArgs( - config_obj, vql_collector_args, collector_request) - if err != nil { - return nil, err - } - - err = artifacts.Obfuscate(config_obj, vql_collector_args) - return vql_collector_args, err -} - -func ScheduleArtifactCollectionFromCollectorArgs( - config_obj *config_proto.Config, - collector_request *flows_proto.ArtifactCollectorArgs, - vql_collector_args *actions_proto.VQLCollectorArgs) (string, error) { - - client_id := collector_request.ClientId - if client_id == "" { - return "", errors.New("Client id not provided.") - } - - // Generate a new collection context. - collection_context := &flows_proto.ArtifactCollectorContext{ - SessionId: NewFlowId(client_id), - CreateTime: uint64(time.Now().UnixNano() / 1000), - State: flows_proto.ArtifactCollectorContext_RUNNING, - Request: collector_request, - ClientId: client_id, - } - db, err := datastore.GetDB(config_obj) - if err != nil { - return "", err - } - - // Save the collection context. - flow_path_manager := paths.NewFlowPathManager(client_id, - collection_context.SessionId) - err = db.SetSubject(config_obj, - flow_path_manager.Path(), - collection_context) - if err != nil { - return "", err - } - - // The task we will schedule for the client. - task := &crypto_proto.GrrMessage{ - SessionId: collection_context.SessionId, - RequestId: processVQLResponses, - VQLClientAction: vql_collector_args} - - // Send an urgent request to the client. - if collector_request.Urgent { - task.Urgent = true - } - - // Record the tasks for provenance of what we actually did. - err = db.SetSubject(config_obj, - flow_path_manager.Task().Path(), - &api_proto.ApiFlowRequestDetails{ - Items: []*crypto_proto.GrrMessage{task}}) - if err != nil { - return "", err - } - - return collection_context.SessionId, QueueMessageForClient( - config_obj, client_id, task) -} - func closeContext( config_obj *config_proto.Config, collection_context *flows_proto.ArtifactCollectorContext) error { @@ -730,23 +577,3 @@ func (self *FlowRunner) ProcessMessages(ctx context.Context, return message_info.IterateJobs(ctx, self.ProcessSingleMessage) } - -// Adds any parameters set in the ArtifactCollectorArgs into the -// VQLCollectorArgs. -func AddArtifactCollectorArgs( - config_obj *config_proto.Config, - vql_collector_args *actions_proto.VQLCollectorArgs, - collector_args *flows_proto.ArtifactCollectorArgs) error { - - // Add any Environment Parameters from the request. - if collector_args.Parameters == nil { - return nil - } - - for _, item := range collector_args.Parameters.Env { - vql_collector_args.Env = append(vql_collector_args.Env, - &actions_proto.VQLEnv{Key: item.Key, Value: item.Value}) - } - - return nil -} diff --git a/flows/foreman.go b/flows/foreman.go index 554d2cc402c..62820199d43 100644 --- a/flows/foreman.go +++ b/flows/foreman.go @@ -102,7 +102,7 @@ func ForemanProcessMessage( config_obj, client_id, &crypto_proto.GrrMessage{ SessionId: constants.MONITORING_WELL_KNOWN_FLOW, - RequestId: processVQLResponses, + RequestId: constants.ProcessVQLResponses, VQLClientAction: flow_condition_query}) if err != nil { return err diff --git a/flows/hunts.go b/flows/hunts.go index 4aad9d346ed..0a35162104f 100644 --- a/flows/hunts.go +++ b/flows/hunts.go @@ -106,7 +106,7 @@ func CreateHunt( // time. This ensures that if the artifact definition is // changed after this point, the hunt will continue to // schedule consistent VQL on the clients. - hunt.StartRequest.CompiledCollectorArgs, err = CompileCollectorArgs( + hunt.StartRequest.CompiledCollectorArgs, err = artifacts.CompileCollectorArgs( config_obj, principal, hunt.StartRequest) if err != nil { return nil, err diff --git a/flows/monitoring.go b/flows/monitoring.go index 796917441ae..e0d16353077 100644 --- a/flows/monitoring.go +++ b/flows/monitoring.go @@ -35,10 +35,7 @@ func MonitoringProcessMessage( } // Deobfuscate the response if needed. - err = artifacts.Deobfuscate(config_obj, response) - if err != nil { - return err - } + artifacts.Deobfuscate(config_obj, response) // Store the event log in the client's VFS. if response.Query.Name != "" { diff --git a/paths/client.go b/paths/client.go index afc13c6941a..9c2ae376a65 100644 --- a/paths/client.go +++ b/paths/client.go @@ -6,6 +6,7 @@ import ( "path" "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/utils" ) type ClientPathManager struct { @@ -65,3 +66,8 @@ func (self ClientPathManager) Task(task_id uint64) *ClientPathManager { self.path = path.Join(self.path, "tasks", fmt.Sprintf("%d", task_id)) return &self } + +func (self ClientPathManager) VFSPath(vfs_components []string) string { + return utils.JoinComponents(append([]string{ + "clients", self.client_id, "vfs"}, vfs_components...), "/") +} diff --git a/paths/flow_metadata.go b/paths/flow_metadata.go index 9a9101c75d0..480e555603c 100644 --- a/paths/flow_metadata.go +++ b/paths/flow_metadata.go @@ -18,6 +18,10 @@ func (self FlowPathManager) Path() string { return self.path } +func (self FlowPathManager) ContainerPath() string { + return path.Join("/clients", self.client_id, "collections") +} + func (self FlowPathManager) GetPathForWriting() (string, error) { return self.path, nil } diff --git a/server/comms.go b/server/comms.go index efd435f0ef4..e4805b330e4 100644 --- a/server/comms.go +++ b/server/comms.go @@ -357,12 +357,14 @@ func control(server_obj *Server) http.Handler { // can not encrypt for it), we // indicate this by providing it with // an HTTP error code. + logger.Debug("Please Enrol (%v)", message_info.Source) http.Error( w, "Please Enrol", http.StatusNotAcceptable) } else { server_obj.Error("Unable to process", err) + logger.Debug("Unable to process (%v)", message_info.Source) http.Error(w, "", http.StatusServiceUnavailable) } return diff --git a/server/enroll.go b/server/enroll.go index f4a40393ed9..91d5fddaacf 100644 --- a/server/enroll.go +++ b/server/enroll.go @@ -20,33 +20,32 @@ package server import ( "context" - "www.velocidex.com/golang/velociraptor/constants" + "github.com/Velocidex/ordereddict" crypto_proto "www.velocidex.com/golang/velociraptor/crypto/proto" - "www.velocidex.com/golang/velociraptor/flows" - flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" + "www.velocidex.com/golang/velociraptor/logging" + "www.velocidex.com/golang/velociraptor/result_sets" + "www.velocidex.com/golang/velociraptor/services" ) func enroll( ctx context.Context, server *Server, csr *crypto_proto.Certificate) error { - if csr.GetType() == crypto_proto.Certificate_CSR && csr.Pem != nil { - client_id, err := server.manager.AddCertificateRequest(csr.Pem) - if err != nil { - return err - } - - // Schedule a collection automatically. - _, err = flows.ScheduleArtifactCollection(server.config, - server.config.Client.PinnedServerName, - &flows_proto.ArtifactCollectorArgs{ - ClientId: client_id, - Artifacts: []string{constants.CLIENT_INFO_ARTIFACT}, - }) - if err != nil { - return err - } + + if csr.GetType() != crypto_proto.Certificate_CSR || csr.Pem == nil { + return nil + } + + client_id, err := server.manager.AddCertificateRequest(csr.Pem) + if err != nil { + logger := logging.GetLogger(server.config, &logging.FrontendComponent) + logger.Error("While enrolling %v: %v", client_id, err) + return err } - return nil + path_manager := result_sets.NewArtifactPathManager( + server.config, "server" /* client_id */, "", "Server.Internal.Enrollment") + + return services.GetJournal().PushRows(path_manager, + []*ordereddict.Dict{ordereddict.NewDict().Set("ClientId", client_id)}) } diff --git a/server/server_test.go b/server/server_test.go index b67cbfdff63..fad0e98b4b2 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/Velocidex/ordereddict" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -17,20 +18,19 @@ import ( api_mock "www.velocidex.com/golang/velociraptor/api/mock" api_proto "www.velocidex.com/golang/velociraptor/api/proto" "www.velocidex.com/golang/velociraptor/artifacts" - "www.velocidex.com/golang/velociraptor/config" config_proto "www.velocidex.com/golang/velociraptor/config/proto" "www.velocidex.com/golang/velociraptor/constants" "www.velocidex.com/golang/velociraptor/crypto" crypto_proto "www.velocidex.com/golang/velociraptor/crypto/proto" "www.velocidex.com/golang/velociraptor/datastore" - "www.velocidex.com/golang/velociraptor/file_store" - "www.velocidex.com/golang/velociraptor/file_store/memory" + "www.velocidex.com/golang/velociraptor/file_store/test_utils" "www.velocidex.com/golang/velociraptor/flows" flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" "www.velocidex.com/golang/velociraptor/paths" "www.velocidex.com/golang/velociraptor/result_sets" "www.velocidex.com/golang/velociraptor/server" "www.velocidex.com/golang/velociraptor/services" + "www.velocidex.com/golang/velociraptor/vtesting" ) type ServerTestSuite struct { @@ -54,24 +54,8 @@ func (self MockAPIClientFactory) GetAPIClient( } -func (self *ServerTestSuite) GetMemoryFileStore() *memory.MemoryFileStore { - file_store_factory, ok := file_store.GetFileStore( - self.config_obj).(*memory.MemoryFileStore) - require.True(self.T(), ok) - - return file_store_factory -} - func (self *ServerTestSuite) SetupTest() { - config_obj, err := config.LoadConfig( - "../http_comms/test_data/server.config.yaml") - require.NoError(self.T(), err) - - require.NoError(self.T(), config.ValidateFrontendConfig(config_obj)) - - self.config_obj = config_obj - self.config_obj.Datastore.Implementation = "Test" - self.config_obj.Frontend.DoNotCompressArtifacts = true + self.config_obj = vtesting.GetTestConfig(self.T()) ctx, cancel := context.WithCancel(context.Background()) self.cancel = cancel @@ -80,17 +64,18 @@ func (self *ServerTestSuite) SetupTest() { // Start the journaling service manually for tests. services.StartJournalService(self.config_obj) services.StartNotificationService(ctx, self.wg, self.config_obj) - artifacts.GetGlobalRepository(config_obj) + artifacts.GetGlobalRepository(self.config_obj) - self.server, err = server.NewServer(config_obj) + var err error + self.server, err = server.NewServer(self.config_obj) require.NoError(self.T(), err) self.client_crypto, err = crypto.NewClientCryptoManager( - config_obj, []byte(config_obj.Writeback.PrivateKey)) + self.config_obj, []byte(self.config_obj.Writeback.PrivateKey)) require.NoError(self.T(), err) _, err = self.client_crypto.AddCertificate([]byte( - config_obj.Frontend.Certificate)) + self.config_obj.Frontend.Certificate)) require.NoError(self.T(), err) @@ -104,7 +89,7 @@ func (self *ServerTestSuite) TearDownTest() { db.Close() self.cancel() - self.GetMemoryFileStore().Clear() + test_utils.GetMemoryFileStore(self.T(), self.config_obj).Clear() self.wg.Wait() } @@ -114,6 +99,13 @@ func (self *ServerTestSuite) TestEnrollment() { csr_message, err := self.client_crypto.GetCSR() require.NoError(self.T(), err) + wg := &sync.WaitGroup{} + messages := []*ordereddict.Dict{} + + wg.Add(1) + services.GetPublishedEvents( + self.config_obj, "Server.Internal.Enrollment", wg, 1, &messages) + self.server.ProcessSingleUnauthenticatedMessage( context.Background(), &crypto_proto.GrrMessage{ @@ -132,15 +124,14 @@ func (self *ServerTestSuite) TestEnrollment() { assert.Regexp(self.T(), "RSA PUBLIC KEY", string(pub_key.Pem)) - // Check that Generic.Client.Info artifact is scheduled for this client. - tasks, err := db.GetClientTasks(self.config_obj, self.client_id, - true /* do_not_lease */) - assert.NoError(self.T(), err) - assert.Equal(self.T(), len(tasks), 1) - queries := tasks[0].VQLClientAction.Query + wg.Wait() - assert.NotNil(self.T(), queries) - assert.Contains(self.T(), queries[len(queries)-1].Name, "Generic.Client.Info") + // Check that Server.Internal.Enrollment is scheduled for this + // client. The entrollment service will respond to this + // message. + client_id, pres := messages[0].GetString("ClientId") + assert.True(self.T(), pres) + assert.Equal(self.T(), client_id, self.client_id) } func (self *ServerTestSuite) TestClientEventTable() { @@ -294,7 +285,7 @@ func (self *ServerTestSuite) TestForeman() { } func (self *ServerTestSuite) RequiredFilestoreContains(filename string, regex string) { - file_store_factory := self.GetMemoryFileStore() + file_store_factory := test_utils.GetMemoryFileStore(self.T(), self.config_obj) value, pres := file_store_factory.Get(filename) if !pres { @@ -485,7 +476,7 @@ func (self *ServerTestSuite) TestScheduleCollection() { Artifacts: []string{"Generic.Client.Info"}, } - flow_id, err := flows.ScheduleArtifactCollection( + flow_id, err := artifacts.ScheduleArtifactCollection( self.config_obj, self.config_obj.Client.PinnedServerName, request) @@ -511,7 +502,7 @@ func (self *ServerTestSuite) TestScheduleCollection() { // Schedule a flow in the database and return its flow id func (self *ServerTestSuite) createArtifactCollection() (string, error) { // Schedule a flow in the database. - flow_id, err := flows.ScheduleArtifactCollection( + flow_id, err := artifacts.ScheduleArtifactCollection( self.config_obj, self.config_obj.Client.PinnedServerName, &flows_proto.ArtifactCollectorArgs{ diff --git a/services/hunt_manager_test.go b/services/hunt_manager_test.go index 533dcd977c7..48cbc2b6380 100644 --- a/services/hunt_manager_test.go +++ b/services/hunt_manager_test.go @@ -23,6 +23,7 @@ import ( flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" "www.velocidex.com/golang/velociraptor/paths" "www.velocidex.com/golang/velociraptor/result_sets" + "www.velocidex.com/golang/velociraptor/vtesting" ) type HuntTestSuite struct { @@ -116,13 +117,12 @@ func (self *HuntTestSuite) TestHuntManager() { Set("Fqdn", "MyHost"). Set("Participate", true)}) - // Make sure manager reacted. - time.Sleep(1 * time.Second) - - // The hunt index is updated. - err = db.CheckIndex(self.config_obj, constants.HUNT_INDEX, - self.client_id, []string{hunt_obj.HuntId}) - assert.NoError(t, err) + vtesting.WaitUntil(2*time.Second, self.T(), func() bool { + // The hunt index is updated. + err = db.CheckIndex(self.config_obj, constants.HUNT_INDEX, + self.client_id, []string{hunt_obj.HuntId}) + return err == nil + }) } func (self *HuntTestSuite) TestHuntWithLabelClientNoLabel() { @@ -173,14 +173,13 @@ func (self *HuntTestSuite) TestHuntWithLabelClientNoLabel() { Set("Fqdn", "MyHost"). Set("Participate", true)}) - // Make sure manager reacted. - time.Sleep(1 * time.Second) - - // The hunt index is updated since we have seen this client - // already (even if we decided not to launch on it). - err = db.CheckIndex(self.config_obj, constants.HUNT_INDEX, - self.client_id, []string{hunt_obj.HuntId}) - assert.NoError(t, err) + vtesting.WaitUntil(2*time.Second, self.T(), func() bool { + // The hunt index is updated since we have seen this client + // already (even if we decided not to launch on it). + err = db.CheckIndex(self.config_obj, constants.HUNT_INDEX, + self.client_id, []string{hunt_obj.HuntId}) + return err == nil + }) } func (self *HuntTestSuite) TestHuntWithLabelClientHasLabelDifferentCase() { @@ -246,14 +245,13 @@ func (self *HuntTestSuite) TestHuntWithLabelClientHasLabelDifferentCase() { Set("Fqdn", "MyHost"). Set("Participate", true)}) - // Make sure manager reacted. - time.Sleep(1 * time.Second) - - // The hunt index is updated since we have seen this client - // already (even if we decided not to launch on it). - err = db.CheckIndex(self.config_obj, constants.HUNT_INDEX, - self.client_id, []string{hunt_obj.HuntId}) - assert.NoError(t, err) + vtesting.WaitUntil(2*time.Second, self.T(), func() bool { + // The hunt index is updated since we have seen this client + // already (even if we decided not to launch on it). + err = db.CheckIndex(self.config_obj, constants.HUNT_INDEX, + self.client_id, []string{hunt_obj.HuntId}) + return err == nil + }) } func (self *HuntTestSuite) TestHuntWithLabelClientHasLabel() { @@ -319,14 +317,13 @@ func (self *HuntTestSuite) TestHuntWithLabelClientHasLabel() { Set("Fqdn", "MyHost"). Set("Participate", true)}) - // Make sure manager reacted. - time.Sleep(1 * time.Second) - - // The hunt index is updated since we have seen this client - // already (even if we decided not to launch on it). - err = db.CheckIndex(self.config_obj, constants.HUNT_INDEX, - self.client_id, []string{hunt_obj.HuntId}) - assert.NoError(t, err) + vtesting.WaitUntil(2*time.Second, self.T(), func() bool { + // The hunt index is updated since we have seen this client + // already (even if we decided not to launch on it). + err = db.CheckIndex(self.config_obj, constants.HUNT_INDEX, + self.client_id, []string{hunt_obj.HuntId}) + return err == nil + }) } func TestHuntTestSuite(t *testing.T) { diff --git a/services/interrogation.go b/services/interrogation.go index ffd15f1fa83..4e0e63a8920 100644 --- a/services/interrogation.go +++ b/services/interrogation.go @@ -2,6 +2,7 @@ package services import ( "context" + "fmt" "sync" "github.com/Velocidex/ordereddict" @@ -13,15 +14,16 @@ import ( config_proto "www.velocidex.com/golang/velociraptor/config/proto" "www.velocidex.com/golang/velociraptor/constants" "www.velocidex.com/golang/velociraptor/datastore" + "www.velocidex.com/golang/velociraptor/file_store" + flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" "www.velocidex.com/golang/velociraptor/grpc_client" "www.velocidex.com/golang/velociraptor/logging" "www.velocidex.com/golang/velociraptor/paths" - vql_subsystem "www.velocidex.com/golang/velociraptor/vql" + "www.velocidex.com/golang/velociraptor/result_sets" "www.velocidex.com/golang/vfilter" ) -// Watch the system's flow completion log for interrogate artifacts. -type InterrogationService struct { +type EnrollmentService struct { mu sync.Mutex APIClientFactory grpc_client.APIClientFactory @@ -29,65 +31,172 @@ type InterrogationService struct { cancel func() } -func (self *InterrogationService) Start( +func (self *EnrollmentService) Start( ctx context.Context, wg *sync.WaitGroup) error { - defer wg.Done() + wg.Add(1) - self.mu.Lock() - defer self.mu.Unlock() + // Wait in this func until we are ready to monitor. + local_wg := &sync.WaitGroup{} + local_wg.Add(1) - logger := logging.GetLogger(self.config_obj, &logging.FrontendComponent) - logger.Info("Starting interrogation service.") + go func() { + defer wg.Done() - scope := artifacts.ScopeBuilder{ - Config: self.config_obj, - ACLManager: vql_subsystem.NewRoleACLManager("administrator"), - }.Build() - defer scope.Close() + self.mu.Lock() + defer self.mu.Unlock() - scope.Logger = logging.NewPlainLogger(self.config_obj, - &logging.FrontendComponent) + logger := logging.GetLogger(self.config_obj, &logging.FrontendComponent) + logger.Info("Starting Enrollment service.") - vql, _ := vfilter.Parse("SELECT * FROM Artifact.Server.Internal.Interrogate()") - go func() { - for row := range vql.Eval(ctx, scope) { - row_dict := vfilter.RowToDict(ctx, scope, row) - err := self.ProcessRow(row_dict) - if err != nil { - logger.Error("Interrogation Service: %v", err) + events, cancel := GetJournal().Watch("Server.Internal.Enrollment") + defer cancel() + + local_wg.Done() + + for { + select { + case <-ctx.Done(): + return + + case event, ok := <-events: + if !ok { + return + } + err := self.ProcessRow(ctx, event) + if err != nil { + logger.Error("Enrollment Service: %v", err) + } } } }() + local_wg.Wait() + return nil } -func (self *InterrogationService) ProcessRow(row *ordereddict.Dict) error { - client_id, ok := row.GetString("ClientId") - if !ok { +func (self *EnrollmentService) ProcessRow( + ctx context.Context, + row *ordereddict.Dict) error { + client_id, pres := row.GetString("ClientId") + if !pres { + return nil + } + + // Get the client record from the data store. + db, err := datastore.GetDB(self.config_obj) + if err != nil { + return err + } + + client_info := &actions_proto.ClientInfo{} + client_path_manager := paths.NewClientPathManager(client_id) + + db.GetSubject(self.config_obj, client_path_manager.Path(), client_info) + + // If we have a valid client record we do not need to + // interrogate. Interrogation happens automatically only once + // - the first time a client appears. + if client_info.ClientId == client_id || + len(client_info.Hostname) > 0 { + return nil + } + + logger := logging.GetLogger(self.config_obj, &logging.FrontendComponent) + logger.Debug("Interrogating %v", client_id) + + // Issue the flow on the client. + flow_id, err := artifacts.ScheduleArtifactCollection(self.config_obj, + self.config_obj.Client.PinnedServerName, /* principal */ + &flows_proto.ArtifactCollectorArgs{ + ClientId: client_id, + Artifacts: []string{constants.CLIENT_INFO_ARTIFACT}, + }) + if err != nil { + return err + } + + // Write an intermediate record while the interrogation is in flight. + client_info.ClientId = client_id + client_info.LastInterrogateFlowId = flow_id + err = db.SetSubject(self.config_obj, client_path_manager.Path(), client_info) + + return err +} + +// Watch the system's flow completion log for interrogate artifacts. +type InterrogationService struct { + mu sync.Mutex + + APIClientFactory grpc_client.APIClientFactory + config_obj *config_proto.Config + cancel func() +} + +// Watch for Generic.Client.Info artifacts. +func (self *InterrogationService) Start( + ctx context.Context, + wg *sync.WaitGroup) error { + + logger := logging.GetLogger(self.config_obj, &logging.FrontendComponent) + + watchForFlowCompletion( + ctx, wg, self.config_obj, "Generic.Client.Info", + func(ctx context.Context, scope *vfilter.Scope, row *ordereddict.Dict) { + err := self.ProcessRow(ctx, scope, row) + if err != nil { + logger.Error(fmt.Sprintf("InterrogationService: %v", err)) + } + }) + + return nil +} + +func (self *InterrogationService) ProcessRow( + ctx context.Context, scope *vfilter.Scope, row *ordereddict.Dict) error { + client_id, _ := row.GetString("ClientId") + if client_id == "" { return errors.New("Unknown ClientId") } - getter := func(field string) string { - result, _ := row.GetString(field) - return result + flow_id, _ := row.GetString("FlowId") + + path_manager := result_sets.NewArtifactPathManager(self.config_obj, + client_id, flow_id, "Generic.Client.Info") + row_chan, err := file_store.GetTimeRange( + ctx, self.config_obj, path_manager, 0, 0) + if err != nil { + return err } - client_info := &actions_proto.ClientInfo{ - Hostname: getter("Hostname"), - System: getter("OS"), - Release: getter("Platform") + getter("PlatformVersion"), - Architecture: getter("Architecture"), - Fqdn: getter("Fqdn"), - ClientName: getter("Name"), - ClientVersion: getter("BuildTime"), - LastInterrogateFlowId: getter("FlowId"), + var client_info *actions_proto.ClientInfo + for row := range row_chan { + getter := func(field string) string { + result, _ := row.GetString(field) + return result + } + + client_info = &actions_proto.ClientInfo{ + ClientId: client_id, + Hostname: getter("Hostname"), + System: getter("OS"), + Release: getter("Platform") + getter("PlatformVersion"), + Architecture: getter("Architecture"), + Fqdn: getter("Fqdn"), + ClientName: getter("Name"), + ClientVersion: getter("BuildTime"), + LastInterrogateFlowId: flow_id, + } + + label_array, ok := row.GetStrings("Labels") + if ok { + client_info.Labels = append(client_info.Labels, label_array...) + } } - label_array, ok := row.GetStrings("Labels") - if ok { - client_info.Labels = append(client_info.Labels, label_array...) + if client_info == nil { + return errors.New("No Generic.Client.Info results") } client_path_manager := paths.NewClientPathManager(client_id) @@ -135,11 +244,17 @@ func startInterrogationService( ctx context.Context, wg *sync.WaitGroup, config_obj *config_proto.Config) { + + enrollment_server := &EnrollmentService{ + config_obj: config_obj, + APIClientFactory: grpc_client.GRPCAPIClient{}, + } + enrollment_server.Start(ctx, wg) + result := &InterrogationService{ config_obj: config_obj, APIClientFactory: grpc_client.GRPCAPIClient{}, } - wg.Add(1) - go result.Start(ctx, wg) + result.Start(ctx, wg) } diff --git a/services/interrogation_test.go b/services/interrogation_test.go new file mode 100644 index 00000000000..736a4d37501 --- /dev/null +++ b/services/interrogation_test.go @@ -0,0 +1,165 @@ +package services + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/Velocidex/ordereddict" + "github.com/alecthomas/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + actions_proto "www.velocidex.com/golang/velociraptor/actions/proto" + config_proto "www.velocidex.com/golang/velociraptor/config/proto" + "www.velocidex.com/golang/velociraptor/datastore" + "www.velocidex.com/golang/velociraptor/file_store/test_utils" + flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" + "www.velocidex.com/golang/velociraptor/paths" + "www.velocidex.com/golang/velociraptor/result_sets" + "www.velocidex.com/golang/velociraptor/vtesting" +) + +type BaseServicesTestSuite struct { + suite.Suite + config_obj *config_proto.Config + cancel func() + wg *sync.WaitGroup + client_id string + flow_id string +} + +func (self *BaseServicesTestSuite) SetupTest() { + self.config_obj = vtesting.GetTestConfig(self.T()) + + ctx, cancel := context.WithCancel(context.Background()) + self.cancel = cancel + self.wg = &sync.WaitGroup{} + + // Start the journaling service manually for tests. + StartJournalService(self.config_obj) + startInterrogationService(ctx, self.wg, self.config_obj) + StartNotificationService(ctx, self.wg, self.config_obj) + startVFSService(ctx, self.wg, self.config_obj) + + self.client_id = "C.12312" + self.flow_id = "F.1232" +} + +func (self *BaseServicesTestSuite) TearDownTest() { + // Reset the data store. + db, err := datastore.GetDB(self.config_obj) + require.NoError(self.T(), err) + + db.Close() + self.cancel() + test_utils.GetMemoryFileStore(self.T(), self.config_obj).Clear() + self.wg.Wait() +} + +func (self *BaseServicesTestSuite) EmulateCollection( + artifact string, rows []*ordereddict.Dict) string { + + // Emulate a Generic.Client.Info collection: First write the + // result set, then write the collection context. + artifact_path_manager := result_sets.NewArtifactPathManager( + self.config_obj, self.client_id, self.flow_id, artifact) + + // Write a result set for this artifact. + GetJournal().PushRows(artifact_path_manager, rows) + + // Emulate a flow completion message coming from the flow processor. + artifact_path_manager = result_sets.NewArtifactPathManager( + self.config_obj, "server", "", "System.Flow.Completion") + + GetJournal().PushRows(artifact_path_manager, + []*ordereddict.Dict{ordereddict.NewDict(). + Set("ClientId", self.client_id). + Set("FlowId", self.flow_id). + Set("Flow", &flows_proto.ArtifactCollectorContext{ + ClientId: self.client_id, + SessionId: self.flow_id, + ArtifactsWithResults: []string{artifact}})}) + return self.flow_id +} + +type ServicesTestSuite struct { + BaseServicesTestSuite +} + +func (self *ServicesTestSuite) TestInterrogationService() { + hostname := "MyHost" + flow_id := self.EmulateCollection( + "Generic.Client.Info", []*ordereddict.Dict{ + ordereddict.NewDict(). + Set("ClientId", self.client_id). + Set("Hostname", hostname), + }) + + // Wait here until the client is fully interrogated + db, err := datastore.GetDB(self.config_obj) + assert.NoError(self.T(), err) + + client_path_manager := paths.NewClientPathManager(self.client_id) + client_info := &actions_proto.ClientInfo{} + + vtesting.WaitUntil(2*time.Second, self.T(), func() bool { + db.GetSubject(self.config_obj, client_path_manager.Path(), client_info) + return client_info.Hostname == hostname + }) + + // Check that we record the last flow id. + assert.Equal(self.T(), client_info.LastInterrogateFlowId, flow_id) +} + +func (self *ServicesTestSuite) TestEnrollService() { + enroll_message := ordereddict.NewDict().Set("ClientId", self.client_id) + + db, err := datastore.GetDB(self.config_obj) + assert.NoError(self.T(), err) + + client_path_manager := paths.NewClientPathManager(self.client_id) + client_info := &actions_proto.ClientInfo{} + db.GetSubject(self.config_obj, client_path_manager.Path(), client_info) + + assert.Equal(self.T(), client_info.ClientId, "") + + // Push many enroll_messages to the internal queue - this will + // trigger the enrollment service to enrolling this client. + + // When the system is loaded it may be that multiple + // enrollment messages are being written before the client is + // able to be enrolled. We should always generate only a + // single interrogate flow if the client is not known. + path_manager := result_sets.NewArtifactPathManager( + self.config_obj, "server" /* client_id */, "", "Server.Internal.Enrollment") + + err = GetJournal().PushRows(path_manager, []*ordereddict.Dict{ + enroll_message, enroll_message, enroll_message, enroll_message}) + assert.NoError(self.T(), err) + + // Wait here until the client is enrolled + vtesting.WaitUntil(2*time.Second, self.T(), func() bool { + db.GetSubject(self.config_obj, client_path_manager.Path(), client_info) + return client_info.ClientId == self.client_id + }) + + // Check that a collection is scheduled. + flow_path_manager := paths.NewFlowPathManager(self.client_id, + client_info.LastInterrogateFlowId) + collection_context := &flows_proto.ArtifactCollectorContext{} + err = db.GetSubject(self.config_obj, flow_path_manager.Path(), collection_context) + assert.Equal(self.T(), collection_context.Request.Artifacts, + []string{"Generic.Client.Info"}) + + // Make sure only one flow is generated + children, err := db.ListChildren( + self.config_obj, flow_path_manager.ContainerPath(), 0, 100) + assert.NoError(self.T(), err) + assert.Equal(self.T(), children, + []string{client_info.LastInterrogateFlowId}) +} + +func TestInterrogationService(t *testing.T) { + suite.Run(t, &ServicesTestSuite{BaseServicesTestSuite{}}) +} diff --git a/services/notfications.go b/services/notfications.go index ada2abd96c4..27b72ccd102 100644 --- a/services/notfications.go +++ b/services/notfications.go @@ -126,5 +126,9 @@ func IsClientConnected(client_id string) bool { pool_mu.Lock() defer pool_mu.Unlock() + if notification_pool == nil { + notification_pool = notifications.NewNotificationPool() + } + return notification_pool.IsClientConnected(client_id) } diff --git a/services/test_utils.go b/services/test_utils.go new file mode 100644 index 00000000000..2ef49d7246d --- /dev/null +++ b/services/test_utils.go @@ -0,0 +1,42 @@ +package services + +import ( + "sync" + + "github.com/Velocidex/ordereddict" + config_proto "www.velocidex.com/golang/velociraptor/config/proto" +) + +// Helpers for testing the filestore. + +// Read num_rows messages from the filestore queues and fill in the +// result array. +func GetPublishedEvents( + config_obj *config_proto.Config, + artifact string, + wg *sync.WaitGroup, + num_rows int, + result *[]*ordereddict.Dict) { + + local_wg := &sync.WaitGroup{} + local_wg.Add(1) + + go func() { + defer wg.Done() + + events, cancel := GetJournal().Watch(artifact) + defer cancel() + + // Wait here until we are set up. + local_wg.Done() + + for row := range events { + *result = append(*result, row) + if len(*result) == num_rows { + return + } + } + }() + + local_wg.Wait() +} diff --git a/services/utils.go b/services/utils.go index 07892f5382f..821e9134345 100644 --- a/services/utils.go +++ b/services/utils.go @@ -7,13 +7,14 @@ import ( "github.com/Velocidex/ordereddict" "www.velocidex.com/golang/velociraptor/artifacts" config_proto "www.velocidex.com/golang/velociraptor/config/proto" + flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" "www.velocidex.com/golang/velociraptor/logging" "www.velocidex.com/golang/velociraptor/utils" vql_subsystem "www.velocidex.com/golang/velociraptor/vql" "www.velocidex.com/golang/vfilter" ) -// Watch the System.Flow.Completion queue for a specific artifacts and +// Watch the System.Flow.Completion queue for specific artifacts and // run the handlers on the rows. func watchForFlowCompletion( ctx context.Context, @@ -21,37 +22,65 @@ func watchForFlowCompletion( config_obj *config_proto.Config, artifact_name string, handler func(ctx context.Context, - scope *vfilter.Scope, row vfilter.Row)) error { - - builder := artifacts.ScopeBuilder{ - Config: config_obj, - ACLManager: vql_subsystem.NewRoleACLManager("administrator"), - Env: ordereddict.NewDict(). - Set("artifact_name", artifact_name), - Logger: logging.NewPlainLogger(config_obj, - &logging.FrontendComponent), - } - - scope := builder.Build() - defer scope.Close() - - vql, err := vfilter.Parse("select * FROM " + - "watch_monitoring(artifact='System.Flow.Completion') " + - "WHERE Flow.artifacts_with_results =~ artifact_name") - if err != nil { - return err - } + scope *vfilter.Scope, row *ordereddict.Dict)) error { + + local_wg := &sync.WaitGroup{} + local_wg.Add(1) wg.Add(1) + go func() { defer wg.Done() - defer utils.CheckForPanic("watchForFlowCompletion: %v", artifact_name) + builder := artifacts.ScopeBuilder{ + Config: config_obj, + ACLManager: vql_subsystem.NewRoleACLManager("administrator"), + Env: ordereddict.NewDict(). + Set("artifact_name", artifact_name), + Logger: logging.NewPlainLogger(config_obj, + &logging.FrontendComponent), + } + + scope := builder.Build() + defer scope.Close() + + // Allow the artifact we are following to be over-ridden by + // the user. + custom_artifact_name := "Custom." + artifact_name + + events, cancel := GetJournal().Watch("System.Flow.Completion") + defer cancel() - for row := range vql.Eval(ctx, scope) { - handler(ctx, scope, row) + local_wg.Done() + + for { + select { + case <-ctx.Done(): + return + + case event, ok := <-events: + if !ok { + return + } + flow_any, pres := event.Get("Flow") + if !pres { + continue + } + + flow, ok := flow_any.(*flows_proto.ArtifactCollectorContext) + if !ok { + continue + } + + if utils.InString(flow.ArtifactsWithResults, artifact_name) || + utils.InString(flow.ArtifactsWithResults, custom_artifact_name) { + handler(ctx, scope, event) + } + } } }() + local_wg.Wait() + return nil } diff --git a/services/vfs_service.go b/services/vfs_service.go index bd03b9cd95a..c591fdeabf4 100644 --- a/services/vfs_service.go +++ b/services/vfs_service.go @@ -11,6 +11,7 @@ import ( "encoding/json" "sync" + "github.com/Velocidex/ordereddict" "github.com/pkg/errors" config_proto "www.velocidex.com/golang/velociraptor/config/proto" "www.velocidex.com/golang/velociraptor/datastore" @@ -18,6 +19,7 @@ import ( flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" "www.velocidex.com/golang/velociraptor/logging" "www.velocidex.com/golang/velociraptor/paths" + "www.velocidex.com/golang/velociraptor/result_sets" "www.velocidex.com/golang/velociraptor/utils" vql_subsystem "www.velocidex.com/golang/velociraptor/vql" "www.velocidex.com/golang/vfilter" @@ -35,55 +37,40 @@ func (self *VFSService) Start( wg *sync.WaitGroup) error { self.logger.Info("Starting VFS writing service.") - err := watchForFlowCompletion( + watchForFlowCompletion( ctx, wg, self.config_obj, "System.VFS.ListDirectory", self.ProcessListDirectory) - if err != nil { - return err - } - err = watchForFlowCompletion( + watchForFlowCompletion( ctx, wg, self.config_obj, "System.VFS.DownloadFile", self.ProcessDownloadFile) - if err != nil { - return err - } return nil } func (self *VFSService) ProcessDownloadFile( - ctx context.Context, scope *vfilter.Scope, row vfilter.Row) { + ctx context.Context, scope *vfilter.Scope, row *ordereddict.Dict) { defer utils.CheckForPanic("ProcessDownloadFile") - client_id := vql_subsystem.GetStringFromRow(scope, row, "ClientId") - flow_id := vql_subsystem.GetStringFromRow(scope, row, "FlowId") - ts := vql_subsystem.GetIntFromRow(scope, row, "_ts") + client_id, _ := row.GetString("ClientId") + flow_id, _ := row.GetString("FlowId") + ts, _ := row.GetInt64("_ts") - // We need to run a query referring to the row. - sub_scope := scope.Copy() - sub_scope.AppendVars(row) - - vql, err := vfilter.Parse( - "select Path, Accessor, Size FROM source(" + - "flow_id=FlowId, " + - "artifact='System.VFS.DownloadFile', " + - "client_id=ClientId)") - if err != nil { - panic(err) - } + flow_path_manager := paths.NewFlowPathManager(client_id, flow_id) - db, err := datastore.GetDB(self.config_obj) + path_manager := result_sets.NewArtifactPathManager(self.config_obj, + client_id, flow_id, "System.VFS.DownloadFile") + row_chan, err := file_store.GetTimeRange( + ctx, self.config_obj, path_manager, 0, 0) if err != nil { - panic(err) + self.logger.Error("Unable to read artifact: %v", err) + return } - flow_path_manager := paths.NewFlowPathManager(client_id, flow_id) - - for row := range vql.Eval(ctx, sub_scope) { - Accessor := vql_subsystem.GetStringFromRow(scope, row, "Accessor") - Path := vql_subsystem.GetStringFromRow(scope, row, "Path") + for row := range row_chan { + Accessor, _ := row.GetString("Accessor") + Path, _ := row.GetString("Path") // Figure out where the file was uploaded to. vfs_path := flow_path_manager.GetUploadsFile(Accessor, Path).Path() @@ -98,6 +85,7 @@ func (self *VFSService) ProcessDownloadFile( // We store a place holder in the VFS pointing at the // read vfs_path of the download. + db, _ := datastore.GetDB(self.config_obj) err = db.SetSubject(self.config_obj, flow_path_manager.GetVFSDownloadInfoPath(Accessor, Path).Path(), &flows_proto.VFSDownloadInfo{ @@ -112,30 +100,29 @@ func (self *VFSService) ProcessDownloadFile( } func (self *VFSService) ProcessListDirectory( - ctx context.Context, scope *vfilter.Scope, row vfilter.Row) { + ctx context.Context, scope *vfilter.Scope, row *ordereddict.Dict) { - client_id := vql_subsystem.GetStringFromRow(scope, row, "ClientId") - flow_id := vql_subsystem.GetStringFromRow(scope, row, "FlowId") - ts := vql_subsystem.GetIntFromRow(scope, row, "_ts") + client_id, _ := row.GetString("ClientId") + flow_id, _ := row.GetString("FlowId") + ts, _ := row.GetInt64("_ts") - // We need to run a query referring to the row. - sub_scope := scope.Copy() - sub_scope.AppendVars(row) + path_manager := result_sets.NewArtifactPathManager(self.config_obj, + client_id, flow_id, "System.VFS.ListDirectory") - vql, err := vfilter.Parse("select * FROM " + - "source(artifact='System.VFS.ListDirectory', " + - "flow_id=FlowId, client_id=ClientId)") + row_chan, err := file_store.GetTimeRange( + ctx, self.config_obj, path_manager, 0, 0) if err != nil { - panic(err) + self.logger.Error("Unable to read artifact: %v", err) + return } - var rows []vfilter.Row + var rows []*ordereddict.Dict var current_vfs_components []string = nil - for row := range vql.Eval(ctx, sub_scope) { - full_path := vql_subsystem.GetStringFromRow(scope, row, "_FullPath") - accessor := vql_subsystem.GetStringFromRow(scope, row, "_Accessor") - name := vql_subsystem.GetStringFromRow(scope, row, "Name") + for row := range row_chan { + full_path, _ := row.GetString("_FullPath") + accessor, _ := row.GetString("_Accessor") + name, _ := row.GetString("Name") if name == "." || name == ".." { continue @@ -162,10 +149,8 @@ func (self *VFSService) ProcessListDirectory( // the first collection before the first row // is processed. if current_vfs_components != nil { - err := self.flush_state( - sub_scope, ts, client_id, - flow_id, - current_vfs_components, rows) + err := self.flush_state(uint64(ts), client_id, + flow_id, current_vfs_components, rows) if err != nil { return } @@ -176,7 +161,7 @@ func (self *VFSService) ProcessListDirectory( rows = append(rows, row) } - err = self.flush_state(sub_scope, ts, client_id, flow_id, + err = self.flush_state(uint64(ts), client_id, flow_id, current_vfs_components, rows) if err != nil { self.logger.Error("Unable to save directory: %v", err) @@ -185,9 +170,8 @@ func (self *VFSService) ProcessListDirectory( } // Flush the current state into the database and clear it for the next directory. -func (self *VFSService) flush_state(scope *vfilter.Scope, - timestamp uint64, client_id, flow_id string, - vfs_components []string, rows []vfilter.Row) error { +func (self *VFSService) flush_state(timestamp uint64, client_id, flow_id string, + vfs_components []string, rows []*ordereddict.Dict) error { if len(rows) == 0 { return nil } @@ -197,16 +181,15 @@ func (self *VFSService) flush_state(scope *vfilter.Scope, return errors.WithStack(err) } - urn := utils.JoinComponents(append([]string{ - "clients", client_id, "vfs"}, vfs_components...), "/") - db, err := datastore.GetDB(self.config_obj) if err != nil { return err } + client_path_manager := paths.NewClientPathManager(client_id) return db.SetSubject(self.config_obj, - urn, &flows_proto.VFSListResponse{ - Columns: scope.GetMembers(rows[0]), + client_path_manager.VFSPath(vfs_components), + &flows_proto.VFSListResponse{ + Columns: rows[0].Keys(), Timestamp: timestamp, Response: string(serialized), TotalRows: uint64(len(rows)), diff --git a/services/vfs_service_test.go b/services/vfs_service_test.go new file mode 100644 index 00000000000..d7e0ca9d7a6 --- /dev/null +++ b/services/vfs_service_test.go @@ -0,0 +1,146 @@ +package services + +import ( + "path" + "testing" + "time" + + "github.com/Velocidex/ordereddict" + "github.com/alecthomas/assert" + "github.com/stretchr/testify/suite" + "www.velocidex.com/golang/velociraptor/datastore" + "www.velocidex.com/golang/velociraptor/flows/proto" + flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" + "www.velocidex.com/golang/velociraptor/paths" + "www.velocidex.com/golang/velociraptor/utils" + "www.velocidex.com/golang/velociraptor/vtesting" +) + +type VFSServiceTestSuite struct { + BaseServicesTestSuite +} + +func (self *VFSServiceTestSuite) TestVFSListDirectory() { + self.EmulateCollection( + "System.VFS.ListDirectory", []*ordereddict.Dict{ + makeStat("/a/b", "c"), + makeStat("/a/b", "d"), + makeStat("/a/b", "e"), + }) + + db, err := datastore.GetDB(self.config_obj) + assert.NoError(self.T(), err) + + client_path_manager := paths.NewClientPathManager(self.client_id) + resp := &flows_proto.VFSListResponse{} + + vtesting.WaitUntil(2*time.Second, self.T(), func() bool { + db.GetSubject(self.config_obj, + client_path_manager.VFSPath([]string{"file", "a", "b"}), + resp) + return resp.TotalRows == 3 + }) + assert.Equal(self.T(), self.getFullPath(resp), []string{ + "/a/b/c", "/a/b/d", "/a/b/e", + }) +} + +func (self *VFSServiceTestSuite) TestRecursiveVFSListDirectory() { + self.EmulateCollection( + "System.VFS.ListDirectory", []*ordereddict.Dict{ + makeStat("/a/b", "A"), + makeStat("/a/b", "B"), + makeStat("/a/b/c", "CA"), + makeStat("/a/b/c", "CB"), + }) + + db, err := datastore.GetDB(self.config_obj) + assert.NoError(self.T(), err) + + client_path_manager := paths.NewClientPathManager(self.client_id) + resp := &flows_proto.VFSListResponse{} + + // The response in VFS path /file/a/b + vtesting.WaitUntil(2*time.Second, self.T(), func() bool { + db.GetSubject(self.config_obj, + client_path_manager.VFSPath([]string{"file", "a", "b"}), + resp) + return resp.TotalRows == 2 + }) + + assert.Equal(self.T(), self.getFullPath(resp), []string{ + "/a/b/A", "/a/b/B", + }) + + // The response in VFS path /file/a/b/c + vtesting.WaitUntil(2*time.Second, self.T(), func() bool { + db.GetSubject(self.config_obj, + client_path_manager.VFSPath([]string{"file", "a", "b", "c"}), + resp) + return resp.TotalRows == 2 + }) + + assert.Equal(self.T(), self.getFullPath(resp), []string{ + "/a/b/c/CA", "/a/b/c/CB", + }) +} + +func (self *VFSServiceTestSuite) TestVFSDownload() { + self.EmulateCollection( + "System.VFS.ListDirectory", []*ordereddict.Dict{ + makeStat("/a/b", "A"), + makeStat("/a/b", "B"), + }) + + self.EmulateCollection( + "System.VFS.DownloadFile", []*ordereddict.Dict{ + ordereddict.NewDict(). + Set("Path", "/a/b/B"). + Set("Accessor", "file"). + Set("Size", 10), + }) + + db, err := datastore.GetDB(self.config_obj) + assert.NoError(self.T(), err) + + flow_path_manager := paths.NewFlowPathManager(self.client_id, self.flow_id) + + // The VFS service stores a file in the VFS area of the + // client's namespace pointing to the real data. The real data + // is stored in the collection's space. + resp := &proto.VFSDownloadInfo{} + vtesting.WaitUntil(2*time.Second, self.T(), func() bool { + db.GetSubject(self.config_obj, + flow_path_manager.GetVFSDownloadInfoPath("file", "/a/b/B").Path(), + resp) + return resp.Size == 10 + }) + + assert.Equal(self.T(), resp.VfsPath, + flow_path_manager.GetUploadsFile("file", "/a/b/B").Path()) +} + +func (self *VFSServiceTestSuite) getFullPath(resp *flows_proto.VFSListResponse) []string { + rows, err := utils.ParseJsonToDicts([]byte(resp.Response)) + assert.NoError(self.T(), err) + + result := []string{} + for _, row := range rows { + full_path, ok := row.GetString("_FullPath") + if ok { + result = append(result, full_path) + } + } + + return result +} + +func makeStat(dirname, name string) *ordereddict.Dict { + fullpath := path.Join(dirname, name) + return ordereddict.NewDict().Set("_FullPath", fullpath). + Set("Name", name).Set("_Accessor", "file") +} + +func TestVFSService(t *testing.T) { + suite.Run(t, &VFSServiceTestSuite{BaseServicesTestSuite{}}) +} diff --git a/vql/server/artifacts.go b/vql/server/artifacts.go index 2a06708e3af..cc7c04040a0 100644 --- a/vql/server/artifacts.go +++ b/vql/server/artifacts.go @@ -28,7 +28,6 @@ import ( actions_proto "www.velocidex.com/golang/velociraptor/actions/proto" "www.velocidex.com/golang/velociraptor/api" "www.velocidex.com/golang/velociraptor/artifacts" - "www.velocidex.com/golang/velociraptor/flows" flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" vql_subsystem "www.velocidex.com/golang/velociraptor/vql" "www.velocidex.com/golang/vfilter" @@ -101,7 +100,7 @@ func (self *ScheduleCollectionFunction) Call(ctx context.Context, principal := vql_subsystem.GetPrincipal(scope) result := &flows_proto.ArtifactCollectorResponse{Request: request} - flow_id, err := flows.ScheduleArtifactCollection( + flow_id, err := artifacts.ScheduleArtifactCollection( config_obj, principal, request) if err != nil { scope.Log("collect_client: %v", err) diff --git a/vtesting/config.go b/vtesting/config.go new file mode 100644 index 00000000000..1af3440762e --- /dev/null +++ b/vtesting/config.go @@ -0,0 +1,22 @@ +package vtesting + +import ( + "testing" + + "github.com/stretchr/testify/require" + "www.velocidex.com/golang/velociraptor/config" + config_proto "www.velocidex.com/golang/velociraptor/config/proto" +) + +func GetTestConfig(t *testing.T) *config_proto.Config { + config_obj, err := config.LoadConfig( + "../http_comms/test_data/server.config.yaml") + require.NoError(t, err) + + require.NoError(t, config.ValidateFrontendConfig(config_obj)) + + config_obj.Datastore.Implementation = "Test" + config_obj.Frontend.DoNotCompressArtifacts = true + + return config_obj +} diff --git a/testing/helpers.go b/vtesting/helpers.go similarity index 82% rename from testing/helpers.go rename to vtesting/helpers.go index c4f7596fec7..3bf0767175d 100644 --- a/testing/helpers.go +++ b/vtesting/helpers.go @@ -18,7 +18,7 @@ /* An internal package with test utilities. */ -package testing +package vtesting import ( "io/ioutil" @@ -47,3 +47,18 @@ func (self RealClock) Now() time.Time { func (self RealClock) After(d time.Duration) <-chan time.Time { return time.After(d) } + +func WaitUntil(deadline time.Duration, t *testing.T, cb func() bool) { + end_time := time.Now().Add(deadline) + + for end_time.After(time.Now()) { + ok := cb() + if ok { + return + } + + time.Sleep(500 * time.Millisecond) + } + + t.Fatalf("Timed out") +}