#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);
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",
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 */
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);
+}