]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
varlink: add generic GetEnvironment() call to the Varlink "service" interface
authorLennart Poettering <lennart@poettering.net>
Tue, 7 Jan 2025 14:23:28 +0000 (15:23 +0100)
committerLennart Poettering <lennart@poettering.net>
Sat, 18 Jan 2025 22:24:29 +0000 (23:24 +0100)
It's just so useful being able to retrieve the current env block from
our services. Add a concept for that. It's really simple, and dumb.

In many ways it's like /proc/$PID/environ, but shows the actual
environ[] array visible to the app, not just some memory that was
originally used for the env block passed in, but might have been rearranged.

src/shared/varlink-io.systemd.service.c
src/shared/varlink-io.systemd.service.h

index 32ed12fd19da93bc6089b6395f0d11c618b08e8f..dd1329f8788a5f1040781252674aa84a022d4bfd 100644 (file)
@@ -2,7 +2,9 @@
 
 #include <unistd.h>
 
+#include "env-util.h"
 #include "json-util.h"
+#include "strv.h"
 #include "varlink-io.systemd.service.h"
 
 static SD_VARLINK_DEFINE_METHOD(Ping);
@@ -14,6 +16,14 @@ static SD_VARLINK_DEFINE_METHOD(
                 SD_VARLINK_FIELD_COMMENT("The maximum log level, using BSD syslog log level integers."),
                 SD_VARLINK_DEFINE_INPUT(level, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
 
+static SD_VARLINK_DEFINE_METHOD(
+                GetEnvironment,
+                SD_VARLINK_FIELD_COMMENT("Returns the current environment block, i.e. the contents of environ[]."),
+                SD_VARLINK_DEFINE_OUTPUT(environment, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY));
+
+static SD_VARLINK_DEFINE_ERROR(
+                InconsistentEnvironment);
+
 SD_VARLINK_DEFINE_INTERFACE(
                 io_systemd_service,
                 "io.systemd.service",
@@ -23,7 +33,11 @@ SD_VARLINK_DEFINE_INTERFACE(
                 SD_VARLINK_SYMBOL_COMMENT("Reloads configuration files."),
                 &vl_method_Reload,
                 SD_VARLINK_SYMBOL_COMMENT("Sets the maximum log level."),
-                &vl_method_SetLogLevel);
+                &vl_method_SetLogLevel,
+                SD_VARLINK_SYMBOL_COMMENT("Get current environment block."),
+                &vl_method_GetEnvironment,
+                SD_VARLINK_SYMBOL_COMMENT("Returned if the environment block is currently not in a valid state."),
+                &vl_error_InconsistentEnvironment);
 
 /* Generic implementations for some of the method calls above */
 
@@ -70,3 +84,48 @@ int varlink_method_set_log_level(sd_varlink *link, sd_json_variant *parameters,
 
         return sd_varlink_reply(link, NULL);
 }
+
+int varlink_method_get_environment(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
+        uid_t uid;
+        int r;
+
+        assert(link);
+        assert(parameters);
+
+        /* This is a lot like /proc/$PID/environ, but can properly report the actual environment block as
+         * seen from the process itself, which might be quite different from the contents of the memory that
+         * was originally passed in. This is particularly relevant for cases where the environ[] block has
+         * been enlarged and similar. */
+
+        r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL);
+        if (r != 0)
+                return r;
+
+        r = sd_varlink_get_peer_uid(link, &uid);
+        if (r < 0)
+                return r;
+
+        /* Don't hand out environment block to arbitrary clients, in some cases people might make the mistake
+         * of passing secrets via env vars */
+        if (uid != 0 && uid != getuid())
+                return sd_varlink_error(link, SD_VARLINK_ERROR_PERMISSION_DENIED, parameters);
+
+        log_debug("Received io.systemd.service.GetEnvironment()");
+
+        _cleanup_strv_free_ char **l = NULL;
+        STRV_FOREACH(e, environ) {
+                if (!env_assignment_is_valid(*e))
+                        goto invalid;
+                if (!utf8_is_valid(*e))
+                        goto invalid;
+
+                r = strv_env_replace_strdup(&l, *e);
+                if (r < 0)
+                        return r;
+        }
+
+        return sd_varlink_replybo(link, SD_JSON_BUILD_PAIR_STRV("environment", l));
+
+invalid:
+        return sd_varlink_error(link, "io.systemd.service.InconsistentEnvironment", parameters);
+}
index 3f164783f598cfdf8f14fedd33861795d066632c..a68d58d6d452d83aa653612035d5c8d4ee6a8177 100644 (file)
@@ -8,3 +8,4 @@ extern const sd_varlink_interface vl_interface_io_systemd_service;
 
 int varlink_method_ping(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
 int varlink_method_set_log_level(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
+int varlink_method_get_environment(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);