struct lttng_condition *condition;
struct lttng_action *action;
- LTTNG_OPTIONAL(struct lttng_credentials) creds;
+ /* For now only the uid portion of the credentials is used. */
+ struct lttng_credentials creds;
};
struct lttng_trigger_comm {
/* length excludes its own length. */
uint32_t length;
+ /*
+ * Credentials, only the uid portion is used for now.
+ * Used as an override when desired by the root user.
+ */
+ uint64_t uid;
/* A condition and action object follow. */
char payload[];
} LTTNG_PACKED;
const struct lttng_trigger *trigger);
LTTNG_HIDDEN
-void lttng_trigger_set_credentials(
- struct lttng_trigger *trigger,
+void lttng_trigger_set_credentials(struct lttng_trigger *trigger,
const struct lttng_credentials *creds);
#endif /* LTTNG_TRIGGER_INTERNAL_H */
#ifndef LTTNG_TRIGGER_H
#define LTTNG_TRIGGER_H
+#include <sys/types.h>
+
struct lttng_action;
struct lttng_condition;
struct lttng_trigger;
LTTNG_REGISTER_TRIGGER_STATUS_INVALID = -1,
};
+enum lttng_trigger_status {
+ LTTNG_TRIGGER_STATUS_OK = 0,
+ LTTNG_TRIGGER_STATUS_ERROR = -1,
+ LTTNG_TRIGGER_STATUS_UNKNOWN = -2,
+ LTTNG_TRIGGER_STATUS_INVALID = -3,
+ LTTNG_TRIGGER_STATUS_UNSET = -4,
+ LTTNG_TRIGGER_STATUS_UNSUPPORTED = -5,
+ LTTNG_TRIGGER_STATUS_PERMISSION_DENIED = -6,
+};
+
/*
* Create a trigger object associating a condition and an action.
*
extern struct lttng_trigger *lttng_trigger_create(
struct lttng_condition *condition, struct lttng_action *action);
+/*
+ * Set the user identity (uid) of a trigger.
+ *
+ * Only available for the root user (uid 0).
+ *
+ * Returns LTTNG_TRIGGER_STATUS_OK on success,
+ * LTTNG_TRIGGER_STATUS_EPERM if not authorized,
+ * LTTNG_TRIGGER_STATUS_INVALID if invalid parameters are passed.
+ */
+extern enum lttng_trigger_status lttng_trigger_set_owner_uid(
+ struct lttng_trigger *trigger, uid_t uid);
+
+/*
+ * Get the user identity (uid) of a trigger.
+ *
+ * Returns LTTNG_TRIGGER_STATUS_OK on success,
+ * LTTNG_TRIGGER_STATUS_UNSET if unset,
+ * LTTNG_TRIGGER_STATUS_INVALID if invalid parameters are passed.
+ */
+extern enum lttng_trigger_status lttng_trigger_get_owner_uid(
+ const struct lttng_trigger *trigger, uid_t *uid);
+
/*
* Get the condition of a trigger.
*
work_item->evaluation,
lttng_trigger_get_credentials(work_item->trigger),
LTTNG_OPTIONAL_GET_PTR(work_item->object_creds),
- client_handle_transmission_status,
- executor);
+ client_handle_transmission_status, executor);
}
static int action_executor_start_session_handler(struct action_executor *executor,
}
}
- /* Set the trigger credential */
- lttng_trigger_set_credentials(trigger, &cmd_creds);
+
+ /*
+ * Validate the trigger credentials against the command credentials.
+ * Only the root user can register a trigger with non-matching
+ * credentials.
+ */
+ if (!lttng_credentials_is_equal_uid(
+ lttng_trigger_get_credentials(trigger),
+ &cmd_creds)) {
+ if (lttng_credentials_get_uid(&cmd_creds) != 0) {
+ ERR("Trigger credentials do not match the command credentials");
+ ret = LTTNG_ERR_INVALID_TRIGGER;
+ goto end;
+ }
+ }
/* Inform the notification thread */
ret = notification_thread_command_register_trigger(notification_thread,
}
}
- lttng_trigger_set_credentials(trigger, &cmd_creds);
+ /*
+ * Validate the trigger credentials against the command credentials.
+ * Only the root user can unregister a trigger with non-matching
+ * credentials.
+ */
+ if (!lttng_credentials_is_equal_uid(
+ lttng_trigger_get_credentials(trigger),
+ &cmd_creds)) {
+ if (lttng_credentials_get_uid(&cmd_creds) != 0) {
+ ERR("Trigger credentials do not match the command credentials");
+ ret = LTTNG_ERR_INVALID_TRIGGER;
+ goto end;
+ }
+ }
ret = notification_thread_command_unregister_trigger(notification_thread,
trigger);
goto end;
}
+ if (!trigger->creds.uid.is_set) {
+ valid = false;
+ goto end;
+ }
+
valid = lttng_condition_validate(trigger->condition) &&
lttng_action_validate(trigger->action);
end:
struct lttng_condition *condition = NULL;
struct lttng_action *action = NULL;
const struct lttng_trigger_comm *trigger_comm;
+ struct lttng_credentials creds = {
+ .uid = LTTNG_OPTIONAL_INIT_UNSET,
+ .gid = LTTNG_OPTIONAL_INIT_UNSET,
+ };
if (!src_view || !trigger) {
ret = -1;
/* lttng_trigger_comm header */
trigger_comm = (typeof(trigger_comm)) src_view->buffer.data;
+
+ /* Set the trigger's creds. */
+ if (trigger_comm->uid > (uint64_t) ((uid_t) -1)) {
+ /* UID out of range for this platform. */
+ ret = -1;
+ goto end;
+ }
+
+ LTTNG_OPTIONAL_SET(&creds.uid, trigger_comm->uid);
+
offset += sizeof(*trigger_comm);
{
/* struct lttng_condition */
goto error;
}
+ lttng_trigger_set_credentials(*trigger, &creds);
+
/*
* The trigger object owns references to the action and condition
* objects.
size_t header_offset, size_before_payload;
struct lttng_trigger_comm trigger_comm = {};
struct lttng_trigger_comm *header;
+ const struct lttng_credentials *creds = NULL;
+
+ creds = lttng_trigger_get_credentials(trigger);
+ assert(creds);
+
+ trigger_comm.uid = LTTNG_OPTIONAL_GET(creds->uid);
header_offset = payload->buffer.size;
ret = lttng_dynamic_buffer_append(&payload->buffer, &trigger_comm,
const struct lttng_credentials *lttng_trigger_get_credentials(
const struct lttng_trigger *trigger)
{
- return LTTNG_OPTIONAL_GET_PTR(trigger->creds);
+ return &trigger->creds;
}
LTTNG_HIDDEN
-void lttng_trigger_set_credentials(
- struct lttng_trigger *trigger,
+void lttng_trigger_set_credentials(struct lttng_trigger *trigger,
const struct lttng_credentials *creds)
{
assert(creds);
- LTTNG_OPTIONAL_SET(&trigger->creds, *creds);
+ trigger->creds = *creds;
+}
+
+enum lttng_trigger_status lttng_trigger_set_owner_uid(
+ struct lttng_trigger *trigger, uid_t uid)
+{
+ enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
+ const struct lttng_credentials creds = {
+ .uid = LTTNG_OPTIONAL_INIT_VALUE(uid),
+ .gid = LTTNG_OPTIONAL_INIT_UNSET,
+ };
+
+ if (!trigger) {
+ ret = LTTNG_TRIGGER_STATUS_INVALID;
+ goto end;
+ }
+
+ /* Client-side validation only to report a clearer error. */
+ if (geteuid() != 0) {
+ ret = LTTNG_TRIGGER_STATUS_PERMISSION_DENIED;
+ goto end;
+ }
+
+ lttng_trigger_set_credentials(trigger, &creds);
+
+end:
+ return ret;
+}
+
+enum lttng_trigger_status lttng_trigger_get_owner_uid(
+ const struct lttng_trigger *trigger, uid_t *uid)
+{
+ enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
+ const struct lttng_credentials *creds = NULL;
+
+ if (!trigger || !uid ) {
+ ret = LTTNG_TRIGGER_STATUS_INVALID;
+ goto end;
+ }
+
+ if (!trigger->creds.uid.is_set ) {
+ ret = LTTNG_TRIGGER_STATUS_UNSET;
+ goto end;
+ }
+
+ creds = lttng_trigger_get_credentials(trigger);
+ *uid = lttng_credentials_get_uid(creds);
+
+end:
+ return ret;
}
struct lttcomm_session_msg *message_lsm;
struct lttng_payload message;
struct lttng_payload reply;
+ const struct lttng_credentials user_creds = {
+ .uid = LTTNG_OPTIONAL_INIT_VALUE(geteuid()),
+ .gid = LTTNG_OPTIONAL_INIT_UNSET,
+ };
lttng_payload_init(&message);
lttng_payload_init(&reply);
goto end;
}
+ if (!trigger->creds.uid.is_set) {
+ /* Use the client's credentials as the trigger credentials. */
+ lttng_trigger_set_credentials(trigger, &user_creds);
+ } else {
+ /*
+ * Validate that either the current trigger credentials and the
+ * client credentials are identical or that the current user is
+ * root. The root user can register, unregister triggers for
+ * himself and other users.
+ *
+ * This check is also present on the sessiond side, using the
+ * credentials passed on the socket. These check are all
+ * "safety" checks.
+ */
+ const struct lttng_credentials *trigger_creds =
+ lttng_trigger_get_credentials(trigger);
+
+ if (!lttng_credentials_is_equal_uid(trigger_creds, &user_creds)) {
+ if (lttng_credentials_get_uid(&user_creds) != 0) {
+ ret = -LTTNG_ERR_EPERM;
+ goto end;
+ }
+ }
+ }
+
if (!lttng_trigger_validate(trigger)) {
ret = -LTTNG_ERR_INVALID_TRIGGER;
goto end;
struct lttcomm_session_msg *message_lsm;
struct lttng_payload message;
struct lttng_payload reply;
+ const struct lttng_credentials user_creds = {
+ .uid = LTTNG_OPTIONAL_INIT_VALUE(geteuid()),
+ .gid = LTTNG_OPTIONAL_INIT_UNSET,
+ };
lttng_payload_init(&message);
lttng_payload_init(&reply);
goto end;
}
+ if (!trigger->creds.uid.is_set) {
+ /* Use the client's credentials as the trigger credentials. */
+ lttng_trigger_set_credentials(trigger, &user_creds);
+ } else {
+ /*
+ * Validate that either the current trigger credentials and the
+ * client credentials are identical or that the current user is
+ * root. The root user can register, unregister triggers for
+ * himself and other users.
+ *
+ * This check is also present on the sessiond side, using the
+ * credentials passed on the socket. These check are all
+ * "safety" checks.
+ */
+ const struct lttng_credentials *trigger_creds =
+ lttng_trigger_get_credentials(trigger);
+
+ if (!lttng_credentials_is_equal_uid(trigger_creds, &user_creds)) {
+ if (lttng_credentials_get_uid(&user_creds) != 0) {
+ ret = -LTTNG_ERR_EPERM;
+ goto end;
+ }
+ }
+ }
+
if (!lttng_trigger_validate(trigger)) {
ret = -LTTNG_ERR_INVALID_TRIGGER;
goto end;