1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "alloc-util.h"
4 #include "cap-list.h"
5 #include "conf-parser.h"
6 #include "cpu-set-util.h"
7 #include "hostname-util.h"
8 #include "namespace-util.h"
9 #include "nspawn-network.h"
10 #include "nspawn-settings.h"
11 #include "parse-util.h"
12 #include "process-util.h"
13 #include "rlimit-util.h"
14 #include "socket-util.h"
15 #include "string-table.h"
16 #include "string-util.h"
17 #include "strv.h"
18 #include "user-util.h"
19 #include "util.h"
20
settings_new(void)21 Settings *settings_new(void) {
22 Settings *s;
23
24 s = new(Settings, 1);
25 if (!s)
26 return NULL;
27
28 *s = (Settings) {
29 .start_mode = _START_MODE_INVALID,
30 .ephemeral = -1,
31 .personality = PERSONALITY_INVALID,
32
33 .resolv_conf = _RESOLV_CONF_MODE_INVALID,
34 .link_journal = _LINK_JOURNAL_INVALID,
35 .timezone = _TIMEZONE_MODE_INVALID,
36
37 .userns_mode = _USER_NAMESPACE_MODE_INVALID,
38 .userns_ownership = _USER_NAMESPACE_OWNERSHIP_INVALID,
39 .uid_shift = UID_INVALID,
40 .uid_range = UID_INVALID,
41
42 .no_new_privileges = -1,
43
44 .read_only = -1,
45 .volatile_mode = _VOLATILE_MODE_INVALID,
46
47 .private_network = -1,
48 .network_veth = -1,
49
50 .full_capabilities = CAPABILITY_QUINTET_NULL,
51
52 .uid = UID_INVALID,
53 .gid = GID_INVALID,
54
55 .console_mode = _CONSOLE_MODE_INVALID,
56 .console_width = UINT_MAX,
57 .console_height = UINT_MAX,
58
59 .clone_ns_flags = ULONG_MAX,
60 .use_cgns = -1,
61
62 .notify_ready = -1,
63 .suppress_sync = -1,
64 };
65
66 return s;
67 }
68
settings_load(FILE * f,const char * path,Settings ** ret)69 int settings_load(FILE *f, const char *path, Settings **ret) {
70 _cleanup_(settings_freep) Settings *s = NULL;
71 int r;
72
73 assert(path);
74 assert(ret);
75
76 s = settings_new();
77 if (!s)
78 return -ENOMEM;
79
80 r = config_parse(NULL, path, f,
81 "Exec\0"
82 "Network\0"
83 "Files\0",
84 config_item_perf_lookup, nspawn_gperf_lookup,
85 CONFIG_PARSE_WARN,
86 s, NULL);
87 if (r < 0)
88 return r;
89
90 /* Make sure that if userns_mode is set, userns_chown is set to something appropriate, and vice versa. Either
91 * both fields shall be initialized or neither. */
92 if (s->userns_mode >= 0 && s->userns_ownership < 0)
93 s->userns_ownership = s->userns_mode == USER_NAMESPACE_PICK ? USER_NAMESPACE_OWNERSHIP_CHOWN : USER_NAMESPACE_OWNERSHIP_OFF;
94 if (s->userns_ownership >= 0 && s->userns_mode < 0)
95 s->userns_mode = USER_NAMESPACE_NO;
96
97 *ret = TAKE_PTR(s);
98 return 0;
99 }
100
free_oci_hooks(OciHook * h,size_t n)101 static void free_oci_hooks(OciHook *h, size_t n) {
102 size_t i;
103
104 assert(h || n == 0);
105
106 for (i = 0; i < n; i++) {
107 free(h[i].path);
108 strv_free(h[i].args);
109 strv_free(h[i].env);
110 }
111
112 free(h);
113 }
114
device_node_array_free(DeviceNode * node,size_t n)115 void device_node_array_free(DeviceNode *node, size_t n) {
116 size_t i;
117
118 for (i = 0; i < n; i++)
119 free(node[i].path);
120
121 free(node);
122 }
123
settings_free(Settings * s)124 Settings* settings_free(Settings *s) {
125 if (!s)
126 return NULL;
127
128 strv_free(s->parameters);
129 strv_free(s->environment);
130 free(s->user);
131 free(s->pivot_root_new);
132 free(s->pivot_root_old);
133 free(s->working_directory);
134 strv_free(s->syscall_allow_list);
135 strv_free(s->syscall_deny_list);
136 rlimit_free_all(s->rlimit);
137 free(s->hostname);
138 cpu_set_reset(&s->cpu_set);
139 strv_free(s->bind_user);
140
141 strv_free(s->network_interfaces);
142 strv_free(s->network_macvlan);
143 strv_free(s->network_ipvlan);
144 strv_free(s->network_veth_extra);
145 free(s->network_bridge);
146 free(s->network_zone);
147 expose_port_free_all(s->expose_ports);
148
149 custom_mount_free_all(s->custom_mounts, s->n_custom_mounts);
150
151 free(s->bundle);
152 free(s->root);
153
154 free_oci_hooks(s->oci_hooks_prestart, s->n_oci_hooks_prestart);
155 free_oci_hooks(s->oci_hooks_poststart, s->n_oci_hooks_poststart);
156 free_oci_hooks(s->oci_hooks_poststop, s->n_oci_hooks_poststop);
157
158 free(s->slice);
159 sd_bus_message_unref(s->properties);
160
161 free(s->supplementary_gids);
162 device_node_array_free(s->extra_nodes, s->n_extra_nodes);
163 free(s->network_namespace_path);
164
165 strv_free(s->sysctl);
166
167 #if HAVE_SECCOMP
168 seccomp_release(s->seccomp);
169 #endif
170
171 return mfree(s);
172 }
173
settings_private_network(Settings * s)174 bool settings_private_network(Settings *s) {
175 assert(s);
176
177 /* Determines whether we shall open up our own private network */
178
179 return
180 s->private_network > 0 ||
181 s->network_veth > 0 ||
182 s->network_bridge ||
183 s->network_zone ||
184 s->network_interfaces ||
185 s->network_macvlan ||
186 s->network_ipvlan ||
187 s->network_veth_extra;
188 }
189
settings_network_veth(Settings * s)190 bool settings_network_veth(Settings *s) {
191 assert(s);
192
193 return
194 s->network_veth > 0 ||
195 s->network_bridge ||
196 s->network_zone;
197 }
198
settings_network_configured(Settings * s)199 bool settings_network_configured(Settings *s) {
200 assert(s);
201
202 /* Determines whether any network configuration setting was used. (i.e. in contrast to
203 * settings_private_network() above this might also indicate if private networking was explicitly
204 * turned off.) */
205
206 return
207 s->private_network >= 0 ||
208 s->network_veth >= 0 ||
209 s->network_bridge ||
210 s->network_zone ||
211 s->network_interfaces ||
212 s->network_macvlan ||
213 s->network_ipvlan ||
214 s->network_veth_extra ||
215 s->network_namespace_path;
216 }
217
settings_allocate_properties(Settings * s)218 int settings_allocate_properties(Settings *s) {
219 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
220 int r;
221
222 assert(s);
223
224 if (s->properties)
225 return 0;
226
227 r = sd_bus_default_system(&bus);
228 if (r < 0)
229 return r;
230
231 r = sd_bus_message_new(bus, &s->properties, SD_BUS_MESSAGE_METHOD_CALL);
232 if (r < 0)
233 return r;
234
235 return 0;
236 }
237
238 DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode, volatile_mode, VolatileMode, "Failed to parse volatile mode");
239
config_parse_expose_port(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)240 int config_parse_expose_port(
241 const char *unit,
242 const char *filename,
243 unsigned line,
244 const char *section,
245 unsigned section_line,
246 const char *lvalue,
247 int ltype,
248 const char *rvalue,
249 void *data,
250 void *userdata) {
251
252 Settings *s = data;
253 int r;
254
255 assert(filename);
256 assert(lvalue);
257 assert(rvalue);
258
259 r = expose_port_parse(&s->expose_ports, rvalue);
260 if (r == -EEXIST)
261 log_syntax(unit, LOG_WARNING, filename, line, r, "Duplicate port specification, ignoring: %s", rvalue);
262 else if (r < 0)
263 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse host port %s: %m", rvalue);
264
265 return 0;
266 }
267
config_parse_capability(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)268 int config_parse_capability(
269 const char *unit,
270 const char *filename,
271 unsigned line,
272 const char *section,
273 unsigned section_line,
274 const char *lvalue,
275 int ltype,
276 const char *rvalue,
277 void *data,
278 void *userdata) {
279
280 uint64_t u = 0, *result = data;
281 int r;
282
283 assert(filename);
284 assert(lvalue);
285 assert(rvalue);
286
287 for (;;) {
288 _cleanup_free_ char *word = NULL;
289
290 r = extract_first_word(&rvalue, &word, NULL, 0);
291 if (r == -ENOMEM)
292 return log_oom();
293 if (r < 0) {
294 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to extract capability string, ignoring: %s", rvalue);
295 return 0;
296 }
297 if (r == 0)
298 break;
299
300 if (streq(word, "all"))
301 u = UINT64_MAX;
302 else {
303 r = capability_from_name(word);
304 if (r < 0) {
305 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse capability, ignoring: %s", word);
306 continue;
307 }
308
309 u |= UINT64_C(1) << r;
310 }
311 }
312
313 *result |= u;
314 return 0;
315 }
316
config_parse_pivot_root(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)317 int config_parse_pivot_root(
318 const char *unit,
319 const char *filename,
320 unsigned line,
321 const char *section,
322 unsigned section_line,
323 const char *lvalue,
324 int ltype,
325 const char *rvalue,
326 void *data,
327 void *userdata) {
328
329 Settings *settings = data;
330 int r;
331
332 assert(filename);
333 assert(lvalue);
334 assert(rvalue);
335
336 r = pivot_root_parse(&settings->pivot_root_new, &settings->pivot_root_old, rvalue);
337 if (r < 0)
338 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid pivot root mount specification %s: %m", rvalue);
339
340 return 0;
341 }
342
config_parse_bind(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)343 int config_parse_bind(
344 const char *unit,
345 const char *filename,
346 unsigned line,
347 const char *section,
348 unsigned section_line,
349 const char *lvalue,
350 int ltype,
351 const char *rvalue,
352 void *data,
353 void *userdata) {
354
355 Settings *settings = data;
356 int r;
357
358 assert(filename);
359 assert(lvalue);
360 assert(rvalue);
361
362 r = bind_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue, ltype);
363 if (r < 0)
364 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid bind mount specification %s: %m", rvalue);
365
366 return 0;
367 }
368
config_parse_tmpfs(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)369 int config_parse_tmpfs(
370 const char *unit,
371 const char *filename,
372 unsigned line,
373 const char *section,
374 unsigned section_line,
375 const char *lvalue,
376 int ltype,
377 const char *rvalue,
378 void *data,
379 void *userdata) {
380
381 Settings *settings = data;
382 int r;
383
384 assert(filename);
385 assert(lvalue);
386 assert(rvalue);
387
388 r = tmpfs_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue);
389 if (r < 0)
390 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid temporary file system specification %s: %m", rvalue);
391
392 return 0;
393 }
394
config_parse_inaccessible(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)395 int config_parse_inaccessible(
396 const char *unit,
397 const char *filename,
398 unsigned line,
399 const char *section,
400 unsigned section_line,
401 const char *lvalue,
402 int ltype,
403 const char *rvalue,
404 void *data,
405 void *userdata) {
406
407 Settings *settings = data;
408 int r;
409
410 assert(filename);
411 assert(lvalue);
412 assert(rvalue);
413
414 r = inaccessible_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue);
415 if (r < 0)
416 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid inaccessible file system specification %s: %m", rvalue);
417
418 return 0;
419 }
420
config_parse_overlay(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)421 int config_parse_overlay(
422 const char *unit,
423 const char *filename,
424 unsigned line,
425 const char *section,
426 unsigned section_line,
427 const char *lvalue,
428 int ltype,
429 const char *rvalue,
430 void *data,
431 void *userdata) {
432
433 Settings *settings = data;
434 int r;
435
436 assert(filename);
437 assert(lvalue);
438 assert(rvalue);
439
440 r = overlay_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue, ltype);
441 if (r < 0)
442 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid overlay file system specification %s, ignoring: %m", rvalue);
443
444 return 0;
445 }
446
config_parse_veth_extra(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)447 int config_parse_veth_extra(
448 const char *unit,
449 const char *filename,
450 unsigned line,
451 const char *section,
452 unsigned section_line,
453 const char *lvalue,
454 int ltype,
455 const char *rvalue,
456 void *data,
457 void *userdata) {
458
459 Settings *settings = data;
460 int r;
461
462 assert(filename);
463 assert(lvalue);
464 assert(rvalue);
465
466 r = veth_extra_parse(&settings->network_veth_extra, rvalue);
467 if (r < 0)
468 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid extra virtual Ethernet link specification %s: %m", rvalue);
469
470 return 0;
471 }
472
config_parse_network_zone(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)473 int config_parse_network_zone(
474 const char *unit,
475 const char *filename,
476 unsigned line,
477 const char *section,
478 unsigned section_line,
479 const char *lvalue,
480 int ltype,
481 const char *rvalue,
482 void *data,
483 void *userdata) {
484
485 Settings *settings = data;
486 _cleanup_free_ char *j = NULL;
487
488 assert(filename);
489 assert(lvalue);
490 assert(rvalue);
491
492 j = strjoin("vz-", rvalue);
493 if (!ifname_valid(j)) {
494 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid network zone name, ignoring: %s", rvalue);
495 return 0;
496 }
497
498 return free_and_replace(settings->network_zone, j);
499 }
500
config_parse_boot(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)501 int config_parse_boot(
502 const char *unit,
503 const char *filename,
504 unsigned line,
505 const char *section,
506 unsigned section_line,
507 const char *lvalue,
508 int ltype,
509 const char *rvalue,
510 void *data,
511 void *userdata) {
512
513 Settings *settings = data;
514 int r;
515
516 assert(filename);
517 assert(lvalue);
518 assert(rvalue);
519
520 r = parse_boolean(rvalue);
521 if (r < 0) {
522 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse Boot= parameter %s, ignoring: %m", rvalue);
523 return 0;
524 }
525
526 if (r) {
527 if (settings->start_mode == START_PID2)
528 goto conflict;
529
530 settings->start_mode = START_BOOT;
531 } else {
532 if (settings->start_mode == START_BOOT)
533 goto conflict;
534
535 if (settings->start_mode < 0)
536 settings->start_mode = START_PID1;
537 }
538
539 return 0;
540
541 conflict:
542 log_syntax(unit, LOG_WARNING, filename, line, 0, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
543 return 0;
544 }
545
config_parse_pid2(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)546 int config_parse_pid2(
547 const char *unit,
548 const char *filename,
549 unsigned line,
550 const char *section,
551 unsigned section_line,
552 const char *lvalue,
553 int ltype,
554 const char *rvalue,
555 void *data,
556 void *userdata) {
557
558 Settings *settings = data;
559 int r;
560
561 assert(filename);
562 assert(lvalue);
563 assert(rvalue);
564
565 r = parse_boolean(rvalue);
566 if (r < 0) {
567 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse ProcessTwo= parameter %s, ignoring: %m", rvalue);
568 return 0;
569 }
570
571 if (r) {
572 if (settings->start_mode == START_BOOT)
573 goto conflict;
574
575 settings->start_mode = START_PID2;
576 } else {
577 if (settings->start_mode == START_PID2)
578 goto conflict;
579
580 if (settings->start_mode < 0)
581 settings->start_mode = START_PID1;
582 }
583
584 return 0;
585
586 conflict:
587 log_syntax(unit, LOG_WARNING, filename, line, 0, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
588 return 0;
589 }
590
config_parse_private_users(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)591 int config_parse_private_users(
592 const char *unit,
593 const char *filename,
594 unsigned line,
595 const char *section,
596 unsigned section_line,
597 const char *lvalue,
598 int ltype,
599 const char *rvalue,
600 void *data,
601 void *userdata) {
602
603 Settings *settings = data;
604 int r;
605
606 assert(filename);
607 assert(lvalue);
608 assert(rvalue);
609
610 r = parse_boolean(rvalue);
611 if (r == 0) {
612 /* no: User namespacing off */
613 settings->userns_mode = USER_NAMESPACE_NO;
614 settings->uid_shift = UID_INVALID;
615 settings->uid_range = UINT32_C(0x10000);
616 } else if (r > 0) {
617 /* yes: User namespacing on, UID range is read from root dir */
618 settings->userns_mode = USER_NAMESPACE_FIXED;
619 settings->uid_shift = UID_INVALID;
620 settings->uid_range = UINT32_C(0x10000);
621 } else if (streq(rvalue, "pick")) {
622 /* pick: User namespacing on, UID range is picked randomly */
623 settings->userns_mode = USER_NAMESPACE_PICK;
624 settings->uid_shift = UID_INVALID;
625 settings->uid_range = UINT32_C(0x10000);
626 } else {
627 const char *range, *shift;
628 uid_t sh, rn;
629
630 /* anything else: User namespacing on, UID range is explicitly configured */
631
632 range = strchr(rvalue, ':');
633 if (range) {
634 shift = strndupa_safe(rvalue, range - rvalue);
635 range++;
636
637 r = safe_atou32(range, &rn);
638 if (r < 0) {
639 log_syntax(unit, LOG_WARNING, filename, line, r, "UID/GID range invalid, ignoring: %s", range);
640 return 0;
641 }
642 } else {
643 shift = rvalue;
644 rn = UINT32_C(0x10000);
645 }
646
647 r = parse_uid(shift, &sh);
648 if (r < 0) {
649 log_syntax(unit, LOG_WARNING, filename, line, r, "UID/GID shift invalid, ignoring: %s", range);
650 return 0;
651 }
652
653 if (!userns_shift_range_valid(sh, rn)) {
654 log_syntax(unit, LOG_WARNING, filename, line, 0, "UID/GID shift and range combination invalid, ignoring: %s", range);
655 return 0;
656 }
657
658 settings->userns_mode = USER_NAMESPACE_FIXED;
659 settings->uid_shift = sh;
660 settings->uid_range = rn;
661 }
662
663 return 0;
664 }
665
config_parse_syscall_filter(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)666 int config_parse_syscall_filter(
667 const char *unit,
668 const char *filename,
669 unsigned line,
670 const char *section,
671 unsigned section_line,
672 const char *lvalue,
673 int ltype,
674 const char *rvalue,
675 void *data,
676 void *userdata) {
677
678 Settings *settings = data;
679 bool negative;
680 const char *items;
681 int r;
682
683 assert(filename);
684 assert(lvalue);
685 assert(rvalue);
686
687 negative = rvalue[0] == '~';
688 items = negative ? rvalue + 1 : rvalue;
689
690 for (;;) {
691 _cleanup_free_ char *word = NULL;
692
693 r = extract_first_word(&items, &word, NULL, 0);
694 if (r == 0)
695 return 0;
696 if (r == -ENOMEM)
697 return log_oom();
698 if (r < 0) {
699 log_syntax(unit, LOG_WARNING, filename, line, r,
700 "Failed to parse SystemCallFilter= parameter %s, ignoring: %m", rvalue);
701 return 0;
702 }
703
704 if (negative)
705 r = strv_extend(&settings->syscall_deny_list, word);
706 else
707 r = strv_extend(&settings->syscall_allow_list, word);
708 if (r < 0)
709 return log_oom();
710 }
711 }
712
config_parse_oom_score_adjust(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)713 int config_parse_oom_score_adjust(
714 const char *unit,
715 const char *filename,
716 unsigned line,
717 const char *section,
718 unsigned section_line,
719 const char *lvalue,
720 int ltype,
721 const char *rvalue,
722 void *data,
723 void *userdata) {
724
725 Settings *settings = data;
726 int oa, r;
727
728 assert(rvalue);
729 assert(settings);
730
731 if (isempty(rvalue)) {
732 settings->oom_score_adjust_set = false;
733 return 0;
734 }
735
736 r = parse_oom_score_adjust(rvalue, &oa);
737 if (r == -ERANGE) {
738 log_syntax(unit, LOG_WARNING, filename, line, r, "OOM score adjust value out of range, ignoring: %s", rvalue);
739 return 0;
740 }
741 if (r < 0) {
742 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
743 return 0;
744 }
745
746 settings->oom_score_adjust = oa;
747 settings->oom_score_adjust_set = true;
748
749 return 0;
750 }
751
config_parse_cpu_affinity(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)752 int config_parse_cpu_affinity(
753 const char *unit,
754 const char *filename,
755 unsigned line,
756 const char *section,
757 unsigned section_line,
758 const char *lvalue,
759 int ltype,
760 const char *rvalue,
761 void *data,
762 void *userdata) {
763
764 Settings *settings = data;
765
766 assert(rvalue);
767 assert(settings);
768
769 return parse_cpu_set_extend(rvalue, &settings->cpu_set, true, unit, filename, line, lvalue);
770 }
771
772 DEFINE_CONFIG_PARSE_ENUM(config_parse_resolv_conf, resolv_conf_mode, ResolvConfMode, "Failed to parse resolv.conf mode");
773
774 static const char *const resolv_conf_mode_table[_RESOLV_CONF_MODE_MAX] = {
775 [RESOLV_CONF_OFF] = "off",
776 [RESOLV_CONF_COPY_HOST] = "copy-host",
777 [RESOLV_CONF_COPY_STATIC] = "copy-static",
778 [RESOLV_CONF_COPY_UPLINK] = "copy-uplink",
779 [RESOLV_CONF_COPY_STUB] = "copy-stub",
780 [RESOLV_CONF_REPLACE_HOST] = "replace-host",
781 [RESOLV_CONF_REPLACE_STATIC] = "replace-static",
782 [RESOLV_CONF_REPLACE_UPLINK] = "replace-uplink",
783 [RESOLV_CONF_REPLACE_STUB] = "replace-stub",
784 [RESOLV_CONF_BIND_HOST] = "bind-host",
785 [RESOLV_CONF_BIND_STATIC] = "bind-static",
786 [RESOLV_CONF_BIND_UPLINK] = "bind-uplink",
787 [RESOLV_CONF_BIND_STUB] = "bind-stub",
788 [RESOLV_CONF_DELETE] = "delete",
789 [RESOLV_CONF_AUTO] = "auto",
790 };
791
792 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(resolv_conf_mode, ResolvConfMode, RESOLV_CONF_AUTO);
793
parse_link_journal(const char * s,LinkJournal * ret_mode,bool * ret_try)794 int parse_link_journal(const char *s, LinkJournal *ret_mode, bool *ret_try) {
795 int r;
796
797 assert(s);
798 assert(ret_mode);
799 assert(ret_try);
800
801 if (streq(s, "auto")) {
802 *ret_mode = LINK_AUTO;
803 *ret_try = false;
804 } else if (streq(s, "guest")) {
805 *ret_mode = LINK_GUEST;
806 *ret_try = false;
807 } else if (streq(s, "host")) {
808 *ret_mode = LINK_HOST;
809 *ret_try = false;
810 } else if (streq(s, "try-guest")) {
811 *ret_mode = LINK_GUEST;
812 *ret_try = true;
813 } else if (streq(s, "try-host")) {
814 *ret_mode = LINK_HOST;
815 *ret_try = true;
816 } else {
817 /* Also support boolean values, to make things less confusing. */
818 r = parse_boolean(s);
819 if (r < 0)
820 return r;
821
822 /* Let's consider "true" to be equivalent to "auto". */
823 *ret_mode = r ? LINK_AUTO : LINK_NO;
824 *ret_try = false;
825 }
826
827 return 0;
828 }
829
config_parse_link_journal(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)830 int config_parse_link_journal(
831 const char *unit,
832 const char *filename,
833 unsigned line,
834 const char *section,
835 unsigned section_line,
836 const char *lvalue,
837 int ltype,
838 const char *rvalue,
839 void *data,
840 void *userdata) {
841
842 Settings *settings = data;
843 int r;
844
845 assert(rvalue);
846 assert(settings);
847
848 r = parse_link_journal(rvalue, &settings->link_journal, &settings->link_journal_try);
849 if (r < 0)
850 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse link journal mode, ignoring: %s", rvalue);
851
852 return 0;
853 }
854
855 DEFINE_CONFIG_PARSE_ENUM(config_parse_timezone, timezone_mode, TimezoneMode, "Failed to parse timezone mode");
856
857 static const char *const timezone_mode_table[_TIMEZONE_MODE_MAX] = {
858 [TIMEZONE_OFF] = "off",
859 [TIMEZONE_COPY] = "copy",
860 [TIMEZONE_BIND] = "bind",
861 [TIMEZONE_SYMLINK] = "symlink",
862 [TIMEZONE_DELETE] = "delete",
863 [TIMEZONE_AUTO] = "auto",
864 };
865
866 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(timezone_mode, TimezoneMode, TIMEZONE_AUTO);
867
868 DEFINE_CONFIG_PARSE_ENUM(config_parse_userns_ownership, user_namespace_ownership, UserNamespaceOwnership, "Failed to parse user namespace ownership mode");
869
870 static const char *const user_namespace_ownership_table[_USER_NAMESPACE_OWNERSHIP_MAX] = {
871 [USER_NAMESPACE_OWNERSHIP_OFF] = "off",
872 [USER_NAMESPACE_OWNERSHIP_CHOWN] = "chown",
873 [USER_NAMESPACE_OWNERSHIP_MAP] = "map",
874 [USER_NAMESPACE_OWNERSHIP_AUTO] = "auto",
875 };
876
877 DEFINE_STRING_TABLE_LOOKUP(user_namespace_ownership, UserNamespaceOwnership);
878
config_parse_userns_chown(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)879 int config_parse_userns_chown(
880 const char *unit,
881 const char *filename,
882 unsigned line,
883 const char *section,
884 unsigned section_line,
885 const char *lvalue,
886 int ltype,
887 const char *rvalue,
888 void *data,
889 void *userdata) {
890
891 UserNamespaceOwnership *ownership = data;
892 int r;
893
894 assert(rvalue);
895 assert(ownership);
896
897 /* Compatibility support for UserNamespaceChown=, whose job has been taken over by UserNamespaceOwnership= */
898
899 r = parse_boolean(rvalue);
900 if (r < 0) {
901 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse user namespace ownership mode, ignoring: %s", rvalue);
902 return 0;
903 }
904
905 *ownership = r ? USER_NAMESPACE_OWNERSHIP_CHOWN : USER_NAMESPACE_OWNERSHIP_OFF;
906 return 0;
907 }
908
config_parse_bind_user(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)909 int config_parse_bind_user(
910 const char *unit,
911 const char *filename,
912 unsigned line,
913 const char *section,
914 unsigned section_line,
915 const char *lvalue,
916 int ltype,
917 const char *rvalue,
918 void *data,
919 void *userdata) {
920
921 char ***bind_user = data;
922 int r;
923
924 assert(rvalue);
925 assert(bind_user);
926
927 if (isempty(rvalue)) {
928 *bind_user = strv_free(*bind_user);
929 return 0;
930 }
931
932 for (const char* p = rvalue;;) {
933 _cleanup_free_ char *word = NULL;
934
935 r = extract_first_word(&p, &word, NULL, 0);
936 if (r == -ENOMEM)
937 return log_oom();
938 if (r < 0) {
939 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse BindUser= list, ignoring: %s", rvalue);
940 return 0;
941 }
942 if (r == 0)
943 break;
944
945 if (!valid_user_group_name(word, 0)) {
946 log_syntax(unit, LOG_WARNING, filename, line, 0, "User name '%s' not valid, ignoring.", word);
947 return 0;
948 }
949
950 if (strv_consume(bind_user, TAKE_PTR(word)) < 0)
951 return log_oom();
952 }
953
954 return 0;
955 }
956