action-executor: evaluated object credentials are optional
[lttng-tools.git] / src / common / trigger.c
... / ...
CommitLineData
1/*
2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8#include <lttng/trigger/trigger-internal.h>
9#include <lttng/condition/condition-internal.h>
10#include <lttng/action/action-internal.h>
11#include <common/credentials.h>
12#include <common/payload.h>
13#include <common/payload-view.h>
14#include <common/error.h>
15#include <common/optional.h>
16#include <assert.h>
17#include <inttypes.h>
18
19LTTNG_HIDDEN
20bool lttng_trigger_validate(struct lttng_trigger *trigger)
21{
22 bool valid;
23
24 if (!trigger) {
25 valid = false;
26 goto end;
27 }
28
29 if (!trigger->creds.uid.is_set) {
30 valid = false;
31 goto end;
32 }
33
34 valid = lttng_condition_validate(trigger->condition) &&
35 lttng_action_validate(trigger->action);
36end:
37 return valid;
38}
39
40struct lttng_trigger *lttng_trigger_create(
41 struct lttng_condition *condition,
42 struct lttng_action *action)
43{
44 struct lttng_trigger *trigger = NULL;
45
46 if (!condition || !action) {
47 goto end;
48 }
49
50 trigger = zmalloc(sizeof(struct lttng_trigger));
51 if (!trigger) {
52 goto end;
53 }
54
55 urcu_ref_init(&trigger->ref);
56
57 lttng_condition_get(condition);
58 trigger->condition = condition;
59
60 lttng_action_get(action);
61 trigger->action = action;
62
63end:
64 return trigger;
65}
66
67/*
68 * Note: the lack of reference counting 'get' on the condition object is normal.
69 * This API was exposed as such in 2.11. The client is not expected to call
70 * lttng_condition_destroy on the returned object.
71 */
72struct lttng_condition *lttng_trigger_get_condition(
73 struct lttng_trigger *trigger)
74{
75 return trigger ? trigger->condition : NULL;
76}
77
78LTTNG_HIDDEN
79const struct lttng_condition *lttng_trigger_get_const_condition(
80 const struct lttng_trigger *trigger)
81{
82 return trigger->condition;
83}
84
85
86/*
87 * Note: the lack of reference counting 'get' on the action object is normal.
88 * This API was exposed as such in 2.11. The client is not expected to call
89 * lttng_action_destroy on the returned object.
90 */
91struct lttng_action *lttng_trigger_get_action(
92 struct lttng_trigger *trigger)
93{
94 return trigger ? trigger->action : NULL;
95}
96
97LTTNG_HIDDEN
98const struct lttng_action *lttng_trigger_get_const_action(
99 const struct lttng_trigger *trigger)
100{
101 return trigger->action;
102}
103
104static void trigger_destroy_ref(struct urcu_ref *ref)
105{
106 struct lttng_trigger *trigger =
107 container_of(ref, struct lttng_trigger, ref);
108 struct lttng_action *action = lttng_trigger_get_action(trigger);
109 struct lttng_condition *condition =
110 lttng_trigger_get_condition(trigger);
111
112 assert(action);
113 assert(condition);
114
115 /* Release ownership. */
116 lttng_action_put(action);
117 lttng_condition_put(condition);
118
119 free(trigger->name);
120 free(trigger);
121}
122
123void lttng_trigger_destroy(struct lttng_trigger *trigger)
124{
125 lttng_trigger_put(trigger);
126}
127
128LTTNG_HIDDEN
129ssize_t lttng_trigger_create_from_payload(
130 struct lttng_payload_view *src_view,
131 struct lttng_trigger **trigger)
132{
133 ssize_t ret, offset = 0, condition_size, action_size, name_size = 0;
134 struct lttng_condition *condition = NULL;
135 struct lttng_action *action = NULL;
136 const struct lttng_trigger_comm *trigger_comm;
137 const char *name = NULL;
138 struct lttng_credentials creds = {
139 .uid = LTTNG_OPTIONAL_INIT_UNSET,
140 .gid = LTTNG_OPTIONAL_INIT_UNSET,
141 };
142
143 if (!src_view || !trigger) {
144 ret = -1;
145 goto end;
146 }
147
148 /* lttng_trigger_comm header */
149 trigger_comm = (typeof(trigger_comm)) src_view->buffer.data;
150
151 /* Set the trigger's creds. */
152 if (trigger_comm->uid > (uint64_t) ((uid_t) -1)) {
153 /* UID out of range for this platform. */
154 ret = -1;
155 goto end;
156 }
157
158 LTTNG_OPTIONAL_SET(&creds.uid, trigger_comm->uid);
159
160 offset += sizeof(*trigger_comm);
161
162 if (trigger_comm->name_length != 0) {
163 /* Name. */
164 const struct lttng_payload_view name_view =
165 lttng_payload_view_from_view(
166 src_view, offset, trigger_comm->name_length);
167
168 name = name_view.buffer.data;
169 if (!lttng_buffer_view_contains_string(&name_view.buffer, name,
170 trigger_comm->name_length)) {
171 ret = -1;
172 goto end;
173 }
174
175 offset += trigger_comm->name_length;
176 name_size = trigger_comm->name_length;
177 }
178
179 {
180 /* struct lttng_condition */
181 struct lttng_payload_view condition_view =
182 lttng_payload_view_from_view(
183 src_view, offset, -1);
184
185 condition_size = lttng_condition_create_from_payload(&condition_view,
186 &condition);
187 }
188
189 if (condition_size < 0) {
190 ret = condition_size;
191 goto end;
192 }
193
194 offset += condition_size;
195 {
196 /* struct lttng_action */
197 struct lttng_payload_view action_view =
198 lttng_payload_view_from_view(
199 src_view, offset, -1);
200
201 action_size = lttng_action_create_from_payload(&action_view, &action);
202 }
203
204 if (action_size < 0) {
205 ret = action_size;
206 goto end;
207 }
208 offset += action_size;
209
210 /* Unexpected size of inner-elements; the buffer is corrupted. */
211 if ((ssize_t) trigger_comm->length != condition_size + action_size + name_size) {
212 ret = -1;
213 goto error;
214 }
215
216 *trigger = lttng_trigger_create(condition, action);
217 if (!*trigger) {
218 ret = -1;
219 goto error;
220 }
221
222 lttng_trigger_set_credentials(*trigger, &creds);
223
224 /*
225 * The trigger object owns references to the action and condition
226 * objects.
227 */
228 lttng_condition_put(condition);
229 condition = NULL;
230
231 lttng_action_put(action);
232 action = NULL;
233
234 if (name) {
235 const enum lttng_trigger_status status =
236 lttng_trigger_set_name(*trigger, name);
237
238 if (status != LTTNG_TRIGGER_STATUS_OK) {
239 ret = -1;
240 goto end;
241 }
242 }
243
244 ret = offset;
245
246error:
247 lttng_condition_destroy(condition);
248 lttng_action_destroy(action);
249end:
250 return ret;
251}
252
253/*
254 * Both elements are stored contiguously, see their "*_comm" structure
255 * for the detailed format.
256 */
257LTTNG_HIDDEN
258int lttng_trigger_serialize(struct lttng_trigger *trigger,
259 struct lttng_payload *payload)
260{
261 int ret;
262 size_t header_offset, size_before_payload, size_name;
263 struct lttng_trigger_comm trigger_comm = {};
264 struct lttng_trigger_comm *header;
265 const struct lttng_credentials *creds = NULL;
266
267 creds = lttng_trigger_get_credentials(trigger);
268 assert(creds);
269
270 trigger_comm.uid = LTTNG_OPTIONAL_GET(creds->uid);
271
272 if (trigger->name != NULL) {
273 size_name = strlen(trigger->name) + 1;
274 } else {
275 size_name = 0;
276 }
277
278 trigger_comm.name_length = size_name;
279
280 header_offset = payload->buffer.size;
281 ret = lttng_dynamic_buffer_append(&payload->buffer, &trigger_comm,
282 sizeof(trigger_comm));
283 if (ret) {
284 goto end;
285 }
286
287 size_before_payload = payload->buffer.size;
288
289 /* Trigger name. */
290 ret = lttng_dynamic_buffer_append(
291 &payload->buffer, trigger->name, size_name);
292 if (ret) {
293 goto end;
294 }
295
296 ret = lttng_condition_serialize(trigger->condition, payload);
297 if (ret) {
298 goto end;
299 }
300
301 ret = lttng_action_serialize(trigger->action, payload);
302 if (ret) {
303 goto end;
304 }
305
306 /* Update payload size. */
307 header = (typeof(header)) (payload->buffer.data + header_offset);
308 header->length = payload->buffer.size - size_before_payload;
309end:
310 return ret;
311}
312
313LTTNG_HIDDEN
314bool lttng_trigger_is_equal(
315 const struct lttng_trigger *a, const struct lttng_trigger *b)
316{
317 /*
318 * Name is not taken into account since it is cosmetic only.
319 */
320 if (!lttng_condition_is_equal(a->condition, b->condition)) {
321 return false;
322 }
323
324 if (!lttng_action_is_equal(a->action, b->action)) {
325 return false;
326 }
327
328 if (!lttng_credentials_is_equal(lttng_trigger_get_credentials(a),
329 lttng_trigger_get_credentials(b))) {
330 return false;
331 }
332
333 return true;
334}
335
336enum lttng_trigger_status lttng_trigger_set_name(struct lttng_trigger *trigger,
337 const char* name)
338{
339 char *name_copy = NULL;
340 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
341
342 if (!trigger || !name ||
343 strlen(name) == 0) {
344 status = LTTNG_TRIGGER_STATUS_INVALID;
345 goto end;
346 }
347
348 name_copy = strdup(name);
349 if (!name_copy) {
350 status = LTTNG_TRIGGER_STATUS_ERROR;
351 goto end;
352 }
353
354 free(trigger->name);
355
356 trigger->name = name_copy;
357 name_copy = NULL;
358end:
359 return status;
360}
361
362enum lttng_trigger_status lttng_trigger_get_name(
363 const struct lttng_trigger *trigger, const char **name)
364{
365 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
366
367 if (!trigger || !name) {
368 status = LTTNG_TRIGGER_STATUS_INVALID;
369 goto end;
370 }
371
372 if (!trigger->name) {
373 status = LTTNG_TRIGGER_STATUS_UNSET;
374 }
375
376 *name = trigger->name;
377end:
378 return status;
379}
380
381LTTNG_HIDDEN
382int lttng_trigger_assign_name(struct lttng_trigger *dst,
383 const struct lttng_trigger *src)
384{
385 int ret = 0;
386 enum lttng_trigger_status status;
387
388 status = lttng_trigger_set_name(dst, src->name);
389 if (status != LTTNG_TRIGGER_STATUS_OK) {
390 ret = -1;
391 ERR("Failed to set name for trigger");
392 goto end;
393 }
394end:
395 return ret;
396}
397
398LTTNG_HIDDEN
399void lttng_trigger_set_tracer_token(struct lttng_trigger *trigger,
400 uint64_t token)
401{
402 assert(trigger);
403 LTTNG_OPTIONAL_SET(&trigger->tracer_token, token);
404}
405
406LTTNG_HIDDEN
407uint64_t lttng_trigger_get_tracer_token(const struct lttng_trigger *trigger)
408{
409 assert(trigger);
410
411 return LTTNG_OPTIONAL_GET(trigger->tracer_token);
412}
413
414LTTNG_HIDDEN
415int lttng_trigger_generate_name(struct lttng_trigger *trigger,
416 uint64_t unique_id)
417{
418 int ret = 0;
419 char *generated_name = NULL;
420
421 ret = asprintf(&generated_name, "T%" PRIu64 "", unique_id);
422 if (ret < 0) {
423 ERR("Failed to generate trigger name");
424 ret = -1;
425 goto end;
426 }
427
428 ret = 0;
429 free(trigger->name);
430 trigger->name = generated_name;
431end:
432 return ret;
433}
434
435LTTNG_HIDDEN
436void lttng_trigger_get(struct lttng_trigger *trigger)
437{
438 urcu_ref_get(&trigger->ref);
439}
440
441LTTNG_HIDDEN
442void lttng_trigger_put(struct lttng_trigger *trigger)
443{
444 if (!trigger) {
445 return;
446 }
447
448 urcu_ref_put(&trigger->ref , trigger_destroy_ref);
449}
450
451LTTNG_HIDDEN
452const struct lttng_credentials *lttng_trigger_get_credentials(
453 const struct lttng_trigger *trigger)
454{
455 return &trigger->creds;
456}
457
458LTTNG_HIDDEN
459void lttng_trigger_set_credentials(struct lttng_trigger *trigger,
460 const struct lttng_credentials *creds)
461{
462 assert(creds);
463 trigger->creds = *creds;
464}
465
466enum lttng_trigger_status lttng_trigger_set_owner_uid(
467 struct lttng_trigger *trigger, uid_t uid)
468{
469 enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
470 const struct lttng_credentials creds = {
471 .uid = LTTNG_OPTIONAL_INIT_VALUE(uid),
472 .gid = LTTNG_OPTIONAL_INIT_UNSET,
473 };
474
475 if (!trigger) {
476 ret = LTTNG_TRIGGER_STATUS_INVALID;
477 goto end;
478 }
479
480 /* Client-side validation only to report a clearer error. */
481 if (geteuid() != 0) {
482 ret = LTTNG_TRIGGER_STATUS_PERMISSION_DENIED;
483 goto end;
484 }
485
486 lttng_trigger_set_credentials(trigger, &creds);
487
488end:
489 return ret;
490}
491
492enum lttng_trigger_status lttng_trigger_get_owner_uid(
493 const struct lttng_trigger *trigger, uid_t *uid)
494{
495 enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
496 const struct lttng_credentials *creds = NULL;
497
498 if (!trigger || !uid ) {
499 ret = LTTNG_TRIGGER_STATUS_INVALID;
500 goto end;
501 }
502
503 if (!trigger->creds.uid.is_set ) {
504 ret = LTTNG_TRIGGER_STATUS_UNSET;
505 goto end;
506 }
507
508 creds = lttng_trigger_get_credentials(trigger);
509 *uid = lttng_credentials_get_uid(creds);
510
511end:
512 return ret;
513}
This page took 0.024028 seconds and 4 git commands to generate.