trigger: expose trigger owner uid
[lttng-tools.git] / src / lib / lttng-ctl / lttng-ctl.c
index b2f25ecd06ac58c471f94c4ea34daa2d30383cbb..60dcdc7d33872cbf190e79b1dfe9e3385f72e545 100644 (file)
 #define _LGPL_SOURCE
 #include <assert.h>
 #include <grp.h>
-#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include <common/common.h>
+#include <common/compat/errno.h>
 #include <common/compat/string.h>
 #include <common/defaults.h>
 #include <common/dynamic-buffer.h>
+#include <common/dynamic-array.h>
 #include <common/payload.h>
 #include <common/payload-view.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 #include <common/tracker.h>
+#include <common/unix.h>
 #include <common/uri.h>
 #include <common/utils.h>
 #include <lttng/channel-internal.h>
 #include <lttng/session-internal.h>
 #include <lttng/trigger/trigger-internal.h>
 #include <lttng/userspace-probe-internal.h>
+#include <lttng/lttng-error.h>
 
-#include "filter/filter-ast.h"
-#include "filter/filter-parser.h"
-#include "filter/filter-bytecode.h"
-#include "filter/memstream.h"
+#include <common/filter/filter-ast.h>
+#include <common/filter/filter-parser.h>
+#include <common/filter/filter-bytecode.h>
+#include <common/filter/memstream.h>
 #include "lttng-ctl-helper.h"
 
-#ifdef DEBUG
-static const int print_xml = 1;
-#define dbg_printf(fmt, args...)       \
-       printf("[debug liblttng-ctl] " fmt, ## args)
-#else
-static const int print_xml = 0;
-#define dbg_printf(fmt, args...)                               \
-do {                                                           \
-       /* do nothing but check printf format */                \
-       if (0)                                                  \
-               printf("[debug liblttnctl] " fmt, ## args);     \
-} while (0)
-#endif
-
 #define COPY_DOMAIN_PACKED(dst, src)                           \
 do {                                                           \
        struct lttng_domain _tmp_domain;                        \
@@ -627,9 +616,10 @@ int lttng_ctl_ask_sessiond_payload(struct lttng_payload_view *message,
 {
        int ret;
        struct lttcomm_lttng_msg llm;
+       const int fd_count = lttng_payload_view_get_fd_handle_count(message);
 
        assert(reply->buffer.size == 0);
-       assert(reply->_fds.size == 0);
+       assert(lttng_dynamic_pointer_array_get_count(&reply->_fd_handles) == 0);
 
        ret = connect_sessiond();
        if (ret < 0) {
@@ -648,10 +638,13 @@ int lttng_ctl_ask_sessiond_payload(struct lttng_payload_view *message,
                goto end;
        }
 
-       if (lttng_payload_view_get_fd_count(message) > 0) {
-               ret = lttcomm_send_fds_unix_sock(sessiond_socket,
-                               (const int *) message->_fds.buffer.data,
-                               lttng_dynamic_array_get_count(&message->_fds));
+       if (fd_count > 0) {
+               ret = lttcomm_send_payload_view_fds_unix_sock(sessiond_socket,
+                               message);
+               if (ret < 0) {
+                       ret = -LTTNG_ERR_FATAL;
+                       goto end;
+               }
        }
 
        /* Get header from data transmission */
@@ -685,19 +678,9 @@ int lttng_ctl_ask_sessiond_payload(struct lttng_payload_view *message,
        }
 
        if (llm.fd_count > 0) {
-               ret = lttng_dynamic_array_set_count(&reply->_fds, llm.fd_count);
-               if (ret) {
-                       ret = -LTTNG_ERR_NOMEM;
-                       goto end;
-               }
-
-               ret = lttcomm_recv_fds_unix_sock(sessiond_socket,
-                               (int *) reply->_fds.buffer.data, llm.fd_count);
-               if (ret > 0 && ret != llm.fd_count * sizeof(int)) {
-                       ret = -LTTNG_ERR_INVALID_PROTOCOL;
-                       goto end;
-               } else if (ret <= 0) {
-                       ret = -LTTNG_ERR_FATAL;
+               ret = lttcomm_recv_payload_fds_unix_sock(
+                               sessiond_socket, llm.fd_count, reply);
+               if (ret < 0) {
                        goto end;
                }
        }
@@ -1053,133 +1036,6 @@ error:
        return NULL;
 }
 
-/*
- * Generate the filter bytecode from a given filter expression string. Put the
- * newly allocated parser context in ctxp and populate the lsm object with the
- * expression len.
- *
- * Return 0 on success else a LTTNG_ERR_* code and ctxp is untouched.
- */
-static int generate_filter(char *filter_expression,
-               struct lttcomm_session_msg *lsm, struct filter_parser_ctx **ctxp)
-{
-       int ret;
-       struct filter_parser_ctx *ctx = NULL;
-       FILE *fmem = NULL;
-
-       assert(filter_expression);
-       assert(lsm);
-       assert(ctxp);
-
-       /*
-        * Casting const to non-const, as the underlying function will use it in
-        * read-only mode.
-        */
-       fmem = lttng_fmemopen((void *) filter_expression,
-                       strlen(filter_expression), "r");
-       if (!fmem) {
-               fprintf(stderr, "Error opening memory as stream\n");
-               ret = -LTTNG_ERR_FILTER_NOMEM;
-               goto error;
-       }
-       ctx = filter_parser_ctx_alloc(fmem);
-       if (!ctx) {
-               fprintf(stderr, "Error allocating parser\n");
-               ret = -LTTNG_ERR_FILTER_NOMEM;
-               goto filter_alloc_error;
-       }
-       ret = filter_parser_ctx_append_ast(ctx);
-       if (ret) {
-               fprintf(stderr, "Parse error\n");
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-       if (print_xml) {
-               ret = filter_visitor_print_xml(ctx, stdout, 0);
-               if (ret) {
-                       fflush(stdout);
-                       fprintf(stderr, "XML print error\n");
-                       ret = -LTTNG_ERR_FILTER_INVAL;
-                       goto parse_error;
-               }
-       }
-
-       dbg_printf("Generating IR... ");
-       fflush(stdout);
-       ret = filter_visitor_ir_generate(ctx);
-       if (ret) {
-               fprintf(stderr, "Generate IR error\n");
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-       dbg_printf("done\n");
-
-       dbg_printf("Validating IR... ");
-       fflush(stdout);
-       ret = filter_visitor_ir_check_binary_op_nesting(ctx);
-       if (ret) {
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-
-       /* Normalize globbing patterns in the expression. */
-       ret = filter_visitor_ir_normalize_glob_patterns(ctx);
-       if (ret) {
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-
-       /* Validate strings used as literals in the expression. */
-       ret = filter_visitor_ir_validate_string(ctx);
-       if (ret) {
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-
-       /* Validate globbing patterns in the expression. */
-       ret = filter_visitor_ir_validate_globbing(ctx);
-       if (ret) {
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-
-       dbg_printf("done\n");
-
-       dbg_printf("Generating bytecode... ");
-       fflush(stdout);
-       ret = filter_visitor_bytecode_generate(ctx);
-       if (ret) {
-               fprintf(stderr, "Generate bytecode error\n");
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-       dbg_printf("done\n");
-       dbg_printf("Size of bytecode generated: %u bytes.\n",
-                       bytecode_get_len(&ctx->bytecode->b));
-
-       lsm->u.enable.bytecode_len = sizeof(ctx->bytecode->b)
-               + bytecode_get_len(&ctx->bytecode->b);
-       lsm->u.enable.expression_len = strlen(filter_expression) + 1;
-
-       /* No need to keep the memory stream. */
-       if (fclose(fmem) != 0) {
-               PERROR("fclose");
-       }
-
-       *ctxp = ctx;
-       return 0;
-
-parse_error:
-       filter_ir_free(ctx);
-       filter_parser_ctx_free(ctx);
-filter_alloc_error:
-       if (fclose(fmem) != 0) {
-               PERROR("fclose");
-       }
-error:
-       return ret;
-}
-
 /*
  * Enable event(s) for a channel, possibly with exclusions and a filter.
  * If no event name is specified, all events are enabled.
@@ -1282,10 +1138,14 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle,
                        }
                }
 
-               ret = generate_filter(filter_expression, &lsm, &ctx);
+               ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx);
                if (ret) {
                        goto filter_error;
                }
+
+               lsm.u.enable.bytecode_len = sizeof(ctx->bytecode->b)
+                       + bytecode_get_len(&ctx->bytecode->b);
+               lsm.u.enable.expression_len = strlen(filter_expression) + 1;
        }
 
        ret = lttng_dynamic_buffer_set_capacity(&payload.buffer,
@@ -1360,7 +1220,7 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle,
        {
                struct lttng_payload_view view = lttng_payload_view_from_payload(
                        &payload, 0, -1);
-               int fd_count = lttng_payload_view_get_fd_count(&view);
+               int fd_count = lttng_payload_view_get_fd_handle_count(&view);
                int fd_to_send;
 
                if (fd_count < 0) {
@@ -1369,12 +1229,15 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle,
 
                assert(fd_count == 0 || fd_count == 1);
                if (fd_count == 1) {
-                       ret = lttng_payload_view_pop_fd(&view);
-                       if (ret < 0) {
+                       struct fd_handle *handle =
+                                       lttng_payload_view_pop_fd_handle(&view);
+
+                       if (!handle) {
                                goto mem_error;
                        }
 
-                       fd_to_send = ret;
+                       fd_to_send = fd_handle_get_fd(handle);
+                       fd_handle_put(handle);
                }
 
                ret = lttng_ctl_ask_sessiond_fds_varlen(&lsm,
@@ -1509,10 +1372,14 @@ int lttng_disable_event_ext(struct lttng_handle *handle,
                        }
                }
 
-               ret = generate_filter(filter_expression, &lsm, &ctx);
+               ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx);
                if (ret) {
                        goto filter_error;
                }
+
+               lsm.u.enable.bytecode_len = sizeof(ctx->bytecode->b)
+                       + bytecode_get_len(&ctx->bytecode->b);
+               lsm.u.enable.expression_len = strlen(filter_expression) + 1;
        }
 
        varlen_data = zmalloc(lsm.u.disable.bytecode_len
@@ -3083,33 +2950,92 @@ end:
 int lttng_register_trigger(struct lttng_trigger *trigger)
 {
        int ret;
-       struct lttcomm_session_msg lsm;
-       struct lttng_payload payload;
+       struct lttcomm_session_msg lsm = {
+               .cmd_type = LTTNG_REGISTER_TRIGGER,
+       };
+       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);
 
-       lttng_payload_init(&payload);
        if (!trigger) {
                ret = -LTTNG_ERR_INVALID;
                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;
        }
 
-       ret = lttng_trigger_serialize(trigger, &payload);
+       ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm));
+       if (ret) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       /*
+        * This is needed to populate the trigger object size for the command
+        * header.
+       */
+       message_lsm = (struct lttcomm_session_msg *) message.buffer.data;
+
+       ret = lttng_trigger_serialize(trigger, &message);
        if (ret < 0) {
                ret = -LTTNG_ERR_UNK;
                goto end;
        }
 
-       memset(&lsm, 0, sizeof(lsm));
-       lsm.cmd_type = LTTNG_REGISTER_TRIGGER;
-       lsm.u.trigger.length = (uint32_t) payload.buffer.size;
-       ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(
-                       &lsm, payload.buffer.data, payload.buffer.size, NULL);
+       message_lsm->u.trigger.length = (uint32_t) message.buffer.size - sizeof(lsm);
+
+       {
+               struct lttng_payload_view message_view =
+                               lttng_payload_view_from_payload(
+                                               &message, 0, -1);
+
+               message_lsm->fd_count = lttng_payload_view_get_fd_handle_count(
+                               &message_view);
+               ret = lttng_ctl_ask_sessiond_payload(&message_view, &reply);
+               if (ret < 0) {
+                       goto end;
+               }
+       }
+
+       ret = 0;
 end:
-       lttng_payload_reset(&payload);
+       lttng_payload_reset(&message);
+       lttng_payload_reset(&reply);
        return ret;
 }
 
@@ -3117,32 +3043,97 @@ int lttng_unregister_trigger(struct lttng_trigger *trigger)
 {
        int ret;
        struct lttcomm_session_msg lsm;
-       struct lttng_payload payload;
+       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);
 
-       lttng_payload_init(&payload);
        if (!trigger) {
                ret = -LTTNG_ERR_INVALID;
                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;
        }
 
-       ret = lttng_trigger_serialize(trigger, &payload);
+       memset(&lsm, 0, sizeof(lsm));
+       lsm.cmd_type = LTTNG_UNREGISTER_TRIGGER;
+
+       ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm));
+       if (ret) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       /*
+        * This is needed to populate the trigger object size for the command
+        * header and number of fds sent.
+       */
+       message_lsm = (struct lttcomm_session_msg *) message.buffer.data;
+
+       ret = lttng_trigger_serialize(trigger, &message);
        if (ret < 0) {
                ret = -LTTNG_ERR_UNK;
                goto end;
        }
 
-       memset(&lsm, 0, sizeof(lsm));
-       lsm.cmd_type = LTTNG_UNREGISTER_TRIGGER;
-       lsm.u.trigger.length = (uint32_t) payload.buffer.size;
-       ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(
-                       &lsm, payload.buffer.data, payload.buffer.size, NULL);
+       message_lsm->u.trigger.length = (uint32_t) message.buffer.size - sizeof(lsm);
+
+       {
+               struct lttng_payload_view message_view =
+                               lttng_payload_view_from_payload(
+                                               &message, 0, -1);
+
+               /*
+                * Update the message header with the number of fd that will be
+                * sent.
+                */
+               message_lsm->fd_count = lttng_payload_view_get_fd_handle_count(
+                               &message_view);
+
+               ret = lttng_ctl_ask_sessiond_payload(&message_view, &reply);
+               if (ret < 0) {
+                       goto end;
+               }
+       }
+
+       ret = 0;
 end:
-       lttng_payload_reset(&payload);
+       lttng_payload_reset(&message);
+       lttng_payload_reset(&reply);
        return ret;
 }
 
This page took 0.028395 seconds and 4 git commands to generate.