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