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