1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "bus-error.h"
4 #include "bus-locator.h"
5 #include "env-util.h"
6 #include "escape.h"
7 #include "systemctl-set-environment.h"
8 #include "systemctl-util.h"
9 #include "systemctl.h"
10 
json_transform_message(sd_bus_message * m,JsonVariant ** ret)11 static int json_transform_message(sd_bus_message *m, JsonVariant **ret) {
12         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
13         const char *text;
14         int r;
15 
16         assert(m);
17         assert(ret);
18 
19         while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &text)) > 0) {
20                 _cleanup_free_ char *n = NULL;
21                 const char *sep;
22 
23                 sep = strchr(text, '=');
24                 if (!sep)
25                         return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
26                                                "Invalid environment block");
27 
28                 n = strndup(text, sep - text);
29                 if (!n)
30                         return log_oom();
31 
32                 sep++;
33 
34                 r = json_variant_set_field_string(&v, n, sep);
35                 if (r < 0)
36                         return log_error_errno(r, "Failed to set JSON field '%s' to '%s': %m", n, sep);
37         }
38         if (r < 0)
39                 return bus_log_parse_error(r);
40 
41         *ret = TAKE_PTR(v);
42         return 0;
43 }
44 
print_variable(const char * s)45 static int print_variable(const char *s) {
46         const char *sep;
47         _cleanup_free_ char *esc = NULL;
48 
49         sep = strchr(s, '=');
50         if (!sep)
51                 return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
52                                        "Invalid environment block");
53 
54         esc = shell_maybe_quote(sep + 1, SHELL_ESCAPE_POSIX);
55         if (!esc)
56                 return log_oom();
57 
58         printf("%.*s=%s\n", (int)(sep-s), s, esc);
59         return 0;
60 }
61 
verb_show_environment(int argc,char * argv[],void * userdata)62 int verb_show_environment(int argc, char *argv[], void *userdata) {
63         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
64         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
65         const char *text;
66         sd_bus *bus;
67         int r;
68 
69         r = acquire_bus(BUS_MANAGER, &bus);
70         if (r < 0)
71                 return r;
72 
73         pager_open(arg_pager_flags);
74 
75         r = bus_get_property(bus, bus_systemd_mgr, "Environment", &error, &reply, "as");
76         if (r < 0)
77                 return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r));
78 
79         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
80         if (r < 0)
81                 return bus_log_parse_error(r);
82 
83         if (OUTPUT_MODE_IS_JSON(arg_output)) {
84                 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
85 
86                 r = json_transform_message(reply, &v);
87                 if (r < 0)
88                         return r;
89 
90                 json_variant_dump(v, output_mode_to_json_format_flags(arg_output), stdout, NULL);
91         } else {
92                 while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0) {
93                         r = print_variable(text);
94                         if (r < 0)
95                                 return r;
96                 }
97                 if (r < 0)
98                         return bus_log_parse_error(r);
99         }
100 
101         r = sd_bus_message_exit_container(reply);
102         if (r < 0)
103                 return bus_log_parse_error(r);
104 
105         return 0;
106 }
107 
invalid_callback(const char * p,void * userdata)108 static void invalid_callback(const char *p, void *userdata) {
109         _cleanup_free_ char *t = cescape(p);
110 
111         log_debug("Ignoring invalid environment assignment \"%s\".", strnull(t));
112 }
113 
verb_set_environment(int argc,char * argv[],void * userdata)114 int verb_set_environment(int argc, char *argv[], void *userdata) {
115         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
116         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
117         const char *method;
118         sd_bus *bus;
119         int r;
120 
121         assert(argc > 1);
122         assert(argv);
123 
124         r = acquire_bus(BUS_MANAGER, &bus);
125         if (r < 0)
126                 return r;
127 
128         polkit_agent_open_maybe();
129 
130         method = streq(argv[0], "set-environment")
131                 ? "SetEnvironment"
132                 : "UnsetEnvironment";
133 
134         r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
135         if (r < 0)
136                 return bus_log_create_error(r);
137 
138         r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
139         if (r < 0)
140                 return bus_log_create_error(r);
141 
142         r = sd_bus_call(bus, m, 0, &error, NULL);
143         if (r < 0)
144                 return log_error_errno(r, "Failed to set environment: %s", bus_error_message(&error, r));
145 
146         return 0;
147 }
148 
verb_import_environment(int argc,char * argv[],void * userdata)149 int verb_import_environment(int argc, char *argv[], void *userdata) {
150         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
151         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
152         sd_bus *bus;
153         int r;
154 
155         r = acquire_bus(BUS_MANAGER, &bus);
156         if (r < 0)
157                 return r;
158 
159         polkit_agent_open_maybe();
160 
161         r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "SetEnvironment");
162         if (r < 0)
163                 return bus_log_create_error(r);
164 
165         if (argc < 2) {
166                 log_warning("Calling import-environment without a list of variable names is deprecated.");
167 
168                 _cleanup_strv_free_ char **copy = strv_copy(environ);
169                 if (!copy)
170                         return log_oom();
171 
172                 strv_env_clean_with_callback(copy, invalid_callback, NULL);
173 
174                 STRV_FOREACH(e, copy)
175                         if (string_has_cc(*e, NULL))
176                                 log_notice("Environment variable $%.*s contains control characters, importing anyway.",
177                                            (int) strcspn(*e, "="), *e);
178 
179                 r = sd_bus_message_append_strv(m, copy);
180 
181         } else {
182                 r = sd_bus_message_open_container(m, 'a', "s");
183                 if (r < 0)
184                         return bus_log_create_error(r);
185 
186                 STRV_FOREACH(a, strv_skip(argv, 1)) {
187 
188                         if (!env_name_is_valid(*a))
189                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
190                                                        "Not a valid environment variable name: %s", *a);
191 
192                         bool found = false;
193                         STRV_FOREACH(b, environ) {
194                                 const char *eq;
195 
196                                 eq = startswith(*b, *a);
197                                 if (eq && *eq == '=') {
198                                         if (string_has_cc(eq + 1, NULL))
199                                                 log_notice("Environment variable $%.*s contains control characters, importing anyway.",
200                                                            (int) (eq - *b), *b);
201 
202                                         r = sd_bus_message_append(m, "s", *b);
203                                         if (r < 0)
204                                                 return bus_log_create_error(r);
205 
206                                         found = true;
207                                         break;
208                                 }
209                         }
210 
211                         if (!found)
212                                 log_notice("Environment variable $%s not set, ignoring.", *a);
213                 }
214 
215                 r = sd_bus_message_close_container(m);
216         }
217         if (r < 0)
218                 return bus_log_create_error(r);
219 
220         r = sd_bus_call(bus, m, 0, &error, NULL);
221         if (r < 0)
222                 return log_error_errno(r, "Failed to import environment: %s", bus_error_message(&error, r));
223 
224         return 0;
225 }
226