]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-execute.c
honor SELinux labels, when creating and writing config files
[thirdparty/systemd.git] / src / core / dbus-execute.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <dbus/dbus.h>
24 #include <sys/prctl.h>
25
26 #include "dbus-execute.h"
27 #include "missing.h"
28 #include "ioprio.h"
29 #include "strv.h"
30 #include "dbus-common.h"
31 #include "syscall-list.h"
32 #include "fileio.h"
33
34 DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput);
35 DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput);
36
37 int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data) {
38 char **env_files = data, **j;
39 DBusMessageIter sub, sub2;
40
41 assert(i);
42 assert(property);
43
44 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sb)", &sub))
45 return -ENOMEM;
46
47 STRV_FOREACH(j, env_files) {
48 dbus_bool_t b = false;
49 char *fn = *j;
50
51 if (fn[0] == '-') {
52 b = true;
53 fn++;
54 }
55
56 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
57 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &fn) ||
58 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) ||
59 !dbus_message_iter_close_container(&sub, &sub2))
60 return -ENOMEM;
61 }
62
63 if (!dbus_message_iter_close_container(i, &sub))
64 return -ENOMEM;
65
66 return 0;
67 }
68
69 int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data) {
70 ExecContext *c = data;
71 int32_t n;
72
73 assert(i);
74 assert(property);
75 assert(c);
76
77 if (c->oom_score_adjust_set)
78 n = c->oom_score_adjust;
79 else {
80 char *t;
81
82 n = 0;
83 if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0) {
84 safe_atoi(t, &n);
85 free(t);
86 }
87 }
88
89 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
90 return -ENOMEM;
91
92 return 0;
93 }
94
95 int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data) {
96 ExecContext *c = data;
97 int32_t n;
98
99 assert(i);
100 assert(property);
101 assert(c);
102
103 if (c->nice_set)
104 n = c->nice;
105 else
106 n = getpriority(PRIO_PROCESS, 0);
107
108 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
109 return -ENOMEM;
110
111 return 0;
112 }
113
114 int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data) {
115 ExecContext *c = data;
116 int32_t n;
117
118 assert(i);
119 assert(property);
120 assert(c);
121
122 if (c->ioprio_set)
123 n = c->ioprio;
124 else
125 n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
126
127 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
128 return -ENOMEM;
129
130 return 0;
131 }
132
133 int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data) {
134 ExecContext *c = data;
135 int32_t n;
136
137 assert(i);
138 assert(property);
139 assert(c);
140
141 if (c->cpu_sched_set)
142 n = c->cpu_sched_policy;
143 else
144 n = sched_getscheduler(0);
145
146 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
147 return -ENOMEM;
148
149 return 0;
150 }
151
152 int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data) {
153 ExecContext *c = data;
154 int32_t n;
155
156 assert(i);
157 assert(property);
158 assert(c);
159
160 if (c->cpu_sched_set)
161 n = c->cpu_sched_priority;
162 else {
163 struct sched_param p;
164 n = 0;
165
166 zero(p);
167 if (sched_getparam(0, &p) >= 0)
168 n = p.sched_priority;
169 }
170
171 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
172 return -ENOMEM;
173
174 return 0;
175 }
176
177 int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data) {
178 ExecContext *c = data;
179 dbus_bool_t b;
180 DBusMessageIter sub;
181
182 assert(i);
183 assert(property);
184 assert(c);
185
186 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub))
187 return -ENOMEM;
188
189 if (c->cpuset)
190 b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
191 else
192 b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, 0);
193
194 if (!b)
195 return -ENOMEM;
196
197 if (!dbus_message_iter_close_container(i, &sub))
198 return -ENOMEM;
199
200 return 0;
201 }
202
203 int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data) {
204 ExecContext *c = data;
205 uint64_t u;
206
207 assert(i);
208 assert(property);
209 assert(c);
210
211 if (c->timer_slack_nsec != (nsec_t) -1)
212 u = (uint64_t) c->timer_slack_nsec;
213 else
214 u = (uint64_t) prctl(PR_GET_TIMERSLACK);
215
216 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
217 return -ENOMEM;
218
219 return 0;
220 }
221
222 int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data) {
223 ExecContext *c = data;
224 uint64_t normal, inverted;
225
226 assert(i);
227 assert(property);
228 assert(c);
229
230 /* We store this negated internally, to match the kernel, but
231 * we expose it normalized. */
232
233 normal = *(uint64_t*) data;
234 inverted = ~normal;
235
236 return bus_property_append_uint64(i, property, &inverted);
237 }
238
239 int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data) {
240 ExecContext *c = data;
241 char *t = NULL;
242 const char *s;
243 dbus_bool_t b;
244
245 assert(i);
246 assert(property);
247 assert(c);
248
249 if (c->capabilities)
250 s = t = cap_to_text(c->capabilities, NULL);
251 else
252 s = "";
253
254 if (!s)
255 return -ENOMEM;
256
257 b = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &s);
258
259 if (t)
260 cap_free(t);
261
262 if (!b)
263 return -ENOMEM;
264
265 return 0;
266 }
267
268 int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data) {
269 ExecContext *c = data;
270 int r;
271 uint64_t u;
272
273 assert(i);
274 assert(property);
275 assert(c);
276
277 assert_se((r = rlimit_from_string(property)) >= 0);
278
279 if (c->rlimit[r])
280 u = (uint64_t) c->rlimit[r]->rlim_max;
281 else {
282 struct rlimit rl;
283
284 zero(rl);
285 getrlimit(r, &rl);
286
287 u = (uint64_t) rl.rlim_max;
288 }
289
290 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
291 return -ENOMEM;
292
293 return 0;
294 }
295
296 int bus_execute_append_command(DBusMessageIter *i, const char *property, void *data) {
297 ExecCommand *c = data;
298 DBusMessageIter sub, sub2, sub3;
299
300 assert(i);
301 assert(property);
302
303 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sasbttttuii)", &sub))
304 return -ENOMEM;
305
306 LIST_FOREACH(command, c, c) {
307 char **l;
308 uint32_t pid;
309 int32_t code, status;
310 dbus_bool_t b;
311
312 if (!c->path)
313 continue;
314
315 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
316 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &c->path) ||
317 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_ARRAY, "s", &sub3))
318 return -ENOMEM;
319
320 STRV_FOREACH(l, c->argv)
321 if (!dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, l))
322 return -ENOMEM;
323
324 pid = (uint32_t) c->exec_status.pid;
325 code = (int32_t) c->exec_status.code;
326 status = (int32_t) c->exec_status.status;
327
328 b = !!c->ignore;
329
330 if (!dbus_message_iter_close_container(&sub2, &sub3) ||
331 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) ||
332 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.realtime) ||
333 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.monotonic) ||
334 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.realtime) ||
335 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.monotonic) ||
336 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid) ||
337 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &code) ||
338 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &status))
339 return -ENOMEM;
340
341 if (!dbus_message_iter_close_container(&sub, &sub2))
342 return -ENOMEM;
343 }
344
345 if (!dbus_message_iter_close_container(i, &sub))
346 return -ENOMEM;
347
348 return 0;
349 }
350
351 int bus_execute_append_syscall_filter(DBusMessageIter *i, const char *property, void *data) {
352 ExecContext *c = data;
353 dbus_bool_t b;
354 DBusMessageIter sub;
355
356 assert(i);
357 assert(property);
358 assert(c);
359
360 if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "u", &sub))
361 return -ENOMEM;
362
363 if (c->syscall_filter)
364 b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_UINT32, &c->syscall_filter, (syscall_max() + 31) >> 4);
365 else
366 b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_UINT32, &c->syscall_filter, 0);
367
368 if (!b)
369 return -ENOMEM;
370
371 if (!dbus_message_iter_close_container(i, &sub))
372 return -ENOMEM;
373
374 return 0;
375 }
376
377 const BusProperty bus_exec_context_properties[] = {
378 { "Environment", bus_property_append_strv, "as", offsetof(ExecContext, environment), true },
379 { "EnvironmentFiles", bus_execute_append_env_files, "a(sb)", offsetof(ExecContext, environment_files), true },
380 { "UMask", bus_property_append_mode, "u", offsetof(ExecContext, umask) },
381 { "LimitCPU", bus_execute_append_rlimits, "t", 0 },
382 { "LimitFSIZE", bus_execute_append_rlimits, "t", 0 },
383 { "LimitDATA", bus_execute_append_rlimits, "t", 0 },
384 { "LimitSTACK", bus_execute_append_rlimits, "t", 0 },
385 { "LimitCORE", bus_execute_append_rlimits, "t", 0 },
386 { "LimitRSS", bus_execute_append_rlimits, "t", 0 },
387 { "LimitNOFILE", bus_execute_append_rlimits, "t", 0 },
388 { "LimitAS", bus_execute_append_rlimits, "t", 0 },
389 { "LimitNPROC", bus_execute_append_rlimits, "t", 0 },
390 { "LimitMEMLOCK", bus_execute_append_rlimits, "t", 0 },
391 { "LimitLOCKS", bus_execute_append_rlimits, "t", 0 },
392 { "LimitSIGPENDING", bus_execute_append_rlimits, "t", 0 },
393 { "LimitMSGQUEUE", bus_execute_append_rlimits, "t", 0 },
394 { "LimitNICE", bus_execute_append_rlimits, "t", 0 },
395 { "LimitRTPRIO", bus_execute_append_rlimits, "t", 0 },
396 { "LimitRTTIME", bus_execute_append_rlimits, "t", 0 },
397 { "WorkingDirectory", bus_property_append_string, "s", offsetof(ExecContext, working_directory), true },
398 { "RootDirectory", bus_property_append_string, "s", offsetof(ExecContext, root_directory), true },
399 { "OOMScoreAdjust", bus_execute_append_oom_score_adjust, "i", 0 },
400 { "Nice", bus_execute_append_nice, "i", 0 },
401 { "IOScheduling", bus_execute_append_ioprio, "i", 0 },
402 { "CPUSchedulingPolicy", bus_execute_append_cpu_sched_policy, "i", 0 },
403 { "CPUSchedulingPriority", bus_execute_append_cpu_sched_priority, "i", 0 },
404 { "CPUAffinity", bus_execute_append_affinity, "ay", 0 },
405 { "TimerSlackNSec", bus_execute_append_timer_slack_nsec, "t", 0 },
406 { "CPUSchedulingResetOnFork", bus_property_append_bool, "b", offsetof(ExecContext, cpu_sched_reset_on_fork) },
407 { "NonBlocking", bus_property_append_bool, "b", offsetof(ExecContext, non_blocking) },
408 { "StandardInput", bus_execute_append_input, "s", offsetof(ExecContext, std_input) },
409 { "StandardOutput", bus_execute_append_output, "s", offsetof(ExecContext, std_output) },
410 { "StandardError", bus_execute_append_output, "s", offsetof(ExecContext, std_error) },
411 { "TTYPath", bus_property_append_string, "s", offsetof(ExecContext, tty_path), true },
412 { "TTYReset", bus_property_append_bool, "b", offsetof(ExecContext, tty_reset) },
413 { "TTYVHangup", bus_property_append_bool, "b", offsetof(ExecContext, tty_vhangup) },
414 { "TTYVTDisallocate", bus_property_append_bool, "b", offsetof(ExecContext, tty_vt_disallocate) },
415 { "SyslogPriority", bus_property_append_int, "i", offsetof(ExecContext, syslog_priority) },
416 { "SyslogIdentifier", bus_property_append_string, "s", offsetof(ExecContext, syslog_identifier), true },
417 { "SyslogLevelPrefix", bus_property_append_bool, "b", offsetof(ExecContext, syslog_level_prefix) },
418 { "Capabilities", bus_execute_append_capabilities, "s", 0 },
419 { "SecureBits", bus_property_append_int, "i", offsetof(ExecContext, secure_bits) },
420 { "CapabilityBoundingSet", bus_execute_append_capability_bs, "t", offsetof(ExecContext, capability_bounding_set_drop) },
421 { "User", bus_property_append_string, "s", offsetof(ExecContext, user), true },
422 { "Group", bus_property_append_string, "s", offsetof(ExecContext, group), true },
423 { "SupplementaryGroups", bus_property_append_strv, "as", offsetof(ExecContext, supplementary_groups), true },
424 { "TCPWrapName", bus_property_append_string, "s", offsetof(ExecContext, tcpwrap_name), true },
425 { "PAMName", bus_property_append_string, "s", offsetof(ExecContext, pam_name), true },
426 { "ReadWriteDirectories", bus_property_append_strv, "as", offsetof(ExecContext, read_write_dirs), true },
427 { "ReadOnlyDirectories", bus_property_append_strv, "as", offsetof(ExecContext, read_only_dirs), true },
428 { "InaccessibleDirectories", bus_property_append_strv, "as", offsetof(ExecContext, inaccessible_dirs), true },
429 { "MountFlags", bus_property_append_ul, "t", offsetof(ExecContext, mount_flags) },
430 { "PrivateTmp", bus_property_append_bool, "b", offsetof(ExecContext, private_tmp) },
431 { "PrivateNetwork", bus_property_append_bool, "b", offsetof(ExecContext, private_network) },
432 { "SameProcessGroup", bus_property_append_bool, "b", offsetof(ExecContext, same_pgrp) },
433 { "UtmpIdentifier", bus_property_append_string, "s", offsetof(ExecContext, utmp_id), true },
434 { "ControlGroupModify", bus_property_append_bool, "b", offsetof(ExecContext, control_group_modify) },
435 { "ControlGroupPersistent", bus_property_append_tristate_false, "b", offsetof(ExecContext, control_group_persistent) },
436 { "IgnoreSIGPIPE", bus_property_append_bool, "b", offsetof(ExecContext, ignore_sigpipe) },
437 { "NoNewPrivileges", bus_property_append_bool, "b", offsetof(ExecContext, no_new_privileges) },
438 { "SystemCallFilter", bus_execute_append_syscall_filter, "au", 0 },
439 { NULL, }
440 };