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