1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2015 Lennart Poettering
8 #include "alloc-util.h"
10 #include "conf-parser.h"
11 #include "nspawn-network.h"
12 #include "nspawn-settings.h"
13 #include "parse-util.h"
14 #include "process-util.h"
15 #include "socket-util.h"
16 #include "string-util.h"
18 #include "user-util.h"
21 int settings_load(FILE *f
, const char *path
, Settings
**ret
) {
22 _cleanup_(settings_freep
) Settings
*s
= NULL
;
28 s
= new0(Settings
, 1);
32 s
->start_mode
= _START_MODE_INVALID
;
33 s
->personality
= PERSONALITY_INVALID
;
34 s
->userns_mode
= _USER_NAMESPACE_MODE_INVALID
;
35 s
->uid_shift
= UID_INVALID
;
36 s
->uid_range
= UID_INVALID
;
39 s
->volatile_mode
= _VOLATILE_MODE_INVALID
;
42 s
->private_network
= -1;
45 r
= config_parse(NULL
, path
, f
,
49 config_item_perf_lookup
, nspawn_gperf_lookup
,
55 /* Make sure that if userns_mode is set, userns_chown is set to something appropriate, and vice versa. Either
56 * both fields shall be initialized or neither. */
57 if (s
->userns_mode
== USER_NAMESPACE_PICK
)
58 s
->userns_chown
= true;
59 else if (s
->userns_mode
!= _USER_NAMESPACE_MODE_INVALID
&& s
->userns_chown
< 0)
60 s
->userns_chown
= false;
62 if (s
->userns_chown
>= 0 && s
->userns_mode
== _USER_NAMESPACE_MODE_INVALID
)
63 s
->userns_mode
= USER_NAMESPACE_NO
;
70 Settings
* settings_free(Settings
*s
) {
75 strv_free(s
->parameters
);
76 strv_free(s
->environment
);
78 free(s
->pivot_root_new
);
79 free(s
->pivot_root_old
);
80 free(s
->working_directory
);
81 strv_free(s
->syscall_whitelist
);
82 strv_free(s
->syscall_blacklist
);
84 strv_free(s
->network_interfaces
);
85 strv_free(s
->network_macvlan
);
86 strv_free(s
->network_ipvlan
);
87 strv_free(s
->network_veth_extra
);
88 free(s
->network_bridge
);
89 free(s
->network_zone
);
90 expose_port_free_all(s
->expose_ports
);
92 custom_mount_free_all(s
->custom_mounts
, s
->n_custom_mounts
);
96 bool settings_private_network(Settings
*s
) {
100 s
->private_network
> 0 ||
101 s
->network_veth
> 0 ||
104 s
->network_interfaces
||
105 s
->network_macvlan
||
107 s
->network_veth_extra
;
110 bool settings_network_veth(Settings
*s
) {
114 s
->network_veth
> 0 ||
119 DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode
, volatile_mode
, VolatileMode
, "Failed to parse volatile mode");
121 int config_parse_expose_port(
123 const char *filename
,
126 unsigned section_line
,
140 r
= expose_port_parse(&s
->expose_ports
, rvalue
);
142 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Duplicate port specification, ignoring: %s", rvalue
);
146 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse host port %s: %m", rvalue
);
153 int config_parse_capability(
155 const char *filename
,
158 unsigned section_line
,
165 uint64_t u
= 0, *result
= data
;
173 _cleanup_free_
char *word
= NULL
;
176 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
178 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract capability string, ignoring: %s", rvalue
);
184 cap
= capability_from_name(word
);
186 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse capability, ignoring: %s", word
);
190 u
|= UINT64_C(1) << cap
;
200 int config_parse_id128(
202 const char *filename
,
205 unsigned section_line
,
212 sd_id128_t t
, *result
= data
;
219 r
= sd_id128_from_string(rvalue
, &t
);
221 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue
);
229 int config_parse_pivot_root(
231 const char *filename
,
234 unsigned section_line
,
241 Settings
*settings
= data
;
248 r
= pivot_root_parse(&settings
->pivot_root_new
, &settings
->pivot_root_old
, rvalue
);
250 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid pivot root mount specification %s: %m", rvalue
);
257 int config_parse_bind(
259 const char *filename
,
262 unsigned section_line
,
269 Settings
*settings
= data
;
276 r
= bind_mount_parse(&settings
->custom_mounts
, &settings
->n_custom_mounts
, rvalue
, ltype
);
278 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid bind mount specification %s: %m", rvalue
);
285 int config_parse_tmpfs(
287 const char *filename
,
290 unsigned section_line
,
297 Settings
*settings
= data
;
304 r
= tmpfs_mount_parse(&settings
->custom_mounts
, &settings
->n_custom_mounts
, rvalue
);
306 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid temporary file system specification %s: %m", rvalue
);
313 int config_parse_overlay(
315 const char *filename
,
318 unsigned section_line
,
325 Settings
*settings
= data
;
332 r
= overlay_mount_parse(&settings
->custom_mounts
, &settings
->n_custom_mounts
, rvalue
, ltype
);
334 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid overlay file system specification %s, ignoring: %m", rvalue
);
339 int config_parse_veth_extra(
341 const char *filename
,
344 unsigned section_line
,
351 Settings
*settings
= data
;
358 r
= veth_extra_parse(&settings
->network_veth_extra
, rvalue
);
360 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid extra virtual Ethernet link specification %s: %m", rvalue
);
367 int config_parse_network_zone(
369 const char *filename
,
372 unsigned section_line
,
379 Settings
*settings
= data
;
380 _cleanup_free_
char *j
= NULL
;
386 j
= strappend("vz-", rvalue
);
387 if (!ifname_valid(j
)) {
388 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid network zone name %s, ignoring: %m", rvalue
);
392 free_and_replace(settings
->network_zone
, j
);
397 int config_parse_boot(
399 const char *filename
,
402 unsigned section_line
,
409 Settings
*settings
= data
;
416 r
= parse_boolean(rvalue
);
418 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse Boot= parameter %s, ignoring: %m", rvalue
);
423 if (settings
->start_mode
== START_PID2
)
426 settings
->start_mode
= START_BOOT
;
428 if (settings
->start_mode
== START_BOOT
)
431 if (settings
->start_mode
< 0)
432 settings
->start_mode
= START_PID1
;
438 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
442 int config_parse_pid2(
444 const char *filename
,
447 unsigned section_line
,
454 Settings
*settings
= data
;
461 r
= parse_boolean(rvalue
);
463 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse ProcessTwo= parameter %s, ignoring: %m", rvalue
);
468 if (settings
->start_mode
== START_BOOT
)
471 settings
->start_mode
= START_PID2
;
473 if (settings
->start_mode
== START_PID2
)
476 if (settings
->start_mode
< 0)
477 settings
->start_mode
= START_PID1
;
483 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
487 int config_parse_private_users(
489 const char *filename
,
492 unsigned section_line
,
499 Settings
*settings
= data
;
506 r
= parse_boolean(rvalue
);
508 /* no: User namespacing off */
509 settings
->userns_mode
= USER_NAMESPACE_NO
;
510 settings
->uid_shift
= UID_INVALID
;
511 settings
->uid_range
= UINT32_C(0x10000);
513 /* yes: User namespacing on, UID range is read from root dir */
514 settings
->userns_mode
= USER_NAMESPACE_FIXED
;
515 settings
->uid_shift
= UID_INVALID
;
516 settings
->uid_range
= UINT32_C(0x10000);
517 } else if (streq(rvalue
, "pick")) {
518 /* pick: User namespacing on, UID range is picked randomly */
519 settings
->userns_mode
= USER_NAMESPACE_PICK
;
520 settings
->uid_shift
= UID_INVALID
;
521 settings
->uid_range
= UINT32_C(0x10000);
523 const char *range
, *shift
;
526 /* anything else: User namespacing on, UID range is explicitly configured */
528 range
= strchr(rvalue
, ':');
530 shift
= strndupa(rvalue
, range
- rvalue
);
533 r
= safe_atou32(range
, &rn
);
534 if (r
< 0 || rn
<= 0) {
535 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "UID/GID range invalid, ignoring: %s", range
);
540 rn
= UINT32_C(0x10000);
543 r
= parse_uid(shift
, &sh
);
545 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "UID/GID shift invalid, ignoring: %s", range
);
549 settings
->userns_mode
= USER_NAMESPACE_FIXED
;
550 settings
->uid_shift
= sh
;
551 settings
->uid_range
= rn
;
557 int config_parse_syscall_filter(
559 const char *filename
,
562 unsigned section_line
,
569 Settings
*settings
= data
;
578 negative
= rvalue
[0] == '~';
579 items
= negative
? rvalue
+ 1 : rvalue
;
582 _cleanup_free_
char *word
= NULL
;
584 r
= extract_first_word(&items
, &word
, NULL
, 0);
590 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SystemCallFilter= parameter %s, ignoring: %m", rvalue
);
595 r
= strv_extend(&settings
->syscall_blacklist
, word
);
597 r
= strv_extend(&settings
->syscall_whitelist
, word
);