chiark / gitweb /
bus-policy: append items rather than prepending them
[elogind.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 <sys/prctl.h>
23
24 #ifdef HAVE_SECCOMP
25 #include <seccomp.h>
26 #endif
27
28 #include "bus-util.h"
29 #include "missing.h"
30 #include "ioprio.h"
31 #include "strv.h"
32 #include "fileio.h"
33 #include "execute.h"
34 #include "dbus-execute.h"
35 #include "capability.h"
36 #include "env-util.h"
37 #include "af-list.h"
38 #include "namespace.h"
39
40 #ifdef HAVE_SECCOMP
41 #include "seccomp-util.h"
42 #endif
43
44 BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
45
46 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput);
47
48 static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_home, protect_home, ProtectHome);
49 static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_system, protect_system, ProtectSystem);
50
51 static int property_get_environment_files(
52                 sd_bus *bus,
53                 const char *path,
54                 const char *interface,
55                 const char *property,
56                 sd_bus_message *reply,
57                 void *userdata,
58                 sd_bus_error *error) {
59
60         ExecContext *c = userdata;
61         char **j;
62         int r;
63
64         assert(bus);
65         assert(reply);
66         assert(c);
67
68         r = sd_bus_message_open_container(reply, 'a', "(sb)");
69         if (r < 0)
70                 return r;
71
72         STRV_FOREACH(j, c->environment_files) {
73                 const char *fn = *j;
74
75                 r = sd_bus_message_append(reply, "(sb)", fn[0] == '-' ? fn + 1 : fn, fn[0] == '-');
76                 if (r < 0)
77                         return r;
78         }
79
80         return sd_bus_message_close_container(reply);
81 }
82
83 static int property_get_rlimit(
84                 sd_bus *bus,
85                 const char *path,
86                 const char *interface,
87                 const char *property,
88                 sd_bus_message *reply,
89                 void *userdata,
90                 sd_bus_error *error) {
91
92         struct rlimit *rl;
93         uint64_t u;
94         rlim_t x;
95
96         assert(bus);
97         assert(reply);
98         assert(userdata);
99
100         rl = *(struct rlimit**) userdata;
101         if (rl)
102                 x = rl->rlim_max;
103         else {
104                 struct rlimit buf = {};
105                 int z;
106
107                 z = rlimit_from_string(property);
108                 assert(z >= 0);
109
110                 getrlimit(z, &buf);
111                 x = buf.rlim_max;
112         }
113
114         /* rlim_t might have different sizes, let's map
115          * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
116          * all archs */
117         u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
118
119         return sd_bus_message_append(reply, "t", u);
120 }
121
122 static int property_get_oom_score_adjust(
123                 sd_bus *bus,
124                 const char *path,
125                 const char *interface,
126                 const char *property,
127                 sd_bus_message *reply,
128                 void *userdata,
129                 sd_bus_error *error) {
130
131
132         ExecContext *c = userdata;
133         int32_t n;
134
135         assert(bus);
136         assert(reply);
137         assert(c);
138
139         if (c->oom_score_adjust_set)
140                 n = c->oom_score_adjust;
141         else {
142                 _cleanup_free_ char *t = NULL;
143
144                 n = 0;
145                 if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0)
146                         safe_atoi(t, &n);
147         }
148
149         return sd_bus_message_append(reply, "i", n);
150 }
151
152 static int property_get_nice(
153                 sd_bus *bus,
154                 const char *path,
155                 const char *interface,
156                 const char *property,
157                 sd_bus_message *reply,
158                 void *userdata,
159                 sd_bus_error *error) {
160
161
162         ExecContext *c = userdata;
163         int32_t n;
164
165         assert(bus);
166         assert(reply);
167         assert(c);
168
169         if (c->nice_set)
170                 n = c->nice;
171         else {
172                 errno = 0;
173                 n = getpriority(PRIO_PROCESS, 0);
174                 if (errno != 0)
175                         n = 0;
176         }
177
178         return sd_bus_message_append(reply, "i", n);
179 }
180
181 static int property_get_ioprio(
182                 sd_bus *bus,
183                 const char *path,
184                 const char *interface,
185                 const char *property,
186                 sd_bus_message *reply,
187                 void *userdata,
188                 sd_bus_error *error) {
189
190
191         ExecContext *c = userdata;
192         int32_t n;
193
194         assert(bus);
195         assert(reply);
196         assert(c);
197
198         if (c->ioprio_set)
199                 n = c->ioprio;
200         else {
201                 n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
202                 if (n < 0)
203                         n = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 4);
204         }
205
206         return sd_bus_message_append(reply, "i", n);
207 }
208
209 static int property_get_cpu_sched_policy(
210                 sd_bus *bus,
211                 const char *path,
212                 const char *interface,
213                 const char *property,
214                 sd_bus_message *reply,
215                 void *userdata,
216                 sd_bus_error *error) {
217
218         ExecContext *c = userdata;
219         int32_t n;
220
221         assert(bus);
222         assert(reply);
223         assert(c);
224
225         if (c->cpu_sched_set)
226                 n = c->cpu_sched_policy;
227         else {
228                 n = sched_getscheduler(0);
229                 if (n < 0)
230                         n = SCHED_OTHER;
231         }
232
233         return sd_bus_message_append(reply, "i", n);
234 }
235
236 static int property_get_cpu_sched_priority(
237                 sd_bus *bus,
238                 const char *path,
239                 const char *interface,
240                 const char *property,
241                 sd_bus_message *reply,
242                 void *userdata,
243                 sd_bus_error *error) {
244
245         ExecContext *c = userdata;
246         int32_t n;
247
248         assert(bus);
249         assert(reply);
250         assert(c);
251
252         if (c->cpu_sched_set)
253                 n = c->cpu_sched_priority;
254         else {
255                 struct sched_param p = {};
256
257                 if (sched_getparam(0, &p) >= 0)
258                         n = p.sched_priority;
259                 else
260                         n = 0;
261         }
262
263         return sd_bus_message_append(reply, "i", n);
264 }
265
266 static int property_get_cpu_affinity(
267                 sd_bus *bus,
268                 const char *path,
269                 const char *interface,
270                 const char *property,
271                 sd_bus_message *reply,
272                 void *userdata,
273                 sd_bus_error *error) {
274
275         ExecContext *c = userdata;
276
277         assert(bus);
278         assert(reply);
279         assert(c);
280
281         if (c->cpuset)
282                 return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
283         else
284                 return sd_bus_message_append_array(reply, 'y', NULL, 0);
285 }
286
287 static int property_get_timer_slack_nsec(
288                 sd_bus *bus,
289                 const char *path,
290                 const char *interface,
291                 const char *property,
292                 sd_bus_message *reply,
293                 void *userdata,
294                 sd_bus_error *error) {
295
296         ExecContext *c = userdata;
297         uint64_t u;
298
299         assert(bus);
300         assert(reply);
301         assert(c);
302
303         if (c->timer_slack_nsec != NSEC_INFINITY)
304                 u = (uint64_t) c->timer_slack_nsec;
305         else
306                 u = (uint64_t) prctl(PR_GET_TIMERSLACK);
307
308         return sd_bus_message_append(reply, "t", u);
309 }
310
311 static int property_get_capability_bounding_set(
312                 sd_bus *bus,
313                 const char *path,
314                 const char *interface,
315                 const char *property,
316                 sd_bus_message *reply,
317                 void *userdata,
318                 sd_bus_error *error) {
319
320         ExecContext *c = userdata;
321
322         assert(bus);
323         assert(reply);
324         assert(c);
325
326         /* We store this negated internally, to match the kernel, but
327          * we expose it normalized. */
328         return sd_bus_message_append(reply, "t", ~c->capability_bounding_set_drop);
329 }
330
331 static int property_get_capabilities(
332                 sd_bus *bus,
333                 const char *path,
334                 const char *interface,
335                 const char *property,
336                 sd_bus_message *reply,
337                 void *userdata,
338                 sd_bus_error *error) {
339
340         ExecContext *c = userdata;
341         _cleanup_cap_free_charp_ char *t = NULL;
342         const char *s;
343
344         assert(bus);
345         assert(reply);
346         assert(c);
347
348         if (c->capabilities)
349                 s = t = cap_to_text(c->capabilities, NULL);
350         else
351                 s = "";
352
353         if (!s)
354                 return -ENOMEM;
355
356         return sd_bus_message_append(reply, "s", s);
357 }
358
359 static int property_get_syscall_filter(
360                 sd_bus *bus,
361                 const char *path,
362                 const char *interface,
363                 const char *property,
364                 sd_bus_message *reply,
365                 void *userdata,
366                 sd_bus_error *error) {
367
368         ExecContext *c = userdata;
369         _cleanup_strv_free_ char **l = NULL;
370         int r;
371
372 #ifdef HAVE_SECCOMP
373         Iterator i;
374         void *id;
375 #endif
376
377         assert(bus);
378         assert(reply);
379         assert(c);
380
381         r = sd_bus_message_open_container(reply, 'r', "bas");
382         if (r < 0)
383                 return r;
384
385         r = sd_bus_message_append(reply, "b", c->syscall_whitelist);
386         if (r < 0)
387                 return r;
388
389 #ifdef HAVE_SECCOMP
390         SET_FOREACH(id, c->syscall_filter, i) {
391                 char *name;
392
393                 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
394                 if (!name)
395                         continue;
396
397                 r = strv_consume(&l, name);
398                 if (r < 0)
399                         return r;
400         }
401 #endif
402
403         strv_sort(l);
404
405         r = sd_bus_message_append_strv(reply, l);
406         if (r < 0)
407                 return r;
408
409         return sd_bus_message_close_container(reply);
410 }
411
412 static int property_get_syscall_archs(
413                 sd_bus *bus,
414                 const char *path,
415                 const char *interface,
416                 const char *property,
417                 sd_bus_message *reply,
418                 void *userdata,
419                 sd_bus_error *error) {
420
421         ExecContext *c = userdata;
422         _cleanup_strv_free_ char **l = NULL;
423         int r;
424
425 #ifdef HAVE_SECCOMP
426         Iterator i;
427         void *id;
428 #endif
429
430         assert(bus);
431         assert(reply);
432         assert(c);
433
434 #ifdef HAVE_SECCOMP
435         SET_FOREACH(id, c->syscall_archs, i) {
436                 const char *name;
437
438                 name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
439                 if (!name)
440                         continue;
441
442                 r = strv_extend(&l, name);
443                 if (r < 0)
444                         return -ENOMEM;
445         }
446 #endif
447
448         strv_sort(l);
449
450         r = sd_bus_message_append_strv(reply, l);
451         if (r < 0)
452                 return r;
453
454         return 0;
455 }
456
457 static int property_get_syscall_errno(
458                 sd_bus *bus,
459                 const char *path,
460                 const char *interface,
461                 const char *property,
462                 sd_bus_message *reply,
463                 void *userdata,
464                 sd_bus_error *error) {
465
466         ExecContext *c = userdata;
467
468         assert(bus);
469         assert(reply);
470         assert(c);
471
472         return sd_bus_message_append(reply, "i", (int32_t) c->syscall_errno);
473 }
474
475 static int property_get_selinux_context(
476                 sd_bus *bus,
477                 const char *path,
478                 const char *interface,
479                 const char *property,
480                 sd_bus_message *reply,
481                 void *userdata,
482                 sd_bus_error *error) {
483
484         ExecContext *c = userdata;
485
486         assert(bus);
487         assert(reply);
488         assert(c);
489
490         return sd_bus_message_append(reply, "(bs)", c->selinux_context_ignore, c->selinux_context);
491 }
492
493 static int property_get_apparmor_profile(
494                 sd_bus *bus,
495                 const char *path,
496                 const char *interface,
497                 const char *property,
498                 sd_bus_message *reply,
499                 void *userdata,
500                 sd_bus_error *error) {
501
502         ExecContext *c = userdata;
503
504         assert(bus);
505         assert(reply);
506         assert(c);
507
508         return sd_bus_message_append(reply, "(bs)", c->apparmor_profile_ignore, c->apparmor_profile);
509 }
510
511 static int property_get_personality(
512                 sd_bus *bus,
513                 const char *path,
514                 const char *interface,
515                 const char *property,
516                 sd_bus_message *reply,
517                 void *userdata,
518                 sd_bus_error *error) {
519
520         ExecContext *c = userdata;
521
522         assert(bus);
523         assert(reply);
524         assert(c);
525
526         return sd_bus_message_append(reply, "s", personality_to_string(c->personality));
527 }
528
529 static int property_get_address_families(
530                 sd_bus *bus,
531                 const char *path,
532                 const char *interface,
533                 const char *property,
534                 sd_bus_message *reply,
535                 void *userdata,
536                 sd_bus_error *error) {
537
538         ExecContext *c = userdata;
539         _cleanup_strv_free_ char **l = NULL;
540         Iterator i;
541         void *af;
542         int r;
543
544         assert(bus);
545         assert(reply);
546         assert(c);
547
548         r = sd_bus_message_open_container(reply, 'r', "bas");
549         if (r < 0)
550                 return r;
551
552         r = sd_bus_message_append(reply, "b", c->address_families_whitelist);
553         if (r < 0)
554                 return r;
555
556         SET_FOREACH(af, c->address_families, i) {
557                 const char *name;
558
559                 name = af_to_name(PTR_TO_INT(af));
560                 if (!name)
561                         continue;
562
563                 r = strv_extend(&l, name);
564                 if (r < 0)
565                         return -ENOMEM;
566         }
567
568         strv_sort(l);
569
570         r = sd_bus_message_append_strv(reply, l);
571         if (r < 0)
572                 return r;
573
574         return sd_bus_message_close_container(reply);
575 }
576
577 const sd_bus_vtable bus_exec_vtable[] = {
578         SD_BUS_VTABLE_START(0),
579         SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
580         SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
581         SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
582         SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
583         SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
584         SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
585         SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
586         SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
587         SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
588         SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
589         SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
590         SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
591         SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
592         SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
593         SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
594         SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
595         SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
596         SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
597         SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
598         SD_BUS_PROPERTY("WorkingDirectory", "s", NULL, offsetof(ExecContext, working_directory), SD_BUS_VTABLE_PROPERTY_CONST),
599         SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
600         SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
601         SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
602         SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, SD_BUS_VTABLE_PROPERTY_CONST),
603         SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
604         SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
605         SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST),
606         SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
607         SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), SD_BUS_VTABLE_PROPERTY_CONST),
608         SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), SD_BUS_VTABLE_PROPERTY_CONST),
609         SD_BUS_PROPERTY("StandardInput", "s", property_get_exec_input, offsetof(ExecContext, std_input), SD_BUS_VTABLE_PROPERTY_CONST),
610         SD_BUS_PROPERTY("StandardOutput", "s", bus_property_get_exec_output, offsetof(ExecContext, std_output), SD_BUS_VTABLE_PROPERTY_CONST),
611         SD_BUS_PROPERTY("StandardError", "s", bus_property_get_exec_output, offsetof(ExecContext, std_error), SD_BUS_VTABLE_PROPERTY_CONST),
612         SD_BUS_PROPERTY("TTYPath", "s", NULL, offsetof(ExecContext, tty_path), SD_BUS_VTABLE_PROPERTY_CONST),
613         SD_BUS_PROPERTY("TTYReset", "b", bus_property_get_bool, offsetof(ExecContext, tty_reset), SD_BUS_VTABLE_PROPERTY_CONST),
614         SD_BUS_PROPERTY("TTYVHangup", "b", bus_property_get_bool, offsetof(ExecContext, tty_vhangup), SD_BUS_VTABLE_PROPERTY_CONST),
615         SD_BUS_PROPERTY("TTYVTDisallocate", "b", bus_property_get_bool, offsetof(ExecContext, tty_vt_disallocate), SD_BUS_VTABLE_PROPERTY_CONST),
616         SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
617         SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST),
618         SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
619         SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
620         SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
621         SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
622         SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST),
623         SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST),
624         SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
625         SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST),
626         SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
627         SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
628         SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
629         SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
630         SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST),
631         SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
632         SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST),
633         SD_BUS_PROPERTY("ProtectHome", "s", bus_property_get_protect_home, offsetof(ExecContext, protect_home), SD_BUS_VTABLE_PROPERTY_CONST),
634         SD_BUS_PROPERTY("ProtectSystem", "s", bus_property_get_protect_system, offsetof(ExecContext, protect_system), SD_BUS_VTABLE_PROPERTY_CONST),
635         SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST),
636         SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), SD_BUS_VTABLE_PROPERTY_CONST),
637         SD_BUS_PROPERTY("SELinuxContext", "(bs)", property_get_selinux_context, 0, SD_BUS_VTABLE_PROPERTY_CONST),
638         SD_BUS_PROPERTY("AppArmorProfile", "(bs)", property_get_apparmor_profile, 0, SD_BUS_VTABLE_PROPERTY_CONST),
639         SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), SD_BUS_VTABLE_PROPERTY_CONST),
640         SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), SD_BUS_VTABLE_PROPERTY_CONST),
641         SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
642         SD_BUS_PROPERTY("SystemCallArchitectures", "as", property_get_syscall_archs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
643         SD_BUS_PROPERTY("SystemCallErrorNumber", "i", property_get_syscall_errno, 0, SD_BUS_VTABLE_PROPERTY_CONST),
644         SD_BUS_PROPERTY("Personality", "s", property_get_personality, 0, SD_BUS_VTABLE_PROPERTY_CONST),
645         SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST),
646         SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, runtime_directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
647         SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST),
648         SD_BUS_VTABLE_END
649 };
650
651 static int append_exec_command(sd_bus_message *reply, ExecCommand *c) {
652         int r;
653
654         assert(reply);
655         assert(c);
656
657         if (!c->path)
658                 return 0;
659
660         r = sd_bus_message_open_container(reply, 'r', "sasbttttuii");
661         if (r < 0)
662                 return r;
663
664         r = sd_bus_message_append(reply, "s", c->path);
665         if (r < 0)
666                 return r;
667
668         r = sd_bus_message_append_strv(reply, c->argv);
669         if (r < 0)
670                 return r;
671
672         r = sd_bus_message_append(reply, "bttttuii",
673                                   c->ignore,
674                                   c->exec_status.start_timestamp.realtime,
675                                   c->exec_status.start_timestamp.monotonic,
676                                   c->exec_status.exit_timestamp.realtime,
677                                   c->exec_status.exit_timestamp.monotonic,
678                                   (uint32_t) c->exec_status.pid,
679                                   (int32_t) c->exec_status.code,
680                                   (int32_t) c->exec_status.status);
681         if (r < 0)
682                 return r;
683
684         return sd_bus_message_close_container(reply);
685 }
686
687 int bus_property_get_exec_command(
688                 sd_bus *bus,
689                 const char *path,
690                 const char *interface,
691                 const char *property,
692                 sd_bus_message *reply,
693                 void *userdata,
694                 sd_bus_error *ret_error) {
695
696         ExecCommand *c = (ExecCommand*) userdata;
697         int r;
698
699         assert(bus);
700         assert(reply);
701
702         r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
703         if (r < 0)
704                 return r;
705
706         r = append_exec_command(reply, c);
707         if (r < 0)
708                 return r;
709
710         return sd_bus_message_close_container(reply);
711 }
712
713 int bus_property_get_exec_command_list(
714                 sd_bus *bus,
715                 const char *path,
716                 const char *interface,
717                 const char *property,
718                 sd_bus_message *reply,
719                 void *userdata,
720                 sd_bus_error *ret_error) {
721
722         ExecCommand *c = *(ExecCommand**) userdata;
723         int r;
724
725         assert(bus);
726         assert(reply);
727
728         r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
729         if (r < 0)
730                 return r;
731
732         LIST_FOREACH(command, c, c) {
733                 r = append_exec_command(reply, c);
734                 if (r < 0)
735                         return r;
736         }
737
738         return sd_bus_message_close_container(reply);
739 }
740
741 int bus_exec_context_set_transient_property(
742                 Unit *u,
743                 ExecContext *c,
744                 const char *name,
745                 sd_bus_message *message,
746                 UnitSetPropertiesMode mode,
747                 sd_bus_error *error) {
748
749         int r;
750
751         assert(u);
752         assert(c);
753         assert(name);
754         assert(message);
755
756         if (streq(name, "User")) {
757                 const char *uu;
758
759                 r = sd_bus_message_read(message, "s", &uu);
760                 if (r < 0)
761                         return r;
762
763                 if (mode != UNIT_CHECK) {
764
765                         if (isempty(uu)) {
766                                 free(c->user);
767                                 c->user = NULL;
768                         } else {
769                                 char *t;
770
771                                 t = strdup(uu);
772                                 if (!t)
773                                         return -ENOMEM;
774
775                                 free(c->user);
776                                 c->user = t;
777                         }
778
779                         unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu);
780                 }
781
782                 return 1;
783
784         } else if (streq(name, "Group")) {
785                 const char *gg;
786
787                 r = sd_bus_message_read(message, "s", &gg);
788                 if (r < 0)
789                         return r;
790
791                 if (mode != UNIT_CHECK) {
792
793                         if (isempty(gg)) {
794                                 free(c->group);
795                                 c->group = NULL;
796                         } else {
797                                 char *t;
798
799                                 t = strdup(gg);
800                                 if (!t)
801                                         return -ENOMEM;
802
803                                 free(c->group);
804                                 c->group = t;
805                         }
806
807                         unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg);
808                 }
809
810                 return 1;
811
812         } else if (streq(name, "Nice")) {
813                 int n;
814
815                 r = sd_bus_message_read(message, "i", &n);
816                 if (r < 0)
817                         return r;
818
819                 if (n < PRIO_MIN || n >= PRIO_MAX)
820                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Nice value out of range");
821
822                 if (mode != UNIT_CHECK) {
823                         c->nice = n;
824                         unit_write_drop_in_private_format(u, mode, name, "Nice=%i\n", n);
825                 }
826
827                 return 1;
828
829         } else if (streq(name, "Environment")) {
830
831                 _cleanup_strv_free_ char **l = NULL;
832
833                 r = sd_bus_message_read_strv(message, &l);
834                 if (r < 0)
835                         return r;
836
837                 if (!strv_env_is_valid(l))
838                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block.");
839
840                 if (mode != UNIT_CHECK) {
841                         _cleanup_free_ char *joined = NULL;
842                         char **e;
843
844                         e = strv_env_merge(2, c->environment, l);
845                         if (!e)
846                                 return -ENOMEM;
847
848                         strv_free(c->environment);
849                         c->environment = e;
850
851                         joined = strv_join_quoted(c->environment);
852                         if (!joined)
853                                 return -ENOMEM;
854
855                         unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
856                 }
857
858                 return 1;
859
860         } else if (rlimit_from_string(name) >= 0) {
861                 uint64_t rl;
862                 rlim_t x;
863
864                 r = sd_bus_message_read(message, "t", &rl);
865                 if (r < 0)
866                         return r;
867
868                 if (rl == (uint64_t) -1)
869                         x = RLIM_INFINITY;
870                 else {
871                         x = (rlim_t) rl;
872
873                         if ((uint64_t) x != rl)
874                                 return -ERANGE;
875                 }
876
877                 if (mode != UNIT_CHECK) {
878                         int z;
879
880                         z = rlimit_from_string(name);
881
882                         if (!c->rlimit[z]) {
883                                 c->rlimit[z] = new(struct rlimit, 1);
884                                 if (!c->rlimit[z])
885                                         return -ENOMEM;
886                         }
887
888                         c->rlimit[z]->rlim_cur = c->rlimit[z]->rlim_max = x;
889
890                         if (x == RLIM_INFINITY)
891                                 unit_write_drop_in_private_format(u, mode, name, "%s=infinity\n", name);
892                         else
893                                 unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64 "\n", name, rl);
894                 }
895
896                 return 1;
897         }
898
899         return 0;
900 }