1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2015 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include "alloc-util.h"
23 #include "conf-parser.h"
24 #include "nspawn-network.h"
25 #include "nspawn-settings.h"
26 #include "parse-util.h"
27 #include "process-util.h"
28 #include "socket-util.h"
29 #include "string-util.h"
31 #include "user-util.h"
34 int settings_load(FILE *f
, const char *path
, Settings
**ret
) {
35 _cleanup_(settings_freep
) Settings
*s
= NULL
;
41 s
= new0(Settings
, 1);
45 s
->start_mode
= _START_MODE_INVALID
;
46 s
->personality
= PERSONALITY_INVALID
;
47 s
->userns_mode
= _USER_NAMESPACE_MODE_INVALID
;
48 s
->uid_shift
= UID_INVALID
;
49 s
->uid_range
= UID_INVALID
;
52 s
->volatile_mode
= _VOLATILE_MODE_INVALID
;
55 s
->private_network
= -1;
58 r
= config_parse(NULL
, path
, f
,
62 config_item_perf_lookup
, nspawn_gperf_lookup
,
68 /* Make sure that if userns_mode is set, userns_chown is set to something appropriate, and vice versa. Either
69 * both fields shall be initialized or neither. */
70 if (s
->userns_mode
== USER_NAMESPACE_PICK
)
71 s
->userns_chown
= true;
72 else if (s
->userns_mode
!= _USER_NAMESPACE_MODE_INVALID
&& s
->userns_chown
< 0)
73 s
->userns_chown
= false;
75 if (s
->userns_chown
>= 0 && s
->userns_mode
== _USER_NAMESPACE_MODE_INVALID
)
76 s
->userns_mode
= USER_NAMESPACE_NO
;
83 Settings
* settings_free(Settings
*s
) {
88 strv_free(s
->parameters
);
89 strv_free(s
->environment
);
91 free(s
->pivot_root_new
);
92 free(s
->pivot_root_old
);
93 free(s
->working_directory
);
94 strv_free(s
->syscall_whitelist
);
95 strv_free(s
->syscall_blacklist
);
97 strv_free(s
->network_interfaces
);
98 strv_free(s
->network_macvlan
);
99 strv_free(s
->network_ipvlan
);
100 strv_free(s
->network_veth_extra
);
101 free(s
->network_bridge
);
102 free(s
->network_zone
);
103 expose_port_free_all(s
->expose_ports
);
105 custom_mount_free_all(s
->custom_mounts
, s
->n_custom_mounts
);
109 bool settings_private_network(Settings
*s
) {
113 s
->private_network
> 0 ||
114 s
->network_veth
> 0 ||
117 s
->network_interfaces
||
118 s
->network_macvlan
||
120 s
->network_veth_extra
;
123 bool settings_network_veth(Settings
*s
) {
127 s
->network_veth
> 0 ||
132 DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode
, volatile_mode
, VolatileMode
, "Failed to parse volatile mode");
134 int config_parse_expose_port(
136 const char *filename
,
139 unsigned section_line
,
153 r
= expose_port_parse(&s
->expose_ports
, rvalue
);
155 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Duplicate port specification, ignoring: %s", rvalue
);
159 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse host port %s: %m", rvalue
);
166 int config_parse_capability(
168 const char *filename
,
171 unsigned section_line
,
178 uint64_t u
= 0, *result
= data
;
186 _cleanup_free_
char *word
= NULL
;
189 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
191 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract capability string, ignoring: %s", rvalue
);
197 cap
= capability_from_name(word
);
199 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse capability, ignoring: %s", word
);
203 u
|= UINT64_C(1) << cap
;
213 int config_parse_id128(
215 const char *filename
,
218 unsigned section_line
,
225 sd_id128_t t
, *result
= data
;
232 r
= sd_id128_from_string(rvalue
, &t
);
234 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue
);
242 int config_parse_pivot_root(
244 const char *filename
,
247 unsigned section_line
,
254 Settings
*settings
= data
;
261 r
= pivot_root_parse(&settings
->pivot_root_new
, &settings
->pivot_root_old
, rvalue
);
263 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid pivot root mount specification %s: %m", rvalue
);
270 int config_parse_bind(
272 const char *filename
,
275 unsigned section_line
,
282 Settings
*settings
= data
;
289 r
= bind_mount_parse(&settings
->custom_mounts
, &settings
->n_custom_mounts
, rvalue
, ltype
);
291 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid bind mount specification %s: %m", rvalue
);
298 int config_parse_tmpfs(
300 const char *filename
,
303 unsigned section_line
,
310 Settings
*settings
= data
;
317 r
= tmpfs_mount_parse(&settings
->custom_mounts
, &settings
->n_custom_mounts
, rvalue
);
319 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid temporary file system specification %s: %m", rvalue
);
326 int config_parse_overlay(
328 const char *filename
,
331 unsigned section_line
,
338 Settings
*settings
= data
;
345 r
= overlay_mount_parse(&settings
->custom_mounts
, &settings
->n_custom_mounts
, rvalue
, ltype
);
347 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid overlay file system specification %s, ignoring: %m", rvalue
);
352 int config_parse_veth_extra(
354 const char *filename
,
357 unsigned section_line
,
364 Settings
*settings
= data
;
371 r
= veth_extra_parse(&settings
->network_veth_extra
, rvalue
);
373 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid extra virtual Ethernet link specification %s: %m", rvalue
);
380 int config_parse_network_zone(
382 const char *filename
,
385 unsigned section_line
,
392 Settings
*settings
= data
;
393 _cleanup_free_
char *j
= NULL
;
399 j
= strappend("vz-", rvalue
);
400 if (!ifname_valid(j
)) {
401 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid network zone name %s, ignoring: %m", rvalue
);
405 free_and_replace(settings
->network_zone
, j
);
410 int config_parse_boot(
412 const char *filename
,
415 unsigned section_line
,
422 Settings
*settings
= data
;
429 r
= parse_boolean(rvalue
);
431 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse Boot= parameter %s, ignoring: %m", rvalue
);
436 if (settings
->start_mode
== START_PID2
)
439 settings
->start_mode
= START_BOOT
;
441 if (settings
->start_mode
== START_BOOT
)
444 if (settings
->start_mode
< 0)
445 settings
->start_mode
= START_PID1
;
451 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
455 int config_parse_pid2(
457 const char *filename
,
460 unsigned section_line
,
467 Settings
*settings
= data
;
474 r
= parse_boolean(rvalue
);
476 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse ProcessTwo= parameter %s, ignoring: %m", rvalue
);
481 if (settings
->start_mode
== START_BOOT
)
484 settings
->start_mode
= START_PID2
;
486 if (settings
->start_mode
== START_PID2
)
489 if (settings
->start_mode
< 0)
490 settings
->start_mode
= START_PID1
;
496 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
500 int config_parse_private_users(
502 const char *filename
,
505 unsigned section_line
,
512 Settings
*settings
= data
;
519 r
= parse_boolean(rvalue
);
521 /* no: User namespacing off */
522 settings
->userns_mode
= USER_NAMESPACE_NO
;
523 settings
->uid_shift
= UID_INVALID
;
524 settings
->uid_range
= UINT32_C(0x10000);
526 /* yes: User namespacing on, UID range is read from root dir */
527 settings
->userns_mode
= USER_NAMESPACE_FIXED
;
528 settings
->uid_shift
= UID_INVALID
;
529 settings
->uid_range
= UINT32_C(0x10000);
530 } else if (streq(rvalue
, "pick")) {
531 /* pick: User namespacing on, UID range is picked randomly */
532 settings
->userns_mode
= USER_NAMESPACE_PICK
;
533 settings
->uid_shift
= UID_INVALID
;
534 settings
->uid_range
= UINT32_C(0x10000);
536 const char *range
, *shift
;
539 /* anything else: User namespacing on, UID range is explicitly configured */
541 range
= strchr(rvalue
, ':');
543 shift
= strndupa(rvalue
, range
- rvalue
);
546 r
= safe_atou32(range
, &rn
);
547 if (r
< 0 || rn
<= 0) {
548 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "UID/GID range invalid, ignoring: %s", range
);
553 rn
= UINT32_C(0x10000);
556 r
= parse_uid(shift
, &sh
);
558 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "UID/GID shift invalid, ignoring: %s", range
);
562 settings
->userns_mode
= USER_NAMESPACE_FIXED
;
563 settings
->uid_shift
= sh
;
564 settings
->uid_range
= rn
;
570 int config_parse_syscall_filter(
572 const char *filename
,
575 unsigned section_line
,
582 Settings
*settings
= data
;
591 negative
= rvalue
[0] == '~';
592 items
= negative
? rvalue
+ 1 : rvalue
;
595 _cleanup_free_
char *word
= NULL
;
597 r
= extract_first_word(&items
, &word
, NULL
, 0);
603 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SystemCallFilter= parameter %s, ignoring: %m", rvalue
);
608 r
= strv_extend(&settings
->syscall_blacklist
, word
);
610 r
= strv_extend(&settings
->syscall_whitelist
, word
);