1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
22 #include <sys/prctl.h>
34 #include "dbus-execute.h"
35 #include "capability.h"
40 #include "seccomp-util.h"
43 BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
45 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput);
47 static int property_get_environment_files(
50 const char *interface,
52 sd_bus_message *reply,
54 sd_bus_error *error) {
56 ExecContext *c = userdata;
64 r = sd_bus_message_open_container(reply, 'a', "(sb)");
68 STRV_FOREACH(j, c->environment_files) {
71 r = sd_bus_message_append(reply, "(sb)", fn[0] == '-' ? fn + 1 : fn, fn[0] == '-');
76 return sd_bus_message_close_container(reply);
79 static int property_get_rlimit(
82 const char *interface,
84 sd_bus_message *reply,
86 sd_bus_error *error) {
95 rl = *(struct rlimit**) userdata;
97 u = (uint64_t) rl->rlim_max;
99 struct rlimit buf = {};
102 z = rlimit_from_string(property);
107 u = (uint64_t) buf.rlim_max;
110 return sd_bus_message_append(reply, "t", u);
113 static int property_get_oom_score_adjust(
116 const char *interface,
117 const char *property,
118 sd_bus_message *reply,
120 sd_bus_error *error) {
123 ExecContext *c = userdata;
130 if (c->oom_score_adjust_set)
131 n = c->oom_score_adjust;
133 _cleanup_free_ char *t = NULL;
136 if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0)
140 return sd_bus_message_append(reply, "i", n);
143 static int property_get_nice(
146 const char *interface,
147 const char *property,
148 sd_bus_message *reply,
150 sd_bus_error *error) {
153 ExecContext *c = userdata;
164 n = getpriority(PRIO_PROCESS, 0);
169 return sd_bus_message_append(reply, "i", n);
172 static int property_get_ioprio(
175 const char *interface,
176 const char *property,
177 sd_bus_message *reply,
179 sd_bus_error *error) {
182 ExecContext *c = userdata;
192 n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
194 n = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 4);
197 return sd_bus_message_append(reply, "i", n);
200 static int property_get_cpu_sched_policy(
203 const char *interface,
204 const char *property,
205 sd_bus_message *reply,
207 sd_bus_error *error) {
209 ExecContext *c = userdata;
216 if (c->cpu_sched_set)
217 n = c->cpu_sched_policy;
219 n = sched_getscheduler(0);
224 return sd_bus_message_append(reply, "i", n);
227 static int property_get_cpu_sched_priority(
230 const char *interface,
231 const char *property,
232 sd_bus_message *reply,
234 sd_bus_error *error) {
236 ExecContext *c = userdata;
243 if (c->cpu_sched_set)
244 n = c->cpu_sched_priority;
246 struct sched_param p = {};
248 if (sched_getparam(0, &p) >= 0)
249 n = p.sched_priority;
254 return sd_bus_message_append(reply, "i", n);
257 static int property_get_cpu_affinity(
260 const char *interface,
261 const char *property,
262 sd_bus_message *reply,
264 sd_bus_error *error) {
266 ExecContext *c = userdata;
273 return sd_bus_message_append_array(reply, 'y', c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
275 return sd_bus_message_append_array(reply, 'y', NULL, 0);
278 static int property_get_timer_slack_nsec(
281 const char *interface,
282 const char *property,
283 sd_bus_message *reply,
285 sd_bus_error *error) {
287 ExecContext *c = userdata;
294 if (c->timer_slack_nsec != (nsec_t) -1)
295 u = (uint64_t) c->timer_slack_nsec;
297 u = (uint64_t) prctl(PR_GET_TIMERSLACK);
299 return sd_bus_message_append(reply, "t", u);
302 static int property_get_capability_bounding_set(
305 const char *interface,
306 const char *property,
307 sd_bus_message *reply,
309 sd_bus_error *error) {
311 ExecContext *c = userdata;
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);
322 static int property_get_capabilities(
325 const char *interface,
326 const char *property,
327 sd_bus_message *reply,
329 sd_bus_error *error) {
331 ExecContext *c = userdata;
332 _cleanup_cap_free_charp_ char *t = NULL;
340 s = t = cap_to_text(c->capabilities, NULL);
347 return sd_bus_message_append(reply, "s", s);
350 static int property_get_syscall_filter(
353 const char *interface,
354 const char *property,
355 sd_bus_message *reply,
357 sd_bus_error *error) {
359 ExecContext *c = userdata;
360 _cleanup_strv_free_ char **l = NULL;
372 r = sd_bus_message_open_container(reply, 'r', "bas");
376 r = sd_bus_message_append(reply, "b", c->syscall_whitelist);
381 SET_FOREACH(id, c->syscall_filter, i) {
384 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
388 r = strv_push(&l, name);
398 r = sd_bus_message_append_strv(reply, l);
402 return sd_bus_message_close_container(reply);
405 static int property_get_syscall_archs(
408 const char *interface,
409 const char *property,
410 sd_bus_message *reply,
412 sd_bus_error *error) {
414 ExecContext *c = userdata;
415 _cleanup_strv_free_ char **l = NULL;
428 SET_FOREACH(id, c->syscall_archs, i) {
431 name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
435 r = strv_extend(&l, name);
443 r = sd_bus_message_append_strv(reply, l);
450 static int property_get_syscall_errno(
453 const char *interface,
454 const char *property,
455 sd_bus_message *reply,
457 sd_bus_error *error) {
459 ExecContext *c = userdata;
465 return sd_bus_message_append(reply, "i", (int32_t) c->syscall_errno);
468 static int property_get_selinux_context(
471 const char *interface,
472 const char *property,
473 sd_bus_message *reply,
475 sd_bus_error *error) {
477 ExecContext *c = userdata;
483 return sd_bus_message_append(reply, "(bs)", c->selinux_context_ignore, c->selinux_context);
486 static int property_get_apparmor_profile(
489 const char *interface,
490 const char *property,
491 sd_bus_message *reply,
493 sd_bus_error *error) {
495 ExecContext *c = userdata;
501 return sd_bus_message_append(reply, "(bs)", c->apparmor_profile_ignore, c->apparmor_profile);
504 static int property_get_personality(
507 const char *interface,
508 const char *property,
509 sd_bus_message *reply,
511 sd_bus_error *error) {
513 ExecContext *c = userdata;
519 return sd_bus_message_append(reply, "s", personality_to_string(c->personality));
522 static int property_get_address_families(
525 const char *interface,
526 const char *property,
527 sd_bus_message *reply,
529 sd_bus_error *error) {
531 ExecContext *c = userdata;
532 _cleanup_strv_free_ char **l = NULL;
541 r = sd_bus_message_open_container(reply, 'r', "bas");
545 r = sd_bus_message_append(reply, "b", c->address_families_whitelist);
549 SET_FOREACH(af, c->address_families, i) {
552 name = af_to_name(PTR_TO_INT(af));
556 r = strv_extend(&l, name);
563 r = sd_bus_message_append_strv(reply, l);
567 return sd_bus_message_close_container(reply);
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),
641 static int append_exec_command(sd_bus_message *reply, ExecCommand *c) {
650 r = sd_bus_message_open_container(reply, 'r', "sasbttttuii");
654 r = sd_bus_message_append(reply, "s", c->path);
658 r = sd_bus_message_append_strv(reply, c->argv);
662 r = sd_bus_message_append(reply, "bttttuii",
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);
674 return sd_bus_message_close_container(reply);
677 int bus_property_get_exec_command(
680 const char *interface,
681 const char *property,
682 sd_bus_message *reply,
684 sd_bus_error *ret_error) {
686 ExecCommand *c = (ExecCommand*) userdata;
692 r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
696 r = append_exec_command(reply, c);
700 return sd_bus_message_close_container(reply);
703 int bus_property_get_exec_command_list(
706 const char *interface,
707 const char *property,
708 sd_bus_message *reply,
710 sd_bus_error *ret_error) {
712 ExecCommand *c = *(ExecCommand**) userdata;
718 r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
722 LIST_FOREACH(command, c, c) {
723 r = append_exec_command(reply, c);
728 return sd_bus_message_close_container(reply);
731 int bus_exec_context_set_transient_property(
735 sd_bus_message *message,
736 UnitSetPropertiesMode mode,
737 sd_bus_error *error) {
746 if (streq(name, "User")) {
749 r = sd_bus_message_read(message, "s", &uu);
753 if (mode != UNIT_CHECK) {
769 unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu);
774 } else if (streq(name, "Group")) {
777 r = sd_bus_message_read(message, "s", &gg);
781 if (mode != UNIT_CHECK) {
797 unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg);
802 } else if (streq(name, "Nice")) {
805 r = sd_bus_message_read(message, "i", &n);
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");
812 if (mode != UNIT_CHECK) {
814 unit_write_drop_in_private_format(u, mode, name, "Nice=%i\n", n);
819 } else if (streq(name, "Environment")) {
821 _cleanup_strv_free_ char **l = NULL;
823 r = sd_bus_message_read_strv(message, &l);
827 if (!strv_env_is_valid(l))
828 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block.");
830 if (mode != UNIT_CHECK) {
831 _cleanup_free_ char *joined = NULL;
834 e = strv_env_merge(2, c->environment, l);
838 strv_free(c->environment);
841 joined = strv_join(c->environment, " ");
845 unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);