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