endpoint_security 0.1.0-universal-darwin
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rubocop.yml +44 -0
- data/LICENSE.txt +21 -0
- data/README.md +114 -0
- data/Rakefile +170 -0
- data/codegen/ast.rb +67 -0
- data/codegen/emit_c.rb +68 -0
- data/codegen/emit_ruby.rb +128 -0
- data/codegen/ir.rb +193 -0
- data/codegen/overlay/availability.yml +158 -0
- data/codegen/overlay/version_map.yml +92 -0
- data/codegen/run.rb +80 -0
- data/codegen/snapshots/26.5.json +5828 -0
- data/examples/eslogger_clone.rb +5 -0
- data/examples/execblock.rb +16 -0
- data/examples/filemon.rb +10 -0
- data/examples/procmon.rb +13 -0
- data/ext/endpoint_security/client.c +795 -0
- data/ext/endpoint_security/client.h +88 -0
- data/ext/endpoint_security/endpoint_security.c +17 -0
- data/ext/endpoint_security/extconf.rb +37 -0
- data/ext/endpoint_security/field.c +719 -0
- data/ext/endpoint_security/field.h +42 -0
- data/ext/endpoint_security/generated/es_schema.c +1233 -0
- data/ext/endpoint_security/message.c +426 -0
- data/ext/endpoint_security/message.h +13 -0
- data/ext/endpoint_security/mute.c +291 -0
- data/ext/endpoint_security/mute.h +8 -0
- data/ext/endpoint_security/queue.c +124 -0
- data/ext/endpoint_security/queue.h +46 -0
- data/ext/endpoint_security/watchdog.c +243 -0
- data/lib/endpoint_security/availability.rb +30 -0
- data/lib/endpoint_security/client.rb +280 -0
- data/lib/endpoint_security/diagnostics.rb +26 -0
- data/lib/endpoint_security/doctor.rb +35 -0
- data/lib/endpoint_security/errors.rb +42 -0
- data/lib/endpoint_security/generated/availability.rb +169 -0
- data/lib/endpoint_security/generated/enums.rb +409 -0
- data/lib/endpoint_security/generated/event_types.rb +520 -0
- data/lib/endpoint_security/message.rb +29 -0
- data/lib/endpoint_security/object_model.rb +170 -0
- data/lib/endpoint_security/recorder.rb +26 -0
- data/lib/endpoint_security/version.rb +6 -0
- data/lib/endpoint_security.rb +38 -0
- data/support/entitlements.plist +8 -0
- data/support/esmock/esmock.c +482 -0
- data/support/esmock/esmock.h +21 -0
- data/support/sign_ruby.sh +13 -0
- metadata +90 -0
|
@@ -0,0 +1,719 @@
|
|
|
1
|
+
/* field.c
|
|
2
|
+
* Calling thread: Ruby dispatcher with the GVL. Every view retains its owning Message.
|
|
3
|
+
*/
|
|
4
|
+
#include "field.h"
|
|
5
|
+
|
|
6
|
+
#include <bsm/libbsm.h>
|
|
7
|
+
#include <limits.h>
|
|
8
|
+
#include <ruby/encoding.h>
|
|
9
|
+
#include <string.h>
|
|
10
|
+
#include <sys/acl.h>
|
|
11
|
+
#include <sys/attr.h>
|
|
12
|
+
#include <sys/mount.h>
|
|
13
|
+
#include <sys/proc_info.h>
|
|
14
|
+
|
|
15
|
+
#include "message.h"
|
|
16
|
+
|
|
17
|
+
typedef struct {
|
|
18
|
+
VALUE owner;
|
|
19
|
+
const unsigned char *pointer;
|
|
20
|
+
const esrb_schema_t *schema;
|
|
21
|
+
uint32_t message_version;
|
|
22
|
+
bool strict_version;
|
|
23
|
+
} esrb_view_t;
|
|
24
|
+
|
|
25
|
+
static VALUE c_native_view;
|
|
26
|
+
|
|
27
|
+
static const esrb_schema_t *
|
|
28
|
+
find_schema(const char *name)
|
|
29
|
+
{
|
|
30
|
+
for (size_t index = 0; index < esrb_schema_count; index++) {
|
|
31
|
+
if (strcmp(esrb_schemas[index].name, name) == 0) {
|
|
32
|
+
return &esrb_schemas[index];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return NULL;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static void
|
|
39
|
+
view_mark(void *pointer)
|
|
40
|
+
{
|
|
41
|
+
esrb_view_t *view = pointer;
|
|
42
|
+
rb_gc_mark(view->owner);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static void
|
|
46
|
+
view_free(void *pointer)
|
|
47
|
+
{
|
|
48
|
+
xfree(pointer);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static size_t
|
|
52
|
+
view_size(const void *pointer)
|
|
53
|
+
{
|
|
54
|
+
return pointer == NULL ? 0 : sizeof(esrb_view_t);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static const rb_data_type_t view_type = {
|
|
58
|
+
.wrap_struct_name = "EndpointSecurity::NativeView",
|
|
59
|
+
.function = {.dmark = view_mark, .dfree = view_free, .dsize = view_size},
|
|
60
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
static esrb_view_t *
|
|
64
|
+
get_view(VALUE self)
|
|
65
|
+
{
|
|
66
|
+
esrb_view_t *view;
|
|
67
|
+
TypedData_Get_Struct(self, esrb_view_t, &view_type, view);
|
|
68
|
+
if (!esrb_message_valid_object(view->owner)) {
|
|
69
|
+
rb_raise(rb_path2class("EndpointSecurity::MessageInvalidatedError"), "message has been released");
|
|
70
|
+
}
|
|
71
|
+
return view;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static VALUE
|
|
75
|
+
class_for_schema(const char *schema)
|
|
76
|
+
{
|
|
77
|
+
if (strcmp(schema, "es_process_t") == 0) {
|
|
78
|
+
return rb_path2class("EndpointSecurity::Process");
|
|
79
|
+
}
|
|
80
|
+
if (strcmp(schema, "es_file_t") == 0) {
|
|
81
|
+
return rb_path2class("EndpointSecurity::File");
|
|
82
|
+
}
|
|
83
|
+
if (strcmp(schema, "es_thread_t") == 0) {
|
|
84
|
+
return rb_path2class("EndpointSecurity::Thread");
|
|
85
|
+
}
|
|
86
|
+
return strncmp(schema, "es_event_", 9) == 0 ? rb_path2class("EndpointSecurity::Event") : c_native_view;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
VALUE
|
|
90
|
+
esrb_view_wrap(VALUE owner, const void *pointer, const char *schema_name, uint32_t message_version, bool strict_version)
|
|
91
|
+
{
|
|
92
|
+
if (pointer == NULL) {
|
|
93
|
+
return Qnil;
|
|
94
|
+
}
|
|
95
|
+
const esrb_schema_t *schema = find_schema(schema_name);
|
|
96
|
+
if (schema == NULL) {
|
|
97
|
+
return Qnil;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
esrb_view_t *view;
|
|
101
|
+
VALUE object = TypedData_Make_Struct(class_for_schema(schema_name), esrb_view_t, &view_type, view);
|
|
102
|
+
view->owner = owner;
|
|
103
|
+
view->pointer = pointer;
|
|
104
|
+
view->schema = schema;
|
|
105
|
+
view->message_version = message_version;
|
|
106
|
+
view->strict_version = strict_version;
|
|
107
|
+
return object;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static VALUE
|
|
111
|
+
time_value(time_t seconds, long nanoseconds)
|
|
112
|
+
{
|
|
113
|
+
return rb_time_nano_new(seconds, nanoseconds);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
VALUE
|
|
117
|
+
esrb_string_token_value(const es_string_token_t *token)
|
|
118
|
+
{
|
|
119
|
+
if (token->length > LONG_MAX) {
|
|
120
|
+
return Qnil;
|
|
121
|
+
}
|
|
122
|
+
VALUE string = token->data == NULL ? rb_str_new("", 0) : rb_str_new(token->data, (long)token->length);
|
|
123
|
+
VALUE mode = rb_funcall(rb_path2class("EndpointSecurity"), rb_intern("string_encoding"), 0);
|
|
124
|
+
rb_enc_associate(string, mode == ID2SYM(rb_intern("binary")) ? rb_ascii8bit_encoding() : rb_utf8_encoding());
|
|
125
|
+
return string;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
static VALUE
|
|
129
|
+
tagged_union_value(const char *kind, VALUE value)
|
|
130
|
+
{
|
|
131
|
+
return rb_funcall(rb_path2class("EndpointSecurity::TaggedUnion"), rb_intern("__native_new"), 2,
|
|
132
|
+
ID2SYM(rb_intern(kind)), value);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
static VALUE
|
|
136
|
+
hex_value(const uint8_t *bytes, size_t length)
|
|
137
|
+
{
|
|
138
|
+
static const char digits[] = "0123456789abcdef";
|
|
139
|
+
VALUE string = rb_str_new(NULL, (long)(length * 2));
|
|
140
|
+
char *output = RSTRING_PTR(string);
|
|
141
|
+
for (size_t index = 0; index < length; index++) {
|
|
142
|
+
output[index * 2] = digits[bytes[index] >> 4];
|
|
143
|
+
output[index * 2 + 1] = digits[bytes[index] & 0x0f];
|
|
144
|
+
}
|
|
145
|
+
return string;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static VALUE
|
|
149
|
+
binary_value(const void *bytes, size_t length)
|
|
150
|
+
{
|
|
151
|
+
VALUE value = rb_str_new(bytes, (long)length);
|
|
152
|
+
rb_enc_associate(value, rb_ascii8bit_encoding());
|
|
153
|
+
return value;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static VALUE
|
|
157
|
+
acl_value(acl_t acl)
|
|
158
|
+
{
|
|
159
|
+
if (acl == NULL) {
|
|
160
|
+
return Qnil;
|
|
161
|
+
}
|
|
162
|
+
ssize_t size = acl_size(acl);
|
|
163
|
+
if (size <= 0) {
|
|
164
|
+
return Qnil;
|
|
165
|
+
}
|
|
166
|
+
VALUE value = rb_str_new(NULL, size);
|
|
167
|
+
ssize_t copied = acl_copy_ext(RSTRING_PTR(value), acl, size);
|
|
168
|
+
if (copied < 0) {
|
|
169
|
+
return Qnil;
|
|
170
|
+
}
|
|
171
|
+
rb_str_set_len(value, copied);
|
|
172
|
+
rb_enc_associate(value, rb_ascii8bit_encoding());
|
|
173
|
+
return value;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
static VALUE
|
|
177
|
+
uid_union(bool available, uid_t uid)
|
|
178
|
+
{
|
|
179
|
+
return tagged_union_value(available ? "uid" : "unavailable", available ? UINT2NUM(uid) : Qnil);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
static VALUE
|
|
183
|
+
destination_union(const esrb_view_t *view, bool create)
|
|
184
|
+
{
|
|
185
|
+
es_destination_type_t type;
|
|
186
|
+
es_file_t *existing_file;
|
|
187
|
+
es_file_t *directory;
|
|
188
|
+
es_string_token_t filename;
|
|
189
|
+
mode_t mode = 0;
|
|
190
|
+
if (create) {
|
|
191
|
+
const es_event_create_t *event = (const es_event_create_t *)view->pointer;
|
|
192
|
+
type = event->destination_type;
|
|
193
|
+
existing_file = event->destination.existing_file;
|
|
194
|
+
directory = event->destination.new_path.dir;
|
|
195
|
+
filename = event->destination.new_path.filename;
|
|
196
|
+
mode = event->destination.new_path.mode;
|
|
197
|
+
} else {
|
|
198
|
+
const es_event_rename_t *event = (const es_event_rename_t *)view->pointer;
|
|
199
|
+
type = event->destination_type;
|
|
200
|
+
existing_file = event->destination.existing_file;
|
|
201
|
+
directory = event->destination.new_path.dir;
|
|
202
|
+
filename = event->destination.new_path.filename;
|
|
203
|
+
}
|
|
204
|
+
if (type == ES_DESTINATION_TYPE_EXISTING_FILE) {
|
|
205
|
+
VALUE file = esrb_view_wrap(
|
|
206
|
+
view->owner, existing_file, "es_file_t", view->message_version, view->strict_version);
|
|
207
|
+
return tagged_union_value("existing_file", file);
|
|
208
|
+
}
|
|
209
|
+
if (type != ES_DESTINATION_TYPE_NEW_PATH) {
|
|
210
|
+
return tagged_union_value("unknown", Qnil);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
VALUE path = rb_hash_new();
|
|
214
|
+
rb_hash_aset(path, ID2SYM(rb_intern("dir")),
|
|
215
|
+
esrb_view_wrap(view->owner, directory, "es_file_t", view->message_version, view->strict_version));
|
|
216
|
+
rb_hash_aset(path, ID2SYM(rb_intern("filename")), esrb_string_token_value(&filename));
|
|
217
|
+
if (create) {
|
|
218
|
+
rb_hash_aset(path, ID2SYM(rb_intern("mode")), UINT2NUM(mode));
|
|
219
|
+
}
|
|
220
|
+
return tagged_union_value("new_path", path);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
static VALUE
|
|
224
|
+
authentication_union(const esrb_view_t *view)
|
|
225
|
+
{
|
|
226
|
+
const es_event_authentication_t *event = (const es_event_authentication_t *)view->pointer;
|
|
227
|
+
const void *pointer = NULL;
|
|
228
|
+
const char *kind = "unknown";
|
|
229
|
+
const char *schema = NULL;
|
|
230
|
+
switch (event->type) {
|
|
231
|
+
case ES_AUTHENTICATION_TYPE_OD:
|
|
232
|
+
kind = "od";
|
|
233
|
+
schema = "es_event_authentication_od_t";
|
|
234
|
+
pointer = event->data.od;
|
|
235
|
+
break;
|
|
236
|
+
case ES_AUTHENTICATION_TYPE_TOUCHID:
|
|
237
|
+
kind = "touchid";
|
|
238
|
+
schema = "es_event_authentication_touchid_t";
|
|
239
|
+
pointer = event->data.touchid;
|
|
240
|
+
break;
|
|
241
|
+
case ES_AUTHENTICATION_TYPE_TOKEN:
|
|
242
|
+
kind = "token";
|
|
243
|
+
schema = "es_event_authentication_token_t";
|
|
244
|
+
pointer = event->data.token;
|
|
245
|
+
break;
|
|
246
|
+
case ES_AUTHENTICATION_TYPE_AUTO_UNLOCK:
|
|
247
|
+
kind = "auto_unlock";
|
|
248
|
+
schema = "es_event_authentication_auto_unlock_t";
|
|
249
|
+
pointer = event->data.auto_unlock;
|
|
250
|
+
break;
|
|
251
|
+
default:
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
VALUE value = schema == NULL
|
|
255
|
+
? Qnil
|
|
256
|
+
: esrb_view_wrap(view->owner, pointer, schema, view->message_version, view->strict_version);
|
|
257
|
+
return tagged_union_value(kind, value);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
static VALUE
|
|
261
|
+
od_member_union(const esrb_view_t *view)
|
|
262
|
+
{
|
|
263
|
+
const es_od_member_id_t *member = (const es_od_member_id_t *)view->pointer;
|
|
264
|
+
if (member->member_type == ES_OD_MEMBER_TYPE_USER_NAME) {
|
|
265
|
+
return tagged_union_value("name", esrb_string_token_value(&member->member_value.name));
|
|
266
|
+
}
|
|
267
|
+
if (member->member_type != ES_OD_MEMBER_TYPE_USER_UUID && member->member_type != ES_OD_MEMBER_TYPE_GROUP_UUID) {
|
|
268
|
+
return tagged_union_value("unknown", Qnil);
|
|
269
|
+
}
|
|
270
|
+
return tagged_union_value("uuid", hex_value(member->member_value.uuid, sizeof(uuid_t)));
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
static VALUE
|
|
274
|
+
od_member_array_union(const esrb_view_t *view)
|
|
275
|
+
{
|
|
276
|
+
const es_od_member_id_array_t *members = (const es_od_member_id_array_t *)view->pointer;
|
|
277
|
+
if (members->member_count > UINT32_MAX) {
|
|
278
|
+
return tagged_union_value("invalid", Qnil);
|
|
279
|
+
}
|
|
280
|
+
VALUE values = rb_ary_new_capa((long)members->member_count);
|
|
281
|
+
if (members->member_type == ES_OD_MEMBER_TYPE_USER_NAME) {
|
|
282
|
+
for (size_t index = 0; index < members->member_count; index++) {
|
|
283
|
+
rb_ary_push(values, esrb_string_token_value(&members->member_array.names[index]));
|
|
284
|
+
}
|
|
285
|
+
return tagged_union_value("names", values);
|
|
286
|
+
}
|
|
287
|
+
if (members->member_type != ES_OD_MEMBER_TYPE_USER_UUID && members->member_type != ES_OD_MEMBER_TYPE_GROUP_UUID) {
|
|
288
|
+
return tagged_union_value("unknown", Qnil);
|
|
289
|
+
}
|
|
290
|
+
for (size_t index = 0; index < members->member_count; index++) {
|
|
291
|
+
rb_ary_push(values, hex_value(members->member_array.uuids[index], sizeof(uuid_t)));
|
|
292
|
+
}
|
|
293
|
+
return tagged_union_value("uuids", values);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
static VALUE
|
|
297
|
+
read_union(const esrb_view_t *view, const esrb_field_t *field)
|
|
298
|
+
{
|
|
299
|
+
const char *schema = view->schema->name;
|
|
300
|
+
if (strcmp(field->name, "destination") == 0 && strcmp(schema, "es_event_rename_t") == 0) {
|
|
301
|
+
return destination_union(view, false);
|
|
302
|
+
}
|
|
303
|
+
if (strcmp(field->name, "destination") == 0 && strcmp(schema, "es_event_create_t") == 0) {
|
|
304
|
+
return destination_union(view, true);
|
|
305
|
+
}
|
|
306
|
+
if (strcmp(field->name, "uid") == 0 && strcmp(schema, "es_event_authentication_touchid_t") == 0) {
|
|
307
|
+
const es_event_authentication_touchid_t *event = (const es_event_authentication_touchid_t *)view->pointer;
|
|
308
|
+
return uid_union(event->has_uid, event->uid.uid);
|
|
309
|
+
}
|
|
310
|
+
if (strcmp(field->name, "uid") == 0 && strcmp(schema, "es_event_openssh_login_t") == 0) {
|
|
311
|
+
const es_event_openssh_login_t *event = (const es_event_openssh_login_t *)view->pointer;
|
|
312
|
+
return uid_union(event->has_uid, event->uid.uid);
|
|
313
|
+
}
|
|
314
|
+
if (strcmp(field->name, "uid") == 0 && strcmp(schema, "es_event_login_login_t") == 0) {
|
|
315
|
+
const es_event_login_login_t *event = (const es_event_login_login_t *)view->pointer;
|
|
316
|
+
return uid_union(event->has_uid, event->uid.uid);
|
|
317
|
+
}
|
|
318
|
+
if (strcmp(field->name, "to_uid") == 0 && strcmp(schema, "es_event_su_t") == 0) {
|
|
319
|
+
const es_event_su_t *event = (const es_event_su_t *)view->pointer;
|
|
320
|
+
return uid_union(event->has_to_uid, event->to_uid.uid);
|
|
321
|
+
}
|
|
322
|
+
if (strcmp(schema, "es_event_sudo_t") == 0 && strcmp(field->name, "from_uid") == 0) {
|
|
323
|
+
const es_event_sudo_t *event = (const es_event_sudo_t *)view->pointer;
|
|
324
|
+
return uid_union(event->has_from_uid, event->from_uid.uid);
|
|
325
|
+
}
|
|
326
|
+
if (strcmp(schema, "es_event_sudo_t") == 0 && strcmp(field->name, "to_uid") == 0) {
|
|
327
|
+
const es_event_sudo_t *event = (const es_event_sudo_t *)view->pointer;
|
|
328
|
+
return uid_union(event->has_to_uid, event->to_uid.uid);
|
|
329
|
+
}
|
|
330
|
+
if (strcmp(field->name, "data") == 0 && strcmp(schema, "es_event_authentication_t") == 0) {
|
|
331
|
+
return authentication_union(view);
|
|
332
|
+
}
|
|
333
|
+
if (strcmp(field->name, "member_value") == 0 && strcmp(schema, "es_od_member_id_t") == 0) {
|
|
334
|
+
return od_member_union(view);
|
|
335
|
+
}
|
|
336
|
+
if (strcmp(field->name, "member_array") == 0 && strcmp(schema, "es_od_member_id_array_t") == 0) {
|
|
337
|
+
return od_member_array_union(view);
|
|
338
|
+
}
|
|
339
|
+
if (strcmp(field->name, "file") == 0 && strcmp(schema, "es_event_gatekeeper_user_override_t") == 0) {
|
|
340
|
+
const es_event_gatekeeper_user_override_t *event = (const es_event_gatekeeper_user_override_t *)view->pointer;
|
|
341
|
+
if (event->file_type == ES_GATEKEEPER_USER_OVERRIDE_FILE_TYPE_PATH) {
|
|
342
|
+
return tagged_union_value("path", esrb_string_token_value(&event->file.file_path));
|
|
343
|
+
}
|
|
344
|
+
if (event->file_type != ES_GATEKEEPER_USER_OVERRIDE_FILE_TYPE_FILE) {
|
|
345
|
+
return tagged_union_value("unknown", Qnil);
|
|
346
|
+
}
|
|
347
|
+
VALUE file = esrb_view_wrap(
|
|
348
|
+
view->owner, event->file.file, "es_file_t", view->message_version, view->strict_version);
|
|
349
|
+
return tagged_union_value("file", file);
|
|
350
|
+
}
|
|
351
|
+
if (strcmp(field->name, "acl") == 0 && strcmp(schema, "es_event_setacl_t") == 0) {
|
|
352
|
+
const es_event_setacl_t *event = (const es_event_setacl_t *)view->pointer;
|
|
353
|
+
if (event->set_or_clear == ES_SET) {
|
|
354
|
+
return tagged_union_value("set", acl_value(event->acl.set));
|
|
355
|
+
}
|
|
356
|
+
return tagged_union_value(event->set_or_clear == ES_CLEAR ? "clear" : "unknown", Qnil);
|
|
357
|
+
}
|
|
358
|
+
return Qundef;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
static VALUE
|
|
362
|
+
string_array(const es_string_token_t *tokens, size_t count)
|
|
363
|
+
{
|
|
364
|
+
if (tokens == NULL || count > UINT32_MAX) {
|
|
365
|
+
return rb_ary_new();
|
|
366
|
+
}
|
|
367
|
+
VALUE values = rb_ary_new_capa((long)count);
|
|
368
|
+
for (size_t index = 0; index < count; index++) {
|
|
369
|
+
rb_ary_push(values, esrb_string_token_value(&tokens[index]));
|
|
370
|
+
}
|
|
371
|
+
return values;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
static VALUE
|
|
375
|
+
read_array(const esrb_view_t *view, const esrb_field_t *field)
|
|
376
|
+
{
|
|
377
|
+
const char *schema = view->schema->name;
|
|
378
|
+
if (strcmp(schema, "es_event_su_t") == 0) {
|
|
379
|
+
const es_event_su_t *event = (const es_event_su_t *)view->pointer;
|
|
380
|
+
if (strcmp(field->name, "argv") == 0) {
|
|
381
|
+
return string_array(event->argv, event->argc);
|
|
382
|
+
}
|
|
383
|
+
if (strcmp(field->name, "env") == 0) {
|
|
384
|
+
return string_array(event->env, event->env_count);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
if (strcmp(schema, "es_event_authorization_petition_t") == 0 && strcmp(field->name, "rights") == 0) {
|
|
388
|
+
const es_event_authorization_petition_t *event = (const es_event_authorization_petition_t *)view->pointer;
|
|
389
|
+
return string_array(event->rights, event->right_count);
|
|
390
|
+
}
|
|
391
|
+
if (strcmp(schema, "es_event_od_attribute_set_t") == 0 && strcmp(field->name, "attribute_values") == 0) {
|
|
392
|
+
const es_event_od_attribute_set_t *event = (const es_event_od_attribute_set_t *)view->pointer;
|
|
393
|
+
return string_array(event->attribute_values, event->attribute_value_count);
|
|
394
|
+
}
|
|
395
|
+
if (strcmp(schema, "es_event_authorization_judgement_t") == 0 && strcmp(field->name, "results") == 0) {
|
|
396
|
+
const es_event_authorization_judgement_t *event = (const es_event_authorization_judgement_t *)view->pointer;
|
|
397
|
+
if (event->results == NULL || event->result_count > UINT32_MAX) {
|
|
398
|
+
return rb_ary_new();
|
|
399
|
+
}
|
|
400
|
+
VALUE values = rb_ary_new_capa((long)event->result_count);
|
|
401
|
+
for (size_t index = 0; index < event->result_count; index++) {
|
|
402
|
+
rb_ary_push(values, esrb_view_wrap(view->owner, &event->results[index], "es_authorization_result_t",
|
|
403
|
+
view->message_version, view->strict_version));
|
|
404
|
+
}
|
|
405
|
+
return values;
|
|
406
|
+
}
|
|
407
|
+
return Qundef;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
static VALUE
|
|
411
|
+
audit_token_value(const audit_token_t *token)
|
|
412
|
+
{
|
|
413
|
+
VALUE arguments[] = {
|
|
414
|
+
UINT2NUM(audit_token_to_pid(*token)),
|
|
415
|
+
UINT2NUM(audit_token_to_pidversion(*token)),
|
|
416
|
+
UINT2NUM(audit_token_to_ruid(*token)),
|
|
417
|
+
UINT2NUM(audit_token_to_euid(*token)),
|
|
418
|
+
UINT2NUM(audit_token_to_rgid(*token)),
|
|
419
|
+
UINT2NUM(audit_token_to_egid(*token)),
|
|
420
|
+
UINT2NUM(audit_token_to_asid(*token)),
|
|
421
|
+
UINT2NUM(audit_token_to_auid(*token))
|
|
422
|
+
};
|
|
423
|
+
return rb_funcallv(rb_path2class("EndpointSecurity::AuditToken"), rb_intern("__native_new"), 8, arguments);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
static VALUE
|
|
427
|
+
stat_value(const struct stat *stat)
|
|
428
|
+
{
|
|
429
|
+
VALUE arguments[] = {
|
|
430
|
+
ULL2NUM(stat->st_dev), ULL2NUM(stat->st_ino), UINT2NUM(stat->st_mode), UINT2NUM(stat->st_nlink),
|
|
431
|
+
UINT2NUM(stat->st_uid), UINT2NUM(stat->st_gid), ULL2NUM(stat->st_rdev), LL2NUM(stat->st_size),
|
|
432
|
+
LL2NUM(stat->st_blocks), LONG2NUM(stat->st_blksize), time_value(stat->st_atimespec.tv_sec, stat->st_atimespec.tv_nsec),
|
|
433
|
+
time_value(stat->st_mtimespec.tv_sec, stat->st_mtimespec.tv_nsec),
|
|
434
|
+
time_value(stat->st_ctimespec.tv_sec, stat->st_ctimespec.tv_nsec),
|
|
435
|
+
time_value(stat->st_birthtimespec.tv_sec, stat->st_birthtimespec.tv_nsec)
|
|
436
|
+
};
|
|
437
|
+
return rb_funcallv(rb_path2class("EndpointSecurity::Stat"), rb_intern("__native_new"), 14, arguments);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
static VALUE
|
|
441
|
+
statfs_value(const struct statfs *statfs)
|
|
442
|
+
{
|
|
443
|
+
size_t type_length = strnlen(statfs->f_fstypename, sizeof(statfs->f_fstypename));
|
|
444
|
+
size_t path_length = strnlen(statfs->f_mntonname, sizeof(statfs->f_mntonname));
|
|
445
|
+
size_t source_length = strnlen(statfs->f_mntfromname, sizeof(statfs->f_mntfromname));
|
|
446
|
+
VALUE fsid = rb_ary_new_from_args(2, INT2NUM(statfs->f_fsid.val[0]), INT2NUM(statfs->f_fsid.val[1]));
|
|
447
|
+
VALUE arguments[] = {
|
|
448
|
+
UINT2NUM(statfs->f_bsize), INT2NUM(statfs->f_iosize), ULL2NUM(statfs->f_blocks), ULL2NUM(statfs->f_bfree),
|
|
449
|
+
ULL2NUM(statfs->f_bavail), ULL2NUM(statfs->f_files), ULL2NUM(statfs->f_ffree), fsid,
|
|
450
|
+
UINT2NUM(statfs->f_owner), UINT2NUM(statfs->f_type), UINT2NUM(statfs->f_flags), UINT2NUM(statfs->f_fssubtype),
|
|
451
|
+
rb_str_new(statfs->f_fstypename, (long)type_length), rb_str_new(statfs->f_mntonname, (long)path_length),
|
|
452
|
+
rb_str_new(statfs->f_mntfromname, (long)source_length), UINT2NUM(statfs->f_flags_ext)
|
|
453
|
+
};
|
|
454
|
+
return rb_funcallv(rb_path2class("EndpointSecurity::Statfs"), rb_intern("__native_new"), 16, arguments);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
static VALUE
|
|
458
|
+
attrlist_value(const struct attrlist *attributes)
|
|
459
|
+
{
|
|
460
|
+
VALUE arguments[] = {
|
|
461
|
+
UINT2NUM(attributes->bitmapcount), UINT2NUM(attributes->reserved), UINT2NUM(attributes->commonattr),
|
|
462
|
+
UINT2NUM(attributes->volattr), UINT2NUM(attributes->dirattr), UINT2NUM(attributes->fileattr),
|
|
463
|
+
UINT2NUM(attributes->forkattr)
|
|
464
|
+
};
|
|
465
|
+
return rb_funcallv(rb_path2class("EndpointSecurity::Attrlist"), rb_intern("__native_new"), 7, arguments);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
static const esrb_field_t *
|
|
469
|
+
find_field(const esrb_view_t *view, const char *name)
|
|
470
|
+
{
|
|
471
|
+
for (size_t index = 0; index < view->schema->field_count; index++) {
|
|
472
|
+
if (strcmp(view->schema->fields[index].name, name) == 0) {
|
|
473
|
+
return &view->schema->fields[index];
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return NULL;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
static void
|
|
480
|
+
referenced_schema_name(const char *type, char *name, size_t capacity)
|
|
481
|
+
{
|
|
482
|
+
if (strncmp(type, "union ", 6) == 0 || strncmp(type, "struct ", 7) == 0) {
|
|
483
|
+
name[0] = '\0';
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
const char *start = strstr(type, "es_");
|
|
487
|
+
const char *end = start == NULL ? NULL : strstr(start, "_t");
|
|
488
|
+
if (end == NULL || (size_t)(end + 2 - start) >= capacity) {
|
|
489
|
+
name[0] = '\0';
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
size_t length = (size_t)(end + 2 - start);
|
|
493
|
+
memcpy(name, start, length);
|
|
494
|
+
name[length] = '\0';
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
static VALUE
|
|
498
|
+
read_field(VALUE self, VALUE name_value)
|
|
499
|
+
{
|
|
500
|
+
esrb_view_t *view = get_view(self);
|
|
501
|
+
const char *name = StringValueCStr(name_value);
|
|
502
|
+
const esrb_field_t *field = find_field(view, name);
|
|
503
|
+
if (field == NULL) {
|
|
504
|
+
return Qundef;
|
|
505
|
+
}
|
|
506
|
+
if (field->minimum_version > view->message_version) {
|
|
507
|
+
if (view->strict_version) {
|
|
508
|
+
rb_raise(rb_path2class("EndpointSecurity::FieldUnavailableError"),
|
|
509
|
+
"%s requires message version %u (got %u)", field->name, field->minimum_version, view->message_version);
|
|
510
|
+
}
|
|
511
|
+
return Qnil;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const unsigned char *address = view->pointer + field->offset;
|
|
515
|
+
const char *type = field->type;
|
|
516
|
+
if (strncmp(type, "union ", 6) == 0) {
|
|
517
|
+
VALUE value = read_union(view, field);
|
|
518
|
+
return value == Qundef ? Qnil : value;
|
|
519
|
+
}
|
|
520
|
+
if (strchr(type, '*') != NULL) {
|
|
521
|
+
VALUE value = read_array(view, field);
|
|
522
|
+
if (value != Qundef) {
|
|
523
|
+
return value;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
if (strcmp(type, "es_string_token_t") == 0) {
|
|
527
|
+
return esrb_string_token_value((const es_string_token_t *)address);
|
|
528
|
+
}
|
|
529
|
+
if (strcmp(type, "es_string_token_t *") == 0) {
|
|
530
|
+
const es_string_token_t *token = *(const es_string_token_t *const *)address;
|
|
531
|
+
return token == NULL ? Qnil : esrb_string_token_value(token);
|
|
532
|
+
}
|
|
533
|
+
if (strcmp(type, "es_token_t") == 0) {
|
|
534
|
+
const es_token_t *token = (const es_token_t *)address;
|
|
535
|
+
if (token->size > LONG_MAX) {
|
|
536
|
+
return Qnil;
|
|
537
|
+
}
|
|
538
|
+
return token->data == NULL ? rb_str_new("", 0) : rb_str_new((const char *)token->data, (long)token->size);
|
|
539
|
+
}
|
|
540
|
+
if (strcmp(type, "audit_token_t") == 0) {
|
|
541
|
+
return audit_token_value((const audit_token_t *)address);
|
|
542
|
+
}
|
|
543
|
+
if (strcmp(type, "audit_token_t *") == 0) {
|
|
544
|
+
const audit_token_t *token = *(const audit_token_t *const *)address;
|
|
545
|
+
return token == NULL ? Qnil : audit_token_value(token);
|
|
546
|
+
}
|
|
547
|
+
if (strcmp(type, "struct stat") == 0) {
|
|
548
|
+
return stat_value((const struct stat *)address);
|
|
549
|
+
}
|
|
550
|
+
if (strcmp(type, "struct statfs *") == 0) {
|
|
551
|
+
const struct statfs *statfs = *(const struct statfs *const *)address;
|
|
552
|
+
return statfs == NULL ? Qnil : statfs_value(statfs);
|
|
553
|
+
}
|
|
554
|
+
if (strcmp(type, "struct attrlist") == 0) {
|
|
555
|
+
return attrlist_value((const struct attrlist *)address);
|
|
556
|
+
}
|
|
557
|
+
if (strcmp(type, "struct timespec") == 0) {
|
|
558
|
+
const struct timespec *time = (const struct timespec *)address;
|
|
559
|
+
return time_value(time->tv_sec, time->tv_nsec);
|
|
560
|
+
}
|
|
561
|
+
if (strcmp(type, "struct timeval") == 0) {
|
|
562
|
+
const struct timeval *time = (const struct timeval *)address;
|
|
563
|
+
return time_value(time->tv_sec, time->tv_usec * 1000L);
|
|
564
|
+
}
|
|
565
|
+
if (strcmp(type, "bool") == 0 || strcmp(type, "_Bool") == 0) {
|
|
566
|
+
return *(const bool *)address ? Qtrue : Qfalse;
|
|
567
|
+
}
|
|
568
|
+
if (strstr(type, "[20]") != NULL) {
|
|
569
|
+
return binary_value(address, 20);
|
|
570
|
+
}
|
|
571
|
+
if (strcmp(type, "es_sha256_t *") == 0) {
|
|
572
|
+
const es_sha256_t *sha256 = *(const es_sha256_t *const *)address;
|
|
573
|
+
return sha256 == NULL ? Qnil : binary_value(*sha256, sizeof(*sha256));
|
|
574
|
+
}
|
|
575
|
+
if (strcmp(type, "struct _acl *") == 0) {
|
|
576
|
+
return acl_value(*(acl_t const *)address);
|
|
577
|
+
}
|
|
578
|
+
if (strcmp(view->schema->name, "es_fd_t") == 0 && strcmp(field->name, "pipe") == 0) {
|
|
579
|
+
const es_fd_t *descriptor = (const es_fd_t *)view->pointer;
|
|
580
|
+
if (descriptor->fdtype != PROX_FDTYPE_PIPE) {
|
|
581
|
+
return Qnil;
|
|
582
|
+
}
|
|
583
|
+
VALUE pipe = rb_hash_new();
|
|
584
|
+
rb_hash_aset(pipe, ID2SYM(rb_intern("pipe_id")), ULL2NUM(descriptor->pipe.pipe_id));
|
|
585
|
+
return pipe;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
char schema_name[128];
|
|
589
|
+
referenced_schema_name(type, schema_name, sizeof(schema_name));
|
|
590
|
+
if (schema_name[0] != '\0' && find_schema(schema_name) != NULL) {
|
|
591
|
+
const void *nested = strchr(type, '*') == NULL ? address : *(const void *const *)address;
|
|
592
|
+
return esrb_view_wrap(view->owner, nested, schema_name, view->message_version, view->strict_version);
|
|
593
|
+
}
|
|
594
|
+
if (strchr(type, '*') != NULL) {
|
|
595
|
+
return Qnil;
|
|
596
|
+
}
|
|
597
|
+
if (strncmp(type, "es_", 3) == 0) {
|
|
598
|
+
VALUE enumeration = rb_path2class("EndpointSecurity::Enum");
|
|
599
|
+
return rb_funcall(enumeration, rb_intern("symbol"), 2, rb_str_new_cstr(type), INT2NUM(*(const int32_t *)address));
|
|
600
|
+
}
|
|
601
|
+
if (strcmp(type, "unsigned long long") == 0 || strcmp(type, "uint64_t") == 0) {
|
|
602
|
+
return ULL2NUM(*(const uint64_t *)address);
|
|
603
|
+
}
|
|
604
|
+
if (strcmp(type, "long long") == 0 || strcmp(type, "int64_t") == 0) {
|
|
605
|
+
return LL2NUM(*(const int64_t *)address);
|
|
606
|
+
}
|
|
607
|
+
if (strcmp(type, "unsigned long") == 0) {
|
|
608
|
+
return ULONG2NUM(*(const unsigned long *)address);
|
|
609
|
+
}
|
|
610
|
+
if (strcmp(type, "long") == 0) {
|
|
611
|
+
return LONG2NUM(*(const long *)address);
|
|
612
|
+
}
|
|
613
|
+
if (strcmp(type, "unsigned int") == 0 || strcmp(type, "uint32_t") == 0) {
|
|
614
|
+
return UINT2NUM(*(const uint32_t *)address);
|
|
615
|
+
}
|
|
616
|
+
if (strcmp(type, "int") == 0 || strcmp(type, "int32_t") == 0) {
|
|
617
|
+
return INT2NUM(*(const int32_t *)address);
|
|
618
|
+
}
|
|
619
|
+
if (strcmp(type, "unsigned short") == 0 || strcmp(type, "uint16_t") == 0) {
|
|
620
|
+
return UINT2NUM(*(const uint16_t *)address);
|
|
621
|
+
}
|
|
622
|
+
if (strcmp(type, "short") == 0 || strcmp(type, "int16_t") == 0) {
|
|
623
|
+
return INT2NUM(*(const int16_t *)address);
|
|
624
|
+
}
|
|
625
|
+
if (strcmp(type, "unsigned char") == 0 || strcmp(type, "uint8_t") == 0) {
|
|
626
|
+
return UINT2NUM(*(const uint8_t *)address);
|
|
627
|
+
}
|
|
628
|
+
if (strcmp(type, "signed char") == 0 || strcmp(type, "int8_t") == 0 || strcmp(type, "char") == 0) {
|
|
629
|
+
return INT2NUM(*(const int8_t *)address);
|
|
630
|
+
}
|
|
631
|
+
return Qnil;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
static VALUE
|
|
635
|
+
field_names(VALUE self)
|
|
636
|
+
{
|
|
637
|
+
esrb_view_t *view = get_view(self);
|
|
638
|
+
VALUE names = rb_ary_new_capa((long)view->schema->field_count);
|
|
639
|
+
for (size_t index = 0; index < view->schema->field_count; index++) {
|
|
640
|
+
const esrb_field_t *field = &view->schema->fields[index];
|
|
641
|
+
rb_ary_push(names, ID2SYM(rb_intern(field->name)));
|
|
642
|
+
}
|
|
643
|
+
return names;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
static VALUE
|
|
647
|
+
schema_name(VALUE self)
|
|
648
|
+
{
|
|
649
|
+
return rb_str_new_cstr(get_view(self)->schema->name);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
static VALUE
|
|
653
|
+
warn_on_truncated_path(VALUE self)
|
|
654
|
+
{
|
|
655
|
+
return rb_funcall(get_view(self)->owner, rb_intern("__warn_on_truncated_path?"), 0);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
static VALUE
|
|
659
|
+
exec_values(VALUE self, VALUE kind_value)
|
|
660
|
+
{
|
|
661
|
+
esrb_view_t *view = get_view(self);
|
|
662
|
+
if (strcmp(view->schema->name, "es_event_exec_t") != 0) {
|
|
663
|
+
return Qnil;
|
|
664
|
+
}
|
|
665
|
+
ID kind = SYM2ID(kind_value);
|
|
666
|
+
const es_event_exec_t *event = (const es_event_exec_t *)view->pointer;
|
|
667
|
+
uint32_t count;
|
|
668
|
+
VALUE values;
|
|
669
|
+
if (kind == rb_intern("args") || kind == rb_intern("env")) {
|
|
670
|
+
count = kind == rb_intern("args") ? es_exec_arg_count(event) : es_exec_env_count(event);
|
|
671
|
+
values = rb_ary_new_capa(count);
|
|
672
|
+
for (uint32_t index = 0; index < count; index++) {
|
|
673
|
+
es_string_token_t token = kind == rb_intern("args") ? es_exec_arg(event, index) : es_exec_env(event, index);
|
|
674
|
+
rb_ary_push(values, esrb_string_token_value(&token));
|
|
675
|
+
}
|
|
676
|
+
return values;
|
|
677
|
+
}
|
|
678
|
+
if (kind == rb_intern("fds")) {
|
|
679
|
+
count = es_exec_fd_count(event);
|
|
680
|
+
values = rb_ary_new_capa(count);
|
|
681
|
+
for (uint32_t index = 0; index < count; index++) {
|
|
682
|
+
rb_ary_push(values,
|
|
683
|
+
esrb_view_wrap(view->owner, es_exec_fd(event, index), "es_fd_t", view->message_version, view->strict_version));
|
|
684
|
+
}
|
|
685
|
+
return values;
|
|
686
|
+
}
|
|
687
|
+
return Qnil;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
VALUE
|
|
691
|
+
esrb_event_wrap(VALUE owner, const es_message_t *message, bool strict_version)
|
|
692
|
+
{
|
|
693
|
+
for (size_t index = 0; index < esrb_event_schema_count; index++) {
|
|
694
|
+
const esrb_event_schema_t *event = &esrb_event_schemas[index];
|
|
695
|
+
if (event->event_type != message->event_type) {
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
|
+
const unsigned char *address = (const unsigned char *)&message->event + event->offset;
|
|
699
|
+
const void *pointer = event->indirect ? *(const void *const *)address : address;
|
|
700
|
+
return esrb_view_wrap(owner, pointer, event->schema, message->version, strict_version);
|
|
701
|
+
}
|
|
702
|
+
return Qnil;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
void
|
|
706
|
+
esrb_init_field(VALUE endpoint_security)
|
|
707
|
+
{
|
|
708
|
+
c_native_view = rb_define_class_under(endpoint_security, "NativeView", rb_cObject);
|
|
709
|
+
rb_undef_alloc_func(c_native_view);
|
|
710
|
+
rb_define_method(c_native_view, "__read_field", read_field, 1);
|
|
711
|
+
rb_define_method(c_native_view, "__field_names", field_names, 0);
|
|
712
|
+
rb_define_method(c_native_view, "__schema_name", schema_name, 0);
|
|
713
|
+
rb_define_method(c_native_view, "__warn_on_truncated_path?", warn_on_truncated_path, 0);
|
|
714
|
+
rb_define_method(c_native_view, "__exec_values", exec_values, 1);
|
|
715
|
+
rb_define_class_under(endpoint_security, "Event", c_native_view);
|
|
716
|
+
rb_define_class_under(endpoint_security, "Process", c_native_view);
|
|
717
|
+
rb_define_class_under(endpoint_security, "File", c_native_view);
|
|
718
|
+
rb_define_class_under(endpoint_security, "Thread", c_native_view);
|
|
719
|
+
}
|