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