From: Lennart Poettering Date: Tue, 7 Jan 2025 14:23:28 +0000 (+0100) Subject: varlink: add generic GetEnvironment() call to the Varlink "service" interface X-Git-Tag: v258-rc1~1559^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fef9eb4e6af5c224258959dbdd266eb53bac057f;p=thirdparty%2Fsystemd.git varlink: add generic GetEnvironment() call to the Varlink "service" interface 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. --- diff --git a/src/shared/varlink-io.systemd.service.c b/src/shared/varlink-io.systemd.service.c index 32ed12fd19d..dd1329f8788 100644 --- a/src/shared/varlink-io.systemd.service.c +++ b/src/shared/varlink-io.systemd.service.c @@ -2,7 +2,9 @@ #include +#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); +} diff --git a/src/shared/varlink-io.systemd.service.h b/src/shared/varlink-io.systemd.service.h index 3f164783f59..a68d58d6d45 100644 --- a/src/shared/varlink-io.systemd.service.h +++ b/src/shared/varlink-io.systemd.service.h @@ -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);