]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-execute.c
b07b5775ff4e5364834dd9d986b04e780edd5b8f
[thirdparty/systemd.git] / src / core / dbus-execute.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <sys/mount.h>
4 #include <sys/prctl.h>
5
6 #if HAVE_SECCOMP
7 #include <seccomp.h>
8 #endif
9
10 #include "af-list.h"
11 #include "alloc-util.h"
12 #include "bus-get-properties.h"
13 #include "cap-list.h"
14 #include "capability-util.h"
15 #include "cpu-set-util.h"
16 #include "creds-util.h"
17 #include "dbus-execute.h"
18 #include "dbus-util.h"
19 #include "env-util.h"
20 #include "errno-list.h"
21 #include "escape.h"
22 #include "execute.h"
23 #include "fd-util.h"
24 #include "fileio.h"
25 #include "hexdecoct.h"
26 #include "io-util.h"
27 #include "ioprio-util.h"
28 #include "journal-file.h"
29 #include "missing_ioprio.h"
30 #include "mountpoint-util.h"
31 #include "namespace.h"
32 #include "parse-util.h"
33 #include "path-util.h"
34 #include "pcre2-util.h"
35 #include "process-util.h"
36 #include "rlimit-util.h"
37 #if HAVE_SECCOMP
38 #include "seccomp-util.h"
39 #endif
40 #include "securebits-util.h"
41 #include "specifier.h"
42 #include "stat-util.h"
43 #include "strv.h"
44 #include "syslog-util.h"
45 #include "unit-printf.h"
46 #include "user-util.h"
47 #include "utf8.h"
48
49 BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
50 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput);
51 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode);
52 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_preserve_mode, exec_preserve_mode, ExecPreserveMode);
53 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode);
54 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_protect_proc, protect_proc, ProtectProc);
55 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_proc_subset, proc_subset, ProcSubset);
56 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_protect_home, protect_home, ProtectHome);
57 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_protect_system, protect_system, ProtectSystem);
58 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_personality, personality, unsigned long);
59 static BUS_DEFINE_PROPERTY_GET(property_get_ioprio, "i", ExecContext, exec_context_get_effective_ioprio);
60 static BUS_DEFINE_PROPERTY_GET(property_get_mount_apivfs, "b", ExecContext, exec_context_get_effective_mount_apivfs);
61 static BUS_DEFINE_PROPERTY_GET2(property_get_ioprio_class, "i", ExecContext, exec_context_get_effective_ioprio, ioprio_prio_class);
62 static BUS_DEFINE_PROPERTY_GET2(property_get_ioprio_priority, "i", ExecContext, exec_context_get_effective_ioprio, ioprio_prio_data);
63 static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_empty_string, "s", NULL);
64 static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_level, "i", int, LOG_PRI);
65 static BUS_DEFINE_PROPERTY_GET_REF(property_get_syslog_facility, "i", int, LOG_FAC);
66 static BUS_DEFINE_PROPERTY_GET(property_get_cpu_affinity_from_numa, "b", ExecContext, exec_context_get_cpu_affinity_from_numa);
67
68 static int property_get_environment_files(
69 sd_bus *bus,
70 const char *path,
71 const char *interface,
72 const char *property,
73 sd_bus_message *reply,
74 void *userdata,
75 sd_bus_error *error) {
76
77 ExecContext *c = ASSERT_PTR(userdata);
78 int r;
79
80 assert(bus);
81 assert(reply);
82
83 r = sd_bus_message_open_container(reply, 'a', "(sb)");
84 if (r < 0)
85 return r;
86
87 STRV_FOREACH(j, c->environment_files) {
88 const char *fn = *j;
89
90 r = sd_bus_message_append(reply, "(sb)", fn[0] == '-' ? fn + 1 : fn, fn[0] == '-');
91 if (r < 0)
92 return r;
93 }
94
95 return sd_bus_message_close_container(reply);
96 }
97
98 static int property_get_oom_score_adjust(
99 sd_bus *bus,
100 const char *path,
101 const char *interface,
102 const char *property,
103 sd_bus_message *reply,
104 void *userdata,
105 sd_bus_error *error) {
106
107 ExecContext *c = ASSERT_PTR(userdata);
108 int r, n;
109
110 assert(bus);
111 assert(reply);
112
113 if (c->oom_score_adjust_set)
114 n = c->oom_score_adjust;
115 else {
116 n = 0;
117 r = get_oom_score_adjust(&n);
118 if (r < 0)
119 log_debug_errno(r, "Failed to read /proc/self/oom_score_adj, ignoring: %m");
120 }
121
122 return sd_bus_message_append(reply, "i", n);
123 }
124
125 static int property_get_coredump_filter(
126 sd_bus *bus,
127 const char *path,
128 const char *interface,
129 const char *property,
130 sd_bus_message *reply,
131 void *userdata,
132 sd_bus_error *error) {
133
134 ExecContext *c = ASSERT_PTR(userdata);
135 uint64_t n;
136 int r;
137
138 assert(bus);
139 assert(reply);
140
141 if (c->coredump_filter_set)
142 n = c->coredump_filter;
143 else {
144 _cleanup_free_ char *t = NULL;
145
146 n = COREDUMP_FILTER_MASK_DEFAULT;
147 r = read_one_line_file("/proc/self/coredump_filter", &t);
148 if (r < 0)
149 log_debug_errno(r, "Failed to read /proc/self/coredump_filter, ignoring: %m");
150 else {
151 r = safe_atoux64(t, &n);
152 if (r < 0)
153 log_debug_errno(r, "Failed to parse \"%s\" from /proc/self/coredump_filter, ignoring: %m", t);
154 }
155 }
156
157 return sd_bus_message_append(reply, "t", n);
158 }
159
160 static int property_get_nice(
161 sd_bus *bus,
162 const char *path,
163 const char *interface,
164 const char *property,
165 sd_bus_message *reply,
166 void *userdata,
167 sd_bus_error *error) {
168
169 ExecContext *c = ASSERT_PTR(userdata);
170 int32_t n;
171
172 assert(bus);
173 assert(reply);
174
175 if (c->nice_set)
176 n = c->nice;
177 else {
178 errno = 0;
179 n = getpriority(PRIO_PROCESS, 0);
180 if (errno > 0)
181 n = 0;
182 }
183
184 return sd_bus_message_append(reply, "i", n);
185 }
186
187 static int property_get_cpu_sched_policy(
188 sd_bus *bus,
189 const char *path,
190 const char *interface,
191 const char *property,
192 sd_bus_message *reply,
193 void *userdata,
194 sd_bus_error *error) {
195
196 ExecContext *c = ASSERT_PTR(userdata);
197 int32_t n;
198
199 assert(bus);
200 assert(reply);
201
202 if (c->cpu_sched_set)
203 n = c->cpu_sched_policy;
204 else {
205 n = sched_getscheduler(0);
206 if (n < 0)
207 n = SCHED_OTHER;
208 }
209
210 return sd_bus_message_append(reply, "i", n);
211 }
212
213 static int property_get_cpu_sched_priority(
214 sd_bus *bus,
215 const char *path,
216 const char *interface,
217 const char *property,
218 sd_bus_message *reply,
219 void *userdata,
220 sd_bus_error *error) {
221
222 ExecContext *c = ASSERT_PTR(userdata);
223 int32_t n;
224
225 assert(bus);
226 assert(reply);
227
228 if (c->cpu_sched_set)
229 n = c->cpu_sched_priority;
230 else {
231 struct sched_param p = {};
232
233 if (sched_getparam(0, &p) >= 0)
234 n = p.sched_priority;
235 else
236 n = 0;
237 }
238
239 return sd_bus_message_append(reply, "i", n);
240 }
241
242 static int property_get_cpu_affinity(
243 sd_bus *bus,
244 const char *path,
245 const char *interface,
246 const char *property,
247 sd_bus_message *reply,
248 void *userdata,
249 sd_bus_error *error) {
250
251 ExecContext *c = ASSERT_PTR(userdata);
252 _cleanup_(cpu_set_reset) CPUSet s = {};
253 _cleanup_free_ uint8_t *array = NULL;
254 size_t allocated;
255
256 assert(bus);
257 assert(reply);
258
259 if (c->cpu_affinity_from_numa) {
260 int r;
261
262 r = numa_to_cpu_set(&c->numa_policy, &s);
263 if (r < 0)
264 return r;
265 }
266
267 (void) cpu_set_to_dbus(c->cpu_affinity_from_numa ? &s : &c->cpu_set, &array, &allocated);
268
269 return sd_bus_message_append_array(reply, 'y', array, allocated);
270 }
271
272 static int property_get_numa_mask(
273 sd_bus *bus,
274 const char *path,
275 const char *interface,
276 const char *property,
277 sd_bus_message *reply,
278 void *userdata,
279 sd_bus_error *error) {
280
281 ExecContext *c = ASSERT_PTR(userdata);
282 _cleanup_free_ uint8_t *array = NULL;
283 size_t allocated;
284
285 assert(bus);
286 assert(reply);
287
288 (void) cpu_set_to_dbus(&c->numa_policy.nodes, &array, &allocated);
289
290 return sd_bus_message_append_array(reply, 'y', array, allocated);
291 }
292
293 static int property_get_numa_policy(
294 sd_bus *bus,
295 const char *path,
296 const char *interface,
297 const char *property,
298 sd_bus_message *reply,
299 void *userdata,
300 sd_bus_error *error) {
301 ExecContext *c = ASSERT_PTR(userdata);
302 int32_t policy;
303
304 assert(bus);
305 assert(reply);
306
307 policy = numa_policy_get_type(&c->numa_policy);
308
309 return sd_bus_message_append_basic(reply, 'i', &policy);
310 }
311
312 static int property_get_timer_slack_nsec(
313 sd_bus *bus,
314 const char *path,
315 const char *interface,
316 const char *property,
317 sd_bus_message *reply,
318 void *userdata,
319 sd_bus_error *error) {
320
321 ExecContext *c = ASSERT_PTR(userdata);
322 uint64_t u;
323
324 assert(bus);
325 assert(reply);
326
327 if (c->timer_slack_nsec != NSEC_INFINITY)
328 u = (uint64_t) c->timer_slack_nsec;
329 else
330 u = (uint64_t) prctl(PR_GET_TIMERSLACK);
331
332 return sd_bus_message_append(reply, "t", u);
333 }
334
335 static int property_get_syscall_filter(
336 sd_bus *bus,
337 const char *path,
338 const char *interface,
339 const char *property,
340 sd_bus_message *reply,
341 void *userdata,
342 sd_bus_error *error) {
343
344 ExecContext *c = ASSERT_PTR(userdata);
345 _cleanup_strv_free_ char **l = NULL;
346 int r;
347
348 assert(bus);
349 assert(reply);
350
351 r = sd_bus_message_open_container(reply, 'r', "bas");
352 if (r < 0)
353 return r;
354
355 r = sd_bus_message_append(reply, "b", c->syscall_allow_list);
356 if (r < 0)
357 return r;
358
359 #if HAVE_SECCOMP
360 void *id, *val;
361 HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
362 _cleanup_free_ char *name = NULL;
363 const char *e = NULL;
364 char *s;
365 int num = PTR_TO_INT(val);
366
367 if (c->syscall_allow_list && num >= 0)
368 /* syscall with num >= 0 in allow-list is denied. */
369 continue;
370
371 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
372 if (!name)
373 continue;
374
375 if (num >= 0) {
376 e = seccomp_errno_or_action_to_string(num);
377 if (e) {
378 s = strjoin(name, ":", e);
379 if (!s)
380 return -ENOMEM;
381 } else {
382 r = asprintf(&s, "%s:%d", name, num);
383 if (r < 0)
384 return -ENOMEM;
385 }
386 } else
387 s = TAKE_PTR(name);
388
389 r = strv_consume(&l, s);
390 if (r < 0)
391 return r;
392 }
393 #endif
394
395 strv_sort(l);
396
397 r = sd_bus_message_append_strv(reply, l);
398 if (r < 0)
399 return r;
400
401 return sd_bus_message_close_container(reply);
402 }
403
404 static int property_get_syscall_log(
405 sd_bus *bus,
406 const char *path,
407 const char *interface,
408 const char *property,
409 sd_bus_message *reply,
410 void *userdata,
411 sd_bus_error *error) {
412
413 ExecContext *c = ASSERT_PTR(userdata);
414 _cleanup_strv_free_ char **l = NULL;
415 int r;
416
417 assert(bus);
418 assert(reply);
419
420 r = sd_bus_message_open_container(reply, 'r', "bas");
421 if (r < 0)
422 return r;
423
424 r = sd_bus_message_append(reply, "b", c->syscall_log_allow_list);
425 if (r < 0)
426 return r;
427
428 #if HAVE_SECCOMP
429 void *id, *val;
430 HASHMAP_FOREACH_KEY(val, id, c->syscall_log) {
431 char *name = NULL;
432
433 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
434 if (!name)
435 continue;
436
437 r = strv_consume(&l, name);
438 if (r < 0)
439 return r;
440 }
441 #endif
442
443 strv_sort(l);
444
445 r = sd_bus_message_append_strv(reply, l);
446 if (r < 0)
447 return r;
448
449 return sd_bus_message_close_container(reply);
450 }
451
452 static int property_get_syscall_archs(
453 sd_bus *bus,
454 const char *path,
455 const char *interface,
456 const char *property,
457 sd_bus_message *reply,
458 void *userdata,
459 sd_bus_error *error) {
460
461 _cleanup_strv_free_ char **l = NULL;
462 int r;
463
464 assert(bus);
465 assert(reply);
466
467 #if HAVE_SECCOMP
468 void *id;
469 SET_FOREACH(id, ASSERT_PTR((ExecContext*) userdata)->syscall_archs) {
470 const char *name;
471
472 name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
473 if (!name)
474 continue;
475
476 r = strv_extend(&l, name);
477 if (r < 0)
478 return -ENOMEM;
479 }
480 #endif
481
482 strv_sort(l);
483
484 r = sd_bus_message_append_strv(reply, l);
485 if (r < 0)
486 return r;
487
488 return 0;
489 }
490
491 static int property_get_selinux_context(
492 sd_bus *bus,
493 const char *path,
494 const char *interface,
495 const char *property,
496 sd_bus_message *reply,
497 void *userdata,
498 sd_bus_error *error) {
499
500 ExecContext *c = ASSERT_PTR(userdata);
501
502 assert(bus);
503 assert(reply);
504
505 return sd_bus_message_append(reply, "(bs)", c->selinux_context_ignore, c->selinux_context);
506 }
507
508 static int property_get_apparmor_profile(
509 sd_bus *bus,
510 const char *path,
511 const char *interface,
512 const char *property,
513 sd_bus_message *reply,
514 void *userdata,
515 sd_bus_error *error) {
516
517 ExecContext *c = ASSERT_PTR(userdata);
518
519 assert(bus);
520 assert(reply);
521
522 return sd_bus_message_append(reply, "(bs)", c->apparmor_profile_ignore, c->apparmor_profile);
523 }
524
525 static int property_get_smack_process_label(
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 = ASSERT_PTR(userdata);
535
536 assert(bus);
537 assert(reply);
538
539 return sd_bus_message_append(reply, "(bs)", c->smack_process_label_ignore, c->smack_process_label);
540 }
541
542 static int property_get_address_families(
543 sd_bus *bus,
544 const char *path,
545 const char *interface,
546 const char *property,
547 sd_bus_message *reply,
548 void *userdata,
549 sd_bus_error *error) {
550
551 ExecContext *c = ASSERT_PTR(userdata);
552 _cleanup_strv_free_ char **l = NULL;
553 void *af;
554 int r;
555
556 assert(bus);
557 assert(reply);
558
559 r = sd_bus_message_open_container(reply, 'r', "bas");
560 if (r < 0)
561 return r;
562
563 r = sd_bus_message_append(reply, "b", c->address_families_allow_list);
564 if (r < 0)
565 return r;
566
567 SET_FOREACH(af, c->address_families) {
568 const char *name;
569
570 name = af_to_name(PTR_TO_INT(af));
571 if (!name)
572 continue;
573
574 r = strv_extend(&l, name);
575 if (r < 0)
576 return -ENOMEM;
577 }
578
579 strv_sort(l);
580
581 r = sd_bus_message_append_strv(reply, l);
582 if (r < 0)
583 return r;
584
585 return sd_bus_message_close_container(reply);
586 }
587
588 static int property_get_working_directory(
589 sd_bus *bus,
590 const char *path,
591 const char *interface,
592 const char *property,
593 sd_bus_message *reply,
594 void *userdata,
595 sd_bus_error *error) {
596
597 ExecContext *c = ASSERT_PTR(userdata);
598 const char *wd;
599
600 assert(bus);
601 assert(reply);
602
603 if (c->working_directory_home)
604 wd = "~";
605 else
606 wd = c->working_directory;
607
608 if (c->working_directory_missing_ok)
609 wd = strjoina("!", wd);
610
611 return sd_bus_message_append(reply, "s", wd);
612 }
613
614 static int property_get_stdio_fdname(
615 sd_bus *bus,
616 const char *path,
617 const char *interface,
618 const char *property,
619 sd_bus_message *reply,
620 void *userdata,
621 sd_bus_error *error) {
622
623 ExecContext *c = ASSERT_PTR(userdata);
624 int fileno;
625
626 assert(bus);
627 assert(property);
628 assert(reply);
629
630 if (streq(property, "StandardInputFileDescriptorName"))
631 fileno = STDIN_FILENO;
632 else if (streq(property, "StandardOutputFileDescriptorName"))
633 fileno = STDOUT_FILENO;
634 else {
635 assert(streq(property, "StandardErrorFileDescriptorName"));
636 fileno = STDERR_FILENO;
637 }
638
639 return sd_bus_message_append(reply, "s", exec_context_fdname(c, fileno));
640 }
641
642 static int property_get_input_data(
643 sd_bus *bus,
644 const char *path,
645 const char *interface,
646 const char *property,
647 sd_bus_message *reply,
648 void *userdata,
649 sd_bus_error *error) {
650
651 ExecContext *c = ASSERT_PTR(userdata);
652
653 assert(bus);
654 assert(property);
655 assert(reply);
656
657 return sd_bus_message_append_array(reply, 'y', c->stdin_data, c->stdin_data_size);
658 }
659
660 static int property_get_restrict_filesystems(
661 sd_bus *bus,
662 const char *path,
663 const char *interface,
664 const char *property,
665 sd_bus_message *reply,
666 void *userdata,
667 sd_bus_error *error) {
668
669 ExecContext *c = ASSERT_PTR(userdata);
670 _cleanup_free_ char **l = NULL;
671 int r;
672
673 assert(bus);
674 assert(reply);
675
676 r = sd_bus_message_open_container(reply, 'r', "bas");
677 if (r < 0)
678 return r;
679
680 r = sd_bus_message_append(reply, "b", c->restrict_filesystems_allow_list);
681 if (r < 0)
682 return r;
683
684 #if HAVE_LIBBPF
685 l = set_get_strv(c->restrict_filesystems);
686 if (!l)
687 return -ENOMEM;
688 #endif
689
690 strv_sort(l);
691
692 r = sd_bus_message_append_strv(reply, l);
693 if (r < 0)
694 return r;
695
696 return sd_bus_message_close_container(reply);
697 }
698
699 static int property_get_bind_paths(
700 sd_bus *bus,
701 const char *path,
702 const char *interface,
703 const char *property,
704 sd_bus_message *reply,
705 void *userdata,
706 sd_bus_error *error) {
707
708 ExecContext *c = ASSERT_PTR(userdata);
709 bool ro;
710 int r;
711
712 assert(bus);
713 assert(property);
714 assert(reply);
715
716 ro = strstr(property, "ReadOnly");
717
718 r = sd_bus_message_open_container(reply, 'a', "(ssbt)");
719 if (r < 0)
720 return r;
721
722 for (size_t i = 0; i < c->n_bind_mounts; i++) {
723
724 if (ro != c->bind_mounts[i].read_only)
725 continue;
726
727 r = sd_bus_message_append(
728 reply, "(ssbt)",
729 c->bind_mounts[i].source,
730 c->bind_mounts[i].destination,
731 c->bind_mounts[i].ignore_enoent,
732 c->bind_mounts[i].recursive ? (uint64_t) MS_REC : (uint64_t) 0);
733 if (r < 0)
734 return r;
735 }
736
737 return sd_bus_message_close_container(reply);
738 }
739
740 static int property_get_temporary_filesystems(
741 sd_bus *bus,
742 const char *path,
743 const char *interface,
744 const char *property,
745 sd_bus_message *reply,
746 void *userdata,
747 sd_bus_error *error) {
748
749 ExecContext *c = ASSERT_PTR(userdata);
750 int r;
751
752 assert(bus);
753 assert(property);
754 assert(reply);
755
756 r = sd_bus_message_open_container(reply, 'a', "(ss)");
757 if (r < 0)
758 return r;
759
760 for (unsigned i = 0; i < c->n_temporary_filesystems; i++) {
761 TemporaryFileSystem *t = c->temporary_filesystems + i;
762
763 r = sd_bus_message_append(
764 reply, "(ss)",
765 t->path,
766 t->options);
767 if (r < 0)
768 return r;
769 }
770
771 return sd_bus_message_close_container(reply);
772 }
773
774 static int property_get_log_extra_fields(
775 sd_bus *bus,
776 const char *path,
777 const char *interface,
778 const char *property,
779 sd_bus_message *reply,
780 void *userdata,
781 sd_bus_error *error) {
782
783 ExecContext *c = ASSERT_PTR(userdata);
784 int r;
785
786 assert(bus);
787 assert(property);
788 assert(reply);
789
790 r = sd_bus_message_open_container(reply, 'a', "ay");
791 if (r < 0)
792 return r;
793
794 for (size_t i = 0; i < c->n_log_extra_fields; i++) {
795 r = sd_bus_message_append_array(reply, 'y', c->log_extra_fields[i].iov_base, c->log_extra_fields[i].iov_len);
796 if (r < 0)
797 return r;
798 }
799
800 return sd_bus_message_close_container(reply);
801 }
802
803 static int sd_bus_message_append_log_filter_patterns(sd_bus_message *reply, Set *patterns, bool is_allowlist) {
804 const char *pattern;
805 int r;
806
807 assert(reply);
808
809 SET_FOREACH(pattern, patterns) {
810 r = sd_bus_message_append(reply, "(bs)", is_allowlist, pattern);
811 if (r < 0)
812 return r;
813 }
814
815 return 0;
816 }
817
818 static int property_get_log_filter_patterns(
819 sd_bus *bus,
820 const char *path,
821 const char *interface,
822 const char *property,
823 sd_bus_message *reply,
824 void *userdata,
825 sd_bus_error *error) {
826
827 ExecContext *c = userdata;
828 int r;
829
830 assert(c);
831 assert(reply);
832
833 r = sd_bus_message_open_container(reply, 'a', "(bs)");
834 if (r < 0)
835 return r;
836
837 r = sd_bus_message_append_log_filter_patterns(reply, c->log_filter_allowed_patterns,
838 /* is_allowlist = */ true);
839 if (r < 0)
840 return r;
841
842 r = sd_bus_message_append_log_filter_patterns(reply, c->log_filter_denied_patterns,
843 /* is_allowlist = */ false);
844 if (r < 0)
845 return r;
846
847 return sd_bus_message_close_container(reply);
848 }
849
850 static int property_get_set_credential(
851 sd_bus *bus,
852 const char *path,
853 const char *interface,
854 const char *property,
855 sd_bus_message *reply,
856 void *userdata,
857 sd_bus_error *error) {
858
859 ExecContext *c = ASSERT_PTR(userdata);
860 ExecSetCredential *sc;
861 int r;
862
863 assert(bus);
864 assert(property);
865 assert(reply);
866
867 r = sd_bus_message_open_container(reply, 'a', "(say)");
868 if (r < 0)
869 return r;
870
871 HASHMAP_FOREACH(sc, c->set_credentials) {
872
873 if (sc->encrypted != streq(property, "SetCredentialEncrypted"))
874 continue;
875
876 r = sd_bus_message_open_container(reply, 'r', "say");
877 if (r < 0)
878 return r;
879
880 r = sd_bus_message_append(reply, "s", sc->id);
881 if (r < 0)
882 return r;
883
884 r = sd_bus_message_append_array(reply, 'y', sc->data, sc->size);
885 if (r < 0)
886 return r;
887
888 r = sd_bus_message_close_container(reply);
889 if (r < 0)
890 return r;
891 }
892
893 return sd_bus_message_close_container(reply);
894 }
895
896 static int property_get_load_credential(
897 sd_bus *bus,
898 const char *path,
899 const char *interface,
900 const char *property,
901 sd_bus_message *reply,
902 void *userdata,
903 sd_bus_error *error) {
904
905 ExecContext *c = ASSERT_PTR(userdata);
906 ExecLoadCredential *lc;
907 int r;
908
909 assert(bus);
910 assert(property);
911 assert(reply);
912
913 r = sd_bus_message_open_container(reply, 'a', "(ss)");
914 if (r < 0)
915 return r;
916
917 HASHMAP_FOREACH(lc, c->load_credentials) {
918
919 if (lc->encrypted != streq(property, "LoadCredentialEncrypted"))
920 continue;
921
922 r = sd_bus_message_append(reply, "(ss)", lc->id, lc->path);
923 if (r < 0)
924 return r;
925 }
926
927 return sd_bus_message_close_container(reply);
928 }
929
930 static int property_get_root_hash(
931 sd_bus *bus,
932 const char *path,
933 const char *interface,
934 const char *property,
935 sd_bus_message *reply,
936 void *userdata,
937 sd_bus_error *error) {
938
939 ExecContext *c = ASSERT_PTR(userdata);
940
941 assert(bus);
942 assert(property);
943 assert(reply);
944
945 return sd_bus_message_append_array(reply, 'y', c->root_hash, c->root_hash_size);
946 }
947
948 static int property_get_root_hash_sig(
949 sd_bus *bus,
950 const char *path,
951 const char *interface,
952 const char *property,
953 sd_bus_message *reply,
954 void *userdata,
955 sd_bus_error *error) {
956
957 ExecContext *c = ASSERT_PTR(userdata);
958
959 assert(bus);
960 assert(property);
961 assert(reply);
962
963 return sd_bus_message_append_array(reply, 'y', c->root_hash_sig, c->root_hash_sig_size);
964 }
965
966 static int property_get_root_image_options(
967 sd_bus *bus,
968 const char *path,
969 const char *interface,
970 const char *property,
971 sd_bus_message *reply,
972 void *userdata,
973 sd_bus_error *error) {
974
975 ExecContext *c = ASSERT_PTR(userdata);
976 int r;
977
978 assert(bus);
979 assert(property);
980 assert(reply);
981
982 r = sd_bus_message_open_container(reply, 'a', "(ss)");
983 if (r < 0)
984 return r;
985
986 LIST_FOREACH(mount_options, m, c->root_image_options) {
987 r = sd_bus_message_append(reply, "(ss)",
988 partition_designator_to_string(m->partition_designator),
989 m->options);
990 if (r < 0)
991 return r;
992 }
993
994 return sd_bus_message_close_container(reply);
995 }
996
997 static int property_get_mount_images(
998 sd_bus *bus,
999 const char *path,
1000 const char *interface,
1001 const char *property,
1002 sd_bus_message *reply,
1003 void *userdata,
1004 sd_bus_error *error) {
1005
1006 ExecContext *c = ASSERT_PTR(userdata);
1007 int r;
1008
1009 assert(bus);
1010 assert(property);
1011 assert(reply);
1012
1013 r = sd_bus_message_open_container(reply, 'a', "(ssba(ss))");
1014 if (r < 0)
1015 return r;
1016
1017 for (size_t i = 0; i < c->n_mount_images; i++) {
1018 r = sd_bus_message_open_container(reply, SD_BUS_TYPE_STRUCT, "ssba(ss)");
1019 if (r < 0)
1020 return r;
1021 r = sd_bus_message_append(
1022 reply, "ssb",
1023 c->mount_images[i].source,
1024 c->mount_images[i].destination,
1025 c->mount_images[i].ignore_enoent);
1026 if (r < 0)
1027 return r;
1028 r = sd_bus_message_open_container(reply, 'a', "(ss)");
1029 if (r < 0)
1030 return r;
1031 LIST_FOREACH(mount_options, m, c->mount_images[i].mount_options) {
1032 r = sd_bus_message_append(reply, "(ss)",
1033 partition_designator_to_string(m->partition_designator),
1034 m->options);
1035 if (r < 0)
1036 return r;
1037 }
1038 r = sd_bus_message_close_container(reply);
1039 if (r < 0)
1040 return r;
1041 r = sd_bus_message_close_container(reply);
1042 if (r < 0)
1043 return r;
1044 }
1045
1046 return sd_bus_message_close_container(reply);
1047 }
1048
1049 static int property_get_extension_images(
1050 sd_bus *bus,
1051 const char *path,
1052 const char *interface,
1053 const char *property,
1054 sd_bus_message *reply,
1055 void *userdata,
1056 sd_bus_error *error) {
1057
1058 ExecContext *c = ASSERT_PTR(userdata);
1059 int r;
1060
1061 assert(bus);
1062 assert(property);
1063 assert(reply);
1064
1065 r = sd_bus_message_open_container(reply, 'a', "(sba(ss))");
1066 if (r < 0)
1067 return r;
1068
1069 for (size_t i = 0; i < c->n_extension_images; i++) {
1070 r = sd_bus_message_open_container(reply, SD_BUS_TYPE_STRUCT, "sba(ss)");
1071 if (r < 0)
1072 return r;
1073 r = sd_bus_message_append(
1074 reply, "sb",
1075 c->extension_images[i].source,
1076 c->extension_images[i].ignore_enoent);
1077 if (r < 0)
1078 return r;
1079 r = sd_bus_message_open_container(reply, 'a', "(ss)");
1080 if (r < 0)
1081 return r;
1082 LIST_FOREACH(mount_options, m, c->extension_images[i].mount_options) {
1083 r = sd_bus_message_append(reply, "(ss)",
1084 partition_designator_to_string(m->partition_designator),
1085 m->options);
1086 if (r < 0)
1087 return r;
1088 }
1089 r = sd_bus_message_close_container(reply);
1090 if (r < 0)
1091 return r;
1092 r = sd_bus_message_close_container(reply);
1093 if (r < 0)
1094 return r;
1095 }
1096
1097 return sd_bus_message_close_container(reply);
1098 }
1099
1100 static int bus_property_get_exec_dir(
1101 sd_bus *bus,
1102 const char *path,
1103 const char *interface,
1104 const char *property,
1105 sd_bus_message *reply,
1106 void *userdata,
1107 sd_bus_error *error) {
1108
1109 ExecDirectory *d = ASSERT_PTR(userdata);
1110 int r;
1111
1112 assert(bus);
1113 assert(property);
1114 assert(reply);
1115
1116 r = sd_bus_message_open_container(reply, 'a', "s");
1117 if (r < 0)
1118 return r;
1119
1120 for (size_t i = 0; i < d->n_items; i++) {
1121 r = sd_bus_message_append_basic(reply, 's', d->items[i].path);
1122 if (r < 0)
1123 return r;
1124 }
1125
1126 return sd_bus_message_close_container(reply);
1127 }
1128
1129 static int bus_property_get_exec_dir_symlink(
1130 sd_bus *bus,
1131 const char *path,
1132 const char *interface,
1133 const char *property,
1134 sd_bus_message *reply,
1135 void *userdata,
1136 sd_bus_error *error) {
1137
1138 ExecDirectory *d = ASSERT_PTR(userdata);
1139 int r;
1140
1141 assert(bus);
1142 assert(property);
1143 assert(reply);
1144
1145 r = sd_bus_message_open_container(reply, 'a', "(sst)");
1146 if (r < 0)
1147 return r;
1148
1149 for (size_t i = 0; i < d->n_items; i++)
1150 STRV_FOREACH(dst, d->items[i].symlinks) {
1151 r = sd_bus_message_append(reply, "(sst)", d->items[i].path, *dst, 0 /* flags, unused for now */);
1152 if (r < 0)
1153 return r;
1154 }
1155
1156 return sd_bus_message_close_container(reply);
1157 }
1158
1159 const sd_bus_vtable bus_exec_vtable[] = {
1160 SD_BUS_VTABLE_START(0),
1161 SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
1162 SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1163 SD_BUS_PROPERTY("PassEnvironment", "as", NULL, offsetof(ExecContext, pass_environment), SD_BUS_VTABLE_PROPERTY_CONST),
1164 SD_BUS_PROPERTY("UnsetEnvironment", "as", NULL, offsetof(ExecContext, unset_environment), SD_BUS_VTABLE_PROPERTY_CONST),
1165 SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
1166 SD_BUS_PROPERTY("LimitCPU", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
1167 SD_BUS_PROPERTY("LimitCPUSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
1168 SD_BUS_PROPERTY("LimitFSIZE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
1169 SD_BUS_PROPERTY("LimitFSIZESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
1170 SD_BUS_PROPERTY("LimitDATA", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
1171 SD_BUS_PROPERTY("LimitDATASoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
1172 SD_BUS_PROPERTY("LimitSTACK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
1173 SD_BUS_PROPERTY("LimitSTACKSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
1174 SD_BUS_PROPERTY("LimitCORE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
1175 SD_BUS_PROPERTY("LimitCORESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
1176 SD_BUS_PROPERTY("LimitRSS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
1177 SD_BUS_PROPERTY("LimitRSSSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
1178 SD_BUS_PROPERTY("LimitNOFILE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
1179 SD_BUS_PROPERTY("LimitNOFILESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
1180 SD_BUS_PROPERTY("LimitAS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
1181 SD_BUS_PROPERTY("LimitASSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
1182 SD_BUS_PROPERTY("LimitNPROC", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
1183 SD_BUS_PROPERTY("LimitNPROCSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
1184 SD_BUS_PROPERTY("LimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
1185 SD_BUS_PROPERTY("LimitMEMLOCKSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
1186 SD_BUS_PROPERTY("LimitLOCKS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
1187 SD_BUS_PROPERTY("LimitLOCKSSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
1188 SD_BUS_PROPERTY("LimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
1189 SD_BUS_PROPERTY("LimitSIGPENDINGSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
1190 SD_BUS_PROPERTY("LimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
1191 SD_BUS_PROPERTY("LimitMSGQUEUESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
1192 SD_BUS_PROPERTY("LimitNICE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
1193 SD_BUS_PROPERTY("LimitNICESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
1194 SD_BUS_PROPERTY("LimitRTPRIO", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
1195 SD_BUS_PROPERTY("LimitRTPRIOSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
1196 SD_BUS_PROPERTY("LimitRTTIME", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
1197 SD_BUS_PROPERTY("LimitRTTIMESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
1198 SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1199 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
1200 SD_BUS_PROPERTY("RootImage", "s", NULL, offsetof(ExecContext, root_image), SD_BUS_VTABLE_PROPERTY_CONST),
1201 SD_BUS_PROPERTY("RootImageOptions", "a(ss)", property_get_root_image_options, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1202 SD_BUS_PROPERTY("RootHash", "ay", property_get_root_hash, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1203 SD_BUS_PROPERTY("RootHashPath", "s", NULL, offsetof(ExecContext, root_hash_path), SD_BUS_VTABLE_PROPERTY_CONST),
1204 SD_BUS_PROPERTY("RootHashSignature", "ay", property_get_root_hash_sig, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1205 SD_BUS_PROPERTY("RootHashSignaturePath", "s", NULL, offsetof(ExecContext, root_hash_sig_path), SD_BUS_VTABLE_PROPERTY_CONST),
1206 SD_BUS_PROPERTY("RootVerity", "s", NULL, offsetof(ExecContext, root_verity), SD_BUS_VTABLE_PROPERTY_CONST),
1207 SD_BUS_PROPERTY("ExtensionDirectories", "as", NULL, offsetof(ExecContext, extension_directories), SD_BUS_VTABLE_PROPERTY_CONST),
1208 SD_BUS_PROPERTY("ExtensionImages", "a(sba(ss))", property_get_extension_images, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1209 SD_BUS_PROPERTY("MountImages", "a(ssba(ss))", property_get_mount_images, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1210 SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1211 SD_BUS_PROPERTY("CoredumpFilter", "t", property_get_coredump_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1212 SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1213 SD_BUS_PROPERTY("IOSchedulingClass", "i", property_get_ioprio_class, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1214 SD_BUS_PROPERTY("IOSchedulingPriority", "i", property_get_ioprio_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1215 SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1216 SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1217 SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1218 SD_BUS_PROPERTY("CPUAffinityFromNUMA", "b", property_get_cpu_affinity_from_numa, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1219 SD_BUS_PROPERTY("NUMAPolicy", "i", property_get_numa_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1220 SD_BUS_PROPERTY("NUMAMask", "ay", property_get_numa_mask, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1221 SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1222 SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), SD_BUS_VTABLE_PROPERTY_CONST),
1223 SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), SD_BUS_VTABLE_PROPERTY_CONST),
1224 SD_BUS_PROPERTY("StandardInput", "s", property_get_exec_input, offsetof(ExecContext, std_input), SD_BUS_VTABLE_PROPERTY_CONST),
1225 SD_BUS_PROPERTY("StandardInputFileDescriptorName", "s", property_get_stdio_fdname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1226 SD_BUS_PROPERTY("StandardInputData", "ay", property_get_input_data, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1227 SD_BUS_PROPERTY("StandardOutput", "s", bus_property_get_exec_output, offsetof(ExecContext, std_output), SD_BUS_VTABLE_PROPERTY_CONST),
1228 SD_BUS_PROPERTY("StandardOutputFileDescriptorName", "s", property_get_stdio_fdname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1229 SD_BUS_PROPERTY("StandardError", "s", bus_property_get_exec_output, offsetof(ExecContext, std_error), SD_BUS_VTABLE_PROPERTY_CONST),
1230 SD_BUS_PROPERTY("StandardErrorFileDescriptorName", "s", property_get_stdio_fdname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1231 SD_BUS_PROPERTY("TTYPath", "s", NULL, offsetof(ExecContext, tty_path), SD_BUS_VTABLE_PROPERTY_CONST),
1232 SD_BUS_PROPERTY("TTYReset", "b", bus_property_get_bool, offsetof(ExecContext, tty_reset), SD_BUS_VTABLE_PROPERTY_CONST),
1233 SD_BUS_PROPERTY("TTYVHangup", "b", bus_property_get_bool, offsetof(ExecContext, tty_vhangup), SD_BUS_VTABLE_PROPERTY_CONST),
1234 SD_BUS_PROPERTY("TTYVTDisallocate", "b", bus_property_get_bool, offsetof(ExecContext, tty_vt_disallocate), SD_BUS_VTABLE_PROPERTY_CONST),
1235 SD_BUS_PROPERTY("TTYRows", "q", bus_property_get_unsigned, offsetof(ExecContext, tty_rows), SD_BUS_VTABLE_PROPERTY_CONST),
1236 SD_BUS_PROPERTY("TTYColumns", "q", bus_property_get_unsigned, offsetof(ExecContext, tty_cols), SD_BUS_VTABLE_PROPERTY_CONST),
1237 SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
1238 SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST),
1239 SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
1240 SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
1241 SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
1242 SD_BUS_PROPERTY("LogLevelMax", "i", bus_property_get_int, offsetof(ExecContext, log_level_max), SD_BUS_VTABLE_PROPERTY_CONST),
1243 SD_BUS_PROPERTY("LogRateLimitIntervalUSec", "t", bus_property_get_usec, offsetof(ExecContext, log_ratelimit_interval_usec), SD_BUS_VTABLE_PROPERTY_CONST),
1244 SD_BUS_PROPERTY("LogRateLimitBurst", "u", bus_property_get_unsigned, offsetof(ExecContext, log_ratelimit_burst), SD_BUS_VTABLE_PROPERTY_CONST),
1245 SD_BUS_PROPERTY("LogExtraFields", "aay", property_get_log_extra_fields, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1246 SD_BUS_PROPERTY("LogFilterPatterns", "a(bs)", property_get_log_filter_patterns, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1247 SD_BUS_PROPERTY("LogNamespace", "s", NULL, offsetof(ExecContext, log_namespace), SD_BUS_VTABLE_PROPERTY_CONST),
1248 SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
1249 SD_BUS_PROPERTY("CapabilityBoundingSet", "t", NULL, offsetof(ExecContext, capability_bounding_set), SD_BUS_VTABLE_PROPERTY_CONST),
1250 SD_BUS_PROPERTY("AmbientCapabilities", "t", NULL, offsetof(ExecContext, capability_ambient_set), SD_BUS_VTABLE_PROPERTY_CONST),
1251 SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST),
1252 SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST),
1253 SD_BUS_PROPERTY("DynamicUser", "b", bus_property_get_bool, offsetof(ExecContext, dynamic_user), SD_BUS_VTABLE_PROPERTY_CONST),
1254 SD_BUS_PROPERTY("RemoveIPC", "b", bus_property_get_bool, offsetof(ExecContext, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
1255 SD_BUS_PROPERTY("SetCredential", "a(say)", property_get_set_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1256 SD_BUS_PROPERTY("SetCredentialEncrypted", "a(say)", property_get_set_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1257 SD_BUS_PROPERTY("LoadCredential", "a(ss)", property_get_load_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1258 SD_BUS_PROPERTY("LoadCredentialEncrypted", "a(ss)", property_get_load_credential, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1259 SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
1260 SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST),
1261 SD_BUS_PROPERTY("ReadWritePaths", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST),
1262 SD_BUS_PROPERTY("ReadOnlyPaths", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST),
1263 SD_BUS_PROPERTY("InaccessiblePaths", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST),
1264 SD_BUS_PROPERTY("ExecPaths", "as", NULL, offsetof(ExecContext, exec_paths), SD_BUS_VTABLE_PROPERTY_CONST),
1265 SD_BUS_PROPERTY("NoExecPaths", "as", NULL, offsetof(ExecContext, no_exec_paths), SD_BUS_VTABLE_PROPERTY_CONST),
1266 SD_BUS_PROPERTY("ExecSearchPath", "as", NULL, offsetof(ExecContext, exec_search_path), SD_BUS_VTABLE_PROPERTY_CONST),
1267 SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
1268 SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST),
1269 SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST),
1270 SD_BUS_PROPERTY("ProtectClock", "b", bus_property_get_bool, offsetof(ExecContext, protect_clock), SD_BUS_VTABLE_PROPERTY_CONST),
1271 SD_BUS_PROPERTY("ProtectKernelTunables", "b", bus_property_get_bool, offsetof(ExecContext, protect_kernel_tunables), SD_BUS_VTABLE_PROPERTY_CONST),
1272 SD_BUS_PROPERTY("ProtectKernelModules", "b", bus_property_get_bool, offsetof(ExecContext, protect_kernel_modules), SD_BUS_VTABLE_PROPERTY_CONST),
1273 SD_BUS_PROPERTY("ProtectKernelLogs", "b", bus_property_get_bool, offsetof(ExecContext, protect_kernel_logs), SD_BUS_VTABLE_PROPERTY_CONST),
1274 SD_BUS_PROPERTY("ProtectControlGroups", "b", bus_property_get_bool, offsetof(ExecContext, protect_control_groups), SD_BUS_VTABLE_PROPERTY_CONST),
1275 SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
1276 SD_BUS_PROPERTY("PrivateUsers", "b", bus_property_get_bool, offsetof(ExecContext, private_users), SD_BUS_VTABLE_PROPERTY_CONST),
1277 SD_BUS_PROPERTY("PrivateMounts", "b", bus_property_get_bool, offsetof(ExecContext, private_mounts), SD_BUS_VTABLE_PROPERTY_CONST),
1278 SD_BUS_PROPERTY("PrivateIPC", "b", bus_property_get_bool, offsetof(ExecContext, private_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
1279 SD_BUS_PROPERTY("ProtectHome", "s", property_get_protect_home, offsetof(ExecContext, protect_home), SD_BUS_VTABLE_PROPERTY_CONST),
1280 SD_BUS_PROPERTY("ProtectSystem", "s", property_get_protect_system, offsetof(ExecContext, protect_system), SD_BUS_VTABLE_PROPERTY_CONST),
1281 SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST),
1282 SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), SD_BUS_VTABLE_PROPERTY_CONST),
1283 SD_BUS_PROPERTY("UtmpMode", "s", property_get_exec_utmp_mode, offsetof(ExecContext, utmp_mode), SD_BUS_VTABLE_PROPERTY_CONST),
1284 SD_BUS_PROPERTY("SELinuxContext", "(bs)", property_get_selinux_context, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1285 SD_BUS_PROPERTY("AppArmorProfile", "(bs)", property_get_apparmor_profile, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1286 SD_BUS_PROPERTY("SmackProcessLabel", "(bs)", property_get_smack_process_label, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1287 SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), SD_BUS_VTABLE_PROPERTY_CONST),
1288 SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), SD_BUS_VTABLE_PROPERTY_CONST),
1289 SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1290 SD_BUS_PROPERTY("SystemCallArchitectures", "as", property_get_syscall_archs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1291 SD_BUS_PROPERTY("SystemCallErrorNumber", "i", bus_property_get_int, offsetof(ExecContext, syscall_errno), SD_BUS_VTABLE_PROPERTY_CONST),
1292 SD_BUS_PROPERTY("SystemCallLog", "(bas)", property_get_syscall_log, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1293 SD_BUS_PROPERTY("Personality", "s", property_get_personality, offsetof(ExecContext, personality), SD_BUS_VTABLE_PROPERTY_CONST),
1294 SD_BUS_PROPERTY("LockPersonality", "b", bus_property_get_bool, offsetof(ExecContext, lock_personality), SD_BUS_VTABLE_PROPERTY_CONST),
1295 SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1296 SD_BUS_PROPERTY("RuntimeDirectorySymlink", "a(sst)", bus_property_get_exec_dir_symlink, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
1297 SD_BUS_PROPERTY("RuntimeDirectoryPreserve", "s", property_get_exec_preserve_mode, offsetof(ExecContext, runtime_directory_preserve_mode), SD_BUS_VTABLE_PROPERTY_CONST),
1298 SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME].mode), SD_BUS_VTABLE_PROPERTY_CONST),
1299 SD_BUS_PROPERTY("RuntimeDirectory", "as", bus_property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
1300 SD_BUS_PROPERTY("StateDirectorySymlink", "a(sst)", bus_property_get_exec_dir_symlink, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE]), SD_BUS_VTABLE_PROPERTY_CONST),
1301 SD_BUS_PROPERTY("StateDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE].mode), SD_BUS_VTABLE_PROPERTY_CONST),
1302 SD_BUS_PROPERTY("StateDirectory", "as", bus_property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE]), SD_BUS_VTABLE_PROPERTY_CONST),
1303 SD_BUS_PROPERTY("CacheDirectorySymlink", "a(sst)", bus_property_get_exec_dir_symlink, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE]), SD_BUS_VTABLE_PROPERTY_CONST),
1304 SD_BUS_PROPERTY("CacheDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE].mode), SD_BUS_VTABLE_PROPERTY_CONST),
1305 SD_BUS_PROPERTY("CacheDirectory", "as", bus_property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE]), SD_BUS_VTABLE_PROPERTY_CONST),
1306 SD_BUS_PROPERTY("LogsDirectorySymlink", "a(sst)", bus_property_get_exec_dir_symlink, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS]), SD_BUS_VTABLE_PROPERTY_CONST),
1307 SD_BUS_PROPERTY("LogsDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS].mode), SD_BUS_VTABLE_PROPERTY_CONST),
1308 SD_BUS_PROPERTY("LogsDirectory", "as", bus_property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS]), SD_BUS_VTABLE_PROPERTY_CONST),
1309 SD_BUS_PROPERTY("ConfigurationDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION].mode), SD_BUS_VTABLE_PROPERTY_CONST),
1310 SD_BUS_PROPERTY("ConfigurationDirectory", "as", bus_property_get_exec_dir, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION]), SD_BUS_VTABLE_PROPERTY_CONST),
1311 SD_BUS_PROPERTY("TimeoutCleanUSec", "t", bus_property_get_usec, offsetof(ExecContext, timeout_clean_usec), SD_BUS_VTABLE_PROPERTY_CONST),
1312 SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST),
1313 SD_BUS_PROPERTY("RestrictRealtime", "b", bus_property_get_bool, offsetof(ExecContext, restrict_realtime), SD_BUS_VTABLE_PROPERTY_CONST),
1314 SD_BUS_PROPERTY("RestrictSUIDSGID", "b", bus_property_get_bool, offsetof(ExecContext, restrict_suid_sgid), SD_BUS_VTABLE_PROPERTY_CONST),
1315 SD_BUS_PROPERTY("RestrictNamespaces", "t", bus_property_get_ulong, offsetof(ExecContext, restrict_namespaces), SD_BUS_VTABLE_PROPERTY_CONST),
1316 SD_BUS_PROPERTY("RestrictFileSystems", "(bas)", property_get_restrict_filesystems, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1317 SD_BUS_PROPERTY("BindPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1318 SD_BUS_PROPERTY("BindReadOnlyPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1319 SD_BUS_PROPERTY("TemporaryFileSystem", "a(ss)", property_get_temporary_filesystems, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1320 SD_BUS_PROPERTY("MountAPIVFS", "b", property_get_mount_apivfs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1321 SD_BUS_PROPERTY("KeyringMode", "s", property_get_exec_keyring_mode, offsetof(ExecContext, keyring_mode), SD_BUS_VTABLE_PROPERTY_CONST),
1322 SD_BUS_PROPERTY("ProtectProc", "s", property_get_protect_proc, offsetof(ExecContext, protect_proc), SD_BUS_VTABLE_PROPERTY_CONST),
1323 SD_BUS_PROPERTY("ProcSubset", "s", property_get_proc_subset, offsetof(ExecContext, proc_subset), SD_BUS_VTABLE_PROPERTY_CONST),
1324 SD_BUS_PROPERTY("ProtectHostname", "b", bus_property_get_bool, offsetof(ExecContext, protect_hostname), SD_BUS_VTABLE_PROPERTY_CONST),
1325 SD_BUS_PROPERTY("NetworkNamespacePath", "s", NULL, offsetof(ExecContext, network_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
1326 SD_BUS_PROPERTY("IPCNamespacePath", "s", NULL, offsetof(ExecContext, ipc_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
1327
1328 /* Obsolete/redundant properties: */
1329 SD_BUS_PROPERTY("Capabilities", "s", property_get_empty_string, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1330 SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1331 SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1332 SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1333 SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
1334
1335 SD_BUS_VTABLE_END
1336 };
1337
1338 static int append_exec_command(sd_bus_message *reply, ExecCommand *c) {
1339 int r;
1340
1341 assert(reply);
1342 assert(c);
1343
1344 if (!c->path)
1345 return 0;
1346
1347 r = sd_bus_message_open_container(reply, 'r', "sasbttttuii");
1348 if (r < 0)
1349 return r;
1350
1351 r = sd_bus_message_append(reply, "s", c->path);
1352 if (r < 0)
1353 return r;
1354
1355 r = sd_bus_message_append_strv(reply, c->argv);
1356 if (r < 0)
1357 return r;
1358
1359 r = sd_bus_message_append(reply, "bttttuii",
1360 !!(c->flags & EXEC_COMMAND_IGNORE_FAILURE),
1361 c->exec_status.start_timestamp.realtime,
1362 c->exec_status.start_timestamp.monotonic,
1363 c->exec_status.exit_timestamp.realtime,
1364 c->exec_status.exit_timestamp.monotonic,
1365 (uint32_t) c->exec_status.pid,
1366 (int32_t) c->exec_status.code,
1367 (int32_t) c->exec_status.status);
1368 if (r < 0)
1369 return r;
1370
1371 return sd_bus_message_close_container(reply);
1372 }
1373
1374 static int append_exec_ex_command(sd_bus_message *reply, ExecCommand *c) {
1375 _cleanup_strv_free_ char **ex_opts = NULL;
1376 int r;
1377
1378 assert(reply);
1379 assert(c);
1380
1381 if (!c->path)
1382 return 0;
1383
1384 r = sd_bus_message_open_container(reply, 'r', "sasasttttuii");
1385 if (r < 0)
1386 return r;
1387
1388 r = sd_bus_message_append(reply, "s", c->path);
1389 if (r < 0)
1390 return r;
1391
1392 r = sd_bus_message_append_strv(reply, c->argv);
1393 if (r < 0)
1394 return r;
1395
1396 r = exec_command_flags_to_strv(c->flags, &ex_opts);
1397 if (r < 0)
1398 return r;
1399
1400 r = sd_bus_message_append_strv(reply, ex_opts);
1401 if (r < 0)
1402 return r;
1403
1404 r = sd_bus_message_append(reply, "ttttuii",
1405 c->exec_status.start_timestamp.realtime,
1406 c->exec_status.start_timestamp.monotonic,
1407 c->exec_status.exit_timestamp.realtime,
1408 c->exec_status.exit_timestamp.monotonic,
1409 (uint32_t) c->exec_status.pid,
1410 (int32_t) c->exec_status.code,
1411 (int32_t) c->exec_status.status);
1412 if (r < 0)
1413 return r;
1414
1415 return sd_bus_message_close_container(reply);
1416 }
1417
1418 int bus_property_get_exec_command(
1419 sd_bus *bus,
1420 const char *path,
1421 const char *interface,
1422 const char *property,
1423 sd_bus_message *reply,
1424 void *userdata,
1425 sd_bus_error *ret_error) {
1426
1427 ExecCommand *c = (ExecCommand*) userdata;
1428 int r;
1429
1430 assert(bus);
1431 assert(reply);
1432
1433 r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
1434 if (r < 0)
1435 return r;
1436
1437 r = append_exec_command(reply, c);
1438 if (r < 0)
1439 return r;
1440
1441 return sd_bus_message_close_container(reply);
1442 }
1443
1444 int bus_property_get_exec_command_list(
1445 sd_bus *bus,
1446 const char *path,
1447 const char *interface,
1448 const char *property,
1449 sd_bus_message *reply,
1450 void *userdata,
1451 sd_bus_error *ret_error) {
1452
1453 ExecCommand *exec_command = *(ExecCommand**) userdata;
1454 int r;
1455
1456 assert(bus);
1457 assert(reply);
1458
1459 r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
1460 if (r < 0)
1461 return r;
1462
1463 LIST_FOREACH(command, c, exec_command) {
1464 r = append_exec_command(reply, c);
1465 if (r < 0)
1466 return r;
1467 }
1468
1469 return sd_bus_message_close_container(reply);
1470 }
1471
1472 int bus_property_get_exec_ex_command_list(
1473 sd_bus *bus,
1474 const char *path,
1475 const char *interface,
1476 const char *property,
1477 sd_bus_message *reply,
1478 void *userdata,
1479 sd_bus_error *ret_error) {
1480
1481 ExecCommand *exec_command = *(ExecCommand**) userdata;
1482 int r;
1483
1484 assert(bus);
1485 assert(reply);
1486
1487 r = sd_bus_message_open_container(reply, 'a', "(sasasttttuii)");
1488 if (r < 0)
1489 return r;
1490
1491 LIST_FOREACH(command, c, exec_command) {
1492 r = append_exec_ex_command(reply, c);
1493 if (r < 0)
1494 return r;
1495 }
1496
1497 return sd_bus_message_close_container(reply);
1498 }
1499
1500 static char *exec_command_flags_to_exec_chars(ExecCommandFlags flags) {
1501 return strjoin(FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE) ? "-" : "",
1502 FLAGS_SET(flags, EXEC_COMMAND_NO_ENV_EXPAND) ? ":" : "",
1503 FLAGS_SET(flags, EXEC_COMMAND_FULLY_PRIVILEGED) ? "+" : "",
1504 FLAGS_SET(flags, EXEC_COMMAND_NO_SETUID) ? "!" : "",
1505 FLAGS_SET(flags, EXEC_COMMAND_AMBIENT_MAGIC) ? "!!" : "");
1506 }
1507
1508 int bus_set_transient_exec_command(
1509 Unit *u,
1510 const char *name,
1511 ExecCommand **exec_command,
1512 sd_bus_message *message,
1513 UnitWriteFlags flags,
1514 sd_bus_error *error) {
1515 bool is_ex_prop = endswith(name, "Ex");
1516 unsigned n = 0;
1517 int r;
1518
1519 r = sd_bus_message_enter_container(message, 'a', is_ex_prop ? "(sasas)" : "(sasb)");
1520 if (r < 0)
1521 return r;
1522
1523 while ((r = sd_bus_message_enter_container(message, 'r', is_ex_prop ? "sasas" : "sasb")) > 0) {
1524 _cleanup_strv_free_ char **argv = NULL, **ex_opts = NULL;
1525 const char *path;
1526 int b;
1527
1528 r = sd_bus_message_read(message, "s", &path);
1529 if (r < 0)
1530 return r;
1531
1532 if (!path_is_absolute(path) && !filename_is_valid(path))
1533 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
1534 "\"%s\" is neither a valid executable name nor an absolute path",
1535 path);
1536
1537 r = sd_bus_message_read_strv(message, &argv);
1538 if (r < 0)
1539 return r;
1540
1541 if (strv_isempty(argv))
1542 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
1543 "\"%s\" argv cannot be empty", name);
1544
1545 r = is_ex_prop ? sd_bus_message_read_strv(message, &ex_opts) : sd_bus_message_read(message, "b", &b);
1546 if (r < 0)
1547 return r;
1548
1549 r = sd_bus_message_exit_container(message);
1550 if (r < 0)
1551 return r;
1552
1553 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1554 ExecCommand *c;
1555
1556 c = new0(ExecCommand, 1);
1557 if (!c)
1558 return -ENOMEM;
1559
1560 c->path = strdup(path);
1561 if (!c->path) {
1562 free(c);
1563 return -ENOMEM;
1564 }
1565
1566 c->argv = TAKE_PTR(argv);
1567
1568 if (is_ex_prop) {
1569 r = exec_command_flags_from_strv(ex_opts, &c->flags);
1570 if (r < 0)
1571 return r;
1572 } else
1573 c->flags = b ? EXEC_COMMAND_IGNORE_FAILURE : 0;
1574
1575 path_simplify(c->path);
1576 exec_command_append_list(exec_command, c);
1577 }
1578
1579 n++;
1580 }
1581 if (r < 0)
1582 return r;
1583
1584 r = sd_bus_message_exit_container(message);
1585 if (r < 0)
1586 return r;
1587
1588 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1589 _cleanup_free_ char *buf = NULL;
1590 _cleanup_fclose_ FILE *f = NULL;
1591 size_t size = 0;
1592
1593 if (n == 0)
1594 *exec_command = exec_command_free_list(*exec_command);
1595
1596 f = open_memstream_unlocked(&buf, &size);
1597 if (!f)
1598 return -ENOMEM;
1599
1600 fprintf(f, "%s=\n", name);
1601
1602 LIST_FOREACH(command, c, *exec_command) {
1603 _cleanup_free_ char *a = NULL, *exec_chars = NULL;
1604
1605 exec_chars = exec_command_flags_to_exec_chars(c->flags);
1606 if (!exec_chars)
1607 return -ENOMEM;
1608
1609 a = unit_concat_strv(c->argv, UNIT_ESCAPE_SPECIFIERS|UNIT_ESCAPE_EXEC_SYNTAX);
1610 if (!a)
1611 return -ENOMEM;
1612
1613 if (streq_ptr(c->path, c->argv ? c->argv[0] : NULL))
1614 fprintf(f, "%s=%s%s\n", name, exec_chars, a);
1615 else {
1616 _cleanup_free_ char *t = NULL;
1617 const char *p;
1618
1619 p = unit_escape_setting(c->path,
1620 UNIT_ESCAPE_SPECIFIERS|UNIT_ESCAPE_EXEC_SYNTAX, &t);
1621 if (!p)
1622 return -ENOMEM;
1623
1624 fprintf(f, "%s=%s@%s %s\n", name, exec_chars, p, a);
1625 }
1626 }
1627
1628 r = fflush_and_check(f);
1629 if (r < 0)
1630 return r;
1631
1632 unit_write_setting(u, flags, name, buf);
1633 }
1634
1635 return 1;
1636 }
1637
1638 static int parse_personality(const char *s, unsigned long *p) {
1639 unsigned long v;
1640
1641 assert(p);
1642
1643 v = personality_from_string(s);
1644 if (v == PERSONALITY_INVALID)
1645 return -EINVAL;
1646
1647 *p = v;
1648 return 0;
1649 }
1650
1651 static const char* mount_propagation_flag_to_string_with_check(unsigned long n) {
1652 if (!mount_propagation_flag_is_valid(n))
1653 return NULL;
1654
1655 return mount_propagation_flag_to_string(n);
1656 }
1657
1658 static BUS_DEFINE_SET_TRANSIENT(nsec, "t", uint64_t, nsec_t, NSEC_FMT);
1659 static BUS_DEFINE_SET_TRANSIENT_IS_VALID(log_level, "i", int32_t, int, "%" PRIi32, log_level_is_valid);
1660 #if HAVE_SECCOMP
1661 static BUS_DEFINE_SET_TRANSIENT_IS_VALID(errno, "i", int32_t, int, "%" PRIi32, seccomp_errno_or_action_is_valid);
1662 #endif
1663 static BUS_DEFINE_SET_TRANSIENT_PARSE(std_input, ExecInput, exec_input_from_string);
1664 static BUS_DEFINE_SET_TRANSIENT_PARSE(std_output, ExecOutput, exec_output_from_string);
1665 static BUS_DEFINE_SET_TRANSIENT_PARSE(utmp_mode, ExecUtmpMode, exec_utmp_mode_from_string);
1666 static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_system, ProtectSystem, protect_system_from_string);
1667 static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_home, ProtectHome, protect_home_from_string);
1668 static BUS_DEFINE_SET_TRANSIENT_PARSE(keyring_mode, ExecKeyringMode, exec_keyring_mode_from_string);
1669 static BUS_DEFINE_SET_TRANSIENT_PARSE(protect_proc, ProtectProc, protect_proc_from_string);
1670 static BUS_DEFINE_SET_TRANSIENT_PARSE(proc_subset, ProcSubset, proc_subset_from_string);
1671 static BUS_DEFINE_SET_TRANSIENT_PARSE(preserve_mode, ExecPreserveMode, exec_preserve_mode_from_string);
1672 static BUS_DEFINE_SET_TRANSIENT_PARSE_PTR(personality, unsigned long, parse_personality);
1673 static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(secure_bits, "i", int32_t, int, "%" PRIi32, secure_bits_to_string_alloc_with_check);
1674 static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(capability, "t", uint64_t, uint64_t, "%" PRIu64, capability_set_to_string);
1675 static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(namespace_flag, "t", uint64_t, unsigned long, "%" PRIu64, namespace_flags_to_string);
1676 static BUS_DEFINE_SET_TRANSIENT_TO_STRING(mount_flags, "t", uint64_t, unsigned long, "%" PRIu64, mount_propagation_flag_to_string_with_check);
1677
1678 int bus_exec_context_set_transient_property(
1679 Unit *u,
1680 ExecContext *c,
1681 const char *name,
1682 sd_bus_message *message,
1683 UnitWriteFlags flags,
1684 sd_bus_error *error) {
1685
1686 const char *suffix;
1687 int r;
1688
1689 assert(u);
1690 assert(c);
1691 assert(name);
1692 assert(message);
1693
1694 flags |= UNIT_PRIVATE;
1695
1696 if (streq(name, "User"))
1697 return bus_set_transient_user_relaxed(u, name, &c->user, message, flags, error);
1698
1699 if (streq(name, "Group"))
1700 return bus_set_transient_user_relaxed(u, name, &c->group, message, flags, error);
1701
1702 if (streq(name, "TTYPath"))
1703 return bus_set_transient_path(u, name, &c->tty_path, message, flags, error);
1704
1705 if (streq(name, "RootImage"))
1706 return bus_set_transient_path(u, name, &c->root_image, message, flags, error);
1707
1708 if (streq(name, "RootImageOptions")) {
1709 _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
1710 _cleanup_free_ char *format_str = NULL;
1711
1712 r = bus_read_mount_options(message, error, &options, &format_str, " ");
1713 if (r < 0)
1714 return r;
1715
1716 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1717 if (options) {
1718 LIST_JOIN(mount_options, c->root_image_options, options);
1719 unit_write_settingf(
1720 u, flags|UNIT_ESCAPE_SPECIFIERS, name,
1721 "%s=%s",
1722 name,
1723 format_str);
1724 } else {
1725 c->root_image_options = mount_options_free_all(c->root_image_options);
1726 unit_write_settingf(u, flags, name, "%s=", name);
1727 }
1728 }
1729
1730 return 1;
1731 }
1732
1733 if (streq(name, "RootHash")) {
1734 const void *roothash_decoded;
1735 size_t roothash_decoded_size;
1736
1737 r = sd_bus_message_read_array(message, 'y', &roothash_decoded, &roothash_decoded_size);
1738 if (r < 0)
1739 return r;
1740
1741 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1742 _cleanup_free_ char *encoded = NULL;
1743
1744 if (roothash_decoded_size == 0) {
1745 c->root_hash_path = mfree(c->root_hash_path);
1746 c->root_hash = mfree(c->root_hash);
1747 c->root_hash_size = 0;
1748
1749 unit_write_settingf(u, flags, name, "RootHash=");
1750 } else {
1751 _cleanup_free_ void *p = NULL;
1752
1753 encoded = hexmem(roothash_decoded, roothash_decoded_size);
1754 if (!encoded)
1755 return -ENOMEM;
1756
1757 p = memdup(roothash_decoded, roothash_decoded_size);
1758 if (!p)
1759 return -ENOMEM;
1760
1761 free_and_replace(c->root_hash, p);
1762 c->root_hash_size = roothash_decoded_size;
1763 c->root_hash_path = mfree(c->root_hash_path);
1764
1765 unit_write_settingf(u, flags, name, "RootHash=%s", encoded);
1766 }
1767 }
1768
1769 return 1;
1770 }
1771
1772 if (streq(name, "RootHashPath")) {
1773 c->root_hash_size = 0;
1774 c->root_hash = mfree(c->root_hash);
1775
1776 return bus_set_transient_path(u, "RootHash", &c->root_hash_path, message, flags, error);
1777 }
1778
1779 if (streq(name, "RootHashSignature")) {
1780 const void *roothash_sig_decoded;
1781 size_t roothash_sig_decoded_size;
1782
1783 r = sd_bus_message_read_array(message, 'y', &roothash_sig_decoded, &roothash_sig_decoded_size);
1784 if (r < 0)
1785 return r;
1786
1787 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1788 _cleanup_free_ char *encoded = NULL;
1789
1790 if (roothash_sig_decoded_size == 0) {
1791 c->root_hash_sig_path = mfree(c->root_hash_sig_path);
1792 c->root_hash_sig = mfree(c->root_hash_sig);
1793 c->root_hash_sig_size = 0;
1794
1795 unit_write_settingf(u, flags, name, "RootHashSignature=");
1796 } else {
1797 _cleanup_free_ void *p = NULL;
1798 ssize_t len;
1799
1800 len = base64mem(roothash_sig_decoded, roothash_sig_decoded_size, &encoded);
1801 if (len < 0)
1802 return -ENOMEM;
1803
1804 p = memdup(roothash_sig_decoded, roothash_sig_decoded_size);
1805 if (!p)
1806 return -ENOMEM;
1807
1808 free_and_replace(c->root_hash_sig, p);
1809 c->root_hash_sig_size = roothash_sig_decoded_size;
1810 c->root_hash_sig_path = mfree(c->root_hash_sig_path);
1811
1812 unit_write_settingf(u, flags, name, "RootHashSignature=base64:%s", encoded);
1813 }
1814 }
1815
1816 return 1;
1817 }
1818
1819 if (streq(name, "RootHashSignaturePath")) {
1820 c->root_hash_sig_size = 0;
1821 c->root_hash_sig = mfree(c->root_hash_sig);
1822
1823 return bus_set_transient_path(u, "RootHashSignature", &c->root_hash_sig_path, message, flags, error);
1824 }
1825
1826 if (streq(name, "RootVerity"))
1827 return bus_set_transient_path(u, name, &c->root_verity, message, flags, error);
1828
1829 if (streq(name, "RootDirectory"))
1830 return bus_set_transient_path(u, name, &c->root_directory, message, flags, error);
1831
1832 if (streq(name, "SyslogIdentifier"))
1833 return bus_set_transient_string(u, name, &c->syslog_identifier, message, flags, error);
1834
1835 if (streq(name, "LogLevelMax"))
1836 return bus_set_transient_log_level(u, name, &c->log_level_max, message, flags, error);
1837
1838 if (streq(name, "LogRateLimitIntervalUSec"))
1839 return bus_set_transient_usec(u, name, &c->log_ratelimit_interval_usec, message, flags, error);
1840
1841 if (streq(name, "LogRateLimitBurst"))
1842 return bus_set_transient_unsigned(u, name, &c->log_ratelimit_burst, message, flags, error);
1843
1844 if (streq(name, "LogFilterPatterns")) {
1845 /* Use _cleanup_free_, not _cleanup_strv_free_, as we don't want the content of the strv
1846 * to be freed. */
1847 _cleanup_free_ char **allow_list = NULL, **deny_list = NULL;
1848 const char *pattern;
1849 int is_allowlist;
1850
1851 r = sd_bus_message_enter_container(message, 'a', "(bs)");
1852 if (r < 0)
1853 return r;
1854
1855 while ((r = sd_bus_message_read(message, "(bs)", &is_allowlist, &pattern)) > 0) {
1856 _cleanup_(pattern_freep) pcre2_code *compiled_pattern = NULL;
1857
1858 if (isempty(pattern))
1859 continue;
1860
1861 r = pattern_compile_and_log(pattern, 0, &compiled_pattern);
1862 if (r < 0)
1863 return r;
1864
1865 r = strv_push(is_allowlist ? &allow_list : &deny_list, (char *)pattern);
1866 if (r < 0)
1867 return r;
1868 }
1869 if (r < 0)
1870 return r;
1871
1872 r = sd_bus_message_exit_container(message);
1873 if (r < 0)
1874 return r;
1875
1876 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
1877 if (strv_isempty(allow_list) && strv_isempty(deny_list)) {
1878 c->log_filter_allowed_patterns = set_free(c->log_filter_allowed_patterns);
1879 c->log_filter_denied_patterns = set_free(c->log_filter_denied_patterns);
1880 unit_write_settingf(u, flags, name, "%s=", name);
1881 } else {
1882 r = set_put_strdupv(&c->log_filter_allowed_patterns, allow_list);
1883 if (r < 0)
1884 return r;
1885 r = set_put_strdupv(&c->log_filter_denied_patterns, deny_list);
1886 if (r < 0)
1887 return r;
1888
1889 STRV_FOREACH(unit_pattern, allow_list)
1890 unit_write_settingf(u, flags, name, "%s=%s", name, *unit_pattern);
1891 STRV_FOREACH(unit_pattern, deny_list)
1892 unit_write_settingf(u, flags, name, "%s=~%s", name, *unit_pattern);
1893 }
1894 }
1895
1896 return 1;
1897 }
1898
1899 if (streq(name, "Personality"))
1900 return bus_set_transient_personality(u, name, &c->personality, message, flags, error);
1901
1902 if (streq(name, "StandardInput"))
1903 return bus_set_transient_std_input(u, name, &c->std_input, message, flags, error);
1904
1905 if (streq(name, "StandardOutput"))
1906 return bus_set_transient_std_output(u, name, &c->std_output, message, flags, error);
1907
1908 if (streq(name, "StandardError"))
1909 return bus_set_transient_std_output(u, name, &c->std_error, message, flags, error);
1910
1911 if (streq(name, "IgnoreSIGPIPE"))
1912 return bus_set_transient_bool(u, name, &c->ignore_sigpipe, message, flags, error);
1913
1914 if (streq(name, "TTYVHangup"))
1915 return bus_set_transient_bool(u, name, &c->tty_vhangup, message, flags, error);
1916
1917 if (streq(name, "TTYReset"))
1918 return bus_set_transient_bool(u, name, &c->tty_reset, message, flags, error);
1919
1920 if (streq(name, "TTYVTDisallocate"))
1921 return bus_set_transient_bool(u, name, &c->tty_vt_disallocate, message, flags, error);
1922
1923 if (streq(name, "TTYRows"))
1924 return bus_set_transient_unsigned(u, name, &c->tty_rows, message, flags, error);
1925
1926 if (streq(name, "TTYColumns"))
1927 return bus_set_transient_unsigned(u, name, &c->tty_cols, message, flags, error);
1928
1929 if (streq(name, "PrivateTmp"))
1930 return bus_set_transient_bool(u, name, &c->private_tmp, message, flags, error);
1931
1932 if (streq(name, "PrivateDevices"))
1933 return bus_set_transient_bool(u, name, &c->private_devices, message, flags, error);
1934
1935 if (streq(name, "PrivateMounts"))
1936 return bus_set_transient_bool(u, name, &c->private_mounts, message, flags, error);
1937
1938 if (streq(name, "PrivateNetwork"))
1939 return bus_set_transient_bool(u, name, &c->private_network, message, flags, error);
1940
1941 if (streq(name, "PrivateIPC"))
1942 return bus_set_transient_bool(u, name, &c->private_ipc, message, flags, error);
1943
1944 if (streq(name, "PrivateUsers"))
1945 return bus_set_transient_bool(u, name, &c->private_users, message, flags, error);
1946
1947 if (streq(name, "NoNewPrivileges"))
1948 return bus_set_transient_bool(u, name, &c->no_new_privileges, message, flags, error);
1949
1950 if (streq(name, "SyslogLevelPrefix"))
1951 return bus_set_transient_bool(u, name, &c->syslog_level_prefix, message, flags, error);
1952
1953 if (streq(name, "MemoryDenyWriteExecute"))
1954 return bus_set_transient_bool(u, name, &c->memory_deny_write_execute, message, flags, error);
1955
1956 if (streq(name, "RestrictRealtime"))
1957 return bus_set_transient_bool(u, name, &c->restrict_realtime, message, flags, error);
1958
1959 if (streq(name, "RestrictSUIDSGID"))
1960 return bus_set_transient_bool(u, name, &c->restrict_suid_sgid, message, flags, error);
1961
1962 if (streq(name, "DynamicUser"))
1963 return bus_set_transient_bool(u, name, &c->dynamic_user, message, flags, error);
1964
1965 if (streq(name, "RemoveIPC"))
1966 return bus_set_transient_bool(u, name, &c->remove_ipc, message, flags, error);
1967
1968 if (streq(name, "ProtectKernelTunables"))
1969 return bus_set_transient_bool(u, name, &c->protect_kernel_tunables, message, flags, error);
1970
1971 if (streq(name, "ProtectKernelModules"))
1972 return bus_set_transient_bool(u, name, &c->protect_kernel_modules, message, flags, error);
1973
1974 if (streq(name, "ProtectKernelLogs"))
1975 return bus_set_transient_bool(u, name, &c->protect_kernel_logs, message, flags, error);
1976
1977 if (streq(name, "ProtectClock"))
1978 return bus_set_transient_bool(u, name, &c->protect_clock, message, flags, error);
1979
1980 if (streq(name, "ProtectControlGroups"))
1981 return bus_set_transient_bool(u, name, &c->protect_control_groups, message, flags, error);
1982
1983 if (streq(name, "CPUSchedulingResetOnFork"))
1984 return bus_set_transient_bool(u, name, &c->cpu_sched_reset_on_fork, message, flags, error);
1985
1986 if (streq(name, "NonBlocking"))
1987 return bus_set_transient_bool(u, name, &c->non_blocking, message, flags, error);
1988
1989 if (streq(name, "LockPersonality"))
1990 return bus_set_transient_bool(u, name, &c->lock_personality, message, flags, error);
1991
1992 if (streq(name, "ProtectHostname"))
1993 return bus_set_transient_bool(u, name, &c->protect_hostname, message, flags, error);
1994
1995 if (streq(name, "UtmpIdentifier"))
1996 return bus_set_transient_string(u, name, &c->utmp_id, message, flags, error);
1997
1998 if (streq(name, "UtmpMode"))
1999 return bus_set_transient_utmp_mode(u, name, &c->utmp_mode, message, flags, error);
2000
2001 if (streq(name, "PAMName"))
2002 return bus_set_transient_string(u, name, &c->pam_name, message, flags, error);
2003
2004 if (streq(name, "TimerSlackNSec"))
2005 return bus_set_transient_nsec(u, name, &c->timer_slack_nsec, message, flags, error);
2006
2007 if (streq(name, "ProtectSystem"))
2008 return bus_set_transient_protect_system(u, name, &c->protect_system, message, flags, error);
2009
2010 if (streq(name, "ProtectHome"))
2011 return bus_set_transient_protect_home(u, name, &c->protect_home, message, flags, error);
2012
2013 if (streq(name, "KeyringMode"))
2014 return bus_set_transient_keyring_mode(u, name, &c->keyring_mode, message, flags, error);
2015
2016 if (streq(name, "ProtectProc"))
2017 return bus_set_transient_protect_proc(u, name, &c->protect_proc, message, flags, error);
2018
2019 if (streq(name, "ProcSubset"))
2020 return bus_set_transient_proc_subset(u, name, &c->proc_subset, message, flags, error);
2021
2022 if (streq(name, "RuntimeDirectoryPreserve"))
2023 return bus_set_transient_preserve_mode(u, name, &c->runtime_directory_preserve_mode, message, flags, error);
2024
2025 if (streq(name, "UMask"))
2026 return bus_set_transient_mode_t(u, name, &c->umask, message, flags, error);
2027
2028 if (streq(name, "RuntimeDirectoryMode"))
2029 return bus_set_transient_mode_t(u, name, &c->directories[EXEC_DIRECTORY_RUNTIME].mode, message, flags, error);
2030
2031 if (streq(name, "StateDirectoryMode"))
2032 return bus_set_transient_mode_t(u, name, &c->directories[EXEC_DIRECTORY_STATE].mode, message, flags, error);
2033
2034 if (streq(name, "CacheDirectoryMode"))
2035 return bus_set_transient_mode_t(u, name, &c->directories[EXEC_DIRECTORY_CACHE].mode, message, flags, error);
2036
2037 if (streq(name, "LogsDirectoryMode"))
2038 return bus_set_transient_mode_t(u, name, &c->directories[EXEC_DIRECTORY_LOGS].mode, message, flags, error);
2039
2040 if (streq(name, "ConfigurationDirectoryMode"))
2041 return bus_set_transient_mode_t(u, name, &c->directories[EXEC_DIRECTORY_CONFIGURATION].mode, message, flags, error);
2042
2043 if (streq(name, "SELinuxContext"))
2044 return bus_set_transient_string(u, name, &c->selinux_context, message, flags, error);
2045
2046 if (streq(name, "SecureBits"))
2047 return bus_set_transient_secure_bits(u, name, &c->secure_bits, message, flags, error);
2048
2049 if (streq(name, "CapabilityBoundingSet"))
2050 return bus_set_transient_capability(u, name, &c->capability_bounding_set, message, flags, error);
2051
2052 if (streq(name, "AmbientCapabilities"))
2053 return bus_set_transient_capability(u, name, &c->capability_ambient_set, message, flags, error);
2054
2055 if (streq(name, "RestrictNamespaces"))
2056 return bus_set_transient_namespace_flag(u, name, &c->restrict_namespaces, message, flags, error);
2057
2058 if (streq(name, "RestrictFileSystems")) {
2059 int allow_list;
2060 _cleanup_strv_free_ char **l = NULL;
2061
2062 r = sd_bus_message_enter_container(message, 'r', "bas");
2063 if (r < 0)
2064 return r;
2065
2066 r = sd_bus_message_read(message, "b", &allow_list);
2067 if (r < 0)
2068 return r;
2069
2070 r = sd_bus_message_read_strv(message, &l);
2071 if (r < 0)
2072 return r;
2073
2074 r = sd_bus_message_exit_container(message);
2075 if (r < 0)
2076 return r;
2077
2078 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2079 _cleanup_free_ char *joined = NULL;
2080 FilesystemParseFlags invert_flag = allow_list ? 0 : FILESYSTEM_PARSE_INVERT;
2081
2082 if (strv_isempty(l)) {
2083 c->restrict_filesystems_allow_list = false;
2084 c->restrict_filesystems = set_free(c->restrict_filesystems);
2085
2086 unit_write_setting(u, flags, name, "RestrictFileSystems=");
2087 return 1;
2088 }
2089
2090 if (!c->restrict_filesystems)
2091 c->restrict_filesystems_allow_list = allow_list;
2092
2093 STRV_FOREACH(s, l) {
2094 r = lsm_bpf_parse_filesystem(
2095 *s,
2096 &c->restrict_filesystems,
2097 FILESYSTEM_PARSE_LOG|
2098 (invert_flag ? FILESYSTEM_PARSE_INVERT : 0)|
2099 (c->restrict_filesystems_allow_list ? FILESYSTEM_PARSE_ALLOW_LIST : 0),
2100 u->id, NULL, 0);
2101 if (r < 0)
2102 return r;
2103 }
2104
2105 joined = strv_join(l, " ");
2106 if (!joined)
2107 return -ENOMEM;
2108
2109 unit_write_settingf(u, flags, name, "%s=%s%s", name, allow_list ? "" : "~", joined);
2110 }
2111
2112 return 1;
2113 }
2114
2115 if (streq(name, "MountFlags"))
2116 return bus_set_transient_mount_flags(u, name, &c->mount_flags, message, flags, error);
2117
2118 if (streq(name, "NetworkNamespacePath"))
2119 return bus_set_transient_path(u, name, &c->network_namespace_path, message, flags, error);
2120
2121 if (streq(name, "IPCNamespacePath"))
2122 return bus_set_transient_path(u, name, &c->ipc_namespace_path, message, flags, error);
2123
2124 if (streq(name, "SupplementaryGroups")) {
2125 _cleanup_strv_free_ char **l = NULL;
2126
2127 r = sd_bus_message_read_strv(message, &l);
2128 if (r < 0)
2129 return r;
2130
2131 STRV_FOREACH(p, l)
2132 if (!isempty(*p) && !valid_user_group_name(*p, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN))
2133 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
2134 "Invalid supplementary group names");
2135
2136 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2137 if (strv_isempty(l)) {
2138 c->supplementary_groups = strv_free(c->supplementary_groups);
2139 unit_write_settingf(u, flags, name, "%s=", name);
2140 } else {
2141 _cleanup_free_ char *joined = NULL;
2142
2143 r = strv_extend_strv(&c->supplementary_groups, l, true);
2144 if (r < 0)
2145 return -ENOMEM;
2146
2147 joined = strv_join(c->supplementary_groups, " ");
2148 if (!joined)
2149 return -ENOMEM;
2150
2151 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, joined);
2152 }
2153 }
2154
2155 return 1;
2156
2157 } else if (STR_IN_SET(name, "SetCredential", "SetCredentialEncrypted")) {
2158 bool isempty = true;
2159
2160 r = sd_bus_message_enter_container(message, 'a', "(say)");
2161 if (r < 0)
2162 return r;
2163
2164 for (;;) {
2165 const char *id;
2166 const void *p;
2167 size_t sz;
2168
2169 r = sd_bus_message_enter_container(message, 'r', "say");
2170 if (r < 0)
2171 return r;
2172 if (r == 0)
2173 break;
2174
2175 r = sd_bus_message_read(message, "s", &id);
2176 if (r < 0)
2177 return r;
2178
2179 r = sd_bus_message_read_array(message, 'y', &p, &sz);
2180 if (r < 0)
2181 return r;
2182
2183 r = sd_bus_message_exit_container(message);
2184 if (r < 0)
2185 return r;
2186
2187 if (!credential_name_valid(id))
2188 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Credential ID is invalid: %s", id);
2189
2190 isempty = false;
2191
2192 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2193 _cleanup_free_ char *a = NULL, *b = NULL;
2194 _cleanup_free_ void *copy = NULL;
2195 ExecSetCredential *old;
2196
2197 copy = memdup(p, sz);
2198 if (!copy)
2199 return -ENOMEM;
2200
2201 old = hashmap_get(c->set_credentials, id);
2202 if (old) {
2203 free_and_replace(old->data, copy);
2204 old->size = sz;
2205 old->encrypted = streq(name, "SetCredentialEncrypted");
2206 } else {
2207 _cleanup_(exec_set_credential_freep) ExecSetCredential *sc = NULL;
2208
2209 sc = new(ExecSetCredential, 1);
2210 if (!sc)
2211 return -ENOMEM;
2212
2213 *sc = (ExecSetCredential) {
2214 .id = strdup(id),
2215 .data = TAKE_PTR(copy),
2216 .size = sz,
2217 .encrypted = streq(name, "SetCredentialEncrypted"),
2218 };
2219
2220 if (!sc->id)
2221 return -ENOMEM;
2222
2223 r = hashmap_ensure_put(&c->set_credentials, &exec_set_credential_hash_ops, sc->id, sc);
2224 if (r < 0)
2225 return r;
2226
2227 TAKE_PTR(sc);
2228 }
2229
2230 a = specifier_escape(id);
2231 if (!a)
2232 return -ENOMEM;
2233
2234 b = cescape_length(p, sz);
2235 if (!b)
2236 return -ENOMEM;
2237
2238 (void) unit_write_settingf(u, flags, name, "%s=%s:%s", name, a, b);
2239 }
2240 }
2241
2242 r = sd_bus_message_exit_container(message);
2243 if (r < 0)
2244 return r;
2245
2246 if (!UNIT_WRITE_FLAGS_NOOP(flags) && isempty) {
2247 c->set_credentials = hashmap_free(c->set_credentials);
2248 (void) unit_write_settingf(u, flags, name, "%s=", name);
2249 }
2250
2251 return 1;
2252
2253 } else if (STR_IN_SET(name, "LoadCredential", "LoadCredentialEncrypted")) {
2254 bool isempty = true;
2255
2256 r = sd_bus_message_enter_container(message, 'a', "(ss)");
2257 if (r < 0)
2258 return r;
2259
2260 for (;;) {
2261 const char *id, *source;
2262
2263 r = sd_bus_message_read(message, "(ss)", &id, &source);
2264 if (r < 0)
2265 return r;
2266 if (r == 0)
2267 break;
2268
2269 if (!credential_name_valid(id))
2270 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Credential ID is invalid: %s", id);
2271
2272 if (!(path_is_absolute(source) ? path_is_normalized(source) : credential_name_valid(source)))
2273 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Credential source is invalid: %s", source);
2274
2275 isempty = false;
2276
2277 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2278 _cleanup_free_ char *copy = NULL;
2279 ExecLoadCredential *old;
2280
2281 copy = strdup(source);
2282 if (!copy)
2283 return -ENOMEM;
2284
2285 old = hashmap_get(c->load_credentials, id);
2286 if (old) {
2287 free_and_replace(old->path, copy);
2288 old->encrypted = streq(name, "LoadCredentialEncrypted");
2289 } else {
2290 _cleanup_(exec_load_credential_freep) ExecLoadCredential *lc = NULL;
2291
2292 lc = new(ExecLoadCredential, 1);
2293 if (!lc)
2294 return -ENOMEM;
2295
2296 *lc = (ExecLoadCredential) {
2297 .id = strdup(id),
2298 .path = TAKE_PTR(copy),
2299 .encrypted = streq(name, "LoadCredentialEncrypted"),
2300 };
2301
2302 if (!lc->id)
2303 return -ENOMEM;
2304
2305 r = hashmap_ensure_put(&c->load_credentials, &exec_load_credential_hash_ops, lc->id, lc);
2306 if (r < 0)
2307 return r;
2308
2309 TAKE_PTR(lc);
2310 }
2311
2312 (void) unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s:%s", name, id, source);
2313 }
2314 }
2315
2316 r = sd_bus_message_exit_container(message);
2317 if (r < 0)
2318 return r;
2319
2320 if (!UNIT_WRITE_FLAGS_NOOP(flags) && isempty) {
2321 c->load_credentials = hashmap_free(c->load_credentials);
2322 (void) unit_write_settingf(u, flags, name, "%s=", name);
2323 }
2324
2325 return 1;
2326
2327 } else if (streq(name, "SyslogLevel")) {
2328 int32_t level;
2329
2330 r = sd_bus_message_read(message, "i", &level);
2331 if (r < 0)
2332 return r;
2333
2334 if (!log_level_is_valid(level))
2335 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Log level value out of range");
2336
2337 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2338 c->syslog_priority = (c->syslog_priority & LOG_FACMASK) | level;
2339 unit_write_settingf(u, flags, name, "SyslogLevel=%i", level);
2340 }
2341
2342 return 1;
2343
2344 } else if (streq(name, "SyslogFacility")) {
2345 int32_t facility;
2346
2347 r = sd_bus_message_read(message, "i", &facility);
2348 if (r < 0)
2349 return r;
2350
2351 if (!log_facility_unshifted_is_valid(facility))
2352 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Log facility value out of range");
2353
2354 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2355 c->syslog_priority = (facility << 3) | LOG_PRI(c->syslog_priority);
2356 unit_write_settingf(u, flags, name, "SyslogFacility=%i", facility);
2357 }
2358
2359 return 1;
2360
2361 } else if (streq(name, "LogNamespace")) {
2362 const char *n;
2363
2364 r = sd_bus_message_read(message, "s", &n);
2365 if (r < 0)
2366 return r;
2367
2368 if (!isempty(n) && !log_namespace_name_valid(n))
2369 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Log namespace name not valid");
2370
2371 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2372
2373 if (isempty(n)) {
2374 c->log_namespace = mfree(c->log_namespace);
2375 unit_write_settingf(u, flags, name, "%s=", name);
2376 } else {
2377 r = free_and_strdup(&c->log_namespace, n);
2378 if (r < 0)
2379 return r;
2380
2381 unit_write_settingf(u, flags, name, "%s=%s", name, n);
2382 }
2383 }
2384
2385 return 1;
2386
2387 } else if (streq(name, "LogExtraFields")) {
2388 size_t n = 0;
2389
2390 r = sd_bus_message_enter_container(message, 'a', "ay");
2391 if (r < 0)
2392 return r;
2393
2394 for (;;) {
2395 _cleanup_free_ void *copy = NULL;
2396 struct iovec *t;
2397 const char *eq;
2398 const void *p;
2399 size_t sz;
2400
2401 /* Note that we expect a byte array for each field, instead of a string. That's because on the
2402 * lower-level journal fields can actually contain binary data and are not restricted to text,
2403 * and we should not "lose precision" in our types on the way. That said, I am pretty sure
2404 * actually encoding binary data as unit metadata is not a good idea. Hence we actually refuse
2405 * any actual binary data, and only accept UTF-8. This allows us to eventually lift this
2406 * limitation, should a good, valid usecase arise. */
2407
2408 r = sd_bus_message_read_array(message, 'y', &p, &sz);
2409 if (r < 0)
2410 return r;
2411 if (r == 0)
2412 break;
2413
2414 if (memchr(p, 0, sz))
2415 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field contains zero byte");
2416
2417 eq = memchr(p, '=', sz);
2418 if (!eq)
2419 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field contains no '=' character");
2420 if (!journal_field_valid(p, eq - (const char*) p, false))
2421 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field invalid");
2422
2423 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2424 t = reallocarray(c->log_extra_fields, c->n_log_extra_fields+1, sizeof(struct iovec));
2425 if (!t)
2426 return -ENOMEM;
2427 c->log_extra_fields = t;
2428 }
2429
2430 copy = malloc(sz + 1);
2431 if (!copy)
2432 return -ENOMEM;
2433
2434 memcpy(copy, p, sz);
2435 ((uint8_t*) copy)[sz] = 0;
2436
2437 if (!utf8_is_valid(copy))
2438 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Journal field is not valid UTF-8");
2439
2440 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2441 c->log_extra_fields[c->n_log_extra_fields++] = IOVEC_MAKE(copy, sz);
2442 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS|UNIT_ESCAPE_C, name, "LogExtraFields=%s", (char*) copy);
2443
2444 copy = NULL;
2445 }
2446
2447 n++;
2448 }
2449
2450 r = sd_bus_message_exit_container(message);
2451 if (r < 0)
2452 return r;
2453
2454 if (!UNIT_WRITE_FLAGS_NOOP(flags) && n == 0) {
2455 exec_context_free_log_extra_fields(c);
2456 unit_write_setting(u, flags, name, "LogExtraFields=");
2457 }
2458
2459 return 1;
2460 }
2461
2462 #if HAVE_SECCOMP
2463
2464 if (streq(name, "SystemCallErrorNumber"))
2465 return bus_set_transient_errno(u, name, &c->syscall_errno, message, flags, error);
2466
2467 if (streq(name, "SystemCallFilter")) {
2468 int allow_list;
2469 _cleanup_strv_free_ char **l = NULL;
2470
2471 r = sd_bus_message_enter_container(message, 'r', "bas");
2472 if (r < 0)
2473 return r;
2474
2475 r = sd_bus_message_read(message, "b", &allow_list);
2476 if (r < 0)
2477 return r;
2478
2479 r = sd_bus_message_read_strv(message, &l);
2480 if (r < 0)
2481 return r;
2482
2483 r = sd_bus_message_exit_container(message);
2484 if (r < 0)
2485 return r;
2486
2487 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2488 _cleanup_free_ char *joined = NULL;
2489 SeccompParseFlags invert_flag = allow_list ? 0 : SECCOMP_PARSE_INVERT;
2490
2491 if (strv_isempty(l)) {
2492 c->syscall_allow_list = false;
2493 c->syscall_filter = hashmap_free(c->syscall_filter);
2494
2495 unit_write_settingf(u, flags, name, "SystemCallFilter=");
2496 return 1;
2497 }
2498
2499 if (!c->syscall_filter) {
2500 c->syscall_filter = hashmap_new(NULL);
2501 if (!c->syscall_filter)
2502 return log_oom();
2503
2504 c->syscall_allow_list = allow_list;
2505
2506 if (c->syscall_allow_list) {
2507 r = seccomp_parse_syscall_filter("@default",
2508 -1,
2509 c->syscall_filter,
2510 SECCOMP_PARSE_PERMISSIVE |
2511 SECCOMP_PARSE_ALLOW_LIST,
2512 u->id,
2513 NULL, 0);
2514 if (r < 0)
2515 return r;
2516 }
2517 }
2518
2519 STRV_FOREACH(s, l) {
2520 _cleanup_free_ char *n = NULL;
2521 int e;
2522
2523 r = parse_syscall_and_errno(*s, &n, &e);
2524 if (r < 0)
2525 return r;
2526
2527 if (allow_list && e >= 0)
2528 return -EINVAL;
2529
2530 r = seccomp_parse_syscall_filter(n,
2531 e,
2532 c->syscall_filter,
2533 SECCOMP_PARSE_LOG | SECCOMP_PARSE_PERMISSIVE |
2534 invert_flag |
2535 (c->syscall_allow_list ? SECCOMP_PARSE_ALLOW_LIST : 0),
2536 u->id,
2537 NULL, 0);
2538 if (r < 0)
2539 return r;
2540 }
2541
2542 joined = strv_join(l, " ");
2543 if (!joined)
2544 return -ENOMEM;
2545
2546 unit_write_settingf(u, flags, name, "SystemCallFilter=%s%s", allow_list ? "" : "~", joined);
2547 }
2548
2549 return 1;
2550
2551 } else if (streq(name, "SystemCallLog")) {
2552 int allow_list;
2553 _cleanup_strv_free_ char **l = NULL;
2554
2555 r = sd_bus_message_enter_container(message, 'r', "bas");
2556 if (r < 0)
2557 return r;
2558
2559 r = sd_bus_message_read(message, "b", &allow_list);
2560 if (r < 0)
2561 return r;
2562
2563 r = sd_bus_message_read_strv(message, &l);
2564 if (r < 0)
2565 return r;
2566
2567 r = sd_bus_message_exit_container(message);
2568 if (r < 0)
2569 return r;
2570
2571 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2572 _cleanup_free_ char *joined = NULL;
2573 SeccompParseFlags invert_flag = allow_list ? 0 : SECCOMP_PARSE_INVERT;
2574
2575 if (strv_isempty(l)) {
2576 c->syscall_log_allow_list = false;
2577 c->syscall_log = hashmap_free(c->syscall_log);
2578
2579 unit_write_settingf(u, flags, name, "SystemCallLog=");
2580 return 1;
2581 }
2582
2583 if (!c->syscall_log) {
2584 c->syscall_log = hashmap_new(NULL);
2585 if (!c->syscall_log)
2586 return log_oom();
2587
2588 c->syscall_log_allow_list = allow_list;
2589 }
2590
2591 STRV_FOREACH(s, l) {
2592 r = seccomp_parse_syscall_filter(*s,
2593 -1, /* errno not used */
2594 c->syscall_log,
2595 SECCOMP_PARSE_LOG | SECCOMP_PARSE_PERMISSIVE |
2596 invert_flag |
2597 (c->syscall_log_allow_list ? SECCOMP_PARSE_ALLOW_LIST : 0),
2598 u->id,
2599 NULL, 0);
2600 if (r < 0)
2601 return r;
2602 }
2603
2604 joined = strv_join(l, " ");
2605 if (!joined)
2606 return -ENOMEM;
2607
2608 unit_write_settingf(u, flags, name, "SystemCallLog=%s%s", allow_list ? "" : "~", joined);
2609 }
2610
2611 return 1;
2612
2613 } else if (streq(name, "SystemCallArchitectures")) {
2614 _cleanup_strv_free_ char **l = NULL;
2615
2616 r = sd_bus_message_read_strv(message, &l);
2617 if (r < 0)
2618 return r;
2619
2620 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2621 _cleanup_free_ char *joined = NULL;
2622
2623 if (strv_isempty(l))
2624 c->syscall_archs = set_free(c->syscall_archs);
2625 else
2626 STRV_FOREACH(s, l) {
2627 uint32_t a;
2628
2629 r = seccomp_arch_from_string(*s, &a);
2630 if (r < 0)
2631 return r;
2632
2633 r = set_ensure_put(&c->syscall_archs, NULL, UINT32_TO_PTR(a + 1));
2634 if (r < 0)
2635 return r;
2636 }
2637
2638 joined = strv_join(l, " ");
2639 if (!joined)
2640 return -ENOMEM;
2641
2642 unit_write_settingf(u, flags, name, "%s=%s", name, joined);
2643 }
2644
2645 return 1;
2646
2647 } else if (streq(name, "RestrictAddressFamilies")) {
2648 _cleanup_strv_free_ char **l = NULL;
2649 int allow_list;
2650
2651 r = sd_bus_message_enter_container(message, 'r', "bas");
2652 if (r < 0)
2653 return r;
2654
2655 r = sd_bus_message_read(message, "b", &allow_list);
2656 if (r < 0)
2657 return r;
2658
2659 r = sd_bus_message_read_strv(message, &l);
2660 if (r < 0)
2661 return r;
2662
2663 r = sd_bus_message_exit_container(message);
2664 if (r < 0)
2665 return r;
2666
2667 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2668 _cleanup_free_ char *joined = NULL;
2669
2670 if (strv_isempty(l)) {
2671 c->address_families_allow_list = allow_list;
2672 c->address_families = set_free(c->address_families);
2673
2674 unit_write_settingf(u, flags, name, "RestrictAddressFamilies=%s",
2675 allow_list ? "none" : "");
2676 return 1;
2677 }
2678
2679 if (!c->address_families) {
2680 c->address_families = set_new(NULL);
2681 if (!c->address_families)
2682 return log_oom();
2683
2684 c->address_families_allow_list = allow_list;
2685 }
2686
2687 STRV_FOREACH(s, l) {
2688 int af;
2689
2690 af = af_from_name(*s);
2691 if (af < 0)
2692 return af;
2693
2694 if (allow_list == c->address_families_allow_list) {
2695 r = set_put(c->address_families, INT_TO_PTR(af));
2696 if (r < 0)
2697 return r;
2698 } else
2699 set_remove(c->address_families, INT_TO_PTR(af));
2700 }
2701
2702 joined = strv_join(l, " ");
2703 if (!joined)
2704 return -ENOMEM;
2705
2706 unit_write_settingf(u, flags, name, "RestrictAddressFamilies=%s%s", allow_list ? "" : "~", joined);
2707 }
2708
2709 return 1;
2710 }
2711 #endif
2712 if (STR_IN_SET(name, "CPUAffinity", "NUMAMask")) {
2713 const void *a;
2714 size_t n;
2715 bool affinity = streq(name, "CPUAffinity");
2716 _cleanup_(cpu_set_reset) CPUSet set = {};
2717
2718 r = sd_bus_message_read_array(message, 'y', &a, &n);
2719 if (r < 0)
2720 return r;
2721
2722 r = cpu_set_from_dbus(a, n, &set);
2723 if (r < 0)
2724 return r;
2725
2726 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2727 if (n == 0) {
2728 cpu_set_reset(affinity ? &c->cpu_set : &c->numa_policy.nodes);
2729 unit_write_settingf(u, flags, name, "%s=", name);
2730 } else {
2731 _cleanup_free_ char *str = NULL;
2732
2733 str = cpu_set_to_string(&set);
2734 if (!str)
2735 return -ENOMEM;
2736
2737 /* We forego any optimizations here, and always create the structure using
2738 * cpu_set_add_all(), because we don't want to care if the existing size we
2739 * got over dbus is appropriate. */
2740 r = cpu_set_add_all(affinity ? &c->cpu_set : &c->numa_policy.nodes, &set);
2741 if (r < 0)
2742 return r;
2743
2744 unit_write_settingf(u, flags, name, "%s=%s", name, str);
2745 }
2746 }
2747
2748 return 1;
2749
2750 } else if (streq(name, "CPUAffinityFromNUMA")) {
2751 int q;
2752
2753 r = sd_bus_message_read_basic(message, 'b', &q);
2754 if (r < 0)
2755 return r;
2756
2757 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2758 c->cpu_affinity_from_numa = q;
2759 unit_write_settingf(u, flags, name, "%s=%s", "CPUAffinity", "numa");
2760 }
2761
2762 return 1;
2763
2764 } else if (streq(name, "NUMAPolicy")) {
2765 int32_t type;
2766
2767 r = sd_bus_message_read(message, "i", &type);
2768 if (r < 0)
2769 return r;
2770
2771 if (!mpol_is_valid(type))
2772 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NUMAPolicy value: %i", type);
2773
2774 if (!UNIT_WRITE_FLAGS_NOOP(flags))
2775 c->numa_policy.type = type;
2776
2777 return 1;
2778
2779 } else if (streq(name, "Nice")) {
2780 int32_t q;
2781
2782 r = sd_bus_message_read(message, "i", &q);
2783 if (r < 0)
2784 return r;
2785
2786 if (!nice_is_valid(q))
2787 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Nice value: %i", q);
2788
2789 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2790 c->nice = q;
2791 c->nice_set = true;
2792
2793 unit_write_settingf(u, flags, name, "Nice=%i", q);
2794 }
2795
2796 return 1;
2797
2798 } else if (streq(name, "CPUSchedulingPolicy")) {
2799 int32_t q;
2800
2801 r = sd_bus_message_read(message, "i", &q);
2802 if (r < 0)
2803 return r;
2804
2805 if (!sched_policy_is_valid(q))
2806 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid CPU scheduling policy: %i", q);
2807
2808 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2809 _cleanup_free_ char *s = NULL;
2810
2811 r = sched_policy_to_string_alloc(q, &s);
2812 if (r < 0)
2813 return r;
2814
2815 c->cpu_sched_policy = q;
2816 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(q), sched_get_priority_max(q));
2817 c->cpu_sched_set = true;
2818
2819 unit_write_settingf(u, flags, name, "CPUSchedulingPolicy=%s", s);
2820 }
2821
2822 return 1;
2823
2824 } else if (streq(name, "CPUSchedulingPriority")) {
2825 int32_t p;
2826
2827 r = sd_bus_message_read(message, "i", &p);
2828 if (r < 0)
2829 return r;
2830
2831 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0. Policy might be set
2832 * later so we do not check the precise range, but only the generic outer bounds. */
2833 if (p < 0 || p > 99)
2834 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid CPU scheduling priority: %i", p);
2835
2836 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2837 c->cpu_sched_priority = p;
2838 c->cpu_sched_set = true;
2839
2840 unit_write_settingf(u, flags, name, "CPUSchedulingPriority=%i", p);
2841 }
2842
2843 return 1;
2844
2845 } else if (streq(name, "IOSchedulingClass")) {
2846 int32_t q;
2847
2848 r = sd_bus_message_read(message, "i", &q);
2849 if (r < 0)
2850 return r;
2851
2852 if (!ioprio_class_is_valid(q))
2853 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid IO scheduling class: %i", q);
2854
2855 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2856 _cleanup_free_ char *s = NULL;
2857
2858 r = ioprio_class_to_string_alloc(q, &s);
2859 if (r < 0)
2860 return r;
2861
2862 c->ioprio = ioprio_normalize(ioprio_prio_value(q, ioprio_prio_data(c->ioprio)));
2863 c->ioprio_set = true;
2864
2865 unit_write_settingf(u, flags, name, "IOSchedulingClass=%s", s);
2866 }
2867
2868 return 1;
2869
2870 } else if (streq(name, "IOSchedulingPriority")) {
2871 int32_t p;
2872
2873 r = sd_bus_message_read(message, "i", &p);
2874 if (r < 0)
2875 return r;
2876
2877 if (!ioprio_priority_is_valid(p))
2878 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid IO scheduling priority: %i", p);
2879
2880 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2881 c->ioprio = ioprio_normalize(ioprio_prio_value(ioprio_prio_class(c->ioprio), p));
2882 c->ioprio_set = true;
2883
2884 unit_write_settingf(u, flags, name, "IOSchedulingPriority=%i", p);
2885 }
2886
2887 return 1;
2888
2889 } else if (streq(name, "MountAPIVFS")) {
2890 bool b;
2891
2892 r = bus_set_transient_bool(u, name, &b, message, flags, error);
2893 if (r < 0)
2894 return r;
2895
2896 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2897 c->mount_apivfs = b;
2898 c->mount_apivfs_set = true;
2899 }
2900
2901 return 1;
2902
2903 } else if (streq(name, "WorkingDirectory")) {
2904 const char *s;
2905 bool missing_ok;
2906
2907 r = sd_bus_message_read(message, "s", &s);
2908 if (r < 0)
2909 return r;
2910
2911 if (s[0] == '-') {
2912 missing_ok = true;
2913 s++;
2914 } else
2915 missing_ok = false;
2916
2917 if (!isempty(s) && !streq(s, "~") && !path_is_absolute(s))
2918 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects an absolute path or '~'");
2919
2920 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2921 if (streq(s, "~")) {
2922 c->working_directory = mfree(c->working_directory);
2923 c->working_directory_home = true;
2924 } else {
2925 r = free_and_strdup(&c->working_directory, empty_to_null(s));
2926 if (r < 0)
2927 return r;
2928
2929 c->working_directory_home = false;
2930 }
2931
2932 c->working_directory_missing_ok = missing_ok;
2933 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "WorkingDirectory=%s%s", missing_ok ? "-" : "", s);
2934 }
2935
2936 return 1;
2937
2938 } else if (STR_IN_SET(name,
2939 "StandardInputFileDescriptorName", "StandardOutputFileDescriptorName", "StandardErrorFileDescriptorName")) {
2940 const char *s;
2941
2942 r = sd_bus_message_read(message, "s", &s);
2943 if (r < 0)
2944 return r;
2945
2946 if (!isempty(s) && !fdname_is_valid(s))
2947 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid file descriptor name");
2948
2949 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2950
2951 if (streq(name, "StandardInputFileDescriptorName")) {
2952 r = free_and_strdup(c->stdio_fdname + STDIN_FILENO, empty_to_null(s));
2953 if (r < 0)
2954 return r;
2955
2956 c->std_input = EXEC_INPUT_NAMED_FD;
2957 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardInput=fd:%s", exec_context_fdname(c, STDIN_FILENO));
2958
2959 } else if (streq(name, "StandardOutputFileDescriptorName")) {
2960 r = free_and_strdup(c->stdio_fdname + STDOUT_FILENO, empty_to_null(s));
2961 if (r < 0)
2962 return r;
2963
2964 c->std_output = EXEC_OUTPUT_NAMED_FD;
2965 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=fd:%s", exec_context_fdname(c, STDOUT_FILENO));
2966
2967 } else {
2968 assert(streq(name, "StandardErrorFileDescriptorName"));
2969
2970 r = free_and_strdup(&c->stdio_fdname[STDERR_FILENO], empty_to_null(s));
2971 if (r < 0)
2972 return r;
2973
2974 c->std_error = EXEC_OUTPUT_NAMED_FD;
2975 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=fd:%s", exec_context_fdname(c, STDERR_FILENO));
2976 }
2977 }
2978
2979 return 1;
2980
2981 } else if (STR_IN_SET(name,
2982 "StandardInputFile",
2983 "StandardOutputFile", "StandardOutputFileToAppend", "StandardOutputFileToTruncate",
2984 "StandardErrorFile", "StandardErrorFileToAppend", "StandardErrorFileToTruncate")) {
2985 const char *s;
2986
2987 r = sd_bus_message_read(message, "s", &s);
2988 if (r < 0)
2989 return r;
2990
2991 if (!isempty(s)) {
2992 if (!path_is_absolute(s))
2993 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute", s);
2994 if (!path_is_normalized(s))
2995 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not normalized", s);
2996 }
2997
2998 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
2999
3000 if (streq(name, "StandardInputFile")) {
3001 r = free_and_strdup(&c->stdio_file[STDIN_FILENO], empty_to_null(s));
3002 if (r < 0)
3003 return r;
3004
3005 c->std_input = EXEC_INPUT_FILE;
3006 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardInput=file:%s", s);
3007
3008 } else if (STR_IN_SET(name, "StandardOutputFile", "StandardOutputFileToAppend", "StandardOutputFileToTruncate")) {
3009 r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], empty_to_null(s));
3010 if (r < 0)
3011 return r;
3012
3013 if (streq(name, "StandardOutputFile")) {
3014 c->std_output = EXEC_OUTPUT_FILE;
3015 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=file:%s", s);
3016 } else if (streq(name, "StandardOutputFileToAppend")) {
3017 c->std_output = EXEC_OUTPUT_FILE_APPEND;
3018 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=append:%s", s);
3019 } else {
3020 assert(streq(name, "StandardOutputFileToTruncate"));
3021 c->std_output = EXEC_OUTPUT_FILE_TRUNCATE;
3022 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=truncate:%s", s);
3023 }
3024 } else {
3025 assert(STR_IN_SET(name, "StandardErrorFile", "StandardErrorFileToAppend", "StandardErrorFileToTruncate"));
3026
3027 r = free_and_strdup(&c->stdio_file[STDERR_FILENO], empty_to_null(s));
3028 if (r < 0)
3029 return r;
3030
3031 if (streq(name, "StandardErrorFile")) {
3032 c->std_error = EXEC_OUTPUT_FILE;
3033 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=file:%s", s);
3034 } else if (streq(name, "StandardErrorFileToAppend")) {
3035 c->std_error = EXEC_OUTPUT_FILE_APPEND;
3036 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=append:%s", s);
3037 } else {
3038 assert(streq(name, "StandardErrorFileToTruncate"));
3039 c->std_error = EXEC_OUTPUT_FILE_TRUNCATE;
3040 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=truncate:%s", s);
3041 }
3042 }
3043 }
3044
3045 return 1;
3046
3047 } else if (streq(name, "StandardInputData")) {
3048 const void *p;
3049 size_t sz;
3050
3051 r = sd_bus_message_read_array(message, 'y', &p, &sz);
3052 if (r < 0)
3053 return r;
3054
3055 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3056 _cleanup_free_ char *encoded = NULL;
3057
3058 if (sz == 0) {
3059 c->stdin_data = mfree(c->stdin_data);
3060 c->stdin_data_size = 0;
3061
3062 unit_write_settingf(u, flags, name, "StandardInputData=");
3063 } else {
3064 void *q;
3065 ssize_t n;
3066
3067 if (c->stdin_data_size + sz < c->stdin_data_size || /* check for overflow */
3068 c->stdin_data_size + sz > EXEC_STDIN_DATA_MAX)
3069 return -E2BIG;
3070
3071 n = base64mem(p, sz, &encoded);
3072 if (n < 0)
3073 return (int) n;
3074
3075 q = realloc(c->stdin_data, c->stdin_data_size + sz);
3076 if (!q)
3077 return -ENOMEM;
3078
3079 memcpy((uint8_t*) q + c->stdin_data_size, p, sz);
3080
3081 c->stdin_data = q;
3082 c->stdin_data_size += sz;
3083
3084 unit_write_settingf(u, flags, name, "StandardInputData=%s", encoded);
3085 }
3086 }
3087
3088 return 1;
3089
3090 } else if (streq(name, "Environment")) {
3091
3092 _cleanup_strv_free_ char **l = NULL;
3093
3094 r = sd_bus_message_read_strv(message, &l);
3095 if (r < 0)
3096 return r;
3097
3098 if (!strv_env_is_valid(l))
3099 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block.");
3100
3101 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3102 if (strv_isempty(l)) {
3103 c->environment = strv_free(c->environment);
3104 unit_write_setting(u, flags, name, "Environment=");
3105 } else {
3106 _cleanup_free_ char *joined = NULL;
3107 char **e;
3108
3109 joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS|UNIT_ESCAPE_C);
3110 if (!joined)
3111 return -ENOMEM;
3112
3113 e = strv_env_merge(c->environment, l);
3114 if (!e)
3115 return -ENOMEM;
3116
3117 strv_free_and_replace(c->environment, e);
3118 unit_write_settingf(u, flags, name, "Environment=%s", joined);
3119 }
3120 }
3121
3122 return 1;
3123
3124 } else if (streq(name, "UnsetEnvironment")) {
3125
3126 _cleanup_strv_free_ char **l = NULL;
3127
3128 r = sd_bus_message_read_strv(message, &l);
3129 if (r < 0)
3130 return r;
3131
3132 if (!strv_env_name_or_assignment_is_valid(l))
3133 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UnsetEnvironment= list.");
3134
3135 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3136 if (strv_isempty(l)) {
3137 c->unset_environment = strv_free(c->unset_environment);
3138 unit_write_setting(u, flags, name, "UnsetEnvironment=");
3139 } else {
3140 _cleanup_free_ char *joined = NULL;
3141 char **e;
3142
3143 joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS|UNIT_ESCAPE_C);
3144 if (!joined)
3145 return -ENOMEM;
3146
3147 e = strv_env_merge(c->unset_environment, l);
3148 if (!e)
3149 return -ENOMEM;
3150
3151 strv_free_and_replace(c->unset_environment, e);
3152 unit_write_settingf(u, flags, name, "UnsetEnvironment=%s", joined);
3153 }
3154 }
3155
3156 return 1;
3157
3158 } else if (streq(name, "OOMScoreAdjust")) {
3159 int oa;
3160
3161 r = sd_bus_message_read(message, "i", &oa);
3162 if (r < 0)
3163 return r;
3164
3165 if (!oom_score_adjust_is_valid(oa))
3166 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "OOM score adjust value out of range");
3167
3168 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3169 c->oom_score_adjust = oa;
3170 c->oom_score_adjust_set = true;
3171 unit_write_settingf(u, flags, name, "OOMScoreAdjust=%i", oa);
3172 }
3173
3174 return 1;
3175
3176 } else if (streq(name, "CoredumpFilter")) {
3177 uint64_t f;
3178
3179 r = sd_bus_message_read(message, "t", &f);
3180 if (r < 0)
3181 return r;
3182
3183 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3184 c->coredump_filter = f;
3185 c->coredump_filter_set = true;
3186 unit_write_settingf(u, flags, name, "CoredumpFilter=0x%"PRIx64, f);
3187 }
3188
3189 return 1;
3190
3191 } else if (streq(name, "EnvironmentFiles")) {
3192
3193 _cleanup_free_ char *joined = NULL;
3194 _cleanup_fclose_ FILE *f = NULL;
3195 _cleanup_strv_free_ char **l = NULL;
3196 size_t size = 0;
3197
3198 r = sd_bus_message_enter_container(message, 'a', "(sb)");
3199 if (r < 0)
3200 return r;
3201
3202 f = open_memstream_unlocked(&joined, &size);
3203 if (!f)
3204 return -ENOMEM;
3205
3206 fputs("EnvironmentFile=\n", f);
3207
3208 STRV_FOREACH(i, c->environment_files) {
3209 _cleanup_free_ char *q = NULL;
3210
3211 q = specifier_escape(*i);
3212 if (!q)
3213 return -ENOMEM;
3214
3215 fprintf(f, "EnvironmentFile=%s\n", q);
3216 }
3217
3218 while ((r = sd_bus_message_enter_container(message, 'r', "sb")) > 0) {
3219 const char *path;
3220 int b;
3221
3222 r = sd_bus_message_read(message, "sb", &path, &b);
3223 if (r < 0)
3224 return r;
3225
3226 r = sd_bus_message_exit_container(message);
3227 if (r < 0)
3228 return r;
3229
3230 if (!path_is_absolute(path))
3231 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
3232
3233 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3234 _cleanup_free_ char *q = NULL, *buf = NULL;
3235
3236 buf = strjoin(b ? "-" : "", path);
3237 if (!buf)
3238 return -ENOMEM;
3239
3240 q = specifier_escape(buf);
3241 if (!q)
3242 return -ENOMEM;
3243
3244 fprintf(f, "EnvironmentFile=%s\n", q);
3245
3246 r = strv_consume(&l, TAKE_PTR(buf));
3247 if (r < 0)
3248 return r;
3249 }
3250 }
3251 if (r < 0)
3252 return r;
3253
3254 r = sd_bus_message_exit_container(message);
3255 if (r < 0)
3256 return r;
3257
3258 r = fflush_and_check(f);
3259 if (r < 0)
3260 return r;
3261
3262 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3263 if (strv_isempty(l)) {
3264 c->environment_files = strv_free(c->environment_files);
3265 unit_write_setting(u, flags, name, "EnvironmentFile=");
3266 } else {
3267 r = strv_extend_strv(&c->environment_files, l, true);
3268 if (r < 0)
3269 return r;
3270
3271 unit_write_setting(u, flags, name, joined);
3272 }
3273 }
3274
3275 return 1;
3276
3277 } else if (streq(name, "PassEnvironment")) {
3278
3279 _cleanup_strv_free_ char **l = NULL;
3280
3281 r = sd_bus_message_read_strv(message, &l);
3282 if (r < 0)
3283 return r;
3284
3285 if (!strv_env_name_is_valid(l))
3286 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PassEnvironment= block.");
3287
3288 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3289 if (strv_isempty(l)) {
3290 c->pass_environment = strv_free(c->pass_environment);
3291 unit_write_setting(u, flags, name, "PassEnvironment=");
3292 } else {
3293 _cleanup_free_ char *joined = NULL;
3294
3295 r = strv_extend_strv(&c->pass_environment, l, true);
3296 if (r < 0)
3297 return r;
3298
3299 /* We write just the new settings out to file, with unresolved specifiers. */
3300 joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS);
3301 if (!joined)
3302 return -ENOMEM;
3303
3304 unit_write_settingf(u, flags, name, "PassEnvironment=%s", joined);
3305 }
3306 }
3307
3308 return 1;
3309
3310 } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
3311 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths", "ExecPaths", "NoExecPaths",
3312 "ExtensionDirectories")) {
3313 _cleanup_strv_free_ char **l = NULL;
3314 char ***dirs;
3315
3316 r = sd_bus_message_read_strv(message, &l);
3317 if (r < 0)
3318 return r;
3319
3320 STRV_FOREACH(p, l) {
3321 char *i = *p;
3322 size_t offset;
3323
3324 offset = i[0] == '-';
3325 offset += i[offset] == '+';
3326 if (!path_is_absolute(i + offset))
3327 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
3328
3329 path_simplify(i + offset);
3330 }
3331
3332 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3333 if (STR_IN_SET(name, "ReadWriteDirectories", "ReadWritePaths"))
3334 dirs = &c->read_write_paths;
3335 else if (STR_IN_SET(name, "ReadOnlyDirectories", "ReadOnlyPaths"))
3336 dirs = &c->read_only_paths;
3337 else if (streq(name, "ExecPaths"))
3338 dirs = &c->exec_paths;
3339 else if (streq(name, "NoExecPaths"))
3340 dirs = &c->no_exec_paths;
3341 else if (streq(name, "ExtensionDirectories"))
3342 dirs = &c->extension_directories;
3343 else /* "InaccessiblePaths" */
3344 dirs = &c->inaccessible_paths;
3345
3346 if (strv_isempty(l)) {
3347 *dirs = strv_free(*dirs);
3348 unit_write_settingf(u, flags, name, "%s=", name);
3349 } else {
3350 _cleanup_free_ char *joined = NULL;
3351
3352 joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS);
3353 if (!joined)
3354 return -ENOMEM;
3355
3356 r = strv_extend_strv(dirs, l, true);
3357 if (r < 0)
3358 return -ENOMEM;
3359
3360 unit_write_settingf(u, flags, name, "%s=%s", name, joined);
3361 }
3362 }
3363
3364 return 1;
3365
3366 } else if (streq(name, "ExecSearchPath")) {
3367 _cleanup_strv_free_ char **l = NULL;
3368
3369 r = sd_bus_message_read_strv(message, &l);
3370 if (r < 0)
3371 return r;
3372
3373 STRV_FOREACH(p, l)
3374 if (!path_is_absolute(*p) || !path_is_normalized(*p) || strchr(*p, ':'))
3375 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
3376
3377 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3378 if (strv_isempty(l)) {
3379 c->exec_search_path = strv_free(c->exec_search_path);
3380 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "ExecSearchPath=");
3381 } else {
3382 _cleanup_free_ char *joined = NULL;
3383 r = strv_extend_strv(&c->exec_search_path, l, true);
3384 if (r < 0)
3385 return -ENOMEM;
3386 joined = strv_join(c->exec_search_path, ":");
3387 if (!joined)
3388 return log_oom();
3389 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "ExecSearchPath=%s", joined);
3390 }
3391 }
3392
3393 return 1;
3394
3395 } else if (STR_IN_SET(name, "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory")) {
3396 _cleanup_strv_free_ char **l = NULL;
3397
3398 r = sd_bus_message_read_strv(message, &l);
3399 if (r < 0)
3400 return r;
3401
3402 STRV_FOREACH(p, l) {
3403 if (!path_is_normalized(*p))
3404 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path is not normalized: %s", name, *p);
3405
3406 if (path_is_absolute(*p))
3407 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path is absolute: %s", name, *p);
3408
3409 if (path_startswith(*p, "private"))
3410 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path can't be 'private': %s", name, *p);
3411 }
3412
3413 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3414 ExecDirectoryType i;
3415 ExecDirectory *d;
3416
3417 assert_se((i = exec_directory_type_from_string(name)) >= 0);
3418 d = c->directories + i;
3419
3420 if (strv_isempty(l)) {
3421 exec_directory_done(d);
3422 unit_write_settingf(u, flags, name, "%s=", name);
3423 } else {
3424 _cleanup_free_ char *joined = NULL;
3425
3426 STRV_FOREACH(source, l) {
3427 r = exec_directory_add(d, *source, NULL);
3428 if (r < 0)
3429 return log_oom();
3430 }
3431 exec_directory_sort(d);
3432
3433 joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS);
3434 if (!joined)
3435 return -ENOMEM;
3436
3437 unit_write_settingf(u, flags, name, "%s=%s", name, joined);
3438 }
3439 }
3440
3441 return 1;
3442
3443 } else if (STR_IN_SET(name, "AppArmorProfile", "SmackProcessLabel")) {
3444 int ignore;
3445 const char *s;
3446
3447 r = sd_bus_message_read(message, "(bs)", &ignore, &s);
3448 if (r < 0)
3449 return r;
3450
3451 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3452 char **p;
3453 bool *b;
3454
3455 if (streq(name, "AppArmorProfile")) {
3456 p = &c->apparmor_profile;
3457 b = &c->apparmor_profile_ignore;
3458 } else { /* "SmackProcessLabel" */
3459 p = &c->smack_process_label;
3460 b = &c->smack_process_label_ignore;
3461 }
3462
3463 if (isempty(s)) {
3464 *p = mfree(*p);
3465 *b = false;
3466 } else {
3467 if (free_and_strdup(p, s) < 0)
3468 return -ENOMEM;
3469 *b = ignore;
3470 }
3471
3472 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s%s", name, ignore ? "-" : "", strempty(s));
3473 }
3474
3475 return 1;
3476
3477 } else if (STR_IN_SET(name, "BindPaths", "BindReadOnlyPaths")) {
3478 char *source, *destination;
3479 int ignore_enoent;
3480 uint64_t mount_flags;
3481 bool empty = true;
3482
3483 r = sd_bus_message_enter_container(message, 'a', "(ssbt)");
3484 if (r < 0)
3485 return r;
3486
3487 while ((r = sd_bus_message_read(message, "(ssbt)", &source, &destination, &ignore_enoent, &mount_flags)) > 0) {
3488
3489 if (!path_is_absolute(source))
3490 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not absolute.", source);
3491 if (!path_is_absolute(destination))
3492 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path %s is not absolute.", destination);
3493 if (!IN_SET(mount_flags, 0, MS_REC))
3494 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown mount flags.");
3495
3496 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3497 r = bind_mount_add(&c->bind_mounts, &c->n_bind_mounts,
3498 &(BindMount) {
3499 .source = source,
3500 .destination = destination,
3501 .read_only = !!strstr(name, "ReadOnly"),
3502 .recursive = !!(mount_flags & MS_REC),
3503 .ignore_enoent = ignore_enoent,
3504 });
3505 if (r < 0)
3506 return r;
3507
3508 unit_write_settingf(
3509 u, flags|UNIT_ESCAPE_SPECIFIERS, name,
3510 "%s=%s%s:%s:%s",
3511 name,
3512 ignore_enoent ? "-" : "",
3513 source,
3514 destination,
3515 (mount_flags & MS_REC) ? "rbind" : "norbind");
3516 }
3517
3518 empty = false;
3519 }
3520 if (r < 0)
3521 return r;
3522
3523 r = sd_bus_message_exit_container(message);
3524 if (r < 0)
3525 return r;
3526
3527 if (empty) {
3528 bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
3529 c->bind_mounts = NULL;
3530 c->n_bind_mounts = 0;
3531
3532 unit_write_settingf(u, flags, name, "%s=", name);
3533 }
3534
3535 return 1;
3536
3537 } else if (streq(name, "TemporaryFileSystem")) {
3538 const char *path, *options;
3539 bool empty = true;
3540
3541 r = sd_bus_message_enter_container(message, 'a', "(ss)");
3542 if (r < 0)
3543 return r;
3544
3545 while ((r = sd_bus_message_read(message, "(ss)", &path, &options)) > 0) {
3546
3547 if (!path_is_absolute(path))
3548 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Mount point %s is not absolute.", path);
3549
3550 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3551 r = temporary_filesystem_add(&c->temporary_filesystems, &c->n_temporary_filesystems, path, options);
3552 if (r < 0)
3553 return r;
3554
3555 unit_write_settingf(
3556 u, flags|UNIT_ESCAPE_SPECIFIERS, name,
3557 "%s=%s:%s",
3558 name,
3559 path,
3560 options);
3561 }
3562
3563 empty = false;
3564 }
3565 if (r < 0)
3566 return r;
3567
3568 r = sd_bus_message_exit_container(message);
3569 if (r < 0)
3570 return r;
3571
3572 if (empty) {
3573 temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
3574 c->temporary_filesystems = NULL;
3575 c->n_temporary_filesystems = 0;
3576
3577 unit_write_settingf(u, flags, name, "%s=", name);
3578 }
3579
3580 return 1;
3581
3582 } else if ((suffix = startswith(name, "Limit"))) {
3583 const char *soft = NULL;
3584 int ri;
3585
3586 ri = rlimit_from_string(suffix);
3587 if (ri < 0) {
3588 soft = endswith(suffix, "Soft");
3589 if (soft) {
3590 const char *n;
3591
3592 n = strndupa_safe(suffix, soft - suffix);
3593 ri = rlimit_from_string(n);
3594 if (ri >= 0)
3595 name = strjoina("Limit", n);
3596 }
3597 }
3598
3599 if (ri >= 0) {
3600 uint64_t rl;
3601 rlim_t x;
3602
3603 r = sd_bus_message_read(message, "t", &rl);
3604 if (r < 0)
3605 return r;
3606
3607 if (rl == UINT64_MAX)
3608 x = RLIM_INFINITY;
3609 else {
3610 x = (rlim_t) rl;
3611
3612 if ((uint64_t) x != rl)
3613 return -ERANGE;
3614 }
3615
3616 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3617 _cleanup_free_ char *f = NULL;
3618 struct rlimit nl;
3619
3620 if (c->rlimit[ri]) {
3621 nl = *c->rlimit[ri];
3622
3623 if (soft)
3624 nl.rlim_cur = x;
3625 else
3626 nl.rlim_max = x;
3627 } else
3628 /* When the resource limit is not initialized yet, then assign the value to both fields */
3629 nl = (struct rlimit) {
3630 .rlim_cur = x,
3631 .rlim_max = x,
3632 };
3633
3634 r = rlimit_format(&nl, &f);
3635 if (r < 0)
3636 return r;
3637
3638 if (c->rlimit[ri])
3639 *c->rlimit[ri] = nl;
3640 else {
3641 c->rlimit[ri] = newdup(struct rlimit, &nl, 1);
3642 if (!c->rlimit[ri])
3643 return -ENOMEM;
3644 }
3645
3646 unit_write_settingf(u, flags, name, "%s=%s", name, f);
3647 }
3648
3649 return 1;
3650 }
3651
3652 } else if (streq(name, "MountImages")) {
3653 _cleanup_free_ char *format_str = NULL;
3654 MountImage *mount_images = NULL;
3655 size_t n_mount_images = 0;
3656 char *source, *destination;
3657 int permissive;
3658
3659 r = sd_bus_message_enter_container(message, 'a', "(ssba(ss))");
3660 if (r < 0)
3661 return r;
3662
3663 for (;;) {
3664 _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
3665 _cleanup_free_ char *source_escaped = NULL, *destination_escaped = NULL;
3666 char *tuple;
3667
3668 r = sd_bus_message_enter_container(message, 'r', "ssba(ss)");
3669 if (r < 0)
3670 return r;
3671
3672 r = sd_bus_message_read(message, "ssb", &source, &destination, &permissive);
3673 if (r <= 0)
3674 break;
3675
3676 if (!path_is_absolute(source))
3677 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not absolute.", source);
3678 if (!path_is_normalized(source))
3679 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not normalized.", source);
3680 if (!path_is_absolute(destination))
3681 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path %s is not absolute.", destination);
3682 if (!path_is_normalized(destination))
3683 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path %s is not normalized.", destination);
3684
3685 /* Need to store them in the unit with the escapes, so that they can be parsed again */
3686 source_escaped = shell_escape(source, ":");
3687 if (!source_escaped)
3688 return -ENOMEM;
3689 destination_escaped = shell_escape(destination, ":");
3690 if (!destination_escaped)
3691 return -ENOMEM;
3692
3693 tuple = strjoin(format_str,
3694 format_str ? " " : "",
3695 permissive ? "-" : "",
3696 source_escaped,
3697 ":",
3698 destination_escaped);
3699 if (!tuple)
3700 return -ENOMEM;
3701 free_and_replace(format_str, tuple);
3702
3703 r = bus_read_mount_options(message, error, &options, &format_str, ":");
3704 if (r < 0)
3705 return r;
3706
3707 r = sd_bus_message_exit_container(message);
3708 if (r < 0)
3709 return r;
3710
3711 r = mount_image_add(&mount_images, &n_mount_images,
3712 &(MountImage) {
3713 .source = source,
3714 .destination = destination,
3715 .mount_options = options,
3716 .ignore_enoent = permissive,
3717 .type = MOUNT_IMAGE_DISCRETE,
3718 });
3719 if (r < 0)
3720 return r;
3721 }
3722 if (r < 0)
3723 return r;
3724
3725 r = sd_bus_message_exit_container(message);
3726 if (r < 0)
3727 return r;
3728
3729 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3730 if (n_mount_images == 0) {
3731 c->mount_images = mount_image_free_many(c->mount_images, &c->n_mount_images);
3732
3733 unit_write_settingf(u, flags, name, "%s=", name);
3734 } else {
3735 for (size_t i = 0; i < n_mount_images; ++i) {
3736 r = mount_image_add(&c->mount_images, &c->n_mount_images, &mount_images[i]);
3737 if (r < 0)
3738 return r;
3739 }
3740
3741 unit_write_settingf(u, flags|UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS,
3742 name,
3743 "%s=%s",
3744 name,
3745 format_str);
3746 }
3747 }
3748
3749 mount_images = mount_image_free_many(mount_images, &n_mount_images);
3750
3751 return 1;
3752 } else if (streq(name, "ExtensionImages")) {
3753 _cleanup_free_ char *format_str = NULL;
3754 MountImage *extension_images = NULL;
3755 size_t n_extension_images = 0;
3756
3757 r = sd_bus_message_enter_container(message, 'a', "(sba(ss))");
3758 if (r < 0)
3759 return r;
3760
3761 for (;;) {
3762 _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
3763 _cleanup_free_ char *source_escaped = NULL;
3764 char *source, *tuple;
3765 int permissive;
3766
3767 r = sd_bus_message_enter_container(message, 'r', "sba(ss)");
3768 if (r < 0)
3769 return r;
3770
3771 r = sd_bus_message_read(message, "sb", &source, &permissive);
3772 if (r <= 0)
3773 break;
3774
3775 if (!path_is_absolute(source))
3776 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not absolute.", source);
3777 if (!path_is_normalized(source))
3778 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not normalized.", source);
3779
3780 /* Need to store them in the unit with the escapes, so that they can be parsed again */
3781 source_escaped = shell_escape(source, ":");
3782 if (!source_escaped)
3783 return -ENOMEM;
3784
3785 tuple = strjoin(format_str,
3786 format_str ? " " : "",
3787 permissive ? "-" : "",
3788 source_escaped);
3789 if (!tuple)
3790 return -ENOMEM;
3791 free_and_replace(format_str, tuple);
3792
3793 r = bus_read_mount_options(message, error, &options, &format_str, ":");
3794 if (r < 0)
3795 return r;
3796
3797 r = sd_bus_message_exit_container(message);
3798 if (r < 0)
3799 return r;
3800
3801 r = mount_image_add(&extension_images, &n_extension_images,
3802 &(MountImage) {
3803 .source = source,
3804 .mount_options = options,
3805 .ignore_enoent = permissive,
3806 .type = MOUNT_IMAGE_EXTENSION,
3807 });
3808 if (r < 0)
3809 return r;
3810 }
3811 if (r < 0)
3812 return r;
3813
3814 r = sd_bus_message_exit_container(message);
3815 if (r < 0)
3816 return r;
3817
3818 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3819 if (n_extension_images == 0) {
3820 c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images);
3821
3822 unit_write_settingf(u, flags, name, "%s=", name);
3823 } else {
3824 for (size_t i = 0; i < n_extension_images; ++i) {
3825 r = mount_image_add(&c->extension_images, &c->n_extension_images, &extension_images[i]);
3826 if (r < 0)
3827 return r;
3828 }
3829
3830 unit_write_settingf(u, flags|UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS,
3831 name,
3832 "%s=%s",
3833 name,
3834 format_str);
3835 }
3836 }
3837
3838 extension_images = mount_image_free_many(extension_images, &n_extension_images);
3839
3840 return 1;
3841
3842 } else if (STR_IN_SET(name, "StateDirectorySymlink", "RuntimeDirectorySymlink", "CacheDirectorySymlink", "LogsDirectorySymlink")) {
3843 char *source, *destination;
3844 ExecDirectory *directory;
3845 uint64_t symlink_flags; /* No flags for now, reserved for future uses. */
3846 ExecDirectoryType i;
3847
3848 assert_se((i = exec_directory_type_symlink_from_string(name)) >= 0);
3849 directory = c->directories + i;
3850
3851 r = sd_bus_message_enter_container(message, 'a', "(sst)");
3852 if (r < 0)
3853 return r;
3854
3855 while ((r = sd_bus_message_read(message, "(sst)", &source, &destination, &symlink_flags)) > 0) {
3856 if (!path_is_valid(source))
3857 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not valid.", source);
3858 if (path_is_absolute(source))
3859 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is absolute.", source);
3860 if (!path_is_normalized(source))
3861 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not normalized.", source);
3862 if (!path_is_valid(destination))
3863 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path %s is not valid.", destination);
3864 if (path_is_absolute(destination))
3865 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path %s is absolute.", destination);
3866 if (!path_is_normalized(destination))
3867 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path %s is not normalized.", destination);
3868 if (symlink_flags != 0)
3869 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Flags must be zero.");
3870
3871 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
3872 _cleanup_free_ char *destination_escaped = NULL, *source_escaped = NULL;
3873
3874 r = exec_directory_add(directory, source, destination);
3875 if (r < 0)
3876 return r;
3877
3878 /* Need to store them in the unit with the escapes, so that they can be parsed again */
3879 source_escaped = xescape(source, ":");
3880 destination_escaped = xescape(destination, ":");
3881 if (!source_escaped || !destination_escaped)
3882 return -ENOMEM;
3883
3884 unit_write_settingf(
3885 u, flags|UNIT_ESCAPE_SPECIFIERS, exec_directory_type_to_string(i),
3886 "%s=%s:%s",
3887 exec_directory_type_to_string(i),
3888 source_escaped,
3889 destination_escaped);
3890 }
3891 }
3892 if (r < 0)
3893 return r;
3894
3895 exec_directory_sort(directory);
3896
3897 r = sd_bus_message_exit_container(message);
3898 if (r < 0)
3899 return r;
3900
3901 return 1;
3902
3903 }
3904
3905 return 0;
3906 }